From e9a1c629d9e134716c0d1dca9097d4001b6b3b2f Mon Sep 17 00:00:00 2001 From: Georg Hagen Date: Sun, 5 Jan 2025 00:02:01 +0100 Subject: [PATCH] Switch to more compact TextGlyph vertex format --- examples/ExampleApps/TextExampleApp.cpp | 2 +- openVulkanoCpp/Extensions/FreetypeHelper.hpp | 2 +- .../Scene/Prefabs/LabelDrawable.cpp | 80 ++++++------ .../Scene/Prefabs/LabelDrawable.hpp | 9 +- openVulkanoCpp/Scene/TextDrawable.cpp | 116 ++++++++---------- openVulkanoCpp/Scene/TextDrawable.hpp | 28 +++-- openVulkanoCpp/Shader/msdfText.frag | 30 ++--- openVulkanoCpp/Shader/sdfText.frag | 21 ++-- openVulkanoCpp/Shader/text.frag | 15 +-- openVulkanoCpp/Shader/text.vert | 26 ++-- openVulkanoCpp/Shader/textBillboard.vert | 64 ++++++++++ .../Scene/LabelDrawableVulkanEncoder.cpp | 69 ++++------- .../Scene/TextDrawableVulkanEncoder.cpp | 35 ++---- 13 files changed, 249 insertions(+), 248 deletions(-) create mode 100644 openVulkanoCpp/Shader/textBillboard.vert diff --git a/examples/ExampleApps/TextExampleApp.cpp b/examples/ExampleApps/TextExampleApp.cpp index 11be545..f5b11ee 100644 --- a/examples/ExampleApps/TextExampleApp.cpp +++ b/examples/ExampleApps/TextExampleApp.cpp @@ -54,7 +54,7 @@ namespace OpenVulkano texts.push_back(std::make_pair("\u0410\u0411\u0412\u041F", TextConfig())); texts.push_back(std::make_pair("Unsupported glyphs \u1E30\u1E31 are coming", TextConfig())); texts.push_back(std::make_pair("This is first line\nSecond gg line\nThird G line", TextConfig())); - texts[1].second.backgroundColor.a = 1; + texts[1].second.backgroundColor.a = 255; const int N = texts.size(); auto& resourceLoader = ResourceLoader::GetInstance(); diff --git a/openVulkanoCpp/Extensions/FreetypeHelper.hpp b/openVulkanoCpp/Extensions/FreetypeHelper.hpp index 3f05c93..7860f50 100644 --- a/openVulkanoCpp/Extensions/FreetypeHelper.hpp +++ b/openVulkanoCpp/Extensions/FreetypeHelper.hpp @@ -6,7 +6,7 @@ #pragma once -#include <../../../cmake-build/debug/_deps/freetype-src/freetype-install/include/freetype2/ft2build.h> +#include #include FT_FREETYPE_H #include diff --git a/openVulkanoCpp/Scene/Prefabs/LabelDrawable.cpp b/openVulkanoCpp/Scene/Prefabs/LabelDrawable.cpp index 5e5b0c1..89926ad 100644 --- a/openVulkanoCpp/Scene/Prefabs/LabelDrawable.cpp +++ b/openVulkanoCpp/Scene/Prefabs/LabelDrawable.cpp @@ -7,6 +7,8 @@ #include "LabelDrawable.hpp" #include "Scene/TextDrawable.hpp" #include "Scene/DrawEncoder.hpp" +#include "Scene/Vertex.hpp" +#include "Scene/Shader/Shader.hpp" #include "Scene/IFontAtlasGenerator.hpp" #include "Base/Logger.hpp" #include @@ -39,10 +41,45 @@ namespace OpenVulkano::Scene backgroundShader.cullMode = CullMode::NONE; return backgroundShader; } - } - Shader LabelDrawable::BACKGROUND_SHADER = MakeLabelBgShader(false); - Shader LabelDrawable::BACKGROUND_BILLBOARD_SHADER = MakeLabelBgShader(true); + Shader MakeLabelTextShader(const FontAtlasType type, const bool billboard) + { + Shader shader = TextDrawable::MakeDefaultShader(type); + shader.depthTest = false; + shader.depthCompareOp = CompareOp::LESS_OR_EQUAL; + if (billboard) + { + for (auto& program : shader.shaderPrograms) + { + if (program.type == ShaderProgramType::VERTEX) + { + program.name = "Shader/textBillboard"; + break; + } + } + DescriptorSetLayoutBinding billboardUniformBinding = UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING; + billboardUniformBinding.stageFlags = ShaderProgramType::Type::VERTEX; + shader.AddDescriptorSetLayoutBinding(billboardUniformBinding, 4); + } + return shader; + } + + Shader BACKGROUND_SHADER = MakeLabelBgShader(false); + Shader BACKGROUND_BILLBOARD_SHADER = MakeLabelBgShader(true); + std::array TEXT_SHADERS = { + MakeLabelTextShader(FontAtlasType::SDF, false), + MakeLabelTextShader(FontAtlasType::SDF, true), + MakeLabelTextShader(FontAtlasType::MSDF, false), + MakeLabelTextShader(FontAtlasType::MSDF, true), + MakeLabelTextShader(FontAtlasType::BITMAP, false), + MakeLabelTextShader(FontAtlasType::BITMAP, true), + }; + + Shader* GetTextShader(const FontAtlasType type, const bool billboard) + { + return &TEXT_SHADERS[static_cast(type) << 1 | billboard]; + } + } LabelDrawable::LabelDrawable(const std::shared_ptr& atlasData, const LabelDrawableSettings& settings, const bool isBillboard) : Drawable(DrawEncoder::GetDrawEncoder(), DrawPhase::MAIN), m_atlasData(atlasData), m_isBillboard(isBillboard) @@ -52,7 +89,7 @@ namespace OpenVulkano::Scene throw std::runtime_error("Can't create label drawable. Either glyphs or texture is empty"); } SetLabelSettings(settings); - SetupShaders(); + SetShader(IsBillboard() ? &BACKGROUND_BILLBOARD_SHADER : &BACKGROUND_SHADER); SetupBuffers(); } @@ -72,11 +109,10 @@ namespace OpenVulkano::Scene if (text.empty()) return; TextDrawable& textDrawable = m_texts.emplace_back(m_atlasData, config); - // do not render glyph's background - textDrawable.GetConfig().backgroundColor.a = 0; + textDrawable.GetConfig().backgroundColor.a = 0; // do not render glyph's background double lineHeight = m_atlasData->meta.lineHeight; textDrawable.GenerateText(text, m_position); - textDrawable.SetShader(&m_textShader); + textDrawable.SetShader(GetTextShader(m_atlasData->meta.atlasType, m_isBillboard)); m_bbox.Grow(textDrawable.GetBoundingBox()); // update position for next text entry m_position.y = m_bbox.GetMin().y - lineHeight; @@ -107,36 +143,6 @@ namespace OpenVulkano::Scene return ray.IntersectAABB(m_bbox); } - void LabelDrawable::SetupShaders() - { - SetShader(IsBillboard() ? &BACKGROUND_BILLBOARD_SHADER : &BACKGROUND_SHADER); - - FontAtlasType fontAtlasType(static_cast(m_atlasData->meta.atlasType)); - if (!m_isBillboard) - { - m_textShader.AddShaderProgram(ShaderProgramType::VERTEX, "Shader/text"); - } - else - { - m_textShader.AddShaderProgram(ShaderProgramType::VERTEX, "Shader/billboard"); - DescriptorSetLayoutBinding billboardUniformBinding = UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING; - billboardUniformBinding.stageFlags = ShaderProgramType::Type::VERTEX; - m_textShader.AddDescriptorSetLayoutBinding(billboardUniformBinding, 4); - } - - DescriptorSetLayoutBinding textUniformBinding = UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING; - textUniformBinding.stageFlags = ShaderProgramType::FRAGMENT; - m_textShader.AddDescriptorSetLayoutBinding(textUniformBinding, 3); - m_textShader.AddShaderProgram(ShaderProgramType::FRAGMENT, - std::string(fontAtlasType.GetDefaultFragmentShader())); - m_textShader.AddVertexInputDescription(Vertex::GetVertexInputDescription()); - m_textShader.AddDescriptorSetLayoutBinding(Texture::DESCRIPTOR_SET_LAYOUT_BINDING, 2); - m_textShader.alphaBlend = true; - m_textShader.cullMode = CullMode::NONE; - m_textShader.depthWrite = false; - m_textShader.depthCompareOp = CompareOp::LESS_OR_EQUAL; - } - void LabelDrawable::SetupBuffers() { m_billboardBuffer.size = sizeof(BillboardControlBlock); diff --git a/openVulkanoCpp/Scene/Prefabs/LabelDrawable.hpp b/openVulkanoCpp/Scene/Prefabs/LabelDrawable.hpp index cb406d9..4357b42 100644 --- a/openVulkanoCpp/Scene/Prefabs/LabelDrawable.hpp +++ b/openVulkanoCpp/Scene/Prefabs/LabelDrawable.hpp @@ -6,12 +6,9 @@ #pragma once -#include "Base/Wrapper.hpp" #include "Scene/Drawable.hpp" -#include "Scene/Shader/Shader.hpp" #include "Scene/Texture.hpp" #include "Scene/UniformBuffer.hpp" -#include "Scene/Vertex.hpp" #include "Scene/BillboardControlBlock.hpp" #include "Math/AABB.hpp" #include "Scene/TextDrawable.hpp" @@ -19,6 +16,8 @@ namespace OpenVulkano::Scene { + class Shader; + struct LabelDrawableSettings { Math::Vector4f backgroundColor = { 1, 0, 0, 1 }; @@ -45,8 +44,6 @@ namespace OpenVulkano::Scene class LabelDrawable final : public Drawable { - static Shader BACKGROUND_SHADER, BACKGROUND_BILLBOARD_SHADER; - public: LabelDrawable(const std::shared_ptr& atlasData, const LabelDrawableSettings& settings = LabelDrawableSettings(), bool isBillboard = false); @@ -65,13 +62,11 @@ namespace OpenVulkano::Scene std::optional Intersect(const Ray& ray) const override; private: - void SetupShaders(); void SetupBuffers(); UniformBuffer m_billboardBuffer; UniformBuffer m_labelBuffer; std::list m_texts; // Using list instead of vector for stable iterators - Shader m_textShader; LabelDrawableSettings m_settings; LabelUniformData m_labelData; std::shared_ptr m_atlasData; diff --git a/openVulkanoCpp/Scene/TextDrawable.cpp b/openVulkanoCpp/Scene/TextDrawable.cpp index b127b1d..88acca2 100644 --- a/openVulkanoCpp/Scene/TextDrawable.cpp +++ b/openVulkanoCpp/Scene/TextDrawable.cpp @@ -6,9 +6,7 @@ #include "TextDrawable.hpp" #include "Scene/Geometry.hpp" -#include "Scene/Material.hpp" -#include "Scene/Vertex.hpp" -#include "Scene/UniformBuffer.hpp" +#include "Shader/Shader.hpp" #include "Scene/IFontAtlasGenerator.hpp" #include "Base/Logger.hpp" #include "Host/ResourceLoader.hpp" @@ -24,32 +22,39 @@ namespace OpenVulkano::Scene { constexpr uint32_t MISSING_GLYPH_SYMBOL = '?'; - Shader MakeDefaultShader(FontAtlasType type) - { - Shader shader; - shader.AddShaderProgram(ShaderProgramType::VERTEX, "Shader/text"); - shader.AddShaderProgram(ShaderProgramType::FRAGMENT, std::string(type.GetDefaultFragmentShader())); - shader.AddVertexInputDescription(Vertex::GetVertexInputDescription()); - shader.AddDescriptorSetLayoutBinding(Texture::DESCRIPTOR_SET_LAYOUT_BINDING); - DescriptorSetLayoutBinding desc = UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING; - desc.stageFlags = ShaderProgramType::FRAGMENT; - shader.AddDescriptorSetLayoutBinding(desc); - shader.alphaBlend = true; - shader.cullMode = CullMode::NONE; - return shader; - } + Shader DEFAULT_SHADER_BITMAP = TextDrawable::MakeDefaultShader(FontAtlasType::BITMAP); + Shader DEFAULT_SHADER_SDF = TextDrawable::MakeDefaultShader(FontAtlasType::SDF); + Shader DEFAULT_SHADER_MSDF = TextDrawable::MakeDefaultShader(FontAtlasType::MSDF); + } - Shader DEFAULT_SHADER_BITMAP = MakeDefaultShader(FontAtlasType::BITMAP); - Shader DEFAULT_SHADER_SDF = MakeDefaultShader(FontAtlasType::SDF); - Shader DEFAULT_SHADER_MSDF = MakeDefaultShader(FontAtlasType::MSDF); + Shader TextDrawable::MakeDefaultShader(const FontAtlasType type) + { + Shader shader; + shader.AddShaderProgram(ShaderProgramType::VERTEX, "Shader/text"); + shader.AddShaderProgram(ShaderProgramType::FRAGMENT, std::string(type.GetDefaultFragmentShader())); + VertexInputDescription inputDesc(0, sizeof(TextGlyphVertex)); + inputDesc.AddInputParameter(DataFormat::R32G32_SFLOAT, offsetof(TextGlyphVertex, position)); + inputDesc.AddInputParameter(DataFormat::R32G32_SFLOAT, offsetof(TextGlyphVertex, position)+8); + inputDesc.AddInputParameter(DataFormat::R32G32_SFLOAT, offsetof(TextGlyphVertex, position)+16); + inputDesc.AddInputParameter(DataFormat::R32G32_SFLOAT, offsetof(TextGlyphVertex, position)+24); + inputDesc.AddInputParameter(DataFormat::R32G32_SFLOAT, offsetof(TextGlyphVertex, uv)); + inputDesc.AddInputParameter(DataFormat::R32G32_SFLOAT, offsetof(TextGlyphVertex, uv)+8); + inputDesc.AddInputParameter(DataFormat::R32G32_SFLOAT, offsetof(TextGlyphVertex, uv)+16); + inputDesc.AddInputParameter(DataFormat::R32G32_SFLOAT, offsetof(TextGlyphVertex, uv)+24); + inputDesc.AddInputParameter(DataFormat::R8G8B8A8_UNORM, offsetof(TextGlyphVertex, color)); + inputDesc.AddInputParameter(DataFormat::R8G8B8A8_UNORM, offsetof(TextGlyphVertex, background)); + inputDesc.stepMode = VertexStepMode::INSTANCE; + shader.AddVertexInputDescription(inputDesc); + shader.AddDescriptorSetLayoutBinding(Texture::DESCRIPTOR_SET_LAYOUT_BINDING); + shader.alphaBlend = true; + shader.cullMode = CullMode::NONE; + shader.topology = Topology::TRIANGLE_FAN; + return shader; } TextDrawable::TextDrawable(const TextConfig& config) : Drawable(DrawEncoder::GetDrawEncoder()), m_cfg(config) - { - m_uniBuffer.Init(sizeof(TextConfig), &m_cfg, 3); - m_uniBuffer.binding.stageFlags = ShaderProgramType::FRAGMENT; - } + {} TextDrawable::TextDrawable(const Array& atlasMetadata, const TextConfig& config) : TextDrawable(atlasMetadata, nullptr, config) @@ -106,8 +111,6 @@ namespace OpenVulkano::Scene read_bytes += sizeof(GlyphInfo); readMetadataBytes += sizeof(GlyphInfo); } - m_uniBuffer.Init(sizeof(TextConfig), &m_cfg, 3); - m_uniBuffer.binding.stageFlags = ShaderProgramType::FRAGMENT; if (m_atlasData->meta.atlasType == FontAtlasType::BITMAP) { m_atlasData->texture.m_samplerConfig = &SamplerConfig::NEAREST; @@ -118,8 +121,6 @@ namespace OpenVulkano::Scene : Drawable(DrawEncoder::GetDrawEncoder()), m_atlasData(atlasData), m_cfg(config) { if (!atlasData || !*atlasData) throw std::runtime_error("Cannot initialize text drawable with empty atlas data"); - m_uniBuffer.Init(sizeof(TextConfig), &m_cfg, 3); - m_uniBuffer.binding.stageFlags = ShaderProgramType::FRAGMENT; } uint32_t TextDrawable::GetFallbackGlyph() const @@ -132,25 +133,24 @@ namespace OpenVulkano::Scene return m_atlasData->glyphs.begin()->first; } - - void TextDrawable::GenerateText(const std::string& text, const Math::Vector3f& pos) + void TextDrawable::GenerateText(const std::string& text, const Math::Vector2f& pos) { if (text.empty()) return; + if (m_vertexBuffer.data) throw std::runtime_error("Text has already been initialized"); const uint32_t fallbackGlyph = GetFallbackGlyph(); m_text = text; - + m_symbolCount = 0; const size_t len = utf8::distance(text.begin(), text.end()); - m_geometry.Close(); - m_geometry.Init(len * 4, len * 6); + m_vertexBuffer.Close(); + TextGlyphVertex* vertices = m_vertexBuffer.Init(len); std::map* symbols = &m_atlasData->glyphs; AtlasMetadata* meta = &m_atlasData->meta; double cursorX = pos.x; const double lineHeight = meta->lineHeight; double posY = pos.y; - Math::Vector3f bmin(pos), bmax(pos); - int i = 0; + Math::Vector3f bmin(pos, 0), bmax(pos, 0); for (auto begin = text.begin(), end = text.end(); begin != end;) { uint32_t c = utf8::next(begin, end); @@ -160,6 +160,7 @@ namespace OpenVulkano::Scene cursorX = pos.x; continue; } + // TODO handle special chars if (!symbols->contains(c)) { @@ -167,44 +168,29 @@ namespace OpenVulkano::Scene c = fallbackGlyph; } - uint32_t vIdx = i * 4; - uint32_t indices[] = { 1 + vIdx, 2 + vIdx, 3 + vIdx, 1 + vIdx, 3 + vIdx, 0 + vIdx }; GlyphInfo& info = symbols->at(c); - // left bottom - m_geometry.vertices[vIdx].position.x = info.xyz[0].x + cursorX; - m_geometry.vertices[vIdx].position.y = posY - info.xyz[0].y; - m_geometry.vertices[vIdx].position.z = info.xyz[0].z; - m_geometry.vertices[vIdx].textureCoordinates = Math::Vector3f(info.uv[0], 0); + for (int i = 0; i < 4; i++) + { + vertices->position[i].x = info.xyz[i].x + cursorX; + vertices->uv[i] = info.uv[i]; + if (i < 2) vertices->position[i].y = posY - info.xyz[i].y; + else vertices->position[i].y = posY + info.xyz[i].y; + vertices->color = m_cfg.textColor; + vertices->background = m_cfg.backgroundColor; + } - // right bottom - m_geometry.vertices[vIdx + 1].position.x = info.xyz[1].x + cursorX; - m_geometry.vertices[vIdx + 1].position.y = posY - info.xyz[1].y; - m_geometry.vertices[vIdx + 1].position.z = info.xyz[1].z; - m_geometry.vertices[vIdx + 1].textureCoordinates = Math::Vector3f(info.uv[1], 0); - - // top right - m_geometry.vertices[vIdx + 2].position.x = info.xyz[2].x + cursorX; - m_geometry.vertices[vIdx + 2].position.y = posY + info.xyz[2].y; - m_geometry.vertices[vIdx + 2].position.z = info.xyz[2].z; - m_geometry.vertices[vIdx + 2].textureCoordinates = Math::Vector3f(info.uv[2], 0); - - // top left - m_geometry.vertices[vIdx + 3].position.x = info.xyz[3].x + cursorX; - m_geometry.vertices[vIdx + 3].position.y = posY + info.xyz[3].y; - m_geometry.vertices[vIdx + 3].position.z = info.xyz[3].z; - m_geometry.vertices[vIdx + 3].textureCoordinates = Math::Vector3f(info.uv[3], 0); - m_geometry.SetIndices(indices, 6, 6 * i); // TODO: change to lower value(or ideally remove completely) to avoid overlapping and make less space between symbols // when setting for depth comparison operator will be available( <= ) cursorX += info.advance + 0.08; - bmax.x = std::max(bmax.x, m_geometry.vertices[vIdx + 1].position.x); - bmax.y = std::max(bmax.y, m_geometry.vertices[vIdx + 2].position.y); - bmin.y = std::min(bmin.y, m_geometry.vertices[vIdx + 1].position.y); - ++i; + bmax.x = std::max(bmax.x, vertices->position[1].x); + bmax.y = std::max(bmax.y, vertices->position[2].y); + bmin.y = std::min(bmin.y, vertices->position[1].y); + vertices++; + m_symbolCount++; } - bmin.x = m_geometry.vertices[0].position.x; + bmin.x = vertices->position[0].x; m_bbox.Init(bmin, bmax); if (!GetShader()) SetShader(GetDefaultShader(m_atlasData->meta.atlasType)); diff --git a/openVulkanoCpp/Scene/TextDrawable.hpp b/openVulkanoCpp/Scene/TextDrawable.hpp index c4eb502..0af8ed4 100644 --- a/openVulkanoCpp/Scene/TextDrawable.hpp +++ b/openVulkanoCpp/Scene/TextDrawable.hpp @@ -8,8 +8,7 @@ #include "Drawable.hpp" #include "Texture.hpp" -#include "Geometry.hpp" -#include "UniformBuffer.hpp" +#include "VertexBuffer.hpp" #include "AtlasData.hpp" #include "Image/Image.hpp" @@ -19,19 +18,25 @@ namespace OpenVulkano::Scene struct TextConfig { - Math::Vector4f textColor = { 1, 1, 1, 1 }; - Math::Vector4f backgroundColor = { 0, 1, 0, 0 }; - float threshold = 0.4f; - float smoothing = 1.f/32.f; + Math::Vector4uc textColor = { 255, 255, 255, 255 }; + Math::Vector4uc backgroundColor = { 0, 255, 0, 0 }; + }; + + struct TextGlyphVertex + { + std::array position; + std::array uv; + Math::Vector4uc color = { 255, 255, 255, 255 }; + Math::Vector4uc background = {}; }; class TextDrawable : public Drawable { - Geometry m_geometry; - UniformBuffer m_uniBuffer; + VertexBuffer m_vertexBuffer; std::shared_ptr m_atlasData; Math::AABB m_bbox; std::string m_text; + size_t m_symbolCount = 0; TextConfig m_cfg; uint32_t GetFallbackGlyph() const; @@ -43,7 +48,7 @@ namespace OpenVulkano::Scene TextDrawable(const std::string& atlasMetadataFile, Texture* atlasTex, const TextConfig& config = TextConfig()); TextDrawable(const Array& atlasMetadata, Texture* atlasTex, const TextConfig& config = TextConfig()); TextDrawable(const std::shared_ptr& atlasData, const TextConfig& config = TextConfig()); - void GenerateText(const std::string& text, const Math::Vector3f& pos = Math::Vector3f(0.f)); + void GenerateText(const std::string& text, const Math::Vector2f& pos = Math::Vector2f(0.f)); void SetConfig(const TextConfig& cfg) { m_cfg = cfg; } void SetAtlasData(const std::shared_ptr& atlasData); [[nodiscard]] Math::AABB& GetBoundingBox() { return m_bbox; } @@ -51,10 +56,11 @@ namespace OpenVulkano::Scene [[nodiscard]] const std::string& GetText() const { return m_text; } [[nodiscard]] const std::shared_ptr& GetAtlasData() { return m_atlasData; } - [[nodiscard]] Geometry* GetGeometry() { return &m_geometry; } + [[nodiscard]] VertexBuffer* GetVertexBuffer() { return &m_vertexBuffer; } [[nodiscard]] Texture* GetTexture() { return &m_atlasData->texture; } - [[nodiscard]] UniformBuffer* GetUniformBuffer() { return &m_uniBuffer; } + [[nodiscard]] size_t GetSymbolCount() const { return m_symbolCount; } + [[nodiscard]] static Shader MakeDefaultShader(FontAtlasType type); [[nodiscard]] static Shader* GetDefaultShader(FontAtlasType type); }; } diff --git a/openVulkanoCpp/Shader/msdfText.frag b/openVulkanoCpp/Shader/msdfText.frag index 5bb8fd3..ad08fbd 100644 --- a/openVulkanoCpp/Shader/msdfText.frag +++ b/openVulkanoCpp/Shader/msdfText.frag @@ -1,44 +1,40 @@ #version 450 -layout(location = 1) in vec2 texCoord; +layout(location = 0) in vec4 color; +layout(location = 1) in vec4 bgColor; +layout(location = 2) in vec2 texCoord; layout(location = 0) out vec4 outColor; layout(set = 2, binding = 0) uniform sampler2D texSampler; -layout(set = 3, binding = 0) uniform TextConfig +float median(float r, float g, float b) { - vec4 textColor; - vec4 backgroundColor; - float threshold; - float smoothing; -} textConfig; - -float median(float r, float g, float b) { return max(min(r, g), min(max(r, g), b)); } // this parameter should be same as FontAtlasGeneratorConfig::pixelRange const float pxRange = 3; -float screenPxRange() { - vec2 unitRange = vec2(pxRange)/vec2(textureSize(texSampler, 0)); - vec2 screenTexSize = vec2(1.0)/fwidth(texCoord); - return max(0.5*dot(unitRange, screenTexSize), 1.0); +float screenPxRange() +{ + vec2 unitRange = vec2(pxRange) / vec2(textureSize(texSampler, 0)); + vec2 screenTexSize = vec2(1.0) / fwidth(texCoord); + return max(0.5 * dot(unitRange, screenTexSize), 1.0); } void main() { vec3 msd = texture(texSampler, texCoord).rgb; float sd = median(msd.r, msd.g, msd.b); - float screenPxDistance = screenPxRange()*(sd - 0.5); + float screenPxDistance = screenPxRange() * (sd - 0.5); float opacity = clamp(screenPxDistance + 0.5, 0.0, 1.0); - if (textConfig.backgroundColor.a != 0) + if (bgColor.a != 0) { - outColor = mix(textConfig.backgroundColor, textConfig.textColor, opacity); + outColor = mix(bgColor, color, opacity); } else { - outColor = vec4(vec3(textConfig.textColor), opacity); + outColor = vec4(vec3(color), opacity); } } diff --git a/openVulkanoCpp/Shader/sdfText.frag b/openVulkanoCpp/Shader/sdfText.frag index 49cc3ab..c5e17fa 100644 --- a/openVulkanoCpp/Shader/sdfText.frag +++ b/openVulkanoCpp/Shader/sdfText.frag @@ -1,27 +1,24 @@ #version 450 -layout(location = 1) in vec2 texCoord; +layout(location = 0) in vec4 color; +layout(location = 1) in vec4 bgColor; +layout(location = 2) in vec2 texCoord; layout(location = 0) out vec4 outColor; layout(set = 2, binding = 0) uniform sampler2D texSampler; -layout(set = 3, binding = 0) uniform TextConfig -{ - vec4 textColor; - vec4 backgroundColor; - float threshold; - float smoothing; -} textConfig; +const float threshold = 0.4f; +const float smoothing = 1.f/32.f; void main() { float distance = texture(texSampler, texCoord).r; - float alpha = smoothstep(textConfig.threshold - textConfig.smoothing, textConfig.threshold + textConfig.smoothing, distance); - outColor = vec4(textConfig.textColor) * alpha; + float alpha = smoothstep(threshold - smoothing, threshold + smoothing, distance); + outColor = vec4(color) * alpha; - if (textConfig.backgroundColor.a != 0) + if (bgColor.a != 0) { - outColor = mix(textConfig.backgroundColor, outColor, alpha); + outColor = mix(bgColor, outColor, alpha); } } diff --git a/openVulkanoCpp/Shader/text.frag b/openVulkanoCpp/Shader/text.frag index 460a50d..47a7164 100644 --- a/openVulkanoCpp/Shader/text.frag +++ b/openVulkanoCpp/Shader/text.frag @@ -1,22 +1,15 @@ #version 450 -//layout(location = 0) in vec4 color; -layout(location = 1) in vec2 texCoord; +layout(location = 0) in vec4 color; +layout(location = 1) in vec4 bgColor; +layout(location = 2) in vec2 texCoord; layout(location = 0) out vec4 outColor; layout(set = 2, binding = 0) uniform sampler2D texSampler; -layout(set = 3, binding = 0) uniform TextConfig -{ - vec4 textColor; - vec4 backgroundColor; - float threshold; - float smoothing; -} textConfig; - void main() { vec4 sampled = vec4(1.0, 1.0, 1.0, texture(texSampler, texCoord).r); - outColor = vec4(textConfig.textColor) * sampled; + outColor = vec4(color) * sampled; } diff --git a/openVulkanoCpp/Shader/text.vert b/openVulkanoCpp/Shader/text.vert index 47f4b61..7d0f209 100644 --- a/openVulkanoCpp/Shader/text.vert +++ b/openVulkanoCpp/Shader/text.vert @@ -1,13 +1,13 @@ #version 450 -layout(location = 0) in vec3 position; -layout(location = 1) in vec3 normal; -layout(location = 2) in vec3 tangent; -layout(location = 3) in vec3 biTangent; -layout(location = 4) in vec3 textureCoordinates; -layout(location = 5) in vec4 color; + +layout(location = 0) in vec2 position[4]; +layout(location = 4) in vec2 textureCoordinates[4]; +layout(location = 8) in vec4 color; +layout(location = 9) in vec4 bgColor; layout(location = 0) out vec4 outColor; -layout(location = 1) out vec2 fragTextureCoordinates; +layout(location = 1) out vec4 outBgColor; +layout(location = 2) out vec2 fragTextureCoordinates; layout(set = 0, binding = 0) uniform NodeData { @@ -16,14 +16,12 @@ layout(set = 0, binding = 0) uniform NodeData layout(set = 1, binding = 0) uniform CameraData { - mat4 viewProjection; - mat4 view; - mat4 projection; - vec4 camPos; + mat4 viewProjection; } cam; void main() { - gl_Position = cam.viewProjection * node.world * vec4(position, 1.0); - fragTextureCoordinates.xy = textureCoordinates.xy; - outColor = color; + gl_Position = cam.viewProjection * node.world * vec4(position[gl_VertexIndex], 1.0, 1.0); + fragTextureCoordinates = textureCoordinates[gl_VertexIndex]; + outColor = color; + outBgColor = bgColor; } diff --git a/openVulkanoCpp/Shader/textBillboard.vert b/openVulkanoCpp/Shader/textBillboard.vert new file mode 100644 index 0000000..0326fce --- /dev/null +++ b/openVulkanoCpp/Shader/textBillboard.vert @@ -0,0 +1,64 @@ +#version 450 + +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec2 position[4]; +layout(location = 4) in vec2 textureCoordinates[4]; +layout(location = 8) in vec4 color; +layout(location = 9) in vec4 bgColor; + +layout(location = 0) out vec4 outColor; +layout(location = 1) out vec4 outBgColor; +layout(location = 2) out vec2 outTexture; + +layout(set = 0, binding = 0) uniform NodeData +{ + mat4 world; +} node; + +layout(set = 1, binding = 0) uniform CameraData +{ + mat4 viewProjection; + mat4 view; + mat4 projection; + vec4 camPos; +} cam; + +layout(set = 4, binding = 0) uniform BillboardData +{ + vec2 size; + bool isFixedSize; +} billboardInfo; + +void main() +{ + vec4 pos = vec4(position[gl_VertexIndex], 0, 1); + if (!billboardInfo.isFixedSize) + { + mat4 mv = cam.view * node.world; + + mv[0][0] = 1; + mv[0][1] = 0; + mv[0][2] = 0; + + mv[1][0] = 0; + mv[1][1] = 1; + mv[1][2] = 0; + + mv[2][0] = 0; + mv[2][1] = 0; + mv[2][2] = 1; + + gl_Position = cam.projection * mv * pos; + } + else + { + vec4 billboardPos = vec4(0.5, 0.5, 0.5, 1); + vec4 viewPos = cam.view * node.world * billboardPos; + float dist = -viewPos.z; + gl_Position = cam.projection * (viewPos + vec4(pos.xy * dist * 0.2, 0, 0)); + } + outTexture = textureCoordinates[gl_VertexIndex]; + outColor = color; + outBgColor = bgColor; +} diff --git a/openVulkanoCpp/Vulkan/Scene/LabelDrawableVulkanEncoder.cpp b/openVulkanoCpp/Vulkan/Scene/LabelDrawableVulkanEncoder.cpp index eeac1f7..5241cc7 100644 --- a/openVulkanoCpp/Vulkan/Scene/LabelDrawableVulkanEncoder.cpp +++ b/openVulkanoCpp/Vulkan/Scene/LabelDrawableVulkanEncoder.cpp @@ -12,6 +12,7 @@ #include "Vulkan/VulkanDrawContext.hpp" #include "Vulkan/Scene/VulkanTexture.hpp" #include "Vulkan/Scene/VulkanUniformBuffer.hpp" +#include "Vulkan/Scene/VulkanVertexBuffer.hpp" using namespace OpenVulkano::Scene; @@ -33,18 +34,12 @@ namespace OpenVulkano::Vulkan Scene::UniformBuffer* labelBuffer = labelDrawable->GetLabelBuffer(); VulkanUniformBuffer* vkBuffer = labelBuffer->GetRenderResource(); - if (!vkBuffer) - { - vkBuffer = drawContext->renderer->GetResourceManager().PrepareUniformBuffer(labelBuffer); - } + if (!vkBuffer) vkBuffer = drawContext->renderer->GetResourceManager().PrepareUniformBuffer(labelBuffer); vkBuffer->Record(drawContext); for (Node* node: labelDrawable->GetNodes()) { - if (!node->IsEnabled()) [[unlikely]] - { - continue; - } + if (!node->IsEnabled()) [[unlikely]] continue; drawContext->EncodeNode(node); } drawContext->commandBuffer.draw(4, 1, 0, 0); @@ -54,56 +49,34 @@ namespace OpenVulkano::Vulkan { for (TextDrawable& entry : labelDrawable->GetTexts()) { - Shader* shader = entry.GetShader(); - drawContext->EncodeShader(shader); - Geometry* mesh = entry.GetGeometry(); - VulkanGeometry* renderGeo = mesh->GetRenderResource(); - if (!renderGeo) - { - renderGeo = drawContext->renderer->GetResourceManager().PrepareGeometry(mesh); - } - renderGeo->RecordBind(drawContext->commandBuffer); - - std::array uniforms = { nullptr, nullptr }; - // fragment shader buffer - uniforms[0] = entry.GetUniformBuffer(); + drawContext->EncodeShader(entry.GetShader()); + VertexBuffer* vbo = entry.GetVertexBuffer(); + VulkanVertexBuffer* renderVbo = vbo->GetRenderResource(); + if (!renderVbo) renderVbo = drawContext->renderer->GetResourceManager().PrepareVertexBuffer(vbo); + renderVbo->RecordBind(drawContext->commandBuffer); + if (labelDrawable->IsBillboard()) { - // vertex shader buffer - uniforms[1] = labelDrawable->GetBillboardBuffer(); + VulkanUniformBuffer* vkBuffer = labelDrawable->GetBillboardBuffer()->GetRenderResource(); + if (!vkBuffer) + { + vkBuffer = drawContext->renderer->GetResourceManager().PrepareUniformBuffer(labelDrawable->GetBillboardBuffer()); + } + vkBuffer->Record(drawContext); } - for (Scene::UniformBuffer* buffer : uniforms) + VulkanTexture* renderTexture = entry.GetTexture()->GetRenderResource(); + if (!renderTexture) { - if (buffer) - { - VulkanUniformBuffer* vkBuffer = buffer->GetRenderResource(); - if (!vkBuffer) - { - vkBuffer = drawContext->renderer->GetResourceManager().PrepareUniformBuffer(buffer); - } - vkBuffer->Record(drawContext); - } - } - - if (Texture* texture = entry.GetTexture()) - { - VulkanTexture* renderTexture = texture->GetRenderResource(); - if (!renderTexture) - { - renderTexture = drawContext->renderer->GetResourceManager().PrepareTexture(entry.GetTexture()); - } - renderTexture->Record(drawContext); + renderTexture = drawContext->renderer->GetResourceManager().PrepareTexture(entry.GetTexture()); } + renderTexture->Record(drawContext); for (Node* node: labelDrawable->GetNodes()) { - if (!node->IsEnabled()) [[unlikely]] - { - continue; - } + if (!node->IsEnabled()) [[unlikely]] continue; drawContext->EncodeNode(node); - renderGeo->RecordDraw(drawContext->commandBuffer); + drawContext->commandBuffer.draw(4, entry.GetSymbolCount(), 0, 0); } } } diff --git a/openVulkanoCpp/Vulkan/Scene/TextDrawableVulkanEncoder.cpp b/openVulkanoCpp/Vulkan/Scene/TextDrawableVulkanEncoder.cpp index 9589ba4..445a4c6 100644 --- a/openVulkanoCpp/Vulkan/Scene/TextDrawableVulkanEncoder.cpp +++ b/openVulkanoCpp/Vulkan/Scene/TextDrawableVulkanEncoder.cpp @@ -5,49 +5,36 @@ */ #include "Scene/TextDrawable.hpp" -#include "VulkanGeometry.hpp" #include "VulkanNode.hpp" #include "Vulkan/VulkanDrawContext.hpp" #include "Vulkan/Scene/VulkanUniformBuffer.hpp" +#include "Vulkan/Scene/VulkanVertexBuffer.hpp" #include "VulkanTexture.hpp" using namespace OpenVulkano::Scene; namespace OpenVulkano::Vulkan { - void EncodeTextDrawable(Drawable* instance, Vulkan::VulkanDrawContext* drawContext) + void EncodeTextDrawable(Drawable* instance, VulkanDrawContext* drawContext) { TextDrawable* drawable = static_cast(instance); - Geometry* mesh = drawable->GetGeometry(); - VulkanGeometry* renderGeo = mesh->GetRenderResource(); - if (!renderGeo) renderGeo = drawContext->renderer->GetResourceManager().PrepareGeometry(mesh); - renderGeo->RecordBind(drawContext->commandBuffer); + VertexBuffer* vbo = drawable->GetVertexBuffer(); + VulkanVertexBuffer* renderVbo = vbo->GetRenderResource(); + if (!renderVbo) renderVbo = drawContext->renderer->GetResourceManager().PrepareVertexBuffer(vbo); + renderVbo->RecordBind(drawContext->commandBuffer); - if (drawable->GetUniformBuffer()) + VulkanTexture* renderTexture = drawable->GetTexture()->GetRenderResource(); + if (!renderTexture) { - VulkanUniformBuffer* vkBuffer = drawable->GetUniformBuffer()->GetRenderResource(); - if (!vkBuffer) - { - vkBuffer = drawContext->renderer->GetResourceManager().PrepareUniformBuffer(drawable->GetUniformBuffer()); - } - vkBuffer->Record(drawContext); - } - - if (Texture* texture = drawable->GetTexture()) - { - VulkanTexture* renderTexture = texture->GetRenderResource(); - if (!renderTexture) - { - renderTexture = drawContext->renderer->GetResourceManager().PrepareTexture(drawable->GetTexture()); - } - renderTexture->Record(drawContext); + renderTexture = drawContext->renderer->GetResourceManager().PrepareTexture(drawable->GetTexture()); } + renderTexture->Record(drawContext); for(Node* node : instance->GetNodes()) { if (!node->IsEnabled()) [[unlikely]] continue; drawContext->EncodeNode(node); - renderGeo->RecordDraw(drawContext->commandBuffer); + drawContext->commandBuffer.draw(4, drawable->GetSymbolCount(), 0, 0); } } }