package com.akjava.gwt.three.client.java;
import java.util.List;
import com.akjava.gwt.lib.client.LogUtils;
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.Matrix4;
import com.akjava.gwt.three.client.js.math.Vector3;
import com.akjava.gwt.three.client.js.math.Vector4;
import com.akjava.gwt.three.client.js.objects.SkinnedMesh;
import com.google.common.collect.Lists;
/**
* for attach something with skinning-geometry
* @author aki
*
*/
public class SkinningVertexCalculator {
private SkinnedMesh skinnedMesh;
public SkinningVertexCalculator(SkinnedMesh skinnedMesh) {
super();
this.skinnedMesh = skinnedMesh;
}
public SkinnedMesh getSkinnedMesh() {
return skinnedMesh;
}
public void setSkinnedMesh(SkinnedMesh skinnedMesh) {
this.skinnedMesh = skinnedMesh;
}
private List<Vector3> result=Lists.newArrayList();
public List<Vector3> getResult() {
return result;
}
private List<SkinningVertex> skinningVertexs=Lists.newArrayList();
public List<SkinningVertex> getSkinningVertexs() {
return skinningVertexs;
}
//add from skinnedMesh vertex
public SkinningVertex createSkinningVertex(int index,int targetClothIndex){
Vector4 skinIndices =skinnedMesh.getGeometry().getSkinIndices().get(index);
Vector4 skinWeights =skinnedMesh.getGeometry().getSkinWeights().get(index);
Vector3 vertex =skinnedMesh.getGeometry().getVertices().get(index).clone();
SkinningVertex skinningVertex=new SkinningVertex(vertex, skinIndices, skinWeights);
skinningVertex.setTargetClothIndex(targetClothIndex);
return skinningVertex;
}
public int size(){
return skinningVertexs.size();
}
public void add(SkinningVertex vertex){
skinningVertexs.add(vertex);
result.add(THREE.Vector3());
}
public void update(){
for(int i=0;i<skinningVertexs.size();i++){
result.get(i).copy(transformSkinningVertex(skinnedMesh,skinningVertexs.get(i)).applyMatrix4(skinnedMesh.getMatrixWorld()));
}
}
/**
* only workd geometry ,not buffer geometry
* @param vertex
* @return
//from http://stackoverflow.com/questions/31620194/how-to-calculate-transformed-skin-vertices
*/
public static Vector3 transformSkinningVertex(SkinnedMesh skinnedMesh,SkinningVertex vertex){
//for thread safe
Vector3 vec3=THREE.Vector3();
vec3.copy(vertex.getVertex()).applyMatrix4(skinnedMesh.getBindMatrix());
Vector3 result = THREE.Vector3 ();
Vector3 temp = THREE.Vector3 ();
Matrix4 tempMatrix = THREE.Matrix4 ();
//properties = ['x', 'y', 'z', 'w'];
for (int i = 0; i < 4; i++) {
int boneIndex;
double boneWeight;
if(i==0){
boneIndex=(int)vertex.getSkinIndices().getX();
boneWeight=vertex.getSkinWeights().getX();
}else if(i==1){
boneIndex=(int)vertex.getSkinIndices().getY();
boneWeight=vertex.getSkinWeights().getY();
}else if(i==2){
boneIndex=(int)vertex.getSkinIndices().getZ();
boneWeight=vertex.getSkinWeights().getZ();
}else{
boneIndex=(int)vertex.getSkinIndices().getW();
boneWeight=vertex.getSkinWeights().getW();
}
if(boneIndex<0 || boneIndex>=skinnedMesh.getSkeleton().getBones().length()){
LogUtils.log("boneIndex="+boneIndex+",but bones below size="+skinnedMesh.getSkeleton().getBones().length());
LogUtils.log(skinnedMesh.getSkeleton().getBones());
throw new RuntimeException("out of index");
}
tempMatrix.multiplyMatrices (skinnedMesh.getSkeleton().getBones().get(boneIndex).getMatrixWorld(), skinnedMesh.getSkeleton().getBoneInverses().get(boneIndex));
result.add (temp.copy (vec3).applyMatrix4 (tempMatrix).multiplyScalar (boneWeight));
}
return result.applyMatrix4 (skinnedMesh.getBindMatrixInverse());
}
public static Vector3 transformSkinningVertex(SkinnedMesh skinnedMesh,int index,Vector3 vertex){
//for thread safe
Vector3 vec3=THREE.Vector3();
vec3.copy(vertex).applyMatrix4(skinnedMesh.getBindMatrix());
Vector3 result = THREE.Vector3 ();
Vector3 temp = THREE.Vector3 ();
Matrix4 tempMatrix = THREE.Matrix4 ();
//properties = ['x', 'y', 'z', 'w'];
for (int i = 0; i < 4; i++) {
int boneIndex;
double boneWeight;
if(i==0){
boneIndex=(int)skinnedMesh.getGeometry().getSkinIndices().get(index).getX();
boneWeight=skinnedMesh.getGeometry().getSkinWeights().get(index).getX();
}else if(i==1){
boneIndex=(int)skinnedMesh.getGeometry().getSkinIndices().get(index).getY();
boneWeight=skinnedMesh.getGeometry().getSkinWeights().get(index).getY();
}else if(i==2){
boneIndex=(int)skinnedMesh.getGeometry().getSkinIndices().get(index).getZ();
boneWeight=skinnedMesh.getGeometry().getSkinWeights().get(index).getZ();
}else{
boneIndex=(int)skinnedMesh.getGeometry().getSkinIndices().get(index).getW();
boneWeight=skinnedMesh.getGeometry().getSkinWeights().get(index).getW();
}
if(boneIndex<0 || boneIndex>=skinnedMesh.getSkeleton().getBones().length()){
LogUtils.log("boneIndex="+boneIndex+",but bones below.size="+skinnedMesh.getSkeleton().getBones().length());
LogUtils.log(skinnedMesh.getSkeleton().getBones());
throw new RuntimeException("out of index");
}
tempMatrix.multiplyMatrices (skinnedMesh.getSkeleton().getBones().get(boneIndex).getMatrixWorld(), skinnedMesh.getSkeleton().getBoneInverses().get(boneIndex));
result.add (temp.copy (vec3).applyMatrix4 (tempMatrix).multiplyScalar (boneWeight));
}
return result.applyMatrix4 (skinnedMesh.getBindMatrixInverse());
}
public static class SkinningVertex{
private Vector3 vertex;//usually it's copy
public SkinningVertex(Vector3 vertex, Vector4 skinIndices, Vector4 skinWeights) {
super();
this.vertex = vertex;
this.skinIndices = skinIndices;
this.skinWeights = skinWeights;
}
public Vector3 getVertex() {
return vertex;
}
public void setVertex(Vector3 vertex) {
this.vertex = vertex;
}
public Vector4 getSkinIndices() {
return skinIndices;
}
public void setSkinIndices(Vector4 skinIndices) {
this.skinIndices = skinIndices;
}
public Vector4 getSkinWeights() {
return skinWeights;
}
public void setSkinWeights(Vector4 skinWeights) {
this.skinWeights = skinWeights;
}
private Vector4 skinIndices;//usually from origin don't modify
private Vector4 skinWeights;//usually from origin don't modify
//for custom cloth mapping
private int targetClothIndex=-1;
public int getTargetClothIndex() {
return targetClothIndex;
}
public void setTargetClothIndex(int targetClothIndex) {
this.targetClothIndex = targetClothIndex;
}
}
//from http://stackoverflow.com/questions/31620194/how-to-calculate-transformed-skin-vertices
public static final native Vector3 transformedSkinVertex (SkinnedMesh skin,int index)/*-{
//var skinIndices = (new $wnd.THREE.Vector4 ()).fromAttribute (skin.geometry.getAttribute ('skinIndex'), index);
//var skinWeights = (new $wnd.THREE.Vector4 ()).fromAttribute (skin.geometry.getAttribute ('skinWeight'), index);
//var skinVertex = (new $wnd.THREE.Vector3 ()).fromAttribute (skin.geometry.getAttribute ('position'), index).applyMatrix4 (skin.bindMatrix);
var skinIndices =skin.geometry.skinIndices[index];
var skinWeights =skin.geometry.skinWeights[index];
var skinVertex =skin.geometry.vertices[index].clone().applyMatrix4(skin.bindMatrix);
var result = new $wnd.THREE.Vector3 (), temp = new $wnd.THREE.Vector3 (), tempMatrix = new $wnd.THREE.Matrix4 (); properties = ['x', 'y', 'z', 'w'];
for (var i = 0; i < 4; i++) {
var boneIndex = skinIndices[properties[i]];
tempMatrix.multiplyMatrices (skin.skeleton.bones[boneIndex].matrixWorld, skin.skeleton.boneInverses[boneIndex]);
// result.add (temp.copy (skinVertex).multiplyScalar (skinWeights[properties[i]]).applyMatrix4 (tempMatrix));
result.add (temp.copy (skinVertex).applyMatrix4 (tempMatrix).multiplyScalar (skinWeights[properties[i]]));
}
return result.applyMatrix4 (skin.bindMatrixInverse);
}-*/;
}