From 5bf0f106a46e589bbea6efd8943da20ffd2eed03 Mon Sep 17 00:00:00 2001 From: Mugen87 Date: Sat, 17 Jun 2017 17:02:46 +0200 Subject: [PATCH 1/9] SceneUtils: Added up axis conversion support --- examples/js/loaders/ColladaLoader2.js | 21 +-- src/extras/SceneUtils.js | 235 ++++++++++++++++++++++++++ 2 files changed, 244 insertions(+), 12 deletions(-) diff --git a/examples/js/loaders/ColladaLoader2.js b/examples/js/loaders/ColladaLoader2.js index 67124594bc1d2a..4f3d78d5a8877d 100644 --- a/examples/js/loaders/ColladaLoader2.js +++ b/examples/js/loaders/ColladaLoader2.js @@ -6,6 +6,9 @@ THREE.ColladaLoader = function ( manager ) { this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; + this.options = { + convertUpAxis: false + }; }; @@ -30,16 +33,6 @@ THREE.ColladaLoader.prototype = { }, - options: { - - set convertUpAxis( value ) { - - console.log( 'THREE.ColladaLoader.options.convertUpAxis: TODO' ); - - } - - }, - setCrossOrigin: function ( value ) { this.crossOrigin = value; @@ -2660,9 +2653,13 @@ THREE.ColladaLoader.prototype = { var scene = parseScene( getElementsByTagName( collada, 'scene' )[ 0 ] ); - if ( asset.upAxis === 'Z_UP' ) { + if ( this.options.convertUpAxis === true ) { + + if ( asset.upAxis === 'Z_UP' ) { - scene.rotation.x = - Math.PI / 2; + THREE.SceneUtils.convertFromZUp( scene, animations ); + + } } diff --git a/src/extras/SceneUtils.js b/src/extras/SceneUtils.js index bf8242dfdb7036..14b5a612286a2e 100644 --- a/src/extras/SceneUtils.js +++ b/src/extras/SceneUtils.js @@ -1,9 +1,13 @@ +import { Vector3 } from '../math/Vector3'; +import { Quaternion } from '../math/Quaternion'; import { Matrix4 } from '../math/Matrix4'; import { Mesh } from '../objects/Mesh'; import { Group } from '../objects/Group'; +import { PropertyBinding } from '../animation/PropertyBinding'; /** * @author alteredq / http://alteredqualia.com/ + * @author Mugen87 / https://github.com/Mugen87 */ var SceneUtils = { @@ -37,9 +41,240 @@ var SceneUtils = { scene.remove( child ); parent.add( child ); + }, + + convertFromZUp: function ( root, animations ) { + + // see https://gamedev.stackexchange.com/a/7932 + + var conversionMatrix = new Matrix4().set( + 1, 0, 0, 0, + 0, 0, 1, 0, + 0, - 1, 0, 0, + 0, 0, 0, 1 + ); + + var converter = new UpAxisConverter( conversionMatrix ); + converter.convert( root, animations ); + } }; +// up axis converter + +function UpAxisConverter( conversionMatrix ) { + + this.conversionMatrix = conversionMatrix; + +} + +Object.assign( UpAxisConverter.prototype, { + + convert: function ( root, animations ) { + + var scope = this; + + root.traverse( function( object ) { + + // position, quaternion, scale + + scope.convertMatrix4( object.matrix ); + object.matrix.decompose( object.position, object.quaternion, object.scale ); + + // geometry + + var geometry = object.geometry; + + if ( geometry !== undefined && geometry.isBufferGeometry === true ) { + + var position = geometry.attributes.position; + var normal = geometry.attributes.normal; + + if ( position !== null ) scope.conversionMatrix.applyToBufferAttribute( position ); + if ( normal !== null ) scope.conversionMatrix.applyToBufferAttribute( normal ); + + } + + // skinned mesh + + if ( object.isSkinnedMesh ) { + + scope.convertMatrix4( object.bindMatrix ); + scope.convertMatrix4( object.bindMatrixInverse ); + + var boneInverses = object.skeleton.boneInverses; + + for ( var i = 0, il = boneInverses.length; i < il; i ++ ) { + + scope.convertMatrix4( boneInverses[ i ] ); + + } + + // bones are already converted within the scene hierarchy + + } + + } ); + + // animations + + if ( animations !== undefined ) { + + for ( var i = 0, il = animations.length; i < il; i ++ ) { + + var clip = animations[ i ]; + var tracks = clip.tracks; + + for ( var j = 0, jl = tracks.length; j < jl; j ++ ) { + + this.convertKeyframeTrack( tracks[ j ] ); + + } + + } + + } + + }, + + convertMatrix4: function() { + + var xAxis = new Vector3(); + var yAxis = new Vector3(); + var zAxis = new Vector3(); + var translation = new Vector3(); + + return function convertMatrix4( matrix ) { + + // columns first + + xAxis.setFromMatrixColumn( matrix, 0 ); + yAxis.setFromMatrixColumn( matrix, 1 ); + zAxis.setFromMatrixColumn( matrix, 2 ); + translation.setFromMatrixColumn( matrix, 3 ); + + xAxis.applyMatrix4( this.conversionMatrix ); + yAxis.applyMatrix4( this.conversionMatrix ); + zAxis.applyMatrix4( this.conversionMatrix ); + + matrix.set( + xAxis.x, yAxis.x, zAxis.x, 0, + xAxis.y, yAxis.y, zAxis.y, 0, + xAxis.z, yAxis.z, zAxis.z, 0, + 0, 0, 0, 1 + ); + + // then rows + + matrix.transpose(); + + xAxis.setFromMatrixColumn( matrix, 0 ); + yAxis.setFromMatrixColumn( matrix, 1 ); + zAxis.setFromMatrixColumn( matrix, 2 ); + + xAxis.applyMatrix4( this.conversionMatrix ); + yAxis.applyMatrix4( this.conversionMatrix ); + zAxis.applyMatrix4( this.conversionMatrix ); + + matrix.set( + xAxis.x, yAxis.x, zAxis.x, 0, + xAxis.y, yAxis.y, zAxis.y, 0, + xAxis.z, yAxis.z, zAxis.z, 0, + 0, 0, 0, 1 + ); + + matrix.transpose(); + + // translation at the end + + translation.applyMatrix4( this.conversionMatrix ); + + matrix.elements[ 12 ] = translation.x; + matrix.elements[ 13 ] = translation.y; + matrix.elements[ 14 ] = translation.z; + + return matrix; + + }; + + } (), + + convertKeyframeTrack: function() { + + var vector = new Vector3(); + var quaternion = new Quaternion(); + var rotationMatrix = new Matrix4(); + + return function convertKeyframeTrack( track ) { + + var result = PropertyBinding.parseTrackName( track.name ); + var propertyName = result.propertyName; + + var values = track.values; + var stride = track.values.length / track.times.length; + + var i, il, j, jl; + + switch ( propertyName ) { + + case 'position': + + for ( i = 0, il = values.length; i < il; i += stride ) { + + vector.fromArray( values, i ).applyMatrix4( this.conversionMatrix ); + + for ( j = 0, jl = stride; j < jl; j ++ ) { + + values[ i + j ] = vector.getComponent( j ); + + } + + } + + break; + + case 'scale': + + for ( i = 0, il = values.length; i < il; i += stride ) { + + vector.fromArray( values, i ).applyMatrix4( this.conversionMatrix ); + + for ( j = 0, jl = stride; j < jl; j ++ ) { + + values[ i + j ] = Math.abs( vector.getComponent( j ) ); + + } + + } + + break; + + case 'quaternion': + + for ( i = 0, il = values.length; i < il; i += stride ) { + + quaternion.fromArray( values, i ); + rotationMatrix.makeRotationFromQuaternion( quaternion ); + this.convertMatrix4( rotationMatrix ); + quaternion.setFromRotationMatrix( rotationMatrix ); + + values[ i + 0 ] = quaternion.x; + values[ i + 1 ] = quaternion.y; + values[ i + 2 ] = quaternion.z; + values[ i + 3 ] = quaternion.w; + + } + + break; + + } + + }; + + } (), + +} ); + export { SceneUtils }; From eeecb918b95de6efe9df9cc3772f01f269fdb801 Mon Sep 17 00:00:00 2001 From: Mugen87 Date: Sat, 17 Jun 2017 17:05:32 +0200 Subject: [PATCH 2/9] SceneUtils: Format --- src/extras/SceneUtils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/extras/SceneUtils.js b/src/extras/SceneUtils.js index 14b5a612286a2e..bbf01f50d745eb 100644 --- a/src/extras/SceneUtils.js +++ b/src/extras/SceneUtils.js @@ -268,9 +268,9 @@ Object.assign( UpAxisConverter.prototype, { break; - } + } - }; + }; } (), From 37cdfcc45909e811ec4f5199c56bc98b6030cae8 Mon Sep 17 00:00:00 2001 From: Mugen87 Date: Sat, 17 Jun 2017 22:55:26 +0200 Subject: [PATCH 3/9] SceneUtils: Clean up --- src/extras/SceneUtils.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/extras/SceneUtils.js b/src/extras/SceneUtils.js index bbf01f50d745eb..981f6f9649257a 100644 --- a/src/extras/SceneUtils.js +++ b/src/extras/SceneUtils.js @@ -212,7 +212,8 @@ Object.assign( UpAxisConverter.prototype, { var propertyName = result.propertyName; var values = track.values; - var stride = track.values.length / track.times.length; + var times = track.times; + var stride = values.length / times.length; var i, il, j, jl; From 3b6bf16f95bec74a68b8149c1cb6009edca4d218 Mon Sep 17 00:00:00 2001 From: Mugen87 Date: Sun, 18 Jun 2017 14:26:45 +0200 Subject: [PATCH 4/9] SceneUtils: Use normal matrix for normal attribute conversion --- src/extras/SceneUtils.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/extras/SceneUtils.js b/src/extras/SceneUtils.js index 981f6f9649257a..9130a9d6055faf 100644 --- a/src/extras/SceneUtils.js +++ b/src/extras/SceneUtils.js @@ -1,6 +1,7 @@ import { Vector3 } from '../math/Vector3'; import { Quaternion } from '../math/Quaternion'; import { Matrix4 } from '../math/Matrix4'; +import { Matrix3 } from '../math/Matrix3'; import { Mesh } from '../objects/Mesh'; import { Group } from '../objects/Group'; import { PropertyBinding } from '../animation/PropertyBinding'; @@ -91,8 +92,20 @@ Object.assign( UpAxisConverter.prototype, { var position = geometry.attributes.position; var normal = geometry.attributes.normal; - if ( position !== null ) scope.conversionMatrix.applyToBufferAttribute( position ); - if ( normal !== null ) scope.conversionMatrix.applyToBufferAttribute( normal ); + var conversionMatrix = scope.conversionMatrix; + + if ( position !== null ) { + + conversionMatrix.applyToBufferAttribute( position ); + + } + + if ( normal !== null ) { + + var normalMatrix = new Matrix3().setFromMatrix4( conversionMatrix ); + normalMatrix.applyToBufferAttribute( normal ); + + } } From ce10579e37afb7c0980e7136758e0f00a07e7613 Mon Sep 17 00:00:00 2001 From: Mugen87 Date: Sun, 18 Jun 2017 19:41:30 +0200 Subject: [PATCH 5/9] SceneUtils: Clean up --- src/extras/SceneUtils.js | 61 ++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 37 deletions(-) diff --git a/src/extras/SceneUtils.js b/src/extras/SceneUtils.js index 9130a9d6055faf..61fd472332d90b 100644 --- a/src/extras/SceneUtils.js +++ b/src/extras/SceneUtils.js @@ -48,29 +48,30 @@ var SceneUtils = { // see https://gamedev.stackexchange.com/a/7932 - var conversionMatrix = new Matrix4().set( + // this matrix will change the coordinate system of an object hierarchy and + // animations (optional) from right-handed Z-up to right-handed Y-up + + var matrix = new Matrix4().set( 1, 0, 0, 0, 0, 0, 1, 0, 0, - 1, 0, 0, 0, 0, 0, 1 ); - var converter = new UpAxisConverter( conversionMatrix ); + var converter = new CoordSystemConverter( matrix ); converter.convert( root, animations ); } }; -// up axis converter - -function UpAxisConverter( conversionMatrix ) { +function CoordSystemConverter( matrix ) { - this.conversionMatrix = conversionMatrix; + this.matrix = matrix; } -Object.assign( UpAxisConverter.prototype, { +Object.assign( CoordSystemConverter.prototype, { convert: function ( root, animations ) { @@ -92,17 +93,17 @@ Object.assign( UpAxisConverter.prototype, { var position = geometry.attributes.position; var normal = geometry.attributes.normal; - var conversionMatrix = scope.conversionMatrix; + var matrix = scope.matrix; if ( position !== null ) { - conversionMatrix.applyToBufferAttribute( position ); + matrix.applyToBufferAttribute( position ); } if ( normal !== null ) { - var normalMatrix = new Matrix3().setFromMatrix4( conversionMatrix ); + var normalMatrix = new Matrix3().setFromMatrix4( matrix ); normalMatrix.applyToBufferAttribute( normal ); } @@ -162,46 +163,32 @@ Object.assign( UpAxisConverter.prototype, { // columns first - xAxis.setFromMatrixColumn( matrix, 0 ); - yAxis.setFromMatrixColumn( matrix, 1 ); - zAxis.setFromMatrixColumn( matrix, 2 ); + matrix.extractBasis( xAxis, yAxis, zAxis ); translation.setFromMatrixColumn( matrix, 3 ); - xAxis.applyMatrix4( this.conversionMatrix ); - yAxis.applyMatrix4( this.conversionMatrix ); - zAxis.applyMatrix4( this.conversionMatrix ); + xAxis.applyMatrix4( this.matrix ); + yAxis.applyMatrix4( this.matrix ); + zAxis.applyMatrix4( this.matrix ); - matrix.set( - xAxis.x, yAxis.x, zAxis.x, 0, - xAxis.y, yAxis.y, zAxis.y, 0, - xAxis.z, yAxis.z, zAxis.z, 0, - 0, 0, 0, 1 - ); + matrix.makeBasis( xAxis, yAxis, zAxis ); // then rows matrix.transpose(); - xAxis.setFromMatrixColumn( matrix, 0 ); - yAxis.setFromMatrixColumn( matrix, 1 ); - zAxis.setFromMatrixColumn( matrix, 2 ); + matrix.extractBasis( xAxis, yAxis, zAxis ); - xAxis.applyMatrix4( this.conversionMatrix ); - yAxis.applyMatrix4( this.conversionMatrix ); - zAxis.applyMatrix4( this.conversionMatrix ); + xAxis.applyMatrix4( this.matrix ); + yAxis.applyMatrix4( this.matrix ); + zAxis.applyMatrix4( this.matrix ); - matrix.set( - xAxis.x, yAxis.x, zAxis.x, 0, - xAxis.y, yAxis.y, zAxis.y, 0, - xAxis.z, yAxis.z, zAxis.z, 0, - 0, 0, 0, 1 - ); + matrix.makeBasis( xAxis, yAxis, zAxis ); matrix.transpose(); // translation at the end - translation.applyMatrix4( this.conversionMatrix ); + translation.applyMatrix4( this.matrix ); matrix.elements[ 12 ] = translation.x; matrix.elements[ 13 ] = translation.y; @@ -236,7 +223,7 @@ Object.assign( UpAxisConverter.prototype, { for ( i = 0, il = values.length; i < il; i += stride ) { - vector.fromArray( values, i ).applyMatrix4( this.conversionMatrix ); + vector.fromArray( values, i ).applyMatrix4( this.matrix ); for ( j = 0, jl = stride; j < jl; j ++ ) { @@ -252,7 +239,7 @@ Object.assign( UpAxisConverter.prototype, { for ( i = 0, il = values.length; i < il; i += stride ) { - vector.fromArray( values, i ).applyMatrix4( this.conversionMatrix ); + vector.fromArray( values, i ).applyMatrix4( this.matrix ); for ( j = 0, jl = stride; j < jl; j ++ ) { From 2db2efba0d0fb1d0fd4bc5392208434e2c82ff2e Mon Sep 17 00:00:00 2001 From: Mugen87 Date: Sun, 18 Jun 2017 19:45:36 +0200 Subject: [PATCH 6/9] SceneUtils: Rename converter --- src/extras/SceneUtils.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/extras/SceneUtils.js b/src/extras/SceneUtils.js index 61fd472332d90b..67c1ffc81a4eb2 100644 --- a/src/extras/SceneUtils.js +++ b/src/extras/SceneUtils.js @@ -58,20 +58,20 @@ var SceneUtils = { 0, 0, 0, 1 ); - var converter = new CoordSystemConverter( matrix ); + var converter = new BasisConverter( matrix ); converter.convert( root, animations ); } }; -function CoordSystemConverter( matrix ) { +function BasisConverter( matrix ) { this.matrix = matrix; } -Object.assign( CoordSystemConverter.prototype, { +Object.assign( BasisConverter.prototype, { convert: function ( root, animations ) { From 9fc1d71c2d8450a91152177ab5ef4ce8133d0333 Mon Sep 17 00:00:00 2001 From: Mugen87 Date: Wed, 21 Jun 2017 00:58:57 +0200 Subject: [PATCH 7/9] SceneUtils: Refactoring --- src/extras/SceneUtils.js | 77 ++++++++++------------------------------ 1 file changed, 18 insertions(+), 59 deletions(-) diff --git a/src/extras/SceneUtils.js b/src/extras/SceneUtils.js index 67c1ffc81a4eb2..bb9c4dee0b97dd 100644 --- a/src/extras/SceneUtils.js +++ b/src/extras/SceneUtils.js @@ -1,7 +1,6 @@ import { Vector3 } from '../math/Vector3'; import { Quaternion } from '../math/Quaternion'; import { Matrix4 } from '../math/Matrix4'; -import { Matrix3 } from '../math/Matrix3'; import { Mesh } from '../objects/Mesh'; import { Group } from '../objects/Group'; import { PropertyBinding } from '../animation/PropertyBinding'; @@ -67,8 +66,15 @@ var SceneUtils = { function BasisConverter( matrix ) { + // change-of-basis matrix + this.matrix = matrix; + // because the change-of-basis matrix is orthonormal, the inverse of + // this.matrix is the transposition of this.matrix + + this.matrixInverse = this.matrix.clone().transpose(); + } Object.assign( BasisConverter.prototype, { @@ -79,7 +85,11 @@ Object.assign( BasisConverter.prototype, { root.traverse( function( object ) { - // position, quaternion, scale + // ensure matrix is up to date + + object.updateMatrix(); + + // convert position, quaternion, scale scope.convertMatrix4( object.matrix ); object.matrix.decompose( object.position, object.quaternion, object.scale ); @@ -93,20 +103,11 @@ Object.assign( BasisConverter.prototype, { var position = geometry.attributes.position; var normal = geometry.attributes.normal; - var matrix = scope.matrix; - - if ( position !== null ) { + if ( position !== null ) scope.matrix.applyToBufferAttribute( position ); - matrix.applyToBufferAttribute( position ); - - } + // the change-of-basis matrix contains no non-uniform scaling - if ( normal !== null ) { - - var normalMatrix = new Matrix3().setFromMatrix4( matrix ); - normalMatrix.applyToBufferAttribute( normal ); - - } + if ( normal !== null ) scope.matrix.applyToBufferAttribute( normal ); } @@ -152,53 +153,11 @@ Object.assign( BasisConverter.prototype, { }, - convertMatrix4: function() { - - var xAxis = new Vector3(); - var yAxis = new Vector3(); - var zAxis = new Vector3(); - var translation = new Vector3(); - - return function convertMatrix4( matrix ) { - - // columns first - - matrix.extractBasis( xAxis, yAxis, zAxis ); - translation.setFromMatrixColumn( matrix, 3 ); + convertMatrix4: function( matrix ) { - xAxis.applyMatrix4( this.matrix ); - yAxis.applyMatrix4( this.matrix ); - zAxis.applyMatrix4( this.matrix ); + return matrix.premultiply( this.matrix ).multiply( this.matrixInverse ); - matrix.makeBasis( xAxis, yAxis, zAxis ); - - // then rows - - matrix.transpose(); - - matrix.extractBasis( xAxis, yAxis, zAxis ); - - xAxis.applyMatrix4( this.matrix ); - yAxis.applyMatrix4( this.matrix ); - zAxis.applyMatrix4( this.matrix ); - - matrix.makeBasis( xAxis, yAxis, zAxis ); - - matrix.transpose(); - - // translation at the end - - translation.applyMatrix4( this.matrix ); - - matrix.elements[ 12 ] = translation.x; - matrix.elements[ 13 ] = translation.y; - matrix.elements[ 14 ] = translation.z; - - return matrix; - - }; - - } (), + }, convertKeyframeTrack: function() { From 852771439bdccb07f1c85fa46b26a1511ed5a825 Mon Sep 17 00:00:00 2001 From: Mugen87 Date: Wed, 21 Jun 2017 01:06:11 +0200 Subject: [PATCH 8/9] SceneUtils: Better comments --- src/extras/SceneUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/extras/SceneUtils.js b/src/extras/SceneUtils.js index bb9c4dee0b97dd..56cdf409569d04 100644 --- a/src/extras/SceneUtils.js +++ b/src/extras/SceneUtils.js @@ -71,7 +71,7 @@ function BasisConverter( matrix ) { this.matrix = matrix; // because the change-of-basis matrix is orthonormal, the inverse of - // this.matrix is the transposition of this.matrix + // this.matrix is its transposition this.matrixInverse = this.matrix.clone().transpose(); From 253c89df8eeebc57db59a73159a0facbe37af115 Mon Sep 17 00:00:00 2001 From: Mugen87 Date: Thu, 22 Jun 2017 19:17:51 +0200 Subject: [PATCH 9/9] SceneUtils: Update comments --- src/extras/SceneUtils.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/extras/SceneUtils.js b/src/extras/SceneUtils.js index 56cdf409569d04..2730b223589eed 100644 --- a/src/extras/SceneUtils.js +++ b/src/extras/SceneUtils.js @@ -45,10 +45,8 @@ var SceneUtils = { convertFromZUp: function ( root, animations ) { - // see https://gamedev.stackexchange.com/a/7932 - - // this matrix will change the coordinate system of an object hierarchy and - // animations (optional) from right-handed Z-up to right-handed Y-up + // this change-of-basis matrix performs a change-of basis from right-handed Z-up to right-handed Y-up + // for a given object hierarchy and animations (optional) var matrix = new Matrix4().set( 1, 0, 0, 0, @@ -71,7 +69,7 @@ function BasisConverter( matrix ) { this.matrix = matrix; // because the change-of-basis matrix is orthonormal, the inverse of - // this.matrix is its transposition + // this.matrix is its transpose this.matrixInverse = this.matrix.clone().transpose();