zoukankan      html  css  js  c++  java
  • CSharpGL(30)用条件渲染(Conditional Rendering)来提升OpenGL的渲染效率

    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被改变了。

    1 glBeginQuery(GL_SAMPLES_PASSED, queryId);
    2 glDrawArrays(GL_TRIANGLES, 0, 3);
    3 glEndQuery(GL_SAMPLES_PASSED);

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

     1         /// <summary>
     2         /// 
     3         /// </summary>
     4         /// <returns></returns>
     5         public bool SampleRendered()
     6         {
     7             var result = new int[1];
     8             int count = 1000;
     9             while (result[0] == 0 && count-- > 0)
    10             {
    11                 glGetQueryObjectiv(this.Id, OpenGL.GL_QUERY_RESULT_AVAILABLE, result);
    12             }
    13 
    14             if (result[0] != 0)
    15             {
    16                 glGetQueryObjectiv(this.Id, OpenGL.GL_QUERY_RESULT, result);
    17             }
    18             else
    19             {
    20                 result[0] = 1;
    21             }
    22 
    23             return result[0] != 0;
    24         }

    条件渲染(Conditional Rendering)

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

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

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

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

    1 glBeginConditionalRender(queryId, GL_QUERY_WAIT);
    2 glDrawArrays(GL_TRIANGLE_FAN, 0, numVertices);
    3 glEndConditionalRender();

    示例

    一个特别的3D模型

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

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

      1     /// <summary>
      2     /// demostrates how to perform conditional rendering.
      3     /// </summary>
      4     internal class ConditionalRenderer : RendererBase
      5     {
      6         private const int xside = 5, yside = 5, zside = 5;
      7         private const int pointCount = 10000;
      8         private static readonly vec3 unitLengths = new vec3(1, 1, 1);
      9         private const float scaleFactor = 1.0f;
     10 
     11         private List<Tuple<CubeRenderer, RendererBase, Query>> coupleList = new List<Tuple<CubeRenderer, RendererBase, Query>>();
     12         private DepthMaskSwitch depthMaskSwitch = new DepthMaskSwitch(false);
     13         private ColorMaskSwitch colorMaskSwitch = new ColorMaskSwitch(false, false, false, false);
     14 
     15         private bool enableConditionalRendering = true;
     16 
     17         public bool ConditionalRendering
     18         {
     19             get { return enableConditionalRendering; }
     20             set { enableConditionalRendering = value; }
     21         }
     22 
     23         private bool renderBoundingBox = false;
     24 
     25         public bool RenderBoundingBox
     26         {
     27             get { return renderBoundingBox; }
     28             set { renderBoundingBox = value; }
     29         }
     30 
     31         private bool renderTargetModel = true;
     32 
     33         public bool RenderTargetModel
     34         {
     35             get { return renderTargetModel; }
     36             set { renderTargetModel = value; }
     37         }
     38 
     39         public static ConditionalRenderer Create()
     40         {
     41             var result = new ConditionalRenderer();
     42             {
     43                 var wallRenderer = CubeRenderer.Create(new Cube(new vec3(unitLengths.x * 2, unitLengths.y * 2, 0.1f) * new vec3(xside, yside, zside)));
     44                 wallRenderer.WorldPosition = new vec3(0, 0, 6);
     45                 var boxRenderer = CubeRenderer.Create(new Cube(new vec3(unitLengths.x * 2, unitLengths.y * 2, 0.1f) * new vec3(xside, yside, zside)));
     46                 boxRenderer.WorldPosition = new vec3(0, 0, 6);
     47                 var query = new Query();
     48                 result.coupleList.Add(new Tuple<CubeRenderer, RendererBase, Query>(boxRenderer, wallRenderer, query));
     49             }
     50             for (int x = 0; x < xside; x++)
     51             {
     52                 for (int y = 0; y < yside; y++)
     53                 {
     54                     for (int z = 0; z < zside; z++)
     55                     {
     56                         var model = new RandomPointsModel(unitLengths, pointCount);
     57                         RandomPointsRenderer renderer = RandomPointsRenderer.Create(model);
     58                         renderer.PointColor = Color.FromArgb(
     59                             (int)((float)(x + 1) / (float)xside * 255),
     60                             (int)((float)(y + 1) / (float)yside * 255),
     61                             (int)((float)(z + 1) / (float)zside * 255));
     62                         renderer.WorldPosition =
     63                             (new vec3(x, y, z) * unitLengths * scaleFactor)
     64                             - (new vec3(xside - 1, yside - 1, zside - 1) * unitLengths * scaleFactor * 0.5f);
     65                         var cubeRenderer = CubeRenderer.Create(new Cube(unitLengths));
     66                         cubeRenderer.WorldPosition = renderer.WorldPosition;
     67                         var query = new Query();
     68                         result.coupleList.Add(new Tuple<CubeRenderer, RendererBase, Query>(cubeRenderer, renderer, query));
     69                     }
     70                 }
     71             }
     72 
     73             result.Lengths = new vec3(xside + 1, yside + 1, zside + 1) * unitLengths * scaleFactor;
     74 
     75             return result;
     76         }
     77 
     78         private ConditionalRenderer()
     79         { }
     80 
     81         protected override void DoInitialize()
     82         {
     83             foreach (var item in this.coupleList)
     84             {
     85                 item.Item1.Initialize();
     86                 item.Item2.Initialize();
     87                 item.Item3.Initialize();
     88             }
     89         }
     90 
     91         protected override void DoRender(RenderEventArgs arg)
     92         {
     93             if (this.ConditionalRendering)
     94             {
     95                 this.depthMaskSwitch.On();
     96                 this.colorMaskSwitch.On();
     97                 foreach (var item in this.coupleList)
     98                 {
     99                     item.Item3.BeginQuery(QueryTarget.AnySamplesPassed);
    100                     item.Item1.Render(arg);
    101                     item.Item3.EndQuery(QueryTarget.AnySamplesPassed);
    102                 }
    103                 this.colorMaskSwitch.Off();
    104                 this.depthMaskSwitch.Off();
    105                 var result = new int[1];
    106                 foreach (var item in this.coupleList)
    107                 {
    108                     item.Item3.BeginConditionalRender(ConditionalRenderMode.QueryByRegionWait);
    109                     //if (item.Item3.SampleRendered())
    110                     {
    111                         if (this.renderTargetModel) { item.Item2.Render(arg); }
    112                         if (this.renderBoundingBox) { item.Item1.Render(arg); }
    113                     }
    114                     item.Item3.EndConditionalRender();
    115                 }
    116             }
    117             else
    118             {
    119                 foreach (var item in this.coupleList)
    120                 {
    121                     if (this.renderTargetModel) { item.Item2.Render(arg); }
    122                     if (this.renderBoundingBox) { item.Item1.Render(arg); }
    123                 }
    124             }
    125         }
    126     }
    conditional rendering demo. 

    条件渲染效果

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

    总结

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

  • 相关阅读:
    课程开始的第一次作业
    第四次寒假作业——实现五种语言的选择
    关于改良报告与学习总结(Ⅰ)
    Vue路由守卫之路由独享守卫
    Vue路由守卫之组件内路由守卫
    Vue中如何插入m3u8格式视频,3分钟学会!
    Vue中如何使用less
    第一章 初识爬虫
    【JQuery】注册中实现图片预览
    【Python】多种方式实现生成验证码
  • 原文地址:https://www.cnblogs.com/bitzhuwei/p/CSharpGL-30-conditional-rendering-in-opengl.html
Copyright © 2011-2022 走看看