我正在使用OpenGLE 2使用Android、Java代码进行3D物体渲染。如何使用下面的代码近距离和远位置来识别3D对象或3D对象之外的点击?

public static PointF screenToWorld(float[] viewMatrix,
                                       float[] projMatrix, float screenX, float screenY) {
        float[] nearPos = unProject(viewMatrix, projMatrix, screenX, screenY, 0);
        float[] farPos = unProject(viewMatrix, projMatrix, screenX, screenY, 1);

        Log.d(LOGTAG,"nearPos ->"+nearPos.length+" "+nearPos);
        Log.d(LOGTAG,"farPos ->"+farPos.length+" "+farPos);

        // The click occurred in somewhere on the line between the two points
        // nearPos and farPos. We want to find
        // where that line intersects the plane at z=0
        float distance = nearPos[2] / (nearPos[2] - farPos[2]); // Distance between nearPos and z=0
        float x = nearPos[0] + (farPos[0] - nearPos[0]) * distance;
        float y = nearPos[1] + (farPos[1] - nearPos[0]) * distance;
        return new PointF(x, y);
    }

    private static float[] unProject(float[] viewMatrix,
                                     float[] projMatrix, float screenX, float screenY, float depth) {
        float[] position = {0, 0, 0, 0};
        int[] viewPort = {0, 0, 1, 1};
        GLU.gluUnProject(screenX, screenY, depth, viewMatrix, 0, projMatrix, 0,
                viewPort, 0, position, 0);
        position[0] /= position[3];
        position[1] /= position[3];
        position[2] /= position[3];
        position[3] = 1;
        return position;

    }

最佳答案

如何识别三维对象内部或外部的单击?
必须验证是否命中了对象的任何基本体。
近平面上的点和远平面上的点定义了穿过世界的光线:

float[] nearPos = unProject(viewMatrix, projMatrix, screenX, screenY, 0);
float[] farPos  = unProject(viewMatrix, projMatrix, screenX, screenY, 1);

伪代码:
R0 = nearPos
D  = normalize(farPos - nearPos)

找到光线与基本体的交点
要找到被光线击中的曲面,必须计算每个曲面(基本体)与光线的交点和光线的起点的距离。击中距离(射线方向)最小的曲面。
要查找光线与三角形基本体相交点的距离,必须执行以下步骤:
找到由三角形基本体的3个点定义的光线和平面的交点。
计算相交点和光线起点之间的距离。
测试交点是否在光线的方向上(不是在相反的方向上)
测试交点是否在三角形控件中或三角形控件上。
找到交点和交点距离:
android - 如何使用近处和远处位置识别3D对象内部或外部3D对象的单击-LMLPHP
平面由范数向量(NV)和平面上的点(P0)定义。如果三角形是由3个点PAPBPC给出的,则平面的计算如下:
P0 = PA
NV = normalize( cross( PB-PA, PC-PA ) )

射线与平面的交线是通过代入射线方程来计算的
P_isect = dist * D + R0进入平面方程。
如下:
dist_isect = dot( P0 - R0, NV ) / dot( D, NV )
P_isect    = R0 + D * dist_isect

测试交点是否在光线方向:
如果距离大于或等于0.0,则交点在射线方向上。
测试交点是否在三角形控件中或三角形控件上
要查明,如果一个点位于三角形内部,则必须进行测试,如果从一个角点到交点的直线位于连接到该角点的“到”腿之间:
bool PointInOrOn( P1, P2, A, B )
{
    CP1 = cross( B - A, P1 - A )
    CP2 = cross( B - A, P2 - A )
    return dot( CP1, CP2 ) >= 0
}

bool PointInOrOnTriangle( P, A, B, C )
{
    return PointInOrOn( P, A, B, C ) &&
           PointInOrOn( P, B, C, A ) &&
           PointInOrOn( P, C, A, B )
}

另请参见:Is it possble get which surface of cube will be click in OpenGL?

07-28 03:24
查看更多