【问题标题】:Animating planet orbiting it's parent idependent on parent's rotation state动画行星环绕其父级取决于父级旋转状态
【发布时间】:2015-06-26 23:06:36
【问题描述】:

我正在尝试学习 Three.js,对这些技术很陌生。我实现了一个行星绕着太阳运行,月亮绕着行星运行。我所关心的是,要做我目前所做的事情,我必须制作相当多的对象并在渲染循环期间执行相当多的计算。

1。源代码:

WestLangley 为我们提供了以更易于理解的方式呈现问题的小提琴:

  • this fiddle 呈现的更像是它现在的样子——行星在太阳内部有它的父级,旋转该父级将形成行星轨道。但是除了每个行星/月亮一个额外的物体外,还有一个问题是父旋转也会将行星旋转到位,在 updateMatrixWorld Object3D 方法期间。因此,它会比您通过查看mesh2.rotateOnAxis( AXIS, 0.01 ); bit 所想象的要快一些。
  • this fiddle 展示了一种无父方法。案例是,我正在尝试找到方法,我可以在系统启动时配置行星位置/旋转速度/轨道速度,而不仅仅是提供服务器时间,因此它会让处于同一位置的玩家之间感觉同步.

3。问题本身

就我浏览手册而言,我发现有可能使用 Three.js 矩阵逻辑来执行此类动画。我愿意尽可能减少对象内部::animate() 的使用(可能通过覆盖updateMatrixupdateMatrixWorld 方法)。不幸的是,我的英语和数学都不足以理解,这些矩阵发生了什么。如果有人可以帮助我,我将不胜感激。

4。目前工作进展

工作小提琴是here。我能够创造一个星球并拥有几乎所有我想要的东西。剩下的一个问题是,a 想以更随机的角度绕行星轨道。

【问题讨论】:

  • This fiddle 展示了three.js 的使用方式。有关一些数学资源,请参阅 this post
  • @WestLangley 这看起来和我现在的完全一样。问题是,随着网格 2 位置的变化,枢轴的旋转会改变其局部旋转,从而导致 updateWorldMatrix 我愿意单独控制其旋转速度并避免使用空的 Object3D 元素作为父元素。至少有可能吗?
  • 这就是你的意思——没有枢轴吗? jsfiddle.net/t83pzoj2/4
  • @WestLangley 看起来像我愿意实现的方式工作,但我想知道用这种方法在某个位置绕行星旋转月球。如果您能够简单地管理它,我可以接受它作为答案:)
  • 只有 15 分钟。我希望你能自己弄清楚并回答你自己的问题。 : - )

标签: javascript matrix three.js matrix-transform


【解决方案1】:

分叉了这一点。我愿意减少太阳系中的物体数量,隐藏动画循环中的计算并使其尽可能可配置。

为此,我实现了自定义Mesh,称为Planet

var Planet =  function ( geometry, material ) {
    THREE.Mesh.call( this, geometry, material );
    this.type = 'Planet';
};
Planet.prototype = Object.create( THREE.Mesh.prototype );

并覆盖标准Object3D 矩阵计算函数:

Planet.prototype._matrixUpdate = THREE.Object3D.prototype.updateMatrix;
Planet.prototype._updateMatrixWorld = THREE.Object3D.prototype.updateMatrixWorld;
Planet.prototype.updateMatrix = function() {};
Planet.prototype.updateMatrixWorld = function() {};

多亏了它,我可以在运行每个渲染调用的标准方法中重新计算在该基础上创建的行星/卫星的位置和旋转。

为了一个好的开始,我在 Planet 构造函数中创建了一些我需要的基本参数:

    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

这些应该可以在创建时进行配置,但现在硬编码是可以的。

比起进入新的updateMatrix(),来计算当前行星相对于其父级的位置:

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
};

最后但并非最不重要的一点 - 通过 updateMatrixWorld 实现向 Object3D.worldMatrix 提供这些更改:

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.

工作代码在this fiddle。通过这种方式,我减少了渲染循环期间的数学时间,减少了嵌套代码,最后:减少了高达 50% 的对象计数。但我对这个答案不是 100% 有信心,因此我们感谢任何进一步的优化。

【讨论】:

  • 感谢您的提琴。帮了大忙。
猜你喜欢
  • 2021-12-16
  • 2020-12-23
  • 1970-01-01
  • 2019-02-03
  • 2012-01-31
  • 1970-01-01
  • 1970-01-01
  • 2016-11-18
  • 1970-01-01
相关资源
最近更新 更多