光照的计算需要在切线空间下计算。先将法线、切线传到顶点着色器中,叉乘计算出副切线
float3x3(切线、副切线、法线)构成世界空间转切线空间转换矩阵
将法线纹理中解包UnpackNormal,参与计算。
Shader "Custom/Bump"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Main Tex", 2D) = "white" {}
_Gloss ("Gloss", Range(8,256)) = 20
_Specular ("Specular", Color) = (1,1,1,1)
_BumpTex("Bump Tex",2D) = "bump"{}
_Scale("Scale",Range(0,1)) = 0.1
_HeightTex("Height Tex",2D) = "black"{}
}
SubShader
{
Pass
{
Tags{"LightMode" = "ForwardBase"}
CGPROGRAM
#include "Lighting.cginc"
#pragma vertex vert
#pragma fragment frag
fixed4 _Color;
sampler2D _MainTex;
float _Gloss;
fixed4 _Specular;
sampler2D _HeightTex;
sampler2D _BumpTex;
float _Scale;
struct a2v
{
fixed4 vertex : POSITION;
fixed3 normal : NORMAL;
fixed3 tangent : TANGENT;
fixed2 texcoord : TEXCOORD0;
};
struct v2f
{
fixed4 pos : SV_POSITION;
fixed2 uv : TEXCOORD0;
fixed3 worldNormal : TEXCOORD1;
fixed3 worldTangent :TEXCOORD2;
fixed3 worldBinormal : TEXCOORD3;
fixed3 worldPos : TEXCOORD4;
};
v2f vert(a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = v.texcoord.xy;
o.worldNormal = normalize(mul(v.normal,(float3x3)unity_WorldToObject));
o.worldTangent = normalize(mul(unity_ObjectToWorld,v.tangent));
o.worldBinormal = normalize(cross(o.worldNormal,o.worldTangent));
o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;
return o;
}
//视差映射
float2 ParallaxMapping(float2 uv ,float3 viewDir)
{
fixed height = 1 - tex2D(_HeightTex,uv).r;
float2 offset = viewDir.xy / viewDir.z * height * _Scale;
return uv + offset;
}
fixed4 frag(v2f i) : SV_Target
{
fixed3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos));
fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
fixed3 worldNormal = i.worldNormal;
float3x3 TBN = float3x3(i.worldTangent,i.worldBinormal,i.worldNormal);
float3 viewDir = mul(TBN,worldViewDir);
float3 lightDir = mul(TBN,worldLightDir);
float2 uv = ParallaxMapping(i.uv,viewDir);
fixed3 tangentNormal = UnpackNormal(tex2D(_BumpTex,uv));
fixed3 halfDir = normalize(lightDir + viewDir);
fixed3 albedo = _Color.rgb * tex2D(_MainTex,uv);
fixed3 diffuse = albedo * _LightColor0.rgb * saturate(dot(lightDir,tangentNormal));
fixed3 specular = albedo * _Specular.rgb * pow(saturate(dot(tangentNormal,halfDir)),_Gloss);
fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
return fixed4(diffuse + specular + ambient,1);
}
ENDCG
}
}
FallBack "Specular"
}
视差映射前:
视差映射:
靠近了之后效果会变得很差
陡峭视差映射 :
float2 SteepParallaxMapping(float2 uv ,float3 viewDir)
{
//层数100层
float layerNum = 100;
//层深度初始化为1/100
float layerHeight = 1.0/layerNum;
//当前层深度为0
float currentLayerHeight = 0.0;
//偏移UV = 视线方向.xy / 视线方向.z * 偏移范围控制量
float2 offLayerUV = viewDir.xy/viewDir.z*_Scale;
//迭代增加的步数 偏移UV/100
float2 Steeping = offLayerUV/layerNum;
//迭代uv的增加量
float2 AddUV = float2(0,0);
//当前所取的uv点的深度图的值
float currentHeightMapValue = 1-tex2D(_HeightTex,uv+AddUV);
//当层深度>当前uv点的深度图的值时立刻返回
for (int i = 0;i<layerNum;i++)
{
if(currentLayerHeight > currentHeightMapValue)
{
return uv+AddUV;
}
AddUV += Steeping;
currentHeightMapValue =1- tex2D(_HeightTex,uv+AddUV);
currentLayerHeight+=layerHeight;
}
return uv+AddUV;
}
效果会好很多,但是消耗有点高