package com.akjava.gwt.bvh.client.threejs; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.akjava.bvh.client.BVH; import com.akjava.bvh.client.BVHNode; import com.akjava.bvh.client.Channels; import com.akjava.bvh.client.NameAndChannel; import com.akjava.gwt.three.client.gwt.boneanimation.AnimationBone; import com.akjava.gwt.three.client.gwt.boneanimation.AnimationData; import com.akjava.gwt.three.client.gwt.boneanimation.AnimationHierarchyItem; import com.akjava.gwt.three.client.gwt.boneanimation.AnimationKey; import com.akjava.gwt.three.client.java.utils.AnimationUtils; import com.akjava.gwt.three.client.java.utils.GWTThreeUtils; import com.akjava.gwt.three.client.js.THREE; import com.akjava.gwt.three.client.js.core.Object3D; import com.akjava.gwt.three.client.js.math.Matrix4; import com.akjava.gwt.three.client.js.math.Quaternion; import com.akjava.gwt.three.client.js.math.Vector3; import com.google.gwt.core.client.JsArray; public class AnimationDataConverter { //list of bone names private List<String> nameOrderList; private boolean skipFirst=true; public boolean isSkipFirst() { return skipFirst; } public void setSkipFirst(boolean skipFirst) { this.skipFirst = skipFirst; } public AnimationData convertJsonAnimation(BVH bvh){ return convertJsonAnimation(bvh.getHiearchy(),bvh); } public AnimationData convertJsonAnimation(JsArray<AnimationBone> bones,BVH bvh){ BVHNode rootNode=new BVHConverter().convertBVHNode(bones); //maybe same as <AnimationBone> nameOrderList=new ArrayList<String>(); String oldName=null; for(int i=0;i<bvh.getNameAndChannels().size();i++){ String newName=bvh.getNameAndChannels().get(i).getName(); if(!newName.equals(oldName)){ nameOrderList.add(newName); oldName=newName; } } // LogUtils.log("xx1"); /* List<Quaternion> boneQ=new ArrayList<Quaternion>(); for(int i=0;i<bones.length();i++){ boneQ.add(GWTThreeUtils.jsArrayToQuaternion(bones.get(i).getRotq())); } */ //boneMap = new HashMap<String, Matrix4>(); AnimationData data=AnimationUtils.createAnimationData(); parentIdMaps=new HashMap<String,Integer>(); jointMap=new HashMap<String,Object3D>(); matrixMap=new HashMap<String,Matrix4>(); angleMap=new HashMap<String,Vector3>(); for(int i=0;i<nameOrderList.size();i++){ //parentIdMaps.put(nameOrderList.get(i), i); jointMap.put(nameOrderList.get(i), THREE.Object3D()); } for(int i=0;i<bones.length();i++){ parentIdMaps.put(bones.get(i).getName(), i); } // LogUtils.log("2"); //create hierarchy Map<String,AnimationHierarchyItem> hmap=new HashMap<String,AnimationHierarchyItem>(); AnimationHierarchyItem rootItem=AnimationUtils.createAnimationHierarchyItem(); rootItem.setParent(-1); hmap.put(rootNode.getName(), rootItem); convert(hmap,rootNode); //List<AnimationHierarchyItem> aList=new ArrayList<AnimationHierarchyItem>(); //IdNames=new HashMap<Integer,String>(); //LogUtils.log("nc:"+nameOrderList.size()); /* for(int i=0;i<nameOrderList.size();i++){ AnimationHierarchyItem abone=hmap.get(nameOrderList.get(i)); data.getHierarchy().push(abone); //IdNames.put(i, bvh.getNameAndChannels().get(i).getName()); }*/ //create bones order by bones for(int i=0;i<bones.length();i++){ AnimationHierarchyItem abone=hmap.get(bones.get(i).getName()); data.getHierarchy().push(abone); } // LogUtils.log("3"); double ft=bvh.getFrameTime(); data.setName("BVHMotion"); data.setFps(30);//TODO change int minus=1; if(skipFirst){ minus++; } data.setLength(ft*(bvh.getFrames()-minus)); //convert each frame int start=0; if(skipFirst){ start=1; } // LogUtils.log("4"); for(int i=start;i<bvh.getFrames();i++){ //get each joint rotation to object3 doPose(bvh,bvh.getFrameAt(i)); //create matrix for key matrixMap.clear(); angleMap.clear(); //BVHNode rootNode=bvh.getHiearchy(); Object3D o3d=jointMap.get(rootNode.getName()); if(o3d==null){ continue;//not found } Matrix4 mx=THREE.Matrix4(); Vector3 bpos=THREE.Vector3(); bpos.addVectors(o3d.getPosition(),BVHUtils.toVector3(rootNode.getOffset())); //LogUtils.log(rootNode.getName()+","+bpos.getX()+","+bpos.getY()+","+bpos.getZ()); //mx.setRotationFromEuler(o3d.getRotation(), "XYZ"); mx.makeRotationFromEuler(o3d.getRotation()); mx.setPosition(bpos); //mx.multiply(nodeToMatrix(rootNode), mx); matrixMap.put(rootNode.getName(), mx); angleMap.put(rootNode.getName(), GWTThreeUtils.radiantToDegree(o3d.getRotation())); doMatrix(rootNode); // LogUtils.log("5"); for(int j=0;j<nameOrderList.size();j++){ AnimationHierarchyItem item=hmap.get(nameOrderList.get(j)); if(item==null){ continue; } //AnimationHierarchyItem item=data.getHierarchy().get(j); //create Key Matrix4 matrix=matrixMap.get(nameOrderList.get(j)); Vector3 pos=THREE.Vector3(); pos.setFromMatrixPosition(matrix); Quaternion q=THREE.Quaternion(); q.setFromRotationMatrix(matrix); //q.multiplySelf(boneQ.get(j)); AnimationKey key=AnimationUtils.createAnimationKey(); key.setPos(pos);//key same as bone? key.setRot(GWTThreeUtils.quaternionToJsArray(q)); key.setAngle(angleMap.get(nameOrderList.get(j))); int frame=i; if(skipFirst){ frame--; } key.setTime(ft*frame); item.getKeys().push(key); } //LogUtils.log("6"); } //check Quaternion emptyQ=THREE.Quaternion(); Vector3 emptyAngle=THREE.Vector3(); for(int j=0;j<bones.length();j++){ AnimationHierarchyItem item=hmap.get(bones.get(j).getName()); int totalFrames=bvh.getFrames(); if(skipFirst){ totalFrames--; } if(item.getKeys().length()==0){ for(int i=0;i<totalFrames;i++){ //add empty frame AnimationKey key=AnimationUtils.createAnimationKey(); key.setPos(GWTThreeUtils.jsArrayToVector3(bones.get(j).getPos())); key.setRot(GWTThreeUtils.quaternionToJsArray(emptyQ)); key.setAngle(emptyAngle); key.setTime(ft*i); item.getKeys().push(key); } } } return data; } public AnimationData convertJsonAnimation(BVHNode rootNode,BVH bvh){ //maybe same as <AnimationBone> nameOrderList=new ArrayList<String>(); String oldName=null; for(int i=0;i<bvh.getNameAndChannels().size();i++){ String newName=bvh.getNameAndChannels().get(i).getName(); if(!newName.equals(oldName)){ nameOrderList.add(newName); oldName=newName; } } /* List<Quaternion> boneQ=new ArrayList<Quaternion>(); for(int i=0;i<bones.length();i++){ boneQ.add(GWTThreeUtils.jsArrayToQuaternion(bones.get(i).getRotq())); } */ //boneMap = new HashMap<String, Matrix4>(); AnimationData data=AnimationUtils.createAnimationData(); parentIdMaps=new HashMap<String,Integer>(); jointMap=new HashMap<String,Object3D>(); matrixMap=new HashMap<String,Matrix4>(); angleMap=new HashMap<String,Vector3>(); for(int i=0;i<nameOrderList.size();i++){ parentIdMaps.put(nameOrderList.get(i), i); jointMap.put(nameOrderList.get(i), THREE.Object3D()); } //create hierarchy Map<String,AnimationHierarchyItem> hmap=new HashMap<String,AnimationHierarchyItem>(); AnimationHierarchyItem rootItem=AnimationUtils.createAnimationHierarchyItem(); rootItem.setParent(-1); hmap.put(rootNode.getName(), rootItem); convert(hmap,rootNode); //List<AnimationHierarchyItem> aList=new ArrayList<AnimationHierarchyItem>(); //IdNames=new HashMap<Integer,String>(); //LogUtils.log("nc:"+nameOrderList.size()); for(int i=0;i<nameOrderList.size();i++){ AnimationHierarchyItem abone=hmap.get(nameOrderList.get(i)); data.getHierarchy().push(abone); //IdNames.put(i, bvh.getNameAndChannels().get(i).getName()); } double ft=bvh.getFrameTime(); data.setName("BVHMotion"); data.setFps(30);//TODO change int minus=1; if(skipFirst){ minus++; } data.setLength(ft*(bvh.getFrames()-minus)); //convert each frame int start=0; if(skipFirst){ start=1; } for(int i=start;i<bvh.getFrames();i++){ //get each joint rotation to object3 doPose(bvh,bvh.getFrameAt(i)); //create matrix for key matrixMap.clear(); angleMap.clear(); //BVHNode rootNode=bvh.getHiearchy(); Object3D o3d=jointMap.get(rootNode.getName()); if(o3d==null){ continue;//not found } Matrix4 mx=THREE.Matrix4(); Vector3 bpos=THREE.Vector3(); bpos.addVectors(o3d.getPosition(),BVHUtils.toVector3(rootNode.getOffset())); //LogUtils.log(rootNode.getName()+","+bpos.getX()+","+bpos.getY()+","+bpos.getZ()); mx.makeRotationFromEuler(o3d.getRotation()); mx.setPosition(bpos); //mx.multiply(nodeToMatrix(rootNode), mx); matrixMap.put(rootNode.getName(), mx); angleMap.put(rootNode.getName(), GWTThreeUtils.radiantToDegree(o3d.getRotation())); doMatrix(rootNode); for(int j=0;j<nameOrderList.size();j++){ AnimationHierarchyItem item=hmap.get(nameOrderList.get(j)); if(item==null){ continue; } //AnimationHierarchyItem item=data.getHierarchy().get(j); //create Key Matrix4 matrix=matrixMap.get(nameOrderList.get(j)); Vector3 pos=THREE.Vector3(); pos.setFromMatrixPosition(matrix); Quaternion q=THREE.Quaternion(); q.setFromRotationMatrix(matrix); //q.multiplySelf(boneQ.get(j)); AnimationKey key=AnimationUtils.createAnimationKey(); key.setPos(pos);//key same as bone? key.setRot(GWTThreeUtils.quaternionToJsArray(q)); key.setAngle(angleMap.get(nameOrderList.get(j))); int frame=i; if(skipFirst){ frame--; } key.setTime(ft*frame); item.getKeys().push(key); } } return data; } //private void BoneTo private Matrix4 nodeToMatrix(BVHNode node){ Matrix4 mx=THREE.Matrix4(); mx.setPosition(BVHUtils.toVector3(node.getOffset())); return mx; } private void doMatrix(BVHNode parent) { for(BVHNode children:parent.getJoints()){ Object3D o3d=jointMap.get(children.getName()); if(o3d==null){ continue;//not found } //GWT.log(message); Matrix4 mx=THREE.Matrix4(); Vector3 mpos=THREE.Vector3(); mpos.addVectors(o3d.getPosition(), BVHUtils.toVector3(children.getOffset())); //LogUtils.log("doMatrix:"+children.getName()+",o3d="+ThreeLog.get(o3d.getPosition())+",childoffset="+children.getOffset()); mx.makeRotationFromEuler(o3d.getRotation()); mx.setPosition(mpos); //mx=mx.multiply(nodeToMatrix(children), mx); Matrix4 parentM=matrixMap.get(parent.getName()); //TODO If you wish absolutepath use parent matrix,but this version format dont need it. //mx=mx.multiply(parentM, mx); matrixMap.put(children.getName(), mx); angleMap.put(children.getName(), GWTThreeUtils.radiantToDegree(o3d.getRotation())); doMatrix(children); } } private Map<String,Vector3> angleMap; private Map<String,Matrix4> matrixMap; private Map<String,Object3D> jointMap; private Map<String,Integer> parentIdMaps; //private Map<String,Matrix4> boneMap; //private Map<Integer,String> IdNames; private void convert(Map<String,AnimationHierarchyItem> map,BVHNode parent){ for(BVHNode children:parent.getJoints()){ AnimationHierarchyItem item=AnimationUtils.createAnimationHierarchyItem(); item.setParent(parentIdMaps.get(parent.getName())); map.put(children.getName(), item); convert(map,children); } } private void doPose(BVH bvh,double[] vs){ Object3D oldTarget=null; String lastOrder=null; for(int i=0;i<vs.length;i++){ NameAndChannel nchannel=bvh.getNameAndChannels().get(i); lastOrder=nchannel.getOrder(); Object3D target=jointMap.get(nchannel.getName()); switch(nchannel.getChannel()){ case Channels.XROTATION: target.getRotation().setX(Math.toRadians(vs[i])); break; case Channels.YROTATION: target.getRotation().setY(Math.toRadians(vs[i])); break; case Channels.ZROTATION: target.getRotation().setZ(Math.toRadians(vs[i])); break; case Channels.XPOSITION: target.getPosition().setX(vs[i]); break; case Channels.YPOSITION: target.getPosition().setY(vs[i]); break; case Channels.ZPOSITION: target.getPosition().setZ(vs[i]); break; } if(oldTarget!=null && oldTarget!=target){ setRotation(oldTarget,lastOrder); } oldTarget=target; } setRotation(oldTarget,lastOrder);//do last one } /** * this is just set order * @param target * @param lastOrder */ private void setRotation(Object3D target,String lastOrder){ target.getRotation().setOrder(lastOrder); } }