3

I'm studied the pARK example project (http://developer.apple.com/library/IOS/#samplecode/pARk/Introduction/Intro.html#//apple_ref/doc/uid/DTS40011083) so I can apply some of its fundamentals in an app i'm working on. I understand nearly everything, except:

  • The way it has to calculate if a point of interest must appear or not. It gets the attitude, multiply it with the projection matrix (to get the rotation in GL coords?), then multiply that matrix with the coordinates of the point of interest and, at last, look at the last coordinate of that vector to find out if the point of interest must be shown. Which are the mathematic fundamentals of this?

Thanks a lot!!

Varyvol
  • 113
  • 1
  • 8

1 Answers1

11

I assume you are referring to the following method:

- (void)drawRect:(CGRect)rect
{
     if (placesOfInterestCoordinates == nil) {
         return;
     }

    mat4f_t projectionCameraTransform;
    multiplyMatrixAndMatrix(projectionCameraTransform, projectionTransform, cameraTransform);

    int i = 0;
    for (PlaceOfInterest *poi in [placesOfInterest objectEnumerator]) {
        vec4f_t v;
        multiplyMatrixAndVector(v, projectionCameraTransform, placesOfInterestCoordinates[i]);

        float x = (v[0] / v[3] + 1.0f) * 0.5f;
        float y = (v[1] / v[3] + 1.0f) * 0.5f;
        if (v[2] < 0.0f) {
            poi.view.center = CGPointMake(x*self.bounds.size.width, self.bounds.size.height-y*self.bounds.size.height);
            poi.view.hidden = NO;
        } else {
            poi.view.hidden = YES;
        }
        i++;
    }
}

This is performing an OpenGL like vertex transformation on the places of interest to check if they are in a viewable frustum. The frustum is created in the following line:

createProjectionMatrix(projectionTransform, 60.0f*DEGREES_TO_RADIANS, self.bounds.size.width*1.0f / self.bounds.size.height, 0.25f, 1000.0f);

This sets up a frustum with a 60 degree field of view, a near clipping plane of 0.25 and a far clipping plane of 1000. Any point of interest that is further away than 1000 units will then not be visible.

So, to step through the code, first the projection matrix that sets up the frustum, and the camera view matrix, which simply rotates the object so it is the right way up relative to the camera, are multiplied together. Then, for each place of interest, its location is multiplied by the viewProjection matrix. This will project the location of the place of interest into the view frustum, applying rotation and perspective.

The next two lines then convert the transformed location of the place into whats known as normalized device coordinates. The 4 component vector needs to be collapsed to 3 dimensional space, this is achieved by projecting it onto the plane w == 1, by dividing the vector by its w component, v[3]. It is then possible to determine if the point lies within the projection frustum by checking if its coordinates lie in the cube with side length 2 with origin [0, 0, 0]. In this case, the x and y coordinates are being biased from the range [-1 1] to [0 1] to match up with the UIKit coordinate system, by adding 1 and dividing by 2.

Next, the v[2] component, z, is checked to see if it is greater than 0. This is actually incorrect as it has not been biased, it should be checked to see if it is greater than -1. This will detect if the place of interest is in the first half of the projection frustum, if it is then the object is deemed visible and displayed.

If you are unfamiliar with vertex projection and coordinate systems, this is a huge topic with a fairly steep learning curve. There is however a lot of material online covering it, here are a couple of links to get you started:

http://www.falloutsoftware.com/tutorials/gl/gl0.htm

http://www.opengl.org/wiki/Vertex_Transformation

Good luck//

Tark
  • 5,153
  • 3
  • 24
  • 23
  • So then, we multiply projection matrix and the camera matrix just to rotate the object in a propper way? Is that right? – Varyvol Mar 13 '12 at 10:25
  • the camera matrix rotates the place to match the devices current rotation, in `- (void)onDisplayLink:(id)sender`. the projection matrix projects the location into a frustum as described above. by multiplying these matrices together, the two transforms can be performed in a single matrix vector multiplication on the places position. – Tark Mar 13 '12 at 10:30
  • Perfect, this is all I needed. I only have one doubt still: why do we check if the location is in the cube with side lenght 2 with the origin [0, 0, 0]? Is it because of the way the projection matrix is created or is it always the same, independently of the way that matrix is created? – Varyvol Mar 13 '12 at 11:49
  • the projection matrix is constructed so that anything that falls within the defined frustum will be transformed to the cube space and contained within the cube. if the position lies outside the frustum then it will be transformed to a position outside the cube. it makes clipping objects simple, and also makes objects scale correctly depending on their z coordinate. – Tark Mar 13 '12 at 11:56
  • Yeah, I know that. But why side lenght 2, and not 3 for example? Is it for this particular example or always? – Varyvol Mar 13 '12 at 12:07
  • just because. got to pick something, and the range [-1 1] is easy to work with. this is always the case for OpenGL and DirectX, and all computer graphics systems that i am aware of. – Tark Mar 13 '12 at 12:21
  • ok, everything clear now!! Thank you very much, I appreciate your help a lot! – Varyvol Mar 13 '12 at 13:00
  • How did you solve the problem of aligning the overlapping POI items in the park,AR- sample application from apple? – thatzprem Jan 17 '14 at 10:30