工程GIT位址:https://gitee.com/yaksue/yaksue-graphics
目标
“頂點緩沖”最初是在《圖形API學習工程(5):圖形管線&頂點緩沖》進行了引入,不過當時沒有好的封裝,這讓後續新内容的添加會導緻較多的代碼的調整。例如:
- 當着色器所需的頂點資料的布局變化時:我需要改動現有的頂點資料與之比對;還需要改動各個圖形API版本中關于頂點資料布局的代碼。
- 如果未來一個mesh将送往多個管線中,而他們的頂點資料布局不一樣,則一個mesh應該對應多個頂點緩沖。
本篇的目标是重構代碼來解決這些問題。另外為了能确定代碼結構沒問題,我将實驗是否能設定多份頂點緩沖并調用多個DrawCall來實作渲染多個mesh。
明确重構方向
1. 頂點資料布局
首先要明确的是 “頂點資料布局” 的概念,我這裡指的是着色器中“每個頂點所攜帶的屬性”:
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL9UEVPpXSU1EMNRVT3V1MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL1YzMzMTNwYTMzEjMxAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
可以明白:
- 當管線中的shader确定下來之後,頂點資料布局也随之确定下來。也就是說,管線隻能有一個頂點資料布局。
是以接下來的重構方向之一是,将頂點資料布局放到“管線”對象中。同時以一個統一的方式指定它們。
2. 模型資料
如果一個mesh将被送到多個管線渲染且它們的頂點資料布局不一樣,則實際上需要多個頂點緩沖。
可以明白:
- “模型”和頂點緩沖應該是一對多的關系。每個布局都有其比對的 頂點緩沖 。
是以,我決定将模型資料抽象出來,并提供接口,讓其為每一個管線都生成其比對的頂點緩沖(精确上講,不需要為每個管線都設定,因為管線之間的頂點資料布局有可能重複,此處待後續更複雜的重構)
實作
詳見代碼改動:
- 藍色部分是對頂點資料布局相關代碼進行重構。
- 紅色部分是抽象出“模型資料”的概念,作為測試讓其實作渲染多個mesh。
其中需要注意的是,我将頂點的屬性種類以以enum來指定:
enum VertexInputAttributeType
{
VIA_POSITION, //頂點位置
VIA_NORMAL, //頂點法線
VIA_COLOR, //頂點顔色
VIA_TEXCOORD, //貼圖UV坐标
};
而關于每一種屬性的占位是多少,目前是寫死的:
//描述一個頂點屬性
struct VertexInputAttributeDescription
{
VertexInputAttributeType Type; //種類
unsigned int Float32Cout; //這個屬性有多少個Float
VertexInputAttributeDescription(VertexInputAttributeType InType)
{
Type = InType;
//在此依照種類對Float32Cout做自動的設定:
switch (Type)
{
case VIA_POSITION:
Float32Cout = 3; //XYZ三個方向
break;
case VIA_NORMAL:
Float32Cout = 3; //XYZ三個方向
break;
case VIA_COLOR:
Float32Cout = 4; //RGBA四個通道
break;
case VIA_TEXCOORD:
Float32Cout = 2; //UV兩個方向
break;
default:
break;
}
}
};
這樣,我便可以用它來指定頂點屬性的布局了:
//作為測試的圖形管線資料:
GraphicsPipelineInfo Info;
//shader檔案:
Info.VertexShaderFile = "TestShader_vs";
Info.PixelShaderFile = "TestShader_ps";
//頂點屬性:
Info.VertexInputAttributeTypes.push_back(VIA_POSITION); //位置
Info.VertexInputAttributeTypes.push_back(VIA_NORMAL); //法線
Info.VertexInputAttributeTypes.push_back(VIA_TEXCOORD); //貼圖UV
随後各個圖形API将根據這一資訊來“布置”自己的管線(詳見代碼)。而模型也知道了該如何提供自己的頂點資料來比對這個布局。
其實理論上,頂點屬性應該是“沒有具體含義”的,其含義應該被展現在shader算法中。我這裡顯式的賦予其“含義”僅僅是為了使用上更容易并讓代碼可讀性更高。不過,這也和HLSL語義對應了起來。(關于HLSL語義的意義詳細見官方文檔,目前我還沒有較深的了解)
效果
後續的發展與問題
- 模型應該根據頂點布局來生成對應的頂點緩沖,而不是管線,因為管線可能存在相同頂點布局的情況,此時則會造成頂點緩沖資料的重複
- Vulkan畫面颠倒問題待修正
- 随後需要對管線相關代碼進行重構,支援多個UniformBuffer/貼圖,支援多個管線。