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) {
// The font does all the OpenGL work
if (_font) {
// Cache color so that the pointer stays valid.
_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 <glm/glm.hpp>
#include <QColor>
#include <gpu/Forward.h>
namespace gpu {
class Batch;
}
class Font;
#include "text/Font.h"
#include "text/EffectType.h"
#include "text/FontFamilies.h"
@ -51,7 +53,7 @@ private:
// text color
glm::vec4 _color;
Font::DrawInfo _drawInfo;
std::shared_ptr<Font> _font;
};

View file

@ -14,8 +14,15 @@
<@include render-utils/ShaderConstants.h@>
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
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) {
// retrieve signed distance
float sdf = textureLod(Font, texCoord, TAA_TEXTURE_LOD_BIAS).g;
if (Outline) {
if (params.outline > 0.0) {
if (sdf > interiorCutoff) {
sdf = 1.0 - sdf;
} else {
@ -62,8 +69,8 @@ void main() {
packDeferredFragment(
normalize(_normalWS),
a * Color.a,
Color.rgb,
a * params.color.a,
params.color.rgb,
DEFAULT_ROUGHNESS,
DEFAULT_METALLIC,
DEFAULT_EMISSIVE,

View file

@ -14,8 +14,15 @@
<@include render-utils/ShaderConstants.h@>
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
layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS;
@ -31,7 +38,7 @@ const float outlineExpansion = 0.2;
void main() {
// retrieve signed distance
float sdf = texture(Font, _texCoord0).g;
if (Outline) {
if (params.outline > 0.0) {
if (sdf > interiorCutoff) {
sdf = 1.0 - sdf;
} else {
@ -51,8 +58,8 @@ void main() {
packDeferredFragmentTranslucent(
normalize(_normalWS),
a * Color.a,
Color.rgb,
a * params.color.a,
params.color.rgb,
DEFAULT_FRESNEL,
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) {
_verticesBuffer = std::make_shared<gpu::Buffer>();
_numVertices = 0;
_indicesBuffer = std::make_shared<gpu::Buffer>();
_numIndices = 0;
void Font::buildVertices(Font::DrawInfo& drawInfo, const QString& str, const glm::vec2& origin, const glm::vec2& bounds) {
drawInfo.verticesBuffer = std::make_shared<gpu::Buffer>();
drawInfo.indicesBuffer = std::make_shared<gpu::Buffer>();
drawInfo.indexCount = 0;
int numVertices = 0;
_lastStringRendered = str;
_lastBounds = bounds;
drawInfo.string = str;
drawInfo.bounds = bounds;
drawInfo.origin = origin;
// Top left of text
glm::vec2 advance = glm::vec2(x, y);
glm::vec2 advance = origin;
foreach(const QString& token, tokenizeForWrapping(str)) {
bool isNewLine = (token == QString('\n'));
bool forceNewLine = false;
// 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
forceNewLine = true;
}
if (isNewLine || forceNewLine) {
// 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) {
// 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;
}
}
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
break;
}
@ -297,11 +298,11 @@ void Font::rebuildVertices(float x, float y, const QString& str, const glm::vec2
if (!isNewLine) {
for (auto c : token) {
auto glyph = _glyphs[c];
quint16 verticesOffset = _numVertices;
quint16 verticesOffset = numVertices;
QuadBuilder qd(glyph, advance - glm::vec2(0.0f, _ascent));
_verticesBuffer->append(sizeof(QuadBuilder), (const gpu::Byte*)&qd);
_numVertices += 4;
drawInfo.verticesBuffer->append(qd);
numVertices += 4;
// Sam's recommended triangle slices
// 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[4] = verticesOffset + 1;
indices[5] = verticesOffset + 3;
_indicesBuffer->append(sizeof(indices), (const gpu::Byte*)indices);
_numIndices += NUMBER_OF_INDICES_PER_QUAD;
drawInfo.indicesBuffer->append(sizeof(indices), (const gpu::Byte*)indices);
drawInfo.indexCount += NUMBER_OF_INDICES_PER_QUAD;
// 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,
EffectType effectType, const glm::vec2& bounds, bool layered) {
void Font::drawString(gpu::Batch& batch, Font::DrawInfo& drawInfo, const QString& str, const glm::vec4& color,
EffectType effectType, const glm::vec2& origin, const glm::vec2& bounds, bool layered) {
if (str == "") {
return;
}
if (str != _lastStringRendered || bounds != _lastBounds) {
rebuildVertices(x, y, str, bounds);
if (str != drawInfo.string || bounds != drawInfo.bounds || origin != drawInfo.origin) {
buildVertices(drawInfo, str, origin, bounds);
}
setupGPU();
batch.setPipeline(((*color).a < 1.0f || layered) ? _transparentPipeline : _pipeline);
batch.setResourceTexture(render_utils::slot::texture::TextFont, _texture);
batch._glUniform1i(render_utils::slot::uniform::TextOutline, (effectType == OUTLINE_EFFECT));
struct GpuDrawParams {
glm::vec4 color;
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
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.setInputBuffer(0, _verticesBuffer, 0, _format->getChannels().at(0)._stride);
batch.setIndexBuffer(gpu::UINT16, _indicesBuffer, 0);
batch.drawIndexed(gpu::TRIANGLES, _numIndices, 0);
batch.setInputBuffer(0, drawInfo.verticesBuffer, 0, _format->getChannels().at(0)._stride);
batch.setResourceTexture(render_utils::slot::texture::TextFont, _texture);
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);
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;
float getFontSize() const { return _fontSize; }
// Render string to batch
void drawString(gpu::Batch& batch, float x, float y, const QString& str,
const glm::vec4* color, EffectType effectType,
const glm::vec2& bound, bool layered = false);
void drawString(gpu::Batch& batch, DrawInfo& drawInfo, const QString& str,
const glm::vec4& color, EffectType effectType,
const glm::vec2& origin, const glm::vec2& bound, bool layered = false);
static Pointer load(const QString& family);
private:
static Pointer load(QIODevice& fontFile);
QStringList tokenizeForWrapping(const QString& str) const;
@ -40,7 +58,7 @@ private:
glm::vec2 computeTokenExtent(const QString& str) 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();
@ -66,15 +84,7 @@ private:
gpu::PipelinePointer _transparentPipeline;
gpu::TexturePointer _texture;
gpu::Stream::FormatPointer _format;
gpu::BufferPointer _verticesBuffer;
gpu::BufferPointer _indicesBuffer;
gpu::BufferStreamPointer _stream;
unsigned int _numVertices = 0;
unsigned int _numIndices = 0;
// last string render characteristics
QString _lastStringRendered;
glm::vec2 _lastBounds;
};
#endif