Статья: Получение исходных 3D-координат по значениям из z-буфера.
Приведены подробные вычисления в соответствии с матрицей проекции. В конце выведена формула для частного случая:
Самым простым способом достижения этого является вывод прямоугольника с zeye=1 границы которого соответствуют пересечению данной плоскости и (неусеченной) пирамиды видимости.
в которой мы находим положение камеры
float zEye = zFar * zNear / ( d * (zFar - zNear) - zFar );
vec3 eyeCoord = pos * zEye;
И самое неприятное - для другой матрицы проекции нам снова надо пройти все эти вычисления
Как то все сложно. Гораздо проще на мой взгляд привести позицию позицию фрагмента к кубу [-1; 1] и умножить на обратную матрицу проекции gl_ProjectionMatrixInverse
И таким образом код фрагментного шейдера выглядит так:
uniform sampler2D depthMap;
uniform vec2 uWindowSize; //ширина и высота вьюпорта (с рассчетом на то что вьюпорт у нас начинается в точке 0,0)
uniform vec2 uTexSize; //ширина и высота заполненой части текстуры для NPOT текстуры
void main()
{
vec2 texCoord = gl_FragCoord.xy / uTexSize; //я тут не использую NPOT текстуры, поэтому перевожу координаты фрагмента в координаты текстуры
float Depth = texture2D(depthMap, texCoord).r; //читам глубину
vec4 PixelPos = gl_ProjectionMatrixInverse * vec4((gl_FragCoord.xy/uWindowSize * 2.0 - 1.0), Depth * 2.0 - 1.0, 1.0); //переводим XY Depth в куб [-1; 1] и умножаем на обратную матрицу
PixelPos /= PixelPos.w; //восстанавливаем W в 1
}
Все, в PixelPos имеем координаты пикселя, Eye координаты у нас находятся в точке 0,0,0
Приимущества очевидны - не зависим от матрицы проекции. Главное только чтобы на обоих проходах была одна и та же матрица проекции.
Может стоит добавить этот способ в эту статью, а тот рассматривать как альтернативный вариант?
Статья: Deferred Shading.
Цитирую:
Как видно из данного рисунка необходимо вычислять освещенность только для тех фрагментов нелицевой части границы области влияния источника (сферы), для которых не пройден тест глубины.
Это позволяет использовать буфер трафарета (отключив при этом запись во все остальные буфера) для выделения фрагментов, действительно требующих освещения.
При этом каждый источник требует двух проходов - на первом (очень быстром, так как идет запись только в буфер трафарета) помечаются те фрагменты, которые нужно освещать (т.е. для которых тест глубины не пройден), а на втором - осуществляется вычисление освещенности тех фрагментов, которые проходят тест трафарет.
Таким образом, первый проход запрещает запись во все буфера, кроме буфера трафарета, устанавливает отсечение лицевых граней, в качестве теста глубины задает режим GL_LESS, в качестве теста трафарета задает режим GL_ALWAYS и задает операцию GL_REPLACE для тех фрагментов, для которых не пройден тест глубины.
В результате этого прохода у нас в буфере трафарета будут помечены заданным значением только те пикселы, которые требуют освещения.
Второй проход опять выводит только нелицевые грани области влияния источника света, выключив запись в буфер глубины и буфер трафарета, однако задав отбрасывание при помощи теста трафарета ненужных фрагментов.
Вопрос: Зачем?
Зачем делать 2 прохода? Зачем писать в стенсил? Зачем, если во время первого прохода, если имеем Depth test fail - то попадаем во фрагментный, в котором можем как надо все осветить сразу?
Более того, ни слова не сказано, что при подобном способе рискуем на zNear и zFar клапминг для треугольников. А ведь для "мощных" источников света с большим Range сфера запросто может пересечь zFar. Вывод: надо следить за этим либо отключать клампинг глубины используя например NV_DEPTH_CLAMP расширение.
Статья: Screen-Space Ambient Occlusion.
Я сначала скачал демки и посмотрел. Удивился высокой фрагментированности теней. На всех демках явно виден тайлинг тени. Стал читать. Сначала разумно все объясняется про случайные вектора, все как надо, но потом смотрю в шейдер и вижу:
vec4 rndTable [8] = vec4 [8]
(
vec4 ( -0.5, -0.5, -0.5, 0.0 ),
vec4 ( 0.5, -0.5, -0.5, 0.0 ),
vec4 ( -0.5, 0.5, -0.5, 0.0 ),
vec4 ( 0.5, 0.5, -0.5, 0.0 ),
vec4 ( -0.5, -0.5, 0.5, 0.0 ),
vec4 ( 0.5, -0.5, 0.5, 0.0 ),
vec4 ( -0.5, 0.5, 0.5, 0.0 ),
vec4 ( 0.5, 0.5, 0.5, 0.0 )
);
Просто в шейдере (даже не в юниформе) заполняем КОНСТАНТАМИ
Не удивительно что тень фрагментирована. Смысл то reflect тогда? Дополнительное вычисление не приводящее посути ни к какому визуальному изменению?
Решение: rndTable нужно сделать зависмой от gl_FragCoord.
Пока все, вот как то так...