Unity:製作可相交的視差遮蔽貼圖 Shader 續 (Parallax Occlusion Mapping Shader with Pixel Depth Offset)

前言 在 幾年前的文章 曾有提到嘗試製作可相交的視差遮蔽貼圖(以下都簡稱 POM) Shader,然而當時一直留下一個疑問,就是計算深度偏移的量一直不是很正確。 本文新的實現方法,與幾年前的看起來相似,但是有穩定的深度位移 多年後終於有能力重新整理過一次,看了 Unity 的原始碼才發現當年已經離問題的所在很接近了,在後來版本的 Unity 裡面可以看到解決方法,在 Shader Graph Parallax Occlusion Mapping 這個 Node 的參數可以看到問題的所在。 POM 控制垂直偏移高度的參數(Unity 中為 Amplitude)在本文章使用的是物件空間座標,如果偏移高度參數是 0.6,代表著表面到最底部距離在物件空間的座標下相差 0.6 公尺。 原始碼 有關原始碼,請詳見 Github 專案 。 問題根源-如何計算逐像素的世界空間座標偏移量 這個問題關鍵就在於 UV 空間座標的 U軸 和 V 軸這兩個基向量在物件空間的長度。當要計算各個像素位移後的深度時必須知道各個像素在偏移後的世界座標是多少,然後再計算出深度。 提醒一點:U 軸 和 V 軸基向量在某些條件對應到切線與副切線,但不是絕對,因為 U軸 和 V 軸可以沒有正交,切線與副切線卻必須正交,這個限制了使用 POM 的模型不能有太多 UV 扭曲和法線調整 從 POM 的計算裡會得到射線(viewDir)與位移後表面交點的高度(Tp 點的高度),可以藉此高度值計算 T0 到 Tp 的位移向量 T0Tp ,如果這個位移向量的長度正好就是世界空間的長度,那麼只需要將是世界空間的射線向量乘以這個長度,然而在將射線的向量轉換的過程中會令這個長度可能沒有符合世界空間的長度,所以要在轉換過程中確保轉換後的長度一致。 Unity 版本的視差遮蔽,由物件表面為 1 起始 Created by modifying " LearnOpenGL " (© JoeyDeVries ( Licensed under CC BY 4.0 )) 用來計算 POM 的射線一開始為世界空間的單位向量(viewDirWS),如果使用此向量,得到的偏移高度會是世界空間,無法跟隨物體縮放,於是一開始先除以...