Sharder学习 3
在看shader入门精要。
第六章 Unity中的基础光照
半兰伯特模型(Half Lambert)
6.5 高光反射光照模型
逐顶点光照
逐像素光照
Blinn-Phong光照模型
使用Unity内置的函数
unity ShaderLab 基础之【UnityCG.cginc 库】命令详解
第七章 基础纹理
实践
Properties {
_Color ("Color Tint", Color) = (1,1,1,1)
_MainTex ("Main Tex", 2D) = "white" {}
_Specular ("Specular", Color) = (1,1,1,1)
_Gloss ("Gloss", Range(8.0,256)) = 20
}
//CG代码中声明
fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST; //这个是需要的
fixed4 _Specular;
float _Gloss;
_MainTex_ST中的ST是scale和translation,通过它得到缩放和平移值。
_MainTex_ST.xy存储缩放值
_MainTex_ST.zw存储偏移值
struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 texcoord : TEXCOORD0;
}
struct v2f {
float4 pos : SV_POSITION;
float3 worldNormal : TEXCOORD1;
float2 uv : TEXCOORD2;
}
v2f vert(a2v v) {
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.worldNormal = UnityObjectToWorldNormal(v.normal);
o.worldPos = mul(_Object2World, v.vertex).xyz;
o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_St.zw;
// or
//o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
return o;
}
fixed4 frag(v2f i) : SV_Target {
fixed3 worldNormal = normalize(i.worldNormal);
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb; // 反射率;漫反射系数
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo; // 环境光
fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, worldLightDir)); // 漫反射
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
fixed3 halfDir = normalize(worldLightDir + viewDir);
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(worldNormal, halfDir)), _Gloss);
return fixed4(ambient + diffuse + specular, 1.0);
}
纹理的属性
Texture Type: Texture, Normal map, Cubemap
Wrap Mode: Repeat, Clamp。当纹理坐标超过[0,1]范围后如何平铺。
Filter Mode: 当纹理由于变换而产生拉伸时采用哪种滤波。Point,Biliner,Trilinear。
纹理缩小的过程比放大更加复杂一些。多级渐远纹理技术(minmapping),提前用滤波处理来得到很多更小的图像,形成了一个图像金字塔,每一层都是对上一层图像降采样的结果。但会多占用33%的内存。纹理导入中,将纹理类型(Texture Type)选择成Advanced,再勾选Generate Mip Maps即可开启多级渐远纹理技术。
纹理的最大尺寸和纹理模式。
用了大量Truecolor类型纹理会增加内存。
凹凸映射bump mapping
不会真的改变模型的顶点位置,只是让模型看起来好像是凹凸的。
有2种实现方法:
高度纹理height mapping,使用高度图存储强度值,表示模型的表面高度。但是计算复杂。
法线纹理normal mapping。
将修改后的模型空间中的表面法线存储在一张纹理中,称为模型空间的法线纹理(object-space normal map)。实际制作中会用另一种坐标空间,切线空间(tangent space)来存储法线。
模型空间存储法线的优点:
- 实现简单,直观。
- 可见的突变缝隙较少。
切线空间优点更多:
- 自由度很高
- 可进行UV动画。
- 可重用法线纹理
- 可压缩
实践
我们需要在计算光照模型中统一各个方向矢量所在的坐标空间。
一种是在切线空间下进行光照计算,一种是在世界空间下进行光照计算。
计算前需要变换到统一的坐标系(空间)。还可以是模型空间。
在切线空间下进行光照计算
基本思路是:在片元着色器中通过纹理采样得到切线空间下的法线,然后再与切线空间下的视角方向、光照方向等进行计算,等到最终的光照结果。
Shader "somename" {
Properties {
_Color ("Color Tint", Color) = (1,1,1,1)
_MainTex ("Main Tex", 2D) = "white" {}
_BumpMap ("Normal Map", 2D) = "bump" {} // "bump"是unity内置法线纹理
_BumpScale ("Bump Scale", Float) = 1.0
_Specular ("Specular", Color) = (1,1,1,1)
_Gloss ("Gloss", Range(8.0, 256)) = 20
}
SubShader {
Pass {
Tags {"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#inlcude "Lighting.cginc"
fixed _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _BumpMap;
float4 _BumpMap_ST;
float _BumpScale;
fixed4 _Specular;
float _Gloss;
struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 tangent :TANGENT; // tangent.w分量是决定切线空间z坐标轴--副切线的方向性
float4 texcoord : TEXCOORD0;
}
struct v2f {
float4 pos : SV_POSITION;
float4 uv : TEXCOORD0;
float3 lightDir : TEXCOORD1;
float3 viewDir : TEXCOORD2;
}
v2f vert(a2v v) {
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw; //计算缩放和平移后的坐标
o.uv.zw = v.texcoord.xy * _BumpMap_ST.xy + _BumpMap_ST.zw;
// Compute the binormal
// float3 binormal = cross(normalize(v.normal), normalize(v.tangent.xyz)) * v.tangent.w;
//Construct a matrix which transform vectors from object space to tangent space
//float3x3 rotation = float3x3(v.tangent.xyz, binormal, v.normal);
//Or just use the built-in macro
TANGENT_SPACE_ROTATION;
o.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex)).xyz;
o.viewDir = mul(rotation, ObjSpaceViewDir(v.vertex)).xyz;
return 0;
}
fixed4 frag(v2f i) : SV_Target {
fixed3 tangentLightDir = normalize(i.lightDir);
fixed3 tangentViewDir = normalize(i.viewDir);
//Get the texel in the normal map
fixed4 packedNormal = tex2D(_BumpMap, i.uv.zw);
fixed3 tangentNormal;
//If the texture is not marked as "Normal Map"
//tangentNormal.xy = (packedNormal.xy*2 -1) * _BumpScale;
//tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy, tangentNormal.xy)));
//Or mark the texture as "Normal Map", and use the built-in funtion
tangentNormal = UnpackNormal(packedNormal);
tangentNormal.xy *= _BumpScale;
tangentNormal.z = sqrt(1.0 - saturate(dot(tangentNormal.xy, tangeNormal.xy)));
fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(tangentNormal, tangentLightDir));
fixed3 halfDir = normalize(tangentLightDir + tangentViewDir);
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(tangentNormal, halfDir)), _Gloss);
return fixed4(ambient + diffuse + specular, 1.0);
}
ENDCG
}
}
Fallback "Specular"
}
2.在世界空间下计算
fixed4 frag(v2f i) : SV_Target {
//get the position in world space
float3 worldPos = float3(i.TtoW0.w, i.TtoW1.w, i.TtoW2.w);
//
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPos));
fixed3 viewDir = normalize(UnityWorldSpaceViewDir(worldPos));
fixed3 bump = UnpackNormal(tex2d(_BumpMap, i.uv.zw));
bump.xy *= _BumpScale;
bump.z = sqrt(1.0 - saturate(dot(bump.xy, bump.xy)));
bump = normalize(half3(dot(i.TtoW0.xyz, bump), dot(i.TtoW1.xyz, bump), dot(i.TtoW2.xyz, bump)));
///////
。。。。
}
7.4 遮罩纹理
Shader "Mask Texture" {
Properties {
_Color ("Color Tint", Color) = (1,1,1,1)
_MainTex ("Main Tex", 2D) = "white" {}
_BumpMap ("Normal Map", 2D) = "bump" {}
_BumpScale ("Bump Scale", Float) = 1.0
_SpecularMask ("Specular Mask", 2D) = "white" {}
_SpecularScale ("Specular Scale", Float) = 1.0
_Gloss ("Gloss", Range(8.0, 256)) = 20
}
SubShader {
Pass {
Tags { "LightMode"="ForwardBase" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
fixed4 _Color;
sampler2D _MainTex;
float4 _MainTex_ST;
sampler2D _BumpMap;
float _BumpScale;
Sampler2D _SpecularMask;
float _SpecularScale;
fixed4 _Specular;
float _Gloss;
struct a2v {
float4 vertex : POSITION;
float3 normal : NORMAL;
float4 tangent : TANGENT;
float4 texcoord : TEXCOORD0;
};
struct v2f {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float3 lightDir : TEXCOORD1;
float3 viewDir : TEXCOORD2;
};
v2f vert(a2v v) {
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv.xy = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
TANGENT_SPACE_ROTATION;
o.lightDir = mul(rotation, ObjSpaceLightDir(v.vertex)).xyz;
o.viewDir = mul(rotation, ObjSpaceViewDir(v.vertex)).xyz
return o;
}
fixed4 frag(v2f i) : SV_Target {
fixed3 tangentLightDir = normalize(i.lightDir);
fixed3 tangentViewDir = normalize(i.viewDir);
fixed3 tangentNormal = UnpackNormal(tex2D(_BumpMap, i.uv));
tangentNormal.xy *= _BumpScale;
tangentNormal.z = sqrt(1.0-saturate(dot(tangentNormal.xy, tangentNormal.xy)));
fixed3 albedo = tex2D(_MainTex, i.uv).rgb * _Color.rgb;
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(tangentNormal, tangentLightDir));
fixed3 halfDir = normalize(tangentLightDir + tangentViewDir);
fixed specularMask = tex2D(_SpecularMask, i.uv).r * _SpecularScale;
fixed3 specular = _LightColor0.rgb * _Specular.rgb * pow(max(0, dot(tangentNormal, halfDir)), _Gloss) * specularMask;
return fixed4(ambient + diffuse + specular, 1.0);
}
ENDCG
}
}
}