// 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; }