Я работаю с JavaScript (React) над программа геометрии, который создает аксонометрия (лучше параллельные проекции), указанный объект, определенный по вершинам и граням (лицо может иметь разное количество вершин).
Он отлично работает, если вы не используете нужно, чтобы лица были непрозрачными, иначе есть грани выше других, которые должны быть ниже.
Итак, я хочу упорядочить свой список лиц от дальнего до ближайшего:
[
[[100, 0, 100], [50, 50, 50], [120, 170, 120], [10, 200, 150]],
[[10, 20, 30], [10, 200, 250], [50, 50, 50], [100, 30, 30]],...
]
Я буду использовать faces.sort(sortingFunction).
Меня не волнуют пересекающиеся лица
(он возьмет грани всех объектов вместе)
Каким должен быть sortingFunction?
Вы должны учитывать как определяется аксонометрия. Он определяется Вращение по осям X, Y (Xrotation может быть как больше, так и меньше, чем Yrotation), Вращение по оси Z составляет π / 4 (90 °).
Вот старая версия приложения, который дает вам понять, что я имею в виду: http://dev_proiezioni.surge.sh/
Простите за мой ужасный английский. Спасибо



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Сортировать по расстоянию от камеры.
function distanceBetweenTwoPoints (p1, p2) {
return Math.hypot(p1.x - p2.x, p1.y - p2.y, p1.z - p2.z)
}
function sortFunction (p1, p2) {
return distanceBetweenTwoPoints(camera, p1) > distanceBetweenTwoPoints(camera,p2) ? -1 : 1
}
Измените знак > в зависимости от того, какой порядок вы хотите.
Ах, конечно. Не продумала, извините. Я думаю, вам больше повезет с ответами на каком-нибудь сайте Stack Exchange, посвященном математике.
I don't care about intersecting faces
Это означает, что мы можем уменьшить равнины до точек, взяв точку посередине:
const vecOp = op => (a, b) => a.map((c, i) => op(c, b[i] || b));
const add = vecOp((a, b) => a + b);
const sub = vecOp((a, b) => a - b);
const mul = vecOp((a, b) => a * b);
const div = vecOp((a, b) => a / b);
const sum = v => v.reduce((a, b) => a + b, 0);
const middle = (a, b) => div(add(a, b), 2);
const planeToPoint = ([a, b, c, d]) => middle(
middle(a, b),
middle(c, d)
);
Теперь, чтобы отсортировать по «ближе к камере», можно провести линию между центрами двух плоскостей, в результате получится направление:
const aToB = (a, b) =>
sub(
planeToPoint(b),
planeToPoint(a)
);
Теперь мы могли превратить поворот камеры в вид камеры:
const rotToVec = (yaw, pitch) => ([
Math.cos(yaw) * Math.cos(pitch),
Math.sin(yaw) * Math.cos(pitch),
Math.sin(pitch)
]);
и это направление можно сравнить с направлением камер, что дает угол между ними:
const angle = (a, b) => sum(mul(a, b)) / sum(a) * sum(b)
Теперь давайте перевернем это все вместе:
const camVec = rotToVec(cam.yaw, cam.pitch);
planes.sort((a, b) =>
Math.abs(angle(aToB(a, b), camVec)) < Math.PI / 4 /*90°*/ ? 1 : -1
);
Отказ от ответственности: я не пробовал приведенный выше код, не работал с параллельными проекциями и плохо разбираюсь в математике, поэтому примите мои слова осторожно, я понятия не имею, о чем говорю.
Большое спасибо, но вы заметили, что моя проекция определяется двумерным вращением осей, так как я могу получить cam.jaw и cam.pitch?
@strategaD, то есть рыскание и тангаж
Для приблизительного решения используйте преобразование из 3D в 3D и учитывайте координату Z. Для каждого лица сохраните ближайшую Z и отсортируйте лица по этой Z.
Для более точного решения рассмотрим https://en.wikipedia.org/wiki/Newell%27s_algorithm.
То, что вы пытаетесь сделать, называется "отбраковкой обратной стороны". Один из распространенных методов - определить, находится ли список точек в представлении многоугольника по часовой стрелке или против часовой стрелки с точки зрения камеры. Для этого необходимо, чтобы вы очень внимательно относитесь к тому, как вы создаете список вершин. Подробнее читайте в статье в Википедии: https://en.wikipedia.org/wiki/Back-face_culling. В разделе «Реализация» описываются задействованные математические аспекты, которые вам придется перевести в JavaScript. Обратите внимание, что этот метод быстрее, чем сортировка список лиц, потому что он требует проверки каждого лица только один раз, а не сравнения каждого лица с другими лицами.
Спасибо, а как мне найти положение камеры в параллельной проекции? А как мне приблизить лицо к точке? Средний?