Shader学习笔记之DetailTextureInScreenSpace
注:代码来自于官方,下面是我的理解。不对之处请指正。
Shader "Custom/OfficialEaxm6_DetailTextureInScreen" {
Properties {
_MainTex ("Base (RGB)", 2D) = "white" {}
_Detail("Detail (RGB)",2D) = "gray"{}
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Lambert
sampler2D _MainTex;
sampler2D _Detail;
struct Input {
float2 uv_MainTex;
float4 screenPos;
};
void surf (Input IN, inout SurfaceOutput o) {
half4 c = tex2D (_MainTex, IN.uv_MainTex);
o.Albedo = c.rgb;
// o.Alpha = c.a;
float2 screenUV = IN.screenPos.xy/IN.screenPos.w;
screenUV *= float2(8,6);
o.Albedo *= tex2D(_Detail,screenUV).rgb *2;
}
ENDCG
}
FallBack "Diffuse"
}
首先对shader语法做一些解释。
shader命令后跟一个字符串作为shader的名字出现在inspector视图的层级列表中。
shader 由几个属性构成:properties,subshader,fallback;
properties模块中的属性将会出现在 material inspector中,供美工使用。
一个shader包含若干subshader,计算机将会选择第一个硬件支持的subshader执行。
fallback 当所有subshader都不被硬件所支持的时候执行。也就是说fallback 后面的shader必须支持最低端的硬件设备才能保证在所有机器上执行。
本例中使用的是Surface Shader,在unity3d中在Shaderlab中嵌入Cg/hlsl来变现surface Shader 程序 和 vertex & fragment shader。
使用CGPROGRAM 和ENDCG作为cg/hlsl程序的开始和结束。
#pragma surface surf Lambert, 表示使用surface shader, 要调用的函数为 surf,Lambert表示光照模型(diffuse)。
sampler2D _MainTex; 这里对应properties属性中的_MainTex, 在properties中的属性是显示在可视化界面中的并不直接与cg程序关联,这里声明之后将会与之前的关联起来。(名字必须一样!)
先来看核心函数:
<span style="font-size:18px;">void surf (Input IN, inout SurfaceOutput o) {}</span>
注意到这里有两个参数,Input 也就是上面我们定义的Input结构体,SurfaceOutput 这个结构体事由系统自定义的一个结构。我们通过输入的Input计算之后,填充surfaceOutput结构,硬件使用这个结构中的内容进行渲染。
再来看Input结构:我们把在surf函数中要用到的变量在这里声明。比如,我们这里的uv_MainTex 。需要说明的是,在变量名之前加上uv系统会默认使用他的uv坐标进行采样。准确的说将其uv是保存在一个float2中,在surf函数中使用。
float2 - 4 这样子的类型是一个float 类型的2-4维向量。
一个着色器最重要的是其渲染方法,这里做的事使用一个2维浮点向量取屏幕坐标,再在x轴,y轴分贝乘 8 和 6。 最后使用这个uv坐标来对用户输入的Detail贴图取样。
最后看到的效果就会这样:
下面将代码具体分析:
<span style="font-size:18px;">float2 screenUV = IN.screenPos.xy/IN.screenPos.w;
screenUV *= float2(8,6);
o.Albedo *= tex2D(_Detail,screenUV).rgb *2;</span>
screenPos 是一个四元数即(x,y,z,w)其三维向量为(x/w,y/w,z/w),我们知道屏幕坐标没有z轴。所以标准化向量为(x/w,y/w)。将其x,y乘以8,6之后这个uv将会为分别在x,y轴扩大8,6倍。使用tex2D函数采样,第一个参数为采样贴图,第二个为uv坐标。
试试:我们把8,6改为1,1之后将shader赋给一个材质再将材质赋给一个plane或者quad 将其放缩到screen视口大小,出现了整个视口出现一张贴图,贴图不随对象放缩而改变。
由此猜测 :贴图normalize 之后与一个单位uv 所对应。理解为:x(0~1),y(0~1)当乘以倍数之后 x(0,m),y(0,n)。这样就明白了。
注:这事我的理解不对之处请大虾指正。