108 lines
3.5 KiB
HLSL

// SPDX-License-Identifier: (Not available for this version, you are only allowed to use this software if you have express permission from the copyright holder and agreed to the latest NiloToonURP EULA)
// Copyright (c) 2021 Kuroneko ShaderLab Limited
// For more information, visit -> https://github.com/ColinLeung-NiloCat/UnityURPToonLitShaderExample
// #pragma once is a safe guard best practice in almost every .hlsl,
// doing this can make sure your .hlsl's user can include this .hlsl anywhere anytime without producing any multi include conflict
#pragma once
// direct copy of G1V(...) from https://github.com/bartwronski/CSharpRenderer/blob/master/shaders/optimized-ggx.hlsl
float G1V(float dotNV, float k)
{
return 1.0f/(dotNV*(1.0f-k)+k);
}
// direct copy of LightingFuncGGX_REF(...) from https://github.com/bartwronski/CSharpRenderer/blob/master/shaders/optimized-ggx.hlsl
float GGXDirectSpecular(float3 N, float3 V, float3 L, float roughness, float F0)
{
float alpha = roughness*roughness;
float3 H = normalize(V+L);
float dotNL = saturate(dot(N,L));
float dotNV = saturate(dot(N,V));
float dotNH = saturate(dot(N,H));
float dotLH = saturate(dot(L,H));
float F, D, vis;
// D
float alphaSqr = alpha*alpha;
float pi = 3.14159f;
float denom = dotNH * dotNH *(alphaSqr-1.0) + 1.0f;
D = alphaSqr/(pi * denom * denom);
// F
float dotLH5 = pow(1.0f-dotLH,5);
F = F0 + (1.0-F0)*(dotLH5);
// V
float k = alpha/2.0f;
vis = G1V(dotNL,k)*G1V(dotNV,k);
float specular = dotNL * D * F * vis;
return specular;
}
///////////////////////////////////////////////////////////////////////////////////////////
// This is the same function as GGXDirectSpecular(...),
// but assumed L equals V (assumed light always come from camera, for NPR purpose),
// when L equals V we can do some more optimization!
//
// Don't convert to half, else mobile will have precision problem!
// Keep float is needed.
///////////////////////////////////////////////////////////////////////////////////////////
float GGXDirectSpecular_LequalsV_Optimized(float NdotV,float VdotV, float roughness, float F0)
{
float alpha = roughness * roughness;
float F, D, vis;
// D
float alphaSqr = alpha * alpha;
float pi = 3.14159f;
float denom = NdotV * NdotV * (alphaSqr - 1.0) + 1.0f;
D = alphaSqr / (pi * denom * denom);
// F
float dotLH5 = pow(1.0f - VdotV, 5);
F = F0 + (1.0 - F0) * (dotLH5);
// V
float k = alpha / 2.0f;
float G1VResult = G1V(NdotV, k);
vis = G1VResult * G1VResult;
float directSpecular = NdotV * D * F * vis;
return directSpecular;
}
///////////////////////////////////////////////////////////////////////////////////////////
// This is the same function as GGXDirectSpecular(...)
// But don't require calculating H,dotNL,dotNV,dotNH,dotLH again inside the function.
// User should provide all of the above data.
///////////////////////////////////////////////////////////////////////////////////////////
float GGXDirectSpecular_Optimized(float3 H, float dotNL, float dotNV, float dotNH, float dotLH, float roughness, float F0)
{
float alpha = roughness*roughness;
float F, D, vis;
// D
float alphaSqr = alpha*alpha;
float pi = 3.14159f;
float denom = dotNH * dotNH *(alphaSqr-1.0) + 1.0f;
D = alphaSqr/(pi * denom * denom);
// F
float dotLH5 = pow(1.0f-dotLH,5);
F = F0 + (1.0-F0)*(dotLH5);
// V
float k = alpha/2.0f;
vis = G1V(dotNL,k)*G1V(dotNV,k);
float specular = dotNL * D * F * vis;
return specular;
}