在Objective-C中将纹理绑定到GLSL着色器

时间:2013-09-17 17:38:22

标签: objective-c opengl glsl shader texture-mapping

我在Mac OSX下工作并尝试通过GLSL着色器在多维数据集上映射图像。

我显示多维数据集的方法(以及图像,当它没有通过着色器时)是:

glPushMatrix();
{

    glTranslatef(position.getX(), position.getY(), position.getZ());
    glRotatef(angle, axis.getX(), axis.getY(), axis.getZ());

    if (bodyImage &&
        textureCoords != 0 &&
        [bodyImage lockTextureRepresentationWithColorSpace:CGColorSpaceCreateDeviceRGB() forBounds:[bodyImage imageBounds]]) {

        [bodyImage bindTextureRepresentationToCGLContext:cgl_ctx textureUnit:GL_TEXTURE0 normalizeCoordinates:YES];
        texture = [bodyImage textureName];


        if(shader != nil) {

            glUseProgramObjectARB([shader programObject]);
            glUniform1iARB([shader getUniformLocation:"tex0"], 0);

        } else {

            glEnableClientState(GL_TEXTURE_COORD_ARRAY);
            glTexCoordPointer(3, GL_FLOAT, sizeof(btVector3), &textureCoords[0].getX());

        }


    }



    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);


    glVertexPointer(3, GL_FLOAT, sizeof(btVector3), &vertices[0].getX());
    glNormalPointer(GL_FLOAT, sizeof(btVector3), &normals[0].getX());


    glDrawElements(GL_TRIANGLES, indicesCount, GL_UNSIGNED_INT, indices);


    glDisableClientState(GL_NORMAL_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);




    if (bodyImage) {

        if (shader != nil) {
            glUseProgramObjectARB(NULL);
        } else {
            glDisableClientState(GL_TEXTURE_COORD_ARRAY);
        }


        [bodyImage unbindTextureRepresentationFromCGLContext:cgl_ctx textureUnit:GL_TEXTURE0];
        [bodyImage unlockTextureRepresentation];

    }


}
glPopMatrix();

正如你所看到的,我正在检查,测试是否有一个着色器应用于我的对象(这是一个非常好的包装。)

如果没有着色器,我只启用GL_TEXTURE_COORD_ARRAY,如果有的话我尝试将图像绑定到着色器中的sampler2D制服。

我使用的着色器非常简单:它只显示纹理。我在Quartz Composer下进行了测试,效果很好。

但是,在这里,它只显示黑色。

修改

这是着色器......

顶点

varying vec2 texture_coordinate;

void main() {
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
texture_coordinate = vec2(gl_MultiTexCoord0);
}

片段

varying vec2 texture_coordinate;
uniform sampler2D tex0;

void main()
{
gl_FragColor = gl_Color * texture2D(tex0, gl_TexCoord[0].xy);
}

1 个答案:

答案 0 :(得分:2)

替换您的错误逻辑,该逻辑仅在着色器为NULL时才应用纹理坐标指针,而不是:

if(shader != nil) {
  glUseProgramObjectARB([shader programObject]);
  glUniform1iARB([shader getUniformLocation:"tex0"], 0);
}

// You need texture coordinates in shaders too!
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(3, GL_FLOAT, sizeof(btVector3), &textureCoords[0].getX());

稍后,您还需要更正清理代码:

if (shader != nil) {
  glUseProgramObjectARB(NULL);
}

glDisableClientState(GL_TEXTURE_COORD_ARRAY);

然后,在您需要纹理坐标的顶点着色器中,使用gl_MultiTexCoord0 ...使用变化将其传递给片段着色器。

当你在这里时,每次画画时都不要费心设置tex0采样器的值。 GLSL程序持续保持统一状态,当您在大多数时间设置采样器时,它们在整个程序的生命周期内引用相同的纹理单元。因此,在链接程序后立即设置采样器制服的值更有意义,并且在此之后再也不要再设置它们。