Browse Source

Merge remote-tracking branch 'remotes/mrdoob/dev' into dev

alteredq 14 years ago
parent
commit
29e51a6ed9
2 changed files with 170 additions and 29 deletions
  1. 42 28
      examples/webgl_collada.html
  2. 128 1
      src/extras/collada/dae.js

+ 42 - 28
examples/webgl_collada.html

@@ -22,7 +22,7 @@
 		<script type="text/javascript" src="js/RequestAnimationFrame.js"></script>
 		<script type="text/javascript" src="js/Stats.js"></script>
 		<script type="text/javascript" src="../src/extras/collada/dae.js"></script>
-
+		
 		<script type="text/javascript">
 
 			if ( ! Detector.webgl ) Detector.addGetWebGLMessage();
@@ -31,22 +31,24 @@
 
 			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();
 				animate();
 			}
-
+			
 			function init() {
-
+					
 				container = document.createElement('div');
 				document.body.appendChild(container);
 
@@ -59,7 +61,7 @@
 
 				// Grid
 
-				var line_material = new THREE.LineBasicMaterial( { color: 0xffffff, opacity: 0.1 } ),
+				var line_material = new THREE.LineBasicMaterial( { color: 0xcccccc, opacity: 0.2 } ),
 					geometry = new THREE.Geometry(),
 					floor = -0.04, step = 1, size = 14;
 
@@ -75,24 +77,25 @@
 
 				var line = new THREE.Line( geometry, line_material, THREE.LinePieces );
 				scene.addObject( line );
-
-				//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( 0.1, 8, 8 ), new THREE.MeshBasicMaterial( { color: 0xffffff } ) );
-				particleLight.position.x = 10;
+				particleLight = new THREE.Mesh( new THREE.SphereGeometry( 4, 8, 8 ), new THREE.MeshBasicMaterial( { color: 0xffffff } ) );
 				scene.addObject( particleLight );
 
 				// Lights
 
-				scene.addLight( new THREE.AmbientLight( 0x808080 ) );
+				scene.addLight( new THREE.AmbientLight( 0xaaaaaa) );
+
+				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;
+				directionalLight.position.normalize();
+				scene.addLight( directionalLight );
 
-				pointLight = new THREE.PointLight( 0xffffff, 4 );
+				pointLight = new THREE.PointLight( 0xdddddd, 0.6 );
 				scene.addLight( pointLight );
 
 				renderer = new THREE.WebGLRenderer();
@@ -108,11 +111,22 @@
 			}
 
 			//
-
+			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();
 
@@ -122,13 +136,13 @@
 
 				var timer = new Date().getTime() * 0.0005;
 
-				camera.position.x = Math.cos( timer ) * 20;
-				camera.position.y = 10;
-				camera.position.z = Math.sin( timer ) * 20;
+				camera.position.x = Math.cos( timer ) * 10;
+				camera.position.y = 2;
+				camera.position.z = Math.sin( timer ) * 10;
 
-				particleLight.position.x = Math.sin( timer * 2 ) * 3;
-				particleLight.position.y = Math.cos( timer * 1 ) * 4;
-				particleLight.position.z = Math.cos( timer * 2 ) * 3;
+				particleLight.position.x = Math.sin( timer * 4 ) * 300;
+				particleLight.position.y = Math.cos( timer * 5 ) * 400;
+				particleLight.position.z = Math.cos( timer * 4 ) * 300;
 
 				pointLight.position.x = particleLight.position.x;
 				pointLight.position.y = particleLight.position.y;

+ 128 - 1
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
 	};
 })();