ARCore中根据屏幕坐标计算射线的算法

ARCore中提供了根据屏幕坐标、视口大小及view、 project矩阵计算从屏幕坐标发射一条射线的方法,此方法用于3D拾取。

 1 class Ray {
 2 
 3     public final Vector3f origin;//射线起点
 4     public final Vector3f direction;//射线方向
 5 
 6     public Ray(Vector3f origin, Vector3f direction) {
 7         this.origin = origin;
 8         this.direction = direction;
 9     }
10 
11     //根据屏幕坐标计算射线——3D拾取
12     public static Ray screenPointToRay(Vector2f point, Vector2f viewportSize, float[] viewProjMtx) {
13         point.y = viewportSize.y - point.y;//转化为左下角为原点
14         float x = point.x * 2.0F / viewportSize.x - 1.0F;//转换到[-1,1]
15         float y = point.y * 2.0F / viewportSize.y - 1.0F;//转换到[-1,1]
16 
17         float[] farScreenPoint = new float[]{x, y, 1.0F, 1.0F};//远平面上的坐标透视除法之后的值
18         float[] nearScreenPoint = new float[]{x, y, -1.0F, 1.0F};//近平面上的坐标透视除法之后的值
19 
20         float[] nearPlanePoint = new float[4];//用于记录世界坐标系下,近平面上的点
21         float[] farPlanePoint = new float[4];//用于记录世界坐标系下,远平面上的点
22 
23         float[] invertedProjectionMatrix = new float[16];
24         Matrix.setIdentityM(invertedProjectionMatrix, 0);
25         Matrix.invertM(invertedProjectionMatrix, 0, viewProjMtx, 0);//计算逆矩阵
26 
27         Matrix.multiplyMV(nearPlanePoint, 0, invertedProjectionMatrix, 0, nearScreenPoint, 0);//计算世界坐标系中,对应到近平面的坐标
28         Matrix.multiplyMV(farPlanePoint, 0, invertedProjectionMatrix, 0, farScreenPoint, 0);
29 
30         Vector3f direction = new Vector3f(farPlanePoint[0] / farPlanePoint[3], farPlanePoint[1] / farPlanePoint[3], farPlanePoint[2] / farPlanePoint[3]);
31         Vector3f origin = new Vector3f(new Vector3f(nearPlanePoint[0] / nearPlanePoint[3], nearPlanePoint[1] / nearPlanePoint[3], nearPlanePoint[2] / nearPlanePoint[3]));
32         direction.sub(origin);
33         direction.normalize();
34         return new Ray(origin, direction);
35     }   
36 }

 

原理:

一、世界坐标系的点P1转化到投影空间得到点P2的公式是:P2 = P1 * viewMatrix * projectMatrix = P1 * viewProjMatrix;

在渲染管线中,投影空间的点还需要经过透视除法,转化到x , y , z值均为[-1,1]区间内,是一个单位立方体。公式是:point_clip = P2/P2.w;

 

那么将点从单位立方体坐标系转化到世界坐标系的公式跟上述情况是逆过程,公式:

P2 = point_clip * wValue;
P1 = P2 * viewProjMatrix_invert;

其中wValue代表给定的w值,在ARCore中此值为1,所以并未体现在代码中。

 

二、上面代码片段,是将屏幕上的点的x,y坐标值均转化到[-1,1],给定近裁剪平面的点的z为-1,远裁剪平面上的点的z为1,其w值均为1,这种方法得到透视除法后单位立方体中的坐标。

因为wValue为1,所以此时farScreenPoint和nearScreenPoint就代表投影空间中的坐标点。

然后根据(一)中的结论即可得到对应到世界坐标系的坐标点,根据两个点可得到射线方法,最终即可得到射线的起点和方向。

posted @ 2017-09-07 12:03  bky2016  阅读(1493)  评论(0编辑  收藏  举报