如何使用近距和远距识别3D对象内部或外部3D对象中的单击 [英] How to identify click inside the 3D object or outside 3D object using near and far positions

查看:129
本文介绍了如何使用近距和远距识别3D对象内部或外部3D对象中的单击的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用OpenGLES 2.0和Android,Java代码进行3D对象渲染.如何使用下面的代码在近和远位置识别3D对象内部或外部3D对象中的单击?

I am working in 3D object rendering using OpenGLES 2.0 with Android,Java code.How to identify click inside the 3D object or outside 3D object using following code near and far positions?

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;

    }

推荐答案

如何识别3D对象内部或3D对象外部的单击?

How to identify click inside the 3D object or outside 3D objec?

您必须验证是否击中了该对象的任何图元.

You have to verify if you hit any of the primitives of the object.

近平面上的点和远平面上的点定义了穿过世界的光线:

The point at the near plane and the point at the far plane define a ray through the world:

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

伪代码:

R0 = nearPos
D  = normalize(farPos - nearPos)


要找到被射线撞击的表面,必须计算每个表面(原始)与射线的交点与射线起点的距离. (在射线方向上)距离最小的表面被击中.

To find the surface which is hit by the ray, the distance of the intersection point of each surface (primitive) with the ray and the start point of the ray has to be calculated. The surface which has the lowest distance (in the ray direction), is hit.

要找到射线与三角形图元的交点的距离,必须执行以下步骤:

To find the distance of the intersection point of a ray with a triangle primitive, the following steps has to be done:

  1. 找到射线与由三角形图元的3个点定义的平面的交点.
  2. 计算射线的交点与起点之间的距离.
  3. 测试交点是否在射线方向(不是相反方向)
  4. 测试交点是否在三角形构造内或上.

找到相交点和相交距离:

一个平面由范数矢量(NV)和该平面上的一个点(P0)定义.如果由三个点PAPBPC给出三角形,则可以按以下方式计算平面:

A plane is defined by a norm vector (NV) and a point on the plane (P0). If a triangle is given by the 3 points PA, PB and PC, the plane can be calculated as follows:

P0 = PA
NV = normalize( cross( PB-PA, PC-PA ) )

通过代入射线方程,可以计算出射线与平面的交点
P_isect = dist * D + R0进入平面dot( P_isect - P0, NV ) == 0的方程式中.
如下:

The intersection of a ray with a plane is calculated by substituting the equation of the ray
P_isect = dist * D + R0 into the equation of the plane dot( P_isect - P0, NV ) == 0.
It follows:

dist_isect = dot( P0 - R0, NV ) / dot( D, NV ) 
P_isect    = R0 + D * dist_isect

测试交点是否在射线的方向上:

如果`dist_isect大于或等于0.0,则交点指向射线方向.

The intersection point is in the direction of the ray, if `dist_isect is greater or equal 0.0.

测试交点是否在三角形contur内或上

要找出一个点是否在三角形内,是否必须进行测试,即从拐角点到相交点的线是否在连接到拐角点的支腿之间:

To find out, if a point is inside a triangle, has to be tested, if the line from a corner point to the intersection point is between the to legs which are connect to the corner point:

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 )
} 


另请参阅:是否可以在OpenGL中单击立方体的哪个表面?


See also: Is it possble get which surface of cube will be click in OpenGL?

这篇关于如何使用近距和远距识别3D对象内部或外部3D对象中的单击的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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