Here is an example "GLKView Subview" app I wrote, based on the OpenGL Game sample project in Xcode 4.5. It creates a GLKView subview with its delegate set to the File Owner's GLKViewController, so that both OpenGL ES 2 views are controlled by one controller:
Here is a screenshot, I've tinted the subview's background red for contrast:
I was excited that I had a straightforward way to add multiple GLKViews under one GLKViewController and EAGLContext (for sharing textures etc), until I realized that the frame size is broken in:
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
NSLog(@"My view frame: %@", NSStringFromCGRect(view.bounds));
float aspect = fabsf(view.bounds.size.width / 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, _rotation, 0.0f, 1.0f, 0.0f);
// Compute the model view matrix for the object rendered with GLKit
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, -1.5f);
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, _rotation, 1.0f, 1.0f, 1.0f);
modelViewMatrix = GLKMatrix4Multiply(baseModelViewMatrix, modelViewMatrix);
self.effect.transform.modelviewMatrix = modelViewMatrix;
// Compute the model view matrix for the object rendered with ES2
modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, 1.5f);
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, _rotation, 1.0f, 1.0f, 1.0f);
modelViewMatrix = GLKMatrix4Multiply(baseModelViewMatrix, modelViewMatrix);
_normalMatrix = GLKMatrix3InvertAndTranspose(GLKMatrix4GetMatrix3(modelViewMatrix), NULL);
_modelViewProjectionMatrix = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix);
if(view == self.view)
{
glClearColor(0.65f, 0.65f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArrayOES(_vertexArray);
// Render the object with GLKit
[self.effect prepareToDraw];
glDrawArrays(GL_TRIANGLES, 0, 36);
// Render the object again with ES2
glUseProgram(_program);
glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
glUniformMatrix3fv(uniforms[UNIFORM_NORMAL_MATRIX], 1, 0, _normalMatrix.m);
glDrawArrays(GL_TRIANGLES, 0, 36);
[self.subview display];
}
else
{
glClearColor(1.0f, 0.65f, 0.65f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArrayOES(_vertexArray);
// Render the object with GLKit
[self.effect prepareToDraw];
glDrawArrays(GL_TRIANGLES, 0, 36);
// Render the object again with ES2
glUseProgram(_program);
glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
glUniformMatrix3fv(uniforms[UNIFORM_NORMAL_MATRIX], 1, 0, _normalMatrix.m);
glDrawArrays(GL_TRIANGLES, 0, 36);
}
}
Output in iOS Simulator with iPhone 4" Retina:
2013-04-27 15:50:56.149 GLKView Subview[48136:11903] My view frame: {{0, 0}, {568, 320}}
2013-04-27 15:50:56.152 GLKView Subview[48136:11903] My view frame: {{0, 0}, {248, 100}}
The subview's frame should be {100, 100} but for some reason it's coming out to {248, 100}. I've tried everything I can think of, even embedding it in a UIView, thinking that perhaps its autoresize constraints were getting set wrong if the main GLKView was its parent. As you can see the UIView's size is correct but the child GLKView's size is borked.
As a developer, this seemed like the first thing to try, but Apple generally has other ideas. Without autoresize, GLKView is useless for freeform layouts that work with any device size.
I managed to get multiple GLKViewControllers sharing a single EAGLContext working as child controllers in a different project. But I don't see why we should have to carry the baggage of creating a GLKViewController every time we want to add a GLKView to the screen. My guess is that GLKViewController gets confused when it's a delegate for a GLKView that isn't its own view.
I also managed to get my views working manually by just using glViewport() and after losing two days to GLKView issues, I would probably recommend going that route to anyone reading this (gaining cross platform advantages as well).
I'm hoping there is a simple explanation/fix, even if it's just "you have to make a GLKViewController for every GLKView". Thanks in advance to anyone who manages to get it working. If not, maybe an example of this bug feature will help someone.