Cg Programming In Unity Layers of Textures (Wiki翻译自用)


本教程介绍了多重纹理化,即在着色器中使用多个纹理图像。

表面层

许多真实的表面(例如人的皮肤)由几层不同的颜色,透明度,反射率等组成。如果最顶层是不透明的并且不透射任何光,那么对于渲染表面并不重要。但是,在许多情况下,最顶层是(半)透明的,因此要精确的绘制表面,必须考虑到多层。
实际上,Phong反射模型中包含的镜面反射通常对应于反射光的透明层:人体皮肤上的汗水,水果上的蜡,带有嵌入颜料颗粒的透明塑料等。另一方面,漫反射对应于最顶层透明层的下面的层。
照亮此类分层表面不需要层的几何模型:它们可以由单个无限薄的多边形网格表示。但是,照明计算必须为不同的层计算不同的反射,并且必须考虑各层之间的光传输(当光进入层时和光离开层时)。这种方法的示例包含在Nvidia的“ Dawn”演示中(请参见在线“ GPU Gems”一书的第3章)和Nvidia的“ Human Head”演示(请参见“ GPU Gems3”一书的第14章)。
这些过程的完整描述超出了本教程的范围。可以说图层通常与纹理图像相关联以指定其特征。在这里,我们仅展示如何使用两种纹理以及一种将他们组合的特殊方式。该示例实际上与层无关,因此说明了多重纹理比表面层具有更多的应用。

阳光照射和未照射的地球

由于人类活动,地球上未照亮的一面并非完全黑暗。 取而代之的是,人造灯会标记城市的位置和延伸。因此,地球的漫射照明不仅应使阳光照射表面的纹理图像变暗,而且应将其实际混合到未照明的纹理图像中。请注意,阳光照射过的地球比未照亮的一面的人造光要明亮得多。但是,为了显示夜间纹理,我们降低了对比度。
着色器代码将代码从“Textured Spheres”部分扩展到两个纹理图像,并对单个定向光源使用“Diffuse Reflection”部分中描述的计算:
I d i f f u s e = I i n c o m i n g k d i f f u s e m a x ( 0 , N ⋅ L ) I_{diffuse} = I_{incoming}k_{diffuse}max(0,N·L) Idiffuse=Iincomingkdiffusemax(0,NL)
根据此等式,漫反射照明度levelOfLighting的度数为max(0,N·L)。然后,我们根据levelOfLighting混合白天和夜间纹理的颜色。这可以通过将白天的颜色与levelOfLighting相乘,并将夜间的颜色与1.0-levelOfLighting相乘,然后再将它们相加以确定片段的颜色来实现。或者,使用内置的Cg函数lerp(lerp(a, b, w) = b*w + a*(1.0-w)),这可能会更有效。因此,片元着色器代码如下:

  float4 frag(vertexOutput input) : COLOR
         {
            float4 nighttimeColor = 
               tex2D(_MainTex, input.tex.xy);    
            float4 daytimeColor = 
               tex2D(_DecalTex, input.tex.xy);    
            return lerp(nighttimeColor, daytimeColor, 
               input.levelOfLighting);
               // = daytimeColor * levelOfLighting 
               // + nighttimeColor * (1.0 - levelOfLighting)
         }

请注意,此混合与“透明度”部分中讨论的Alpha混合非常相似,不同之处在于我们在片段着色器内执行混合,并使用levelOfLighting而不是应混合的纹理的Alpha分量(即不透明度)“覆盖”其他纹理。实际上,如果_DecalTex指定了alpha分量(请参见“透明纹理”一节),我们可以使用此alpha分量在_MainTex上混合_DecalTex。实际上,这就是Unity的标准Decal着色器所做的事情,它对应于在不透明层之上部分透明的层,该层在最顶层是透明的情况下可见。

完整的Shader代码

选择该着色器的属性名称与后备着色器的属性名称一致-在本例中为Decal着色器(请注意,后备Decal着色器和标准Decal着色器似乎以相反的方式使用这两个纹理)。此外,还引入了一个附加属性_Color,并将其与夜间纹理的纹理颜色相乘(逐分量),以控制其总体亮度。将光源_LightColor0的颜色与白天纹理的颜色相乘(也是逐分量),以便将有色光源考虑在内。

Shader "Cg multitexturing of Earth" {
   Properties {
      _DecalTex ("Daytime Earth", 2D) = "white" {}
      _MainTex ("Nighttime Earth", 2D) = "white" {} 
      _Color ("Nighttime Color Filter", Color) = (1,1,1,1)
   }
   SubShader {
      Pass {	
         Tags { "LightMode" = "ForwardBase" } 
            // pass for the first, directional light 
 
         CGPROGRAM
 
         #pragma vertex vert  
         #pragma fragment frag 
 
         #include "UnityCG.cginc"
         uniform float4 _LightColor0; 
            // color of light source (from "Lighting.cginc")
 
         uniform sampler2D _MainTex;
         uniform sampler2D _DecalTex;
         uniform float4 _Color; 
 
         struct vertexInput {
            float4 vertex : POSITION;
            float3 normal : NORMAL;
            float4 texcoord : TEXCOORD0;
         };
         struct vertexOutput {
            float4 pos : SV_POSITION;
            float4 tex : TEXCOORD0;
            float levelOfLighting : TEXCOORD1;
               // level of diffuse lighting computed in vertex shader
         };
 
         vertexOutput vert(vertexInput input) 
         {
            vertexOutput output;
 
            float4x4 modelMatrix = unity_ObjectToWorld;
            float4x4 modelMatrixInverse = unity_WorldToObject;
 
            float3 normalDirection = normalize(
               mul(float4(input.normal, 0.0), modelMatrixInverse).xyz);
            float3 lightDirection = normalize(
               _WorldSpaceLightPos0.xyz);
 
            output.levelOfLighting = 
               max(0.0, dot(normalDirection, lightDirection));
            output.tex = input.texcoord;
            output.pos = UnityObjectToClipPos(input.vertex);
            return output;
         }
 
         float4 frag(vertexOutput input) : COLOR
         {
            float4 nighttimeColor = 
               tex2D(_MainTex, input.tex.xy) * _Color;    
            float4 daytimeColor = 
               tex2D(_DecalTex, input.tex.xy) * _LightColor0;    
            return lerp(nighttimeColor, daytimeColor, 
               input.levelOfLighting);
               // = daytimeColor * levelOfLighting 
               // + nighttimeColor * (1.0 - levelOfLighting)
         }
 
         ENDCG
      }
   } 
   Fallback "Decal"
}

运行此着色器时,请确保场景中具有激活的定向光源。

总结

本节中,我们看到了:

  • 表面层如何影响材质的外观(例如人类的皮肤、蜡果、塑料等)
  • 在对代表地球的球体进行纹理化时,如何考虑未照亮一侧的人造光
  • 如何在着色器中实现此技术。
  • 这与在第二个不透明纹理上混合 alpha 纹理有什么关系
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值