2D освещение с шейдерами - радиус света зависит от размера окна

У меня есть шейдер, который добавляет освещение в 2D-сцену (источники света немного выше 2D-плоскости). В моем фрагментном шейдере я зацикливаюсь на каждом источнике света, чтобы вычислить направление и расстояние, применяя мою орто-матрицу к положению источника света.

Проблема в том, что "радиус" света зависит от размера и соотношения сторон моего окна. Я думал, что перевод координат с использованием орто-матрицы гарантирует, что размер экрана не будет иметь значения, но широкое окно создает овальный свет, а меньшие окна создают меньшие овалы, чем большие. Должен ли я использовать другую матрицу какого-то рода?

Полный шейдер здесь (измените размер окна, чтобы увидеть нежелательный эффект): http://glsl.heroku.com/e

uniform vec2 resolution;

void main(void)
{
    //orthographic matrix
    mat4 ortho_matrix = mat4(
        2.0/resolution.x, 0, 0, 0,
        0, 2.0/-resolution.y, 0, 0,
        0, 0, -1, 0,
        -1, 1, 0, 1
        );

    //surface normal of the 2D plane (looking straight down)
    vec3 surface_normal = vec3(0.0, 0.0, 1.0);

    //screen position of the light
    vec2 light_screen_pos = vec2(650, 150);

    //translate light's position to normalized coordinates
    //the z value makes sure it is slightly above the 2D plane
    vec4 light_ortho_pos = ortho_matrix * vec4(light_screen_pos, -0.03, 1.0);

    //calculate the light for this fragment
    vec3 light_direction = light_ortho_pos.xyz - vec3(gl_FragCoord.x / resolution.x, gl_FragCoord.y / resolution.y, 0);
    float dist = length(light_direction);
    light_direction = normalize(light_direction);
    vec3 light = clamp(dot(surface_normal, light_direction), 0.0, 1.0) * vec3(0.5, 0.5, 0.5);
    vec3 cel_light = step(0.15, (light.r + light.g + light.b) / 3.0) * light;

    gl_FragColor = vec4(pow(light + cel_light, vec3(0.4545)), 1.0);
}

Примечание: я знаю, что это не оптимально, чтобы сделать этот расчет для каждого источника света, каждого пикселя - я должен был бы передать положение источника света в другой униформе, вероятно.

1 ответ

Решение

Направление света необходимо масштабировать в соответствии с разрешением экрана. В итоге я добавил следующий код, чтобы он работал, с произвольной яркостью 500 или около того:

light_direction *= vec3(resolution.x / brightness, resolution.y / brightness, 1.0);
Другие вопросы по тегам