opengl透明网格

opengl transparent mesh

我正在使用 GLSL 渲染一个立方体,使用纯白色材质和一个网格作为参考地板。出于某种原因,有时(大约 10 次中有 1 次)立方体呈现大约 50% 的透明度。我最初认为这是一个深度缓冲区问题(例如禁用深度缓冲区),但我找不到任何关于它的信息。代码中只有一个地方涉及深度缓冲区,它正在初始化它。 我什至强制 GLSL 着色器将 Alpha 的固定值设置为 1,但仍然不行。

以下是我用来说明问题的一些屏幕截图:

这是着色器代码:

Lighting.vs

#version 300 es

in vec3 VertexPosition;
uniform mat4 MVP;
in vec2 TexCoord;
out vec2 TexCoord0;

void main()
    {
    gl_Position = MVP * vec4(VertexPosition, 1.0);
    TexCoord0 = TexCoord;
    }

Lighting.fs

#version 300 es

precision lowp float;
in vec2 TexCoord0;
out vec4 FragColor;
uniform sampler2D TextureSampler;

uniform struct
    {
    bool Textured;
    bool Litable;
    }Flags;

uniform struct
    {
    vec4 Diffuse;
    }Material;

uniform struct
    {
    vec3 Color;
    float Intensity;
    }AmbientLight;

vec4 ApplyTexturing ( vec4 Input )
    {
    Input *= texture(TextureSampler, TexCoord0);
    return Input;
    }

vec4 ApplyLighting ( vec4 Input )
    {
    Input *= vec4(AmbientLight.Color * AmbientLight.Intensity, 1.0f );
    return Input;
    }

void main()
    {
    vec4 TempFragColor = vec4 ( Material.Diffuse.xyz, 1.0f );
    if ( Flags.Textured )
    TempFragColor = ApplyTexturing( TempFragColor );

    if ( Flags.Litable )
    TempFragColor = ApplyLighting ( TempFragColor );

    FragColor = vec4(TempFragColor.xyz, 1.0f);
    }

这是代码中唯一接触深度缓冲区的地方:

glEnable ( GL_CULL_FACE );
glCullFace ( GL_BACK );
glFrontFace ( GL_CCW );
glEnable ( GL_DEPTH_TEST );
glDepthMask ( GL_TRUE );
glDepthFunc ( GL_LEQUAL );
glDepthRange ( 1, 100 );

现在,当我写这篇文章时,我想知道我是否应该使用 glClearDepth() 来设置默认值?我假设驱动程序会使用一个不错的默认值,所以我没有指定。

编辑:好的,所以我更改了代码以使用 glClearDepth。没变。不过,这绝对看起来像是一个透明度问题。看看这张带有纹理立方体的照片。

bool CGLWindow::StartFrame ( void )
{
    glfwMakeContextCurrent ( MyGLFWWindow );
    glfwPollEvents();
    glEnable ( GL_CULL_FACE );
    glCullFace ( GL_BACK );
    glFrontFace ( GL_CCW );
    glEnable ( GL_DEPTH_TEST );
    glDepthMask ( GL_TRUE );
    glDepthFunc ( GL_LEQUAL );
    glDepthRange ( 1, 100 );
    glClearColor ( 0, 0, 0, 1.0f );
    glClearDepth ( 1.0f );

    Clear();
    glfwGetCursorPos ( MyGLFWWindow, & ( MouseCursor.CursorPos.X ), & ( MouseCursor.CursorPos.Y ) );
    return glfwWindowShouldClose ( MyGLFWWindow );
}

bool CGLWindow::Clear ( void )
{
    glViewport ( 0, 0, Size.X, Size.Y );
    glScissor ( 0, 0, Size.X, Size.Y );
    glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
    return glCheckError();
}

编辑: 好的,一些突破。 我切换到一个简单的片段着色器:

#version 300 es
precision lowp float;

out vec4 FragColor;
in vec4 Color;

void main()
    {
    FragColor.r = FragColor.g = FragColor.b = FragColor.a = 1.0f;
    }

这不是确定性的,但就像我说的,每隔一段时间,我会得到一个透明的立方体。而现在,它不再这样做了。现在一切正常了。

所以,我开始减少我的片段着色器。这是我得到的最小值,透明立方体失败了。

#version 300 es

precision lowp float;
in vec2 TexCoord0;
out vec4 FragColor;
uniform sampler2D TextureSampler;

uniform struct
    {
    vec4 Diffuse;
    }Material;

void main()
    {
    vec4 TempFragColor = vec4 ( Material.Diffuse.xyz, 1.0f );

    FragColor = vec4(TempFragColor.xyz, 1.0f);
    }

我可能在这里做错了什么? 看来肯定是着色器了。

您的设置不会为您提供功能深度缓冲区。问题在于此调用:

glDepthRange ( 1, 100 );

深度缓冲区的范围是 0.0 到 1.0。这些值决定了从 NDC(标准化设备坐标)到深度缓冲区范围的映射。默认值对应于:

glDepthRange(0.0, 1.0);

这意味着NDC中的深度范围(从-1.0到1.0)被映射到整个可用的深度缓冲区范围。 glDepthRange()只能减少 NDC范围映射到的深度值范围。您不能将深度缓冲区的范围扩展到其默认的完整范围之外。

因此,glDepthRange() 的两个参数都需要介于 0.0 和 1.0 之间。指定此范围之外的值不是错误。这些值被限定,如规范中所定义:

The parameters n and f are clamped to the range [0,1], as are all arguments of type clampd or clampf.

夹紧第二个参数 100 后,您的调用相当于:

glDepthRange(1.0, 1.0);

这意味着所有内容都映射到深度值 1.0,这几乎就像根本没有深度缓冲区一样。

除非您有充分的理由选择不同的值,否则您根本不需要调用 glDepthRange()。默认值适用于最常见的用例。

根据您使用的值,您可能期望它们是 world/eye 坐标中的深度范围。但该范围由投影变换的 near 和 far 参数定义,负责将 [near, far] 范围映射到 [-1, 1] NDC 范围。我们在这里使用 glDepthRange() 参数查看的内容稍后会在管道中发生。