【发布时间】:2017-09-13 07:28:12
【问题描述】:
我一直致力于将贴花投影到贴花边界框封装的任何东西上。在阅读并尝试了许多代码 sn-ps(通常在 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)
【问题讨论】:
-
嗯,从概念上讲,你的方法是可行的。目前还不清楚您的贴花矩阵是如何构造的,以及您的“贴花空间”是如何定义的。我没有得到的是
clip函数与您在文本中给出的值的组合。它转换为if (v.x < 0.5 || v.x > -0.5),这始终是正确的。您可能混淆了文本中的值... -
我最近很困惑 :) 我可能已经切换了 tr 和 bl 的值.. id 必须查看通过它们的代码。贴花矩阵只是从模型到世界空间的标准 4x4 变换矩阵。它实际上确实在正确的位置夹住了贴花和绘画,只是它没有投影到正确的尺寸。它基本上保留了剪辑中的 1x1 尺寸。
-
好吧..它没有保留 1x1 比例..我错了。它正在扩展,但不像我预期的那样。在我发布的第二张图片中,即边界框 (1 x 1 x 1) 乘以它们的相关矩阵。如果我能以某种方式缩放剪辑测试的边界框角而不引起任何旋转,那可能会解决它。我会看看我是否能找到一种方法来做到这一点,并尽快返回这里并提供有关我的结果的信息。
-
您的边界框(用于创建第二张图像的边界框)实际上是如何定义的?
[-0.5, 0.5]在对象空间中?你用什么样的矩阵来放置贴花? -
对于边界框,我创建了一个带有 6 个四边形的立方体。这主要是一种可视化辅助工具,因为我并不真的需要它来进行剪裁。我使用每个贴花的逆矩阵将我从屏幕上得到的点反向转换回边界框的原始大小。每个贴花都有自己的关联矩阵。它与世界矩阵的任何模型没有什么不同。我尝试缩放边界框大小的 2 个角,但到目前为止,它不起作用。我可能混淆了矩阵行/列?