Question

I want to orbit the camera around the object in OpenGL. Not quite happening. Here is my code:

The object is the standard cube.

- (void)update {

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

    float radius = 10.0f;
    float startAngle = -3 * M_PI/4.0;

     float newX = 0.0f + radius *cos(phi)*sin(theta);
     float newY = 0.0f + radius *sin(phi)*sin(theta);
     float newZ = 0.0f + radius *cos(theta);

    GLKMatrix4 projectionMatrix = GLKMatrix4MakeLookAt(newX, 0.0, newZ 
                                                       0.0, 0.0, 0.0,
                                                       0.0, 1.0, 0.0);


    self.effect.transform.projectionMatrix = projectionMatrix;

    GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, 0.0f);
   self.effect.transform.modelviewMatrix = modelViewMatrix;



}



-(void) viewPanned:(UIPanGestureRecognizer *) sender

{

    CGPoint curTouch = [sender locationInView:self.view];

    if ([sender state] == UIGestureRecognizerStateBegan){
        oldX = curTouch.x;
        oldY = curTouch.y;

    }


    theta += (curTouch.x-oldX)*0.001f;
    phi   += (curTouch.y-oldY)*0.001f;

    oldX = curTouch.x;
    oldY = curTouch.y;
}
Was it helpful?

Solution

Your ModelView and Projection matrices are set up incorrectly -- between the two of them you have a model view transformation, but no projection from eye space to clip space.

To understand why, it helps to study coordinate spaces, transformations, and their common roles in 3D graphics programming... there are lots of good tutorials out there (like this one -- it's for desktop GL, and uses the C++ GLM library where for iOS you'd do better to use GLKit math, but the concepts are the same), but here's a quick overview.


In a traditional graphics pipeline (as modeled by GLKBaseEffect), there are four coordinate spaces you might care about:

  • Model space is the arbitrary coordinate system your vertex data is defined in. For example, if you're drawing a scene with a lot of boxy shapes, you can just define a unit cube centered at the origin, and use transformations to stretch, move, and rotate it to various positions in your scene.

  • World space is the arbitrary coordinate system you design your scene in. For example, if you're using that cube to draw a cityscape, you can put the origin at a street corner and translate the cube in X and Z directions to make buildings.

  • Eye (or Camera or View) coordinate space is defined in terms of how you view the scene. The previous two spaces can be defined in any way that's convenient to you, but with this one there start being rules for how the space starts mapping to the screen. In eye space, the X axis increases to the right, the Y axis increases upward, and the Z axis points behind you -- that is, the camera looks in the negative Z direction.

  • Clip space is where the rubber meets the road -- it's where OpenGL (ES) chooses what to draw and where it goes on the screen. As such it's very strictly defined: anything in the cube that extends from -1.0 to 1.0 in all three axes appears on the screen. (Anything outside that cube gets "clipped".) As with eye space, +X is right, +Y is up, and +Z is closer to the viewer.

Vertex processing uses up to three transformations (often concatenated together) to get your vertex data (which is specified in model space) all the way to clip space so that OpenGL (ES) can draw it. Each transformation is specified by a 4x4 matrix (with GLKBaseEffect that's a GLKMatrix4), which itself may be the concatenation of several transforms.

  • The Model matrix transforms from Model to World space. That cityscape example? For each building, you scale the cube in one direction to make a skyscraper, then translate it in X and Z directions to place it in the world -- that's a model transform.

  • The View matrix transforms from World to Eye space. You can build a View matrix from translations and rotations (after all, moving the camera is the same as moving the world in the opposite direction), but most 3D math libraries give you conveniences like GLKMatrix4MakeLookAt that let you specify a view transform in terms of a) the location of the camera, b) the point you're looking at, and c) which direction should be "up".

  • The Projection matrix transforms from Eye space to Clip space. Typically you use a perspective projection (GLKMatrix4MakePerspective), which defines what you can see in terms of a viewing angle, aspect ratio, and near and far limits. (In other words, the area you can see fits inside a pyramid expanding from your eye out to infinity, and we slice a section, or frustrum, off that pyramid to define the range of depth that actually gets drawn on screen.)

To get your vertex data rendered to the screen, it has to go through all three transformations -- usually they're multiplied together to create a ModelViewProjection matrix which is then provided to the GPU for use in transforming each vertex position. Lighting calculations are usually done in eye space, so you typically provide a ModelView matrix to the GPU separately (or rather, its inverse transpose, for use in transforming surface normals).

When you use GLKBaseEffect, you provide a ModelView matrix and a Projection matrix, and it multiplies or inverts them as necessary.


Still here? :)

What you've got is a transform from model space to eye space. (In simple scenes like yours, model space and world space are often the same.) You don't have a projection transform to clip space, so OpenGL ES is interpreting your eye space as if it's supposed to be clip space. Depending on what your vertex coordinates are, all of your geometry might be outside the -1 to 1 cube, so you won't see anything.

All the transformations you have so far should be multiplied together and provided to GLKBaseEffect as a ModelView matrix. Then, create a perspective projection (GLKMatrix4MakePerspective) using the aspect ratio you've already calculated and provide it to GLKBaseEffect as the Projection matrix.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top