跳轉到內容

Cg 程式設計/Unity/天空盒

來自華夏公益教科書
從摩天大樓看出去。只要背景是靜態的並且足夠遠,它就非常適合做天空盒。

本教程介紹如何使用立方體貼圖將環境貼圖渲染為背景

它基於“反射表面”部分。如果你還沒有閱讀過該教程,現在是閱讀它的最佳時機。

在背景中渲染天空盒

[編輯 | 編輯原始碼]

正如“反射表面”部分中所解釋的那樣,天空盒可以被認為是一個無限大的、紋理化的盒子,它包圍著一個場景。有時,天空盒(或天空穹頂)是透過足夠大的紋理化模型來實現的,這些模型近似於一個無限大的盒子(或穹頂)。但是,“反射表面”部分介紹了立方體貼圖的概念,它實際上表示一個無限大的盒子;因此,我們不需要使用有限大小的盒子或穹頂的近似值。相反,我們可以渲染任何填充螢幕的模型(無論它是一個盒子、一個穹頂,還是一顆蘋果樹,只要它覆蓋了整個背景),在頂點著色器中計算從相機到光柵化表面點的視向量(正如我們在“反射表面”部分中所做的那樣),然後在片段著色器中使用該視向量在立方體貼圖中執行查詢(而不是在“反射表面”部分中的反射視向量)。

         float4 frag(vertexOutput input) : COLOR
         {
            return texCUBE(_Cube, input.viewDir);
         }

為了獲得最佳效能,我們當然應該渲染一個只有幾個頂點的模型,並且每個畫素都應該只光柵化一次。因此,渲染包圍相機(或整個場景)的立方體的內部就可以了。

完整的著色器程式碼

[編輯 | 編輯原始碼]

著色器應該附加到一個材質,該材質應該附加到包圍相機的立方體。在著色器程式碼中,我們使用ZWrite Off停用寫入深度緩衝區,這樣就不會有任何物體被天空盒遮擋。(參見“每片段操作”部分中對深度測試的描述。)正面剔除使用Cull Front啟用,這樣只有立方體的“內部”會被光柵化。(參見“剖檢視”部分。)Tags { "Queue" = "Background" }行指示 Unity 在渲染其他物體之前渲染此通道。

Shader "Cg shader for skybox" {
   Properties {
      _Cube ("Environment Map", Cube) = "" {}
   }
   SubShader {
      Tags { "Queue" = "Background" }
      
      Pass {   
         ZWrite Off
         Cull Front

         CGPROGRAM
 
         #pragma vertex vert  
         #pragma fragment frag 
 
         #include "UnityCG.cginc"

         // User-specified uniforms
         uniform samplerCUBE _Cube;   
 
         struct vertexInput {
            float4 vertex : POSITION;
         };
         struct vertexOutput {
            float4 pos : SV_POSITION;
            float3 viewDir : TEXCOORD1;
         };
 
         vertexOutput vert(vertexInput input) 
         {
            vertexOutput output;
 
            float4x4 modelMatrix = unity_ObjectToWorld;
            output.viewDir = mul(modelMatrix, input.vertex).xyz 
               - _WorldSpaceCameraPos;
            output.pos = UnityObjectToClipPos(input.vertex);
            return output;
         }
 
         float4 frag(vertexOutput input) : COLOR
         {
            return texCUBE(_Cube, input.viewDir);
         }
 
         ENDCG
      }
   }
}

Unity 的天空盒系統的著色器程式碼

[編輯 | 編輯原始碼]

上面的著色器演示瞭如何透過渲染一個圍繞相機的立方體並使用特定的著色器來渲染天空盒。這是一種非常通用的方法。但是,Unity 有它自己的天空盒系統,它不需要任何遊戲物件:你只需要在主選單視窗 > 渲染 > 照明設定 > 場景 > 天空盒材質中指定具有天空盒著色器的材質,Unity 會完成剩下的工作。不幸的是,我們不能將我們的著色器用於此係統,因為我們必須在由頂點紋理座標指定的座標處對立方體紋理進行查詢。這實際上比計算視方向更容易。以下是程式碼

Shader "Cg shader for Unity-specific skybox" {
   Properties {
      _Cube ("Environment Map", Cube) = "white" {}
   }

   SubShader {
      Tags { "Queue"="Background"  }

      Pass {
         ZWrite Off 
         Cull Off

         CGPROGRAM
         #pragma vertex vert
         #pragma fragment frag

         // User-specified uniforms
         samplerCUBE _Cube;

         struct vertexInput {
            float4 vertex : POSITION;
            float3 texcoord : TEXCOORD0;
         };

         struct vertexOutput {
            float4 vertex : SV_POSITION;
            float3 texcoord : TEXCOORD0;
         };

         vertexOutput vert(vertexInput input)
         {
            vertexOutput output;
            output.vertex = UnityObjectToClipPos(input.vertex);
            output.texcoord = input.texcoord;
            return output;
         }

         fixed4 frag (vertexOutput input) : COLOR
         {
            return texCUBE (_Cube, input.texcoord);
         }
         ENDCG 
      }
   } 	
}

如上所述,你應該使用此著色器建立一個材質,並將該材質拖放到視窗 > 渲染 > 照明設定 > 場景 > 天空盒材質。無需將材質附加到任何遊戲物件。

恭喜,你已經完成了另一個教程!我們已經看到了

  • 如何一般性地渲染天空盒。
  • 如何在 Unity 中不使用遊戲物件渲染天空盒。

進一步閱讀

[編輯 | 編輯原始碼]

如果你還想了解更多

< Cg 程式設計/Unity

除非另有說明,否則此頁面上的所有示例原始碼均已歸入公有領域。
華夏公益教科書