跳转到内容

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

除非另有说明,否则此页面上的所有示例源代码均已归入公有领域。
华夏公益教科书