Browse Source

updates to dae

timk 14 years ago
parent
commit
003fe471f8
1 changed files with 538 additions and 128 deletions
  1. 538 128
      src/extras/collada/dae.js

+ 538 - 128
src/extras/collada/dae.js

@@ -14,8 +14,11 @@ var DAE = (function() {
 	var materials = {};
 	var effects = {};
 	var visualScenes;
+	var flip_uv = true;
 	var readyCallbackFunc = null;
 	var baseUrl;
+	var morphs;
+	var skins;
 	
 	function load(url, readyCallback) {
 		if (document.implementation && document.implementation.createDocument) {
@@ -65,6 +68,9 @@ var DAE = (function() {
 		animations = parseLib("//dae:library_animations/dae:animation", Animation, "animation");
 		visualScenes = parseLib(".//dae:library_visual_scenes/dae:visual_scene", VisualScene, "visual_scene");
 		
+		morphs = [];
+		skins = [];
+		
 		daeScene = parseScene();
 		scene = new THREE.Object3D();
 		for (var i = 0; i < daeScene.nodes.length; i++) {
@@ -75,6 +81,8 @@ var DAE = (function() {
 
 		var result = {
 			scene: scene, 
+			morphs: morphs,
+			skins: skins,
 			dae: {
 				images: images,
 				materials: materials,
@@ -128,70 +136,104 @@ var DAE = (function() {
 	}
 	
 	function createAnimations() {
+		calcAnimationBounds();
 		for (animation_id in animations) {
 			createAnimation(animations[animation_id]);
 		}
 	}
 	
 	function createAnimation(animation) {
+	}
+	
+	function calcAnimationBounds() {
+		var start = 1000000;
+		var end = -start;
 		
-		for (var i = 0; i < animation.channel.length; i++) {
-			var channel = animation.channel[i];
-			var sampler = animation.sampler[i];
-			
-			var parts = channel.target.split("/");
-			var id = parts.shift();
-			var node = daeScene.getChildById(id, true);
-			var object = scene.getChildByName(id, true);
-			
-			if (!node || !object) {
-				console.error("Dae::createAnimation : could not find node with id=" + id);
-				continue;
+		for (id in animations) {
+			var animation = animations[id];
+			for (var i = 0; i < animation.sampler.length; i++) {
+				var sampler = animation.sampler[i];
+				sampler.create();	
+				start = Math.min(start, sampler.startTime);
+				end = Math.max(end, sampler.endTime);
 			}
-			
-			if (parts.length > 1) {
-				console.log("Dae::createAnimation : can only handle simple paths [" + channel.target + "]");
+		}
+		return {start:start, end:end}
+	}
+	
+	function createMorph(geometry, ctrl) {
+		var morphCtrl = ctrl instanceof InstanceController ? controllers[ctrl.url] : ctrl;
+		if (!morphCtrl || !morphCtrl.morph) {
+			console.log("could not find morph controller!");
+			return;
+		}
+		var morph = morphCtrl.morph;
+
+		for (var i = 0; i < morph.targets.length; i++) {
+			var target_id = morph.targets[i];
+			var daeGeometry = geometries[target_id];
+			if (!daeGeometry.mesh || 
+				!daeGeometry.mesh.primitives || 
+				!daeGeometry.mesh.primitives.length) {
 				continue;
 			}
-			var sid = parts.shift();
-			var dotSyntax = (sid.indexOf(".") >= 0);
-			var arrSyntax = (sid.indexOf("(") >= 0);
-			var arrIndices;
-			var member;
-			
-			if (dotSyntax) {
-				parts = sid.split(".");
-				sid = parts.shift();
-				member = parts.shift();
-			} else if (arrSyntax) {
-				arrIndices = sid.split("(");
-				sid = arrIndices.shift();
-				for (var j = 0; j < arrIndices.length; j++) {
-					arrIndices[j] = parseInt(arrIndices[j].replace(/\)/, ''));
-				}
+			var target = daeGeometry.mesh.primitives[0].geometry;
+			if (target.vertices.length === geometry.vertices.length) {
+				geometry.morphTargets.push( { name: "target_1", vertices: target.vertices } );
 			}
-			var transform = node.getTransformBySid(sid);
-			
-			sampler.create();
-			switch (transform.type) {
-				case 'matrix':
-					//console.log(sampler.output[0]);
-					break;
-				default:
-					break;
+		}
+		geometry.morphTargets.push( { name: "target_Z", vertices: geometry.vertices } );
+	}
+	
+	function createSkin(geometry, ctrl, applyBindShape) {
+		var skinCtrl = controllers[ctrl.url];
+		if (!skinCtrl || !skinCtrl.skin) {
+			console.log("could not find skin controller!");
+			return;
+		}
+		if (!ctrl.skeleton || !ctrl.skeleton.length) {
+			console.log("could not find the skeleton for the skin!");
+			return;
+		}
+		var skin = skinCtrl.skin;
+		var skeleton = daeScene.getChildById(ctrl.skeleton[0]);
+		var hierarchy = [];
+		
+		applyBindShape = applyBindShape !== undefined ? applyBindShape : true;
+		
+		var bones = [];
+		geometry.skinWeights = [];
+		geometry.skinIndices = [];
+		
+		createBones(geometry.bones, skin, hierarchy, skeleton, null, -1);
+		createWeights(skin, geometry.bones, geometry.skinIndices, geometry.skinWeights);
+		/*
+		geometry.animation = {
+			name: 'take_001',
+			fps: 30,
+			length: 2,
+			JIT: true,
+			hierarchy: hierarchy
+		};
+		*/
+		if (applyBindShape) {
+			for (var i = 0; i < geometry.vertices.length; i++) {
+				skin.bindShapeMatrix.multiplyVector3(geometry.vertices[i].position);
 			}
 		}
 	}
 	
-	function createSceneGraph(node) {
+	function createSceneGraph(node, parent) {
 		var obj = new THREE.Object3D();
 		var skinned = false;
+		var skinController;
+		var morphController;
 		var i;
 		
 		obj.name = node.id || "";
 		obj.matrixAutoUpdate = false;
 		obj.matrix = node.matrix;
-
+		
 		// FIXME: controllers
 		for (i =0; i < node.controllers.length; i++) {
 			var controller = controllers[node.controllers[i].url];
@@ -203,8 +245,13 @@ var DAE = (function() {
 						inst_geom.instance_material = node.controllers[i].instance_material;
 						node.geometries.push(inst_geom);
 						skinned = true;
+						skinController = node.controllers[i];
 					} else if (controllers[controller.skin.source]) {
+						// urgh: controller can be chained
+						// handle the most basic case...
 						var second = controllers[controller.skin.source];
+						morphController = second;
+					//	skinController = node.controllers[i];
 						if (second.morph && geometries[second.morph.source]) {
 							var inst_geom = new InstanceGeometry();
 							inst_geom.url = second.morph.source;
@@ -213,12 +260,13 @@ var DAE = (function() {
 						}
 					}
 					break;
-				case 'morph': // unsupported
+				case 'morph':
 					if (geometries[controller.morph.source]) {
 						var inst_geom = new InstanceGeometry();
 						inst_geom.url = controller.morph.source;
 						inst_geom.instance_material = node.controllers[i].instance_material;
 						node.geometries.push(inst_geom);
+						morphController = node.controllers[i];
 					}
 					console.log("DAE: morph-controller partially supported.")
 				default:
@@ -226,24 +274,13 @@ var DAE = (function() {
 			}
 		}
 		
+		// FIXME: multi-material mesh?
 		// geometries
 		for (i = 0; i < node.geometries.length; i++) {
 			var instance_geometry = node.geometries[i];
 			var instance_materials = instance_geometry.instance_material;
 			var geometry = geometries[instance_geometry.url];
-			var shaders = {};
-			
-			// collect materials for this geometry instance
-			if (instance_materials) {
-				for (j = 0; j < instance_materials.length; j++) {
-					var inst_material = instance_materials[j];
-					var target = inst_material.target;
-					var symbol = inst_material.symbol;
-					var effect_id = materials[target].instance_effect.url;
-					var effect = effects[effect_id];
-					shaders[symbol] = effect;
-				}
-			}
+			var used_effects = {};
 
 			if (geometry) {
 				if (!geometry.mesh || !geometry.mesh.primitives)
@@ -253,64 +290,115 @@ var DAE = (function() {
 					obj.name = geometry.id;
 				}
 				
+				// collect used fx for this geometry-instance
+				if (instance_materials) {
+					for (j = 0; j < instance_materials.length; j++) {
+						var inst_material = instance_materials[j];
+						var effect_id = materials[inst_material.target].instance_effect.url;
+						used_effects[inst_material.symbol] = effects[effect_id];
+					}
+				}
+				
 				var primitives = geometry.mesh.primitives;
+				
 				for (j = 0; j < primitives.length; j++) {
-					var symbol = primitives[j].material;
-					var effect = shaders[symbol];
+					var effect = used_effects[ primitives[j].material ];
 					var shader = effect.shader;
-					var ambient = shader.ambient ? shader.ambient.color : 0x505050;
-					var diffuse = shader.diffuse ? shader.diffuse.color : 0xff0000;
-					var specular = shader.specular ? shader.specular.color : null;
-					var transparency = shader.transparency;
-					var use_transparency = (transparency !== undefined && transparency < 1.0);
-					var opacity = use_transparency ? transparency : 1.0;
-					var texture;
+					var geom = primitives[j].geometry;
+					var material = shader.material;
+					var mesh;
 					
-					if (shader.diffuse && shader.diffuse.isTexture() && effect.sampler && effect.surface) {
-						if (effect.sampler.source == effect.surface.sid) {
-							var image = images[effect.surface.init_from];
-							if (image) {
-								texture = THREE.ImageUtils.loadTexture(baseUrl + image.init_from);
-							}
-						}
-					}
-					var mat = new THREE.MeshLambertMaterial( { 
-						map: texture,
-						color: diffuse.getHex(), 
-						opacity: opacity, 
-						transparent: use_transparency,
-						shading: THREE.SmoothShading } );
-					
-					if (shader.type != 'lambert' && shader.shininess && specular && ambient) {
-						mat = new THREE.MeshPhongMaterial( { 
-							map: texture,
-							ambient: ambient.getHex(), 
-							color: diffuse.getHex(), 
-							specular: specular.getHex(), 
-							shininess: shader.shininess, 
-							shading: THREE.SmoothShading,
-							opacity: opacity,
-							transparent: use_transparency } )
-					}
-					if (Math.abs(primitives[j].geometry.boundingBox.z[0]) < 0.01) {
-						obj.matrix.n34 += Math.random() * 0.001;
-					}
-					if (skinned) {
-						obj.addChild(new THREE.SkinnedMesh( primitives[j].geometry, mat ));
+					if (skinController !== undefined) {
+						//createSkin(geom, skinController);
+						//material.skinning = true;
+						mesh = new THREE.SkinnedMesh( geom, material );
+						mesh.name = 'skin_' + skins.length;
+						skins.push(mesh);
 					} else {
-						obj.addChild(new THREE.Mesh( primitives[j].geometry, mat ));
+						if (morphController !== undefined) {
+							console.log("morphing")
+							createMorph(geom, morphController);
+							material.morphTargets = true;
+							mesh = new THREE.Mesh( geom, material );
+							mesh.name = 'morph_' + morphs.length;
+							morphs.push(mesh);
+						} else {
+							mesh = new THREE.Mesh( geom, material );
+						}
 					}
+					obj.addChild(mesh);
 				}
 			}
 		}
 		
 		for (i = 0; i < node.nodes.length; i++) {
-			obj.addChild(createSceneGraph(node.nodes[i]));
+			obj.addChild(createSceneGraph(node.nodes[i], node));
 		}
 		
 		return obj;
 	}
 	
+	function getJointId(skin, id) {
+		for (var i = 0; i < skin.joints.length; i++) {
+			if (skin.joints[i] == id) {
+				return i;
+			}
+		}
+	}
+	function test(geometry, skin) {
+		var maxId = -1000;
+		var skinIndices = [];
+		var skinWeights = [];
+		for (var i = 0; i < geometry.vertices.length; i++) {
+			var v = geometry.vertices[i];
+			var weights = skin.weights[v.daeId];
+			var vi = new THREE.Vector3();
+			var wi = new THREE.Vector3();
+			for (var j = 0; j < weights.length && j < 2; j++) {
+				var vw = weights[j];
+				var jointIdx = getJointId(skin, vw.joint);
+				if (j == 0) {
+					vi.x = jointIdx;
+					wi.x = vw.weight;
+				} else {
+					vi.y = jointIdx;
+					wi.y = vw.weight;
+				}
+			}
+			skinIndices.push(vi);
+			skinWeights.push(wi);
+		}
+		geometry.skinIndices = skinIndices;
+		geometry.skinWeights = skinWeights;
+		geometry.bones = [];
+		var hierarchy = [];
+		
+		for (var i = 0; i < skin.joints.length; i++) {
+			var bone = skin.joints[i];
+			var idx = i == 0 ? -1 : Math.round(Math.random()*10);
+			var n = daeScene.getChildBySid(bone, true);
+			if (n && n.keys) {
+				hierarchy.push({parent:idx, keys:n.keys});
+			
+			
+			geometry.bones.push({
+				parent: idx,
+				pos: [0, 0, 0],
+				rotq: [0, 0, 0, 1],
+				scl: [1,1,1],
+				rot: [0,0,0]
+			});
+		}
+		}
+		geometry.animation = {
+			name: 'take_001',
+			fps: 30,
+			length: 3.333,
+			JIT: undefined,
+			hierarchy: hierarchy
+		};
+		console.log(hierarchy)
+	}
 	function getLibraryNode(id) {
 		return COLLADA.evaluate(".//dae:library_nodes//dae:node[@id='"+id+"']", 
 			COLLADA, 
@@ -319,6 +407,103 @@ var DAE = (function() {
 			null).iterateNext();
 	}
 	
+	function getChannelsForNode(node) {
+		var channels = [];
+		var startTime = 1000000;
+		var endTime = -1000000;
+		for (var id in animations) {
+			var animation = animations[id];
+			for (var i = 0; i < animation.channel.length; i++) {
+				var channel = animation.channel[i];
+				var sampler = animation.sampler[i];
+				var id = channel.target.split('/')[0];
+				if (id == node.id) {
+					sampler.create();
+					channel.sampler = sampler;
+					startTime = Math.min(startTime, sampler.startTime);
+					endTime = Math.max(endTime, sampler.endTime);
+					channels.push(channel);
+				}
+			}
+		}
+		if (channels.length) {
+			node.startTime = startTime;
+			node.endTime = endTime;	
+		}
+		return channels;
+	}
+	
+	function calcFrameDuration(node) {
+		var minT = 10000000;
+		for (i = 0; i < node.channels.length; i++) {
+			var sampler = node.channels[i].sampler;
+			
+			for (var j = 0; j < sampler.input.length - 1; j++) {
+				var t0 = sampler.input[j];
+				var t1 = sampler.input[j+1];
+				minT = Math.min(minT, t1 - t0);
+			}
+		}
+		return minT;
+	}
+	
+	function calcMatrixAt(node, t) {
+		var animated = {};
+		var i, j;
+		for (i = 0; i < node.channels.length; i++) {
+			var channel = node.channels[i];
+			animated[ channel.sid ] = channel;
+		}
+		var matrix = new THREE.Matrix4();
+		for (i = 0; i < node.transforms.length; i++) {
+			var transform = node.transforms[i];
+			var channel = animated[transform.sid];
+			if (channel !== undefined) {
+				var sampler = channel.sampler;
+				var value;
+				for (var j = 0; j < sampler.input.length - 1; j++) {
+					if (sampler.input[j+1] > t) {
+						value = sampler.output[j];
+						//console.log(value.flatten)
+						break;
+					}
+				}
+				if (value !== undefined) {
+					if (value instanceof THREE.Matrix4) {
+						matrix = matrix.multiply(matrix, value);
+					} else {
+						// FIXME: handle other types
+						matrix = matrix.multiply(matrix, transform.matrix);
+					}
+				} else {
+					matrix = matrix.multiply(matrix, transform.matrix);
+				}
+			} else {
+				matrix = matrix.multiply(matrix, transform.matrix);
+			}
+		}
+		return matrix;
+	}
+	
+	function bakeAnimations(node) {
+		if (node.channels && node.channels.length) {
+			var frameDuration = calcFrameDuration(node);
+			var t, matrix;
+			var keys = [];
+			for (t = node.startTime; t < node.endTime; t += frameDuration) {
+				matrix = calcMatrixAt(node, t);
+				//keys.push({time: t, mat: matrix.flatten()})
+				keys.push({
+					time: t,
+					pos: [matrix.n14, matrix.n24, matrix.n34],
+					rotq: [0, 0, 0, 1],
+					scl: [1,1,1]
+				});
+			}
+			node.keys = keys;
+		}
+	}
+	
 	function _Image() {
 		this.id = "";
 		this.init_from = "";
@@ -441,7 +626,14 @@ var DAE = (function() {
 			if (child.nodeType != 1) continue;
 			switch (child.nodeName) {
 				case 'bind_shape_matrix':
-					this.bindShapeMatrix = new THREE.Matrix4(_floats(child.textContent));
+					var f = _floats(child.textContent);
+					this.bindShapeMatrix = new THREE.Matrix4();
+					this.bindShapeMatrix.set(
+						f[0], f[1], f[2], f[3],
+						f[4], f[5], f[6], f[7],
+						f[8], f[9], f[10], f[11],
+						f[12], f[13], f[14], f[15]
+						);
 					break;
 				case 'source':
 					var src = new Source().parse(child);
@@ -543,6 +735,15 @@ var DAE = (function() {
 		}
 		return null;
 	}
+	VisualScene.prototype.getChildBySid = function(sid, recursive) {
+		for (var i = 0; i < this.nodes.length; i++) {
+			var node = this.nodes[i].getChildBySid(sid, recursive);
+			if (node) {
+				return node;
+			}
+		}
+		return null;
+	}
 	VisualScene.prototype.parse = function(element) {
 		this.id = element.getAttribute('id');
 		this.name = element.getAttribute('name');
@@ -559,7 +760,6 @@ var DAE = (function() {
 					break;
 			}
 		}
-		
 		return this;
 	}
 	
@@ -571,8 +771,38 @@ var DAE = (function() {
 		this.controllers = [];
 		this.transforms = [];
 		this.geometries = [];
+		this.channels = [];
 		this.matrix = new THREE.Matrix4();
 	}
+	Node.prototype.getChannelForTransform = function(transformSid) {
+		for (var i = 0; i < this.channels.length; i++) {
+			var channel = this.channels[i];
+			var parts = channel.target.split('/');
+			var id = parts.shift();
+			var sid = parts.shift();
+			var dotSyntax = (sid.indexOf(".") >= 0);
+			var arrSyntax = (sid.indexOf("(") >= 0);
+			var arrIndices;
+			var member;
+			
+			if (dotSyntax) {
+				parts = sid.split(".");
+				sid = parts.shift();
+				member = parts.shift();
+			} else if (arrSyntax) {
+				arrIndices = sid.split("(");
+				sid = arrIndices.shift();
+				for (var j = 0; j < arrIndices.length; j++) {
+					arrIndices[j] = parseInt(arrIndices[j].replace(/\)/, ''));
+				}
+			}
+			if (sid == transformSid) {
+				channel.info = {sid:sid, dotSyntax:dotSyntax, arrSyntax:arrSyntax, arrIndices:arrIndices};
+				return channel;
+			}
+		}
+		return null;
+	}
 	Node.prototype.getChildById = function(id, recursive) {
 		if (this.id == id) {
 			return this;
@@ -587,6 +817,20 @@ var DAE = (function() {
 		}
 		return null;
 	}
+	Node.prototype.getChildBySid = function(sid, recursive) {
+		if (this.sid == sid) {
+			return this;
+		}
+		if (recursive) {
+			for (var i = 0; i < this.nodes.length; i++) {
+				var n = this.nodes[i].getChildBySid(sid, recursive);
+				if (n) {
+					return n;
+				}
+			}
+		}
+		return null;
+	}
 	Node.prototype.getTransformBySid = function(sid) {
 		for (var i = 0; i < this.transforms.length; i++) {
 			if (this.transforms[i].sid == sid) return this.transforms[i];
@@ -646,7 +890,10 @@ var DAE = (function() {
 					break;
 			}
 		}
+		this.channels = getChannelsForNode(this);
+		bakeAnimations(this);
 		this.updateMatrix();
+		
 		return this;
 	}
 	Node.prototype.updateMatrix = function() {
@@ -874,7 +1121,7 @@ var DAE = (function() {
 							break;
 						case 'TEXCOORD':
 							if (ts[input.set] == undefined) ts[input.set] = [];
-							t = new THREE.UV(source.data[idx32+0], source.data[idx32+1]);
+							t = new THREE.UV(source.data[idx32+0], (flip_uv ? 1-source.data[idx32+1] : source.data[idx32+1]));
 							t.daeId = ts[input.set].length;
 							ts[input.set].push(t);
 							break;
@@ -892,13 +1139,17 @@ var DAE = (function() {
 	}
 	Polylist.prototype.triangulate = function(polygons, texture_sets) {
 		var i, j, k;
+		var vertex_store = {};
+		var last_index = 0;
 		
-		function clone(v) {
-			var x = v.position.x;
-			var y = v.position.y;
-			var z = v.position.z;
-			return new THREE.Vertex(new THREE.Vector3(x, y, z));
+		function get_vertex(v)  {
+			var hash = _hash_vector3(v.position);
+			if (vertex_store[hash] === undefined) {
+				vertex_store[hash] = {v:v, index:last_index++};
+			}
+			return vertex_store[hash];
 		}
+		
 		for (i = 0; i < polygons.length; i++) {
 			var polygon = polygons[i];
 			var v = polygon[0];
@@ -910,17 +1161,17 @@ var DAE = (function() {
 			}
 			var has_uv = (uvs.length > 0 && uvs[0].length > 0);
 			if (v.length < 3) continue;
-			var va = v[0];
+			var va = get_vertex(v[0]);
 			var na = n[0];
 			for (j = 1; j < v.length - 1; j++) {
-				var vb = v[j];
-				var vc = v[j+1];
+				var vb = get_vertex(v[j]);
+				var vc = get_vertex(v[j+1]);
+				var a = va.index;
+				var b = vb.index;
+				var c = vc.index;
 				var nb = n[j];
 				var nc = n[j+1];
-
-				var c = this.geometry.vertices.length;
-				this.geometry.vertices.push(va, vb, vc);
-				this.geometry.faces.push( new THREE.Face3(c+0, c+1, c+2, [na, nb, nc] ) );
+				this.geometry.faces.push( new THREE.Face3(a, b, c, [na, nb, nc] ) );
 				if (has_uv) {
 					for (k = 0; k < uvs.length; k++) {
 						this.geometry.faceVertexUvs[ k ].push( [uvs[k][0], uvs[k][j], uvs[k][j+1]] );
@@ -928,6 +1179,9 @@ var DAE = (function() {
 				}
 			}
 		}
+		for (var hash in vertex_store) {
+			this.geometry.vertices.push(vertex_store[hash].v);
+		}
 		this.geometry.material = this.material;
 		this.geometry.computeCentroids();
 		this.geometry.computeFaceNormals();
@@ -935,7 +1189,7 @@ var DAE = (function() {
 		this.geometry.computeBoundingBox();
 	}
 	
-	function Triangles() {
+	function Triangles(flip_uv) {
 		this.material = "";
 		this.count = 0;
 		this.inputs = [];
@@ -948,6 +1202,16 @@ var DAE = (function() {
 		var i = 0, j, k, p = this.p, inputs = this.inputs, input, index;
 		var v, n, t;
 		var texture_sets = [];
+		var vertex_store = {};
+		var last_index = 0;
+		
+		function get_vertex(v)  {
+			var hash = _hash_vector3(v.position);
+			if (vertex_store[hash] === undefined) {
+				vertex_store[hash] = {v:v, index:last_index++};
+			}
+			return vertex_store[hash];
+		}
 		
 		for (j = 0; j < inputs.length; j++) {
 			input = inputs[j];
@@ -957,7 +1221,8 @@ var DAE = (function() {
 		}
 		
 		this.geometry = new THREE.Geometry();
-
+		var daeIdx = 0;
+		
 		while (i < p.length) {
 			vs = [];
 			ns = [];
@@ -972,33 +1237,34 @@ var DAE = (function() {
 					switch (input.semantic) {
 						case 'VERTEX':
 							v = new THREE.Vertex(new THREE.Vector3(source.data[idx32+0], source.data[idx32+1], source.data[idx32+2]));
-							v.daeId = vs.length;
+							v.daeId = index;
 							vs.push(v);
-							
 							break;
 						case 'NORMAL':
 							n = new THREE.Vector3(source.data[idx32+0], source.data[idx32+1], source.data[idx32+2]);
-							n.daeId = ns.length;
+							n.daeId = daeIdx;
 							ns.push(n);
 							break;
 						case 'TEXCOORD':
 							if (ts[input.set] == undefined) ts[input.set] = [];
 							t = new THREE.UV(source.data[idx32+0], source.data[idx32+1]);
-							t.daeId = ts[input.set].length;
+							t.daeId = daeIdx;
 							ts[input.set].push(t);
 							break;
 						default:
 							break;
 					}
 				}
+				
 			}
+
 			var has_v = (vs.length == 3);
 			var has_t = (texture_sets.length > 0 && ts[texture_sets[0]].length == 3);
 			if (has_v) {
-				var c = this.geometry.vertices.length;
-				this.geometry.vertices.push(vs[0], vs[1], vs[2]);
-				
-				this.geometry.faces.push( new THREE.Face3(c+0, c+1, c+2, ns ) );
+				var a = get_vertex(vs[0]);
+				var b = get_vertex(vs[1]);
+				var c = get_vertex(vs[2]);
+				this.geometry.faces.push( new THREE.Face3(a.index, b.index, c.index, ns ) );
 				if (has_t) {
 					for (k = 0; k < texture_sets.length; k++) {
 						this.geometry.faceVertexUvs[ k ].push( ts[texture_sets[k]] );
@@ -1007,6 +1273,9 @@ var DAE = (function() {
 			}
 			i += 3 * inputs.length;
 		}
+		for (var hash in vertex_store) {
+			this.geometry.vertices.push(vertex_store[hash].v);
+		}
 		this.geometry.material = this.material;
 		this.geometry.computeCentroids();
 		this.geometry.computeFaceNormals();
@@ -1207,7 +1476,15 @@ var DAE = (function() {
 					return this.data;
 				case 'float4x4':
 					for (var j = 0; j < this.data.length; j += 16) {
-						result.push(new THREE.Matrix4(this.data.slice(j, j+16)));
+						var s = this.data.slice(j, j+16);
+						var m = new THREE.Matrix4();
+						m.set(
+							s[0], s[1], s[2], s[3],
+							s[4], s[5], s[6], s[7],
+							s[8], s[9], s[10], s[11],
+							s[12], s[13], s[14], s[15]
+							);
+						result.push(m);
 					}
 					break;
 				default:
@@ -1269,8 +1546,10 @@ var DAE = (function() {
 		return this;
 	}
 	
-	function Shader(type) {
+	function Shader(type, effect) {
 		this.type = type;
+		this.effect = effect;
+		this.material;
 	}
 	Shader.prototype.parse = function(element) {
 		for (var i = 0; i < element.childNodes.length; i++) {
@@ -1295,8 +1574,75 @@ var DAE = (function() {
 					break;
 			}
 		}
+		this.create();
 		return this;
 	}
+	Shader.prototype.create = function() {
+		var props = {};
+		var transparent = (this['transparency'] !== undefined && this['transparency'] < 1.0);
+		for (var prop in this) {
+			switch (prop) {
+				case 'ambient':
+				case 'emission':
+				case 'diffuse':
+				case 'specular':
+					var cot = this[prop];
+					if (cot instanceof ColorOrTexture) {
+						if (cot.isTexture()) {
+							if (this.effect.sampler && this.effect.surface) {
+								if (this.effect.sampler.source == this.effect.surface.sid) {
+									var image = images[this.effect.surface.init_from];
+									if (image) {
+										props['map'] = THREE.ImageUtils.loadTexture(baseUrl + image.init_from);
+										props['map'].wrapS = THREE.RepeatWrapping;
+										props['map'].wrapT = THREE.RepeatWrapping;
+									//	props['map'].repeat.x = 1;
+									//	props['map'].repeat.y = 1;
+									}
+								}
+							}
+						} else {
+							if (prop == 'diffuse') {
+								props['color'] = cot.color.getHex();
+							} else if (!transparent){
+								props[prop] = cot.color.getHex();
+							}
+						}
+					}
+					break;
+				case 'shininess':
+				case 'reflectivity':
+					props[prop] = this[prop];
+					break;
+				case 'transparency':
+					if (transparent) {
+						props['transparent'] = true;
+						props['opacity'] = this[prop];
+						transparent = true;
+					}
+					break;
+				default:
+					break;
+			}
+		}
+
+		props['shading'] = THREE.SmoothShading;
+		this.material = new THREE.MeshLambertMaterial(props);
+		
+		switch (this.type) {
+			case 'constant':
+			case 'lambert':
+				break;
+			case 'phong':
+			case 'blinn':
+			default:
+				if (!transparent) {
+					this.material = new THREE.MeshPhongMaterial(props);
+				}
+				break;
+		}
+		return this.material;
+	}
 	
 	function Surface(effect) {
 		this.effect = effect;
@@ -1368,16 +1714,23 @@ var DAE = (function() {
 		this.surface;
 		this.sampler;
 	}
+	Effect.prototype.create = function() {
+		if (this.shader == null) {
+			return null;
+		}
+		
+	}
 	Effect.prototype.parse = function(element) {
 		this.id = element.getAttribute('id');
 		this.name = element.getAttribute('name');
+		this.shader = null;
 		
 		for (var i = 0; i < element.childNodes.length; i++) {
 			var child = element.childNodes[i];
 			if (child.nodeType != 1) continue;
 			switch (child.nodeName) {
 				case 'profile_COMMON':
-					this.parseProfileCOMMON(child);
+					this.parseTechnique(this.parseProfileCOMMON(child));
 					break;
 				default:
 					break;
@@ -1399,6 +1752,8 @@ var DAE = (function() {
 					this.sampler = (new Sampler2D(this)).parse(child);
 					this.sampler.sid = sid;
 					break;
+				case 'extra':
+					break;
 				default:
 					console.log(child.nodeName);
 					break;
@@ -1406,6 +1761,7 @@ var DAE = (function() {
 		}
 	}
 	Effect.prototype.parseProfileCOMMON = function(element) {
+		var technique;
 		for (var i = 0; i < element.childNodes.length; i++) {
 			var child = element.childNodes[i];
 			if (child.nodeType != 1) continue;
@@ -1414,16 +1770,19 @@ var DAE = (function() {
 					this.parseProfileCOMMON(child);
 					break;
 				case 'technique':
-					this.parseTechnique(child);
+					technique = child;
 					break;
 				case 'newparam':
 					this.parseNewparam(child);
 					break;
+				case 'extra':
+					break;
 				default:
 					console.log(child.nodeName);
 					break;
 			}
 		}
+		return technique;
 	}
 	Effect.prototype.parseTechnique= function(element) {
 		for (var i = 0; i < element.childNodes.length; i++) {
@@ -1433,7 +1792,7 @@ var DAE = (function() {
 				case 'lambert':
 				case 'blinn':
 				case 'phong':
-					this.shader = (new Shader(child.nodeName)).parse(child);
+					this.shader = (new Shader(child.nodeName, this)).parse(child);
 					break;
 				default:
 					break;
@@ -1480,14 +1839,45 @@ var DAE = (function() {
 		}
 		return this;
 	}
+
 	function Channel(animation) {
 		this.animation = animation;
 		this.source = "";
 		this.target = "";
+		this.sid;
+		this.dotSyntax;
+		this.arrSyntax;
+		this.arrIndices;
+		this.member;
 	}
 	Channel.prototype.parse = function(element) {
 		this.source = element.getAttribute('source').replace(/^#/, '');
 		this.target = element.getAttribute('target');
+		
+		var parts = this.target.split('/');
+		var id = parts.shift();
+		var sid = parts.shift();
+		var dotSyntax = (sid.indexOf(".") >= 0);
+		var arrSyntax = (sid.indexOf("(") >= 0);
+		var arrIndices;
+		var member;
+		
+		if (dotSyntax) {
+			parts = sid.split(".");
+			sid = parts.shift();
+			member = parts.shift();
+		} else if (arrSyntax) {
+			arrIndices = sid.split("(");
+			sid = arrIndices.shift();
+			for (var j = 0; j < arrIndices.length; j++) {
+				arrIndices[j] = parseInt(arrIndices[j].replace(/\)/, ''));
+			}
+		}
+		this.sid = sid;
+		this.dotSyntax = dotSyntax;
+		this.arrSyntax = arrSyntax;
+		this.arrIndices = arrIndices;
+		this.member = member;
 		return this;
 	}	
 	function Sampler(animation) {
@@ -1497,6 +1887,9 @@ var DAE = (function() {
 		this.input;
 		this.output;
 		this.interpolation;
+		this.startTime;
+		this.endTime;
+		this.duration = 0;
 	}
 	Sampler.prototype.parse = function(element) {
 		this.id = element.getAttribute('id');
@@ -1528,11 +1921,28 @@ var DAE = (function() {
 				case 'INTERPOLATION':
 					this.interpolation = source.read();
 					break;
+				case 'IN_TANGENT':
+					break;
+				case 'OUT_TANGENT':
+					break;
 				default:
 					console.log(input.semantic);
 					break;
 			}
 		}
+		
+		this.startTime = 0;
+		this.endTime = 0;
+		this.duration = 0;
+		if (this.input.length) {
+			this.startTime = 100000000;
+			this.endTime = -100000000;
+			for (var i = 0; i < this.input.length; i++) {
+				this.startTime = Math.min(this.startTime, this.input[i]);
+				this.endTime = Math.max(this.endTime, this.input[i]);
+			}
+			this.duration = this.endTime - this.startTime;
+		}
 	}
 	
 	function _source(element) {