[Day 19] 2D 批次渲染 (一)

今日目标

  • 2D批次渲染

DrawLine

照理来说,今天要实作DrawLine但是为什麽没有呢?

这是我预计画线功能接口的样子

void DrawLine(V2f p0, V2f p1, int thinkness, Color c)

只要给两点,就会画出来,然後arg2是线的宽度,所以事实上,他画出来的不是单纯的「线」,而是一条「矩形」。

那应该可以直接用DrawRectangle了吧,但会有一个麻烦的地方,虽说DrawRectangle可以用旋转,达成从A点画线到B点的功能,但是这就要利用给的矩形的原点,推出四个点後,然後再看是哪一点到哪一点的斜率,再从斜率推出旋转的角度,於是我想就索性改写,可以直接带已经算好四个座标进去独立画出来的功能。

进一步想,那原本的DrawRectangle是不是也可变成代入四个点画出的功能,而且好像比画线简单,又再进一步想...是不是可以把这些点集中起来来一次画出来,因为事实上都是矩形...

等一下!这不就是批次渲染吗!

为什麽要批次渲染

现今的商业游戏引擎,一定都会有批次渲染(或是有Instancing),如果熟悉一点GPU管线的话,CPU算好的顶点资料到GPU称作应用期,开发者在处理好绘图相关的逻辑後,也就是在CPU的地方,会传送到GPU,然後接下来才是GPU的工作。

所以问题的消耗点,就是在这个CPU与GPU沟通的过程。例如之前的DrawRectangle就是四个顶点算好後,直接给GPU,叫他画。那当我要画10000个、1000000个矩形的时候,他就会呼叫N次,这会造成消耗,最有可能的结果是,GPU都已经画好了,但卡在CPU还在计算画多少个图形。

上面说到的,「10000个、1000000个矩形的时候,他就会呼叫N次」,这个就是Draw Call,然後在OpenGL里面呼叫
glDrawElements或是glDrawTriangles,就会是一次Draw Call。

批次渲染规划

今天只先说一下我的规划,目前正写到一半,发生一些问题,还没写完也还没测试。

既然要一次画完,首先会在新的iron_render_window底下的CONTEXT.RenderData新增一个VertexBuffer的结构来装我们要的「2D顶点」资料。

一个顶点通常会有这些资料,这些会影响到原本的Shader。

struct Vertex{
    V2f position;
    V2f texture_coordinate;
    V2f color;
}

然後可以看一下color属性,原本在Shader是用uniform,但这次要把它以VertexAttribute(glVertexAttribPointer)得方式传进去,因为如果使用uniform的话,他会变更使用中的Shader的状态,那就要对这个Shader的状态独立画出来,那每改一次Shader状态的颜色,就要再呼叫Draw一次,於是纪录顶点资料的结构 - VertexBuffer长这样

typedef struct VertexBuffer {
    V2f* vertices;
    size_t vertices_count;
    size_t vertices_max;

    V2f* texcoords;
    size_t texcoords_count;
    size_t texcoords_max;

    V4f* colors;
    size_t colors_count;
    size_t colors_max;

    unsigned int* indices;
    size_t indices_count;
    size_t indices_max;

    unsigned int vbo[4]; // positions, texture coordinates, colors, indicess
    unsigned int vao;
} VertexBuffer;

每种资料独立出来,分别有新的VBO储存,而不是包成Vertex是因为这样可以一次性的把同种类的资料进行读取,不用透过计算间距一部分一部分的读取。

然後会在EndRendering的时候,把蒐集且算好顶点,一次性丢给GPU绘制,DrawXXX里的内容就会是把顶点放到这个Vertex Buffer里面。

但这边会有一个问题,假如这一帧要画得顶点已经超过VertexBuffer上限了,换句话说,这一帧的DrawCall有N个(其实通常一定会大於1),目前预想有两种做法:

  1. 加入新顶点的时候检查,如果达到上限,就直接画出
  2. 设置一个新的结构,标示当前Vertex Buffer已满,需要由新的Draw Call纪录,一样在EndRendering汇出

目前会尝试第二种。

参考

今天批次渲染还没完成,原本就预计大概会要跨个两三篇才会完成,所以也没有新的code上传。


<<:  R^2 决定系数 | ML#Day22

>>:  Day 14:第三方 SDK / API

自动化 End-End 测试 Nightwatch.js 串接 Google sheet

之前撰写测试时有提到串接 BrowserStack 的服务,而执行时也可以透过 nightwatch...

【第十五天 - Linked list 题目分析】

先简单回顾一下,今天预计分析的题目: Swap Nodes in Pairs 题目连结:https...

Day19# Leetcode - Palindrome Number

今天是第 19 天,要来写的题目是 Palindrome Number 那麽话不多说,我们就开始吧 ...

【Day 15】Python MySQL

今天发烧用手机打字 後面明天一定补完QQ 明天是不是该想想要做什麽mysql小projectㄌ.....

[从0到1] C#小乳牛 练成基础程序逻辑 Day 19 - for loop 中断点 + watch

已知次数用for loop | 您最好的程序码侦错社 | watch全面追踪 ...