提交 b8c2d8aa 编写于 作者: L Lucas Doyle

ColladaLoader: kinematics support for collada loader

上级 d505e4d1
......@@ -7,7 +7,8 @@ THREE.ColladaLoader = function () {
var COLLADA = null;
var scene = null;
var daeScene;
var visualScene;
var kinematicsModel;
var readyCallbackFunc = null;
......@@ -22,7 +23,9 @@ THREE.ColladaLoader = function () {
var lights = {};
var animData;
var kinematics;
var visualScenes;
var kinematicsModel;
var baseUrl;
var morphs;
var skins;
......@@ -141,16 +144,17 @@ THREE.ColladaLoader = function () {
controllers = parseLib( "library_controllers controller", Controller, "controller" );
animations = parseLib( "library_animations animation", Animation, "animation" );
visualScenes = parseLib( "library_visual_scenes visual_scene", VisualScene, "visual_scene" );
kinematicsModels = parseLib( "library_kinematics_models kinematics_model", KinematicsModel, "kinematics_model" );
morphs = [];
skins = [];
daeScene = parseScene();
visualScene = parseScene();
scene = new THREE.Scene();
for ( var i = 0; i < daeScene.nodes.length; i ++ ) {
for ( var i = 0; i < visualScene.nodes.length; i ++ ) {
scene.add( createSceneGraph( daeScene.nodes[ i ] ) );
scene.add( createSceneGraph( visualScene.nodes[ i ] ) );
}
......@@ -159,12 +163,16 @@ THREE.ColladaLoader = function () {
createAnimations();
kinematicsModel = parseKinematicsModel();
createKinematics();
var result = {
scene: scene,
morphs: morphs,
skins: skins,
animations: animData,
kinematics: kinematics,
dae: {
images: images,
materials: materials,
......@@ -175,7 +183,10 @@ THREE.ColladaLoader = function () {
controllers: controllers,
animations: animations,
visualScenes: visualScenes,
scene: daeScene
visualScene: visualScene,
scene: visualScene,
kinematicsModels: kinematicsModels,
kinematicsModel: kinematicsModel
}
};
......@@ -276,6 +287,23 @@ THREE.ColladaLoader = function () {
}
function parseKinematicsModel() {
var kinematicsModelElement = COLLADA.querySelectorAll('instance_kinematics_model')[0];
if ( kinematicsModelElement ) {
var url = kinematicsModelElement.getAttribute( 'url' ).replace(/^#/, '');
return kinematicsModels[ url.length > 0 ? url : 'kinematics_model0' ];
} else {
return null;
}
}
function createAnimations() {
animData = [];
......@@ -287,7 +315,7 @@ THREE.ColladaLoader = function () {
function recurseHierarchy( node ) {
var n = daeScene.getChildById( node.id, true ),
var n = visualScene.getChildById( node.id, true ),
newData = null;
if ( n && n.keys ) {
......@@ -427,7 +455,7 @@ THREE.ColladaLoader = function () {
}
var skin = skinCtrl.skin;
var skeleton = daeScene.getChildById( ctrl.skeleton[ 0 ] );
var skeleton = visualScene.getChildById( ctrl.skeleton[ 0 ] );
var hierarchy = [];
applyBindShape = applyBindShape !== undefined ? applyBindShape : true;
......@@ -663,8 +691,8 @@ THREE.ColladaLoader = function () {
}
var animationBounds = calcAnimationBounds();
var skeleton = daeScene.getChildById( instanceCtrl.skeleton[0], true ) ||
daeScene.getChildBySid( instanceCtrl.skeleton[0], true );
var skeleton = visualScene.getChildById( instanceCtrl.skeleton[0], true ) ||
visualScene.getChildBySid( instanceCtrl.skeleton[0], true );
//flatten the skeleton into a list of bones
var bonelist = flattenSkeleton(skeleton);
......@@ -793,6 +821,210 @@ THREE.ColladaLoader = function () {
};
function createKinematics() {
if ( kinematicsModel && kinematicsModel.joints.length === 0 ) {
kinematics = undefined;
return;
}
var jointMap = {};
var _addToMap = function( jointIndex, parentVisualElement ) {
var parentVisualElementId = parentVisualElement.getAttribute( 'id' );
var colladaNode = visualScene.getChildById( parentVisualElementId, true );
var joint = kinematicsModel.joints[ jointIndex ];
scene.traverse(function( node ) {
if ( node.id == parentVisualElementId ) {
jointMap[ jointIndex ] = {
node: node,
transforms: colladaNode.transforms,
joint: joint,
position: joint.zeroPosition
};
}
});
};
kinematics = {
joints: kinematicsModel && kinematicsModel.joints,
getJointValue: function( jointIndex ) {
var jointData = jointMap[ jointIndex ];
if ( jointData ) {
return jointData.position;
} else {
console.log( 'getJointValue: joint ' + jointIndex + ' doesn\'t exist' );
}
},
setJointValue: function( jointIndex, value ) {
var jointData = jointMap[ jointIndex ];
if ( jointData ) {
var joint = jointData.joint;
if ( value > joint.limits.max || value < joint.limits.min ) {
console.log( 'setJointValue: joint ' + jointIndex + ' value ' + value + ' outside of limits (min: ' + joint.limits.min + ', max: ' + joint.limits.max + ')' );
} else if ( joint.static ) {
console.log( 'setJointValue: joint ' + jointIndex + ' is static' );
} else {
var threejsNode = jointData.node;
var axis = joint.axis;
var transforms = jointData.transforms;
var matrix = new THREE.Matrix4();
for (i = 0; i < transforms.length; i++ ) {
var transform = transforms[ i ];
// kinda ghetto joint detection
if ( transform.sid && transform.sid.indexOf( 'joint' + jointIndex ) !== -1 ) {
// apply actual joint value here
switch ( joint.type ) {
case 'revolute':
matrix.multiply( m1.makeRotationAxis( axis, THREE.Math.degToRad(value) ) );
break;
case 'prismatic':
matrix.multiply( m1.makeTranslation(axis.x * value, axis.y * value, axis.z * value ) );
break;
default:
console.warn( 'setJointValue: unknown joint type: ' + joint.type );
break;
}
} else {
var m1 = new THREE.Matrix4();
switch ( transform.type ) {
case 'matrix':
matrix.multiply( transform.obj );
break;
case 'translate':
matrix.multiply( m1.makeTranslation( transform.obj.x, transform.obj.y, transform.obj.z ) );
break;
case 'rotate':
matrix.multiply( m1.makeRotationAxis( transform.obj, transform.angle ) );
break;
}
}
}
// apply the matrix to the threejs node
var elementsFloat32Arr = matrix.elements;
var elements = Array.prototype.slice.call( elementsFloat32Arr );
var elementsRowMajor = [
elements[ 0 ],
elements[ 4 ],
elements[ 8 ],
elements[ 12 ],
elements[ 1 ],
elements[ 5 ],
elements[ 9 ],
elements[ 13 ],
elements[ 2 ],
elements[ 6 ],
elements[ 10 ],
elements[ 14 ],
elements[ 3 ],
elements[ 7 ],
elements[ 11 ],
elements[ 15 ]
];
threejsNode.matrix.set.apply( threejsNode.matrix, elementsRowMajor );
threejsNode.matrix.decompose( threejsNode.position, threejsNode.quaternion, threejsNode.scale );
}
}
else {
console.log( 'setJointValue: joint ' + jointIndex + ' doesn\'t exist' );
}
}
};
var element = COLLADA.querySelector('scene instance_kinematics_scene');
if ( element ) {
for (var i = 0; i < element.childNodes.length; i++ ) {
var child = element.childNodes[ i ];
if ( child.nodeType != 1 ) continue;
switch ( child.nodeName ) {
case 'bind_joint_axis':
var visualTarget = child.getAttribute( 'target' ).split( '/' ).pop();
var axis = child.querySelector('axis param').textContent;
var jointIndex = parseInt( axis.split( 'joint' ).pop().split( '.' )[0] );
var visualTargetElement = COLLADA.querySelector( '[sid="' + visualTarget + '"]' );
if ( visualTargetElement ) {
var parentVisualElement = visualTargetElement.parentElement;
_addToMap(jointIndex, parentVisualElement);
}
break;
default:
break;
}
}
}
};
function createSceneGraph ( node, parent ) {
var obj = new THREE.Object3D();
......@@ -4539,6 +4771,231 @@ THREE.ColladaLoader = function () {
};
function KinematicsModel( ) {
this.id = '';
this.name = '';
this.joints = [];
this.links = [];
}
KinematicsModel.prototype.parse = function( element ) {
this.id = element.getAttribute('id');
this.name = element.getAttribute('name');
this.joints = [];
this.links = [];
for (var i = 0; i < element.childNodes.length; i++ ) {
var child = element.childNodes[ i ];
if ( child.nodeType != 1 ) continue;
switch ( child.nodeName ) {
case 'technique_common':
this.parseCommon(child);
break;
default:
break;
}
}
return this;
};
KinematicsModel.prototype.parseCommon = function( element ) {
for (var i = 0; i < element.childNodes.length; i++ ) {
var child = element.childNodes[ i ];
if ( child.nodeType != 1 ) continue;
switch ( element.childNodes[ i ].nodeName ) {
case 'joint':
this.joints.push( (new Joint()).parse(child) );
break;
case 'link':
this.links.push( (new Link()).parse(child) );
break;
default:
break;
}
}
return this;
};
function Joint( ) {
this.sid = '';
this.name = '';
this.axis = new THREE.Vector3();
this.limits = {
min: 0,
max: 0
};
this.type = '';
this.static = false;
this.zeroPosition = 0.0;
this.middlePosition = 0.0;
}
Joint.prototype.parse = function( element ) {
this.sid = element.getAttribute('sid');
this.name = element.getAttribute('name');
this.axis = new THREE.Vector3();
this.limits = {
min: 0,
max: 0
};
this.type = '';
this.static = false;
this.zeroPosition = 0.0;
this.middlePosition = 0.0;
var axisElement = element.querySelector('axis');
var _axis = _floats(axisElement.textContent);
this.axis = getConvertedVec3(_axis, 0);
var min = element.querySelector('limits min') ? parseFloat(element.querySelector('limits min').textContent) : -360;
var max = element.querySelector('limits max') ? parseFloat(element.querySelector('limits max').textContent) : 360;
this.limits = {
min: min,
max: max
};
var jointTypes = ['prismatic', 'revolute'];
for (var i = 0; i < jointTypes.length; i++ ) {
var type = jointTypes[ i ];
var jointElement = element.querySelector(type);
if ( jointElement ) {
this.type = type;
}
}
// if the min is equal to or somehow greater than the max, consider the joint static
if ( this.limits.min >= this.limits.max ) {
this.static = true;
}
this.middlePosition = (this.limits.min + this.limits.max) / 2.0;
return this;
};
function Link( ) {
this.sid = '';
this.name = '';
this.transforms = [];
this.attachments = [];
}
Link.prototype.parse = function( element ) {
this.sid = element.getAttribute('sid');
this.name = element.getAttribute('name');
this.transforms = [];
this.attachments = [];
for (var i = 0; i < element.childNodes.length; i++ ) {
var child = element.childNodes[ i ];
if ( child.nodeType != 1 ) continue;
switch ( child.nodeName ) {
case 'attachment_full':
this.attachments.push( (new Attachment()).parse(child) );
break;
case 'rotate':
case 'translate':
case 'matrix':
this.transforms.push( (new Transform()).parse(child) );
break;
default:
break;
}
}
return this;
};
function Attachment( ) {
this.joint = '';
this.transforms = [];
this.links = [];
}
Attachment.prototype.parse = function( element ) {
this.joint = element.getAttribute('joint').split('/').pop();
this.links = [];
for (var i = 0; i < element.childNodes.length; i++ ) {
var child = element.childNodes[ i ];
if ( child.nodeType != 1 ) continue;
switch ( child.nodeName ) {
case 'link':
this.links.push( (new Link()).parse(child) );
break;
case 'rotate':
case 'translate':
case 'matrix':
this.transforms.push( (new Transform()).parse(child) );
break;
default:
break;
}
}
return this;
};
function _source( element ) {
var id = element.getAttribute( 'id' );
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册