目录[-]

  • 遮挡查询之前
  • 包围体
  • 遮挡查询

在一个场景中,如果有有些物体被其他物体遮住了不可见。那么我们就不需要绘制它。在复杂的场景中,这可以减少大量的顶点和像素的处理,大幅度的提高帧率。遮挡查询就是允许我们判断一组图形在进行了深度测试之后是否可见。

遮挡查询之前

为了显示遮挡查询对性能的提升,我们需要一个对照组(不使用遮挡查询来渲染场景)。

首先我们先绘制“主遮挡物”。这个主遮挡物不需要太多的细节,一般是墙,天花板,地板之类的物体。在下面的例子中我们,使用6面墙来组成这个主遮挡物。

void DrawOccluder()
{glColor3f(0.5f, 0.25f, 0.0f);glPushMatrix();glScalef(30.0f, 30.0f, 1.0f);glTranslatef(0.0f, 0.0f, 50.0f);glutSolidCube(10.0f);glTranslatef(0.0f, 0.0f, -100.0f);glutSolidCube(10.0f);glPopMatrix();glPushMatrix();glScalef(1.0f, 30.0f, 30.0f);glTranslatef(50.0f, 0.0f, 0.0f);glutSolidCube(10.0f);glTranslatef(-100.0f, 0.0f, 0.0f);glutSolidCube(10.0f);glPopMatrix();glPushMatrix();glScalef(30.0f, 1.0f, 30.0f);glTranslatef(0.0f, 50.0f, 0.0f);glutSolidCube(10.0f);glTranslatef(0.0f, -100.0f, 0.0f);glutSolidCube(10.0f);glPopMatrix();
}

现在我们在每一个单元格中,放置一个高度分挌化的纹理球体。这些球体可能是被遮挡物,也可能是遮挡物。

void DrawSphere(GLint sphereNum)
{ ...glutSolidSphere(50.0f, 200, 200);
...}void DrawModels(void)
{ //开启纹理 自动生成纹理坐标glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); //绘制27个不同颜色的球体for (r = 0; r < 3; r++) { for (g = 0; g < 3; g++) { for (b = 0; b < 3; b++) { glColor3f(r * 0.5f, g * 0.5f, b * 0.5f); glPushMatrix(); glTranslatef(100.0f * r - 100.0f,  100.0f * g - 100.0f,  100.0f * b - 100.0f); DrawSphere((r*9)+(g*3)+b); glPopMatrix(); } } } glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); }

在我的机器上没有遮挡查询下渲染的帧率是20左右。

包围体

在遮挡查询中,如果一个物体的边界都是不可见的,那么就代表这个物体不可见。所以我们只需检测物体外围的包围体可见,就可以判断物体是否被遮挡。物 体外围的包围体包含着整个物体,这也就意味着包围体的体积是大于等于物体的体积的。对于一个球体来说,包围体可以有很多种,最常见的就是立方盒子,四面体 等。

为什么要选择包围体去判断遮挡,而不是直接用球体的。因为球体太过于复杂,包含的顶点也多,渲染较耗时。遮挡之所以能够提升性能,就是我们可以在无 光照,无纹理等其他效果的下,并且不需要改变缓冲区的值,先渲染简单的包围体。通过这些包围体进行深度测试,我们就能判断出哪些物体被遮挡,那些被遮挡的 物体就可以不需要被渲染(不需要调用任何渲染该物体的命令),如果这个物体拥有非常多的顶点,那么遮挡在这个时候就能大幅度的提高性能。

遮挡查询

遮挡查询的步骤:

  1. 首先为这些物体生成查询对象ID 调用glGenQueries

  2. 调用glBeginQuery开始遮挡查询

  3. 渲染包围体

  4. 调用glEndQuery 结束遮挡查询

  5. 调用glGetQueryObject[u]iv,根据ID提取遮挡查询的结果,并根据结果进行相应的操作

  6. glDeleteQueries 删除ID,回收资源

查询对象的标识符(ID/名称)是一个无符号整数,我们可以通过glGenQueries函数生成,也可以自己定义。一般用OpenGL提供的glGenQueries会比较方便。

void glGenQueries(GLsizei n, GLuint *ids);

第一个参数是生成ID的个数,第二个参数是来存放这些ID的数组。0是保留的ID,不会被产生。我们还可以通过glIsQuery来判断一个ID是否是一个遮挡查询对象的ID。

void glIsQuery(GLuint id);

如果是返回GL_TRUE,不是则返回GL_FALSE。

有了遮挡查询对象的ID后,可以开始遮挡查询了。例如

glBeginQuery(GL_SAMPLES_PASSED, 1);
glBegin(GL_TRIANGLES);glVertex3f(1.0f, 1.0f, 0.0f);glVertex3f(-1.0f, 5.0f, 0.0f);glVertex3f(6.0f, 20.0f, 0.0f);
glEnd();
glEndQuery(GL_SAMPLES_PASSED);

void glBeginQuery(GLenum target, GLuint id);

其中target必须是GL_SAMPLES_PASSED. id是用来标识这次遮挡查询的ID。

void glEndQuery(GLenum target);结束这次遮挡查询,其中target必须是GL_SAMPLES_PASSED。

在完成对需要遮挡查询的物体渲染之后,我们需要提取遮挡查询的结果,可以通过glGetQueryObject[u]iv来提取结果,函数将返回片段或采样的数量。

void glGetQueryObjectiv(GLenum id, GLenum pname, GLint *param);

void glGetQueryObjectuiv(GLenum id, GLenum pname, GLuint *param);

id是这个遮挡查询对象的id,pname如果是GL_QUERY_RESULT, param将包含了通过深度测试的片段或样本(如果启用了多重采样)的数量,如果数量为0,则表示这个物体完全被遮挡。

在完成遮挡查询操作时,可能会有延迟。我们可以通过设置pname为GL_QUERY_RESULT_AVAILABLE来检查是否完成了。如果遮挡查询有效地完成了,则param将为GL_TRUE,否则为GL_FALSE.

例:

int count = 1000; //等待1000次循环
GLuint queryReady = GL_FALSE;
while (!queryReady && count--)
{glGetQueryObjectuiv(1, GL_QUERY_RESULT_AVAILABLE, &queryReady);
}GLuint samples;glGetQueryObjectuiv(1, GL_QUERY_RESULT, &samples);
if(samples > 0)DrawSomething();

使用完遮挡查询对象之后,调用glDeleteQueries回收资源。

void glDeleteQueries(GLsizei n, const GLuint *ids);

修改前面的例子,我们可以先渲染27个球体的包围体,进行遮挡查询,如果有哪个包围体被完全遮挡,我们就不需要绘制这个球体了。代码片段如下:

void DrawModels(void)
{ GLint r, g, b; //绘制主遮挡物DrawOccluder(); //在绘制包围体时,越简单越好。关掉纹理,光照等等。//不需要往缓冲区中写值。glShadeModel(GL_FLAT); glDisable(GL_LIGHTING); glDisable(GL_COLOR_MATERIAL); glDisable(GL_NORMALIZE); glDepthMask(GL_FALSE); glColorMask(0, 0, 0, 0); // 画27个立方体for (r = 0; r < 3; r++) { for (g = 0; g < 3; g++) { for (b = 0; b < 3; b++) { if (showBoundingVolume) glColor3f(r * 0.5f, g * 0.5f, b * 0.5f); glPushMatrix(); glTranslatef(100.0f * r - 100.0f,  100.0f * g - 100.0f,  100.0f * b - 100.0f); //开始遮挡查询glBeginQuery(GL_SAMPLES_PASSED, queryIDs[(r*9)+(g*3)+b]); //绘制包围体glutSolidCube(100.0f); //结束遮挡查询glEndQuery(GL_SAMPLES_PASSED); glPopMatrix(); } } }//恢复正常的渲染状态glDisable(GL_POLYGON_STIPPLE); glShadeModel(GL_SMOOTH); glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); glEnable(GL_NORMALIZE); glColorMask(1, 1, 1, 1); glDepthMask(GL_TRUE); //开启纹理 自动生成纹理坐标glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); //绘制27个不同颜色的球体for (r = 0; r < 3; r++) { for (g = 0; g < 3; g++) { for (b = 0; b < 3; b++) { glColor3f(r * 0.5f, g * 0.5f, b * 0.5f); glPushMatrix(); glTranslatef(100.0f * r - 100.0f,  100.0f * g - 100.0f,  100.0f * b - 100.0f); //函数中根据,遮挡查询的结果来判断是否要绘制这个球体DrawSphere((r*9)+(g*3)+b); glPopMatrix(); } } } glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T);
}
void DrawSphere(GLint sphereNum)
{ GLboolean occluded = GL_FALSE; if (occlusionDetection) { GLint passingSamples; //检查物体是否被完全遮挡glGetQueryObjectiv(queryIDs[sphereNum], GL_QUERY_RESULT,  &passingSamples); if (passingSamples == 0) occluded = GL_TRUE; } //没有被遮挡则绘制if (!occluded) { glutSolidSphere(50.0f, 200, 200); }
}

有了遮挡查询后,帧率达到了32左右,当然还要看观察场景的角度。如果从某个角度看大部分球体都被遮挡了,性能的提升更大。

在osg中 example_osgocclusionquery
一)演示了osg::OcclusionQueryNode的使用。

转载于:https://www.cnblogs.com/mazhenyu/p/5083026.html

OpenGL超级宝典笔记——遮挡查询 [转]相关推荐

  1. OpenGL超级宝典笔记——累积缓冲区与其他颜色操作

    2019独角兽企业重金招聘Python工程师标准>>> 累积缓冲区 OpenGL除了颜色缓冲区.深度缓冲区.模板缓冲区之外,还有累积缓冲区.累积缓冲区允许你把渲染到颜色缓冲区的值,拷 ...

  2. Opengl超级宝典笔记——空间绘图画点

    2019独角兽企业重金招聘Python工程师标准>>> <h2>3D概念</h2> <ol> <li>像素,计算机显示器中的最小元素. ...

  3. 【转】OpenGL超级宝典笔记——纹理映射Mipmap

    原文地址 http://my.oschina.net/sweetdark/blog/177812 , 感谢作者,若非法转载请联系本人. 目录[-] Mipmapping Mipmap过滤 构建Mip层 ...

  4. OpenGL超级宝典笔记——光照参数与材料属性

    2019独角兽企业重金招聘Python工程师标准>>> <h3>添加光照</h3> <p>glEnable(GL_LIGHTING);</p ...

  5. OpenGL 超级宝典笔记 —— 纹理高级(一)

    辅助颜色 一般情况下,我们设置纹理的环境为 GL_MODULATE 模式,在这种情况下,受到光照的几何图形会和纹理的颜色进行结合.正常情况下,OpenGL 进行光照计算,并根据标准的光照模型进行单个片 ...

  6. OpenGL 超级宝典笔记 —— 雾

    应用雾 雾是 OpenGL 支持的一种易于使用的特殊效果.在使用雾时,OpenGL 把雾的颜色与完成所有其他颜色计算的几何图元进行混合.雾与几何图元的混合程度取决于几何图元离观察者的距离.雾可以使物体 ...

  7. OpenGL超级宝典(第7版)笔记11 帧缓存运算 计算着色器 清单 3.13

    OpenGL超级宝典(第7版)笔记11 帧缓存运算 计算着色器 清单 3.13 文章目录 OpenGL超级宝典(第7版)笔记11 帧缓存运算 计算着色器 清单 3.13 1 帧缓存运算 1.1 裁剪测 ...

  8. OpenGL超级宝典(第7版)笔记20 统一变量 一致区块 uniform相关内容 清单5.9-5.28

    OpenGL超级宝典(第7版)笔记20 统一变量 一致区块 uniform相关内容 清单5.9-5.28 文章目录 OpenGL超级宝典(第7版)笔记20 统一变量 一致区块 uniform相关内容 ...

  9. OpenGL超级宝典(第7版)笔记4 渲染管线介绍 清单2.3-2.7

    OpenGL超级宝典(第7版)笔记4 渲染管线介绍 清单2.3-2.7 文章目录 OpenGL超级宝典(第7版)笔记4 渲染管线介绍 清单2.3-2.7 1 OpenGL简介 2 OpenGL渲染管线 ...

最新文章

  1. 浅谈Python flask框架浅析
  2. iphone6 微信浏览器高度适配的问题
  3. 静态路由中的下一跳地址和送出接口的区别和使用
  4. IT兄弟连 JavaWeb教程 监听器3
  5. matlab中数组创建方法
  6. 用Middleware给ASP.NET Core Web API添加自己的授权验证
  7. html form urlencode,form-data和x-www-form-urlencode的区别
  8. jquery图片预加载+自动等比例缩放插件
  9. 【CCCC】L3-012 水果忍者 (30分),,枚举斜率
  10. 普元EOS的项目部署
  11. C++处理有道单词导出单词本
  12. 移动光猫获取管理员密码过程记录(吉比特TEWA-272G)
  13. 一套5A数据中心机房建设方案(143页),可作投标技术方案模板
  14. 解决 EIGEN_STACK_ALLOCATION_LIMIT, OBJECT_ALLOCATED_ON_STACK_IS_TOO_BIG 报错
  15. php 清除word标签,word如何取消修改标注
  16. 很多人都说flash as3 经常都是使用MC或者sprite(请问这里的sprite是什么意思?)...
  17. 解决Spark数据倾斜(Data Skew)的 N 种姿势 与 问题定位
  18. qtablewidget翻页禁止_PyQt—QTableWidget实现翻页功能
  19. 快速原型设计工具(Axure)的简单使用
  20. 怎么在Word中制作表格?简单的Word表格制作方法分享

热门文章

  1. spring boot 异常汇总
  2. 洛谷P1396营救(最小生成树)
  3. 如何安装使用PHP MyAdmin
  4. XXX 不是当前用户的有效责任,请联系您的系统管理员
  5. web项目的两个创建形式website和webapplication
  6. 用饮水机教你什么是RAID [转]
  7. lixuxmint系统定制与配置(4)-应用安装
  8. Windows Server 2012系列之二安装AD及创建域
  9. 45. ExtJS ComboBox 下拉列表详细用法
  10. 性能优化--布局优化技巧