Chrome 播放影片時,顯示即時字幕

有時候英文影片沒有字幕,我們可以使用 Chrome 來播放它,並產生即時字幕。
這個功能預設是不開啟的,以下說明如何開啟。

在 Chrome 瀏覽器位置輸入 chrome://settings ,進入設定畫面,找到 無障礙設定
無障礙設定 中的 即時字幕 開啟,他會自動下載語言,你可以選擇添加自己想要的語言。

之後,將影片檔案拖入到 Chrome 中,它就會為你即時產生字幕了。

LTX-Video Test

以下紀錄使用 LTX-Video 的筆記

https://github.com/Lightricks/LTX-Video

首先要將它從 GitHub 拉下來

1
git clone https://github.com/Lightricks/LTX-Video.git

切換到他的資料夾下

1
cd LTX-Video

建立 Python 虛擬環境

1
2
3
python -m venv env
source env/bin/activate
python -m pip install -e .\[inference-script\]

前往 https://huggingface.co/Lightricks/LTX-Video 下載 Model

使用 文字生成影片

1
python inference.py --ckpt_path /Volumes/test/video/ltx-video-2b-v0.9.1.safetensors --prompt "A monkey dance" --height 768 --width 1024 --num_frames 10 --seed 2

使用 圖片生成影片

1
python inference.py --ckpt_path /Volumes/test/video/ltx-video-2b-v0.9.1.safetensors --prompt "A monkey dance" --input_image_path /Volumes/test/video/8e5352fc-70b0-41cd-9a9a-704445df7ab0.png --height 768 --width 1024 --num_frames 200 --frame_rate 20 --seed 3

Mac 使用 ComfyUI

以下紀錄在 Mac 上安裝 ComfyUI 的步驟

  1. 安裝 Homebrew
    • /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
    • https://brew.sh/zh-tw/
  2. 安裝 Python
    • brew install cmake protobuf rust python@3.10 git wget
  3. 切換到你想放 ComfyUI 的位置,在執行 git clone
  4. 切換到下載來 ConfyUI 的位置
    • cd ComfyUI
  5. 執行 Python
    • python3 -m venv venv
  6. 執行以下指令安裝
    • ./venv/bin/pip install torch torchvision torchaudio
    • ./venv/bin/pip install -r requirements.txt
  7. 下載模型
  8. 下載下來的檔案副檔名可能是 .ckpt.safetensors
  9. 把下載完畢的模型放到 ComfyUI 中的 /models/checkpoints 的路徑
    • /ComfyUI/models/checkpoints
  10. 啟動 ComfyUI
    • ./venv/bin/python main.py

若想與 AUTOMATIC1111 Stable Diffusion WebUI 一起使用相同的模型的話,可以找到 extra_model_paths.yaml.example 這個檔案,他應該直接在 ComfyUI 的目錄下。
將檔案複製一份,並更改檔名為 extra_model_paths.yaml
打開後會看到

1
2
a111:
base_path: path/to/stable-diffusion-webui/

把 base_path: 更改為你AUTOMATIC1111 Stable Diffusion WebUI的位置。

1
2
a111:
base_path: /Volumes/test/stable-diffusion-webui/

最後重新啟動 ComfyUI 就可以了。


想更新的話,在資料夾中執行 git pull,然後在執行 ./venv/bin/python main.py 即可

Spring Console Line App

以下紀錄如何使用 Spring Boot 作為 Console Line App
Spring Boot 的版本是 3.4.2

在 application.properties 中加入 spring.main.web-application-type=NONE , 告訴 Spring Boot 不啟動 Web 環境

1
spring.main.web-application-type=NONE

新增一個實作 CommandLineRunner 的類,並標記上 @Component
之後你就可以在這個類的 run() 方法中寫你的 Console Line App 邏輯並使用 Spring 的依賴注入了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Component
public class AppCommandLineRunner implements CommandLineRunner {

Logger logger = LoggerFactory.getLogger(AppCommandLineRunner.class);


@Autowired
private SomeService service;

@Override
public void run(String... args) throws Exception {

logger.info("run the app, args="+ Arrays.toString(args));

service.do();
}

}

如果你每次在執行 Console Line App 時,不想要顯示 Spring banner 的訊息的話,可以在 application.properties 中加入

1
spring.main.banner-mode=off

Java 時間

GMT(Greenwich Mean Time): GMT 是格林威治標準時間,基於地球自轉,定義為通過倫敦格林威治天文台的子午線(本初子午線)的時間。
UTC(Coordinated Universal Time):UTC 是全球協調時間,基於原子鐘的精確計時,與 GMT 基本一致。
在 Java 等程式語言中,通常使用 UTC 作為標準時間,如 Instant.now() 獲取的是 UTC 時間。

台灣的時區是 GMT+8,這表示台灣的時間比格林威治標準時間(GMT)快 8 小時
而英國的時區為 GMT+0 ,這意味著英國的時間與 GMT 相同。
而這兩個地區的時間差了 8 小時 。

如果在台灣的時間是 2025年2月19日 15:30(GMT+8),那麼同一個時間裡,在英國(GMT+0)看到的時間會是 2025年2月19日 15:30 - 8小時 = 2025年2月19日 07:30

Timestamp(時間戳) 是一個整數,代表著從 UTC 1970 年 1 月 1 日 0 時 0 分 0 秒 起至現在的總秒數。

  • 在 Java 中使用 System.currentTimeMillis() 取得 Timestamp

Java 8 以前, 使用 Date ,而 Date 有以下缺陷,不建議使用

  • 是可變的(mutable),是執行緒不安全的
  • 時區 和 Timestamp 混在一起,會因不同的電腦系統導致顯示不同時間。
  • 若要處理時區需借助 SimpleDateFormat 或其他 Library 輔助。
    • SimpleDateFormat 是執行緒不安全的
  • 日期與時間沒有分開,無法只單獨處理時間或是日期。
    • 你只想要日期的話,在 Date 物件中仍然會有時間的部分,它會顯示為 2025-02-06 00:00:00

Java 8 推出了 java.time

無時區的日期時間

LocalDate

  • LocalDate 代表日期,只儲存了年、月、日。
  • 是不可變的(immutable)
1
2
3
4
5
6
7
8
9
10
LocalDate date = LocalDate.now();
System.out.println(date1); // 2025-02-06

date = LocalDate.of(2025, 2, 6);
// 由於是不可變的,因此透過重新賦值來更改。
date = date.plusDays(5); // 增加 5 天
System.out.println(date.getYear()); // 2025
System.out.println(date.getMonth()); // FEBRUARY
System.out.println(date.getMonthValue()); // 2
System.out.println(date.getDayOfMonth()); // 11

LocalTime

  • 代表時間,只儲存時間,時、分、秒,此外,也儲存奈秒。
  • 是不可變的(immutable)
1
2
3
4
5
6
7
LocalTime time = LocalTime.now();
System.out.println(time); // 15:40:54.204743

time = time.minusSeconds(5); // 減少 5 秒
System.out.println(time.getHour()); // 15
System.out.println(time.getMinute()); // 40
System.out.println(time.getSecond()); // 49

LocalDateTime

  • 封裝了 LocalDateLocalTime 代表日期時間
  • 是不可變的(immutable)
1
2
3
4
5
6
7
8
9
10
11
LocalDateTime dateTime = LocalDateTime.now();
System.out.println(dateTime); // 2025-02-19T15:43:26.124154

dateTime = dateTime.plusDays(30);

System.out.println(dateTime.getYear()); // 2025
System.out.println(dateTime.getMonthValue()); // 3
System.out.println(dateTime.getDayOfMonth()); // 21
System.out.println(dateTime.getHour()); // 15
System.out.println(dateTime.getMinute()); // 43
System.out.println(dateTime.getSecond()); // 26

DateTimeFormatter

  • 和 SimpleDateFormat 類似,用來進行日期時間物件,與字串之間的互換,但不用處理 ParseException 這個 checked exception。
1
2
3
4
5
var formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");

LocalDateTime dateTime = LocalDateTime.parse("2025/02/06 01:02:03", formatter);
System.out.println(dateTime); // 2025-02-06T01:02:03
System.out.println(formatter.format(dateTime)); // 2025/02/06 01:02:03

有時區的日期時間

ZonedDateTime

  • 有時區的日期時間

ZoneId

  • 可以使用 ZoneId.getAvailableZoneIds() 取得支援的 key 值。
1
2
3
4
5
6
7
8
ZonedDateTime now = ZonedDateTime.now();
System.out.println("Current ZonedDateTime: " + now); // Current ZonedDateTime: 2025-02-19T15:56:36.652708+08:00[Asia/Taipei]

ZonedDateTime nowInUTC = ZonedDateTime.now(ZoneId.of("UTC"));
System.out.println("Current time in UTC: " + nowInUTC); // Current time in UTC: 2025-02-19T07:56:36.652850Z[UTC]

ZonedDateTime nowInTaipei = ZonedDateTime.now(ZoneId.of("Asia/Taipei"));
System.out.println("Current time in Taipei: " + nowInTaipei); // Current time in Taipei: 2025-02-19T15:56:36.652881+08:00[Asia/Taipei]

亦可直接使用偏移量即 UTC/GMT,來定義 ZoneId

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var dateTime = LocalDateTime.now();

// 定義東京的 ZoneId (UTC+9)
var tokyoZoneId = ZoneId.of("+0900");
var tokyoDateTime = ZonedDateTime.of(dateTime, tokyoZoneId);

// 定義倫敦的 ZoneId (UTC+0)
var londonZoneId = ZoneId.of("+0000");
var londonDateTime = tokyoDateTime.withZoneSameInstant(londonZoneId);

// 輸出東京時間
System.out.println(tokyoDateTime); // 2025-02-19T16:04:38.833229+09:00
// 輸出倫敦時間
System.out.println(londonDateTime); // 2025-02-19T07:04:38.833229Z


參考

Shader Graph 入門

以下將使用 Shader Graph 建立一個簡單的 Shader , 這個 Shader 能夠正常接收 Sprite Renderer 的 Sprite,並允許透過 Sprite Renderer 的 Color 來調整顏色。

  1. 建立 Shader Graph : 在 Unity,前往 Assets 資料夾,右鍵點擊 → Create → Shader Graph → Unlit Shader Graph。命名 為 Color Shader Graph。並雙擊打開 Shader Graph 編輯器。
  2. 在 Shader Graph 中,我們需要一個 Texture2D 屬性
    • 在左側的面板上,找到 + , 點擊 + 並選擇 Texture2D,將其命名(Name)為 MainTex。
    • 命名為 MainTex , 會發現 Reference 變為 _MainTex。這樣當這個 Shader 被應用到 Sprite Renderer 的 Material 上時,Sprite Renderer 會自動把它的 Sprite 貼圖傳遞給 _MainTex。這樣 Shader 就能正確使用 Sprite 的貼圖,而不需要手動指定 Texture。
  3. 在 Shader Graph 中,我們需要三個 Node
    • Sample Texture 2D : 把建立好的 Texture2D 屬性 (_MainTex) 輸入到這個 Sample Texture 2D 節點的 Texture 2D 。
    • Vertex Color : 這個節點會讀取 Sprite Renderer 設定的 Color 。
    • Multiply : 建立一個 後。
      • 將 Sample Texture 2D 的輸出(RGBA) 連接到 Multiply(A 輸入)
      • 將 Vertex Color 的輸出(RGBA) 連接到 Multiply(B 輸入)
  4. 最後將 Multiply 的輸出 連接到 Fragment Output 的 Base Color。
  5. 建立一個 Material , 將他的 Shader 設為在上面的 Shader Graph 。
  6. 建立一個 Sprite Renderer , 指定一個 Sprite , 並賦予剛剛建立的 Material
  7. 調整 Sprite Renderer 中的 Color 看看是否有變更顏色。
  8. 可以發現當 Sprite Renderer Color 為白色的時候,呈現的是材質本身的顏色。這就是我們為何使用相乘 (Multiply) 的原因。

為什麼需要建立一個 Vertex Color ?

  • 這是因為 Sprite Renderer 的 Color 其實是「頂點顏色(Vertex Color)」,Unity 會把它當作一個 Color 傳進 Shader。
  • 如果你的 Shader 沒有讀取 Vertex Color,那麼 Sprite Renderer 改變 Color 也不會影響最終顯示的顏色。

為什麼要用相乘 (Multiply)?

  • 因為 Sprite Renderer 的 Color 本質上是「顏色的縮放因子」,影響材質的最終顏色。
  • 所以,Shader 必須把 Texture 的顏色與 Vertex Color 相乘,這樣才能讓 Color 正確影響結果!
  • 假設:
    • Texture Color 是 (1, 1, 1, 1)(白色)
    • Vertex Color 是 (1, 0, 0, 1)(紅色)
    • 那麼,最終顏色 = 𝑇𝑒𝑥𝑡𝑢𝑟𝑒𝐶𝑜𝑙𝑜𝑟 × 𝑉𝑒𝑟𝑡𝑒𝑥𝐶𝑜𝑙𝑜𝑟 = (1,1,1,1)×(1,0,0,1)=(1,0,0,1) → 結果變成紅色!
  • 同理:
    • (0.5, 0.5, 0.5, 1) × (1, 0, 0, 1) = (0.5, 0, 0, 1) → 半透明紅色!
    • (1, 1, 1, 1) × (1, 1, 1, 1) = (1, 1, 1, 1) → 不變!
    • (1, 1, 1, 1) × (0.5, 0.5, 0.5, 1) = (0.5, 0.5, 0.5, 1) → 降低亮度!

Shader Graph 筆記大綱

  1. Shader Graph 的 Space:在 Shader Graph 中,Space(空間)是指資料在不同坐標系統中的表示方式。不同的空間決定了資料如何被處理和顯示,對於著色器的效果有著重要的影響。Shader Graph 中常見的空間類型有:Object Space、World Space、View/Camera Space、Tangent Space 和 Clip Space。
  2. Shader Graph Block Nodes:在 Shader Graph 中,Block Nodes(區塊節點)是組成著色器的基本元素。每個區塊節點代表著一個特定的資料處理功能,這些區塊節點可以在 Master Stack 中組合,最終輸出到著色器的結果。這些節點會處理像是頂點、法線、顏色、光照等屬性,並控制著色器的行為。
  3. Shader Graph Properties : 在 Shader Graph 中,Properties (屬性)是用來設定和控制著色器的外部變量,這些變量可以從 Unity 的材質面板中進行調整,並影響著色器的輸出。這些屬性讓你在不修改 Shader Graph 設定的情況下,動態改變材質的外觀。它們通常用來創建可調整的材質效果,並且可以進行繫結到 Shader Graph 中的不同節點,以控制最終渲染結果。
  4. Shader Graph Nodes :Shader Graph Nodes 是 Shader Graph 中的組件,每個節點都有特定的功能,並且可以連接到其他節點來實現所需的效果。這些節點提供了創建圖形效果所需的數學計算、變換、顏色處理、貼圖采樣等操作。
  5. Shader Graph 入門 : 這篇教學使用 Shader Graph 建立了一個簡單的 Shader,讓 Sprite Renderer 在使用 Material 的時候,仍然可以用 Color 影響顏色。

Shader Graph Properties

在 Shader Graph 中,Properties(屬性)是用來設定和控制著色器的外部變量,這些變量可以從 Unity 的材質面板中進行調整,並影響著色器的輸出。這些屬性讓你在不修改 Shader Graph 設定的情況下,動態改變材質的外觀。它們通常用來創建可調整的材質效果,並且可以進行繫結到 Shader Graph 中的不同節點,以控制最終渲染結果。

在 Unity 中,屬性有 NameReference 兩種名稱,其中

  • Name 這是人類可讀的屬性名稱,會在 Unity Editor 的 Inspector 視窗中顯示,供設計師或開發者查看和修改。
  • Reference 這是 C# 腳本 中引用該屬性的名稱。在編寫腳本時,會使用這個名稱來取得和設置該屬性的值。
  • 命名規範一般為
    • Name : Main Tex
    • Reference : _MainTex

Shader Graph Properties 的種類

  • Float (浮點數) : 這是一個單一的數值屬性,用來控制各種數值參數,如金屬度、光滑度、透明度等。
  • Vector2、Vector3 和 Vector4 : 這是一個具有多個分量的數值屬性,常見的有 Vector2、Vector3 和 Vector4。
  • Color (顏色) : 顏色屬性通常表示為 Vector4,其中四個分量分別對應紅色 (R)、綠色 (G)、藍色 (B) 和透明度(Alpha)。
  • Boolean (布林): 用來表示一個開(True)/關(False)狀態,通常是用來控制某些效果的開啟或關閉。
  • Gradient (漸變): 用來控制顏色漸變,在 Gradient Window 中添加或移除控制點(handles),來設定漸變中某個位置的顏色(底部標記設定顏色)或透明度(上部標誌設定透明度)。
  • Texture 2D (2D 紋理) : 此屬性用來將圖像或紋理資料傳遞給著色器,並可以用來改變物體的外觀。
  • Texture 2D Array (2D 紋理陣列) : Texture 2D Array 是一組具有相同大小和格式的 2D 紋理,這些紋理被打包在一起,讓 GPU 可以將它們當作一個單一的紋理來讀取,從而提高效能。
  • Texture 3D (3D 紋理) : Texture 3D 類似於 Texture 2D,但它多了一個維度,因此它是一個 3D 顏色數據的區塊。簡單來說,Texture 3D 是一個包含多層紋理的三維紋理,每一層就像是 2D 紋理,但它們在第三個維度中有不同的深度。
  • Cubemap : Cubemap 是一種特殊的紋理類型,概念上就像是立方體的網格(網格展開圖)。可以將它理解為六個紋理被拼接在一起,形成一個立方體的外表面。這使得 Cubemap 在處理一些三維效果時非常有用,特別是對於天空盒和反射映射。
  • Virtual Texture : 虛擬紋理(Virtual Textures) 可用於減少高解析度紋理的記憶體佔用,這對於使用多個高解析度紋理的情況特別有用。不過,虛擬紋理目前僅在 HDRP(高畫質渲染管線)中受支持。
  • Matrix (矩陣) : 這些屬性用來描述坐標轉換,通常是用來處理模型、視圖和投影矩陣。
    • Matrix 2 : 2x2 浮點數矩陣,當你創建一個這種類型的屬性時,預設值會是 2x2 單位矩陣(identity matrix),該矩陣的對角線上是 1,其餘位置是 0。
    • Matrix 3 : 3x3 浮點數矩陣。
    • Matrix 4 : 4x4 浮點數矩陣。
    • 矩陣類型(Matrix 2、Matrix 3 和 Matrix 4)都無法暴露到 Inspector 面板中。
  • Sampler State : Sampler State 用來控制如何取樣一個紋理(Texture)。這些屬性可以幫助我們定義紋理在渲染過程中的取樣行為,包括濾鏡(Filter)和包裹模式(Wrap Mode)等。這些設置決定了當紋理的 UV 坐標超過紋理邊界時的行為,以及紋理如何進行平滑處理。
    • Sampler State 無法暴露到 Inspector 面板中
    • Filter(濾鏡):控制紋理的平滑方式,通常用於當紋理縮放時進行處理。
      • Point:不進行平滑處理,使用最接近的像素顏色,通常稱為最近鄰取樣,適合小尺寸紋理。
      • Linear:對相鄰的像素進行平滑過渡,這是一種常見的紋理過渡方式,適用於中等解析度的紋理。
      • Trilinear:除了在像素間進行平滑處理,還會在不同的 mipmap 層級之間進行平滑過渡,這對於大範圍的紋理變換來說更為平滑。
    • Wrap Mode(包裹模式):控制當紋理的 UV 坐標超出範圍時的處理方式。
      • Repeat:紋理會在超出範圍的區域重複顯示,無縫平鋪。
      • Clamp:UV 坐標會被限制在紋理邊界內,超出範圍的部分會使用紋理的邊緣顏色。
      • Mirror:類似於 Repeat,但每次穿越邊界時會鏡像反射紋理,會創建一種鏡像效果。
      • MirrorOnce:與 Mirror 類似,但超出範圍的 UV 坐標會被限制在第一次反射後的區域。

Keyword

使用 Keyword 創建不同的 Shader Graph 變體 (variants),這些特性可以根據需求開啟或關閉,並可以針對不同的平台或條件進行調整。這些變體可以增加 Shader 的複雜度,也能根據設定的條件進行縮放。

  • 在 Keyword 面板中,會有一個 Scope 屬性,選擇 Local 的話,表示是只在該 Shader Graph 私有(private) , 選擇 Global 則表示在整個專案中所有 Shaders 皆可使用此屬性。
  • Boolean (Keyword) : 值為 true 或 false,使用它會導致生成兩個不同的著色器變體(shader variants)。根據定義的不同,這些變體的行為會有所不同。這類關鍵字常用於啟用或禁用某些功能,或根據條件選擇不同的著色器邏輯。
  • Enum (Keyword) : Enum 關鍵字類型 允許我們添加一組字符串,這些字符串是該枚舉可以取的值,並可以設置其中一個為預設值。這使得我們能夠根據這個枚舉的值來改變 Shader Graph 的行為。
  • Material Quality (Keyword) : 是一個內建的枚舉關鍵字,根據您的項目中的品質設置,自動由 Unity 或特定的渲染管線添加。這個關鍵字基於遊戲的圖形質量設定來調整 Shader Graph 的行為。例如,您可能會選擇在較低的材質品質設置下,使用較低的 LOD(細節層級)來減少渲染負擔,從而提高遊戲的運行效能。

參考

Shader Graph Block Node 筆記

Block Node

  • 是一種特殊類型的節點,用於 Master Stack 中。每個 Block 代表了 Shader Graph 在最終著色器輸出中使用的單一表面(surface)(或頂點(vertex))描述資料。
  • 內建的 Block 節點 始終可用,
  • 但特定渲染管線的節點僅在該管線中可用。例如,
    • Universal Block 節點 只在 Universal Render Pipeline(URP) 中可用,
    • 而 High Definition Block 節點 只在 High Definition Render Pipeline(HDRP) 中可用。
  • 某些 Block 只有在特定的 Graph Settings 下才會兼容,並且可能會根據你選擇的圖表設置變為啟用或禁用。
  • 你無法對 Block 進行剪切、複製或粘貼操作。
  • 而某些節點只能在 頂點階段(Vertex Stage) 或 片段階段(Fragment Stage) 使用。

Vertex Stage Blocks

在 頂點階段(Vertex Stage),著色器(shader)會對網格 (mesh) 上的每個頂點(vertex)進行處理,並將它們移動到螢幕(screen)上的正確位置。我們可以對頂點進行操作,例如移動它們,或改變光照與它們的互動方式。

Position (Block): Position(位置)區塊 定義了 網格(Mesh)上每個頂點的位置。

  • 如果不進行修改,頂點的位置將與 建模軟體中的原始位置 相同。
  • 我們可以調整這個 Vector3 來改變頂點的位置,使網格實際發生形變,例如海浪效果。
  • 但要注意,我們無法修改單獨的像素(Pixels)或片段(Fragments)的位置,只能操作頂點(Vertices)。

Normal (Block): Normal(法線)區塊 定義了 頂點法線(vertex normal points)的方向(direction)。

  • 這個方向對許多 光照計算 來說非常重要,因此修改它可能會影響 物件與光線的互動方式。
  • 與 Position Block 不同,我們可以在 片段階段(Fragment Stage) 透過其他區塊節點來 逐像素(Per-Pixel)修改法線,而不只是修改頂點的法線。
  • Normal 也是一個 Vector3,用來表示法線的方向。

Tangent (Block) : Tangent(切線)區塊 可以用來 修改切線向量。

  • 切線向量(Tangent vector) 與 頂點法線(Vertex Normal)垂直(perpendicular),在平坦的表面上,它通常會沿著物件的表面方向。
  • 如果你更改了頂點法線(Vertex Normal),建議你也調整切線(Tangent),以確保它仍然與法線保持垂直關係。
  • Tangent 也是一個 Vector3,表示方向。

Fragment Stage Blocks

  • 當 頂點階段(Vertex Stage)完成頂點的變換並確定它們的新位置後,畫面會進行 光柵化(Rasterization),將 3D 資訊轉換成一個片段(Fragment)陣列。
  • 通常,每個片段(Fragment)對應到一個像素(Pixel),但在某些情況下,片段的大小可能會小於像素(例如抗鋸齒技術)。
  • 為了簡化討論,這裡我們將「片段」與「像素」視為相同的概念。
    片段階段(Fragment Stage) 中的區塊(Block Nodes)會對每個像素進行操作,例如決定顏色、透明度、光照等效果。

Base Color (Block)

  • 在某些版本的 Shader Graph 中,這個屬性被稱為 Albedo(反照率)。
    Base Color(基礎顏色) 是物件的純顏色,如果忽略所有光照、透明度與其他效果,物件將會顯示這個顏色。

Normal (Tangent/Object/World) (Block)

  • 在頂點階段(Vertex Stage) 有自己的 Normal(法線)區塊。在這個片段階段(Fragment Stage),我們可以存取這個法線資訊,進一步修改每個像素的法線向量,並將修改後的法線傳回 Unity 的內建光照計算系統。
  • Shader Graph 中有 三種 Normal(法線)區塊,它們的差別在於所使用的座標空間:
    • Tangent Space(切線空間)
    • Object Space(物件空間)
    • World Space(世界空間)
  • 在 Shader 設定中,同一時間只能啟用一種法線空間,你可以在 Graph Settings(圖形設定)中透過 Fragment Normal Space(片段法線空間) 選擇要使用的空間類型。

Emission (Block)

  • 自發光(Emissive)光源 是一種非常適合用來 創建物件周圍的輝光(Bloom)效果 的技術。可以想像像是 霓虹燈、發光火焰 或 魔法咒語 等效果。
  • Emission(發光)區塊 接受 HDR 顏色(高動態範圍顏色),這讓我們能夠將光源的強度 提高到遠超過一般顏色的範圍,產生更亮、更強烈的光效。

Metallic (Block)

  • Metallic(金屬性)區塊 接受一個 浮點數(float) 值。當數值為 0 時,物體的光照效果會像是 完全非金屬(non-metallic),而當數值為 1 時,物體會呈現 完全金屬(totally metallic)。
  • 這個屬性只有在使用 金屬性工作流(Metallic workflow) 時才會生效。你可以在 Graph Settings(圖形設定) 中,使用 Workflow 選項來選擇使用金屬性工作流還是 鏡面反射工作流(Specular workflow),且只有在材質設定為 Lit(有光照) 時,這個選項才會出現。

Specular (Block)

  • 與 Metallic(金屬性) 區塊不同,Specular(鏡面反射) 區塊接收的是 顏色 作為輸入,因為鏡面反射高光(Specular Highlights)可以有不同的顏色。顏色越亮、越接近白色,鏡面反射的高光就越強。

Smoothness (Block)

  • 物體表面越光滑,光照高光的顯示就越明顯。當 Smoothness(光滑度) 為 0 時,物體表面的光照會顯得粗糙且無光澤;而當 Smoothness 為 1 時,物體表面會像 鏡面一樣光滑,反射出明亮的高光。

Ambient Occlusion (Block)

環境遮蔽(Ambient Occlusion,簡稱 AO) 是一種測量像素受到其他場景物體(如牆壁)遮擋,從而減少光源照射的程度。這是一個 浮點數(float) 值,當值為 0 時,該像素應該完全根據照射到它的光源來顯示照明效果;當值為 1 時,光照會被人為減少到最小值。

Alpha (Block)

Alpha 是衡量像素透明度的數值,它的範圍從 0 到 1,其中 0 代表完全透明(totally transparent),而 1 代表完全不透明(fully opaque)。渲染透明物體比渲染不透明物體更消耗計算資源,因此在 Unity 中,我們需要在 Graph Settings 中選擇 Transparent Surface 選項,讓 Unity 正確處理這個著色器。

Alpha Clip Threshold (Block)

Alpha 剪裁(Alpha Clipping),當像素的 alpha 值低於特定閾值時,這些像素會被剔除(culling)。我們可以通過在 Graph Settings 中勾選 Alpha Clip 選項來啟用 Alpha Clip Threshold 區塊。這項技術無論是物體表面設置為透明(Transparent)還是完全不透明(Opaque)都可以使用,因此 Alpha 區塊在不透明材質上也不一定是完全無用的!這在模擬透明效果時非常有用,通常會使用不透明渲染,但會根據一定模式剔除像素,從而創造出透明的假象。


參考

Shader Graph 的空間

Object Space

  • 模型的所有頂點位置都是 相對於該物件的中心點(Pivot Point) 來計算的,而不是世界原點 (0,0,0)

World Space

  • 世界空間(World Space) 是所有物件共享的一個全域座標系統,其中所有物件的位置都是相對於 世界原點 (0,0,0) 來計算的。在 Unity Editor 中,當你修改某個 Object Transform 的位置,就是在修改那個 Object 的 World Space。
  • 假設有一個物件 A 在 (3,2,1) 的世界座標,然後它的子物件 B 在 localPosition = (1,1,1):
    • A.position = (3,2,1)(世界空間)
    • B.localPosition = (1,1,1)(本地空間,相對於 A)
    • B.position = (4,3,2)(世界空間,因為 A 的位置 + B 的本地位置 = 世界位置)
    • 所以,如果你在 Unity 編輯器中修改 B.position,你就是在改變它的 世界空間座標,而 B.localPosition 會自動調整,以維持相對於 A 的關係。

Absolute World Space 與 World Space

  • URP:Universal Render Pipeline(通用渲染管線),較強調效能,適合跨平台。
  • HDRP:High Definition Render Pipeline(高解析度渲染管線),較強調畫質,適用於 高端 PC、主機遊戲、電影級畫質
  • 在 URP 中,world space 與 absolute world space 是一樣的。
  • 但是在 HDRP 中,他使用 camera relative rendering , 因此 HDRP 的 world space 是相對於相機的 (camera-relative) ,而他的 absolute world space 則不管相機。

Tangent Space

  • 在 切線空間(Tangent Space) 中,位置和方向是相對於每個頂點及其法線來定義的。

View/Eye Space

  • 在 視圖空間(View/Eye Space) 中,物件的位置是相對於相機及其朝前的方向( forward-facing direction )來描述的。這與 相機相對渲染(Camera-Relative Rendering) 不同,因為視圖空間會考慮相機的旋轉。

Clip space

  • 在 裁剪空間(Clip Space) 中,物件的位置是相對於螢幕(Screen)的。這個空間是在視圖空間經過投影變換(projected)後產生的,其結果取決於相機的視野範圍(Field of View, FOV)和裁剪平面(Clipping Planes)。通常,超出裁剪空間範圍的物體會被裁剪(Clipped),也稱為剔除(Culled),簡單來說就是被刪除,因此這個空間被稱為「裁剪空間」。