207 lines
7.3 KiB
C
207 lines
7.3 KiB
C
// GI
|
|
float cascadeScales[CASCADES];
|
|
float cascadeScalesInv[CASCADES];
|
|
void precomputeCascades() {
|
|
for ( int i = 0; i < CASCADES; ++i ) {
|
|
cascadeScales[i] = cascadePower(i);
|
|
cascadeScalesInv[i] = 1.0 / cascadeScales[i];
|
|
}
|
|
}
|
|
vec4 voxelTrace( inout Ray ray, float aperture, float maxDistance ) {
|
|
ray.origin += ray.direction * voxelInfo.radianceSizeRecip * 1.5;
|
|
|
|
#if VXGI_NDC
|
|
ray.origin = vec3( ubo.settings.vxgi.matrix * vec4( ray.origin, 1.0 ) );
|
|
ray.direction = vec3( ubo.settings.vxgi.matrix * vec4( ray.direction, 0.0 ) );
|
|
float absMax = max3(abs(ray.origin));
|
|
#else
|
|
const float voxelOrigin = vec3( ubo.settings.vxgi.matrix * vec4( ray.origin, 1.0 ) );
|
|
float absMax = max3(abs(voxelOrigin));
|
|
#endif
|
|
|
|
uint cascade = 0;
|
|
for ( uint c = 0; c < CASCADES - 1; ++c ) {
|
|
if ( absMax * cascadeScalesInv[c] < (1.0 - voxelInfo.radianceSizeRecip)) {
|
|
cascade = c;
|
|
break;
|
|
}
|
|
cascade = CASCADES - 1;
|
|
}
|
|
|
|
const float maxCascadeScale = cascadeScales[CASCADES-1];
|
|
float currentCascadeScale = cascadeScales[cascade];
|
|
float currentCascadeScaleInv = cascadeScalesInv[cascade];
|
|
|
|
const float granularity = ubo.settings.vxgi.granularity;
|
|
const float occlusionFalloff = ubo.settings.vxgi.occlusionFalloff;
|
|
const float coneCoefficient = 2.0 * tan(aperture * 0.5);
|
|
|
|
const uint maxSteps = uint(voxelInfo.radianceSize * maxCascadeScale * granularity);
|
|
const float maxRadiance = 0.90;
|
|
// box
|
|
const vec2 rayBoxInfoA = rayBoxDst( voxelInfo.min * currentCascadeScale, voxelInfo.max * currentCascadeScale, ray );
|
|
const vec2 rayBoxInfoB = rayBoxDst( voxelInfo.min * maxCascadeScale, voxelInfo.max * maxCascadeScale, ray );
|
|
|
|
const float tStart = rayBoxInfoA.x;
|
|
const float tEnd = maxDistance > 0 ? min(maxDistance, rayBoxInfoB.y) : rayBoxInfoB.y;
|
|
const float tDelta = voxelInfo.radianceSizeRecip * granularity;
|
|
|
|
// marcher
|
|
ray.distance = tStart + tDelta * ubo.settings.vxgi.traceStartOffsetFactor;
|
|
ray.position = vec3(0);
|
|
|
|
vec4 radiance = vec4(0);
|
|
vec3 uvw = vec3(0);
|
|
float coneDiameter = coneCoefficient * ray.distance;
|
|
float level = aperture > 0 ? log2( coneDiameter ) : 0;
|
|
vec4 color = vec4(0);
|
|
float occlusion = 0;
|
|
uint stepCounter = 0;
|
|
|
|
ray.distance += tDelta * rand2(gl_GlobalInvocationID.xy);
|
|
|
|
while ( color.a < maxRadiance && occlusion < 1.0 && ray.distance < tEnd && stepCounter++ < maxSteps ) {
|
|
float stepScale = max(1.0, (coneDiameter * currentCascadeScale) * 1.5);
|
|
ray.distance += tDelta * stepScale;
|
|
ray.position = ray.origin + ray.direction * ray.distance;
|
|
|
|
absMax = max3(abs(ray.position));
|
|
if ( absMax * currentCascadeScaleInv > 0.99 ) {
|
|
if ( ++cascade >= CASCADES ) break;
|
|
|
|
currentCascadeScale = cascadeScales[cascade];
|
|
currentCascadeScaleInv = cascadeScalesInv[cascade];
|
|
|
|
ray.distance += tDelta * currentCascadeScale;
|
|
continue;
|
|
}
|
|
|
|
uvw = ray.position * currentCascadeScaleInv * 0.5 + 0.5;
|
|
coneDiameter = coneCoefficient * ray.distance;
|
|
level = aperture > 0 ? log2( coneDiameter ) : 0;
|
|
|
|
radiance = textureLod(voxelOutput[nonuniformEXT(cascade)], uvw.xzy, level);
|
|
|
|
color.rgb += (1.0 - color.a) * radiance.rgb * radiance.a;
|
|
color.a += (1.0 - color.a) * radiance.a;
|
|
|
|
occlusion += ((1.0f - occlusion) * radiance.a) / (1.0f + occlusionFalloff * coneDiameter);
|
|
}
|
|
return maxDistance > 0 ? color : vec4(color.rgb, occlusion);
|
|
}
|
|
vec4 voxelConeTrace( inout Ray ray, float aperture ) {
|
|
return voxelTrace( ray, aperture, 0 );
|
|
}
|
|
vec4 voxelTrace( inout Ray ray, float maxDistance ) {
|
|
return voxelTrace( ray, 0, maxDistance );
|
|
}
|
|
uint voxelShadowsCount = 0;
|
|
float shadowFactorVXGI( const Light light, float def ) {
|
|
if ( ubo.settings.vxgi.shadows < ++voxelShadowsCount ) return 1.0;
|
|
|
|
const float SHADOW_APERTURE = 0.2;
|
|
const float DEPTH_BIAS = 0.0;
|
|
|
|
Ray ray;
|
|
ray.direction = normalize( light.position - surface.position.world );
|
|
ray.origin = surface.position.world + ray.direction * 0.5;
|
|
float z = distance( surface.position.world, light.position ) - DEPTH_BIAS;
|
|
return 1.0 - voxelTrace( ray, SHADOW_APERTURE, z ).a;
|
|
}
|
|
void indirectLightingVXGI() {
|
|
precomputeCascades();
|
|
|
|
voxelInfo.radianceSize = textureSize( voxelOutput[0], 0 ).x;
|
|
voxelInfo.radianceSizeRecip = 1.0 / voxelInfo.radianceSize;
|
|
voxelInfo.mipmapLevels = log2(voxelInfo.radianceSize) + 1;
|
|
|
|
#if VXGI_NDC
|
|
voxelInfo.min = vec3( -1 );
|
|
voxelInfo.max = vec3( 1 );
|
|
#else
|
|
const mat4 inverseOrtho = inverse( ubo.settings.vxgi.matrix );
|
|
voxelInfo.min = vec3( inverseOrtho * vec4( -1, -1, -1, 1 ) );
|
|
voxelInfo.max = vec3( inverseOrtho * vec4( 1, 1, 1, 1 ) );
|
|
#endif
|
|
|
|
vec4 indirectDiffuse = vec4(0);
|
|
vec4 indirectSpecular = vec4(0);
|
|
|
|
const vec3 P = surface.position.world;
|
|
const vec3 N = surface.normal.world;
|
|
|
|
const vec3 right = normalize(orthogonal(N));
|
|
const vec3 up = normalize(cross(right, N));
|
|
|
|
#if 0
|
|
{
|
|
Ray ray;
|
|
ray.direction = N;
|
|
ray.origin = P + N * (voxelInfo.radianceSizeRecip * 4.0);
|
|
|
|
indirectDiffuse = voxelConeTrace(ray, 1.0f);
|
|
surface.material.occlusion += 1.0 - clamp(indirectDiffuse.a, 0.0, 1.0);
|
|
}
|
|
#else
|
|
const uint CONES_COUNT = 4;
|
|
const vec3 CONES[] = {
|
|
normalize(N + right + up),
|
|
normalize(N - right + up),
|
|
normalize(N + right - up),
|
|
normalize(N - right - up)
|
|
};
|
|
|
|
const float DIFFUSE_CONE_APERTURE = 1.1547;
|
|
const float DIFFUSE_INDIRECT_FACTOR = 1.0f / float(CONES_COUNT) * 0.125f;
|
|
|
|
if ( DIFFUSE_INDIRECT_FACTOR > 0.0f ) {
|
|
float weight = PI * 0.25f;
|
|
for ( uint i = 0; i < CONES_COUNT; ++i ) {
|
|
Ray ray;
|
|
ray.direction = CONES[i].xyz;
|
|
ray.origin = P; // + ray.direction;
|
|
indirectDiffuse += voxelConeTrace( ray, DIFFUSE_CONE_APERTURE ) * weight;
|
|
weight = PI * 0.15f;
|
|
}
|
|
surface.material.occlusion += 1.0 - clamp(indirectDiffuse.a, 0.0, 1.0);
|
|
}
|
|
indirectDiffuse *= DIFFUSE_INDIRECT_FACTOR;
|
|
#endif
|
|
|
|
const float SPECULAR_CONE_APERTURE = clamp(tan(PI * 0.5f * surface.material.roughness), 0.0174533f, PI); // tan( R * PI * 0.5f * 0.1f );
|
|
const float SPECULAR_INDIRECT_FACTOR = (1.0f - surface.material.metallic) * (1.0f - surface.material.roughness); // * 0.25; // 1.0f;
|
|
if ( SPECULAR_INDIRECT_FACTOR > 0.0f ) {
|
|
const vec3 R = reflect( normalize(P - surface.ray.origin), N );
|
|
Ray ray;
|
|
ray.direction = R;
|
|
ray.origin = P; // + ray.direction;
|
|
indirectSpecular = voxelConeTrace( ray, SPECULAR_CONE_APERTURE );
|
|
}
|
|
indirectSpecular *= SPECULAR_INDIRECT_FACTOR;
|
|
|
|
// Calculate Fresnel
|
|
{
|
|
const vec3 V = normalize(surface.ray.origin - surface.position.world);
|
|
const vec3 N = surface.normal.world;
|
|
const float NdotV = max(dot(N, V), 0.0);
|
|
|
|
const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic);
|
|
const vec3 F = fresnelSchlick(F0, NdotV);
|
|
|
|
indirectDiffuse.rgb *= (1.0 - F) * (1.0 - surface.material.metallic) * surface.material.occlusion;
|
|
}
|
|
|
|
surface.material.indirect += indirectDiffuse + indirectSpecular;
|
|
|
|
// deferred sampling doesn't have a blended albedo buffer
|
|
// in place we'll just cone trace behind the window
|
|
#if !RT
|
|
if ( 0.1 < surface.material.albedo.a && surface.material.albedo.a < 1.0 ) {
|
|
Ray ray;
|
|
ray.direction = surface.ray.direction;
|
|
ray.origin = surface.position.world + ray.direction;
|
|
vec4 radiance = voxelConeTrace( ray, surface.material.albedo.a * 0.5 );
|
|
surface.fragment.rgb += (1.0 - surface.material.albedo.a) * radiance.rgb;
|
|
}
|
|
#endif
|
|
} |