animation system updates... still not 100%

beta.r3js.org
-=yb4f310 2017-09-18 15:39:40 +02:00
parent 14df05ab5b
commit 4d7ac34a8a
5 changed files with 205 additions and 86 deletions

View File

@ -64,7 +64,7 @@ GameLib.Clock.prototype.getDelta = function() {
*/ */
if (delta > (1 / 30.0)) { if (delta > (1 / 30.0)) {
console.log('clipped ' + (delta - (1/30.0)) + ' seconds - essentially lost time'); // console.log('clipped ' + (delta - (1/30.0)) + ' seconds - essentially lost time');
delta = (1 / 30.0); delta = (1 / 30.0);
} }

View File

@ -9,6 +9,7 @@
* @param translationFn * @param translationFn
* @param scaleFn * @param scaleFn
* @param blocking * @param blocking
* @param applyToMeshWhenDone
* @param parentMesh * @param parentMesh
* @param parentEntity * @param parentEntity
* @constructor * @constructor
@ -23,6 +24,7 @@ GameLib.D3.API.Animation = function (
translationFn, translationFn,
scaleFn, scaleFn,
blocking, blocking,
applyToMeshWhenDone,
parentMesh, parentMesh,
parentEntity parentEntity
) { ) {
@ -71,6 +73,11 @@ GameLib.D3.API.Animation = function (
} }
this.blocking = blocking; this.blocking = blocking;
if (GameLib.Utils.UndefinedOrNull(applyToMeshWhenDone)) {
applyToMeshWhenDone = true;
}
this.applyToMeshWhenDone = applyToMeshWhenDone;
if (GameLib.Utils.UndefinedOrNull(parentMesh)) { if (GameLib.Utils.UndefinedOrNull(parentMesh)) {
parentMesh = null; parentMesh = null;
} }
@ -102,6 +109,7 @@ GameLib.D3.API.Animation.FromObject = function(objectComponent) {
objectComponent.translationFn, objectComponent.translationFn,
objectComponent.scaleFn, objectComponent.scaleFn,
objectComponent.blocking, objectComponent.blocking,
objectComponent.applyToMeshWhenDone,
objectComponent.parentMesh, objectComponent.parentMesh,
objectComponent.parentEntity objectComponent.parentEntity
); );

View File

@ -31,6 +31,7 @@ GameLib.D3.Animation = function(
apiAnimation.translationFn, apiAnimation.translationFn,
apiAnimation.scaleFn, apiAnimation.scaleFn,
apiAnimation.blocking, apiAnimation.blocking,
apiAnimation.applyToMeshWhenDone,
apiAnimation.parentMesh, apiAnimation.parentMesh,
apiAnimation.parentEntity apiAnimation.parentEntity
); );
@ -39,6 +40,12 @@ GameLib.D3.Animation = function(
this.editor = null; this.editor = null;
/**
* This indicates whether an animation is currently in process - for blocking to take effect
* @type {boolean}
*/
this.inProcess = false;
GameLib.Component.call( GameLib.Component.call(
this, this,
GameLib.Component.COMPONENT_ANIMATION GameLib.Component.COMPONENT_ANIMATION
@ -159,6 +166,7 @@ GameLib.D3.Animation.prototype.toApiObject = function() {
this.translationFn, this.translationFn,
this.scaleFn, this.scaleFn,
this.blocking, this.blocking,
this.applyToMeshWhenDone,
GameLib.Utils.IdOrNull(this.parentMesh), GameLib.Utils.IdOrNull(this.parentMesh),
GameLib.Utils.IdOrNull(this.parentEntity) GameLib.Utils.IdOrNull(this.parentEntity)
); );

View File

@ -486,15 +486,7 @@ GameLib.D3.Mesh.prototype.updateInstance = function() {
} }
if (this.updateRotationFromAxisAngle) { if (this.updateRotationFromAxisAngle) {
this.quaternion.axis.instance.x = this.quaternion.axis.x; this.updateInstanceRotationFromAxisAngle();
this.quaternion.axis.instance.y = this.quaternion.axis.y;
this.quaternion.axis.instance.z = this.quaternion.axis.z;
this.quaternion.instance.setFromAxisAngle(this.quaternion.axis.instance, this.quaternion.angle);
this.instance.quaternion.copy(this.quaternion.instance);
this.quaternion.x = this.quaternion.instance.x;
this.quaternion.y = this.quaternion.instance.y;
this.quaternion.z = this.quaternion.instance.z;
this.quaternion.w = this.quaternion.instance.w;
} else { } else {
this.instance.quaternion.x = this.quaternion.x; this.instance.quaternion.x = this.quaternion.x;
this.instance.quaternion.y = this.quaternion.y; this.instance.quaternion.y = this.quaternion.y;
@ -809,11 +801,19 @@ GameLib.D3.Mesh.prototype.createInstanceDefaults = function(instance) {
instance.position.y = this.position.y; instance.position.y = this.position.y;
instance.position.z = this.position.z; instance.position.z = this.position.z;
instance.quaternion.x = this.quaternion.x; instance.quaternion.x = this.quaternion.x;
instance.quaternion.y = this.quaternion.y; instance.quaternion.y = this.quaternion.y;
instance.quaternion.z = this.quaternion.z; instance.quaternion.z = this.quaternion.z;
instance.quaternion.w = this.quaternion.w; instance.quaternion.w = this.quaternion.w;
instance.quaternion.setFromAxisAngle(this.quaternion.axis.instance, this.quaternion.angle); instance.quaternion.setFromAxisAngle(
new THREE.Vector3(
this.quaternion.axis.x,
this.quaternion.axis.y,
this.quaternion.axis.z
),
this.quaternion.angle
);
instance.scale.x = this.scale.x; instance.scale.x = this.scale.x;
instance.scale.y = this.scale.y; instance.scale.y = this.scale.y;
@ -937,6 +937,18 @@ GameLib.D3.Mesh.prototype.centerAroundOrigin = function() {
this.updateInstance(); this.updateInstance();
}; };
GameLib.D3.Mesh.prototype.getDistanceFromCenter = function() {
var position = this.instance.geometry.center();
return new GameLib.Vector3(
this.graphics,
new GameLib.API.Vector3(
position.x,
position.y,
position.z
)
)
};
/** /**
* Applies position, rotation and scale to the object vertice data, resets scale, rotation and sets position to origin. * Applies position, rotation and scale to the object vertice data, resets scale, rotation and sets position to origin.
*/ */
@ -947,31 +959,58 @@ GameLib.D3.Mesh.prototype.applyPositionRotationScale = function() {
this.instance.geometry.applyMatrix(this.instance.matrix); this.instance.geometry.applyMatrix(this.instance.matrix);
this.position.x = 0; this.position.x = 0;
this.position.y = 0; this.position.y = 0;
this.position.z = 0; this.position.z = 0;
this.instance.position.set(0,0,0); this.updateInstancePosition();
this.scale.x = 1; this.scale.x = 1;
this.scale.y = 1; this.scale.y = 1;
this.scale.z = 1; this.scale.z = 1;
this.instance.scale.set(1,1,1); this.instance.scale.set(1,1,1);
this.quaternion.axis.x = 0; this.updateInstanceRotationFromAxisAngle(
this.quaternion.axis.y = 0; new GameLib.Vector3(
this.quaternion.axis.z = 0; this.graphics,
this.quaternion.axis.w = 1; new GameLib.API.Vector3(
this.quaternion.angle = 0; 0,0,0
this.instance.quaternion.setFromAxisAngle(this.quaternion.axis.instance, this.quaternion.angle); )
this.quaternion.x = this.instance.quaternion.x; ),
this.quaternion.y = this.instance.quaternion.y; 0
this.quaternion.z = this.instance.quaternion.z; );
this.quaternion.w = this.instance.quaternion.w;
this.instance.updateMatrix(); this.instance.updateMatrix();
this.updateVerticesFromGeometryInstance(this.instance.geometry); this.updateVerticesFromGeometryInstance(this.instance.geometry);
}; };
GameLib.D3.Mesh.prototype.updateInstanceRotationFromAxisAngle = function(axis, angle) {
if (GameLib.Utils.UndefinedOrNull(axis)) {
axis = this.quaternion.axis;
}
if (GameLib.Utils.UndefinedOrNull(angle)) {
angle = this.quaternion.angle;
}
this.quaternion.axis.instance.x = axis.x;
this.quaternion.axis.instance.y = axis.y;
this.quaternion.axis.instance.z = axis.z;
this.quaternion.instance.setFromAxisAngle(this.quaternion.axis.instance, angle);
this.instance.quaternion.copy(this.quaternion.instance);
this.quaternion.x = this.quaternion.instance.x;
this.quaternion.y = this.quaternion.instance.y;
this.quaternion.z = this.quaternion.instance.z;
this.quaternion.w = this.quaternion.instance.w;
};
GameLib.D3.Mesh.prototype.updateInstancePosition = function() {
this.position.instance.x = this.position.x;
this.position.instance.y = this.position.y;
this.position.instance.z = this.position.z;
this.instance.position.copy(this.position.instance);
};
/** /**
* Gets all children components of this Mesh (all linked objects only - no object references i.e. string ids) * Gets all children components of this Mesh (all linked objects only - no object references i.e. string ids)

View File

@ -44,16 +44,29 @@ GameLib.System.Animation.prototype.start = function() {
targetAngle : mesh.quaternion.angle, targetAngle : mesh.quaternion.angle,
angleIncrement : true, angleIncrement : true,
intermediateAngle : mesh.quaternion.angle, intermediateAngle : mesh.quaternion.angle,
subscription : null subscription : null,
inProcess : false,
blocking : animation.blocking,
callbacks : [],
storedValues : []
}; };
var getIntermediateAngle = function() { var getIntermediateAngle = function() {
return mesh.animationObject.intermediateAngle; return mesh.animationObject.intermediateAngle;
}; };
var getTargetAngle = function() {
if (mesh.animationObject.storedValues.length > 0) {
return mesh.animationObject.storedValues[mesh.animationObject.storedValues.length - 1];
}
return mesh.animationObject.targetAngle;
};
var animateRotation = function(value) { var animateRotation = function(value) {
mesh.animationObject.intermediateAngle = value; mesh.animationObject.intermediateAngle += value;
var done = false; var done = false;
@ -61,7 +74,7 @@ GameLib.System.Animation.prototype.start = function() {
/** /**
* We are rotating upwards * We are rotating upwards
*/ */
if (value >= mesh.animationObject.targetAngle) { if (mesh.animationObject.intermediateAngle >= mesh.animationObject.targetAngle) {
/** /**
* We need to stop * We need to stop
*/ */
@ -71,7 +84,7 @@ GameLib.System.Animation.prototype.start = function() {
/** /**
* We are rotating downwards * We are rotating downwards
*/ */
if (value <= mesh.animationObject.targetAngle) { if (mesh.animationObject.intermediateAngle <= mesh.animationObject.targetAngle) {
/** /**
* We need to stop * We need to stop
*/ */
@ -81,69 +94,139 @@ GameLib.System.Animation.prototype.start = function() {
if (done) { if (done) {
/**
* We clamp to our target angle
*/
mesh.animationObject.intermediateAngle = mesh.animationObject.targetAngle;
/**
* We limit our intermediate angle between values of -pi and pi
*/
while (mesh.animationObject.intermediateAngle > Math.PI) {
mesh.animationObject.intermediateAngle -= (Math.PI * 2);
}
while (mesh.animationObject.intermediateAngle < -(Math.PI)) {
mesh.animationObject.intermediateAngle += (Math.PI * 2);
}
/**
* We apply our new intermediate angle to our target
*/
mesh.animationObject.targetAngle = mesh.animationObject.intermediateAngle;
}
/**
* Apply the actual rotation to the mesh
*/
mesh.updateInstanceRotationFromAxisAngle(mesh.quaternion.axis, mesh.animationObject.intermediateAngle);
/**
* Check again if we are done, we need to do some additional work -
*/
if (done) {
if (!mesh.animationObject.subscription) {
var message = 'mesh animation object subscription went missing for ';
message += mesh.name + ': ';
message += animation.name;
console.warn(message);
throw new Error(message);
}
/** /**
* Stop subscribing to before render events * Stop subscribing to before render events
*/ */
mesh.animationObject.subscription.remove(); mesh.animationObject.subscription.remove();
/** /**
*
* @type {null} * @type {null}
*/ */
mesh.animationObject.subscription = null; mesh.animationObject.subscription = null;
/** /**
* Start checking again for animation requests * For some meshes, when we are done with the animation, we want to apply
* the current state of the mesh to the object data itself (i.e. update
* its vertices etc)
*/ */
Object.defineProperty( if (animation.applyToMeshWhenDone) {
mesh.quaternion, /**
'angle', * Now we say that our intermediate angle is zero, because we will apply our rotation
{ * and this will prevent us from re-registering a new 'animationRender' event
'get' : getIntermediateAngle, */
'set' : animationCheck, mesh.animationObject.targetAngle = 0;
'configurable' : true mesh.animationObject.intermediateAngle = 0;
}
); /**
* Apply our position, rotation and scale to the mesh
*/
mesh.applyPositionRotationScale();
}
/** /**
* Set our target angle value * Tell our animation component that it is no longer in process...
* @type {boolean}
*/ */
mesh.animationObject.intermediateAngle = mesh.animationObject.targetAngle; mesh.animationObject.inProcess = false;
/** // if (mesh.animationObject.callbacks.length > 0) {
* Update our actual angle // var callback = mesh.animationObject.callbacks[0];
*/ // mesh.animationObject.callbacks.splice(0,1);
mesh.quaternion.angle = mesh.animationObject.targetAngle; // callback();
// }
/** mesh.animationObject.storedValues = [];
* Update our instance
*/
mesh.updateInstance();
/**
* Now we say that our intermediate angle is zero, because we will apply our rotation
* and this will prevent us from re-registering a new 'animationRender' event
*/
mesh.animationObject.intermediateAngle = 0;
/**
* Apply our position, rotation and scale to the mesh
*/
mesh.applyPositionRotationScale();
} }
}; };
var animationCheck = function(value) { var setTargetAngle = function(value) {
/** /**
* Check if we have work to do * Check if we have work to do
*/ */
if (mesh.animationObject.intermediateAngle === value) { if (mesh.animationObject.intermediateAngle === value) {
mesh.animationObject.inProcess = false;
/** /**
* Nothing to do * Nothing to do
*/ */
return; return;
} else if (mesh.animationObject.intermediateAngle > value) { }
/**
* Check if we have another animation in process
*/
if (mesh.animationObject.inProcess && mesh.animationObject.blocking) {
console.log('another animation is already in process');
GameLib.Utils.PushUnique(mesh.animationObject.storedValues, value);
// mesh.animationObject.callbacks.push(
// function(__value) {
// return function(){
// mesh.quaternion.angle = __value;
// }
// }(value)
// );
/**
* Respond that our angle is actually our target angle (it will be that soon)
*/
return;
}
/**
* We indicate that we now have an animation in process
* @type {boolean}
*/
mesh.animationObject.inProcess = true;
/**
* Ok - all good - lets start the animation
*/
if (mesh.animationObject.intermediateAngle > value) {
/** /**
* We will rotate towards by decrementing * We will rotate towards by decrementing
*/ */
@ -161,19 +244,6 @@ GameLib.System.Animation.prototype.start = function() {
*/ */
mesh.animationObject.targetAngle = value; mesh.animationObject.targetAngle = value;
/**
* Now override the setter again
*/
Object.defineProperty(
mesh.quaternion,
'angle',
{
'get' : getIntermediateAngle,
'set' : animateRotation,
'configurable' : true
}
);
/** /**
* Now we subscribe to 'before render' events, and slowly increment the value * Now we subscribe to 'before render' events, and slowly increment the value
* @type {{fn, remove}} * @type {{fn, remove}}
@ -184,17 +254,11 @@ GameLib.System.Animation.prototype.start = function() {
var increment = Math.abs(animation.rotationSpeed); var increment = Math.abs(animation.rotationSpeed);
if (mesh.angleIncrement) { if (!mesh.animationObject.angleIncrement) {
increment *= -1; increment *= -1;
} }
mesh.quaternion.angle = (data.delta * increment) + mesh.animationObject.intermediateAngle; animateRotation(data.delta * increment);
var backup = mesh.updateRotationFromAxisAngle;
mesh.updateRotationFromAxisAngle = true;
mesh.updateInstance();
mesh.updateRotationFromAxisAngle = backup;
} }
); );
}; };
@ -208,8 +272,8 @@ GameLib.System.Animation.prototype.start = function() {
mesh.quaternion, mesh.quaternion,
'angle', 'angle',
{ {
'get' : getIntermediateAngle, 'get' : getTargetAngle,
'set' : animationCheck, 'set' : setTargetAngle,
'configurable' : true 'configurable' : true
} }
); );