From 550063367e8503aa3885b8e7a8d53398d7d7b719 Mon Sep 17 00:00:00 2001 From: kaelthas Date: Thu, 6 Nov 2014 20:21:04 +0100 Subject: [PATCH] Bugfix: fixed issues with subdivision surface modifier. --- .../plugins/blender/meshes/TemporalMesh.java | 32 +++++++------ .../modifiers/SubdivisionSurfaceModifier.java | 47 +++++++++++++------ 2 files changed, 50 insertions(+), 29 deletions(-) diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/meshes/TemporalMesh.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/meshes/TemporalMesh.java index ee899d268..c359f6219 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/meshes/TemporalMesh.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/meshes/TemporalMesh.java @@ -4,11 +4,14 @@ import java.nio.IntBuffer; import java.nio.ShortBuffer; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; @@ -71,9 +74,10 @@ public class TemporalMesh extends Geometry { protected List edges = new ArrayList(); /** The points of the mesh. */ protected List points = new ArrayList(); - - protected Map> indexToFaceMapping = new HashMap>(); - protected Map> indexToEdgeMapping = new HashMap>(); + /** A map between index and faces that contain it (for faster index - face queries). */ + protected Map> indexToFaceMapping = new HashMap>(); + /** A map between index and edges that contain it (for faster index - edge queries). */ + protected Map> indexToEdgeMapping = new HashMap>(); /** The bounding box of the temporal mesh. */ protected BoundingBox boundingBox; @@ -183,7 +187,7 @@ public class TemporalMesh extends Geometry { /** * @return the faces that contain the given index or null if none contain it */ - public List getAdjacentFaces(Integer index) { + public Collection getAdjacentFaces(Integer index) { return indexToFaceMapping.get(index); } @@ -192,10 +196,10 @@ public class TemporalMesh extends Geometry { * edge of the mesh * @return a list of faces that contain the given edge or an empty list */ - public List getAdjacentFaces(Edge edge) { + public Collection getAdjacentFaces(Edge edge) { List result = new ArrayList(indexToFaceMapping.get(edge.getFirstIndex())); - List secondIndexAdjacentFaces = indexToFaceMapping.get(edge.getSecondIndex()); - if(secondIndexAdjacentFaces != null) { + Set secondIndexAdjacentFaces = indexToFaceMapping.get(edge.getSecondIndex()); + if (secondIndexAdjacentFaces != null) { result.retainAll(indexToFaceMapping.get(edge.getSecondIndex())); } return result; @@ -206,7 +210,7 @@ public class TemporalMesh extends Geometry { * index of the mesh * @return a list of edges that contain the index */ - public List getAdjacentEdges(Integer index) { + public Collection getAdjacentEdges(Integer index) { return indexToEdgeMapping.get(index); } @@ -229,7 +233,7 @@ public class TemporalMesh extends Geometry { * @return true if the index is a boundary one and false otherwise */ public boolean isBoundary(Integer index) { - List adjacentEdges = this.getAdjacentEdges(index); + Collection adjacentEdges = this.getAdjacentEdges(index); for (Edge edge : adjacentEdges) { if (this.isBoundary(edge)) { return true; @@ -287,24 +291,24 @@ public class TemporalMesh extends Geometry { indexToFaceMapping.clear(); for (Face face : faces) { for (Integer index : face.getIndexes()) { - List faces = indexToFaceMapping.get(index); + Set faces = indexToFaceMapping.get(index); if (faces == null) { - faces = new ArrayList(); + faces = new HashSet(); indexToFaceMapping.put(index, faces); } faces.add(face); } } for (Edge edge : edges) { - List edges = indexToEdgeMapping.get(edge.getFirstIndex()); + Set edges = indexToEdgeMapping.get(edge.getFirstIndex()); if (edges == null) { - edges = new ArrayList(); + edges = new HashSet(); indexToEdgeMapping.put(edge.getFirstIndex(), edges); } edges.add(edge); edges = indexToEdgeMapping.get(edge.getSecondIndex()); if (edges == null) { - edges = new ArrayList(); + edges = new HashSet(); indexToEdgeMapping.put(edge.getSecondIndex(), edges); } edges.add(edge); diff --git a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/modifiers/SubdivisionSurfaceModifier.java b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/modifiers/SubdivisionSurfaceModifier.java index cbd003ed5..2f3d12d60 100644 --- a/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/modifiers/SubdivisionSurfaceModifier.java +++ b/jme3-blender/src/main/java/com/jme3/scene/plugins/blender/modifiers/SubdivisionSurfaceModifier.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -41,8 +42,8 @@ public class SubdivisionSurfaceModifier extends Modifier { private int levels; /** Indicates if the UV's should also be subdivided. */ private boolean subdivideUVS; - - private List verticesOnOriginalEdges = new ArrayList(); + /** Stores the vertices that are located on original edges of the mesh. */ + private Set verticesOnOriginalEdges = new HashSet(); /** * Constructor loads all neccessary modifier data. @@ -77,7 +78,8 @@ public class SubdivisionSurfaceModifier extends Modifier { TemporalMesh temporalMesh = this.getTemporalMesh(node); if (temporalMesh != null) { LOGGER.log(Level.FINE, "Applying subdivision surface modifier to: {0}", temporalMesh); - + verticesOnOriginalEdges.clear();//in case the instance of this class was used more than once + for (Edge edge : temporalMesh.getEdges()) { verticesOnOriginalEdges.add(edge.getFirstIndex()); verticesOnOriginalEdges.add(edge.getSecondIndex()); @@ -109,10 +111,16 @@ public class SubdivisionSurfaceModifier extends Modifier { */ private void subdivideCatmullClark(TemporalMesh temporalMesh) { Set boundaryVertices = new HashSet(); - for (Face face : temporalMesh.getFaces()) { - for (Integer index : face.getIndexes()) { - if (temporalMesh.isBoundary(index)) { - boundaryVertices.add(index); + for (Edge edge : temporalMesh.getEdges()) { + if (!edge.isInFace()) { + boundaryVertices.add(edge.getFirstIndex()); + boundaryVertices.add(edge.getSecondIndex()); + } else { + if (temporalMesh.isBoundary(edge.getFirstIndex())) { + boundaryVertices.add(edge.getFirstIndex()); + } + if (temporalMesh.isBoundary(edge.getSecondIndex())) { + boundaryVertices.add(edge.getSecondIndex()); } } } @@ -160,7 +168,8 @@ public class SubdivisionSurfaceModifier extends Modifier { averageVert[edge.getFirstIndex()] = averageVert[edge.getFirstIndex()] == null ? centroid.clone() : averageVert[edge.getFirstIndex()].addLocal(centroid); averageVert[edge.getSecondIndex()] = averageVert[edge.getSecondIndex()] == null ? centroid.clone() : averageVert[edge.getSecondIndex()].addLocal(centroid); - averageCount[edge.getSecondIndex()] += 2; + averageCount[edge.getFirstIndex()] += 1; + averageCount[edge.getSecondIndex()] += 1; } } @@ -196,8 +205,8 @@ public class SubdivisionSurfaceModifier extends Modifier { private void subdivideSimple(TemporalMesh temporalMesh) { Map edgePoints = new HashMap(); Map facePoints = new HashMap(); - List newFaces = new ArrayList(); - List newEdges = new ArrayList(temporalMesh.getEdges().size() * 2); + Set newFaces = new LinkedHashSet(); + Set newEdges = new LinkedHashSet(temporalMesh.getEdges().size() * 4); int originalFacesCount = temporalMesh.getFaces().size(); @@ -240,7 +249,7 @@ public class SubdivisionSurfaceModifier extends Modifier { Vector3f v = temporalMesh.getVertices().get(vIndex); if (vPrevEdgeVertIndex < 0) { vPrevEdgeVertIndex = vertices.size() + originalFacesCount + edgeVertices.size(); - verticesOnOriginalEdges.add(vNextEdgeVertIndex); + verticesOnOriginalEdges.add(vPrevEdgeVertIndex); edgeVertices.add(vertices.get(vPrevIndex).add(v).divideLocal(2)); edgeNormals.add(normals.get(vPrevIndex).add(normals.get(vIndex)).normalizeLocal()); edgePoints.put(prevEdge, vPrevEdgeVertIndex); @@ -250,7 +259,7 @@ public class SubdivisionSurfaceModifier extends Modifier { } if (vNextEdgeVertIndex < 0) { vNextEdgeVertIndex = vertices.size() + originalFacesCount + edgeVertices.size(); - verticesOnOriginalEdges.add(vPrevEdgeVertIndex); + verticesOnOriginalEdges.add(vNextEdgeVertIndex); edgeVertices.add(vertices.get(vNextIndex).add(v).divideLocal(2)); edgeNormals.add(normals.get(vNextIndex).add(normals.get(vIndex)).normalizeLocal()); edgePoints.put(nextEdge, vNextEdgeVertIndex); @@ -312,8 +321,9 @@ public class SubdivisionSurfaceModifier extends Modifier { vertices.add(vertices.get(edge.getFirstIndex()).add(vertices.get(edge.getSecondIndex())).divideLocal(2)); normals.add(normals.get(edge.getFirstIndex()).add(normals.get(edge.getSecondIndex())).normalizeLocal()); - newEdges.add(new Edge(edge.getFirstIndex(), newVertexIndex, 0, false, temporalMesh)); - newEdges.add(new Edge(newVertexIndex, edge.getSecondIndex(), 0, false, temporalMesh)); + newEdges.add(new Edge(edge.getFirstIndex(), newVertexIndex, edge.getCrease(), false, temporalMesh)); + newEdges.add(new Edge(newVertexIndex, edge.getSecondIndex(), edge.getCrease(), false, temporalMesh)); + verticesOnOriginalEdges.add(newVertexIndex); } } @@ -576,8 +586,10 @@ public class SubdivisionSurfaceModifier extends Modifier { private static class CreasePoint { private Vector3f target = new Vector3f(); private float weight; + private int index; public CreasePoint(int index, boolean borderIndex, List creaseEdges, TemporalMesh temporalMesh) { + this.index = index; if (creaseEdges == null || creaseEdges.size() <= 1) { target = null;// crease is used when vertex belongs to at least 2 creased edges } else { @@ -596,7 +608,7 @@ public class SubdivisionSurfaceModifier extends Modifier { if (borderIndex) { target.set(temporalMesh.getVertices().get(index)); } else { - target.divideLocal(creasedEdgesCount); + target.addLocal(temporalMesh.getVertices().get(index)).divideLocal(creasedEdgesCount + 1); } } else { target.set(temporalMesh.getVertices().get(index)); @@ -614,5 +626,10 @@ public class SubdivisionSurfaceModifier extends Modifier { public float getWeight() { return weight; } + + @Override + public String toString() { + return "CreasePoint [index = " + index + ", target=" + target + ", weight=" + weight + "]"; + } } }