Привязать текстуру к шейдеру GLSL в Objective-C

Я работаю под 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 в шейдере.

Используемый шейдер очень прост: он отображает только текстуру. Я проверил это под Кварцевым Композитором, и это работает хорошо.

Но здесь он только черный.

РЕДАКТИРОВАТЬ

Вот этот шейдер...

темя

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 ответ

Замените неисправную логику, которая применяет указатель координат текстуры, только когда шейдер равен 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 постоянно сохраняют единообразное состояние, когда вы настраиваете сэмплеры большую часть времени, когда они ссылаются на одну и ту же текстурную единицу в течение всего времени жизни программы. Поэтому имеет смысл устанавливать значения форм сэмплера сразу после связывания вашей программы и никогда не устанавливать их снова после этой точки.

Другие вопросы по тегам