Проблема проверки границ с использованием системы декали с отложенным пространственным отображением - PullRequest
0 голосов
/ 15 января 2019

Я пытаюсь внедрить систему отложенных надписей в пространстве экрана, используя OpenGL, следуя статье под названием «Рисование материала на других объектах с отложенными надписями в пространстве экрана», ссылка: http://martindevans.me/game-development/2015/02/27/Drawing-Stuff-On-Other-Stuff-With-Deferred-Screenspace-Decals/.

Красный куб затенен поверхсцена, которая соответствует стене с маской глубины, установленной в false.Ссылка на изображение (куб без границ): https://gyazo.com/8487947bd4afb08d8d0431551057ad6f

Глубинный буфер от стены вместе с некоторыми выходами вершинного шейдера используются для вычисления положения пространства объектов в стене в пределах размеров куба. Связанные проверки гарантируют, чточто каждый пиксель куба, находящийся за пределами пространственного положения объекта стены, отбрасывается.

Проблема в том, что границы не работают должным образом, куб полностью исчезает.

Потенциалнеисправности

Я проверил, правильно ли работает буфер глубины, визуализируя его в проходе освещения, и, кажется, он работает нормально.Глубинный буфер хранится в приложении цвета в gbuffer с плавающим размером GL_RGB32F.Ссылка на изображение (визуализация глубинного буфера Ligtingpass далекой стены): https://gyazo.com/69920a532ca27aa9f57478cb57e0c84c

Код шейдера декаля

VertexShader

// Vertex positions    
vec4 InputPosition = vec4(aPos, 1);   

// Viewspace Position    
PositionVS = view* model* InputPosition;    

// Clipspace Position    
PositionCS = projection*PositionVS;

gl_Position = PositionCS;    

FragmentShader

// Position on the screen    
vec2 screenPos = PositionCS.xy / PositionCS.w;

// Convert into a texture coordinate   
vec2 texCoord = vec2((1 + screenPos.x) / 2 + (0.5 / resolution.x), (1 - 
screenPos.y) / 2 + (0.5 / resolution.y));

// Sampled value from depth buffer   
vec4 sampledDepth = texture(gDepth, texCoord);

// View-direction   
vec3 viewRay = PositionVS.xyz * (farClip / -PositionVS.z);

// Wallposition in view-space   
vec3 viewPosition = viewRay*sampledDepth.z;

// Transformation from view-space to world-space   
vec3 WorldPos = (invView*vec4(viewPosition, 1)).xyz;

// Transformation from world-space to object-space   
vec3 objectPosition = (invModel*vec4(WorldPos, 1)).xyz;

// Bounds check, discard pixels outside the wall in object-space    
if (abs(objectPosition.x) > 0.5) discard;    
else if (abs(objectPosition.y) > 0.5) discard;    
else if (abs(objectPosition.z) > 0.5) discard;    

// Color to Gbuffer    
gAlbedoSpec = vec4(1, 0, 0, 1);

Кодdescription

invView и invModel являются инверсией матриц вида и модели соответственно.Обратный расчет матрицы выполняется в ЦП и передается в виде фрагментов фрагменту шейдера.farClip - расстояние до дальней плоскости камеры (здесь установлено значение 3000).gDepth - это текстура глубины Гбуффера.

Проблема

Часть стены, которая соответствует кубу, должна быть затенена красным, как показано ниже, ее явно нет.

Ссылка на изображение (куб с границами): https://gyazo.com/ab6d0db2483a969db932d2480a5acd08

Я предполагаю, что проблема заключается в том, как позиция в пространстве вида преобразуется в позицию в пространстве объектов, но не могу разобраться!

1 Ответ

0 голосов
/ 17 января 2019

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

vec2 ndcPos = PositionCS.xyz / PositionCS.w;

sampledDepth является значением глубины (которое по умолчанию находится в диапазоне [0, 1]) и может быть получено путем считывания «красного» цветового канала (.r, .x) из текстуры буфера глубины. Глубину можно преобразовать в нормализованную координату Z пространства устройства с помощью depth*2.0-1.0:

vec2 texCoord = ndcPos.xy * 0.5 + 0.5; 
   // (+ 0.5/resolution.xy;) is not necessary if texture filter is GL_NEAREST

float sampledDepth = texture(gDepth, texCoord).x;

float sampleNdcZ = sampledDepth * 2.0 - 1.0;

В перспективной проекции и в нормализованном пространстве устройства все точки с одинаковыми координатами x и y находятся на одном луче, который начинается в позиции просмотра.

Это означает, что если буфер глубины gDepth был создан с той же матрицей вида и матрицей проекции, что и ndcPos (PositionCS), вы можете заменить ndcPos.z соответствующей z-координатой NDC из буфера глубины (sampleNdcZ) и точка все еще находится на том же луче обзора.
ndcPos.z и sampleNdcZ являются сопоставимыми значениями в одной и той же системе отсчета.

vec3 ndcSample = vec3(ndcPos.xy, sampleNdcZ);

Эта координата может быть преобразована в координату пространства обзора с помощью матрицы обратной проекции и деления перспективы.
Если точки NDC на том же луче обзора преобразуются в пространство обзора, то координаты XY будут другими. Обратите внимание, что преобразование не является линейным из-за (* 1/.w). См. Также OpenGL - Координаты мыши для координат пространства .

uniform mat4 invProj; // = inverse(projection)
vec4 hViewPos     = invProj * vec4(ndcSample, 1.0);
vec3 viewPosition = hViewPos.xyz / hViewPos.w;

Это может быть дополнительно преобразовано с помощью матрицы обратного просмотра в мировое пространство и матрицы обратной модели в пространство объектов:

vec3 WorldPos       = (invView * vec4(viewPosition, 1.0)).xyz;
vec3 objectPosition = (invModel * vec4(WorldPos, 1.0)).xyz;

...