大约一个小时前,我经历了一个美好而令人尴尬的时刻,在很长一段时间后,一些东西发出咔嚓声。快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;
...
}..。其中的调制,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;
};在学习和/或记忆的同时,当我重温这段代码时,我意识到:这是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;
};到目前为止还很开心!使用数学--数学是为了什么!但后来我检查了表演。而我自己的“实现”在FF、Chrome和IE中要快得多。使用1.000.000次迭代,在我的本地设置中它的增益在35%到45%之间。
有人知道为什么吗?它只是Math.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;
};
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;
};
var iterations = 1000000;
console.time('setModulation');
for(var i = 0; i < iterations; i++ ){
setModulation(i, i / 2);
};
console.timeEnd('setModulation')
console.time('setModulationMath');
for(var i = 0; i < iterations; i++ ){
setModulationMath(i, i / 2);
};
console.timeEnd('setModulationMath')
发布于 2016-06-13 10:53:38
你的功能可能会更快。但是,这种比较没有任何意义,因为函数产生的结果完全不同。让我们对错误进行基准测试:
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);
}和…
err_z == 49.17730025861921
err_x == 113.58865012930961那太糟了。如果两者是完全相似的,您将期望值接近于0。
虽然我的第一个假设是,我一定是以某种方式伪造了它:它是完美的。这两个函数给出相同的调制值。话虽如此:我很高兴被告知这是一次黑客攻击,只因为x.:)
证明,z轴上的平均误差为0.137,x轴上为0.316。这可能对您来说已经足够好了,但是肯定有一些值的差异更大。你可能只是检查正交方向吗?在这种情况下,您需要的是一个switch,而不是三角学。
编辑:哦,这是z部分的图表。曲线是余弦,直线是你的近似值。

但我离题了。
(尝试)滚动您自己实现的trig函数、数学函数等并不一定是坏事。它确实取决于应用程序的具体情况,有时您会发现您不需要这样的精度,或者您的角度只表示为整数度…。在这些情况下,使用更简单的近似或查找表可能是有益的。
实际上,Javascript (和许多其他标准库)中的正弦和余弦是非常优化和非常精确的。
发布于 2016-06-13 11:03:47
由于许多原因,数学运算比较昂贵,但主要是因为它们处理一般情况和边缘情况,而不像简单的乘法和加法运算。
此外,对象查找和函数调用非常昂贵,因此缓存PI始终是一条经验法则。我将setModulationMath操作更改为以下操作。我使用的是performance.now()而不是timeEnd,因为它更准确。在这里阅读更多信息:https://developer.mozilla.org/en-US/docs/Web/API/Performance/now
我的研究结果:
var PI180 = Math.PI/180;
function setModulationMath(rotation) {
var rotationC = rotation * PI180;
return {
z: Math.cos(rotationC),
x: Math.sin(rotationC)
};
};
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;
};
var iterations = 1000000;
var t0 = performance.now();
for (var i = 0; i < iterations; i++){
setModulation(i);
}
var t1=performance.now();
console.log("setModulation: "+(t1-t0)+"ms");
var t2 = performance.now();
for (var l = 0; l < iterations; l++){
setModulationMath(l);
}
var t3=performance.now();
console.log("setModulationMath: "+(t3-t2)+"ms");
https://stackoverflow.com/questions/37787302
复制相似问题