Автор: Евгений Николаевич Саблин
Как известно, при применении обычной перспективной матрицы проекций мы получаем следующие выражения для экранных координат...
(экранные координаты указаны с суффиксом s, координаты в view space указаны с суффиксом v)
Ys = 2*Yv*Znear/Zv/ScreenHeight (2)
Zs = (Zv–Znear)*Zfar/Zv/(Zfar–Znear) (3)
где ScreenWidth и ScreenHeight — размеры плоскости, на которую происходит проекция в мировых координатах. В формулах уже учтено деление всех компонент вектора на червертую (W)
Из формулы (3) видно, что преобразование z нелинейно. Это может приводить к неприятным последстиям (о них ниже). Для того, чтобы преобразование было линейным, было бы разумно применить следующую формулу для z:
В этом случае мы получим равномерное распределение глубины. При этом соглашения о величинах z не нарушаются:
- -все так же ближней плоскости отсечения соответствует Zs=0 , а дальней — Zs=1,
-все так же значение Zs для более близких к экрану точек меньше, чем для более далеких.
Вот так примерно это можно реализовать в шейдере (используя (1),(2),(4)):
matrix WorldView;
float Zfar;
float Znear;
float ScreenWidth;
float ScreemHeight;
float4 VertexShader (float4 inPos : POSITION) :POSITION
{
float4 vec;
vec=mul(inPos,WorldView);
vec=float4(vec.x/vec.z*Znear/ScreenWidth,vec.y/vec.z*Znear/ScreenHeight,(vec.z-Znear)/(Zfar-Znear),vec.w);
return vec;
} |
Плюсы этой методики:
- +Потенциально код из предложенного шейдера может работать быстрее, чем еще одно перемножение матриц.
+В шейдер нужно пересылать немного меньше данных (на 12 float меньше каждый DIP)
+При применении этой методики можно спокойно обходиться буферами глубины меньшего размера для обеспечения той же точности.
+Восстановление координаты z из буфера проще, быстрее и точнее, чем при использовании матрицы проекций. Это может быть полезно при использовании техник shadow map и Deferred Shading (Отложенное освещение).
+Самое главное: решена проблема, в которой 90% сцены занимает 10% буфера глубины. Это помогает избежать необходимости слишком сильно отдалять ближнюю плоскость отсечения в случаях, когда надо выводить на экран огромные пространства, для получения приемлемой точности во избежание z-fighting.
Минусы этой методики:
- –Подобное преобразование невозможно выполнить при помощи умножения вектора на матрицу.
–Как следствие из предыдущего: методику нельзя применять при использовании ffp (fixed function pipeline).
10 ноября 2009
Категории: буферы, z-fighting, глубина
Обновление: 11 ноября 2009