diff --git a/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/cull.glsl b/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/cull.glsl index 395979d5c..2817e4b69 100644 --- a/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/cull.glsl +++ b/common/src/backend/resources/assets/flywheel/flywheel/internal/indirect/cull.glsl @@ -87,38 +87,46 @@ bool _flw_isVisible(uint instanceIndex, uint modelIndex) { transformBoundingSphere(flw_view, center, radius); vec4 aabb; - if (projectSphere(center, radius, _flw_cullData.znear, _flw_cullData.P00, _flw_cullData.P11, aabb)) - { - float width = (aabb.z - aabb.x) * _flw_cullData.pyramidWidth; - float height = (aabb.w - aabb.y) * _flw_cullData.pyramidHeight; + if (projectSphere(center, radius, _flw_cullData.znear, _flw_cullData.P00, _flw_cullData.P11, aabb)) { + vec2 size = aabb.zw - aabb.xy; - int level = clamp(int(ceil(log2(max(width, height)))), 0, _flw_cullData.pyramidLevels); + vec2 sizeInPixels = size * flw_viewportSize; - ivec2 levelSize = textureSize(_flw_depthPyramid, level); + // Cull objects that are less than a pixel in size. Could probably make this configurable. + isVisible = isVisible && any(greaterThan(sizeInPixels, vec2(1.))); - ivec4 levelSizePair = ivec4(levelSize, levelSize); + if (isVisible) { + float width = size.x * _flw_cullData.pyramidWidth; + float height = size.y * _flw_cullData.pyramidHeight; - ivec4 bounds = ivec4(aabb * vec4(levelSizePair)); + int level = clamp(int(ceil(log2(max(width, height)))), 0, _flw_cullData.pyramidLevels); - // Clamp to the texture bounds. - // Since we're not going through a sampler out of bounds texel fetches will return 0. - bounds = clamp(bounds, ivec4(0), levelSizePair); + ivec2 levelSize = textureSize(_flw_depthPyramid, level); - float depth01 = texelFetch(_flw_depthPyramid, bounds.xw, level).r; - float depth11 = texelFetch(_flw_depthPyramid, bounds.zw, level).r; - float depth10 = texelFetch(_flw_depthPyramid, bounds.zy, level).r; - float depth00 = texelFetch(_flw_depthPyramid, bounds.xy, level).r; + ivec4 levelSizePair = ivec4(levelSize, levelSize); - float depth; - if (_flw_cullData.useMin == 0) { - depth = max(max(depth00, depth01), max(depth10, depth11)); - } else { - depth = min(min(depth00, depth01), min(depth10, depth11)); - } + ivec4 bounds = ivec4(aabb * vec4(levelSizePair)); + + // Clamp to the texture bounds. + // Since we're not going through a sampler out of bounds texel fetches will return 0. + bounds = clamp(bounds, ivec4(0), levelSizePair); + + float depth01 = texelFetch(_flw_depthPyramid, bounds.xw, level).r; + float depth11 = texelFetch(_flw_depthPyramid, bounds.zw, level).r; + float depth10 = texelFetch(_flw_depthPyramid, bounds.zy, level).r; + float depth00 = texelFetch(_flw_depthPyramid, bounds.xy, level).r; - float depthSphere = 1. + _flw_cullData.znear / (center.z + radius); + float depth; + if (_flw_cullData.useMin == 0) { + depth = max(max(depth00, depth01), max(depth10, depth11)); + } else { + depth = min(min(depth00, depth01), min(depth10, depth11)); + } - isVisible = isVisible && depthSphere <= depth; + float depthSphere = 1. + _flw_cullData.znear / (center.z + radius); + + isVisible = isVisible && depthSphere <= depth; + } } } diff --git a/common/src/lib/java/dev/engine_room/flywheel/lib/visual/text/TextVisual.java b/common/src/lib/java/dev/engine_room/flywheel/lib/visual/text/TextVisual.java index 677a60ab2..14b72b742 100644 --- a/common/src/lib/java/dev/engine_room/flywheel/lib/visual/text/TextVisual.java +++ b/common/src/lib/java/dev/engine_room/flywheel/lib/visual/text/TextVisual.java @@ -308,9 +308,8 @@ private record GlyphMesh(float glyphWidth, float glyphHeight, Vector2fc[] offset private static final float[] X = new float[] { 0, 0, 1, 1 }; private static final float[] Y = new float[] { 0, 1, 1, 0 }; - // FIXME: what is the actual bounding sphere?? public GlyphMesh(float glyphWidth, float glyphHeight, Vector2fc[] offsets) { - this(glyphWidth, glyphHeight, offsets, new Vector4f(0, 0, 0, Math.max(glyphWidth, glyphHeight) * 2 * Mth.SQRT_OF_TWO)); + this(glyphWidth, glyphHeight, offsets, boundingSphere(glyphWidth, glyphHeight, offsets)); } @Override @@ -344,6 +343,36 @@ public void write(MutableVertexList vertexList) { public Vector4fc boundingSphere() { return boundingSphere; } + + private static Vector4fc boundingSphere(float glyphWidth, float glyphHeight, Vector2fc[] offsets) { + if (offsets.length == 0) { + return new Vector4f(0, 0, 0, 0); + } + + float minX = Float.POSITIVE_INFINITY; + float minY = Float.POSITIVE_INFINITY; + float maxX = Float.NEGATIVE_INFINITY; + float maxY = Float.NEGATIVE_INFINITY; + for (Vector2fc offset : offsets) { + for (int j = 0; j < 4; j++) { + var x = offset.x() + (glyphWidth * X[j]); + var y = offset.y() + (glyphHeight * Y[j]); + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + } + } + + float x = (minX + maxX) / 2; + float y = (minY + maxY) / 2; + + float sizeX = maxX - minX; + float sizeY = maxY - minY; + float maxSize = Math.max(sizeX, sizeY); + + return new Vector4f(x, y, 0, Mth.SQRT_OF_TWO * maxSize / 2); + } } private record GlyphEffectMesh() implements QuadMesh {