package com.akjava.gwt.bvh.client.threejs; import java.util.ArrayList; import java.util.List; import com.akjava.bvh.client.BVH; import com.akjava.bvh.client.BVHMotion; import com.akjava.bvh.client.BVHNode; import com.akjava.bvh.client.Channels; import com.akjava.bvh.client.NameAndChannel; import com.akjava.bvh.client.Vec3; import com.akjava.gwt.lib.client.LogUtils; import com.akjava.gwt.three.client.gwt.boneanimation.AngleAndPosition; import com.akjava.gwt.three.client.gwt.boneanimation.AnimationBone; import com.akjava.gwt.three.client.java.utils.GWTThreeUtils; import com.akjava.gwt.three.client.js.THREE; 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 BVHConverter { public BVHNode convertBVHNode(JsArray<AnimationBone> bones){ List<BVHNode> bvhs=new ArrayList<BVHNode>(); for(int i=0;i<bones.length();i++){ AnimationBone bone=bones.get(i); BVHNode node=null; if(bone.getParent()!=-1){ node=boneToBVHNode(bone,bones);//try has rotq //node=boneToBVHNode(bone); }else{ node=boneToBVHNode(bone); } //BVHNode node=boneToBVHNode(bone); /* if(i==0){ node.setOffset(new Vec3(0,0,0));//i think it's better,i change mind, need this one } */ bvhs.add(node); //add parent if(bone.getParent()!=-1){ bvhs.get(bone.getParent()).add(node); } } //add endsite for(BVHNode node:bvhs){ if(node.getJoints().size()==0){//empty has end site Vec3 endSite=node.getOffset().clone();//.multiplyScalar(2); node.addEndSite(endSite); } } return bvhs.get(0); } public BVH createBVH(JsArray<AnimationBone> bones){ BVHConverter converter=new BVHConverter(); BVHNode rootNode=converter.convertBVHNode(bones); converter.setChannels(rootNode,0,"XYZ"); //TODO support other order BVH bvh=new BVH(); bvh.setHiearchy(rootNode); BVHMotion motion=new BVHMotion(); motion.setFrameTime(.25); createChannels(bvh,rootNode); //create initial zero motion motion.add(new double[bvh.getNameAndChannels().size()]);//only root has pos,TODO find better way motion.setFrames(motion.getMotions().size());// bvh.setMotion(motion); return bvh; } private void createChannels(BVH bvh,BVHNode node){ if(node.getChannels().isXposition()){ bvh.add(new NameAndChannel(node.getName(), Channels.XPOSITION,node.getChannels())); } if(node.getChannels().isYposition()){ bvh.add(new NameAndChannel(node.getName(), Channels.YPOSITION,node.getChannels())); } if(node.getChannels().isZposition()){ bvh.add(new NameAndChannel(node.getName(), Channels.ZPOSITION,node.getChannels())); } if(node.getChannels().isXrotation()){ bvh.add(new NameAndChannel(node.getName(), Channels.XROTATION,node.getChannels())); } if(node.getChannels().isYrotation()){ bvh.add(new NameAndChannel(node.getName(), Channels.YROTATION,node.getChannels())); } if(node.getChannels().isZrotation()){ bvh.add(new NameAndChannel(node.getName(), Channels.ZROTATION,node.getChannels())); } for(BVHNode joint:node.getJoints()){ createChannels(bvh, joint); } } public double[] angleAndMatrixsToMotion(List<AngleAndPosition> matrixs,int mode,String order){ List<Double> values=new ArrayList<Double>(); for(int i=0;i<matrixs.size();i++){ Matrix4 mx=matrixs.get(i).getMatrix();//TODO change angle if((i==0 && mode==ROOT_POSITION_ROTATE_ONLY) || mode==POSITION_ROTATE){ Vector3 pos=GWTThreeUtils.toPositionVec(mx); values.add(pos.getX()); values.add(pos.getY()); values.add(pos.getZ()); } Vector3 tmprot=GWTThreeUtils.rotationToVector3(mx); //TODO order convert; if(!order.equals("XYZ")){ LogUtils.log("Warning:only support-XYZ"); } //rot has problem /* Vector3 rotDegree=GWTThreeUtils.radiantToDegree(tmprot); values.add(rotDegree.getX()); values.add(rotDegree.getY()); values.add(rotDegree.getZ()); */ Vector3 angle=matrixs.get(i).getDegreeAngle(); values.add(angle.getX()); values.add(angle.getY()); values.add(angle.getZ()); } double[] bt=new double[values.size()]; for(int i=0;i<values.size();i++){ bt[i]=values.get(i).doubleValue(); } return bt; } /** * bugs cant handle over 90 angle * @deprecated * @param matrixs * @param mode * @param order * @return */ public double[] matrixsToMotion(List<Matrix4> matrixs,int mode,String order){ List<Double> values=new ArrayList<Double>(); for(int i=0;i<matrixs.size();i++){ Matrix4 mx=matrixs.get(i); if((i==0 && mode==ROOT_POSITION_ROTATE_ONLY) || mode==POSITION_ROTATE){ Vector3 pos=GWTThreeUtils.toPositionVec(mx); values.add(pos.getX()); values.add(pos.getY()); values.add(pos.getZ()); } Vector3 tmprot=GWTThreeUtils.rotationToVector3(mx); //TODO order convert; if(!order.equals("XYZ")){ LogUtils.log("Warning:only support-XYZ"); } Vector3 rotDegree=GWTThreeUtils.radiantToDegree(tmprot); values.add(rotDegree.getX()); values.add(rotDegree.getY()); values.add(rotDegree.getZ()); } double[] bt=new double[values.size()]; for(int i=0;i<values.size();i++){ bt[i]=values.get(i).doubleValue(); } return bt; } private BVHNode boneToBVHNode(AnimationBone bone,JsArray<AnimationBone> bones){ BVHNode bvhNode=new BVHNode(); bvhNode.setName(bone.getName()); Quaternion q=THREE.Quaternion(); AnimationBone parent=bones.get(bone.getParent()); List<Integer> parents=new ArrayList<Integer>(); parents.add(bone.getParent()); while(parent.getParent()!=-1){ parents.add(parent.getParent()); parent=bones.get(parent.getParent()); } //order is very important for(int i=parents.size()-1;i>=0;i--){ int v=parents.get(i); q.multiply(THREE.Quaternion().fromArray(bones.get(v).getRotq())); } Vector3 v=THREE.Vector3().fromArray(bone.getPos()); v.applyQuaternion(q); Vec3 pos=new Vec3(v.getX(),v.getY(),v.getZ()); //Vec3 pos=new Vec3(bone.getPos().get(0),bone.getPos().get(1),bone.getPos().get(2)); bvhNode.setOffset(pos); //no channels return bvhNode; } private BVHNode boneToBVHNode(AnimationBone bone){ BVHNode bvhNode=new BVHNode(); bvhNode.setName(bone.getName()); //TODO support rotQ //Matrix4 m4=THREE.Matrix4().makeRotationFromQuaternion(THREE.Quaternion().fromArray(bone.getRotq())); //Quaternion q=THREE.Quaternion().fromArray(bone.getRotq()); Vector3 v=THREE.Vector3().fromArray(bone.getPos()); //v.applyQuaternion(q); Vec3 pos=new Vec3(v.getX(),v.getY(),v.getZ()); //Vec3 pos=new Vec3(bone.getPos().get(0),bone.getPos().get(1),bone.getPos().get(2)); bvhNode.setOffset(pos); //no channels return bvhNode; } public static int ROOT_POSITION_ROTATE_ONLY=0; public static int ROTATE_ONLY=1; public static int POSITION_ROTATE=2; public void setChannels(BVHNode node,int mode,String order){ Channels ch=new Channels(); if(mode==ROOT_POSITION_ROTATE_ONLY || mode==POSITION_ROTATE){ ch.setXposition(true); ch.setYposition(true); ch.setZposition(true); } if(order.equals("XZY")){ ch.setXrotation(true); ch.setZrotation(true); ch.setYrotation(true); }else if(order.equals("YZX")){ ch.setYrotation(true); ch.setZrotation(true); ch.setXrotation(true); }else if(order.equals("YXZ")){ ch.setYrotation(true); ch.setXrotation(true); ch.setZrotation(true); }else if(order.equals("ZXY")){ ch.setZrotation(true); ch.setXrotation(true); ch.setYrotation(true); }else if(order.equals("ZYX")){ ch.setZrotation(true); ch.setYrotation(true); ch.setXrotation(true); }else{//XYZ ch.setXrotation(true); ch.setYrotation(true); ch.setZrotation(true); } node.setChannels(ch); for(BVHNode child:node.getJoints()){ int m=mode; if(mode==ROOT_POSITION_ROTATE_ONLY){ m=ROTATE_ONLY; } setChannels(child,m,order); } } }