339 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			GLSL
		
	
	
	
	
	
			
		
		
	
	
			339 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			GLSL
		
	
	
	
	
	
/*
 | 
						|
Copyright (c) 2024 Turánszki János
 | 
						|
 | 
						|
Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
						|
of this software and associated documentation files (the "Software"), to deal
 | 
						|
in the Software without restriction, including without limitation the rights
 | 
						|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
						|
copies of the Software, and to permit persons to whom the Software is
 | 
						|
furnished to do so, subject to the following conditions:
 | 
						|
 | 
						|
The above copyright notice and this permission notice shall be included in
 | 
						|
all copies or substantial portions of the Software.
 | 
						|
 | 
						|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
						|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
						|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 | 
						|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
						|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
						|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
						|
THE SOFTWARE.
 | 
						|
 */
 | 
						|
#ifndef _CONETRACE_GLSL_
 | 
						|
#define _CONETRACE_GLSL_
 | 
						|
 | 
						|
#include "std/constants.glsl"
 | 
						|
 | 
						|
// References
 | 
						|
// https://github.com/Friduric/voxel-cone-tracing
 | 
						|
// https://github.com/Cigg/Voxel-Cone-Tracing
 | 
						|
// https://github.com/GreatBlambo/voxel_cone_tracing/
 | 
						|
// http://simonstechblog.blogspot.com/2013/01/implementing-voxel-cone-tracing.html
 | 
						|
// http://leifnode.com/2015/05/voxel-cone-traced-global-illumination/
 | 
						|
// http://www.seas.upenn.edu/%7Epcozzi/OpenGLInsights/OpenGLInsights-SparseVoxelization.pdf
 | 
						|
// https://research.nvidia.com/sites/default/files/publications/GIVoxels-pg2011-authors.pdf
 | 
						|
 | 
						|
const float MAX_DISTANCE = voxelgiRange;
 | 
						|
 | 
						|
#ifdef _VoxelGI
 | 
						|
uniform sampler3D dummy;
 | 
						|
 | 
						|
vec4 sampleVoxel(sampler3D voxels, vec3 P, const float clipmaps[voxelgiClipmapCount * 10], const float clipmap_index, const float step_dist, const int precomputed_direction, const vec3 face_offset, const vec3 direction_weight) {
 | 
						|
 	vec4 col = vec4(0.0);
 | 
						|
	vec3 tc = (P - vec3(clipmaps[int(clipmap_index * 10 + 4)], clipmaps[int(clipmap_index * 10 + 5)], clipmaps[int(clipmap_index * 10 + 6)])) / (float(clipmaps[int(clipmap_index * 10)]) * voxelgiResolution);
 | 
						|
	vec3 half_texel = vec3(0.5) / voxelgiResolution;
 | 
						|
	tc = tc * 0.5 + 0.5;
 | 
						|
	tc = clamp(tc, half_texel, 1.0 - half_texel);
 | 
						|
	tc.x = (tc.x + precomputed_direction) / (6 + DIFFUSE_CONE_COUNT);
 | 
						|
	tc.y = (tc.y + clipmap_index) / voxelgiClipmapCount;
 | 
						|
 | 
						|
	if (precomputed_direction == 0) {
 | 
						|
		col = direction_weight.x * textureLod(voxels, vec3(tc.x + face_offset.x, tc.y, tc.z), 0)
 | 
						|
			+ direction_weight.y * textureLod(voxels, vec3(tc.x + face_offset.y, tc.y, tc.z), 0)
 | 
						|
			+ direction_weight.z * textureLod(voxels, vec3(tc.x + face_offset.z, tc.y, tc.z), 0);
 | 
						|
	}
 | 
						|
	else
 | 
						|
		col = textureLod(voxels, tc, 0);
 | 
						|
 | 
						|
	col *= step_dist / float(clipmaps[int(clipmap_index * 10)]);
 | 
						|
 | 
						|
	return col;
 | 
						|
}
 | 
						|
 | 
						|
#endif
 | 
						|
#ifdef _VoxelAOvar
 | 
						|
float sampleVoxel(sampler3D voxels, vec3 P, const float clipmaps[voxelgiClipmapCount * 10], const float clipmap_index, const float step_dist, const int precomputed_direction, const vec3 face_offset, const vec3 direction_weight) {
 | 
						|
 	float opac = 0.0;
 | 
						|
	vec3 tc = (P - vec3(clipmaps[int(clipmap_index * 10 + 4)], clipmaps[int(clipmap_index * 10 + 5)], clipmaps[int(clipmap_index * 10 + 6)])) / (float(clipmaps[int(clipmap_index * 10)]) * voxelgiResolution);
 | 
						|
	vec3 half_texel = vec3(0.5) / voxelgiResolution;
 | 
						|
	tc = tc * 0.5 + 0.5;
 | 
						|
	tc = clamp(tc, half_texel, 1.0 - half_texel);
 | 
						|
	tc.x = (tc.x + precomputed_direction) / (6 + DIFFUSE_CONE_COUNT);
 | 
						|
	tc.y = (tc.y + clipmap_index) / voxelgiClipmapCount;
 | 
						|
 | 
						|
	if (precomputed_direction == 0) {
 | 
						|
		opac = direction_weight.x * textureLod(voxels, vec3(tc.x + face_offset.x, tc.y, tc.z), 0).r
 | 
						|
			+ direction_weight.y * textureLod(voxels, vec3(tc.x + face_offset.y, tc.y, tc.z), 0).r
 | 
						|
			+ direction_weight.z * textureLod(voxels, vec3(tc.x + face_offset.z, tc.y, tc.z), 0).r;
 | 
						|
	}
 | 
						|
	else
 | 
						|
		opac = textureLod(voxels, tc, 0).r;
 | 
						|
 | 
						|
	opac *= step_dist / float(clipmaps[int(clipmap_index * 10)]);
 | 
						|
 | 
						|
	return opac;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef _VoxelGI
 | 
						|
vec4 traceCone(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 origin, const vec3 n, const vec3 dir, const int precomputed_direction, const bool use_sdf, const float aperture, const float step_size, const float clipmaps[voxelgiClipmapCount * 10]) {
 | 
						|
    vec4 sampleCol = vec4(0.0);
 | 
						|
	float voxelSize0 = float(clipmaps[0]) * 2.0;
 | 
						|
	float dist = voxelSize0;
 | 
						|
	float step_dist = dist;
 | 
						|
	vec3 samplePos;
 | 
						|
	vec3 start_pos = origin + n * voxelSize0;
 | 
						|
	int clipmap_index0 = 0;
 | 
						|
 | 
						|
	vec3 aniso_direction = -dir;
 | 
						|
	vec3 face_offset = vec3(
 | 
						|
		aniso_direction.x > 0.0 ? 0 : 1,
 | 
						|
		aniso_direction.y > 0.0 ? 2 : 3,
 | 
						|
		aniso_direction.z > 0.0 ? 4 : 5
 | 
						|
	) / (6 + DIFFUSE_CONE_COUNT);
 | 
						|
	vec3 direction_weight = abs(dir);
 | 
						|
 | 
						|
	float coneCoefficient = 2.0 * tan(aperture * 0.5);
 | 
						|
 | 
						|
    while (sampleCol.a < 1.0 && dist < MAX_DISTANCE && clipmap_index0 < voxelgiClipmapCount) {
 | 
						|
		vec4 mipSample = vec4(0.0);
 | 
						|
		float diam = max(voxelSize0, dist * coneCoefficient);
 | 
						|
        float lod = clamp(log2(diam / voxelSize0), clipmap_index0, voxelgiClipmapCount - 1);
 | 
						|
        float clipmap_index = floor(lod);
 | 
						|
		float clipmap_blend = fract(lod);
 | 
						|
		vec3 p0 = start_pos + dir * dist;
 | 
						|
 | 
						|
        samplePos = (p0 - vec3(clipmaps[int(clipmap_index * 10 + 4)], clipmaps[int(clipmap_index * 10 + 5)], clipmaps[int(clipmap_index * 10 + 6)])) / (float(clipmaps[int(clipmap_index * 10)]) * voxelgiResolution);
 | 
						|
		samplePos = samplePos * 0.5 + 0.5;
 | 
						|
 | 
						|
		if (any(notEqual(samplePos, clamp(samplePos, 0.0, 1.0)))) {
 | 
						|
			clipmap_index0++;
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		mipSample = sampleVoxel(voxels, p0, clipmaps, clipmap_index, step_dist, precomputed_direction, face_offset, direction_weight);
 | 
						|
 | 
						|
		if(clipmap_blend > 0.0 && clipmap_index < voxelgiClipmapCount - 1) {
 | 
						|
			vec4 mipSampleNext = sampleVoxel(voxels, p0, clipmaps, clipmap_index + 1.0, step_dist, precomputed_direction, face_offset, direction_weight);
 | 
						|
			mipSample = mix(mipSample, mipSampleNext, clipmap_blend);
 | 
						|
		}
 | 
						|
 | 
						|
		sampleCol += (1.0 - sampleCol.a) * mipSample;
 | 
						|
 | 
						|
		float stepSizeCurrent = step_size;
 | 
						|
		if (use_sdf) {
 | 
						|
			// half texel correction is applied to avoid sampling over current clipmap:
 | 
						|
			const vec3 half_texel = vec3(0.5) / voxelgiResolution;
 | 
						|
			vec3 tc0 = clamp(samplePos, half_texel, 1 - half_texel);
 | 
						|
			tc0.y = (tc0.y + clipmap_index) / voxelgiClipmapCount; // remap into clipmap
 | 
						|
			float sdf = textureLod(voxelsSDF, tc0, 0).r;
 | 
						|
			stepSizeCurrent = max(step_size, sdf - diam);
 | 
						|
		}
 | 
						|
		step_dist = diam * stepSizeCurrent;
 | 
						|
		dist += step_dist;
 | 
						|
	}
 | 
						|
    return sampleCol;
 | 
						|
}
 | 
						|
 | 
						|
vec4 traceDiffuse(const vec3 origin, const vec3 normal, const sampler3D voxels, const float clipmaps[voxelgiClipmapCount * 10]) {
 | 
						|
	float sum = 0.0;
 | 
						|
	vec4 amount = vec4(0.0);
 | 
						|
	mat3 TBN = makeTangentBasis(normal);
 | 
						|
	for (int i = 0; i < DIFFUSE_CONE_COUNT; ++i) {
 | 
						|
		vec3 coneDir = TBN * DIFFUSE_CONE_DIRECTIONS[i];
 | 
						|
		const float cosTheta = dot(normal, coneDir);
 | 
						|
		if (cosTheta <= 0)
 | 
						|
			continue;
 | 
						|
		int precomputed_direction = 6 + i;
 | 
						|
		amount += traceCone(voxels, dummy, origin, normal, coneDir, precomputed_direction, false, DIFFUSE_CONE_APERTURE, 1.0, clipmaps) * cosTheta;
 | 
						|
		sum += cosTheta;
 | 
						|
	}
 | 
						|
 | 
						|
	amount /= sum;
 | 
						|
	amount.rgb = max(amount.rgb, vec3(0.0));
 | 
						|
	amount.a = clamp(amount.a, 0.0, 1.0);
 | 
						|
 | 
						|
	return amount * voxelgiOcc;
 | 
						|
}
 | 
						|
 | 
						|
vec4 traceSpecular(const vec3 origin, const vec3 normal, const sampler3D voxels, const sampler3D voxelsSDF, const vec3 viewDir, const float roughness, const float clipmaps[voxelgiClipmapCount * 10], const vec2 pixel, const vec2 velocity) {
 | 
						|
	vec3 specularDir = reflect(normalize(-viewDir), normal);
 | 
						|
	vec3 P = origin + specularDir * ((BayerMatrix8[int(pixel.x + velocity.x) % 8][int(pixel.y + velocity.y) % 8] - 0.5)) * voxelgiStep;
 | 
						|
	vec4 amount = traceCone(voxels, voxelsSDF, P, normal, specularDir, 0, true, roughness, voxelgiStep, clipmaps);
 | 
						|
 | 
						|
	amount.rgb = max(vec3(0.0), amount.rgb);
 | 
						|
	amount.a = clamp(amount.a, 0.0, 1.0);
 | 
						|
 | 
						|
	return amount * voxelgiOcc;
 | 
						|
}
 | 
						|
 | 
						|
vec4 traceRefraction(const vec3 origin, const vec3 normal, sampler3D voxels, sampler3D voxelsSDF, const vec3 viewDir, const float ior, const float roughness, const float clipmaps[voxelgiClipmapCount * 10], const vec2 pixel, const vec2 velocity, const float opacity) {
 | 
						|
 	const float transmittance = 1.0 - opacity;
 | 
						|
 	vec3 refractionDir = refract(normalize(-viewDir), normal, 1.0 / ior);
 | 
						|
 	vec3 P = origin + refractionDir * (BayerMatrix8[int(pixel.x + velocity.x) % 8][int(pixel.y + velocity.y) % 8] - 0.5) * voxelgiStep;
 | 
						|
	vec4 amount =  transmittance * traceCone(voxels, voxelsSDF, P, normal, refractionDir, 0, true, roughness, voxelgiStep, clipmaps);
 | 
						|
 | 
						|
	amount.rgb = max(vec3(0.0), amount.rgb);
 | 
						|
	amount.a = clamp(amount.a, 0.0, 1.0);
 | 
						|
 | 
						|
	return amount * voxelgiOcc;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef _VoxelAOvar
 | 
						|
float traceConeAO(const sampler3D voxels, const vec3 origin, const vec3 n, const vec3 dir, const int precomputed_direction, const float aperture, const float step_size, const float clipmaps[voxelgiClipmapCount * 10]) {
 | 
						|
	float sampleCol = 0.0;
 | 
						|
	float voxelSize0 = float(clipmaps[0]) * 2.0;
 | 
						|
	float dist = voxelSize0;
 | 
						|
	float step_dist = dist;
 | 
						|
	vec3 samplePos;
 | 
						|
	vec3 start_pos = origin + n * voxelSize0;
 | 
						|
	int clipmap_index0 = 0;
 | 
						|
 | 
						|
	vec3 aniso_direction = -dir;
 | 
						|
	vec3 face_offset = vec3(
 | 
						|
		aniso_direction.x > 0.0 ? 0 : 1,
 | 
						|
		aniso_direction.y > 0.0 ? 2 : 3,
 | 
						|
		aniso_direction.z > 0.0 ? 4 : 5
 | 
						|
	) / (6 + DIFFUSE_CONE_COUNT);
 | 
						|
	vec3 direction_weight = abs(dir);
 | 
						|
 | 
						|
	float coneCoefficient = 2.0 * tan(aperture * 0.5);
 | 
						|
 | 
						|
    while (sampleCol < 1.0 && dist < MAX_DISTANCE && clipmap_index0 < voxelgiClipmapCount) {
 | 
						|
		float mipSample = 0.0;
 | 
						|
		float diam = max(voxelSize0, dist * coneCoefficient);
 | 
						|
        float lod = clamp(log2(diam / voxelSize0), clipmap_index0, voxelgiClipmapCount - 1);
 | 
						|
		float clipmap_index = floor(lod);
 | 
						|
		float clipmap_blend = fract(lod);
 | 
						|
		vec3 p0 = start_pos + dir * dist;
 | 
						|
 | 
						|
        samplePos = (p0 - vec3(clipmaps[int(clipmap_index * 10 + 4)], clipmaps[int(clipmap_index * 10 + 5)], clipmaps[int(clipmap_index * 10 + 6)])) / (float(clipmaps[int(clipmap_index * 10)]) * voxelgiResolution.x);
 | 
						|
		samplePos = samplePos * 0.5 + 0.5;
 | 
						|
 | 
						|
		if ((any(notEqual(clamp(samplePos, 0.0, 1.0), samplePos)))) {
 | 
						|
			clipmap_index0++;
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		mipSample = sampleVoxel(voxels, p0, clipmaps, clipmap_index, step_dist, precomputed_direction, face_offset, direction_weight);
 | 
						|
 | 
						|
		if(clipmap_blend > 0.0 && clipmap_index < voxelgiClipmapCount - 1) {
 | 
						|
			float mipSampleNext = sampleVoxel(voxels, p0, clipmaps, clipmap_index + 1.0, step_dist, precomputed_direction, face_offset, direction_weight);
 | 
						|
			mipSample = mix(mipSample, mipSampleNext, clipmap_blend);
 | 
						|
		}
 | 
						|
 | 
						|
		sampleCol += (1.0 - sampleCol) * mipSample;
 | 
						|
 | 
						|
		step_dist = diam * step_size;
 | 
						|
		dist += step_dist;
 | 
						|
	}
 | 
						|
    return sampleCol;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
float traceAO(const vec3 origin, const vec3 normal, const sampler3D voxels, const float clipmaps[voxelgiClipmapCount * 10]) {
 | 
						|
	float sum = 0.0;
 | 
						|
	float amount = 0.0;
 | 
						|
	for (int i = 0; i < DIFFUSE_CONE_COUNT; i++) {
 | 
						|
		vec3 coneDir = DIFFUSE_CONE_DIRECTIONS[i];
 | 
						|
		int precomputed_direction = 6 + i;
 | 
						|
		const float cosTheta = dot(normal, coneDir);
 | 
						|
		if (cosTheta <= 0)
 | 
						|
			continue;
 | 
						|
		amount += traceConeAO(voxels, origin, normal, coneDir, precomputed_direction, DIFFUSE_CONE_APERTURE, 1.0, clipmaps) * cosTheta;
 | 
						|
		sum += cosTheta;
 | 
						|
	}
 | 
						|
	amount /= sum;
 | 
						|
	amount = clamp(amount, 0.0, 1.0);
 | 
						|
	return amount * voxelgiOcc;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef _VoxelShadow
 | 
						|
float traceConeShadow(const sampler3D voxels, const sampler3D voxelsSDF, const vec3 origin, const vec3 n, const vec3 dir, const float aperture, const float step_size, const float clipmaps[voxelgiClipmapCount * 10]) {
 | 
						|
    float sampleCol = 0.0;
 | 
						|
	float voxelSize0 = float(clipmaps[0]) * 2.0;
 | 
						|
	float dist = voxelSize0;
 | 
						|
	float step_dist = dist;
 | 
						|
	vec3 samplePos;
 | 
						|
	vec3 start_pos = origin + n * voxelSize0;
 | 
						|
	int clipmap_index0 = 0;
 | 
						|
 | 
						|
	vec3 aniso_direction = -dir;
 | 
						|
	vec3 face_offset = vec3(
 | 
						|
		aniso_direction.x > 0.0 ? 0 : 1,
 | 
						|
		aniso_direction.y > 0.0 ? 2 : 3,
 | 
						|
		aniso_direction.z > 0.0 ? 4 : 5
 | 
						|
	) / (6 + DIFFUSE_CONE_COUNT);
 | 
						|
	vec3 direction_weight = abs(dir);
 | 
						|
	float coneCoefficient = 2.0 * tan(aperture * 0.5);
 | 
						|
 | 
						|
    while (sampleCol < 1.0 && dist < MAX_DISTANCE && clipmap_index0 < voxelgiClipmapCount) {
 | 
						|
		float mipSample = 0.0;
 | 
						|
		float diam = max(voxelSize0, dist * coneCoefficient);
 | 
						|
        float lod = clamp(log2(diam / voxelSize0), clipmap_index0, voxelgiClipmapCount - 1);
 | 
						|
		float clipmap_index = floor(lod);
 | 
						|
		float clipmap_blend = fract(lod);
 | 
						|
		vec3 p0 = start_pos + dir * dist;
 | 
						|
 | 
						|
        samplePos = (p0 - vec3(clipmaps[int(clipmap_index * 10 + 4)], clipmaps[int(clipmap_index * 10 + 5)], clipmaps[int(clipmap_index * 10 + 6)])) / (float(clipmaps[int(clipmap_index * 10)]) * voxelgiResolution);
 | 
						|
		samplePos = samplePos * 0.5 + 0.5;
 | 
						|
 | 
						|
		if ((any(notEqual(samplePos, clamp(samplePos, 0.0, 1.0))))) {
 | 
						|
			clipmap_index0++;
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		#ifdef _VoxelAOvar
 | 
						|
		mipSample = sampleVoxel(voxels, p0, clipmaps, clipmap_index, step_dist, 0, face_offset, direction_weight);
 | 
						|
		#else
 | 
						|
		mipSample = sampleVoxel(voxels, p0, clipmaps, clipmap_index, step_dist, 0, face_offset, direction_weight).a;
 | 
						|
		#endif
 | 
						|
 | 
						|
		if(clipmap_blend > 0.0 && clipmap_index < voxelgiClipmapCount - 1) {
 | 
						|
			#ifdef _VoxelAOvar
 | 
						|
			float mipSampleNext = sampleVoxel(voxels, p0, clipmaps, clipmap_index + 1.0, step_dist, 0, face_offset, direction_weight);
 | 
						|
			#else
 | 
						|
			float mipSampleNext = sampleVoxel(voxels, p0, clipmaps, clipmap_index + 1.0, step_dist, 0, face_offset, direction_weight).a;
 | 
						|
			#endif
 | 
						|
			mipSample = mix(mipSample, mipSampleNext, clipmap_blend);
 | 
						|
		}
 | 
						|
 | 
						|
		sampleCol += (1.0 - sampleCol) * mipSample;
 | 
						|
 | 
						|
		float stepSizeCurrent = step_size;
 | 
						|
 | 
						|
		// half texel correction is applied to avoid sampling over current clipmap:
 | 
						|
		const vec3 half_texel = vec3(0.5) / voxelgiResolution;
 | 
						|
		vec3 tc0 = clamp(samplePos, half_texel, 1 - half_texel);
 | 
						|
		tc0.y = (tc0.y + clipmap_index) / voxelgiClipmapCount; // remap into clipmap
 | 
						|
		float sdf = textureLod(voxelsSDF, tc0, 0.0).r;
 | 
						|
		stepSizeCurrent = max(step_size, sdf - diam);
 | 
						|
 | 
						|
		step_dist = diam * stepSizeCurrent;
 | 
						|
		dist += step_dist;
 | 
						|
	}
 | 
						|
	return sampleCol;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
float traceShadow(const vec3 origin, const vec3 normal, const sampler3D voxels, const sampler3D voxelsSDF, const vec3 dir, const float clipmaps[voxelgiClipmapCount * 10], const vec2 pixel, const vec2 velocity) {
 | 
						|
 	vec3 P = origin + dir * (BayerMatrix8[int(pixel.x + velocity.x) % 8][int(pixel.y + velocity.y) % 8] - 0.5) * voxelgiStep;
 | 
						|
	float amount = traceConeShadow(voxels, voxelsSDF, P, normal, dir, SHADOW_CONE_APERTURE, voxelgiStep, clipmaps);
 | 
						|
	amount = clamp(amount, 0.0, 1.0);
 | 
						|
	return amount * voxelgiOcc;
 | 
						|
}
 | 
						|
#endif
 | 
						|
#endif // _CONETRACE_GLSL_
 |