- Moved video screen into its own separate movie tent. - Adjusted stable post-processing volume. - Chickens are now at full volume. - Added button to toggle chickens off and on.
120 lines
4.4 KiB
HLSL
120 lines
4.4 KiB
HLSL
#ifndef FILAMENT_COMMON_OCCLUSION
|
|
#define FILAMENT_COMMON_OCCLUSION
|
|
//------------------------------------------------------------------------------
|
|
// Ambient occlusion configuration
|
|
//------------------------------------------------------------------------------
|
|
|
|
// Diffuse BRDFs
|
|
#define SPECULAR_AO_OFF 0
|
|
#define SPECULAR_AO_SIMPLE 1
|
|
#define SPECULAR_AO_BENT_NORMALS 2
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Ambient occlusion helpers
|
|
//------------------------------------------------------------------------------
|
|
|
|
float SpecularAO_Lagarde(float NoV, float visibility, float roughness) {
|
|
// Lagarde and de Rousiers 2014, "Moving Frostbite to PBR"
|
|
return saturate(pow(NoV + visibility, exp2(-16.0 * roughness - 1.0)) - 1.0 + visibility);
|
|
}
|
|
|
|
#if defined(MATERIAL_HAS_BENT_NORMAL)
|
|
float sphericalCapsIntersection(float cosCap1, float cosCap2, float cosDistance) {
|
|
// Oat and Sander 2007, "Ambient Aperture Lighting"
|
|
// Approximation mentioned by Jimenez et al. 2016
|
|
float r1 = acosFastPositive(cosCap1);
|
|
float r2 = acosFastPositive(cosCap2);
|
|
float d = acosFast(cosDistance);
|
|
|
|
// We work with cosine angles, replace the original paper's use of
|
|
// cos(min(r1, r2)) with max(cosCap1, cosCap2)
|
|
// We also remove a multiplication by 2 * PI to simplify the computation
|
|
// since we divide by 2 * PI in computeBentSpecularAO()
|
|
|
|
if (min(r1, r2) <= max(r1, r2) - d) {
|
|
return 1.0 - max(cosCap1, cosCap2);
|
|
} else if (r1 + r2 <= d) {
|
|
return 0.0;
|
|
}
|
|
|
|
float delta = abs(r1 - r2);
|
|
float x = 1.0 - saturate((d - delta) / max(r1 + r2 - delta, 1e-4));
|
|
// simplified smoothstep()
|
|
float area = sq(x) * (-2.0 * x + 3.0);
|
|
return area * (1.0 - max(cosCap1, cosCap2));
|
|
}
|
|
#endif
|
|
|
|
// This function could (should?) be implemented as a 3D LUT instead, but we need to save samplers
|
|
float SpecularAO_Cones(float NoV, float visibility, float roughness) {
|
|
#if defined(MATERIAL_HAS_BENT_NORMAL)
|
|
// Jimenez et al. 2016, "Practical Realtime Strategies for Accurate Indirect Occlusion"
|
|
|
|
// aperture from ambient occlusion
|
|
float cosAv = sqrt(1.0 - visibility);
|
|
// aperture from roughness, log(10) / log(2) = 3.321928
|
|
float cosAs = exp2(-3.321928 * sq(roughness));
|
|
// angle betwen bent normal and reflection direction
|
|
float cosB = dot(shading_bentNormal, shading_reflected);
|
|
|
|
// Remove the 2 * PI term from the denominator, it cancels out the same term from
|
|
// sphericalCapsIntersection()
|
|
float ao = sphericalCapsIntersection(cosAv, cosAs, cosB) / (1.0 - cosAs);
|
|
// Smoothly kill specular AO when entering the perceptual roughness range [0.1..0.3]
|
|
// Without this, specular AO can remove all reflections, which looks bad on metals
|
|
return lerp(1.0, ao, smoothstep(0.01, 0.09, roughness));
|
|
#else
|
|
return SpecularAO_Lagarde(NoV, visibility, roughness);
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Computes a specular occlusion term from the ambient occlusion term.
|
|
*/
|
|
float computeSpecularAO(float NoV, float visibility, float roughness) {
|
|
#if SPECULAR_AMBIENT_OCCLUSION == SPECULAR_AO_SIMPLE
|
|
return SpecularAO_Lagarde(NoV, visibility, roughness);
|
|
#elif SPECULAR_AMBIENT_OCCLUSION == SPECULAR_AO_BENT_NORMALS
|
|
return SpecularAO_Cones(NoV, visibility, roughness);
|
|
#else
|
|
return 1.0;
|
|
#endif
|
|
}
|
|
|
|
#if MULTI_BOUNCE_AMBIENT_OCCLUSION == 1
|
|
/**
|
|
* Returns a color ambient occlusion based on a pre-computed visibility term.
|
|
* The albedo term is meant to be the diffuse color or f0 for the diffuse and
|
|
* specular terms respectively.
|
|
*/
|
|
float3 gtaoMultiBounce(float visibility, const float3 albedo) {
|
|
// Jimenez et al. 2016, "Practical Realtime Strategies for Accurate Indirect Occlusion"
|
|
float3 a = 2.0404 * albedo - 0.3324;
|
|
float3 b = -4.7951 * albedo + 0.6417;
|
|
float3 c = 2.7552 * albedo + 0.6903;
|
|
|
|
return max((visibility), ((visibility * a + b) * visibility + c) * visibility);
|
|
}
|
|
#endif
|
|
|
|
void multiBounceAO(float visibility, const float3 albedo, inout float3 color) {
|
|
#if MULTI_BOUNCE_AMBIENT_OCCLUSION == 1
|
|
color *= gtaoMultiBounce(visibility, albedo);
|
|
#endif
|
|
}
|
|
|
|
void multiBounceSpecularAO(float visibility, const float3 albedo, inout float3 color) {
|
|
#if MULTI_BOUNCE_AMBIENT_OCCLUSION == 1 && SPECULAR_AMBIENT_OCCLUSION != SPECULAR_AO_OFF
|
|
color *= gtaoMultiBounce(visibility, albedo);
|
|
#endif
|
|
}
|
|
|
|
float singleBounceAO(float visibility) {
|
|
#if MULTI_BOUNCE_AMBIENT_OCCLUSION == 1
|
|
return 1.0;
|
|
#else
|
|
return visibility;
|
|
#endif
|
|
}
|
|
|
|
#endif // FILAMENT_COMMON_OCCLUSION |