views:

1471

answers:

1

Basically, I draw a 3D cube, I can spin it around but I want to be able to touch it and know where on my cube's surface the user touched.

I'm using for setting up, generating and spinning. Its based on the Molecules code and NeHe tutorial #5.

Any help, links, tutorials and code would be greatly appreciated. I have lots of development experience but nothing much in the way of openGL and 3d.

//
//  GLViewController.h
//  NeHe Lesson 05
//
//  Created by Jeff LaMarche on 12/12/08.
//  Copyright Jeff LaMarche Consulting 2008. All rights reserved.
//

#import "GLViewController.h"
#import "GLView.h"

@implementation GLViewController
- (void)drawBox
{
    static const GLfloat cubeVertices[] = { 
     -1.0f, 1.0f, 1.0f,
     1.0f, 1.0f, 1.0f, 
     1.0f,-1.0f, 1.0f, 
     -1.0f,-1.0f, 1.0f,
     -1.0f, 1.0f,-1.0f,
     1.0f, 1.0f,-1.0f, 
     1.0f,-1.0f,-1.0f, 
     -1.0f,-1.0f,-1.0f 
    };
    static const GLubyte cubeNumberOfIndices = 36;

    const GLubyte cubeVertexFaces[] = { 
     0, 1, 5, // Half of top face
     0, 5, 4, // Other half of top face

     4, 6, 5, // Half of front face
     4, 6, 7,    // Other half of front face

     0, 1, 2, // Half of back face
     0, 3, 2, // Other half of back face

     1, 2, 5, // Half of right face
     2, 5, 6, // Other half of right face

     0, 3, 4, // Half of left face
     7, 4, 3, // Other half of left face

     3, 6, 2, // Half of bottom face
     6, 7, 3, // Other half of bottom face

    }; 
    const GLubyte cubeFaceColors[] = { 
     0, 255,   0, 255,
     255, 125,   0, 255,
     255,   0,   0, 255,
     255, 255,   0, 255,
     0,   0, 255, 255,
     255,   0, 255, 255
    };


    glEnableClientState(GL_VERTEX_ARRAY);

    glVertexPointer(3, GL_FLOAT, 0, cubeVertices);
    int colorIndex = 0;
    for(int i = 0; i < cubeNumberOfIndices; i += 3) 
    { 
     glColor4ub(cubeFaceColors[colorIndex], cubeFaceColors[colorIndex+1], cubeFaceColors[colorIndex+2], cubeFaceColors[colorIndex+3]);
     int face = (i / 3.0);
     if (face%2 != 0.0)
      colorIndex+=4;

     glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_BYTE, &cubeVertexFaces[i]);
    } 

    glDisableClientState(GL_VERTEX_ARRAY);
}

//move this to a data model later!
- (GLfixed)floatToFixed:(GLfloat)aValue;
{ 
    return (GLfixed) (aValue * 65536.0f); 
}

- (void)drawViewByRotatingAroundX:(float)xRotation rotatingAroundY:(float)yRotation scaling:(float)scaleFactor translationInX:(float)xTranslation translationInY:(float)yTranslation view:(GLView*)view;
{
    glMatrixMode(GL_MODELVIEW);
    GLfixed currentModelViewMatrix[16]  = {  45146, 47441, 2485,  0,
              -25149, 26775,-54274, 0,
              -40303, 36435, 36650, 0,
                 0,    0,     0, 65536 };
    /*
    GLfixed currentModelViewMatrix[16]  = { 0, 0, 0, 0,
              0, 0, 0, 0,
              0, 0, 0, 0,
              0, 0, 0, 65536 };
    */
    //glLoadIdentity();
    //glOrthof(-1.0f, 1.0f, -1.5f, 1.5f, -10.0f, 4.0f);

    // Reset rotation system
    if (isFirstDrawing)
    { 
     //glLoadIdentity();
     glMultMatrixx(currentModelViewMatrix);
     [self configureLighting];
     isFirstDrawing = NO;
    }

    // Scale the view to fit current multitouch scaling
    GLfixed fixedPointScaleFactor = [self floatToFixed:scaleFactor];
    glScalex(fixedPointScaleFactor, fixedPointScaleFactor, fixedPointScaleFactor);  

    // Perform incremental rotation based on current angles in X and Y
    glGetFixedv(GL_MODELVIEW_MATRIX, currentModelViewMatrix); 

    GLfloat totalRotation = sqrt(xRotation*xRotation + yRotation*yRotation);

    glRotatex([self floatToFixed:totalRotation],
        (GLfixed)((xRotation/totalRotation) * (GLfloat)currentModelViewMatrix[1] + (yRotation/totalRotation) * (GLfloat)currentModelViewMatrix[0]),
        (GLfixed)((xRotation/totalRotation) * (GLfloat)currentModelViewMatrix[5] + (yRotation/totalRotation) * (GLfloat)currentModelViewMatrix[4]),
        (GLfixed)((xRotation/totalRotation) * (GLfloat)currentModelViewMatrix[9] + (yRotation/totalRotation) * (GLfloat)currentModelViewMatrix[8])
        );

    // Translate the model by the accumulated amount
    glGetFixedv(GL_MODELVIEW_MATRIX, currentModelViewMatrix); 
    float currentScaleFactor = sqrt(pow((GLfloat)currentModelViewMatrix[0] / 65536.0f, 2.0f) + pow((GLfloat)currentModelViewMatrix[1] / 65536.0f, 2.0f) + pow((GLfloat)currentModelViewMatrix[2] / 65536.0f, 2.0f)); 

    xTranslation = xTranslation / (currentScaleFactor * currentScaleFactor);
    yTranslation = yTranslation / (currentScaleFactor * currentScaleFactor);
    // Grab the current model matrix, and use the (0,4,8) components to figure the eye's X axis in the model coordinate system, translate along that
    glTranslatef(xTranslation * (GLfloat)currentModelViewMatrix[0] / 65536.0f, xTranslation * (GLfloat)currentModelViewMatrix[4] / 65536.0f, xTranslation * (GLfloat)currentModelViewMatrix[8] / 65536.0f);
    // Grab the current model matrix, and use the (1,5,9) components to figure the eye's Y axis in the model coordinate system, translate along that
    glTranslatef(yTranslation * (GLfloat)currentModelViewMatrix[1] / 65536.0f, yTranslation * (GLfloat)currentModelViewMatrix[5] / 65536.0f, yTranslation * (GLfloat)currentModelViewMatrix[9] / 65536.0f);

    // Black background, with depth buffer enabled
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    [self drawBox];
}

- (void)configureLighting;
{
    const GLfixed   lightAmbient[] = {13107, 13107, 13107, 65535};
    const GLfixed   lightDiffuse[] = {65535, 65535, 65535, 65535};
    const GLfixed   matAmbient[] = {65535, 65535, 65535, 65535};
    const GLfixed   matDiffuse[] = {65535, 65535, 65535, 65535}; 
    const GLfixed   lightPosition[] = {30535, -30535, 0, 0}; 
    const GLfixed   lightShininess = 20; 

    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_COLOR_MATERIAL);
    glMaterialxv(GL_FRONT_AND_BACK, GL_AMBIENT, matAmbient);
    glMaterialxv(GL_FRONT_AND_BACK, GL_DIFFUSE, matDiffuse);
    glMaterialx(GL_FRONT_AND_BACK, GL_SHININESS, lightShininess);
    glLightxv(GL_LIGHT0, GL_AMBIENT, lightAmbient);
    glLightxv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse);
    glLightxv(GL_LIGHT0, GL_POSITION, lightPosition);   

    glEnable(GL_DEPTH_TEST);

    glShadeModel(GL_SMOOTH);
    glEnable(GL_NORMALIZE);   
}

-(void)setupView:(GLView*)view
{
    const GLfloat zNear = 0.1, 
    zFar = 1000.0, 
    fieldOfView = 60.0; 
    GLfloat size; 

    glMatrixMode(GL_PROJECTION); 
    glEnable(GL_DEPTH_TEST); 
    size = zNear * tanf(DEGREES_TO_RADIANS(fieldOfView) / 2.0); 
    CGRect rect = view.bounds; 
    glFrustumf(-size, size, -size / (rect.size.width / rect.size.height), size / 
         (rect.size.width / rect.size.height), zNear, zFar); 
    glViewport(0, 0, rect.size.width, rect.size.height);
    glScissor(0, 0, rect.size.width, rect.size.height);
    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f); 

    glTranslatef(0.0f, 0.0f, -6.0f);
    isFirstDrawing = YES;
}

- (void)didReceiveMemoryWarning 
{
    [super didReceiveMemoryWarning]; 
}

- (void)dealloc 
{
    [super dealloc];
}

@end
A: 

Hi Big Fizzy,

In order to implement Ray cast hit checking, you should check these sources:
http://www.mvps.org/directx/articles/rayproj.htm
http://bookofhook.com/mousepick.pdf
http://eigenclass.blogspot.com/2008/10/opengl-es-picking-using-ray-boundingbox.html

Basically, first, create a 3D ray from a 2D touch. Then use that ray to check for intersection with objects in your world. You should create the matrix inverse of your current matrix, and from the inverse matrix you can create start and end position using your near and far clip plane. and then when calculating the near and far points you should apply the projection settings.

BTW: In my project, my point recognition is based on color unique pixel comparison rather than ray cast hit check. It is much easier to implement hit check with just finding unique colors. Only a suggestion, hope it helps :) cheers,
Guvener

Guvener Gokce