【问题标题】:Problem mapping textures to VBO in OpenGL在OpenGL中将纹理映射到VBO的问题
【发布时间】: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;
}

【问题讨论】:

    标签: opengl textures shader vbo


    【解决方案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()。

    【讨论】:

      猜你喜欢
      • 2011-08-30
      • 2014-11-19
      • 1970-01-01
      • 1970-01-01
      • 2013-07-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-04
      相关资源
      最近更新 更多