Cg Programming In Unity Textured Spheres (Wiki翻译自用)


本教程介绍纹理映射。
这是有关Unity中Cg着色器纹理的一系列教程的第一篇。 在本教程中,我们从球体上的单个纹理贴图开始。 更具体地说,我们将地球表面的图像映射到球体上。 基于此,进一步的教程涵盖了主题,例如纹理表面的照明,透明纹理,多纹理,光泽贴图等。

纹理贴图

“纹理贴图”(或“纹理”)的基本思想是将图像(即“纹理”或“纹理贴图”)映射到三角形网格上; 换句话说,将平面图像放置在三维形状的表面上。

为此,定义了“纹理坐标”,其仅指定纹理(即图像)中的位置。 在OpenGL中,水平坐标称为S,垂直坐标为T。然而,将它们分别称为xy是很常见的。 在动画和建模工具中,纹理坐标通常称为UV
为了将纹理图像映射到网格,网格的每个顶点都具有一对纹理坐标。 (此过程(及其结果)有时被称为“ UV映射”,因为每个顶点都映射到UV空间中的一个点。)因此,每个顶点都映射到纹理图像中的一个点。 然后可以为三个顶点之间的任何三角形的每个点内插顶点的纹理坐标,因此网格的所有三角形的每个点都可以具有一对(内插的)纹理坐标。 这些纹理坐标将网格的每个点映射到纹理图中的特定位置,因此也映射到该位置处的颜色。 因此,对于所有可见点,渲染纹理映射的网格包括两个步骤:纹理坐标的插值和在由插值纹理坐标指定的位置查找纹理图像的颜色。

通常,任何有效的浮点数都是有效的纹理坐标。 但是,当要求GPU查找纹理图像的像素(或“纹理像素”)(例如,使用以下所述的“ tex2D”指令)时,它将在内部将纹理坐标映射到0到1之间的范围内。方式取决于导入纹理时指定的Wrap ModeWrap Moderepeat基本上是使用纹理坐标的小数部分来确定纹理坐标在0到1之间的范围内。另一方面,Wrap Modeclamp将纹理坐标固定在此范围内。然后,使用这些内部纹理坐标(介于0和1之间)来确定纹理图像中的位置:(0,0)指定纹理图像的左下角;(1,0)为右下角;(0,1)为左上角等

在Unity中对球体进行纹理处理

导入图像到Unity中在这里插入图片描述
现在创建一个球体,一个材质和一个着色器,将着色器附加到材质上,并将材质附加到球体上。 着色器代码如下:

Shader "Cg shader with single texture" {
   Properties {
      _MainTex ("Texture Image", 2D) = "white" {} 
         // a 2D texture property that we call "_MainTex", which should
         // be labeled "Texture Image" in Unity's user interface.
         // By default we use the built-in texture "white"  
         // (alternatives: "black", "gray" and "bump").
   }
   SubShader {
      Pass {	
         CGPROGRAM
 
         #pragma vertex vert  
         #pragma fragment frag 
 
         uniform sampler2D _MainTex;	
            // a uniform variable refering to the property above
            // (in fact, this is just a small integer specifying a 
            // "texture unit", which has the texture image "bound" 
            // to it; Unity takes care of this).
 
         struct vertexInput {
            float4 vertex : POSITION;
            float4 texcoord : TEXCOORD0;
         };
         struct vertexOutput {
            float4 pos : SV_POSITION;
            float4 tex : TEXCOORD0;
         };
 
         vertexOutput vert(vertexInput input) 
         {
            vertexOutput output;
 
            output.tex = input.texcoord;
               // Unity provides default longitude-latitude-like 
               // texture coordinates at all vertices of a 
               // sphere mesh as the input parameter 
               // "input.texcoord" with semantic "TEXCOORD0".
            output.pos = UnityObjectToClipPos(input.vertex);
            return output;
         }
         float4 frag(vertexOutput input) : COLOR
         {
         		//在指定的纹理图像_MainTex查找对应input.tex.xy的对应纹理颜色并返回
            return tex2D(_MainTex, input.tex.xy);	
               // look up the color of the texture image specified by 
               // the uniform "_MainTex" at the position specified by 
               // "input.tex.x" and "input.tex.y" and return it
 
         }
 
         ENDCG
      }
   }
   Fallback "Unlit/Texture"
}

注意命名为_MainTex是为了确保Fallback 着色器"Unlit/Texture"可以访问到。
现在,球体应该是白色的。 如果为灰色,则应检查着色器是否已附加到材质上,以及材质是否已附加到球体上。 如果球体是洋红色,则应检查着色器代码。 特别是,您应该在“项目”窗口中选择着色器,并在“检查器”窗口中阅读错误消息。 将导入的纹理图像赋值给对应着色器属性得到带有纹理图像的球体。

它是怎么工作的?

由于许多技术都使用纹理映射,因此了解这里发生的事情非常有好处。 因此,让我们回顾一下着色器代码:
Unity球体对象的顶点带有TEXCOORD0语义的顶点输入参数保存了每个顶点的纹理坐标。这些坐标类似于经度和纬度(但范围从0到1)。 这类似于具有语义POSITION的顶点输入参数vertex,它指定对象空间中的位置,不同之处在于texcoord指定纹理图像空间中的纹理坐标。

然后,顶点着色器将每个顶点的纹理坐标写入顶点输出参数output.tex。对于三角形的每个片段(即每个覆盖的像素),将在三个三角形顶点处对该输出参数的值进行插值(请参见“光栅化”一节中的描述),并将插值后的纹理坐标作为输入参数提供给片段着色器 。 然后,片段着色器使用它们在纹理空间内插位置处的统一_MainTex指定的纹理图像中查找颜色,并将该颜色作为片段输出参数返回,然后将其写入帧缓冲区并显示在屏幕上。

至关重要的是,您必须对这些步骤有所了解,才能理解其他教程中介绍的更复杂的纹理映射技术。

重复和移动纹理

在上面的着色器的Unity界面中,您可能已经注意到参数Tiling和Offset,每个参数都有一个x和y分量。 在内置着色器中,这些参数允许您重复纹理(通过在纹理坐标空间中缩小纹理图像)并在表面上移动纹理图像(通过在纹理坐标空间中偏移它)。 为了与这种行为保持一致,必须定义另一个属性:

 			uniform float4 _MainTex_ST; 
            // tiling and offset parameters of property "_MainTex"

对于每个纹理属性,Unity提供了一个带有结尾“ _ST”的float4 unifrom。 (请记住:“ S”和“ T”是纹理坐标的正式名称,通常称为“ U”和“ V”,或“ x”和“ y”。) _MainTex_ST.x_MainTex_ST.y对应Tiling参数的x和y,而Offset参数的x和y分量存储在_MainTex_ST.z和_MainTex_ST.w中。 该属性应该像这样使用:

 return tex2D(_MainTex, 
               _MainTex_ST.xy * input.tex.xy + _MainTex_ST.zw);

这使着色器的行为类似于内置着色器。 在其他教程中,通常不会实现此功能,以使着色器代码更简洁。
仅出于完整性考虑,以下是具有此功能的完整着色器代码:

Shader "Cg shader with single texture" {
   Properties {
      _MainTex ("Texture Image", 2D) = "white" {} 
         // a 2D texture property that we call "_MainTex", which should
         // be labeled "Texture Image" in Unity's user interface.
         // By default we use the built-in texture "white"  
         // (alternatives: "black", "gray" and "bump").
   }
   SubShader {
      Pass {	
         CGPROGRAM
 
         #pragma vertex vert  
         #pragma fragment frag 
                   
         uniform sampler2D _MainTex;	
         uniform float4 _MainTex_ST; 
            // tiling and offset parameters of property

         struct vertexInput {
            float4 vertex : POSITION;
            float4 texcoord : TEXCOORD0;
         };
         struct vertexOutput {
            float4 pos : SV_POSITION;
            float4 tex : TEXCOORD0;
         };

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

         float4 frag(vertexOutput input) : COLOR
         {
            return tex2D(_MainTex, 
               _MainTex_ST.xy * input.tex.xy + _MainTex_ST.zw);	
               // texture coordinates are multiplied with the tiling 
               // parameters and the offset parameters are added
         }

         ENDCG
      }
   }
   Fallback "Unlit/Texture"
}

翻译结果
Unity在UnityCG.cginc中为此类纹理坐标转换提供了一个宏,即,您必须在Pass中包含以下行:

#include "UnityCG.cginc"

这样,您可以使用宏TRANSFORM_TEX()从上面重写return语句:

 return tex2D(_MainTex, TRANSFORM_TEX(input.tex, _MainTex));

总结

本节我们看到:

  • 如何导入纹理图像以及如何将其附加到着色器的纹理属性。
  • 顶点着色器和片段着色器如何一起工作以将纹理图像映射到网格上。
  • Unity的纹理平铺和偏移参数如何工作以及如何实现它们。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值