如何计算两点之间的3D角度?

时间:2019-06-11 04:39:06

标签: javascript algorithm geometry

比方说,我有两个顶点,并且我想知道两个顶点之间的3D角度。所谓3D角,是指在三个维平面中的一个顶点与另一个顶点之间的角度,存储为

{ x, y, z }

function getAngleBetweenVertices(vert1, vert2){
  return {
    x: 0, // ?
    y: 0, // ?
    z: 0  // ?
  }
}

// Classes

class Vertex {
  constructor(position){
    this.position = {
      x: 0,
      y: 0,
      z: 0,
      ...position
    };
  }
}

// Init

let vert1 = new Vertex({ x: 1, y: 0, z: 1 });
let vert2 = new Vertex({ x: 0, y: 1, z: 1 });
let angle = getAngleBetweenVertices(vert1, vert2);
console.log("angle ", angle);

enter image description here

例如,在上图中,我在连接三角形上两个顶点的线段上进行了追踪。应该可以找到x,y和z轴上两个顶点位置之间的角度。

如何计算两个顶点之间的三维角度?

2 个答案:

答案 0 :(得分:1)

您可以在两个方向v1,v2(向量)之间设置角度,如下所示:

ang = acos(dot(v1,v2)/(|v1|.|v2|))

3D 转换为:

ang = acos( (x1*x2 + y1*y2 + z1*z1) / sqrt( (x1*x1 + y1*y1 + z1*z1)*(x2*x2+y2*y2+z2*z2) ) )

但是,您不能在两点之间没有完全没有意义的角度。还要注意3D角度不是您想的那样(它的角度为球面度,您可以将其视为体积覆盖率...法线角度是面积覆盖率),是的,它也是标量值。因此,您要查找的是方向余弦欧拉角(您需要更多信息和变换顺序以免过于雄心勃勃)或transform matrices。 / p>

但是由于我怀疑它是XY问题,并且根据您的评论,我是对的。

因此,您的实际问题(基于评论)是从(三角形)面上找到反射光线。使用角度(方向余弦,欧拉角或变换矩阵)不是一个好主意,因为那样做会非常慢。而是使用简单的矢量数学,我会这样看:

reflect

因此,您获得了射线方向dir,并希望从具有正常dir'的脸部反射nor,所以:

dir' = 2 * ( nor*dot(-dir,nor) + dir ) - dir
dir' = 2 * ( -nor*dot(dir,nor) + dir ) - dir
dir' = -2*nor*dot(dir,nor) + 2*dir - dir
dir' = -2*nor*dot(dir,nor) + dir
dir' = dir-2*nor*dot(dir,nor)

所以在 3D 中是:

dir=(dx,dy,dz)
nor=(nx,ny,nz)
t = 2*(dx*nx + dy*ny + dz*nz) // 2*dot(dir,nor)
dx' = dx-t*nx
dy' = dy-t*ny
dz' = dz-t*nz

正如您所见,根本不需要角度测量法或角度... dot的法向点是否在人脸/物体中也无关紧要...

如果需要法线,则可以通过其2边的叉积来计算,因此,如果三角形由v0,v1,v2点定义,则:

nor = cross( v1-v0 , v2-v1 )

在此示例中,我将这种技术用于raytracer:

它的我的 GLSL 射线跟踪器支持三角形面上的反射,并且其中没有测角法...在片段着色器中寻找// reflect评论,尤其是寻找:

ray[rays].dir=ray[rays].dir-(2.0*t*ray[rays].nor);

将其反射到

t=dot(ray[i0].dir,ray[i0].nor);

其中dir是射线方向,nor是面法线(看起来很熟悉?是的,它是相同的方程式)...

答案 1 :(得分:0)

我不确定这段代码是否正确,但是我认为它是我想要的。

// Utilities

function normalizeAngle(angle){
  if (angle > 360) return angle - 360;
  if (angle < 0) return 360 + angle;
  else return angle;
}

function getAngleBetweenPoints(cx, cy, ex, ey){
  var dy = ey - cy;
  var dx = ex - cx;
  var theta = Math.atan2(dy, dx);
  theta *= 180 / Math.PI;
  return theta;
}

function getAngleBetweenVertices(vert1, vert2){
  return {
    x: normalizeAngle(getAngleBetweenPoints(vert1.position.z, 
        vert1.position.x, vert2.position.z, vert2.position.x)),
    y: normalizeAngle(getAngleBetweenPoints(vert1.position.z, 
        vert1.position.y, vert2.position.z, vert2.position.y)),
    z: normalizeAngle(getAngleBetweenPoints(vert1.position.x, 
        vert1.position.y, vert2.position.x, vert2.position.y))
  }
}

// Classes

class Vertex {
  constructor(position){
    this.position = {
      x: 0,
      y: 0,
      z: 0,
      ...position
    };
  }
}

// Init

let vert1 = new Vertex({ x: 1, y: 0, z: 1 });
let vert2 = new Vertex({ x: 0, y: 1, z: 1 });
let angle = getAngleBetweenVertices(vert1, vert2);
console.log("angle ", angle);