日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

Unity3D教程宝典之Shader篇:第二十讲法线贴图

發(fā)布時間:2023/12/15 综合教程 43 生活家
生活随笔 收集整理的這篇文章主要介紹了 Unity3D教程宝典之Shader篇:第二十讲法线贴图 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

轉載自風宇沖Unity3D教程學院



上一講我們講了凹凸貼圖以及生成法線貼圖。
這一講來談談怎么使用法線貼圖。
一:法線貼圖的原理
二:法線貼圖的實現(xiàn)
三:法線貼圖的使用
四:法線貼圖的格式

一:法線貼圖的原理
光照效果很大程度上是由垂直于物體表面的法線決定的,因為法線影響反射光的方向。均勻垂直的法線是鏡面貼圖。但是有時候我們會給一個平面使用磚墻貼圖,磚墻應該是凹凸不平的,而如果讓磚墻使用該平面的法線的話,畫面就會很假,神馬?一面墻像鏡子一樣反光=。=

而如果按真實磚墻去做模型的話,即做高精度模型,一方面制作麻煩,另一方面運行時對性能損耗大。
法線貼圖就是來解決這個問題的。法線貼圖就是把法線信息儲存在一張圖里。使用法線貼圖時,通常頂點數(shù)和三角形面數(shù)只有高精度模型的十分之一不到。

二:法線貼圖的實現(xiàn)
將材質貼圖對應的法線 繪制在一張貼圖上。將貼圖對應點的單位法線向量信息float3(x,y,z) 儲存在圖對應的顏色里color(r,g,b)里,其中x,y,z分別對應r,g,b。單位法線向量 float3(x,y,z),x,y,z的取值范圍是 [-1,1]。在法線貼圖中被壓縮在顏色的范圍[0,1]中,所以需要轉換:
顏色 = 0.5 * 法線 + 0.5;
線= 2 * (顏色- 0.5);

三:法線貼圖的使用
主要步驟
(1)對法線貼圖進行采樣,取得壓縮在顏色空間[0,1]里的法線
float4 packedNormal = tex2D(_NormalMap, IN.uv_MainTex);
(2)將壓縮在[0,1]里的法線轉換至3D空間[-1,1] (因為是單位向量)
float3 expand(float3 v) {return(v -0.5) *2; }
之后使用該法線即可,方法與16講里一樣。

具體實現(xiàn)詳見本文末的腳本。

四:法線貼圖的格式
法線貼圖主要分為2個類別:
(1)RGB法線貼圖,即上面使用的。通常呈藍色。(后綴可以是常見的.png .jpg等)
(2)壓縮格式的法線貼圖。例如DXT5nm(后綴名為.dds)

dds是DirectDraw Surface的縮寫,實際上,它是DirectX紋理壓縮(DirectX Texture Compression,簡稱DXTC)的產(chǎn)物。DXTC減少了紋理內存消耗的50%甚至更多,有3種DXTC的格式可供使用,它們分別是DXT1,DXT3和DXT5。 

有關DDS的延伸閱讀

壓縮法線貼圖的原理
法線(x,y,z)是一條單位向量。故X2+ Y2+Z2=1。所以知道了x,y,z里的任意兩個,剩下的那個就可以通過計算得出。所以我們就可以使用2個通道的圖儲存x,y,z里的兩個值,將xyz里剩余的值省略,通過計算得出。

壓縮法線貼圖的好處
壓縮后的法線貼圖,大小只有原來的1/4左右,故可以使用更大或者更多的貼圖來提升畫面品質。

Unity3d的法線貼圖
Unity3d使用的壓縮法線貼圖是DXT5nm格式的。有A和G兩個通道。對于法線(x,y,z) A對應x,G對應y。
對壓縮法線貼圖的采樣依然是如下函數(shù):

float4 packedNormal = tex2D(_NormalMap, IN.uv_MainTex);

packedNormal.w對應A通道,即法線的x。

packedNormal.y對應G通道,即法線的y。

范圍依然是[0,1], 依然需要轉換至[-1,1]。
對DXT5nm法線貼圖進行轉換的函數(shù)如下,其中v傳入packedNormal

float3 expand(float3 v)
{ 
    fixed3 normal;
    normal.xy = v.wy * 2 - 1;
    normal.z = sqrt(1 - normal.x*normal.x - normal.y * normal.y);
    return normal;
}

  


Unity3d的標準法線解壓函數(shù)是fixed3 UnpackNormal(fixed4 packednormal)。
打開UnityCG.cginc找到對應函數(shù):

inline fixed3 UnpackNormal(fixed4 packednormal)
{
    #if defined(SHADER_API_GLES) && defined(SHADER_API_MOBILE)
        return packednormal.xyz * 2 - 1;
    #else
        fixed3 normal;
        normal.xy = packednormal.wy * 2 - 1;
        normal.z = sqrt(1 - normal.x*normal.x - normal.y * normal.y);
        return normal;
    #endif
}    

  

該函數(shù)定義的如果是移動平臺或者OpenGL ES,那么斷定使用的是RGB法線貼圖,否則則為DXT5nm貼圖。
但實際上移動平臺也可以用壓縮格式的法線貼圖,而Windows也能使用RGB法線貼圖。故不建議使用UnpackNormal函數(shù),建議根據(jù)法線貼圖的具體格式來使用自己寫的對應函數(shù)。

================================================================================================
================================================================================================
================================================================================================

腳本:

//  Shader: 帶法線貼圖的Surface Shader
//  Author: 風宇沖
Shader "Custom/3_NormalMap" {
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _NormalMap ("NormalMap", 2D) = "white" {}
    }
 
    Subshader
    {
        CGPROGRAM
        #pragma surface surf BlinnPhong 
        struct Input
        {
            float2 uv_MainTex;
        };
 
        //法線范圍轉換:單位法線 float3(x,y,z),x,y,z的取值范圍是 [-1,1]。在法線貼圖中被壓縮在顏色的范圍[0,1]中,所以需要轉換
        //(1)RGB法線貼圖
        float3 expand(float3 v) { return (v - 0.5) * 2; }
        //(2)DXT5nm法線貼圖
        float3 expand2(float4 v)
        { 
            fixed3 normal;
            normal.xy = v.wy * 2 - 1;
            normal.z = sqrt(1 - normal.x*normal.x - normal.y * normal.y);
            return normal;
        }
 
        sampler2D _MainTex;
        sampler2D _NormalMap;
 
        void surf(Input IN,inout SurfaceOutput o)
        {
            half4 c = tex2D(_MainTex, IN.uv_MainTex);
            o.Albedo = c.rgb;
            o.Alpha = c.a;
 
            //對法線貼圖進行采樣,取得壓縮在顏色空間里的法線([0,1])
            float4 packedNormal = tex2D(_NormalMap, IN.uv_MainTex);
 
            //要將顏色空間里的法線[0,1],轉換至真正3D空間里的法線范圍[-1,1]
            //注意:范圍基本都是從[0,1]轉換至[-1,1].主要是圖的通道與法線xyz的對應關系要根據(jù)法線貼圖格式而定
            //UnpackNormal, UnityCG.cginc里的函數(shù)
            //o.Normal = UnpackNormal(packedNormal);
 
            //expand,標準法線解壓函數(shù)
            o.Normal = expand(packedNormal.xyz);
        }
        ENDCG
    }
}

  

總結

以上是生活随笔為你收集整理的Unity3D教程宝典之Shader篇:第二十讲法线贴图的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。