游戲圖形學入門知識整理

分享和整理一些覺得不錯的教程和理解

在此感謝各位老師!

教程:
線性代數(shù)基礎:https://www.bilibili.com/video/BV1ib411t7YR?p=1
GAMES101-現(xiàn)代計算機圖形學入門-閆令琪:https://www.bilibili.com/video/BV1X7411F744
GAMES202-高質量實時渲染-閆令琪:https://www.bilibili.com/video/BV1YK4y1T7yY
華中科技大學-計算機圖形學-萬琳:https://www.bilibili.com/video/BV1Zj411f7S3?p=13&spm_id_from=pageDriver
論壇:
計算機圖形學與混合現(xiàn)實研討會
博客:
馮樂樂(Shader入門精要)http://candycat1992.github.io/

GPU渲染管線的工作過程

image.png

幾何階段

空間變換:模型空間(左手)→世界空間(左手)→觀察空間(右手)
image.png
投影準備:觀察空間→觀察空間(投影變換)→觀察空間(裁剪空間)

經過以上變換,此時物體處在裁剪空間,
★下圖需要注意,每個教材的解釋略有不同,下圖直接就齊次除法變成規(guī)范化的了
實際上這里只是為真正是投影(齊次除法)做準備,此時裁剪面依然是梯形四棱錐形態(tài)
目的:
1.為后面真正投影做準備,賦予W特殊意義。
2.對X,Y,Z縮放,W作為范圍值,便于裁剪。
裁剪空間之前,W=0表示矢量方向,W=1表示點,投影變換之后,W的意義改變了,如下
投影變換對X,Y,Z分量進行縮放,W分量變成-z,如X,Y,Z在W范圍內[-w,w],說明該頂點在裁剪空間內
Unity下,觀察空間為右手坐標系,列矩陣右乘,投影變換后Z分量范圍為[-w,w]
DirectX,投影變換后Z為[0,w]
進入裁剪空間后,右手坐標系,轉為左手坐標系,離攝像機越遠Z值越大


image.png
屏幕映射:規(guī)范化的觀察空間(裁剪)→屏幕空間(真正的投影)

齊次除法=透視除法=歸一化的設備坐標NDC(OpenGL)=W分量除以X,Y,Z分量
裁剪空間→NDC(經過齊次除法后,變換到一個立方體內)
立方體X,Y,Z分量的范圍是[1,-1](OpenGL)
DirectX中Z分量是[0,1]
Unity=OpenGL
Unity中屏幕空間左下角是[0,0],右上角是[pixelWidth,pixelHeight]
由于當前的X,Y都是[1,-1],所以屏幕映射就是一個縮放的過程
此時Z分量經過齊次除法,也就是除W,得到的數(shù)值直接存進了深度緩沖區(qū),這步是自動的,當然也可手動
W分量的意義主要是充當分母來得到NDC

image.png

以上就是從模型空間變換到屏幕坐標的過程

光柵化階段

image.png
下面說下關于屏幕坐標的問題

視口空間坐標公式如下


image.png

上面公式的思想就是,首先對裁剪空間下的坐標進行齊次除法,得到范圍在[ ? 1, 1] 的 NDC,然后再將其映射到范圍在[ 0, 1] 的視口空間下的坐標。
ComputScreenPos 用法


image.png

image.png

Unity中先在頂點著色器里將其映射到范圍[ 0, W] ,然后再片段著色器中自己手動齊次除法變?yōu)閇 0, 1] 。

z和w值就是裁剪空間下的值。
詳情請看ComputScreenPos ,其定義位于UnityCG.cginc中

更新:2022/8/8
CPU部分:
Unity內置管線 Build-in
調用Render()→
剔除:視錐剔除、遮擋剔除、層級剔除→
渲染順序:按距離、渲染隊列→
打包數(shù)據(jù)、參數(shù),調用Shader:SetPassCall(渲染狀態(tài),剔除,混合模式等),DrawCall(模型數(shù)據(jù))→
(頂點坐標,法線,UV,切線,頂點色,索引列表)
(世界變換矩陣,視角VP矩陣,fov)
(shader,材質參數(shù),燈光信息)

GPU部分:(頂點處理→圖元裝配及光柵化→片元處理→輸出合并→Framebuffer)
Shader處理(GPU渲染管線)→
幀緩沖區(qū)→
后處理→
再次Shader處理(GPU渲染管線)→
最終結果顯示到屏幕

頂點Shader:(MVP)
模型空間→(Model Matrix)→世界空間→(View Space)→相機空間→(Projection Matrix)→裁剪空間
經過投影矩陣變換(將三維物體投影到2D平面上)


image.png

硬件操作階段(圖元裝配及光柵化階段):
裁剪空間→(裁剪操作)→


image.png

(透視除法)→NDC標準化設備坐標(Z值保留,就是光柵化后片元 深度值)→背面剔除


image.png

(視口轉換,將-1,1轉換到比如1920*1080的屏幕區(qū)間)→屏幕坐標→
image.png

圖元裝配(將點連線成面)→光柵化(填充顏色像素)→片元

片元數(shù)據(jù)(color,depth)→Alpha測試→模板測試StencilTest→深度測試DepthTest→混合Blending→幀緩沖區(qū)(colorbuffer,depthbuffer,stencilbuffer)

什么視Early-Z?
————————————————
版權聲明:本文為CSDN博主「白筱風」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權協(xié)議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/whitebreeze/article/details/118688150

image.png

在以下幾種情況中,Ealry-Z會不生效

開啟Alpha Test 或 clip/discard 等手動丟棄片元操作
手動修改GPU插值得到的深度
開啟Alpha Blend
關閉深度測試Depth Test
注:前兩點情況原理類似,由于手動進行了片元的丟棄,會導致深度測試篩選出的片元也可能會被舍棄;第三點是由于開啟了Alpha Blend一般會關閉深度寫入,所以也不會生效;第四點關閉深度測試自然不會生效


image.png

image.png

有大量OverDraw的場景中使用Z-prepass可以很好的減小消耗
如渲染頭發(fā):
第一個pass用于生成Z Buffer:開啟透明度測試僅通過不透明的測試,并關閉背面剔除,開啟深度寫入,關閉顏色緩沖區(qū)寫入,只返回透明度值
之后的3個PASS與之前類似:第一個是渲染不透明物體,并剔除背面,設置深度測試為等于,關閉深度寫入
第二個渲染背面,剔除正面,并關閉深度寫入,深度測試為小于
第三個渲染正面,剔除背面,并開啟深度寫入,深度測試同上
DepthPrePass示范:

Pass {
            Tags{"LightMode"="DepthPrePass"}
            ZWrite On
            ColorMask 0
            Cull Off
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
            struct Attributes
            {
                float4 vertex : POSITION;
                float4 texcoord : TEXCOORD0;
                float4 color : COLOR;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct Varyings
            {
                float4 pos : SV_POSITION;
                float2 uv:TEXCOORD0;
                UNITY_VERTEX_INPUT_INSTANCE_ID
                UNITY_VERTEX_OUTPUT_STEREO
            };
            Varyings vert (Attributes input)
            {
                Varyings output = (Varyings)0;
                float3 worldPos = WaveVertex(input.vertex, input.texcoord.xy, input.color, _WaveSpeed, _GrassWaveIntensity);
                output.pos = TransformWorldToHClip(worldPos);
                output.uv = TRANSFORM_TEX(input.texcoord.xy, _MainTex);
                return output;
            }
            float4 frag (Varyings input) : SV_Target
            {
                float4 albedo = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, input.uv)*_Color;
                float4 col = albedo * _Color;
                clip(col.a - _Cutoff);
                return 0;
            }
            ENDHLSL
        }
常用數(shù)學知識

Sin:對邊比斜邊
Cos:鄰邊比斜邊
Tan:對邊比臨邊。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容