为什么我的 OpenGL 场景在 z 距离为 1 处被裁剪?
Why is my OpenGL scene clipping at z distance of 1?
我正在研究 GLSL Cookbook,但我正在使用 C# 进行编程,因此我正在尝试使用 OpenTK 转换代码。
我目前正在使用 Phong Shading 示例,我可以让照明机制正常工作,但我使用的环面模型不会渲染任何距离相机的 Z 距离超过 1 的元素.
这里是正确渲染的例子(x rotation = 0, y rotation = 0, camera.z = 1, model.z = 0)
Torus Rendering Correctly
此处应用了 X 和 Y 旋转(x 旋转 = -0.5,y 旋转 = 0.5,camera.z = 1,model.z = 0)
Torus rotated showing clipping
注意:如果在旋转的示例中,我将相机 更靠近 移动到 0.4 的 Z 位置,则环面不会出现裁剪。我不知道为什么将相机移近会减少剪裁!
有很多代码,所以我会尽量避免 post 把它们都写完。如果我确实需要 post,那么我很乐意这样做。
这是我的初始化块:
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);
}
注意:GetProgramInfoLog() 不会 return 任何错误。
另外,我的着色器中有很多调试代码来验证传入的值是否正确 - 它们是正确的。
渲染、更新和调整大小方法如下:
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);
}
我的M、V、P矩阵设置方法如下:
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
}
最后是我的顶点着色器:
#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 );
}
正如我所说,如果 posted 代码不足以找到问题的根源,我很乐意 post 剩下的。
提前感谢您提供的任何建议。
我会说一切都按预期进行。 OpenGL 的剪辑 space 约定是标准化设备 space 中沿所有 3 轴的 [-1,1] 立方体。由于您使用标识作为投影矩阵,因此您的眼睛 space 将与 NDC 相同。换句话说,可见范围将从相机后面的 -1 个单位到相机前面的一个单位。
更糟糕的是,典型的 OpenGL 惯例是眼睛 space 是右撇子(z 指向您,相机朝 -z 方向看),并且 NDC / window space 左手(z 轴指向屏幕)。投影矩阵通常会翻转。因为你使用身份,你也没有得到它 - 所以它可能感觉非常不直观,但是当相机是 z_win = 1
.
时,你正在剪裁通常用作近平面的东西
我正在研究 GLSL Cookbook,但我正在使用 C# 进行编程,因此我正在尝试使用 OpenTK 转换代码。 我目前正在使用 Phong Shading 示例,我可以让照明机制正常工作,但我使用的环面模型不会渲染任何距离相机的 Z 距离超过 1 的元素.
这里是正确渲染的例子(x rotation = 0, y rotation = 0, camera.z = 1, model.z = 0) Torus Rendering Correctly
此处应用了 X 和 Y 旋转(x 旋转 = -0.5,y 旋转 = 0.5,camera.z = 1,model.z = 0) Torus rotated showing clipping
注意:如果在旋转的示例中,我将相机 更靠近 移动到 0.4 的 Z 位置,则环面不会出现裁剪。我不知道为什么将相机移近会减少剪裁!
有很多代码,所以我会尽量避免 post 把它们都写完。如果我确实需要 post,那么我很乐意这样做。
这是我的初始化块:
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);
}
注意:GetProgramInfoLog() 不会 return 任何错误。 另外,我的着色器中有很多调试代码来验证传入的值是否正确 - 它们是正确的。
渲染、更新和调整大小方法如下:
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);
}
我的M、V、P矩阵设置方法如下:
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
}
最后是我的顶点着色器:
#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 );
}
正如我所说,如果 posted 代码不足以找到问题的根源,我很乐意 post 剩下的。 提前感谢您提供的任何建议。
我会说一切都按预期进行。 OpenGL 的剪辑 space 约定是标准化设备 space 中沿所有 3 轴的 [-1,1] 立方体。由于您使用标识作为投影矩阵,因此您的眼睛 space 将与 NDC 相同。换句话说,可见范围将从相机后面的 -1 个单位到相机前面的一个单位。
更糟糕的是,典型的 OpenGL 惯例是眼睛 space 是右撇子(z 指向您,相机朝 -z 方向看),并且 NDC / window space 左手(z 轴指向屏幕)。投影矩阵通常会翻转。因为你使用身份,你也没有得到它 - 所以它可能感觉非常不直观,但是当相机是 z_win = 1
.