UnityShader——SSAO

目錄

1.是什么

2.原理

3.各部分解釋

2.1.從屏幕空間到視圖空間

2.2.以法線半球為基,獲取隨機向量

2.3.應用偏移,并將其轉換為uv坐標

2.4.獲取深度

2.5.比較并計算貢獻

2.6.最后計算

4.改進

4.1.平滑過渡

4.2.模糊

5.變量和語句解釋

5.1._DepthBias

5.2._RangeCheck

5.3.ssDepth >= 0.9999

6.其他事項

6.1.顏色疊加

6.2.向量的隨機

6.3.墻面噪聲

7.效果演示


1.是什么

? ? ? ? SSAO,全稱Screen Space Ambient Occlusion,即屏幕空間環境光遮蔽。其用處是用來模擬全局光照下,一些細節處的陰影。如墻角,縫隙等。也可以讓畫面整體的立體感增強。

? ? ? ? SSAO是由AO發展而來,AO由于性能問題難以被用于實時渲染,因此出現了SSAO,以相對差的效果換取性能。


2.原理

? ? ? ? 對于一個屏幕上像素點而言,將其通過逆變換和深度紋理轉換為視圖空間的點。然后以其法線半球為基,生成隨機向量,用該向量對該點進行偏移,再將偏移后的點轉到屏幕空間,用此時的點對深度紋理進行采樣,得到一個采樣深度,用該深度與原深度(未偏移的點采樣的深度)比較,如果采樣深度小于原深度,說明被遮擋,計算其貢獻;反之未遮擋,貢獻為0。將一個點的每一次偏移的貢獻相加除以偏移的次數,即為該點最終的顏色。

? ? ? ? 我說的可能沒那么清楚,下面通過畫圖演示一下過程(雖然圖畫的也丑就是了):


3.各部分解釋

2.1.從屏幕空間到視圖空間

? ? ? ? 這里采用的是通過先將點轉換到遠裁剪面,然后通過真實深度獲取真實的視圖空間的坐標。參考了這篇文章(https://zhuanlan.zhihu.com/p/92315967)中的方法一。

????????這里簡單講述其原理:

? ? ? ? 我們知道,一個點從世界坐標轉為屏幕坐標需要進行視圖變換(世界空間->視圖空間),投影變換(視圖空間->裁剪空間),透視除法(裁剪空間->ndc空間),視口映射(ndc空間->屏幕空間)。那么我們只需要反向進行就能夠得到一個屏幕坐標在視圖空間的坐標。

? ? ? ? 首先是將屏幕坐標轉到ndc空間,這里可以直接調用shader中的函數來計算,需要注意的是,這里的screenPos需要除以其w分量才能正常使用(如果有uv坐標,可以直接使用uv坐標):

//screenPos
float4 screenPos = ComputeScreenPos(UnityObjectToClipPos(v.vertex));
float2 ndcUV = (screenPos.xy / screenPos.w) * 2 - 1;//uv
float2 ndcUV = uv * 2 - 1;

? ? ? ? 然后是將ndc轉為裁剪,我們先將該點視為遠裁剪面上的點,則:

float3 clipPos = float3(ndcUV.x, ndcUV.y, 1) * _ProjectionParams.z;

? ? ? ? 然后將裁剪轉為視圖,由于轉為視圖后仍是原裁剪面上的點,所以乘以該點的線性深度值來獲取真實坐標。之所以用clipPos.xyzz進行計算,則是因為裁剪空間下,遠裁剪面的zw相同。

//獲取深度和法線(因為后面要用,所以這里將法線一起獲取了)
float4 depthNormal = tex2D(_CameraDepthNormalsTexture, f.uv);
float3 ssNormal; //ss -> Screen Space
float ssDepth; 
DecodeDepthNormal(depthNormal, ssDepth, ssNormal);
float ssDepth01 = Linear01Depth(ssDepth);//變換
float3 viewPos = mul(unity_CameraInvProjection, clipPos.xyzz).xyz * ssDepth01;

? ? ? ? 至此,視圖空間的坐標已得到。

2.2.以法線半球為基,獲取隨機向量

? ? ? ? 我們首先需要知道TBN矩陣,它是由切線,副切線,法線三者構成的一個3*3的矩陣,用途是做切線空間與其他空間轉換的媒介。并且這種轉換不會改變向量的長度(前提是三個都是單位向量)。

? ? ? ? 所以我們先在切線空間中隨機生成一個x在[-1,1],y在[-1,1],z在[0,1]的向量,然后將其轉換到視圖空間下。

float3 viewNormal = normalize(ssNormal);
//隨機生成,是正交基呈現隨機性
float3 viewTangent = normalize(GetRandomVec(f.uv.xy));
float3 viewBitangent = cross(viewTangent, viewNormal);
viewTangent = cross(viewBitangent, viewNormal);
float3x3 TBN = float3x3(viewTangent.x, viewBitangent.x, viewNormal.x,viewTangent.y, viewBitangent.y, viewNormal.y,viewTangent.z, viewBitangent.z, viewNormal.z);//for循環中的語句
float3 randomVec = GetRandomVecHalf(f.uv.yx * i);
//_AORadius是一個由c#腳本傳進的參數,目的是控制陰影的大小
float3 randomVecView = mul(TBN, randomVec) * _AORadius;

2.3.應用偏移,并將其轉換為uv坐標

? ? ? ? 將隨機向量應用到原點,然后通過一系列轉換將其變為uv坐標,以采樣深度法線紋理。

float3 viewOffPos = viewPos + randomVecView;
float4 clipOffPos = mul(unity_CameraProjection, float4(viewOffPos, 1));
float2 sampleUV = clipOffPos.xy / clipOffPos.w;
sampleUV = sampleUV * 0.5 + 0.5;

2.4.獲取深度

? ? ? ? waaaagh!

//獲取深度
float4 sampleDepthNormal = tex2D(_CameraDepthNormalsTexture, sampleUV);
float sampleDepth;
//獲取這個法線的原因是我懶得單獨獲取深度了
float3 sampleNormal;
DecodeDepthNormal(sampleDepthNormal, sampleDepth, sampleNormal);

2.5.比較并計算貢獻

? ? ? ? 需要注意的是,這里比較的是實際的深度值,需要經過LinearEyeDepth轉換。

? ? ? ? 我這里使用大于判斷,是因為最后會將進行1 - ao的運算,相當于黑白取反。

//for外
ssDepth = LinearEyeDepth(ssDepth);//for內
sampleDepth = LinearEyeDepth(sampleDepth);
//_DepthBias:防止自遮擋
float depthDiff = sampleDepth - ssDepth - _DepthBias;
//_RangeCheck:去除不正常的陰影
if (depthDiff > 0 && depthDiff < _RangeCheck)
{ao += 1;
}

2.6.最后計算

? ? ? ? 取平均。

//1-是因為上面進行了相反的運算,所以這里1-再反一次;
//pow和AOStrength都是為了控制強度
ao = 1 - pow(ao / _SampleTime, 1) * _AOStrength;

4.改進

4.1.平滑過渡

? ? ? ? 添加距離衰減,遠距離貢獻小,近距離貢獻大;

? ? ? ? 同樣因為取反操作,所以這里的代碼邏輯為:遠距離貢獻大,近距離貢獻小。

float weight = smoothstep(0, _AORadius, length(randomVec));float depthDiff = sampleDepth - ssDepth - _DepthBias;
if (depthDiff > 0 && depthDiff < _RangeCheck)
{ao += 1 * weight;
}

4.2.模糊

? ? ? ? 因為直接生成的ssao會呈現一種噪聲密布的狀態

就像這樣

?? ? ? ? 所以需要對其進行模糊,模糊的方法很多,我使用的是高斯模糊,原理就不說明了。效果如下:

模糊后的

5.變量和語句解釋

5.1._DepthBias

? ? ? ? 用于防止自遮擋,因為有時會出現由于精度誤差導致的自己遮擋自己的問題。這個變量會將最后的深度差再減小一些,或者理解為將采樣的深度適當減小一些。這樣就不會出現自遮擋的問題了。

5.2._RangeCheck

? ? ? ? 有時我們會發現,明明不該出現陰影的地方出現了陰影,比如兩個僅僅只有前后關系的物體交界處。這個變量就是為了防止這種情況,如果深度差小于指定值,才會計算貢獻,反之舍棄。

奇怪的陰影

5.3.ssDepth >= 0.9999

? ? ? ? 上面沒有寫出來,其位置是在片元著色器中用原點獲取深度之后。用處是為了防止天空盒與物體交界處出現陰影(理論上_RangeCheck就能解決這問題,但不知道什么原因不行):

if (ssDepth >= 0.9999)
{return 1;
}
奇怪的陰影2

6.其他事項

6.1.顏色疊加

? ? ? ? 最后ssao求出來后還有的顏色疊加過程,我是圖方便直接疊上去了。

6.2.向量的隨機

? ? ? ? 向量的隨機性會極大程度地影響最后ssao的效果,所以請盡量保證向量的隨機性。

6.3.墻面噪聲

? ? ? ? 我的實現會導致_AORadius增大時,墻面上會出現噪點,可以通過增大_SampleTime來降低其存在感。當然這不是一個好辦法,我解決后會更新該文章。


7.效果演示

?????????代碼在https://github.com/RedShaoWuHuaQu/UnityShader/tree/main/SSAO中。

before
after

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/90816.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/90816.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/90816.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【設計模式】外觀模式(門面模式)

外觀模式&#xff08;Facade Pattern&#xff09;詳解一、外觀模式簡介 外觀模式&#xff08;Facade Pattern&#xff09; 是一種 結構型設計模式&#xff0c;它為一個復雜的子系統提供一個統一的高層接口&#xff0c;使得子系統更容易使用。 外觀模式又稱為門面模式&#xff0…

【6.1.1 漫畫分庫分表】

漫畫分庫分表 “數據量大了不可怕&#xff0c;可怕的是不知道如何優雅地拆分。” &#x1f3ad; 人物介紹 架構師老王&#xff1a;資深數據庫架構專家&#xff0c;精通各種分庫分表方案Java小明&#xff1a;對分庫分表充滿疑問的開發者ShardingSphere師傅&#xff1a;Apache S…

Tomcat問題:啟動腳本startup.bat中文亂碼問題解決

一、問題描述 我們第一次下載或者打開Tomcat時可能在控制臺會出現中文亂碼問題二、解決辦法 我的是8.x版本的tomcat用notepad打開&#xff1a;logging.properties 找到&#xff1a;java.util.logging.ConsoleHandler.encoding設置成GBK&#xff0c;重啟tomcat即可

Linux中Gitee的使用

一、Gitee簡介&#xff1a;Gitee&#xff08;碼云&#xff09;是中國的一個代碼托管和協作開發平臺&#xff0c;類似于GitHub或GitLab&#xff0c;主要面向開發者提供代碼管理、項目協作及開源生態服務。適用場景個人開發者&#xff1a;托管私有代碼或參與開源項目。中小企業&a…

Oracle大表數據清理優化與注意事項詳解

一、性能優化策略 1. 批量處理優化批量大小選擇&#xff1a; 小批量(1,000-10,000行)&#xff1a;減少UNDO生成&#xff0c;但需要更多提交次數中批量(10,000-100,000行)&#xff1a;平衡性能與資源消耗大批量(100,000行)&#xff1a;適合高配置環境&#xff0c;但需監控資源使…

Anaconda及Conda介紹及使用

文章目錄Anaconda簡介為什么選擇 Anaconda&#xff1f;Anaconda 安裝Win 平臺macOS 平臺Linux 平臺Anaconda 界面使用Conda簡介Conda下載安裝conda 命令環境管理包管理其他常用命令Jupyter Notebook&#xff08;可選&#xff09;Anaconda簡介 Anaconda 是一個數據科學和機器學…

外包干了一周,技術明顯退步

我是一名本科生&#xff0c;自2019年起&#xff0c;我便在南京某軟件公司擔任功能測試的工作。這份工作雖然穩定&#xff0c;但日復一日的重復性工作讓我逐漸陷入了舒適區&#xff0c;失去了前進的動力。兩年的時光匆匆流逝&#xff0c;我卻在原地踏步&#xff0c;技術沒有絲毫…

【QT】多線程相關教程

一、核心概念與 Qt 線程模型 1.線程與進程的區別: 線程是程序執行的最小單元&#xff0c;進程是資源分配的最小單元&#xff0c;線程共享進程的內存空間(堆&#xff0c;全局變量等)&#xff0c;而進程擁有獨立的內存空間。Qt線程只要關注同一進程內的并發。 2.為什么使用多線程…

VS 版本更新git安全保護問題的解決

問題&#xff1a;我可能移動了一個VS C# 項目&#xff0c;然后&#xff0c;發現里面的git版本檢測不能用了 正在打開存儲庫: X:\Prj_C#\3D fatal: detected dubious ownership in repository at X:/Prj_C#/3DSnapCatch X:/Prj_C#/3D is owned by:S-1-5-32-544 but the current …

Git常用命令一覽

Git 是基于 Linux內核開發的版本控制工具。與常用的版本控制工具 CVS, Subversion 等不同&#xff0c;它采用了分布式版本庫的方式&#xff0c;不必服務器端軟件支持&#xff08;ps&#xff1a;這得分是用什么樣的服務端&#xff0c;使用http協議或者git協議等不太一樣。并且在…

基于 JSON 文件定位圖片缺陷點并保存

基于JSON的圖片缺陷處理流程 ├── 1. 輸入檢查 │ ├── 驗證圖片文件是否存在 │ └── 驗證JSON文件是否存在 │ ├── 2. 數據加載 │ ├── 打開并加載圖片 │ └── 讀取并解析JSON文件 │ ├── 3. 缺陷信息提取 │ ├── 檢查JSON中是否存在shapes字…

Redis基礎學習(五大值數據類型的常用操作命令)

目錄 一、Redis基本知識與Redis鍵&#xff08;key&#xff09;常用操作命令。 二、Redis的五大值的數據類型。&#xff08;value&#xff09; 三、Redis關于鍵&#xff08;key&#xff09;的值常用操作指令表格統計。 &#xff08;1&#xff09;字符串&#xff08;String&#…

Ubuntu——辦公軟件 LibreOffice 安裝與使用指南

十四、LibreOffice 安裝與使用1、核心組件組件????圖標????對應MS Office????核心功能定位????Writer??&#x1f4dd;Word專業文檔處理與排版??Calc??&#x1f4ca;Excel數據計算與分析??Impress??&#x1f3ac;PowerPoint演示文稿制作??Draw??&…

Securecrt丟失tab以及終端重新配色

今天在使用 Securecrt 的時候&#xff0c;發現 Securecrt 的 tab 標簽消失不見了&#xff0c;仔細回想起來&#xff0c;應該是上一次誤按了 alt enter 最大化&#xff0c;然后導致配置丟失的問題 還有表現就是菜單中的 Session Tabs 無論勾選還是不勾選都沒有任何變化&#xf…

frp搭建內網穿透教程

frp搭建內網穿透教程 步驟1&#xff1a;準備工作 公網服務器&#xff1a;需要一臺具有公網IP的服務器作為中轉服務器&#xff0c;安裝frp服務器端&#xff08;frps&#xff09;。內網設備&#xff1a;需要暴露服務的內網設備&#xff0c;安裝frp客戶端&#xff08;frpc&#xf…

【JavaEE進階】圖書管理系統(未完待續)

目錄 用戶登錄 添加圖書 圖書列表 修改圖書 刪除圖書 批量刪除 攔截器 &#x1f343;前言 什么是攔截器? 攔截器的基本使用 自定義攔截器 注冊配置攔截器 攔截路徑 攔截器執行流程 項目實現統一攔截 定義攔截器 注冊配置攔截器 前?圖書管理系統, 咱們只完成了??登錄和圖書列…

基于同花順API的熊市與牛市識別模型開發及因子分析

基于同花順API的熊市與牛市識別模型開發及因子分析 1. 引言 1.1 研究背景與意義 金融市場中的牛市與熊市識別一直是投資者和研究人員關注的重點問題。牛市(Bull Market)通常指價格持續上漲的市場環境,投資者信心充足,交易活躍;而熊市(Bear Market)則指價格持續下跌的市場…

AMD 銳龍 AI MAX+ 395 處理器與端側 AI 部署的行業實踐

2025 年 7 月 10 日&#xff0c;AMD 在深圳召開 Mini AI 工作站行業解決方案峰會&#xff0c;正式發布基于銳龍 AI MAX 395 處理器的端側 AI 部署方案&#xff0c;與 200 余家生態伙伴共同探討 AI 技術在千行百業的落地路徑。這一硬件平臺通過異構計算架構與開放生態設計&#…

期權盤位是什么意思?

本文主要介紹期權盤位是什么意思&#xff1f;“期權盤位”并非金融交易中的標準術語&#xff0c;可能是口語化表達或對某些概念的簡化描述。期權盤位是什么意思&#xff1f;1. 期權盤口的“價位”&#xff08;買賣報價位置&#xff09;在期權交易中&#xff0c;“盤口”通常指實…

【Trea】Trea國內版|國際版|海外版下載|Mac版|Windows版|Linux下載配置教程

【Trea】Trea國內版&#xff5c;國際版&#xff5c;海外版下載&#xff5c;Mac版&#xff5c;Windows版下載配置教程 本文適用讀者&#xff1a; 想要第一次安裝 Trea需要在 Windows 或 macOS 上完成環境配置想深入了解 Doubao、DeepSeek、ChatGPT、Claude 等模型在 Trea 中的接…