【问题标题】:Grid-based lighting engine基于网格的光照引擎
【发布时间】:2013-06-02 01:18:29
【问题描述】:

我正在尝试使用 JavaScript 创建一个基于网格的阴影引擎。我的算法根据相对于光源的位置是否在块“后面”来对正方形进行着色。

这是我目前的算法:https://jsfiddle.net/jexqpfLf/

var canvas = document.createElement('canvas');
canvas.width = 600;
canvas.height = 400;
document.body.appendChild(canvas);
var ctx = canvas.getContext('2d');

var light_x = 90;
var light_y = 110;

var block_x = 120;
var block_y = 120;

requestAnimationFrame(render);
function render() {
    ctx.fillStyle = 'white';
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    var vec1_x = block_x - light_x;
    var vec1_y = block_y - light_y;
    var vec1_mag = Math.sqrt(vec1_x * vec1_x + vec1_y * vec1_y);

    ctx.fillStyle = 'black';
    for (var x = 0; x < canvas.width; x += 10)
        for (var y = 0; y < canvas.width; y += 10) {
            var vec2_x = x - light_x;
            var vec2_y = y - light_y;
            var vec2_mag = Math.sqrt(vec2_x * vec2_x + vec2_y * vec2_y);
            var dotproduct = vec1_x * vec2_x + vec1_y * vec2_y;

            var angle = Math.acos(dotproduct / (vec1_mag * vec2_mag));

            if (vec2_mag > vec1_mag && angle < Math.PI / 8 / vec1_mag * 10)
                ctx.fillRect(x, y, 10, 10);
        }

    ctx.fillStyle = 'green';
    ctx.fillRect(light_x, light_y, 10, 10);

    ctx.fillStyle = 'red';
    ctx.fillRect(block_x, block_y, 10, 10);

    requestAnimationFrame(render);
}

onkeydown = function (e) {
    if (e.which == 65)
        light_x -= 10;
    if (e.which == 68)
        light_x += 10;
    if (e.which == 87)
        light_y -= 10;
    if (e.which == 83)
        light_y += 10;
}

不幸的是,正如您在演示中看到的那样,我发现某些角度存在问题。一些应该加阴影的方块没有加阴影。这发生在某些角度和距离(在光源和块之间),但不是其他的。例如,将光源放置在 (60, 90) 也会显示这些伪影。

我使用向量 LP(从光到点)和 LB(从光到块),取它们的点积并除以它们的大小的乘积来找到阴影角度,然后根据距离缩放这个角度在块和光源之间。

这些伪影可能是由于舍入错误造成的吗?还是算法本身有问题?任何帮助将不胜感激:-)

【问题讨论】:

    标签: javascript canvas graphics shadow lighting


    【解决方案1】:

    很好的问题。你不会喜欢这个的。

    这是一个浮点数学问题。

    Math.acos(1.000000000000000) 的值是多少?

    0.

    Math.acos(1.0000000000000003) 的值是多少?

    NaN.

    这很烦人,不是吗?

    在某些值下,您的dotproduct6000,而您的(vec1_mag * vec2_mag)5999.999999999999,导致上述问题。

    (vec1_mag * vec2_mag) 更改为Math.round(vec1_mag * vec2_mag) 将解决您的问题。

    当我们一起盯着这个小提琴时你应该知道还有另一个错误:

    for (var x = 0; x < canvas.width; x += 10) {
        for (var y = 0; y < canvas.width; y += 10) {
    

    你在这里使用了两次canvas.width。我想第二个应该是canvas.height,所以请确保您在那里写的内容是您想要的。

    Working fiddle for you!

    【讨论】:

    • 非常感谢!这解决了问题(实际上是两个)。当参数超出范围时,数学函数似乎没有发出警告。那将使调试变得容易得多。过去,舍入错误让我很头疼!
    猜你喜欢
    • 1970-01-01
    • 2022-01-05
    • 1970-01-01
    • 1970-01-01
    • 2011-01-27
    • 1970-01-01
    • 1970-01-01
    • 2010-12-17
    • 1970-01-01
    相关资源
    最近更新 更多