編碼全稱:AV1(Alliance for Open Media Video 1)。
算力消耗大:目前(截至 2025 年中)軟件解碼 AV1 的 CPU 開銷非常高,如果沒有專門的硬件解碼單元,播放高清視頻時會很吃 CPU,容易出現卡頓、發熱或掉幀。
-
在許多視頻/圖像場景里,壓縮率常常表示為“源文件大小 ÷ 壓縮后文件大小”,比率越大代表壓縮得越厲害;但更直觀常用的是“碼率”(bitrate),比如視頻的碼率是 4 Mbps,或者圖片的 JPEG 質量參數 90%。
-
一般情況下,碼率越高(即單位時間/單位像素所分配的數據越多),可還原的畫面細節就越豐富,相對的畫質也會更好。壓縮率越大則對應碼率越低,畫面細節和銳度就更容易丟失,出現模糊、塊狀或色帶等偽影。
如果不在意流量消耗,就讓播放器調度盡可能高的 AV1 碼率(比如 4K 甚至 8K 的高碼流)來保證最豐富的細節。
ShaderForge介紹_嗶哩嗶哩_bilibili
明天了解一下吧
和Graph差不多的,但是built-in
在 Photoshop 中,“線性減淡(Linear Dodge)”與“線性減淡(添加)(Linear Dodge (Add))”實際上是同一個 Blend Mode,Photoshop 官方簡稱:“Linear Dodge (Add)”。它的核心思路就是把兩張圖像做加法,然后對結果做飽和剪裁(clamp)
濾色(Screen)融合模式通常被稱為“反相相乘”(Inverse Multiply)。數學表達式是:
C = 1 - (1 - A) * (1 - B)
更柔和的疊加效果:與 Add/Linear Dodge “一旦相加就飽和到白”相比,Screen 會在低亮度區累加時更明顯,在高亮度區飽和時更平滑。
高光到達白色的過程是漸進、滑順的,不會像簡單的加法
-
Linear Dodge 一旦 A+B > 1,就直接剪裁為 1,區域會瞬間變白。
-
Screen 則是在 A+B 越來越大時,按照 A+B?A*B 的方式漸進逼近 1,在值接近 1 之前都會有細微過渡。
暗部細節保存更好
內發光和外發光,內發光不能超出模型的邊界
用了之后任何功能都需要自己連出來,不連就沒有,右邊一下子就少了很多接口,變灰不讓接上了
unity中的fixed用宏定義了half,換了一種表示方法
在 Unity Shader 中,half
并不直接代表“固定 16 位浮點”,而是“編譯器抽象”→等同于 fixed
。
-
在移動 GPU 上,使用
half
或fixed
可以減少寄存器壓力、提高并行度。 -
在 Pixel Shader 中使用
fixed
做顏色計算可以節省資源。 -
GPU 內部的向量化 SIMD 單元更適合處理中低精度數據。
→ 所以手動標記可以讓你顯式告訴編譯器:這個變量不需要高精度,編譯器可以幫你優化。
-
如果你在高精度 float 上做了大量運算,再賦值給一個低精度
fixed
,可能造成明顯的精度丟失(顏色值斷層、光照閃爍等)。 -
所以手動標記數據類型,能讓你顯式暴露這種意圖,并對精度損失行為負責。
half用給插值出來的值,fixed用來裝顏色的,,這是優雅的寫法了(pc上統一float32,不影響)
“在手機上 fixed 是小于 half 的”
“顏色需要的精度更少”
為什么 Unity/Shader 寫顏色用 fixed
?
fixed
≈ lowp
≈ 用于顏色值
fixed
最早其實不是 Unity 發明的,而是從舊版 Cg/HLSL 中延續而來的術語,它的名字原義是:
fixed
表示 固定精度范圍 的數值(比如 -2 到 2),比 half 更低精度,但更小更快。
不同的平臺,取模可能要用規定的函數,*也是一樣的,乘要用規定的函數
static
-
在 Shader 里,
static
表示“靜態變量”,也就是該變量只在當前編譯單元(通常是當前.cginc
/.hlsl
文件)中可見,外部無法訪問或修改它。 -
典型場景:
-
你在同一個 Shader 文件里定義了一段公用函數,而這個函數里面需要一個只讀的臨時常量或緩存,你可以用
static
聲明它,確保不被其他包(pass、include)意外重寫。 -
static
并不是“靜態內存”那種概念(不像 C/C++ 全局變量會駐留在固定內存地址)。在 GPU 編譯時,static
只是一個作用域限制:告訴編譯器“外面別來碰我”。
-
uniform
-
跨階段共享:一個
uniform
(如 CBUFFER 里的某個結構體、或者 samplers/紋理)能同時被頂點著色器(VS)和片段著色器(PS)訪問。 -
外部驅動:它真正的值來源于 CPU 端代碼(C#、C++)或渲染框架主循環,在每次 Draw Call 時由引擎更新。
在 Shader 里只能讀取它們,不能在 Shader 里寫回賦值。
const
編譯期展開:一旦你寫了 const float PI = 3.14159;
,編譯器會在預處理階段將所有 PI
的引用替換為 3.14159f
,并且不會占用寄存器或 uniform 緩存。
對性能友好:因為它根本不占用寄存器或常量寄存器,所有對它的引用都被直接打入字節碼里,相當于純粹的“文本替換”。
只讀:與 uniform
一樣,在 Shader 代碼中不能給 const
變量重新賦值;但區別在于,它根本不是由外部賦值,而是在編譯時就固定了。
GPU 在遇到 if else 時會把兩個分支都執行一遍
因為現代 GPU(無論是桌面級的 NVIDIA/AMD,還是移動端的 ARM Mali/Qualcomm Adreno)內部都是基于SIMD(或 SIMT)并行架構
簡單來說,GPU 會把若干個線程(Thread)組織成一個“線程束”(在 NVIDIA 中叫 Warp、在 AMD 中叫 Wavefront),比如一個 Warp 通常是 32 條線程。然后這 32 條線程在硬件上會同步執行同一條指令。
什么是 Mipmap?
-
假設你有一張原始紋理貼圖(比如 1024×1024 像素)。Mipmap 會在這張貼圖之上再依次生成幾個尺寸越來越小的版本,比如:
1024×1024 → 512×512 → 256×256 → 128×128 → 64×64 → … → 一直到 1×1
-
每一級的圖像都是對上一層用雙線性/三線性濾波之類的方法預先縮小或預過濾得到的。所以當你把同一張紋理應用到遠處(或尺寸很小)的物體時,GPU 不必去采樣原始的 1024×1024,而是直接采樣一個更低分辨率的級別(比如 128×128 或 64×64),這樣能夠減少鋸齒、閃爍和紋理閃變現象,同時提高采樣效率。
https://en.wikibooks.org/wiki/Cg_Programming/Unity/Minimal_Shader
https://enjoyphysics.cn/%E6%96%87%E4%BB%B6/soft/Hlsl/GPU-Programming-AndCgLanguage-Primer.pdf
-
使用 HTTPS 協議,不需要專門配置 SSH Key,即使沒配置 SSH 也能正常克隆/拉取代碼。
-
在公司網絡或學校網絡里,HTTPS 通常不被屏蔽,更容易成功下載。
GitHub Desktop 是 GitHub 官方推出的一款圖形化桌面客戶端(Windows 和 macOS 均支持),可以讓不熟悉命令行的用戶用可視化界面來管理本地 Git 倉庫。
當你點擊“Open with GitHub Desktop”時,如果本地安裝并打開了 GitHub Desktop 應用,Launcher 會自動在 GitHub Desktop 里創建一個“克隆”任務,讓你選擇存放路徑,然后把倉庫克隆到你指定的本地文件夾。
“Download ZIP” 按鈕
-
優點:
-
極其簡單,連命令行都不需要,適合只想“拿來直接看代碼/文檔”的場景。
-
不用擔心本地有沒有安裝 Git;只要會解壓就行。
-
-
缺點:
-
你無法繼承該倉庫的版本控制歷史,也不能向遠端推送更新、創建分支,甚至都拿不到原來的
.gitignore
、.gitattributes
等元信息。 -
如果后續該項目在 GitHub 上更新了,你需要手動重新下載最新的 ZIP,無法用
git pull
一鍵拉取更新。
-
-
如果你:
-
主要在 GitHub 上做開源、個人項目;
-
希望操作直觀、界面干凈;
-
不想花時間學命令行或太多 Git 細節;
→ 用 GitHub Desktop 就夠了。
-
-
如果你:
-
想用 GUI 方式做深入的 Git 操作(如多級分支管理、隱式多分支合并、交互式 rebase、子模塊、stash 等);
-
項目不一定只在 GitHub,還可能在 GitLab、自建私庫;
-
喜歡一次性把常用 Git 操作都放在一個軟件里(不用每次都切命令行);
→ 用 GitExtensions 會更專業,也更靈活。
-
shader中的函數性質
GLSL(OpenGL Shading Language)**的頂點著色器(Vertex Shader)代碼,通常用在桌面或者移動端的原生 OpenGL 項目里
-
Unity 里我們平時寫的 Surface Shader、Vertex/Fragment Shader,文件后綴一般是
.shader
(里面會混合 ShaderLab 語法和 CGPROGRAM/ENDCG 段落)或者.cginc
、.hlsl
、.compute
(Compute Shader),它們的語法看起來像 HLSL/CG。 -
你這里看到的文件名是
vert.glsl
(以及右邊大概率還有frag.glsl
),這明確表明它是 OpenGL/GLSL 的程序。GLSL 在語法上用的關鍵詞是attribute
、varying
、gl_Position
,這在 Unity 的 CG/HLSL 中并不出現。
attribute
關鍵字表示頂點輸入屬性(頂點位置、UV、法線等),這是 GLSL 里的寫法;varying
用來把頂點著色器算出的數據(例如頂點法線、坐標插值)傳給片元著色器;gl_Position
則是 OpenGL 里必須寫的輸出變量,決定當前頂點在屏幕上的裁剪空間位置。
這些在 Unity 的 ShaderLab/CG 里都不使用。Unity 要輸出給固定流水線的是 o.pos
或者 SV_POSITION
(在 HLSL/DirectX 中)。所以從關鍵字 attribute
、varying
、gl_Position
就能看出這是原生 GLSL,不是 Unity 的。
// 頂點屬性:從 CPU 端傳過來的每個頂點數據
attribute vec3 VaPos; // 頂點的世界/模型空間位置 (x, y, z)
attribute vec2 VaUV; // 原始貼圖 UV 坐標 (u, v)
attribute vec3 VaNormal; // 頂點法線// 統一變量(Uniform),從 CPU 端傳過來,在繪制一批頂點時統一不變
uniform mat4 MVP; // Model-View-Projection 矩陣,用于把頂點從模型空間 → 世界空間 → 視圖空間 → 裁剪空間
uniform int rows; // 多重紋理拼接時的行數
uniform int cols; // 多重紋理拼接時的列數
uniform int index; // 當前要使用哪張子紋理(編號)// 這是要傳給片元著色器的插值數據(每個頂點算一次,片元階段會自動插值)
varying vec3 VNormal;
varying vec2 VUV;void main() {// 1. 把原始頂點法線直接傳給片元著色器VNormal = VaNormal;// 2. 計算新的 UV —— 例如把一張大貼圖分割成 rows×cols 幾塊子圖,再根據 index 選其中一塊vec2 temp = vec2(VaUV.x / float(rows), VaUV.y / float(cols));vec2 ranks = vec2(0.0, 0.0);ranks.x = mod(float(index), float(rows)); // 第幾列ranks.y = floor(float(index) / float(cols)); // 第幾行temp.x += ranks.x * 1.0 / float(cols);temp.y += ranks.y * 1.0 / float(rows);VUV = temp; // 這樣最終傳到片元階段的 VUV 就是“在大貼圖里選取子圖的坐標”// 3. 計算最終 gl_Position(OpenGL 固定變量),告訴 GPU 該頂點在裁剪空間里的坐標gl_Position = MVP * vec4(VaPos, 1.0);
}
(把一張大貼圖拆為 rows×cols 個小紋理,然后根據 index 去采樣)
shader forge
Shader Forge
“應用階段的流水線化”指的就是 把渲染管線里原本只在 CPU 上按幀串行做的那塊“應用”工序(場景遍歷、剔除、動畫、排序、命令構建),拆分成多個子階段或分成多條命令緩沖,并且跟后面的 GPU 渲染階段錯開時間、同時執行。這樣才能讓 CPU+GPU 兩端都保持高吞吐、低空閑,從而推高幀率和抗卡頓能力。
Shader Graph 里,UV 坐標并 不 被系統強制“鉗制”到 [0,1] 區間——它只是一個浮點向量,可以讀到任意值。只要你的采樣模式是 Repeat/Tiled(而不是 Clamp),UV 超出 0–1 時就會按小數部分去“重復”取樣(也就是把紋理無縫平鋪)。
“Light Attenuation”(光照衰減) 節點,它負責根據當前光源類型和距離,給你算出一個 0~1 之間的衰減系數,用來模擬燈光在空間里“隨距離衰減”的效果。
“固定函數”著色器(Fixed-Function Shader)其實并不是一種你要手寫的 shader 腳本,而是指在早期圖形 API(如 OpenGL 2.x、Direct3D 9 以前)中,GPU 內置的一整套“流水線功能”,你只需要用一組固定的命令和參數就能完成頂點變換、光照計算、紋理映射等,而不用自己寫頂點/片元程序。
替換著色器(Replacement Shader)
-
當你用
Camera.SetReplacementShader(shader, "RenderType")
時,Unity 會在所有渲染物體上查找他們 SubShader 里帶"RenderType"="..."
的 Pass,并用你提供的替換著色器去渲染這一類物體。 -
典型例子:后期效果里做“基于不透明物體的深度/法線圖”時,就用 Replacement Shader 只渲染
Opaque
物體。
xyzw四維,w維度判斷是什么類型的光源,如果是方向光,那就xyz是方向向量,如果是點光源,則是具體的世界位置
盡量寫小數的0.0,(一些奇葩機型可能自動轉換出錯)
在 Unity 編輯器里,只要讓鼠標焦點在 Scene 視圖窗口上,按下:
Shift + Space
就可以切換該窗口的最大化/恢復(全屏化)狀態。
一般從光照節點開始分析一個新的shader
scene繞著某個物體旋轉自己當前的視角----Alt+左鍵拖拽
Graphics API/渲染接口也就是底層跟顯卡打交道、驅動硬件加速的標準。
Unity、Unreal、Godot(結合對應平臺 API:DX12、Vulkan、Metal)
GPU 驅動只實現「API 規范」,并不區分高層語言
-
顯卡廠商(NVIDIA/AMD/Intel/Apple 等)在驅動里只負責實現底層的 Graphics API(如 DirectX、Vulkan、OpenGL、Metal)的二進制接口——這些接口在本質上是 C/C++ 的 ABI(應用二進制接口)。
-
驅動并不會同時編譯出一堆 “C++ 版”、“C# 版”、“Java 版” 的驅動庫。它導出的是一套底層的函數和數據結構,供任何能調用 C 接口的語言來用。
各種編程語言通過「綁定」來調用這些 C 接口
-
C/C++:可以 直接
#include <d3d12.h>
或者#include <vulkan/vulkan.h>
,在代碼里無縫調用驅動導出的函數。 -
C#:通常使用 P/Invoke(
[DllImport]
)或者像 SharpDX、VulkanSharp 這樣的第三方封裝庫,把底層 DLL 導出的 C 接口“翻譯”成 C# 的類和方法。 -
Java/Python/Go:同樣可以通過 JNI、ctypes、cgo 等方式,把驅動的 C 接口映射到各自語言里。比如 LWJGL(Java),PyOpenGL(Python)都是用這種思路。
游戲引擎和框架通常做更高一層封裝
-
Unity、Unreal、Godot 等引擎,底層已經把對 DirectX/Vulkan/Metal 的調用都寫好 C++ 代碼了,然后再在引擎層給腳本語言(C#, Blueprint, GDScript)提供更易用的接口。
-
比如在 Unity 里你調用
Graphics.DrawMesh()
,它背后跑的是 C++、再到 DirectX/Vulkan 驅動,整個過程對 C# 腳本透明。
-
Unity 引擎核心 是用 C++ 寫的,它直接通過諸如 DirectX、Vulkan、Metal 這些“C 語言風格”的 Graphics API 去驅動 GPU。
-
你在 Unity 里寫的 C# 腳本(例如
Graphics.DrawMesh()
或者修改材質屬性)并不是直接 P/Invoke 調用這些 Graphics API,而是調用了 Unity C++ 引擎提供的“腳本綁定”(bindings)。這些綁定通常是通過 Unity 自己的宿主進程(UnityPlayer.dll)把 C# 的調用轉成內部的 C++ 函數,一次跨語言切換后,后續都在 C++ → 驅動 API 里完成。
這樣設計的好處有兩個:
-
性能: 把所有高頻的、與硬件交互密集的部分都留在 C++ 層;C# ? C++ 的調用只在腳本邏輯層面(每幀僅僅幾百次)發生,而不是每繪制一個三角形、每次設置一個 GPU 狀態就 P/Invoke。
-
穩定性與可維護性: 驅動和 Graphics API 的改動都在 C++ 層處理,對 C# 腳本層透明,不用讓每個 C# 項目都去適配不同平臺的 P/Invoke 簽名。
為什么 Unity 不讓 C# 直接 P/Invoke?
-
減少跨語言調用次數:Unity 把常見的渲染操作都集合成了一套“C++ 原生接口”,C# 只調用這些接口一次進入本地層,之后所有渲染都在 C++ 到驅動的環節。
-
API 統一與封裝:無論你是用 C#、ShaderLab 還是通過 Visual Effect Graph/Shader Graph,最終都走同一個 C++ 實現,不用重復寫綁定。
-
安全與穩定:讓腳本層不直接接觸底層 DLL,也防止用戶誤用不安全的 P/Invoke 導致崩潰或安全漏洞。
其實在 Unity 里,C# → C++ 的“中轉”調用并不是在每個三角形、每次狀態切換、每個像素著色時都發生的——那樣的開銷肯定會大得不可接受。它真正的調用頻率,大致是:
-
每幀幾十到幾百次 的 “腳本層面”渲染命令(DrawMesh、SetGlobalFloat、EnableKeyword……)
-
Unity 內部把這些命令 累積到一套命令緩沖(Command Buffer) 中
-
在 C++ 層一次性向 GPU 提交整個緩沖區(提交 DrawCall 批次,而不是單個三角形)
你在 C# 里寫
Graphics.DrawMesh(mesh, matrix, material, layer);
每次這句腳本執行時,會做一次 C#→C++ 的入口調用。但它并不立刻跑到底層的 GPU 提交,而是 把參數存到 C++ 的渲染隊列里。
-
當一幀結束、所有繪制邏輯跑完后,Unity C++ 層會把這些“渲染命令列表”批量通過一次或幾次
vkQueueSubmit
/ID3D12CommandQueue::ExecuteCommandLists
/MTLCommandBuffer commit
提交給顯卡。
也就是說,你在 C# 里可能調用了 50 次 DrawMesh,但這 50 次調用只會在本地層合并成幾次底層 GPU 提交。P/Invoke 的開銷只體現在那 50 次調用上,而不是每個三角片、每個狀態切換都 P/Invoke 一次。
如果你直接在 C# 里一個 DrawCall 對應一個 P/Invoke,再對每個三角形循環,那肯定會慢;但 Unity 已經幫你把這些細節都封裝在 C++ 里了,你在 C# 里看到的只是高級接口。
C# 這邊的“驅動”其實就是 .NET 運行時/CLR(Common Language Runtime) 本身:
-
.NET 運行時=語言的“驅動”
-
當你安裝了 .NET Framework、.NET Core/5+ 或 Mono,里面就包含了 CLR、垃圾回收、JIT 編譯器、Base Class Library(BCL) 等,負責把你的 C# IL 轉成機器碼并執行。
-
這就類似于顯卡廠商編寫的 GPU 驅動:它實現了 Graphics API 規范,把高層調用(DrawCall)翻譯給硬件;而 CLR 則實現了 ECMA-335 標準,把 C#、VB、F# 編譯出來的 IL 翻譯給 CPU。
-
跨語言調用=互操作(Interop)
-
C# 想調用 C++ 寫的庫,一般通過 P/Invoke(
[DllImport]
) 或 C++/CLI、或 COM,本質上也是 CLR 調用本地 DLL 導出的 C 風格函數。 -
這套互操作機制由 CLR 提供,調用時也會牽涉“托管 ? 非托管”上下文切換、參數封送(marshalling)等,就像 GPU API 驅動要封裝命令緩沖、驅動開銷一樣。
不需要給每種語言都寫一個“驅動”
-
CLR 是同一套運行時/規范,不管是 C#、VB 還是 F#,都跑在同一個 CLR 上。
-
你只需要安裝一次對應平臺的 .NET 運行時,就能運行任意 .NET 語言編譯的程序,不用為每個語言再各寫一份“驅動”。
你寫的 Java 源碼(.java)首先被 javac 編譯成 Java 字節碼(.class 文件),這是一種平臺無關的中間格式,不是機器碼,也不是 C++。
Java JVM | .NET CLR / Mono | |
---|---|---|
輸入 | .class (Java 字節碼) | .dll/.exe (IL 中間語言) |
解釋執行 | 解釋器 + JIT | 解釋器 + JIT |
AOT 支持 | GraalVM Native Image 等 | .NET Native / Mono AOT |
調用本地庫(Interop) | JNI(Java Native Interface) | P/Invoke / C++/CLI |
生態 | Spring、Android Runtime、GraalVM 等 | Unity、ASP.NET、Xamarin、Mono |
可編程化與可定制化:Scriptable Render Pipeline(SRP)
-
傳統引擎(如 Unity 5 之前的內置管線,Unreal 4.XX 的默認前向/延遲管線)對渲染流程是“黑盒”式的,只有少量參數可調。
-
次世代管線(Unity 的 URP/HDRP、Unreal Engine 5 的自定義管線、Godot 4 的 Vulkan 渲染)都采用了可腳本化渲染管線(Scriptable Render Pipeline)理念
-
次世代管線幾乎都把基于物理的渲染(PBR, Physically Based Rendering)作為核心:
-
統一材質模型:F0、粗糙度(Roughness)、金屬度(Metallic)、法線、環境光遮蔽等統一標準;
-
能量守恒:確保光的反射和吸收滿足真實物理規律;
-
一致性:無論場景光照如何變化,材質表現都保持物理自洽。
-
高效的光照計算:延遲+Clustered/Tiled/Nanite
-
延遲渲染(Deferred Rendering):先把幾何信息寫入 G‐Buffer,在屏幕空間做光照,適合大批點光源;
-
Tiled/Clustered Shading:把屏幕或視錐體劃分成小塊或體素,把光源分桶管理,只對相關瓦片/簇做光照,提高效率;
-
GPU 驅動渲染(GPU Driven):把剔除、實例化、Draw Call 構建都放到 GPU Compute Shader 中,減輕 CPU 負擔;
-
虛擬化幾何(Nanite):Unreal 5 的 Nanite 利用海量細分三角陣列在 GPU 上動態 LOD,實時渲染數十億三角。
新一代光照與全局光照:光線追蹤+Lumen
-
硬件光線追蹤(RTX/DXR/Metal Ray Tracing):實時計算反射、折射、陰影;
-
軟件全局光照(Lumen、SVOGI、Probe Grid):混合光柵與光線追蹤做間接照明,既快速又真實;
-
混合渲染:在不同場景階段(GI 探針、后期 SSDO、實時 RT)中動態切換,兼顧性能與畫質。
渲染剖析與工具鏈
-
渲染圖(Frame Graph):所有 Render Pass 都以節點化/依賴圖方式管理,可視化調試和自動合并;
-
GPU Profiler & RenderDoc:細粒度分析每個 Pass、每個 DrawCall 的性能,支持管線統計與著色器調試;
-
資產打包與宏:自動提取 Shader Variant、分批預編譯常用 Shader,減少運行時編譯阻塞。
-
Unity HDRP(High Definition Render Pipeline)
-
專為高端 PC/主機打造:支持物理光照、延遲+Tiled 光照、體積霧、光線追蹤特效。
-
用戶可通過 C# 腳本定制 Frame Graph,增刪 Pass;材質系統與 Shader Graph 深度集成。
-
-
Unity URP(Universal Render Pipeline)
-
面向移動端和跨平臺應用:輕量級延遲或前向+Tiled 渲染,支持 Shader Instancing、輕量級后期。
-
-
Unreal Engine 5
-
Nanite + Lumen 雙核技術,自動化虛擬化幾何與全局光照,無需手工烘焙,實時打造電影級場景。
-
-
Godot 4 Vulkan
-
集成 Clustered Shading、GI 探針、屏幕空間環境光遮蔽,且引擎代碼開源可定制。
-
次世代渲染管線 = 可編程化+物理真實感+高效光照+混合光線追蹤 的一整套現代實時圖形架構。
它不僅要在“畫質”上接近電影工業級效果,更要在“性能”上充分利用多核 CPU、GPU Compute 和硬件光線追蹤等能力,為跨平臺的游戲/實時應用提供可擴展、可定制、高性能的渲染解決方案。
“Tiled 光照” 是一種在實時渲染中優化大量點光源/聚光燈的方法,核心思路是把屏幕空間分成一個一個的小“瓦片”(Tile),然后只對每個瓦片中實際影響到的光源做光照計算,而不用讓每個像素都跑遍所有光源。這樣能大幅減少光照計算量。
-
屏幕拆分成瓦片
-
比如把 1920×1080 的屏幕劃分為 16×16 像素的小塊,得到 120×68 共 8160 個瓦片。
-
-
光源—瓦片關聯
-
在一個專門的 Compute Shader(或 CPU 線程)里,遍歷場景里所有的點光/聚光,判斷它們的影響范圍(球體或錐體),再把每個光源加入到與之相交的那些瓦片的“光源列表”里。
-
最終每個瓦片得到一個「僅包含真正會影響該區域的光源索引」的小列表。
-
-
瓦片內像素光照
-
在主渲染 Pass(通常是延遲光照或前向+Clustered)里,每個像素先定位到它屬于哪個瓦片,然后只從該瓦片的光源列表里取出那些光源,逐一做漫反射/鏡面反射計算。
-
這樣即使場景有幾百、上千個光源,大多數像素最多只要計算幾十盞真正可見/有效的光源。
-
-
可擴展:場景光源越多,瓦片大小/分辨率可調;也可以升級到“Clustered”三維分塊,連同深度一起分區。
-
跨管線:既能用在延遲渲染(Deferred)里,也能在前向渲染(Forward)中做“Forward+”或“Clustered Forward”優化。
傳統做法是在幾何階段就給每個物體算好光照(把燈光的影響一起算進去),只需要一次 Pipeline 就完成。但如果場景有多盞燈,就要對每個物體分別跑幾遍頂點→片元,效率會急劇下降。
eferred 渲染(延遲渲染)怎么做的
延遲渲染把上面兩個階段分開,變成:
-
第一次:填 G-Buffer
-
把場景里的所有像素信息(深度、法線、材質參數)寫到多個渲染目標上(稱為 G-Buffer)。
-
實際上 GPU 會同時寫出幾張“貼圖”:
-
一張存 深度;
-
一張存 法線;
-
一張存 漫反射顏色;
-
可能還有張存 金屬度/粗糙度,……
-
-
-
第二次:屏幕空間光照
-
屏幕上每個像素已經有了上一步的所有必要數據,接下來只需在「屏幕四邊形」上做一次遍歷:
-
讀取 G-Buffer 里的深度+法線+材質,
-
針對每個像素列舉出少量相關的燈(用 Tiled/Clustered)
-
計算漫反射+高光+陰影……
-
-
這樣就不用再跑幾何階段,把所有光照都集中在屏幕上一次性完成。
-
為什么說“但 G-Buffer 的讀寫會帶來很高的帶寬消耗”
-
寫入 G-Buffer:在幾何階段,GPU 要向顯存寫入多張大貼圖(深度、法線、顏色……),這就是“多通道寫入”。
-
讀取 G-Buffer:在光照階段,GPU 又要從顯存里讀回這些貼圖數據(多通道讀取),才能拿到每個像素的深度、法線、材質參數。
-
顯存帶寬:顯卡內存的讀寫速度相比它計算速度要慢得多,頻繁的大規模讀寫就會成為瓶頸。
假設你的游戲目標是 1080p(1920×1080),在一個典型的 Deferred 渲染中,你可能會用到如下的 G-Buffer:
G-Buffer 通道 格式 每像素字節數 深度(Depth) 32-bit 4 B 法線(Normal) RGBA16F 8 B 漫反射顏色(Albedo) RGBA8 4 B 金屬度/粗糙度/AO(MRAO) RGBA8 4 B 合計 — 20 B/px
寫入 G-Buffer(Geometry Pass)
每幀要向顯存寫入:
1920 × 1080 ≈ 2.07 × 10^6 像素 × 20 B/像素 ≈ 41.5 MB/幀
讀取 G-Buffer(Lighting Pass)
同樣地,又要從顯存讀出這 41.5 MB/幀。總帶寬消耗
41.5 MB (寫入) + 41.5 MB (讀取) = 83 MB 每幀
不同幀率下的帶寬需求
幀率 帶寬需求 60FPS 83 MB × 60 ≈ 4.98 GB/s 144FPS 83 MB × 144 ≈ 11.9 GB/s 240FPS 83 MB × 240 ≈ 19.9 GB/s 對比一下市面上典型顯卡的理論顯存帶寬:
GTX 1080:≈320 GB/s
RTX 3060:≈360 GB/s
Radeon RX 6700 XT:≈384 GB/s
雖然看起來 60FPS 只用了 ~5 GB/s(“才”占了帶寬的 1–2%),但這只是寫讀 G-Buffer的部分開銷,還不包括:
后續所有的材質貼圖采樣、環境貼圖讀寫;
Shadow Map 的寫入和讀取;
后期特效(Bloom、TAA、DOF 等)的多輪讀寫;
Compute Shader、Stream-Out、Copy 等其它顯存操作。
把這些加起來,顯存帶寬就很快被攥緊了,尤其在更高分辨率(1440p/4K)或更多 G-Buffer 通道(HDR、法線空間貼圖、動量貼圖等)時,帶寬需求幾何倍上升,延遲渲染的“G-Buffer 二次流式讀寫”成為了最大的性能瓶頸之一。
GPU 核心時鐘(Core/Boost Clock)
-
Core Clock(基礎頻率):GPU 在正常負載下的運行頻率。
-
Boost Clock(加速頻率):當溫度、功耗和負載都允許時,GPU 會自動把核心時鐘「超」到更高的值,以提高每秒能執行的著色器指令和渲染單元操作的吞吐量。
-
這兩個時鐘域只管 GPU “算力” 的快慢——它不決定顯存的讀寫速度。
顯存時鐘(Memory Clock)和總線寬度(Bus Width)
-
Memory Clock:顯存芯片(GDDR6/GDDR5/HBM 等)自身的工作頻率。通常廠商會給一個有效速率,比如 14 000 MHz(也叫 14 Gbps)。
-
Bus Width:GPU 與顯存之間的數據通道寬度,比如 128 bit、192 bit、256 bit。
-
它們共同決定了顯存帶寬(Memory Bandwidth),即每秒能搬多少數據給 GPU 核心用。
針對顯存(Memory Clock)的工作頻率
-
如果顯存標為 14 Gbps(Gigabits per second),可以理解為:
-
它每秒鐘能“嘀嗒”14 × 10? 次,每次在那根數據線上傳輸 1 bit(比特)信息。
-
GDDR6 中通常有很多并行數據線(一根數據線按 Memory Interface Width,比如 128 bit,總共就是 128 條線同時在跑這個頻率)。
-
-
為什么說 14 Gbps 而不是 14 GHz?
-
Gbps 是“千兆比特/秒”,是一種經常用在高速串行接口(把寬總線看作一條條并行線)的標法,和 GHz(10? 周期/秒)在含義上很接近,但針對的是“每條線每秒能跑多少比特”。
-
14 Gbps ≈ 14 × 10? Hz,也就是說那根線每秒鐘能“嘀嗒”14 billion 次。
-
Unreal Engine 的 Lumen 和 Nanite 并不是像 HDRP、URP 那樣“腳本化管線”里的一組可插拔節點,而是深度內置在引擎渲染架構里的兩大核心子系統。它們在源碼層面就和 Deferred/Forward 渲染、材質系統、光線追蹤支持等緊密耦合,所以從“普通項目”層面,確實沒法像 Unity 那樣在 C# 或 Shader Graph 里隨意“拆掉”或“重組”它們。
為什么看起來是“定下來了”
-
引擎級集成
-
Lumen 和 Nanite 從 5.0+ 開始就是 UE5 的默認渲染子系統,你在項目設置里只能打開或關閉它們,全流程(從 G-Buffer、光線追蹤、體素緩存到最終合成)都在引擎核心代碼里。
-
-
無 SRP 式腳本化接口
-
Unity 的 HDRP/URP 是建立在 Scriptable Render Pipeline 之上,整個渲染流程的每一步(剔除、Shadow Pass、G-Buffer、Lighting Pass、Post)都暴露給 C#,方便你按需插拔。
-
UE5 則是基于 Render Graph 和 Pipeline State Object (PSO) 的 C++ 實現,對項目開放的擴展點主要在“添加”而非“替換”已有步驟。
-
雖然不能“拆掉整個 Lumen/Nanite”,但如果你有足夠 C++ 資源和愿意編譯引擎,也能做一些深度定制:
-
修改 Renderer 源碼
-
在引擎源碼的
Source/Runtime/Renderer/Private
目錄下,Lumen、Nanite 相關的模塊都是.cpp/.h
文件,你可以 fork UE5 源碼,刪改這些實現,重新編譯你的定制化渲染管線。
-
-
自定義 Render Graph 節點
-
UE5 的渲染流程是基于 Render Graph 構建的。你可以在
FDeferredShadingSceneRenderer::Render()
等入口,插入自定義的 Render Graph Pass,比如在 Lumen GI 前后做一次額外合成。
-
-
自定義 Shading Model
-
如果你只想改材質層面的光照模型,可以在
Engine/Shaders/Private/MaterialShared.usf
里新增一個EBlendMode::Custom
的 Shading Model,改寫GetBaseLighting
、GetLightingModel
之類函數,仍然保留 Lumen 的 GI。
-
-
插件 + 模塊化源碼
-
將你的定制放到一個引擎插件里,并在
.uproject
或.uplugin
里覆蓋 Renderer 模塊,便于在不同項目間復用。
-
對于“風格化效果”——并不推薦改源碼
-
很多定制效果(卡通、像素化、怪誕色調、線框渲染、特定后期合成)都可以用:
-
自定義材質 + 后處理(Post Process)
-
Custom Shading Model / Custom Depth + Stencil
-
插件級 Render Graph Pass(在現有渲染流程里插入一個額外 Pass)
-
-
這些方式都在引擎開放的高層 API(藍圖/C++ 渲染接口)范圍內,不用重新編譯整個引擎,升級版本也更方便。
只有在這些情況下才該動源碼
-
性能:你確定自己的游戲在目標平臺上已經用盡了所有可調 API,只有改內核才能再提升 10% 幀率。
-
功能缺失:引擎高層接口確實做不到你想要的底層操作(非常罕見)。
-
團隊人手:有專門的渲染工程師維護一個私有 UE 源碼分支,并能承擔后續合并和升級的成本。
否則,只為一個風格化 Shader 效果去改動這么龐大的管線,不但風險極高(升級、Bug、兼容性),也大大降低了迭代效率和可維護性。建議優先在現有可擴展接口里做自定義渲染,再視情況決定是不是真的需要“動刀”到引擎級別。
(P2)OBS參數設置_嗶哩嗶哩_bilibili
音頻比特率同理
錄制視頻到底是哪一軌會被寫進去?
這取決于你在“輸出設置”中的“錄制格式和音軌配置”:
-
如果你在設置中選擇 只啟用音軌1 進行錄制,那么最終導出的視頻就只包含音軌1中的內容。
-
如果你啟用了 多音軌錄制(比如 mp4 + 軌道1~3),那么導出的視頻將會攜帶多個音軌,你可以在后期剪輯軟件中單獨調出每條軌道。
你錄了一個教學視頻:
-
軌道1:合成音軌(用于預覽聽感)
-
軌道2:桌面音頻(PPT 聲音 + 視頻素材)
-
軌道3:麥克風(你講解的聲音)
后期你發現某一段麥克風雜音太重、或咳嗽了。
如果你只錄了一個合成軌道(桌面 + 麥克風),你沒法分離出來,只能忍著或者剪掉整段。
但有了獨立軌道:
-
你可以只剪掉麥克風這段,
-
或者加上降噪插件處理,
-
桌面聲音完全不受影響。
無論是 .mp4
、.mkv
還是 .mov
,一旦音軌寫入進去,它們都是標準化的數據結構:
-
可以被讀取 ?
-
可以單獨靜音、剪切、提取、替換 ?
-
可以重新封裝(不重新編碼) ?
.mkv
是編輯友好的首選格式
(P3)OBS直播(基礎篇)_嗶哩嗶哩_bilibili
轉場特效是場景轉換的時候產生的過渡
點擊開始直播(也就是推流,推流可能更加形象一些),想停止,就停止推流,然后去bzhan上設置停止直播的開關
直播時長,錄制時長
總之,需要直播的時候,就使用obs,拿b站或者其他平臺給的推流碼,填入之后就可以直播自己的電腦屏幕,可以用已經了解的obs的規則去管控自己的直播
視頻錄制如果要錄
obs的文件部分可以轉換文件格式,不用擔心mkv保存了最好的音軌調整性,然后轉別的格式不方便
聽到“糊聲”,不是酷狗變了,而是 OBS 改變了“你整個系統的音頻處理路徑”。
想要聽到原來的音質,需要從驅動層、音頻通道、采樣率上做出限制或隔離。
這樣就改了
禁用不需要的音頻通道
OBS 設置 → 音頻:
-
麥克風/輔助音頻1
→ 只啟用你實際用的 -
桌面音頻
→ 啟用你系統默認的那一個 -
其他通道 → 統統設為“禁用”
這樣 OBS 就不會偷偷“激活”多個音頻輸入或輸出接口。
OBS 打開后會觸發自動采樣轉換,造成插值失真
改用獨立聲卡或虛擬音頻設備隔離 OBS
如果你有:
外置 USB 聲卡
虛擬音頻路由(如 VB-Cable、VoiceMeeter)
可以設置:
酷狗 → 播放到真實聲卡(耳機)
OBS → 捕獲虛擬聲卡 / 第二設備,互不干擾
這樣你聽到的不會是 OBS “截獲后的信號”。
藍牙耳機的“聽”和“說”功能之間存在模式沖突,只有一個能高質量運行。
模式 | 名稱 | 用途 | 特征 |
---|---|---|---|
🎵 A2DP | 高質量立體聲傳輸模式 | 聽音樂、看視頻 | 音質好,但不能用麥克風 |
🎙 HFP/HSP | 通話模式(耳機+麥克風) | 打語音、開麥克風 | 可以說話,但音質極差,像電話音 |
所以結論正確:
🟢 如果你外接一個獨立麥克風(USB 或 3.5mm 插口),
🔁 就可以讓藍牙耳機 只用于播放(A2DP),系統不會切換到 HFP 模式,
🎧 你就能持續享受高質量的音頻輸出。
的藍牙音質問題不是 OBS 特有的
這個問題會在所有場景下觸發,比如:
-
微信語音 → 藍牙瞬間變糊
-
QQ語音 → 音樂變差
-
Discord 開啟麥克 → YouTube 音質崩壞
它是 藍牙協議層面的問題,不是 OBS 的 bug。
聲卡就是外接麥克風設備嗎?
不是。
-
有些外接麥克風設備(比如 USB 麥)內置聲卡 → 是二合一設備。
-
但真正意義上的“外置聲卡”,是可以連接多個音源、調節電平、具備專業音頻處理功能的設備,不一定自帶麥克風。
階段 | 技能模塊 | 目標 |
---|---|---|
① 基礎圖形理解 | Unity 渲染流程、URP/HDRP管線結構、ShaderGraph基本邏輯 | 能夠看懂節點、了解 SRP 是干什么的 |
② 真實光照原理 | 漫反射、高光、陰影類型(硬/軟/SSAO)、光照探針、光照貼圖、SH光照 | 能合理解釋光照表現背后的機制 |
③ 性能分析 | Profiler、Frame Debugger 使用,DrawCall 分析、Batches、RenderTexture 代價 | 能識別“這個場景為什么卡、卡在哪” |
④ ShaderGraph 實戰 | 節點功能實際應用:邊緣光、漸變、遮罩、透明、噪聲、流動、特效寫法 | 能實現效果,能解釋原理(如基于法線/UV/世界空間) |
⑤ 渲染管線控制 | 自定義 SRP、RenderFeature、CommandBuffer、Blit 操作、后處理流程 | 對渲染順序、通道、混合有清晰認知,能做高級控制 |
⑥ 跨模塊優化思維 | 與美術/程序協作,場景組織優化(LOD、烘焙、陰影距離)、動態光源管理 | 能在團隊中定位渲染瓶頸,提出合理建議 |
xxxxxxxxxxxxxxx
一片 1K×4 芯片,一共可以存儲 1024 × 4 = 4096 bit = 512 byte
。
8 片 1K×4
存儲芯片,組成一個 4K×8
的存儲器
利用了 地址譯碼器 + 芯片分組 + 數據線并聯 的方法來實現容量與字位的同時擴展。
譯碼器,它根據地址的高位來決定哪一組芯片工作。
防止多個芯片同時干活沖突
總線是共享的資源,所有芯片的數據線通常都是接在 同一條數據總線上。同一時刻,只能有一個芯片處于“工作”狀態,其他芯片都要“閉嘴”(高阻狀態)。不加片選控制,多個芯片都接在數據總線上,一起輸出東西?? 數據總線上誰說了算?電壓會亂跳,變成垃圾數據甚至損壞芯片。
元件 | 訪問延遲(大概數量級) | 說明 |
---|---|---|
寄存器 | 1 個 CPU 時鐘周期 | CPU 內部,最快 |
L1 Cache | ~3-4 個時鐘周期 | 非常快,但容量小 |
L2 Cache | ~10 個周期 | 稍慢一些,容量大些 |
內存(RAM) | ~100 個周期或更多 | 太慢了,CPU等得焦躁 |
硬盤(HDD) | 幾百萬周期 | 簡直是“烏龜” |
Memory Hierarchy(存儲層次結構),就是為了在速度、容量、成本之間做平衡。?
CPU 內核內部,電子信號的傳輸幾乎不需要走線;
沒有中介,不需要“找地址”、“走總線”、“排隊”;
是專為執行指令準備的高速電路(SRAM結構);
L1/L2 Cache:也在芯片里,但要做“內容匹配”,L1 Cache 也在 CPU 芯片上,但要根據地址查找數據是否命中
現代 CPU(以及 GPU)有專門的模塊叫:
FPU(Floating Point Unit)浮點運算單元
它在硬件層面執行 IEEE-754 定義的操作。
大多數2D虛擬主播不需要穿戴動捕設備,只使用攝像頭 +面部追蹤軟件即可實現面部表情和頭部動作的捕捉。
但如果追求全身動作/復雜動態,才可能用到動捕服或外部設備。
游戲主程序通常是 C++,Lua 只是邏輯腳本,改 Lua 不影響主程序運行