原文地址:http://www.linuxidc.com/Linux/2015-02/114036.htm

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

遮挡查询之前

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

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

  1. void DrawOccluder()
  2. {
  3. glColor3f(0.5f, 0.25f, 0.0f);
  4.  
  5. glPushMatrix();
  6. glScalef(30.0f, 30.0f, 1.0f);
  7. glTranslatef(0.0f, 0.0f, 50.0f);
  8. glutSolidCube(10.0f);
  9. glTranslatef(0.0f, 0.0f, -100.0f);
  10. glutSolidCube(10.0f);
  11. glPopMatrix();
  12.  
  13. glPushMatrix();
  14. glScalef(1.0f, 30.0f, 30.0f);
  15. glTranslatef(50.0f, 0.0f, 0.0f);
  16. glutSolidCube(10.0f);
  17. glTranslatef(-100.0f, 0.0f, 0.0f);
  18. glutSolidCube(10.0f);
  19. glPopMatrix();
  20.  
  21. glPushMatrix();
  22. glScalef(30.0f, 1.0f, 30.0f);
  23. glTranslatef(0.0f, 50.0f, 0.0f);
  24. glutSolidCube(10.0f);
  25. glTranslatef(0.0f, -100.0f, 0.0f);
  26. glutSolidCube(10.0f);
  27. glPopMatrix();
  28. }

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

  1. void DrawSphere(GLint sphereNum)
  2. {
  3.  
  4. ...
  5. glutSolidSphere(50.0f, , );
  6. ...
  7.  
  8. }void DrawModels(void)
  9. {
  10.  
  11. //开启纹理 自动生成纹理坐标
  12. glEnable(GL_TEXTURE_2D);
  13. glEnable(GL_TEXTURE_GEN_S);
  14. glEnable(GL_TEXTURE_GEN_T);
  15.  
  16. //绘制27个不同颜色的球体
  17. for (r = ; r < ; r++)
  18. { for (g = ; g < ; g++)
  19. {
  20. for (b = ; b < ; b++)
  21. {
  22. glColor3f(r * 0.5f, g * 0.5f, b * 0.5f);
  23.  
  24. glPushMatrix();
  25. glTranslatef(100.0f * r - 100.0f,
  26. 100.0f * g - 100.0f,
  27. 100.0f * b - 100.0f);
  28. DrawSphere((r*)+(g*)+b);
  29. glPopMatrix();
  30. }
  31. }
  32. }
  33.  
  34. glDisable(GL_TEXTURE_2D);
  35. glDisable(GL_TEXTURE_GEN_S);
  36. glDisable(GL_TEXTURE_GEN_T);
  37.  
  38. }

在我的机器上没有遮挡查询下渲染的帧率是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后,可以开始遮挡查询了。例如

  1. glBeginQuery(GL_SAMPLES_PASSED, );
  2. glBegin(GL_TRIANGLES);
  3. glVertex3f(1.0f, 1.0f, 0.0f);
  4. glVertex3f(-1.0f, 5.0f, 0.0f);
  5. glVertex3f(6.0f, 20.0f, 0.0f);
  6. glEnd();
  7. 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来提取结果,函数将返回片段或采样的数量。

  1. void glGetQueryObjectiv(GLenum id, GLenum pname, GLint *param);
  2.  
  3. 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.

例:

  1. int count = ; //等待1000次循环
  2. GLuint queryReady = GL_FALSE;
  3. while (!queryReady && count--)
  4. {
  5. glGetQueryObjectuiv(, GL_QUERY_RESULT_AVAILABLE, &queryReady);
  6. }
  7.  
  8. GLuint samples;
  9.  
  10. glGetQueryObjectuiv(, GL_QUERY_RESULT, &samples);
  11. if(samples > )
  12. DrawSomething();

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

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

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

  1. void DrawModels(void)
  2. {
  3. GLint r, g, b;
  4.  
  5. //绘制主遮挡物
  6. DrawOccluder();
  7.  
  8. //在绘制包围体时,越简单越好。关掉纹理,光照等等。
  9. //不需要往缓冲区中写值。
  10. glShadeModel(GL_FLAT);
  11. glDisable(GL_LIGHTING);
  12. glDisable(GL_COLOR_MATERIAL);
  13. glDisable(GL_NORMALIZE);
  14. glDepthMask(GL_FALSE);
  15. glColorMask(, , , );
  16.  
  17. // 画27个立方体
  18. for (r = ; r < ; r++)
  19. {
  20. for (g = ; g < ; g++)
  21. {
  22. for (b = ; b < ; b++)
  23. {
  24. if (showBoundingVolume)
  25. glColor3f(r * 0.5f, g * 0.5f, b * 0.5f);
  26.  
  27. glPushMatrix();
  28. glTranslatef(100.0f * r - 100.0f,
  29. 100.0f * g - 100.0f,
  30. 100.0f * b - 100.0f);
  31. //开始遮挡查询
  32. glBeginQuery(GL_SAMPLES_PASSED, queryIDs[(r*)+(g*)+b]);
  33. //绘制包围体
  34. glutSolidCube(100.0f);
  35. //结束遮挡查询
  36. glEndQuery(GL_SAMPLES_PASSED);
  37. glPopMatrix();
  38. }
  39. }
  40. }
  41.  
  42. //恢复正常的渲染状态
  43. glDisable(GL_POLYGON_STIPPLE);
  44. glShadeModel(GL_SMOOTH);
  45. glEnable(GL_LIGHTING);
  46. glEnable(GL_COLOR_MATERIAL);
  47. glEnable(GL_NORMALIZE);
  48. glColorMask(, , , );
  49. glDepthMask(GL_TRUE);
  50.  
  51. //开启纹理 自动生成纹理坐标
  52. glEnable(GL_TEXTURE_2D);
  53. glEnable(GL_TEXTURE_GEN_S);
  54. glEnable(GL_TEXTURE_GEN_T);
  55.  
  56. //绘制27个不同颜色的球体
  57. for (r = ; r < ; r++)
  58. {
  59. for (g = ; g < ; g++)
  60. {
  61. for (b = ; b < ; b++)
  62. {
  63. glColor3f(r * 0.5f, g * 0.5f, b * 0.5f);
  64.  
  65. glPushMatrix();
  66. glTranslatef(100.0f * r - 100.0f,
  67. 100.0f * g - 100.0f,
  68. 100.0f * b - 100.0f);
  69. //函数中根据,遮挡查询的结果来判断是否要绘制这个球体
  70. DrawSphere((r*)+(g*)+b);
  71. glPopMatrix();
  72. }
  73. }
  74. }
  75.  
  76. glDisable(GL_TEXTURE_2D);
  77. glDisable(GL_TEXTURE_GEN_S);
  78. glDisable(GL_TEXTURE_GEN_T);
  79. }
  80. void DrawSphere(GLint sphereNum)
  81. {
  82. GLboolean occluded = GL_FALSE;
  83.  
  84. if (occlusionDetection)
  85. {
  86. GLint passingSamples;
  87.  
  88. //检查物体是否被完全遮挡
  89. glGetQueryObjectiv(queryIDs[sphereNum], GL_QUERY_RESULT,
  90. &passingSamples);
  91. if (passingSamples == )
  92. occluded = GL_TRUE;
  93. }
  94. //没有被遮挡则绘制
  95. if (!occluded)
  96. {
  97. glutSolidSphere(50.0f, , );
  98. }
  99. }

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

OpenGL 遮挡查询的更多相关文章

  1. OpenGL遮挡查询

    转自:http://www.cnblogs.com/mazhenyu/p/5083026.html 在一个场景中,如果有有些物体被其他物体遮住了不可见.那么我们就不需要绘制它.在复杂的场景中,这可以减 ...

  2. OpenGL超级宝典笔记——遮挡查询 [转]

    目录[-] 遮挡查询之前 包围体 遮挡查询 在一个场景中,如果有有些物体被其他物体遮住了不可见.那么我们就不需要绘制它.在复杂的场景中,这可以减少大量的顶点和像素的处理,大幅度的提高帧率.遮挡查询就是 ...

  3. D3D10/11中的遮挡查询的使用

    原文:D3D10/11中的遮挡查询的使用       在D3D10/11中,有D3D10_QUERY/D3D11_QUERY接口,通过QUERY接口,我们可以查询GPU的一些状态,比如GPU的时间戳信 ...

  4. CSharpGL(31)[译]OpenGL渲染管道那些事

    CSharpGL(31)[译]OpenGL渲染管道那些事 +BIT祝威+悄悄在此留下版了个权的信息说: 开始 自认为对OpenGL的掌握到了一个小瓶颈,现在回头细细地捋一遍OpenGL渲染管道应当是一 ...

  5. OpenGL Insights 阅读有感 - Tile Based架构下的性能调校 翻译

    Performance Tunning for Tile-Based Architecture Tile-Based架构下的性能调校 by Bruce Merry GameKnife译 译序 在大概1 ...

  6. opengl入门学习

    OpenGL入门学习 说起编程作图,大概还有很多人想起TC的#include <graphics.h>吧? 但是各位是否想过,那些画面绚丽的PC游戏是如何编写出来的?就靠TC那可怜的640 ...

  7. OpenGL入门学习(转)

    OpenGL入门学习 http://www.cppblog.com/doing5552/archive/2009/01/08/71532.html 说起编程作图,大概还有很多人想起TC的#includ ...

  8. OpenGL理解

    说起编程作图,大概还有很多人想起TC的#include <graphics.h>吧? 但是各位是否想过,那些画面绚丽的PC游戏是如何编写出来的?就靠TC那可怜的640*480分辨率.16色 ...

  9. OpenGL入门学习(转载)

    说起编程作图,大概还有很多人想起TC的#include <graphics.h>吧? 但是各位是否想过,那些画面绚丽的PC游戏是如何编写出来的?就靠TC那可怜的640*480分辨率.16色 ...

随机推荐

  1. 【php】https请求

    /** * 模拟提交参数,支持https提交 可用于各类api请求 * @param string $url : 提交的地址 * @param array $data :POST数组 * @param ...

  2. 使用线性回归识别sklearn中的手写数字digit

    从昨天晚上,到今天上午12点半左右吧,一直在调这个代码.最开始训练的时候,老是说loss:nan 查了资料,因为是如果损失函数使用交叉熵,如果预测值为0或负数,求log的时候会出错.需要对预测结果进行 ...

  3. Android padding 和margin

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout ...

  4. python中如何使用requests模块下载文件并获取进度提示?

    Reference: https://www.zhihu.com/question/41132103 #!/usr/bin/env python3 import requests from conte ...

  5. 05-老马jQuery教程-动画

    前言 jQuery的动画系统做的非常出色,而且把最常用的显示.隐藏.淡入淡出.滑动显示和折叠凳效果都做了很好的封装.跟jQuery的选择器和事件配合起来,可以实现很多很绚的效果,而且简单易用兼容性好. ...

  6. iOS贝塞尔曲线(UIBezierPath)的基本使用方法

    简介 UIBezierPath是对Core Graphics框架的一个封装,使用UIBezierPath类我们可以画出圆形(弧线)或者多边形(比如:矩形)等形状,所以在画复杂图形的时候会经常用到. 分 ...

  7. [转]Teleport Ultra/Teleport Pro的冗余代码批量清理方法

    原文地址:http://www.abcd9.com/?post=402 Teleport Pro 是款优秀的网站离线浏览工具(即网站整站下载工具),Teleport Ultra是其增强版,但使用此系列 ...

  8. Mac OS X下的移动光标和文字编辑快捷键

    移动光标快捷键 Control-F 光标前进一个字符,相当于右键(F = Forward) Control-B 光标后退一个字符,相当于左键(B = Backward) Control-P 上移一行, ...

  9. ios开发,app调用资源文件到C++的方法

    为了读取资源文件到cpp.供opencv处理,采取的方式是把之前的cpp文件的后缀改成:.mm 然后会出现各种报错,原因是因为命名冲突,前面加上cv::就行. const char* imagePat ...

  10. 关于face alglimnment各种资料,存下来有空慢慢看

    人脸对齐和应用 机器学习--详解人脸对齐算法SDM-LBF 基于MTCNN的人脸自动对齐技术原理及其Tensorflow实现测试 人脸检测——MTCNN CVPR论文<Face Alignmen ...