因此,大约一个小时前,我经历了一段令人愉快而尴尬的时刻,即经过很长一段时间之后,有些声音突然响起。推到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;

...
}


...,其中modulation.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;
};




同时学习和/或记住了一点,在重新阅读此代码后,它突然出现在我身上:这是因果关系和罪过的工作。不好意思

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')

最佳答案

您的功能可能会更快。但是,比较没有任何意义,因为函数产生的结果完全不同。让我们以错误为基准:

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] ...::)的hack。


在z轴上的平均误差可证明是0.137,在x轴上的平均误差是0.316。这对您可能已经足够好了,但是肯定会有一些差异较大的值。您是否仅检查正交方向?在这种情况下,您需要的是switch,而不是三角函数。

编辑:哦,这是z部分的图形。波浪线是余弦,直线是您的近似值。

javascript - Math.sin().cos()与笨拙的自己实现的成本-LMLPHP

但是我离题了。

(尝试)推出自己的触发函数,数学函数等的实现并不一定很糟糕。它确实取决于应用程序的具体情况,有时您会发现不需要这种精度或角度只能表示为整数度数。在这种情况下,使用更简单的近似表或查找表可能会有所帮助。

实际上,JavaScript(以及许多其他标准库)中的正弦和余弦都经过了很好的优化和非常精确的设计。

09-30 13:54
查看更多