在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的问题的主要内容,如果未能解决你的问题,请参考以下文章

C++ openGl 纹理将图像映射到球体上

如何在OpenGL中将像素作为纹理绘制到多边形?

opengl 把纹理映射到立方体的六个面。

OpenGL 纹理未正确映射

OpenGL纹理映射总结

OpenGL 半球纹理映射