Шейдер отображения теней

У меня есть шейдер, который реализует отображение теней следующим образом:

#version 430 core

out vec4 color;

in VS_OUT {
    vec3 N;
    vec3 L;
    vec3 V;
    vec4 shadow_coord;
} fs_in;

layout(binding = 0) uniform sampler2DShadow shadow_tex;

uniform vec3 light_ambient_albedo = vec3(1.0);
uniform vec3 light_diffuse_albedo = vec3(1.0);
uniform vec3 light_specular_albedo = vec3(1.0);

uniform vec3 ambient_albedo = vec3(0.1, 0.1, 0.2);
uniform vec3 diffuse_albedo = vec3(0.4, 0.4, 0.8);
uniform vec3 specular_albedo = vec3(0.0, 0.0, 0.0);
uniform float specular_power = 128.0;

void main(void) {
    //color = vec4(0.4, 0.4, 0.8, 1.0);

    //normalize
    vec3 N = normalize(fs_in.N);
    vec3 L = normalize(fs_in.L);
    vec3 V = normalize(fs_in.V);

    //calculate R
    vec3 R = reflect(-L, N);

    //calcualte ambient
    vec3 ambient = ambient_albedo * light_ambient_albedo;

    //calculate diffuse
    vec3 diffuse = max(dot(N, L), 0.0) * diffuse_albedo * light_diffuse_albedo;

    //calcualte spcular
    vec3 specular = pow(max(dot(R, V), 0.0), specular_power) * specular_albedo * light_specular_albedo;

    //write color
    color = textureProj(shadow_tex, fs_in.shadow_coord) * vec4(ambient + diffuse + specular, 0.5);
    //if in shadow, then multiply color by 0.5 ^^, except alpha
}

Что я хочу сделать, так это сначала проверить, действительно ли фрагмент находится в тени, и только затем изменить цвет (уменьшить его вдвое, чтобы он стал на полпути между полностью черным и исходным цветом).

Однако как проверить, действительно ли результат textureProj(...) находится в тени, насколько мне известно, он возвращает нормализованное значение float.

Будет ли уже достаточно textureProj(...) > 0.9999? Я знаю, что он может возвращать значения, отличные от нуля или единицы, если вы используете множественную выборку, и мне бы хотелось, чтобы поведение не прерывалось в какой-то момент.

Выходной вершинный шейдер:

#version 430 core

layout(location = 0) in vec4 position;

layout(location = 0) uniform mat4 model_matrix;
layout(location = 1) uniform mat4 view_matrix;
layout(location = 2) uniform mat4 proj_matrix;
layout(location = 3) uniform mat4 shadow_matrix;

out VS_OUT {
    vec3 N;
    vec3 L;
    vec3 V;
    vec4 shadow_coord;
} vs_out;

uniform vec4 light_pos = vec4(-20.0, 7.5, -20.0, 1.0);

void main(void) {
    vec4 local_light_pos = view_matrix * light_pos;
    vec4 p = view_matrix * model_matrix * position;

    //normal
    vs_out.N = vec3(0.0, 1.0, 0.0);

    //light vector
    vs_out.L = local_light_pos.xyz - p.xyz;

    //view vector
    vs_out.V = -p.xyz;

    //light space coordinates
    vs_out.shadow_coord = shadow_matrix * position;

    gl_Position = proj_matrix * p;
}

Обратите внимание, что фрагментный шейдер предназначен для ландшафта, а вершинный шейдер — для пола, поэтому между ними могут быть небольшие несоответствия, но они не должны иметь значения.

shadow_matrix — это униформа, переданная как bias_matrix * light_projection_matrix * light_view_matrix * light_model_matrix.


person skiwi    schedule 06.02.2014    source источник
comment
Как мультисэмплинг должен изменить результат textureProj (...)? Нет такой вещи, как sampler2DShadowMS. Единственное, что изменит ваш поиск текстур, возвращая 0.0 или 1.0, — это фильтрация текстур. Я объяснил это в своем ответе.   -  person Andon M. Coleman    schedule 06.02.2014


Ответы (2)


textureProj (...) не возвращает нормализованное значение с плавающей запятой. Он возвращает один float, если вы используете его для sampler<1D|2D|2DRect>Shadow, но это значение представляет собой результат проверки глубины. 1,0 = успешно, 0,0 = не пройдено.

Теперь следует отметить интересную вещь, и причина, по которой возврат float для сэмплера теней вообще имеет смысл, связана с фильтрацией карты теней. Если вы используете режим фильтра GL_LINEAR на карте теней вместе с сэмплером теней, GL фактически выберет 4 ближайших тексела в карте теней и выполнит 4 независимых теста глубины.

Каждый тест глубины по-прежнему имеет двоичный результат, но GL вернет средневзвешенный результат всех 4 тестов (на основе расстояния от идеального местоположения образца). Таким образом, если вы используете GL_LINEAR в сочетании с сэмплером теней, у вас будет значение, которое находится где-то между 0,0 и 1,0, представляющее среднюю окклюзию для 4 ближайших сэмплов глубины. .

Я должен указать, что ваше использование textureProj (...) выглядит потенциально неправильным для меня. Координата, которую он использует, представляет собой четырехмерный вектор, состоящий из (s,t,r) [проекционных координат] и (q) [значения глубины для проверки]. Я не вижу нигде в вашем коде, где вы присваиваете q значение глубины. Если бы вы могли отредактировать свой вопрос, включив в него вершинный/геометрический шейдер, который выводит shadow_coord, это помогло бы.

person Andon M. Coleman    schedule 06.02.2014
comment
Я отредактировал вопрос, включив в него вершинный шейдер, который их создает. Большая часть из них все еще является копией из книги, которую я читал, и я начинаю думать, что их пример с картами теней неверен со всех сторон. Код можно найти на github.com/openglsuperbible/sb6code/tree/master/src. / и шейдеры на github.com/openglsuperbible/ sb6code/tree/master/bin/media/. - person skiwi; 06.02.2014

Попробуйте следующее:

Получите расстояние от каждой вершины вашей модели до источника света.

Отправьте это расстояние в ваш фрагментный шейдер.

Сравните расстояние со значением, хранящимся в вашем сэмплере карты теней (я предполагаю, что эта текстура хранит значения глубины вашей сцены с точки зрения камеры?)

Если расстояние больше, чем сэмплер, точка находится в тени. Иначе это не так.

Если это сбивает с толку, вот пара руководств, которые должны помочь: http://ogldev.atspace.co.uk/www/tutorial23/tutorial23.html http://ogldev.atspace.co.uk/www/tutorial24/tutorial24.html

person redsoxfantom    schedule 06.02.2014
comment
Можете ли вы объяснить, почему я использую textureProj вместо обычного метода texture? Я также нашел это в книге, но я до сих пор не знаю, почему. - person skiwi; 06.02.2014
comment
Честно говоря, раньше я не использовал textureProj. Я читал об этом, и он выполняет выборку текстуры с проекцией, что означает, что координаты, которые вы передаете в функцию, проецируются (т. Е. Если вы передаете 3 элемента x, y, z, textureProj вычисляет x/z, y /z перед выборкой текстуры). Зачем нужна эта проекция, немного выходит за рамки комментария :), но эти ссылки должны немного помочь: opengl.org/sdk/docs/manglsl/xhtml/textureProj.xml en.wikipedia.org/wiki/3D_projection en.wikipedia.org/wiki /Гомогенные_координаты - person redsoxfantom; 07.02.2014
comment
Если вы все еще смущены проекцией, я бы определенно взял одну или две книги по 3D-математике. Это не так тяжело и пугающе, как кажется, и выручит неизмеримо. Я рекомендую этот: amazon.com/Math-Primer-Graphics -Разработка-Выпуск/dp/ - person redsoxfantom; 07.02.2014