使用 VBO 和元素数组索引的 OpenGL 纹理

Posted

技术标签:

【中文标题】使用 VBO 和元素数组索引的 OpenGL 纹理【英文标题】:OpenGL texturing using VBO and element array indexing 【发布时间】:2012-09-08 22:38:18 【问题描述】:

我正在尝试将元素索引与存储在矢量类型中的顶点和纹理坐标一起使用。

我的问题是纹理没有在我的矩形上正确渲染。

这里是相关的着色器初始化:

prog = f.compile_shaders(vshader, fshader);
const char* uniform_name = "mvp";
this->uni_mvp = glGetUniformLocation(prog, uniform_name);
if (this->uni_mvp == -1) 
    fprintf(stderr, "Could not bind uniform %s\n", uniform_name);
    return;


uniform_name = "texData";
this->uni_texdata = glGetUniformLocation(prog, uniform_name);
if (this->uni_texdata == -1) 
    fprintf(stderr, "Could not bind uniform %s\n", uniform_name);
    return;

和顶点着色器:

layout(location = 0) in vec4 coord3d;
layout(location = 1) in vec2 texcoord;
uniform mat4 mvp;
out vec2 uv;

void main(void) 
    gl_Position = mvp * coord3d;
    uv = texcoord;

和片段着色器:

in vec2 uv;
out vec3 color;

uniform sampler2D texData;

void main()
    color = texture2D(texData, uv).rgb;

这是我相关的BUFFER初始化代码:

    glGenVertexArrays(1, &this->vao);
    glBindVertexArray(this->vao);

    glm::vec2 bar;
    bar.x = 0.0; bar.y = 0.0;
    texcoords.push_back(bar);
    bar.x = 1.0; bar.y = 0.0;
    texcoords.push_back(bar);
    bar.x = 1.0; bar.y = 1.0;
    texcoords.push_back(bar);
    bar.x = 0.0; bar.y = 1.0;
    texcoords.push_back(bar);


    glm::vec4 foo;
    foo.x = 0.0; foo.y = 0.0; foo.z = 0; foo.w = 1.0;
    vertices.push_back(foo);
    foo.x = 10.0; foo.y = 0.0; foo.z = 0; foo.w = 1.0;
    vertices.push_back(foo);
    foo.x = 10.0; foo.y = 10.0; foo.z = 0; foo.w = 1.0;
    vertices.push_back(foo);
    foo.x = 0.0; foo.y = 10.0; foo.z = 0; foo.w = 1.0;
    vertices.push_back(foo);

    elements.push_back(0);
    elements.push_back(1);
    elements.push_back(2);
    elements.push_back(3);

    glGenBuffers(1, &this->tbo);
    glBindBuffer(GL_ARRAY_BUFFER, this->tbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(texcoords) * sizeof(texcoords[0]), texcoords.data(), GL_STATIC_DRAW);

    glGenBuffers(1, &this->vbo);
    glBindBuffer(GL_ARRAY_BUFFER, this->vbo);
    glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(vertices[0]), vertices.data(), GL_STATIC_DRAW);

    glGenBuffers(1, &this->ibo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->ibo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, elements.size() * sizeof(elements[0]), elements.data(), GL_STATIC_DRAW);

这是我相关的TEXTURE初始化代码:

    glGenTextures(1, &this->texture_id);
glBindTexture(GL_TEXTURE_2D, this->texture_id);

int k = 12;
GLubyte image[12][12][3];
for ( int i = 0; i < k; i++ ) 
    for ( int j = 0; j < k; j++ ) 
        GLubyte c = (((i & 0x8) == 0) ^ ((j & 0x8)  == 0)) * 255;
        image[i][j][0]  = c;
        image[i][j][1]  = c;
        image[i][j][2]  = c;
    

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);    
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, k, k, 0, GL_RGB, GL_UNSIGNED_BYTE, image);

这里是相关的渲染/显示代码:

    glUseProgram(this->prog);
glBindVertexArray(this->vao);
glUniformMatrix4fv(this->uni_mvp, 1, GL_FALSE, glm::value_ptr(f.mvp));

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,  this->texture_id);
glUniform1i(this->uni_texdata, 0);

glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, this->vbo);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);

glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, this->tbo);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->ibo);
glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &size);
glDrawElements(GL_QUADS, size / sizeof(GLushort), GL_UNSIGNED_SHORT, 0);

glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);

glBindVertexArray(0);

这段代码用纹理渲染我的矩形,但是纹理是错误的(只是没有在矩形上正确显示)。据我所知,这个简单示例的纹理坐标应该是正确的。索引和纹理是否存在问题 - 我如何执行此操作的顶点坐标?

这是我的绿色背景上的渲染图片:

我期待一个矩形黑白棋盘(12 部分)。

好的,添加最后一个纹理坐标后,渲染如下:

UDPATE: 当创建更大的棋盘纹理时,例如GLubyte image[16][16][3];,我得到以下渲染:

我还注意到我的 .raw 文件可以正确呈现。我仍然希望在我的棋盘纹理中看到 16 x 16 的正方形吗?

【问题讨论】:

这还不足以找到问题所在。例如,我看不到您在哪里创建程序。 我现在添加了着色器代码。没有那么多,只是设置了两个统一变量。然后在渲染/显示功能中使用该程序。 我也很确定纹理很好,因为我之前已经成功地使用了一些不同的代码。我不认为我的顶点数组对象使用在这里是最佳的,但这也不应该与问题相关.. sizeof(texcoords) 应该是texcoords.size() 您只需通过push_back 方法将3 个坐标对添加到您的texcoords 设置中。我假设您也想添加第 4 个坐标对。 【参考方案1】:

我不认为你的 OpenGL 有什么问题了,尽管我认为你的纹理生成函数没有达到你的预期。

for ( int i = 0; i < k; i++ ) 
    for ( int j = 0; j < k; j++ ) 
        GLubyte c = (((i & 0x8) == 0) ^ ((j & 0x8)  == 0)) * 255;
        ...
    

您从左到右有 16 个纹素,并且在 X 或 Y 方向上每隔 8 个颜色交替一次。

为什么您认为这会产生 12 个(或 16 个)跳棋?如果你想在每个增量上交替颜色,你应该删除&amp; 0x8

【讨论】:

以上是关于使用 VBO 和元素数组索引的 OpenGL 纹理的主要内容,如果未能解决你的问题,请参考以下文章

使用 VBO/IBO 的 OpenGL 纹理三角形

Android OpenGL ES2 一个 VBO 的许多纹理

OpenGL 索引和数组纹理

Android OpenGL 1.1 FBO 和 VBO 支持

如何将元素映射到 OpenGL VBO 中的颜色?

OpenGL- glDrawElements 只绘制第一个元素