Shader "URP/PBR"
{
Properties
{
_BaseColor("_BaseColor", Color) = (1,1,1,1)
_DiffuseTex("Texture", 2D) = "white" {}
[Normal]_NormalTex("_NormalTex", 2D) = "bump" {}
_NormalScale("_NormalScale",Range(0,1)) = 1
_AO("_AO",Range(0,1))=0
_Metallic("_Metallic", Range(0,1)) = 1
_Smoothness("_Smoothness", Range(0,1)) = 1
_LightInt("_LightInt", Range(0,1)) = 0.3
_EmissivInt("_EmissivInt", Float) = 1
_EmissivColor("_EmissivColor", Color) = (0,0,0,1)
}
SubShader
{
Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline"}
LOD 100
HLSLINCLUDE
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" //增加光照函数库
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
#pragma shader_feature _ADDITIONALLIGHTS
// 接收阴影所需关键字
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS //接受阴影
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE //产生阴影
#pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS //额外光源阴影
#pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS //开启额外其它光源计算
#pragma multi_compile _ _SHADOWS_SOFT //软阴影
//C缓存区
CBUFFER_START(UnityPerMaterial)
float4 _DiffuseTex_ST;
float4 _Diffuse;
float _NormalScale,_Metallic,_Smoothness;
float4 _BaseColor;
half _AO;
half _LightInt;
half _EmissivInt;
half4 _EmissivColor;
CBUFFER_END
struct appdata
{
float4 positionOS : POSITION; //输入顶点
float4 normalOS : NORMAL; //输入法线
float2 texcoord : TEXCOORD0; //输入uv信息
float4 tangentOS : TANGENT; //输入切线
};
struct v2f
{
float2 uv : TEXCOORD0; //输出uv
float4 positionCS : SV_POSITION; //齐次位置
float4 normalWS : TEXCOORD1;
float4 tangentWS : TEXCOORD2;
float4 btangentWS : TEXCOORD3;
half4 shadowCoord: TEXCOORD4;
};
TEXTURE2D(_DiffuseTex); SAMPLER(sampler_DiffuseTex);
TEXTURE2D(_NormalTex); SAMPLER(sampler_NormalTex);
ENDHLSL
Pass
{
Tags{ "LightMode" = "UniversalForward" }
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
// D 的方法
float Distribution(float roughness, float nh)
{
float lerpSquareRoughness = pow(lerp(0.01,1, roughness),2); // 这里限制最小高光点
float D = lerpSquareRoughness / (pow((pow(nh,2) * (lerpSquareRoughness - 1) + 1), 2) * PI);
return D;
}
// G_1
// 直接光照 G项子项
inline real G_subSection(float X,float roughness)
{
float a = (roughness + 1.0) / 2;
float k = a * a / 8.0;//UE
float nominator = X;
float denominator = X * (1.0 - k) + k;
return nominator / max(denominator, 0.0000001);//防止分母为0
}
// G 的方法
float Geometry(float roughness, float nl, float nv)
{
//half k = pow(roughness + 1,2)/8.0; // 直接光的K值
//half k = pow(roughness,2)/2; // 间接光的K值
return G_subSection(nv, roughness) * G_subSection(nl, roughness);
}
// 间接光 F 的方法
float3 IndirF_Function(float NdotV, float3 F0, float roughness)
{
float Fre = exp2((-5.55473 * NdotV - 6.98316) * NdotV);
return F0 + Fre * saturate(1 - roughness - F0);
}
// 直接光 F的方法
float3 FresnelEquation(float3 F0,float lh)
{
return F0 + (1.0 - F0) * pow(1.0 - lh, 5);
}
//间接光高光 反射探针
real3 IndirectSpeCube(float3 normalWS, float3 viewWS, float roughness, float AO)
{
float3 reflectDirWS = reflect(-viewWS, normalWS); // 计算出反射向量
roughness = roughness * (1.7 - 0.7 * roughness); // Unity内部不是线性 调整下拟合曲线求近似
float MidLevel = roughness * 6; // 把粗糙度remap到0-6 7个阶级 然后进行lod采样
float4 speColor = SAMPLE_TEXTURECUBE_LOD(unity_SpecCube0, samplerunity_SpecCube0, reflectDirWS, MidLevel);//根据不同的等级进行采样
#if !defined(UNITY_USE_NATIVE_HDR)
return DecodeHDREnvironment(speColor, unity_SpecCube0_HDR) * AO;//用DecodeHDREnvironment将颜色从HDR编码下解码。可以看到采样出的rgbm是一个4通道的值,最后一个m存的是一个参数,解码时将前三个通道表示的颜色乘上xM^y,x和y都是由环境贴图定义的系数,存储在unity_SpecCube0_HDR这个结构中。
#else
return speColor.xyz*AO;
#endif
}
half3 IndirectSpeFactor(half roughness, half smoothness, half3 BRDFspe, half3 F0, half NdotV)
{
#ifdef UNITY_COLORSPACE_GAMMA
half SurReduction = 1 - 0.28 * roughness * roughness;
#else
half SurReduction = 1 / (roughness * roughness + 1);
#endif
#if defined(SHADER_API_GLES)
half Reflectivity = BRDFspe.x;
#else
half Reflectivity = max(max(BRDFspe.x, BRDFspe.y), BRDFspe.z);
#endif
half GrazingTSection = saturate(Reflectivity + smoothness);
half fre = Pow4(1 - NdotV);
return lerp(F0, GrazingTSection, fre) * SurReduction;
}
real3 SH_IndirectionDiff(float3 normal)
{
real4 SHCoefficients[7];
SHCoefficients[0] = unity_SHAr;
SHCoefficients[1] = unity_SHAg;
SHCoefficients[2] = unity_SHAb;
SHCoefficients[3] = unity_SHBr;
SHCoefficients[4] = unity_SHBg;
SHCoefficients[5] = unity_SHBb;
SHCoefficients[6] = unity_SHC;
float3 Color = SampleSH9(SHCoefficients, normal);
return max(0, Color);
}
half3 PBRDirectLightResult(Light light, float3 view,float3 normal, float3 albedo, float rough, float metal)
{
half4 lightColor = float4(light.color,1); // 获取光照颜色
float3 viewDir = normalize(view);
float3 normalDir = normalize(normal);
float3 lightDir = normalize(light.direction); // 获取光照颜色
float3 halfDir = normalize(viewDir + lightDir);
float nh = max(saturate(dot(normalDir, halfDir)), 0.001);
float nl = max(saturate(dot(normalDir, lightDir)),0.001);
float nv = max(saturate(dot(normalDir, viewDir)),0.01);
float vh = max(saturate(dot(viewDir, halfDir)),0.0001);
float hl = max(saturate(dot(halfDir, lightDir)), 0.0001);
half3 F0 = lerp(0.04,albedo.rgb,metal);
half D = Distribution(rough, nh);
half G = Geometry(rough,nl,nv);
half3 F = FresnelEquation(F0,hl);
half3 ks = F;
half3 kd = (1- ks) * (1 - metal); // 计算kd
half3 SpecularResult = (D * G * F) / (nv * nl * 4);
half3 DirectSpeColor = saturate(SpecularResult * lightColor.rgb * nl * PI );
half3 DirectDiffColor = kd * albedo.rgb * lightColor.rgb * nl;
half3 directLightResult = DirectDiffColor + DirectSpeColor;
return directLightResult;
}
v2f vert(appdata v)
{
v2f o;
o.uv = TRANSFORM_TEX(v.texcoord, _DiffuseTex);
VertexPositionInputs PositionInputs = GetVertexPositionInputs(v.positionOS.xyz);
o.positionCS = PositionInputs.positionCS; //获取齐次空间位置
half3 positionWS = PositionInputs.positionWS; //获取世界空间位置信息
VertexNormalInputs NormalInputs = GetVertexNormalInputs(v.normalOS.xyz,v.tangentOS);
o.normalWS =half4(NormalInputs.normalWS.xyz,positionWS.x); // 获取世界空间下法线信息
o.tangentWS = half4(NormalInputs.tangentWS,positionWS.y); // 获取世界空间下切线信息
o.btangentWS = half4(NormalInputs.bitangentWS,positionWS.z); // 获取世界空间下副切线信息
o.shadowCoord=TransformWorldToShadowCoord( positionWS);
return o;
}
half4 frag(v2f i) : SV_Target
{
// ============================================= 贴图纹理 =============================================
half4 albedo = SAMPLE_TEXTURE2D(_DiffuseTex,sampler_DiffuseTex,i.uv) * _BaseColor;
half4 normal = SAMPLE_TEXTURE2D(_NormalTex,sampler_NormalTex,i.uv);
half3 emissive= _EmissivColor.rgb * _EmissivInt*_Smoothness;
half metallic = _Metallic;
half smoothness = _Smoothness;
half roughness = pow((1 - smoothness),2);
half ao = _AO;
// ============================================== 法线计算 ========================================
float3x3 TBN = {i.tangentWS.xyz, i.btangentWS.xyz, i.normalWS.xyz}; // 矩阵
TBN = transpose(TBN);
float3 norTS = UnpackNormalScale(normal, _NormalScale); // 使用变量控制法线的强度
norTS.z = sqrt(1 - saturate(dot(norTS.xy, norTS.xy))); // 规范化法线
half3 N = NormalizeNormalPerPixel(mul(TBN, norTS)); // 顶点法线和法线贴图融合 = 输出世界空间法线信息
// ================================================ 需要的数据 ==========================================
Light mainLight = GetMainLight(i.shadowCoord); // 获取光照
half atten = mainLight.shadowAttenuation * mainLight.distanceAttenuation;
float4 lightColor = float4(mainLight.color,1); // 获取光照颜色
half3 positionWS=half3(i.normalWS.w,i.tangentWS.w,i.btangentWS.w);
float3 viewDir = SafeNormalize(GetCameraPositionWS() - positionWS);
float3 normalDir = normalize(N);
float3 lightDir = normalize(mainLight.direction);
float3 halfDir = normalize(viewDir + lightDir);
float nh = max(saturate(dot(normalDir, halfDir)), 0.0001);
float nl = max(saturate(dot(normalDir, lightDir)),0.01);
float nv = max(saturate(dot(normalDir, viewDir)),0.01);
float vh = max(saturate(dot(viewDir, lightDir)),0.0001);
float hl = max(saturate(dot(halfDir, lightDir)), 0.0001);
float3 F0 = lerp(0.04,albedo.rgb,metallic);
// ================================================ 直接光高光反射 ==========================================
half D = Distribution(roughness,nh);
half G = Geometry(roughness,nl,nv);
half3 F = FresnelEquation(F0,nh);
float3 SpecularResult = (D * G * F) / (nv * nl * 4);
float3 SpecColor = saturate(SpecularResult * lightColor.xyz * nl*ao); // 这里可以AO
// ================================================ 直接光漫反射 ==========================================
float3 ks = F;
float3 kd = (1- ks) * (1 - metallic); // 计算kd
float3 diffColor = kd * albedo.xyz * lightColor.xyz * nl*atten; // 这里增加自发光
// ================================================ 直接光 ==========================================
float3 directLightResult = diffColor + SpecColor;
// ================================================ 间接光漫反射 ==========================================
half3 shcolor = SH_IndirectionDiff(N)*ao; // 这里可以AO
half3 indirect_ks = IndirF_Function(nv,F0,roughness); // 计算 ks
half3 indirect_kd = (1 - indirect_ks) * (1 - metallic); // 计算kd
half3 indirectDiffColor = shcolor * indirect_kd * albedo.xyz;
//return half4(indirectDiffColor, 1);
// ================================================ 间接光高光反射 ==========================================
half3 IndirectSpeCubeColor = IndirectSpeCube(N, viewDir, roughness, ao);
half3 IndirectSpeCubeFactor = IndirectSpeFactor(roughness, smoothness, SpecularResult, F0, nv);
half3 IndirectSpeColor = IndirectSpeCubeColor * IndirectSpeCubeFactor;
//return half4(IndirectSpeColor.rgb,1);
// ================================================ 间接光 ==========================================
half3 IndirectColor = IndirectSpeColor + indirectDiffColor;
// ================================================ 合并光 ==========================================
half3 finalCol = IndirectColor + directLightResult;
#ifdef _ADDITIONALLIGHTS
int pixelLightCount = GetAdditionalLightsCount();
for(int index = 0; index < pixelLightCount; index++)
{
Light light = GetAdditionalLight(index,positionWS);
finalCol += PBRDirectLightResult(light,i.viewDirWS,N,albedo.rgb,roughness,metallic) * _LightInt; // 多光源计算
}
#endif
return half4(finalCol.rgb,1);
}
ENDHLSL
}
Pass
{
Tags{ "LightMode" = "ShadowCaster" }
HLSLPROGRAM
#pragma vertex vertshadow
#pragma fragment fragshadow
v2f vertshadow(appdata v)
{
v2f o=(v2f) 0;
float3 posWS = TransformObjectToWorld(v.positionOS.xyz); //世界空间下顶点位置
float3 norWS = TransformObjectToWorldNormal(v.normalOS.xyz); //世界空间下顶点位置
Light MainLight = GetMainLight(); //获取灯光
o.positionCS = TransformWorldToHClip(ApplyShadowBias(posWS,norWS,MainLight.direction)); //这里是公共结构体里调用就可以
#if UNITY_REVERSED_Z
o.positionCS.z - min(o.positionCS.z,o.positionCS.w * UNITY_NEAR_CLIP_VALUE);
#else
o.positionCS.z - max(o.positionCS.z,o.positionCS.w * UNITY_NEAR_CLIP_VALUE);
#endif
return o;
}
float4 fragshadow(v2f i) : SV_Target
{
half4 color=half4(0,0,0,1);
color.xyz = float3(0.0, 0.0, 0.0);
return color;
}
ENDHLSL
}
}
}