4 votes

OpenGL ES 2.0 Comment dessiner plusieurs VBOs avec différents programmes de shaders dans iOS

J'essaie de pirater le template générique Xcode iOS OpenGL Game pour dessiner deux objets vertex buffer et les rendre avec des shaders GLSL différents. Je "pense" que je rends les deux VBO correctement (parce que je les vois tous les deux quand je les fais passer par le premier programme de shaders), mais mon second shader ne semble pas rendre mon second objet du tout.

Voici les données relatives aux sommets des deux carrés :

GLfloat gCubeVertexData[36] = 
{
    // Data layout for each line below is:
    // positionX, positionY, positionZ,     normalX, normalY, normalZ,

    0.5f, 0.5f, 0.5f,          0.0f, 0.0f, 1.0f,
    -0.5f, 0.5f, 0.5f,         0.0f, 0.0f, 1.0f,
    0.5f, -0.5f, 0.5f,         0.0f, 0.0f, 1.0f,
    0.5f, -0.5f, 0.5f,         0.0f, 0.0f, 1.0f,
    -0.5f, 0.5f, 0.5f,         0.0f, 0.0f, 1.0f,
    -0.5f, -0.5f, 0.5f,        0.0f, 0.0f, 1.0f

};

GLfloat fooVertexData[36] = 
{
    // Data layout for each line below is:
    // positionX, positionY, positionZ,     normalX, normalY, normalZ

    0.5f, 0.5f, 0.5f,          0.0f, 0.0f, 1.0f,
    -0.5f, 0.5f, 0.5f,         0.0f, 0.0f, 1.0f,
    0.5f, -0.5f, 0.5f,         0.0f, 0.0f, 1.0f,
    0.5f, -0.5f, 0.5f,         0.0f, 0.0f, 1.0f,
    -0.5f, 0.5f, 0.5f,         0.0f, 0.0f, 1.0f,
    -0.5f, -0.5f, 0.5f,        0.0f, 0.0f, 1.0f
};

Voici où j'essaie de générer deux VBO et de les lier aux données. Je ne sais pas exactement à quoi sert le 'glBindVertexArrayOES(0)' à la fin :

- (void)setupGL
{
    [EAGLContext setCurrentContext:self.context];

    [self loadShaders];

    //---- First Vertex Array Object --------
    glGenVertexArraysOES(1, &_vertexArray1);
    glGenBuffers(1, &_vertexBuffer1);   

    glBindVertexArrayOES(_vertexArray1);

    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer1);
    glBufferData(GL_ARRAY_BUFFER, sizeof(gCubeVertexData), gCubeVertexData, GL_STATIC_DRAW);

    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(0));
    glEnableVertexAttribArray(GLKVertexAttribNormal);
    glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(12));

    //----- Second Vertex Array Object ----------
    glGenVertexArraysOES(1, &_vertexArray2);
    glGenBuffers(1, &_vertexBuffer2);

    glBindVertexArrayOES(_vertexArray2);

    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer2);
    glBufferData(GL_ARRAY_BUFFER, sizeof(fooVertexData), fooVertexData, GL_STATIC_DRAW);

    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(0));
    glEnableVertexAttribArray(GLKVertexAttribNormal);
    glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(12));

    glBindBuffer(GL_ARRAY_BUFFER,0);
    glBindVertexArrayOES(0);
}

J'utilise ce code de mise à jour pour animer les matrices modèle-vue-projection :

- (void)update
{
    _rotation += self.timeSinceLastUpdate * 0.2f;

    float aspect = fabsf(self.view.bounds.size.width / self.view.bounds.size.height);

    GLKMatrix4 projectionMatrix = GLKMatrix4MakeOrtho(-1.0f, 1.0f, -1.0f / aspect, 1.0f / aspect, -10.0f, 10.0f);
    GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.5f, 0.0f, 0.0f);
    modelViewMatrix = GLKMatrix4Multiply(modelViewMatrix, GLKMatrix4MakeZRotation(0.0 - _rotation));
    _modelViewProjectionMatrix = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix);

    GLKMatrix4 modelViewMatrix2 = GLKMatrix4MakeTranslation(-0.5f, 0.0f, 0.0f);
    modelViewMatrix2 = GLKMatrix4Multiply(modelViewMatrix2, GLKMatrix4MakeZRotation(_rotation));
    _modelViewProjectionMatrix2 = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix2);
}

Lorsque j'appelle le shader '_program2', je ne vois pas le deuxième carré :

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
    glClearColor(0.65f, 0.65f, 0.65f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glBindVertexArrayOES(_vertexArray1);
    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer1);

    glUseProgram(_program);
    glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
    glDrawArrays(GL_TRIANGLES, 0, 6);

    ///////// second object and shader program:
    glBindVertexArrayOES(_vertexArray2);
    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer2);

    glUseProgram(_program2);
    glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX2], 1, 0, _modelViewProjectionMatrix2.m);
    glDrawArrays(GL_TRIANGLES, 0, 6);

}

J'ai essayé de dupliquer le code de chargement du premier shader pour charger le second. Je pense que je fais quelque chose de mal ici, mais je ne suis pas sûr de savoir quoi :

- (BOOL)loadShaders
{
    GLuint vertShader, fragShader, vertShader2, fragShader2;
    NSString *vertShaderPathname, *fragShaderPathname, *vertShaderPathname2, *fragShaderPathname2;

    // Create shader program.
    _program = glCreateProgram();

    // Create and compile vertex shader.
    vertShaderPathname = [[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"vsh"];
    if (![self compileShader:&vertShader type:GL_VERTEX_SHADER file:vertShaderPathname]) {
        NSLog(@"Failed to compile vertex shader");
        return NO;
    }

    // Create and compile fragment shader.
    fragShaderPathname = [[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"fsh"];
    if (![self compileShader:&fragShader type:GL_FRAGMENT_SHADER file:fragShaderPathname]) {
        NSLog(@"Failed to compile fragment shader");
        return NO;
    }

    // Attach vertex shader to program.
    glAttachShader(_program, vertShader);

    // Attach fragment shader to program.
    glAttachShader(_program, fragShader);

    // Bind attribute locations.
    // This needs to be done prior to linking.
    glBindAttribLocation(_program, ATTRIB_VERTEX, "position");

    // Link program.
    if (![self linkProgram:_program]) {
        NSLog(@"Failed to link program: %d", _program);

        if (vertShader) {
            glDeleteShader(vertShader);
            vertShader = 0;
        }
        if (fragShader) {
            glDeleteShader(fragShader);
            fragShader = 0;
        }
        if (_program) {
            glDeleteProgram(_program);
            _program = 0;
        }

        return NO;
    }

    // Get uniform locations.
    uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX] = glGetUniformLocation(_program, "modelViewProjectionMatrix");

    // Release vertex and fragment shaders.
    if (vertShader) {
        glDetachShader(_program, vertShader);
        glDeleteShader(vertShader);
    }
    if (fragShader) {
        glDetachShader(_program, fragShader);
        glDeleteShader(fragShader);
    }

    ///////////////// the second shader:

    _program2 = glCreateProgram();

    vertShaderPathname2 = [[NSBundle mainBundle] pathForResource:@"Shader2" ofType:@"vsh"];
    if (![self compileShader:&vertShader2 type:GL_VERTEX_SHADER file:vertShaderPathname2]) {
        NSLog(@"Failed to compile vertex shader2");
        return NO;
    }

    fragShaderPathname2 = [[NSBundle mainBundle] pathForResource:@"Shader2" ofType:@"fsh"];
    if (![self compileShader:&fragShader2 type:GL_FRAGMENT_SHADER file:fragShaderPathname2]) {
        NSLog(@"Failed to compile fragment shader2");
        return NO;
    }

        glAttachShader(_program2, vertShader2);
        glAttachShader(_program2, fragShader2);

        glBindAttribLocation(_program2, ATTRIB_VERTEX2, "position2");

    if (![self linkProgram:_program2]) {
        NSLog(@"Failed to link program: %d", _program2);

        if (vertShader2) {
            glDeleteShader(vertShader2);
            vertShader2 = 0;
        }
        if (fragShader2) {
            glDeleteShader(fragShader2);
            fragShader2 = 0;
        }
        if (_program2) {
            glDeleteProgram(_program2);
            _program2 = 0;
        }

        return NO;
    }

        uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX2] = glGetUniformLocation(_program2, "modelViewProjectionMatrix2");
    if (vertShader2) {
        glDetachShader(_program2, vertShader2);
        glDeleteShader(vertShader2);
    }
    if (fragShader2) {
        glDetachShader(_program2, fragShader2);
        glDeleteShader(fragShader2);
    }    

    return YES;
}

- (BOOL)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file
{
    GLint status;
    const GLchar *source;

    source = (GLchar *)[[NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil] UTF8String];
    if (!source) {
        NSLog(@"Failed to load vertex shader");
        return NO;
    }

    *shader = glCreateShader(type);
    glShaderSource(*shader, 1, &source, NULL);
    glCompileShader(*shader);

#if defined(DEBUG)
    GLint logLength;
    glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength);
    if (logLength > 0) {
        GLchar *log = (GLchar *)malloc(logLength);
        glGetShaderInfoLog(*shader, logLength, &logLength, log);
        NSLog(@"Shader compile log:\n%s", log);
        free(log);
    }
#endif

    glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
    if (status == 0) {
        glDeleteShader(*shader);
        return NO;
    }

    return YES;
}

- (BOOL)linkProgram:(GLuint)prog
{
    GLint status;
    glLinkProgram(prog);

#if defined(DEBUG)
    GLint logLength;
    glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
    if (logLength > 0) {
        GLchar *log = (GLchar *)malloc(logLength);
        glGetProgramInfoLog(prog, logLength, &logLength, log);
        NSLog(@"Program link log:\n%s", log);
        free(log);
    }
#endif

    glGetProgramiv(prog, GL_LINK_STATUS, &status);
    if (status == 0) {
        return NO;
    }

    return YES;
}

- (BOOL)validateProgram:(GLuint)prog
{
    GLint logLength, status;

    glValidateProgram(prog);
    glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
    if (logLength > 0) {
        GLchar *log = (GLchar *)malloc(logLength);
        glGetProgramInfoLog(prog, logLength, &logLength, log);
        NSLog(@"Program validate log:\n%s", log);
        free(log);
    }

    glGetProgramiv(prog, GL_VALIDATE_STATUS, &status);
    if (status == 0) {
        return NO;
    }

    return YES;
}

Mes nuanceurs de vert et de fragment sont simples :

// vert shader1:
attribute vec4 position;
uniform mat4 modelViewProjectionMatrix;

void main()
{
    gl_Position = modelViewProjectionMatrix * position;
}

// vert shader2:
attribute vec4 position2;
uniform mat4 modelViewProjectionMatrix2;

void main()
{
    gl_Position = modelViewProjectionMatrix2 * position2;
}

// frag shader(s):
void main()
{
    gl_FragColor = vec4(0.12,0.32,0.54,1.0);
}

2voto

Matisse VerDuyn Points 833

La chose la plus importante à retenir avec OpenGL ES, c'est que vous utilisez un langage procédural au sein d'un langage OOP.

Vous ne pouvez lier que un tableau de sommets dans la mémoire tampon des vertex à la fois.

Le fait de lier deux tableaux de sommets à l'OBV, l'un après l'autre, et d'appliquer ensuite des transformations, ne transformera que le dernier tableau de sommets attaché à l'OBV.

Dans votre boucle principale, vous devez parcourir la liste de vos tableaux de sommets. Pour chaque tableau de sommets, vous devez le lier au VBO, puis effectuer toutes les transformations nécessaires.

2voto

Jerome Dewhurst Points 81

Le principal problème était l'emplacement de l'attribut "position" pour le deuxième vertex shader. J'avais utilisé un ATTRIB_VERTEX2 "séparé" dans mon enum. Une fois que j'ai lié l'emplacement de l'attribut 'position' à ATTRIB_VERTEX, j'ai pu voir le second VBO avec l'autre programme de shader appliqué... Voici le code mis au point pour ceux qui ont le même problème/question :

// Uniform index.
enum
{
    UNIFORM_MODELVIEWPROJECTION_MATRIX,
    UNIFORM_MODELVIEWPROJECTION_MATRIX2,    
    NUM_UNIFORMS
};
GLint uniforms[NUM_UNIFORMS];

// Attribute index.
enum
{
    ATTRIB_VERTEX,
    NUM_ATTRIBUTES
};

GLfloat square1Data[18] = 
{
    // Data layout for each line below is:
    // positionX, positionY, positionZ

    0.5f, 0.5f, 0.5f,  
    -0.5f, 0.5f, 0.5f, 
    0.5f, -0.5f, 0.5f, 
    0.5f, -0.5f, 0.5f, 
    -0.5f, 0.5f, 0.5f, 
    -0.5f, -0.5f, 0.5f

};

GLfloat square2Data[18] = 
{
    // Data layout for each line below is:
    // positionX, positionY, positionZ

    0.5f, 0.5f, 0.5f,   
    -0.5f, 0.5f, 0.5f,  
    0.5f, -0.5f, 0.5f,  
    0.5f, -0.5f, 0.5f,  
    -0.5f, 0.5f, 0.5f,  
    -0.5f, -0.5f, 0.5f
};

- (void)setupGL
{
    [EAGLContext setCurrentContext:self.context];

    [self loadShaders];

    //---- First Vertex Array Object --------
    glGenVertexArraysOES(1, &_vertexArray1);
    glGenBuffers(1, &_vertexBuffer1);   

    glBindVertexArrayOES(_vertexArray1);

    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer1);
    glBufferData(GL_ARRAY_BUFFER, sizeof(square1Data), square1Data, GL_STATIC_DRAW);

    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 12, BUFFER_OFFSET(0));
//    glEnableVertexAttribArray(GLKVertexAttribNormal);
//    glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(12));

    //----- Second Vertex Array Object ----------
    glGenBuffers(1, &_vertexBuffer2);

    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer2);
    glBufferData(GL_ARRAY_BUFFER, sizeof(square2Data), square2Data, GL_STATIC_DRAW);

    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 12, BUFFER_OFFSET(0));
//    glEnableVertexAttribArray(GLKVertexAttribNormal);
//    glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, 24, BUFFER_OFFSET(12));

    glBindBuffer(GL_ARRAY_BUFFER,0);
    glBindVertexArrayOES(0);
}

- (void)update
{
    _rotation += self.timeSinceLastUpdate * 0.2f;

    float aspect = fabsf(self.view.bounds.size.width / self.view.bounds.size.height);

    GLKMatrix4 projectionMatrix = GLKMatrix4MakeOrtho(-1.0f, 1.0f, -1.0f / aspect, 1.0f / aspect, -10.0f, 10.0f);

    GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.5f, 0.0f, 0.0f);
    modelViewMatrix = GLKMatrix4Multiply(modelViewMatrix, GLKMatrix4MakeZRotation(0.0 - _rotation));
    _modelViewProjectionMatrix = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix);

    GLKMatrix4 modelViewMatrix2 = GLKMatrix4MakeTranslation(-0.5f, 0.0f, 0.0f);
    modelViewMatrix2 = GLKMatrix4Multiply(modelViewMatrix2, GLKMatrix4MakeZRotation(_rotation));
    _modelViewProjectionMatrix2 = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix2);

}

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
    glClearColor(0.65f, 0.65f, 0.65f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glBindVertexArrayOES(_vertexArray1);

    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer1);
    glUseProgram(_program);
    glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
    glDrawArrays(GL_TRIANGLES, 0, 6);

    ///////// second VBO and shader program:
    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer2);
    glUseProgram(_program2);
    glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX2], 1, 0, _modelViewProjectionMatrix2.m);
    glDrawArrays(GL_TRIANGLES, 0, 6); 
}

- (BOOL)loadShaders
{
    GLuint vertShader, fragShader, vertShader2, fragShader2;
    NSString *vertShaderPathname, *fragShaderPathname, *vertShaderPathname2, *fragShaderPathname2;

    // Create shader program.
    _program = glCreateProgram();
    _program2 = glCreateProgram(); 

    // Create and compile vertex shader.
    vertShaderPathname = [[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"vsh"];
    if (![self compileShader:&vertShader type:GL_VERTEX_SHADER file:vertShaderPathname]) {
        NSLog(@"Failed to compile vertex shader");
        return NO;
    }

    // Create and compile fragment shader.
    fragShaderPathname = [[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"fsh"];
    if (![self compileShader:&fragShader type:GL_FRAGMENT_SHADER file:fragShaderPathname]) {
        NSLog(@"Failed to compile fragment shader");
        return NO;
    }

    // Create and compile vertex shader.
    vertShaderPathname2 = [[NSBundle mainBundle] pathForResource:@"Shader2" ofType:@"vsh"];
    if (![self compileShader:&vertShader2 type:GL_VERTEX_SHADER file:vertShaderPathname2]) {
        NSLog(@"Failed to compile vertex shader");
        return NO;
    }

    // Create and compile fragment shader.
    fragShaderPathname2 = [[NSBundle mainBundle] pathForResource:@"Shader2" ofType:@"fsh"];
    if (![self compileShader:&fragShader2 type:GL_FRAGMENT_SHADER file:fragShaderPathname2]) {
        NSLog(@"Failed to compile fragment shader");
        return NO;
    }

    // Attach vertex shader to program.
    glAttachShader(_program, vertShader);
    glAttachShader(_program2, vertShader2);

    // Attach fragment shader to program.
    glAttachShader(_program, fragShader);
    glAttachShader(_program2, fragShader2);

    // Bind attribute locations.
    // This needs to be done prior to linking.
    glBindAttribLocation(_program, ATTRIB_VERTEX, "position");
    glBindAttribLocation(_program2, ATTRIB_VERTEX, "position");

    // Link program.
    if (![self linkProgram:_program]) {
        NSLog(@"Failed to link program: %d", _program);

        if (vertShader) {
            glDeleteShader(vertShader);
            vertShader = 0;
        }
        if (fragShader) {
            glDeleteShader(fragShader);
            fragShader = 0;
        }
        if (_program) {
            glDeleteProgram(_program);
            _program = 0;
        }

        return NO;
    }
    if (![self linkProgram:_program2]) {
        NSLog(@"Failed to link program: %d", _program2);

        if (vertShader2) {
            glDeleteShader(vertShader2);
            vertShader2 = 0;
        }
        if (fragShader2) {
            glDeleteShader(fragShader2);
            fragShader2 = 0;
        }
        if (_program2) {
            glDeleteProgram(_program2);
            _program2 = 0;
        }

        return NO;
    }    

    // Get uniform locations.
    uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX] = glGetUniformLocation(_program, "modelViewProjectionMatrix");
    uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX2] = glGetUniformLocation(_program2, "modelViewProjectionMatrix2");

    // Release vertex and fragment shaders.
    if (vertShader) {
        glDetachShader(_program, vertShader);
        glDeleteShader(vertShader);
    }
    if (fragShader) {
        glDetachShader(_program, fragShader);
        glDeleteShader(fragShader);
    }

    if (vertShader2) {
        glDetachShader(_program2, vertShader2);
        glDeleteShader(vertShader2);
    }
    if (fragShader2) {
        glDetachShader(_program2, fragShader2);
        glDeleteShader(fragShader2);
    }    

    return YES;
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X