OpenGL ES (iPhone) 触摸拾取 [英] OpenGL ES (iPhone) Touch Picking

查看:33
本文介绍了OpenGL ES (iPhone) 触摸拾取的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

希望在 ES 中进行经典的 OpenGL 鼠标拾取.我宁愿不使用第三方库,GLU 端口和 OpenGL 名称堆栈等都已淘汰.这几乎留下了逆视图变换和光线相交,对吗?

Looking to do classic OpenGL mouse picking in ES. I'd prefer not to use third party libs, GLU ports and OpenGL name stacks, etc, are out. This pretty much leaves inverse view transformation and ray intersection, correct?

在以下方面的帮助下,我已经取得了很大进展:http://trac.bookofhook.com/bookofhook/trac.cgi/wiki/MousePickinghttp://eigenclass.blogspot.com/2008/10/opengl-es-picking-using-ray-boundingbox.html

I've gotten pretty far with the help of: http://trac.bookofhook.com/bookofhook/trac.cgi/wiki/MousePicking http://eigenclass.blogspot.com/2008/10/opengl-es-picking-using-ray-boundingbox.html

...但我还没到.这也让人觉得必须有更简单的方法!!

. . .but I'm not there yet. This also reeks of THERE MUST BE AN EASIER WAY!!

这里有一些代码:

    -(void)handleTouch:(CGPoint)point {
    GLfloat width = backingWidth;
    GLfloat height = backingHeight;
    GLfloat x = point.x;
    GLfloat y = point.y;
    GLfloat z = 0.0f;

    //viewport -> normalized dev coord -> clip
    GLfloat n[] = {
        2 * x / width - 1,
        2 * y / height,
        2 * z - 1,
        1
    };

    float fov = 45.0f * (M_PI / 180.0f);
    float near = 0.01, far = 10.0f;
    float aspect = (float)backingWidth / (float)backingHeight;
    float top = tan(fov) * near;
    //float bottom = -top;
    //float left = aspect * bottom;
    float right = aspect * top;

    //I'm a viewing volume symmetric projection matrix
    GLfloat P[] = {
        near / right, 0, 0, 0,
        0, near / top, 0, 0,
        0, 0, -(far + near) / (far - near), (-2 * far * near) / (far - near),
        0, 0, -1, 0
    };

    GLfloat Pminus1[] = {
        1/P[0], 0, 0, 0,
        0, 1/P[5], 0, 0,
        0, 0, 0, 1/P[14],
        0, 0, 1/P[11], -(P[10]/ (P[11]*P[14]))
    };

    //clip -> view
    GLfloat v[] = {
        Pminus1[0] * n[0] + Pminus1[1] * n[1] + Pminus1[2] * n[2] + Pminus1[3] * n[3],
        Pminus1[4] * n[0] + Pminus1[5] * n[1] + Pminus1[6] * n[2] + Pminus1[7] * n[3],
        Pminus1[8] * n[0] + Pminus1[9] * n[1] + Pminus1[10] * n[2] + Pminus1[11] * n[3],
        Pminus1[12] * n[0] + Pminus1[13] * n[1] + Pminus1[14] * n[2] + Pminus1[15] * n[3]
    };

    //view -> world
    GLfloat Rt[] = {
        mv[0], mv[4], mv[8],
        mv[1], mv[5], mv[9],
        mv[2], mv[6], mv[10]
    };

    GLfloat tPrime[] = {
        Rt[0] * mv[3] + Rt[1] * mv[7] + Rt[2] * mv[11],
        Rt[3] * mv[3] + Rt[4] * mv[7] + Rt[5] * mv[11],
        Rt[6] * mv[3] + Rt[7] * mv[7] + Rt[8] * mv[11]
    };

    GLfloat Mminus1[] = {
        Rt[0], Rt[1], Rt[2], -(tPrime[0]),
        Rt[3], Rt[4], Rt[5], -(tPrime[1]),
        Rt[6], Rt[7], Rt[8], -(tPrime[2]),
        0, 0, 0, 1
    };

    //point in world space
    GLfloat w[] = {
        Mminus1[0] * v[0] + Mminus1[1] * v[1] + Mminus1[2] * v[2] + Mminus1[3] * v[3],
        Mminus1[4] * v[0] + Mminus1[5] * v[1] + Mminus1[6] * v[2] + Mminus1[7] * v[3],
        Mminus1[8] * v[0] + Mminus1[9] * v[1] + Mminus1[10] * v[2] + Mminus1[11] * v[3],
        Mminus1[12] * v[0] + Mminus1[13] * v[1] + Mminus1[14] * v[2] + Mminus1[15] * v[3]
    };

    //r = a + t(w - a)
    GLfloat a[] = {0.0f, -0.1f, 0.0f};
    GLfloat wminusa[] = {w[0] - a[0], w[1] - a[1], w[2] - a[2]};

    vector[0] = a[0];
    vector[1] = a[1],
    vector[2] = a[2];
    vector[3] = w[0];
    vector[4] = w[1];
    vector[5] = -10.0f;

    //3 non-colinear points on the plane 
    GLfloat p1[] = {rect.origin.x, rect.origin.y, 0};
    GLfloat p2[] = {rect.origin.x + rect.size.width, rect.origin.y, 0};
    GLfloat p3[] = {rect.origin.x + rect.size.width, rect.origin.y + rect.size.height, 0};

    //location plane normal vector, Ax + By + Cz + D = 0
    GLfloat lp[] = {
        p1[1] * (p2[2] - p3[2]) + p2[1] * (p3[2] - p1[2]) + p3[1] * (p1[2] - p2[2]),
        p1[2] * (p2[0] - p3[0]) + p2[2] * (p3[0] - p1[0]) + p3[2] * (p1[0] - p2[0]),
        p1[0] * (p2[1] - p3[1]) + p2[0] * (p3[1] - p1[1]) + p3[0] * (p1[1] - p2[1]),
        -(p1[0] * (((p2[1] * p3[2]) - (p3[1] * p2[2]))) + p2[0] * (((p3[1] * p1[2]) - (p1[1] * p3[2]))) + p3[0] * (((p1[1] * p2[2]) - (p2[1] * p1[2]))))
    };

    GLfloat PnRd = (lp[0] * wminusa[0]) + (lp[1] * wminusa[1]) + (lp[2] * wminusa[2]);
    if(PnRd != 0) {
        GLfloat PnR0D = -((lp[0] * a[0]) + (lp[1] * a[1]) + (lp[2] * a[2]) + lp[3]);
        if(PnR0D != 0) {
            GLfloat t = PnR0D / PnRd;
            if(t >= 0) {
                GLfloat p[] = {
                    a[0] + wminusa[0] * t,
                    a[1] + wminusa[1] * t,
                    a[2] + wminusa[2] * t
                };
                if(p[0] > rect.origin.x &&
                   p[0] < rect.origin.x + rect.size.width &&
                   p[1] > rect.origin.y &&
                   p[1] < rect.origin.y + rect.size.height)
                    NSLog(@"BOOM!!!");
            }
        }
    }
}

推荐答案

好吧,好吧,还是有点问题.以下是目前最有效的方法:

Okay, okay that was still a bit buggy. Here is what is MOSTLY working now:

-(void)view2WorldPoint:(CGPoint)point :(GLfloat*)worldPoint {
    float clickX = point.x;
    float clickY = point.y;
    float clickZ = -near;

    //viewport -> normalized device coord -> clip
    GLint viewport[4];
    glGetIntegerv(GL_VIEWPORT, viewport);

    GLfloat n[] = {
        (clickX - (float)viewport[0]) / (float)viewport[2] * 2.0 - 1.0,
        -((clickY - (float)viewport[1]) / (float)viewport[3] * 2.0 - 1.0),
        2.0 * clickZ - 1.0,
        1.0
    };

    GLfloat MP[16], MPInv[16];
    MatMatMultiply(MP, projMat, modelMat);
    GenerateInverseMatrix4f(MPInv, MP); // replace this one with the whole 1/p thang?

    GLfloat w[] = {
        (MPInv[0]  * n[0]) + (MPInv[4]  * n[1]) + (MPInv[8]  * n[2]) + (MPInv[12] * n[3]),
        (MPInv[1]  * n[0]) + (MPInv[5]  * n[1]) + (MPInv[9]  * n[2]) + (MPInv[13] * n[3]),
        (MPInv[2]  * n[0]) + (MPInv[6]  * n[1]) + (MPInv[10] * n[2]) + (MPInv[14] * n[3]),
        (MPInv[3]  * n[0]) + (MPInv[7]  * n[1]) + (MPInv[11] * n[2]) + (MPInv[15] * n[3])
    };

    worldPoint[0] = w[0] / w[3];
    worldPoint[1] = w[1] / w[3];
    worldPoint[2] = w[2] / w[3];
}


float Determinant4f(const float m[16])
{
    return
    m[12]*m[9]*m[6]*m[3]-
    m[8]*m[13]*m[6]*m[3]-
    m[12]*m[5]*m[10]*m[3]+
    m[4]*m[13]*m[10]*m[3]+
    m[8]*m[5]*m[14]*m[3]-
    m[4]*m[9]*m[14]*m[3]-
    m[12]*m[9]*m[2]*m[7]+
    m[8]*m[13]*m[2]*m[7]+
    m[12]*m[1]*m[10]*m[7]-
    m[0]*m[13]*m[10]*m[7]-
    m[8]*m[1]*m[14]*m[7]+
    m[0]*m[9]*m[14]*m[7]+
    m[12]*m[5]*m[2]*m[11]-
    m[4]*m[13]*m[2]*m[11]-
    m[12]*m[1]*m[6]*m[11]+
    m[0]*m[13]*m[6]*m[11]+
    m[4]*m[1]*m[14]*m[11]-
    m[0]*m[5]*m[14]*m[11]-
    m[8]*m[5]*m[2]*m[15]+
    m[4]*m[9]*m[2]*m[15]+
    m[8]*m[1]*m[6]*m[15]-
    m[0]*m[9]*m[6]*m[15]-
    m[4]*m[1]*m[10]*m[15]+
    m[0]*m[5]*m[10]*m[15];
}

BOOL GenerateInverseMatrix4f(float i[16], const float m[16])
{
    float x=Determinant4f(m);
    if (x==0) return FALSE;

    i[0]= (-m[13]*m[10]*m[7] +m[9]*m[14]*m[7] +m[13]*m[6]*m[11]
           -m[5]*m[14]*m[11] -m[9]*m[6]*m[15] +m[5]*m[10]*m[15])/x;
    i[4]= ( m[12]*m[10]*m[7] -m[8]*m[14]*m[7] -m[12]*m[6]*m[11]
           +m[4]*m[14]*m[11] +m[8]*m[6]*m[15] -m[4]*m[10]*m[15])/x;
    i[8]= (-m[12]*m[9]* m[7] +m[8]*m[13]*m[7] +m[12]*m[5]*m[11]
           -m[4]*m[13]*m[11] -m[8]*m[5]*m[15] +m[4]*m[9]* m[15])/x;
    i[12]=( m[12]*m[9]* m[6] -m[8]*m[13]*m[6] -m[12]*m[5]*m[10]
           +m[4]*m[13]*m[10] +m[8]*m[5]*m[14] -m[4]*m[9]* m[14])/x;
    i[1]= ( m[13]*m[10]*m[3] -m[9]*m[14]*m[3] -m[13]*m[2]*m[11]
           +m[1]*m[14]*m[11] +m[9]*m[2]*m[15] -m[1]*m[10]*m[15])/x;
    i[5]= (-m[12]*m[10]*m[3] +m[8]*m[14]*m[3] +m[12]*m[2]*m[11]
           -m[0]*m[14]*m[11] -m[8]*m[2]*m[15] +m[0]*m[10]*m[15])/x;
    i[9]= ( m[12]*m[9]* m[3] -m[8]*m[13]*m[3] -m[12]*m[1]*m[11]
           +m[0]*m[13]*m[11] +m[8]*m[1]*m[15] -m[0]*m[9]* m[15])/x;
    i[13]=(-m[12]*m[9]* m[2] +m[8]*m[13]*m[2] +m[12]*m[1]*m[10]
           -m[0]*m[13]*m[10] -m[8]*m[1]*m[14] +m[0]*m[9]* m[14])/x;
    i[2]= (-m[13]*m[6]* m[3] +m[5]*m[14]*m[3] +m[13]*m[2]*m[7]
           -m[1]*m[14]*m[7] -m[5]*m[2]*m[15] +m[1]*m[6]* m[15])/x;
    i[6]= ( m[12]*m[6]* m[3] -m[4]*m[14]*m[3] -m[12]*m[2]*m[7]
           +m[0]*m[14]*m[7] +m[4]*m[2]*m[15] -m[0]*m[6]* m[15])/x;
    i[10]=(-m[12]*m[5]* m[3] +m[4]*m[13]*m[3] +m[12]*m[1]*m[7]
           -m[0]*m[13]*m[7] -m[4]*m[1]*m[15] +m[0]*m[5]* m[15])/x;
    i[14]=( m[12]*m[5]* m[2] -m[4]*m[13]*m[2] -m[12]*m[1]*m[6]
           +m[0]*m[13]*m[6] +m[4]*m[1]*m[14] -m[0]*m[5]* m[14])/x;
    i[3]= ( m[9]* m[6]* m[3] -m[5]*m[10]*m[3] -m[9]* m[2]*m[7]
           +m[1]*m[10]*m[7] +m[5]*m[2]*m[11] -m[1]*m[6]* m[11])/x;
    i[7]= (-m[8]* m[6]* m[3] +m[4]*m[10]*m[3] +m[8]* m[2]*m[7]
           -m[0]*m[10]*m[7] -m[4]*m[2]*m[11] +m[0]*m[6]* m[11])/x;
    i[11]=( m[8]* m[5]* m[3] -m[4]*m[9]* m[3] -m[8]* m[1]*m[7]
           +m[0]*m[9]* m[7] +m[4]*m[1]*m[11] -m[0]*m[5]* m[11])/x;
    i[15]=(-m[8]* m[5]* m[2] +m[4]*m[9]* m[2] +m[8]* m[1]*m[6]
           -m[0]*m[9]* m[6] -m[4]*m[1]*m[10] +m[0]*m[5]* m[10])/x;

    return TRUE;
}

void MatMatMultiply(GLfloat *result, GLfloat *matrix1, GLfloat *matrix2)
{
    result[0]=matrix1[0]*matrix2[0]+
    matrix1[4]*matrix2[1]+
    matrix1[8]*matrix2[2]+
    matrix1[12]*matrix2[3];
    result[4]=matrix1[0]*matrix2[4]+
    matrix1[4]*matrix2[5]+
    matrix1[8]*matrix2[6]+
    matrix1[12]*matrix2[7];
    result[8]=matrix1[0]*matrix2[8]+
    matrix1[4]*matrix2[9]+
    matrix1[8]*matrix2[10]+
    matrix1[12]*matrix2[11];
    result[12]=matrix1[0]*matrix2[12]+
    matrix1[4]*matrix2[13]+
    matrix1[8]*matrix2[14]+
    matrix1[12]*matrix2[15];
    result[1]=matrix1[1]*matrix2[0]+
    matrix1[5]*matrix2[1]+
    matrix1[9]*matrix2[2]+
    matrix1[13]*matrix2[3];
    result[5]=matrix1[1]*matrix2[4]+
    matrix1[5]*matrix2[5]+
    matrix1[9]*matrix2[6]+
    matrix1[13]*matrix2[7];
    result[9]=matrix1[1]*matrix2[8]+
    matrix1[5]*matrix2[9]+
    matrix1[9]*matrix2[10]+
    matrix1[13]*matrix2[11];
    result[13]=matrix1[1]*matrix2[12]+
    matrix1[5]*matrix2[13]+
    matrix1[9]*matrix2[14]+
    matrix1[13]*matrix2[15];
    result[2]=matrix1[2]*matrix2[0]+
    matrix1[6]*matrix2[1]+
    matrix1[10]*matrix2[2]+
    matrix1[14]*matrix2[3];
    result[6]=matrix1[2]*matrix2[4]+
    matrix1[6]*matrix2[5]+
    matrix1[10]*matrix2[6]+
    matrix1[14]*matrix2[7];
    result[10]=matrix1[2]*matrix2[8]+
    matrix1[6]*matrix2[9]+
    matrix1[10]*matrix2[10]+
    matrix1[14]*matrix2[11];
    result[14]=matrix1[2]*matrix2[12]+
    matrix1[6]*matrix2[13]+
    matrix1[10]*matrix2[14]+
    matrix1[14]*matrix2[15];
    result[3]=matrix1[3]*matrix2[0]+
    matrix1[7]*matrix2[1]+
    matrix1[11]*matrix2[2]+
    matrix1[15]*matrix2[3];
    result[7]=matrix1[3]*matrix2[4]+
    matrix1[7]*matrix2[5]+
    matrix1[11]*matrix2[6]+
    matrix1[15]*matrix2[7];
    result[11]=matrix1[3]*matrix2[8]+
    matrix1[7]*matrix2[9]+
    matrix1[11]*matrix2[10]+
    matrix1[15]*matrix2[11];
    result[15]=matrix1[3]*matrix2[12]+
    matrix1[7]*matrix2[13]+
    matrix1[11]*matrix2[14]+
    matrix1[15]*matrix2[15];
}

这篇关于OpenGL ES (iPhone) 触摸拾取的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆