Parcourir la source

Bugfix: fixing errors that appeared during mirror modifier loading (there is still mirror rotation being not supported, but hope to fix that soon).

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10944 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
Kae..pl il y a 11 ans
Parent
commit
cf830b4c7c

+ 144 - 57
engine/src/blender/com/jme3/scene/plugins/blender/modifiers/MirrorModifier.java

@@ -5,14 +5,13 @@ import java.nio.FloatBuffer;
 import java.nio.IntBuffer;
 import java.nio.ShortBuffer;
 import java.util.ArrayList;
-import java.util.HashMap;
 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;
 
+import com.jme3.math.Matrix4f;
 import com.jme3.math.Vector3f;
 import com.jme3.scene.Geometry;
 import com.jme3.scene.Mesh;
@@ -31,10 +30,21 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper;
  * @author Marcin Roguski (Kaelthas)
  */
 /* package */class MirrorModifier extends Modifier {
-    private static final Logger LOGGER       = Logger.getLogger(MirrorModifier.class.getName());
+    private static final Logger LOGGER            = Logger.getLogger(MirrorModifier.class.getName());
 
-    /** Parameters of the modifier. */
-    private Map<String, Object> modifierData = new HashMap<String, Object>();
+    private static final int    FLAG_MIRROR_X     = 0x08;
+    private static final int    FLAG_MIRROR_Y     = 0x10;
+    private static final int    FLAG_MIRROR_Z     = 0x20;
+    private static final int    FLAG_MIRROR_U     = 0x02;
+    private static final int    FLAG_MIRROR_V     = 0x04;
+    // private static final int FLAG_MIRROR_VERTEX_GROUP = 0x40;
+    private static final int    FLAG_MIRROR_MERGE = 0x80;
+
+    private boolean[]           isMirrored;
+    private boolean             mirrorU, mirrorV;
+    private boolean             merge;
+    private float               tolerance;
+    private Pointer             pMirrorObject;
 
     /**
      * This constructor reads mirror data from the modifier structure. The
@@ -54,12 +64,21 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper;
      */
     public MirrorModifier(Structure modifierStructure, BlenderContext blenderContext) {
         if (this.validate(modifierStructure, blenderContext)) {
-            modifierData.put("flag", modifierStructure.getFieldValue("flag"));
-            modifierData.put("tolerance", modifierStructure.getFieldValue("tolerance"));
-            Pointer pMirrorOb = (Pointer) modifierStructure.getFieldValue("mirror_ob");
-            if (pMirrorOb.isNotNull()) {
-                modifierData.put("mirrorob", pMirrorOb);
+            int flag = ((Number) modifierStructure.getFieldValue("flag")).intValue();
+
+            isMirrored = new boolean[] { (flag & FLAG_MIRROR_X) != 0, (flag & FLAG_MIRROR_Y) != 0, (flag & FLAG_MIRROR_Z) != 0 };
+            if (blenderContext.getBlenderKey().isFixUpAxis()) {
+                boolean temp = isMirrored[1];
+                isMirrored[1] = isMirrored[2];
+                isMirrored[2] = temp;
             }
+            mirrorU = (flag & FLAG_MIRROR_U) != 0;
+            mirrorV = (flag & FLAG_MIRROR_V) != 0;
+            // boolean mirrorVGroup = (flag & FLAG_MIRROR_VERTEX_GROUP) != 0;
+            merge = (flag & FLAG_MIRROR_MERGE) == 0;// in this case we use == instead of != (this is not a mistake)
+
+            tolerance = ((Number) modifierStructure.getFieldValue("tolerance")).floatValue();
+            pMirrorObject = (Pointer) modifierStructure.getFieldValue("mirror_ob");
         }
     }
 
@@ -68,46 +87,48 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper;
         if (invalid) {
             LOGGER.log(Level.WARNING, "Mirror modifier is invalid! Cannot be applied to: {0}", node.getName());
         } else {
-            int flag = ((Number) modifierData.get("flag")).intValue();
-            boolean[] isMirrored = new boolean[] { (flag & 0x08) != 0, (flag & 0x10) != 0, (flag & 0x20) != 0 };
-            if (blenderContext.getBlenderKey().isFixUpAxis()) {
-                boolean temp = isMirrored[1];
-                isMirrored[1] = isMirrored[2];
-                isMirrored[2] = temp;
-            }
-            float[] center = new float[] { 0.0f, 0.0f, 0.0f };
-            Pointer pObject = (Pointer) modifierData.get("mirrorob");
-            if (pObject != null) {
+            Vector3f mirrorPlaneCenter = new Vector3f();
+            if (pMirrorObject.isNotNull()) {
                 Structure objectStructure;
                 try {
-                    objectStructure = pObject.fetchData(blenderContext.getInputStream()).get(0);
+                    objectStructure = pMirrorObject.fetchData(blenderContext.getInputStream()).get(0);
                     ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
                     Node object = (Node) objectHelper.toObject(objectStructure, blenderContext);
                     if (object != null) {
-                        Vector3f translation = object.getWorldTranslation();
-                        center[0] = translation.x;
-                        center[1] = translation.y;
-                        center[2] = translation.z;
+                        // compute the mirror object coordinates in node's local space
+                        mirrorPlaneCenter = this.getWorldMatrix(node).invertLocal().mult(object.getWorldTranslation());
                     }
                 } catch (BlenderFileException e) {
                     LOGGER.log(Level.SEVERE, "Cannot load mirror''s reference object. Cause: {0}", e.getLocalizedMessage());
+                    LOGGER.log(Level.SEVERE, "Mirror modifier will not be applied to node named: {0}", node.getName());
+                    return;
                 }
             }
-            float tolerance = ((Number) modifierData.get("tolerance")).floatValue();
-            boolean mirrorU = (flag & 0x01) != 0;
-            boolean mirrorV = (flag & 0x02) != 0;
-            // boolean mirrorVGroup = (flag & 0x20) != 0;
 
+            LOGGER.finest("Allocating temporal variables.");
+            float d;
+            Vector3f mirrorPlaneNormal = new Vector3f();
+            Vector3f shiftVector = new Vector3f();
+            Vector3f point = new Vector3f();
+            Vector3f normal = new Vector3f();
             Set<Integer> modifiedIndexes = new HashSet<Integer>();
             List<Geometry> geometriesToAdd = new ArrayList<Geometry>();
+            final char[] mirrorNames = new char[] { 'X', 'Y', 'Z' };
+
+            LOGGER.fine("Mirroring mesh.");
             for (int mirrorIndex = 0; mirrorIndex < 3; ++mirrorIndex) {
                 if (isMirrored[mirrorIndex]) {
+                    boolean mirrorAtPoint0 = mirrorPlaneCenter.get(mirrorIndex) == 0;
+                    if (!mirrorAtPoint0) {// compute mirror's plane normal vector in node's space
+                        mirrorPlaneNormal.set(0, 0, 0).set(mirrorIndex, Math.signum(mirrorPlaneCenter.get(mirrorIndex)));
+                    }
+
                     for (Spatial spatial : node.getChildren()) {
                         if (spatial instanceof Geometry) {
                             Mesh mesh = ((Geometry) spatial).getMesh();
                             Mesh clone = mesh.deepClone();
 
-                            // getting buffers
+                            LOGGER.log(Level.FINEST, "Fetching buffers of cloned spatial: {0}", spatial.getName());
                             FloatBuffer position = mesh.getFloatBuffer(Type.Position);
                             FloatBuffer bindPosePosition = mesh.getFloatBuffer(Type.BindPosePosition);
 
@@ -121,34 +142,33 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper;
                                 int index = cloneIndexes instanceof ShortBuffer ? ((ShortBuffer) cloneIndexes).get(i) : ((IntBuffer) cloneIndexes).get(i);
                                 if (!modifiedIndexes.contains(index)) {
                                     modifiedIndexes.add(index);
-                                    int valueIndex = index * 3 + mirrorIndex;
 
-                                    float value = clonePosition.get(valueIndex);
-                                    float d = center[mirrorIndex] - value;
+                                    this.get(clonePosition, index, point);
+                                    if (mirrorAtPoint0) {
+                                        d = Math.abs(point.get(mirrorIndex));
+                                        shiftVector.set(0, 0, 0).set(mirrorIndex, -point.get(mirrorIndex));
+                                    } else {
+                                        d = this.computeDistanceFromPlane(point, mirrorPlaneCenter, mirrorPlaneNormal);
+                                        mirrorPlaneNormal.mult(d, shiftVector);
+                                    }
 
-                                    if (Math.abs(d) <= tolerance) {
-                                        clonePosition.put(valueIndex, center[mirrorIndex]);
-                                        if (cloneBindPosePosition != null) {
-                                            cloneBindPosePosition.put(valueIndex, center[mirrorIndex]);
-                                        }
-                                        position.put(valueIndex, center[mirrorIndex]);
-                                        if (bindPosePosition != null) {
-                                            bindPosePosition.put(valueIndex, center[mirrorIndex]);
-                                        }
-                                        
-                                        cloneNormals.put(valueIndex, 0);
-                                        if (cloneBindPoseNormals != null) {
-                                            cloneBindPoseNormals.put(valueIndex, 0);
+                                    if (merge && d <= tolerance) {
+                                        point.addLocal(shiftVector);
+
+                                        this.set(index, point, clonePosition, cloneBindPosePosition, position, bindPosePosition);
+                                        if (cloneNormals != null) {
+                                            this.get(cloneNormals, index, normal);
+                                            normal.set(mirrorIndex, 0);
+                                            this.set(index, normal, cloneNormals, cloneBindPoseNormals);
                                         }
                                     } else {
-                                        clonePosition.put(valueIndex, value + 2.0f * d);
-                                        if (cloneBindPosePosition != null) {
-                                            cloneBindPosePosition.put(valueIndex, value + 2.0f * d);
-                                        }
-                                        
-                                        cloneNormals.put(valueIndex, -cloneNormals.get(valueIndex));
-                                        if (cloneBindPoseNormals != null) {
-                                            cloneBindPoseNormals.put(valueIndex, -cloneNormals.get(valueIndex));
+                                        point.addLocal(shiftVector.multLocal(2));
+
+                                        this.set(index, point, clonePosition, cloneBindPosePosition);
+                                        if (cloneNormals != null) {
+                                            this.get(cloneNormals, index, normal);
+                                            normal.set(mirrorIndex, -normal.get(mirrorIndex));
+                                            this.set(index, normal, cloneNormals, cloneBindPoseNormals);
                                         }
                                     }
                                 }
@@ -156,7 +176,7 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper;
                             modifiedIndexes.clear();
 
                             LOGGER.finer("Flipping index order.");
-                            switch(mesh.getMode()) {
+                            switch (mesh.getMode()) {
                                 case Points:
                                     cloneIndexes.flip();
                                     break;
@@ -191,25 +211,27 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper;
                             }
 
                             if (mirrorU && clone.getBuffer(Type.TexCoord) != null) {
+                                LOGGER.finer("Mirroring U coordinates.");
                                 FloatBuffer cloneUVs = (FloatBuffer) clone.getBuffer(Type.TexCoord).getData();
                                 for (int i = 0; i < cloneUVs.limit(); i += 2) {
                                     cloneUVs.put(i, 1.0f - cloneUVs.get(i));
                                 }
                             }
                             if (mirrorV && clone.getBuffer(Type.TexCoord) != null) {
+                                LOGGER.finer("Mirroring V coordinates.");
                                 FloatBuffer cloneUVs = (FloatBuffer) clone.getBuffer(Type.TexCoord).getData();
                                 for (int i = 1; i < cloneUVs.limit(); i += 2) {
                                     cloneUVs.put(i, 1.0f - cloneUVs.get(i));
                                 }
                             }
 
-                            Geometry geometry = new Geometry(null, clone);
+                            Geometry geometry = new Geometry(spatial.getName() + " - mirror " + mirrorNames[mirrorIndex], clone);
                             geometry.setMaterial(((Geometry) spatial).getMaterial());
                             geometriesToAdd.add(geometry);
                         }
                     }
 
-                    // adding meshes to node
+                    LOGGER.log(Level.FINE, "Adding {0} geometries to current node.", geometriesToAdd.size());
                     for (Geometry geometry : geometriesToAdd) {
                         node.attachChild(geometry);
                     }
@@ -218,4 +240,69 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper;
             }
         }
     }
+
+    /**
+     * Fetches the world matrix transformation of the given node.
+     * @param node
+     *            the node
+     * @return the node's world transformation matrix
+     */
+    private Matrix4f getWorldMatrix(Node node) {
+        Matrix4f result = new Matrix4f();
+        result.setTranslation(node.getWorldTranslation());
+        result.setRotationQuaternion(node.getWorldRotation());
+        result.setScale(node.getWorldScale());
+        return result;
+    }
+
+    /**
+     * The method computes the distance between a point and a plane (described by point in space and normal vector).
+     * @param p
+     *            the point in the space
+     * @param c
+     *            mirror's plane center
+     * @param n
+     *            mirror's plane normal (should be normalized)
+     * @return the minimum distance from point to plane
+     */
+    private float computeDistanceFromPlane(Vector3f p, Vector3f c, Vector3f n) {
+        return Math.abs(n.dot(p) - c.dot(n));
+    }
+
+    /**
+     * Sets the given value (v) into every of the buffers at the given index.
+     * The index is cosidered to be an index of a vertex of the mesh.
+     * @param index
+     *            the index of vertex of the mesh
+     * @param value
+     *            the value to be set
+     * @param buffers
+     *            the buffers where the value will be set
+     */
+    private void set(int index, Vector3f value, FloatBuffer... buffers) {
+        index *= 3;
+        for (FloatBuffer buffer : buffers) {
+            if (buffer != null) {
+                buffer.put(index, value.x);
+                buffer.put(index + 1, value.y);
+                buffer.put(index + 2, value.z);
+            }
+        }
+    }
+
+    /**
+     * Fetches the vector's value from the given buffer at specified index.
+     * @param buffer
+     *            the buffer we get the data from
+     * @param index
+     *            the index of vertex of the mesh
+     * @param store
+     *            the vector where the result will be set
+     */
+    private void get(FloatBuffer buffer, int index, Vector3f store) {
+        index *= 3;
+        store.x = buffer.get(index);
+        store.y = buffer.get(index + 1);
+        store.z = buffer.get(index + 2);
+    }
 }