Bugfix: fixed issues with subdivision surface modifier.
This commit is contained in:
parent
3992ed89af
commit
550063367e
@ -4,11 +4,14 @@ import java.nio.IntBuffer;
|
|||||||
import java.nio.ShortBuffer;
|
import java.nio.ShortBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@ -71,9 +74,10 @@ public class TemporalMesh extends Geometry {
|
|||||||
protected List<Edge> edges = new ArrayList<Edge>();
|
protected List<Edge> edges = new ArrayList<Edge>();
|
||||||
/** The points of the mesh. */
|
/** The points of the mesh. */
|
||||||
protected List<Point> points = new ArrayList<Point>();
|
protected List<Point> points = new ArrayList<Point>();
|
||||||
|
/** A map between index and faces that contain it (for faster index - face queries). */
|
||||||
protected Map<Integer, List<Face>> indexToFaceMapping = new HashMap<Integer, List<Face>>();
|
protected Map<Integer, Set<Face>> indexToFaceMapping = new HashMap<Integer, Set<Face>>();
|
||||||
protected Map<Integer, List<Edge>> indexToEdgeMapping = new HashMap<Integer, List<Edge>>();
|
/** A map between index and edges that contain it (for faster index - edge queries). */
|
||||||
|
protected Map<Integer, Set<Edge>> indexToEdgeMapping = new HashMap<Integer, Set<Edge>>();
|
||||||
|
|
||||||
/** The bounding box of the temporal mesh. */
|
/** The bounding box of the temporal mesh. */
|
||||||
protected BoundingBox boundingBox;
|
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
|
* @return the faces that contain the given index or null if none contain it
|
||||||
*/
|
*/
|
||||||
public List<Face> getAdjacentFaces(Integer index) {
|
public Collection<Face> getAdjacentFaces(Integer index) {
|
||||||
return indexToFaceMapping.get(index);
|
return indexToFaceMapping.get(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,10 +196,10 @@ public class TemporalMesh extends Geometry {
|
|||||||
* edge of the mesh
|
* edge of the mesh
|
||||||
* @return a list of faces that contain the given edge or an empty list
|
* @return a list of faces that contain the given edge or an empty list
|
||||||
*/
|
*/
|
||||||
public List<Face> getAdjacentFaces(Edge edge) {
|
public Collection<Face> getAdjacentFaces(Edge edge) {
|
||||||
List<Face> result = new ArrayList<Face>(indexToFaceMapping.get(edge.getFirstIndex()));
|
List<Face> result = new ArrayList<Face>(indexToFaceMapping.get(edge.getFirstIndex()));
|
||||||
List<Face> secondIndexAdjacentFaces = indexToFaceMapping.get(edge.getSecondIndex());
|
Set<Face> secondIndexAdjacentFaces = indexToFaceMapping.get(edge.getSecondIndex());
|
||||||
if(secondIndexAdjacentFaces != null) {
|
if (secondIndexAdjacentFaces != null) {
|
||||||
result.retainAll(indexToFaceMapping.get(edge.getSecondIndex()));
|
result.retainAll(indexToFaceMapping.get(edge.getSecondIndex()));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -206,7 +210,7 @@ public class TemporalMesh extends Geometry {
|
|||||||
* index of the mesh
|
* index of the mesh
|
||||||
* @return a list of edges that contain the index
|
* @return a list of edges that contain the index
|
||||||
*/
|
*/
|
||||||
public List<Edge> getAdjacentEdges(Integer index) {
|
public Collection<Edge> getAdjacentEdges(Integer index) {
|
||||||
return indexToEdgeMapping.get(index);
|
return indexToEdgeMapping.get(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,7 +233,7 @@ public class TemporalMesh extends Geometry {
|
|||||||
* @return <b>true</b> if the index is a boundary one and <b>false</b> otherwise
|
* @return <b>true</b> if the index is a boundary one and <b>false</b> otherwise
|
||||||
*/
|
*/
|
||||||
public boolean isBoundary(Integer index) {
|
public boolean isBoundary(Integer index) {
|
||||||
List<Edge> adjacentEdges = this.getAdjacentEdges(index);
|
Collection<Edge> adjacentEdges = this.getAdjacentEdges(index);
|
||||||
for (Edge edge : adjacentEdges) {
|
for (Edge edge : adjacentEdges) {
|
||||||
if (this.isBoundary(edge)) {
|
if (this.isBoundary(edge)) {
|
||||||
return true;
|
return true;
|
||||||
@ -287,24 +291,24 @@ public class TemporalMesh extends Geometry {
|
|||||||
indexToFaceMapping.clear();
|
indexToFaceMapping.clear();
|
||||||
for (Face face : faces) {
|
for (Face face : faces) {
|
||||||
for (Integer index : face.getIndexes()) {
|
for (Integer index : face.getIndexes()) {
|
||||||
List<Face> faces = indexToFaceMapping.get(index);
|
Set<Face> faces = indexToFaceMapping.get(index);
|
||||||
if (faces == null) {
|
if (faces == null) {
|
||||||
faces = new ArrayList<Face>();
|
faces = new HashSet<Face>();
|
||||||
indexToFaceMapping.put(index, faces);
|
indexToFaceMapping.put(index, faces);
|
||||||
}
|
}
|
||||||
faces.add(face);
|
faces.add(face);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (Edge edge : edges) {
|
for (Edge edge : edges) {
|
||||||
List<Edge> edges = indexToEdgeMapping.get(edge.getFirstIndex());
|
Set<Edge> edges = indexToEdgeMapping.get(edge.getFirstIndex());
|
||||||
if (edges == null) {
|
if (edges == null) {
|
||||||
edges = new ArrayList<Edge>();
|
edges = new HashSet<Edge>();
|
||||||
indexToEdgeMapping.put(edge.getFirstIndex(), edges);
|
indexToEdgeMapping.put(edge.getFirstIndex(), edges);
|
||||||
}
|
}
|
||||||
edges.add(edge);
|
edges.add(edge);
|
||||||
edges = indexToEdgeMapping.get(edge.getSecondIndex());
|
edges = indexToEdgeMapping.get(edge.getSecondIndex());
|
||||||
if (edges == null) {
|
if (edges == null) {
|
||||||
edges = new ArrayList<Edge>();
|
edges = new HashSet<Edge>();
|
||||||
indexToEdgeMapping.put(edge.getSecondIndex(), edges);
|
indexToEdgeMapping.put(edge.getSecondIndex(), edges);
|
||||||
}
|
}
|
||||||
edges.add(edge);
|
edges.add(edge);
|
||||||
|
@ -4,6 +4,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
@ -41,8 +42,8 @@ public class SubdivisionSurfaceModifier extends Modifier {
|
|||||||
private int levels;
|
private int levels;
|
||||||
/** Indicates if the UV's should also be subdivided. */
|
/** Indicates if the UV's should also be subdivided. */
|
||||||
private boolean subdivideUVS;
|
private boolean subdivideUVS;
|
||||||
|
/** Stores the vertices that are located on original edges of the mesh. */
|
||||||
private List<Integer> verticesOnOriginalEdges = new ArrayList<Integer>();
|
private Set<Integer> verticesOnOriginalEdges = new HashSet<Integer>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor loads all neccessary modifier data.
|
* Constructor loads all neccessary modifier data.
|
||||||
@ -77,7 +78,8 @@ public class SubdivisionSurfaceModifier extends Modifier {
|
|||||||
TemporalMesh temporalMesh = this.getTemporalMesh(node);
|
TemporalMesh temporalMesh = this.getTemporalMesh(node);
|
||||||
if (temporalMesh != null) {
|
if (temporalMesh != null) {
|
||||||
LOGGER.log(Level.FINE, "Applying subdivision surface modifier to: {0}", temporalMesh);
|
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()) {
|
for (Edge edge : temporalMesh.getEdges()) {
|
||||||
verticesOnOriginalEdges.add(edge.getFirstIndex());
|
verticesOnOriginalEdges.add(edge.getFirstIndex());
|
||||||
verticesOnOriginalEdges.add(edge.getSecondIndex());
|
verticesOnOriginalEdges.add(edge.getSecondIndex());
|
||||||
@ -109,10 +111,16 @@ public class SubdivisionSurfaceModifier extends Modifier {
|
|||||||
*/
|
*/
|
||||||
private void subdivideCatmullClark(TemporalMesh temporalMesh) {
|
private void subdivideCatmullClark(TemporalMesh temporalMesh) {
|
||||||
Set<Integer> boundaryVertices = new HashSet<Integer>();
|
Set<Integer> boundaryVertices = new HashSet<Integer>();
|
||||||
for (Face face : temporalMesh.getFaces()) {
|
for (Edge edge : temporalMesh.getEdges()) {
|
||||||
for (Integer index : face.getIndexes()) {
|
if (!edge.isInFace()) {
|
||||||
if (temporalMesh.isBoundary(index)) {
|
boundaryVertices.add(edge.getFirstIndex());
|
||||||
boundaryVertices.add(index);
|
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.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);
|
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) {
|
private void subdivideSimple(TemporalMesh temporalMesh) {
|
||||||
Map<Edge, Integer> edgePoints = new HashMap<Edge, Integer>();
|
Map<Edge, Integer> edgePoints = new HashMap<Edge, Integer>();
|
||||||
Map<Face, Integer> facePoints = new HashMap<Face, Integer>();
|
Map<Face, Integer> facePoints = new HashMap<Face, Integer>();
|
||||||
List<Face> newFaces = new ArrayList<Face>();
|
Set<Face> newFaces = new LinkedHashSet<Face>();
|
||||||
List<Edge> newEdges = new ArrayList<Edge>(temporalMesh.getEdges().size() * 2);
|
Set<Edge> newEdges = new LinkedHashSet<Edge>(temporalMesh.getEdges().size() * 4);
|
||||||
|
|
||||||
int originalFacesCount = temporalMesh.getFaces().size();
|
int originalFacesCount = temporalMesh.getFaces().size();
|
||||||
|
|
||||||
@ -240,7 +249,7 @@ public class SubdivisionSurfaceModifier extends Modifier {
|
|||||||
Vector3f v = temporalMesh.getVertices().get(vIndex);
|
Vector3f v = temporalMesh.getVertices().get(vIndex);
|
||||||
if (vPrevEdgeVertIndex < 0) {
|
if (vPrevEdgeVertIndex < 0) {
|
||||||
vPrevEdgeVertIndex = vertices.size() + originalFacesCount + edgeVertices.size();
|
vPrevEdgeVertIndex = vertices.size() + originalFacesCount + edgeVertices.size();
|
||||||
verticesOnOriginalEdges.add(vNextEdgeVertIndex);
|
verticesOnOriginalEdges.add(vPrevEdgeVertIndex);
|
||||||
edgeVertices.add(vertices.get(vPrevIndex).add(v).divideLocal(2));
|
edgeVertices.add(vertices.get(vPrevIndex).add(v).divideLocal(2));
|
||||||
edgeNormals.add(normals.get(vPrevIndex).add(normals.get(vIndex)).normalizeLocal());
|
edgeNormals.add(normals.get(vPrevIndex).add(normals.get(vIndex)).normalizeLocal());
|
||||||
edgePoints.put(prevEdge, vPrevEdgeVertIndex);
|
edgePoints.put(prevEdge, vPrevEdgeVertIndex);
|
||||||
@ -250,7 +259,7 @@ public class SubdivisionSurfaceModifier extends Modifier {
|
|||||||
}
|
}
|
||||||
if (vNextEdgeVertIndex < 0) {
|
if (vNextEdgeVertIndex < 0) {
|
||||||
vNextEdgeVertIndex = vertices.size() + originalFacesCount + edgeVertices.size();
|
vNextEdgeVertIndex = vertices.size() + originalFacesCount + edgeVertices.size();
|
||||||
verticesOnOriginalEdges.add(vPrevEdgeVertIndex);
|
verticesOnOriginalEdges.add(vNextEdgeVertIndex);
|
||||||
edgeVertices.add(vertices.get(vNextIndex).add(v).divideLocal(2));
|
edgeVertices.add(vertices.get(vNextIndex).add(v).divideLocal(2));
|
||||||
edgeNormals.add(normals.get(vNextIndex).add(normals.get(vIndex)).normalizeLocal());
|
edgeNormals.add(normals.get(vNextIndex).add(normals.get(vIndex)).normalizeLocal());
|
||||||
edgePoints.put(nextEdge, vNextEdgeVertIndex);
|
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));
|
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());
|
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(edge.getFirstIndex(), newVertexIndex, edge.getCrease(), false, temporalMesh));
|
||||||
newEdges.add(new Edge(newVertexIndex, edge.getSecondIndex(), 0, 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 static class CreasePoint {
|
||||||
private Vector3f target = new Vector3f();
|
private Vector3f target = new Vector3f();
|
||||||
private float weight;
|
private float weight;
|
||||||
|
private int index;
|
||||||
|
|
||||||
public CreasePoint(int index, boolean borderIndex, List<Edge> creaseEdges, TemporalMesh temporalMesh) {
|
public CreasePoint(int index, boolean borderIndex, List<Edge> creaseEdges, TemporalMesh temporalMesh) {
|
||||||
|
this.index = index;
|
||||||
if (creaseEdges == null || creaseEdges.size() <= 1) {
|
if (creaseEdges == null || creaseEdges.size() <= 1) {
|
||||||
target = null;// crease is used when vertex belongs to at least 2 creased edges
|
target = null;// crease is used when vertex belongs to at least 2 creased edges
|
||||||
} else {
|
} else {
|
||||||
@ -596,7 +608,7 @@ public class SubdivisionSurfaceModifier extends Modifier {
|
|||||||
if (borderIndex) {
|
if (borderIndex) {
|
||||||
target.set(temporalMesh.getVertices().get(index));
|
target.set(temporalMesh.getVertices().get(index));
|
||||||
} else {
|
} else {
|
||||||
target.divideLocal(creasedEdgesCount);
|
target.addLocal(temporalMesh.getVertices().get(index)).divideLocal(creasedEdgesCount + 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
target.set(temporalMesh.getVertices().get(index));
|
target.set(temporalMesh.getVertices().get(index));
|
||||||
@ -614,5 +626,10 @@ public class SubdivisionSurfaceModifier extends Modifier {
|
|||||||
public float getWeight() {
|
public float getWeight() {
|
||||||
return weight;
|
return weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "CreasePoint [index = " + index + ", target=" + target + ", weight=" + weight + "]";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user