opengl - GBUFFER 贴花投影和缩放

标签 opengl glsl decal


我一直致力于将贴花投影到贴花边界框封装的任何东西上。在阅读并尝试了大量代码片段(通常在 HLSL 中)之后,我在 GLSL 中找到了一些用于投影贴花的工作方法。

让我首先尝试解释一下我在做什么以及它是如何工作的(到目前为止)。
下面的代码现已修复并可以运行!

这一切都是在透视 View 模式下进行的。
我将 2 个制服发送到片段着色器“tr”和“bl”。这些是边界框的两个角。我可以并且将会用硬编码尺寸替换它们,因为它们是贴花原始边界框的尺寸。 tr = vec3(.5, .5, .5) 和 br = vec3(-.5, -.5, -.5)。我更愿意找到一种在贴花转换状态下进行位置测试的方法。 (最后有更多相关信息)。

为了清楚起见添加此内容。从顶点程序发出的顶点是边界框乘以贴花矩阵,然后乘以模型 View 投影矩阵。我将其用于下一步:
通过该顶点,我从深度纹理中获取深度值,并使用它使用投影矩阵的逆来计算世界空间中的位置。

接下来,我使用贴花矩阵的逆来平移该位置。 (缩放、旋转和平移 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;

    }

这里有几张图片显示了问题所在。 我从投影中得到什么: enter image description here

这是贴花的实际尺寸..比我的着色器创建的大得多! enter image description here

我尝试使用贴花和投影矩阵创建一个新的矩阵,以构造一种“观看”矩阵,并将屏幕位置转换为贴花后转换状态。我无法使其正常工作。有些地方我遗漏了一些东西,但在哪里?我认为使用贴花矩阵的逆进行翻译可以处理变换并将屏幕位置置于正确的变换状态。有想法吗?

更新了纹理 UV 的代码。您可能需要摆弄 y 和 x,具体取决于您的纹理是在 x 还是 y 上翻转。我还修复了剪辑子,使其正常工作。事实上,这段代码现在可以工作了。如果需要的话,我会对此进行更多更新,这样其他人就不必经历我为使其正常工作而经历的痛苦。 需要解决的一些问题是贴花相互重叠。上面的写了下面的。我想我必须将颜色和法线累积到默认的 FBO 中,然后在照明 channel 之前或期间将它们混合(添加)到 GBUFFER 纹理中。添加更多屏幕尺寸的纹理并不是一个好主意,因此我需要发挥创意并尽可能回收任何纹理。

我找到了贴花相互重叠的解决方案。 绘制贴花时关闭深度 mask ,然后重新打开 int:

glDepthMask(GL_FALSE)

最佳答案

好吧..我很兴奋。我发现了这个问题。 我再次更新了上面的代码。 我在发送 tr 和 bl 着色器时犯了一个错误: 以下是对剪辑的更改:

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; }
}

关于opengl - GBUFFER 贴花投影和缩放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43455546/

相关文章:

c++ - 添加文本停止渲染自定义 GL 项目

opengl - 如何将深度缓冲区复制到GPU上的纹理?

GLSL 片段着色器获取顶点位置

c++ - Ogre Projector 透过物体发光

c++ - 计算高度图的法线

c++ - opengl-glsl单虚光

c - 为什么我转换为float时gcc总是报错?

opengl - glsl 更新 2D 纹理的特定行

java - 用于 3D 游戏的 Libgdx 渲染层

javascript - 三个 js 贴花