package com.akjava.gwt.three.client.java.bone; import static com.google.common.base.Preconditions.checkArgument; import java.util.ArrayList; import java.util.List; import com.akjava.gwt.lib.client.JavaScriptUtils; import com.akjava.gwt.three.client.gwt.boneanimation.AnimationBone; import com.akjava.gwt.three.client.java.ThreeLog; import com.akjava.gwt.three.client.js.THREE; import com.akjava.gwt.three.client.js.core.Geometry; import com.akjava.gwt.three.client.js.math.Vector3; import com.akjava.gwt.three.client.js.math.Vector4; import com.google.common.base.Joiner; import com.google.common.collect.Lists; import com.google.gwt.core.client.JsArray; /* * not support initial bone-matrix */ public class SimpleAutoWeight { private int influence; public SimpleAutoWeight(int influence){ checkArgument(influence>0 && influence<=4,"influence 1-4"); this.influence=influence; } public static List<List<Integer>> boneToPath(JsArray<AnimationBone> bones){ List<List<Integer>> data=new ArrayList<List<Integer>>(); for(int i=0;i<bones.length();i++){ List<Integer> path=new ArrayList<Integer>(); AnimationBone bone=bones.get(i); path.add(i); data.add(path); while(bone.getParent()!=-1){ //path.add(bone.getParent()); path.add(0,bone.getParent()); bone=bones.get(bone.getParent()); } } return data; } public List<Vector3> convertAbsolutePosition(JsArray<AnimationBone> bones){ List<Vector3> bonePositions=Lists.newArrayList(); for(int j=0;j<bones.length();j++){//TODO make a function AnimationBone ab=bones.get(j); Vector3 bonePos=THREE.Vector3().fromArray(ab.getPos()); bonePositions.add(bonePos); } return convertAbsolutePosition(bonePositions, boneToPath(bones)); } //no care about rotate matrix private List<Vector3> convertAbsolutePosition(List<Vector3> positions,List<List<Integer>> paths){ List<Vector3> absolutePositions=Lists.newArrayList(); checkArgument(positions.size()==paths.size(),"sumPosition:must be same"); for(int i=0;i<paths.size();i++){ Vector3 pos=THREE.Vector3(); List<Integer> path=paths.get(i); for(int index:path){ pos.add(positions.get(index)); } absolutePositions.add(pos); } return absolutePositions; } public WeightResult autoWeight(Geometry geometry,JsArray<AnimationBone> bones){ return autoWeight(geometry, bones,Lists.<Integer>newArrayList()); } private List<Integer> enableBones; public SimpleAutoWeight enableBones(List<Integer> enableBones){ this.enableBones=enableBones; return this; } /* * some case no need root,suchc case add 0 to ignore * * TODO ignore root option usually root 0 ignored */ public WeightResult autoWeight(Geometry geometry,JsArray<AnimationBone> bones,List<Integer> ignoreBones){ List<Vector3> bonePositions=Lists.newArrayList(); JsArray<Vector4> bodyIndicesArray=JavaScriptUtils.createJSArray(); JsArray<Vector4> bodyWeightArray=JavaScriptUtils.createJSArray(); for(int j=0;j<bones.length();j++){//TODO make a function AnimationBone ab=bones.get(j); Vector3 bonePos=THREE.Vector3().fromArray(ab.getPos()); bonePositions.add(bonePos); //ThreeLog.log("bone:"+j,bonePos); } List<Vector3> absolutePositions=convertAbsolutePosition(bonePositions,boneToPath(bones)); for(int j=0;j<bones.length();j++){ //ThreeLog.log("ab:"+j,absolutePositions.get(j)); } //LogUtils.log("bones:"+bonePositions.size()+",vertices:"+geometry.getVertices().length()); for(int i=0;i<geometry.getVertices().length();i++){ List<DistanceData> distanceDatas=Lists.newArrayList(); Vector3 vertex=geometry.getVertices().get(i); //ThreeLog.log("vertex:"+i,vertex); for(int j=0;j<absolutePositions.size();j++){ double distance=absolutePositions.get(j).distanceTo(vertex); if(ignoreBones.contains(j)){ distance=Double.MAX_VALUE; } if(enableBones!=null && !enableBones.contains(j)){ distance=Double.MAX_VALUE; } distanceDatas.add(new DistanceData(j, distance)); } //sort java.util.Collections.sort(distanceDatas); if(i==0){ // LogUtils.log(Joiner.on("\n").join(distanceDatas)); } Vector4 vector4=THREE.Vector4(0,0,0,0); for(int k=0;k<influence;k++){ vector4.gwtSet(k,distanceDatas.get(k).getDistance()); } if(i==121){ // ThreeLog.log("distance",vector4); } vector4.normalize(); if(i==121){ // ThreeLog.log("normalized",vector4); } double total=0; for(int k=0;k<influence;k++){ total+=vector4.gwtGet(k); } for(int k=0;k<influence;k++){ vector4.gwtSet(k,vector4.gwtGet(k)/total); } //TODO make test //switch value for(int k=0;k<influence;k++){ vector4.gwtSet(k,1-vector4.gwtGet(k)); } if(i==121){ // ThreeLog.log("clone one is bigger",vector4); } double total2=0; for(int k=0;k<influence;k++){ total2+=vector4.gwtGet(k); } for(int k=0;k<influence;k++){ vector4.gwtSet(k,vector4.gwtGet(k)/total2); } //if multiple 0 exist,but no need solve divided total //vector4.normalize(); //NaN on JavaScript //LogUtils.log("test:"+(1-(0/0))); if(i==121){ // ThreeLog.log("modify total",vector4); } if(influence==1){ vector4.gwtSet(0,1); } Vector4 bodyIndices=THREE.Vector4(0,0,0,0); for(int k=0;k<influence;k++){ bodyIndices.gwtSet(k, distanceDatas.get(k).getBoneIndex()); //LogUtils.log("vertex="+i+",index="+distanceDatas.get(k).getBoneIndex()+",distance="+distanceDatas.get(k).getDistance()); } bodyWeightArray.push(vector4); bodyIndicesArray.push(bodyIndices); } return new WeightResult(bodyIndicesArray, bodyWeightArray).setInfluence(influence); } //TODO make independent class }