Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

skinning -> morph-targets

  • Loading branch information...
commit f7c4d504f9310b23e25569fbc64a06f9764492ac 1 parent 8a68b94
@timknip2 timknip2 authored
Showing with 151 additions and 105 deletions.
  1. +1 −1  build/Three.js
  2. +22 −103 examples/webgl_collada.html
  3. +128 −1 src/extras/collada/dae.js
View
2  build/Three.js
@@ -39,7 +39,7 @@ h*k,m=h*g,p=f*k,u=f*g;this.n11=o+u*e;this.n12=p*e-m;this.n13=j*f;this.n21=j*g;th
j*f;p=e*h;u=e*f;this.n11=h*k;this.n12=u-o*g;this.n13=p*g+m;this.n21=g;this.n22=j*k;this.n23=-e*k;this.n31=-f*k;this.n32=m*g+p;this.n33=o-u*g;break;case "XZY":o=j*h;m=j*f;p=e*h;u=e*f;this.n11=h*k;this.n12=-g;this.n13=f*k;this.n21=o*g+u;this.n22=j*k;this.n23=m*g-p;this.n31=p*g-m;this.n32=e*k;this.n33=u*g+o;break;default:o=j*k,m=j*g,p=e*k,u=e*g,this.n11=h*k,this.n12=-h*g,this.n13=f,this.n21=m+p*f,this.n22=o-u*f,this.n23=-e*h,this.n31=u-o*f,this.n32=p+m*f,this.n33=j*h}return this},setRotationFromQuaternion:function(b){var c=
b.x,e=b.y,f=b.z,g=b.w,j=c+c,h=e+e,k=f+f,b=c*j,o=c*h;c*=k;var m=e*h;e*=k;f*=k;j*=g;h*=g;g*=k;this.n11=1-(m+f);this.n12=o-g;this.n13=c+h;this.n21=o+g;this.n22=1-(b+f);this.n23=e-j;this.n31=c-h;this.n32=e+j;this.n33=1-(b+m);return this},scale:function(b){var c=b.x,e=b.y,b=b.z;this.n11*=c;this.n12*=e;this.n13*=b;this.n21*=c;this.n22*=e;this.n23*=b;this.n31*=c;this.n32*=e;this.n33*=b;this.n41*=c;this.n42*=e;this.n43*=b;return this},compose:function(b,c,e){var f=new THREE.Matrix4,g=new THREE.Matrix4;f.setRotationFromQuaternion(c);
g.setScale(e.x,e.y,e.z);this.multiply(f,g);this.n14=b.x;this.n24=b.y;this.n34=b.z;return this},decompose:function(b,c,e){var f=new THREE.Vector3(this.n11,this.n21,this.n31),g=new THREE.Vector3(this.n12,this.n22,this.n32),j=new THREE.Vector3(this.n13,this.n23,this.n33),b=b instanceof THREE.Vector3?b:new THREE.Vector3,c=c instanceof THREE.Quaternion?c:new THREE.Quaternion,e=e instanceof THREE.Vector3?e:new THREE.Vector3;e.x=f.length();e.y=g.length();e.z=j.length();b.x=this.n14;b.y=this.n24;b.z=this.n34;
-b=this.clone();b.n11/=e.x;b.n21/=e.x;b.n31/=e.x;b.n12/=e.y;b.n22/=e.y;b.n32/=e.y;b.n13/=e.z;b.n23/=e.z;b.n33/=e.z;c.setFromRotationMatrix(b)},extractPosition:function(b){this.n14=b.n14;this.n24=b.n24;this.n34=b.n34},extractRotation:function(b,c){var e=1/c.x,f=1/c.y,g=1/c.z;this.n11=b.n11*e;this.n21=b.n21*e;this.n31=b.n31*e;this.n12=b.n12*f;this.n22=b.n22*f;this.n32=b.n32*f;this.n13=b.n13*g;this.n23=b.n23*g;this.n33=b.n33*g}};
+f=this.clone();f.n11/=e.x;f.n21/=e.x;f.n31/=e.x;f.n12/=e.y;f.n22/=e.y;f.n32/=e.y;f.n13/=e.z;f.n23/=e.z;f.n33/=e.z;c.setFromRotationMatrix(f);return[b,c,e]},extractPosition:function(b){this.n14=b.n14;this.n24=b.n24;this.n34=b.n34},extractRotation:function(b,c){var e=1/c.x,f=1/c.y,g=1/c.z;this.n11=b.n11*e;this.n21=b.n21*e;this.n31=b.n31*e;this.n12=b.n12*f;this.n22=b.n22*f;this.n32=b.n32*f;this.n13=b.n13*g;this.n23=b.n23*g;this.n33=b.n33*g}};
THREE.Matrix4.makeInvert=function(b,c){var e=b.n11,f=b.n12,g=b.n13,j=b.n14,h=b.n21,k=b.n22,o=b.n23,m=b.n24,p=b.n31,u=b.n32,v=b.n33,t=b.n34,w=b.n41,x=b.n42,B=b.n43,A=b.n44;c===void 0&&(c=new THREE.Matrix4);c.n11=o*t*x-m*v*x+m*u*B-k*t*B-o*u*A+k*v*A;c.n12=j*v*x-g*t*x-j*u*B+f*t*B+g*u*A-f*v*A;c.n13=g*m*x-j*o*x+j*k*B-f*m*B-g*k*A+f*o*A;c.n14=j*o*u-g*m*u-j*k*v+f*m*v+g*k*t-f*o*t;c.n21=m*v*w-o*t*w-m*p*B+h*t*B+o*p*A-h*v*A;c.n22=g*t*w-j*v*w+j*p*B-e*t*B-g*p*A+e*v*A;c.n23=j*o*w-g*m*w-j*h*B+e*m*B+g*h*A-e*o*A;c.n24=
g*m*p-j*o*p+j*h*v-e*m*v-g*h*t+e*o*t;c.n31=k*t*w-m*u*w+m*p*x-h*t*x-k*p*A+h*u*A;c.n32=j*u*w-f*t*w-j*p*x+e*t*x+f*p*A-e*u*A;c.n33=g*m*w-j*k*w+j*h*x-e*m*x-f*h*A+e*k*A;c.n34=j*k*p-f*m*p-j*h*u+e*m*u+f*h*t-e*k*t;c.n41=o*u*w-k*v*w-o*p*x+h*v*x+k*p*B-h*u*B;c.n42=f*v*w-g*u*w+g*p*x-e*v*x-f*p*B+e*u*B;c.n43=g*k*w-f*o*w-g*h*x+e*o*x+f*h*B-e*k*B;c.n44=f*o*p-g*k*p+g*h*u-e*o*u-f*h*v+e*k*v;c.multiplyScalar(1/b.determinant());return c};
THREE.Matrix4.makeInvert3x3=function(b){var c=b.m33,e=c.m,f=b.n33*b.n22-b.n32*b.n23,g=-b.n33*b.n21+b.n31*b.n23,j=b.n32*b.n21-b.n31*b.n22,h=-b.n33*b.n12+b.n32*b.n13,k=b.n33*b.n11-b.n31*b.n13,o=-b.n32*b.n11+b.n31*b.n12,m=b.n23*b.n12-b.n22*b.n13,p=-b.n23*b.n11+b.n21*b.n13,u=b.n22*b.n11-b.n21*b.n12,b=b.n11*f+b.n21*h+b.n31*m;b==0&&console.error("THREE.Matrix4.makeInvert3x3: Matrix not invertible.");b=1/b;e[0]=b*f;e[1]=b*g;e[2]=b*j;e[3]=b*h;e[4]=b*k;e[5]=b*o;e[6]=b*m;e[7]=b*p;e[8]=b*u;return c};
View
125 examples/webgl_collada.html
@@ -31,14 +31,16 @@
var camera, scene, renderer, objects;
var particleLight, pointLight;
- var dae;
+ var dae, skin;
DAE.load('./models/monster.dae', colladaReady);
function colladaReady(collada) {
dae = collada.scene;
- dae.scale.x = dae.scale.y = dae.scale.z = 0.003;
- //dae.rotation.x = -Math.PI/2;
+ skin = collada.skins[0];
+
+ dae.scale.x = dae.scale.y = dae.scale.z = 0.002;
+ dae.rotation.x = -Math.PI/2;
dae.updateMatrix();
init();
@@ -59,7 +61,7 @@
// Grid
- var line_material = new THREE.LineBasicMaterial( { color: 0x0, opacity: 0.2 } ),
+ var line_material = new THREE.LineBasicMaterial( { color: 0xcccccc, opacity: 0.2 } ),
geometry = new THREE.Geometry(),
floor = -0.04, step = 1, size = 14;
@@ -75,85 +77,18 @@
var line = new THREE.Line( geometry, line_material, THREE.LinePieces );
scene.addObject( line );
-
- // Materials
-
- var generatedTexture = new THREE.Texture( generateTexture() );
- generatedTexture.needsUpdate = true;
-
- var materials = [];
- materials.push( new THREE.MeshLambertMaterial( { map: generatedTexture } ) );
- materials.push( new THREE.MeshLambertMaterial( { color: 0xdddddd, shading: THREE.FlatShading } ) );
- materials.push( new THREE.MeshPhongMaterial( { ambient: 0x030303, color: 0xdddddd, specular: 0x009900, shininess: 30, shading: THREE.FlatShading } ) );
- materials.push( new THREE.MeshNormalMaterial( ) );
- materials.push( new THREE.MeshBasicMaterial( { color: 0x665500, blending: THREE.AdditiveBlending } ) );
- //materials.push( new THREE.MeshBasicMaterial( { color: 0xff0000, blending: THREE.SubtractiveBlending } ) );
-
- materials.push( new THREE.MeshLambertMaterial( { color: 0xdddddd, shading: THREE.SmoothShading } ) );
- materials.push( new THREE.MeshPhongMaterial( { ambient: 0x030303, color: 0xdddddd, specular: 0x009900, shininess: 30, shading: THREE.SmoothShading } ) );
- materials.push( new THREE.MeshNormalMaterial( { shading: THREE.SmoothShading } ) );
- materials.push( new THREE.MeshBasicMaterial( { color: 0xffaa00, wireframe: true } ) );
-
- materials.push( new THREE.MeshDepthMaterial() );
- materials.push( new THREE.MeshBasicMaterial( { map: generatedTexture } ) );
-
- // Spheres geometry
-
- var geometry_smooth = new THREE.SphereGeometry( 70, 32, 16 );
- var geometry_flat = new THREE.SphereGeometry( 70, 32, 16 );
- var geometry_pieces = new THREE.SphereGeometry( 70, 32, 16 ); // Extra geometry to be broken down for MeshFaceMaterial
-
- for ( var i = 0, l = geometry_pieces.faces.length; i < l; i ++ ) {
-
- var face = geometry_pieces.faces[ i ];
- if ( Math.random() > 0.7 ) face.materials = [ materials[ Math.floor( Math.random() * materials.length ) ] ];
-
- }
-
- materials.push( new THREE.MeshFaceMaterial() );
-
- objects = [];
-
- var sphere, geometry, material;
-
- for ( var i = 0, l = materials.length; i < l; i ++ ) {
-
- material = materials[ i ];
-
- geometry = material instanceof THREE.MeshFaceMaterial ? geometry_pieces :
- ( material.shading == THREE.FlatShading ? geometry_flat : geometry_smooth );
-
- sphere = new THREE.Mesh( geometry, material );
-
- sphere.position.x = ( i % 4 ) * 200 - 400;
- sphere.position.z = Math.floor( i / 4 ) * 200 - 200;
-
- sphere.rotation.x = Math.random() * 200 - 100;
- sphere.rotation.y = Math.random() * 200 - 100;
- sphere.rotation.z = Math.random() * 200 - 100;
-
- objects.push( sphere );
-
- //scene.addObject( sphere );
-
- }
- //dae.rotation.x = -Math.PI/2;
+ // Add the COLLADA
scene.addObject(dae);
- //var wall = dae_geometries['wall-geometry'][0];
-
- //var dae = new THREE.Mesh( wall, materials[3] );
- //dae.scale.x = dae.scale.y = dae.scale.z = 100.0;
- //scene.addObject(dae);
particleLight = new THREE.Mesh( new THREE.SphereGeometry( 4, 8, 8 ), new THREE.MeshBasicMaterial( { color: 0xffffff } ) );
scene.addObject( particleLight );
// Lights
- scene.addLight( new THREE.AmbientLight( 0x202020 ) );
+ scene.addLight( new THREE.AmbientLight( 0xaaaaaa) );
- var directionalLight = new THREE.DirectionalLight(/*Math.random() * 0xffffff*/0xcccccc);
+ var directionalLight = new THREE.DirectionalLight(/*Math.random() * 0xffffff*/0xbbbbbb);
directionalLight.position.x = Math.random() - 0.5;
directionalLight.position.y = Math.random() - 0.5;
directionalLight.position.z = Math.random() - 0.5;
@@ -175,39 +110,23 @@
}
- function generateTexture() {
-
- var canvas = document.createElement( 'canvas' );
- canvas.width = 256;
- canvas.height = 256;
-
- var context = canvas.getContext( '2d' );
- var image = context.getImageData( 0, 0, 256, 256 );
-
- var x = 0, y = 0;
-
- for ( var i = 0, j = 0, l = image.data.length; i < l; i += 4, j ++ ) {
-
- x = j % 256;
- y = x == 0 ? y + 1 : y;
-
- image.data[ i + 2 ] = Math.floor( x ^ y );
- image.data[ i + 3 ] = 255;
-
- }
-
- context.putImageData( image, 0, 0 );
-
- return canvas;
-
- }
-
//
-
+ var t = 0;
function animate() {
requestAnimationFrame( animate );
-
+
+ if (t > 101) t = 0;
+ if (skin) {
+ // guess this can be done smarter...
+ for (var i = 0; i < skin.morphTargetInfluences.length; i++) {
+ skin.morphTargetInfluences[i] = 0;
+ }
+ skin.morphTargetInfluences[Math.floor(t)] = 1;
+
+ t += 0.5;
+ }
+
render();
stats.update();
View
129 src/extras/collada/dae.js
@@ -152,6 +152,7 @@ var DAE = (function() {
function calcAnimationBounds() {
var start = 1000000;
var end = -start;
+ var frames = 0;
for (id in animations) {
var animation = animations[id];
@@ -160,9 +161,10 @@ var DAE = (function() {
sampler.create();
start = Math.min(start, sampler.startTime);
end = Math.max(end, sampler.endTime);
+ frames = Math.max(frames, sampler.input.length);
}
}
- return {start:start, end:end}
+ return {start:start, end:end, frames:frames}
}
function createMorph(geometry, ctrl) {
@@ -227,6 +229,127 @@ var DAE = (function() {
}
}
+ function setupSkeleton(node, bones, frame, parent) {
+ node.world = node.world || new THREE.Matrix4();
+ node.world.copy(node.matrix);
+
+ if (node.channels && node.channels.length) {
+ var channel = node.channels[0];
+ var m = channel.sampler.output[frame];
+ if (m instanceof THREE.Matrix4) {
+ node.world.copy(m);
+ }
+ }
+
+ if (parent) {
+ node.world.multiply(parent, node.world);
+ }
+
+ bones.push(node);
+
+ for (var i = 0; i < node.nodes.length; i++) {
+ setupSkeleton(node.nodes[i], bones, frame, node.world);
+ }
+ }
+
+ function setupSkinningMatrices(bones, skin) {
+ // FIXME: this is dumb...
+ for (var i = 0; i < bones.length; i++) {
+ var bone = bones[i];
+ var found = -1;
+ for (var j = 0; j < skin.joints.length; j++) {
+ if (bone.sid == skin.joints[j]) {
+ found = j;
+ break;
+ }
+ }
+ if (found >= 0){
+ var inv = skin.invBindMatrices[found];
+ bone.invBindMatrix = inv;
+ bone.skinningMatrix = new THREE.Matrix4();
+ bone.skinningMatrix.multiply(bone.world, inv);
+ bone.weights = [];
+ for (var j = 0; j < skin.weights.length; j++) {
+ for (var k = 0; k < skin.weights[j].length; k++) {
+ var w = skin.weights[j][k];
+ if (w.joint == found) {
+ bone.weights.push(w);
+ }
+ }
+ }
+ } else {
+ throw "could not find joint!";
+ }
+ }
+ }
+
+ function applySkin(geometry, instanceCtrl, frame) {
+ var skinController = controllers[instanceCtrl.url];
+
+ frame = frame !== undefined ? frame : 40;
+
+ if (!skinController || !skinController.skin) {
+ console.log("could not find skin controller!");
+ return;
+ }
+
+ if (!instanceCtrl.skeleton || !instanceCtrl.skeleton.length) {
+ console.log("could not find the skeleton for the skin!");
+ return;
+ }
+
+ var animationBounds = calcAnimationBounds();
+ var skeleton = daeScene.getChildById(instanceCtrl.skeleton[0], true) ||
+ daeScene.getChildBySid(instanceCtrl.skeleton[0], true);
+ var i, j, w, vidx, weight;
+ var v = new THREE.Vector3(), o, s;
+
+ // move vertices to bind shape
+ for (i = 0; i < geometry.vertices.length; i++) {
+ skinController.skin.bindShapeMatrix.multiplyVector3(geometry.vertices[i].position);
+ }
+
+ // process animation, or simply pose the rig if no animation
+ for (frame = 0; frame < animationBounds.frames; frame++) {
+ var bones = [];
+ var skinned = [];
+
+ // zero skinned vertices
+ for (i = 0; i < geometry.vertices.length; i++) {
+ skinned.push( new THREE.Vertex( new THREE.Vector3() ) );
+ }
+
+ // process the frame and setup the rig with a fresh
+ // transform, possibly from the bone's animation channel(s)
+ setupSkeleton(skeleton, bones, frame);
+ setupSkinningMatrices(bones, skinController.skin);
+
+ // skin 'm
+ for (i = 0; i < bones.length; i++) {
+ for (j = 0; j < bones[i].weights.length; j++) {
+ w = bones[i].weights[j];
+ vidx = w.index;
+ weight = w.weight;
+
+ o = geometry.vertices[vidx];
+ s = skinned[vidx];
+
+ v.x = o.position.x;
+ v.y = o.position.y;
+ v.z = o.position.z;
+
+ bones[i].skinningMatrix.multiplyVector3(v);
+
+ s.position.x += (v.x * weight);
+ s.position.y += (v.y * weight);
+ s.position.z += (v.z * weight);
+ }
+ }
+
+ geometry.morphTargets.push( { name: "target_" + frame, vertices: skinned } );
+ }
+ }
+
function createSceneGraph(node, parent) {
var obj = new THREE.Object3D();
var skinned = false;
@@ -322,9 +445,12 @@ var DAE = (function() {
}
if (skinController !== undefined) {
+ applySkin(geom, skinController);
+ material.morphTargets = true;
mesh = new THREE.SkinnedMesh( geom, material );
mesh.skeleton = skinController.skeleton;
mesh.skinController = controllers[skinController.url];
+ mesh.skinInstanceController = skinController;
mesh.name = 'skin_' + skins.length;
skins.push(mesh);
} else if (morphController !== undefined) {
@@ -1898,6 +2024,7 @@ var DAE = (function() {
return {
load: load,
setPreferredShading: setPreferredShading,
+ applySkin: applySkin,
geometries : geometries
};
})();
Please sign in to comment.
Something went wrong with that request. Please try again.