我使用freetype和freetype-gl来渲染文本。 不幸的是我的文字呈现为四边形。
我就是这样做的:
enum
{
//Max num of objects
MAX_SPRITES = 60000,
//Max num of indices
//One sprite got 6 indices
MAX_INDICES = MAX_SPRITES * 6,
//Once sprite got 4 vertices
SPRITE_SIZE = sizeof(Vertex) * 4,
//Max num of GL_TEXTUREX => X -> int <0; 32>
MAX_TEXTURES = 32
};
enum BUFFER_SIZE
{
VERTEX = SPRITE_SIZE * MAX_SPRITES,
INDEX = MAX_INDICES * sizeof(GLuint),
};
enum SHADER_OUT
{
POSITION = 0,
COLOR = 1,
UV = 2,
TEXTURE = 3,
};
class Renderer2D
{
public:
Renderer2D() = default;
~Renderer2D();
void Create();
void RenderClear();
void DrawString(const std::string& text, const Vector2& position, const Color& color);
void Render();
private:
Uint vao = 0,
vbo = 0,
ebo = 0,
indexCount = 0,
drawCalls = 0;
ftgl::texture_atlas_t* textureAtlas = nullptr;
ftgl::texture_font_t* font = nullptr;
std::vector<MiUint> textureSlots;
Vertex* mappedVertex = nullptr;
void End();
Uint* SetIndices();
float FindTexture();
};
Renderer2D::~Renderer2D()
{
glDeleteBuffers(1, &vbo);
glDeleteBuffers(1, &ebo);
glDeleteVertexArrays(1, &vao);
ftgl::texture_atlas_delete(textureAtlas);
ftgl::texture_font_delete(font);
textureSlots.clear();
}
void Renderer2D::Create()
{
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, BUFFER_SIZE::VERTEX, nullptr, GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(SHADER_OUT::POSITION);
glEnableVertexAttribArray(SHADER_OUT::COLOR);
glEnableVertexAttribArray(SHADER_OUT::UV);
glEnableVertexAttribArray(SHADER_OUT::TEXTURE);
glVertexAttribPointer(SHADER_OUT::POSITION, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, position));
glVertexAttribPointer(SHADER_OUT::COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), (const void*)offsetof(Vertex, color));
glVertexAttribPointer(SHADER_OUT::UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, uv));
glVertexAttribPointer(SHADER_OUT::TEXTURE, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, texID));
glGenBuffers(1, &ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, BUFFER_SIZE::INDEX, nullptr, GL_STATIC_DRAW);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, NULL, BUFFER_SIZE::INDEX, SetIndices());
glBindVertexArray(0);
textureAtlas = ftgl::texture_atlas_new(512, 512, 1);
font = ftgl::texture_font_new_from_file(textureAtlas, 50, "Media/arial.ttf");
}
void Renderer2D::RenderClear()
{
textureSlots.clear();
mappedVertex = nullptr;
mappedVertex = (Vertex*)glMapNamedBufferRange(vbo, NULL, BUFFER_SIZE::VERTEX, GL_MAP_WRITE_BIT);
}
void Renderer2D::DrawString(const std::string& text, const Vector2& position, const Color& color)
{
using namespace ftgl;
float ts = FindTexture(),
x = position.x;
for (MiUint i = 0; i < text.length(); i++) {
char c = text[i];
texture_glyph_t* glyph = texture_font_get_glyph(font, c);
if (glyph != nullptr) {
if (i > 0) {
float kerning = texture_glyph_get_kerning(glyph, text[i - 1]);
x += kerning;
}
float x0 = x + glyph->offset_x,
x1 = x0 + glyph->width,
y0 = position.y + glyph->offset_y,
y1 = y0 - glyph->height,
u0 = glyph->s0,
u1 = glyph->s1,
v0 = glyph->t0,
v1 = glyph->t1;
mappedVertex->position = Vector3(x0, y0, 0.0f);
mappedVertex->uv = Vector2(u0, v0);
mappedVertex->texID = ts;
mappedVertex->color = color;
mappedVertex++;
mappedVertex->position = Vector3(x0, y1, 0.0f);
mappedVertex->uv = Vector2(u0, v1);
mappedVertex->texID = ts;
mappedVertex->color = color;
mappedVertex++;
mappedVertex->position = Vector3(x1, y1, 0.0f);
mappedVertex->uv = Vector2(u1, v1);
mappedVertex->texID = ts;
mappedVertex->color = color;
mappedVertex++;
mappedVertex->position = Vector3(x1, y0, 0.0f);
mappedVertex->uv = Vector2(u1, v0);
mappedVertex->texID = ts;
mappedVertex->color = color;
mappedVertex++;
indexCount += 6;
x += glyph->advance_x;
}
}
}
void Renderer2D::Render()
{
End();
drawCalls = 0;
for (int i = 0; i < (int)textureSlots.size(); ++i) {
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, textureSlots[i]);
}
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, nullptr);
glBindVertexArray(0);
++drawCalls;
indexCount = 0;
textureSlots.clear();
mappedVertex = nullptr;
glDisable(GL_BLEND);
}
void Renderer2D::End()
{
glUnmapNamedBuffer(vbo);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
MiUint* Renderer2D::SetIndices()
{
MiUint* indices = new MiUint[BUFFER_SIZE::INDEX],
offset = 0;
for (int i = 0; i < BUFFER_SIZE::INDEX; i += 6) {
indices[i] = offset;
indices[i + 1] = offset + 1;
indices[i + 2] = offset + 2;
indices[i + 3] = offset + 2;
indices[i + 4] = offset + 3;
indices[i + 5] = offset;
offset += 4;
}
return indices;
}
float Renderer2D::FindTexture()
{
float result = 0.0f;
bool found = false;
for (MiUint i = 0; i < (MiUint)textureSlots.size(); i++) {
if (textureSlots[i] == textureAtlas->id) {
result = (float)(i + 1);
found = true;
break;
}
}
if (!found) {
if (textureSlots.size() >= MAX_TEXTURES)
{
Render();
RenderClear();
}
textureSlots.push_back(textureAtlas->id);
result = (float)(textureSlots.size());
}
return result;
}
我的主要是在主循环renderer.Create
,d clear renderer
和rawString("STRING", Vector2(0.0f, 0.0f), Color(255, 0, 0, 255))
中设置一个二维摄像机(正交矩阵等),renderer render
。< / p>
结果如:
如何解决?我经历了drawString方法,看起来好像完美无缺。是什么导致它像这样呈现?
@ Rabbid76
只需
顶点:
#version 460 core
layout (location = 0) in vec2 a_position;
layout (location = 1) in vec4 a_color;
layout (location = 2) in vec2 a_uv;
layout (location = 3) in float a_texID;
out vec2 v_fragmentUV;
out vec4 v_fragmentColor;
out vec2 v_fragmenPosition;
out float v_texID;
uniform mat4 u_camera;
void main()
{
gl_Position = u_camera * vec4(a_position, 0.0, 1.0);
v_fragmenPosition = a_position;
v_fragmentColor = a_color;
v_texID = a_texID;
v_fragmentUV = vec2(a_uv.x, 1 - a_uv.y);
}
像素:
#version 460 core
out vec4 outColor;
in vec2 v_fragmentUV;
in vec4 v_fragmentColor;
in vec2 v_fragmenPosition;
in float v_texID;
layout (location = 0) uniform sampler2D u_textureSampler[32];
void main()
{
int texID = int(v_texID - 0.5);
outColor = texture(u_textureSampler[texID], v_fragmentUV);
}
我将tetxure采样器设置为主体均匀。当我像玩家一样渲染纹理时,渲染效果非常好。只有文字问题。
Wher do you use glUniform* to set the texture unit index to the texture sampler uniform?
也许我应该只展示我的主要课程
App2D::App2D()
{
window.Init(4, 6);
window.Create("w", 1280, 720, WINDOW_RESIZABLE);
camera.Projection(0.0f, 1280.0f, 0.0f, 720.0f);
SetupShaders();
renderer2D.Create();
glClearColor(0.5, 0.5, 0.5, 1.0);
/*short textureIDS[] = {
texture.LoadFromFile("Media/MenuImage.png"),
texture.LoadFromFile("Media/image1.png"),
texture.LoadFromFile("Media/image2.png"),
};
for (int y = 0; y < 720; y += 4.) {
for (int x = 0; x < 1280; x += 4.) {
sprite.push_back(new Sprite2D(Rect(x, y, 4.0f), Rect(0.0f, 0.0f, 1.0f, 1.0f), rand() % 3 + 1));
}
}
std::cout << sprite.size() << std::endl;*/
}
void App2D::MainLoop()
{
int frames = 0;
float time = 0.0f;
while (!quit) {
timer.Reset();
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
ExitGame();
}
UpdateInput();
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
SetupCameraShader();
camera.Update();
Update(1.0f);
renderer2D.RenderClear();
renderer2D.DrawString("STRING", Vector2(0.0f, 0.0f), Color(255, 0, 0, 255));
renderer2D.Render();
window.SwapBuffers();
frames++;
if (timer.Elapsed() - time > 1.0f) {
time++;
Log("FPS: " + std::to_string(frames) + "\n");
frames = 0;
}
}
}
void App2D::SetupShaders()
{
shader.Free();
GLuint shaders[2] = {
shader.CreateShader("vertex.shader", GL_VERTEX_SHADER),
shader.CreateShader("fragment.shader", GL_FRAGMENT_SHADER)
}; shader.CreateAndUseProgram(shaders, 2);
GLint textures[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
};
glUniform1iv(0, 10, textures);
}
void App2D::SetupCameraShader()
{
GLint u_camera = shader.GetUniformLocation("u_camera");
Mat4 cameraMatrix = Mat4(1.0f);
cameraMatrix = camera.getCameraMatrix();
//cameraMatrix = textCamera.getCameraMatrix();
glUniformMatrix4fv(u_camera, 1, GL_FALSE, &(cameraMatrix[0][0]));
}