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),目前預想有兩種做法:
EndRendering
匯出目前會嘗試第二種。