在 OpenGL 中将纹理映射到 VBO 时出现问题
我无法使用 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;
}
I'm having trouble getting a texture to map onto geometry properly with OpenGL. In fact I seem to have even broken the colour interpolation that used to work fine. I've created a test case in C99 that uses SDL, GLee and 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;
}
The only thing that renders is a plain blue square on top of the glClearColor.
Any help much appreciated.
Thanks for answers, I've attached fixed code for completeness.
#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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您没有正确启用顶点属性数组。
vertex_loc
,但您不应该依赖它)尝试以下操作:
编辑以添加:我不妨指出其他细节:
我只设置采样器位置一次。设置它往往会迫使驱动程序进行额外的工作,并且由于每次只将其设置为相同的纹理单元,因此您最好在初始化时进行设置。
你调用glBindBuffer(GL_ARRAY_BUFFER, 0)的地方并没有错,但我会把它放在VertexAttribPointer调用之后。当前绑定的缓冲区实际上只是这些调用的额外参数...并且它不会影响 glDrawArrays 调用本身。
You're not enabling the vertex attrib arrays correctly.
vertex_loc
, but you should not rely on it)Try the following:
Edit to add: I might as well point out other details:
I'd set the sampler location only once. setting it tends to force extra work in the driver, and since you'll only set it to the same texture unit every time, you might as well do it at initilization.
The place you call
glBindBuffer(GL_ARRAY_BUFFER, 0)
is not wrong, but I'd put it just after the VertexAttribPointer calls. The currently bound buffer is really just an extra argument to those calls... And it does not affect the glDrawArrays call itself.您的着色器包含子表达式
,这将使您的纹理在大多数显示器上基本上不可见,不是吗?
Your shader includes the subexpression
Which would make your texture essentially invisible on most displays, wouldn't it?
据我所知,在为 VBO 绑定纹理之前,您需要使用 glClientActiveTexture() 。
Afaik you need to use glClientActiveTexture() before binding a texture for a VBO.