Bugfix: fixed a bug that caused ba UV coordinates to be applied on the

face after triangulation
Refactoring: made temporal mesh more exposed for external modifications;
this allows modifiers to properly modify the mesh and to remove some
modifier-specific code from the temporal mesh implementation
experimental
jmekaelthas 10 years ago
parent 1992da3471
commit 6e05304d26
  1. 2
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/meshes/Edge.java
  2. 42
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/meshes/Face.java
  3. 24
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/meshes/MeshHelper.java
  4. 2
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/meshes/Point.java
  5. 214
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/meshes/TemporalMesh.java
  6. 19
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/modifiers/ArrayModifier.java
  7. 80
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/modifiers/MaskModifier.java
  8. 26
      jme3-blender/src/main/java/com/jme3/scene/plugins/blender/modifiers/MirrorModifier.java

@ -18,7 +18,7 @@ import com.jme3.scene.plugins.blender.meshes.IndexesLoop.IndexPredicate;
* *
* @author Marcin Roguski (Kaelthas) * @author Marcin Roguski (Kaelthas)
*/ */
/* package */class Edge extends Line { public class Edge extends Line {
private static final long serialVersionUID = 7172714692126675311L; private static final long serialVersionUID = 7172714692126675311L;
private static final Logger LOGGER = Logger.getLogger(Edge.class.getName()); private static final Logger LOGGER = Logger.getLogger(Edge.class.getName());

@ -25,13 +25,13 @@ import com.jme3.scene.plugins.blender.file.Structure;
* *
* @author Marcin Roguski (Kaelthas) * @author Marcin Roguski (Kaelthas)
*/ */
/* package */class Face implements Comparator<Integer> { public class Face implements Comparator<Integer> {
private static final Logger LOGGER = Logger.getLogger(Face.class.getName()); private static final Logger LOGGER = Logger.getLogger(Face.class.getName());
/** The indexes loop of the face. */ /** The indexes loop of the face. */
private IndexesLoop indexes; private IndexesLoop indexes;
private List<IndexesLoop> triangulatedFaces; private List<IndexesLoop> triangulatedFaces;
/** Indicates if the face is smooth or solid. */ /** Indicates if the face is smooth or solid. */
private boolean smooth; private boolean smooth;
/** The material index of the face. */ /** The material index of the face. */
@ -117,6 +117,13 @@ import com.jme3.scene.plugins.blender.file.Structure;
return indexes.get(indexPosition); return indexes.get(indexPosition);
} }
/**
* @return the mesh this face belongs to
*/
public TemporalMesh getTemporalMesh() {
return temporalMesh;
}
/** /**
* @return the original indexes of the face * @return the original indexes of the face
*/ */
@ -129,11 +136,11 @@ import com.jme3.scene.plugins.blender.file.Structure;
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public List<List<Integer>> getCurrentIndexes() { public List<List<Integer>> getCurrentIndexes() {
if(triangulatedFaces == null) { if (triangulatedFaces == null) {
return Arrays.asList(indexes.getAll()); return Arrays.asList(indexes.getAll());
} }
List<List<Integer>> result = new ArrayList<List<Integer>>(triangulatedFaces.size()); List<List<Integer>> result = new ArrayList<List<Integer>>(triangulatedFaces.size());
for(IndexesLoop loop : triangulatedFaces) { for (IndexesLoop loop : triangulatedFaces) {
result.add(loop.getAll()); result.add(loop.getAll());
} }
return result; return result;
@ -155,6 +162,7 @@ import com.jme3.scene.plugins.blender.file.Structure;
if (triangleIndexes.length != 3) { if (triangleIndexes.length != 3) {
throw new IllegalArgumentException("Cannot detach triangle with that does not have 3 indexes!"); throw new IllegalArgumentException("Cannot detach triangle with that does not have 3 indexes!");
} }
MeshHelper meshHelper = temporalMesh.getBlenderContext().getHelper(MeshHelper.class);
List<Face> detachedFaces = new ArrayList<Face>(); List<Face> detachedFaces = new ArrayList<Face>();
List<Integer> path = new ArrayList<Integer>(indexes.size()); List<Integer> path = new ArrayList<Integer>(indexes.size());
@ -171,7 +179,8 @@ import com.jme3.scene.plugins.blender.file.Structure;
throw new IllegalStateException("Triangulation failed. Cannot find path between two indexes. Please apply triangulation in Blender as a workaround."); throw new IllegalStateException("Triangulation failed. Cannot find path between two indexes. Please apply triangulation in Blender as a workaround.");
} }
if (detachedFaces.size() == 0 && path.size() < indexes.size()) { if (detachedFaces.size() == 0 && path.size() < indexes.size()) {
detachedFaces.add(new Face(path.toArray(new Integer[path.size()]), smooth, materialNumber, faceUVCoords, vertexColors, temporalMesh)); Integer[] indexesSublist = path.toArray(new Integer[path.size()]);
detachedFaces.add(new Face(indexesSublist, smooth, materialNumber, meshHelper.selectUVSubset(this, indexesSublist), vertexColors, temporalMesh));
for (int j = 0; j < path.size() - 1; ++j) { for (int j = 0; j < path.size() - 1; ++j) {
indexes.removeEdge(path.get(j), path.get(j + 1)); indexes.removeEdge(path.get(j), path.get(j + 1));
} }
@ -244,12 +253,8 @@ import com.jme3.scene.plugins.blender.file.Structure;
/** /**
* The method triangulates the face. * The method triangulates the face.
* @param vertices
* the vertices of the mesh (all verts and not only those belonging to the face)
* @param normals
* the normals of the mesh (all normals and not only those belonging to the face)
*/ */
public void triangulate(List<Vector3f> vertices, List<Vector3f> normals) { public void triangulate() {
LOGGER.fine("Triangulating face."); LOGGER.fine("Triangulating face.");
assert indexes.size() >= 3 : "Invalid indexes amount for face. 3 is the required minimum!"; assert indexes.size() >= 3 : "Invalid indexes amount for face. 3 is the required minimum!";
triangulatedFaces = new ArrayList<IndexesLoop>(indexes.size() - 2); triangulatedFaces = new ArrayList<IndexesLoop>(indexes.size() - 2);
@ -266,13 +271,11 @@ import com.jme3.scene.plugins.blender.file.Structure;
indexes[2] = face.findClosestVertex(indexes[0], indexes[1]); indexes[2] = face.findClosestVertex(indexes[0], indexes[1]);
LOGGER.finer("Veryfying improper triangulation of the temporal mesh."); LOGGER.finer("Veryfying improper triangulation of the temporal mesh.");
if(indexes[0] < 0 || indexes[1] < 0 || indexes[2] < 0) { if (indexes[0] < 0 || indexes[1] < 0 || indexes[2] < 0) {
throw new BlenderFileException("Unable to find two closest vertices while triangulating face in mesh: " + temporalMesh + throw new BlenderFileException("Unable to find two closest vertices while triangulating face in mesh: " + temporalMesh + "Please apply triangulation modifier in blender as a workaround and load again!");
"Please apply triangulation modifier in blender as a workaround and load again!");
} }
if(previousIndex1 == indexes[0] && previousIndex2 == indexes[1] && previousIndex3 == indexes[2]) { if (previousIndex1 == indexes[0] && previousIndex2 == indexes[1] && previousIndex3 == indexes[2]) {
throw new BlenderFileException("Infinite loop detected during triangulation of mesh: " + temporalMesh + throw new BlenderFileException("Infinite loop detected during triangulation of mesh: " + temporalMesh + "Please apply triangulation modifier in blender as a workaround and load again!");
"Please apply triangulation modifier in blender as a workaround and load again!");
} }
previousIndex1 = indexes[0]; previousIndex1 = indexes[0];
previousIndex2 = indexes[1]; previousIndex2 = indexes[1];
@ -283,11 +286,10 @@ import com.jme3.scene.plugins.blender.file.Structure;
triangulatedFaces.add(new IndexesLoop(indexes)); triangulatedFaces.add(new IndexesLoop(indexes));
} }
} }
} catch(BlenderFileException e) { } catch (BlenderFileException e) {
LOGGER.log(Level.WARNING, "Errors occured during face triangulation: {0}. The face will be triangulated with the most direct algorithm, " + LOGGER.log(Level.WARNING, "Errors occured during face triangulation: {0}. The face will be triangulated with the most direct algorithm, " + "but the results might not be identical to blender.", e.getLocalizedMessage());
"but the results might not be identical to blender.", e.getLocalizedMessage());
indexes[0] = this.getIndex(0); indexes[0] = this.getIndex(0);
for(int i=1;i<this.vertexCount() - 1;++i) { for (int i = 1; i < this.vertexCount() - 1; ++i) {
indexes[1] = this.getIndex(i); indexes[1] = this.getIndex(i);
indexes[2] = this.getIndex(i + 1); indexes[2] = this.getIndex(i + 1);
triangulatedFaces.add(new IndexesLoop(indexes)); triangulatedFaces.add(new IndexesLoop(indexes));

@ -36,6 +36,7 @@ import java.util.HashMap;
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.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -317,6 +318,29 @@ public class MeshHelper extends AbstractBlenderHelper {
return result; return result;
} }
/**
* Selects the proper subsets of UV coordinates for the given sublist of indexes.
* @param face
* the face with the original UV sets
* @param indexesSublist
* the sub list of indexes
* @return a map of UV coordinates subsets
*/
public Map<String, List<Vector2f>> selectUVSubset(Face face, Integer... indexesSublist) {
Map<String, List<Vector2f>> result = null;
if (face.getUvSets() != null) {
result = new HashMap<String, List<Vector2f>>();
for (Entry<String, List<Vector2f>> entry : face.getUvSets().entrySet()) {
List<Vector2f> uvs = new ArrayList<Vector2f>(indexesSublist.length);
for (Integer index : indexesSublist) {
uvs.add(entry.getValue().get(face.getIndexes().indexOf(index)));
}
result.put(entry.getKey(), uvs);
}
}
return result;
}
/** /**
* Returns the black unshaded material. It is used for lines and points because that is how blender * Returns the black unshaded material. It is used for lines and points because that is how blender
* renders it. * renders it.

@ -17,7 +17,7 @@ import com.jme3.scene.plugins.blender.meshes.IndexesLoop.IndexPredicate;
* *
* @author Marcin Roguski (Kaelthas) * @author Marcin Roguski (Kaelthas)
*/ */
/* package */class Point { public class Point {
private static final Logger LOGGER = Logger.getLogger(Point.class.getName()); private static final Logger LOGGER = Logger.getLogger(Point.class.getName());
/** The point's index. */ /** The point's index. */

@ -4,15 +4,11 @@ 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.Collections;
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;
@ -32,7 +28,6 @@ import com.jme3.scene.plugins.blender.BlenderContext.LoadedDataType;
import com.jme3.scene.plugins.blender.file.BlenderFileException; import com.jme3.scene.plugins.blender.file.BlenderFileException;
import com.jme3.scene.plugins.blender.file.Structure; import com.jme3.scene.plugins.blender.file.Structure;
import com.jme3.scene.plugins.blender.materials.MaterialContext; import com.jme3.scene.plugins.blender.materials.MaterialContext;
import com.jme3.scene.plugins.blender.meshes.IndexesLoop.IndexPredicate;
import com.jme3.scene.plugins.blender.meshes.MeshBuffers.BoneBuffersData; import com.jme3.scene.plugins.blender.meshes.MeshBuffers.BoneBuffersData;
import com.jme3.scene.plugins.blender.modifiers.Modifier; import com.jme3.scene.plugins.blender.modifiers.Modifier;
import com.jme3.scene.plugins.blender.objects.Properties; import com.jme3.scene.plugins.blender.objects.Properties;
@ -123,6 +118,62 @@ public class TemporalMesh extends Geometry {
} }
} }
/**
* @return the blender context
*/
public BlenderContext getBlenderContext() {
return blenderContext;
}
/**
* @return the vertices of the mesh
*/
public List<Vector3f> getVertices() {
return vertices;
}
/**
* @return the normals of the mesh
*/
public List<Vector3f> getNormals() {
return normals;
}
/**
* @return all faces
*/
public List<Face> getFaces() {
return faces;
}
/**
* @return all edges
*/
public List<Edge> getEdges() {
return edges;
}
/**
* @return all points (do not mistake it with vertices)
*/
public List<Point> getPoints() {
return points;
}
/**
* @return all vertices colors
*/
public List<byte[]> getVerticesColors() {
return verticesColors;
}
/**
* @return all vertex groups for the vertices (each map has groups for the proper vertex)
*/
public List<Map<String, Float>> getVertexGroups() {
return vertexGroups;
}
@Override @Override
public TemporalMesh clone() { public TemporalMesh clone() {
try { try {
@ -159,20 +210,6 @@ public class TemporalMesh extends Geometry {
return null; return null;
} }
/**
* @return the vertices of the mesh
*/
protected List<Vector3f> getVertices() {
return vertices;
}
/**
* @return the normals of the mesh
*/
protected List<Vector3f> getNormals() {
return normals;
}
@Override @Override
public void updateModelBound() { public void updateModelBound() {
if (boundingBox == null) { if (boundingBox == null) {
@ -212,7 +249,7 @@ public class TemporalMesh extends Geometry {
public void triangulate() { public void triangulate() {
LOGGER.fine("Triangulating temporal mesh."); LOGGER.fine("Triangulating temporal mesh.");
for (Face face : faces) { for (Face face : faces) {
face.triangulate(vertices, normals); face.triangulate();
} }
} }
@ -248,19 +285,6 @@ public class TemporalMesh extends Geometry {
boneIndexes.putAll(mesh.boneIndexes); boneIndexes.putAll(mesh.boneIndexes);
} }
/**
* Translate all vertices by the given vector.
* @param translation
* the translation vector
* @return this mesh after translation (NO new instance is created)
*/
public TemporalMesh translate(Vector3f translation) {
for (Vector3f v : vertices) {
v.addLocal(translation);
}
return this;
}
/** /**
* Sets the properties of the mesh. * Sets the properties of the mesh.
* @param properties * @param properties
@ -304,47 +328,6 @@ public class TemporalMesh extends Geometry {
return vertices.size(); return vertices.size();
} }
/**
* Returns the vertex at the given position.
* @param i
* the vertex position
* @return the vertex at the given position
*/
public Vector3f getVertex(int i) {
return vertices.get(i);
}
/**
* Returns the normal at the given position.
* @param i
* the normal position
* @return the normal at the given position
*/
public Vector3f getNormal(int i) {
return normals.get(i);
}
/**
* Returns the vertex groups at the given vertex index.
* @param i
* the vertex groups for vertex with a given index
* @return the vertex groups at the given vertex index
*/
public Map<String, Float> getVertexGroups(int i) {
return vertexGroups.size() > i ? vertexGroups.get(i) : null;
}
/**
* @return a collection of vertex group names for this mesh
*/
public Collection<String> getVertexGroupNames() {
Set<String> result = new HashSet<String>();
for (Map<String, Float> groups : vertexGroups) {
result.addAll(groups.keySet());
}
return result;
}
/** /**
* Removes all vertices from the mesh. * Removes all vertices from the mesh.
*/ */
@ -358,86 +341,6 @@ public class TemporalMesh extends Geometry {
points.clear(); points.clear();
} }
/**
* Every face, edge and point that contains
* the vertex will be removed.
* @param index
* the index of a vertex to be removed
* @throws IndexOutOfBoundsException
* thrown when given index is negative or beyond the count of vertices
*/
public void removeVertexAt(final int index) {
if (index < 0 || index >= vertices.size()) {
throw new IndexOutOfBoundsException("The given index is out of bounds: " + index);
}
vertices.remove(index);
normals.remove(index);
if(vertexGroups.size() > 0) {
vertexGroups.remove(index);
}
if(verticesColors.size() > 0) {
verticesColors.remove(index);
}
IndexPredicate shiftPredicate = new IndexPredicate() {
@Override
public boolean execute(Integer i) {
return i > index;
}
};
for (int i = faces.size() - 1; i >= 0; --i) {
Face face = faces.get(i);
if (face.getIndexes().indexOf(index) >= 0) {
faces.remove(i);
} else {
face.getIndexes().shiftIndexes(-1, shiftPredicate);
}
}
for (int i = edges.size() - 1; i >= 0; --i) {
Edge edge = edges.get(i);
if (edge.getFirstIndex() == index || edge.getSecondIndex() == index) {
edges.remove(i);
} else {
edge.shiftIndexes(-1, shiftPredicate);
}
}
for (int i = points.size() - 1; i >= 0; --i) {
Point point = points.get(i);
if (point.getIndex() == index) {
points.remove(i);
} else {
point.shiftIndexes(-1, shiftPredicate);
}
}
}
/**
* Flips the order of the mesh's indexes.
*/
public void flipIndexes() {
for (Face face : faces) {
face.flipIndexes();
}
for (Edge edge : edges) {
edge.flipIndexes();
}
Collections.reverse(points);
}
/**
* Flips UV coordinates.
* @param u
* indicates if U coords should be flipped
* @param v
* indicates if V coords should be flipped
*/
public void flipUV(boolean u, boolean v) {
for (Face face : faces) {
face.flipUV(u, v);
}
}
/** /**
* The mesh builds geometries from the mesh. The result is stored in the blender context * The mesh builds geometries from the mesh. The result is stored in the blender context
* under the mesh's OMA. * under the mesh's OMA.
@ -513,7 +416,8 @@ public class TemporalMesh extends Geometry {
} }
} }
meshBuffers.append(face.isSmooth(), tempVerts, tempNormals, face.getUvSets(), tempVertColors, boneBuffers); Map<String, List<Vector2f>> uvs = meshHelper.selectUVSubset(face, indexes.toArray(new Integer[indexes.size()]));
meshBuffers.append(face.isSmooth(), tempVerts, tempNormals, uvs, tempVertColors, boneBuffers);
} }
} }

@ -210,15 +210,28 @@ import com.jme3.scene.shape.Curve;
if (count > 0) { if (count > 0) {
TemporalMesh originalMesh = temporalMesh.clone(); TemporalMesh originalMesh = temporalMesh.clone();
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
temporalMesh.append(originalMesh.clone().translate(totalTranslation)); TemporalMesh clone = originalMesh.clone();
for (Vector3f v : clone.getVertices()) {
v.addLocal(totalTranslation);
}
temporalMesh.append(clone);
totalTranslation.addLocal(translationVector); totalTranslation.addLocal(translationVector);
} }
} }
if (caps[0] != null) { if (caps[0] != null) {
temporalMesh.append(caps[0].clone().translate(translationVector.multLocal(-1))); translationVector.multLocal(-1);
TemporalMesh capsClone = caps[0].clone();
for (Vector3f v : capsClone.getVertices()) {
v.addLocal(translationVector);
}
temporalMesh.append(capsClone);
} }
if (caps[1] != null) { if (caps[1] != null) {
temporalMesh.append(caps[1].clone().translate(totalTranslation)); TemporalMesh capsClone = caps[1].clone();
for (Vector3f v : capsClone.getVertices()) {
v.addLocal(totalTranslation);
}
temporalMesh.append(capsClone);
} }
} else { } else {
LOGGER.log(Level.WARNING, "Cannot find temporal mesh for node: {0}. The modifier will NOT be applied!", node); LOGGER.log(Level.WARNING, "Cannot find temporal mesh for node: {0}. The modifier will NOT be applied!", node);

@ -1,10 +1,11 @@
package com.jme3.scene.plugins.blender.modifiers; package com.jme3.scene.plugins.blender.modifiers;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -14,6 +15,10 @@ import com.jme3.scene.plugins.blender.animations.BoneContext;
import com.jme3.scene.plugins.blender.file.BlenderFileException; import com.jme3.scene.plugins.blender.file.BlenderFileException;
import com.jme3.scene.plugins.blender.file.Pointer; import com.jme3.scene.plugins.blender.file.Pointer;
import com.jme3.scene.plugins.blender.file.Structure; import com.jme3.scene.plugins.blender.file.Structure;
import com.jme3.scene.plugins.blender.meshes.Edge;
import com.jme3.scene.plugins.blender.meshes.Face;
import com.jme3.scene.plugins.blender.meshes.IndexesLoop.IndexPredicate;
import com.jme3.scene.plugins.blender.meshes.Point;
import com.jme3.scene.plugins.blender.meshes.TemporalMesh; import com.jme3.scene.plugins.blender.meshes.TemporalMesh;
/** /**
@ -22,12 +27,12 @@ import com.jme3.scene.plugins.blender.meshes.TemporalMesh;
* @author Marcin Roguski (Kaelthas) * @author Marcin Roguski (Kaelthas)
*/ */
/* package */class MaskModifier extends Modifier { /* package */class MaskModifier extends Modifier {
private static final Logger LOGGER = Logger.getLogger(MaskModifier.class.getName()); private static final Logger LOGGER = Logger.getLogger(MaskModifier.class.getName());
private static final int FLAG_INVERT_MASK = 0x01; private static final int FLAG_INVERT_MASK = 0x01;
private static final int MODE_VERTEX_GROUP = 0; private static final int MODE_VERTEX_GROUP = 0;
private static final int MODE_ARMATURE = 1; private static final int MODE_ARMATURE = 1;
private Pointer pArmatureObject; private Pointer pArmatureObject;
private String vertexGroupName; private String vertexGroupName;
@ -78,7 +83,10 @@ import com.jme3.scene.plugins.blender.meshes.TemporalMesh;
// if the mesh has no vertex groups then remove all verts // if the mesh has no vertex groups then remove all verts
// if the mesh has at least one vertex group - then do nothing // if the mesh has at least one vertex group - then do nothing
// I have no idea why we should do that, but blender works this way // I have no idea why we should do that, but blender works this way
Collection<String> vertexGroupNames = temporalMesh.getVertexGroupNames(); Set<String> vertexGroupNames = new HashSet<String>();
for (Map<String, Float> groups : temporalMesh.getVertexGroups()) {
vertexGroupNames.addAll(groups.keySet());
}
if (vertexGroupNames.size() == 0 && !invertMask || vertexGroupNames.size() > 0 && invertMask) { if (vertexGroupNames.size() == 0 && !invertMask || vertexGroupNames.size() > 0 && invertMask) {
temporalMesh.clear(); temporalMesh.clear();
} }
@ -87,9 +95,9 @@ import com.jme3.scene.plugins.blender.meshes.TemporalMesh;
if (vertexGroupsToRemove.size() > 0) { if (vertexGroupsToRemove.size() > 0) {
List<Integer> vertsToBeRemoved = new ArrayList<Integer>(); List<Integer> vertsToBeRemoved = new ArrayList<Integer>();
for (int i = 0; i < temporalMesh.getVertexCount(); ++i) { for (int i = 0; i < temporalMesh.getVertexCount(); ++i) {
Map<String, Float> vertexGroups = temporalMesh.getVertexGroups(i); Map<String, Float> vertexGroups = temporalMesh.getVertexGroups().get(i);
boolean hasVertexGroup = false; boolean hasVertexGroup = false;
if(vertexGroups != null) { if (vertexGroups != null) {
for (String groupName : vertexGroupsToRemove) { for (String groupName : vertexGroupsToRemove) {
Float weight = vertexGroups.get(groupName); Float weight = vertexGroups.get(groupName);
if (weight != null && weight > 0) { if (weight != null && weight > 0) {
@ -106,7 +114,7 @@ import com.jme3.scene.plugins.blender.meshes.TemporalMesh;
Collections.reverse(vertsToBeRemoved); Collections.reverse(vertsToBeRemoved);
for (Integer vertexIndex : vertsToBeRemoved) { for (Integer vertexIndex : vertsToBeRemoved) {
temporalMesh.removeVertexAt(vertexIndex); this.removeVertexAt(vertexIndex, temporalMesh);
} }
} }
} else { } else {
@ -115,6 +123,60 @@ import com.jme3.scene.plugins.blender.meshes.TemporalMesh;
} }
} }
/**
* Every face, edge and point that contains
* the vertex will be removed.
* @param index
* the index of a vertex to be removed
* @throws IndexOutOfBoundsException
* thrown when given index is negative or beyond the count of vertices
*/
private void removeVertexAt(final int index, TemporalMesh temporalMesh) {
if (index < 0 || index >= temporalMesh.getVertexCount()) {
throw new IndexOutOfBoundsException("The given index is out of bounds: " + index);
}
temporalMesh.getVertices().remove(index);
temporalMesh.getNormals().remove(index);
if (temporalMesh.getVertexGroups().size() > 0) {
temporalMesh.getVertexGroups().remove(index);
}
if (temporalMesh.getVerticesColors().size() > 0) {
temporalMesh.getVerticesColors().remove(index);
}
IndexPredicate shiftPredicate = new IndexPredicate() {
@Override
public boolean execute(Integer i) {
return i > index;
}
};
for (int i = temporalMesh.getFaces().size() - 1; i >= 0; --i) {
Face face = temporalMesh.getFaces().get(i);
if (face.getIndexes().indexOf(index) >= 0) {
temporalMesh.getFaces().remove(i);
} else {
face.getIndexes().shiftIndexes(-1, shiftPredicate);
}
}
for (int i = temporalMesh.getEdges().size() - 1; i >= 0; --i) {
Edge edge = temporalMesh.getEdges().get(i);
if (edge.getFirstIndex() == index || edge.getSecondIndex() == index) {
temporalMesh.getEdges().remove(i);
} else {
edge.shiftIndexes(-1, shiftPredicate);
}
}
for (int i = temporalMesh.getPoints().size() - 1; i >= 0; --i) {
Point point = temporalMesh.getPoints().get(i);
if (point.getIndex() == index) {
temporalMesh.getPoints().remove(i);
} else {
point.shiftIndexes(-1, shiftPredicate);
}
}
}
/** /**
* Reads the names of the bones from the given bone base. * Reads the names of the bones from the given bone base.
* @param boneBase * @param boneBase

@ -1,5 +1,6 @@
package com.jme3.scene.plugins.blender.modifiers; package com.jme3.scene.plugins.blender.modifiers;
import java.util.Collections;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -10,6 +11,8 @@ import com.jme3.scene.plugins.blender.BlenderContext;
import com.jme3.scene.plugins.blender.file.BlenderFileException; import com.jme3.scene.plugins.blender.file.BlenderFileException;
import com.jme3.scene.plugins.blender.file.Pointer; import com.jme3.scene.plugins.blender.file.Pointer;
import com.jme3.scene.plugins.blender.file.Structure; import com.jme3.scene.plugins.blender.file.Structure;
import com.jme3.scene.plugins.blender.meshes.Edge;
import com.jme3.scene.plugins.blender.meshes.Face;
import com.jme3.scene.plugins.blender.meshes.TemporalMesh; import com.jme3.scene.plugins.blender.meshes.TemporalMesh;
import com.jme3.scene.plugins.blender.objects.ObjectHelper; import com.jme3.scene.plugins.blender.objects.ObjectHelper;
@ -70,7 +73,7 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper;
tolerance = ((Number) modifierStructure.getFieldValue("tolerance")).floatValue(); tolerance = ((Number) modifierStructure.getFieldValue("tolerance")).floatValue();
pMirrorObject = (Pointer) modifierStructure.getFieldValue("mirror_ob"); pMirrorObject = (Pointer) modifierStructure.getFieldValue("mirror_ob");
if(mirrorVGroup) { if (mirrorVGroup) {
LOGGER.warning("Mirroring vertex groups is currently not supported."); LOGGER.warning("Mirroring vertex groups is currently not supported.");
} }
} }
@ -117,8 +120,8 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper;
TemporalMesh mirror = temporalMesh.clone(); TemporalMesh mirror = temporalMesh.clone();
for (int i = 0; i < mirror.getVertexCount(); ++i) { for (int i = 0; i < mirror.getVertexCount(); ++i) {
Vector3f vertex = mirror.getVertex(i); Vector3f vertex = mirror.getVertices().get(i);
Vector3f normal = mirror.getNormal(i); Vector3f normal = mirror.getNormals().get(i);
if (mirrorAtPoint0) { if (mirrorAtPoint0) {
d = Math.abs(vertex.get(mirrorIndex)); d = Math.abs(vertex.get(mirrorIndex));
@ -131,18 +134,27 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper;
if (merge && d <= tolerance) { if (merge && d <= tolerance) {
vertex.addLocal(shiftVector); vertex.addLocal(shiftVector);
normal.set(mirrorIndex, 0); normal.set(mirrorIndex, 0);
temporalMesh.getVertex(i).addLocal(shiftVector); temporalMesh.getVertices().get(i).addLocal(shiftVector);
temporalMesh.getNormal(i).set(mirrorIndex, 0); temporalMesh.getNormals().get(i).set(mirrorIndex, 0);
} else { } else {
vertex.addLocal(shiftVector.multLocal(2)); vertex.addLocal(shiftVector.multLocal(2));
normal.set(mirrorIndex, -normal.get(mirrorIndex)); normal.set(mirrorIndex, -normal.get(mirrorIndex));
} }
} }
mirror.flipIndexes(); // flipping the indexes
for (Face face : mirror.getFaces()) {
face.flipIndexes();
}
for (Edge edge : mirror.getEdges()) {
edge.flipIndexes();
}
Collections.reverse(mirror.getPoints());
if (mirrorU || mirrorV) { if (mirrorU || mirrorV) {
mirror.flipUV(mirrorU, mirrorV); for (Face face : mirror.getFaces()) {
face.flipUV(mirrorU, mirrorV);
}
} }
temporalMesh.append(mirror); temporalMesh.append(mirror);

Loading…
Cancel
Save