Ver código fonte

JSM: Added module and TS files for animation classes.

Mugen87 6 anos atrás
pai
commit
e630833a35

+ 7 - 1
docs/manual/en/introduction/Import-via-modules.html

@@ -66,7 +66,7 @@
 		<p>
 			The core of three.js is focused on the most important components of a 3D engine. Many other components like loaders or controls are part of the
 			examples directory. three.js ensures that these files are kept in sync with the core but users have to import them separately if they are required
-			for their project. However, most of these files are not modules which makes their usage in certain cases inconvenient. In order to address this issue,
+			for their project. However, not all files are modules which makes their usage in certain cases inconvenient. In order to address this issue,
 			we are working to provide all the examples as modules in the [link:https://github.com/mrdoob/three.js/tree/master/examples/jsm examples/jsm] directory.
 			If you install three.js via npm, you can import them like so:
 		</p>
@@ -76,6 +76,12 @@
 		<p>
 			The following examples files are already available as modules:
 			<ul>
+				<li>animation
+					<ul>
+						<li>AnimationClipCreator</li>
+						<li>TimelinerController</li>
+					</ul>
+				</li>
 				<li>cameras
 					<ul>
 						<li>CinematicCamera</li>

+ 16 - 0
examples/jsm/animation/AnimationClipCreator.d.ts

@@ -0,0 +1,16 @@
+import {
+  AnimationClip,
+  Vector3
+} from '../../../src/Three';
+
+export class AnimationClipCreator  {
+  constructor();
+
+  static CreateRotationAnimation(period: number, axis: string): AnimationClip;
+  static CreateScaleAxisAnimation(period: number, axis: string): AnimationClip;
+  static CreateShakeAnimation(duration: number, shakeScale: Vector3): AnimationClip;
+  static CreatePulsationAnimation(duration: number, pulseScale: number): AnimationClip;
+  static CreateVisibilityAnimation(duration: number): AnimationClip;
+  static CreateMaterialColorAnimation(duration: number, colors: number[]): AnimationClip;
+
+}

+ 125 - 0
examples/jsm/animation/AnimationClipCreator.js

@@ -0,0 +1,125 @@
+/**
+ *
+ * Creator of typical test AnimationClips / KeyframeTracks
+ *
+ * @author Ben Houston / http://clara.io/
+ * @author David Sarno / http://lighthaus.us/
+ */
+
+import {
+	AnimationClip,
+	BooleanKeyframeTrack,
+	ColorKeyframeTrack,
+	NumberKeyframeTrack,
+	Vector3,
+	VectorKeyframeTrack
+} from "../../../build/three.module.js";
+
+var AnimationClipCreator = function () {};
+
+AnimationClipCreator.CreateRotationAnimation = function ( period, axis ) {
+
+	var times = [ 0, period ], values = [ 0, 360 ];
+
+	axis = axis || 'x';
+	var trackName = '.rotation[' + axis + ']';
+
+	var track = new NumberKeyframeTrack( trackName, times, values );
+
+	return new AnimationClip( null, period, [ track ] );
+
+};
+
+AnimationClipCreator.CreateScaleAxisAnimation = function ( period, axis ) {
+
+	var times = [ 0, period ], values = [ 0, 1 ];
+
+	axis = axis || 'x';
+	var trackName = '.scale[' + axis + ']';
+
+	var track = new NumberKeyframeTrack( trackName, times, values );
+
+	return new AnimationClip( null, period, [ track ] );
+
+};
+
+AnimationClipCreator.CreateShakeAnimation = function ( duration, shakeScale ) {
+
+	var times = [], values = [], tmp = new Vector3();
+
+	for ( var i = 0; i < duration * 10; i ++ ) {
+
+		times.push( i / 10 );
+
+		tmp.set( Math.random() * 2.0 - 1.0, Math.random() * 2.0 - 1.0, Math.random() * 2.0 - 1.0 ).
+			multiply( shakeScale ).
+			toArray( values, values.length );
+
+	}
+
+	var trackName = '.position';
+
+	var track = new VectorKeyframeTrack( trackName, times, values );
+
+	return new AnimationClip( null, duration, [ track ] );
+
+};
+
+
+AnimationClipCreator.CreatePulsationAnimation = function ( duration, pulseScale ) {
+
+	var times = [], values = [], tmp = new Vector3();
+
+	for ( var i = 0; i < duration * 10; i ++ ) {
+
+		times.push( i / 10 );
+
+		var scaleFactor = Math.random() * pulseScale;
+		tmp.set( scaleFactor, scaleFactor, scaleFactor ).
+			toArray( values, values.length );
+
+	}
+
+	var trackName = '.scale';
+
+	var track = new VectorKeyframeTrack( trackName, times, values );
+
+	return new AnimationClip( null, duration, [ track ] );
+
+};
+
+
+AnimationClipCreator.CreateVisibilityAnimation = function ( duration ) {
+
+	var times = [ 0, duration / 2, duration ], values = [ true, false, true ];
+
+	var trackName = '.visible';
+
+	var track = new BooleanKeyframeTrack( trackName, times, values );
+
+	return new AnimationClip( null, duration, [ track ] );
+
+};
+
+
+AnimationClipCreator.CreateMaterialColorAnimation = function ( duration, colors ) {
+
+	var times = [], values = [],
+		timeStep = duration / colors.length;
+
+	for ( var i = 0; i <= colors.length; i ++ ) {
+
+		times.push( i * timeStep );
+		values.push( colors[ i % colors.length ] );
+
+	}
+
+	var trackName = '.material[0].color';
+
+	var track = new ColorKeyframeTrack( trackName, times, values );
+
+	return new AnimationClip( null, duration, [ track ] );
+
+};
+
+export { AnimationClipCreator };

+ 20 - 0
examples/jsm/animation/TimelinerController.d.ts

@@ -0,0 +1,20 @@
+import {
+  AnimationClip,
+  Scene,
+  Vector3
+} from '../../../src/Three';
+
+export class TimelinerController  {
+  constructor(scene: Scene, trackInfo: object[], onUpdate: () => void);
+
+  delKeyframe(channelName: string, time: number): void;
+  deserialize(structs: object): void;
+  getChannelKeyTimes(): number[];
+  getChannelNames(): string[];
+  init(): void;
+  moveKeyframe(channelName: string, time: number, delta: number, moveRemaining: boolean): void;
+  serialize(): object;
+  setDisplayTime(time: number): void;
+  setDuration(duration: number): void;
+  setKeyframe(channelName: string, time: number): void;
+}

+ 283 - 0
examples/jsm/animation/TimelinerController.js

@@ -0,0 +1,283 @@
+/**
+ * Controller class for the Timeliner GUI.
+ *
+ * Timeliner GUI library (required to use this class):
+ *
+ * 		../libs/timeliner_gui.min.js
+ *
+ * Source code:
+ *
+ * 		https://github.com/tschw/timeliner_gui
+ * 		https://github.com/zz85/timeliner (fork's origin)
+ *
+ * @author tschw
+ *
+ */
+
+import {
+	AnimationClip,
+	AnimationMixer,
+	AnimationUtils,
+	PropertyBinding
+} from "../../../build/three.module.js";
+
+var TimelinerController = function TimelinerController( scene, trackInfo, onUpdate ) {
+
+	this._scene = scene;
+	this._trackInfo = trackInfo;
+
+	this._onUpdate = onUpdate;
+
+	this._mixer = new AnimationMixer( scene );
+	this._clip = null;
+	this._action = null;
+
+	this._tracks = {};
+	this._propRefs = {};
+	this._channelNames = [];
+
+};
+
+TimelinerController.prototype = {
+
+	constructor: TimelinerController,
+
+	init: function () {
+
+		var tracks = [],
+			trackInfo = this._trackInfo;
+
+		for ( var i = 0, n = trackInfo.length; i !== n; ++ i ) {
+
+			var spec = trackInfo[ i ];
+
+			tracks.push( this._addTrack( spec.type, spec.propertyPath, spec.initialValue, spec.interpolation ) );
+
+		}
+
+		this._clip = new AnimationClip( 'editclip', 0, tracks );
+		this._action = this._mixer.clipAction( this._clip ).play();
+
+	},
+
+	setDisplayTime: function ( time ) {
+
+		this._action.time = time;
+		this._mixer.update( 0 );
+
+		this._onUpdate();
+
+	},
+
+	setDuration: function ( duration ) {
+
+		this._clip.duration = duration;
+
+	},
+
+	getChannelNames: function () {
+
+		return this._channelNames;
+
+	},
+
+	getChannelKeyTimes: function ( channelName ) {
+
+		return this._tracks[ channelName ].times;
+
+	},
+
+	setKeyframe: function ( channelName, time ) {
+
+		var track = this._tracks[ channelName ],
+			times = track.times,
+			index = Timeliner.binarySearch( times, time ),
+			values = track.values,
+			stride = track.getValueSize(),
+			offset = index * stride;
+
+		if ( index < 0 ) {
+
+			// insert new keyframe
+
+			index = ~ index;
+			offset = index * stride;
+
+			var nTimes = times.length + 1,
+				nValues = values.length + stride;
+
+			for ( var i = nTimes - 1; i !== index; -- i ) {
+
+				times[ i ] = times[ i - 1 ];
+
+			}
+
+			for ( var i = nValues - 1, e = offset + stride - 1; i !== e; -- i ) {
+
+				values[ i ] = values[ i - stride ];
+
+			}
+
+		}
+
+		times[ index ] = time;
+		this._propRefs[ channelName ].getValue( values, offset );
+
+	},
+
+	delKeyframe: function ( channelName, time ) {
+
+		var track = this._tracks[ channelName ],
+			times = track.times,
+			index = Timeliner.binarySearch( times, time );
+
+		// we disallow to remove the keyframe when it is the last one we have,
+		// since the animation system is designed to always produce a defined
+		// state
+
+		if ( times.length > 1 && index >= 0 ) {
+
+			var nTimes = times.length - 1,
+				values = track.values,
+				stride = track.getValueSize(),
+				nValues = values.length - stride;
+
+			// note: no track.getValueSize when array sizes are out of sync
+
+			for ( var i = index; i !== nTimes; ++ i ) {
+
+				times[ i ] = times[ i + 1 ];
+
+			}
+
+			times.pop();
+
+			for ( var offset = index * stride; offset !== nValues; ++ offset ) {
+
+				values[ offset ] = values[ offset + stride ];
+
+			}
+
+			values.length = nValues;
+
+		}
+
+	},
+
+	moveKeyframe: function ( channelName, time, delta, moveRemaining ) {
+
+		var track = this._tracks[ channelName ],
+			times = track.times,
+			index = Timeliner.binarySearch( times, time );
+
+		if ( index >= 0 ) {
+
+			var endAt = moveRemaining ? times.length : index + 1,
+				needsSort = times[ index - 1 ] <= time ||
+					! moveRemaining && time >= times[ index + 1 ];
+
+			while ( index !== endAt ) times[ index ++ ] += delta;
+
+			if ( needsSort ) this._sort( track );
+
+		}
+
+	},
+
+	serialize: function () {
+
+		var result = {
+				duration: this._clip.duration,
+				channels: {}
+			},
+
+			names = this._channelNames,
+			tracks = this._tracks,
+
+			channels = result.channels;
+
+		for ( var i = 0, n = names.length; i !== n; ++ i ) {
+
+			var name = names[ i ],
+				track = tracks[ name ];
+
+			channels[ name ] = {
+
+				times: track.times,
+				values: track.values
+
+			};
+
+		}
+
+		return result;
+
+	},
+
+	deserialize: function ( structs ) {
+
+		var names = this._channelNames,
+			tracks = this._tracks,
+
+			channels = structs.channels;
+
+		this.setDuration( structs.duration );
+
+		for ( var i = 0, n = names.length; i !== n; ++ i ) {
+
+			var name = names[ i ],
+				track = tracks[ name ],
+				data = channels[ name ];
+
+			this._setArray( track.times, data.times );
+			this._setArray( track.values, data.values );
+
+		}
+
+		// update display
+		this.setDisplayTime( this._mixer.time );
+
+	},
+
+	_sort: function ( track ) {
+
+		var times = track.times, order = AnimationUtils.getKeyframeOrder( times );
+
+		this._setArray( times, AnimationUtils.sortedArray( times, 1, order ) );
+
+		var values = track.values,
+			stride = track.getValueSize();
+
+		this._setArray( values, AnimationUtils.sortedArray( values, stride, order ) );
+
+	},
+
+	_setArray: function ( dst, src ) {
+
+		dst.length = 0;
+		dst.push.apply( dst, src );
+
+	},
+
+	_addTrack: function ( type, prop, initialValue, interpolation ) {
+
+		var track = new type( prop, [ 0 ], initialValue, interpolation );
+
+		// data must be in JS arrays so it can be resized
+		track.times = Array.prototype.slice.call( track.times );
+		track.values = Array.prototype.slice.call( track.values );
+
+		this._channelNames.push( prop );
+		this._tracks[ prop ] = track;
+
+		// for recording the state:
+		this._propRefs[ prop ] =
+				new PropertyBinding( this._scene, prop );
+
+		return track;
+
+	}
+
+};
+
+export { TimelinerController };

+ 3 - 0
utils/modularize.js

@@ -10,6 +10,9 @@ var srcFolder = __dirname + '/../examples/js/';
 var dstFolder = __dirname + '/../examples/jsm/';
 
 var files = [
+	{ path: 'animation/AnimationClipCreator.js', dependencies: [], ignoreList: [] },
+	{ path: 'animation/TimelinerController.js', dependencies: [], ignoreList: [] },
+
 	{ path: 'cameras/CinematicCamera.js', dependencies: [ { name: 'BokehShader', path: 'shaders/BokehShader2.js' }, { name: 'BokehDepthShader', path: 'shaders/BokehShader2.js' } ], ignoreList: [] },
 
 	{ path: 'controls/DragControls.js', dependencies: [], ignoreList: [] },