protected void updateSubBatch(Geometry bg) { Batch batch = batchesByGeom.get(bg); if (batch != null) { Mesh mesh = batch.geometry.getMesh(); Mesh origMesh = bg.getMesh(); VertexBuffer pvb = mesh.getBuffer(VertexBuffer.Type.Position); FloatBuffer posBuf = (FloatBuffer) pvb.getData(); VertexBuffer nvb = mesh.getBuffer(VertexBuffer.Type.Normal); FloatBuffer normBuf = (FloatBuffer) nvb.getData(); VertexBuffer opvb = origMesh.getBuffer(VertexBuffer.Type.Position); FloatBuffer oposBuf = (FloatBuffer) opvb.getData(); VertexBuffer onvb = origMesh.getBuffer(VertexBuffer.Type.Normal); FloatBuffer onormBuf = (FloatBuffer) onvb.getData(); Matrix4f transformMat = getTransformMatrix(bg); if (mesh.getBuffer(VertexBuffer.Type.Tangent) != null) { VertexBuffer tvb = mesh.getBuffer(VertexBuffer.Type.Tangent); FloatBuffer tanBuf = (FloatBuffer) tvb.getData(); VertexBuffer otvb = origMesh.getBuffer(VertexBuffer.Type.Tangent); FloatBuffer otanBuf = (FloatBuffer) otvb.getData(); doTransformsTangents( oposBuf, onormBuf, otanBuf, posBuf, normBuf, tanBuf, bg.startIndex, bg.startIndex + bg.getVertexCount(), transformMat); tvb.updateData(tanBuf); } else { doTransforms( oposBuf, onormBuf, posBuf, normBuf, bg.startIndex, bg.startIndex + bg.getVertexCount(), transformMat); } pvb.updateData(posBuf); nvb.updateData(normBuf); batch.needMeshUpdate = true; } }
void resetToBind() { for (Mesh mesh : targets) { if (isMeshAnimated(mesh)) { FloatBuffer bwBuff = (FloatBuffer) mesh.getBuffer(Type.BoneWeight).getData(); ByteBuffer biBuff = (ByteBuffer) mesh.getBuffer(Type.BoneIndex).getData(); if (!biBuff.hasArray() || !bwBuff.hasArray()) { mesh.prepareForAnim(true); // prepare for software animation } VertexBuffer bindPos = mesh.getBuffer(Type.BindPosePosition); VertexBuffer bindNorm = mesh.getBuffer(Type.BindPoseNormal); VertexBuffer pos = mesh.getBuffer(Type.Position); VertexBuffer norm = mesh.getBuffer(Type.Normal); FloatBuffer pb = (FloatBuffer) pos.getData(); FloatBuffer nb = (FloatBuffer) norm.getData(); FloatBuffer bpb = (FloatBuffer) bindPos.getData(); FloatBuffer bnb = (FloatBuffer) bindNorm.getData(); pb.clear(); nb.clear(); bpb.clear(); bnb.clear(); // reseting bind tangents if there is a bind tangent buffer VertexBuffer bindTangents = mesh.getBuffer(Type.BindPoseTangent); if (bindTangents != null) { VertexBuffer tangents = mesh.getBuffer(Type.Tangent); FloatBuffer tb = (FloatBuffer) tangents.getData(); FloatBuffer btb = (FloatBuffer) bindTangents.getData(); tb.clear(); btb.clear(); tb.put(btb).clear(); } pb.put(bpb).clear(); nb.put(bnb).clear(); } } }
/** * Merges all geometries in the collection into the output mesh. Does not take into account * materials. * * @param geometries * @param outMesh */ private void mergeGeometries(Mesh outMesh, List<Geometry> geometries) { int[] compsForBuf = new int[VertexBuffer.Type.values().length]; VertexBuffer.Format[] formatForBuf = new VertexBuffer.Format[compsForBuf.length]; int totalVerts = 0; int totalTris = 0; int totalLodLevels = 0; int maxWeights = -1; Mesh.Mode mode = null; for (Geometry geom : geometries) { totalVerts += geom.getVertexCount(); totalTris += geom.getTriangleCount(); totalLodLevels = Math.min(totalLodLevels, geom.getMesh().getNumLodLevels()); if (maxVertCount < geom.getVertexCount()) { maxVertCount = geom.getVertexCount(); } Mesh.Mode listMode; int components; switch (geom.getMesh().getMode()) { case Points: listMode = Mesh.Mode.Points; components = 1; break; case LineLoop: case LineStrip: case Lines: listMode = Mesh.Mode.Lines; components = 2; break; case TriangleFan: case TriangleStrip: case Triangles: listMode = Mesh.Mode.Triangles; components = 3; break; default: throw new UnsupportedOperationException(); } for (VertexBuffer vb : geom.getMesh().getBufferList().getArray()) { compsForBuf[vb.getBufferType().ordinal()] = vb.getNumComponents(); formatForBuf[vb.getBufferType().ordinal()] = vb.getFormat(); } maxWeights = Math.max(maxWeights, geom.getMesh().getMaxNumWeights()); if (mode != null && mode != listMode) { throw new UnsupportedOperationException( "Cannot combine different" + " primitive types: " + mode + " != " + listMode); } mode = listMode; compsForBuf[VertexBuffer.Type.Index.ordinal()] = components; } outMesh.setMaxNumWeights(maxWeights); outMesh.setMode(mode); if (totalVerts >= 65536) { // make sure we create an UnsignedInt buffer so // we can fit all of the meshes formatForBuf[VertexBuffer.Type.Index.ordinal()] = VertexBuffer.Format.UnsignedInt; } else { formatForBuf[VertexBuffer.Type.Index.ordinal()] = VertexBuffer.Format.UnsignedShort; } // generate output buffers based on retrieved info for (int i = 0; i < compsForBuf.length; i++) { if (compsForBuf[i] == 0) { continue; } Buffer data; if (i == VertexBuffer.Type.Index.ordinal()) { data = VertexBuffer.createBuffer(formatForBuf[i], compsForBuf[i], totalTris); } else { data = VertexBuffer.createBuffer(formatForBuf[i], compsForBuf[i], totalVerts); } VertexBuffer vb = new VertexBuffer(VertexBuffer.Type.values()[i]); vb.setupData(VertexBuffer.Usage.Dynamic, compsForBuf[i], formatForBuf[i], data); outMesh.setBuffer(vb); } int globalVertIndex = 0; int globalTriIndex = 0; for (Geometry geom : geometries) { Mesh inMesh = geom.getMesh(); if (!isBatch(geom)) { geom.batch(this, globalVertIndex); } int geomVertCount = inMesh.getVertexCount(); int geomTriCount = inMesh.getTriangleCount(); for (int bufType = 0; bufType < compsForBuf.length; bufType++) { VertexBuffer inBuf = inMesh.getBuffer(VertexBuffer.Type.values()[bufType]); VertexBuffer outBuf = outMesh.getBuffer(VertexBuffer.Type.values()[bufType]); if (outBuf == null) { continue; } if (VertexBuffer.Type.Index.ordinal() == bufType) { int components = compsForBuf[bufType]; IndexBuffer inIdx = inMesh.getIndicesAsList(); IndexBuffer outIdx = outMesh.getIndexBuffer(); for (int tri = 0; tri < geomTriCount; tri++) { for (int comp = 0; comp < components; comp++) { int idx = inIdx.get(tri * components + comp) + globalVertIndex; outIdx.put((globalTriIndex + tri) * components + comp, idx); } } } else if (VertexBuffer.Type.Position.ordinal() == bufType) { FloatBuffer inPos = (FloatBuffer) inBuf.getData(); FloatBuffer outPos = (FloatBuffer) outBuf.getData(); doCopyBuffer(inPos, globalVertIndex, outPos, 3); } else if (VertexBuffer.Type.Normal.ordinal() == bufType || VertexBuffer.Type.Tangent.ordinal() == bufType) { FloatBuffer inPos = (FloatBuffer) inBuf.getData(); FloatBuffer outPos = (FloatBuffer) outBuf.getData(); doCopyBuffer(inPos, globalVertIndex, outPos, compsForBuf[bufType]); if (VertexBuffer.Type.Tangent.ordinal() == bufType) { useTangents = true; } } else { inBuf.copyElements(0, outBuf, globalVertIndex, geomVertCount); // for (int vert = 0; vert < geomVertCount; vert++) { // int curGlobalVertIndex = globalVertIndex + vert; // inBuf.copyElement(vert, outBuf, curGlobalVertIndex); // } } } globalVertIndex += geomVertCount; globalTriIndex += geomTriCount; } }
/** * Specific method for skinning with tangents to avoid cluttering the classic skinning calculation * with null checks that would slow down the process even if tangents don't have to be computed. * Also the iteration has additional indexes since tangent has 4 components instead of 3 for pos * and norm * * @param maxWeightsPerVert maximum number of weights per vertex * @param mesh the mesh * @param offsetMatrices the offsetMaytrices to apply * @param tb the tangent vertexBuffer */ private void applySkinningTangents(Mesh mesh, Matrix4f[] offsetMatrices, VertexBuffer tb) { int maxWeightsPerVert = mesh.getMaxNumWeights(); if (maxWeightsPerVert <= 0) { throw new IllegalStateException("Max weights per vert is incorrectly set!"); } int fourMinusMaxWeights = 4 - maxWeightsPerVert; // NOTE: This code assumes the vertex buffer is in bind pose // resetToBind() has been called this frame VertexBuffer vb = mesh.getBuffer(Type.Position); FloatBuffer fvb = (FloatBuffer) vb.getData(); fvb.rewind(); VertexBuffer nb = mesh.getBuffer(Type.Normal); FloatBuffer fnb = (FloatBuffer) nb.getData(); fnb.rewind(); FloatBuffer ftb = (FloatBuffer) tb.getData(); ftb.rewind(); // get boneIndexes and weights for mesh ByteBuffer ib = (ByteBuffer) mesh.getBuffer(Type.BoneIndex).getData(); FloatBuffer wb = (FloatBuffer) mesh.getBuffer(Type.BoneWeight).getData(); ib.rewind(); wb.rewind(); float[] weights = wb.array(); byte[] indices = ib.array(); int idxWeights = 0; TempVars vars = TempVars.get(); float[] posBuf = vars.skinPositions; float[] normBuf = vars.skinNormals; float[] tanBuf = vars.skinTangents; int iterations = (int) FastMath.ceil(fvb.capacity() / ((float) posBuf.length)); int bufLength = 0; int tanLength = 0; for (int i = iterations - 1; i >= 0; i--) { // read next set of positions and normals from native buffer bufLength = Math.min(posBuf.length, fvb.remaining()); tanLength = Math.min(tanBuf.length, ftb.remaining()); fvb.get(posBuf, 0, bufLength); fnb.get(normBuf, 0, bufLength); ftb.get(tanBuf, 0, tanLength); int verts = bufLength / 3; int idxPositions = 0; // tangents has their own index because of the 4 components int idxTangents = 0; // iterate vertices and apply skinning transform for each effecting bone for (int vert = verts - 1; vert >= 0; vert--) { float nmx = normBuf[idxPositions]; float vtx = posBuf[idxPositions++]; float nmy = normBuf[idxPositions]; float vty = posBuf[idxPositions++]; float nmz = normBuf[idxPositions]; float vtz = posBuf[idxPositions++]; float tnx = tanBuf[idxTangents++]; float tny = tanBuf[idxTangents++]; float tnz = tanBuf[idxTangents++]; // skipping the 4th component of the tangent since it doesn't have to be transformed idxTangents++; float rx = 0, ry = 0, rz = 0, rnx = 0, rny = 0, rnz = 0, rtx = 0, rty = 0, rtz = 0; for (int w = maxWeightsPerVert - 1; w >= 0; w--) { float weight = weights[idxWeights]; Matrix4f mat = offsetMatrices[indices[idxWeights++]]; rx += (mat.m00 * vtx + mat.m01 * vty + mat.m02 * vtz + mat.m03) * weight; ry += (mat.m10 * vtx + mat.m11 * vty + mat.m12 * vtz + mat.m13) * weight; rz += (mat.m20 * vtx + mat.m21 * vty + mat.m22 * vtz + mat.m23) * weight; rnx += (nmx * mat.m00 + nmy * mat.m01 + nmz * mat.m02) * weight; rny += (nmx * mat.m10 + nmy * mat.m11 + nmz * mat.m12) * weight; rnz += (nmx * mat.m20 + nmy * mat.m21 + nmz * mat.m22) * weight; rtx += (tnx * mat.m00 + tny * mat.m01 + tnz * mat.m02) * weight; rty += (tnx * mat.m10 + tny * mat.m11 + tnz * mat.m12) * weight; rtz += (tnx * mat.m20 + tny * mat.m21 + tnz * mat.m22) * weight; } idxWeights += fourMinusMaxWeights; idxPositions -= 3; normBuf[idxPositions] = rnx; posBuf[idxPositions++] = rx; normBuf[idxPositions] = rny; posBuf[idxPositions++] = ry; normBuf[idxPositions] = rnz; posBuf[idxPositions++] = rz; idxTangents -= 4; tanBuf[idxTangents++] = rtx; tanBuf[idxTangents++] = rty; tanBuf[idxTangents++] = rtz; // once again skipping the 4th component of the tangent idxTangents++; } fvb.position(fvb.position() - bufLength); fvb.put(posBuf, 0, bufLength); fnb.position(fnb.position() - bufLength); fnb.put(normBuf, 0, bufLength); ftb.position(ftb.position() - tanLength); ftb.put(tanBuf, 0, tanLength); } vars.release(); vb.updateData(fvb); nb.updateData(fnb); tb.updateData(ftb); }