Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I manipulate objects independently of one another in OpenGL ES 2.0?

I am building an iOS game with OpenGL ES 2.0 that contains a scene with around 100 different 'objects' which I need to be able to transform independently of one another. I am new to OpenGL ES. As such, I initially thought I should start with OpenGL ES 1.1, then later migrate the app to 2.0 to take advantage of the enhanced visual effects.

However, just as I was getting comfortable with 1.1, I realized, partly based on Apple's very 2.0-centric Xcode template for OpenGL, that it was going to be more trouble than it's worth to fight moving straight into 2.0, so I bit the bullet.

Now, I'm finding it difficult to grasp the concepts enough to do simple transforms on my vertex array objects independently of one another. I read in the OpenGLES 2.0 docs that the best way to do this would be to use multiple VBOs, one for each vertex array. However, I can't seem to transform one of them without affecting the entire scene.

I started the project with the Apple OpenGL ES template and streamlined it, such that the setupGL method looks like this:

-(void)setupGL
{
    // Setup
    [EAGLContext setCurrentContext:self.context];        
    [self loadShaders];
    self.effect = [[GLKBaseEffect alloc] init];
    self.effect.light0.enabled = GL_TRUE;
    self.effect.light0.diffuseColor = GLKVector4Make(1.0f, 0.4f, 0.4f, 1.0f);
    glEnable(GL_DEPTH_TEST); // do depth comparisons and update the depth buffer

    // Initialize first buffer
    glGenVertexArraysOES(1, &_vertexArray);
    glBindVertexArrayOES(_vertexArray);    
    glGenBuffers(1, &_vertexBuffer);    
    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);    
    glBufferData(GL_ARRAY_BUFFER, sizeof(gPyramidVertexData), gPyramidVertexData, GL_DYNAMIC_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));    
    glBindVertexArrayOES(0);

    // Initialize second buffer
    glGenVertexArraysOES(2, &_vertexArray2);
    glBindVertexArrayOES(_vertexArray2);
    glGenBuffers(2, &_vertexBuffer2);
    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer2);
    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));
    glBindVertexArrayOES(0);
}

I know that's incredibly sloppy code- I basically copy-and-pasted the buffer creation portion to set myself up for experimenting with two different vertextArrays in separate buffers. It appears to have worked, as I can render both buffers in the drawInRect method:

-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
    glBindVertexArrayOES(_vertexArray);
    glUseProgram(_program);
    glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
    glUniformMatrix3fv(uniforms[UNIFORM_NORMAL_MATRIX], 1, 0, _normalMatrix.m);    
    glDrawArrays(GL_TRIANGLES, 0, numberOfVerteces);

    glBindVertexArrayOES(_vertexArray2);
    glUseProgram(_program);
    glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
    glUniformMatrix3fv(uniforms[UNIFORM_NORMAL_MATRIX], 1, 0, _normalMatrix.m);
    glDrawArrays(GL_TRIANGLES, 0, numberOfVerteces2);
}

My problem comes when I try to do transforms on one vertex array without affecting the other one. I tried adding transforms in the above method just before the glDrawArrays calls, without success- I think that may only work with 1.1. It appears my transforms must be done within the update method:

-(void)update
{
    float aspect = fabsf(self.view.bounds.size.width / self.view.bounds.size.height);
    GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 0.1f, 100.0f);        
    self.effect.transform.projectionMatrix = projectionMatrix;

    GLKMatrix4 baseModelViewMatrix = GLKMatrix4MakeTranslation( 0.0f, 0.0f, -4.0f);
    baseModelViewMatrix = GLKMatrix4Rotate(baseModelViewMatrix, _sceneRotation, 1.0f, 1.0f, 1.0f);

    GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, zoomFactor);
    modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, _objectRotation, 0.0f, 1.0f, 0.0f);
    modelViewMatrix = GLKMatrix4Multiply(baseModelViewMatrix, modelViewMatrix);

    _normalMatrix = GLKMatrix3InvertAndTranspose(GLKMatrix4GetMatrix3(modelViewMatrix), NULL);
    _modelViewProjectionMatrix = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix);    
}

However, this is where I get really confused-- it's not at all clear how I could modify this method to do transforms to one VBO or the other. It's not even clear that th above code is making any reference to one particular buffer at all.

Eventually I would like to expand my game by moving the code for each game object into an instance of a custom class, which would handle the transforms, etc. But I would like to know if I'm completely misguided in my approach before doing so.

like image 458
todd412 Avatar asked Oct 08 '22 19:10

todd412


1 Answers

In case this is helpful to anyone having similar issues, I found the answers I was looking for on Ian Terrell's excellent blog, Games by Ian Terrell.

In particular, this tutorial and its accompanying sample code were exactly what I needed to get a grip on this very complicated subject. Hope this helps!

like image 147
todd412 Avatar answered Oct 12 '22 12:10

todd412