【问题标题】:Bind texture to GLSL shader in Objective-C在 Objective-C 中将纹理绑定到 GLSL 着色器
【发布时间】:2013-09-17 17:38:22
【问题描述】:

我在 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);
}

【问题讨论】:

  • 你能给我们看看着色器吗?一方面,GL_TEXTURE_COORD_ARRAY 已被弃用,您应该使用顶点属性。如果您不使用顶点属性,则需要使用适当的固定功能 GLSL 保留字(例如 gl_MultiTexCoord0)。想一想,即使您在着色器中使用该保留字来获取纹理坐标,因为当着色器为非 NULL 时您没有设置纹理坐标指针,这无论如何都不起作用。
  • 谢谢,我完成了着色器代码。即使您的回答也无法正常工作...会是我的 GLSL 中的内容吗?
  • 是的,问题是您使用的是gl_TexCoord [0].xy。我建议您在片段着色器中将其替换为 texture_coordinate,然后您应该就可以了。 gl_TexCoord [n] 可用于存储顶点和片段着色器阶段之间的纹理坐标,但如果您想迁移到现代 OpenGL(其中不存在该特定保留字),最好避免使用它。或者,您可以在顶点着色器中设置gl_TexCoord [0] = gl_MultiTexCoord0;,但我再次尝试为您设置一条有助于您过渡到现代 GLSL 的路径。
  • 对不起,但不...它不起作用。但是,我开始明白了,谢谢你。我想当我能够展示这种纹理时,我的生活会像梦一样:)
  • 顺便问一下,你真的有 3D 纹理坐标吗?如果它们以二维坐标的形式存储在数组中,那么您向 OpenGL 传递了错误的指针信息。我通常希望看到:glTexCoordPointer(2, GL_FLOAT, sizeof(btVector2), &textureCoords[0].getX());,除非您正在执行纹理投影或 3D 纹理等操作。

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


【解决方案1】:

将你的错误逻辑替换为仅在着色器为 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 程序持续保持统一状态,当您设置采样器时,它们在整个程序的生命周期中大部分时间都引用相同的纹理单元。因此,在链接程序后立即设置采样器制服的值并在此之后不再设置它们更有意义。

【讨论】:

    猜你喜欢
    • 2013-06-13
    • 2012-12-27
    • 2013-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-27
    • 1970-01-01
    相关资源
    最近更新 更多