游戏引擎开发:如何计算射线与三角形的交点坐标?
射线-三角形相交检测获取交点坐标的最佳实现方式
我自研一款游戏引擎,此前完整实现了射线-三角形相交检测功能,目前仅能判断两者是否相交,我想获取交点的精确坐标,请问最佳实现方式是什么?
我准备了用于测试的最小可复现代码:
var cube = { "positions": [-1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0 ], "indices": [ 0, 3, 2, 1, 3, 0, 3, 1, 7, 1, 5, 7, 0, 4, 5, 5, 1, 0, 6, 2, 7, 2, 3, 7, 5, 4, 7, 7, 4, 6, 0, 6, 4, 0, 2, 6 ], "uv": [ 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0 ] } var camPos = [0, 0, -10]; var camRot = [0, 0, 0]; setInterval(() => { for (var j = 0; j < cube.indices.length; j += 3) { var startPos = [camPos[0], camPos[1], camPos[2]]; var rotation = [-camRot[0], camRot[1], camRot[2]]; var len = 1000000; var endPos = [ startPos[0] + (len * Math.sin(rotation[1])), startPos[1] + (len * Math.tan(rotation[0])), startPos[2] + (len * Math.cos(rotation[1])) ]; var dir = [ endPos[0] - startPos[0], endPos[1] - startPos[1], endPos[2] - startPos[2], ]; var v1 = [ cube.positions[cube.indices[j] * 3], cube.positions[cube.indices[j] * 3 + 1], cube.positions[cube.indices[j] * 3 + 2] ]; var v2 = [ cube.positions[cube.indices[j + 1] * 3], cube.positions[cube.indices[j + 1] * 3 + 1], cube.positions[cube.indices[j + 1] * 3 + 2] ]; var v3 = [ cube.positions[cube.indices[j + 2] * 3], cube.positions[cube.indices[j + 2] * 3 + 1], cube.positions[cube.indices[j + 2] * 3 + 2] ]; var u = [ v2[0] - v1[0], v2[1] - v1[1], v2[2] - v1[2] ]; var v = [ v3[0] - v1[0], v3[1] - v1[1], v3[2] - v1[2] ]; var n = [ u[1] * v[2] - u[2] * v[1], u[2] * v[0] - u[0] * v[2], u[0] * v[1] - u[1] * v[0] ]; var w0 = [ startPos[0] - v1[0], startPos[1] - v1[1], startPos[2] - v1[2] ]; var a = -(n[0] * w0[0] + n[1] * w0[1] + n[2] * w0[2]); var b = (n[0] * dir[0] + n[1] * dir[1] + n[2] * dir[2]); if (b < 0) { continue; } /*if(Math.abs(b) < 0.00001){ if(a==0){ //console.log("parallel"); continue;} else{ //console.log("not intersecting"); continue;} }*/ var r = a / b; //console.log(r); if (r <= 0 || r >= 1) { //console.log("not intersecting"); continue; } var rd = [ dir[0] * r, dir[1] * r, dir[2] * r ]; var ii = [ startPos[0] + rd[0], startPos[1] + rd[1], startPos[2] + rd[2] ]; var uu = u[0] * u[0] + u[1] * u[1] + u[2] * u[2]; var uv = u[0] * v[0] + u[1] * v[1] + u[2] * v[2]; var vv = v[0] * v[0] + v[1] * v[1] + v[2] * v[2]; var w = [ ii[0] - v1[0], ii[1] - v1[1], ii[2] - v1[2] ]; var wu = w[0] * u[0] + w[1] * u[1] + w[2] * u[2]; var wv = w[0] * v[0] + w[1] * v[1] + w[2] * v[2]; var d = uv * uv - uu * vv; var s = (uv * wv - vv * wu) / d; if (s <= 0 || s > 1) { //console.log("not intersecting"); continue; } var t = (uv * wu - uu * wv) / d; if (t <= 0 || (s + t) > 1) { //console.log("not intersecting"); continue; } // use these values to find the point of intersection somehow?? console.log(s + "," + t + "," + (s + t)); } camRot[1] = Math.sin(Date.now() / 1000) * .1; }, 10);
我的假设是利用边界检查返回的值,通过线性插值计算交点,但目前尚未成功,后续会反馈进展。
内容的提问来源于stack exchange,提问作者rbw
相关产品推荐
相关产品推荐

