|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Precompute part of lambdaV |
|
|
|
float GetSmithJointGGXPreLambdaV(float NdotV, float roughness) |
|
|
|
float GetSmithJointGGXPartLambdaV(float NdotV, float roughness) |
|
|
|
{ |
|
|
|
float a2 = roughness * roughness; |
|
|
|
return sqrt((-NdotV * a2 + NdotV) * NdotV + a2); |
|
|
|
|
|
|
// Ref: http://jcgt.org/published/0003/02/03/paper.pdf |
|
|
|
float V_SmithJointGGX(float NdotL, float NdotV, float roughness, float preLambdaV) |
|
|
|
float V_SmithJointGGX(float NdotL, float NdotV, float roughness, float partLambdaV) |
|
|
|
{ |
|
|
|
float a2 = roughness * roughness; |
|
|
|
|
|
|
|
|
|
|
// G = 1 / (1 + lambda_v + lambda_l); |
|
|
|
|
|
|
|
// Reorder code to be more optimal: |
|
|
|
float lambdaV = NdotL * preLambdaV; |
|
|
|
float lambdaV = NdotL * partLambdaV; |
|
|
|
float lambdaL = NdotV * sqrt((-NdotL * a2 + NdotL) * NdotL + a2); |
|
|
|
|
|
|
|
// Simplify visibility term: (2.0 * NdotL * NdotV) / ((4.0 * NdotL * NdotV) * (lambda_v + lambda_l)); |
|
|
|
|
|
|
float V_SmithJointGGX(float NdotL, float NdotV, float roughness) |
|
|
|
{ |
|
|
|
float preLambdaV = GetSmithJointGGXPreLambdaV(NdotV, roughness); |
|
|
|
return V_SmithJointGGX(NdotL, NdotV, roughness, preLambdaV); |
|
|
|
float partLambdaV = GetSmithJointGGXPartLambdaV(NdotV, roughness); |
|
|
|
return V_SmithJointGGX(NdotL, NdotV, roughness, partLambdaV); |
|
|
|
float DV_SmithJointGGX(float NdotH, float NdotL, float NdotV, float roughness, float preLambdaV) |
|
|
|
float DV_SmithJointGGX(float NdotH, float NdotL, float NdotV, float roughness, float partLambdaV) |
|
|
|
float lambdaV = NdotL * preLambdaV; |
|
|
|
float lambdaV = NdotL * partLambdaV; |
|
|
|
float lambdaL = NdotV * sqrt((-NdotL * a2 + NdotL) * NdotL + a2); |
|
|
|
|
|
|
|
float2 G = float2(1, lambdaV + lambdaL); // Fraction without the constant (0.5) |
|
|
|
|
|
|
|
|
|
|
float DV_SmithJointGGX(float NdotH, float NdotL, float NdotV, float roughness) |
|
|
|
{ |
|
|
|
float preLambdaV = GetSmithJointGGXPreLambdaV(NdotV, roughness); |
|
|
|
return DV_SmithJointGGX(NdotH, NdotL, NdotV, roughness, preLambdaV); |
|
|
|
float partLambdaV = GetSmithJointGGXPartLambdaV(NdotV, roughness); |
|
|
|
return DV_SmithJointGGX(NdotH, NdotL, NdotV, roughness, partLambdaV); |
|
|
|
} |
|
|
|
|
|
|
|
// Precompute a part of LambdaV. |
|
|
|
|
|
|
// https://www.desmos.com/calculator/wtp8lnjutx |
|
|
|
float GetSmithJointGGXPreLambdaVApprox(float NdotV, float roughness) |
|
|
|
float GetSmithJointGGXPartLambdaVApprox(float NdotV, float roughness) |
|
|
|
float V_SmithJointGGXApprox(float NdotL, float NdotV, float roughness, float preLambdaV) |
|
|
|
float V_SmithJointGGXApprox(float NdotL, float NdotV, float roughness, float partLambdaV) |
|
|
|
float lambdaV = NdotL * preLambdaV; |
|
|
|
float lambdaV = NdotL * partLambdaV; |
|
|
|
float lambdaL = NdotV * (NdotL * (1 - a) + a); |
|
|
|
|
|
|
|
return 0.5 / (lambdaV + lambdaL); |
|
|
|
|
|
|
{ |
|
|
|
float preLambdaV = GetSmithJointGGXPreLambdaVApprox(NdotV, roughness); |
|
|
|
return V_SmithJointGGXApprox(NdotL, NdotV, roughness, preLambdaV); |
|
|
|
float partLambdaV = GetSmithJointGGXPartLambdaVApprox(NdotV, roughness); |
|
|
|
return V_SmithJointGGXApprox(NdotL, NdotV, roughness, partLambdaV); |
|
|
|
} |
|
|
|
|
|
|
|
// roughnessT -> roughness in tangent direction |
|
|
|
|
|
|
return INV_PI * D_GGXAnisoNoPI(TdotH, BdotH, NdotH, roughnessT, roughnessB); |
|
|
|
} |
|
|
|
|
|
|
|
float GetSmithJointGGXAnisoPreLambdaV(float TdotV, float BdotV, float NdotV, float roughnessT, float roughnessB) |
|
|
|
float GetSmithJointGGXAnisoPartLambdaV(float TdotV, float BdotV, float NdotV, float roughnessT, float roughnessB) |
|
|
|
{ |
|
|
|
float aT2 = roughnessT * roughnessT; |
|
|
|
float aB2 = roughnessB * roughnessB; |
|
|
|
|
|
|
|
|
|
|
// Note: V = G / (4 * NdotL * NdotV) |
|
|
|
// Ref: https://cedec.cesa.or.jp/2015/session/ENG/14698.html The Rendering Materials of Far Cry 4 |
|
|
|
float V_SmithJointGGXAniso(float TdotV, float BdotV, float NdotV, float TdotL, float BdotL, float NdotL, float roughnessT, float roughnessB, float preLambdaV) |
|
|
|
float V_SmithJointGGXAniso(float TdotV, float BdotV, float NdotV, float TdotL, float BdotL, float NdotL, float roughnessT, float roughnessB, float partLambdaV) |
|
|
|
float lambdaV = NdotL * preLambdaV; |
|
|
|
float lambdaV = NdotL * partLambdaV; |
|
|
|
float lambdaL = NdotV * sqrt(aT2 * TdotL * TdotL + aB2 * BdotL * BdotL + NdotL * NdotL); |
|
|
|
|
|
|
|
return 0.5 / (lambdaV + lambdaL); |
|
|
|
|
|
|
{ |
|
|
|
float preLambdaV = GetSmithJointGGXAnisoPreLambdaV(TdotV, BdotV, NdotV, roughnessT, roughnessB); |
|
|
|
return V_SmithJointGGXAniso(TdotV, BdotV, NdotV, TdotL, BdotL, NdotL, roughnessT, roughnessB, preLambdaV); |
|
|
|
float partLambdaV = GetSmithJointGGXAnisoPartLambdaV(TdotV, BdotV, NdotV, roughnessT, roughnessB); |
|
|
|
return V_SmithJointGGXAniso(TdotV, BdotV, NdotV, TdotL, BdotL, NdotL, roughnessT, roughnessB, partLambdaV); |
|
|
|
} |
|
|
|
|
|
|
|
// Inline D_GGXAniso() * V_SmithJointGGXAniso() together for better code generation. |
|
|
|
|
|
|
float roughnessT, float roughnessB, float preLambdaV) |
|
|
|
float roughnessT, float roughnessB, float partLambdaV) |
|
|
|
{ |
|
|
|
float aT2 = roughnessT * roughnessT; |
|
|
|
float aB2 = roughnessB * roughnessB; |
|
|
|
|
|
|
|
|
|
|
float lambdaV = NdotL * preLambdaV; |
|
|
|
float lambdaV = NdotL * partLambdaV; |
|
|
|
float lambdaL = NdotV * sqrt(aT2 * TdotL * TdotL + aB2 * BdotL * BdotL + NdotL * NdotL); |
|
|
|
|
|
|
|
float2 G = float2(1, lambdaV + lambdaL); // Fraction without the constant (0.5) |
|
|
|
|
|
|
float TdotL, float BdotL, float NdotL, |
|
|
|
float roughnessT, float roughnessB) |
|
|
|
{ |
|
|
|
float preLambdaV = GetSmithJointGGXAnisoPreLambdaV(TdotV, BdotV, NdotV, roughnessT, roughnessB); |
|
|
|
float partLambdaV = GetSmithJointGGXAnisoPartLambdaV(TdotV, BdotV, NdotV, roughnessT, roughnessB); |
|
|
|
roughnessT, roughnessB, preLambdaV); |
|
|
|
roughnessT, roughnessB, partLambdaV); |
|
|
|
} |
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
|
|