20/20 vision

- Calculate actual bounding sphere for glyph meshes
- Cull objects that are less than a pixel on the screen
This commit is contained in:
Jozufozu 2024-10-05 21:54:18 -07:00
parent 39b2508d02
commit 47b6648681
2 changed files with 63 additions and 26 deletions

View file

@ -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 depth;
if (_flw_cullData.useMin == 0) {
depth = max(max(depth00, depth01), max(depth10, depth11));
} else {
depth = min(min(depth00, depth01), min(depth10, depth11));
}
float depthSphere = 1. + _flw_cullData.znear / (center.z + radius);
isVisible = isVisible && depthSphere <= depth;
}
float depthSphere = 1. + _flw_cullData.znear / (center.z + radius);
isVisible = isVisible && depthSphere <= depth;
}
}

View file

@ -308,9 +308,8 @@ public final class TextVisual {
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 final class TextVisual {
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 {