public SkySphere(Vector3 position, float scale, Texture texture) { this.scale = scale; this.position = position; this.mTexture = texture; VertexBufferDeclaration vbd = new VertexBufferDeclaration(); vbd.add( new VertexBufferDefinition( VertexBufferDefinition.FLOAT, VertexBufferDefinition.DEF_VERTEX, 3, VertexBufferDefinition.ACCESS_DYNAMIC)); vbd.add( new VertexBufferDefinition( VertexBufferDefinition.FLOAT, VertexBufferDefinition.DEF_TEXTURE_COORD, 2, VertexBufferDefinition.ACCESS_DYNAMIC)); vbd.add( new VertexBufferDefinition( VertexBufferDefinition.FLOAT, VertexBufferDefinition.DEF_NORMAL, 3, VertexBufferDefinition.ACCESS_DYNAMIC)); mVertexBuffer = new VertexBuffer(128, vbd); mIndexBuffer = new IndexBufferShort(GLES20.GL_TRIANGLES, 256 * 3); mIndexBuffer.put(indexdata); mVertexBuffer.getBuffer(0).put(vertexdata); mVertexBuffer.getBuffer(1).put(stdata); mVertexBuffer.getBuffer(2).put(normaldata); }
private void renderLines() { if (phenixLineProgram != null) { if (!phenixLineProgram.use()) { return; } float angle = 360.0f * getTimeDeltaByScale((long) (1 * 50000L / speedFactor / rotationSpeedFactor)); Matrix.setRotateM(M_matrix, 0, angle, 0, 0, 1.0f); Matrix.multiplyMM(MVP_matrix, 0, V_matrix, 0, M_matrix, 0); Matrix.multiplyMM(MVP_matrix, 0, P_matrix, 0, MVP_matrix, 0); float delta = getTimeDeltaByScale((long) (1 * 25000L / speedFactor)); lineVertices.bind(phenixLineProgram, "aPosition", null); GLES20.glUniformMatrix4fv( phenixLineProgram.getUniformLocation("uMVPMatrix"), 1, false, MVP_matrix, 0); GLES20.glUniform1f(phenixLineProgram.getUniformLocation("uDelta"), delta); GLES20.glUniform1f( phenixLineProgram.getUniformLocation("uBrightness"), brightness * brightnessFactor); GLES20.glUniform3f( phenixLineProgram.getUniformLocation("uColor"), linesColorRed, linesColorGreen, linesColorBlue); GLES20.glEnable(GLES20.GL_BLEND); GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE); GLES20.glLineWidth(lineWidth * lineWidthFactor); lineVertices.draw(GLES20.GL_LINES, 0, MOVING_LINE_COUNT); GLES20.glUniform1f(phenixLineProgram.getUniformLocation("uDelta"), 0.0f); lineVertices.draw(GLES20.GL_LINES, MOVING_LINE_COUNT, STALE_LINE_COUNT); GLES20.glDisable(GLES20.GL_BLEND); lineVertices.unbind(phenixLineProgram, "aPosition", null); } }
private void renderBlurTexture(int textureIndex) { if (postProgram.use()) { renderTextures[textureIndex].bind(GLES20.GL_TEXTURE0, postProgram, "sTexture"); quadVertices.bind(postProgram, "aPosition", "aTextureCoord"); GLES20.glUniform1f(postProgram.getUniformLocation("uBlur"), blur * blurFactor); GLES20.glUniformMatrix4fv( postProgram.getUniformLocation("uMVPMatrix"), 1, false, Q_matrix, 0); GLES20.glEnable(GLES20.GL_BLEND); GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE); quadVertices.draw(GLES20.GL_TRIANGLE_STRIP); GLES20.glDisable(GLES20.GL_BLEND); quadVertices.unbind(postProgram, "aPosition", "aTextureCoord"); renderTextures[textureIndex].unbind(GLES20.GL_TEXTURE0); } }
public void Draw() { GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexture.getID()); GLES20.glDisable(GLES20.GL_DEPTH_TEST); // GLES20.glDisable(GLES20.GL_CULL_FACE); // GLES20.glDisable(GLES20.GL_LIGHTING); // GLES20.glPushMatrix(); // GLES20.glTranslatef(position.X, position.Y, position.Z); Renderer.pushModelViewMatrix(); Renderer.modelview.translate(position.X, position.Y, position.Z); // GLES20.glScalef(scale, scale, scale); Renderer.modelview.scale(scale, scale, scale); Renderer.loadModelViewMatrix(); mVertexBuffer.Draw(mIndexBuffer); // GLES20.glPopMatrix(); Renderer.popModelViewMatrix(); Renderer.loadModelViewMatrix(); GLES20.glEnable(GLES20.GL_DEPTH_TEST); // GLES20.glEnable(GLES20.GL_CULL_FACE); // GLES20.glEnable(GLES20.GL_LIGHTING); }
private static AttributeData[] createAttributeData(VertexBuffer vbuffer) { List<AttributeData> attribute = new ArrayList<>(); for (Element el : vbuffer.layout.getElements()) { if (el.equals(POSITION) || el.equals(NORMAL) || el.equals(TEX_COORD)) { continue; } if (el.getDataType() != FLOAT || el.getVectorType().getElementCount() > CTM_ATTR_ELEMENT_COUNT) { logger.warn( "The mesh-attribute " + el.toString() + " can't be exported to the ctm format! Only float " + "attributes with max. 4 elements are supported."); continue; } float[] values = new float[vbuffer.getVcount() * CTM_ATTR_ELEMENT_COUNT]; { int k = 0; for (Vertex v : vbuffer) { copyToBuffer(values, k, v, el); k += CTM_ATTR_ELEMENT_COUNT; } } attribute.add( new AttributeData(el.getBezeichnung(), null, AttributeData.STANDARD_PRECISION, values)); } AttributeData[] atts = new AttributeData[attribute.size()]; attribute.toArray(atts); return atts; }
public static Object3D[] load(byte[] data, int offset) { DataInputStream old = dis; dis = new DataInputStream(new ByteArrayInputStream(data)); try { while (dis.available() > 0) { int objectType = readByte(); int length = readInt(); System.out.println("objectType: " + objectType); System.out.println("length: " + length); dis.mark(Integer.MAX_VALUE); if (objectType == 0) { int versionHigh = readByte(); int versionLow = readByte(); boolean hasExternalReferences = readBoolean(); int totolFileSize = readInt(); int approximateContentSize = readInt(); String authoringField = readString(); objs.addElement(new Group()); // dummy } else if (objectType == 255) { // TODO: load external resource System.out.println("Loader: Loading external resources not implemented."); String uri = readString(); } else if (objectType == 1) { System.out.println("Loader: AnimationController not implemented."); objs.addElement(new Group()); // dummy } else if (objectType == 2) { System.out.println("Loader: AnimationTrack not implemented."); objs.addElement(new Group()); // dummy } else if (objectType == 3) { // System.out.println("Appearance"); Appearance appearance = new Appearance(); loadObject3D(appearance); appearance.setLayer(readByte()); appearance.setCompositingMode((CompositingMode) getObject(readInt())); appearance.setFog((Fog) getObject(readInt())); appearance.setPolygonMode((PolygonMode) getObject(readInt())); appearance.setMaterial((Material) getObject(readInt())); int numTextures = readInt(); for (int i = 0; i < numTextures; ++i) appearance.setTexture(i, (Texture2D) getObject(readInt())); objs.addElement(appearance); } else if (objectType == 4) { // System.out.println("Background"); Background background = new Background(); loadObject3D(background); background.setColor(readRGBA()); background.setImage((Image2D) getObject(readInt())); int modeX = readByte(); int modeY = readByte(); background.setImageMode(modeX, modeY); int cropX = readInt(); int cropY = readInt(); int cropWidth = readInt(); int cropHeight = readInt(); background.setCrop(cropX, cropY, cropWidth, cropHeight); background.setDepthClearEnable(readBoolean()); background.setColorClearEnable(readBoolean()); objs.addElement(background); // dummy } else if (objectType == 5) { // System.out.println("Camera"); Camera camera = new Camera(); loadNode(camera); int projectionType = readByte(); if (projectionType == Camera.GENERIC) { Transform t = new Transform(); t.set(readMatrix()); camera.setGeneric(t); } else { float fovy = readFloat(); float aspect = readFloat(); float near = readFloat(); float far = readFloat(); if (projectionType == Camera.PARALLEL) camera.setParallel(fovy, aspect, near, far); else camera.setPerspective(fovy, aspect, near, far); } objs.addElement(camera); } else if (objectType == 6) { // System.out.println("CompositingMode"); CompositingMode compositingMode = new CompositingMode(); loadObject3D(compositingMode); compositingMode.setDepthTestEnabled(readBoolean()); compositingMode.setDepthWriteEnabled(readBoolean()); compositingMode.setColorWriteEnabled(readBoolean()); compositingMode.setAlphaWriteEnabled(readBoolean()); compositingMode.setBlending(readByte()); compositingMode.setAlphaThreshold((float) readByte() / 255.0f); compositingMode.setDepthOffsetFactor(readFloat()); compositingMode.setDepthOffsetUnits(readFloat()); objs.addElement(compositingMode); } else if (objectType == 7) { // System.out.println("Fog"); Fog fog = new Fog(); loadObject3D(fog); fog.setColor(readRGB()); fog.setMode(readByte()); if (fog.getMode() == Fog.EXPONENTIAL) fog.setDensity(readFloat()); else { fog.setNearDistance(readFloat()); fog.setFarDistance(readFloat()); } objs.addElement(fog); } else if (objectType == 9) { // System.out.println("Group"); Group group = new Group(); loadGroup(group); objs.addElement(group); } else if (objectType == 10) { // System.out.println("Image2D"); Image2D image = null; loadObject3D(new Group()); // dummy int format = readByte(); boolean isMutable = readBoolean(); int width = readInt(); int height = readInt(); if (!isMutable) { // Read palette int paletteSize = readInt(); byte[] palette = null; if (paletteSize > 0) { palette = new byte[paletteSize]; dis.readFully(palette); } // Read pixels int pixelSize = readInt(); byte[] pixel = new byte[pixelSize]; dis.readFully(pixel); // Create image if (palette != null) image = new Image2D(format, width, height, pixel, palette); else image = new Image2D(format, width, height, pixel); } else image = new Image2D(format, width, height); dis.reset(); loadObject3D(image); objs.addElement(image); } else if (objectType == 19) { System.out.println("Loader: KeyframeSequence not implemented."); /* Byte interpolation; Byte repeatMode; Byte encoding; UInt32 duration; UInt32 validRangeFirst; UInt32 validRangeLast; UInt32 componentCount; UInt32 keyframeCount; IF encoding == 0 FOR each key frame... UInt32 time; Float32[componentCount] vectorValue; END ELSE IF encoding == 1 Float32[componentCount] vectorBias; Float32[componentCount] vectorScale; FOR each key frame... UInt32 time; Byte[componentCount] vectorValue; END ELSE IF encoding == 2 Float32[componentCount] vectorBias; Float32[componentCount] vectorScale; FOR each key frame... UInt32 time; UInt16[componentCount] vectorValue; END END */ objs.addElement(new Group()); // dummy } else if (objectType == 12) { // System.out.println("Light"); Light light = new Light(); loadNode(light); float constant = readFloat(); float linear = readFloat(); float quadratic = readFloat(); light.setAttenuation(constant, linear, quadratic); light.setColor(readRGB()); light.setMode(readByte()); light.setIntensity(readFloat()); light.setSpotAngle(readFloat()); light.setSpotExponent(readFloat()); objs.addElement(light); } else if (objectType == 13) { // System.out.println("Material"); Material material = new Material(); loadObject3D(material); material.setColor(Material.AMBIENT, readRGB()); material.setColor(Material.DIFFUSE, readRGBA()); material.setColor(Material.EMISSIVE, readRGB()); material.setColor(Material.SPECULAR, readRGB()); material.setShininess(readFloat()); material.setVertexColorTrackingEnable(readBoolean()); objs.addElement(material); } else if (objectType == 14) { // System.out.println("Mesh"); loadNode(new Group()); // dummy VertexBuffer vertices = (VertexBuffer) getObject(readInt()); int submeshCount = readInt(); IndexBuffer[] submeshes = new IndexBuffer[submeshCount]; Appearance[] appearances = new Appearance[submeshCount]; for (int i = 0; i < submeshCount; ++i) { submeshes[i] = (IndexBuffer) getObject(readInt()); appearances[i] = (Appearance) getObject(readInt()); } Mesh mesh = new Mesh(vertices, submeshes, appearances); dis.reset(); loadNode(mesh); objs.addElement(mesh); } else if (objectType == 15) { System.out.println("Loader: MorphingMesh not implemented."); /* UInt32 morphTargetCount; FOR each target buffer... ObjectIndex morphTarget; Float32 initialWeight; END */ objs.addElement(new Group()); // dummy } else if (objectType == 8) { // System.out.println("PolygonMode"); PolygonMode polygonMode = new PolygonMode(); loadObject3D(polygonMode); polygonMode.setCulling(readByte()); polygonMode.setShading(readByte()); polygonMode.setWinding(readByte()); polygonMode.setTwoSidedLightingEnable(readBoolean()); polygonMode.setLocalCameraLightingEnable(readBoolean()); polygonMode.setPerspectiveCorrectionEnable(readBoolean()); objs.addElement(polygonMode); } else if (objectType == 16) { System.out.println("Loader: SkinnedMesh not implemented."); /* ObjectIndex skeleton; UInt32 transformReferenceCount; FOR each bone reference... ObjectIndex transformNode; UInt32 firstVertex; UInt32 vertexCount; Int32 weight; END */ objs.addElement(new Group()); // dummy } else if (objectType == 18) { System.out.println("Loader: Sprite not implemented."); /* ObjectIndex image; ObjectIndex appearance; Boolean isScaled; Int32 cropX; Int32 cropY; Int32 cropWidth; Int32 cropHeight; */ objs.addElement(new Group()); // dummy } else if (objectType == 17) { // System.out.println("Texture2D"); loadTransformable(new Group()); // dummy Texture2D texture = new Texture2D((Image2D) getObject(readInt())); texture.setBlendColor(readRGB()); texture.setBlending(readByte()); int wrapS = readByte(); int wrapT = readByte(); texture.setWrapping(wrapS, wrapT); int levelFilter = readByte(); int imageFilter = readByte(); texture.setFiltering(levelFilter, imageFilter); dis.reset(); loadTransformable(texture); objs.addElement(texture); } else if (objectType == 11) { // System.out.println("TriangleStripArray"); loadObject3D(new Group()); // dummy int encoding = readByte(); int firstIndex = 0; int[] indices = null; if (encoding == 0) firstIndex = readInt(); else if (encoding == 1) firstIndex = readByte(); else if (encoding == 2) firstIndex = readShort(); else if (encoding == 128) { int numIndices = readInt(); indices = new int[numIndices]; for (int i = 0; i < numIndices; ++i) indices[i] = readInt(); } else if (encoding == 129) { int numIndices = readInt(); indices = new int[numIndices]; for (int i = 0; i < numIndices; ++i) indices[i] = readByte(); } else if (encoding == 130) { int numIndices = readInt(); indices = new int[numIndices]; for (int i = 0; i < numIndices; ++i) indices[i] = readShort(); } int numStripLengths = readInt(); int[] stripLengths = new int[numStripLengths]; for (int i = 0; i < numStripLengths; ++i) stripLengths[i] = readInt(); dis.reset(); TriangleStripArray triStrip = null; if (indices == null) triStrip = new TriangleStripArray(firstIndex, stripLengths); else triStrip = new TriangleStripArray(indices, stripLengths); loadObject3D(triStrip); objs.addElement(triStrip); } else if (objectType == 20) { // System.out.println("VertexArray"); loadObject3D(new Group()); // dummy int componentSize = readByte(); int componentCount = readByte(); int encoding = readByte(); int vertexCount = readShort(); VertexArray vertices = new VertexArray(vertexCount, componentCount, componentSize); if (componentSize == 1) { byte[] values = new byte[componentCount * vertexCount]; if (encoding == 0) dis.readFully(values); else { byte last = 0; for (int i = 0; i < vertexCount * componentCount; ++i) { last += readByte(); values[i] = last; } } vertices.set(0, vertexCount, values); } else { short last = 0; short[] values = new short[componentCount * vertexCount]; for (int i = 0; i < componentCount * vertexCount; ++i) { if (encoding == 0) values[i] = (short) readShort(); else { last += (short) readShort(); values[i] = last; } } vertices.set(0, vertexCount, values); } dis.reset(); loadObject3D(vertices); objs.addElement(vertices); } else if (objectType == 21) { // System.out.println("VertexBuffer"); VertexBuffer vertices = new VertexBuffer(); loadObject3D(vertices); vertices.setDefaultColor(readRGBA()); VertexArray positions = (VertexArray) getObject(readInt()); float[] bias = new float[3]; bias[0] = readFloat(); bias[1] = readFloat(); bias[2] = readFloat(); float scale = readFloat(); vertices.setPositions(positions, scale, bias); vertices.setNormals((VertexArray) getObject(readInt())); vertices.setColors((VertexArray) getObject(readInt())); int texCoordArrayCount = readInt(); for (int i = 0; i < texCoordArrayCount; ++i) { VertexArray texcoords = (VertexArray) getObject(readInt()); bias[0] = readFloat(); bias[1] = readFloat(); bias[2] = readFloat(); scale = readFloat(); vertices.setTexCoords(i, texcoords, scale, bias); } objs.addElement(vertices); } else if (objectType == 22) { // System.out.println("World"); World world = new World(); loadGroup(world); world.setActiveCamera((Camera) getObject(readInt())); world.setBackground((Background) getObject(readInt())); objs.addElement(world); } else { System.out.println("Loader: unsupported objectType " + objectType + "."); } dis.reset(); dis.skipBytes(length); } } catch (Exception e) { System.out.println("Exception: " + e.getMessage()); e.printStackTrace(); } dis = old; return null; }
/** * 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; } }
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; } }
/** * 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); }
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(); } } }