在 OpenGL 中应用着色器时不会渲染纹理
Texture doesn't get rendered when applying a shader in OpenGL
按照教程,我正在尝试使用 FreeType 在 OpenGL 中呈现文本。因此,灰度 8 位图像用作每个字符的纹理,图像的每个字节对应于纹理的红色分量。
为了渲染其他颜色的文字,建议使用Shader。但是,当使用提供的着色器时,我看到的不是彩色字母,而是彩色框,就好像根本没有涉及纹理一样。
下面是没有着色器的样子:
下面是着色器的外观:
(盒子也移动了它的位置)
这是顶点着色器代码:
#version 330 core
layout (location = 0) in vec4 vertex;
out vec2 TexCoords;
void main() {
gl_Position = vec4(vertex.xy, 0.0, 1.0);
TexCoords = vertex.zw;
}
这是片段着色器代码:
#version 330 core
in vec2 TexCoords;
out vec4 color;
uniform sampler2D text;
uniform vec4 textColor;
void main() {
vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);
color = textColor * sampled;
}
这是在屏幕上呈现的代码:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Shader here
glUseProgram(shaderProgram);
glUniform4f(
glGetUniformLocation(shaderProgram, "textColor"),
0.0f, 1.0f, 0.0f, 1.0f
);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texID);
glUniform1i(glGetUniformLocation(shaderProgram, "text"), 0);
// Draw here
glBegin(GL_QUADS);
glTexCoord2f(1., 0.);
glVertex2f(20. / WIDTH, 20. / HEIGHT);
glTexCoord2f(0., 0.);
glVertex2f(100. / WIDTH, 20. / HEIGHT);
glTexCoord2f(0., 1.);
glVertex2f(100. / WIDTH, 100. / HEIGHT);
glTexCoord2f(1., 1.);
glVertex2f(20. / WIDTH, 100. / HEIGHT);
glEnd();
另外,这是完整的代码:
#include <stdio.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <freetype2/freetype/freetype.h>
const unsigned int WIDTH = 640;
const unsigned int HEIGHT= 480;
const char *vertex_shader_src =
"#version 330 core\n"
"layout (location = 0) in vec4 vertex;\n"
"out vec2 TexCoords;\n"
"void main() {\n"
"gl_Position = vec4(vertex.xy, 0.0, 1.0);\n"
"TexCoords = vertex.zw;}[=13=]";
const char *frag_shader_src =
"#version 330 core\n"
"in vec2 TexCoords;\n"
"out vec4 color;\n"
"uniform sampler2D text;\n"
"uniform vec4 textColor;\n"
"void main() {\n"
"vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);\n"
"color = textColor * sampled;}[=13=]";
int main() {
// -------------------------------------------------------------------------
// WINDOW INITIALIZATION
GLFWwindow *window;
glfwInit();
window = glfwCreateWindow(640, 480, "SHADER", NULL, NULL);
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
glClearColor(0., 0. , 0., 1.);
glColor4f(1., 1., 1., 1.);
glPointSize(1.);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, (WIDTH*1.)/HEIGHT, 1., 0, 1., -1.);
glViewport(0, 0, WIDTH, HEIGHT);
// -------------------------------------------------------------------------
// SHADER INITIALIZATION
glewInit();
int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertex_shader_src, NULL);
glCompileShader(vertexShader);
int fragShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragShader, 1, &frag_shader_src, NULL);
glCompileShader(fragShader);
int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragShader);
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragShader);
// -------------------------------------------------------------------------
// TEXTURE FOR A SINGLE CHARACTER
FT_Library ft;
if (FT_Init_FreeType(&ft)) {
printf("Error in FT_Init_FreeType\n");
return 1;
}
FT_Face face;
if (FT_New_Face(ft, "Ubuntu-R.ttf", 0, &face)) {
printf("Error in FT_New_Face\n");
return 1;
}
FT_Set_Pixel_Sizes(face, 0, 96);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
if (FT_Load_Char(face, 'A', FT_LOAD_RENDER)) {
printf("Error in FT_Load_Char\n");
return 1;
}
unsigned int texID;
glGenTextures(1, &texID);
glBindTexture(GL_TEXTURE_2D, texID);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RED,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0, GL_RED, GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
FT_Done_Face(face);
FT_Done_FreeType(ft);
// -------------------------------------------------------------------------
// MAIN LOOP
while (!glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Shader here
glUseProgram(shaderProgram);
glUniform4f(
glGetUniformLocation(shaderProgram, "textColor"),
0.0f, 1.0f, 0.0f, 1.0f
);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texID);
glUniform1i(glGetUniformLocation(shaderProgram, "text"), 0);
// Draw here
glBegin(GL_QUADS);
glTexCoord2f(1., 0.);
glVertex2f(20. / WIDTH, 20. / HEIGHT);
glTexCoord2f(0., 0.);
glVertex2f(100. / WIDTH, 20. / HEIGHT);
glTexCoord2f(0., 1.);
glVertex2f(100. / WIDTH, 100. / HEIGHT);
glTexCoord2f(1., 1.);
glVertex2f(20. / WIDTH, 100. / HEIGHT);
glEnd();
glUseProgram(0);
glFlush();
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteProgram(shaderProgram);
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
我怀疑问题要么是因为我实际上没有将纹理发送到着色器,要么是着色器错误。
您正在使用 Legacy OpenGL OpenGL and you are drawing the geometry by immediate mode glBegin
/glEnd
sequences. You cannot access the texture coordinates which are set by glTexCoord
by a general vertex shader input. See What are the Attribute locations for fixed function pipeline in OpenGL 4.0++ core profile?.
您必须将顶点着色器降级到 GLSL 版本 1.20 (OpenGL Shading Language 1.20 Specification),并且必须通过 gl_Vertex
访问顶点坐标,通过 gl_MultiTexCoord0
:
访问纹理坐标
#version 120
varying vec2 TexCoords;
void main()
{
gl_Position = vec4(gl_Vertex.xy, 0.0, 1.0);
TexCoords = gl_MultiTexCoord0.st;
}
如果要使用问题中的着色器,则必须通过 glVertexAttribPointer
(see Vertex Specification) and you have to draw the geometry by glDrawArrays
:
指定顶点属性数组
例如:
float vertex_attributes[] = {
20. / WIDTH, 20. / HEIGHT, 1., 0.,
100. / WIDTH, 20. / HEIGHT, 0., 0.,
100. / WIDTH, 100. / HEIGHT, 0., 1.,
20. / WIDTH, 100. / HEIGHT, 1., 1.
};
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, &vertex_attributes);
glEnableVertexAttribArray(0);
glDrawArrays(GL_QUADS, 0, 4);
glDisableVertexAttribArray(0);
请注意,glewInit()
必须在 glfwMakeContextCurrent()
之后但在任何 OpenGL 指令之前完成。
按照教程,我正在尝试使用 FreeType 在 OpenGL 中呈现文本。因此,灰度 8 位图像用作每个字符的纹理,图像的每个字节对应于纹理的红色分量。
为了渲染其他颜色的文字,建议使用Shader。但是,当使用提供的着色器时,我看到的不是彩色字母,而是彩色框,就好像根本没有涉及纹理一样。
下面是没有着色器的样子:
下面是着色器的外观:
(盒子也移动了它的位置)
这是顶点着色器代码:
#version 330 core
layout (location = 0) in vec4 vertex;
out vec2 TexCoords;
void main() {
gl_Position = vec4(vertex.xy, 0.0, 1.0);
TexCoords = vertex.zw;
}
这是片段着色器代码:
#version 330 core
in vec2 TexCoords;
out vec4 color;
uniform sampler2D text;
uniform vec4 textColor;
void main() {
vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);
color = textColor * sampled;
}
这是在屏幕上呈现的代码:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Shader here
glUseProgram(shaderProgram);
glUniform4f(
glGetUniformLocation(shaderProgram, "textColor"),
0.0f, 1.0f, 0.0f, 1.0f
);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texID);
glUniform1i(glGetUniformLocation(shaderProgram, "text"), 0);
// Draw here
glBegin(GL_QUADS);
glTexCoord2f(1., 0.);
glVertex2f(20. / WIDTH, 20. / HEIGHT);
glTexCoord2f(0., 0.);
glVertex2f(100. / WIDTH, 20. / HEIGHT);
glTexCoord2f(0., 1.);
glVertex2f(100. / WIDTH, 100. / HEIGHT);
glTexCoord2f(1., 1.);
glVertex2f(20. / WIDTH, 100. / HEIGHT);
glEnd();
另外,这是完整的代码:
#include <stdio.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <freetype2/freetype/freetype.h>
const unsigned int WIDTH = 640;
const unsigned int HEIGHT= 480;
const char *vertex_shader_src =
"#version 330 core\n"
"layout (location = 0) in vec4 vertex;\n"
"out vec2 TexCoords;\n"
"void main() {\n"
"gl_Position = vec4(vertex.xy, 0.0, 1.0);\n"
"TexCoords = vertex.zw;}[=13=]";
const char *frag_shader_src =
"#version 330 core\n"
"in vec2 TexCoords;\n"
"out vec4 color;\n"
"uniform sampler2D text;\n"
"uniform vec4 textColor;\n"
"void main() {\n"
"vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);\n"
"color = textColor * sampled;}[=13=]";
int main() {
// -------------------------------------------------------------------------
// WINDOW INITIALIZATION
GLFWwindow *window;
glfwInit();
window = glfwCreateWindow(640, 480, "SHADER", NULL, NULL);
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
glClearColor(0., 0. , 0., 1.);
glColor4f(1., 1., 1., 1.);
glPointSize(1.);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, (WIDTH*1.)/HEIGHT, 1., 0, 1., -1.);
glViewport(0, 0, WIDTH, HEIGHT);
// -------------------------------------------------------------------------
// SHADER INITIALIZATION
glewInit();
int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertex_shader_src, NULL);
glCompileShader(vertexShader);
int fragShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragShader, 1, &frag_shader_src, NULL);
glCompileShader(fragShader);
int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragShader);
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragShader);
// -------------------------------------------------------------------------
// TEXTURE FOR A SINGLE CHARACTER
FT_Library ft;
if (FT_Init_FreeType(&ft)) {
printf("Error in FT_Init_FreeType\n");
return 1;
}
FT_Face face;
if (FT_New_Face(ft, "Ubuntu-R.ttf", 0, &face)) {
printf("Error in FT_New_Face\n");
return 1;
}
FT_Set_Pixel_Sizes(face, 0, 96);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
if (FT_Load_Char(face, 'A', FT_LOAD_RENDER)) {
printf("Error in FT_Load_Char\n");
return 1;
}
unsigned int texID;
glGenTextures(1, &texID);
glBindTexture(GL_TEXTURE_2D, texID);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RED,
face->glyph->bitmap.width,
face->glyph->bitmap.rows,
0, GL_RED, GL_UNSIGNED_BYTE,
face->glyph->bitmap.buffer
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
FT_Done_Face(face);
FT_Done_FreeType(ft);
// -------------------------------------------------------------------------
// MAIN LOOP
while (!glfwWindowShouldClose(window)) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Shader here
glUseProgram(shaderProgram);
glUniform4f(
glGetUniformLocation(shaderProgram, "textColor"),
0.0f, 1.0f, 0.0f, 1.0f
);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texID);
glUniform1i(glGetUniformLocation(shaderProgram, "text"), 0);
// Draw here
glBegin(GL_QUADS);
glTexCoord2f(1., 0.);
glVertex2f(20. / WIDTH, 20. / HEIGHT);
glTexCoord2f(0., 0.);
glVertex2f(100. / WIDTH, 20. / HEIGHT);
glTexCoord2f(0., 1.);
glVertex2f(100. / WIDTH, 100. / HEIGHT);
glTexCoord2f(1., 1.);
glVertex2f(20. / WIDTH, 100. / HEIGHT);
glEnd();
glUseProgram(0);
glFlush();
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteProgram(shaderProgram);
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
我怀疑问题要么是因为我实际上没有将纹理发送到着色器,要么是着色器错误。
您正在使用 Legacy OpenGL OpenGL and you are drawing the geometry by immediate mode glBegin
/glEnd
sequences. You cannot access the texture coordinates which are set by glTexCoord
by a general vertex shader input. See What are the Attribute locations for fixed function pipeline in OpenGL 4.0++ core profile?.
您必须将顶点着色器降级到 GLSL 版本 1.20 (OpenGL Shading Language 1.20 Specification),并且必须通过 gl_Vertex
访问顶点坐标,通过 gl_MultiTexCoord0
:
#version 120
varying vec2 TexCoords;
void main()
{
gl_Position = vec4(gl_Vertex.xy, 0.0, 1.0);
TexCoords = gl_MultiTexCoord0.st;
}
如果要使用问题中的着色器,则必须通过 glVertexAttribPointer
(see Vertex Specification) and you have to draw the geometry by glDrawArrays
:
例如:
float vertex_attributes[] = {
20. / WIDTH, 20. / HEIGHT, 1., 0.,
100. / WIDTH, 20. / HEIGHT, 0., 0.,
100. / WIDTH, 100. / HEIGHT, 0., 1.,
20. / WIDTH, 100. / HEIGHT, 1., 1.
};
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, &vertex_attributes);
glEnableVertexAttribArray(0);
glDrawArrays(GL_QUADS, 0, 4);
glDisableVertexAttribArray(0);
请注意,glewInit()
必须在 glfwMakeContextCurrent()
之后但在任何 OpenGL 指令之前完成。