From 41b2f443d939a456e7118fa3276e31235cbe7325 Mon Sep 17 00:00:00 2001 From: NULL511 Date: Tue, 18 Jun 2024 22:23:29 -0400 Subject: [PATCH] faster floodfill sampling in rgb not hsv --- shaders/dimensions/shadowcomp.csh | 193 +++++++++++++++--------------- shaders/lib/lpv_render.glsl | 48 ++------ shaders/lib/voxel_write.glsl | 2 - 3 files changed, 108 insertions(+), 135 deletions(-) diff --git a/shaders/dimensions/shadowcomp.csh b/shaders/dimensions/shadowcomp.csh index a415a99..730c7eb 100644 --- a/shaders/dimensions/shadowcomp.csh +++ b/shaders/dimensions/shadowcomp.csh @@ -11,92 +11,87 @@ layout (local_size_x = 8, local_size_y = 8, local_size_z = 8) in; #endif #ifdef IS_LPV_ENABLED - shared vec4 lpvSharedData[10*10*10]; - shared uint voxelSharedData[10*10*10]; + shared vec4 lpvSharedData[10*10*10]; + shared uint voxelSharedData[10*10*10]; - const vec2 LpvBlockSkyFalloff = vec2(0.96, 0.96); - const ivec3 lpvFlatten = ivec3(1, 10, 100); + const vec2 LpvBlockSkyFalloff = vec2(0.96, 0.96); + const ivec3 lpvFlatten = ivec3(1, 10, 100); - uniform int frameCounter; - uniform vec3 cameraPosition; - uniform vec3 previousCameraPosition; + uniform int frameCounter; + uniform vec3 cameraPosition; + uniform vec3 previousCameraPosition; - #include "/lib/hsv.glsl" - #include "/lib/util.glsl" - #include "/lib/blocks.glsl" - #include "/lib/lpv_common.glsl" - #include "/lib/lpv_blocks.glsl" - #include "/lib/lpv_buffer.glsl" - #include "/lib/voxel_common.glsl" + #include "/lib/hsv.glsl" + #include "/lib/util.glsl" + #include "/lib/blocks.glsl" + #include "/lib/lpv_common.glsl" + #include "/lib/lpv_blocks.glsl" + #include "/lib/lpv_buffer.glsl" + #include "/lib/voxel_common.glsl" - int sumOf(ivec3 vec) {return vec.x + vec.y + vec.z;} + int sumOf(ivec3 vec) {return vec.x + vec.y + vec.z;} - vec3 Lpv_RgbToHsv(const in vec3 lightColor, const in float lightRange) { - vec3 lightValue = RgbToHsv(lightColor); - lightValue.b = lightRange / LpvBlockSkyRange.x; - return lightValue; - } + int getSharedIndex(ivec3 pos) { + return sumOf(pos * lpvFlatten); + } - vec4 GetLpvValue(in ivec3 texCoord) { - if (clamp(texCoord, ivec3(0), ivec3(LpvSize) - 1) != texCoord) return vec4(0.0); + vec4 GetLpvValue(in ivec3 texCoord) { + if (clamp(texCoord, ivec3(0), ivec3(LpvSize) - 1) != texCoord) return vec4(0.0); - vec4 lpvSample = (frameCounter % 2) == 0 - ? imageLoad(imgLpv2, texCoord) - : imageLoad(imgLpv1, texCoord); + vec4 lpvSample = (frameCounter % 2) == 0 + ? imageLoad(imgLpv2, texCoord) + : imageLoad(imgLpv1, texCoord); - lpvSample.ba = exp2(lpvSample.ba * LpvBlockSkyRange) - 1.0; - lpvSample.rgb = HsvToRgb(lpvSample.rgb); + vec4 hsv_sky = vec4(RgbToHsv(lpvSample.rgb), lpvSample.a); + hsv_sky.zw = exp2(hsv_sky.zw * LpvBlockSkyRange) - 1.0; + lpvSample = vec4(HsvToRgb(hsv_sky.xyz), hsv_sky.w); - return lpvSample; - } + return lpvSample; + } + + uint GetVoxelBlock(const in ivec3 voxelPos) { + if (clamp(voxelPos, ivec3(0), ivec3(VoxelSize3-1u)) != voxelPos) + return BLOCK_EMPTY; + + return imageLoad(imgVoxelMask, voxelPos).r; + } - int getSharedIndex(ivec3 pos) { - return sumOf(pos * lpvFlatten); - } + void PopulateSharedIndex(const in ivec3 imgCoordOffset, const in ivec3 workGroupOffset, const in uint i) { + ivec3 pos = workGroupOffset + ivec3(i / lpvFlatten) % 10; - vec4 sampleShared(ivec3 pos, int mask_index) { - int shared_index = getSharedIndex(pos + 1); + lpvSharedData[i] = GetLpvValue(imgCoordOffset + pos); + voxelSharedData[i] = GetVoxelBlock(pos); + } - float mixWeight = 1.0; - uint mask = 0xFFFF; - uint blockId = voxelSharedData[shared_index]; - - if (blockId > 0 && blockId != BLOCK_EMPTY) { - uvec2 blockData = imageLoad(imgBlockData, int(blockId)).rg; - mask = (blockData.g >> 24) & 0xFFFF; - } + vec4 sampleShared(ivec3 pos, int mask_index) { + int shared_index = getSharedIndex(pos + 1); - return lpvSharedData[shared_index] * ((mask >> mask_index) & 1u); - } + float mixWeight = 1.0; + uint mask = 0xFFFF; + uint blockId = voxelSharedData[shared_index]; + + if (blockId > 0 && blockId != BLOCK_EMPTY) { + uvec2 blockData = imageLoad(imgBlockData, int(blockId)).rg; + mask = (blockData.g >> 24) & 0xFFFF; + } - vec4 mixNeighbours(const in ivec3 fragCoord, const in uint mask) { - uvec3 m1 = (uvec3(mask) >> uvec3(0, 2, 4)) & uvec3(1u); - uvec3 m2 = (uvec3(mask) >> uvec3(1, 3, 5)) & uvec3(1u); + return lpvSharedData[shared_index] * ((mask >> mask_index) & 1u); + } - vec4 sX1 = sampleShared(fragCoord + ivec3(-1, 0, 0), 1) * m1.x; - vec4 sX2 = sampleShared(fragCoord + ivec3( 1, 0, 0), 0) * m2.x; - vec4 sY1 = sampleShared(fragCoord + ivec3( 0, -1, 0), 3) * m1.y; - vec4 sY2 = sampleShared(fragCoord + ivec3( 0, 1, 0), 2) * m2.y; - vec4 sZ1 = sampleShared(fragCoord + ivec3( 0, 0, -1), 5) * m1.z; - vec4 sZ2 = sampleShared(fragCoord + ivec3( 0, 0, 1), 4) * m2.z; + vec4 mixNeighbours(const in ivec3 fragCoord, const in uint mask) { + uvec3 m1 = (uvec3(mask) >> uvec3(0, 2, 4)) & uvec3(1u); + uvec3 m2 = (uvec3(mask) >> uvec3(1, 3, 5)) & uvec3(1u); - const vec4 avgFalloff = (1.0/6.0) * LpvBlockSkyFalloff.xxxy; - return (sX1 + sX2 + sY1 + sY2 + sZ1 + sZ2) * avgFalloff; - } - - uint GetVoxelBlock(const in ivec3 voxelPos) { - if (clamp(voxelPos, ivec3(0), ivec3(VoxelSize3-1u)) != voxelPos) - return BLOCK_EMPTY; - - return imageLoad(imgVoxelMask, voxelPos).r; - } + vec4 sX1 = sampleShared(fragCoord + ivec3(-1, 0, 0), 1) * m1.x; + vec4 sX2 = sampleShared(fragCoord + ivec3( 1, 0, 0), 0) * m2.x; + vec4 sY1 = sampleShared(fragCoord + ivec3( 0, -1, 0), 3) * m1.y; + vec4 sY2 = sampleShared(fragCoord + ivec3( 0, 1, 0), 2) * m2.y; + vec4 sZ1 = sampleShared(fragCoord + ivec3( 0, 0, -1), 5) * m1.z; + vec4 sZ2 = sampleShared(fragCoord + ivec3( 0, 0, 1), 4) * m2.z; - void PopulateSharedIndex(const in ivec3 imgCoordOffset, const in ivec3 workGroupOffset, const in uint i) { - ivec3 pos = workGroupOffset + ivec3(i / lpvFlatten) % 10; - - lpvSharedData[i] = GetLpvValue(imgCoordOffset + pos); - voxelSharedData[i] = GetVoxelBlock(pos); - } + const vec4 avgFalloff = (1.0/6.0) * LpvBlockSkyFalloff.xxxy; + return (sX1 + sX2 + sY1 + sY2 + sZ1 + sZ2) * avgFalloff; + } #endif @@ -107,53 +102,61 @@ void main() { uvec3 chunkPos = gl_WorkGroupID * gl_WorkGroupSize; if (any(greaterThanEqual(chunkPos, LpvSize3))) return; - uint i = uint(gl_LocalInvocationIndex) * 2u; - if (i < 1000u) { - ivec3 imgCoordOffset = ivec3(floor(cameraPosition) - floor(previousCameraPosition)); - ivec3 workGroupOffset = ivec3(gl_WorkGroupID * gl_WorkGroupSize) - 1; + // Pre-populate shared-memory buffer for improved sampling performance + uint i = uint(gl_LocalInvocationIndex) * 2u; + if (i < 1000u) { + ivec3 imgCoordOffset = ivec3(floor(cameraPosition) - floor(previousCameraPosition)); + ivec3 workGroupOffset = ivec3(gl_WorkGroupID * gl_WorkGroupSize) - 1; - PopulateSharedIndex(imgCoordOffset, workGroupOffset, i); - PopulateSharedIndex(imgCoordOffset, workGroupOffset, i + 1u); - } + PopulateSharedIndex(imgCoordOffset, workGroupOffset, i); + PopulateSharedIndex(imgCoordOffset, workGroupOffset, i + 1u); + } barrier(); + // Exit early if outside LPV buffer size ivec3 imgCoord = ivec3(gl_GlobalInvocationID); if (any(greaterThanEqual(imgCoord, LpvSize3))) return; - uint blockId = voxelSharedData[getSharedIndex(ivec3(gl_LocalInvocationID) + 1)]; vec4 lightValue = vec4(0.0); - vec3 tintColor = vec3(1.0); + vec3 lightColor = vec3(0.0); + vec3 tintColor = vec3(1.0); + float lightRange = 0.0; uint mixMask = 0xFFFF; + + // Decode light data for current voxel + uint blockId = voxelSharedData[getSharedIndex(ivec3(gl_LocalInvocationID) + 1)]; if (blockId > 0u) { - tintColor = vec3(0.0); - - uvec2 blockData = imageLoad(imgBlockData, int(blockId)).rg; + uvec2 blockData = imageLoad(imgBlockData, int(blockId)).rg; vec4 lightColorRange = unpackUnorm4x8(blockData.r); + lightColor = srgbToLinear(lightColorRange.rgb); + lightRange = lightColorRange.a * 255.0; vec4 tintColorMask = unpackUnorm4x8(blockData.g); - tintColor = srgbToLinear(tintColorMask.rgb); - mixMask = (blockData.g >> 24) & 0xFFFF; - - vec3 lightColor = srgbToLinear(lightColorRange.rgb); - float lightRange = lightColorRange.a * 255.0; - - if (lightRange > 0.0) { - lightValue.rgb = Lpv_RgbToHsv(lightColor, lightRange); - lightValue.ba = exp2(lightValue.ba * LpvBlockSkyRange) - 1.0; - lightValue.rgb = HsvToRgb(lightValue.rgb); - } + tintColor = srgbToLinear(tintColorMask.rgb); + mixMask = (blockData.g >> 24) & 0xFFFF; } - + + // Mix neighbor voxel light values if (any(greaterThan(tintColor, vec3(0.0)))) { vec4 lightMixed = mixNeighbours(ivec3(gl_LocalInvocationID), mixMask); lightMixed.rgb *= tintColor; lightValue += lightMixed; } - lightValue.rgb = RgbToHsv(lightValue.rgb); - lightValue.ba = log2(lightValue.ba + 1.0) / LpvBlockSkyRange; + // Add light for current voxel + if (lightRange > 0.0) { + vec3 hsv = RgbToHsv(lightColor); + hsv.z = exp2(lightRange) - 1.0; + lightValue.rgb += HsvToRgb(hsv); + } + // Convert back to linear RGB space + vec4 hsv_sky = vec4(RgbToHsv(lightValue.rgb), lightValue.a); + hsv_sky.zw = log2(hsv_sky.zw + 1.0) / LpvBlockSkyRange; + lightValue = vec4(HsvToRgb(hsv_sky.xyz), hsv_sky.w); + + // Store final value if (frameCounter % 2 == 0) imageStore(imgLpv1, imgCoord, lightValue); else diff --git a/shaders/lib/lpv_render.glsl b/shaders/lib/lpv_render.glsl index 0ae24ab..c682f93 100644 --- a/shaders/lib/lpv_render.glsl +++ b/shaders/lib/lpv_render.glsl @@ -1,51 +1,23 @@ -// LPV falloff curve -const float LpvBlockPower = 4.0; - // LPV block brightness scale const float LpvBlockBrightness = 2.0; -float lpvCurve(float values){ - // return pow(values, LpvBlockPower) ; - return pow(1.0-sqrt(1.0-values),2.0); - // return values; -} -vec4 SampleLpvNearest(const in ivec3 lpvPos) { - vec4 lpvSample = (frameCounter % 2) == 0 - ? texelFetch(texLpv1, lpvPos, 0) - : texelFetch(texLpv2, lpvPos, 0); - - lpvSample.b = lpvCurve(lpvSample.b) * LpvBlockSkyRange.x; - lpvSample.rgb = HsvToRgb(lpvSample.rgb); - - return lpvSample; +float lpvCurve(float values) { + return pow(1.0 - sqrt(1.0-values), 2.0); } vec4 SampleLpvLinear(const in vec3 lpvPos) { - vec3 pos = lpvPos - 0.5; - ivec3 lpvCoord = ivec3(floor(pos)); - vec3 lpvF = fract(pos); + vec3 texcoord = lpvPos / LpvSize3; - vec4 sample_x1y1z1 = SampleLpvNearest(lpvCoord + ivec3(0, 0, 0)); - vec4 sample_x2y1z1 = SampleLpvNearest(lpvCoord + ivec3(1, 0, 0)); - vec4 sample_x1y2z1 = SampleLpvNearest(lpvCoord + ivec3(0, 1, 0)); - vec4 sample_x2y2z1 = SampleLpvNearest(lpvCoord + ivec3(1, 1, 0)); + vec4 lpvSample = (frameCounter % 2) == 0 + ? textureLod(texLpv1, texcoord, 0) + : textureLod(texLpv2, texcoord, 0); - vec4 sample_x1y1z2 = SampleLpvNearest(lpvCoord + ivec3(0, 0, 1)); - vec4 sample_x2y1z2 = SampleLpvNearest(lpvCoord + ivec3(1, 0, 1)); - vec4 sample_x1y2z2 = SampleLpvNearest(lpvCoord + ivec3(0, 1, 1)); - vec4 sample_x2y2z2 = SampleLpvNearest(lpvCoord + ivec3(1, 1, 1)); + vec3 hsv = RgbToHsv(lpvSample.rgb); + hsv.z = lpvCurve(hsv.b) * LpvBlockSkyRange.x; + lpvSample.rgb = HsvToRgb(hsv); - vec4 sample_y1z1 = mix(sample_x1y1z1, sample_x2y1z1, lpvF.x); - vec4 sample_y2z1 = mix(sample_x1y2z1, sample_x2y2z1, lpvF.x); - - vec4 sample_y1z2 = mix(sample_x1y1z2, sample_x2y1z2, lpvF.x); - vec4 sample_y2z2 = mix(sample_x1y2z2, sample_x2y2z2, lpvF.x); - - vec4 sample_z1 = mix(sample_y1z1, sample_y2z1, lpvF.y); - vec4 sample_z2 = mix(sample_y1z2, sample_y2z2, lpvF.y); - - return mix(sample_z1, sample_z2, lpvF.z); + return lpvSample; } vec3 GetLpvBlockLight(const in vec4 lpvSample) { diff --git a/shaders/lib/voxel_write.glsl b/shaders/lib/voxel_write.glsl index e410804..06c137f 100644 --- a/shaders/lib/voxel_write.glsl +++ b/shaders/lib/voxel_write.glsl @@ -33,8 +33,6 @@ void PopulateShadowVoxel(const in vec3 playerPos) { if ( ((renderStage == MC_RENDER_STAGE_ENTITIES && (currentRenderedItemId > 0 || entityId > 0)) || renderStage == MC_RENDER_STAGE_BLOCK_ENTITIES) ) { - voxelId = uint(mc_Entity.x + 0.5); - if (renderStage == MC_RENDER_STAGE_BLOCK_ENTITIES) { if (blockEntityId > 0 && blockEntityId < 500) voxelId = uint(blockEntityId);