2018-01-28 Shader中法線變換的記錄

1.從“模型空間”到“世界空間”(Object To World):

(1)方法1,使用和“頂點”到“世界”變換矩陣的“逆轉置矩陣“對法線進行相同的變換,因此先得到頂點的模型到世界的變換矩陣的“逆矩陣”(Unity_WorldToObject),然后通過調換它在mul函數中的位置,得到和轉置矩陣相同的矩陣乘法,由于法線是一個三維矢量,因此我們只需要街截取unity_WorldToObject的前三行前三列:

worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject))

最外側的運算“normalize(x)”表示歸一化。

(2)使用Unity內置的語法“UnityObjectToWorldNormal()”。
這是Unity5.x在中,可以通過“內置著色器”中的“Unity.cginc”中找到相關的用法,截一小段代碼:

// Transforms normal from object to world space
inline float3 UnityObjectToWorldNormal( in float3 norm )
{
#ifdef UNITY_ASSUME_UNIFORM_SCALING
    return UnityObjectToWorldDir(norm);
#else
    // mul(IT_M, norm) => mul(norm, I_M) => {dot(norm, I_M.col0), dot(norm, I_M.col1), dot(norm, I_M.col2)}
    return normalize(mul(norm, (float3x3)unity_WorldToObject));
#endif
}

注釋已經寫的很清楚了“把法線從模型空間變換到世界空間”,里面做了個判斷。如果是“統一縮放”那么這個方法用的是“UnityObjectToWorldDir()”,如果是非統一縮放,則用“normalize(mul(norm, (float3x3)unity_WorldToObject)”,這個就是和“方法1”是一模一樣的。之所以這種寫法,就是為了保證模型“非統一縮放”也不會得到錯誤的法線。
而Unity封裝的這個方法,就解決了,不管模型是不是統一縮放,用這個肯定沒有錯。在Unity4.x和之前,是不用管是不是統一縮放的,因為當模型縮放后,unity會在背后重新生成一個模型,和縮放后的一樣大,從而法線肯定不會錯。但是unity5.x及以后,就必須要注意這個問題。
下面看一下在shader中,怎么使用這個方法:

normalDir = UnityObjectToWorldNormal(v.normal)

很簡單的一句話。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容