예제 #1
0
  /**
   * Generate a collision shape for a prop.
   *
   * @param propType the type of the prop (not null)
   * @param relativeSize the prop's size relative to standard (>0)
   * @param parts (not null)
   * @return a new instance
   */
  private CollisionShape createShape(String propType, float relativeSize, List<Spatial> parts) {
    assert propType != null;
    assert relativeSize > 0f : relativeSize;
    assert parts != null;
    assert !parts.isEmpty();

    if ("barrel".equals(propType)) {
      /*
       * Generate a cylindrical shape aligned with the Y-axis.
       */
      float halfHeight = 0.5f * relativeSize; // meters
      float radius = 0.472f * relativeSize; // meters
      Vector3f halfExtents = new Vector3f(radius, halfHeight, radius);
      float scaleFactor = scene.getScaleFactor();
      halfExtents.divideLocal(scaleFactor);
      CollisionShape shape = new CylinderCollisionShape(halfExtents, PhysicsSpace.AXIS_Y);
      return shape;
    }
    /*
     * Generate a compound shape composed of GImpact shapes,
     * one for each geometry.
     */
    CompoundCollisionShape shape = new CompoundCollisionShape();
    for (Spatial part : parts) {
      Geometry geometry = (Geometry) part;
      Mesh mesh = geometry.getMesh();
      CollisionShape partShape = new GImpactCollisionShape(mesh);
      Vector3f scale = part.getWorldScale();
      partShape.setScale(scale);
      shape.addChildShape(partShape, Vector3f.ZERO);
    }
    return shape;
  }
예제 #2
0
  /**
   * Updates the points array to contain the frustum corners of the given camera. The nearOverride
   * and farOverride variables can be used to override the camera's near/far values with own values.
   *
   * <p>TODO: Reduce creation of new vectors
   *
   * @param viewCam
   * @param nearOverride
   * @param farOverride
   */
  public static void updateFrustumPoints(
      Camera viewCam, float nearOverride, float farOverride, float scale, Vector3f[] points) {

    Vector3f pos = viewCam.getLocation();
    Vector3f dir = viewCam.getDirection();
    Vector3f up = viewCam.getUp();

    float depthHeightRatio = viewCam.getFrustumTop() / viewCam.getFrustumNear();
    float near = nearOverride;
    float far = farOverride;
    float ftop = viewCam.getFrustumTop();
    float fright = viewCam.getFrustumRight();
    float ratio = fright / ftop;

    float near_height;
    float near_width;
    float far_height;
    float far_width;

    if (viewCam.isParallelProjection()) {
      near_height = ftop;
      near_width = near_height * ratio;
      far_height = ftop;
      far_width = far_height * ratio;
    } else {
      near_height = depthHeightRatio * near;
      near_width = near_height * ratio;
      far_height = depthHeightRatio * far;
      far_width = far_height * ratio;
    }

    Vector3f right = dir.cross(up).normalizeLocal();

    Vector3f temp = new Vector3f();
    temp.set(dir).multLocal(far).addLocal(pos);
    Vector3f farCenter = temp.clone();
    temp.set(dir).multLocal(near).addLocal(pos);
    Vector3f nearCenter = temp.clone();

    Vector3f nearUp = temp.set(up).multLocal(near_height).clone();
    Vector3f farUp = temp.set(up).multLocal(far_height).clone();
    Vector3f nearRight = temp.set(right).multLocal(near_width).clone();
    Vector3f farRight = temp.set(right).multLocal(far_width).clone();

    points[0].set(nearCenter).subtractLocal(nearUp).subtractLocal(nearRight);
    points[1].set(nearCenter).addLocal(nearUp).subtractLocal(nearRight);
    points[2].set(nearCenter).addLocal(nearUp).addLocal(nearRight);
    points[3].set(nearCenter).subtractLocal(nearUp).addLocal(nearRight);

    points[4].set(farCenter).subtractLocal(farUp).subtractLocal(farRight);
    points[5].set(farCenter).addLocal(farUp).subtractLocal(farRight);
    points[6].set(farCenter).addLocal(farUp).addLocal(farRight);
    points[7].set(farCenter).subtractLocal(farUp).addLocal(farRight);

    if (scale != 1.0f) {
      // find center of frustum
      Vector3f center = new Vector3f();
      for (int i = 0; i < 8; i++) {
        center.addLocal(points[i]);
      }
      center.divideLocal(8f);

      Vector3f cDir = new Vector3f();
      for (int i = 0; i < 8; i++) {
        cDir.set(points[i]).subtractLocal(center);
        cDir.multLocal(scale - 1.0f);
        points[i].addLocal(cDir);
      }
    }
  }
  private static void processTriangleData(
      Mesh mesh, List<VertexData> vertices, boolean approxTangent, boolean splitMirrored) {
    ArrayList<VertexInfo> vertexMap = linkVertices(mesh, splitMirrored);

    FloatBuffer tangents = BufferUtils.createFloatBuffer(vertices.size() * 4);

    ColorRGBA[] cols = null;
    if (debug) {
      cols = new ColorRGBA[vertices.size()];
    }

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

    Vector3f tangentUnit = new Vector3f();
    Vector3f binormalUnit = new Vector3f();

    for (int k = 0; k < vertexMap.size(); k++) {
      float wCoord = -1;

      VertexInfo vertexInfo = vertexMap.get(k);

      givenNormal.set(vertexInfo.normal);
      givenNormal.normalizeLocal();

      TriangleData firstTriangle = vertices.get(vertexInfo.indices.get(0)).triangles.get(0);

      // check tangent and binormal consistency
      tangent.set(firstTriangle.tangent);
      tangent.normalizeLocal();
      binormal.set(firstTriangle.binormal);
      binormal.normalizeLocal();

      for (int i : vertexInfo.indices) {
        ArrayList<TriangleData> triangles = vertices.get(i).triangles;

        for (int j = 0; j < triangles.size(); j++) {
          TriangleData triangleData = triangles.get(j);

          tangentUnit.set(triangleData.tangent);
          tangentUnit.normalizeLocal();
          if (tangent.dot(tangentUnit) < toleranceDot) {
            // log.log(Level.WARNING,
            // "Angle between tangents exceeds tolerance "
            // + "for vertex {0}.", i);
            break;
          }

          if (!approxTangent) {
            binormalUnit.set(triangleData.binormal);
            binormalUnit.normalizeLocal();
            if (binormal.dot(binormalUnit) < toleranceDot) {
              // log.log(Level.WARNING,
              // "Angle between binormals exceeds tolerance "
              // + "for vertex {0}.", i);
              break;
            }
          }
        }
      }

      // find average tangent
      tangent.set(0, 0, 0);
      binormal.set(0, 0, 0);

      int triangleCount = 0;
      for (int i : vertexInfo.indices) {
        ArrayList<TriangleData> triangles = vertices.get(i).triangles;
        triangleCount += triangles.size();
        if (debug) {
          cols[i] = ColorRGBA.White;
        }

        for (int j = 0; j < triangles.size(); j++) {
          TriangleData triangleData = triangles.get(j);
          tangent.addLocal(triangleData.tangent);
          binormal.addLocal(triangleData.binormal);
        }
      }

      int blameVertex = vertexInfo.indices.get(0);

      if (tangent.length() < ZERO_TOLERANCE) {
        log.log(Level.WARNING, "Shared tangent is zero for vertex {0}.", blameVertex);
        // attempt to fix from binormal
        if (binormal.length() >= ZERO_TOLERANCE) {
          binormal.cross(givenNormal, tangent);
          tangent.normalizeLocal();
        } // if all fails use the tangent from the first triangle
        else {
          tangent.set(firstTriangle.tangent);
        }
      } else {
        tangent.divideLocal(triangleCount);
      }

      tangentUnit.set(tangent);
      tangentUnit.normalizeLocal();
      if (Math.abs(Math.abs(tangentUnit.dot(givenNormal)) - 1) < ZERO_TOLERANCE) {
        log.log(Level.WARNING, "Normal and tangent are parallel for vertex {0}.", blameVertex);
      }

      if (!approxTangent) {
        if (binormal.length() < ZERO_TOLERANCE) {
          log.log(Level.WARNING, "Shared binormal is zero for vertex {0}.", blameVertex);
          // attempt to fix from tangent
          if (tangent.length() >= ZERO_TOLERANCE) {
            givenNormal.cross(tangent, binormal);
            binormal.normalizeLocal();
          } // if all fails use the binormal from the first triangle
          else {
            binormal.set(firstTriangle.binormal);
          }
        } else {
          binormal.divideLocal(triangleCount);
        }

        binormalUnit.set(binormal);
        binormalUnit.normalizeLocal();
        if (Math.abs(Math.abs(binormalUnit.dot(givenNormal)) - 1) < ZERO_TOLERANCE) {
          log.log(Level.WARNING, "Normal and binormal are parallel for vertex {0}.", blameVertex);
        }

        if (Math.abs(Math.abs(binormalUnit.dot(tangentUnit)) - 1) < ZERO_TOLERANCE) {
          log.log(Level.WARNING, "Tangent and binormal are parallel for vertex {0}.", blameVertex);
        }
      }

      Vector3f finalTangent = new Vector3f();
      Vector3f tmp = new Vector3f();
      for (int i : vertexInfo.indices) {
        if (approxTangent) {
          // Gram-Schmidt orthogonalize
          finalTangent
              .set(tangent)
              .subtractLocal(tmp.set(givenNormal).multLocal(givenNormal.dot(tangent)));
          finalTangent.normalizeLocal();

          wCoord = tmp.set(givenNormal).crossLocal(tangent).dot(binormal) < 0f ? -1f : 1f;

          tangents.put((i * 4), finalTangent.x);
          tangents.put((i * 4) + 1, finalTangent.y);
          tangents.put((i * 4) + 2, finalTangent.z);
          tangents.put((i * 4) + 3, wCoord);
        } else {
          tangents.put((i * 4), tangent.x);
          tangents.put((i * 4) + 1, tangent.y);
          tangents.put((i * 4) + 2, tangent.z);
          tangents.put((i * 4) + 3, wCoord);

          // setInBuffer(binormal, binormals, i);
        }
      }
    }
    tangents.limit(tangents.capacity());
    // If the model already had a tangent buffer, replace it with the regenerated one
    mesh.clearBuffer(Type.Tangent);
    mesh.setBuffer(Type.Tangent, 4, tangents);

    if (mesh.isAnimated()) {
      mesh.clearBuffer(Type.BindPoseNormal);
      mesh.clearBuffer(Type.BindPosePosition);
      mesh.clearBuffer(Type.BindPoseTangent);
      mesh.generateBindPose(true);
    }

    if (debug) {
      writeColorBuffer(vertices, cols, mesh);
    }
    mesh.updateBound();
    mesh.updateCounts();
  }