问题
I'm trying to learn Three.js, beeing new to those technologies. I achieved a sun with planet orbitting around, with moon orbitting around planet. What am I concerned of, is to do what i have so far i have to make quite a lot of objects and perform quite a lot of calculations during rendering loops.
1. Sourcecodes:
WestLangley provided us with fiddles presenting problem in more easy-to-understand way so:
- this fiddle presents more like it is looking right now - planet has its parent inside sun, and rotating that parent will make planet orbit. But along with one extra object per planet/moon, theres an issue that parent rotation spins planet in place too, during to
updateMatrixWorld
Object3D method. So it will spin a bit faster than you may assume by looking atmesh2.rotateOnAxis( AXIS, 0.01 );
bit. - this fiddle shows one parent-less approach. Case is, I'm trying to find way, where I can configure planet positions/spins-speed/orbit-speed at system start and than just feed it with server time, so it will make it feel synchronised between players being at same location.
3. Question itself
As far as I travelled through manuals, I found there may be a possibility of performing such animation using Three.js matrix logic. I'm willing to reduce usage of ::animate()
inside objects as far as possible (maybe by overriding updateMatrix
and updateMatrixWorld
methods). Unfortunately my english nor math are not good enough to understand, whats going around with those matrixes. If somebody can help me, I would really appreciate this.
4. Current work progress
Working fiddle is here. I was able to create a Planet and have almost all I want. One left issue is that, a would like to planet orbit at more random-looking degrees.
回答1:
Forked this bit around. I was willing to reduce object count in my solar system, hide calculations from animation loop nad make it as configurable as possible.
To make this I implemented custom Mesh
called Planet
:
var Planet = function ( geometry, material ) {
THREE.Mesh.call( this, geometry, material );
this.type = 'Planet';
};
Planet.prototype = Object.create( THREE.Mesh.prototype );
and overriden standard Object3D
matrix-calculation functions:
Planet.prototype._matrixUpdate = THREE.Object3D.prototype.updateMatrix;
Planet.prototype._updateMatrixWorld = THREE.Object3D.prototype.updateMatrixWorld;
Planet.prototype.updateMatrix = function() {};
Planet.prototype.updateMatrixWorld = function() {};
Thanks to that I can recalculate positions and rotations of planets/moons created on that base inside standard methods been running every render call.
For good start I've prototyped in Planet constructor some basic arguments I will need:
this.rotationAxis = new THREE.Vector3( 0, 1, 0 ).normalize(); // always rotate on Y
this.rotationSpeed = Math.PI/2; // length of planet day
this.orbitAxis = new THREE.Vector3( 0, 0.1, 1 ).normalize(); // y,z for orbit AXIS
this.orbitSpeed = Math.PI / 8; // length of planet year
those should be configurable on creation time, but for now hardcode is ok.
Than going into new updateMatrix()
, to calculate current planet position in relation of it's parent:
Planet.prototype.updateMatrix = function() {
var dta = delta || 0; // THREE.Clock::getDelta
// just for now, sun is not orbiting around
// anything, so checking instance
if ( this.parent instanceof Planet ) {
// rotate position in relation to parent, to make planet orbit
this.position.applyAxisAngle(this.orbitAxis, this.orbitSpeed * dta);
}
// rotate planet in place, to make it spin
this.rotateOnAxis(this.rotationAxis, this.rotationSpeed * dta);
this._matrixUpdate(); // fabricating Object3D.matrix
};
And last, but not least - providing those changes to Object3D.worldMatrix
via updateMatrixWorld
implementation:
Planet.prototype.updateMatrixWorld = function() {
if ( this.matrixAutoUpdate === true ) this.updateMatrix();
if ( this.matrixWorldNeedsUpdate === true || force === true ) {
if ( this.parent === undefined ) {
this.matrixWorld.copy( this.matrix );
} else {
// THIS else block is all whats different
// between Planet and standard Object3Dmethod
v = new THREE.Vector3(); // empty vector
v.applyMatrix4(this.parent.matrixWorld); // setup with parent position
v.add(this.position); // add local position
// compose instead of multiplication
this.matrixWorld.compose(v, this.quaternion, this.scale);
}
// ... rest like in THREE's (71) git.
Working code is in this fiddle. This way I have reduced math-time during render loop, reduced nested code and finally: reduced objects count by up to 50%. But I'm am not 100% confident about that answer, so any further optimisations are appreciated.
来源:https://stackoverflow.com/questions/29744233/animating-planet-orbiting-its-parent-idependent-on-parents-rotation-state