我一直致力于将贴花投影到贴花边界框封装的任何东西上。在阅读并尝试了大量代码片段(通常在 HLSL 中)之后,我在 GLSL 中有一些用于投影贴花的工作方法。
让我首先尝试解释我在做什么以及它是如何工作的(到目前为止)。
下面的代码现在已经修复并且可以工作了!
这一切都是在透视视图模式下进行的。
我将 2 个制服发送到片段着色器“tr”和“bl”。这些是边界框的两个角。我可以并且将用硬编码尺寸替换它们,因为它们是贴花原始边界框的尺寸。tr = vec3(.5, .5, .5) 和 br = vec3(-.5, -.5, -.5)。我更愿意找到一种在贴花转换状态下进行位置测试的方法。(最后更多关于这个)。
为清楚起见添加此内容。从顶点程序发出的顶点是边界框乘以贴花矩阵,而不是乘以模型视图投影矩阵。我将其用于下一步:
使用该顶点,我从深度纹理中获取深度值并使用它,使用投影矩阵的逆计算在世界空间中的位置。
接下来,我使用贴花矩阵的逆矩阵转换这个位置。(缩放、旋转并将 1,1,1 立方体转换到其世界位置的矩阵。我认为通过使用贴花变换矩阵的逆矩阵,可以正确处理屏幕点的正确大小和旋转,但它是不是。
顶点程序:
//Decals color pass.
#version 330 compatibility
out mat4 matPrjInv;
out vec4 positionSS;
out vec4 positionWS;
out mat4 invd_mat;
uniform mat4 decal_matrix;
void main(void)
{
gl_Position = decal_matrix * gl_Vertex;
gl_Position = gl_ModelViewProjectionMatrix * gl_Position;
positionWS = (decal_matrix * gl_Vertex);;
positionSS = gl_Position;
matPrjInv = inverse(gl_ModelViewProjectionMatrix);
invd_mat = inverse(decal_matrix);
}
片段程序:
#version 330 compatibility
layout (location = 0) out vec4 gPosition;
layout (location = 1) out vec4 gNormal;
layout (location = 2) out vec4 gColor;
uniform sampler2D depthMap;
uniform sampler2D colorMap;
uniform sampler2D normalMap;
uniform mat4 matrix;
uniform vec3 tr;
uniform vec3 bl;
in vec2 TexCoords;
in vec4 positionSS; // screen space
in vec4 positionWS; // world space
in mat4 invd_mat; // inverse decal matrix
in mat4 matPrjInv; // inverse projection matrix
void clip(vec3 v){
if (v.x > tr.x || v.x < bl.x ) { discard; }
if (v.y > tr.y || v.y < bl.y ) { discard; }
if (v.z > tr.z || v.z < bl.z ) { discard; }
}
vec2 postProjToScreen(vec4 position)
{
vec2 screenPos = position.xy / position.w;
return 0.5 * (vec2(screenPos.x, screenPos.y) + 1);
}
void main(){
// Calculate UVs
vec2 UV = postProjToScreen(positionSS);
// sample the Depth from the Depthsampler
float Depth = texture2D(depthMap, UV).x * 2.0 - 1.0;
// Calculate Worldposition by recreating it out of the coordinates and depth-sample
vec4 ScreenPosition;
ScreenPosition.xy = UV * 2.0 - 1.0;
ScreenPosition.z = (Depth);
ScreenPosition.w = 1.0f;
// Transform position from screen space to world space
vec4 WorldPosition = matPrjInv * ScreenPosition ;
WorldPosition.xyz /= WorldPosition.w;
WorldPosition.w = 1.0f;
// transform to decal original position and size.
// 1 x 1 x 1
WorldPosition = invd_mat * WorldPosition;
clip (WorldPosition.xyz);
// Get UV for textures;
WorldPosition.xy += 0.5;
WorldPosition.y *= -1.0;
vec4 bump = texture2D(normalMap, WorldPosition.xy);
gColor = texture2D(colorMap, WorldPosition.xy);
//Going to have to do decals in 2 passes..
//Blend doesn't work with GBUFFER.
//Lots more to sort out.
gNormal.xyz = bump;
gPosition = positionWS;
}
我尝试使用贴花和投影矩阵创建一个新矩阵来构造一种“lookat”矩阵并将屏幕位置转换为贴花后转换状态。我无法使其正常工作。有些地方我错过了一些东西,但在哪里?我认为使用贴花矩阵的逆进行平移可以处理变换并将屏幕位置置于正确的变换状态。想法?
更新了纹理 UV 的代码。您可能需要调整 y 和 x,具体取决于您的纹理是在 x 还是 y 上翻转。我还修复了剪辑子,使其正常工作。事实上,这段代码现在可以工作了。如果需要,我将对此进行更多更新,这样其他人就不必经历我为使其正常工作而付出的痛苦。一些需要解决的问题是贴花相互叠加。上面的那个写下面的那个。我想我必须将颜色和法线累积到默认的 FBO 中,然后在光照传递之前或期间将它们混合(添加)到 GBUFFER 纹理。添加更多屏幕尺寸的纹理不是一个好主意,所以我需要有创意并尽可能回收任何纹理。
我找到了贴花相互重叠的解决方案。在绘制贴花时关闭深度遮罩,然后重新打开 int:
glDepthMask(GL_FALSE)