Переглянути джерело

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

jmekaelthas 11 роки тому
батько
коміт
6e05304d26

+ 1 - 1
jme3-blender/src/main/java/com/jme3/scene/plugins/blender/meshes/Edge.java

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

+ 28 - 26
jme3-blender/src/main/java/com/jme3/scene/plugins/blender/meshes/Face.java

@@ -25,13 +25,13 @@ import com.jme3.scene.plugins.blender.file.Structure;
  * 
  * @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());
 
     /** The indexes loop of the face. */
     private IndexesLoop                 indexes;
-    
-    private List<IndexesLoop> triangulatedFaces;
+
+    private List<IndexesLoop>           triangulatedFaces;
     /** Indicates if the face is smooth or solid. */
     private boolean                     smooth;
     /** The material index of the face. */
@@ -116,7 +116,14 @@ import com.jme3.scene.plugins.blender.file.Structure;
         }
         return indexes.get(indexPosition);
     }
-    
+
+    /**
+     * @return the mesh this face belongs to
+     */
+    public TemporalMesh getTemporalMesh() {
+        return temporalMesh;
+    }
+
     /**
      * @return the original indexes of the face
      */
@@ -129,11 +136,11 @@ import com.jme3.scene.plugins.blender.file.Structure;
      */
     @SuppressWarnings("unchecked")
     public List<List<Integer>> getCurrentIndexes() {
-        if(triangulatedFaces == null) {
+        if (triangulatedFaces == null) {
             return Arrays.asList(indexes.getAll());
         }
         List<List<Integer>> result = new ArrayList<List<Integer>>(triangulatedFaces.size());
-        for(IndexesLoop loop : triangulatedFaces) {
+        for (IndexesLoop loop : triangulatedFaces) {
             result.add(loop.getAll());
         }
         return result;
@@ -155,9 +162,10 @@ import com.jme3.scene.plugins.blender.file.Structure;
         if (triangleIndexes.length != 3) {
             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<Integer> path = new ArrayList<Integer>(indexes.size());
-        
+
         boolean[] edgeRemoved = new boolean[] { indexes.removeEdge(triangleIndexes[0], triangleIndexes[1]), indexes.removeEdge(triangleIndexes[0], triangleIndexes[2]), indexes.removeEdge(triangleIndexes[1], triangleIndexes[2]) };
         Integer[][] indexesPairs = new Integer[][] { new Integer[] { triangleIndexes[0], triangleIndexes[1] }, new Integer[] { triangleIndexes[0], triangleIndexes[2] }, new Integer[] { triangleIndexes[1], triangleIndexes[2] } };
 
@@ -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.");
                 }
                 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) {
                         indexes.removeEdge(path.get(j), path.get(j + 1));
                     }
@@ -244,17 +253,13 @@ import com.jme3.scene.plugins.blender.file.Structure;
 
     /**
      * 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.");
         assert indexes.size() >= 3 : "Invalid indexes amount for face. 3 is the required minimum!";
         triangulatedFaces = new ArrayList<IndexesLoop>(indexes.size() - 2);
         Integer[] indexes = new Integer[3];
-        
+
         try {
             List<Face> facesToTriangulate = new ArrayList<Face>(Arrays.asList(this.clone()));
             while (facesToTriangulate.size() > 0) {
@@ -264,30 +269,27 @@ import com.jme3.scene.plugins.blender.file.Structure;
                     indexes[0] = face.getIndex(0);
                     indexes[1] = face.findClosestVertex(indexes[0], -1);
                     indexes[2] = face.findClosestVertex(indexes[0], indexes[1]);
-                    
+
                     LOGGER.finer("Veryfying improper triangulation of the temporal mesh.");
-                    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 +
-                                "Please apply triangulation modifier in blender as a workaround and load again!");
+                    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 + "Please apply triangulation modifier in blender as a workaround and load again!");
                     }
-                    if(previousIndex1 == indexes[0] && previousIndex2 == indexes[1] && previousIndex3 == indexes[2]) {
-                        throw new BlenderFileException("Infinite loop detected during triangulation of mesh: " + temporalMesh +
-                                "Please apply triangulation modifier in blender as a workaround and load again!");
+                    if (previousIndex1 == indexes[0] && previousIndex2 == indexes[1] && previousIndex3 == indexes[2]) {
+                        throw new BlenderFileException("Infinite loop detected during triangulation of mesh: " + temporalMesh + "Please apply triangulation modifier in blender as a workaround and load again!");
                     }
                     previousIndex1 = indexes[0];
                     previousIndex2 = indexes[1];
                     previousIndex3 = indexes[2];
-                    
+
                     Arrays.sort(indexes, this);
                     facesToTriangulate.addAll(face.detachTriangle(indexes));
                     triangulatedFaces.add(new IndexesLoop(indexes));
                 }
             }
-        } catch(BlenderFileException e) {
-            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());
+        } catch (BlenderFileException e) {
+            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());
             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[2] = this.getIndex(i + 1);
                 triangulatedFaces.add(new IndexesLoop(indexes));

+ 24 - 0
jme3-blender/src/main/java/com/jme3/scene/plugins/blender/meshes/MeshHelper.java

@@ -36,6 +36,7 @@ import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -317,6 +318,29 @@ public class MeshHelper extends AbstractBlenderHelper {
         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
      * renders it.

+ 1 - 1
jme3-blender/src/main/java/com/jme3/scene/plugins/blender/meshes/Point.java

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

+ 59 - 155
jme3-blender/src/main/java/com/jme3/scene/plugins/blender/meshes/TemporalMesh.java

@@ -4,15 +4,11 @@ import java.nio.IntBuffer;
 import java.nio.ShortBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
 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;
 
@@ -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.Structure;
 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.modifiers.Modifier;
 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
     public TemporalMesh clone() {
         try {
@@ -159,20 +210,6 @@ public class TemporalMesh extends Geometry {
         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
     public void updateModelBound() {
         if (boundingBox == null) {
@@ -212,7 +249,7 @@ public class TemporalMesh extends Geometry {
     public void triangulate() {
         LOGGER.fine("Triangulating temporal mesh.");
         for (Face face : faces) {
-            face.triangulate(vertices, normals);
+            face.triangulate();
         }
     }
 
@@ -248,19 +285,6 @@ public class TemporalMesh extends Geometry {
         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.
      * @param properties
@@ -304,47 +328,6 @@ public class TemporalMesh extends Geometry {
         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.
      */
@@ -358,86 +341,6 @@ public class TemporalMesh extends Geometry {
         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
      * 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);
             }
         }
 

+ 16 - 3
jme3-blender/src/main/java/com/jme3/scene/plugins/blender/modifiers/ArrayModifier.java

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

+ 72 - 10
jme3-blender/src/main/java/com/jme3/scene/plugins/blender/modifiers/MaskModifier.java

@@ -1,10 +1,11 @@
 package com.jme3.scene.plugins.blender.modifiers;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.logging.Level;
 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.Pointer;
 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;
 
 /**
@@ -22,12 +27,12 @@ import com.jme3.scene.plugins.blender.meshes.TemporalMesh;
  * @author Marcin Roguski (Kaelthas)
  */
 /* 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_ARMATURE      = 1;
+    private static final int    MODE_VERTEX_GROUP = 0;
+    private static final int    MODE_ARMATURE     = 1;
 
     private Pointer             pArmatureObject;
     private String              vertexGroupName;
@@ -37,7 +42,7 @@ import com.jme3.scene.plugins.blender.meshes.TemporalMesh;
         if (this.validate(modifierStructure, blenderContext)) {
             int flag = ((Number) modifierStructure.getFieldValue("flag")).intValue();
             invertMask = (flag & FLAG_INVERT_MASK) != 0;
-            
+
             int mode = ((Number) modifierStructure.getFieldValue("mode")).intValue();
             if (mode == MODE_VERTEX_GROUP) {
                 vertexGroupName = modifierStructure.getFieldValue("vgroup").toString();
@@ -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 at least one vertex group - then do nothing
                     // 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) {
                         temporalMesh.clear();
                     }
@@ -87,9 +95,9 @@ import com.jme3.scene.plugins.blender.meshes.TemporalMesh;
                 if (vertexGroupsToRemove.size() > 0) {
                     List<Integer> vertsToBeRemoved = new ArrayList<Integer>();
                     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;
-                        if(vertexGroups != null) {
+                        if (vertexGroups != null) {
                             for (String groupName : vertexGroupsToRemove) {
                                 Float weight = vertexGroups.get(groupName);
                                 if (weight != null && weight > 0) {
@@ -106,7 +114,7 @@ import com.jme3.scene.plugins.blender.meshes.TemporalMesh;
 
                     Collections.reverse(vertsToBeRemoved);
                     for (Integer vertexIndex : vertsToBeRemoved) {
-                        temporalMesh.removeVertexAt(vertexIndex);
+                        this.removeVertexAt(vertexIndex, temporalMesh);
                     }
                 }
             } 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.
      * @param boneBase

+ 20 - 8
jme3-blender/src/main/java/com/jme3/scene/plugins/blender/modifiers/MirrorModifier.java

@@ -1,5 +1,6 @@
 package com.jme3.scene.plugins.blender.modifiers;
 
+import java.util.Collections;
 import java.util.logging.Level;
 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.Pointer;
 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.objects.ObjectHelper;
 
@@ -69,8 +72,8 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper;
 
             tolerance = ((Number) modifierStructure.getFieldValue("tolerance")).floatValue();
             pMirrorObject = (Pointer) modifierStructure.getFieldValue("mirror_ob");
-            
-            if(mirrorVGroup) {
+
+            if (mirrorVGroup) {
                 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();
                         for (int i = 0; i < mirror.getVertexCount(); ++i) {
-                            Vector3f vertex = mirror.getVertex(i);
-                            Vector3f normal = mirror.getNormal(i);
+                            Vector3f vertex = mirror.getVertices().get(i);
+                            Vector3f normal = mirror.getNormals().get(i);
 
                             if (mirrorAtPoint0) {
                                 d = Math.abs(vertex.get(mirrorIndex));
@@ -131,18 +134,27 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper;
                             if (merge && d <= tolerance) {
                                 vertex.addLocal(shiftVector);
                                 normal.set(mirrorIndex, 0);
-                                temporalMesh.getVertex(i).addLocal(shiftVector);
-                                temporalMesh.getNormal(i).set(mirrorIndex, 0);
+                                temporalMesh.getVertices().get(i).addLocal(shiftVector);
+                                temporalMesh.getNormals().get(i).set(mirrorIndex, 0);
                             } else {
                                 vertex.addLocal(shiftVector.multLocal(2));
                                 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) {
-                            mirror.flipUV(mirrorU, mirrorV);
+                            for (Face face : mirror.getFaces()) {
+                                face.flipUV(mirrorU, mirrorV);
+                            }
                         }
 
                         temporalMesh.append(mirror);