环境是Unity2019.4.4 ,抄了一个第一档的BRDF,在此记录一下
先从直射光部分(direct light)开始吧
公式是
在我的另外一篇里有
然后就是复制了一下
里的部分内容
其实就是 一个 diffuse项加specular项,最后我简单的架权平均了下😂不知道对不,看起来差不多。
最后上代码
Shader "Unlit/MyBRDF"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Smoothness("Smoothness",Range(0,1))=0.5
}
SubShader
{
Tags { "RenderType"="Opaque"}
Pass
{
Tags {"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase
#include "UnityCG.cginc"
#include "UnityLightingCommon.cginc"
struct a2v
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal:NORMAL;
float4 tangent:TANGENT;
};
struct v2f
{
float4 pos : SV_POSITION;
float3 normal:TEXCOORD1;
float3 tangent:TEXCOORD3;
float2 uv : TEXCOORD0;
float3 worldPos:TEXCOORD2;
};
#define PI 3.14159265f
sampler2D _MainTex;
float4 _MainTex_ST;
half _Smoothness;
// Pow5 uses the same amount of instructions as generic pow(), but has 2 advantages:
// 1) better instruction pipelining
// 2) no need to worry about NaNs
inline half Pow5 (half x)
{
return x*x * x*x * x;
}
inline half2 Pow5 (half2 x)
{
return x*x * x*x * x;
}
inline half3 Pow5 (half3 x)
{
return x*x * x*x * x;
}
inline half4 Pow5 (half4 x)
{
return x*x * x*x * x;
}
// Smoothness is the user facing name
// it should be perceptualSmoothness but we don't want the user to have to deal with this name
half SmoothnessToRoughness(half smoothness)
{
return (1 - smoothness) * (1 - smoothness);
}
float SmoothnessToPerceptualRoughness(float smoothness)
{
return (1 - smoothness);
}
float PerceptualRoughnessToRoughness(float perceptualRoughness)
{
return perceptualRoughness * perceptualRoughness;
}
half RoughnessToPerceptualRoughness(half roughness)
{
return sqrt(roughness);
}
v2f vert (a2v v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.worldPos = mul(unity_ObjectToWorld,v.vertex);
o.normal = UnityObjectToWorldNormal(v.normal);
o.tangent = UnityObjectToWorldNormal(v.tangent);
return o;
}
// Note: Disney diffuse must be multiply by diffuseAlbedo / PI. This is done outside of this function.
half DisneyDiffuse(half NdotV, half NdotL, half LdotH, half perceptualRoughness)
{
half fd90 = 0.5 + 2 * LdotH * LdotH * perceptualRoughness;
// Two schlick fresnel term
half lightScatter = (1 + (fd90 - 1) * Pow5(1 - NdotL));
half viewScatter = (1 + (fd90 - 1) * Pow5(1 - NdotV));
return lightScatter * viewScatter;
}
// Ref: http://jcgt.org/published/0003/02/03/paper.pdf
inline float SmithJointGGXVisibilityTerm (float NdotL, float NdotV, float roughness)
{
// Approximation of the above formulation (simplify the sqrt, not mathematically correct but close enough)
float a = roughness;
float lambdaV = NdotL * (NdotV * (1 - a) + a);
float lambdaL = NdotV * (NdotL * (1 - a) + a);
#if defined(SHADER_API_SWITCH)
return 0.5f / (lambdaV + lambdaL + 1e-4f); // work-around against hlslcc rounding error
#else
return 0.5f / (lambdaV + lambdaL + 1e-5f);
#endif
}
inline float GGXTerm (float NdotH, float roughness)
{
float a2 = roughness * roughness;
float d = (NdotH * a2 - NdotH) * NdotH + 1.0f; // 2 mad
return UNITY_INV_PI * a2 / (d * d + 1e-7f); // This function is not intended to be running on Mobile,
// therefore epsilon is smaller than what can be represented by half
}
inline half3 FresnelTerm (half3 F0, half cosA)
{
half t = Pow5 (1 - cosA); // ala Schlick interpoliation
return F0 + (1-F0) * t;
}
fixed4 frag (v2f i) : SV_Target
{
// sample the texture
fixed4 col = tex2D(_MainTex, i.uv);
float3 worldViewDir = normalize(UnityWorldSpaceViewDir(i.worldPos)) ;
float3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)) ;
float3 worldNormal = normalize(i.normal);
float3 worldTangent = normalize(i.tangent);
float3 worldHalfDir = normalize(worldViewDir + worldLightDir);
half NoH = saturate(dot(worldNormal, worldHalfDir));
half VoH = saturate(dot(worldViewDir, worldHalfDir));
half NoV = saturate(dot(worldNormal, worldViewDir));
half NoL = saturate(dot(worldNormal, worldLightDir));
half LoV = saturate(dot(worldLightDir, worldViewDir));
half LoH = saturate(dot(worldLightDir, worldHalfDir));
float perceptualRoughness = SmoothnessToPerceptualRoughness (_Smoothness);
half3 diffuse = DisneyDiffuse(NoH, NoL, LoH, perceptualRoughness) * NoL;
float roughness = PerceptualRoughnessToRoughness(perceptualRoughness);
roughness = max(roughness, 0.002);
float V = SmithJointGGXVisibilityTerm (NoL, NoV, roughness);
float D = GGXTerm (NoH, roughness);
float3 F = FresnelTerm (half3(1,1,1), LoH);
float specularTerm = V * D * PI;
specularTerm = max(0, specularTerm * NoL);
// specularTerm *= any(specColor) ? 1.0 : 0.0;
half3 specular = specularTerm * F;
col.xyz = diffuse * _LightColor0.rgb + specular * _LightColor0.rgb;
col.xyz = col.xyz / 2;
return col;
}
ENDCG
}
}
}