Jon*_*ter 1 javascript performance trigonometry game-engine
所以大约一个小时前,我经历了一个美好而尴尬的时刻,在很长一段时间后点击了一些东西。推动 30 我终于得到了窦和余弦。在一个只能被描述为基本上重新实现轮子的插曲之后。
为了让 WASD 控件在两个轴上移动,考虑到玩家的视线方向,我决定使用一个简单的开关:
switch (key) {
case 'up':
movement.z -= 1 * modulation.z;
movement.x += 1 * modulation.x;
break;
case 'down':
movement.z += 1 * modulation.z;
movement.x -= 1 * modulation.x;
break;
case 'left':
movement.x -= 1 * modulation.z;
movement.z -= 1 * modulation.x;
break;
case 'right':
movement.x += 1 * modulation.z;
movement.z += 1 * modulation.x;
break;
...
}
Run Code Online (Sandbox Code Playgroud)
...其中调制.z 和.x 将基于玩家面对的方向。调制值需要在 -1 到 +1 的范围内。(这应该是我的第一个线索,是的!)所以我帮自己拿了一些可靠的笔和纸,并且对我 9 年级的教育一无所知,我想出了:
function setModulation(rotation) {
var rotationTemp = 0;
var modulation = {};
rotationTemp = rotation;
if (rotationTemp > 180) {
rotationTemp = 360 - rotationTemp;
}
rotationTemp /= 180;
modulation.z = 1 - rotationTemp * 2;
rotationTemp = rotation + 90;
if (rotationTemp > 180) {
rotationTemp = 360 - rotationTemp;
}
rotationTemp /= 180;
modulation.x = 1 - rotationTemp * 2;
modulation.x *= -1;
return modulation;
};
Run Code Online (Sandbox Code Playgroud)
在此期间学习和/或记住了一点,在重新审视这段代码时,我突然明白了:这是 cos 和 sin 的工作。亲爱的。
function setModulationMath(rotation) {
var modulation = {};
modulation.z = Math.cos(rotation * Math.PI / 180);
modulation.x = Math.sin(rotation * Math.PI / 180);
return modulation;
};
Run Code Online (Sandbox Code Playgroud)
到目前为止很开心!使用数学数学是什么!但后来我检查了性能。我自己的“实现”在 FF、Chrome 和 IE 中要快得多。使用 1.000.000 次迭代,它在我本地设置上的增益介于 35% 到 45% 之间。
任何人都知道为什么?它只是 Math.cos() / .sin() 吗?可衡量的增长超出了人们的预期,不是吗?任何有经验的人愿意分享她*他的见解?
switch (key) {
case 'up':
movement.z -= 1 * modulation.z;
movement.x += 1 * modulation.x;
break;
case 'down':
movement.z += 1 * modulation.z;
movement.x -= 1 * modulation.x;
break;
case 'left':
movement.x -= 1 * modulation.z;
movement.z -= 1 * modulation.x;
break;
case 'right':
movement.x += 1 * modulation.z;
movement.z += 1 * modulation.x;
break;
...
}
Run Code Online (Sandbox Code Playgroud)
您的功能很可能会更快。然而,这种比较没有任何意义,因为这些函数会产生完全不同的结果。让我们来看看错误的基准:
var err_z = 0;
var err_x = 0;
for (var i = 0; i < 360; ++i){
var mm = setModulationMath(i);
var m = setModulation(i);
err_z += Math.abs(mm.z - m.z);
err_x += Math.abs(mm.x - m.x);
}
Run Code Online (Sandbox Code Playgroud)
和 …
err_z == 49.17730025861921
err_x == 113.58865012930961
Run Code Online (Sandbox Code Playgroud)
这很糟糕。如果两者完全相似,您会期望值接近 0。
虽然我的第一个假设是我必须以某种方式伪造我的方式:它完美地工作。两个函数给出相同的调制值。这就是说:我很高兴被告知这是一个 hack 只因为 [x]... :)
可以证明,z 轴上的平均误差为 0.137,x 轴上的平均误差为 0.316。这对您来说可能已经足够了,但肯定存在差异更大的值。您可能只检查正交方向吗?在这种情况下,您需要的是switch,而不是三角函数。
编辑:哦,这是 z 部分的图表。波浪线是余弦,直线是您的近似值。
但我离题了。
(尝试)自己实现三角函数、数学函数等不一定是坏事。这真的取决于应用程序的具体情况,有时你会发现你不需要这样的精度,或者你的角度将仅表示为整数度数……在这些情况下,使用更简单的近似值或查找表可能会有所帮助。
事实上,Javascript(以及许多其他标准库)中的正弦和余弦经过很好的优化和非常精确。