1b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/* 2b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Copyright (c) 2009-2010 jMonkeyEngine 3b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * All rights reserved. 4b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * 5b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Redistribution and use in source and binary forms, with or without 6b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * modification, are permitted provided that the following conditions are 7b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * met: 8b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * 9b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * * Redistributions of source code must retain the above copyright 10b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * notice, this list of conditions and the following disclaimer. 11b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * 12b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * * Redistributions in binary form must reproduce the above copyright 13b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * notice, this list of conditions and the following disclaimer in the 14b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * documentation and/or other materials provided with the distribution. 15b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * 16b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * * Neither the name of 'jMonkeyEngine' nor the names of its contributors 17b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * may be used to endorse or promote products derived from this software 18b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * without specific prior written permission. 19b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * 20b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */ 32b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochpackage com.jme3.util; 33b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 34b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport com.jme3.math.ColorRGBA; 35b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport com.jme3.math.FastMath; 36b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport com.jme3.math.Vector2f; 37b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport com.jme3.math.Vector3f; 38b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport com.jme3.scene.*; 39b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport com.jme3.scene.VertexBuffer.Format; 40b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport com.jme3.scene.VertexBuffer.Type; 41b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport com.jme3.scene.VertexBuffer.Usage; 42b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport com.jme3.scene.mesh.IndexBuffer; 43b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport static com.jme3.util.BufferUtils.*; 44b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport java.nio.FloatBuffer; 45b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport java.nio.IntBuffer; 46b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport java.util.ArrayList; 47b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport java.util.logging.Level; 48b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport java.util.logging.Logger; 49b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 50b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/** 51b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * 52b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * @author Lex (Aleksey Nikiforov) 53b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */ 54b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochpublic class TangentBinormalGenerator { 55b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 56b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch private static final float ZERO_TOLERANCE = 0.0000001f; 57b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch private static final Logger log = Logger.getLogger( 58b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch TangentBinormalGenerator.class.getName()); 59b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch private static float toleranceAngle; 60b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch private static float toleranceDot; 61b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 62b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch static { 63b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch setToleranceAngle(45); 64b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 65b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 66b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 67b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch private static class VertexInfo { 68b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch public final Vector3f position; 69b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch public final Vector3f normal; 70b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch public final ArrayList<Integer> indices = new ArrayList<Integer>(); 71b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 72b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch public VertexInfo(Vector3f position, Vector3f normal) { 73b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch this.position = position; 74b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch this.normal = normal; 75b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 76b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 77b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 78b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch /** Collects all the triangle data for one vertex. 79b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */ 80b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch private static class VertexData { 81b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch public final ArrayList<TriangleData> triangles = new ArrayList<TriangleData>(); 82b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 83b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch public VertexData() { } 84b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 85b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 86b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch /** Keeps track of tangent, binormal, and normal for one triangle. 87b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */ 88b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch public static class TriangleData { 89b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch public final Vector3f tangent; 90b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch public final Vector3f binormal; 91b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch public final Vector3f normal; 92b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 93b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch public TriangleData(Vector3f tangent, Vector3f binormal, Vector3f normal) { 94b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch this.tangent = tangent; 95b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch this.binormal = binormal; 96b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch this.normal = normal; 97b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 98b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 99b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 100b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch private static VertexData[] initVertexData(int size) { 101b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch VertexData[] vertices = new VertexData[size]; 102b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch for (int i = 0; i < size; i++) { 103b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch vertices[i] = new VertexData(); 104b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 105b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return vertices; 106b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 107b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 108b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch public static void generate(Mesh mesh) { 109b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch generate(mesh, true); 110b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 111b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 112b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch public static void generate(Spatial scene) { 113b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (scene instanceof Node) { 114b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Node node = (Node) scene; 115b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch for (Spatial child : node.getChildren()) { 116b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch generate(child); 117b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 118b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } else { 119b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Geometry geom = (Geometry) scene; 120b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Mesh mesh = geom.getMesh(); 121b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 122b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Check to ensure mesh has texcoords and normals before generating 123b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (mesh.getBuffer(Type.TexCoord) != null 124b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch && mesh.getBuffer(Type.Normal) != null){ 125b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch generate(geom.getMesh()); 126b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 127b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 128b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 129b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 130b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch public static void generate(Mesh mesh, boolean approxTangents) { 131b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch int[] index = new int[3]; 132b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector3f[] v = new Vector3f[3]; 133b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector2f[] t = new Vector2f[3]; 134b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch for (int i = 0; i < 3; i++) { 135b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch v[i] = new Vector3f(); 136b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch t[i] = new Vector2f(); 137b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 138b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 139b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (mesh.getBuffer(Type.Normal) == null) { 140b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch throw new IllegalArgumentException("The given mesh has no normal data!"); 141b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 142b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 143b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch VertexData[] vertices; 144b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch switch (mesh.getMode()) { 145b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch case Triangles: 146b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch vertices = processTriangles(mesh, index, v, t); 147b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch break; 148b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch case TriangleStrip: 149b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch vertices = processTriangleStrip(mesh, index, v, t); 150b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch break; 151b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch case TriangleFan: 152b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch vertices = processTriangleFan(mesh, index, v, t); 153b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch break; 154b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch default: 155b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch throw new UnsupportedOperationException( 156b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch mesh.getMode() + " is not supported."); 157b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 158b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 159b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch processTriangleData(mesh, vertices, approxTangents); 160b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 161b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch //if the mesh has a bind pose, we need to generate the bind pose for the tangent buffer 162b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (mesh.getBuffer(Type.BindPosePosition) != null) { 163b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 164b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch VertexBuffer tangents = mesh.getBuffer(Type.Tangent); 165b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (tangents != null) { 166b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch VertexBuffer bindTangents = new VertexBuffer(Type.BindPoseTangent); 167b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch bindTangents.setupData(Usage.CpuOnly, 168b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 4, 169b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Format.Float, 170b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch BufferUtils.clone(tangents.getData())); 171b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 172b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (mesh.getBuffer(Type.BindPoseTangent) != null) { 173b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch mesh.clearBuffer(Type.BindPoseTangent); 174b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 175b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch mesh.setBuffer(bindTangents); 176b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangents.setUsage(Usage.Stream); 177b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 178b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 179b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 180b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 181b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch private static VertexData[] processTriangles(Mesh mesh, 182b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch int[] index, Vector3f[] v, Vector2f[] t) { 183b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch IndexBuffer indexBuffer = mesh.getIndexBuffer(); 184b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData(); 185b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (mesh.getBuffer(Type.TexCoord) == null) { 186b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch throw new IllegalArgumentException("Can only generate tangents for " 187b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch + "meshes with texture coordinates"); 188b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 189b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 190b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch FloatBuffer textureBuffer = (FloatBuffer) mesh.getBuffer(Type.TexCoord).getData(); 191b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 192b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch VertexData[] vertices = initVertexData(vertexBuffer.capacity() / 3); 193b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 194b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch for (int i = 0; i < indexBuffer.size() / 3; i++) { 195b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch for (int j = 0; j < 3; j++) { 196b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch index[j] = indexBuffer.get(i * 3 + j); 197b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch populateFromBuffer(v[j], vertexBuffer, index[j]); 198b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch populateFromBuffer(t[j], textureBuffer, index[j]); 199b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 200b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 201b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch TriangleData triData = processTriangle(index, v, t); 202b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (triData != null) { 203b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch vertices[index[0]].triangles.add(triData); 204b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch vertices[index[1]].triangles.add(triData); 205b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch vertices[index[2]].triangles.add(triData); 206b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 207b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 208b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 209b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return vertices; 210b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 211b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 212b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch private static VertexData[] processTriangleStrip(Mesh mesh, 213b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch int[] index, Vector3f[] v, Vector2f[] t) { 214b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch IndexBuffer indexBuffer = mesh.getIndexBuffer(); 215b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData(); 216b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch FloatBuffer textureBuffer = (FloatBuffer) mesh.getBuffer(Type.TexCoord).getData(); 217b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 218b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch VertexData[] vertices = initVertexData(vertexBuffer.capacity() / 3); 219b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 220b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch index[0] = indexBuffer.get(0); 221b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch index[1] = indexBuffer.get(1); 222b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 223b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch populateFromBuffer(v[0], vertexBuffer, index[0]); 224b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch populateFromBuffer(v[1], vertexBuffer, index[1]); 225b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 226b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch populateFromBuffer(t[0], textureBuffer, index[0]); 227b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch populateFromBuffer(t[1], textureBuffer, index[1]); 228b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 229b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch for (int i = 2; i < indexBuffer.size(); i++) { 230b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch index[2] = indexBuffer.get(i); 231b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch BufferUtils.populateFromBuffer(v[2], vertexBuffer, index[2]); 232b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch BufferUtils.populateFromBuffer(t[2], textureBuffer, index[2]); 233b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 234b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch boolean isDegenerate = isDegenerateTriangle(v[0], v[1], v[2]); 235b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch TriangleData triData = processTriangle(index, v, t); 236b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 237b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (triData != null && !isDegenerate) { 238b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch vertices[index[0]].triangles.add(triData); 239b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch vertices[index[1]].triangles.add(triData); 240b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch vertices[index[2]].triangles.add(triData); 241b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 242b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 243b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector3f vTemp = v[0]; 244b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch v[0] = v[1]; 245b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch v[1] = v[2]; 246b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch v[2] = vTemp; 247b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 248b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector2f tTemp = t[0]; 249b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch t[0] = t[1]; 250b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch t[1] = t[2]; 251b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch t[2] = tTemp; 252b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 253b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch index[0] = index[1]; 254b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch index[1] = index[2]; 255b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 256b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 257b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return vertices; 258b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 259b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 260b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch private static VertexData[] processTriangleFan(Mesh mesh, 261b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch int[] index, Vector3f[] v, Vector2f[] t) { 262b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch IndexBuffer indexBuffer = mesh.getIndexBuffer(); 263b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData(); 264b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch FloatBuffer textureBuffer = (FloatBuffer) mesh.getBuffer(Type.TexCoord).getData(); 265b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 266b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch VertexData[] vertices = initVertexData(vertexBuffer.capacity() / 3); 267b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 268b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch index[0] = indexBuffer.get(0); 269b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch index[1] = indexBuffer.get(1); 270b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 271b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch populateFromBuffer(v[0], vertexBuffer, index[0]); 272b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch populateFromBuffer(v[1], vertexBuffer, index[1]); 273b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 274b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch populateFromBuffer(t[0], textureBuffer, index[0]); 275b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch populateFromBuffer(t[1], textureBuffer, index[1]); 276b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 277b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch for (int i = 2; i < vertexBuffer.capacity() / 3; i++) { 278b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch index[2] = indexBuffer.get(i); 279b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch populateFromBuffer(v[2], vertexBuffer, index[2]); 280b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch populateFromBuffer(t[2], textureBuffer, index[2]); 281b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 282b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch TriangleData triData = processTriangle(index, v, t); 283b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (triData != null) { 284b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch vertices[index[0]].triangles.add(triData); 285b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch vertices[index[1]].triangles.add(triData); 286b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch vertices[index[2]].triangles.add(triData); 287b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 288b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 289b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector3f vTemp = v[1]; 290b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch v[1] = v[2]; 291b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch v[2] = vTemp; 292b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 293b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector2f tTemp = t[1]; 294b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch t[1] = t[2]; 295b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch t[2] = tTemp; 296b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 297b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch index[1] = index[2]; 298b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 299b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 300b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return vertices; 301b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 302b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 303b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // check if the area is greater than zero 304b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch private static boolean isDegenerateTriangle(Vector3f a, Vector3f b, Vector3f c) { 305b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return (a.subtract(b).cross(c.subtract(b))).lengthSquared() == 0; 306b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 307b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 308b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch public static TriangleData processTriangle(int[] index, 309b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector3f[] v, Vector2f[] t) { 310b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector3f edge1 = new Vector3f(); 311b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector3f edge2 = new Vector3f(); 312b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector2f edge1uv = new Vector2f(); 313b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector2f edge2uv = new Vector2f(); 314b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 315b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector3f tangent = new Vector3f(); 316b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector3f binormal = new Vector3f(); 317b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector3f normal = new Vector3f(); 318b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 319b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch t[1].subtract(t[0], edge1uv); 320b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch t[2].subtract(t[0], edge2uv); 321b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch float det = edge1uv.x * edge2uv.y - edge1uv.y * edge2uv.x; 322b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 323b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch boolean normalize = false; 324b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (Math.abs(det) < ZERO_TOLERANCE) { 325b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch log.log(Level.WARNING, "Colinear uv coordinates for triangle " 326b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch + "[{0}, {1}, {2}]; tex0 = [{3}, {4}], " 327b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch + "tex1 = [{5}, {6}], tex2 = [{7}, {8}]", 328b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch new Object[]{index[0], index[1], index[2], 329b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch t[0].x, t[0].y, t[1].x, t[1].y, t[2].x, t[2].y}); 330b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch det = 1; 331b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch normalize = true; 332b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 333b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 334b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch v[1].subtract(v[0], edge1); 335b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch v[2].subtract(v[0], edge2); 336b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 337b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangent.set(edge1); 338b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangent.normalizeLocal(); 339b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch binormal.set(edge2); 340b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch binormal.normalizeLocal(); 341b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 342b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (Math.abs(Math.abs(tangent.dot(binormal)) - 1) 343b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch < ZERO_TOLERANCE) { 344b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch log.log(Level.WARNING, "Vertices are on the same line " 345b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch + "for triangle [{0}, {1}, {2}].", 346b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch new Object[]{index[0], index[1], index[2]}); 347b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 348b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 349b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch float factor = 1 / det; 350b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangent.x = (edge2uv.y * edge1.x - edge1uv.y * edge2.x) * factor; 351b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangent.y = (edge2uv.y * edge1.y - edge1uv.y * edge2.y) * factor; 352b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangent.z = (edge2uv.y * edge1.z - edge1uv.y * edge2.z) * factor; 353b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (normalize) { 354b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangent.normalizeLocal(); 355b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 356b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 357b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch binormal.x = (edge1uv.x * edge2.x - edge2uv.x * edge1.x) * factor; 358b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch binormal.y = (edge1uv.x * edge2.y - edge2uv.x * edge1.y) * factor; 359b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch binormal.z = (edge1uv.x * edge2.z - edge2uv.x * edge1.z) * factor; 360b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (normalize) { 361b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch binormal.normalizeLocal(); 362b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 363b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 364b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangent.cross(binormal, normal); 365b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch normal.normalizeLocal(); 366b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 367b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return new TriangleData( 368b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangent, 369b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch binormal, 370b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch normal); 371b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 372b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 373b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch public static void setToleranceAngle(float angle) { 374b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (angle < 0 || angle > 179) { 375b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch throw new IllegalArgumentException( 376b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch "The angle must be between 0 and 179 degrees."); 377b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 378b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch toleranceDot = FastMath.cos(angle * FastMath.DEG_TO_RAD); 379b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch toleranceAngle = angle; 380b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 381b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 382b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 383b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch private static boolean approxEqual(Vector3f u, Vector3f v) { 384b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch float tolerance = 1E-4f; 385b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return (FastMath.abs(u.x - v.x) < tolerance) && 386b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch (FastMath.abs(u.y - v.y) < tolerance) && 387b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch (FastMath.abs(u.z - v.z) < tolerance); 388b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 389b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 390b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch private static ArrayList<VertexInfo> linkVertices(Mesh mesh) { 391b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ArrayList<VertexInfo> vertexMap = new ArrayList<VertexInfo>(); 392b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 393b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData(); 394b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch FloatBuffer normalBuffer = (FloatBuffer) mesh.getBuffer(Type.Normal).getData(); 395b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 396b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector3f position = new Vector3f(); 397b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector3f normal = new Vector3f(); 398b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 399b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch final int size = vertexBuffer.capacity() / 3; 400b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch for (int i = 0; i < size; i++) { 401b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 402b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch populateFromBuffer(position, vertexBuffer, i); 403b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch populateFromBuffer(normal, normalBuffer, i); 404b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 405b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch boolean found = false; 406b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 407b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch for (int j = 0; j < vertexMap.size(); j++) { 408b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch VertexInfo vertexInfo = vertexMap.get(j); 409b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (approxEqual(vertexInfo.position, position) && 410b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch approxEqual(vertexInfo.normal, normal)) 411b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch { 412b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch vertexInfo.indices.add(i); 413b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch found = true; 414b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch break; 415b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 416b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 417b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 418b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (!found) { 419b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch VertexInfo vertexInfo = new VertexInfo(position.clone(), normal.clone()); 420b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch vertexInfo.indices.add(i); 421b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch vertexMap.add(vertexInfo); 422b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 423b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 424b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 425b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return vertexMap; 426b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 427b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 428b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch private static void processTriangleData(Mesh mesh, VertexData[] vertices, 429b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch boolean approxTangent) 430b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch { 431b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ArrayList<VertexInfo> vertexMap = linkVertices(mesh); 432b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 433b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch FloatBuffer normalBuffer = (FloatBuffer) mesh.getBuffer(Type.Normal).getData(); 434b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 435b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch FloatBuffer tangents = BufferUtils.createFloatBuffer(vertices.length * 4); 436b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// FloatBuffer binormals = BufferUtils.createFloatBuffer(vertices.length * 3); 437b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 438b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector3f tangent = new Vector3f(); 439b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector3f binormal = new Vector3f(); 440b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector3f normal = new Vector3f(); 441b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector3f givenNormal = new Vector3f(); 442b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 443b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector3f tangentUnit = new Vector3f(); 444b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector3f binormalUnit = new Vector3f(); 445b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 446b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch for (int k = 0; k < vertexMap.size(); k++) { 447b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch float wCoord = -1; 448b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 449b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch VertexInfo vertexInfo = vertexMap.get(k); 450b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 451b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch givenNormal.set(vertexInfo.normal); 452b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch givenNormal.normalizeLocal(); 453b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 454b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch TriangleData firstTriangle = vertices[vertexInfo.indices.get(0)].triangles.get(0); 455b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 456b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // check tangent and binormal consistency 457b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangent.set(firstTriangle.tangent); 458b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangent.normalizeLocal(); 459b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch binormal.set(firstTriangle.binormal); 460b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch binormal.normalizeLocal(); 461b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 462b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch for (int i : vertexInfo.indices) { 463b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ArrayList<TriangleData> triangles = vertices[i].triangles; 464b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 465b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch for (int j = 0; j < triangles.size(); j++) { 466b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch TriangleData triangleData = triangles.get(j); 467b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 468b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangentUnit.set(triangleData.tangent); 469b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangentUnit.normalizeLocal(); 470b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (tangent.dot(tangentUnit) < toleranceDot) { 471b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch log.log(Level.WARNING, 472b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch "Angle between tangents exceeds tolerance " 473b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch + "for vertex {0}.", i); 474b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch break; 475b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 476b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 477b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (!approxTangent) { 478b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch binormalUnit.set(triangleData.binormal); 479b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch binormalUnit.normalizeLocal(); 480b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (binormal.dot(binormalUnit) < toleranceDot) { 481b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch log.log(Level.WARNING, 482b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch "Angle between binormals exceeds tolerance " 483b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch + "for vertex {0}.", i); 484b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch break; 485b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 486b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 487b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 488b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 489b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 490b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 491b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // find average tangent 492b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangent.set(0, 0, 0); 493b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch binormal.set(0, 0, 0); 494b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 495b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch int triangleCount = 0; 496b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch for (int i : vertexInfo.indices) { 497b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ArrayList<TriangleData> triangles = vertices[i].triangles; 498b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch triangleCount += triangles.size(); 499b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 500b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch boolean flippedNormal = false; 501b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch for (int j = 0; j < triangles.size(); j++) { 502b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch TriangleData triangleData = triangles.get(j); 503b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangent.addLocal(triangleData.tangent); 504b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch binormal.addLocal(triangleData.binormal); 505b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 506b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (givenNormal.dot(triangleData.normal) < 0) { 507b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch flippedNormal = true; 508b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 509b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 510b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (flippedNormal /*&& approxTangent*/) { 511b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Generated normal is flipped for this vertex, 512b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // so binormal = normal.cross(tangent) will be flipped in the shader 513b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // log.log(Level.WARNING, 514b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // "Binormal is flipped for vertex {0}.", i); 515b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 516b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch wCoord = 1; 517b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 518b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 519b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 520b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 521b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch int blameVertex = vertexInfo.indices.get(0); 522b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 523b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (tangent.length() < ZERO_TOLERANCE) { 524b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch log.log(Level.WARNING, 525b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch "Shared tangent is zero for vertex {0}.", blameVertex); 526b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // attempt to fix from binormal 527b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (binormal.length() >= ZERO_TOLERANCE) { 528b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch binormal.cross(givenNormal, tangent); 529b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangent.normalizeLocal(); 530b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } // if all fails use the tangent from the first triangle 531b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch else { 532b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangent.set(firstTriangle.tangent); 533b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 534b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } else { 535b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangent.divideLocal(triangleCount); 536b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 537b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 538b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangentUnit.set(tangent); 539b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangentUnit.normalizeLocal(); 540b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (Math.abs(Math.abs(tangentUnit.dot(givenNormal)) - 1) 541b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch < ZERO_TOLERANCE) { 542b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch log.log(Level.WARNING, 543b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch "Normal and tangent are parallel for vertex {0}.", blameVertex); 544b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 545b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 546b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 547b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (!approxTangent) { 548b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (binormal.length() < ZERO_TOLERANCE) { 549b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch log.log(Level.WARNING, 550b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch "Shared binormal is zero for vertex {0}.", blameVertex); 551b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // attempt to fix from tangent 552b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (tangent.length() >= ZERO_TOLERANCE) { 553b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch givenNormal.cross(tangent, binormal); 554b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch binormal.normalizeLocal(); 555b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } // if all fails use the binormal from the first triangle 556b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch else { 557b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch binormal.set(firstTriangle.binormal); 558b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 559b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } else { 560b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch binormal.divideLocal(triangleCount); 561b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 562b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 563b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch binormalUnit.set(binormal); 564b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch binormalUnit.normalizeLocal(); 565b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (Math.abs(Math.abs(binormalUnit.dot(givenNormal)) - 1) 566b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch < ZERO_TOLERANCE) { 567b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch log.log(Level.WARNING, 568b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch "Normal and binormal are parallel for vertex {0}.", blameVertex); 569b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 570b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 571b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (Math.abs(Math.abs(binormalUnit.dot(tangentUnit)) - 1) 572b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch < ZERO_TOLERANCE) { 573b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch log.log(Level.WARNING, 574b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch "Tangent and binormal are parallel for vertex {0}.", blameVertex); 575b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 576b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 577b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 578b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch for (int i : vertexInfo.indices) { 579b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (approxTangent) { 580b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // This calculation ensures that normal and tagent have a 90 degree angle. 581b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Removing this will lead to visual artifacts. 582b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch givenNormal.cross(tangent, binormal); 583b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch binormal.cross(givenNormal, tangent); 584b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 585b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangent.normalizeLocal(); 586b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 587b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangents.put((i * 4), tangent.x); 588b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangents.put((i * 4) + 1, tangent.y); 589b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangents.put((i * 4) + 2, tangent.z); 590b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangents.put((i * 4) + 3, wCoord); 591b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } else { 592b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangents.put((i * 4), tangent.x); 593b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangents.put((i * 4) + 1, tangent.y); 594b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangents.put((i * 4) + 2, tangent.z); 595b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangents.put((i * 4) + 3, wCoord); 596b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 597b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch //setInBuffer(binormal, binormals, i); 598b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 599b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 600b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 601b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 602b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch mesh.setBuffer(Type.Tangent, 4, tangents); 603b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// if (!approxTangent) mesh.setBuffer(Type.Binormal, 3, binormals); 604b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 605b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 606b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch public static Mesh genTbnLines(Mesh mesh, float scale) { 607b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (mesh.getBuffer(Type.Tangent) == null) { 608b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return genNormalLines(mesh, scale); 609b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } else { 610b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return genTangentLines(mesh, scale); 611b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 612b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 613b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 614b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch public static Mesh genNormalLines(Mesh mesh, float scale) { 615b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData(); 616b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch FloatBuffer normalBuffer = (FloatBuffer) mesh.getBuffer(Type.Normal).getData(); 617b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 618b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ColorRGBA originColor = ColorRGBA.White; 619b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ColorRGBA normalColor = ColorRGBA.Blue; 620b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 621b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Mesh lineMesh = new Mesh(); 622b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch lineMesh.setMode(Mesh.Mode.Lines); 623b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 624b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector3f origin = new Vector3f(); 625b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector3f point = new Vector3f(); 626b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 627b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch FloatBuffer lineVertex = BufferUtils.createFloatBuffer(vertexBuffer.capacity() * 2); 628b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch FloatBuffer lineColor = BufferUtils.createFloatBuffer(vertexBuffer.capacity() / 3 * 4 * 2); 629b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 630b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch for (int i = 0; i < vertexBuffer.capacity() / 3; i++) { 631b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch populateFromBuffer(origin, vertexBuffer, i); 632b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch populateFromBuffer(point, normalBuffer, i); 633b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 634b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch int index = i * 2; 635b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 636b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch setInBuffer(origin, lineVertex, index); 637b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch setInBuffer(originColor, lineColor, index); 638b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 639b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch point.multLocal(scale); 640b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch point.addLocal(origin); 641b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch setInBuffer(point, lineVertex, index + 1); 642b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch setInBuffer(normalColor, lineColor, index + 1); 643b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 644b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 645b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch lineMesh.setBuffer(Type.Position, 3, lineVertex); 646b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch lineMesh.setBuffer(Type.Color, 4, lineColor); 647b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 648b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch lineMesh.setStatic(); 649b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch //lineMesh.setInterleaved(); 650b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return lineMesh; 651b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 652b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 653b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch private static Mesh genTangentLines(Mesh mesh, float scale) { 654b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData(); 655b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch FloatBuffer normalBuffer = (FloatBuffer) mesh.getBuffer(Type.Normal).getData(); 656b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch FloatBuffer tangentBuffer = (FloatBuffer) mesh.getBuffer(Type.Tangent).getData(); 657b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 658b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch FloatBuffer binormalBuffer = null; 659b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (mesh.getBuffer(Type.Binormal) != null) { 660b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch binormalBuffer = (FloatBuffer) mesh.getBuffer(Type.Binormal).getData(); 661b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 662b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 663b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ColorRGBA originColor = ColorRGBA.White; 664b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ColorRGBA tangentColor = ColorRGBA.Red; 665b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ColorRGBA binormalColor = ColorRGBA.Green; 666b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ColorRGBA normalColor = ColorRGBA.Blue; 667b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 668b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Mesh lineMesh = new Mesh(); 669b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch lineMesh.setMode(Mesh.Mode.Lines); 670b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 671b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector3f origin = new Vector3f(); 672b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector3f point = new Vector3f(); 673b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector3f tangent = new Vector3f(); 674b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Vector3f normal = new Vector3f(); 675b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 676b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch IntBuffer lineIndex = BufferUtils.createIntBuffer(vertexBuffer.capacity() / 3 * 6); 677b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch FloatBuffer lineVertex = BufferUtils.createFloatBuffer(vertexBuffer.capacity() * 4); 678b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch FloatBuffer lineColor = BufferUtils.createFloatBuffer(vertexBuffer.capacity() / 3 * 4 * 4); 679b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 680b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch boolean hasParity = mesh.getBuffer(Type.Tangent).getNumComponents() == 4; 681b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch float tangentW = 1; 682b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 683b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch for (int i = 0; i < vertexBuffer.capacity() / 3; i++) { 684b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch populateFromBuffer(origin, vertexBuffer, i); 685b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch populateFromBuffer(normal, normalBuffer, i); 686b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 687b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (hasParity) { 688b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangent.x = tangentBuffer.get(i * 4); 689b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangent.y = tangentBuffer.get(i * 4 + 1); 690b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangent.z = tangentBuffer.get(i * 4 + 2); 691b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch tangentW = tangentBuffer.get(i * 4 + 3); 692b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } else { 693b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch populateFromBuffer(tangent, tangentBuffer, i); 694b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 695b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 696b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch int index = i * 4; 697b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 698b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch int id = i * 6; 699b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch lineIndex.put(id, index); 700b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch lineIndex.put(id + 1, index + 1); 701b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch lineIndex.put(id + 2, index); 702b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch lineIndex.put(id + 3, index + 2); 703b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch lineIndex.put(id + 4, index); 704b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch lineIndex.put(id + 5, index + 3); 705b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 706b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch setInBuffer(origin, lineVertex, index); 707b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch setInBuffer(originColor, lineColor, index); 708b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 709b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch point.set(tangent); 710b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch point.multLocal(scale); 711b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch point.addLocal(origin); 712b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch setInBuffer(point, lineVertex, index + 1); 713b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch setInBuffer(tangentColor, lineColor, index + 1); 714b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 715b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // wvBinormal = cross(wvNormal, wvTangent) * -inTangent.w 716b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 717b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (binormalBuffer == null) { 718b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch normal.cross(tangent, point); 719b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch point.multLocal(-tangentW); 720b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch point.normalizeLocal(); 721b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } else { 722b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch populateFromBuffer(point, binormalBuffer, i); 723b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 724b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 725b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch point.multLocal(scale); 726b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch point.addLocal(origin); 727b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch setInBuffer(point, lineVertex, index + 2); 728b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch setInBuffer(binormalColor, lineColor, index + 2); 729b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 730b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch point.set(normal); 731b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch point.multLocal(scale); 732b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch point.addLocal(origin); 733b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch setInBuffer(point, lineVertex, index + 3); 734b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch setInBuffer(normalColor, lineColor, index + 3); 735b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 736b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 737b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch lineMesh.setBuffer(Type.Index, 1, lineIndex); 738b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch lineMesh.setBuffer(Type.Position, 3, lineVertex); 739b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch lineMesh.setBuffer(Type.Color, 4, lineColor); 740b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 741b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch lineMesh.setStatic(); 742b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch //lineMesh.setInterleaved(); 743b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return lineMesh; 744b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 745b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 746b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch