Browse Source

Simplified PropertyMixer for additive animation

-Back to storing values in a single buffer, just extended the original buffer to accommodate additive values

- Added some helper functions for restoring the additive region to identity rather than maintaining identity values in the buffer
Christine Morten 5 years ago
parent
commit
6de35af84b

+ 2 - 7
src/animation/AnimationAction.js

@@ -368,12 +368,7 @@ Object.assign( AnimationAction.prototype, {
 		// note: _updateTime may disable the action resulting in
 		// an effective weight of 0
 
-		var accuFn,
-			weight = this._updateWeight( time );
-
-		if ( this.isAdditive ) accuFn = 'accumulateAdditive';
-
-		else accuFn = 'accumulate';
+		var weight = this._updateWeight( time );
 
 		if ( weight > 0 ) {
 
@@ -383,7 +378,7 @@ Object.assign( AnimationAction.prototype, {
 			for ( var j = 0, m = interpolants.length; j !== m; ++ j ) {
 
 				interpolants[ j ].evaluate( clipTime );
-				propertyMixers[ j ][ accuFn ]( accuIndex, weight );
+				propertyMixers[ j ].accumulate( accuIndex, weight, this.isAdditive );
 
 			}
 

+ 1 - 3
src/animation/AnimationMixer.js

@@ -92,9 +92,7 @@ AnimationMixer.prototype = Object.assign( Object.create( EventDispatcher.prototy
 
 			}
 
-			if ( action.isAdditive ) interpolants[ i ].resultBuffer = binding.bufferAdditive;
-
-			else interpolants[ i ].resultBuffer = binding.buffer;
+			interpolants[ i ].resultBuffer = binding.buffer;
 
 		}
 

+ 1 - 3
src/animation/PropertyMixer.d.ts

@@ -5,14 +5,12 @@ export class PropertyMixer {
 	binding: any;
 	valueSize: number;
 	buffer: any;
-	bufferAdditive: any;
 	cumulativeWeight: number;
 	cumulativeWeightAdditive: number;
 	useCount: number;
 	referenceCount: number;
 
-	accumulate( accuIndex: number, weight: number ): void;
-	accumulateAdditive( accuIndex: number, weight: number ): void;
+	accumulate( accuIndex: number, weight: number, isAdditive?: boolean ): void;
 	apply( accuIndex: number ): void;
 	saveOriginalState(): void;
 	restoreOriginalState(): void;

+ 73 - 61
src/animation/PropertyMixer.js

@@ -16,9 +16,10 @@ function PropertyMixer( binding, typeName, valueSize ) {
 	this.valueSize = valueSize;
 
 	var mixFunction,
-		mixFunctionAdditive;
+		mixFunctionAdditive,
+		setIdentity;
 
-	// buffer layout: [ incoming | accu0 | accu1 | orig ]
+	// buffer layout: [ incoming | accu0 | accu1 | orig | addAccu | (optional work) ]
 	//
 	// interpolators can use .buffer as their .result
 	// the data then goes to 'incoming'
@@ -28,58 +29,50 @@ function PropertyMixer( binding, typeName, valueSize ) {
 	// changes
 	//
 	// 'orig' stores the original state of the property
-
-
-	// additiveBuffer layout: [ incoming | accu | identity | ( optional work ) ]
-	//
-	// interpolators can use .additiveBuffer as their .result
-	// the data then goes to 'incoming'
-	//
-	// 'accu' is used frame-interleaved for the cumulative result
 	//
-	// 'identity' stores the zeroed out state of the property
+	// 'add' is used for additive cumulative results
 	//
-	// optional work is only valid for quaternions. It is used to store
-	// intermediate quaternion muliplication results.
+	// 'work' is optional and is only present for quaternion types. It is used
+	// to store intermediate quaternion multiplication results
 
 	switch ( typeName ) {
 
 		case 'quaternion':
 			mixFunction = this._slerp;
 			mixFunctionAdditive = this._slerpAdditive;
+			setIdentity = this._setAdditiveIdentityQuaternion;
 
-			this.buffer = new Float64Array( 16 );
-			this.bufferAdditive = new Float64Array( 16 );
-			this.bufferAdditive.fill( 0 );
-			this.bufferAdditive[ 3 ] = 1;
-			this.bufferAdditive[ 7 ] = 1;
-			this.bufferAdditive[ 11 ] = 1;
-			this.bufferAdditive[ 15 ] = 1;
+			this.buffer = new Float64Array( 24 );
+			this._workIndex = 5;
 			break;
 
 		case 'string':
 		case 'bool':
 			mixFunction = this._select;
-			this.buffer = new Array( valueSize * 4 );
 
-			// Use the regular mix function and buffer for additive on these types,
+			// Use the regular mix function and for additive on these types,
 			// additive is not relevant for non-numeric types
 			mixFunctionAdditive = this._select;
-			this.bufferAdditive = this.buffer;
+
+			setIdentity = this._setAdditiveIdentityOther;
+
+			this.buffer = new Array( valueSize * 5 );
 			break;
 
 		default:
 			mixFunction = this._lerp;
 			mixFunctionAdditive = this._lerpAdditive;
+			setIdentity = this._setAdditiveIdentityNumeric;
 
-			this.buffer = new Float64Array( valueSize * 4 );
-			this.bufferAdditive = new Float64Array( valueSize * 3 );
-			this.bufferAdditive.fill( 0 );
+			this.buffer = new Float64Array( valueSize * 5 );
 
 	}
 
 	this._mixBufferRegion = mixFunction;
 	this._mixBufferRegionAdditive = mixFunctionAdditive;
+	this._setIdentity = setIdentity;
+	this._origIndex = 3;
+	this._addIndex = 4;
 
 	this.cumulativeWeight = 0;
 	this.cumulativeWeightAdditive = 0;
@@ -91,8 +84,16 @@ function PropertyMixer( binding, typeName, valueSize ) {
 
 Object.assign( PropertyMixer.prototype, {
 
+	accumulate: function ( accuIndex, weight, isAdditive = false ) {
+
+		if ( isAdditive ) this._accumulateAdditive( weight );
+
+		else this._accumulate( accuIndex, weight );
+
+	},
+
 	// accumulate data in the 'incoming' region into 'accu<i>'
-	accumulate: function ( accuIndex, weight ) {
+	_accumulate: function ( accuIndex, weight ) {
 
 		// note: happily accumulating nothing when weight = 0, the caller knows
 		// the weight and shouldn't have made the call in the first place
@@ -129,32 +130,24 @@ Object.assign( PropertyMixer.prototype, {
 
 	},
 
-	accumulateAdditive: function ( accuIndex, weight ) {
+	// accumulate data in the 'incoming' region into 'add'
+	_accumulateAdditive: function ( weight ) {
 
-		// note: happily accumulating nothing when weight = 0, the caller knows
-		// the weight and shouldn't have made the call in the first place
-
-		var buffer = this.bufferAdditive,
+		var buffer = this.buffer,
 			stride = this.valueSize,
-			offset = stride;
+			offset = stride * this._addIndex;
 
 		if ( this.cumulativeWeightAdditive === 0 ) {
 
-			// accuN = original
+			// add = identity
 
-			var originalValueOffset = stride * 2;
-
-			for ( var i = 0; i !== stride; ++ i ) {
-
-				buffer[ offset + i ] = buffer[ originalValueOffset + i ];
-
-			}
+			this._setIdentity();
 
 		}
 
-		// accuN := accuN + incoming * weight
+		// add := add + incoming * weight
 
-		this._mixBufferRegionAdditive( buffer, offset, buffer, 0, weight, stride );
+		this._mixBufferRegionAdditive( buffer, offset, 0, weight, stride );
 		this.cumulativeWeightAdditive += weight;
 
 	},
@@ -164,7 +157,6 @@ Object.assign( PropertyMixer.prototype, {
 
 		var stride = this.valueSize,
 			buffer = this.buffer,
-			bufferAdditive = this.bufferAdditive,
 			offset = accuIndex * stride + stride,
 
 			weight = this.cumulativeWeight,
@@ -179,7 +171,7 @@ Object.assign( PropertyMixer.prototype, {
 
 			// accuN := accuN + original * ( 1 - cumulativeWeight )
 
-			var originalValueOffset = stride * 3;
+			var originalValueOffset = stride * this._origIndex;
 
 			this._mixBufferRegion(
 				buffer, offset, originalValueOffset, 1 - weight, stride );
@@ -190,7 +182,7 @@ Object.assign( PropertyMixer.prototype, {
 
 			// accuN := accuN + additive accuN
 
-			this._mixBufferRegionAdditive( buffer, offset, bufferAdditive, stride, 1, stride );
+			this._mixBufferRegionAdditive( buffer, offset, this._addIndex * stride, 1, stride );
 
 		}
 
@@ -215,28 +207,22 @@ Object.assign( PropertyMixer.prototype, {
 		var binding = this.binding;
 
 		var buffer = this.buffer,
-			bufferAdditive = this.bufferAdditive,
 			stride = this.valueSize,
 
-			originalValueOffset = stride * 3,
-			originalValueOffsetAdditive = stride * 2;
+			originalValueOffset = stride * this._origIndex;
 
 		binding.getValue( buffer, originalValueOffset );
 
 		// accu[0..1] := orig -- initially detect changes against the original
-		// original for additive is identity
 		for ( var i = stride, e = originalValueOffset; i !== e; ++ i ) {
 
 			buffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ];
 
-			if ( originalValueOffset <= originalValueOffsetAdditive ) {
-
-				bufferAdditive[ i ] = bufferAdditive[ originalValueOffset + ( i % stride ) ];
-
-			}
-
 		}
 
+		// Add to identity for additive
+		this._setIdentity();
+
 		this.cumulativeWeight = 0;
 		this.cumulativeWeightAdditive = 0;
 
@@ -250,6 +236,30 @@ Object.assign( PropertyMixer.prototype, {
 
 	},
 
+	_setAdditiveIdentityNumeric: function () {
+
+		var startIndex = this._addIndex * this.valueSize;
+
+		this.buffer.fill( 0, startIndex, startIndex + this.valueSize );
+
+	},
+
+	_setAdditiveIdentityQuaternion: function () {
+
+		this._setAdditiveIdentityNumeric();
+		this.buffer[ this._addIndex * 4 + 3 ] = 1;
+
+	},
+
+	_setAdditiveIdentityOther: function () {
+
+		var startIndex = this._origIndex * this.valueSize;
+		var targetIndex = this._addIndex * this.valueSize;
+
+		this.buffer.copyWithin( targetIndex, startIndex, this.valueSize );
+
+	},
+
 
 	// mix functions
 
@@ -273,13 +283,15 @@ Object.assign( PropertyMixer.prototype, {
 
 	},
 
-	_slerpAdditive: function ( dstBuffer, dstOffset, srcBuffer, srcOffset, t ) {
+	_slerpAdditive: function ( buffer, dstOffset, srcOffset, t, stride ) {
+
+		var workOffset = this._workIndex * stride;
 
 		// Store result in intermediate buffer offset
-		Quaternion.multiplyQuaternionsFlat( srcBuffer, 12, dstBuffer, dstOffset, srcBuffer, srcOffset );
+		Quaternion.multiplyQuaternionsFlat( buffer, workOffset, buffer, dstOffset, buffer, srcOffset );
 
 		// Slerp to the intermediate result
-		Quaternion.slerpFlat( dstBuffer, dstOffset, dstBuffer, dstOffset, srcBuffer, 12, t );
+		Quaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, workOffset, t );
 
 	},
 
@@ -297,13 +309,13 @@ Object.assign( PropertyMixer.prototype, {
 
 	},
 
-	_lerpAdditive: function ( dstBuffer, dstOffset, srcBuffer, srcOffset, t, stride ) {
+	_lerpAdditive: function ( buffer, dstOffset, srcOffset, t, stride ) {
 
 		for ( var i = 0; i !== stride; ++ i ) {
 
 			var j = dstOffset + i;
 
-			dstBuffer[ j ] = dstBuffer[ j ] + srcBuffer[ srcOffset + i ] * t;
+			buffer[ j ] = buffer[ j ] + buffer[ srcOffset + i ] * t;
 
 		}