OpenGL编程(七)3D模型的深度(z轴)检测
下图是我们要修改后的效果图:
一、深度检测
1、模型Z轴显示有问题:
上一次试验中,如果认真留意,会发现一个问题。当控制锥体在左右或上下旋转时,你会发现锥体看起来是在+-180度之间来回摆动,而不是360度的旋转。锥体的底面总是朝向观察者。这个我们可以通过修改锥体底面的颜色方便观察。如下图:
正如上面的两幅图,在不同的角度看,底面永远都是在最上面。其实这是跟我们前面代码上的画图有关。前面我们的代码是,先画锥体的侧面,再画底面。类似于我们小学画画时一样,最后画的都是把前面画的给覆盖了。
那应该怎样处理这个问题呢?
2、怎样处理Z轴显示的问题:
这个问题不需要我们操心,OpenGL已经帮我们处理好了。我们只需要添加一个语句,开启OpenGL的深度检测。
glEnable(GL_DEPTH_TEST);
3、深度检测原理
OpenGL在2D平面绘制3D场景时,对每一个绘画的像素点都分配一个Z轴的值(即这个点在3D场景里距离观察者的距离)。有一个深度缓冲区,每次绘画一个像素点就会把该像素点的信息添加进深度缓冲区中。绘制新的像素点时,先判断在同一个2D位置是否已经绘画过像素点,如果是,判断新绘画的像素点的Z轴是不是比已经花了的Z轴更接近观察者,如果是则覆盖掉前面的像素点,修改深度缓冲区,否则不需要画该像素点。
注意:每帧前我们都需要清空深度缓冲区,否则会导致z轴判断错误。因为每一帧中,某个像素点的z轴的值可能会变化。
glClear(GL_DEPTH_BUFFER_BIT);
4、增加深度检测后的效果
加入深度检测后:
二、剔除隐藏表面
1、剔除隐藏表面好处
首先介绍绘图的底层工作原理,有一个3D模型,首先我们先确定需要绘制的3D模型的像素点,把这些像素点发送给计算机图形处理(GPU)相关硬件;相关硬件把这个3D模型绘制到2D屏幕上会检测Z轴(我们前面说到的深度检测)。
从上面的工作步骤我们容易发现,对于3D模型背后的部分,有时我们不需要画出来,可是还是进行了Z轴检测。如果我们在前面处理,直接把背后我们看不见的部分,不用发送给GPU处理的相关硬件,将会提升渲染性能。
这种剔除技术就是“回溯剔除”,回溯剔除将剔除掉3D模型的内部。使用回溯剔除能大大提升渲染性能。
2、正面与背面
在上一节中,我们讲了怎样通过3角形绕出3D模型。我们通过三角形绕出来的面,有正面、背面。
按照OpenGL的约定,通过顺时针绕法,绕出来的面,我们看到的是正面,另外一面是背面,
如上图所示,对于底面,上面(靠近侧面的一面)是正面,底面是背面。对于侧面,按照我们的绕法,外面是正面,里面是背面。
2、开启剔除
glEnable(GL_CULL_FACE);
使用上面的语句能开启回溯剔除功能。
3、启用剔除容易引起的问题
如前面的例子,我们开启了回溯剔除的效果如下:
如上图所示,开启回溯剔除后,把 锥体的底面给剔除了。正如2中的分析,我们的锥体底面上面是正面,下面是背面,所我们看到的背面被剔除掉了。
那应该怎样处理这个问题呢?
很简单,我们在绕锥体底面的时候,我们使用逆时针绕法,这样锥体底面的在下面的是正面,靠近侧面的是背面,这样当我们转到锥体底面的角度的时候就不会被剔除掉了。
逆时针绕法
glFrontFace(GL_CCW);
顺时针绕法
glFrontFace(GL_CW);
我们在绕侧面事前开启顺时针绕法,在绕底面之前开发逆时针绕法。这样就能保证在开启回溯剔除不影响我们的视觉效果。如一下代码:
4、为什么需要回溯剔除
也许有同学会疑问“为什么还要设置开启、关闭回溯剔除呢?而不是直接设置成回溯剔除。为什么还需要我们去开启、关闭?”
因为在绘制3D图形的过程中,我们有的时候是不能看到物品的背面,可是当物品的前面是玻璃材料,具有半透明会透明效果的时候,我们是需要去显示背面,所以要根据我们的需求再自己决定是否需要开启回溯剔除。
三、总结
这次实验主要是在上一次实验的基础上进行修改。上次的实验看似完美,可是如果认真检查会发现前面提到的问题。通过这次实验,掌握了深度检测,回溯剔除的基本原理以及使用方法。
四、修改后的效果
五、完整代码
#include <windows.h>
#include <gl/glut.h>
#include<math.h>
const GLfloat PI = 3.1415f;
GLfloat xRot = 0.0f;
GLfloat yRot = 0.0f;
void rendererScene(void);
void changeWindowSize(GLsizei w, GLsizei h);
void setupRC(void);
void rotateMode(int key, int x, int y);
int main(int argc, char* argv[])
{
//设置显示模式
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
//设置窗口大小
glutInitWindowSize(300, 300);
//设置窗口在屏幕上的位置
glutInitWindowPosition(200, 200);
//创建窗口标题
glutCreateWindow("三角形绘3D模型");
//注册显示窗口时回调渲染函数
glutDisplayFunc(rendererScene);
glOrtho(-100.0f, 100.0f, -100.0f, 100.0f, -100.0f, 100.0f);
//注册窗口大小改变时回调函数
glutReshapeFunc(changeWindowSize);
//注册点击上下左右方向按钮时回调rotateMode函数
glutSpecialFunc(rotateMode);
setupRC();
//消息循环(处理操作系统等的消息,例如键盘、鼠标事件等)
glutMainLoop();
return 0;
}
/**
渲染函数
*/
void rendererScene(void)
{
GLfloat x, y, angle;
BOOL bCull = TRUE; //是否开启回溯剔除
BOOL bDepth = FALSE; //是否开启深度检测
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if(bCull) glEnable(GL_CULL_FACE);
else glDisable(GL_CULL_FACE);
if(bDepth) glEnable(GL_DEPTH_TEST);
else glDisable(GL_DEPTH_TEST);
glPushMatrix();
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
int ipvot = 0;
glFrontFace(GL_CW);
glBegin(GL_TRIANGLE_FAN);
glVertex3f(0.0f, 0.0f, 75.0f);
for(angle = 0.0f; angle < (2.0f * PI); angle += (PI / 8.0f))
{
x = 50.0f * sin(angle);
y = 50.0f * cos(angle);
if(ipvot % 2 == 0) glColor3f(0.0f, 1.0f, 0.0f);
else glColor3f(1.0f, 0.0f, 0.0f);
ipvot++;
glVertex3f(x, y, 0.0f);
}
glEnd();
glFrontFace(GL_CCW);
glBegin(GL_TRIANGLE_FAN);
glVertex3f(0.0f, 0.0f, 0.0f);
for(angle = 0; angle < (2.0f * PI); angle += (PI / 8.0f))
{
x = 50.0f * sin(angle);
y = 50.0f * cos(angle);
if(ipvot % 2 == 0) glColor3f(0.0f, 1.0f, 1.0f);
else glColor3f(0.0f, 0.0f, 1.0f);
ipvot++;
glVertex3f(x, y, 0.0f);
}
glEnd();
glPopMatrix();
glutSwapBuffers();
}
/**
改变窗口大小时回调函数
*/
void changeWindowSize(GLsizei w, GLsizei h)
{
GLfloat length = 100.0f;
if(h == 0) h = 1;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(w <= h) glOrtho(-length, length, -length * h / w, length * h / w, -length, length);
else glOrtho(-length * w / h, length * w / h, -length, length, -length, length);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
/**
设置
*/
void setupRC(void)
{
//背景颜色
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glShadeModel(GL_FLAT);
}
/**
旋转
*/
void rotateMode(int key, int x, int y)
{
if(key == GLUT_KEY_UP) xRot -= 5.0f;
else if(key == GLUT_KEY_DOWN) xRot += 5.0f;
else if(key == GLUT_KEY_LEFT) yRot -= 5.0f;
else if(key == GLUT_KEY_RIGHT) yRot += 5.0f;
if(xRot < 0) xRot = 355.0f;
if(xRot > 360.0f) xRot = 0.0f;
if(yRot < 0) yRot = 355.0f;
if(yRot > 360.0f) yRot = 0.0f;
glutPostRedisplay();
}
OpenGL编程(七)3D模型的深度(z轴)检测的更多相关文章
- OpenGl读取导入3D模型并且添加鼠标移动旋转显示
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11543828.html 最近实习要用到opengl库就是跟opencv 有点像的那个,然后下了 ...
- bullet物理引擎与OpenGL结合 导入3D模型进行碰撞检测 以及画三角网格的坑
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11681069.html 一.初始化世界以及模型 /// 冲突配置包含内存的默认设置,冲突设置. ...
- OpenGl 导入读取多个3D模型 并且添加鼠标控制移动旋转
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11627508.html 前言: 因为接下来的项目需求是要读取多个3D模型,并且移动拼接,那么我 ...
- OpenGL编程逐步深入(三)在窗口中显示一个三角形
这一节教程的内容会比较少,我们仅仅是对上一节教程中的代码进行扩展,在窗口中渲染一个三角形出来. 本节我们以下图所示正方形来讲解OpenGl中的坐标系统.当沿着Z轴负方向看时,可见顶点的坐标必须在这个正 ...
- OpenGL编程(六)通过三角形绘画出3D模型
使用三角形绘制3D模型 三角形是基本的多边形,任何多变形都能由三角形组成.三角形是由三个顶点的连线组成.三个点分别是v0:v1:v2. 1.绕法 从某个顶点开始,有两种连线的方法,顺时针和逆时针,这是 ...
- c# winform用sharpGL(OpenGl)解析读取3D模型obj
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11783026.html 自己写了个简单的类读取解析obj模型,使用导入类,然后new个对象,在 ...
- [OpenGL ES 03]3D变换:模型,视图,投影与Viewport
[OpenGL ES 03]3D变换:模型,视图,投影与Viewport 罗朝辉 (http://blog.csdn.net/kesalin) 本文遵循“署名-非商业用途-保持一致”创作公用协议 系列 ...
- OpenGL编程(八)3D数学与坐标变换
笛卡尔坐标 一维坐标系 以一个点为原点,选定一个方向为正方向(相反的方向为反方向),以一定的距离为标尺建立一维坐标系.一维坐标系一般应用于描述在一维空间中的距离. 举个例子:一维坐标系好比一条拉直的电 ...
- OpenGl 实现鼠标分别移动多个物体 ----------移动一个物体另外一个物体不动--读取多个3d模型操作的前期踏脚石
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11620088.html 前言: 因为接下来的项目需求是要读取多个3D模型,并且移动拼接,那么我 ...
随机推荐
- 【转】C# ABP WebApi与Swagger UI的集成
以前在做WebAPI调用测试时,一直在使用Fiddler测试工具了,而且这个用起来比较繁琐,需要各种配置,并且不直观,还有一点是还得弄明白URL地址和要传递的参数,然后才能调用. 最近新入职,公司里 ...
- 移动端 | Vue.js对比微信小程序基础语法
(1)vue 自定义组件与父组件的通信,props:[abb],可以看成自组建的一个自定义属性 (2)vue 模版语法{{}} 只能是在DOM中插入,<div>{{acc}}</di ...
- iOS11中navigationBar上 按钮图片设置frame无效 不受约束 产生错位问题 解决
问题描述: 正常样式: 在iOS 11 iPhone X上显示效果: 观察顶部navBar上的左侧按钮 在ios 11 上 这个按钮的图片不受设置的尺寸约束,按其真实大小展示,造成图片错位,影响界 ...
- Golden Gate 相关组件介绍:
OGG组件: Manager: 启动其它进程 Collector Extract Data Pump:可选进程,建议使用 Replicat Trails: 可以压缩,加密 Checkpoint OGG ...
- vue-router 设置默认路由
加入 {path: '/', redirect: 'ratings'},vue 1.0版本版本使用go,但是在2.0中是用router.go(‘/ratings’);会一直刷新
- 在使用easyui datagrid在tab中遇到的问题
当切换tab时,数据加载了,但是table的宽和高不能不能够初始化. 郁闷了好久解决了这个问题: 在页面加载时和切换tab时,获取当前tab的名字,进行内容的初始化 $('a[name="m ...
- SyntaxError Generator expression must be parenthesized
环境: Windows10 python3.7.0 Django1.11.15 异常 启动Django时抛出以下异常: Unhandled exception in thread started by ...
- NOIP2016 DAY1 T1 玩具谜题
题目描述 小南有一套可爱的玩具小人,它们各有不同的职业. 有一天,这些玩具小人把小南的眼镜藏了起来.小南发现玩具小人们围成了一个圈,它们有的面朝圈内,有的面朝圈外.如下图: 这时 singer 告诉小 ...
- mysql linux查看配置文件my.cnf位置
原文:mysql linux查看配置文件my.cnf位置 命令: mysql --help | grep 'Default options' -A 1
- W10子系统UBantu命令安装Redis及其启动
W10子系统UBantu命令安装Redis及其启动 打开W10子系统UBantu 安装Redis $sudo apt-get install redis-server 启动Redis redis-se ...