Android OpenGL ES上的Ray对象选择

时间:2014-02-03 13:13:57

标签: android opengl-es rajawali

我正在Android平台上使用OpenGL绘制一个地球仪,并尝试在用户点击的球体上找到一个点。我是OpenGL的新手,我正在使用opensource lib Rajawali,因为它在示例Touch & Drag中显示,但如果有人知道更好的方法,请建议我,因为Rajawali的代码完全没有评论和大部分文档都已过时:(

double[] np4 = new double[4]; //near plane
double[] fp4 = new double[4]; // far plane

GLU.gluUnProject(
        x, mViewportHeight - y, 0.0f, 
        mViewMatrix.getDoubleValues(), 0, 
        mProjectionMatrix.getDoubleValues(), 0, 
        mViewport, 0, 
        np4, 0
);

GLU.gluUnProject(
        x, mViewportHeight - y, 1.0f, 
        mViewMatrix.getDoubleValues(), 0, 
        mProjectionMatrix.getDoubleValues(), 0, 
        mViewport, 0, 
        fp4, 0
);

// transform 4D coordinates (x, y, z, w) to 3D (x, y, z) by dividing each coordinate (x, y, z) by w.
return new Ray(
        new Vector3(np4[0] / np4[3], np4[1] / np4[3], np4[2] / np4[3]),
        new Vector3(fp4[0] / fp4[3], fp4[1] / fp4[3], fp4[2] / fp4[3])
    );

然后找到一个与球体(半径= 1,中心(0,0,0))的交点,如here所述

    /**
     * Calculate point of intersection of line and sphere.
     * 
     * @param p1 Point the line goes throw
     * @param p2 Point the line goes throw
     * @param center Center of the sphere
     * @param r Radius of the sphere
     * @return <code>Vector3</code> Coordinates of intersection point
     */
    private Vector3 getIntersectionPoint(Vector3 p1, Vector3 p2, Vector3 center, double r){
        if (p1 == null || p2 == null || center == null)
            return null;

        double a = in2(p2.x - p1.x) + in2(p2.y - p1.y) + in2(p2.z - p1.z);
        double b = 2*( (p2.x - p1.x)*(p1.x - center.x) + (p2.y - p1.y)*(p1.y - center.y) + (p2.z - p1.z)*(p1.z - center.z) );
        double c = in2(center.x) + in2(center.y) + in2(center.z) + in2(p1.x) + in2(p1.y) + in2(p1.z) - 2*(center.x*p1.x + center.y*p1.y + center.z*p1.z) - in2(r);

        //simplified equations for Sphere coordinates are (0, 0, 0) r=1 and cam.x = cam.y = 0
//      double a = in2(p2.x) + in2(p2.y) + in2(p2.z - p1.z);
//      double b = 2*( (p2.z - p1.z)*p1.z );
//      double c = in2(p1.z) - 1;

        for (Vector3 poi : solveQuadraticEquation(a, b, c, p1, p2)){
            if (poi.z > 0)
                return poi;
        }

        return null;
    }


    /**
     * Solve quadratic equation.
     * 
     * @param a Parameter A in equation Ax^2 + Bx + C = 0
     * @param b Parameter B in equation Ax^2 + Bx + C = 0
     * @param c Parameter C in equation Ax^2 + Bx + C = 0
     * @param p1 <code>Vector3</code> Start point for the line
     * @param p2 <code>Vector3</code> End point for the line
     * 
     * @return <code>List<Vector3></code> of results. Empty if no results found.
     */
    private List<Vector3> solveQuadraticEquation(double a, double b, double c, Vector3 p1, Vector3 p2){
        double D = in2(b) - 4*a*c;

        List<Vector3> rez = new ArrayList<Vector3>();

        if (D < 0) {

            return rez;

        } else  if (D == 0) {

            double t = (-b) / (2*a);
            rez.add(new Vector3(p1.x + (p2.x - p1.x)*t, p1.y + (p2.y - p1.y)*t, p1.z + (p2.z - p1.z)*t));

            return rez;

        } else {


            double t = (Math.sqrt(D)-b) / (2*a);
            rez.add(new Vector3(p1.x + (p2.x - p1.x)*t, p1.y + (p2.y - p1.y)*t, p1.z + (p2.z - p1.z)*t));

            t = (-Math.sqrt(D)-b) / (2*a);
            rez.add(new Vector3(p1.x + (p2.x - p1.x)*t, p1.y + (p2.y - p1.y)*t, p1.z + (p2.z - p1.z)*t));

            return rez;

        }
    }

这是一个结果:

enter image description here

下面: 蓝点是(-1,-1,-1),(1,-1,-1),(1,1,-1)和(-1,1,-1) 绿点是(-1,-1,1),(1,-1,1),(1,1,1)和(-1,1,1) 黄色点是(1,0,0),(0,1,0),( - 1,0,0)和(0,-1,0)

当我点击顶部黄色圆圈时,小红点是一个交点: x:405.10202 y:430.5059(触摸监听器中的event.getX(),evet.getY()) 这是一个未经注意的要点: 附近:Vector3:&lt; 0.0038529188490706075,0.08910624125329661,4.999999999999999&gt; far:Vector3:&lt; 0.46235026188847467,10.692748950395632,-114.00000000000048&gt; 交叉口:Vector3:&lt; 0.019687997272589165,0.45532322467387265,0.8901085011592542&gt;

相机位置为(0,0,-6)

请问有人帮我把这个小红点放在手指下吗?

P.S。我需要一个交叉点而不仅仅是一个对象选择因为我将在以后获得国家代码......

1 个答案:

答案 0 :(得分:0)

问题是ViewPort对应于视图尺寸(在这种情况下是GLSurfaceView),但是点是绝对坐标,因此应该转换为相对,例如:

final float x = e.getX() - getLeft();
final float y = e.getY() - getTop();