在OpenGL中将纹理映射到VBO的问题
Posted
技术标签:
【中文标题】在OpenGL中将纹理映射到VBO的问题【英文标题】:Problem mapping textures to VBO in OpenGL 【发布时间】:2010-02-06 03:34:50 【问题描述】:我无法使用 OpenGL 将纹理正确映射到几何体上。事实上,我似乎甚至打破了过去可以正常工作的颜色插值。我在 C99 中创建了一个使用 SDL、GLee 和 SOIL 的测试用例。
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <SDL/SDL.h>
#include <GL/GLee.h>
#include <SOIL/SOIL.h>
static const char *vertex_source = " \
uniform mat4 projection; \
uniform mat4 view_model; \
\
attribute vec2 vertex; \
attribute vec2 texcoord; \
attribute vec4 colour; \
\
varying vec2 _texcoord; \
\
void main() \
\
gl_Position = gl_ModelViewProjectionMatrix * vec4(vertex, 0, 1); \
_texcoord = texcoord; \
gl_FrontColor = colour; \
";
static const char *fragment_source = " \
uniform sampler2D sampler0; \
\
varying vec2 _texcoord; \
\
void main() \
\
gl_FragColor = texture2D(sampler0, _texcoord) * 0.01 + gl_Color; \
";
typedef struct
GLfloat position[2];
GLfloat texcoord[2];
GLubyte colour[4];
Vertex;
static Vertex verts[] =
.position = 1, 1 ,
.texcoord = 1, 1 ,
.colour = 255, 0, 0, 255 ,
,
.position = -1, 1 ,
.texcoord = 0, 1 ,
.colour = 0, 255, 0, 255 ,
,
.position = -1, -1 ,
.texcoord = 0, 0 ,
.colour = 0, 0, 255, 255 ,
,
.position = 1, -1 ,
.texcoord = 1, 0 ,
.colour = 255, 255, 0, 255 ,
,
;
static GLuint vertex, fragment, program, vbo, texture;
static GLint sampler_loc, vertex_loc, texcoord_loc, colour_loc;
static void init()
SDL_Init(SDL_INIT_EVERYTHING);
SDL_SetVideoMode(800, 800, 0, SDL_OPENGL);
glClearColor(1, 0, 0, 0);
glMatrixMode(GL_PROJECTION);
glOrtho(-1, 1, -1, 1, -1, 1);
/* Shaders */
vertex = glCreateShader(GL_VERTEX_SHADER);
assert(vertex != 0);
fragment = glCreateShader(GL_FRAGMENT_SHADER);
assert(fragment != 0);
GLint length = strlen(vertex_source);
glShaderSource(vertex, 1, &vertex_source, &length);
length = strlen(fragment_source);
glShaderSource(fragment, 1, &fragment_source, &length);
glCompileShader(vertex);
glCompileShader(fragment);
program = glCreateProgram();
glAttachShader(program, vertex);
glAttachShader(program, fragment);
glLinkProgram(program);
sampler_loc = glGetUniformLocation(program, "sampler0");
vertex_loc = glGetAttribLocation(program, "vertex");
texcoord_loc = glGetAttribLocation(program, "texcoord");
colour_loc = glGetAttribLocation(program, "colour");
/* VBO */
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), &verts[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
/* Texture */
texture = SOIL_load_OGL_texture("test.png", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y);
assert(texture != 0);
static void draw()
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(sampler_loc, 0);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glScalef(.5, .5, .5);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glEnableVertexAttribArray(0);
glVertexAttribPointer(vertex_loc, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), offsetof(Vertex, position));
glVertexAttribPointer(texcoord_loc, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), offsetof(Vertex, texcoord));
glVertexAttribPointer(colour_loc, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(Vertex), offsetof(Vertex, colour));
glDrawArrays(GL_QUADS, 0, 4);
glDisableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glPopMatrix();
glUseProgram(0);
static void shutdown()
SDL_Quit();
int main()
init();
atexit(shutdown);
while(true)
static SDL_Event event;
while(SDL_PollEvent(&event))
switch(event.type)
case SDL_QUIT:
exit(0);
break;
default:
break;
draw();
SDL_GL_SwapBuffers();
if(glGetError() != GL_NO_ERROR)
printf("Error\n");
exit(1);
return 0;
唯一呈现的是 glClearColor 顶部的纯蓝色方块。
非常感谢任何帮助。
感谢您的回答,为了完整起见,我附上了固定代码。
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <SDL/SDL.h>
#include <GL/GLee.h>
#include <SOIL/SOIL.h>
static const char *vertex_source = " \
uniform mat4 projection; \
uniform mat4 view_model; \
\
attribute vec2 vertex; \
attribute vec2 texcoord; \
attribute vec4 colour; \
\
varying vec2 _texcoord; \
\
void main() \
\
gl_Position = gl_ModelViewProjectionMatrix * vec4(vertex, 0, 1); \
_texcoord = texcoord; \
gl_FrontColor = colour; \
";
static const char *fragment_source = " \
uniform sampler2D sampler0; \
\
varying vec2 _texcoord; \
\
void main() \
\
gl_FragColor = texture2D(sampler0, _texcoord) + gl_Color; \
";
typedef struct
GLfloat position[2];
GLfloat texcoord[2];
GLubyte colour[4];
Vertex;
static Vertex verts[] =
.position = 1, 1 ,
.texcoord = 1, 1 ,
.colour = 255, 0, 0, 255 ,
,
.position = -1, 1 ,
.texcoord = 0, 1 ,
.colour = 0, 255, 0, 255 ,
,
.position = -1, -1 ,
.texcoord = 0, 0 ,
.colour = 0, 0, 255, 255 ,
,
.position = 1, -1 ,
.texcoord = 1, 0 ,
.colour = 255, 255, 0, 255 ,
,
;
static GLuint vertex, fragment, program, vbo, texture;
static GLint sampler_loc, vertex_loc, texcoord_loc, colour_loc;
static void init()
SDL_Init(SDL_INIT_EVERYTHING);
SDL_SetVideoMode(800, 800, 0, SDL_OPENGL);
glClearColor(1, 0, 0, 0);
glMatrixMode(GL_PROJECTION);
glOrtho(-1, 1, -1, 1, -1, 1);
/* Shaders */
vertex = glCreateShader(GL_VERTEX_SHADER);
assert(vertex != 0);
fragment = glCreateShader(GL_FRAGMENT_SHADER);
assert(fragment != 0);
GLint length = strlen(vertex_source);
glShaderSource(vertex, 1, &vertex_source, &length);
length = strlen(fragment_source);
glShaderSource(fragment, 1, &fragment_source, &length);
glCompileShader(vertex);
glCompileShader(fragment);
program = glCreateProgram();
glAttachShader(program, vertex);
glAttachShader(program, fragment);
glLinkProgram(program);
sampler_loc = glGetUniformLocation(program, "sampler0");
vertex_loc = glGetAttribLocation(program, "vertex");
texcoord_loc = glGetAttribLocation(program, "texcoord");
colour_loc = glGetAttribLocation(program, "colour");
glUseProgram(program);
glUniform1i(sampler_loc, 0);
glUseProgram(0);
/* VBO */
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), &verts[0], GL_STATIC_DRAW);
glVertexAttribPointer(vertex_loc, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), offsetof(Vertex, position));
glVertexAttribPointer(texcoord_loc, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), offsetof(Vertex, texcoord));
glVertexAttribPointer(colour_loc, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(Vertex), offsetof(Vertex, colour));
glBindBuffer(GL_ARRAY_BUFFER, 0);
/* Texture */
texture = SOIL_load_OGL_texture("test.png", SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS | SOIL_FLAG_INVERT_Y);
assert(texture != 0);
static void draw()
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glScalef(.5, .5, .5);
glEnableVertexAttribArray(vertex_loc);
glEnableVertexAttribArray(texcoord_loc);
glEnableVertexAttribArray(colour_loc);
glDrawArrays(GL_QUADS, 0, 4);
glDisableVertexAttribArray(vertex_loc);
glDisableVertexAttribArray(texcoord_loc);
glDisableVertexAttribArray(colour_loc);
glBindTexture(GL_TEXTURE_2D, 0);
glPopMatrix();
glUseProgram(0);
static void shutdown()
SDL_Quit();
int main()
init();
atexit(shutdown);
while(true)
static SDL_Event event;
while(SDL_PollEvent(&event))
switch(event.type)
case SDL_QUIT:
exit(0);
break;
default:
break;
draw();
SDL_GL_SwapBuffers();
if(glGetError() != GL_NO_ERROR)
printf("Error\n");
exit(1);
return 0;
【问题讨论】:
【参考方案1】:您没有正确启用顶点属性数组。
您启用 0,这甚至可能不是您使用的东西(好吧,实际上,它可能是vertex_loc
,但您不应该依赖它)
你忽略了其他 2 个数组
尝试以下方法:
glEnableVertexAttribArray(vertex_loc);
glEnableVertexAttribArray(texcoord_loc);
glEnableVertexAttribArray(colour_loc);
编辑添加:我不妨指出其他细节:
我只设置一次采样器位置。设置它往往会在驱动程序中强制执行额外的工作,并且由于您每次只会将其设置为相同的纹理单元,因此您最好在初始化时进行。
你调用glBindBuffer(GL_ARRAY_BUFFER, 0)
的地方没有错,但我会把它放在 VertexAttribPointer 调用之后。当前绑定的缓冲区实际上只是这些调用的一个额外参数......而且它不会影响 glDrawArrays 调用本身。
【讨论】:
是的,我修好了。非常感谢。 (我用我的新代码更新了第一篇文章)【参考方案2】:您的着色器包含子表达式
texture2D(sampler0, _texcoord) * 0.01
这会使您的纹理在大多数显示器上基本上不可见,不是吗?
【讨论】:
啊,是的,但这不是问题所在。那是我到处玩的,看看颜色是从哪里来的。【参考方案3】:在为 VBO 绑定纹理之前,您需要使用 glClientActiveTexture()。
【讨论】:
以上是关于在OpenGL中将纹理映射到VBO的问题的主要内容,如果未能解决你的问题,请参考以下文章