Unity Standard Shader 解析(五)之ShadowCaster

一、ShadowCaster

// ------------------------------------------------------------------//  Shadow rendering passPass {Name "ShadowCaster"Tags { "LightMode" = "ShadowCaster" }ZWrite On ZTest LEqualCGPROGRAM#pragma target 3.0// -------------------------------------#pragma shader_feature_local _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON#pragma shader_feature_local _METALLICGLOSSMAP#pragma shader_feature_local_fragment _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A#pragma shader_feature_local _PARALLAXMAP#pragma multi_compile_shadowcaster#pragma multi_compile_instancing// Uncomment the following line to enable dithering LOD crossfade. Note: there are more in the file to uncomment for other passes.//#pragma multi_compile _ LOD_FADE_CROSSFADE#pragma vertex vertShadowCaster#pragma fragment fragShadowCaster#include "UnityStandardShadow.cginc"ENDCG}

引用了UnityStandardShadow.cginc中的vertShadowCasterfragShadowCaster

以下是UnityStandardCoreForward.cginc的源碼,

二、vertShadowCaster

// 我們必須分別在頂點著色器中輸出 SV_POSITION,并在像素著色器中輸入 VPOS,
// 因為它們在某些平臺上都映射到 "POSITION" 語義,這樣會導致問題。void vertShadowCaster (VertexInput v, out float4 opos : SV_POSITION#ifdef UNITY_STANDARD_USE_SHADOW_OUTPUT_STRUCT, out VertexOutputShadowCaster o#endif#ifdef UNITY_STANDARD_USE_STEREO_SHADOW_OUTPUT_STRUCT, out VertexOutputStereoShadowCaster os#endif
)
{// 設置實例ID,以便在多實例渲染時正確處理每個實例的數據UNITY_SETUP_INSTANCE_ID(v);// 如果啟用了立體陰影輸出結構,則初始化立體陰影輸出結構#ifdef UNITY_STANDARD_USE_STEREO_SHADOW_OUTPUT_STRUCTUNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(os);#endif// 將頂點數據轉換為陰影投射所需的格式,并輸出 SV_POSITIONTRANSFER_SHADOW_CASTER_NOPOS(o, opos)// 如果啟用了陰影UVs#if defined(UNITY_STANDARD_USE_SHADOW_UVS)// 將紋理坐標從對象空間轉換到紋理空間o.tex = TRANSFORM_TEX(v.uv0, _MainTex);// 如果啟用了視差貼圖#ifdef _PARALLAXMAP// 計算切線空間旋轉矩陣TANGENT_SPACE_ROTATION;// 計算視差貼圖所需的視圖方向o.viewDirForParallax = mul(rotation, ObjSpaceViewDir(v.vertex));#endif#endif
}

1.VertexInput


struct VertexInput
{float4 vertex   : POSITION;half3 normal    : NORMAL;float2 uv0      : TEXCOORD0;float2 uv1      : TEXCOORD1;
#if defined(DYNAMICLIGHTMAP_ON) || defined(UNITY_PASS_META)float2 uv2      : TEXCOORD2;
#endif
#ifdef _TANGENT_TO_WORLDhalf4 tangent   : TANGENT;
#endifUNITY_VERTEX_INPUT_INSTANCE_ID
};

2.VertexOutputShadowCaster

#ifdef UNITY_STANDARD_USE_SHADOW_OUTPUT_STRUCT
struct VertexOutputShadowCaster
{V2F_SHADOW_CASTER_NOPOS#if defined(UNITY_STANDARD_USE_SHADOW_UVS)float2 tex : TEXCOORD1;#if defined(_PARALLAXMAP)half3 viewDirForParallax : TEXCOORD2;#endif#endif
};
#endif

3.VertexOutputStereoShadowCaster

#ifdef UNITY_STANDARD_USE_STEREO_SHADOW_OUTPUT_STRUCT
struct VertexOutputStereoShadowCaster
{UNITY_VERTEX_OUTPUT_STEREO
};
#endif

4.TRANSFER_SHADOW_CASTER_NOPOS

#if defined(SHADOWS_CUBE) && !defined(SHADOWS_CUBE_IN_DEPTH_TEX)#define TRANSFER_SHADOW_CASTER_NOPOS(o,opos) o.vec = mul(unity_ObjectToWorld, v.vertex).xyz - _LightPositionRange.xyz; opos = UnityObjectToClipPos(v.vertex);
#else#define TRANSFER_SHADOW_CASTER_NOPOS(o,opos) \opos = UnityClipSpaceShadowCasterPos(v.vertex, v.normal); \opos = UnityApplyLinearShadowBias(opos);
#endif

5.UnityClipSpaceShadowCasterPos

float4 UnityClipSpaceShadowCasterPos(float4 vertex, float3 normal)
{// 將頂點從對象空間轉換到世界空間float4 wPos = mul(unity_ObjectToWorld, vertex);// 如果啟用了法線偏置(normal bias)if (unity_LightShadowBias.z != 0.0){// 將法線從對象空間轉換到世界空間float3 wNormal = UnityObjectToWorldNormal(normal);// 獲取世界空間中的光照方向float3 wLight = normalize(UnityWorldSpaceLightDir(wPos.xyz));// 應用法線偏置(沿法線向內偏移位置)// 偏置需要按法線和光照方向之間的正弦值進行縮放// (http://the-witness.net/news/2013/09/shadow-mapping-summary-part-1/)//// unity_LightShadowBias.z 包含用戶指定的法線偏置量,// 已按世界空間紋理像素大小進行了縮放。// 計算法線和光照方向之間的余弦值float shadowCos = dot(wNormal, wLight);// 計算法線和光照方向之間的正弦值float shadowSine = sqrt(1 - shadowCos * shadowCos);// 計算法線偏置float normalBias = unity_LightShadowBias.z * shadowSine;// 沿法線方向偏移世界空間位置wPos.xyz -= wNormal * normalBias;}// 將世界空間位置轉換到裁剪空間return mul(UNITY_MATRIX_VP, wPos);
}// Legacy, not used anymore; kept around to not break existing user shaders
float4 UnityClipSpaceShadowCasterPos(float3 vertex, float3 normal)
{// 調用帶 float4 參數的重載函數return UnityClipSpaceShadowCasterPos(float4(vertex, 1), normal);
}

6.UnityApplyLinearShadowBias

float4 UnityApplyLinearShadowBias(float4 clipPos)
{// 對于支持深度立方體貼圖的點光源,偏置在采樣陰影貼圖的片段著色器中應用。// 這是因為傳統行為的點光源陰影貼圖無法通過在生成陰影貼圖的頂點著色器中偏移頂點位置來實現。
#if !(defined(SHADOWS_CUBE) && defined(SHADOWS_CUBE_IN_DEPTH_TEX))#if defined(UNITY_REVERSED_Z)// 使用 max/min 而不是 clamp 以確保正確處理極少數情況下分子和分母都為零的情況,// 此時分數會變成 NaN。clipPos.z += max(-1, min(unity_LightShadowBias.x / clipPos.w, 0));#elseclipPos.z += saturate(unity_LightShadowBias.x / clipPos.w);#endif
#endif#if defined(UNITY_REVERSED_Z)float clamped = min(clipPos.z, clipPos.w * UNITY_NEAR_CLIP_VALUE);
#elsefloat clamped = max(clipPos.z, clipPos.w * UNITY_NEAR_CLIP_VALUE);
#endifclipPos.z = lerp(clipPos.z, clamped, unity_LightShadowBias.y);return clipPos;
}

三、fragShadowCaster

half4 fragShadowCaster (UNITY_POSITION(vpos)
#ifdef UNITY_STANDARD_USE_SHADOW_OUTPUT_STRUCT, VertexOutputShadowCaster i
#endif
) : SV_Target
{// 如果啟用了陰影UVs#if defined(UNITY_STANDARD_USE_SHADOW_UVS)// 如果啟用了視差貼圖且著色器目標版本大于等于3.0#if defined(_PARALLAXMAP) && (SHADER_TARGET >= 30)// 歸一化視差貼圖的視圖方向half3 viewDirForParallax = normalize(i.viewDirForParallax);// 獲取視差貼圖的高度值(綠色通道)fixed h = tex2D(_ParallaxMap, i.tex.xy).g;// 計算視差偏移量half2 offset = ParallaxOffset1Step(h, _Parallax, viewDirForParallax);// 應用視差偏移量到紋理坐標i.tex.xy += offset;#endif// 如果平滑度存儲在Albedo通道A中#if defined(_SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A)half alpha = _Color.a;#else// 否則,從主紋理中獲取Alpha值并乘以顏色的Alpha值half alpha = tex2D(_MainTex, i.tex.xy).a * _Color.a;#endif// 如果啟用了Alpha測試#if defined(_ALPHATEST_ON)clip(alpha - _Cutoff); // 裁剪掉透明度低于閾值的部分#endif// 如果啟用了Alpha混合或Alpha預乘#if defined(_ALPHABLEND_ON) || defined(_ALPHAPREMULTIPLY_ON)// 如果啟用了Alpha預乘#if defined(_ALPHAPREMULTIPLY_ON)half outModifiedAlpha;// 預乘Alpha值PreMultiplyAlpha(half3(0, 0, 0), alpha, SHADOW_ONEMINUSREFLECTIVITY(i.tex), outModifiedAlpha);alpha = outModifiedAlpha;#endif// 如果啟用了抖動掩碼進行Alpha混合陰影#if defined(UNITY_STANDARD_USE_DITHER_MASK)// 基于像素位置xy和alpha級別使用抖動掩碼// 我們的抖動紋理是4x4x16。#ifdef LOD_FADE_CROSSFADE#define _LOD_FADE_ON_ALPHAalpha *= unity_LODFade.y; // 應用LOD淡入因子#endif// 計算alpha參考值half alphaRef = tex3D(_DitherMaskLOD, float3(vpos.xy * 0.25, alpha * 0.9375)).a;clip(alphaRef - 0.01); // 裁剪掉不滿足條件的部分#elseclip(alpha - _Cutoff); // 裁剪掉透明度低于閾值的部分#endif#endif#endif // #if defined(UNITY_STANDARD_USE_SHADOW_UVS)// 如果啟用了LOD交叉漸變#ifdef LOD_FADE_CROSSFADE#ifdef _LOD_FADE_ON_ALPHA#undef _LOD_FADE_ON_ALPHA#else// 應用LOD交叉漸變UnityApplyDitherCrossFade(vpos.xy);#endif#endif// 輸出陰影片段SHADOW_CASTER_FRAGMENT(i)
}

1.ParallaxOffset1Step

// Same as ParallaxOffset in Unity CG, except:
//  *) precision - half instead of float
half2 ParallaxOffset1Step (half h, half height, half3 viewDir)
{h = h * height - height/2.0;half3 v = normalize(viewDir);v.z += 0.42;return h * (v.xy / v.z);
}

2.SHADOW_ONEMINUSREFLECTIVITY

#define SHADOW_ONEMINUSREFLECTIVITY SHADOW_JOIN(UNITY_SETUP_BRDF_INPUT, _ShadowGetOneMinusReflectivity)
#define SHADOW_JOIN(a, b) SHADOW_JOIN2(a,b)
#define SHADOW_JOIN2(a, b) a##b

3.UnityApplyDitherCrossFade

// 定義一個采樣器,用于訪問4x4的抖動遮罩紋理
sampler2D unity_DitherMask;/*** 應用基于抖動遮罩的交叉淡入淡出效果* @param vpos 輸入頂點位置,通常是屏幕空間坐標或裁剪空間坐標*/
void UnityApplyDitherCrossFade(float2 vpos)
{// 將輸入的位置除以4,因為抖動遮罩紋理是4x4的分辨率// 這一步是為了將輸入坐標映射到遮罩紋理的UV坐標空間vpos /= 4.0;// 使用tex2D函數從抖動遮罩紋理中采樣,并獲取alpha通道的值// mask的值范圍在[0, 1]之間float mask = tex2D(unity_DitherMask, vpos).a;// 根據unity_LODFade.x的值確定sgn的符號// 如果unity_LODFade.x大于0,則sgn為1.0f,否則為-1.0f// unity_LODFade.x通常用于表示LOD級別的變化方向float sgn = unity_LODFade.x > 0 ? 1.0f : -1.0f;// 使用clip函數進行像素裁剪// 如果unity_LODFade.x - mask * sgn小于0,則該像素會被裁剪掉(即不會被渲染)// 這一步實現了基于抖動遮罩的交叉淡入淡出效果clip(unity_LODFade.x - mask * sgn);
}

4.SHADOW_CASTER_FRAGMENT

//_LightPositionRange 是 float4 類型的內置變量:
//xyz分量?:表示光源在世界空間中的坐標位置。
//w分量?:表示光源的影響范圍(如點光源的半徑)。
//unity_LightShadowBias 是 float4 類型的內置變量,?
?//x 分量?:shadowBias,表示常量偏移值,用于調整頂點沿光源方向的偏移距離。
//y 分量?:shadowNormalBias,表示基于法線的偏移值,用于沿頂點法線方向內推頂點位置。
//z和w 分量?:通常與光源類型或特定計算需求相關(如點光源的歸一化參數)?。
#if defined(SHADOWS_CUBE) && !defined(SHADOWS_CUBE_IN_DEPTH_TEX)#define SHADOW_CASTER_FRAGMENT(i) return UnityEncodeCubeShadowDepth ((length(i.vec) + unity_LightShadowBias.x) * _LightPositionRange.w);
#else#define SHADOW_CASTER_FRAGMENT(i) return 0;
#endif

5.UnityEncodeCubeShadowDepth

float4 UnityEncodeCubeShadowDepth (float z)
{#ifdef UNITY_USE_RGBA_FOR_POINT_SHADOWSreturn EncodeFloatRGBA (min(z, 0.999));#elsereturn z;#endif
}

6.EncodeFloatRGBA

// 函數:將 [0, 1) 范圍內的浮點數編碼為 8 位每通道的 RGBA 顏色值
// 注意:1.0 值不會被正確編碼
inline float4 EncodeFloatRGBA(float v)
{// 定義乘法因子,用于將浮點數分解到四個通道中// kEncodeMul 的值分別是:// 1.0       -> 第一個通道(R)// 255.0     -> 第二個通道(G)// 65025.0   -> 第三個通道(B),即 255^2// 16581375.0-> 第四個通道(A),即 255^3float4 kEncodeMul = float4(1.0, 255.0, 65025.0, 16581375.0);// 定義用于減去溢出部分的常量,即每個通道的最大值(255)的倒數float kEncodeBit = 1.0 / 255.0;// 將輸入浮點數 v 分解到四個通道中float4 enc = kEncodeMul * v;// 取每個分量的小數部分,確保每個分量都在 [0, 1) 范圍內enc = frac(enc);// 減去高位通道對低位通道的溢出影響// enc.yzww 表示取 G、B 和 A 通道的值,并分別乘以 kEncodeBit// 這樣可以避免高位通道的值影響低位通道enc -= enc.yzww * kEncodeBit;// 返回編碼后的 RGBA 顏色值return enc;
}

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

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

相關文章

[MRCTF2020]Ez_bypass

BUUCTF在線評測BUUCTF 是一個 CTF 競賽和訓練平臺,為各位 CTF 選手提供真實賽題在線復現等服務。https://buuoj.cn/challenges#[MRCTF2020]Ez_bypass啟動靶機 有提示F12,那查看一下源碼。和頁面顯示的代碼一樣的,就是格式更規范而已 include…

C/C++關鍵字——union

1.介紹union是一種特殊的數據類型,它允許你在同一塊內存區域中存儲不同的數據類型。它的主要目的是節省內存,尤其是在處理多種可能的數據類型,但一次只使用其中一種的場景。2.特點與 struct(結構體)不同,結…

2024 arXiv Cost-Efficient Prompt Engineering for Unsupervised Entity Resolution

論文基本信息 題目: Cost-Efficient Prompt Engineering for Unsupervised Entity Resolution 作者: Navapat Nananukul, Khanin Sisaengsuwanchai, Mayank Kejriwal 機構: University of Southern California, Information Sciences Institu…

【XR技術概念科普】什么是注視點渲染(Foveated Rendering)?為什么Vision Pro離不開它?

一、前言2023 年,蘋果推出了 Vision Pro 頭顯,把“空間計算”概念推向大眾。與以往的 XR 設備不同,Vision Pro 強調高分辨率、真實感與沉浸感。然而,這種體驗背后隱藏著一個巨大的技術挑戰:如何在有限的計算與能耗條件…

Qt 系統相關 - 1

雖然 Qt 是跨平臺的 C 開發框架,Qt 有很多能力其實是操作系統提供的,只不過 Qt 封裝了系統的 API程序時運行在操作系統上的,需要系統給我們提供支撐!事件文件操作多線程編程網絡編程多媒體(音頻,視頻&#…

“12306”有多牛逼?從架構師的角度詳細的告訴你

12306鐵路票務系統架構深度解析 📚 目錄 系統概述業務特點與技術挑戰整體架構設計核心技術架構高并發處理策略數據存儲與管理緩存體系設計分布式系統架構安全防護體系性能優化策略監控與運維技術演進歷程總結與展望 每到春節、國慶這種全民遷徙的時刻,…

數據采集機器人哪家好?2025 年實測推薦:千里聆 RPA 憑什么成企業首選?

在數字化轉型加速的今天,數據采集已成為企業運營的核心環節,數據采集機器人正在重構企業的效率邊界。2025 年中國 RPA 市場排名顯示,泛微旗下的千里聆 RPA 已躋身行業前五,成為中大型國央企的首選品牌。本文將通過三維評估體系&am…

基礎crud項目(前端部分+總結)

本人根據自己對前端微不足道的理解和 AI 老師的指導下,艱難地完成了基礎crud代碼的全棧開發,算是自己的第一個 Java 項目,對此做個簡單總結。 后端部分 在前后端分離開發中,前端負責頁面交互與數據展示,后端提供接口支…

MATLAB矩陣及其運算(二)函數

函數分為MATLAB內置函數及用戶自定義函數,用戶可以直接調用內置函數進行數據處理。內置函數的使用函數由三部分組成:名稱、輸入和輸出。內置函數示例:單輸入單輸出函數:sqrt(x);單輸入多輸出函數:size(x)&a…

自動化運維-ansible中對于大項目的管理

自動化運維-ansible中對于大項目的管理 一、引用主機清單 在Playbook中引用主機時,hosts 字段指定的目標必須與Ansible主機清單中定義的標識符完全匹配。如果清單中配置的是主機名,則在Playbook中使用IP地址或其他別名將無法匹配,導致任務被跳…

59_基于深度學習的麥穗計數統計系統(yolo11、yolov8、yolov5+UI界面+Python項目源碼+模型+標注好的數據集)

目錄 項目介紹🎯 功能展示🌟 一、環境安裝🎆 環境配置說明📘 安裝指南說明🎥 環境安裝教學視頻 🌟 二、數據集介紹🌟 三、系統環境(框架/依賴庫)說明🧱 系統環…

面試問題詳解十六:Qt 內存管理機制

在 Qt 開發過程中,很多初學者(包括不少有經驗的 C 程序員)經常會產生這樣的疑問:“我在 Qt 中 new 出來的控件好像都沒有 delete,那內存不會泄漏嗎?”比如下面這段代碼: void Widget::createLef…

Pycharm 試用

Ubuntu 重置Pycharm試用期限(30 天) 先關閉Pycharm刪除系統緩存 rm -rf ~/.config/JetBrains/ && rm -rf ~/.local/share/JetBrains/ && rm -rf ~/.cache/JetBrains/刪除已經安裝的 Pycharm 軟件運行目錄去官網下載新的 就行了

C++ Qt 開發核心知識

Qt 框架概述Qt 是一個跨平臺的 C 應用程序開發框架,廣泛用于開發圖形用戶界面程序。其核心特性包括跨平臺能力、豐富的功能模塊和強大的工具集。核心概念與機制元對象系統Qt 擴展了標準 C,通過元對象系統提供信號與槽機制、運行時類型信息和動態屬性系統…

net9 aspose.cell 自定義公式AbstractCalculationEngine,帶超鏈接excel轉html后背景色丟失

AbstractCalculationEngine 是 Aspose.Cells 中一個強大的抽象類,允許您自定義公式計算邏輯。當您需要覆蓋默認計算行為或實現自定義函數時非常有用。直接上代碼1. 創建自定義計算引擎using Aspose.Cells; using System;// 創建自定義計算引擎 public class CustomC…

如何監控員工的電腦?7款實用的員工電腦管理軟件,探索高效管理捷徑!

當銷售團隊在淘寶刷單、設計師用公司電腦挖礦、程序員頻繁訪問代碼托管網站時,企業損失的不僅是帶寬——低效、泄密、合規風險正成為隱形利潤殺手。 傳統管理依賴“人盯人”或抽查日志,但面對分布式辦公與遠程協作趨勢,這些方法早已力不從心…

機器視覺軟件--VisionPro、Visual Master,Halcon 和 OpenCV 的學習路線

Halcon 和 OpenCV區別 Halcon 和 OpenCV 都是計算機視覺領域的重要工具,但它們的設計理念、功能側重和適用場景有顯著不同。下面這個表格匯總了它們的核心區別,方便你快速了解: 開發模式與體驗??:Halcon 配備了強大的??圖形化…

算法-根據前序+中序遍歷打印樹的右視圖

題目請根據二叉樹的前序遍歷,中序遍歷恢復二叉樹,并打印出二叉樹的右視圖數據范圍: 0≤n≤100000≤n≤10000 要求: 空間復雜度 O(n)O(n),時間復雜度 O(n)O(n)如輸入[1,2,4,5,3],[4,2,5,1,3]時,通過前序遍歷…

Kafka面試精講 Day 7:消息序列化與壓縮策略

【Kafka面試精講 Day 7】消息序列化與壓縮策略 在Kafka的高性能消息系統中,消息序列化與壓縮是影響吞吐量、延遲和網絡開銷的核心環節。作為“Kafka面試精講”系列的第7天,本文聚焦于這一關鍵主題,深入剖析其原理、實現方式、配置策略及常見…

Xterminal軟件下載_Xterminal ssh遠程鏈接工具下載__Xterminal安裝包 網盤下載_Xterminal ssh遠程鏈接工具安裝包

Xterminal 作為一款國產 SSH 工具,專為開發人員量身打造。它支持 SSH 和 Telnet 協議連接遠程服務器與虛擬機,無論是進行代碼部署,還是服務器運維,都能輕松勝任。軟件界面采用極簡設計,黑色背景搭配白色文字&#xff0…