我正在尝试使用Android中的C ++渲染一个带有纹理的简单方块,但是在使用纹理时我遇到了一些麻烦。
以下是准备OpenGL ES的代码
margin: 0 -10px 0 0;
这里是顶点着色器:
// set up vertex data (and buffer(s)) and configure vertex attributes
// ------------------------------------------------------------------
float vertices[] = {
// positions // colors // texture coords
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // top right
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, // bottom right
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, // bottom left
-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f // top left
};
unsigned int indices[] = {
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// color attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
// texture coord attribute
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
片段着色器:
attribute vec4 vertexPosition;
attribute vec2 vertexTexCoord;
varying vec2 texCoord;
void main()
{
gl_Position = vec4(vertexPosition.x, vertexPosition.y, vertexPosition.z, 1.0);
texCoord = vertexTexCoord;
}
但是当我在Android上运行此代码时,纹理放置不正确。
原始纹理看起来像这样:
我做错了什么?
答案 0 :(得分:2)
在着色器代码中,您没有任何颜色属性。您只有顶点位置和纹理坐标:
attribute vec4 vertexPosition;
attribute vec2 vertexTexCoord;
但是在c ++代码中,您定义并启用索引为0,1和2的通用顶点属性数组。特别是纹理坐标与属性索引2的关联可能不起作用。
使用glGetAttribLocation
获取属性的属性索引(glLinkProgram
之后):
GLuint prog .....;
GLint vert_loc = glGetAttribLocation(prog , "vertexPosition");
GLint texc_loc = glGetAttribLocation(prog , "texCoord");
并改变你的代码,如下所示:
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// position attribute
glVertexAttribPointer(vert_loc, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(vert_loc);
// texture coord attribute
glVertexAttribPointer(texc_loc, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(texc_loc);
如果使用具有顶点坐标,颜色属性和纹理坐标的顶点着色器,则代码可能有效:
attribute vec3 aPos;
attribute vec3 aColor;
attribute vec2 aTexCoord;
varying vec3 ourColor;
varying vec2 texCoord;
void main()
{
gl_Position = vec4(aPos.xyz, 1.0);
ourColor = aColor;
texCoord = aTexCoord;
}
但是,无法保证aPos
,aColor
和aTexCoord
的属性索引是连续的0,1,2。这取决于硬件和OpenGL驱动程序。因此,您应该使用glGetAttribLocation
来获取属性索引。
此外,您必须使用着色器代码中的所有属性。未使用的属性变为无效。这意味着它没有添加到资源中,也没有属性索引。
见OpenGL ES 2 Specifications - 2.10.4 Shader Variables - p. 32:
如果通用属性变量由编译器和链接器确定在执行着色器时可以访问该属性,则该属性变量被认为是活动的。在顶点着色器中声明但从未使用过的属性变量不被视为活动。如果编译器和链接器无法做出确定的决定,则属性将被视为活动。
.....
要确定程序使用的活动顶点属性集,并确定其类型,请使用以下命令:
void GetActiveAttrib( uint program, uint index, sizei bufSize, sizei *length, int *size, enum *type, char *name );
.....
成功链接程序对象后,可以查询属性变量名称与索引的绑定。命令
int GetAttribLocation( uint program, const char *name );
答案 1 :(得分:0)
着色器出现问题。我已按如下方式更改了着色器:
attribute vec3 aPos;
attribute vec3 aColor;
attribute vec2 aTexCoord;
varying vec3 ourColor;
varying vec2 texCoord;
void main()
{
gl_Position = vec4(aPos.xyz, 1.0);
ourColor = aColor;
texCoord = aTexCoord;
}
和片段:
precision mediump float;
varying vec3 ourColor;
varying vec2 texCoord;
uniform sampler2D texSampler2D;
void main()
{
gl_FragColor = texture2D(texSampler2D, texCoord);
}
但有两件事我不明白: