159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/* 259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * To change this template, choose Tools | Templates 359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * and open the template in the editor. 459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapackage com.jme3.animation; 659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.export.*; 859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.FastMath; 959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.Matrix4f; 1059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.renderer.RenderManager; 1159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.renderer.ViewPort; 1259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.*; 1359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.VertexBuffer.Type; 1459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.control.AbstractControl; 1559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.control.Control; 1659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.util.TempVars; 1759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.io.IOException; 1859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.nio.ByteBuffer; 1959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.nio.FloatBuffer; 2059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.ArrayList; 2159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 2259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/** 2359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * The Skeleton control deforms a model according to a skeleton, 2459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * It handles the computation of the deformation matrices and performs 2559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the transformations on the mesh 2659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 2759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @author Rémy Bouquet Based on AnimControl by Kirill Vainer 2859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 2959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapublic class SkeletonControl extends AbstractControl implements Cloneable { 3059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 3159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 3259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * The skeleton of the model 3359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 3459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private Skeleton skeleton; 3559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 3659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * List of targets which this controller effects. 3759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 3859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private Mesh[] targets; 3959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 4059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Used to track when a mesh was updated. Meshes are only updated 4159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * if they are visible in at least one camera. 4259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 4359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private boolean wasMeshUpdated = false; 4459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 4559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 4659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Serialization only. Do not use. 4759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 4859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public SkeletonControl() { 4959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 5059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 5159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 5259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Creates a skeleton control. 5359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * The list of targets will be acquired automatically when 5459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * the control is attached to a node. 5559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 5659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param skeleton the skeleton 5759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 5859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public SkeletonControl(Skeleton skeleton) { 5959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.skeleton = skeleton; 6059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 6159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 6259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 6359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Creates a skeleton control. 6459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 6559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param targets the meshes controlled by the skeleton 6659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param skeleton the skeleton 6759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 6859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta @Deprecated 6959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta SkeletonControl(Mesh[] targets, Skeleton skeleton) { 7059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.skeleton = skeleton; 7159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta this.targets = targets; 7259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 7359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 7459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private boolean isMeshAnimated(Mesh mesh) { 7559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return mesh.getBuffer(Type.BindPosePosition) != null; 7659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 7759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 7859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private Mesh[] findTargets(Node node) { 7959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Mesh sharedMesh = null; 8059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ArrayList<Mesh> animatedMeshes = new ArrayList<Mesh>(); 8159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 8259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (Spatial child : node.getChildren()) { 8359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (!(child instanceof Geometry)) { 8459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta continue; // could be an attachment node, ignore. 8559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 8659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 8759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Geometry geom = (Geometry) child; 8859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 8959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // is this geometry using a shared mesh? 9059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Mesh childSharedMesh = geom.getUserData(UserData.JME_SHAREDMESH); 9159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 9259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (childSharedMesh != null) { 9359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // Don't bother with non-animated shared meshes 9459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (isMeshAnimated(childSharedMesh)) { 9559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // child is using shared mesh, 9659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // so animate the shared mesh but ignore child 9759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (sharedMesh == null) { 9859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta sharedMesh = childSharedMesh; 9959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else if (sharedMesh != childSharedMesh) { 10059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IllegalStateException("Two conflicting shared meshes for " + node); 10159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 10259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 10359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 10459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Mesh mesh = geom.getMesh(); 10559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (isMeshAnimated(mesh)) { 10659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta animatedMeshes.add(mesh); 10759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 10859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 10959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 11059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 11159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (sharedMesh != null) { 11259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta animatedMeshes.add(sharedMesh); 11359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 11459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 11559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return animatedMeshes.toArray(new Mesh[animatedMeshes.size()]); 11659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 11759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 11859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta @Override 11959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void setSpatial(Spatial spatial) { 12059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta super.setSpatial(spatial); 12159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (spatial != null) { 12259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Node node = (Node) spatial; 12359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta targets = findTargets(node); 12459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 12559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta targets = null; 12659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 12759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 12859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 12959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta @Override 13059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected void controlRender(RenderManager rm, ViewPort vp) { 13159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (!wasMeshUpdated) { 13259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta resetToBind(); // reset morph meshes to bind pose 13359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 13459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Matrix4f[] offsetMatrices = skeleton.computeSkinningMatrices(); 13559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 13659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // if hardware skinning is supported, the matrices and weight buffer 13759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // will be sent by the SkinningShaderLogic object assigned to the shader 13859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = 0; i < targets.length; i++) { 13959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // NOTE: This assumes that code higher up 14059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // Already ensured those targets are animated 14159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // otherwise a crash will happen in skin update 14259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //if (isMeshAnimated(targets[i])) { 14359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta softwareSkinUpdate(targets[i], offsetMatrices); 14459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //} 14559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 14659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 14759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta wasMeshUpdated = true; 14859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 14959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 15059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 15159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta @Override 15259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta protected void controlUpdate(float tpf) { 15359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta wasMeshUpdated = false; 15459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 15559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 15659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta void resetToBind() { 15759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (Mesh mesh : targets) { 15859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (isMeshAnimated(mesh)) { 15959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta VertexBuffer bi = mesh.getBuffer(Type.BoneIndex); 16059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ByteBuffer bib = (ByteBuffer) bi.getData(); 16159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (!bib.hasArray()) { 16259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta mesh.prepareForAnim(true); // prepare for software animation 16359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 16459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta VertexBuffer bindPos = mesh.getBuffer(Type.BindPosePosition); 16559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta VertexBuffer bindNorm = mesh.getBuffer(Type.BindPoseNormal); 16659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta VertexBuffer pos = mesh.getBuffer(Type.Position); 16759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta VertexBuffer norm = mesh.getBuffer(Type.Normal); 16859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer pb = (FloatBuffer) pos.getData(); 16959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer nb = (FloatBuffer) norm.getData(); 17059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer bpb = (FloatBuffer) bindPos.getData(); 17159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer bnb = (FloatBuffer) bindNorm.getData(); 17259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta pb.clear(); 17359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta nb.clear(); 17459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta bpb.clear(); 17559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta bnb.clear(); 17659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 17759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //reseting bind tangents if there is a bind tangent buffer 17859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta VertexBuffer bindTangents = mesh.getBuffer(Type.BindPoseTangent); 17959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (bindTangents != null) { 18059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta VertexBuffer tangents = mesh.getBuffer(Type.Tangent); 18159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer tb = (FloatBuffer) tangents.getData(); 18259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer btb = (FloatBuffer) bindTangents.getData(); 18359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta tb.clear(); 18459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta btb.clear(); 18559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta tb.put(btb).clear(); 18659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 18759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 18859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 18959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta pb.put(bpb).clear(); 19059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta nb.put(bnb).clear(); 19159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 19259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 19359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 19459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 19559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public Control cloneForSpatial(Spatial spatial) { 19659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Node clonedNode = (Node) spatial; 19759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta AnimControl ctrl = spatial.getControl(AnimControl.class); 19859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta SkeletonControl clone = new SkeletonControl(); 19959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta clone.setSpatial(clonedNode); 20059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 20159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta clone.skeleton = ctrl.getSkeleton(); 20259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // Fix animated targets for the cloned node 20359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta clone.targets = findTargets(clonedNode); 20459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 20559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // Fix attachments for the cloned node 20659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = 0; i < clonedNode.getQuantity(); i++) { 20759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // go through attachment nodes, apply them to correct bone 20859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Spatial child = clonedNode.getChild(i); 20959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (child instanceof Node) { 21059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Node clonedAttachNode = (Node) child; 21159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Bone originalBone = (Bone) clonedAttachNode.getUserData("AttachedBone"); 21259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 21359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (originalBone != null) { 21459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Bone clonedBone = clone.skeleton.getBone(originalBone.getName()); 21559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 21659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta clonedAttachNode.setUserData("AttachedBone", clonedBone); 21759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta clonedBone.setAttachmentsNode(clonedAttachNode); 21859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 21959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 22059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 22159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 22259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return clone; 22359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 22459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 22559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 22659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * 22759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param boneName the name of the bone 22859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return the node attached to this bone 22959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 23059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public Node getAttachmentsNode(String boneName) { 23159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Bone b = skeleton.getBone(boneName); 23259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (b == null) { 23359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IllegalArgumentException("Given bone name does not exist " 23459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta + "in the skeleton."); 23559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 23659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 23759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Node n = b.getAttachmentsNode(); 23859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Node model = (Node) spatial; 23959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta model.attachChild(n); 24059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return n; 24159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 24259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 24359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 24459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * returns the skeleton of this control 24559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return 24659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 24759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public Skeleton getSkeleton() { 24859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return skeleton; 24959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 25059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 25159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 25259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * sets the skeleton for this control 25359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param skeleton 25459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 25559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta// public void setSkeleton(Skeleton skeleton) { 25659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta// this.skeleton = skeleton; 25759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta// } 25859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 25959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * returns the targets meshes of this control 26059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @return 26159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 26259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public Mesh[] getTargets() { 26359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta return targets; 26459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 26559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 26659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 26759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * sets the target meshes of this control 26859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param targets 26959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 27059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta// public void setTargets(Mesh[] targets) { 27159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta// this.targets = targets; 27259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta// } 27359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 27459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Update the mesh according to the given transformation matrices 27559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param mesh then mesh 27659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param offsetMatrices the transformation matrices to apply 27759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 27859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private void softwareSkinUpdate(Mesh mesh, Matrix4f[] offsetMatrices) { 27959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 28059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta VertexBuffer tb = mesh.getBuffer(Type.Tangent); 28159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (tb == null) { 28259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //if there are no tangents use the classic skinning 28359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta applySkinning(mesh, offsetMatrices); 28459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } else { 28559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //if there are tangents use the skinning with tangents 28659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta applySkinningTangents(mesh, offsetMatrices, tb); 28759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 28859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 28959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 29059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 29159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 29259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 29359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Method to apply skinning transforms to a mesh's buffers 29459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param mesh the mesh 29559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param offsetMatrices the offset matices to apply 29659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 29759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private void applySkinning(Mesh mesh, Matrix4f[] offsetMatrices) { 29859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int maxWeightsPerVert = mesh.getMaxNumWeights(); 29959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (maxWeightsPerVert <= 0) { 30059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IllegalStateException("Max weights per vert is incorrectly set!"); 30159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 30259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 30359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int fourMinusMaxWeights = 4 - maxWeightsPerVert; 30459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 30559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // NOTE: This code assumes the vertex buffer is in bind pose 30659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // resetToBind() has been called this frame 30759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta VertexBuffer vb = mesh.getBuffer(Type.Position); 30859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer fvb = (FloatBuffer) vb.getData(); 30959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta fvb.rewind(); 31059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 31159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta VertexBuffer nb = mesh.getBuffer(Type.Normal); 31259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer fnb = (FloatBuffer) nb.getData(); 31359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta fnb.rewind(); 31459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 31559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // get boneIndexes and weights for mesh 31659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ByteBuffer ib = (ByteBuffer) mesh.getBuffer(Type.BoneIndex).getData(); 31759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer wb = (FloatBuffer) mesh.getBuffer(Type.BoneWeight).getData(); 31859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 31959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ib.rewind(); 32059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta wb.rewind(); 32159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 32259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float[] weights = wb.array(); 32359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta byte[] indices = ib.array(); 32459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int idxWeights = 0; 32559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 32659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta TempVars vars = TempVars.get(); 32759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 32859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 32959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float[] posBuf = vars.skinPositions; 33059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float[] normBuf = vars.skinNormals; 33159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 33259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int iterations = (int) FastMath.ceil(fvb.capacity() / ((float) posBuf.length)); 33359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int bufLength = posBuf.length; 33459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = iterations - 1; i >= 0; i--) { 33559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // read next set of positions and normals from native buffer 33659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta bufLength = Math.min(posBuf.length, fvb.remaining()); 33759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta fvb.get(posBuf, 0, bufLength); 33859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta fnb.get(normBuf, 0, bufLength); 33959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int verts = bufLength / 3; 34059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int idxPositions = 0; 34159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 34259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // iterate vertices and apply skinning transform for each effecting bone 34359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int vert = verts - 1; vert >= 0; vert--) { 34459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float nmx = normBuf[idxPositions]; 34559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float vtx = posBuf[idxPositions++]; 34659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float nmy = normBuf[idxPositions]; 34759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float vty = posBuf[idxPositions++]; 34859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float nmz = normBuf[idxPositions]; 34959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float vtz = posBuf[idxPositions++]; 35059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 35159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float rx = 0, ry = 0, rz = 0, rnx = 0, rny = 0, rnz = 0; 35259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 35359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int w = maxWeightsPerVert - 1; w >= 0; w--) { 35459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float weight = weights[idxWeights]; 35559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Matrix4f mat = offsetMatrices[indices[idxWeights++]]; 35659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 35759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rx += (mat.m00 * vtx + mat.m01 * vty + mat.m02 * vtz + mat.m03) * weight; 35859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ry += (mat.m10 * vtx + mat.m11 * vty + mat.m12 * vtz + mat.m13) * weight; 35959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rz += (mat.m20 * vtx + mat.m21 * vty + mat.m22 * vtz + mat.m23) * weight; 36059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 36159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rnx += (nmx * mat.m00 + nmy * mat.m01 + nmz * mat.m02) * weight; 36259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rny += (nmx * mat.m10 + nmy * mat.m11 + nmz * mat.m12) * weight; 36359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rnz += (nmx * mat.m20 + nmy * mat.m21 + nmz * mat.m22) * weight; 36459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 36559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 36659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta idxWeights += fourMinusMaxWeights; 36759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 36859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta idxPositions -= 3; 36959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta normBuf[idxPositions] = rnx; 37059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta posBuf[idxPositions++] = rx; 37159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta normBuf[idxPositions] = rny; 37259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta posBuf[idxPositions++] = ry; 37359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta normBuf[idxPositions] = rnz; 37459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta posBuf[idxPositions++] = rz; 37559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 37659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 37759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta fvb.position(fvb.position() - bufLength); 37859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta fvb.put(posBuf, 0, bufLength); 37959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta fnb.position(fnb.position() - bufLength); 38059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta fnb.put(normBuf, 0, bufLength); 38159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 38259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 38359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta vars.release(); 38459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 38559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta vb.updateData(fvb); 38659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta nb.updateData(fnb); 38759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 38859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 38959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 39059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta /** 39159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Specific method for skinning with tangents to avoid cluttering the classic skinning calculation with 39259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * null checks that would slow down the process even if tangents don't have to be computed. 39359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Also the iteration has additional indexes since tangent has 4 components instead of 3 for pos and norm 39459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param maxWeightsPerVert maximum number of weights per vertex 39559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param mesh the mesh 39659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param offsetMatrices the offsetMaytrices to apply 39759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * @param tb the tangent vertexBuffer 39859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */ 39959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta private void applySkinningTangents(Mesh mesh, Matrix4f[] offsetMatrices, VertexBuffer tb) { 40059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int maxWeightsPerVert = mesh.getMaxNumWeights(); 40159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 40259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (maxWeightsPerVert <= 0) { 40359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta throw new IllegalStateException("Max weights per vert is incorrectly set!"); 40459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 40559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 40659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int fourMinusMaxWeights = 4 - maxWeightsPerVert; 40759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 40859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // NOTE: This code assumes the vertex buffer is in bind pose 40959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // resetToBind() has been called this frame 41059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta VertexBuffer vb = mesh.getBuffer(Type.Position); 41159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer fvb = (FloatBuffer) vb.getData(); 41259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta fvb.rewind(); 41359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 41459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta VertexBuffer nb = mesh.getBuffer(Type.Normal); 41559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 41659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer fnb = (FloatBuffer) nb.getData(); 41759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta fnb.rewind(); 41859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 41959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 42059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer ftb = (FloatBuffer) tb.getData(); 42159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ftb.rewind(); 42259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 42359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 42459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // get boneIndexes and weights for mesh 42559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ByteBuffer ib = (ByteBuffer) mesh.getBuffer(Type.BoneIndex).getData(); 42659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta FloatBuffer wb = (FloatBuffer) mesh.getBuffer(Type.BoneWeight).getData(); 42759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 42859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ib.rewind(); 42959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta wb.rewind(); 43059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 43159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float[] weights = wb.array(); 43259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta byte[] indices = ib.array(); 43359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int idxWeights = 0; 43459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 43559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta TempVars vars = TempVars.get(); 43659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 43759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 43859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float[] posBuf = vars.skinPositions; 43959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float[] normBuf = vars.skinNormals; 44059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float[] tanBuf = vars.skinTangents; 44159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 44259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int iterations = (int) FastMath.ceil(fvb.capacity() / ((float) posBuf.length)); 44359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int bufLength = 0; 44459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int tanLength = 0; 44559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int i = iterations - 1; i >= 0; i--) { 44659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // read next set of positions and normals from native buffer 44759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta bufLength = Math.min(posBuf.length, fvb.remaining()); 44859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta tanLength = Math.min(tanBuf.length, ftb.remaining()); 44959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta fvb.get(posBuf, 0, bufLength); 45059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta fnb.get(normBuf, 0, bufLength); 45159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ftb.get(tanBuf, 0, tanLength); 45259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int verts = bufLength / 3; 45359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int idxPositions = 0; 45459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //tangents has their own index because of the 4 components 45559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta int idxTangents = 0; 45659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 45759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta // iterate vertices and apply skinning transform for each effecting bone 45859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int vert = verts - 1; vert >= 0; vert--) { 45959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float nmx = normBuf[idxPositions]; 46059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float vtx = posBuf[idxPositions++]; 46159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float nmy = normBuf[idxPositions]; 46259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float vty = posBuf[idxPositions++]; 46359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float nmz = normBuf[idxPositions]; 46459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float vtz = posBuf[idxPositions++]; 46559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 46659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float tnx = tanBuf[idxTangents++]; 46759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float tny = tanBuf[idxTangents++]; 46859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float tnz = tanBuf[idxTangents++]; 46959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 47059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //skipping the 4th component of the tangent since it doesn't have to be transformed 47159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta idxTangents++; 47259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 47359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float rx = 0, ry = 0, rz = 0, rnx = 0, rny = 0, rnz = 0, rtx = 0, rty = 0, rtz = 0; 47459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 47559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta for (int w = maxWeightsPerVert - 1; w >= 0; w--) { 47659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta float weight = weights[idxWeights]; 47759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Matrix4f mat = offsetMatrices[indices[idxWeights++]]; 47859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 47959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rx += (mat.m00 * vtx + mat.m01 * vty + mat.m02 * vtz + mat.m03) * weight; 48059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ry += (mat.m10 * vtx + mat.m11 * vty + mat.m12 * vtz + mat.m13) * weight; 48159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rz += (mat.m20 * vtx + mat.m21 * vty + mat.m22 * vtz + mat.m23) * weight; 48259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 48359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rnx += (nmx * mat.m00 + nmy * mat.m01 + nmz * mat.m02) * weight; 48459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rny += (nmx * mat.m10 + nmy * mat.m11 + nmz * mat.m12) * weight; 48559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rnz += (nmx * mat.m20 + nmy * mat.m21 + nmz * mat.m22) * weight; 48659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 48759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rtx += (tnx * mat.m00 + tny * mat.m01 + tnz * mat.m02) * weight; 48859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rty += (tnx * mat.m10 + tny * mat.m11 + tnz * mat.m12) * weight; 48959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta rtz += (tnx * mat.m20 + tny * mat.m21 + tnz * mat.m22) * weight; 49059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 49159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 49259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta idxWeights += fourMinusMaxWeights; 49359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 49459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta idxPositions -= 3; 49559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 49659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta normBuf[idxPositions] = rnx; 49759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta posBuf[idxPositions++] = rx; 49859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta normBuf[idxPositions] = rny; 49959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta posBuf[idxPositions++] = ry; 50059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta normBuf[idxPositions] = rnz; 50159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta posBuf[idxPositions++] = rz; 50259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 50359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta idxTangents -= 4; 50459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 50559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta tanBuf[idxTangents++] = rtx; 50659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta tanBuf[idxTangents++] = rty; 50759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta tanBuf[idxTangents++] = rtz; 50859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 50959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta //once again skipping the 4th component of the tangent 51059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta idxTangents++; 51159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 51259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 51359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta fvb.position(fvb.position() - bufLength); 51459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta fvb.put(posBuf, 0, bufLength); 51559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta fnb.position(fnb.position() - bufLength); 51659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta fnb.put(normBuf, 0, bufLength); 51759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ftb.position(ftb.position() - tanLength); 51859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta ftb.put(tanBuf, 0, tanLength); 51959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 52059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 52159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta vars.release(); 52259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 52359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta vb.updateData(fvb); 52459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta nb.updateData(fnb); 52559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta tb.updateData(ftb); 52659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 52759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 52859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 52959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 53059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta @Override 53159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void write(JmeExporter ex) throws IOException { 53259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta super.write(ex); 53359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta OutputCapsule oc = ex.getCapsule(this); 53459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta oc.write(targets, "targets", null); 53559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta oc.write(skeleton, "skeleton", null); 53659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 53759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta 53859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta @Override 53959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta public void read(JmeImporter im) throws IOException { 54059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta super.read(im); 54159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta InputCapsule in = im.getCapsule(this); 54259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta Savable[] sav = in.readSavableArray("targets", null); 54359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta if (sav != null) { 54459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta targets = new Mesh[sav.length]; 54559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta System.arraycopy(sav, 0, targets, 0, sav.length); 54659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 54759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta skeleton = (Skeleton) in.readSavable("skeleton", null); 54859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta } 54959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta} 550