为什么当我的相机离物体远时,OpenGL会剔除我的多边形?

6
我正在使用片段着色器对我从OBJ文件中加载的物体进行Lambert和Fog着色,但我的模型中有一些小问题。当我将相机位置远离物体时,我的网格中的某些多边形被“剔除”。
例如: 老实说,我不知道为什么会发生这种情况,以及为什么只会在我远离物体时发生。以下是我的着色器:
顶点着色器
# version 400

out struct vData {
    vec4 pos;
    vec4 texcoord;
    vec3 normal;
} fdata;

void main() {
    fdata.texcoord = gl_MultiTexCoord0;
    fdata.normal = normalize(gl_NormalMatrix * gl_Normal);
    fdata.pos = gl_Vertex;
    gl_Position = gl_ModelViewProjectionMatrix * fdata.pos;
}

片段着色器

# version 400

layout(binding=0) uniform sampler2D mainTexture;
uniform vec4 lightColor;
uniform vec4 lightPos;

in struct vData {
    vec4 pos;
    vec4 texcoord;
    vec3 normal;
} fdata;

vec4 ComputeLambert(const in vec3 lightdir, const in vec4 lightColor, const in vec3 normal, const in vec4 diffuse) {
    float nDotL = dot(normal, lightdir);
    return diffuse * lightColor * max(nDotL, 0.0);
}

float ComputeFogFactor(const in vec4 coord, const in float density) {
    const float LOG2 = 1.442695;
    float z = coord.z / coord.w;
    float fogFactor = exp2( -density * density * z * z * LOG2 );
    return clamp(fogFactor, 0.0, 1.0);
}

void main() {
    vec3 mypos = fdata.pos.xyz / fdata.pos.w;
    vec3 lightdir = lightPos.xyz / lightPos.w;
    vec3 direction = normalize(lightdir - mypos);

    vec4 diffuse = texture2D(mainTexture, fdata.texcoord.st);
    diffuse = ComputeLambert(direction,lightColor, fdata.normal, diffuse);

    float fogFactor = ComputeFogFactor(gl_FragCoord,gl_Fog.density);

    vec4 finalcolor = mix(gl_Fog.color, diffuse, fogFactor);
    //vec4 finalcolor = vec4(1.0,1.0,1.0,1.0);
    finalcolor.a = 1.0;
    gl_FragColor = finalcolor;
}

在我的绘图调用之前,我确保禁用了面剔除,所以我相当确定这不是问题。有人知道我能做些什么吗?


4
你是在通过视锥体进行剔除,还是更可能是 Z 缓冲区出现问题? - Markus Koivisto
所以你的坐标是什么样的?你离原点很远吗?这可能会导致浮点别名问题,表现出来的样子就像这样。 - Markus Koivisto
那个截图是从相机位置 {x=-4409.8677 y=2500.8369 z=7426.6045 ...} 拍摄的。模型位于位置 {x=-112.00000 y=1610.2000 z=1300.0000 ...} 附近。 - rubbyrubber
是的,这很棘手。我找不到任何人解决过这样的问题...更确切地说,我甚至不知道如何搜索。而且不,这个模型大约有25个单位宽。 - rubbyrubber
花了一些时间,因为我必须为茶壶制作一个mtl文件...但是它在这里...http://i.imgur.com/7PtBU6u.png 错误仍然存在,尽管不那么明显... - rubbyrubber
显示剩余10条评论
2个回答

1

看起来像是Z缓冲区问题...我知道你已经通过注释查看了它,但是:

  1. 你的frustrum设置如何?

    znear,zfar

  2. Z缓冲区使用的位深度是多少?

    当你将这两个东西结合在一起时,你可以估计深度的准确性。

    例如,z = <0.1m - 10000.1m>并且16位需要10000.0/65536=0.15 [m/step],当然正常的gl frustrum具有非线性的Z值,因此更精确的近处和远处要少得多。

    当你比较你的步长和模型的最小细节时,如果它们不是非常不同,那么这就是你的问题。

要修复这个问题,你可以这样做:

  1. 更改视锥体

    扩大近值或降低远值

  2. 使用更多深度缓冲区位数(不适用于所有显卡)

  3. 使用更多视锥体

    对于非常大的渲染范围,我使用更多具有相同视图但不同范围的视锥体

    view1  z = <  0.1,   10.0 >
    view2  z = < 10.0,  100.0 >
    view3  z = <100.0,10000.0 >
    

    当然,在使用另一个视锥体之前,您需要清除深度缓冲区。视图可以重叠,最大绘制模型的大小(然后您不需要在所有视图中都使用所有模型,只需按照视图范围渲染对象)。

    由于多次渲染,速度会变慢,但在重叠情况下,减速仅由范围选择的if引起,这并不是很大的问题。

  4. 使用线性Z缓冲区值...

    GLSL中,不要使用转换后的Z值,而是自己进行转换,这使得在所有范围内精度相同,而不是在更远位置呈指数级降低。

  5. 使用LOD模型

    这会降低远距离处的最小安全精度,但如果您的模型没有LOD范围,则很难正确计算它。

PS. 这不是剔除,而是正面和背面的低z值精度可能会导致它们错位(甚至将正面变成背面,反之亦然)。


1
据我所学,深度缓冲区的值不是线性的,因此,离相机越远的多边形在某些深度范围内给出的位数越少,导致Z-fighting问题。当您将视锥体的远平面选择为非常远(如您所说:地形大小的两倍)时,这个问题会变得更加严重。
因此,请尝试减小视锥体的大小(长度)和/或增加Z缓冲区深度。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接