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; }
/** * 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; }
/** 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; }