为什么我的OpenGL场景在z距离为1时被裁剪? [英] Why is my OpenGL scene clipping at z distance of 1?

查看:71
本文介绍了为什么我的OpenGL场景在z距离为1时被裁剪?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在阅读GLSL Cookbook,但是我正在使用C#进行编程,因此我试图使用OpenTK转换代码.我目前正在使用Phong Shading示例,并且可以使照明的原理正常工作,但是我使用的环面模型将不会渲染与相机相距Z距离大于1的任何元素

以下是正确渲染的示例(x旋转= 0,y旋转= 0,camera.z = 1,model.z = 0)环面渲染正确

在此应用X和Y旋转(x旋转= -0.5,y旋转= 0.5,camera.z = 1,model.z = 0)圆环旋转显示裁剪

注意:如果在旋转的示例中,我将相机 closer 移至Z位置0.4,则圆环出现而没有剪切.我不知道为什么将相机移近些会减少剪切!

有很多代码,所以我将尽量避免全部发布.如果我确实需要发布更多信息,那么我很乐意这样做.

这是我的初始化块:

  void InitProgram(){//编译并链接着色器Compile();//开启深度测试GL.Enable(EnableCap.DepthTest);//圆环以(0,0,0)为中心,外半径= 0.7,内//半径= 0.3,50个细分,50个环_torus =新的VboTorus(0.7f,0.3f,50,50);//设置模型矩阵_model = Matrix4.Identity;_model * = Matrix4.CreateRotationX(-0.5f);_model * = Matrix4.CreateRotationY(0.5f);//设置视图矩阵_view = Matrix4.LookAt(0f,0f,0.4f,0f,0f,0.0f,0f,1f,0f);//设置投影矩阵_projection = Matrix4.Identity;//定位灯var lightPos = new Vector4(5f,5f,2f,1f);//绑定照明属性BindLightUniformBlock(lightPos);//绑定材质属性BindMaterialUniformBlock();//输出任何错误var pil = GL.GetProgramInfoLog(_pgmId);Console.WriteLine(pil);} 

注意:GetProgramInfoLog()不返回任何错误.另外,我的着色器中有很多调试代码,可以验证传入的值正确无误.

以下是渲染,更新和调整大小的方法:

 受保护的重写void OnUpdateFrame(FrameEventArgs e){base.OnUpdateFrame(e);如果(键盘[Key.Escape])出口();GL.UseProgram(_pgmId);}受保护的重写void OnRenderFrame(FrameEventArgs e){base.OnRenderFrame(e);GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);SetMatrices();_torus.Render();GL.Flush();SwapBuffers();}受保护的重写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,参考modelView);//将modelView矩阵统一设置var normMatrix =新的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);//设置法线矩阵统一var temp = _projection * modelView;GL.UniformMatrix4(uniformIndices [2],false,参考温度);//设置lightPosition统一} 

最后是我的顶点着色器:

  #version 430vec3 vertexPosition中的布局(位置= 0);在vec3 vertexNormal中进行布局(位置= 1);布局(std140)统一lightInfo {vec4位置;vec3 environmentalIntensity;vec3diffuseIntensity;vec3 specularIntensity;} 光;布局(std140)统一materialInfo {vec3 environmentReflectivity;vec3diffuseReflectivity;vec3 specularReflectivity;漂浮光泽} 材料;统一的mat4 modelViewMatrix;统一的mat3 normalMatrix;均匀的mat4 mvpMatrix;出vec3 lightIntensity;无效main(){//将法线和位置转换为眼坐标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 =反射(-s,tNorm);vec3环境= light.ambientIntensity * material.ambientReflectivity;浮动sDotN = max(dot(s,tNorm),0.0);vec3diffuse = light.diffuseIntensity * material.diffuseReflectivity * sDotN;//扩散阴影方程vec3 spec = vec3(0.0);如果(sDotN> 0.0){spec = light.specularIntensity * material.specularReflectivity * pow(max(dot(r(v,v),0.0),material.shininess);}lightIntensity =环境+扩散+规格;//将位置转换为剪辑坐标并传递gl_Position = mvpMatrix * vec4(vertexPosition,1.0);} 

正如我所说,如果发布的代码不足以解决问题的根源,我很乐意将其余的代码发布出去.预先感谢您提供的任何建议.

解决方案

我会说一切都按预期进行.OpenGL的剪辑空间约定是标准化设备空间中沿所有3轴的[-1,1]立方体.由于您使用身份作为投影矩阵,因此您的眼部空间将变得与NDC相同.换句话说,可见范围从相机后方的-1单位到相机前方的一个单位.

更糟糕的是,典型的OpenGL约定是右眼右手(z指向您,相机朝-z方向看),NDC/窗口左手(z轴指向屏幕)).投影矩阵通常进行翻转.由于您使用身份,因此您也不了解身份,因此可能会感觉很不直观,但是您正在裁剪 z_win = 1 时通常用作近平面的内容./p>

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.

解决方案

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.

这篇关于为什么我的OpenGL场景在z距离为1时被裁剪?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆