Cg Programming/Unity/Layers of Textures纹理的层级

来源:互联网 发布:linux vim 替换字符串 编辑:程序博客网 时间:2024/06/05 03:45

这里写图片描述人类皮肤的层次

本教程介绍了多重纹理,也就是在着色器中多重纹理贴图的使用。

它把章节“纹理球体”中着色器代码扩展成多重纹理,并且展示了结合它们的一种方法。如果你没有阅读那个教程,这会是一个很好的机会来了解它。

表面层级

很多真实的表面(比如上图中人类的皮肤)包含了不同颜色、透明、反射等的层次。如果最上面那层是不透明的并且不传输任何光,这个实际上并不影响渲染表面。但是,在大多数情况下最上层是(半)透明的,因此表面的精确渲染就必须把多重层级考虑进来。

实际上,Phong反射模型中包含的镜面反射(查阅章节“镜面高光”)通常对应于反射光线的透明层:人类皮肤上的汗,水果上的蜡,嵌入颜色颗粒的透明塑料等等。另一方面,漫反射就对应了最上面透明层下面的层级。

照射到这样的分层表面并不需要层级的几何模型:它们可以用一个无限薄的多边形网格表面。但是光照计算必须计算不同层级间的差异,并且要把层与层之间光线的传输考虑进去(当光线进入该层以及离开该层)。这个方法的例子在Nvidia的“Dawn”示例(查看图书“GPU Gems”的第三章,它在网上可获取到)以及“Human Head”示例(查看图书“GPU Gem 3”的第14章,同样在网上可获取到)中有所包含。

这些过程的详细描述已经远远超过了本教程的范围。可以说层级通常跟纹理贴图相关联,用来指定它们的特性。这里,我们只是展示了如何使用两张纹理以及一种结合它们的特殊方法。这个例子实际上跟层级没关系,并且因此解释了多重纹理比表面层级有更多的应用。

有光及无光的地球

这里写图片描述

因为有人类的活动,地球无光的一面并不是完全漆黑的。相反,如上图所示,人工照明标记着城市的位置和外延。因此,地球的漫射光应该不只是使得光照表面的纹理贴图变暗,还应该实际上把它跟无光纹理贴图进行混合。注意,光照地球比在无光边缘处的人造光明亮得多;但是,我们减少了这种对比,以显示夜间的纹理。

以下的着色器代码把章节“纹理球体”中的代码扩展为两张纹理贴图,并且使用了章节“漫反射”中描述的有一个方向光源的计算方法:
这里写图片描述

根据这个等式,漫射光的等级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分量(参考章节“透明纹理”),我们应该在_MainTex上使用alpha分量来混合。这个实际上就是Unity的标准贴花着色器所做的,并且它对应于在可见的不透明层顶部的部分透明的层,该层最顶部的层是透明的。(我也是醉了,太绕了,我想静静)。

完整的着色器代码

这个着色器属性的名字被选择跟备用着色器的属性名字一致—-在这里就是贴花着色器(注意这个备用贴花着色器与标准贴花着色器看上去是以相反的方式使用这两张纹理)。而且,了为控制总体的光亮度一个额外的属性_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 = _Object2World;            float4x4 modelMatrixInverse = _World2Object;            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 = mul(UNITY_MATRIX_MVP, input.vertex);            return output;         }         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)         }         ENDCG      }   }    Fallback "Decal"}

当你运行该着色器,请确保在你的场景中有一盏激活的方向光源。

总结

Congratulations! You have reached the end of the last tutorial on basic texturing. We have looked at:
How layers of surfaces can influence the appearance of materials (e.g. human skin, waxed fruits, plastics, etc.)
How artificial lights on the unlit side can be taken into account when texturing a sphere representing the Earth.
How to implement this technique in a shader.
How this is related to blending an alpha texture over a second opaque texture.
恭喜!你完成了最后一章的教程!我们学到了:

  • 表面的层级是如何影响到材质的表现(即人类皮肤、带蜡的水果、塑料等)。
  • 当纹理映射到一个球体来表示地球时,如何把无光边缘外的人工光源考虑进去。
  • 如何在着色器中实现这个技术。
  • 如何在第二张不透明纹理上混合一张alpha纹理。
原创粉丝点击