Як я можу орбітувати камеру щодо її цільової точки?


18

Я малюю сцену, де камера вільно рухається по всесвіту. Клас камери відстежує точку зору (або погляд ), положення камери та вектор вгору. Ці вектори / точки потім передаються в gluLookAt.

Панорамування та масштабування майже тривіально реалізовувати. Однак я вважаю, що обертання щодо погляду є значно більшою проблемою. Я хочу написати функцію Camera.rotate, яка займає 2 кути, той, який обертається вгору / вниз, і той, який обертається вліво / вправо вздовж уявної сфери, яка зосереджена навколо погляду в точці.

Чи є простий спосіб це зробити?

Я (коротко) читав про кватерніони, але хотів побачити, чи є простіше рішення, враховуючи відносно просту конструкцію моєї сцени.


Чи є у вашій панелі інструментів щось, щоб обертати точку навколо початку, задаючи вісь та кут?
sam hocevar

Нічого, крім мого слабкого розуміння кватерніонів, немає. Чим більше я дивлюся на це, я думаю, що кватерніони можуть бути відповіддю. Однак я не впевнений, як обчислити осі x, y та z, використовувані у формулах Кватерніона.
Лука

Я не скажу вам, що кватерніони - це не шлях. Вони є дуже хорошим рішенням вашої проблеми. Але вам знадобиться клас кватерніона та способи взаємодії з GL та GLU, і я вважаю, що спершу слід спробувати ознайомитись з матрицями перетворення. Інші можуть не погодитися.
sam hocevar

Подумайте, в якому порядку ви робите обертання. Застосування обертань для переміщення у світовий простір або для переміщення до простору камери відрізняється
Чарлі

Відповіді:


25

Те, про що ви просите, називається обертанням аркболу. Кватерніони - це просте рішення, лише якщо ви розумієте, як вони працюють. Однак ви можете домогтися того ж без кватерніонів.

Попередні реквізити

Ви знаєте, як взагалі обертати об'єкти? Скажімо, у вас є об'єкт біля джерела. Чи знаєте ви, як ви його обертаєте (підказка: помножте на якусь матрицю обертання)? Якщо так, то я припускаю, що ви знаєте, що буде, якщо спершу перекласти об’єкт, а потім повернути його?

Ви повинні знати, як обчислити матрицю обертання від кутової осі (просто, як пиріг, подивіться безліч рівнянь в Інтернеті, багато з них дають вам і код)

Рішення

  • Отримайте камери вгору та вправо . Зауважте, що їх слід нормалізувати.
  • Дістаньте вектор від точки фокусування до камери (camPosition - Фокус). Це вектор, який ви збираєтесь обертати. Назвемо цей camFocusVector .
  • Вирішіть, наскільки ви хочете обертатись у відхиленні / нахилі по відношенню до камери
  • Створіть дві матриці обертання. Матриця 1-го обертання використовуватиме камеру вгору як вісь та кут похилу, які ви вирішили. 2-а матриця обертання використовуватиме праворуч від камери як вісь та крок кута , який ви вирішили.
  • Тепер оберніть camFocusVector за допомогою нових матриць обертання. Тепер це ваше нове положення камери щодо походження. Ми, звичайно, хочемо, щоб це було відносно точки фокусу ...
  • Додайте положення точки фокусування до camFocusVector . Це тепер нове положення камери. Перекладіть відповідним чином свою камеру.
  • Нарешті, попросіть камеру зосередитись на точці фокусування, зателефонувавши на функцію lookAt ()

Коваджі

Вам доведеться шукати певні випадки або особливості, коли ваша камера перестане працювати. Наприклад, дивлячись прямо вниз / вгору. Я дозволю вам зрозуміти, як з цим боротися.

EDIT1: Як перерахувати ортонормальні вектори камери

Ви вже знаєте напрямок камери ((cameraPos - focusPoint) .normalize ()). Тепер припустимо, що вгору вашої камери дорівнює + Y (або ж, якщо ваша поточна вісь у світі - це все, що залежить від вас). Тепер просто перетнути напрямок з вгору , щоб отримати право . Зроблено? Ні! Ваш вектор вгору більше не є ортогональним для двох інших. Щоб виправити це, перехресне право з керівництвом , і ви отримаєте свій новий план .

Зауважте, що Грам-Шмідт - це дійсно те, що слід використовувати для ортонормалізації векторів.

Знову зверніть увагу на застереження, оскільки в деяких випадках це не спрацює (наприклад , паралельний напрямку вгору ).


Зауважте, що правий вектор можна отримати, використовуючи normalize(up ^ camFocusVector)(або його протилежний, якщо лівий).
sam hocevar

Дотепер добре виглядаючи, прекрасно працював для обертання ліворуч / праворуч (у мене є векторний верх, тому це легко). Що означає "^" у вашому коментарі @SamHocevar? Це перехресний продукт? Крім того, як я можу перерахувати вектор вгору, коли я зробив переклади?
Лука

@Luke: Перевір мою EDIT1
Samaursa

1
@Samaursa Дуже дякую Ваше рішення працює чудово, і я багато чого навчився в процесі!
Лука

2
це ОТЛИЧНА відповідь, дуже дякую за ваше пояснення. У моєму випадку я хотів, щоб камера лише оберталася навколо цільової точки в площині XY, і тому, зробивши всі обчислення, я завжди встановлювала cameraRight.z на 0, а потім розраховувала вектор cameraUp. Це дало бажаний ефект. Тільки подумав поділитися
codemonkey

1

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

Це в XNA, але IIRC я ​​раніше використовував цю реалізацію, і вона працювала досить добре:

http://roy-t.nl/index.php/2010/02/21/xna-simple-arcballcamera/


Здається, ця реалізація рухається лише прямо по правильному вектору, що наближатиме аркбол до малих значень суми . Він також переміщує точку LookAt, як там, де я хочу перемістити камеру (близько, але тонко відрізняється). Я вважаю, що Самаурса запропонував найпростіший повний спосіб досягти цього.
Лука

Спасибі за ваш відгук. Я мушу визнати, що я трохи використовував цю реалізацію як «чорний ящик», але я не помітив жодної проблеми. Для уточнення ви, можливо, говорили про методи MoveCameraRight / MoveCameraForward? Ці методи були додані для панорамування камери навколо, але вони не є частиною інтерфейсу Arcball. Якщо ви хочете обертати камеру навколо цілі, ви просто зміните властивості нахилу або нахилу.
Девід Гувейя

Вибачте, ви маєте рацію, це методи панірування. Я не помітив, як він встановлював брудний прапор для матриці, коли змінювались позіхання та висота.
Лука

0

Ось мій код обертання навколо точки, я виявив, що я його багаторазово використовую.

float distance;      // Straight line distance between the camera and look at point

// Calculate the camera position using the distance and angles
float camX = distance * -sinf(camAngleX*(M_PI/180)) * cosf((camAngleY)*(M_PI/180));
float camY = distance * -sinf((camAngleY)*(M_PI/180));
float camZ = -distance * cosf((camAngleX)*(M_PI/180)) * cosf((camAngleY)*(M_PI/180));

// Set the camera position and lookat point
gluLookAt(camX,camY,camZ,   // Camera position
          0.0, 0.0, 0.0,    // Look at point
          0.0, 1.0, 0.0);   // Up vector

1
Це в основному так, як я це робив спочатку. Існує багато проблем з цим способом (принаймні для мене). В основному ця реалізація обертає лише близько 2 нерухомих осей. Припустимо, ви повертаєте вгору майже до північного полюса . Потім поверніть праворуч . Ви опинитеся, що крутитеся в крихітному колі, а не слідуєте за правим вектором камери на всьому світі .
Лука

Тепер, коли ви це згадали, я думаю, є два різні способи розглянути проблему. У своїй програмі я використовував камеру ArcBall, щоб обертатися навколо цільового острова на морі, і якби я використав 3 осі свободи, це виглядало б явно неправильно (наприклад, бачити острів догори дном або збоку).
Девід Гувейя

Як отримати тут кути камери?
rafvasq

0

Цей дуже простий алгоритм досягнення цього приголомшливо:

Будучи P центральною точкою, яку потрібно обертати (точка "погляд на" або "ціль"):

translate(-P)

rotate horizontal
rotate vertical

translate(P)

Я використав це та його приємно.

Джерело знайдено на сестринському сайті stackoverflow: /programming/287655/opengl-rotating-a-camera-around-a-point

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