通過逆重心坐標插值 傳遞多個頂點信息到片段
"Passing whole triangle?Vertices Data to a Fragment, via Inverse Barycentric Coordnate Interpolation."
問題描述
這個問題/需要出自于一個體素系統(tǒng),體素系統(tǒng)構(gòu)建網(wǎng)格時 每個頂點給出一個`int MtlId`材質(zhì)id數(shù)據(jù)。而在渲染片段時,片段為了混合材質(zhì),需要獲取當前三角形3個頂點的 MtlId 和頂點對應(yīng)的BaryCoord重心坐標。
然而,三角形3個頂點的 MtlId 和 BaryCoord 該怎么傳遞給片段著色器呢?
Method 1: +Dummy VertexData | 方法1:通過添加額外的 冗余的頂點數(shù)據(jù)
BaryCoord:?
每個頂點添加一個?`vec3 VertBaryCoord` 的頂點數(shù)據(jù),并且對于每個三角形,其中3個頂點的該條數(shù)據(jù)應(yīng)分別為 `{1, 0, 0}, {0, 1, 0}, {0, 0, 1}`。
由于 頂點著色器varying out傳數(shù)據(jù)給片段著色器時會進行重心坐標插值,因此這些數(shù)據(jù)被傳入片段著色器時 就已經(jīng)是這3個頂點的重心坐標了。
MtlIds
同樣地,在CPU生成網(wǎng)格時,將每個頂點之前的 `int MtlId` 頂點數(shù)據(jù)變?yōu)?`ivec3 MtlIds`,其中3個分量分別是當前三角形3個頂點的 MtlId,三角形內(nèi)3個頂點的該條數(shù)據(jù)均一致。
隨后在頂點著色器中 flat out 傳遞給片段著色器(將會隨機從3個頂點中選一個出來給片段著色器,但由于3個頂點的該數(shù)據(jù)是一致的 因此數(shù)據(jù)無差別),或者默認地?varying out 傳遞(由于三個頂點數(shù)據(jù)一致,因此插值前后無區(qū)別)
e.g.
優(yōu)缺點:
這種方法的跨平臺性很強,因為唯一的變數(shù)只是添加頂點數(shù)據(jù) - 這是每個平臺都基本支持的。
但是,會帶來額外的性能損耗(內(nèi)存開銷增加了很多,同時也會影響到內(nèi)存效率 以降低時間效率)。并且,會影響到‘純粹性’,也就是非常困擾我的 我難以忍受這種不夠純粹的方法 存在于我核心系統(tǒng)上。這些冗余重復(fù)的,有點傻的數(shù)據(jù)。
Method 2: Geometry Shader / Tessellation Shader
我曾在獨立游戲 Ethertia 中實現(xiàn)過這種方法,分別是opengl3 geom?shader和vulkan tess shader對該方法的實現(xiàn)。
通過geom shader 或 tess shader,你可以控制 如何插值圖元內(nèi)的頂點的數(shù)據(jù)。
Geometry Shader (incase OpenGL 3)

圖中的 TriMtlId 則是我們的 MtlIds。而TriMtlWeight則是我們的 BaryCoord。
這種方法相比于上面的“額外頂點數(shù)據(jù)方法” 更neat整潔些。
然而,由于Geomrtry Shader的早期不夠成熟的設(shè)計和過大的靈活性,它的性能存在隱患,已在現(xiàn)代圖形渲染中 不推薦使用。
Tessellation Shader (Control& Evaluation, incase Vulkan)


上面分別是 TessControl 和 TessEval shader。而插值控制在后者。
雖然Tess shader相對晦澀復(fù)雜,但是相比geom shader,具有更好的性能表現(xiàn),和更現(xiàn)代的渲染理念。
Method 3: Ethertia Method
你可能意識到了,這些方法很繁瑣,也比較困擾我。但是由于tess shader方法可用,我也不再繼續(xù)追究。然而我最近在用Unity URP ShaderGraph去做一個shader,在這種情況下 不能用到 geom shader 或 tess shader,我因此感到深深的絕望。在查詢?nèi)W(wǎng)無果后,借助 OpenAI ChatGPT 早年的啟示,我突然想到了這種方法:真是極為簡單和簡潔和強大。
假設(shè)在頂點著色器中,系統(tǒng)對每個頂點給出一個?VertexID 值,即頂點序數(shù)。那么:
只需要幾行,無什么外部/系統(tǒng)依賴。極簡的方法。但很救命。