点选模型是在webgl技术交流群里常被问到一个问题;这里做一个总结
本文一是提供three 基本实现demo,二是从webgl底层去做射线简单实现 ,三是介绍其简单数学原理;
一、three实现
在线demo:
Exp -- rayTestthinkia.github.io源码地址
https://github.com/Thinkia/three-Effect/blob/master/examples/exp/ray/rayTest.htmlgithub.com二、 thinkgl实现
在线demo:
rayTestthinkia.github.io源码地址:
https://github.com/Thinkia/thinkgl/blob/master/example/tutorial/ray/rayTest.jsgithub.com三、数学介绍
- 点击屏幕获取单位屏幕二维坐标;
let x =( event.clientX / window.innerWidth ) * 2 - 1;
let y = - ( event.clientY / window.innerHeight ) * 2 + 1;
let vec = [ x,y,0.5 ];
2.乘投影矩阵的逆获取单位向量
let inversePMat = ia.thinkMath.mat4.getInverse( pMat );
ia.thinkMath.vec3.applyMat4( vec,inversePMat );
前面两点是三维成像原理的逆过程,这里不细说了;
3. 三维向量与三角面是否有交点?
a.三维向量与平面关系无非是平行和相交
b.如果向量与平面的交点为d , 三角面顶点分别为a,b,c;
c.如果向量与平面有交点必然有 Sabd + Sadc + Sdbc - Sabc < 0.0001
三角形面积用海伦公式, 平面方程用待定系数法;
向量与平面交点可参考
上面过程主要使用向量运算,巧妙避开了求模运算中的开方运算,减少了很多的运算量,而且,容易步骤化,易于编程实现。
编程实现: intersectionLinePlane(origin,vec,pointA,pointB,pointC)
/** * * @param p1 射线起始点 * @param p2 射线终点 * @param pointA 三角面片 顶点A * @param pointB 三角面片 顶点B * @param pointC 三角面片 顶点C * @returns {boolean} * */
intersectionLinePlane:function ( p1,p2,pointA,pointB,pointC ) {
let pointD =[];
let p1p2 = [ p2[0]-p1[0],p2[1]-p1[1],p2[2]-p1[2] ];
// 平面方程
let PE = ia.thinkMath.vec3.planeEquation( pointA,pointB,pointC );
let num = PE.A * p1[0] + PE.B * p1[1] + PE.C * p1[2] + PE.D ;
let den = PE.A * p1p2[0] + PE.B * p1p2[1] + PE.C*p1p2[2];
// 平行 与法向量垂直
if( Math.abs(den) <1e-5 ) return false ;
let n = -num/den ;
for( let i=0;i<3;i++) pointD[i] = p1[i] + n*p1p2[i];
// ABC 面积
let s0 = ia.thinkMath.vec3.triangleArea( pointA,pointB,pointC );
// DAB 面积
let s1 = ia.thinkMath.vec3.triangleArea( pointD,pointB,pointC );
// DBC 面积
let s2 = ia.thinkMath.vec3.triangleArea( pointA,pointD,pointC );
// DCA 面积
let s3 = ia.thinkMath.vec3.triangleArea( pointA,pointB,pointD);
if( Math.abs( (s1+s2+s3 -s0)) < 1e-6 )
{
console.log(`射线交点坐标:${pointD}` ) ;
return true;
} else
return false;
},
感谢您的阅读,如有谬误或者不当之处还请指正;