GPT答: |
7i24.cn
|
以下是一个基本的PBR着色器示例,使用Unity ShaderLab编写:
Shader "Custom/PBR" {
Properties {
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Metallic ("Metallic", Range(0,1)) = 0.0
_Smoothness ("Smoothness", Range(0,1)) = 0.5
_NormalMap ("Normal Map", 2D) = "bump" {}
}
SubShader {
Tags {"Queue"="Transparent"}
LOD 100
CGPROGRAM
#pragma surface surf Standard
sampler2D _MainTex;
sampler2D _NormalMap;
struct Input {
float3 worldPos;
float3 worldNormal;
float4 screenPos;
float3 viewDir;
};
half4 LightingStandard (Input i, SurfaceOutputStandard o, half3 lightDir, half atten) {
// Diffuse lighting with Lambertian BRDF
half NdotL = max(dot(i.worldNormal.xyz, lightDir), 0);
// Specular lighting with Cook-Torrance BRDF and Schlick's approximation for Fresnel term.
half roughnessSquared = o.Smoothness * o.Smoothness;
half metallicFactor = o.Metallic;
half F90 = pow(clamp(1 - dot(lightDir.xyz,-i.viewDir),0.001f ,1),5);
half Fd90= pow(clamp(1 - dot(lightDir.xyz,i.worldNormal.xyz),0.001f ,1),5);
half Fr=lerp(Fd90,F90,o.Metallic);
float kS=Fr;
float kD=1-kS;
kD*=(1-o.Metallic);
half3 H = normalize(lightDir + i.viewDir);
half NdotH = max(dot(i.worldNormal.xyz, H), 0);
half D = GGX(NdotH, roughnessSquared);
half G = SmithGGXVisibilityTerm(NdotL, NdotH, roughnessSquared);
half specularFactor=D*G*kS/(4*(max(0.001f,NdotL)*max(0.001f,NdotV)));
half diffuseFactor=(1-kS)*o.Albedo.rgb/(3.14159f);
return (diffuseFactor+specularFactor) * atten;
}
void surf (Input IN, inout SurfaceOutputStandard o) {
// Albedo comes from a texture tinted by color
o.Albedo = tex2D (_MainTex, IN.screenPos.xy).rgb;
// Metallic and smoothness come from slider variables
o.Metallic = _Metallic;
o.Smoothness = _Smoothness;
// Normal map encoding is stored in the alpha channel.
float4 normalMapValue=tex2D(_NormalMap ,IN.screenPos.xy);
normalMapValue.a *= 2.0; // Amplify the effect of the normal map to make it more visible.
float3 normalEncoded=normalMapValue.xyz * 2 - 1; // Decode the RGB values into a vector direction.
float3 worldNormal=normalize(mul(normalEncoded,(float3x3)_WorldSpaceCameraTransform.inverse)); // Transform the vector into world space.
IN.worldNormal=worldNormal;
IN.viewDir=_WorldSpaceCameraPos-IN.worldPos;
fixed4 c=float4(0,0,0,0);
c.rgb+=LightingStandard(IN,o,_WorldSpaceLightPos[0].xyz,_WorldSpaceLightPos.w);
o.Emission=c.rgb;
}
// GGX distribution function
half GGX (half NdotH, half roughnessSquared) {
half alpha = roughnessSquared;
half alphaSquared = alpha * alpha;
half denominator = NdotH * NdotH * (alphaSquared - 1) + 1;
return alphaSquared / (3.14159f * denominator * denominator);
}
// Smith's method for calculating the visibility term in the Cook-Torrance BRDF.
// This is a simplified version that assumes that both V and L are pointing in the same hemisphere.
half SmithGGXVisibilityTerm(half No,half Nh,half roughness)
{
half a=roughness*roughness;
half k=a/2;
return No/(No*(1-k)+k*Nh);
}
ENDCG
}
FallBack "Diffuse"
}
该着色器使用SurfaceOutputStandard结构体来存储表面输出,包括漫反射颜色、金属度和光滑度。它还使用了Cook-Torrance BRDF来计算镜面反射,并使用Schlick的近似公式来计算菲涅尔效应。在光照函数中,我们将漫反射和镜面反射相加,并乘以衰减因子(atten)。
注意,在surf函数中,我们需要将法线从纹理中解码为世界空间向量,并计算视线向量。我们还需要在光照函数中使用世界空间的光源位置和相机位置。
最后,我们将该着色器设置为透明队列,并提供了一个回退选项(Fallback),以便在不支持PBR的设备上仍然能够正常工作。
|