使用 VBO/IBO 的 OpenGL 纹理三角形 [英] Textured triangles with OpenGL using VBO/IBO
问题描述
我正在尝试使用包含屏幕坐标和纹理坐标的 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);}
此时我不知道如何继续.我在这里或任何地方都找不到任何对我有帮助的东西.我尝试了太多东西,以至于我可能使用了一些已弃用的东西或做了一些不受支持的东西,但我不知道是什么.
我可以看到几个问题:
在固定函数中,您必须显式调用
glEnable(GL_TEXTURE_2D)
来告诉 GL 您当前绑定的 2D 纹理将被应用(单独用于每个纹理单元).>您的顶点着色器不会根据您的变换状态来变换顶点.所有与矩阵相关的 GL 函数,如
立>glOrtho
、glTranslate
、glMatrixMode
都已弃用.您必须使用自己的矩阵函数(或类似 glm 的库)并通过统一(或其他方式)将矩阵提供给着色器.在兼容性配置文件中,您还可以使用 GLSL 内置uniforms,它允许您访问带有这些不推荐使用的函数的旧内置矩阵,但我强烈建议不要依赖不推荐使用的功能.无论哪种情况,您的着色器都必须实际应用您的顶点和模型视图转换,这通常归结为矩阵向量产品,例如projection * modelView * vec4(pos,1)
.至少可以说,您的属性指针很奇怪.您对顶点位置使用偏移量 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:
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).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 likeprojection * modelView * vec4(pos,1)
.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屋!