使用 VBO/IBO 的 OpenGL 纹理三角形 [英] Textured triangles with OpenGL using VBO/IBO

查看:39
本文介绍了使用 VBO/IBO 的 OpenGL 纹理三角形的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用包含屏幕坐标和纹理坐标的 VBO 以及带有索引的 IBO 绘制两个带纹理的三角形以制作一个正方形.但是我遇到了一个问题.在不使用着色器的情况下,我获得了两个三角形的正确大小和位置,但无论我如何尝试都没有纹理.使用着色器,我得到了一个纹理,但三角形大小错误,位置错误,并且没有以任何方式使用纹理坐标.

创建纹理

 glGenTextures(1, &texture);glBindTexture(GL_TEXTURE_2D,纹理);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);glTexImage2D(GL_TEXTURE_2D, 0, nOfColors,surface->w,surface->h, 0,纹理格式,GL_UNSIGNED_BYTE,表面-> 像素);glBindTexture(GL_TEXTURE_2D, NULL);

填写 VBO 和 IBO(TileData 是一个有两个大小为 2 的数组的结构体)

 index.push_back(0);index.push_back(1);index.push_back(2);index.push_back(0);index.push_back(2);index.push_back(3);图块数据图块;tile.texCoord[0] = 0/imageSizeX;tile.texCoord[1] = 0/imageSizeY;tile.worldCoord[0] = 0;tile.worldCoord[1] = 0;tiles.push_back(tile);tile.texCoord[0] = (0 + texWidth)/imageSizeX;tile.texCoord[1] = 0/imageSizeY;tile.worldCoord[0] = 0 + texWidth;tile.worldCoord[1] = 0;tiles.push_back(tile);tile.texCoord[0] = (0 + texWidth)/imageSizeX;tile.texCoord[1] = (0 + texHeight)/imageSizeY;tile.worldCoord[0] = 0 + texWidth;tile.worldCoord[1] = 0 + texHeight;tiles.push_back(tile);tile.texCoord[0] = 0/imageSizeX;tile.texCoord[1] = (0 + texHeight)/imageSizeY;tile.worldCoord[0] = 0;tile.worldCoord[1] = 0 + texHeight;tiles.push_back(tile);

这给代码给了我世界坐标和纹理坐标:

0, 0 0, 016, 0 0.25, 016, 16 0.25, 10, 16 0, 1

生成我的缓冲区

 glGenBuffers(1, &vboID);glBindBuffer(GL_ARRAY_BUFFER, vboID);glBufferData(GL_ARRAY_BUFFER, tile.size() * sizeof(TileData), &tiles[0], GL_STATIC_DRAW);glGenBuffers(1, &iboID);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID);glBufferData(GL_ELEMENT_ARRAY_BUFFER, index.size() * sizeof(GLuint), &indices[0], GL_STATIC_DRAW);glBindBuffer(GL_ARRAY_BUFFER, 0);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

使用着色器绘制功能

 glMatrixMode(GL_PROJECTION);glLoadIdentity();glOrtho(camera.x, camera.x + 320, camera.y + 240, camera.y, -1.0f, 1.0f);glClear(GL_COLOR_BUFFER_BIT);glUseProgram(shaderHandler.programID);glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D,纹理);GLint texLocation = glGetUniformLocation(shaderHandler.programID, "tex");glUniform1i(texLocation, 0);glEnableVertexAttribArray(0);glBindBuffer(GL_ARRAY_BUFFER, vboID);glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(CGame::TileData), (GLvoid *)0);glEnableVertexAttribArray(1);glBindBuffer(GL_ARRAY_BUFFER, vboID);glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(CGame::TileData), (GLvoid*)offsetof(CGame::TileData, CGame::TileData::worldCoord));glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID);glDrawElements(GL_TRIANGLES,索引->大小(),GL_UNSIGNED_INT,(GLvoid*)0);glDisableVertexAttribArray(0);glDisableVertexAttribArray(1);glBindTexture(GL_TEXTURE_2D, 0);SDL_GL_SwapWindow(窗口);

结果带着色器

没有着色器的绘制功能(上面的代码如果把shaderprogram解开也可以得到和这个一样的结果)

 glEnableClientState(GL_VERTEX_ARRAY);glEnableClientState(GL_TEXTURE_COORD_ARRAY);glClientActiveTexture(GL_TEXTURE0);glBindBuffer(GL_ARRAY_BUFFER, vboID);glVertexPointer(2, GL_FLOAT, sizeof(CGame::TileData), (GLvoid*)0);glTexCoordPointer(2, GL_FLOAT, sizeof(CGame::TileData), (GLvoid*)offsetof(CGame::TileData, CGame::TileData::worldCoord));glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D,纹理);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID);glDrawElements(GL_TRIANGLES,索引->大小(),GL_UNSIGNED_INT,(GLvoid*)0);glDisableClientState(GL_TEXTURE_COORD_ARRAY);glDisableClientState(GL_VERTEX_ARRAY);glBindBuffer(GL_ARRAY_BUFFER, 0);glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);glBindTexture(GL_TEXTURE_2D, 0);SDL_GL_SwapWindow(窗口);

结果无着色器

顶点着色器

#version 330vec2 vert 中的布局(位置 = 0);vec2 vertTexCoord 中的布局(位置 = 1);出 vec2 fragTexCoord;无效主(){fragTexCoord = vertTexCoord;gl_Position = vec4(vert, 0, 1);}

片段着色器

#version 330均匀采样器2D tex;在 vec2 fragTexCoord 中;出 vec4 finalColor;无效主(){finalColor = texture2D(tex, fragTexCoord);}

此时我不知道如何继续.我在这里或任何地方都找不到任何对我有帮助的东西.我尝试了太多东西,以至于我可能使用了一些已弃用的东西或做了一些不受支持的东西,但我不知道是什么.

解决方案

我可以看到几个问题:

  1. 在固定函数中,您必须显式调用glEnable(GL_TEXTURE_2D) 来告诉 GL 您当前绑定的 2D 纹理将被应用(单独用于每个纹理单元).

  2. 您的顶点着色器不会根据您的变换状态来变换顶点.所有与矩阵相关的 GL 函数,如 glOrthoglTranslateglMatrixMode 都已弃用.您必须使用自己的矩阵函数(或类似 glm 的库)并通过统一(或其他方式)将矩阵提供给着色器.在兼容性配置文件中,您还可以使用 GLSL 内置uniforms,它允许您访问带有这些不推荐使用的函数的旧内置矩阵,但我强烈建议不要依赖不推荐使用的功能.无论哪种情况,您的着色器都必须实际应用您的顶点和模型视图转换,这通常归结为矩阵向量产品,例如 projection * modelView * vec4(pos,1).

  3. 至少可以说,您的属性指针很奇怪.您对顶点位置使用偏移量 0,对 texture 坐标使用 offsetof(...::worldCoord) 偏移量.现在,根据您定义成员的顺序,两者可能指向内存中完全相同的值,这将解释您提到的并且不以任何方式使用纹理坐标"部分.

I'm trying to draw out two textured triangles to make a square using a VBO containing the coordinates on the screen and coordinates of the texture and an IBO with the indices. However I'm running into a problem. Without using a shader I get the correct size and position of the two triangles but no texture no matter how I try. With a shader I get a texture but the triangle is wrong size, in the wrong position and not using the texture coordinates in any way.

Creating the texture

        glGenTextures(1, &texture);

        glBindTexture(GL_TEXTURE_2D, texture);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

        glTexImage2D(GL_TEXTURE_2D, 0, nOfColors, surface->w, surface->h, 0,
                        texture_format, GL_UNSIGNED_BYTE, surface->pixels);

        glBindTexture(GL_TEXTURE_2D, NULL);

Filling the VBO and IBO (TileData is a struct with two size 2 arrays)

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

    TileData tile;

    tile.texCoord[0] = 0 / imageSizeX;
    tile.texCoord[1] = 0 / imageSizeY;
    tile.worldCoord[0] = 0;
    tile.worldCoord[1] = 0;
    tiles.push_back(tile);

    tile.texCoord[0] = (0 + texWidth) / imageSizeX;
    tile.texCoord[1] = 0 / imageSizeY;
    tile.worldCoord[0] = 0 + texWidth;
    tile.worldCoord[1] = 0;
    tiles.push_back(tile);

    tile.texCoord[0] = (0 + texWidth) / imageSizeX;
    tile.texCoord[1] = (0 + texHeight) / imageSizeY;
    tile.worldCoord[0] = 0 + texWidth;
    tile.worldCoord[1] = 0 + texHeight;
    tiles.push_back(tile);

    tile.texCoord[0] = 0 / imageSizeX;
    tile.texCoord[1] = (0 + texHeight) / imageSizeY;
    tile.worldCoord[0] = 0;
    tile.worldCoord[1] = 0 + texHeight;
    tiles.push_back(tile);

This gives code gives me the world coordinates and texture coordinates:

0, 0          0, 0
16, 0         0.25, 0
16, 16        0.25, 1
0, 16         0, 1

Generate my buffers

        glGenBuffers(1, &vboID);
        glBindBuffer(GL_ARRAY_BUFFER, vboID);
        glBufferData(GL_ARRAY_BUFFER, tiles.size() * sizeof(TileData), &tiles[0], GL_STATIC_DRAW);

        glGenBuffers(1, &iboID);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID); 
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLuint), &indices[0], GL_STATIC_DRAW);

        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

Draw function with shader

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(camera.x, camera.x + 320, camera.y + 240, camera.y, -1.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glUseProgram(shaderHandler.programID);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);
    GLint texLocation = glGetUniformLocation(shaderHandler.programID, "tex");

    glUniform1i(texLocation, 0);

    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, vboID);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(CGame::TileData), (GLvoid *)0);

    glEnableVertexAttribArray(1);
    glBindBuffer(GL_ARRAY_BUFFER, vboID);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(CGame::TileData), (GLvoid*)offsetof(CGame::TileData, CGame::TileData::worldCoord));

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID); 
    glDrawElements(GL_TRIANGLES, indices->size(), GL_UNSIGNED_INT, (GLvoid*)0);

    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);
    glBindTexture(GL_TEXTURE_2D, 0);

    SDL_GL_SwapWindow(window);

Result With shader

Draw function without shader (The above code can also get the same result as this one if I unlink the shaderprogram)

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glClientActiveTexture(GL_TEXTURE0);

    glBindBuffer(GL_ARRAY_BUFFER, vboID);
    glVertexPointer(2, GL_FLOAT, sizeof(CGame::TileData), (GLvoid*)0);
    glTexCoordPointer(2, GL_FLOAT, sizeof(CGame::TileData), (GLvoid*)offsetof(CGame::TileData, CGame::TileData::worldCoord));

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texture);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID); 
    glDrawElements(GL_TRIANGLES, indices->size(), GL_UNSIGNED_INT, (GLvoid*)0);

    glDisableClientState(GL_TEXTURE_COORD_ARRAY); 
    glDisableClientState(GL_VERTEX_ARRAY);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindTexture(GL_TEXTURE_2D, 0);

    SDL_GL_SwapWindow(window);

Resulst Without shader

Vertex Shader

#version 330
layout(location = 0) in vec2 vert;
layout(location = 1) in vec2 vertTexCoord;

out vec2 fragTexCoord;

void main() 
{
    fragTexCoord = vertTexCoord; 
    gl_Position = vec4(vert, 0, 1);
}

Fragment Shader

#version 330

uniform sampler2D tex; 
in vec2 fragTexCoord; 
out vec4 finalColor; 

void main() 
{
    finalColor = texture2D(tex, fragTexCoord);
}

At this point I've no idea how to continue. I can't find anything that helps me on here or anywhere. I've tried so much things that I probably use something deprecated or doing something unsupported but I can't figure out what.

解决方案

I can see a couple of issues:

  1. In the fixed function, you have to explicitely call glEnable(GL_TEXTURE_2D) to tell the GL that your currently bound 2D texture shall be applied (separately for each texture unit).

  2. Your vertex shader does never transform the vertices according to your transform state. All the matrix-related GL functions like glOrtho, glTranslate, glMatrixMode are deprecated. You have to use your own matrix functions (or a library like glm) and supply the matrices to the shader via uniforms (or other means). In a compatiblity profile, you could also use the GLSL builtin uniforms which allow you to access the old builtin matrices set with those deprecated functions, but I strongly recommend to not rely on deprecated functionality. In either case, your shader has to actually apply your vertex and modelview transformations, which typically boils down to matrix-vector products like projection * modelView * vec4(pos,1).

  3. Your attribute pointers are weird, to say the least. You use an offset of 0 for the vertex positions, and and offset of offsetof(...::worldCoord) for the texture coordinates. Now depending on which order your members are defined, both might point to the exact same values in memory, which would explain the "and not using the texture coordinates in any way" part you mentioned.

这篇关于使用 VBO/IBO 的 OpenGL 纹理三角形的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆