【问题标题】:How can I calculate the 3D angle between two points?如何计算两点之间的 3D 角度?
【发布时间】:2019-06-11 04:39:06
【问题描述】:

假设我有两个顶点,我想知道这两个顶点之间的 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);

例如,在上图中,我在一条连接三角形上两个顶点的线段上进行了追踪。应该可以求出x、y、z轴上两个顶点位置的夹角。

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

【问题讨论】:

  • 在目前的状态下,这个问题可能因为不清楚(根据您的评论)而关闭,即使您也不清楚。你想达到什么目的?
  • this 被链接为可能的重复候选者,但我无法破译那里的 python 并识别解决方案的正确 JS 版本。
  • @RobbyCornelissen 从一个顶点到另一个顶点的角度。
  • 当我第一次发布这个问题时,我使用的术语是“矢量”而不是“3D 角度”,这是不正确的。我正在寻找所有三个平面上 3D 空间中两个位置之间的角度。
  • @Spektre 获取角度的目的是然后构建一个简单的(不完美但快速)函数,用于确定光线与 tri 碰撞时应该反弹的位置。通过知道从 tri 的一个顶点到下一个顶点的角度,对于所有三个边缘,我相信我可以计算出一个非常快速且有点准确的向量来确定光线应该反弹的位置。最终,为了好玩,我正在努力在光线追踪系统中找出我自己的反射光版本。

标签: javascript algorithm geometry


【解决方案1】:

您可以像这样在两个方向v1,v2(向量)之间设置角度:

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

3D 中转换为:

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

但是,两点之间不能有毫无意义的角度。还要注意 3D 角度不是您认为的那样(它的球面度角,您可以将其视为体积覆盖范围......法线角度是区域覆盖范围),是的,它也是标量值。因此,您正在寻找的是 方向余弦欧拉角(您需要更多信息和变换顺序才能不雄心勃勃)或 transform matrices

但我怀疑这是一个 XY 问题,根据你的 cmets 我是对的。

所以你的真正的问题(基于 cmets)是找到来自(三角形)面的反射光线。使用角度(方向余弦、欧拉角或变换矩阵)是一个非常糟糕的主意,因为这会非常慢。而是使用简单的向量数学,我看到它是这样的:

所以你得到了光线方向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 会自行处理标志...

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

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

这是我将这种技术用于光线追踪器的示例:

它的我的 GLSL 光线追踪器支持三角形面的反射,并且它没有测角仪...在片段着色器中寻找 // reflect 评论特别寻找:

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

它的反射在哪里

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

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

【讨论】:

  • @bramp thx 不错的收获
【解决方案2】:

我不确定这段代码是否正确,但我认为这是我要找的。​​p>

// 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);

【讨论】:

    【解决方案3】:

    这就是我在 Cinema 4d python 中计算 3d 点之间角度的方法...不,感谢互联网:

    def GetAngle(self, a, b):
        length = math.sqrt((a.x - b.x)**2 + (a.y - b.y)**2 + (a.z - b.z)**2)
        rise = b.y - a.y
        run = math.sqrt((length**2) - (rise**2))
        angle = math.degrees(math.atan(rise/run))
        return angle
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多