Skip to content

Commit

Permalink
Merge pull request #17649 from zeux/morph-relative
Browse files Browse the repository at this point in the history
BufferGeometry: Implemented morphTargetsRelative
  • Loading branch information
mrdoob authored Nov 5, 2019
2 parents 0693021 + 18593e6 commit 3276d13
Show file tree
Hide file tree
Showing 18 changed files with 176 additions and 271 deletions.
7 changes: 7 additions & 0 deletions docs/api/en/core/BufferGeometry.html
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,13 @@ <h3>[property:Object morphAttributes]</h3>
Hashmap of [page:BufferAttribute]s holding details of the geometry's [page:Geometry.morphTargets morphTargets].
</p>

<h3>[property:Boolean morphTargetsRelative]</h3>
<p>
Used to control the morph target behavior; when set to true, the morph target data is treated as relative offsets, rather than as absolute positions/normals.

Default is *false*.
</p>

<h3>[property:String name]</h3>
<p>
Optional name for this bufferGeometry instance. Default is an empty string.
Expand Down
20 changes: 12 additions & 8 deletions examples/js/exporters/GLTFExporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -1339,14 +1339,18 @@ THREE.GLTFExporter.prototype = {
// Clones attribute not to override
var relativeAttribute = attribute.clone();

for ( var j = 0, jl = attribute.count; j < jl; j ++ ) {

relativeAttribute.setXYZ(
j,
attribute.getX( j ) - baseAttribute.getX( j ),
attribute.getY( j ) - baseAttribute.getY( j ),
attribute.getZ( j ) - baseAttribute.getZ( j )
);
if ( ! geometry.morphTargetsRelative ) {

for ( var j = 0, jl = attribute.count; j < jl; j ++ ) {

relativeAttribute.setXYZ(
j,
attribute.getX( j ) - baseAttribute.getX( j ),
attribute.getY( j ) - baseAttribute.getY( j ),
attribute.getZ( j ) - baseAttribute.getZ( j )
);

}

}

Expand Down
113 changes: 1 addition & 112 deletions examples/js/loaders/GLTFLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -1309,95 +1309,9 @@ THREE.GLTFLoader = ( function () {
var morphPositions = accessors[ 0 ];
var morphNormals = accessors[ 1 ];

// Clone morph target accessors before modifying them.

for ( var i = 0, il = morphPositions.length; i < il; i ++ ) {

if ( geometry.attributes.position === morphPositions[ i ] ) continue;

morphPositions[ i ] = cloneBufferAttribute( morphPositions[ i ] );

}

for ( var i = 0, il = morphNormals.length; i < il; i ++ ) {

if ( geometry.attributes.normal === morphNormals[ i ] ) continue;

morphNormals[ i ] = cloneBufferAttribute( morphNormals[ i ] );

}

for ( var i = 0, il = targets.length; i < il; i ++ ) {

var target = targets[ i ];
var attributeName = 'morphTarget' + i;

if ( hasMorphPosition ) {

// Three.js morph position is absolute value. The formula is
// basePosition
// + weight0 * ( morphPosition0 - basePosition )
// + weight1 * ( morphPosition1 - basePosition )
// ...
// while the glTF one is relative
// basePosition
// + weight0 * glTFmorphPosition0
// + weight1 * glTFmorphPosition1
// ...
// then we need to convert from relative to absolute here.

if ( target.POSITION !== undefined ) {

var positionAttribute = morphPositions[ i ];
positionAttribute.name = attributeName;

var position = geometry.attributes.position;

for ( var j = 0, jl = positionAttribute.count; j < jl; j ++ ) {

positionAttribute.setXYZ(
j,
positionAttribute.getX( j ) + position.getX( j ),
positionAttribute.getY( j ) + position.getY( j ),
positionAttribute.getZ( j ) + position.getZ( j )
);

}

}

}

if ( hasMorphNormal ) {

// see target.POSITION's comment

if ( target.NORMAL !== undefined ) {

var normalAttribute = morphNormals[ i ];
normalAttribute.name = attributeName;

var normal = geometry.attributes.normal;

for ( var j = 0, jl = normalAttribute.count; j < jl; j ++ ) {

normalAttribute.setXYZ(
j,
normalAttribute.getX( j ) + normal.getX( j ),
normalAttribute.getY( j ) + normal.getY( j ),
normalAttribute.getZ( j ) + normal.getZ( j )
);

}

}

}

}

if ( hasMorphPosition ) geometry.morphAttributes.position = morphPositions;
if ( hasMorphNormal ) geometry.morphAttributes.normal = morphNormals;
geometry.morphTargetsRelative = true;

return geometry;

Expand Down Expand Up @@ -1485,31 +1399,6 @@ THREE.GLTFLoader = ( function () {

}

function cloneBufferAttribute( attribute ) {

if ( attribute.isInterleavedBufferAttribute ) {

var count = attribute.count;
var itemSize = attribute.itemSize;
var array = attribute.array.slice( 0, count * itemSize );

for ( var i = 0, j = 0; i < count; ++ i ) {

array[ j ++ ] = attribute.getX( i );
if ( itemSize >= 2 ) array[ j ++ ] = attribute.getY( i );
if ( itemSize >= 3 ) array[ j ++ ] = attribute.getZ( i );
if ( itemSize >= 4 ) array[ j ++ ] = attribute.getW( i );

}

return new THREE.BufferAttribute( array, itemSize, attribute.normalized );

}

return attribute.clone();

}

/* GLTF PARSER */

function GLTFParser( json, extensions, options ) {
Expand Down
17 changes: 14 additions & 3 deletions examples/js/renderers/Projector.js
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,7 @@ THREE.Projector = function () {
if ( material.morphTargets === true ) {

var morphTargets = geometry.morphAttributes.position;
var morphTargetsRelative = geometry.morphTargetsRelative;
var morphInfluences = object.morphTargetInfluences;

for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) {
Expand All @@ -480,9 +481,19 @@ THREE.Projector = function () {

var target = morphTargets[ t ];

x += ( target.getX( i / 3 ) - positions[ i ] ) * influence;
y += ( target.getY( i / 3 ) - positions[ i + 1 ] ) * influence;
z += ( target.getZ( i / 3 ) - positions[ i + 2 ] ) * influence;
if ( morphTargetsRelative ) {

x += target.getX( i / 3 ) * influence;
y += target.getY( i / 3 ) * influence;
z += target.getZ( i / 3 ) * influence;

} else {

x += ( target.getX( i / 3 ) - positions[ i ] ) * influence;
y += ( target.getY( i / 3 ) - positions[ i + 1 ] ) * influence;
z += ( target.getZ( i / 3 ) - positions[ i + 2 ] ) * influence;

}

}

Expand Down
4 changes: 4 additions & 0 deletions examples/js/utils/BufferGeometryUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,8 @@ THREE.BufferGeometryUtils = {
var attributes = {};
var morphAttributes = {};

var morphTargetsRelative = geometries[ 0 ].morphTargetsRelative;

var mergedGeometry = new THREE.BufferGeometry();

var offset = 0;
Expand All @@ -225,6 +227,8 @@ THREE.BufferGeometryUtils = {

// gather morph attributes, exit early if they're different

if ( morphTargetsRelative !== geometry.morphTargetsRelative ) return null;

for ( var name in geometry.morphAttributes ) {

if ( ! morphAttributesUsed.has( name ) ) return null;
Expand Down
20 changes: 12 additions & 8 deletions examples/jsm/exporters/GLTFExporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -1363,14 +1363,18 @@ GLTFExporter.prototype = {
// Clones attribute not to override
var relativeAttribute = attribute.clone();

for ( var j = 0, jl = attribute.count; j < jl; j ++ ) {

relativeAttribute.setXYZ(
j,
attribute.getX( j ) - baseAttribute.getX( j ),
attribute.getY( j ) - baseAttribute.getY( j ),
attribute.getZ( j ) - baseAttribute.getZ( j )
);
if ( ! geometry.morphTargetsRelative ) {

for ( var j = 0, jl = attribute.count; j < jl; j ++ ) {

relativeAttribute.setXYZ(
j,
attribute.getX( j ) - baseAttribute.getX( j ),
attribute.getY( j ) - baseAttribute.getY( j ),
attribute.getZ( j ) - baseAttribute.getZ( j )
);

}

}

Expand Down
113 changes: 1 addition & 112 deletions examples/jsm/loaders/GLTFLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -1373,95 +1373,9 @@ var GLTFLoader = ( function () {
var morphPositions = accessors[ 0 ];
var morphNormals = accessors[ 1 ];

// Clone morph target accessors before modifying them.

for ( var i = 0, il = morphPositions.length; i < il; i ++ ) {

if ( geometry.attributes.position === morphPositions[ i ] ) continue;

morphPositions[ i ] = cloneBufferAttribute( morphPositions[ i ] );

}

for ( var i = 0, il = morphNormals.length; i < il; i ++ ) {

if ( geometry.attributes.normal === morphNormals[ i ] ) continue;

morphNormals[ i ] = cloneBufferAttribute( morphNormals[ i ] );

}

for ( var i = 0, il = targets.length; i < il; i ++ ) {

var target = targets[ i ];
var attributeName = 'morphTarget' + i;

if ( hasMorphPosition ) {

// Three.js morph position is absolute value. The formula is
// basePosition
// + weight0 * ( morphPosition0 - basePosition )
// + weight1 * ( morphPosition1 - basePosition )
// ...
// while the glTF one is relative
// basePosition
// + weight0 * glTFmorphPosition0
// + weight1 * glTFmorphPosition1
// ...
// then we need to convert from relative to absolute here.

if ( target.POSITION !== undefined ) {

var positionAttribute = morphPositions[ i ];
positionAttribute.name = attributeName;

var position = geometry.attributes.position;

for ( var j = 0, jl = positionAttribute.count; j < jl; j ++ ) {

positionAttribute.setXYZ(
j,
positionAttribute.getX( j ) + position.getX( j ),
positionAttribute.getY( j ) + position.getY( j ),
positionAttribute.getZ( j ) + position.getZ( j )
);

}

}

}

if ( hasMorphNormal ) {

// see target.POSITION's comment

if ( target.NORMAL !== undefined ) {

var normalAttribute = morphNormals[ i ];
normalAttribute.name = attributeName;

var normal = geometry.attributes.normal;

for ( var j = 0, jl = normalAttribute.count; j < jl; j ++ ) {

normalAttribute.setXYZ(
j,
normalAttribute.getX( j ) + normal.getX( j ),
normalAttribute.getY( j ) + normal.getY( j ),
normalAttribute.getZ( j ) + normal.getZ( j )
);

}

}

}

}

if ( hasMorphPosition ) geometry.morphAttributes.position = morphPositions;
if ( hasMorphNormal ) geometry.morphAttributes.normal = morphNormals;
geometry.morphTargetsRelative = true;

return geometry;

Expand Down Expand Up @@ -1549,31 +1463,6 @@ var GLTFLoader = ( function () {

}

function cloneBufferAttribute( attribute ) {

if ( attribute.isInterleavedBufferAttribute ) {

var count = attribute.count;
var itemSize = attribute.itemSize;
var array = attribute.array.slice( 0, count * itemSize );

for ( var i = 0, j = 0; i < count; ++ i ) {

array[ j ++ ] = attribute.getX( i );
if ( itemSize >= 2 ) array[ j ++ ] = attribute.getY( i );
if ( itemSize >= 3 ) array[ j ++ ] = attribute.getZ( i );
if ( itemSize >= 4 ) array[ j ++ ] = attribute.getW( i );

}

return new BufferAttribute( array, itemSize, attribute.normalized );

}

return attribute.clone();

}

/* GLTF PARSER */

function GLTFParser( json, extensions, options ) {
Expand Down
Loading

0 comments on commit 3276d13

Please sign in to comment.