Remove uniform from SDF text rendering

This commit is contained in:
Brad Davis 2018-08-24 23:25:36 -07:00
parent a4cd56532e
commit f704ddc11c
6 changed files with 92 additions and 53 deletions

View file

@ -70,9 +70,8 @@ void TextRenderer3D::draw(gpu::Batch& batch, float x, float y, const QString& st
const glm::vec2& bounds, bool layered) { const glm::vec2& bounds, bool layered) {
// The font does all the OpenGL work // The font does all the OpenGL work
if (_font) { if (_font) {
// Cache color so that the pointer stays valid.
_color = color; _color = color;
_font->drawString(batch, x, y, str, &_color, _effectType, bounds, layered); _font->drawString(batch, _drawInfo, str, _color, _effectType, { x, y }, bounds, layered);
} }
} }

View file

@ -15,12 +15,14 @@
#include <memory> #include <memory>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <QColor> #include <QColor>
#include <gpu/Forward.h>
namespace gpu { namespace gpu {
class Batch; class Batch;
} }
class Font; class Font;
#include "text/Font.h"
#include "text/EffectType.h" #include "text/EffectType.h"
#include "text/FontFamilies.h" #include "text/FontFamilies.h"
@ -51,7 +53,7 @@ private:
// text color // text color
glm::vec4 _color; glm::vec4 _color;
Font::DrawInfo _drawInfo;
std::shared_ptr<Font> _font; std::shared_ptr<Font> _font;
}; };

View file

@ -14,8 +14,15 @@
<@include render-utils/ShaderConstants.h@> <@include render-utils/ShaderConstants.h@>
layout(binding=0) uniform sampler2D Font; layout(binding=0) uniform sampler2D Font;
layout(location=RENDER_UTILS_UNIFORM_TEXT_OUTLINE) uniform bool Outline;
layout(location=RENDER_UTILS_UNIFORM_TEXT_COLOR) uniform vec4 Color; struct TextParams {
vec4 color;
float outline;
};
layout(binding=0) uniform textParamsBuffer {
TextParams params;
};
// the interpolated normal // the interpolated normal
layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS;
@ -32,7 +39,7 @@ const float taaBias = pow(2.0, TAA_TEXTURE_LOD_BIAS);
float evalSDF(vec2 texCoord) { float evalSDF(vec2 texCoord) {
// retrieve signed distance // retrieve signed distance
float sdf = textureLod(Font, texCoord, TAA_TEXTURE_LOD_BIAS).g; float sdf = textureLod(Font, texCoord, TAA_TEXTURE_LOD_BIAS).g;
if (Outline) { if (params.outline > 0.0) {
if (sdf > interiorCutoff) { if (sdf > interiorCutoff) {
sdf = 1.0 - sdf; sdf = 1.0 - sdf;
} else { } else {
@ -62,8 +69,8 @@ void main() {
packDeferredFragment( packDeferredFragment(
normalize(_normalWS), normalize(_normalWS),
a * Color.a, a * params.color.a,
Color.rgb, params.color.rgb,
DEFAULT_ROUGHNESS, DEFAULT_ROUGHNESS,
DEFAULT_METALLIC, DEFAULT_METALLIC,
DEFAULT_EMISSIVE, DEFAULT_EMISSIVE,

View file

@ -14,8 +14,15 @@
<@include render-utils/ShaderConstants.h@> <@include render-utils/ShaderConstants.h@>
layout(binding=0) uniform sampler2D Font; layout(binding=0) uniform sampler2D Font;
layout(location=RENDER_UTILS_UNIFORM_TEXT_OUTLINE) uniform bool Outline;
layout(location=RENDER_UTILS_UNIFORM_TEXT_COLOR) uniform vec4 Color; struct TextParams {
vec4 color;
float outline;
};
layout(binding=0) uniform textParamsBuffer {
TextParams params;
};
// the interpolated normal // the interpolated normal
layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS;
@ -31,7 +38,7 @@ const float outlineExpansion = 0.2;
void main() { void main() {
// retrieve signed distance // retrieve signed distance
float sdf = texture(Font, _texCoord0).g; float sdf = texture(Font, _texCoord0).g;
if (Outline) { if (params.outline > 0.0) {
if (sdf > interiorCutoff) { if (sdf > interiorCutoff) {
sdf = 1.0 - sdf; sdf = 1.0 - sdf;
} else { } else {
@ -51,8 +58,8 @@ void main() {
packDeferredFragmentTranslucent( packDeferredFragmentTranslucent(
normalize(_normalWS), normalize(_normalWS),
a * Color.a, a * params.color.a,
Color.rgb, params.color.rgb,
DEFAULT_FRESNEL, DEFAULT_FRESNEL,
DEFAULT_ROUGHNESS); DEFAULT_ROUGHNESS);
} }

View file

@ -256,29 +256,30 @@ void Font::setupGPU() {
} }
} }
void Font::rebuildVertices(float x, float y, const QString& str, const glm::vec2& bounds) { void Font::buildVertices(Font::DrawInfo& drawInfo, const QString& str, const glm::vec2& origin, const glm::vec2& bounds) {
_verticesBuffer = std::make_shared<gpu::Buffer>(); drawInfo.verticesBuffer = std::make_shared<gpu::Buffer>();
_numVertices = 0; drawInfo.indicesBuffer = std::make_shared<gpu::Buffer>();
_indicesBuffer = std::make_shared<gpu::Buffer>(); drawInfo.indexCount = 0;
_numIndices = 0; int numVertices = 0;
_lastStringRendered = str; drawInfo.string = str;
_lastBounds = bounds; drawInfo.bounds = bounds;
drawInfo.origin = origin;
// Top left of text // Top left of text
glm::vec2 advance = glm::vec2(x, y); glm::vec2 advance = origin;
foreach(const QString& token, tokenizeForWrapping(str)) { foreach(const QString& token, tokenizeForWrapping(str)) {
bool isNewLine = (token == QString('\n')); bool isNewLine = (token == QString('\n'));
bool forceNewLine = false; bool forceNewLine = false;
// Handle wrapping // Handle wrapping
if (!isNewLine && (bounds.x != -1) && (advance.x + computeExtent(token).x > x + bounds.x)) { if (!isNewLine && (bounds.x != -1) && (advance.x + computeExtent(token).x > origin.x + bounds.x)) {
// We are out of the x bound, force new line // We are out of the x bound, force new line
forceNewLine = true; forceNewLine = true;
} }
if (isNewLine || forceNewLine) { if (isNewLine || forceNewLine) {
// Character return, move the advance to a new line // Character return, move the advance to a new line
advance = glm::vec2(x, advance.y - _leading); advance = glm::vec2(origin.x, advance.y - _leading);
if (isNewLine) { if (isNewLine) {
// No need to draw anything, go directly to next token // No need to draw anything, go directly to next token
@ -288,7 +289,7 @@ void Font::rebuildVertices(float x, float y, const QString& str, const glm::vec2
break; break;
} }
} }
if ((bounds.y != -1) && (advance.y - _fontSize < -y - bounds.y)) { if ((bounds.y != -1) && (advance.y - _fontSize < -origin.y - bounds.y)) {
// We are out of the y bound, stop drawing // We are out of the y bound, stop drawing
break; break;
} }
@ -297,11 +298,11 @@ void Font::rebuildVertices(float x, float y, const QString& str, const glm::vec2
if (!isNewLine) { if (!isNewLine) {
for (auto c : token) { for (auto c : token) {
auto glyph = _glyphs[c]; auto glyph = _glyphs[c];
quint16 verticesOffset = _numVertices; quint16 verticesOffset = numVertices;
QuadBuilder qd(glyph, advance - glm::vec2(0.0f, _ascent)); QuadBuilder qd(glyph, advance - glm::vec2(0.0f, _ascent));
_verticesBuffer->append(sizeof(QuadBuilder), (const gpu::Byte*)&qd); drawInfo.verticesBuffer->append(qd);
_numVertices += 4; numVertices += 4;
// Sam's recommended triangle slices // Sam's recommended triangle slices
// Triangle tri1 = { v0, v1, v3 }; // Triangle tri1 = { v0, v1, v3 };
@ -327,8 +328,8 @@ void Font::rebuildVertices(float x, float y, const QString& str, const glm::vec2
indices[3] = verticesOffset + 2; indices[3] = verticesOffset + 2;
indices[4] = verticesOffset + 1; indices[4] = verticesOffset + 1;
indices[5] = verticesOffset + 3; indices[5] = verticesOffset + 3;
_indicesBuffer->append(sizeof(indices), (const gpu::Byte*)indices); drawInfo.indicesBuffer->append(sizeof(indices), (const gpu::Byte*)indices);
_numIndices += NUMBER_OF_INDICES_PER_QUAD; drawInfo.indexCount += NUMBER_OF_INDICES_PER_QUAD;
// Advance by glyph size // Advance by glyph size
@ -341,26 +342,39 @@ void Font::rebuildVertices(float x, float y, const QString& str, const glm::vec2
} }
} }
void Font::drawString(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4* color, void Font::drawString(gpu::Batch& batch, Font::DrawInfo& drawInfo, const QString& str, const glm::vec4& color,
EffectType effectType, const glm::vec2& bounds, bool layered) { EffectType effectType, const glm::vec2& origin, const glm::vec2& bounds, bool layered) {
if (str == "") { if (str == "") {
return; return;
} }
if (str != _lastStringRendered || bounds != _lastBounds) { if (str != drawInfo.string || bounds != drawInfo.bounds || origin != drawInfo.origin) {
rebuildVertices(x, y, str, bounds); buildVertices(drawInfo, str, origin, bounds);
} }
setupGPU(); setupGPU();
batch.setPipeline(((*color).a < 1.0f || layered) ? _transparentPipeline : _pipeline); struct GpuDrawParams {
batch.setResourceTexture(render_utils::slot::texture::TextFont, _texture); glm::vec4 color;
batch._glUniform1i(render_utils::slot::uniform::TextOutline, (effectType == OUTLINE_EFFECT)); float outline;
};
if (!drawInfo.paramsBuffer || drawInfo.params.color != color || drawInfo.params.effect != effectType) {
drawInfo.params.color = color;
drawInfo.params.effect = effectType;
GpuDrawParams gpuDrawParams;
gpuDrawParams.color = ColorUtils::sRGBToLinearVec4(drawInfo.params.color);
gpuDrawParams.outline = (drawInfo.params.effect == OUTLINE_EFFECT) ? 1 : 0;
drawInfo.paramsBuffer = std::make_shared<gpu::Buffer>(sizeof(GpuDrawParams), nullptr);
drawInfo.paramsBuffer->setSubData(0, sizeof(GpuDrawParams), (const gpu::Byte*)&gpuDrawParams);
}
// need the gamma corrected color here // need the gamma corrected color here
glm::vec4 lrgba = ColorUtils::sRGBToLinearVec4(*color);
batch._glUniform4fv(render_utils::slot::uniform::TextColor, 1, (const float*)&lrgba); batch.setPipeline((color.a < 1.0f || layered) ? _transparentPipeline : _pipeline);
batch.setInputFormat(_format); batch.setInputFormat(_format);
batch.setInputBuffer(0, _verticesBuffer, 0, _format->getChannels().at(0)._stride); batch.setInputBuffer(0, drawInfo.verticesBuffer, 0, _format->getChannels().at(0)._stride);
batch.setIndexBuffer(gpu::UINT16, _indicesBuffer, 0); batch.setResourceTexture(render_utils::slot::texture::TextFont, _texture);
batch.drawIndexed(gpu::TRIANGLES, _numIndices, 0); batch.setUniformBuffer(0, drawInfo.paramsBuffer, 0, sizeof(GpuDrawParams));
batch.setIndexBuffer(gpu::UINT16, drawInfo.indicesBuffer, 0);
batch.drawIndexed(gpu::TRIANGLES, drawInfo.indexCount, 0);
} }

View file

@ -23,16 +23,34 @@ public:
void read(QIODevice& path); void read(QIODevice& path);
struct DrawParams {
vec4 color{ -1 };
EffectType effect;
};
struct DrawInfo {
gpu::BufferPointer verticesBuffer;
gpu::BufferPointer indicesBuffer;
gpu::BufferPointer paramsBuffer;
uint32_t indexCount;
QString string;
glm::vec2 origin;
glm::vec2 bounds;
DrawParams params;
};
glm::vec2 computeExtent(const QString& str) const; glm::vec2 computeExtent(const QString& str) const;
float getFontSize() const { return _fontSize; } float getFontSize() const { return _fontSize; }
// Render string to batch // Render string to batch
void drawString(gpu::Batch& batch, float x, float y, const QString& str, void drawString(gpu::Batch& batch, DrawInfo& drawInfo, const QString& str,
const glm::vec4* color, EffectType effectType, const glm::vec4& color, EffectType effectType,
const glm::vec2& bound, bool layered = false); const glm::vec2& origin, const glm::vec2& bound, bool layered = false);
static Pointer load(const QString& family); static Pointer load(const QString& family);
private: private:
static Pointer load(QIODevice& fontFile); static Pointer load(QIODevice& fontFile);
QStringList tokenizeForWrapping(const QString& str) const; QStringList tokenizeForWrapping(const QString& str) const;
@ -40,7 +58,7 @@ private:
glm::vec2 computeTokenExtent(const QString& str) const; glm::vec2 computeTokenExtent(const QString& str) const;
const Glyph& getGlyph(const QChar& c) const; const Glyph& getGlyph(const QChar& c) const;
void rebuildVertices(float x, float y, const QString& str, const glm::vec2& bounds); void buildVertices(DrawInfo& drawInfo, const QString& str, const glm::vec2& origin, const glm::vec2& bounds);
void setupGPU(); void setupGPU();
@ -66,15 +84,7 @@ private:
gpu::PipelinePointer _transparentPipeline; gpu::PipelinePointer _transparentPipeline;
gpu::TexturePointer _texture; gpu::TexturePointer _texture;
gpu::Stream::FormatPointer _format; gpu::Stream::FormatPointer _format;
gpu::BufferPointer _verticesBuffer;
gpu::BufferPointer _indicesBuffer;
gpu::BufferStreamPointer _stream; gpu::BufferStreamPointer _stream;
unsigned int _numVertices = 0;
unsigned int _numIndices = 0;
// last string render characteristics
QString _lastStringRendered;
glm::vec2 _lastBounds;
}; };
#endif #endif