0

我的 iOS 4 应用程序使用 OpenGL ES 2.0 并使用单一纹理渲染元素。我想使用多种不同的纹理来绘制元素,并且在让事情正常工作时遇到了问题。

我在顶点着色器中添加了一个变量来指示要应用的纹理:

...
attribute float TextureIn;
varying float TextureOut;

void main(void)
{ 
    ...
    TextureOut = TextureIn;
}

我在片段着色器中使用该值来选择纹理:

...
varying lowp float TextureOut;

uniform sampler2D Texture0;
uniform sampler2D Texture1;

void main(void)
{   
    if (TextureOut == 1.0) 
    {
        gl_FragColor = texture2D(Texture1, TexCoordOut);
    }
    else // 0
    {
        gl_FragColor = texture2D(Texture0, TexCoordOut);
    }
}

编译着色器:

...
_texture = glGetAttribLocation(programHandle, "TextureIn");
glEnableVertexAttribArray(_texture);
_textureUniform0 = glGetUniformLocation(programHandle, "Texture0");
_textureUniform1 = glGetUniformLocation(programHandle, "Texture1");

初始化/设置:

...
GLuint _texture;
GLuint _textureUniform0;
GLuint _textureUniform1;

...
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D); // ?
glBindTexture(GL_TEXTURE_2D, _textureUniform0);
glUniform1i(_textureUniform0, 0);

glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D); // ?
glBindTexture(GL_TEXTURE_2D, _textureUniform1);
glUniform1i(_textureUniform1, 1);

glActiveTexture(GL_TEXTURE0);

使成为:

...
glVertexAttribPointer(_texture, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 13));    

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _textureUniform0);
glUniform1i(_textureUniform0, 0);

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, _textureUniform1);
glUniform1i(_textureUniform1, 1);

glActiveTexture(GL_TEXTURE0);

glDrawElements(GL_TRIANGLES, indicesCountA, GL_UNSIGNED_SHORT, (GLvoid*) (sizeof(GLushort) * 0));
glDrawElements(GL_TRIANGLES, indicesCountB, GL_UNSIGNED_SHORT, (GLvoid*) (sizeof(GLushort) * indicesCountA));
glDrawElements(GL_TRIANGLES, indicesCountC, GL_UNSIGNED_SHORT, (GLvoid*) (sizeof(GLushort) * (indicesCountA + indicesCountB)));

我希望动态应用与顶点关联的纹理,但它似乎只能识别 GL_TEXTURE0。

我能够更改纹理的唯一方法是将每个纹理与 GL_TEXTURE0 相关联,然后绘制:

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _textureUniformX);
glUniform1i(_textureUniformX, 0);
glDrawElements(GL_TRIANGLES, indicesCountA, GL_UNSIGNED_SHORT, (GLvoid*) (sizeof(GLushort) * 0));
...

为了渲染所有纹理,我需要为每个纹理单独调用 glDrawElements(),并且我已经读到 glDrawElements() 调用对性能有很大影响,应该尽量减少调用次数。这就是为什么我试图动态地指定每个顶点使用哪个纹理。

完全有可能我的理解是错误的,或者我遗漏了一些重要的东西。我对 OpenGL 还是很陌生,我学的越多,我就越觉得我有更多的东西要学。

必须可以使用除 GL_TEXTURE0 以外的纹理,但我还没有弄清楚如何使用。

任何指导或方向将不胜感激。

4

1 回答 1

2

Can it be you're just experiencing floating point rounding issues? There shouldn't be any (except if a single privimitve shares vertices with different textures), but just to be sure replace this TextureOut == 1.0 with a TextureOut > 0.5 or something the like.

As a general advice, you are correct in that the number of draw calls should be reduced as much a possible, but your approach is quite odd. You are buying draw call reduction with fragment shader branching. Your approach also doesn't scale well with the overall number of textures, since you always need all textures in separate texture units.

The usual approach to reduce texture switches is to put all the textures into a single large texture, a so-called texture atlas, and use the texture coordinates to select the appropriate subregion in this texture. This also has some pitfalls (which are an entirely different question), but nothing comes for free.

EDIT: Oh wait, I see what you're actually doing wrong

glBindTexture(GL_TEXTURE_2D, _textureUniform0);

You're binding a texture to the current texture unit, but instead of the texture object you give this function a uniform location, which is complete rubbish (but might even work in some weird circumstances, since both uniform locations and texture objects are themselves just integers). Of course you have to bind the actual texture.

于 2012-09-18T08:28:41.900 回答