4

基本上,我画了一个 3D 立方体,我可以旋转它,但我希望能够触摸它并知道用户触摸了立方体表面的哪个位置。

我用于设置、生成和旋转。它基于分子代码和 NeHe 教程 #5。

任何帮助、链接、教程和代码将不胜感激。我有很多开发经验,但在 openGL 和 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
4

1 回答 1

1

为了实现 Ray cast hit 检查,您应该检查以下来源:
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

基本上,首先,从 2D 触摸创建 3D 射线。然后使用该射线检查与您世界中的对象的交集。您应该创建当前矩阵的逆矩阵,并且从逆矩阵中,您可以使用近和远剪辑平面创建开始和结束位置。然后在计算近点和远点时,您应该应用投影设置。

顺便说一句:在我的项目中,我的点识别是基于颜色唯一像素比较而不是光线投射命中检查。只需找到独特的颜色,就更容易实现命中检查。只是一个建议,希望对您有所帮助:) 干杯,
Guvener

于 2009-04-28T10:25:08.637 回答