/** * Processes the given convex shape to retrieve a correctly ordered FloatBuffer to construct the * shape from with a TriMesh. * * @param convexShape the shape to retreieve the vertices from. * @return the vertices as a FloatBuffer, ordered as Triangles. */ private static FloatBuffer getVertices(ConvexShape convexShape) { // Check there is a hull shape to render if (convexShape.getUserPointer() == null) { // create a hull approximation ShapeHull hull = new ShapeHull(convexShape); float margin = convexShape.getMargin(); hull.buildHull(margin); convexShape.setUserPointer(hull); } // Assert state - should have a pointer to a hull (shape) that'll be drawn assert convexShape.getUserPointer() != null : "Should have a shape for the userPointer, instead got null"; ShapeHull hull = (ShapeHull) convexShape.getUserPointer(); // Assert we actually have a shape to render assert hull.numTriangles() > 0 : "Expecting the Hull shape to have triangles"; int numberOfTriangles = hull.numTriangles(); // The number of bytes needed is: (floats in a vertex) * (vertices in a triangle) * (# of // triangles) * (size of float in bytes) final int numberOfFloats = 3 * 3 * numberOfTriangles; FloatBuffer vertices = BufferUtils.createFloatBuffer(numberOfFloats); // Force the limit, set the cap - most number of floats we will use the buffer for vertices.limit(numberOfFloats); // Loop variables final IntArrayList hullIndicies = hull.getIndexPointer(); final List<Vector3f> hullVertices = hull.getVertexPointer(); Vector3f vertexA, vertexB, vertexC; int index = 0; for (int i = 0; i < numberOfTriangles; i++) { // Grab the data for this triangle from the hull vertexA = hullVertices.get(hullIndicies.get(index++)); vertexB = hullVertices.get(hullIndicies.get(index++)); vertexC = hullVertices.get(hullIndicies.get(index++)); // Put the verticies into the vertex buffer vertices.put(vertexA.x).put(vertexA.y).put(vertexA.z); vertices.put(vertexB.x).put(vertexB.y).put(vertexB.z); vertices.put(vertexC.x).put(vertexC.y).put(vertexC.z); } vertices.clear(); return vertices; }
protected void stepUp(CollisionWorld world) { // phase 1: up Transform start = new Transform(); Transform end = new Transform(); targetPosition.scaleAdd( stepHeight + (verticalOffset > 0.0 ? verticalOffset : 0.0f), upAxisDirection[upAxis], currentPosition); start.setIdentity(); end.setIdentity(); /* FIXME: Handle penetration properly */ start.origin.scaleAdd( convexShape.getMargin() + addedMargin, upAxisDirection[upAxis], currentPosition); end.origin.set(targetPosition); // Find only sloped/flat surface hits, avoid wall and ceiling hits... Vector3d up = new Vector3d(); up.scale(-1f, upAxisDirection[upAxis]); KinematicClosestNotMeConvexResultCallback callback = new KinematicClosestNotMeConvexResultCallback(ghostObject, up, 0.0f); callback.collisionFilterGroup = getGhostObject().getBroadphaseHandle().collisionFilterGroup; callback.collisionFilterMask = getGhostObject().getBroadphaseHandle().collisionFilterMask; if (useGhostObjectSweepTest) { ghostObject.convexSweepTest( convexShape, start, end, callback, world.getDispatchInfo().allowedCcdPenetration); } else { world.convexSweepTest(convexShape, start, end, callback); } if (callback.hasHit()) { // we moved up only a fraction of the step height currentStepOffset = stepHeight * callback.closestHitFraction; currentPosition.interpolate(currentPosition, targetPosition, callback.closestHitFraction); verticalVelocity = 0.0f; verticalOffset = 0.0f; } else { currentStepOffset = stepHeight; currentPosition.set(targetPosition); } }
protected void stepForwardAndStrafe(CollisionWorld collisionWorld, Vector3d walkMove) { // printf("m_normalizedDirection=%f,%f,%f\n", // m_normalizedDirection[0],m_normalizedDirection[1],m_normalizedDirection[2]); // phase 2: forward and strafe Transform start = new Transform(); Transform end = new Transform(); targetPosition.add(currentPosition, walkMove); start.setIdentity(); end.setIdentity(); double fraction = 1.0f; Vector3d distance2Vec = new Vector3d(); distance2Vec.sub(currentPosition, targetPosition); double distance2 = distance2Vec.lengthSquared(); // printf("distance2=%f\n",distance2); /*if (touchingContact) { if (normalizedDirection.dot(touchingNormal) > 0.0f) { updateTargetPositionBasedOnCollision(touchingNormal); } }*/ int maxIter = 10; while (fraction > 0.01f && maxIter-- > 0) { start.origin.set(currentPosition); end.origin.set(targetPosition); KinematicClosestNotMeConvexResultCallback callback = new KinematicClosestNotMeConvexResultCallback( ghostObject, upAxisDirection[upAxis], -1.0f); callback.collisionFilterGroup = getGhostObject().getBroadphaseHandle().collisionFilterGroup; callback.collisionFilterMask = getGhostObject().getBroadphaseHandle().collisionFilterMask; double margin = convexShape.getMargin(); convexShape.setMargin(margin + addedMargin); if (useGhostObjectSweepTest) { ghostObject.convexSweepTest( convexShape, start, end, callback, collisionWorld.getDispatchInfo().allowedCcdPenetration); } else { collisionWorld.convexSweepTest(convexShape, start, end, callback); } convexShape.setMargin(margin); fraction -= callback.closestHitFraction; if (callback.hasHit()) { // we moved only a fraction Vector3d hitDistanceVec = new Vector3d(); hitDistanceVec.sub(callback.hitPointWorld, currentPosition); // double hitDistance = hitDistanceVec.length(); // if the distance is farther than the collision margin, move // if (hitDistance > addedMargin) { // //printf("callback.m_closestHitFraction=%f\n",callback.m_closestHitFraction); // currentPosition.interpolate(currentPosition, targetPosition, // callback.closestHitFraction); // } updateTargetPositionBasedOnCollision(callback.hitNormalWorld); Vector3d currentDir = new Vector3d(); currentDir.sub(targetPosition, currentPosition); distance2 = currentDir.lengthSquared(); if (distance2 > BulletGlobals.SIMD_EPSILON) { currentDir.normalize(); // see Quake2: "If velocity is against original velocity, stop ead to avoid tiny // oscilations in sloping corners." if (currentDir.dot(normalizedDirection) <= 0.0f) { break; } } else { // printf("currentDir: don't normalize a zero vector\n"); break; } } else { // we moved whole way currentPosition.set(targetPosition); } // if (callback.m_closestHitFraction == 0.f) // break; } }
public void convexSweepTest( ConvexShape castShape, Transform convexFromWorld, Transform convexToWorld, CollisionWorld.ConvexResultCallback resultCallback, float allowedCcdPenetration) { Transform convexFromTrans = new Transform(); Transform convexToTrans = new Transform(); convexFromTrans.set(convexFromWorld); convexToTrans.set(convexToWorld); Vector3f castShapeAabbMin = new Vector3f(); Vector3f castShapeAabbMax = new Vector3f(); // compute AABB that encompasses angular movement { Vector3f linVel = new Vector3f(); Vector3f angVel = new Vector3f(); TransformUtil.calculateVelocity(convexFromTrans, convexToTrans, 1f, linVel, angVel); Transform R = new Transform(); R.setIdentity(); R.setRotation(convexFromTrans.getRotation(new Quat4f())); castShape.calculateTemporalAabb(R, linVel, angVel, 1f, castShapeAabbMin, castShapeAabbMax); } Transform tmpTrans = new Transform(); // go over all objects, and if the ray intersects their aabb + cast shape aabb, // do a ray-shape query using convexCaster (CCD) for (int i = 0; i < overlappingObjects.size(); i++) { CollisionObject collisionObject = overlappingObjects.getQuick(i); // only perform raycast if filterMask matches if (resultCallback.needsCollision(collisionObject.getBroadphaseHandle())) { // RigidcollisionObject* collisionObject = ctrl->GetRigidcollisionObject(); Vector3f collisionObjectAabbMin = new Vector3f(); Vector3f collisionObjectAabbMax = new Vector3f(); collisionObject .getCollisionShape() .getAabb( collisionObject.getWorldTransform(tmpTrans), collisionObjectAabbMin, collisionObjectAabbMax); AabbUtil2.aabbExpand( collisionObjectAabbMin, collisionObjectAabbMax, castShapeAabbMin, castShapeAabbMax); float[] hitLambda = new float[] {1f}; // could use resultCallback.closestHitFraction, but needs testing Vector3f hitNormal = new Vector3f(); if (AabbUtil2.rayAabb( convexFromWorld.origin, convexToWorld.origin, collisionObjectAabbMin, collisionObjectAabbMax, hitLambda, hitNormal)) { CollisionWorld.objectQuerySingle( castShape, convexFromTrans, convexToTrans, collisionObject, collisionObject.getCollisionShape(), collisionObject.getWorldTransform(tmpTrans), resultCallback, allowedCcdPenetration); } } } }