CSharpGL(30)用条件渲染(Conditional Rendering)来提升OpenGL的渲染效率

当场景中有比较复杂的模型时,条件渲染能够加速对复杂模型的渲染。

条件渲染(Conditional Rendering)

当我们能够断定一个模型被其他模型挡住(因此不会被Camera看到)时,我们就可以跳过对此模型的渲染。这就是条件渲染的根本。

那么如何去判断?方法就是用一个简单的包围盒(比如一个立方体)去渲染一下,看看fragment是不是有变化(即包围盒上的某些部分通过了depth test,最终渲染到Framebuffer上了)。如果没有任何一个fragment发生改变,就说明这个包围盒是被挡住了,那么被包围起来的模型也必然是被挡住了。

下载

CSharpGL已在GitHub开源,欢迎对OpenGL有兴趣的同学加入(https://github.com/bitzhuwei/CSharpGL

原理

本篇需要用到2个知识点。

遮面查询(Occlusion Query)

这里OpenGL提供了一个Query Object。类似Buffer Object,Vertex Array Object等,也是通过glGen*等方式使用的。

Query Object的作用就是记录一个包围盒是否改变了某些fragment。

如下代码所示,在通常的渲染前后用glBeginQuery和glEndQuery包围起来,Query就会记录是否有fragment被改变了。

 glBeginQuery(GL_SAMPLES_PASSED, queryId);
glDrawArrays(GL_TRIANGLES, , );
glEndQuery(GL_SAMPLES_PASSED);

之后用下述方式即可获知是否有fragment被改变了。只要SampleRendered()返回值为false,那么这个模型就不用渲染了。

         /// <summary>
///
/// </summary>
/// <returns></returns>
public bool SampleRendered()
{
var result = new int[];
int count = ;
while (result[] == && count-- > )
{
glGetQueryObjectiv(this.Id, OpenGL.GL_QUERY_RESULT_AVAILABLE, result);
} if (result[] != )
{
glGetQueryObjectiv(this.Id, OpenGL.GL_QUERY_RESULT, result);
}
else
{
result[] = ;
} return result[] != ;
}

条件渲染(Conditional Rendering)

上述Query对象使用时的一个缺点是,CPU必须用循环等待GPU的Query结果。这就拖延了后续渲染步骤,降低了FPS。

为避免CPU循环等待,OpenGL提供了下面2个指令,他们的作用就是用GPU代替了CPU循环的功能。

 glBeginConditionalRender(uint id, uint mode);
glEndConditionalRender();

其使用方式也像Query对象一样,把通常的渲染指令包围起来即可。

 glBeginConditionalRender(queryId, GL_QUERY_WAIT);
glDrawArrays(GL_TRIANGLE_FAN, , numVertices);
glEndConditionalRender();

示例

一个特别的3D模型

我们需要设计一个顶点多而又被一个简单的模型遮挡住的模型。这个复杂模型就用点云表示,用于遮挡的模型就用一个简单的Cube就可以了。

运用CSharpGL封装的功能,很快就可以做出这个模型来。

     /// <summary>
/// demostrates how to perform conditional rendering.
/// </summary>
internal class ConditionalRenderer : RendererBase
{
private const int xside = , yside = , zside = ;
private const int pointCount = ;
private static readonly vec3 unitLengths = new vec3(, , );
private const float scaleFactor = 1.0f; private List<Tuple<CubeRenderer, RendererBase, Query>> coupleList = new List<Tuple<CubeRenderer, RendererBase, Query>>();
private DepthMaskSwitch depthMaskSwitch = new DepthMaskSwitch(false);
private ColorMaskSwitch colorMaskSwitch = new ColorMaskSwitch(false, false, false, false); private bool enableConditionalRendering = true; public bool ConditionalRendering
{
get { return enableConditionalRendering; }
set { enableConditionalRendering = value; }
} private bool renderBoundingBox = false; public bool RenderBoundingBox
{
get { return renderBoundingBox; }
set { renderBoundingBox = value; }
} private bool renderTargetModel = true; public bool RenderTargetModel
{
get { return renderTargetModel; }
set { renderTargetModel = value; }
} public static ConditionalRenderer Create()
{
var result = new ConditionalRenderer();
{
var wallRenderer = CubeRenderer.Create(new Cube(new vec3(unitLengths.x * , unitLengths.y * , 0.1f) * new vec3(xside, yside, zside)));
wallRenderer.WorldPosition = new vec3(, , );
var boxRenderer = CubeRenderer.Create(new Cube(new vec3(unitLengths.x * , unitLengths.y * , 0.1f) * new vec3(xside, yside, zside)));
boxRenderer.WorldPosition = new vec3(, , );
var query = new Query();
result.coupleList.Add(new Tuple<CubeRenderer, RendererBase, Query>(boxRenderer, wallRenderer, query));
}
for (int x = ; x < xside; x++)
{
for (int y = ; y < yside; y++)
{
for (int z = ; z < zside; z++)
{
var model = new RandomPointsModel(unitLengths, pointCount);
RandomPointsRenderer renderer = RandomPointsRenderer.Create(model);
renderer.PointColor = Color.FromArgb(
(int)((float)(x + ) / (float)xside * ),
(int)((float)(y + ) / (float)yside * ),
(int)((float)(z + ) / (float)zside * ));
renderer.WorldPosition =
(new vec3(x, y, z) * unitLengths * scaleFactor)
- (new vec3(xside - , yside - , zside - ) * unitLengths * scaleFactor * 0.5f);
var cubeRenderer = CubeRenderer.Create(new Cube(unitLengths));
cubeRenderer.WorldPosition = renderer.WorldPosition;
var query = new Query();
result.coupleList.Add(new Tuple<CubeRenderer, RendererBase, Query>(cubeRenderer, renderer, query));
}
}
} result.Lengths = new vec3(xside + , yside + , zside + ) * unitLengths * scaleFactor; return result;
} private ConditionalRenderer()
{ } protected override void DoInitialize()
{
foreach (var item in this.coupleList)
{
item.Item1.Initialize();
item.Item2.Initialize();
item.Item3.Initialize();
}
} protected override void DoRender(RenderEventArgs arg)
{
if (this.ConditionalRendering)
{
this.depthMaskSwitch.On();
this.colorMaskSwitch.On();
foreach (var item in this.coupleList)
{
item.Item3.BeginQuery(QueryTarget.AnySamplesPassed);
item.Item1.Render(arg);
item.Item3.EndQuery(QueryTarget.AnySamplesPassed);
}
this.colorMaskSwitch.Off();
this.depthMaskSwitch.Off();
var result = new int[];
foreach (var item in this.coupleList)
{
item.Item3.BeginConditionalRender(ConditionalRenderMode.QueryByRegionWait);
//if (item.Item3.SampleRendered())
{
if (this.renderTargetModel) { item.Item2.Render(arg); }
if (this.renderBoundingBox) { item.Item1.Render(arg); }
}
item.Item3.EndConditionalRender();
}
}
else
{
foreach (var item in this.coupleList)
{
if (this.renderTargetModel) { item.Item2.Render(arg); }
if (this.renderBoundingBox) { item.Item1.Render(arg); }
}
}
}
}

conditional rendering demo.

条件渲染效果

下面让蓝色的墙遮挡住彩色点云。

总结

条件渲染(Conditional Rendering)是一项非常厉害的技术。当要渲染一个数据量很大的模型时,用条件渲染技术能够显著提升渲染效率,因为这个技术能够少画一些被遮挡的内容。

CSharpGL(30)用条件渲染(Conditional Rendering)来提升OpenGL的渲染效率的更多相关文章

  1. Unity3d 基于物理渲染Physically-Based Rendering之最终篇

    前情提要: 讲求基本算法 Unity3d 基于物理渲染Physically-Based Rendering之specular BRDF plus篇 Unity3d 基于物理渲染Physically-B ...

  2. [读书笔记] 二、条件注解@Conditional,组合注解,元注解

    一.条件注解@Conditional,组合注解,元注解 1. @Conditional:满足特定条件创建一个Bean,SpringBoot就是利用这个特性进行自动配置的. 例子: 首先,两个Condi ...

  3. Spring Boot实战笔记(八)-- Spring高级话题(条件注解@Conditional)

    一.条件注解@Conditional 在之前的学习中,通过活动的profile,我们可以获得不同的Bean.Spring4提供了一个更通用的基于条件的Bean的创建,即使用@Conditional注解 ...

  4. 条件随机场Conditional Random Field-CRF入门级理解

    条件随机场Conditional Random Field-CRF入门级理解   有向图与无向图模型 CRF模型是一个无向概率图模型,更宽泛地说,它是一个概率图模型.现实世界的一些问题可以用概率图模型 ...

  5. 画面渲染:实时渲染(Real-time Rendering)、离线渲染(Offline Rendering)[转]

    实时渲染(Real-time Rendering) 实时渲染的本质就是图形数据的实时计算和输出.最典型的图形数据源是顶点.顶点包括了位置.法向.颜色.纹理坐标.顶点的权重等.在第一代渲染技术中(198 ...

  6. 18.AutoMapper 之条件映射(Conditional Mapping)

    https://www.jianshu.com/p/8ed758ed3c63 条件映射(Conditional Mapping) AutoMapper 允许你给属性添加条件,只有在条件成立的情况下该成 ...

  7. CSharpGL(0)一个易学易用的C#版OpenGL

    +BIT祝威+悄悄在此留下版了个权的信说: CSharpGL(0)一个易学易用的C#版OpenGL CSharpGL是我受到SharpGL的启发,在整理了SharpGL,GLM,SharpFont等开 ...

  8. 为什么说在使用多条件判断时switch case语句比if语句效率高?

    在学习JavaScript中的if控制语句和switch控制语句的时候,提到了使用多条件判断时switch case语句比if语句效率高,但是身为小白的我并没有在代码中看出有什么不同.去度娘找了半个小 ...

  9. Ogre 渲染目标解析与多文本合并渲染

    实现目标 因为需求,想找一个在Ogre中好用的文本显示,经过查找和一些比对.有三种方案 一利用Overlay的2D显示来达到效果. http://www.ogre3d.org/tikiwiki/tik ...

随机推荐

  1. 消息队列 Kafka 的基本知识及 .NET Core 客户端

    前言 最新项目中要用到消息队列来做消息的传输,之所以选着 Kafka 是因为要配合其他 java 项目中,所以就对 Kafka 了解了一下,也算是做个笔记吧. 本篇不谈论 Kafka 和其他的一些消息 ...

  2. 一步一步教你用CSS画爱心

    今天小颖给大家分享一个用CSS画的爱心,底下有代码和制作过程,希望对大家有所帮助. 第一步: 先画一个正方形.如图: <!DOCTYPE html> <html> <he ...

  3. [C#] 简单的 Helper 封装 -- SecurityHelper 安全助手:封装加密算法(MD5、SHA、HMAC、DES、RSA)

    using System; using System.IO; using System.Security.Cryptography; using System.Text; namespace Wen. ...

  4. 套用JQuery EasyUI列表显示数据、分页、查询

    声明,本博客从csdn搬到cnblogs博客园了,以前的csdn不再更新,朋友们可以到这儿来找我的文章,更多的文章会发表,谢谢关注! 有时候闲的无聊,看到extjs那么肥大,真想把自己的项目改了,最近 ...

  5. 《LoadRunner12七天速成宝典》签售会2016-12-17北京

    报名地址: http://www.after615.com/actives/s?id=3141&time=1480042829608&sign=9ac8e25e9ab3cf57f613 ...

  6. IL异常处理

    异常处理在程序中也算是比较重要的一部分了,IL异常处理在C#里面实现会用到一些新的方法 1.BeginExceptionBlock:异常块代码开始,相当于try,但是感觉又不太像 2.EndExcep ...

  7. python 数据类型---文件二

    1.打印进度条 import sys,time for i in range(20): sys.stdout.write("#") sys.stdout.flush() #不等缓冲 ...

  8. FILE文件流的中fopen、fread、fseek、fclose的使用

    FILE文件流用于对文件的快速操作,主要的操作函数有fopen.fseek.fread.fclose,在对文件结构比较清楚时使用这几个函数会比较快捷的得到文件中具体位置的数据,提取对我们有用的信息,满 ...

  9. DevOps对于企业IT的价值

    其实从敏捷延展开的 DevOps 概念很早就已经被提出,不过由于配套的技术成熟度水平层次不齐, DevOps 的价值一直没有有效地发挥出来.现如今,随着容器技术的发展, DevOps 在企业中的实践难 ...

  10. DevExpress - 使用 GaugeControl 标尺组件制作抽奖程序 附源码

    前不久,公司举办了15周年庆,其中添加了一个抽奖环节,要从在读学员中随机抽取幸运学员,当然,这个任务就分到了我这里. 最后的效果如下,启动有个欢迎页面,数据是来自Excel的,点击开始则上面的学号及姓 ...