1
votes

I'm working under Mac OSX and trying to map an image on a cube through a GLSL shader.

My method to display the cube (and the image, when it's not passing through a shader) is :

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();

As you can see, I'm checking, for this test, if there is a shader to be applied on my object (it's a wrapping that works really well.)

If there's no shader, I only enable the GL_TEXTURE_COORD_ARRAY, if there's one I try to bind the image to the sampler2D uniform in the shader.

The shader I'm using is very simple : it's only displaying the texture. I tested it under Quartz Composer and it works well.

But, here, it only display black.

EDIT

Here is the shader...

Vertex

varying vec2 texture_coordinate;

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

Fragment

varying vec2 texture_coordinate;
uniform sampler2D tex0;

void main()
{
gl_FragColor = gl_Color * texture2D(tex0, gl_TexCoord[0].xy);
}
1
Could you please actually show us the shader? For one thing, GL_TEXTURE_COORD_ARRAY is deprecated, you should be using vertex attributes. If you are not using vertex attributes, then you need to use the appropriate fixed-function GLSL reserved word (e.g. gl_MultiTexCoord0). And come to think of it, even if you were using that reserved word in your shader to get the texture coordinates, since you are not setting the texture coordinate pointer when shader is non-NULL this would not work anyhow.Andon M. Coleman
Thank you, I completed with the shader code. Even with your answer it isn't working... Would it be something in my GLSL ?Benoît Lahoz
Yes, the problem is you are using gl_TexCoord [0].xy. I would suggest you replace that with texture_coordinate in your fragment shader and you should be good to go. gl_TexCoord [n] can be used to store texture coordinates between the vertex and fragment shader stages, but it is a good idea to avoid using it if you ever want to migrate to modern OpenGL (where that particular reserved word does not exist). Alternatively, you could have set gl_TexCoord [0] = gl_MultiTexCoord0; in the vertex shader, but again I am trying to set you on a path that will help you transition to modern GLSL.Andon M. Coleman
Sorry, but no... It doesn't work. But, I'm beginning to get it, thanks to you. I guess when I'll be able to display this texture, my life will be like a dream :)Benoît Lahoz
By the way, do you really have 3D texture coordinates? If they are stored as 2D coordinates in an array, then you have passed OpenGL the wrong pointer information. I would usually expect to see: glTexCoordPointer(2, GL_FLOAT, sizeof(btVector2), &textureCoords[0].getX()); unless you are doing things like texture projection or 3D texturing.Andon M. Coleman

1 Answers

2
votes

Replace your faulty logic that only applies the texture coordinate pointer when shader is NULL with this instead:

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());

Later on, you also need to correct your cleanup code:

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

glDisableClientState(GL_TEXTURE_COORD_ARRAY);

Then, in your vertex shader when you need texture coordinates, use gl_MultiTexCoord0... pass this to your fragment shader using a varying.

While you are at it, do not bother setting the value of the tex0 sampler every time you draw. GLSL programs keep uniform state persistently, when you setup samplers the majority of the time they refer to the same texture unit for the entire program's lifetime. So it makes more sense to set the values of sampler uniforms immediately after you link your program and to never set them again after that point.