Как я могу рассчитать угол 3D между двумя точками? - PullRequest
0 голосов
/ 11 июня 2019

Допустим, у меня есть две вершины, и я хочу знать трехмерный угол между ними.Под углом 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 ]

1 голос
/ 12 июня 2019

Вы можете иметь угол между двумя направлениями 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-угол - это не то, что вы думаете (его угол в стерадианах, и вы можете рассматривать его как объемное покрытие ... нормальный угол - это охват области), и да, это также скалярное значение.Итак, вы ищете направляющие косинусы или углы Эйлера (для которых вам нужно больше информации и порядок преобразований, чтобы не быть амбициозными) или матрицы преобразования .

Но поскольку я подозревал, что это проблема 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 обрабатывает знаки самостоятельно ...

В случае, если вам нужно, нормаль может быть вычислена путем перекрестного произведения двух ее сторон.поэтому, если треугольник определен 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 - нормальное лицо (выглядит знакомо?да это же уравнение) ...

0 голосов
/ 11 июня 2019

Я не уверен, что этот код правильный, но я думаю, что это то, что я искал.

// 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...