@author: 白袍小道
轉載悄悄說明下
隨緣查看,施主開心就好
說明:
本篇繼續Unreal搬山部分的渲染模塊的Shader部分,
主要牽扯模塊RenderCore, ShaderCore, RHI, Materia.
可能分成N篇。
(這里放入的UE的模塊框)
(下一篇主要是UE燈光和着色簡要[ush以及對應結構,和UE代碼和DX部分],然后是巴拉巴拉)
前言:
部分算法和流程的實現原理,和細節(往往這部分會成為優化的處理口)。
梳理UEShader的結構,底層的接入,分層。
UE着色使用和細節部分。
對比反觀差距和原因
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
第一部分、渲染管線和着色
Shading Models
描述物體的顏色如何根據表面等因素而變化 (例如方向,視圖方向,和照明)
1、通常具有控制外觀變化的屬性。
2、控制這些變化的屬性而決定了變化。
評估
設計着色實現時,需要根據計算結果進行划分他們的評估頻率。
首先,確定一個給定的結果在整個繪制調用中,計算總是不變的。在這種情況下,計算應用程序可以通過GPU計算(通常在CPU上)執行嗎。着色器可以用於特別昂貴的計算。結果被傳遞給圖形API通過統一着色器輸入。
說明
1、虛擬機
a\ 目前的着色語言都是 C-likelike 的着色語言,比如 HLSL,CG 和 GLSL GLSL,其被編譯成獨立於機器的匯語言 語言,也稱為中間( IL )。
這些匯編語言在單獨的階段,通常是驅動中被轉化成實際機器 )。
這些匯編語言在單獨的階段,通常是驅動中被轉化成實際機器 語言。這樣的安排可以兼容不同硬件實現些匯編被看做是定義一個作為着色譯器.
b\ 着色語言虛擬機可以理解為一個處多種類型寄存器 和數據源、預編了一系列指令的處理器。
2、單指令多數據( SIMD), 寄存器.
a\ 一次DrawCall會通過API做一次(一系列)的圖元繪制,從而驅使圖形管線運行。[如Draw,DrawInstance, …..]
b\ 輸入,輸出和交接。
c\ Shader的語句、加載和編譯。
DX10 虛擬機
語法樹
划分
1、頂點着色
發生在圖元裝配后
頂點着色器(VS)階段處理來自輸入匯編器的頂點,執行每個頂點的操作,如轉換、蒙皮、變形和每個頂點的光照,並編制到輸出結構交付給下一個管道。
(頂點着色器總是操作單個輸入頂點並產生單個輸出頂點。頂點着色器階段必須始終處於活動狀態,以便管道執行。
如果不需要頂點修改或轉換,則必須創建一個直通頂點着色器並將其設置為管道。)
a\ 輸入和輸出:
每個頂點着色器輸入頂點可以由16個32位向量組成(每個頂點最多4個分量),每個輸出頂點可以由16個32位4分量向量組成。
所有頂點着色器都必須至少有一個輸入和一個輸出,可以是一個標量值。
b\ vertexshader階段可以使用輸入匯編程序生成的兩個系統值:VertexID和InstanceID(參見系統值和語義)。
由於VertexID和InstanceID在頂點級別都是有意義的,並且硬件生成的ID只能被輸入到理解它們的第一階段,因此這些ID值只能被輸入到vertexshader階段。
c\ 頂點着色器總是在所有頂點上運行,包括帶有鄰接的輸入基元拓撲中的相鄰頂點。
頂點着色器執行的次數可以使用VSInvocations管道統計從CPU查詢。
2、可選鑲嵌
描述:
Direct3D 11運行時支持三個實現鑲嵌的新階段,它將低細節細分曲面轉換為GPU上的高細節原語。
鑲嵌瓷磚(或分解)高階表面成適合渲染的結構。
通過在硬件中實現鑲嵌,圖形管道可以評估較低的細節(較低的多邊形計數)模型和渲染較高的細節。
雖然可以進行軟件鑲嵌,但是由硬件實現的鑲嵌可以生成大量的視覺細節(包括對位移映射的支持),而不需要向模型大小添加視覺細節和刷新率。
概括:鑲嵌使用GPU計算更詳細的表面從一個由四邊形斑塊,三角形斑塊或等值線構成的表面。
HullShader: |
一個可編程的着色器階段,它產生一個幾何貼片(和貼片常量),對應於每個輸入貼片(四邊形、三角形或直線). |
外殼着色器(每個補加點調用一次)將定義低階表面的輸入控制點轉換為構成補加的控制點。 |
ID3D11Device:: CreateHullShader
ID3D11DeviceContext::HSSetShader
|
|
Tessellator |
一個固定的函數管道階段,它創建表示幾何patch的域的抽樣模式,並生成一組較小的對象(三角形、點或線)來連接這些樣本 |
將一個域(四邊形、三邊形或直線)細分為許多較小的對象(三角形、點或直線)。將uv(和可選的w)坐標和表面拓撲(歸一化的坐標域)輸出到域着色器階段。 |
域着色器在每個tessellator階段點調用一次,並計算表面位置。 |
|
Domain |
一個可編程着色器階段,計算對應於每個域樣本的頂點位置。 |
域着色器計算輸出補丁中細分點的頂點位置,其中每個tesselator階段輸出點運行一次,並且對tesselators階段輸出UV坐標、船體着色器輸出補丁和船體着色器輸出補刪常量具有只讀訪問權限。 |
ID3D11Device:: CreateDomainShader
|
|
3、Geometry Shader
幾何着色器(GS)階段運行應用程序指定的着色器代碼,將頂點作為輸入,並能夠在輸出上生成頂點。
(不像頂點着色器操作單個頂點,幾何着色器的輸入是一個完整語義的頂點(兩個頂點表示線,三個頂點表示三角形,或者單個頂點表示點)。
幾何體着色器還可以將邊緣相鄰基元的頂點數據作為輸入(對於一條直線,額外的兩個頂點,對於三角形,額外的三個頂點)。
下圖顯示了一個三角形和一條有相鄰頂點的直線。)
a\ 可以使用由IA自動生成的SV_PrimitiveID系統生成的值。
b\ 能夠輸出多個頂點,形成單個選定的拓撲(可用的GS階段輸出拓撲有:tristrip、linestrip和pointlist)。
c\ 輸出可以通過流輸出階段反饋到光柵化階段和/或內存中的頂點緩沖區。提供給內存的輸出被擴展到單獨的點/線/三角形列表(它們將被傳遞給光柵化器)。
4、Pixel Shader
像素着色器階段(PS)支持豐富的着色技術,例如逐像素光照和后期處理。
像素着色器是一個程序,它結合了常量變量、紋理數據、每個頂點值的插值和其他數據來產生每個像素的輸出。
對於一個原語覆蓋的每個像素,rasterizer階段只調用一次像素着色器,但是,可以指定一個空着色器來避免運行一個着色器。
a\ 當對紋理進行多采樣時,每個覆蓋的像素只調用一次像素着色器,同時對每個覆蓋的多采樣進行深度/模板測試。通過深度/模版測試的樣本將使用像素着色器輸出顏色進行更新。(所以適當減少)
b\ 像素着色器固有函數產生或使用屏幕空間x和y的數量導數,導數最常用的用途是計算紋理采樣的詳細程度計算,在各向異性濾波的情況下,選擇沿各向異性軸的樣本。
通常,硬件實現同時在多個像素(例如2x2網格)上運行一個像素着色器,以便在像素着色器中計算的量的導數可以合理地近似為相鄰像素中同一執行點上的值的增量。
c\ 輸入:
輸入將被限制(超過會截取)在16(無配置Geo着色)or 32、 32位、4個組件。
關鍵詞:頂點屬性,插值,覆蓋,抽樣,
d\ 輸出
像素着色器最多可以輸出8 32位4分量的顏色,如果像素被丟棄,則不輸出顏色。像素着色器輸出寄存器組件在使用之前必須聲明;每個寄存器都允許有一個不同的輸出-寫入掩碼。
使用depth-write-enable狀態(在輸出合並階段)來控制是否將深度數據寫入深度緩沖區(或使用丟棄指令丟棄該像素的數據)。
像素着色器還可以輸出可選的32位、1個組件、浮點數、深度值來進行深度測試(使用SV_Depth語義)。
深度值在深度寄存器中輸出,並替換深度測試的插值深度值(假設啟用深度測試)。無法在使用固定函數深度和着色器深度之間動態變化。
像素着色器不能輸出模板值。
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
第二部分、Unreal 着色器相關
DX:
1、編譯,讀寫
D3DCompileFromFile(_In_ LPCWSTR pFileName,
_In_reads_opt_(_Inexpressible_(pDefines->Name != NULL)) CONST D3D_SHADER_MACRO* pDefines,
_In_opt_ ID3DInclude* pInclude,
_In_ LPCSTR pEntrypoint,
_In_ LPCSTR pTarget,
_In_ UINT Flags1,
_In_ UINT Flags2,
_Out_ ID3DBlob** ppCode,
_Always_(_Outptr_opt_result_maybenull_) ID3DBlob** ppErrorMsgs);
D3DCompile(_In_reads_bytes_(SrcDataSize) LPCVOID pSrcData,
_In_ SIZE_T SrcDataSize,
_In_opt_ LPCSTR pSourceName,
_In_reads_opt_(_Inexpressible_(pDefines->Name != NULL)) CONST D3D_SHADER_MACRO* pDefines,
_In_opt_ ID3DInclude* pInclude,
_In_opt_ LPCSTR pEntrypoint,
_In_ LPCSTR pTarget,
_In_ UINT Flags1,
_In_ UINT Flags2,
_Out_ ID3DBlob** ppCode,
_Always_(_Outptr_opt_result_maybenull_) ID3DBlob** ppErrorMsgs);
D3DCompressShaders(_In_ UINT uNumShaders,
_In_reads_(uNumShaders) D3D_SHADER_DATA* pShaderData,
_In_ UINT uFlags,
_Out_ ID3DBlob** ppCompressedData)
D3DReadFileToBlob(_In_ LPCWSTR pFileName,_Out_ ID3DBlob** ppContents)
D3DWriteBlobToFile(_In_ ID3DBlob* pBlob,_In_ LPCWSTR pFileName, _In_ BOOL bOverwrite)
2、創建
CreateVertexShader(
_In_reads_(BytecodeLength) const void *pShaderBytecode,
_In_ SIZE_T BytecodeLength,
_In_opt_ ID3D11ClassLinkage *pClassLinkage,
_COM_Outptr_opt_ ID3D11VertexShader **ppVertexShader)
CreateXXXShader類似
Unreal
Unreal的Shader處理包括了:ush的包含,編譯得到轉儲的着色器usf,平台編譯器編譯,創建和使用(綁定)。
1、Global Shaders
全局shader是用於操作固定幾何體(如:full screen quad)的shader,並且它不需要與materials產生交互,例如:陰影過濾、后處理。
這種類型的shader在內存中只有一份實例.
2、Materia
材質由一些控制材質如何渲染的狀態和一些控制材質如何與渲染Pass shader交互的材質輸入(material inputs)組成。
3、Vertex Factories 和 MeshTypes
Material必須能夠賦給各種類型的Mesh Types, 這個是通過和Vertex Factories 配合完成的。 一個FVertexFactoryType表示唯一的Mesh Type。
一個FVertexFactory的實例存有每個幾何體的數據,以便支持特定的Mesh Type。
引擎內Shader位於:Engine\Shaders\Private(Public)下
(詳細分析和說明在下一篇)
使用部分
ShaderCore:
FShader、FGlobalShader、
FShaderType, FVertexFactory
FShaderPipeline, FShaderTarget
材質的編譯
過程說明:
1、生成材質的Shader代碼【只是Shader文件】
2、構建編譯環境,且添加相關文件路徑
3、編譯[可以異步],成功就緩存起來
3.1 創建了一個臨時引用計數指針[主要是確保操作一個引用的着色器映射[或查找]將導致這個着色器映射被刪除]
3.2 往ShaderMapsBeingCompiled添加[占個位置]
3.3 分配唯一編譯ID,配置編譯環境
3.4 迭代處理所有頂點工廠的類型,編譯這個材質和頂點工廠類型組合的所有網格材質着色器。---------FVertexFactoryType
3.5 迭代處理所有材質Shader的類型 ------FShaderType
3.6 迭代處理所有材質Shader管線的類型 ------FShaderPipelineType
3.7 進入映射編譯着色器
類關系: