Як я можу знайти найбільшу сферу, яка вписується у фрустум?


12

Як ви знаєте найбільшу сферу, яку ви можете намалювати в перспективі?

Якщо зверху подивитися, це було б так:

введіть тут опис зображення

Додано: на фрустумі справа, я позначив чотири точки, я думаю, що ми щось знаємо. Ми можемо спроектувати всі вісім куточків плоду, а центри ближнього та далекого кінців. Отже, ми знаємо точки 1, 3 і 4. Ми також знаємо, що точка 2 - це та ж відстань від 3, як 4 - від 3. Тож ми можемо обчислити найближчу точку на прямій 1 до 4 до точки 2, щоб отримати центр? Але власне математика та код уникають мене.

Я хочу намалювати моделі (приблизно сферичні і для яких у мене сфера обмеження для міні-футболу) якомога більше.

Оновлення: Я намагався реалізувати підхід " кругообіг на двох площинах", як запропонували bobobobo та Nathan Reed :

function getFrustumsInsphere(viewport,invMvpMatrix) {
    var midX = viewport[0]+viewport[2]/2,
        midY = viewport[1]+viewport[3]/2,
        centre = unproject(midX,midY,null,null,viewport,invMvpMatrix),
        incircle = function(a,b) {
            var c = ray_ray_closest_point_3(a,b);
            a = a[1]; // far clip plane
            b = b[1]; // far clip plane
            c = c[1]; // camera
            var A = vec3_length(vec3_sub(b,c)),
                B = vec3_length(vec3_sub(a,c)),
                C = vec3_length(vec3_sub(a,b)),
                P = 1/(A+B+C),
                x = ((A*a[0])+(B*a[1])+(C*a[2]))*P,
                y = ((A*b[0])+(B*b[1])+(C*b[2]))*P,
                z = ((A*c[0])+(B*c[1])+(C*c[2]))*P;
            c = [x,y,z]; // now the centre of the incircle
            c.push(vec3_length(vec3_sub(centre[1],c))); // add its radius
            return c;
        },
        left = unproject(viewport[0],midY,null,null,viewport,invMvpMatrix),
        right = unproject(viewport[2],midY,null,null,viewport,invMvpMatrix),
        horiz = incircle(left,right),
        top = unproject(midX,viewport[1],null,null,viewport,invMvpMatrix),
        bottom = unproject(midX,viewport[3],null,null,viewport,invMvpMatrix),
        vert = incircle(top,bottom);
    return horiz[3]<vert[3]? horiz: vert;
}

Я визнаю, що я крила; Я намагаюся адаптувати 2D-код , розширивши його на 3 виміри. Він не обчислює сферу правильно; центральна точка сфери, здається, щоразу знаходиться на лінії між камерою та лівою верхньою частиною, і її занадто велика (або занадто близька). Чи є явні помилки в моєму коді? Чи працює підхід, якщо він фіксований, працює?


Чи повинна сфера бути повністю на дальній стороні далекої площини, як на зображенні?
Mikael Högström

@ MikaelHögström Я думаю, що вони були б, щоб бути максимально великими?
Вілл

Хм, я думаю, це залежить від вашої мети ... Якщо ви намалюєте сферу з половиною поза межами далекої площини, то це було б більше, але, можливо, це суперечить вашим цілям?
Mikael Högström

@ MikaelHögström аха, я розумію ваше запитання; так, я хочу, щоб вся модель була намальована, і далеко не площину прорізала її.
Вілл

Відповіді:


12

Я припускаю, що ваш фруст симетричний, оскільки, здається, ваш малюнок так пропонує. Існує три обмеження (два, якщо ваш фруст 2D):

A. сфера не може бути більшою, ніж відстань між близькою та далекою площинами

Якщо Dце близька відстань, перше обмеження просто:

R  D / 2

B. сфера не може зростати ширше, ніж бічні площини

Тепер для іншого обмеження, скажімо, αце півкут плоду і Lполовина ширини далекої площини, як показано на цьому кресленні:

фрустум

Перша формула задана тригонометрією в трикутнику. Другий походить від суми кутів трикутника. Що дає нам друге обмеження:

R  L tan((π - 2α) / 4)

Якщо ваш фруст - 3D, у вас виникне третє обмеження з новими Lта αцінностями.

Кінцевий результат

RЗначення , яке ви шукаєте, minз трьох кордонів.

Як отримати параметри

Якщо ви не можете спроектувати фрустум у зорі чи світовому просторі, ви можете обчислити L, D і α таким чином, коли Pточки знаходяться від найближчої площини, а Qточки - з далекої площини:

формула2

Стрілки означають вектори "." - крапковий добуток, а || позначає довжину вектора. Замініть Q2на Q3і P2з, P3щоб отримати L і α у вертикальному вимірі.


Як, з-за фрустуму (обчислюється відхиленням точок огляду, щоб наблизитись і далеко), ви визначаєте поле зору? А в 3D є лише два варіанти, а не три, правда? Мої спроби ввести ваш алгоритм у код завжди дають мені дуже великий Р.
Буде

@Чи додам другий малюнок із формулами, які, сподіваюся, допоможуть.
sam hocevar

2

У 2D: розглянути фрусту як трикутник (2D)

введіть тут опис зображення

Потім ви хочете знайти кружок трикутника.

В якості 3D-проблеми потрібно знайти сферу піраміди на основі квадрата.

Якби у мене була формула, я б її надрукував тут, але, на жаль, я не знаю формули.


2
Напевно, достатньо знайти кругообіг вертикального чи горизонтального фрусту в 2D, залежно від того, у кого менше FOV, принаймні для "стандартної" frusta (не стриженої чи нічого).
Натан Рід

1

Найбільша можлива сфера повинна торкатися дальній площини (використовуючи тут терміни для виду-фруструмів) прямо в центрі. Він також торкався б верхньої / нижньої або лівої / правої площин, залежно від того, який кут FoV менший. Я мушу сказати, що у мене немає фактичного математичного підтвердження цих припущень, але вони повинні бути правильними. Можливо, хтось має ідею, як це довести.

Сферу можна визначити її центральною точкою та радіусом. Cx і Cy - те саме, що і центр дальній площини.

Cz і радіус можна отримати, розв’язавши систему рівнянь на основі перелічених вище припущень.

T - одна з нижньої / верхньої площини або зліва / права площина (див. Вище) з t1, t2 і t3 як нормалізований нормальний вектор і t4 як відстань від початку. f - центр дальній площини.

t1 * cx + t2 * cy + t3 * cz - t4 = r

-fz + cz = r

t1 * cx + t2 * cy + t3 * cz - t4 = -fz + cz

t1 * cx + t2 * cy + fz - t2 = + cz - t3 * cz

t1 * cx + t2 * cy - fz - t2 = cz * (1 - t3)

cz = (t1 * cx + t2 * cy - fz - t2) / (1 - t3)

r обчислюється, вставляючи в це cz: -fz + cz = r

Ви можете отримати всі площини з використовуваної матриці проекцій. (У цьому випадку не ViewProjection)

після цього потрібно перемістити сферу в потрібний простір: C '= зворотний (Вид) * C


1

Я намагаюся зробити щось подібне, і в моєму випадку швидкість є більш важливою, ніж точність, доки сфера не існує за межами жодної межі фрустуму.

Якщо обчислити найкоротшу відстань між рядами ліній (або гранями в 3d), знайдене найкоротше відстань може бути використане як діаметр інциркуля / сфери, яка повністю лежить всередині фрусту. Походження incircle / asphere може просто середнє значення всіх вершин (сума & ділення). Це було б досить швидко і також працювало б для всіх типів опуклих багатогранників.

Єдиним недоліком є ​​те, що коло або сфера не обов'язково будуть найбільшими можливими кругообігами або сферою. Для фрустума з великим обсягом і одним дуже коротким краєм коло / сфера поділять набагато менше місця плодів, ніж це можливо.

Ще одна ідея

Якщо ви хочете, щоб атмосфера тривимірного перегляду-фрустума була у вас перспективною матрицею, яка використовується для побудови цього фрустуму, ви можете просто використовувати цю матрицю на сфері одиничного куба, і це має бути ідеальною сферою для фрусту. (Діаметр сфери куба - це довжина одного з країв куба, центр - середина куба, що є середнім значенням вершин куба)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.