better billboarding

This commit is contained in:
ecker 2026-05-31 01:16:48 -05:00
parent 90758175ca
commit a6875adf13
8 changed files with 68 additions and 54 deletions

View File

@ -355,7 +355,7 @@
"contacts": false,
"constraints": true,
"rays": false,
"depthTest": true
"depthTest": false
},
"fixed step": true,
"substeps": 4,

View File

@ -9,17 +9,25 @@ layout (constant_id = 0) const uint PASSES = 1;
layout (location = 0) in vec3 inPos;
layout (location = 1) in vec2 inUv;
layout (location = 2) in vec4 inColor;
layout (location = 3) in vec2 inOffset;
layout( push_constant ) uniform PushBlock {
uint pass;
uint draw;
} PushConstant;
layout (binding = 0) uniform Camera {
Viewport viewport[PASSES];
} camera;
layout (location = 0) out vec2 outUv;
layout (location = 1) out vec4 outColor;
void main() {
outUv = inUv;
outColor = inColor;
gl_Position = vec4(inPos.xyz, 1.0);
}
vec4 clipPos = camera.viewport[PushConstant.pass].projection * camera.viewport[PushConstant.pass].view * vec4(inPos.xyz, 1.0);
//clipPos.xy += inOffset * (clipPos.w / max(clipPos.w, 1.0));
clipPos.xy += inOffset * min(clipPos.w, 1.0);
gl_Position = clipPos;}

View File

@ -1,6 +1,7 @@
layout (constant_id = 0) const uint PASSES = 6;
layout (location = 0) in vec2 inPos;
layout (location = 1) in vec2 inUv;
layout (location = 3) in vec2 inOffset;
#include "./gui.h"
@ -33,10 +34,16 @@ layout (location = 1) out flat Gui outGui;
void main() {
outUv = inUv;
outGui = ubo.gui;
#if GLYPH
outVertexID = gl_VertexIndex;
outGlyph = uboGlyph.glyph;
#endif
gl_Position = ubo.matrices.model[PushConstant.pass] * vec4(inPos.xy, ubo.gui.depth, 1.0);
gl_Position = ubo.matrices.model[PushConstant.pass] * vec4(inPos.xy + inOffset.xy, ubo.gui.depth, 1.0);
/*
vec4 clipPos = ubo.matrices.model[PushConstant.pass] * vec4(inPos.xy, ubo.gui.depth, 1.0);
clipPos.xy += inOffset * clipPos.w;
gl_Position = clipPos;
*/
}

View File

@ -9,11 +9,12 @@
namespace pod {
struct GlyphBox {
struct {
float x, y, w, h, z;
} box;
float x = 0, y = 0, w = 0, h = 0, z = 0;
} box = {};
pod::Vector4f color;
uint64_t code;
pod::Vector4f color = { 1, 1, 1, 1 };
pod::Vector3f anchor = { 0, 0, 0 };
uint64_t code = 0;
};
struct TextToken {
uf::stl::string text;

View File

@ -28,7 +28,7 @@
#define EXT_COLOR_FLOATS 1
namespace {
struct Mesh {
struct GuiVertex {
pod::Vector3f position;
pod::Vector2f uv;
@ -37,6 +37,7 @@ namespace {
#else
pod::Vector4b color;
#endif
pod::Vector2f offset;
static uf::stl::vector<uf::renderer::AttributeDescriptor> descriptor;
};
@ -58,14 +59,15 @@ namespace {
};
}
UF_VERTEX_DESCRIPTOR(Mesh,
UF_VERTEX_DESCRIPTION(Mesh, R32G32B32_SFLOAT, position)
UF_VERTEX_DESCRIPTION(Mesh, R32G32_SFLOAT, uv)
UF_VERTEX_DESCRIPTOR(GuiVertex,
UF_VERTEX_DESCRIPTION(GuiVertex, R32G32B32_SFLOAT, position)
UF_VERTEX_DESCRIPTION(GuiVertex, R32G32_SFLOAT, uv)
#if EXT_COLOR_FLOATS
UF_VERTEX_DESCRIPTION(Mesh, R32G32B32A32_SFLOAT, color)
UF_VERTEX_DESCRIPTION(GuiVertex, R32G32B32A32_SFLOAT, color)
#else
UF_VERTEX_DESCRIPTION(Mesh, R8G8B8A8_UNORM, color)
UF_VERTEX_DESCRIPTION(GuiVertex, R8G8B8A8_UNORM, color)
#endif
UF_VERTEX_DESCRIPTION(GuiVertex, R32G32_SFLOAT, offset)
)
namespace {
@ -87,15 +89,15 @@ namespace {
}
uf::Mesh& generateMesh( uf::Mesh& mesh, const pod::Vector4f& color, const pod::Vector2f& center ) {
mesh.bind<::Mesh, uint16_t>();
mesh.insertVertices<::Mesh>({
{ pod::Vector3f{-1.0f, 1.0f, 0.0f} - center, pod::Vector2f{0.0f, 0.0f}, color },
{ pod::Vector3f{-1.0f, -1.0f, 0.0f} - center, pod::Vector2f{0.0f, 1.0f}, color },
{ pod::Vector3f{ 1.0f, -1.0f, 0.0f} - center, pod::Vector2f{1.0f, 1.0f}, color },
mesh.bind<::GuiVertex, uint16_t>();
mesh.insertVertices<::GuiVertex>({
{ pod::Vector3f{-1.0f, 1.0f, 0.0f}, pod::Vector2f{0.0f, 0.0f}, color, center },
{ pod::Vector3f{-1.0f, -1.0f, 0.0f}, pod::Vector2f{0.0f, 1.0f}, color, center },
{ pod::Vector3f{ 1.0f, -1.0f, 0.0f}, pod::Vector2f{1.0f, 1.0f}, color, center },
{ pod::Vector3f{ 1.0f, -1.0f, 0.0f} - center, pod::Vector2f{1.0f, 1.0f}, color },
{ pod::Vector3f{ 1.0f, 1.0f, 0.0f} - center, pod::Vector2f{1.0f, 0.0f}, color },
{ pod::Vector3f{-1.0f, 1.0f, 0.0f} - center, pod::Vector2f{0.0f, 0.0f}, color },
{ pod::Vector3f{ 1.0f, -1.0f, 0.0f}, pod::Vector2f{1.0f, 1.0f}, color, center },
{ pod::Vector3f{ 1.0f, 1.0f, 0.0f}, pod::Vector2f{1.0f, 0.0f}, color, center },
{ pod::Vector3f{-1.0f, 1.0f, 0.0f}, pod::Vector2f{0.0f, 0.0f}, color, center },
});
mesh.insertIndices<uint16_t>({
0, 1, 2, 3, 4, 5
@ -551,14 +553,20 @@ void ext::GuiBehavior::tick( uf::Object& self ) {
pod::Vector2f min = { std::numeric_limits<float>::max(), std::numeric_limits<float>::max() };
pod::Vector2f max = { -std::numeric_limits<float>::max(), -std::numeric_limits<float>::max() };
uf::Mesh::Attribute vertexAttribute;
for ( auto& attribute : mesh.vertex.attributes ) if ( attribute.descriptor.name == "position" ) { vertexAttribute = attribute; break; }
UF_ASSERT( vertexAttribute.descriptor.name == "position" );
uf::Mesh::Attribute positionAttribute;
uf::Mesh::Attribute offsetAttribute;
for ( auto& attribute : mesh.vertex.attributes ) {
if ( attribute.descriptor.name == "position" ) positionAttribute = attribute;
if ( attribute.descriptor.name == "offset" ) offsetAttribute = attribute;
}
UF_ASSERT( positionAttribute.descriptor.name == "position" );
for ( auto i = 0; i < mesh.vertex.count; ++i ) {
float* p = (float*) (static_cast<uint8_t*>(vertexAttribute.pointer) + i * vertexAttribute.stride );
float* p = (float*) (static_cast<uint8_t*>(positionAttribute.pointer) + i * positionAttribute.stride );
float* o = (float*) (static_cast<uint8_t*>(offsetAttribute.pointer) + i * offsetAttribute.stride );
// pod::Vector4f position = { p[0], p[1], p[2], 1 };
pod::Vector4f position = { p[0], p[1], 0, 1 };
pod::Vector4f position = { p[0] + o[0], p[1] + o[1], 0, 1 };
pod::Vector4f translated = uf::matrix::multiply<float>( model, position );
min.x = std::min( min.x, translated.x );
max.x = std::max( max.x, translated.x );

View File

@ -40,7 +40,7 @@ namespace impl {
pod::GlyphSettings textSettings = {
.alignment = "center",
.font = "FragmentMono.ttf",
.size = 24,
.size = 48,
.sdf = false,
};
}
@ -287,7 +287,7 @@ void uf::debug::drawTexts( float dt ) {
auto& scene = uf::scene::getCurrentScene();
auto& controller = scene.getController();
auto& camera = scene.getCamera( controller );
auto& transform = camera.getTransform();
auto transform = uf::transform::flatten( camera.getTransform() );
uf::stl::vector<pod::GlyphBox> textLayout;
// pre-init with ASCII characters
@ -309,27 +309,8 @@ void uf::debug::drawTexts( float dt ) {
for ( auto& text : texts ) {
auto tokens = uf::glyph::parseTextTokens( text.string, text.color );
auto layout = uf::glyph::calculateLayout( tokens, impl::textSettings );
auto world = pod::Vector4f{ text.position.x, text.position.y, text.position.z, 1.0f };
auto view = camera.getProjection() * camera.getView();
auto clip = uf::matrix::multiply( view, world );
if ( clip.w <= 0.0f ) continue;
auto ndc = pod::Vector3f{ clip.x, clip.y, clip.z } / clip.w;
float scale = 2.0f / clip.w;
if ( ndc.z < 0.0f || ndc.z > 1.0f ) continue;
for ( auto& g : layout ) {
g.box.x = g.box.x * scale + ndc.x;
g.box.y = g.box.y * scale + ndc.y;
g.box.z = ndc.z;
g.box.w *= scale;
g.box.h *= scale;
if ( (g.box.x + g.box.w < -1.0f) || (g.box.x > 1.0f) || (g.box.y + g.box.h < -1.0f) || (g.box.y > 1.0f) ) continue;
g.anchor += text.position;
textLayout.emplace_back( g );
}
}

View File

@ -56,7 +56,7 @@ void impl::drawBody( const pod::PhysicsBody& body ) {
auto& projection = camera.getProjection();
auto fov = std::atan(1.0f / fabs(projection(1,1)));
auto angleThreshold = std::cos(fov * 1.5f);
auto viewThresholdSq = std::pow(5, 2);
auto viewThresholdSq = std::pow(10, 2);
// continuously pick the closest point on the AABB
auto position = impl::closestPointOnAABB( cameraTransform.position, bounds );

View File

@ -28,6 +28,8 @@ namespace {
pod::Vector4b color;
#endif
pod::Vector3f offset;
static uf::stl::vector<uf::renderer::AttributeDescriptor> descriptor;
};
}
@ -40,6 +42,7 @@ UF_VERTEX_DESCRIPTOR(GlyphVertex,
#else
UF_VERTEX_DESCRIPTION(GlyphVertex, R8G8B8A8_UNORM, color)
#endif
UF_VERTEX_DESCRIPTION(GlyphVertex, R32G32_SFLOAT, offset)
)
namespace {
@ -216,6 +219,7 @@ uf::stl::vector<pod::GlyphBox> uf::glyph::calculateLayout( const uf::stl::vector
.z = 0,
},
.color = token.color,
.anchor = anchor,
.code = c,
});
@ -315,10 +319,15 @@ void uf::glyph::generateMesh( const uf::stl::vector<pod::GlyphBox>& layout, cons
indices.insert( indices.end(), { idx, idx + 1, idx + 2, idx, idx + 2, idx + 3 });
// insert vertices
vertices.emplace_back(::GlyphVertex{pod::Vector3f{ g.box.x, g.box.y + g.box.h, g.box.z }, atlas.mapUv(pod::Vector2f{ 0.0f, 0.0f }, hash), color});
vertices.emplace_back(::GlyphVertex{pod::Vector3f{ g.box.x, g.box.y, g.box.z }, atlas.mapUv(pod::Vector2f{ 0.0f, 1.0f }, hash), color});
vertices.emplace_back(::GlyphVertex{pod::Vector3f{ g.box.x + g.box.w, g.box.y, g.box.z }, atlas.mapUv(pod::Vector2f{ 1.0f, 1.0f }, hash), color});
vertices.emplace_back(::GlyphVertex{pod::Vector3f{ g.box.x + g.box.w, g.box.y + g.box.h, g.box.z }, atlas.mapUv(pod::Vector2f{ 1.0f, 0.0f }, hash), color});
auto p0 = pod::Vector2f{ g.box.x, g.box.y + g.box.h };
auto p1 = pod::Vector2f{ g.box.x, g.box.y };
auto p2 = pod::Vector2f{ g.box.x + g.box.w, g.box.y };
auto p3 = pod::Vector2f{ g.box.x + g.box.w, g.box.y + g.box.h };
vertices.emplace_back(::GlyphVertex{g.anchor, atlas.mapUv(pod::Vector2f{ 0.0f, 0.0f }, hash), color, p0});
vertices.emplace_back(::GlyphVertex{g.anchor, atlas.mapUv(pod::Vector2f{ 0.0f, 1.0f }, hash), color, p1});
vertices.emplace_back(::GlyphVertex{g.anchor, atlas.mapUv(pod::Vector2f{ 1.0f, 1.0f }, hash), color, p2});
vertices.emplace_back(::GlyphVertex{g.anchor, atlas.mapUv(pod::Vector2f{ 1.0f, 0.0f }, hash), color, p3});
}
mesh.insertVertices(vertices);