public static TriangleData processTriangle(int[] index, Vector3f[] v, Vector2f[] t) {
    Vector3f edge1 = new Vector3f();
    Vector3f edge2 = new Vector3f();
    Vector2f edge1uv = new Vector2f();
    Vector2f edge2uv = new Vector2f();

    Vector3f tangent = new Vector3f();
    Vector3f binormal = new Vector3f();
    Vector3f normal = new Vector3f();

    t[1].subtract(t[0], edge1uv);
    t[2].subtract(t[0], edge2uv);
    float det = edge1uv.x * edge2uv.y - edge1uv.y * edge2uv.x;

    boolean normalize = false;
    if (Math.abs(det) < ZERO_TOLERANCE) {
      //			log.log(Level.WARNING, "Colinear uv coordinates for triangle " + "[{0}, {1}, {2}]; tex0 =
      // [{3}, {4}], " + "tex1 = [{5}, {6}], tex2 = [{7}, {8}]",
      //					new Object[] { index[0], index[1], index[2], t[0].x, t[0].y, t[1].x, t[1].y, t[2].x,
      // t[2].y });
      det = 1;
      normalize = true;
    }

    v[1].subtract(v[0], edge1);
    v[2].subtract(v[0], edge2);

    tangent.set(edge1);
    tangent.normalizeLocal();
    binormal.set(edge2);
    binormal.normalizeLocal();

    if (Math.abs(Math.abs(tangent.dot(binormal)) - 1) < ZERO_TOLERANCE) {
      //			log.log(Level.WARNING, "Vertices are on the same line " + "for triangle [{0}, {1},
      // {2}].", new Object[] { index[0], index[1], index[2] });
    }

    float factor = 1 / det;
    tangent.x = (edge2uv.y * edge1.x - edge1uv.y * edge2.x) * factor;
    tangent.y = (edge2uv.y * edge1.y - edge1uv.y * edge2.y) * factor;
    tangent.z = (edge2uv.y * edge1.z - edge1uv.y * edge2.z) * factor;
    if (normalize) {
      tangent.normalizeLocal();
    }

    binormal.x = (edge1uv.x * edge2.x - edge2uv.x * edge1.x) * factor;
    binormal.y = (edge1uv.x * edge2.y - edge2uv.x * edge1.y) * factor;
    binormal.z = (edge1uv.x * edge2.z - edge2uv.x * edge1.z) * factor;
    if (normalize) {
      binormal.normalizeLocal();
    }

    tangent.cross(binormal, normal);
    normal.normalizeLocal();

    return new TriangleData(tangent, binormal, normal);
  }
  private void doTransforms(
      FloatBuffer bindBufPos,
      FloatBuffer bindBufNorm,
      FloatBuffer bufPos,
      FloatBuffer bufNorm,
      int start,
      int end,
      Matrix4f transform) {
    TempVars vars = TempVars.get();
    Vector3f pos = vars.vect1;
    Vector3f norm = vars.vect2;

    int length = (end - start) * 3;

    // offset is given in element units
    // convert to be in component units
    int offset = start * 3;
    bindBufPos.rewind();
    bindBufNorm.rewind();
    // bufPos.position(offset);
    // bufNorm.position(offset);
    bindBufPos.get(tmpFloat, 0, length);
    bindBufNorm.get(tmpFloatN, 0, length);
    int index = 0;
    while (index < length) {
      pos.x = tmpFloat[index];
      norm.x = tmpFloatN[index++];
      pos.y = tmpFloat[index];
      norm.y = tmpFloatN[index++];
      pos.z = tmpFloat[index];
      norm.z = tmpFloatN[index];

      transform.mult(pos, pos);
      transform.multNormal(norm, norm);

      index -= 2;
      tmpFloat[index] = pos.x;
      tmpFloatN[index++] = norm.x;
      tmpFloat[index] = pos.y;
      tmpFloatN[index++] = norm.y;
      tmpFloat[index] = pos.z;
      tmpFloatN[index++] = norm.z;
    }
    vars.release();
    bufPos.position(offset);
    // using bulk put as it's faster
    bufPos.put(tmpFloat, 0, length);
    bufNorm.position(offset);
    // using bulk put as it's faster
    bufNorm.put(tmpFloatN, 0, length);
  }
  /**
   * Returns true iff the node contains at least one intersection, after sampling at the MaxDepth
   * level.
   */
  public static boolean containsIntersection(
      OctreeNode octreeNode, int maxDepth, ArrayList<Primitive> primitives) {
    // First off, check if the node is null.
    if (octreeNode == null) {
      return false;
    }

    // Subdivide to the finest possible level.
    // The subdivision level equals 2^n, where n is max-current depth.
    int divisionLevel = 1 << (maxDepth - octreeNode.getDepth());

    Vector3f startPoint = octreeNode.getMinBound();
    Vector3f offset = octreeNode.getMaxBound().subtract(startPoint).divideLocal(divisionLevel);
    boolean sign = getValueAt(startPoint, primitives) > 0;
    Vector3f currentPoint = new Vector3f();
    for (int i = 0; i < divisionLevel + 1; i++) {
      for (int j = 0; j < divisionLevel + 1; j++) {
        for (int k = 0; k < divisionLevel + 1; k++) {
          currentPoint.x = startPoint.x + i * offset.x;
          currentPoint.y = startPoint.y + j * offset.y;
          currentPoint.z = startPoint.z + k * offset.z;

          if (getValueAt(currentPoint, primitives) > 0 != sign) {
            return true;
          }
        }
      }
    }

    return false;
  }
  /** Interpolates the intersection point from CSG values at both corners. */
  public static Vector3f interpolateIntersection(
      ArrayList<Primitive> primitives, Vector3f p1, Vector3f p2, float v1, float v2) {
    // If one of the values is too small, snap to the other point.
    if (Math.abs(v1) < 0.001f) {
      return p1.clone();
    }
    if (Math.abs(v2) < 0.001f) {
      return p2.clone();
    }
    // Also, if the two values are too close, return p1.
    if (Math.abs(v2 - v1) < 0.001f) {
      return p1.clone();
    }

    v1 = Math.abs(v1);
    v2 = Math.abs(v2);

    Vector3f intersectionPoint = new Vector3f();

    float v = v1 + v2;
    intersectionPoint.x = (v2 * p1.x + v1 * p2.x) / v;
    intersectionPoint.y = (v2 * p1.y + v1 * p2.y) / v;
    intersectionPoint.z = (v2 * p1.z + v1 * p2.z) / v;

    return intersectionPoint;
  }
 @Override
 public void getRandomPoint(Vector3f store) {
   do {
     store.x = (FastMath.nextRandomFloat() * 2f - 1f) * radius;
     store.y = (FastMath.nextRandomFloat() * 2f - 1f) * radius;
     store.z = (FastMath.nextRandomFloat() * 2f - 1f) * radius;
   } while (store.distance(center) > radius);
 }
  private void doCopyBuffer(FloatBuffer inBuf, int offset, FloatBuffer outBuf, int componentSize) {
    TempVars vars = TempVars.get();
    Vector3f pos = vars.vect1;

    // offset is given in element units
    // convert to be in component units
    offset *= componentSize;

    for (int i = 0; i < inBuf.limit() / componentSize; i++) {
      pos.x = inBuf.get(i * componentSize + 0);
      pos.y = inBuf.get(i * componentSize + 1);
      pos.z = inBuf.get(i * componentSize + 2);

      outBuf.put(offset + i * componentSize + 0, pos.x);
      outBuf.put(offset + i * componentSize + 1, pos.y);
      outBuf.put(offset + i * componentSize + 2, pos.z);
    }
    vars.release();
  }
  private static void doTransformNorms(
      FloatBuffer inBuf, int offset, FloatBuffer outBuf, Matrix4f transform) {
    Vector3f norm = new Vector3f();

    // offset is given in element units
    // convert to be in component units
    offset *= 3;

    for (int i = 0; i < inBuf.limit() / 3; i++) {
      norm.x = inBuf.get(i * 3 + 0);
      norm.y = inBuf.get(i * 3 + 1);
      norm.z = inBuf.get(i * 3 + 2);

      transform.multNormal(norm, norm);

      outBuf.put(offset + i * 3 + 0, norm.x);
      outBuf.put(offset + i * 3 + 1, norm.y);
      outBuf.put(offset + i * 3 + 2, norm.z);
    }
  }
  private static void doTransformVerts(
      FloatBuffer inBuf, int offset, FloatBuffer outBuf, Matrix4f transform) {
    Vector3f pos = new Vector3f();

    // offset is given in element units
    // convert to be in component units
    offset *= 3;

    for (int i = 0; i < inBuf.limit() / 3; i++) {
      pos.x = inBuf.get(i * 3 + 0);
      pos.y = inBuf.get(i * 3 + 1);
      pos.z = inBuf.get(i * 3 + 2);

      transform.mult(pos, pos);

      outBuf.put(offset + i * 3 + 0, pos.x);
      outBuf.put(offset + i * 3 + 1, pos.y);
      outBuf.put(offset + i * 3 + 2, pos.z);
    }
  }
  /**
   * Compute bounds from an array of points
   *
   * @param pts
   * @param mat
   * @return
   */
  public static BoundingBox computeBoundForPoints(Vector3f[] pts, Matrix4f mat) {
    Vector3f min = new Vector3f(Vector3f.POSITIVE_INFINITY);
    Vector3f max = new Vector3f(Vector3f.NEGATIVE_INFINITY);
    Vector3f temp = new Vector3f();

    for (int i = 0; i < pts.length; i++) {
      float w = mat.multProj(pts[i], temp);

      temp.x /= w;
      temp.y /= w;
      // Why was this commented out?
      temp.z /= w;

      min.minLocal(temp);
      max.maxLocal(temp);
    }

    Vector3f center = min.add(max).multLocal(0.5f);
    Vector3f extent = max.subtract(min).multLocal(0.5f);
    // Nehon 08/18/2010 : Added an offset to the extend to avoid banding artifacts when the frustum
    // are aligned
    return new BoundingBox(center, extent.x + 2.0f, extent.y + 2.0f, extent.z + 2.5f);
  }
  private static void doTransformTangents(
      FloatBuffer inBuf, int offset, int components, FloatBuffer outBuf, Matrix4f transform) {
    Vector3f tan = new Vector3f();

    // offset is given in element units
    // convert to be in component units
    offset *= components;

    for (int i = 0; i < inBuf.limit() / components; i++) {
      tan.x = inBuf.get(i * components + 0);
      tan.y = inBuf.get(i * components + 1);
      tan.z = inBuf.get(i * components + 2);

      transform.multNormal(tan, tan);

      outBuf.put(offset + i * components + 0, tan.x);
      outBuf.put(offset + i * components + 1, tan.y);
      outBuf.put(offset + i * components + 2, tan.z);

      if (components == 4) {
        outBuf.put(offset + i * components + 3, inBuf.get(i * components + 3));
      }
    }
  }
  @Override
  public void updateParticleData(ParticleData[] particles, Camera cam, Matrix3f inverseRotation) {

    for (int i = 0; i < particles.length; i++) {
      ParticleData p = particles[i];
      int offset = templateVerts.capacity() * i;
      int colorOffset = templateColors.capacity() * i;
      if (p.life == 0 || !p.active) {
        for (int x = 0; x < templateVerts.capacity(); x += 3) {
          finVerts.put(offset + x, 0);
          finVerts.put(offset + x + 1, 0);
          finVerts.put(offset + x + 2, 0);
        }
        continue;
      }

      for (int x = 0; x < templateVerts.capacity(); x += 3) {
        switch (emitter.getBillboardMode()) {
          case Velocity:
            if (p.velocity.x != Vector3f.UNIT_Y.x
                && p.velocity.y != Vector3f.UNIT_Y.y
                && p.velocity.z != Vector3f.UNIT_Y.z)
              up.set(p.velocity).crossLocal(Vector3f.UNIT_Y).normalizeLocal();
            else up.set(p.velocity).crossLocal(lock).normalizeLocal();
            left.set(p.velocity).crossLocal(up).normalizeLocal();
            dir.set(p.velocity);
            break;
          case Velocity_Z_Up:
            if (p.velocity.x != Vector3f.UNIT_Y.x
                && p.velocity.y != Vector3f.UNIT_Y.y
                && p.velocity.z != Vector3f.UNIT_Y.z)
              up.set(p.velocity).crossLocal(Vector3f.UNIT_Y).normalizeLocal();
            else up.set(p.velocity).crossLocal(lock).normalizeLocal();
            left.set(p.velocity).crossLocal(up).normalizeLocal();
            dir.set(p.velocity);
            rotStore = tempQ.fromAngleAxis(-90 * FastMath.DEG_TO_RAD, left);
            left = rotStore.mult(left);
            up = rotStore.mult(up);
            break;
          case Velocity_Z_Up_Y_Left:
            up.set(p.velocity).crossLocal(Vector3f.UNIT_Y).normalizeLocal();
            left.set(p.velocity).crossLocal(up).normalizeLocal();
            dir.set(p.velocity);
            tempV3.set(left).crossLocal(up).normalizeLocal();
            rotStore = tempQ.fromAngleAxis(90 * FastMath.DEG_TO_RAD, p.velocity);
            left = rotStore.mult(left);
            up = rotStore.mult(up);
            rotStore = tempQ.fromAngleAxis(-90 * FastMath.DEG_TO_RAD, left);
            up = rotStore.mult(up);
            break;
          case Normal:
            emitter.getShape().setNext(p.triangleIndex);
            tempV3.set(emitter.getShape().getNormal());
            if (tempV3 == Vector3f.UNIT_Y) tempV3.set(p.velocity);

            up.set(tempV3).crossLocal(Vector3f.UNIT_Y).normalizeLocal();
            left.set(tempV3).crossLocal(up).normalizeLocal();
            dir.set(tempV3);
            break;
          case Normal_Y_Up:
            emitter.getShape().setNext(p.triangleIndex);
            tempV3.set(p.velocity);
            if (tempV3 == Vector3f.UNIT_Y) tempV3.set(Vector3f.UNIT_X);

            up.set(Vector3f.UNIT_Y);
            left.set(tempV3).crossLocal(up).normalizeLocal();
            dir.set(tempV3);
            break;
          case Camera:
            up.set(cam.getUp());
            left.set(cam.getLeft());
            dir.set(cam.getDirection());
            break;
          case UNIT_X:
            up.set(Vector3f.UNIT_Y);
            left.set(Vector3f.UNIT_Z);
            dir.set(Vector3f.UNIT_X);
            break;
          case UNIT_Y:
            up.set(Vector3f.UNIT_Z);
            left.set(Vector3f.UNIT_X);
            dir.set(Vector3f.UNIT_Y);
            break;
          case UNIT_Z:
            up.set(Vector3f.UNIT_X);
            left.set(Vector3f.UNIT_Y);
            dir.set(Vector3f.UNIT_Z);
            break;
        }

        tempV3.set(templateVerts.get(x), templateVerts.get(x + 1), templateVerts.get(x + 2));
        tempV3 = rotStore.mult(tempV3);
        tempV3.multLocal(p.size);

        rotStore.fromAngles(p.angles.x, p.angles.y, p.angles.z);
        tempV3 = rotStore.mult(tempV3);

        tempV3.addLocal(p.position);
        if (!emitter.getParticlesFollowEmitter()) {
          tempV3.subtractLocal(
              emitter
                  .getEmitterNode()
                  .getWorldTranslation()
                  .subtract(p.initialPosition)); // .divide(8f));
        }

        finVerts.put(offset + x, tempV3.getX());
        finVerts.put(offset + x + 1, tempV3.getY());
        finVerts.put(offset + x + 2, tempV3.getZ());
      }
      if (p.emitter.getApplyLightingTransform()) {
        for (int v = 0; v < templateNormals.capacity(); v += 3) {
          tempV3.set(
              templateNormals.get(v), templateNormals.get(v + 1), templateNormals.get(v + 2));

          rotStore.fromAngles(p.angles.x, p.angles.y, p.angles.z);
          mat3.set(rotStore.toRotationMatrix());
          float vx = tempV3.x, vy = tempV3.y, vz = tempV3.z;
          tempV3.x = mat3.get(0, 0) * vx + mat3.get(0, 1) * vy + mat3.get(0, 2) * vz;
          tempV3.y = mat3.get(1, 0) * vx + mat3.get(1, 1) * vy + mat3.get(1, 2) * vz;
          tempV3.z = mat3.get(2, 0) * vx + mat3.get(2, 1) * vy + mat3.get(2, 2) * vz;

          finNormals.put(offset + v, tempV3.getX());
          finNormals.put(offset + v + 1, tempV3.getY());
          finNormals.put(offset + v + 2, tempV3.getZ());
        }
      }
      for (int v = 0; v < templateColors.capacity(); v += 4) {
        finColors
            .put(colorOffset + v, p.color.r)
            .put(colorOffset + v + 1, p.color.g)
            .put(colorOffset + v + 2, p.color.b)
            .put(colorOffset + v + 3, p.color.a * p.alpha);
      }
    }

    this.setBuffer(VertexBuffer.Type.Position, 3, finVerts);
    if (particles[0].emitter.getApplyLightingTransform())
      this.setBuffer(VertexBuffer.Type.Normal, 3, finNormals);
    this.setBuffer(VertexBuffer.Type.Color, 4, finColors);

    updateBound();
  }
 public Vector3f getCenterLocation(TerrainPatch patch) {
   Vector3f loc = patch.getWorldTranslation().clone();
   loc.x += patch.getSize() / 2;
   loc.z += patch.getSize() / 2;
   return loc;
 }
Exemple #13
0
  /**
   * Updates the shadow camera to properly contain the given points (which contain the eye camera
   * frustum corners) and the shadow occluder objects.
   *
   * @param occluders
   * @param shadowCam
   * @param points
   */
  public static void updateShadowCamera(
      GeometryList occluders,
      GeometryList receivers,
      Camera shadowCam,
      Vector3f[] points,
      GeometryList splitOccluders) {

    boolean ortho = shadowCam.isParallelProjection();

    shadowCam.setProjectionMatrix(null);

    if (ortho) {
      shadowCam.setFrustum(-1, 1, -1, 1, 1, -1);
    }

    // create transform to rotate points to viewspace
    Matrix4f viewProjMatrix = shadowCam.getViewProjectionMatrix();

    BoundingBox splitBB = computeBoundForPoints(points, viewProjMatrix);

    ArrayList<BoundingVolume> visRecvList = new ArrayList<BoundingVolume>();
    for (int i = 0; i < receivers.size(); i++) {
      // convert bounding box to light's viewproj space
      Geometry receiver = receivers.get(i);
      BoundingVolume bv = receiver.getWorldBound();
      BoundingVolume recvBox = bv.transform(viewProjMatrix, null);

      if (splitBB.intersects(recvBox)) {
        visRecvList.add(recvBox);
      }
    }

    ArrayList<BoundingVolume> visOccList = new ArrayList<BoundingVolume>();
    for (int i = 0; i < occluders.size(); i++) {
      // convert bounding box to light's viewproj space
      Geometry occluder = occluders.get(i);
      BoundingVolume bv = occluder.getWorldBound();
      BoundingVolume occBox = bv.transform(viewProjMatrix, null);

      boolean intersects = splitBB.intersects(occBox);
      if (!intersects && occBox instanceof BoundingBox) {
        BoundingBox occBB = (BoundingBox) occBox;
        // Kirill 01/10/2011
        // Extend the occluder further into the frustum
        // This fixes shadow dissapearing issues when
        // the caster itself is not in the view camera
        // but its shadow is in the camera
        //      The number is in world units
        occBB.setZExtent(occBB.getZExtent() + 50);
        occBB.setCenter(occBB.getCenter().addLocal(0, 0, 25));
        if (splitBB.intersects(occBB)) {
          // To prevent extending the depth range too much
          // We return the bound to its former shape
          // Before adding it
          occBB.setZExtent(occBB.getZExtent() - 50);
          occBB.setCenter(occBB.getCenter().subtractLocal(0, 0, 25));
          visOccList.add(occBox);
          if (splitOccluders != null) {
            splitOccluders.add(occluder);
          }
        }
      } else if (intersects) {
        visOccList.add(occBox);
        if (splitOccluders != null) {
          splitOccluders.add(occluder);
        }
      }
    }

    BoundingBox casterBB = computeUnionBound(visOccList);
    BoundingBox receiverBB = computeUnionBound(visRecvList);

    // Nehon 08/18/2010 this is to avoid shadow bleeding when the ground is set to only receive
    // shadows
    if (visOccList.size() != visRecvList.size()) {
      casterBB.setXExtent(casterBB.getXExtent() + 2.0f);
      casterBB.setYExtent(casterBB.getYExtent() + 2.0f);
      casterBB.setZExtent(casterBB.getZExtent() + 2.0f);
    }

    TempVars vars = TempVars.get();

    Vector3f casterMin = casterBB.getMin(vars.vect1);
    Vector3f casterMax = casterBB.getMax(vars.vect2);

    Vector3f receiverMin = receiverBB.getMin(vars.vect3);
    Vector3f receiverMax = receiverBB.getMax(vars.vect4);

    Vector3f splitMin = splitBB.getMin(vars.vect5);
    Vector3f splitMax = splitBB.getMax(vars.vect6);

    splitMin.z = 0;

    //        if (!ortho) {
    //            shadowCam.setFrustumPerspective(45, 1, 1, splitMax.z);
    //        }

    Matrix4f projMatrix = shadowCam.getProjectionMatrix();

    Vector3f cropMin = vars.vect7;
    Vector3f cropMax = vars.vect8;

    // IMPORTANT: Special handling for Z values
    cropMin.x = max(max(casterMin.x, receiverMin.x), splitMin.x);
    cropMax.x = min(min(casterMax.x, receiverMax.x), splitMax.x);

    cropMin.y = max(max(casterMin.y, receiverMin.y), splitMin.y);
    cropMax.y = min(min(casterMax.y, receiverMax.y), splitMax.y);

    cropMin.z = min(casterMin.z, splitMin.z);
    cropMax.z = min(receiverMax.z, splitMax.z);

    // Create the crop matrix.
    float scaleX, scaleY, scaleZ;
    float offsetX, offsetY, offsetZ;

    scaleX = (2.0f) / (cropMax.x - cropMin.x);
    scaleY = (2.0f) / (cropMax.y - cropMin.y);

    offsetX = -0.5f * (cropMax.x + cropMin.x) * scaleX;
    offsetY = -0.5f * (cropMax.y + cropMin.y) * scaleY;

    scaleZ = 1.0f / (cropMax.z - cropMin.z);
    offsetZ = -cropMin.z * scaleZ;

    Matrix4f cropMatrix = vars.tempMat4;
    cropMatrix.set(
        scaleX, 0f, 0f, offsetX, 0f, scaleY, 0f, offsetY, 0f, 0f, scaleZ, offsetZ, 0f, 0f, 0f, 1f);

    Matrix4f result = new Matrix4f();
    result.set(cropMatrix);
    result.multLocal(projMatrix);
    vars.release();

    shadowCam.setProjectionMatrix(result);
  }
  private void doTransformsTangents(
      FloatBuffer bindBufPos,
      FloatBuffer bindBufNorm,
      FloatBuffer bindBufTangents,
      FloatBuffer bufPos,
      FloatBuffer bufNorm,
      FloatBuffer bufTangents,
      int start,
      int end,
      Matrix4f transform) {
    TempVars vars = TempVars.get();
    Vector3f pos = vars.vect1;
    Vector3f norm = vars.vect2;
    Vector3f tan = vars.vect3;

    int length = (end - start) * 3;
    int tanLength = (end - start) * 4;

    // offset is given in element units
    // convert to be in component units
    int offset = start * 3;
    int tanOffset = start * 4;

    bindBufPos.rewind();
    bindBufNorm.rewind();
    bindBufTangents.rewind();
    bindBufPos.get(tmpFloat, 0, length);
    bindBufNorm.get(tmpFloatN, 0, length);
    bindBufTangents.get(tmpFloatT, 0, tanLength);

    int index = 0;
    int tanIndex = 0;
    while (index < length) {
      pos.x = tmpFloat[index];
      norm.x = tmpFloatN[index++];
      pos.y = tmpFloat[index];
      norm.y = tmpFloatN[index++];
      pos.z = tmpFloat[index];
      norm.z = tmpFloatN[index];

      tan.x = tmpFloatT[tanIndex++];
      tan.y = tmpFloatT[tanIndex++];
      tan.z = tmpFloatT[tanIndex++];

      transform.mult(pos, pos);
      transform.multNormal(norm, norm);
      transform.multNormal(tan, tan);

      index -= 2;
      tanIndex -= 3;

      tmpFloat[index] = pos.x;
      tmpFloatN[index++] = norm.x;
      tmpFloat[index] = pos.y;
      tmpFloatN[index++] = norm.y;
      tmpFloat[index] = pos.z;
      tmpFloatN[index++] = norm.z;

      tmpFloatT[tanIndex++] = tan.x;
      tmpFloatT[tanIndex++] = tan.y;
      tmpFloatT[tanIndex++] = tan.z;

      // Skipping 4th element of tangent buffer (handedness)
      tanIndex++;
    }
    vars.release();
    bufPos.position(offset);
    // using bulk put as it's faster
    bufPos.put(tmpFloat, 0, length);
    bufNorm.position(offset);
    // using bulk put as it's faster
    bufNorm.put(tmpFloatN, 0, length);
    bufTangents.position(tanOffset);
    // using bulk put as it's faster
    bufTangents.put(tmpFloatT, 0, tanLength);
  }
  private static Mesh genTangentLines(Mesh mesh, float scale) {
    FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData();
    FloatBuffer normalBuffer = (FloatBuffer) mesh.getBuffer(Type.Normal).getData();
    FloatBuffer tangentBuffer = (FloatBuffer) mesh.getBuffer(Type.Tangent).getData();

    FloatBuffer binormalBuffer = null;
    if (mesh.getBuffer(Type.Binormal) != null) {
      binormalBuffer = (FloatBuffer) mesh.getBuffer(Type.Binormal).getData();
    }

    ColorRGBA originColor = ColorRGBA.White;
    ColorRGBA tangentColor = ColorRGBA.Red;
    ColorRGBA binormalColor = ColorRGBA.Green;
    ColorRGBA normalColor = ColorRGBA.Blue;

    Mesh lineMesh = new Mesh();
    lineMesh.setMode(Mesh.Mode.Lines);

    Vector3f origin = new Vector3f();
    Vector3f point = new Vector3f();
    Vector3f tangent = new Vector3f();
    Vector3f normal = new Vector3f();

    IntBuffer lineIndex = BufferUtils.createIntBuffer(vertexBuffer.limit() / 3 * 6);
    FloatBuffer lineVertex = BufferUtils.createFloatBuffer(vertexBuffer.limit() * 4);
    FloatBuffer lineColor = BufferUtils.createFloatBuffer(vertexBuffer.limit() / 3 * 4 * 4);

    boolean hasParity = mesh.getBuffer(Type.Tangent).getNumComponents() == 4;
    float tangentW = 1;

    for (int i = 0; i < vertexBuffer.limit() / 3; i++) {
      populateFromBuffer(origin, vertexBuffer, i);
      populateFromBuffer(normal, normalBuffer, i);

      if (hasParity) {
        tangent.x = tangentBuffer.get(i * 4);
        tangent.y = tangentBuffer.get(i * 4 + 1);
        tangent.z = tangentBuffer.get(i * 4 + 2);
        tangentW = tangentBuffer.get(i * 4 + 3);
      } else {
        populateFromBuffer(tangent, tangentBuffer, i);
      }

      int index = i * 4;

      int id = i * 6;
      lineIndex.put(id, index);
      lineIndex.put(id + 1, index + 1);
      lineIndex.put(id + 2, index);
      lineIndex.put(id + 3, index + 2);
      lineIndex.put(id + 4, index);
      lineIndex.put(id + 5, index + 3);

      setInBuffer(origin, lineVertex, index);
      setInBuffer(originColor, lineColor, index);

      point.set(tangent);
      point.multLocal(scale);
      point.addLocal(origin);
      setInBuffer(point, lineVertex, index + 1);
      setInBuffer(tangentColor, lineColor, index + 1);

      // wvBinormal = cross(wvNormal, wvTangent) * -inTangent.w

      if (binormalBuffer == null) {
        normal.cross(tangent, point);
        point.multLocal(-tangentW);
        point.normalizeLocal();
      } else {
        populateFromBuffer(point, binormalBuffer, i);
      }

      point.multLocal(scale);
      point.addLocal(origin);
      setInBuffer(point, lineVertex, index + 2);
      setInBuffer(binormalColor, lineColor, index + 2);

      point.set(normal);
      point.multLocal(scale);
      point.addLocal(origin);
      setInBuffer(point, lineVertex, index + 3);
      setInBuffer(normalColor, lineColor, index + 3);
    }

    lineMesh.setBuffer(Type.Index, 1, lineIndex);
    lineMesh.setBuffer(Type.Position, 3, lineVertex);
    lineMesh.setBuffer(Type.Color, 4, lineColor);

    lineMesh.setStatic();
    // lineMesh.setInterleaved();
    return lineMesh;
  }
Exemple #16
0
  /** Computes which points are inside the hull */
  private Mesh buildPreviewMesh() {
    long start = System.currentTimeMillis();

    // First get the bounding box.
    updateWorldBound();

    BoundingBox bound = (BoundingBox) getWorldBound();
    Vector3f maxBound = bound.getMax(null);
    Vector3f originPoint = bound.getMin(null);
    originPoint.x = Math.min(originPoint.x, -maxBound.x);
    originPoint.y = Math.min(originPoint.y, -maxBound.y);
    originPoint.z = Math.min(originPoint.z, -maxBound.z);

    // Thread Pool
    ForkJoinPool pool = new ForkJoinPool();

    // Create an octree from the data
    OctreeNode octree = new OctreeNode(originPoint, maxBound);
    OctreeConstructionTask dcOctreeTask = new OctreeConstructionTask(octree, primitives, 3, 6);
    pool.invoke(dcOctreeTask);

    // Contour the octree.
    AdaptiveDualContouringTask adaptiveTask = new AdaptiveDualContouringTask(octree, primitives);
    pool.invoke(adaptiveTask);

    // Retrieve computed data.
    ArrayList<Vector3f> verticesList = dcOctreeTask.getVertices();
    ArrayList<Vector3i> triangles = adaptiveTask.getTriangles();

    int numberOfVerticesBefore = verticesList.size();
    int numberOfTrianglesBefore = triangles.size();

    // Compute normals both from data and triangles.
    Vector3f normals[] =
        MeshUtils.facetedNormalsFromFaces(
            triangles, verticesList, primitives, (float) Math.toRadians(10));

    // Drop the triangles to an array.
    int index = 0;
    int[] triangleList = new int[3 * triangles.size()];
    for (Vector3i v : triangles) {
      triangleList[index++] = v.x;
      triangleList[index++] = v.y;
      triangleList[index++] = v.z;
    }

    // Finally, make the mesh itself:
    Mesh mesh = new Mesh();
    mesh.setBuffer(
        Type.Position, 3, BufferUtils.createFloatBuffer(verticesList.toArray(new Vector3f[0])));
    mesh.setBuffer(Type.Index, 3, BufferUtils.createIntBuffer(triangleList));
    mesh.setBuffer(Type.Normal, 3, BufferUtils.createFloatBuffer(normals));
    mesh.updateBound();
    mesh.setStatic();

    long timeTaken = System.currentTimeMillis() - start;
    System.out.println(
        String.format(
            "%d Vertices, %d Triangles in %d Milliseconds",
            verticesList.size(), triangles.size(), timeTaken));

    return mesh;
  }
  /**
   * Resolve a movement vector on the mesh
   *
   * @param startPos
   * @param startCell
   * @param endPos
   * @return
   */
  private Cell resolveMotionOnMesh(
      Vector3f startPos, Cell startCell, Vector3f endPos, Vector3f modifiedEndPos) {
    int i = 0;
    // create a 2D motion path from our Start and End positions, tossing out
    // their Y values to project them
    // down to the XZ plane.
    Line2D motionLine =
        new Line2D(new Vector2f(startPos.x, startPos.z), new Vector2f(endPos.x, endPos.z));

    // these three will hold the results of our tests against the cell walls
    ClassifyResult result = null;

    // TestCell is the cell we are currently examining.
    Cell currentCell = startCell;

    do {
      i++;
      // use NavigationCell to determine how our path and cell interact
      // if(TestCell.IsPointInCellCollumn(MotionPath.EndPointA()))
      // System.out.println("Start is in cell");
      // else
      // System.out.println("Start is NOT in cell");
      // if(TestCell.IsPointInCellCollumn(MotionPath.EndPointB()))
      // System.out.println("End is in cell");
      // else
      // System.out.println("End is NOT in cell");
      result = currentCell.classifyPathToCell(motionLine);

      // if exiting the cell...
      if (result.result == PathResult.ExitingCell) {
        // Set if we are moving to an adjacent cell or we have hit a
        // solid (unlinked) edge
        if (result.cell != null) {
          // moving on. Set our motion origin to the point of
          // intersection with this cell
          // and continue, using the new cell as our test cell.
          motionLine.setPointA(result.intersection);
          currentCell = result.cell;
        } else {
          // we have hit a solid wall. Resolve the collision and
          // correct our path.
          motionLine.setPointA(result.intersection);
          currentCell.projectPathOnCellWall(result.side, motionLine);

          // add some friction to the new MotionPath since we are
          // scraping against a wall.
          // we do this by reducing the magnatude of our motion by 10%
          Vector2f Direction = motionLine.getPointB().subtract(motionLine.getPointA()).mult(0.9f);
          // Direction.mult(0.9f);
          motionLine.setPointB(motionLine.getPointA().add(Direction));
        }
      } else if (result.result == Cell.PathResult.NoRelationship) {
        // Although theoretically we should never encounter this case,
        // we do sometimes find ourselves standing directly on a vertex
        // of the cell.
        // This can be viewed by some routines as being outside the
        // cell.
        // To accomodate this rare case, we can force our starting point
        // to be within
        // the current cell by nudging it back so we may continue.
        Vector2f NewOrigin = motionLine.getPointA();
        // NewOrigin.x -= 0.01f;
        currentCell.forcePointToCellColumn(NewOrigin);
        motionLine.setPointA(NewOrigin);
      }
    } //
    // Keep testing until we find our ending cell or stop moving due to
    // friction
    //
    while ((result.result != Cell.PathResult.EndingCell)
        && (motionLine.getPointA().x != motionLine.getPointB().x
            && motionLine.getPointA().y != motionLine.getPointB().y)
        && i < 5000);
    //
    if (i >= 5000) {
      System.out.println("Loop detected in ResolveMotionOnMesh");
    }
    // we now have our new host cell

    // Update the new control point position,
    // solving for Y using the Plane member of the NavigationCell
    modifiedEndPos.x = motionLine.getPointB().x;
    modifiedEndPos.y = 0.0f;
    modifiedEndPos.z = motionLine.getPointB().y;
    currentCell.computeHeightOnCell(modifiedEndPos);

    return currentCell;
  }