Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does OpenGL cull my polygons when my camera is far from the object?

Tags:

c++

opengl

I am using a fragment shader for Lambert and Fog shading on objects I loaded from an OBJ file, but I have a small issue with polygons. Some polygons in my mesh are "culled" when I move my camera position away from the object.

Example:

I honestly have no clue why this happens, and why it only happens when I move away from the object. Here are my shaders:

Vertex Shader

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

Fragment Shader

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

I made sure to disable Face Culling before my drawing call so I am pretty certain that is not the issue. Does anybody know if there is something I can do about this?

like image 531
rubbyrubber Avatar asked Nov 11 '13 07:11

rubbyrubber


2 Answers

as far as I've learning, the depth buffer values are not linear, so the farther the polygons are away from the camera, the less bits are given for some depth range, leading to z-fighting. This problem becomes even worse when you choose your far-plane of the view-frustum to be very far away (as you said: twice as far as the terrain size).

So try to reduce the frustum size (length) and/or increase the z-buffer depth

like image 96
Micka Avatar answered Nov 02 '22 22:11

Micka


Looks like Z-buffer issue ... I know you have take a look at it by comments but:

  1. how is your frustrum set ?

    znear,zfar ?

  2. what bit depth you use for your Z-buffer ?

    When you combine these two things together then you can estimate depth accuracy.

    for example z = <0.1m - 10000.1m> and 16 bit takes 10000.0/65536=0.15 [m/step] of course normal gl frustrum has nonlinear Z values so more accuracy is near and much much less far

    When you compare your step and min detail of your model and they aren't much much different than this is your issue.

To repair this you can do this:

  1. change frustrum

    enlarge near value or lower far value

  2. use more depth bits per z-buffer (not working on all cards)

  3. use more frustrums

    for very large render range I use more frustrums with the same view but

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

    of course you need to clear z-buffer before use another frustrum. Views can overlap by the max size of drawed model (then you do not need all models in all views just render object by range view).

    It is slower because of multiple rendering passes but in the overlapping case the slow down is only by range selection ifs which is not a big deal.

  4. use linear Z-buffer values ...

    inside GLSL do not use transformed Z-value, instead transform it your self this makes the accuracy the same at all ranges. Instead of exponentially lower at more distant positions

  5. use LOD for model

    this lower min safe accuracy at distant ranges but if your model have no LOD ranges then is very hard to compute it yourself correctly

PS. its not culling but the front face and back face have low z-value accuracy which can lead to misplace them (even change the front to back and vice versa)

like image 38
Spektre Avatar answered Nov 02 '22 23:11

Spektre