|
@@ -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) {
|