Three.JS 的单位,计算旋转和轨道速度

Posted

技术标签:

【中文标题】Three.JS 的单位,计算旋转和轨道速度【英文标题】:Units of Three.JS, Calculating Rotation & Orbit Speeds 【发布时间】:2012-07-06 23:16:15 【问题描述】:

我正在尝试建立一个按比例绘制的太阳系模型。我想看看是否有人可以向我解释旋转速度是如何工作的。这是重要的部分:

objects[index].rotation.y += calculateRotationSpeed(value.radius,value.revolution) * delta;

旋转速度与实际时间有何关系?因此,如果您的速度为 1,那是每毫秒 1 px 的移动吗?或者如果你的速度是 0.1,那是不是每秒不到 1 个像素?

基本上,我正在尝试根据行星的半径和一天中的小时数计算正确的旋转速度。因此,如果您在地球上,它将在 24 小时内完成 1 次旋转。这是我写的现在进行计算的函数:

/* In a day */
function calculateRotationSpeed(radius,hrs,delta) 
    var cir = findCircumference(radius);
    if(delta) 
        var d = delta;
     else 
        var d = 1;
    
    var ms = hrs2ms(hrs) * d;
    var pxPerMS = km2px(cir) / ms;
    return pxPerMS;

我试了一下,它似乎仍然移动得太快。我还需要类似的东西来计算轨道速度。

【问题讨论】:

【参考方案1】:

旋转和单位

Three.JS 中的旋转以 弧度 为单位。对于那些完全不熟悉弧度的人(我的一篇旧论文的一小段摘录):

与数学常数Pi 一样,radian(大约 57.3 度)源自圆的半径(或直径)与其周长之间的关系。一个弧度是 角,它总是跨越一个圆的圆周上的弧,该圆的长度等于同一个圆的半径(对于任何圆都是如此,无论大小如何)。类似地,Pi 是周长与直径的比值,因此单位圆的周长正好是 Pi。弧度和度数实际上不是真正的单位,实际上角度通常是无量纲的(如百分比和分数,我们不使用实际单位来描述它们)。

但是,与度数不同,弧度不是任意定义的,因此在大多数情况下它是更自然的选择;通常比在数学公式中使用度数更容易、更优雅、更清晰、更简洁。巴比伦人可能给了我们度数,将他们的圆分成 6 个相等的部分(使用等边三角形的角度)。考虑到它们的sexagesimal(以 60 为基数)数字系统,这 6 个部分中的每一个都可能进一步细分为 60 个相等的部分。这也将允许他们将这样的系统用于天文学,因为在他们的时间里,一年中估计的天数要低得多,通常被认为是 360 天。

Three.JS 中的基本旋转

所以现在,如果您在 anim 函数中使用以下语句中的 first once 递增(回调到 @987654327 @),您将在 x 轴上将 mesh 的旋转增加一个弧度

mesh.rotation.x += 1;                      // Rotates   1 radian  per frame
mesh.rotation.x += Math.PI / 180;          // Rotates   1 degree  per frame
mesh.rotation.x += 45 * Math.PI / 180      // Rotates  45 degrees per frame

正如上面两个语句中的最后一个所示,如果我们希望使用度数来代替,我们可以在赋值之前使用Math.PI / 180 轻松地将度数转换为弧度。

考虑帧率

在您的情况下,您需要考虑每帧经过多少时间。这是你的delta。你必须这样想:我们以多少 FPS 运行?我们将声明一个全局clock 变量,该变量将存储一个THREE.Clock 对象,该对象具有我们所需信息的接口。我们需要一个全局变量,我们将调用clock(需要在其他函数中可访问,特别是anim):

init内,创建THREE.Clock的实例;将其存储在init 之外声明的变量中(范围更大):

clock = new THREE.Clock();

然后,在您的 anim 函数中,您将进行两次调用,以更新与 clock 关联的两个变量:

time(自实例化时钟以来经过的总时间,以毫秒为单位) delta(每帧之间的时间以毫秒为单位)在另外两个全局变量中: 时间 = 时钟.getElapsedTime(); delta = clock.getDelta();

注意delta意味着返回每帧之间的时间量;但是,如果且clock.getDeltaanim/render 中始终被调用时,这将是正确的

    每个动画/渲染周期一次 每个动画循环都在同一个地方(开始或结束,据我所知,哪个无关紧要)

上述条件是THREE.Clock 实现的结果。 getDelta 最初返回自时钟实例化以来的时间量,之后它返回的时间只是自上次调用以来的时间)。如果它以某种方式被错误地或不一致地调用,它将会把事情搞砸。

以增量因子旋转

现在,如果您的场景没有使处理器或 GPU 陷入困境,Three.JS 和它所包含的 requestAnimationFrame shim 将尝试(使用可用资源)以保持每秒 60 帧的平稳运行。这意味着理想情况下,每帧之间大约有1/60 = .016666 秒,这是您的delta 值,您可以从每帧clock 中读取该值,并使用它通过乘以基于帧速率来标准化您的速度,如下所示。通过这种方式,您可以获得以秒为单位的值,而不管帧速率的微小变化,您可以每次相乘以获得以秒为单位的值。

因此,根据我们一开始在您的 anim 函数中的内容,您可以像这样使用它:

mesh.rotation.x += delta * 1;                     // Rotates  1 radian  per second
mesh.rotation.x += delta * Math.PI / 180;         // Rotates  1 degree  per second
mesh.rotation.x += delta * 45 * Math.PI / 180;    // Rotates 45 degrees per second

转速和单位

因为我们对角度、弧度和度数的测量实际上并不是单位,所以当我们查看角速度的单位时,我们会发现它仅在 时间(而不是作为距离和时间的函数,就像您在代码中一样)。

根据时间计算转速

对于您的具体情况,您不需要半径来计算旋转速度(角速度),而是可以使用一天中的小时数(一整圈所需的时间,即. 2 * Math.PI 弧度 在它的轴上旋转)。如果你有一个名为revolutionTime 的变量,那么你可以这样计算它。

secondsInAnHour = 3600;
rotationalSpeed = (2 * Math.PI) / revolutionTime;

如果你假设地球一天有24 hours = 24 * 60 * 60 = 86,400(它没有)。然后我们将得到rotationalSpeed = 2 * PI / 86,400,或大致为0.0000727每秒弧度。您应该能够找到可能比这更准确的教科书值(考虑到比我们的 24 小时平面数字更准确的测量值,即地球完成一圈所需的时间。

特别考虑您的情况

但是,我不会担心确保行星的所有角速度都完全正确。相反,一个更好的主意是计算出(行星的)每个角速度之间的比率并使用它。这将更好地工作有几个原因:您可能想要更快的转速,这将允许您使用任何运行良好的转速;重要的是,与任何模型(尤其是在涉及天文模型时)一样,您要保持它的比例。

【讨论】:

太棒了,说得通。从来不擅长数学,所以我将如何根据半径和完成 1 圈所需的时间来计算每帧的速度或弧度? 查看我的编辑,我添加了很多东西。但就像我最后说的那样,我不会根据一天中的小时数来使用行星的实际速度。相反,将它们相互比较,并确保它们之间的比率保持不变。此外,我会先让所有东西都保持静止,然后在你尝试制作任何轨道之前,只处理它们各自的旋转。 完美!正是我需要的。非常感谢,如果您想尝试一下(请参阅 cmets),那就太棒了! link "请注意,delta 旨在返回每帧之间的时间量;但是,当且仅当在 anim/render 中始终调用 clock.getDelta 时,这才是正确的" 我想知道为什么getDelta() 在我的情况下返回垃圾......太糟糕了,我需要从 *** 学习一些应该在官方文档中作为粗体字体的东西。 这一定是我在 Stack Overflow 上见过的最好的答案之一

以上是关于Three.JS 的单位,计算旋转和轨道速度的主要内容,如果未能解决你的问题,请参考以下文章

使用vue学习three.js之移动相机-使用轨道控件OrbitControls控制相机

Three.js - 计算相对旋转

THREE.js:计算物体上一点的世界空间位置

THREE.js:如何计算有多少个屏幕像素代表1个世界坐标单位

如何在three.js的3空间中绘制扁平形状?

Three.js不同模型在不同轨道上的动画和移动