5

前几天我问了一个关于使用 SDL 渲染 TTF 字体的问题,并被指向 SDL_TTFL 我尝试使用 SDL_TTF 库,但我得到的只是屏幕上的垃圾

我已经包含了我的着色器,这对于这个程序来说非常简单,还有我用来将文本加载到表面并将其绑定到纹理的剪辑。我根本不想在这里做任何疯狂的事情。你能看到我做错了什么吗?我不太确定如何调试着色器等。

片段着色器(frag.glsl):

#version 330
in vec2 texCoord;
in vec4 fragColor;

out vec3 finalColor;

uniform sampler2D myTextureSampler;
void main() {
    finalColor = texture( myTextureSampler, texCoord ).rgb;
}

顶点着色器 (vert.glsl)

#version 330

in vec3 vert;
in vec4 color;
in vec2 texcoord;

out vec4 fragColor;
out vec2 texCoord;

void main() {
    fragColor = color;
    gl_Position = vec4(vert, 1);
    texCoord = texcoord;
}

字体加载 (loadFont.cpp)

//Initialise TTF
if( TTF_Init() == -1 )
    throw std::runtime_error("SDL_TTF failed to initialise.");

//Load the texture
font = TTF_OpenFont( filePath.c_str(), 12 );
if(!font)
    throw std::runtime_error("Couldn't load: "+ filePath);

TTF_SetFontStyle(font, TTF_STYLE_NORMAL);

surface = TTF_RenderUTF8_Blended(font, "Hello", this->textColor);
Uint8 colors = surface->format->BytesPerPixel;
int texture_format;
if (colors == 4) {   // alpha
    if (surface->format->Rmask == 0x000000ff)
        texture_format = GL_RGBA;
    else
        texture_format = GL_BGRA;
} else {             // no alpha
    if (surface->format->Rmask == 0x000000ff)
        texture_format = GL_RGB;
    else
        texture_format = GL_BGR;
}
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);

glTexImage2D(GL_TEXTURE_2D, 0, colors, surface->w, surface->h, 0,
             texture_format, GL_UNSIGNED_BYTE, surface->pixels);
SDL_FreeSurface(surface);

顶点属性设置

GLfloat vertices[] = {
    //X    Y      Z     R     G     B     A     U    V
    -1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 0.f, 1.f,
     1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 1.f, 1.f,
    -1.0f, -0.4f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 0.f, 0.f,
     1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 1.f, 1.f,
     1.0f, -0.4f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 1.f, 0.f,
    -1.0f, -0.4f, 0.0f, 1.0f, 0.0f, 0.0f, 0.5f, 0.f, 0.f

};


glGenVertexArrays(1, &_vao);
glBindVertexArray(_vao);

glGenBuffers(1, &_vbo);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

glEnableVertexAttribArray(program->attrib("vert"));
glVertexAttribPointer(program->attrib("vert"), 3, GL_FLOAT, GL_FALSE, 9*sizeof(GLfloat), NULL);

glEnableVertexAttribArray(program->attrib("color"));
glVertexAttribPointer(program->attrib("color"), 4, GL_FLOAT, GL_TRUE,  9*sizeof(GLfloat), (const GLvoid*)(3 * sizeof(GLfloat)));

glEnableVertexAttribArray(program->attrib("texcoord"));
glVertexAttribPointer(program->attrib("texcoord"), 2, GL_FLOAT, GL_TRUE,  9*sizeof(GLfloat), (const GLvoid*)(7 * sizeof(GLfloat)));

根据下面的评论,我已附加了用于顶点属性的代码。

编辑:在此后已被删除的回复中,有人询问 SDL_TTF 是返回 3 个还是 4 个频道。它正在返回 BGRA 图像。我尝试将片段着色器更改为

片段着色器

#version 330
in vec2 texCoord;
in vec4 fragColor;

out vec4 finalColor;

uniform sampler2D myTextureSampler;
void main() {
    finalColor = texture( myTextureSampler, texCoord ).rgba;
}

注意 vec4,并使用 rgba 而不是 rgb。这只会导致一个黑色矩形。我还尝试使用 SDL_LoadBMP() 生成表面,它给出了完全相同的结果。

4

2 回答 2

3

您的来电

glTexImage2D(GL_TEXTURE_2D,0,颜色,表面->w,表面->h,0,纹理格式,GL_UNSIGNED_BYTE,表面->像素);

是个问题。

第三个参数错误:

http://www.opengl.org/sdk/docs/man/xhtml/glTexImage2D.xml

内部格式

                Specifies the number of color components in the texture.
                Must be one of base internal formats given in Table 1,
                one of the sized internal formats given in Table 2, or one
                of the compressed internal formats given in Table 3, below.

我怀疑你希望你是 GL_RGBA (或者你希望 opengl 以什么格式存储你的纹理)

编辑:

我现在才看到它,但是您在片段着色器中只使用了 3 个通道。Blended 功能要求您使用 4 个通道,否则 Alpha 通道将被弄乱。

我认为您的“主要”问题出在其他地方,因为那应该只是使整个表面的颜色保持不变。(不是您看到的“垃圾”)

我很快写了这个程序,它主要做你在做的事情。我认为它比我的存储库更能帮助你,因为它直截了当。

#include <GL/glew.h>

#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>
#include <SDL2/SDL_ttf.h>

#include <string>
#include <iostream>

using namespace std;

SDL_Window *window = NULL;
SDL_GLContext context = NULL;
TTF_Font* font = NULL;
SDL_Surface* surface = NULL;

//OpenGL Objects
GLuint vao;
GLuint vbo;
GLuint texture;

//Shader Objects
GLuint program;
GLuint vs;
GLuint fs;

//Sampler Object
GLuint uniformSampler;

//Callback Function
APIENTRY GLvoid debugMessageCallbackFunction( GLenum source, GLenum type, GLuint id, GLenum severity,
                                 GLsizei length, const GLchar* message, GLvoid* userParam)
{
  cerr << endl << "\t" << message << endl;
}

//The shaders are identical to yours
const string fragmentShaderString = 
                "#version 130\n" // My laptop can't do OpenGL 3.3 so 3.0 will have to do
                "in vec2 texCoord;\n"
                "in vec4 fragColor;\n"
                "\n"
                "out vec4 finalColor;\n"
                "\n"
                "uniform sampler2D myTextureSampler;\n"
                "void main() {\n"
                "  finalColor = texture( myTextureSampler, texCoord ) * fragColor;\n"
                "}";

const string vertexShaderString = 
                "#version 130\n"
                "\n"
                "in vec3 vert;\n"
                "in vec4 color;\n"
                "in vec2 texcoord;\n"
                "\n"
                "out vec4 fragColor;\n"
                "out vec2 texCoord;\n"

                "void main() {\n"
                "  fragColor = color;\n"
                "  gl_Position = vec4(vert, 1);\n"
                "  texCoord = texcoord;\n"
                "}\n";

//Your vertices, but I changed alpha to 1.0f
const GLfloat vertices[] = 
{
    //X    Y      Z     R     G     B     A     U    V
    -1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.f, 1.f,
     1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.f, 1.f,
    -1.0f, -0.4f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.f, 0.f,
     1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.f, 1.f,
     1.0f, -0.4f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.f, 0.f,
    -1.0f, -0.4f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.f, 0.f
};

int main(int argc, char* args[])
{
  //Create Window and Context
  window = SDL_CreateWindow("SDL Text with OpenGL", 0, 0, 640, 480, SDL_WINDOW_OPENGL);

  //Set Core Context
  SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, 3 );
  SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, 1 );
  SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

  context = SDL_GL_CreateContext(window);

  //Simple OpenGL State Settings
  glViewport( 0.f, 0.f, 640.f, 480.f);
  glClearColor( 0.f, 0.f, 0.f, 1.f);

  //Init Glew
  //Set glewExperimental for Core Context
  glewExperimental=true;
  glewInit();

  //Set Blending 
  //Required so that the alpha channels show up from the surface
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  //Simple callback function for GL errors
  glDebugMessageCallbackARB(debugMessageCallbackFunction, NULL);

  //Create Shaders
  vs = glCreateShader(GL_VERTEX_SHADER);
  fs = glCreateShader(GL_FRAGMENT_SHADER);

  //Source Pointers
  const GLchar* vsSource= &vertexShaderString[0];
  const GLchar* fsSource = &fragmentShaderString[0];

  //Set Source
  glShaderSource(vs, 1, &vsSource, NULL);
  glShaderSource(fs, 1, &fsSource, NULL);

  //Compile Shaders
  glCompileShader(fs);
  glCompileShader(vs);

  //Create Shader Program
  program = glCreateProgram();

  //Attach Shaders to Program
  glAttachShader(program, vs);
  glAttachShader(program, fs);

  //No need for shaders anymore
  glDeleteShader(vs);
  glDeleteShader(fs);

  //Set Attribute Locations
  glBindAttribLocation(program, 0, "vert");
  glBindAttribLocation(program, 1, "color");
  glBindAttribLocation(program, 2, "texcoord");

  //Link Program
  glLinkProgram(program);

  //Setup VAO and VBO
  glGenVertexArrays(1, &vao);
  glGenBuffers(1, &vbo);

  glBindVertexArray(vao);
  glBindBuffer(GL_ARRAY_BUFFER, vbo);

  glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 9 * 6, vertices, GL_STATIC_DRAW);

  glEnableVertexAttribArray(0);
  glEnableVertexAttribArray(1);
  glEnableVertexAttribArray(2);

  glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 9 * sizeof(GLfloat), NULL);
  glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 9 * sizeof(GLfloat),(GLvoid*)(3*sizeof(GLfloat)));
  glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 9 * sizeof(GLfloat),(GLvoid*)(7*sizeof(GLfloat)));

  //Init TTF
  TTF_Init();

  //Open Font
  font = TTF_OpenFont("DroidSansFallbackFull.ttf", 30);

  SDL_Color color = {255, 255, 255, 255};

  //Create Surface
  surface = TTF_RenderUTF8_Blended(font, "This is TEXT!", color);

  //Your format checker
  GLenum format = (surface->format->BytesPerPixel==3)?GL_RGB:GL_RGBA;

  //Create OpenGL Texture
  glGenTextures(1, &texture);
  glBindTexture(GL_TEXTURE_2D, texture);
  glTexImage2D( GL_TEXTURE_2D, 0, format, surface->w, surface->h, 0, 
              format, GL_UNSIGNED_BYTE, surface->pixels);

  //Set Some basic parameters
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

  //Set up Sampler
  glActiveTexture(GL_TEXTURE0);
  glBindTexture(GL_TEXTURE_2D, texture);

  uniformSampler = glGetUniformLocation(program, "myTextureSampler");
  //It defaults to using GL_TEXTURE0, so it's not necessary to set it
  //in this program it's generally a good idea.

  //-------------------------------------------------------------------------------------- 
  // DRAW STAGE
  //-------------------------------------------------------------------------------------- 

  glUseProgram(program);

  //glBindVertexArray(vao); - still in use

  glClear(GL_COLOR_BUFFER_BIT);

  glDrawArrays(GL_TRIANGLES, 0, 6);

  SDL_GL_SwapWindow(window);

  //Sleep for 2s before closing
  SDL_Delay(2000);
}

我没有做任何错误检查或关闭任何资源,因为它只是作为参考而不是被使用。

通常我不使用glew,但是编写代码来手动获取这样一个小程序的功能似乎毫无意义。

它编译为

g++ source.cpp -g -lSDL2 -lSDL2_ttf -lGL -GLEW -o demo

在 Linux 上。您可能需要对 Windows 进行一些调整(头文件可能会略有变化,库也会发生变化),我认为它可以在 Mac 上正常工作。

编辑2:

要使用 mingw 在 Windows 上编译它,您需要将 APIENTRY 添加到回调函数,并且 main 应该有参数。更改代码以反映这一点。

经过测试,它可以在 Windows 和 linux 上运行。(前提是您的实现可以访问 GL_ARB_debug_callback 扩展,如果不只是将其注释掉)

于 2013-11-04T14:15:32.033 回答
0

效果很好,只需编辑const GLfloat vertices[]数组即可一致地更改文本颜色。对于纯色文本,数组中的所有 RGB 分量都等于 1.0f,并在color. 对于多色文本,首先使用 将纹理渲染为白色SDL_Color color = { 255, 255, 255, 255 };,然后编辑数组,如下所示。

float width = (float)surface->w;
float height = (float)surface->h;

// alpha to 1.0f
const GLfloat vertices[] = {
    // X         Y          Z     R     G     B     A     U     V
    -1.0, -height / width, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f,
    1.0f, -height / width, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
    -1.0f, height / width, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f,
    1.0f, -height / width, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
    1.0f,  height / width, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
    -1.0f, height / width, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f
};

在 OpenGL 中使用 SDL 作为纹理渲染的多色文本

于 2018-02-08T18:54:38.783 回答