Main repository of MikuMikuStudio
Revision | f79ace3f4d5f25353288675f1667dcf7ef04dea9 (tree) |
---|---|
Time | 2013-07-08 06:24:02 |
Author | remy.bouquet@gmail.com <remy.bouquet@gmai...> |
Commiter | remy.bouquet@gmail.com |
- TangentBinormalGenerator now splits vertices with mirrored uvs. This is an optional operation.
It fixes the issue in this thread : http://hub.jmonkeyengine.org/forum/topic/normalmapslighting-issue/
Next step is to split vertices that have triangles with heavily rotated tangent spaces.
git-svn-id: http://jmonkeyengine.googlecode.com/svn/trunk@10698 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
@@ -35,16 +35,22 @@ import com.jme3.math.ColorRGBA; | ||
35 | 35 | import com.jme3.math.FastMath; |
36 | 36 | import com.jme3.math.Vector2f; |
37 | 37 | import com.jme3.math.Vector3f; |
38 | -import com.jme3.math.Vector4f; | |
39 | 38 | import com.jme3.scene.*; |
40 | 39 | import com.jme3.scene.VertexBuffer.Format; |
41 | 40 | import com.jme3.scene.VertexBuffer.Type; |
42 | 41 | import com.jme3.scene.VertexBuffer.Usage; |
43 | 42 | import com.jme3.scene.mesh.IndexBuffer; |
44 | 43 | import static com.jme3.util.BufferUtils.*; |
44 | +import java.nio.Buffer; | |
45 | +import java.nio.ByteBuffer; | |
46 | +import java.nio.DoubleBuffer; | |
45 | 47 | import java.nio.FloatBuffer; |
46 | 48 | import java.nio.IntBuffer; |
49 | +import java.nio.ShortBuffer; | |
47 | 50 | import java.util.ArrayList; |
51 | +import java.util.HashMap; | |
52 | +import java.util.List; | |
53 | +import java.util.Map; | |
48 | 54 | import java.util.logging.Level; |
49 | 55 | import java.util.logging.Logger; |
50 | 56 |
@@ -57,13 +63,13 @@ public class TangentBinormalGenerator { | ||
57 | 63 | private static final float ZERO_TOLERANCE = 0.0000001f; |
58 | 64 | private static final Logger log = Logger.getLogger( |
59 | 65 | TangentBinormalGenerator.class.getName()); |
60 | - private static float toleranceAngle; | |
61 | 66 | private static float toleranceDot; |
67 | + public static boolean debug = false; | |
62 | 68 | |
63 | 69 | static { |
64 | 70 | setToleranceAngle(45); |
65 | 71 | } |
66 | - | |
72 | + | |
67 | 73 | |
68 | 74 | private static class VertexInfo { |
69 | 75 | public final Vector3f position; |
@@ -91,32 +97,39 @@ public class TangentBinormalGenerator { | ||
91 | 97 | public static class TriangleData { |
92 | 98 | public final Vector3f tangent; |
93 | 99 | public final Vector3f binormal; |
94 | - public final Vector3f normal; | |
100 | + public final Vector3f normal; | |
101 | + public int[] index = new int[3]; | |
102 | + public int triangleOffset; | |
95 | 103 | |
96 | 104 | public TriangleData(Vector3f tangent, Vector3f binormal, Vector3f normal) { |
97 | 105 | this.tangent = tangent; |
98 | 106 | this.binormal = binormal; |
99 | 107 | this.normal = normal; |
100 | 108 | } |
109 | + public void setIndex(int[] index) { | |
110 | + for (int i = 0; i < index.length; i++) { | |
111 | + this.index[i] = index[i]; | |
112 | + } | |
113 | + } | |
101 | 114 | } |
102 | 115 | |
103 | - private static VertexData[] initVertexData(int size) { | |
104 | - VertexData[] vertices = new VertexData[size]; | |
116 | + private static List<VertexData> initVertexData(int size) { | |
117 | + List<VertexData> vertices = new ArrayList<VertexData>(size); | |
105 | 118 | for (int i = 0; i < size; i++) { |
106 | - vertices[i] = new VertexData(); | |
119 | + vertices.add(new VertexData()); | |
107 | 120 | } |
108 | 121 | return vertices; |
109 | 122 | } |
110 | 123 | |
111 | 124 | public static void generate(Mesh mesh) { |
112 | - generate(mesh, true); | |
125 | + generate(mesh, true, false); | |
113 | 126 | } |
114 | 127 | |
115 | - public static void generate(Spatial scene) { | |
128 | + public static void generate(Spatial scene, boolean splitMirrored) { | |
116 | 129 | if (scene instanceof Node) { |
117 | 130 | Node node = (Node) scene; |
118 | 131 | for (Spatial child : node.getChildren()) { |
119 | - generate(child); | |
132 | + generate(child, splitMirrored); | |
120 | 133 | } |
121 | 134 | } else { |
122 | 135 | Geometry geom = (Geometry) scene; |
@@ -125,12 +138,16 @@ public class TangentBinormalGenerator { | ||
125 | 138 | // Check to ensure mesh has texcoords and normals before generating |
126 | 139 | if (mesh.getBuffer(Type.TexCoord) != null |
127 | 140 | && mesh.getBuffer(Type.Normal) != null){ |
128 | - generate(geom.getMesh()); | |
141 | + generate(geom.getMesh(),true, splitMirrored); | |
129 | 142 | } |
130 | 143 | } |
131 | 144 | } |
132 | 145 | |
133 | - public static void generate(Mesh mesh, boolean approxTangents) { | |
146 | + public static void generate(Spatial scene) { | |
147 | + generate(scene, false); | |
148 | + } | |
149 | + | |
150 | + public static void generate(Mesh mesh, boolean approxTangents, boolean splitMirrored) { | |
134 | 151 | int[] index = new int[3]; |
135 | 152 | Vector3f[] v = new Vector3f[3]; |
136 | 153 | Vector2f[] t = new Vector2f[3]; |
@@ -143,10 +160,13 @@ public class TangentBinormalGenerator { | ||
143 | 160 | throw new IllegalArgumentException("The given mesh has no normal data!"); |
144 | 161 | } |
145 | 162 | |
146 | - VertexData[] vertices; | |
163 | + List<VertexData> vertices; | |
147 | 164 | switch (mesh.getMode()) { |
148 | 165 | case Triangles: |
149 | - vertices = processTriangles(mesh, index, v, t); | |
166 | + vertices = processTriangles(mesh, index, v, t, splitMirrored); | |
167 | + if(splitMirrored){ | |
168 | + splitVertices(mesh, vertices, splitMirrored); | |
169 | + } | |
150 | 170 | break; |
151 | 171 | case TriangleStrip: |
152 | 172 | vertices = processTriangleStrip(mesh, index, v, t); |
@@ -181,8 +201,8 @@ public class TangentBinormalGenerator { | ||
181 | 201 | } |
182 | 202 | } |
183 | 203 | |
184 | - private static VertexData[] processTriangles(Mesh mesh, | |
185 | - int[] index, Vector3f[] v, Vector2f[] t) { | |
204 | + private static List<VertexData> processTriangles(Mesh mesh, | |
205 | + int[] index, Vector3f[] v, Vector2f[] t, boolean splitMirrored) { | |
186 | 206 | IndexBuffer indexBuffer = mesh.getIndexBuffer(); |
187 | 207 | FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData(); |
188 | 208 | if (mesh.getBuffer(Type.TexCoord) == null) { |
@@ -192,7 +212,7 @@ public class TangentBinormalGenerator { | ||
192 | 212 | |
193 | 213 | FloatBuffer textureBuffer = (FloatBuffer) mesh.getBuffer(Type.TexCoord).getData(); |
194 | 214 | |
195 | - VertexData[] vertices = initVertexData(vertexBuffer.limit() / 3); | |
215 | + List<VertexData> vertices = initVertexData(vertexBuffer.limit() / 3); | |
196 | 216 | |
197 | 217 | for (int i = 0; i < indexBuffer.size() / 3; i++) { |
198 | 218 | for (int j = 0; j < 3; j++) { |
@@ -202,23 +222,201 @@ public class TangentBinormalGenerator { | ||
202 | 222 | } |
203 | 223 | |
204 | 224 | TriangleData triData = processTriangle(index, v, t); |
225 | + if(splitMirrored){ | |
226 | + triData.setIndex(index); | |
227 | + triData.triangleOffset = i * 3 ; | |
228 | + } | |
205 | 229 | if (triData != null) { |
206 | - vertices[index[0]].triangles.add(triData); | |
207 | - vertices[index[1]].triangles.add(triData); | |
208 | - vertices[index[2]].triangles.add(triData); | |
230 | + vertices.get(index[0]).triangles.add(triData); | |
231 | + vertices.get(index[1]).triangles.add(triData); | |
232 | + vertices.get(index[2]).triangles.add(triData); | |
209 | 233 | } |
210 | 234 | } |
211 | 235 | |
212 | 236 | return vertices; |
213 | 237 | } |
214 | 238 | |
215 | - private static VertexData[] processTriangleStrip(Mesh mesh, | |
239 | + //Don't remove splitmirorred boolean,It's not used right now, but i intend to | |
240 | + //make this method also split vertice with rotated tangent space and I'll | |
241 | + //add another splitRotated boolean | |
242 | + private static List<VertexData> splitVertices(Mesh mesh, List<VertexData> vertexData, boolean splitMirorred) { | |
243 | + int nbVertices = mesh.getBuffer(Type.Position).getNumElements(); | |
244 | + List<VertexData> newVertices = new ArrayList<VertexData>(); | |
245 | + Map<Integer, Integer> indiceMap = new HashMap<Integer, Integer>(); | |
246 | + FloatBuffer normalBuffer = mesh.getFloatBuffer(Type.Normal); | |
247 | + | |
248 | + for (int i = 0; i < vertexData.size(); i++) { | |
249 | + ArrayList<TriangleData> triangles = vertexData.get(i).triangles; | |
250 | + Vector3f givenNormal = new Vector3f(); | |
251 | + populateFromBuffer(givenNormal, normalBuffer, i); | |
252 | + | |
253 | + ArrayList<TriangleData> trianglesUp = new ArrayList<TriangleData>(); | |
254 | + ArrayList<TriangleData> trianglesDown = new ArrayList<TriangleData>(); | |
255 | + for (int j = 0; j < triangles.size(); j++) { | |
256 | + TriangleData triangleData = triangles.get(j); | |
257 | + if(parity(givenNormal, triangleData.normal) > 0){ | |
258 | + trianglesUp.add(triangleData); | |
259 | + }else{ | |
260 | + trianglesDown.add(triangleData); | |
261 | + } | |
262 | + } | |
263 | + | |
264 | + //if the vertex has triangles with opposite parity it has to be split | |
265 | + if(!trianglesUp.isEmpty() && !trianglesDown.isEmpty()){ | |
266 | + log.log(Level.FINE, "Splitting vertex {0}", i); | |
267 | + //assigning triangle with the same parity to the original vertex | |
268 | + vertexData.get(i).triangles.clear(); | |
269 | + vertexData.get(i).triangles.addAll(trianglesUp); | |
270 | + | |
271 | + //creating a new vertex | |
272 | + VertexData newVert = new VertexData(); | |
273 | + //assigning triangles with opposite parity to it | |
274 | + newVert.triangles.addAll(trianglesDown); | |
275 | + | |
276 | + newVertices.add(newVert); | |
277 | + //keep vertex index to fix the index buffers later | |
278 | + indiceMap.put(nbVertices, i); | |
279 | + for (TriangleData tri : newVert.triangles) { | |
280 | + for (int j = 0; j < tri.index.length; j++) { | |
281 | + if(tri.index[j] == i){ | |
282 | + tri.index[j] = nbVertices; | |
283 | + } | |
284 | + } | |
285 | + } | |
286 | + nbVertices++; | |
287 | + | |
288 | + } | |
289 | + | |
290 | + | |
291 | + } | |
292 | + | |
293 | + if(!newVertices.isEmpty()){ | |
294 | + | |
295 | + //we have new vertices, we need to update the mesh's buffers. | |
296 | + for (Type type : VertexBuffer.Type.values()) { | |
297 | + //skip tangent buffer as we're gonna overwrite it later | |
298 | + if(type == Type.Tangent || type == Type.BindPoseTangent) continue; | |
299 | + VertexBuffer vb = mesh.getBuffer(type); | |
300 | + //Some buffer (hardware skinning ones) can be there but not | |
301 | + //initialized, they must be skipped. | |
302 | + //They'll be initialized when Hardware Skinning is engaged | |
303 | + if(vb==null || vb.getNumComponents() == 0) continue; | |
304 | + | |
305 | + Buffer buffer = vb.getData(); | |
306 | + //IndexBuffer has special treatement, only swapping the vertex indices is needed | |
307 | + if(type == Type.Index){ | |
308 | + boolean isShortBuffer = vb.getFormat() == VertexBuffer.Format.UnsignedShort; | |
309 | + for (VertexData vertex : newVertices) { | |
310 | + for (TriangleData tri : vertex.triangles) { | |
311 | + for (int i = 0; i < tri.index.length; i++) { | |
312 | + if (isShortBuffer) { | |
313 | + ((ShortBuffer) buffer).put(tri.triangleOffset + i, (short) tri.index[i]); | |
314 | + } else { | |
315 | + ((IntBuffer) buffer).put(tri.triangleOffset + i, tri.index[i]); | |
316 | + } | |
317 | + } | |
318 | + } | |
319 | + } | |
320 | + vb.setUpdateNeeded(); | |
321 | + }else{ | |
322 | + //copy the buffer in a bigger one and append nex vertices to the end | |
323 | + Buffer newVerts = VertexBuffer.createBuffer(vb.getFormat(), vb.getNumComponents(), nbVertices); | |
324 | + if (buffer != null) { | |
325 | + buffer.rewind(); | |
326 | + bulkPut(vb.getFormat(), newVerts,buffer); | |
327 | + | |
328 | + int index = vertexData.size(); | |
329 | + newVerts.position(vertexData.size() * vb.getNumComponents()); | |
330 | + for (int j = 0; j < newVertices.size(); j++) { | |
331 | + int oldInd = indiceMap.get(index) ; | |
332 | + for (int i = 0; i < vb.getNumComponents(); i++) { | |
333 | + putValue(vb.getFormat(), newVerts, buffer, oldInd* vb.getNumComponents() + i); | |
334 | + } | |
335 | + index++; | |
336 | + } | |
337 | + vb.updateData(newVerts); | |
338 | + //destroy previous buffer as it's no longer needed | |
339 | + destroyDirectBuffer(buffer); | |
340 | + } | |
341 | + } | |
342 | + } | |
343 | + vertexData.addAll(newVertices); | |
344 | + | |
345 | + mesh.updateCounts(); | |
346 | + } | |
347 | + | |
348 | + return vertexData; | |
349 | + } | |
350 | + | |
351 | + private static void bulkPut(VertexBuffer.Format format, Buffer buf1, Buffer buf2) { | |
352 | + switch (format) { | |
353 | + case Byte: | |
354 | + case Half: | |
355 | + case UnsignedByte: | |
356 | + ((ByteBuffer) buf1).put((ByteBuffer) buf2); | |
357 | + break; | |
358 | + case Short: | |
359 | + case UnsignedShort: | |
360 | + | |
361 | + ((ShortBuffer) buf1).put((ShortBuffer) buf2); | |
362 | + break; | |
363 | + | |
364 | + case Int: | |
365 | + case UnsignedInt: | |
366 | + ((IntBuffer) buf1).put((IntBuffer) buf2); | |
367 | + break; | |
368 | + case Float: | |
369 | + | |
370 | + ((FloatBuffer) buf1).put((FloatBuffer) buf2); | |
371 | + break; | |
372 | + case Double: | |
373 | + ((DoubleBuffer) buf1).put((DoubleBuffer) buf2); | |
374 | + break; | |
375 | + | |
376 | + default: | |
377 | + throw new UnsupportedOperationException("Unrecoginized buffer format: " + format); | |
378 | + } | |
379 | + } | |
380 | + | |
381 | + private static void putValue(VertexBuffer.Format format, Buffer buf1, Buffer buf2,int index) { | |
382 | + switch (format) { | |
383 | + case Byte: | |
384 | + case Half: | |
385 | + case UnsignedByte: | |
386 | + byte b = ((ByteBuffer) buf2).get(index); | |
387 | + ((ByteBuffer) buf1).put(b); | |
388 | + break; | |
389 | + case Short: | |
390 | + case UnsignedShort: | |
391 | + short s = ((ShortBuffer) buf2).get(index); | |
392 | + ((ShortBuffer) buf1).put(s); | |
393 | + break; | |
394 | + | |
395 | + case Int: | |
396 | + case UnsignedInt: | |
397 | + int i = ((IntBuffer) buf2).get(index); | |
398 | + ((IntBuffer) buf1).put(i); | |
399 | + break; | |
400 | + case Float: | |
401 | + float f = ((FloatBuffer) buf2).get(index); | |
402 | + ((FloatBuffer) buf1).put(f); | |
403 | + break; | |
404 | + case Double: | |
405 | + double d = ((DoubleBuffer) buf2).get(index); | |
406 | + ((DoubleBuffer) buf1).put(d); | |
407 | + break; | |
408 | + default: | |
409 | + throw new UnsupportedOperationException("Unrecoginized buffer format: " + format); | |
410 | + } | |
411 | + } | |
412 | + | |
413 | + private static List<VertexData> processTriangleStrip(Mesh mesh, | |
216 | 414 | int[] index, Vector3f[] v, Vector2f[] t) { |
217 | 415 | IndexBuffer indexBuffer = mesh.getIndexBuffer(); |
218 | 416 | FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData(); |
219 | 417 | FloatBuffer textureBuffer = (FloatBuffer) mesh.getBuffer(Type.TexCoord).getData(); |
220 | 418 | |
221 | - VertexData[] vertices = initVertexData(vertexBuffer.limit() / 3); | |
419 | + List<VertexData> vertices = initVertexData(vertexBuffer.limit() / 3); | |
222 | 420 | |
223 | 421 | index[0] = indexBuffer.get(0); |
224 | 422 | index[1] = indexBuffer.get(1); |
@@ -238,9 +436,9 @@ public class TangentBinormalGenerator { | ||
238 | 436 | TriangleData triData = processTriangle(index, v, t); |
239 | 437 | |
240 | 438 | if (triData != null && !isDegenerate) { |
241 | - vertices[index[0]].triangles.add(triData); | |
242 | - vertices[index[1]].triangles.add(triData); | |
243 | - vertices[index[2]].triangles.add(triData); | |
439 | + vertices.get(index[0]).triangles.add(triData); | |
440 | + vertices.get(index[1]).triangles.add(triData); | |
441 | + vertices.get(index[2]).triangles.add(triData); | |
244 | 442 | } |
245 | 443 | |
246 | 444 | Vector3f vTemp = v[0]; |
@@ -260,13 +458,13 @@ public class TangentBinormalGenerator { | ||
260 | 458 | return vertices; |
261 | 459 | } |
262 | 460 | |
263 | - private static VertexData[] processTriangleFan(Mesh mesh, | |
461 | + private static List<VertexData> processTriangleFan(Mesh mesh, | |
264 | 462 | int[] index, Vector3f[] v, Vector2f[] t) { |
265 | 463 | IndexBuffer indexBuffer = mesh.getIndexBuffer(); |
266 | 464 | FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData(); |
267 | 465 | FloatBuffer textureBuffer = (FloatBuffer) mesh.getBuffer(Type.TexCoord).getData(); |
268 | 466 | |
269 | - VertexData[] vertices = initVertexData(vertexBuffer.limit() / 3); | |
467 | + List<VertexData> vertices = initVertexData(vertexBuffer.limit() / 3); | |
270 | 468 | |
271 | 469 | index[0] = indexBuffer.get(0); |
272 | 470 | index[1] = indexBuffer.get(1); |
@@ -284,9 +482,9 @@ public class TangentBinormalGenerator { | ||
284 | 482 | |
285 | 483 | TriangleData triData = processTriangle(index, v, t); |
286 | 484 | if (triData != null) { |
287 | - vertices[index[0]].triangles.add(triData); | |
288 | - vertices[index[1]].triangles.add(triData); | |
289 | - vertices[index[2]].triangles.add(triData); | |
485 | + vertices.get(index[0]).triangles.add(triData); | |
486 | + vertices.get(index[1]).triangles.add(triData); | |
487 | + vertices.get(index[2]).triangles.add(triData); | |
290 | 488 | } |
291 | 489 | |
292 | 490 | Vector3f vTemp = v[1]; |
@@ -379,7 +577,6 @@ public class TangentBinormalGenerator { | ||
379 | 577 | "The angle must be between 0 and 179 degrees."); |
380 | 578 | } |
381 | 579 | toleranceDot = FastMath.cos(angle * FastMath.DEG_TO_RAD); |
382 | - toleranceAngle = angle; | |
383 | 580 | } |
384 | 581 | |
385 | 582 |
@@ -415,18 +612,20 @@ public class TangentBinormalGenerator { | ||
415 | 612 | populateFromBuffer(texCoord, texcoordBuffer, i); |
416 | 613 | |
417 | 614 | boolean found = false; |
418 | - | |
419 | - for (int j = 0; j < vertexMap.size(); j++) { | |
420 | - VertexInfo vertexInfo = vertexMap.get(j); | |
421 | - if (approxEqual(vertexInfo.position, position) && | |
422 | - approxEqual(vertexInfo.normal, normal) && | |
423 | - approxEqual(vertexInfo.texCoord, texCoord)) | |
424 | - { | |
425 | - vertexInfo.indices.add(i); | |
426 | - found = true; | |
427 | - break; | |
428 | - } | |
429 | - } | |
615 | + //Nehon 07/07/2013 | |
616 | + //Removed this part, joining splitted vertice to compute tangent space makes no sense to me | |
617 | + //separate vertice should have separate tangent space | |
618 | +// for (int j = 0; j < vertexMap.size(); j++) { | |
619 | +// VertexInfo vertexInfo = vertexMap.get(j); | |
620 | +// if (approxEqual(vertexInfo.position, position) && | |
621 | +// approxEqual(vertexInfo.normal, normal) && | |
622 | +// approxEqual(vertexInfo.texCoord, texCoord)) | |
623 | +// { | |
624 | +// vertexInfo.indices.add(i); | |
625 | +// found = true; | |
626 | +// break; | |
627 | +// } | |
628 | +// } | |
430 | 629 | |
431 | 630 | if (!found) { |
432 | 631 | VertexInfo vertexInfo = new VertexInfo(position.clone(), normal.clone(), texCoord.clone()); |
@@ -438,43 +637,44 @@ public class TangentBinormalGenerator { | ||
438 | 637 | return vertexMap; |
439 | 638 | } |
440 | 639 | |
441 | - private static void processTriangleData(Mesh mesh, VertexData[] vertices, | |
442 | - boolean approxTangent) | |
443 | - { | |
640 | + private static void processTriangleData(Mesh mesh, List<VertexData> vertices, | |
641 | + boolean approxTangent) { | |
444 | 642 | ArrayList<VertexInfo> vertexMap = linkVertices(mesh); |
445 | - | |
446 | - // FloatBuffer normalBuffer = (FloatBuffer) mesh.getBuffer(Type.Normal).getData(); | |
447 | - | |
448 | - FloatBuffer tangents = BufferUtils.createFloatBuffer(vertices.length * 4); | |
449 | -// FloatBuffer binormals = BufferUtils.createFloatBuffer(vertices.length * 3); | |
643 | + | |
644 | + FloatBuffer tangents = BufferUtils.createFloatBuffer(vertices.size() * 4); | |
645 | + | |
646 | + ColorRGBA[] cols = null; | |
647 | + if (debug) { | |
648 | + cols = new ColorRGBA[vertices.size()]; | |
649 | + } | |
450 | 650 | |
451 | 651 | Vector3f tangent = new Vector3f(); |
452 | 652 | Vector3f binormal = new Vector3f(); |
453 | 653 | //Vector3f normal = new Vector3f(); |
454 | 654 | Vector3f givenNormal = new Vector3f(); |
455 | - | |
655 | + | |
456 | 656 | Vector3f tangentUnit = new Vector3f(); |
457 | 657 | Vector3f binormalUnit = new Vector3f(); |
458 | - | |
658 | + | |
459 | 659 | for (int k = 0; k < vertexMap.size(); k++) { |
460 | 660 | float wCoord = -1; |
461 | - | |
661 | + | |
462 | 662 | VertexInfo vertexInfo = vertexMap.get(k); |
463 | - | |
663 | + | |
464 | 664 | givenNormal.set(vertexInfo.normal); |
465 | 665 | givenNormal.normalizeLocal(); |
466 | - | |
467 | - TriangleData firstTriangle = vertices[vertexInfo.indices.get(0)].triangles.get(0); | |
666 | + | |
667 | + TriangleData firstTriangle = vertices.get(vertexInfo.indices.get(0)).triangles.get(0); | |
468 | 668 | |
469 | 669 | // check tangent and binormal consistency |
470 | 670 | tangent.set(firstTriangle.tangent); |
471 | 671 | tangent.normalizeLocal(); |
472 | 672 | binormal.set(firstTriangle.binormal); |
473 | 673 | binormal.normalizeLocal(); |
474 | - | |
674 | + | |
475 | 675 | for (int i : vertexInfo.indices) { |
476 | - ArrayList<TriangleData> triangles = vertices[i].triangles; | |
477 | - | |
676 | + ArrayList<TriangleData> triangles = vertices.get(i).triangles; | |
677 | + | |
478 | 678 | for (int j = 0; j < triangles.size(); j++) { |
479 | 679 | TriangleData triangleData = triangles.get(j); |
480 | 680 |
@@ -499,40 +699,31 @@ public class TangentBinormalGenerator { | ||
499 | 699 | } |
500 | 700 | } |
501 | 701 | } |
502 | - | |
503 | - | |
702 | + | |
703 | + | |
504 | 704 | // find average tangent |
505 | 705 | tangent.set(0, 0, 0); |
506 | 706 | binormal.set(0, 0, 0); |
507 | - | |
707 | + | |
508 | 708 | int triangleCount = 0; |
509 | 709 | for (int i : vertexInfo.indices) { |
510 | - ArrayList<TriangleData> triangles = vertices[i].triangles; | |
710 | + ArrayList<TriangleData> triangles = vertices.get(i).triangles; | |
511 | 711 | triangleCount += triangles.size(); |
512 | - | |
513 | - // boolean flippedNormal = false; | |
712 | + if (debug) { | |
713 | + cols[i] = ColorRGBA.White; | |
714 | + } | |
715 | + | |
514 | 716 | for (int j = 0; j < triangles.size(); j++) { |
515 | 717 | TriangleData triangleData = triangles.get(j); |
516 | 718 | tangent.addLocal(triangleData.tangent); |
517 | 719 | binormal.addLocal(triangleData.binormal); |
518 | 720 | |
519 | -// if (givenNormal.dot(triangleData.normal) < 0) { | |
520 | -// flippedNormal = true; | |
521 | -// } | |
522 | 721 | } |
523 | -// if (flippedNormal /*&& approxTangent*/) { | |
524 | -// // Generated normal is flipped for this vertex, | |
525 | -// // so binormal = normal.cross(tangent) will be flipped in the shader | |
526 | -// // log.log(Level.WARNING, | |
527 | -// // "Binormal is flipped for vertex {0}.", i); | |
528 | -// | |
529 | -// wCoord = 1; | |
530 | -// } | |
531 | 722 | } |
532 | 723 | |
533 | - | |
724 | + | |
534 | 725 | int blameVertex = vertexInfo.indices.get(0); |
535 | - | |
726 | + | |
536 | 727 | if (tangent.length() < ZERO_TOLERANCE) { |
537 | 728 | log.log(Level.WARNING, |
538 | 729 | "Shared tangent is zero for vertex {0}.", blameVertex); |
@@ -587,21 +778,21 @@ public class TangentBinormalGenerator { | ||
587 | 778 | "Tangent and binormal are parallel for vertex {0}.", blameVertex); |
588 | 779 | } |
589 | 780 | } |
590 | - | |
781 | + | |
591 | 782 | Vector3f finalTangent = new Vector3f(); |
592 | 783 | Vector3f tmp = new Vector3f(); |
593 | 784 | for (int i : vertexInfo.indices) { |
594 | 785 | if (approxTangent) { |
595 | 786 | // Gram-Schmidt orthogonalize |
596 | - finalTangent.set(tangent).subtractLocal(tmp.set(givenNormal).multLocal(givenNormal.dot(tangent))); | |
787 | + finalTangent.set(tangent).subtractLocal(tmp.set(givenNormal).multLocal(givenNormal.dot(tangent))); | |
597 | 788 | finalTangent.normalizeLocal(); |
598 | - | |
599 | - wCoord = tmp.set(givenNormal).crossLocal(tangent).dot(binormal) <0f? -1f:1f; | |
789 | + | |
790 | + wCoord = tmp.set(givenNormal).crossLocal(tangent).dot(binormal) < 0f ? -1f : 1f; | |
600 | 791 | |
601 | 792 | tangents.put((i * 4), finalTangent.x); |
602 | 793 | tangents.put((i * 4) + 1, finalTangent.y); |
603 | 794 | tangents.put((i * 4) + 2, finalTangent.z); |
604 | - tangents.put((i * 4) + 3, wCoord); | |
795 | + tangents.put((i * 4) + 3, wCoord); | |
605 | 796 | } else { |
606 | 797 | tangents.put((i * 4), tangent.x); |
607 | 798 | tangents.put((i * 4) + 1, tangent.y); |
@@ -612,13 +803,49 @@ public class TangentBinormalGenerator { | ||
612 | 803 | } |
613 | 804 | } |
614 | 805 | } |
615 | - | |
806 | + tangents.limit(tangents.capacity()); | |
616 | 807 | // If the model already had a tangent buffer, replace it with the regenerated one |
617 | - mesh.clearBuffer(Type.Tangent); | |
808 | + mesh.clearBuffer(Type.Tangent); | |
618 | 809 | mesh.setBuffer(Type.Tangent, 4, tangents); |
619 | -// if (!approxTangent) mesh.setBuffer(Type.Binormal, 3, binormals); | |
620 | - } | |
810 | + | |
811 | + | |
812 | + | |
813 | + if(mesh.isAnimated()){ | |
814 | + mesh.clearBuffer(Type.BindPoseNormal); | |
815 | + mesh.clearBuffer(Type.BindPosePosition); | |
816 | + mesh.clearBuffer(Type.BindPoseTangent); | |
817 | + mesh.generateBindPose(true); | |
818 | + } | |
819 | + | |
820 | + if (debug) { | |
821 | + writeColorBuffer( vertices, cols, mesh); | |
822 | + } | |
823 | + mesh.updateBound(); | |
824 | + mesh.updateCounts(); | |
825 | + } | |
621 | 826 | |
827 | + private static void writeColorBuffer(List<VertexData> vertices, ColorRGBA[] cols, Mesh mesh) { | |
828 | + FloatBuffer colors = BufferUtils.createFloatBuffer(vertices.size() * 4); | |
829 | + colors.rewind(); | |
830 | + for (ColorRGBA color : cols) { | |
831 | + colors.put(color.r); | |
832 | + colors.put(color.g); | |
833 | + colors.put(color.b); | |
834 | + colors.put(color.a); | |
835 | + } | |
836 | + mesh.clearBuffer(Type.Color); | |
837 | + mesh.setBuffer(Type.Color, 4, colors); | |
838 | + } | |
839 | + | |
840 | + private static int parity(Vector3f n1, Vector3f n) { | |
841 | + if (n1.dot(n) < 0) { | |
842 | + return -1; | |
843 | + } else { | |
844 | + return 1; | |
845 | + } | |
846 | + | |
847 | + } | |
848 | + | |
622 | 849 | public static Mesh genTbnLines(Mesh mesh, float scale) { |
623 | 850 | if (mesh.getBuffer(Type.Tangent) == null) { |
624 | 851 | return genNormalLines(mesh, scale); |