PrioryOfScion
PrioryOfScion

Reputation: 13

Why is my OpenGL scene clipping at z distance of 1?

I'm working through the GLSL Cookbook, but I'm programming with C#, so I'm trying to convert the code using OpenTK. I'm currently working with a Phong Shading example, and I can get the mechanics of the lighting working correctly, but the torus model I'm using will not render any elements which are more than a Z-distance of 1 away from the camera.

Here is the example rendering correctly (x rotation = 0, y rotation = 0, camera.z = 1, model.z = 0) Torus Rendering Correctly

Here it is with an X and Y rotation applied (x rotation = -0.5, y rotation = 0.5, camera.z = 1, model.z = 0) Torus rotated showing clipping

Note: If, in the rotated example, I move the camera closer to a Z-position of 0.4, then the torus appears without clipping. I have no idea why moving the camera closer causes less clipping!

There's a lot of code, so I'll try to avoid posting it all. If I do need to post any more, then I'm happy to do so.

Here is my initialisation block:

void InitProgram()
{
    // Compile and link shaders
    Compile();

    // Turn on depth testing
    GL.Enable(EnableCap.DepthTest);
    // Torus centred at (0,0,0), outer radius = 0.7, inner
    // radius = 0.3, 50 segments, 50 rings
    _torus = new VboTorus(0.7f, 0.3f, 50, 50);
    // Setup model matrix
    _model = Matrix4.Identity;
    _model *= Matrix4.CreateRotationX(-0.5f);
    _model *= Matrix4.CreateRotationY(0.5f);
    // Setup view matrix
    _view = Matrix4.LookAt(0f, 0f, 0.4f, 0f, 0f, 0.0f, 0f, 1f, 0f);
    // Setup projection matrix
    _projection = Matrix4.Identity;

    // Position the light
    var lightPos = new Vector4(5f, 5f, 2f, 1f);

    // Bind lighting attributes
    BindLightUniformBlock(lightPos);
    // Bind material attributes
    BindMaterialUniformBlock();
    // Output any errors
    var pil = GL.GetProgramInfoLog(_pgmId);
    Console.WriteLine(pil);
}

Note: GetProgramInfoLog() does not return any errors. Also, I have had a lot of debug code in my shaders to verify that the values being passed in are correct - they are.

Here are the render, update and resize methods:

protected override void OnUpdateFrame(FrameEventArgs e)
{
    base.OnUpdateFrame(e);

    if (Keyboard[Key.Escape])
        Exit();

    GL.UseProgram(_pgmId);
}

protected override void OnRenderFrame(FrameEventArgs e)
{
    base.OnRenderFrame(e);
    GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
    SetMatrices();
    _torus.Render();

    GL.Flush();
    SwapBuffers();
}

protected override void OnResize(EventArgs e)
{
    base.OnResize(e);
    GL.Viewport(0, 0, Width, Height);
}

Here is the method for setting my M, V & P matrices:

private void SetMatrices()
{
    var modelView = _view*_model;

    var uniformIndices = new int[3];
    GL.GetUniformIndices(_pgmId, 3, new[] { "modelViewMatrix", "normalMatrix", "mvpMatrix" }, uniformIndices);

    GL.UniformMatrix4(uniformIndices[0], false, ref modelView);   // Set modelView matrix uniform
    var normMatrix = new float[]
    {
        modelView.M11, modelView.M21, modelView.M31,
        modelView.M12, modelView.M22, modelView.M32,
        modelView.M13, modelView.M23, modelView.M33
    };
    GL.UniformMatrix3(uniformIndices[1], 1, false, normMatrix);   // Set normal matrix uniform
    var temp = _projection*modelView;
    GL.UniformMatrix4(uniformIndices[2], false, ref temp);   // Set lightPosition uniform
}

And finally here is my vertex shader:

#version 430

layout (location = 0) in vec3 vertexPosition;
layout (location = 1) in vec3 vertexNormal;

layout( std140 ) uniform lightInfo {
    vec4 position;
    vec3 ambientIntensity;
    vec3 diffuseIntensity;
    vec3 specularIntensity;
} light;

layout( std140 ) uniform materialInfo {
    vec3 ambientReflectivity;
    vec3 diffuseReflectivity;
    vec3 specularReflectivity;
    float shininess;
} material;

uniform mat4 modelViewMatrix;
uniform mat3 normalMatrix;
uniform mat4 mvpMatrix;

out vec3 lightIntensity;

void main()
{
    // Convert normal and position to eye coords
    vec3 tNorm = normalize( normalMatrix * vertexNormal );
    vec4 eyeCoords = modelViewMatrix * vec4( vertexPosition, 1.0 );
    vec3 s = normalize( vec3( light.position - eyeCoords ) );
    vec3 v = normalize( -eyeCoords.xyz );
    vec3 r = reflect( -s, tNorm );
    vec3 ambient = light.ambientIntensity * material.ambientReflectivity;
    float sDotN = max( dot( s, tNorm ), 0.0 );
    vec3 diffuse = light.diffuseIntensity * material.diffuseReflectivity * sDotN;

    // The diffuse shading equation
    vec3 spec = vec3( 0.0 );
    if( sDotN > 0.0 )
    {
        spec = light.specularIntensity * material.specularReflectivity * pow( max( dot( r, v ), 0.0 ), material.shininess );
    }
    lightIntensity = ambient + diffuse + spec;

    // Convert position to clip coordinates and pass along
    gl_Position = mvpMatrix * vec4( vertexPosition, 1.0 );
}

As I said, if the posted code isn't sufficient to get to the root of the problem, I'm happy to post the rest. Thanks in advance for any advice you can give.

Upvotes: 1

Views: 1926

Answers (1)

derhass
derhass

Reputation: 45332

I'd say everything is working as intented. OpenGL's clip space convention is the [-1,1] cube along all 3 axis in the normalized device space. Since you use identity as the projection matrix, your eye space will become identical to the NDC. With other words, the visible range will go from -1 unit behind your camera to one unit in front of the camera.

To make things worse, typical OpenGL convention is that eye space is right handed (z is pointing towards you, the camera is looking in -z direction), and NDC / window space left handed (z axis is pointing into the screen). The projection matrix usually does the flip. Since you use identity, you also don't get that - so it might feel very unintuitive, but you are clipping against what usually is used as the the near plane when the camera is z_win = 1.

Upvotes: 3

Related Questions