Reputation: 13
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
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