跳轉到內容

Cg 程式設計/Unity/置換貼圖

來自華夏公益教科書,開放世界開放書籍
像這樣的不規則形狀的隕石可以使用具有被置換貼圖移動的頂點的球形網格建立。

本教程介紹了置換貼圖,作為頂點著色器中紋理查詢應用的示例。

本教程需要一些關於紋理對映的知識,如“紋理球體”部分中所述。

頂點著色器中的紋理查詢

[編輯 | 編輯原始碼]

本華夏公益教科書中的大多數教程僅在片段著色器中使用紋理查詢,因為頂點著色器中的紋理查詢是 Shader Model 3.0 特性,即,並非所有 GPU 都支援它(參見Unity 對平臺特定渲染差異的描述)。

然而,置換對映需要對每個頂點進行紋理值的查詢,該值用於位移,即移動每個頂點到新的位置。出於技術原因,我們不能使用標準的tex2d命令。相反,我們必須使用命令tex2dlod,使用一個四維向量來指定紋理座標,其中第四個分量為 0。(這確保我們始終從最精細的mipmap級別讀取值,並且我們不會請求 mipmap 級別自動計算,這在頂點著色器中是不可能的。)該命令可能如下所示

      float4 dispTexColor = tex2Dlod(_DisplacementTex, float4(i.texcoord.xy, 0.0, 0.0));

其中i.texcoord.xy是兩個紋理座標。

頂點的位移

[編輯 | 編輯原始碼]

下面的示例將得到的顏色dispTexColor轉換為灰度值,並將其縮放為使用者指定的統一_MaxDisplacement

      float displacement = dot(float3(0.21, 0.72, 0.07), dispTexColor.rgb) * _MaxDisplacement;

然後,此位移值用於沿其表面法線向量移動每個頂點,即,我們將物件座標中的頂點位置(示例中的i.vertex)新增到與位移值相乘的表面法線向量(i.normal)。

      float4 newVertexPos = i.vertex + float4(i.normal * displacement, 0.0);

請注意,i.normal是一個三維向量;因此,我們必須附加一個 0.0 座標以形成一個四維向量,然後才能將其新增到頂點位置。

著色器程式碼

[編輯 | 編輯原始碼]

其餘程式碼應用標準頂點變換,並使用無光照紋理貼圖對錶面進行著色。請確保將其用於具有相對較多頂點的網格上 - 否則位移表面將顯得相當“塊狀”。

Shader "Vertex Displacement" {
   Properties {
      _MainTex ("Main Texture", 2D) = "white" {}
      _DisplacementTex ("Displacement Texture", 2D) = "white" {}
      _MaxDisplacement ("Max Displacement", Float) = 1.0
   }
   SubShader {
      Pass {    
         CGPROGRAM

         #pragma vertex vert
         #pragma fragment frag
   
         uniform sampler2D _MainTex;
         uniform sampler2D _DisplacementTex;
         uniform float _MaxDisplacement;
   
         struct vertexInput {
            float4 vertex : POSITION;
            float3 normal : NORMAL;
            float4 texcoord : TEXCOORD0;
         };
   
         struct vertexOutput {
            float4 position : SV_POSITION;
            float4 texcoord : TEXCOORD0;
         };
   
         vertexOutput vert(vertexInput i) {
            vertexOutput o;
            
            // get color from displacement map, and convert to float from 0 to _MaxDisplacement
            float4 dispTexColor = tex2Dlod(_DisplacementTex, float4(i.texcoord.xy, 0.0, 0.0));
            float displacement = dot(float3(0.21, 0.72, 0.07), dispTexColor.rgb) * _MaxDisplacement;
            
            // displace vertices along surface normal vector
            float4 newVertexPos = i.vertex + float4(i.normal * displacement, 0.0);   

            // output data            
            o.position = UnityObjectToClipPos(newVertexPos); 
            o.texcoord = i.texcoord;
            return o;
   
         }
   
         float4 frag(vertexOutput i) : COLOR
         {
            return tex2D(_MainTex, i.texcoord.xy);
         }
   
         ENDCG
      }
   }
}

請注意,如果紋理影像邊緣的顏色不匹配,或者對應頂點的表面法線向量不匹配,則表面網格的邊緣可能無法對齊。

恭喜你,你已經完成了本教程。你看到了

  • 如何在頂點著色器中使用紋理對映。
  • 如何沿表面法線向量移動頂點位置。

進一步閱讀

[編輯 | 編輯原始碼]

如果你還想了解更多

< Cg 程式設計/Unity

除非另有說明,否則本頁上的所有示例原始碼均授予公有領域。
華夏公益教科書