293
301
* Exports the given Java 3D <code>node</code> and its children to Sunflow API.
295
303
private void exportNode(Node node, boolean noConstantShader) throws IOException {
296
exportNode(node, node, noConstantShader);
304
exportNode(node, noConstantShader, new Transform3D());
300
308
* Exports all the 3D shapes children of <code>node</code> at OBJ format.
302
private void exportNode(Node parent, Node node,
303
boolean noConstantShader) throws IOException {
310
private void exportNode(Node node,
311
boolean noConstantShader,
312
Transform3D parentTransformations) throws IOException {
304
313
if (node instanceof Group) {
314
if (node instanceof TransformGroup) {
315
parentTransformations = new Transform3D(parentTransformations);
316
Transform3D transform = new Transform3D();
317
((TransformGroup)node).getTransform(transform);
318
parentTransformations.mul(transform);
305
320
// Export all children
306
321
Enumeration<?> enumeration = ((Group)node).getAllChildren();
307
322
while (enumeration.hasMoreElements()) {
308
exportNode(parent, (Node)enumeration.nextElement(), noConstantShader);
323
exportNode((Node)enumeration.nextElement(), noConstantShader, parentTransformations);
325
} else if (node instanceof Link) {
326
exportNode(((Link)node).getSharedGroup(), noConstantShader, parentTransformations);
310
327
} else if (node instanceof Shape3D) {
311
328
Shape3D shape = (Shape3D)node;
312
329
Appearance appearance = shape.getAppearance();
330
344
&& shapeName.startsWith(ModelManager.MIRROR_SHAPE_PREFIX);
331
345
exportAppearance(appearance, appearanceName, mirror, noConstantShader);
348
int cullFace = PolygonAttributes.CULL_BACK;
349
boolean backFaceNormalFlip = false;
350
if (appearance != null) {
351
PolygonAttributes polygonAttributes = appearance.getPolygonAttributes();
352
if (polygonAttributes != null) {
353
cullFace = polygonAttributes.getCullFace();
354
backFaceNormalFlip = polygonAttributes.getBackFaceNormalFlip();
334
358
// Export object geometries
335
359
for (int i = 0, n = shape.numGeometries(); i < n; i++) {
336
String objectName = "object" + uuid + "-" + i;
360
String objectNameBase = "object" + uuid + "-" + i;
337
361
// Always ignore normals on walls
338
exportNodeGeometry(shape.getGeometry(i), transformationToParent, texCoordGeneration, objectName);
339
if (appearanceName != null) {
340
this.sunflow.parameter("shaders", new String [] {appearanceName});
362
String [] objectsName = exportNodeGeometry(shape.getGeometry(i), parentTransformations, texCoordGeneration,
363
objectNameBase, cullFace, backFaceNormalFlip);
364
if (objectsName != null) {
365
for (String objectName : objectsName) {
366
if (appearanceName != null) {
367
this.sunflow.parameter("shaders", new String [] {appearanceName});
369
this.sunflow.instance(objectName + ".instance", objectName);
342
this.sunflow.instance(objectName + ".instance", objectName);
349
* Returns the transformation applied to a <code>child</code>
350
* on the path to <code>parent</code>.
352
private Transform3D getTransformationToParent(Node parent, Node child) {
353
Transform3D transform = new Transform3D();
354
if (child instanceof TransformGroup) {
355
((TransformGroup)child).getTransform(transform);
357
if (child != parent) {
358
Transform3D parentTransform = getTransformationToParent(parent, child.getParent());
359
parentTransform.mul(transform);
360
return parentTransform;
367
* Exports a 3D geometry in Sunflow API.
369
private void exportNodeGeometry(Geometry geometry, Transform3D transformationToParent,
370
TexCoordGeneration texCoordGeneration,
378
* Returns the names of the exported 3D geometries in Sunflow API.
380
private String [] exportNodeGeometry(Geometry geometry,
381
Transform3D parentTransformations,
382
TexCoordGeneration texCoordGeneration,
383
String objectNameBase,
385
boolean backFaceNormalFlip) {
372
386
if (geometry instanceof GeometryArray) {
373
387
GeometryArray geometryArray = (GeometryArray)geometry;
375
389
// Create vertices indices array depending on geometry class
376
390
int [] verticesIndices = null;
377
391
int [] stripVertexCount = null;
392
int cullFaceMultiplier = cullFace == PolygonAttributes.CULL_NONE ? 2 : 1;
378
393
if (geometryArray instanceof IndexedGeometryArray) {
379
if (geometryArray instanceof IndexedTriangleArray) {
380
verticesIndices = new int [((IndexedTriangleArray)geometryArray).getIndexCount()];
394
if (geometryArray instanceof IndexedLineArray) {
395
verticesIndices = new int [((IndexedGeometryArray)geometryArray).getIndexCount()];
396
} else if (geometryArray instanceof IndexedTriangleArray) {
397
verticesIndices = new int [((IndexedGeometryArray)geometryArray).getIndexCount() * cullFaceMultiplier];
381
398
} else if (geometryArray instanceof IndexedQuadArray) {
382
verticesIndices = new int [((IndexedQuadArray)geometryArray).getIndexCount() * 3 / 2];
383
} else if (geometryArray instanceof IndexedTriangleStripArray) {
384
IndexedTriangleStripArray triangleStripArray = (IndexedTriangleStripArray)geometryArray;
385
stripVertexCount = new int [triangleStripArray.getNumStrips()];
386
triangleStripArray.getStripIndexCounts(stripVertexCount);
387
verticesIndices = new int [getTriangleCount(stripVertexCount) * 3];
388
} else if (geometryArray instanceof IndexedTriangleFanArray) {
389
IndexedTriangleFanArray triangleFanArray = (IndexedTriangleFanArray)geometryArray;
390
stripVertexCount = new int [triangleFanArray.getNumStrips()];
391
triangleFanArray.getStripIndexCounts(stripVertexCount);
392
verticesIndices = new int [getTriangleCount(stripVertexCount) * 3];
399
verticesIndices = new int [((IndexedQuadArray)geometryArray).getIndexCount() * 3 / 2 * cullFaceMultiplier];
400
} else if (geometryArray instanceof IndexedGeometryStripArray) {
401
IndexedTriangleStripArray geometryStripArray = (IndexedTriangleStripArray)geometryArray;
402
stripVertexCount = new int [geometryStripArray.getNumStrips()];
403
geometryStripArray.getStripIndexCounts(stripVertexCount);
404
if (geometryArray instanceof IndexedLineStripArray) {
405
verticesIndices = new int [getLineCount(stripVertexCount) * 2];
407
verticesIndices = new int [getTriangleCount(stripVertexCount) * 3 * cullFaceMultiplier];
395
if (geometryArray instanceof TriangleArray) {
396
verticesIndices = new int [((TriangleArray)geometryArray).getVertexCount()];
411
if (geometryArray instanceof LineArray) {
412
verticesIndices = new int [((GeometryArray)geometryArray).getVertexCount()];
413
} else if (geometryArray instanceof TriangleArray) {
414
verticesIndices = new int [((GeometryArray)geometryArray).getVertexCount() * cullFaceMultiplier];
397
415
} else if (geometryArray instanceof QuadArray) {
398
verticesIndices = new int [((QuadArray)geometryArray).getVertexCount() * 3 / 2];
399
} else if (geometryArray instanceof TriangleStripArray) {
400
TriangleStripArray triangleStripArray = (TriangleStripArray)geometryArray;
401
stripVertexCount = new int [triangleStripArray.getNumStrips()];
402
triangleStripArray.getStripVertexCounts(stripVertexCount);
403
verticesIndices = new int [getTriangleCount(stripVertexCount) * 3];
404
} else if (geometryArray instanceof TriangleFanArray) {
405
TriangleFanArray triangleFanArray = (TriangleFanArray)geometryArray;
406
stripVertexCount = new int [triangleFanArray.getNumStrips()];
407
triangleFanArray.getStripVertexCounts(stripVertexCount);
408
verticesIndices = new int [getTriangleCount(stripVertexCount) * 3];
416
verticesIndices = new int [((QuadArray)geometryArray).getVertexCount() * 3 / 2 * cullFaceMultiplier];
417
} else if (geometryArray instanceof GeometryStripArray) {
418
GeometryStripArray geometryStripArray = (GeometryStripArray)geometryArray;
419
stripVertexCount = new int [geometryStripArray.getNumStrips() * cullFaceMultiplier];
420
geometryStripArray.getStripVertexCounts(stripVertexCount);
421
if (geometryArray instanceof LineStripArray) {
422
verticesIndices = new int [getLineCount(stripVertexCount) * 2];
424
verticesIndices = new int [getTriangleCount(stripVertexCount) * 3 * cullFaceMultiplier];
412
429
if (verticesIndices != null) {
430
boolean line = geometryArray instanceof IndexedLineArray
431
|| geometryArray instanceof IndexedLineStripArray
432
|| geometryArray instanceof LineArray
433
|| geometryArray instanceof LineStripArray;
413
434
float [] vertices = new float [geometryArray.getVertexCount() * 3];
415
float [] normals = (geometryArray.getVertexFormat() & GeometryArray.NORMALS) != 0
416
? new float [geometryArray.getVertexCount() * 3]
435
float [] normals = !line && (geometryArray.getVertexFormat() & GeometryArray.NORMALS) != 0
436
? new float [geometryArray.getVertexCount() * 3 * cullFaceMultiplier]
419
439
boolean uvsGenerated = false;
420
440
Vector4f planeS = null;
421
441
Vector4f planeT = null;
422
if (texCoordGeneration != null) {
442
if (!line && texCoordGeneration != null) {
423
443
uvsGenerated = texCoordGeneration.getGenMode() == TexCoordGeneration.OBJECT_LINEAR
424
444
&& texCoordGeneration.getEnable();
425
445
if (uvsGenerated) {
549
569
? new int [verticesIndices.length]
552
if (geometryArray instanceof IndexedTriangleArray) {
572
if (geometryArray instanceof IndexedLineArray) {
573
IndexedLineArray lineArray = (IndexedLineArray)geometryArray;
574
for (int i = 0, n = lineArray.getIndexCount(); i < n; i += 2) {
575
exportIndexedLine(lineArray, i, i + 1, verticesIndices, i);
577
} else if (geometryArray instanceof IndexedTriangleArray) {
553
578
IndexedTriangleArray triangleArray = (IndexedTriangleArray)geometryArray;
554
579
for (int i = 0, n = triangleArray.getIndexCount(); i < n; i += 3) {
555
580
exportIndexedTriangle(triangleArray, i, i + 1, i + 2,
556
verticesIndices, normalsIndices, uvsIndices, i);
581
verticesIndices, normalsIndices, uvsIndices, i, 0, cullFace);
558
583
} else if (geometryArray instanceof IndexedQuadArray) {
559
584
IndexedQuadArray quadArray = (IndexedQuadArray)geometryArray;
560
585
for (int i = 0, n = quadArray.getIndexCount(); i < n; i += 4) {
561
586
exportIndexedTriangle(quadArray, i, i + 1, i + 2,
562
verticesIndices, normalsIndices, uvsIndices, i * 3 / 2);
587
verticesIndices, normalsIndices, uvsIndices, i * 3 / 2, 0, cullFace);
563
588
exportIndexedTriangle(quadArray, i, i + 2, i + 3,
564
verticesIndices, normalsIndices, uvsIndices, i * 3 / 2 + 3);
589
verticesIndices, normalsIndices, uvsIndices, i * 3 / 2 + 3, 0, cullFace);
591
} else if (geometryArray instanceof IndexedLineStripArray) {
592
IndexedLineStripArray lineStripArray = (IndexedLineStripArray)geometryArray;
593
for (int initialIndex = 0, lineIndex = 0, strip = 0; strip < stripVertexCount.length; strip++) {
594
for (int i = initialIndex, n = initialIndex + stripVertexCount [strip] - 1;
595
i < n; i++, lineIndex += 2) {
596
exportIndexedLine(lineStripArray, i, i + 1, verticesIndices, lineIndex);
598
initialIndex += stripVertexCount [strip];
566
600
} else if (geometryArray instanceof IndexedTriangleStripArray) {
567
601
IndexedTriangleStripArray triangleStripArray = (IndexedTriangleStripArray)geometryArray;
630
if (geometryArray instanceof TriangleArray) {
664
if (geometryArray instanceof LineArray) {
665
LineArray lineArray = (LineArray)geometryArray;
666
for (int i = 0, n = lineArray.getVertexCount(); i < n; i += 2) {
667
exportLine(lineArray, i, i + 1, verticesIndices, i);
669
} else if (geometryArray instanceof TriangleArray) {
631
670
TriangleArray triangleArray = (TriangleArray)geometryArray;
632
671
for (int i = 0, n = triangleArray.getVertexCount(); i < n; i += 3) {
633
exportTriangle(triangleArray, i, i + 1, i + 2, verticesIndices, i);
672
exportTriangle(triangleArray, i, i + 1, i + 2, verticesIndices, i, cullFace);
635
674
} else if (geometryArray instanceof QuadArray) {
636
675
QuadArray quadArray = (QuadArray)geometryArray;
637
676
for (int i = 0, n = quadArray.getVertexCount(); i < n; i += 4) {
638
exportTriangle(quadArray, i, i + 1, i + 2, verticesIndices, i * 3 / 2);
639
exportTriangle(quadArray, i + 2, i + 3, i, verticesIndices, i * 3 / 2 + 3);
677
exportTriangle(quadArray, i, i + 1, i + 2, verticesIndices, i * 3 / 2, cullFace);
678
exportTriangle(quadArray, i + 2, i + 3, i, verticesIndices, i * 3 / 2 + 3, cullFace);
680
} else if (geometryArray instanceof LineStripArray) {
681
LineStripArray lineStripArray = (LineStripArray)geometryArray;
682
for (int initialIndex = 0, lineIndex = 0, strip = 0; strip < stripVertexCount.length; strip++) {
683
for (int i = initialIndex, n = initialIndex + stripVertexCount [strip] - 1;
684
i < n; i++, lineIndex += 2) {
685
exportLine(lineStripArray, i, i + 1, verticesIndices, lineIndex);
687
initialIndex += stripVertexCount [strip];
641
689
} else if (geometryArray instanceof TriangleStripArray) {
642
690
TriangleStripArray triangleStripArray = (TriangleStripArray)geometryArray;
656
704
for (int initialIndex = 0, triangleIndex = 0, strip = 0; strip < stripVertexCount.length; strip++) {
657
705
for (int i = initialIndex, n = initialIndex + stripVertexCount [strip] - 2;
658
706
i < n; i++, triangleIndex += 3) {
659
exportTriangle(triangleFanArray, initialIndex, i + 1, i + 2, verticesIndices, triangleIndex);
707
exportTriangle(triangleFanArray, initialIndex, i + 1, i + 2, verticesIndices, triangleIndex, cullFace);
661
709
initialIndex += stripVertexCount [strip];
666
this.sunflow.parameter("triangles", verticesIndices);
667
this.sunflow.parameter("points", "point", "vertex", vertices);
668
if (normals != null) {
669
this.sunflow.parameter("normals", "vector", "vertex", normals);
672
this.sunflow.parameter("uvs", "texcoord", "vertex", uvs);
674
this.sunflow.geometry(objectName, "triangle_mesh");
715
String [] objectNames = new String [verticesIndices.length / 2];
716
for (int startIndex = 0; startIndex < verticesIndices.length; startIndex += 2) {
717
String objectName = objectNameBase + "-" + startIndex;
718
objectNames [startIndex / 2] = objectName;
720
// Get points coordinates of a segment
721
float [] points = new float [6];
723
for (int i = startIndex; i <= startIndex + 1; i++) {
724
int indirectIndex = verticesIndices [i] * 3;
725
points [pointIndex++] = vertices [indirectIndex++];
726
points [pointIndex++] = vertices [indirectIndex++];
727
points [pointIndex++] = vertices [indirectIndex];
730
// Create as many hairs as segments otherwise long hairs become invisible
731
this.sunflow.parameter("segments", 1);
732
this.sunflow.parameter("widths", 0.15f);
733
this.sunflow.parameter("points", "point", "vertex", points);
734
this.sunflow.geometry(objectName, "hair");
738
this.sunflow.parameter("triangles", verticesIndices);
739
this.sunflow.parameter("points", "point", "vertex", vertices);
740
if (normals != null) {
741
this.sunflow.parameter("normals", "vector", "vertex", normals);
744
this.sunflow.parameter("uvs", "texcoord", "vertex", uvs);
746
this.sunflow.geometry(objectNameBase, "triangle_mesh");
747
return new String [] {objectNameBase};
738
* Stores in <code>triangles</code> the indices given at vertexIndex1, vertexIndex2, vertexIndex3.
837
* Stores in <code>verticesIndices</code> the indices given at vertexIndex1, vertexIndex2.
839
private void exportIndexedLine(IndexedGeometryArray geometryArray,
840
int vertexIndex1, int vertexIndex2,
841
int [] verticesIndices,
843
verticesIndices [index++] = geometryArray.getCoordinateIndex(vertexIndex1);
844
verticesIndices [index] = geometryArray.getCoordinateIndex(vertexIndex2);
848
* Stores in <code>verticesIndices</code> the indices given at vertexIndex1, vertexIndex2, vertexIndex3.
740
850
private void exportIndexedTriangle(IndexedGeometryArray geometryArray,
741
851
int vertexIndex1, int vertexIndex2, int vertexIndex3,
742
852
int [] verticesIndices, int [] normalsIndices, int [] textureCoordinatesIndices,
854
int normalIndexOffset,
856
if (cullFace == PolygonAttributes.CULL_FRONT) {
857
// Reverse vertex order
858
int tmp = vertexIndex1;
859
vertexIndex1 = vertexIndex3;
744
863
verticesIndices [index] = geometryArray.getCoordinateIndex(vertexIndex1);
745
864
verticesIndices [index + 1] = geometryArray.getCoordinateIndex(vertexIndex2);
746
865
verticesIndices [index + 2] = geometryArray.getCoordinateIndex(vertexIndex3);
747
866
if (normalsIndices != null) {
748
normalsIndices [index] = geometryArray.getNormalIndex(vertexIndex1);
749
normalsIndices [index + 1] = geometryArray.getNormalIndex(vertexIndex2);
750
normalsIndices [index + 2] = geometryArray.getNormalIndex(vertexIndex3);
867
normalsIndices [index] = normalIndexOffset + geometryArray.getNormalIndex(vertexIndex1);
868
normalsIndices [index + 1] = normalIndexOffset + geometryArray.getNormalIndex(vertexIndex2);
869
normalsIndices [index + 2] = normalIndexOffset + geometryArray.getNormalIndex(vertexIndex3);
752
871
if (textureCoordinatesIndices != null) {
753
872
textureCoordinatesIndices [index] = geometryArray.getTextureCoordinateIndex(0, vertexIndex1);
754
873
textureCoordinatesIndices [index + 1] = geometryArray.getTextureCoordinateIndex(0, vertexIndex2);
755
874
textureCoordinatesIndices [index + 2] = geometryArray.getTextureCoordinateIndex(0, vertexIndex3);
760
* Stores in <code>triangles</code> the indices vertexIndex1, vertexIndex2, vertexIndex3.
877
if (cullFace == PolygonAttributes.CULL_NONE) {
878
exportIndexedTriangle(geometryArray, vertexIndex1, vertexIndex2, vertexIndex3,
879
verticesIndices, normalsIndices, textureCoordinatesIndices,
880
index + verticesIndices.length / 2, normalsIndices != null ? normalsIndices.length / 2 : 0,
881
PolygonAttributes.CULL_FRONT);
886
* Stores in <code>verticesIndices</code> the indices vertexIndex1, vertexIndex2, vertexIndex3.
888
private void exportLine(GeometryArray geometryArray,
889
int vertexIndex1, int vertexIndex2,
890
int [] verticesIndices, int index) {
891
verticesIndices [index++] = vertexIndex1;
892
verticesIndices [index] = vertexIndex2;
896
* Stores in <code>verticesIndices</code> the indices vertexIndex1, vertexIndex2, vertexIndex3.
762
898
private void exportTriangle(GeometryArray geometryArray,
763
899
int vertexIndex1, int vertexIndex2, int vertexIndex3,
764
int [] verticesIndices, int index) {
765
verticesIndices [index++] = vertexIndex1;
766
verticesIndices [index++] = vertexIndex2;
767
verticesIndices [index] = vertexIndex3;
900
int [] verticesIndices, int index,
902
if (cullFace == PolygonAttributes.CULL_FRONT) {
903
// Reverse vertex order
904
int tmp = vertexIndex1;
905
vertexIndex1 = vertexIndex3;
909
verticesIndices [index] = vertexIndex1;
910
verticesIndices [index + 1] = vertexIndex2;
911
verticesIndices [index + 2] = vertexIndex3;
913
if (cullFace == PolygonAttributes.CULL_NONE) {
914
exportTriangle(geometryArray, vertexIndex1, vertexIndex2, vertexIndex3,
915
verticesIndices, index + verticesIndices.length / 2, PolygonAttributes.CULL_FRONT);