Selaa lähdekoodia

Feature: added support for bone envelopes.

jmekaelthas 11 vuotta sitten
vanhempi
commit
a2855c1cf0

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

@@ -560,7 +560,7 @@ public class BlenderContext {
      */
     public BoneContext getBoneContext(Bone bone) {
         for (Entry<Long, BoneContext> entry : boneContexts.entrySet()) {
-            if (entry.getValue().getBone().equals(bone)) {
+            if (entry.getValue().getBone().getName().equals(bone.getName())) {
                 return entry.getValue();
             }
         }

+ 18 - 3
jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/BoneContext.java

@@ -23,7 +23,8 @@ import com.jme3.scene.plugins.blender.objects.ObjectHelper;
  */
 public class BoneContext {
     // the flags of the bone
-    public static final int      CONNECTED_TO_PARENT                 = 0x10;
+    public static final int      CONNECTED_TO_PARENT                 = 0x0010;
+    public static final int      DEFORM                              = 0x1000;
 
     /**
      * The bones' matrices have, unlike objects', the coordinate system identical to JME's (Y axis is UP, X to the right and Z toward us).
@@ -54,6 +55,8 @@ public class BoneContext {
     private Bone                 bone;
     /** The length of the bone. */
     private float                length;
+    /** The bone's deform envelope. */
+    private BoneEnvelope         boneEnvelope;
 
     /**
      * Constructor. Creates the basic set of bone's data.
@@ -99,7 +102,7 @@ public class BoneContext {
 
         // first get the bone matrix in its armature space
         globalBoneMatrix = objectHelper.getMatrix(boneStructure, "arm_mat", blenderContext.getBlenderKey().isFixUpAxis());
-        if(blenderContext.getBlenderKey().isFixUpAxis()) {
+        if (blenderContext.getBlenderKey().isFixUpAxis()) {
             // then make sure it is rotated in a proper way to fit the jme bone transformation conventions
             globalBoneMatrix.multLocal(BONE_ARMATURE_TRANSFORMATION_MATRIX);
         }
@@ -111,6 +114,11 @@ public class BoneContext {
         // and now compute the final bone matrix in world space
         globalBoneMatrix = armatureWorldMatrix.mult(globalBoneMatrix);
 
+        // load the bone deformation envelope if necessary
+        if ((flag & DEFORM) == 0) {// if the flag is NOT set then the DEFORM is in use
+            boneEnvelope = new BoneEnvelope(boneStructure, armatureWorldMatrix, blenderContext.getBlenderKey().isFixUpAxis());
+        }
+
         // create the children
         List<Structure> childbase = ((Structure) boneStructure.getFieldValue("childbase")).evaluateListBase();
         for (Structure child : childbase) {
@@ -209,7 +217,7 @@ public class BoneContext {
     public Skeleton getSkeleton() {
         return blenderContext.getSkeleton(armatureObjectOMA);
     }
-    
+
     /**
      * @return the initial bone's matrix in model space
      */
@@ -217,6 +225,13 @@ public class BoneContext {
         return boneMatrixInModelSpace;
     }
 
+    /**
+     * @return the vertex assigning envelope of the bone
+     */
+    public BoneEnvelope getBoneEnvelope() {
+        return boneEnvelope;
+    }
+
     /**
      * Tells if the bone is of specified property defined by its flag.
      * @param flagMask

+ 133 - 0
jme3-blender/src/main/java/com/jme3/scene/plugins/blender/animations/BoneEnvelope.java

@@ -0,0 +1,133 @@
+package com.jme3.scene.plugins.blender.animations;
+
+import com.jme3.math.Matrix4f;
+import com.jme3.math.Vector3f;
+import com.jme3.scene.plugins.blender.file.DynamicArray;
+import com.jme3.scene.plugins.blender.file.Structure;
+
+/**
+ * An implementation of bone envelope. Used when assigning bones to the mesh by envelopes.
+ * 
+ * @author Marcin Roguski
+ */
+public class BoneEnvelope {
+    /** A defined distance that will be included in the envelope space. */
+    private float    distance;
+    /** The bone's weight. */
+    private float    weight;
+    /** The radius of the bone's head. */
+    private float    boneHeadRadius;
+    /** The radius of the bone's tail. */
+    private float    boneTailRadius;
+    /** Head position in rest pose in world space. */
+    private Vector3f head;
+    /** Tail position in rest pose in world space. */
+    private Vector3f tail;
+
+    /**
+     * The constructor of bone envelope. It reads all the needed data. Take notice that the positions of head and tail
+     * are computed in the world space and that the points' positions given for computations should be in world space as well.
+     * 
+     * @param boneStructure
+     *            the blender bone structure
+     * @param armatureWorldMatrix
+     *            the world matrix of the armature object
+     * @param fixUpAxis
+     *            a variable that tells if we use the Y-is up axis orientation
+     */
+    @SuppressWarnings("unchecked")
+    public BoneEnvelope(Structure boneStructure, Matrix4f armatureWorldMatrix, boolean fixUpAxis) {
+        distance = ((Number) boneStructure.getFieldValue("dist")).floatValue();
+        weight = ((Number) boneStructure.getFieldValue("weight")).floatValue();
+        boneHeadRadius = ((Number) boneStructure.getFieldValue("rad_head")).floatValue();
+        boneTailRadius = ((Number) boneStructure.getFieldValue("rad_tail")).floatValue();
+
+        DynamicArray<Number> headArray = (DynamicArray<Number>) boneStructure.getFieldValue("arm_head");
+        head = new Vector3f(headArray.get(0).floatValue(), headArray.get(1).floatValue(), headArray.get(2).floatValue());
+        if (fixUpAxis) {
+            float z = head.z;
+            head.z = -head.y;
+            head.y = z;
+        }
+        armatureWorldMatrix.mult(head, head);// move the head point to global space
+
+        DynamicArray<Number> tailArray = (DynamicArray<Number>) boneStructure.getFieldValue("arm_tail");
+        tail = new Vector3f(tailArray.get(0).floatValue(), tailArray.get(1).floatValue(), tailArray.get(2).floatValue());
+        if (fixUpAxis) {
+            float z = tail.z;
+            tail.z = -tail.y;
+            tail.y = z;
+        }
+        armatureWorldMatrix.mult(tail, tail);// move the tail point to global space
+    }
+
+    /**
+     * The method verifies if the given point is inside the envelope.
+     * @param point
+     *            the point in 3D space (MUST be in a world coordinate space)
+     * @return <b>true</b> if the point is inside the envelope and <b>false</b> otherwise
+     */
+    public boolean isInEnvelope(Vector3f point) {
+        Vector3f v = tail.subtract(head);
+        float boneLength = v.length();
+        v.normalizeLocal();
+
+        // computing a plane that contains 'point' and v is its normal vector
+        // the plane's equation is: Ax + By + Cz + D = 0, where v = [A, B, C]
+        float D = -v.dot(point);
+
+        // computing a point where a line that contains head and tail crosses the plane
+        float temp = -(v.dot(head) + D) / v.dot(v);
+        Vector3f p = head.add(v.x * temp, v.y * temp, v.z * temp);
+
+        // determining if the point p is on the same or other side of head than the tail point
+        Vector3f headToPointOnLineVector = p.subtract(head);
+        float headToPointLength = headToPointOnLineVector.length();
+        float cosinus = headToPointOnLineVector.dot(v) / headToPointLength;// the length of v is already = 1; cosinus should be either 1, 0 or -1
+        if (cosinus < 0 && headToPointLength > boneHeadRadius || headToPointLength > boneLength + boneTailRadius) {
+            return false;// the point is outside the anvelope
+        }
+
+        // now check if the point is inside and envelope
+        float pointDistanceFromLine = point.subtract(p).length(), maximumDistance = 0;
+        if (cosinus < 0) {
+            // checking if the distance from p to point is inside the half sphere defined by head envelope
+            // compute the distance from the line to the half sphere border
+            maximumDistance = boneHeadRadius;
+        } else if (headToPointLength < boneLength) {
+            // compute the maximum available distance
+            if (boneTailRadius > boneHeadRadius) {
+                // compute the distance from head to p
+                float headToPDistance = p.subtract(head).length();
+                // from tangens function we have
+                float x = headToPDistance * ((boneTailRadius - boneHeadRadius) / boneLength);
+                maximumDistance = x + boneHeadRadius;
+            } else if (boneTailRadius < boneHeadRadius) {
+                // compute the distance from head to p
+                float tailToPDistance = p.subtract(tail).length();
+                // from tangens function we have
+                float x = tailToPDistance * ((boneHeadRadius - boneTailRadius) / boneLength);
+                maximumDistance = x + boneTailRadius;
+            } else {
+                maximumDistance = boneTailRadius;
+            }
+        } else {
+            // checking if the distance from p to point is inside the half sphere defined by tail envelope
+            maximumDistance = boneTailRadius;
+        }
+
+        return pointDistanceFromLine <= maximumDistance + distance;
+    }
+
+    /**
+     * @return the weight of the bone
+     */
+    public float getWeight() {
+        return weight;
+    }
+
+    @Override
+    public String toString() {
+        return "BoneEnvelope [d=" + distance + ", w=" + weight + ", hr=" + boneHeadRadius + ", tr=" + boneTailRadius + ", (" + head + ") -> (" + tail + ")]";
+    }
+}

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

@@ -2,9 +2,12 @@ package com.jme3.scene.plugins.blender.meshes;
 
 import java.util.ArrayList;
 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;
 
 import com.jme3.scene.Geometry;
 
@@ -14,10 +17,17 @@ import com.jme3.scene.Geometry;
  * @author Marcin Roguski (Kaelthas)
  */
 public class MeshContext {
+    private static final Logger                       LOGGER       = Logger.getLogger(MeshContext.class.getName());
+
     /** A map between material index and the geometry. */
-    private Map<Integer, List<Geometry>>              geometries = new HashMap<Integer, List<Geometry>>();
+    private Map<Integer, List<Geometry>>              geometries   = new HashMap<Integer, List<Geometry>>();
     /** The vertex reference map. */
     private Map<Integer, Map<Integer, List<Integer>>> vertexReferenceMap;
+    /**
+     * A vertex group map. The key is the vertex group name and the value is the set of vertex groups.
+     * Linked hash map is used because the insertion order is important.
+     */
+    private LinkedHashMap<String, VertexGroup>        vertexGroups = new LinkedHashMap<String, VertexGroup>();
 
     /**
      * Adds a geometry for the specified material index.
@@ -85,4 +95,91 @@ public class MeshContext {
     public void setVertexReferenceMap(Map<Integer, Map<Integer, List<Integer>>> vertexReferenceMap) {
         this.vertexReferenceMap = vertexReferenceMap;
     }
+
+    /**
+     * Adds a new empty vertex group to the mesh context.
+     * @param name
+     *            the name of the vertex group
+     */
+    public void addVertexGroup(String name) {
+        if (!vertexGroups.containsKey(name)) {
+            vertexGroups.put(name, new VertexGroup());
+        } else {
+            LOGGER.log(Level.WARNING, "Vertex group already added: {0}", name);
+        }
+    }
+
+    /**
+     * Adds a vertex to the vertex group with specified index (the index is the order of adding a group).
+     * @param vertexIndex
+     *            the vertex index
+     * @param weight
+     *            the vertex weight
+     * @param vertexGroupIndex
+     *            the index of a vertex group
+     */
+    public void addVertexToGroup(int vertexIndex, float weight, int vertexGroupIndex) {
+        if (vertexGroupIndex < 0 || vertexGroupIndex >= vertexGroups.size()) {
+            throw new IllegalArgumentException("Invalid group index: " + vertexGroupIndex);
+        }
+        int counter = 0;
+        for (Entry<String, VertexGroup> vg : vertexGroups.entrySet()) {
+            if (vertexGroupIndex == counter) {
+                vg.getValue().addVertex(vertexIndex, weight);
+                return;
+            }
+            ++counter;
+        }
+    }
+
+    /**
+     * Returns a group with given name of null if such group does not exist.
+     * @param groupName
+     *            the name of a vertex group
+     * @return vertex group with the given name or null
+     */
+    public VertexGroup getGroup(String groupName) {
+        return vertexGroups.get(groupName);
+    }
+
+    /**
+     * A vertex group class that maps vertex index to its weight in a single group.
+     * The group will need to be set a bone index in order to prepare proper buffers for the jme mesh.
+     * But that information is available after the skeleton is loaded.
+     * 
+     * @author Marcin Roguski (Kaelthas)
+     */
+    public static class VertexGroup extends HashMap<Integer, Float> {
+        private static final long serialVersionUID = 5601646768279643957L;
+
+        /** The index of the bone f the vertex group is to be used for attaching vertices to bones. */
+        private int               boneIndex;
+
+        /**
+         * Adds a mapping between vertex index and its weight.
+         * @param index
+         *            the index of the vertex (in JME mesh)
+         * @param weight
+         *            the weight of the vertex
+         */
+        public void addVertex(int index, float weight) {
+            this.put(index, weight);
+        }
+
+        /**
+         * The method sets the bone index for the current vertex group.
+         * @param boneIndex
+         *            the index of the bone
+         */
+        public void setBoneIndex(int boneIndex) {
+            this.boneIndex = boneIndex;
+        }
+
+        /**
+         * @return the index of the bone
+         */
+        public int getBoneIndex() {
+            return boneIndex;
+        }
+    }
 }

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

@@ -94,14 +94,14 @@ public class MeshHelper extends AbstractBlenderHelper {
     /**
      * This method reads converts the given structure into mesh. The given structure needs to be filled with the appropriate data.
      * 
-     * @param structure
+     * @param meshStructure
      *            the structure we read the mesh from
      * @return the mesh feature
      * @throws BlenderFileException
      */
     @SuppressWarnings("unchecked")
-    public List<Geometry> toMesh(Structure structure, BlenderContext blenderContext) throws BlenderFileException {
-        List<Geometry> geometries = (List<Geometry>) blenderContext.getLoadedFeature(structure.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE);
+    public List<Geometry> toMesh(Structure meshStructure, BlenderContext blenderContext) throws BlenderFileException {
+        List<Geometry> geometries = (List<Geometry>) blenderContext.getLoadedFeature(meshStructure.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE);
         if (geometries != null) {
             List<Geometry> copiedGeometries = new ArrayList<Geometry>(geometries.size());
             for (Geometry geometry : geometries) {
@@ -110,7 +110,7 @@ public class MeshHelper extends AbstractBlenderHelper {
             return copiedGeometries;
         }
 
-        String name = structure.getName();
+        String name = meshStructure.getName();
         MeshContext meshContext = new MeshContext();
         LOGGER.log(Level.FINE, "Reading mesh: {0}.", name);
 
@@ -118,33 +118,22 @@ public class MeshHelper extends AbstractBlenderHelper {
         MaterialHelper materialHelper = blenderContext.getHelper(MaterialHelper.class);
         MaterialContext[] materials = null;
         if ((blenderContext.getBlenderKey().getFeaturesToLoad() & FeaturesToLoad.MATERIALS) != 0) {
-            materials = materialHelper.getMaterials(structure, blenderContext);
+            materials = materialHelper.getMaterials(meshStructure, blenderContext);
         }
 
         LOGGER.fine("Reading vertices.");
-        MeshBuilder meshBuilder = new MeshBuilder(structure, materials, blenderContext);
+        MeshBuilder meshBuilder = new MeshBuilder(meshStructure, materials, blenderContext);
         if (meshBuilder.isEmpty()) {
             LOGGER.fine("The geometry is empty.");
             geometries = new ArrayList<Geometry>(0);
-            blenderContext.addLoadedFeatures(structure.getOldMemoryAddress(), structure.getName(), structure, geometries);
-            blenderContext.setMeshContext(structure.getOldMemoryAddress(), meshContext);
+            blenderContext.addLoadedFeatures(meshStructure.getOldMemoryAddress(), meshStructure.getName(), meshStructure, geometries);
+            blenderContext.setMeshContext(meshStructure.getOldMemoryAddress(), meshContext);
             return geometries;
         }
-
         meshContext.setVertexReferenceMap(meshBuilder.getVertexReferenceMap());
 
-        LOGGER.fine("Reading vertices groups (from the Object structure).");
-        Structure parent = blenderContext.peekParent();
-        Structure defbase = (Structure) parent.getFieldValue("defbase");
-        List<Structure> defs = defbase.evaluateListBase();
-        String[] verticesGroups = new String[defs.size()];
-        int defIndex = 0;
-        for (Structure def : defs) {
-            verticesGroups[defIndex++] = def.getFieldValue("name").toString();
-        }
-
         LOGGER.fine("Reading custom properties.");
-        Properties properties = this.loadProperties(structure, blenderContext);
+        Properties properties = this.loadProperties(meshStructure, blenderContext);
 
         LOGGER.fine("Generating meshes.");
         Map<Integer, List<Mesh>> meshes = meshBuilder.buildMeshes();
@@ -162,9 +151,45 @@ public class MeshHelper extends AbstractBlenderHelper {
             }
         }
 
+        LOGGER.fine("Reading vertices groups.");// this MUST be done AFTER meshes are built, because otherwise we have no vertex references maps
+        Structure parent = blenderContext.peekParent();
+        Structure defbase = (Structure) parent.getFieldValue("defbase");
+        List<Structure> defs = defbase.evaluateListBase();
+        for (Structure def : defs) {
+            meshContext.addVertexGroup(def.getFieldValue("name").toString());
+        }
+
+        Pointer pDvert = (Pointer) meshStructure.getFieldValue("dvert");// dvert = DeformVERTices
+        if (pDvert.isNotNull()) {// assigning weights and bone indices
+            List<Structure> dverts = pDvert.fetchData();
+            int blenderVertexIndex = 0;
+            for (Structure dvert : dverts) {
+                Pointer pDW = (Pointer) dvert.getFieldValue("dw");
+                if (pDW.isNotNull()) {
+                    List<Structure> dw = pDW.fetchData();
+                    for (Structure deformWeight : dw) {
+                        int groupIndex = ((Number) deformWeight.getFieldValue("def_nr")).intValue();
+                        float weight = ((Number) deformWeight.getFieldValue("weight")).floatValue();
+
+                        // we need to use JME vertex index here and NOT blender vertex index
+                        for (Entry<Integer, Map<Integer, List<Integer>>> vertexReferenceMap : meshBuilder.getVertexReferenceMap().entrySet()) {// iterate through the meshes [key is the material index]
+                            for (Entry<Integer, List<Integer>> vertexEntry : vertexReferenceMap.getValue().entrySet()) {// iterate through the vertex references for the specified material
+                                if (vertexEntry.getKey().intValue() == blenderVertexIndex) {// if the indexes match then ...
+                                    for (Integer jmeVertexIndex : vertexEntry.getValue()) {// ... add all jme vertices to the specified group
+                                        meshContext.addVertexToGroup(jmeVertexIndex, weight, groupIndex);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                ++blenderVertexIndex;
+            }
+        }
+
         // store the data in blender context before applying the material
-        blenderContext.addLoadedFeatures(structure.getOldMemoryAddress(), structure.getName(), structure, geometries);
-        blenderContext.setMeshContext(structure.getOldMemoryAddress(), meshContext);
+        blenderContext.addLoadedFeatures(meshStructure.getOldMemoryAddress(), meshStructure.getName(), meshStructure, geometries);
+        blenderContext.setMeshContext(meshStructure.getOldMemoryAddress(), meshContext);
 
         // apply materials only when all geometries are in place
         if (materials != null) {
@@ -175,7 +200,7 @@ public class MeshHelper extends AbstractBlenderHelper {
                 } else if (materials[materialNumber] != null) {
                     LinkedHashMap<String, List<Vector2f>> uvCoordinates = meshBuilder.getUVCoordinates(materialNumber);
                     MaterialContext materialContext = materials[materialNumber];
-                    materialContext.applyMaterial(geometry, structure.getOldMemoryAddress(), uvCoordinates, blenderContext);
+                    materialContext.applyMaterial(geometry, meshStructure.getOldMemoryAddress(), uvCoordinates, blenderContext);
                 } else {
                     geometry.setMaterial(blenderContext.getDefaultMaterial());
                     LOGGER.warning("The importer came accross mesh that points to a null material. Default material is used to prevent loader from crashing, " + "but the model might look not the way it should. Sometimes blender does not assign materials properly. " + "Enter the edit mode and assign materials once more to your faces.");
@@ -203,7 +228,7 @@ public class MeshHelper extends AbstractBlenderHelper {
                     geometry.setMaterial(this.getBlackUnshadedMaterial(blenderContext));
                 } else {
                     Material defaultMaterial = blenderContext.getDefaultMaterial();
-                    if(geometry.getMesh().getBuffer(Type.Color) != null) {
+                    if (geometry.getMesh().getBuffer(Type.Color) != null) {
                         defaultMaterial = defaultMaterial.clone();
                         defaultMaterial.setBoolean("VertexColor", true);
                     }

+ 237 - 273
jme3-blender/src/main/java/com/jme3/scene/plugins/blender/modifiers/ArmatureModifier.java

@@ -1,21 +1,26 @@
 package com.jme3.scene.plugins.blender.modifiers;
 
+import java.nio.Buffer;
 import java.nio.ByteBuffer;
 import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.ShortBuffer;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.TreeMap;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import com.jme3.animation.Bone;
 import com.jme3.animation.Skeleton;
+import com.jme3.math.Matrix4f;
+import com.jme3.math.Vector3f;
 import com.jme3.scene.Geometry;
 import com.jme3.scene.Mesh;
 import com.jme3.scene.Node;
+import com.jme3.scene.Spatial;
 import com.jme3.scene.VertexBuffer;
 import com.jme3.scene.VertexBuffer.Format;
 import com.jme3.scene.VertexBuffer.Type;
@@ -24,10 +29,13 @@ import com.jme3.scene.plugins.blender.BlenderContext;
 import com.jme3.scene.plugins.blender.BlenderContext.LoadedFeatureDataType;
 import com.jme3.scene.plugins.blender.animations.AnimationHelper;
 import com.jme3.scene.plugins.blender.animations.BoneContext;
+import com.jme3.scene.plugins.blender.animations.BoneEnvelope;
+import com.jme3.scene.plugins.blender.constraints.ConstraintHelper;
 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.MeshContext;
+import com.jme3.scene.plugins.blender.meshes.MeshContext.VertexGroup;
 import com.jme3.util.BufferUtils;
 
 /**
@@ -39,13 +47,20 @@ import com.jme3.util.BufferUtils;
     private static final Logger LOGGER                     = Logger.getLogger(ArmatureModifier.class.getName());
     private static final int    MAXIMUM_WEIGHTS_PER_VERTEX = 4;                                                 // JME
 
+    private static final int    FLAG_VERTEX_GROUPS         = 0x01;
+    private static final int    FLAG_BONE_ENVELOPES        = 0x02;
+
     private Structure           armatureObject;
     private Skeleton            skeleton;
-    private Structure           objectStructure;
     private Structure           meshStructure;
-
+    /** The wold transform matrix of the armature object. */
+    private Matrix4f            objectWorldMatrix;
     /** Old memory address of the mesh that will have the skeleton applied. */
     private Long                meshOMA;
+    /** The variable tells if the vertex groups of the mesh should be used to assign verts to bones. */
+    private boolean             useVertexGroups;
+    /** The variable tells if the bones' envelopes should be used to assign verts to bones. */
+    private boolean             useBoneEnvelopes;
 
     /**
      * This constructor reads animation data from the object structore. The
@@ -66,24 +81,35 @@ import com.jme3.util.BufferUtils;
         if (this.validate(modifierStructure, blenderContext)) {
             Pointer pArmatureObject = (Pointer) modifierStructure.getFieldValue("object");
             if (pArmatureObject.isNotNull()) {
-                armatureObject = pArmatureObject.fetchData().get(0);
-
-                // load skeleton
-                Structure armatureStructure = ((Pointer) armatureObject.getFieldValue("data")).fetchData().get(0);
-                List<Structure> bonebase = ((Structure) armatureStructure.getFieldValue("bonebase")).evaluateListBase();
-                List<Bone> bonesList = new ArrayList<Bone>();
-                for (int i = 0; i < bonebase.size(); ++i) {
-                    this.buildBones(armatureObject.getOldMemoryAddress(), bonebase.get(i), null, bonesList, objectStructure.getOldMemoryAddress(), blenderContext);
+                int deformflag = ((Number) modifierStructure.getFieldValue("deformflag")).intValue();
+                useVertexGroups = (deformflag & FLAG_VERTEX_GROUPS) != 0;
+                useBoneEnvelopes = (deformflag & FLAG_BONE_ENVELOPES) != 0;
+                modifying = useBoneEnvelopes || useVertexGroups;
+                if (modifying) {// if neither option is used the modifier will not modify anything anyway
+                    armatureObject = pArmatureObject.fetchData().get(0);
+
+                    // load skeleton
+                    Structure armatureStructure = ((Pointer) armatureObject.getFieldValue("data")).fetchData().get(0);
+                    List<Structure> bonebase = ((Structure) armatureStructure.getFieldValue("bonebase")).evaluateListBase();
+                    List<Bone> bonesList = new ArrayList<Bone>();
+                    for (int i = 0; i < bonebase.size(); ++i) {
+                        this.buildBones(armatureObject.getOldMemoryAddress(), bonebase.get(i), null, bonesList, objectStructure.getOldMemoryAddress(), blenderContext);
+                    }
+                    bonesList.add(0, new Bone(""));
+                    Bone[] bones = bonesList.toArray(new Bone[bonesList.size()]);
+                    skeleton = new Skeleton(bones);
+                    blenderContext.setSkeleton(armatureObject.getOldMemoryAddress(), skeleton);
+                    this.meshStructure = meshStructure;
+
+                    // read mesh indexes
+                    meshOMA = meshStructure.getOldMemoryAddress();
+
+                    if (useBoneEnvelopes) {
+                        ConstraintHelper constraintHelper = blenderContext.getHelper(ConstraintHelper.class);
+                        Spatial object = (Spatial) blenderContext.getLoadedFeature(objectStructure.getOldMemoryAddress(), LoadedFeatureDataType.LOADED_FEATURE);
+                        objectWorldMatrix = constraintHelper.toMatrix(object.getWorldTransform(), new Matrix4f());
+                    }
                 }
-                bonesList.add(0, new Bone(""));
-                Bone[] bones = bonesList.toArray(new Bone[bonesList.size()]);
-                skeleton = new Skeleton(bones);
-                blenderContext.setSkeleton(armatureObject.getOldMemoryAddress(), skeleton);
-                this.objectStructure = objectStructure;
-                this.meshStructure = meshStructure;
-
-                // read mesh indexes
-                meshOMA = meshStructure.getOldMemoryAddress();
             } else {
                 modifying = false;
             }
@@ -114,35 +140,6 @@ import com.jme3.util.BufferUtils;
         bc.buildBone(result, spatialOMA, blenderContext);
     }
 
-    /**
-     * This method returns a map where the key is the object's group index that
-     * is used by a bone and the key is the bone index in the armature.
-     * 
-     * @param defBaseStructure
-     *            a bPose structure of the object
-     * @return bone group-to-index map
-     * @throws BlenderFileException
-     *             this exception is thrown when the blender file is somehow
-     *             corrupted
-     */
-    public Map<Integer, Integer> getGroupToBoneIndexMap(Structure defBaseStructure, Skeleton skeleton) throws BlenderFileException {
-        Map<Integer, Integer> result = null;
-        if (skeleton.getBoneCount() != 0) {
-            result = new HashMap<Integer, Integer>();
-            List<Structure> deformGroups = defBaseStructure.evaluateListBase();// bDeformGroup
-            int groupIndex = 0;
-            for (Structure deformGroup : deformGroups) {
-                String deformGroupName = deformGroup.getFieldValue("name").toString();
-                int boneIndex = skeleton.getBoneIndex(deformGroupName);
-                if (boneIndex >= 0) {
-                    result.put(groupIndex, boneIndex);
-                }
-                ++groupIndex;
-            }
-        }
-        return result;
-    }
-
     @Override
     @SuppressWarnings("unchecked")
     public void apply(Node node, BlenderContext blenderContext) {
@@ -153,39 +150,33 @@ import com.jme3.util.BufferUtils;
             // setting weights for bones
             List<Geometry> geomList = (List<Geometry>) blenderContext.getLoadedFeature(meshOMA, LoadedFeatureDataType.LOADED_FEATURE);
             MeshContext meshContext = blenderContext.getMeshContext(meshOMA);
-            int[] bonesGroups = new int[] { 0 };
             for (Geometry geom : geomList) {
                 int materialIndex = meshContext.getMaterialIndex(geom);
                 Mesh mesh = geom.getMesh();
 
-                try {
-                    VertexBuffer[] buffers = this.readVerticesWeightsData(objectStructure, meshStructure, skeleton, materialIndex, bonesGroups, blenderContext);
-                    if (buffers != null) {
-                        mesh.setMaxNumWeights(bonesGroups[0]);
-                        mesh.setBuffer(buffers[0]);
-                        mesh.setBuffer(buffers[1]);
-
-                        LOGGER.fine("Generating bind pose and normal buffers.");
-                        mesh.generateBindPose(true);
-
-                        // change the usage type of vertex and normal buffers from
-                        // Static to Stream
-                        mesh.getBuffer(Type.Position).setUsage(Usage.Stream);
-                        mesh.getBuffer(Type.Normal).setUsage(Usage.Stream);
-
-                        // creating empty buffers for HW skinning
-                        // the buffers will be setup if ever used.
-                        VertexBuffer verticesWeightsHW = new VertexBuffer(Type.HWBoneWeight);
-                        VertexBuffer verticesWeightsIndicesHW = new VertexBuffer(Type.HWBoneIndex);
-                        mesh.setBuffer(verticesWeightsHW);
-                        mesh.setBuffer(verticesWeightsIndicesHW);
-                    }
-                } catch (BlenderFileException e) {
-                    LOGGER.log(Level.SEVERE, e.getLocalizedMessage(), e);
-                    invalid = true;
+                MeshWeightsData buffers = this.readVerticesWeightsData(meshContext, skeleton, materialIndex, mesh, blenderContext);
+                if (buffers != null) {
+                    mesh.setMaxNumWeights(buffers.maximumWeightsPerVertex);
+                    mesh.setBuffer(buffers.verticesWeights);
+                    mesh.setBuffer(buffers.verticesWeightsIndices);
+
+                    LOGGER.fine("Generating bind pose and normal buffers.");
+                    mesh.generateBindPose(true);
+
+                    // change the usage type of vertex and normal buffers from
+                    // Static to Stream
+                    mesh.getBuffer(Type.Position).setUsage(Usage.Stream);
+                    mesh.getBuffer(Type.Normal).setUsage(Usage.Stream);
+
+                    // creating empty buffers for HW skinning
+                    // the buffers will be setup if ever used.
+                    VertexBuffer verticesWeightsHW = new VertexBuffer(Type.HWBoneWeight);
+                    VertexBuffer verticesWeightsIndicesHW = new VertexBuffer(Type.HWBoneIndex);
+                    mesh.setBuffer(verticesWeightsHW);
+                    mesh.setBuffer(verticesWeightsIndicesHW);
                 }
             }
-            
+
             AnimationHelper animationHelper = blenderContext.getHelper(AnimationHelper.class);
             animationHelper.applyAnimations(node, skeleton, blenderContext.getBlenderKey().getSkeletonAnimationNames(node.getName()));
             node.updateModelBound();
@@ -193,235 +184,208 @@ import com.jme3.util.BufferUtils;
     }
 
     /**
-     * This method reads mesh indexes
+     * Reads the vertices data and prepares appropriate buffers to be added to the mesh. There is a bone index buffer and weitghts buffer.
      * 
-     * @param objectStructure
-     *            structure of the object that has the armature modifier applied
-     * @param meshStructure
-     *            the structure of the object's mesh
+     * @param meshContext
+     *            the mesh context
+     * @param skeleton
+     *            the current skeleton
+     * @param materialIndex
+     *            the material index
+     * @param mesh
+     *            the mesh we create the buffers for
      * @param blenderContext
      *            the blender context
-     * @throws BlenderFileException
-     *             this exception is thrown when the blend file structure is
-     *             somehow invalid or corrupted
+     * @return an instance that aggregates all needed data for the mesh
      */
-    private VertexBuffer[] readVerticesWeightsData(Structure objectStructure, Structure meshStructure, Skeleton skeleton, int materialIndex, int[] bonesGroups, BlenderContext blenderContext) throws BlenderFileException {
-        Structure defBase = (Structure) objectStructure.getFieldValue("defbase");
-        Map<Integer, Integer> groupToBoneIndexMap = this.getGroupToBoneIndexMap(defBase, skeleton);
+    private MeshWeightsData readVerticesWeightsData(MeshContext meshContext, Skeleton skeleton, int materialIndex, Mesh mesh, BlenderContext blenderContext) {
+        int vertexListSize = meshContext.getVertexCount(materialIndex);
+        Map<Integer, List<Integer>> vertexReferenceMap = meshContext.getVertexReferenceMap(materialIndex);
 
-        MeshContext meshContext = blenderContext.getMeshContext(meshStructure.getOldMemoryAddress());
+        Map<String, VertexGroup> vertexGroups = new HashMap<String, VertexGroup>();
+        Buffer indexes = mesh.getBuffer(Type.Index).getData();
+        FloatBuffer positions = mesh.getFloatBuffer(Type.Position);
 
-        return this.getBoneWeightAndIndexBuffer(meshStructure, meshContext.getVertexCount(materialIndex), bonesGroups, meshContext.getVertexReferenceMap(materialIndex), groupToBoneIndexMap);
-    }
+        int maximumWeightsPerVertex = 0;
+        if (useVertexGroups) {
+            LOGGER.fine("Attaching verts to bones using vertex groups.");
+            for (int boneIndex = 1; boneIndex < skeleton.getBoneCount(); ++boneIndex) {// bone with index 0 is a root bone
+                Bone bone = skeleton.getBone(boneIndex);
+                VertexGroup vertexGroup = meshContext.getGroup(bone.getName());
+                if (vertexGroup != null) {
+                    vertexGroup.setBoneIndex(boneIndex);
+                    vertexGroups.put(bone.getName(), vertexGroup);
+                }
+            }
+        }
 
-    /**
-     * This method returns an array of size 2. The first element is a vertex
-     * buffer holding bone weights for every vertex in the model. The second
-     * element is a vertex buffer holding bone indices for vertices (the indices
-     * of bones the vertices are assigned to).
-     * 
-     * @param meshStructure
-     *            the mesh structure object
-     * @param vertexListSize
-     *            a number of vertices in the model
-     * @param bonesGroups
-     *            this is an output parameter, it should be a one-sized array;
-     *            the maximum amount of weights per vertex (up to
-     *            MAXIMUM_WEIGHTS_PER_VERTEX) is stored there
-     * @param vertexReferenceMap
-     *            this reference map allows to map the original vertices read
-     *            from blender to vertices that are really in the model; one
-     *            vertex may appear several times in the result model
-     * @param groupToBoneIndexMap
-     *            this object maps the group index (to which a vertices in
-     *            blender belong) to bone index of the model
-     * @return arrays of vertices weights and their bone indices and (as an
-     *         output parameter) the maximum amount of weights for a vertex
-     * @throws BlenderFileException
-     *             this exception is thrown when the blend file structure is
-     *             somehow invalid or corrupted
-     */
-    private VertexBuffer[] getBoneWeightAndIndexBuffer(Structure meshStructure, int vertexListSize, int[] bonesGroups, Map<Integer, List<Integer>> vertexReferenceMap, Map<Integer, Integer> groupToBoneIndexMap) throws BlenderFileException {
-        bonesGroups[0] = 0;
-        Pointer pDvert = (Pointer) meshStructure.getFieldValue("dvert");// dvert = DeformVERTices
-        FloatBuffer weightsFloatData = BufferUtils.createFloatBuffer(vertexListSize * MAXIMUM_WEIGHTS_PER_VERTEX);
-        ByteBuffer indicesData = BufferUtils.createByteBuffer(vertexListSize * MAXIMUM_WEIGHTS_PER_VERTEX);
+        if (useBoneEnvelopes) {
+            LOGGER.fine("Attaching verts to bones using bone envelopes.");
+            Vector3f pos = new Vector3f();
 
-        if (pDvert.isNotNull()) {// assigning weights and bone indices
-            boolean warnAboutTooManyVertexWeights = false;
-            // dverts.size() = verticesAmount (one dvert per vertex in blender)
-            List<Structure> dverts = pDvert.fetchData();
-            int vertexIndex = 0;
-            // use tree map to sort weights from the lowest to the highest ones
-            TreeMap<Float, Integer> weightToIndexMap = new TreeMap<Float, Integer>();
-
-            for (Structure dvert : dverts) {
-                // we fetch the referenced vertices here
-                List<Integer> vertexIndices = vertexReferenceMap.get(Integer.valueOf(vertexIndex));
-                if (vertexIndices != null) {
-                    // total amount of wights assigned to the vertex (max. 4 in JME)
-                    int totweight = ((Number) dvert.getFieldValue("totweight")).intValue();
-                    Pointer pDW = (Pointer) dvert.getFieldValue("dw");
-                    if (totweight > 0 && groupToBoneIndexMap != null) {
-                        weightToIndexMap.clear();
-                        int weightIndex = 0;
-                        List<Structure> dw = pDW.fetchData();
-                        for (Structure deformWeight : dw) {
-                            Integer boneIndex = groupToBoneIndexMap.get(((Number) deformWeight.getFieldValue("def_nr")).intValue());
-                            float weight = ((Number) deformWeight.getFieldValue("weight")).floatValue();
-                            // boneIndex == null: it here means that we came
-                            // accross group that has no bone attached to, so
-                            // simply ignore it
-                            // if weight == 0 and weightIndex == 0 then ignore
-                            // the weight (do not set weight = 0 as a first
-                            // weight)
-                            if (boneIndex != null && (weight > 0.0f || weightIndex > 0)) {
-                                if (weightIndex < MAXIMUM_WEIGHTS_PER_VERTEX) {
-                                    if (weight == 0.0f) {
-                                        boneIndex = Integer.valueOf(0);
-                                    }
-                                    // we apply the weight to all referenced
-                                    // vertices
-                                    for (Integer index : vertexIndices) {
-                                        weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, weight);
-                                        indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + weightIndex, boneIndex.byteValue());
-                                    }
-                                    weightToIndexMap.put(weight, weightIndex);
-                                    bonesGroups[0] = Math.max(bonesGroups[0], weightIndex + 1);
-                                } else if (weight > 0) {// if weight is zero the
-                                                        // simply ignore it
-                                    warnAboutTooManyVertexWeights = true;
-                                    Entry<Float, Integer> lowestWeightAndIndex = weightToIndexMap.firstEntry();
-                                    if (lowestWeightAndIndex != null && lowestWeightAndIndex.getKey() < weight) {
-                                        // we apply the weight to all referenced
-                                        // vertices
-                                        for (Integer index : vertexIndices) {
-                                            weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + lowestWeightAndIndex.getValue(), weight);
-                                            indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + lowestWeightAndIndex.getValue(), boneIndex.byteValue());
-                                        }
-                                        weightToIndexMap.remove(lowestWeightAndIndex.getKey());
-                                        weightToIndexMap.put(weight, lowestWeightAndIndex.getValue());
-                                    }
+            for (int boneIndex = 1; boneIndex < skeleton.getBoneCount(); ++boneIndex) {// bone with index 0 is a root bone
+                Bone bone = skeleton.getBone(boneIndex);
+                BoneContext boneContext = blenderContext.getBoneContext(bone);
+                BoneEnvelope boneEnvelope = boneContext.getBoneEnvelope();
+                if (boneEnvelope != null) {
+                    VertexGroup vertexGroup = vertexGroups.get(bone.getName());
+                    if (vertexGroup == null) {
+                        vertexGroup = new VertexGroup();
+                        vertexGroups.put(bone.getName(), vertexGroup);
+                    }
+                    vertexGroup.setBoneIndex(boneIndex);
+
+                    for (Entry<Integer, List<Integer>> entry : vertexReferenceMap.entrySet()) {
+                        List<Integer> vertexIndices = entry.getValue();
+                        for (int j = 0; j < indexes.limit(); ++j) {
+                            int index = indexes instanceof ShortBuffer ? ((ShortBuffer) indexes).get(j) : ((IntBuffer) indexes).get(j);
+                            if (vertexIndices.contains(index)) {// current geometry has the index assigned to the current mesh
+                                int ii = index * 3;
+                                pos.set(positions.get(ii), positions.get(ii + 1), positions.get(ii + 2));
+                                // move the vertex to the global space position
+                                objectWorldMatrix.mult(pos, pos);// TODO: optimize: check every vertex once and apply its references
+                                if (boneEnvelope.isInEnvelope(pos)) {
+                                    vertexGroup.addVertex(index, boneEnvelope.getWeight());
+                                } else if (boneIndex == 5) {
+                                    System.out.println("Siê nie za³apa³: " + pos);
                                 }
-                                ++weightIndex;
                             }
                         }
-                    } else {
-                        // 0.0 weight indicates, do not transform this vertex,
-                        // but keep it in bind pose.
-                        for (Integer index : vertexIndices) {
-                            weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, 0.0f);
-                            indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, (byte) 0);
-                        }
                     }
                 }
-                ++vertexIndex;
+            }
+        }
+
+        Map<Integer, WeightsAndBoneIndexes> weights = new HashMap<Integer, WeightsAndBoneIndexes>();// [vertex_index; [bone_index; weight]]
+        if (vertexGroups.size() > 0) {
+            LOGGER.fine("Gathering vertex groups information to prepare the buffers for the mesh.");
+            for (VertexGroup vertexGroup : vertexGroups.values()) {
+                for (Entry<Integer, Float> entry : vertexGroup.entrySet()) {
+                    WeightsAndBoneIndexes vertexWeights = weights.get(entry.getKey());
+                    if (vertexWeights == null) {
+                        vertexWeights = new WeightsAndBoneIndexes();
+                        weights.put(entry.getKey(), vertexWeights);
+                    }
+                    vertexWeights.put(vertexGroup.getBoneIndex(), entry.getValue());
+                }
+            }
+
+            LOGGER.log(Level.FINE, "Equalizing the amount of weights per vertex to {0} if any of them has more or less.", MAXIMUM_WEIGHTS_PER_VERTEX);
+            for (Entry<Integer, WeightsAndBoneIndexes> entry : weights.entrySet()) {
+                maximumWeightsPerVertex = Math.max(maximumWeightsPerVertex, entry.getValue().size());
+                entry.getValue().normalize(MAXIMUM_WEIGHTS_PER_VERTEX);
             }
 
-            if (warnAboutTooManyVertexWeights) {
+            if (maximumWeightsPerVertex > MAXIMUM_WEIGHTS_PER_VERTEX) {
                 LOGGER.log(Level.WARNING, "{0} has vertices with more than 4 weights assigned. The model may not behave as it should.", meshStructure.getName());
+                maximumWeightsPerVertex = MAXIMUM_WEIGHTS_PER_VERTEX;// normalization already made at most 'MAXIMUM_WEIGHTS_PER_VERTEX' weights per vertex
             }
-        } else {
-            // always bind all vertices to 0-indexed bone
-            // this bone makes the model look normally if vertices have no bone
-            // assigned and it is used in object animation, so if we come
-            // accross object
-            // animation we can use the 0-indexed bone for this
-            for (List<Integer> vertexIndexList : vertexReferenceMap.values()) {
-                // we apply the weight to all referenced vertices
-                for (Integer index : vertexIndexList) {
-                    weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, 1.0f);
-                    indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, (byte) 0);
+        }
+
+        LOGGER.fine("Preparing buffers for the mesh.");
+        FloatBuffer weightsFloatData = BufferUtils.createFloatBuffer(vertexListSize * MAXIMUM_WEIGHTS_PER_VERTEX);
+        ByteBuffer indicesData = BufferUtils.createByteBuffer(vertexListSize * MAXIMUM_WEIGHTS_PER_VERTEX);
+        for (int i = 0; i < indexes.limit(); ++i) {
+            int index = indexes instanceof ShortBuffer ? ((ShortBuffer) indexes).get(i) : ((IntBuffer) indexes).get(i);
+            WeightsAndBoneIndexes weightsAndBoneIndexes = weights.get(index);
+            if (weightsAndBoneIndexes != null) {
+                int count = 0;
+                for (Entry<Integer, Float> entry : weightsAndBoneIndexes.entrySet()) {
+                    weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + count, entry.getValue());
+                    indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX + count, entry.getKey().byteValue());
+                    ++count;
                 }
+            } else {
+                // if no bone is assigned to this vertex then attach it to the 0-indexed root bone
+                weightsFloatData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, 1.0f);
+                indicesData.put(index * MAXIMUM_WEIGHTS_PER_VERTEX, (byte) 0);
             }
         }
-
-        bonesGroups[0] = Math.max(bonesGroups[0], 1);
-
-        this.endBoneAssigns(vertexListSize, weightsFloatData);
         VertexBuffer verticesWeights = new VertexBuffer(Type.BoneWeight);
-        verticesWeights.setupData(Usage.CpuOnly, bonesGroups[0], Format.Float, weightsFloatData);
+        verticesWeights.setupData(Usage.CpuOnly, maximumWeightsPerVertex, Format.Float, weightsFloatData);
 
         VertexBuffer verticesWeightsIndices = new VertexBuffer(Type.BoneIndex);
-        verticesWeightsIndices.setupData(Usage.CpuOnly, bonesGroups[0], Format.UnsignedByte, indicesData);
-        return new VertexBuffer[] { verticesWeights, verticesWeightsIndices };
+        verticesWeightsIndices.setupData(Usage.CpuOnly, maximumWeightsPerVertex, Format.UnsignedByte, indicesData);
+
+        return new MeshWeightsData(maximumWeightsPerVertex, verticesWeights, verticesWeightsIndices);
     }
 
     /**
-     * Normalizes weights if needed and finds largest amount of weights used for
-     * all vertices in the buffer.
+     * A class that gathers the data for mesh bone buffers.
+     * Added to increase code readability.
      * 
-     * @param vertCount
-     *            amount of vertices
-     * @param weightsFloatData
-     *            weights for vertices
+     * @author Marcin Roguski (Kaelthas)
      */
-    private void endBoneAssigns(int vertCount, FloatBuffer weightsFloatData) {
-        weightsFloatData.rewind();
-        float[] weights = new float[MAXIMUM_WEIGHTS_PER_VERTEX];
-        for (int v = 0; v < vertCount; ++v) {
+    private static class MeshWeightsData {
+        public final int          maximumWeightsPerVertex;
+        public final VertexBuffer verticesWeights;
+        public final VertexBuffer verticesWeightsIndices;
+
+        public MeshWeightsData(int maximumWeightsPerVertex, VertexBuffer verticesWeights, VertexBuffer verticesWeightsIndices) {
+            this.maximumWeightsPerVertex = maximumWeightsPerVertex;
+            this.verticesWeights = verticesWeights;
+            this.verticesWeightsIndices = verticesWeightsIndices;
+        }
+    }
+
+    /**
+     * A map between the bone index and the bone's weight.
+     * 
+     * @author Marcin Roguski (Kaelthas)
+     */
+    private static class WeightsAndBoneIndexes extends HashMap<Integer, Float> {
+        private static final long serialVersionUID = 2754299007299077459L;
+
+        /**
+         * The method normalizes the weights and bone indexes data.
+         * First it truncates the amount to MAXIMUM_WEIGHTS_PER_VERTEX because this is how many weights JME can handle.
+         * Next it normalizes the weights so that the sum of all verts is 1.
+         * @param maximumSize
+         *            the maximum size that the data will be truncated to (usually: MAXIMUM_WEIGHTS_PER_VERTEX)
+         */
+        public void normalize(int maximumSize) {
+            if (this.size() > maximumSize) {// select only the most significant weights
+                float lowestWeight = Float.MAX_VALUE;
+                int lowestWeightIndex = -1;
+                HashMap<Integer, Float> msw = new HashMap<Integer, Float>(maximumSize);// msw = Most Significant Weight
+                for (Entry<Integer, Float> entry : this.entrySet()) {
+                    if (msw.size() < maximumSize) {
+                        msw.put(entry.getKey(), entry.getValue());
+                        if (entry.getValue() < lowestWeight) {
+                            lowestWeight = entry.getValue();
+                            lowestWeightIndex = entry.getKey();
+                        }
+                    } else if (entry.getValue() > lowestWeight) {
+                        msw.remove(lowestWeightIndex);
+                        msw.put(lowestWeightIndex, lowestWeight);
+
+                        // search again for the lowest weight
+                        lowestWeight = Float.MAX_VALUE;
+                        for (Entry<Integer, Float> e : msw.entrySet()) {
+                            if (e.getValue() < lowestWeight) {
+                                lowestWeight = e.getValue();
+                                lowestWeightIndex = e.getKey();
+                            }
+                        }
+                    }
+                }
+
+                // replace current weights with the given ones
+                this.clear();
+                this.putAll(msw);
+            }
+
+            // normalizing the weights so that the sum of the values is equal to '1'
             float sum = 0;
-            for (int i = 0; i < MAXIMUM_WEIGHTS_PER_VERTEX; ++i) {
-                weights[i] = weightsFloatData.get();
-                sum += weights[i];
+            for (Entry<Integer, Float> entry : this.entrySet()) {
+                sum += entry.getValue();
             }
-            if (sum != 1f && sum != 0.0f) {
-                weightsFloatData.position(weightsFloatData.position() - MAXIMUM_WEIGHTS_PER_VERTEX);
-                // compute new vals based on sum
-                float sumToB = 1f / sum;
-                for (int i = 0; i < MAXIMUM_WEIGHTS_PER_VERTEX; ++i) {
-                    weightsFloatData.put(weights[i] * sumToB);
+
+            if (sum != 0 && sum != 1) {
+                for (Entry<Integer, Float> entry : this.entrySet()) {
+                    entry.setValue(entry.getValue() / sum);
                 }
             }
         }
-        weightsFloatData.rewind();
     }
-    
-//    This method is now not used because it broke animations.
-//    Perhaps in the future I will find a solution to this problem.
-//    I store it here for future use.
-//    
-//    private void loadBonePoses() {
-//        TempVars tempVars = TempVars.get();
-//        try {
-//            Pointer pPose = (Pointer) armatureObject.getFieldValue("pose");
-//            if (pPose.isNotNull()) {
-//                LOGGER.fine("Loading the pose of the armature.");
-//                ObjectHelper objectHelper = blenderContext.getHelper(ObjectHelper.class);
-//                ConstraintHelper constraintHelper = blenderContext.getHelper(ConstraintHelper.class);
-//
-//                Structure pose = pPose.fetchData().get(0);
-//                Structure chanbase = (Structure) pose.getFieldValue("chanbase");
-//                List<Structure> chans = chanbase.evaluateListBase();
-//                Transform transform = new Transform();
-//                for (Structure poseChannel : chans) {
-//                    Pointer pBone = (Pointer) poseChannel.getFieldValue("bone");
-//                    if (pBone.isNull()) {
-//                        throw new BlenderFileException("Cannot find bone for pose channel named: " + poseChannel.getName());
-//                    }
-//                    BoneContext boneContext = blenderContext.getBoneContext(pBone.getOldMemoryAddress());
-//
-//                    LOGGER.log(Level.FINEST, "Getting the global pose transformation for bone: {0}", boneContext);
-//                    Matrix4f poseMat = objectHelper.getMatrix(poseChannel, "pose_mat", blenderContext.getBlenderKey().isFixUpAxis());
-//                    poseMat.multLocal(BoneContext.BONE_ARMATURE_TRANSFORMATION_MATRIX);
-//
-//                    Matrix4f armatureWorldMat = objectHelper.getMatrix(armatureObject, "obmat", blenderContext.getBlenderKey().isFixUpAxis());
-//                    Matrix4f boneWorldMat = armatureWorldMat.multLocal(poseMat);
-//
-//                    boneWorldMat.toTranslationVector(tempVars.vect1);
-//                    boneWorldMat.toRotationQuat(tempVars.quat1);
-//                    boneWorldMat.toScaleVector(tempVars.vect2);
-//                    transform.setTranslation(tempVars.vect1);
-//                    transform.setRotation(tempVars.quat1);
-//                    transform.setScale(tempVars.vect2);
-//
-//                    constraintHelper.applyTransform(boneContext.getArmatureObjectOMA(), boneContext.getBone().getName(), Space.CONSTRAINT_SPACE_WORLD, transform);
-//                }
-//            }
-//        } catch (BlenderFileException e) {
-//            LOGGER.log(Level.WARNING, "Problems occured during pose loading: {0}.", e.getLocalizedMessage());
-//        } finally {
-//            tempVars.release();
-//        }
-//    }
 }