首先声明以下素材和shader代码都来自Kerry佬,我只做整理和学习之用,写此随笔是为了做个笔记方便以后查阅。
SH,英文全称Spherical Harmonics Lighting,即球谐光照,主要用来模拟漫反射。
1. 如何计算SH
SH只需要提供一组Vector4数组,便能通过算法来计算出漫反射光,这种方法的好处是适用于没有光照探针的场景中。如计算方法如下:
1 half3 CalcSH(float3 normal_dir, half4 custom_SHAr, half4 custom_SHAg, half4 custom_SHAb, half4 custom_SHBr, half4 custom_SHBg, half4 custom_SHBb, half4 custom_SHC) 2 { 3 float4 normalForSH = float4(normal_dir, 1.0); 4 //SHEvalLinearL0L1 5 half3 x; 6 x.r = dot(custom_SHAr, normalForSH); 7 x.g = dot(custom_SHAg, normalForSH); 8 x.b = dot(custom_SHAb, normalForSH); 9 10 //SHEvalLinearL2 11 half3 x1, x2; 12 // 4 of the quadratic (L2) polynomials 13 half4 vB = normalForSH.xyzz * normalForSH.yzzx; 14 x1.r = dot(custom_SHBr, vB); 15 x1.g = dot(custom_SHBg, vB); 16 x1.b = dot(custom_SHBb, vB); 17 18 // Final (5th) quadratic (L2) polynomial 19 half vC = normalForSH.x*normalForSH.x - normalForSH.y*normalForSH.y; 20 x2 = custom_SHC.rgb * vC; 21 22 float3 sh = max(float3(0.0, 0.0, 0.0), (x + x1 + x2)); 23 sh = pow(sh, 1.0 / 2.2); 24 return sh; 25 }
这一组Vector4数组如下:
2. 光照探针
unity中提供了Light Probe,即光照探针,来提前把光照信息烘焙到探针球里,这样物体进入探针区域后,通过取出影响物体的所有探针球,来计算出SH光照。
这是一种比较节省性能的做法。shader中计算SH光照可调用方法 half3 SampleSH(half3 worldNormal);
shader如下:
1 Shader "MyURP/Kerry/SH/URPLightProbe" 2 { 3 Properties 4 { 5 _Tint("Tint",Color) = (1,1,1,1) 6 _Expose("Expose",Float) = 1.0 7 _Rotate("Rotate",Range(0,360)) = 0 8 _NormalMap("Normal Map",2D) = "bump"{} 9 _NormalIntensity("Normal Intensity",Float) = 1.0 10 _AOMap("AO Map",2D) = "white"{} 11 _AOAdjust("AO Adjust",Range(0,1)) = 1 12 13 } 14 SubShader 15 { 16 Tags 17 { 18 "RenderType" = "Opaque" 19 "RenderPipeline" = "UniversalPipeline" 20 } 21 LOD 100 22 23 Pass 24 { 25 Tags 26 { 27 "LightMode" = "UniversalForward" 28 } 29 30 HLSLPROGRAM 31 #pragma vertex vert 32 #pragma fragment frag 33 #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" 34 #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" 35 36 struct appdata 37 { 38 float4 vertex : POSITION; 39 float2 texcoord : TEXCOORD0; 40 float3 normal : NORMAL; 41 float4 tangent : TANGENT; 42 }; 43 44 struct v2f 45 { 46 float2 uv : TEXCOORD0; 47 float4 pos : SV_POSITION; 48 float3 normal_world : TEXCOORD1; 49 float3 pos_world : TEXCOORD2; 50 float3 tangent_world : TEXCOORD3; 51 float3 binormal_world : TEXCOORD4; 52 }; 53 54 //sampler2D _MainTex; 55 //float4 _MainTex_ST; 56 TEXTURECUBE(_CubeMap); SAMPLER(sampler_CubeMap); 57 float4 _CubeMap_HDR; 58 float4 _Tint; 59 float _Expose; 60 61 TEXTURE2D(_NormalMap); SAMPLER(sampler_NormalMap); 62 float4 _NormalMap_ST; 63 float _NormalIntensity; 64 TEXTURE2D(_AOMap); SAMPLER(sampler_AOMap); 65 float _AOAdjust; 66 float _Rotate; 67 float _Roughness; 68 TEXTURE2D(_RoughnessMap); SAMPLER(sampler_RoughnessMap); 69 float _RoughnessContrast; 70 float _RoughnessBrightness; 71 float _RoughnessMin; 72 float _RoughnessMax; 73 74 75 float3 RotateAround(float degree, float3 target) 76 { 77 float rad = degree * PI / 180; 78 float2x2 m_rotate = float2x2(cos(rad), -sin(rad), 79 sin(rad), cos(rad)); 80 float2 dir_rotate = mul(m_rotate, target.xz); 81 target = float3(dir_rotate.x, target.y, dir_rotate.y); 82 return target; 83 } 84 85 inline float3 ACES_Tonemapping(float3 x) 86 { 87 float a = 2.51f; 88 float b = 0.03f; 89 float c = 2.43f; 90 float d = 0.59f; 91 float e = 0.14f; 92 float3 encode_color = saturate((x*(a*x + b)) / (x*(c*x + d) + e)); 93 return encode_color; 94 }; 95 96 v2f vert (appdata v) 97 { 98 v2f o; 99 o.pos = TransformObjectToHClip(v.vertex.xyz); 100 o.uv = v.texcoord * _NormalMap_ST.xy + _NormalMap_ST.zw; 101 o.pos_world = mul(unity_ObjectToWorld, v.vertex).xyz; 102 o.normal_world = normalize(mul(float4(v.normal, 0.0), unity_WorldToObject).xyz); 103 o.tangent_world = normalize(mul(unity_ObjectToWorld, float4(v.tangent.xyz, 0.0)).xyz); 104 o.binormal_world = normalize(cross(o.normal_world, o.tangent_world)) * v.tangent.w; 105 return o; 106 } 107 108 half4 frag (v2f i) : SV_Target 109 { 110 half3 normal_dir = normalize(i.normal_world); 111 half3 normaldata = UnpackNormal(SAMPLE_TEXTURE2D(_NormalMap,sampler_NormalMap,i.uv)); 112 normaldata.xy = normaldata.xy* _NormalIntensity; 113 half3 tangent_dir = normalize(i.tangent_world); 114 half3 binormal_dir = normalize(i.binormal_world); 115 normal_dir = normalize(tangent_dir * normaldata.x + binormal_dir * normaldata.y + normal_dir * normaldata.z); 116 117 half ao = SAMPLE_TEXTURE2D(_AOMap, sampler_AOMap, i.uv).r; 118 ao = lerp(1.0,ao, _AOAdjust); 119 120 half3 env_color = SampleSH(normal_dir); 121 half3 final_color = env_color * ao * _Tint.rgb * _Expose; 122 123 return float4(final_color,1.0); 124 } 125 ENDHLSL 126 } 127 } 128 FallBack "Hidden/Universal Render Pipeline/FallbackError" 129 }
效果如下:
转载请注明出处:https://www.cnblogs.com/jietian331/p/17027769.html
标签:normal,float,Shader,custom,Unity,SH,world,dir,float3 From: https://www.cnblogs.com/jietian331/p/17027769.html