Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,48 @@ void computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const

}

// GGX BRDF with multi-scattering energy compensation for direct lighting
// Based on "Practical Multiple Scattering Compensation for Microfacet Models"
// https://blog.selfshadow.com/publications/turquin/ms_comp_final.pdf
vec3 BRDF_GGX_Multiscatter( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material ) {

// Single-scattering BRDF (standard GGX)
vec3 singleScatter = BRDF_GGX( lightDir, viewDir, normal, material );

// Multi-scattering compensation
float dotNL = saturate( dot( normal, lightDir ) );
float dotNV = saturate( dot( normal, viewDir ) );

// Precomputed DFG values for view and light directions
vec2 dfgV = DFGApprox( vec3(0.0, 0.0, 1.0), vec3(sqrt(1.0 - dotNV * dotNV), 0.0, dotNV), material.roughness );
vec2 dfgL = DFGApprox( vec3(0.0, 0.0, 1.0), vec3(sqrt(1.0 - dotNL * dotNL), 0.0, dotNL), material.roughness );

// Single-scattering energy for view and light
vec3 FssEss_V = material.specularColor * dfgV.x + material.specularF90 * dfgV.y;
vec3 FssEss_L = material.specularColor * dfgL.x + material.specularF90 * dfgL.y;

float Ess_V = dfgV.x + dfgV.y;
float Ess_L = dfgL.x + dfgL.y;

// Energy lost to multiple scattering
float Ems_V = 1.0 - Ess_V;
float Ems_L = 1.0 - Ess_L;

// Average Fresnel reflectance
vec3 Favg = material.specularColor + ( 1.0 - material.specularColor ) * 0.047619; // 1/21

// Multiple scattering contribution
vec3 Fms = FssEss_V * FssEss_L * Favg / ( 1.0 - Ems_V * Ems_L * Favg * Favg + EPSILON );

// Energy compensation factor
float compensationFactor = Ems_V * Ems_L;

vec3 multiScatter = Fms * compensationFactor;

return singleScatter + multiScatter;

}

#if NUM_RECT_AREA_LIGHTS > 0

void RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {
Expand Down Expand Up @@ -490,7 +532,7 @@ void RE_Direct_Physical( const in IncidentLight directLight, const in vec3 geome

#endif

reflectedLight.directSpecular += irradiance * BRDF_GGX( directLight.direction, geometryViewDir, geometryNormal, material );
reflectedLight.directSpecular += irradiance * BRDF_GGX_Multiscatter( directLight.direction, geometryViewDir, geometryNormal, material );

reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );
}
Expand Down