Довільне обертання навколо сфери


12

Я кодую механіку, який дозволяє користувачеві рухатися по поверхні кулі. Положення на кулі в даний час зберігається як thetaі phi, де thetaкут між осі z та проекцією xz поточного положення (тобто обертання навколо осі y), і phiє кутом від осі y до положення. Я пояснив це погано, але це по суті theta = yaw,phi = pitch

Vector3 position = new Vector3(0,0,1);
position.X = (float)Math.Sin(phi) * (float)Math.Sin(theta);
position.Y = (float)Math.Sin(phi) * (float)Math.Cos(theta);
position.Z = (float)Math.Cos(phi);
position *= r;

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

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

По суті, мені потрібно заповнити наступний блок:

public void Move(Direction dir)
{   
    switch (dir)
    {
        case Direction.Left:
            // update quaternion to rotate left
            break;
        case Direction.Right:   
            // update quaternion to rotate right
            break;
        case Direction.Up:
            // update quaternion to rotate upward
            break;
        case Direction.Down:
            // update quaternion to rotate downward
            break;
    }
}

Що має відбутися, якщо гравець досягне полюсів? Я помітив, що ви написали "вгору", чи ви буквально маєте на увазі "вгору" (тобто подалі від поверхні сфери), "прямо вперед" або "в бік північного полюса" (останні два такі самі, якщо гравець не можете змінити свою орієнтацію, і "перед ними" або "вгору" на екрані завжди північ)?
Мартін Сойка

Можливо, це було погано сформульовано. Гравець не повинен залишати поверхню сфери і не повинен знати про кардинальну вісь. Отже, коли ви рухаєтеся «вгору», ви рухаєтесь по поверхні сфери у напрямку вгору відносно орієнтації гравця. Наприклад, якщо ви знаходитесь на (r, 0,0) і натискаєте вгору, ви підете в бік z + полюса, але якщо ви продовжуєте рухатися, вам слід загорнутись і продовжувати рух.
azz

Ще залишається одне питання: Чи може гравець змінити орієнтацію (повернути "вліво" та "праворуч")?
Мартін Сойка

Може бути кращим прикладом того, що я йду: Гравець, (1,1,1)тримаючи ліворуч, обертається навколо сфери, проходячи через (~1.2,0,~-1.2), потім (-1,-1,-1), потім (~-1.2,0,~1.2)і назад до (1,1,1).
azz

1
Якщо ви маєте намір завжди відстежувати thetaі phiяк ваші оновлення положення, ви робите вашу проблему надмірно складним. Набагато простіше просто обчислити 2 осі обертання кожного кадру (одна з яких (позіхання) ніколи не змінюється) і Vector3.Transormнавколо сфери. Це спростить вашу проблему, але призведе до відключення з phi& theta.
Стів H

Відповіді:


5

Власне, виявляється, що у вас це не може бути "обома способами": якщо ваш намір не мати відчуття "абсолютної орієнтації" на сферу (тобто якщо гравці не завжди, наприклад, звернені до полюсів ), тоді вам потрібно мати поняття орієнтації гравця. Це тому, що, всупереч тому, що може запропонувати інтуїція, рух по сфері не зовсім як рух по площині, навіть не локально (цілком); внутрішня кривизна сфери означає, що гравці можуть робити дії, які будуть обертатися самі!

Для найбільш крайнього прикладу того, про що я говорю, уявіть, що гравець починається в точці на екваторі (для зручності ми уявимо годинник обличчям, нанесеним на екватор зверху, і поставимо гравця на 6 годин ), звернені «вгору» - тобто в бік Північного полюса. Припустимо, гравець прогуляється аж до Північного полюса; тоді вони будуть стикатися прямо до точки 12 годин. Тепер нехай гравець рухається прямо праворуч від Північного полюса назад до екватора; вони закінчуються в 3-й годині, але тому, що обличчя не змінюється, коли вони рухаються праворуч(ідея полягає в тому, що їх облицювання не змінюється незалежно від того, як вони рухаються), вони все одно стикаються з точкою 12 годин - тепер вони стикаються вздовж екватора! Тепер нехай вони рухаються «назад» назад до своєї початкової (6 годин) точки; тоді вони все ще будуть стикатися вздовж екватора, тож вони будуть звернені до точки 3 годин - просто переміщення по сфері без зміни своєї "особистої" орієнтації призвело до того, що вони повертаються з обличчя на північний полюс до звернені вздовж екватора! У певному сенсі це розробка старого «жарту, який мисливець рухає милю на південь, милі на захід, а потім милі на північ», - але тут ми використовуємо кривизну сфери для зміни зміни напрямку. Зауважте, що той самий ефект все ще відбувається навіть у значно менших масштабах;

На щастя, кватерніони (як ви самі зазначили) вирішують цю ситуацію; оскільки кватерніон являє собою довільне обертання, він фактично представляє довільну "точку плюс орієнтацію" на сфері: уявіть, що починається з "триосності" на початку і надає їй деяке довільне обертання, потім переміщуючи одну одиницю в будь-якому напрямку обертаються осей " Точки осі Z; невелика думка переконає вас, що це приведе вас до точки одиничної сфери з деякою «орієнтацією» (тобто деяким розташуванням осей X і Y вашої триассі), і що ви можете дістатися до кожної точки + орієнтації на поділіть сферу таким чином (просто призначте свою вісь Z для вказівки вздовж лінії від початку до точки на кулі, а потім транспортуйте тріакси назад до початку по цій лінії). Що ще, оскільки множення кватерніонів відповідає складу обертів, кожна операція, яку ви описуєте, може бути представлена ​​шляхом множення вашої "поточної орієнтації" на відповідно обраний кватерніон: конкретно, оскільки (одиниця) кватерніона (qx, qy, qz, qw) означає "обертати навколо осі (qx, qy, qz) по дузі arccos (qw)", то (залежно від вашого конкретного вибору системи координат, і нехай c_a буде cos (альфа) і s_a - sin (альфа)) два три кватерніони M_x = (s_a, 0, 0, c_a), M_y = (0, s_a, 0, c_a) і M_z = (0, 0, s_a, c_a) представлятимуть "поворот (тобто переміщення) у напрямку I "Я зараз стикаюся з альфаю" і "обертаюсь у напрямку, ортогональному до того, з яким я зараз стикаюся з альфою". (Третій з цих кватерніонів представлятиме "обертати мого персонажа щодо власної осі"Cur_q = M_x * Cur_qякщо гравець натиснув вгору, або Cur_q = M_y * Cur_qякщо гравець натиснув праворуч (або, можливо, щось на зразок, Cur_q = M_yinv * Cur_qякщо гравець натиснув ліворуч, де M_yinv - "зворотний" кватерніона M_y, що представляє обертання в інший бік). Зауважте, що ви повинні бути обережними, на якій стороні ви застосуєте обертання, чи потрібно попередньо розмножувати чи післяміряти; якщо бути відвертим, це може бути найпростіше вирішити з допомогою проб і помилок, спробувавши і множення, і побачити, що працює.

Перехід від оновленого кватерніона до точки на кулі (і до орієнтації вашого персонажа) теж досить простий: відповідно до відповідності останнього абзацу, все, що вам потрібно зробити, - це використовувати ваш кватерніон на основі векторів (1, 0,0), (0,1,0) і (0,0,1) вашого кадру через операцію 'обертання вектора кватерніоном' v → qvq -1 (де множення тут кватерніон помножується, і ми ідентифікуємо вектор v = (x, y, z) з 'виродженим кватерніоном' (x, y, z, 0)). Наприклад, позиція на одиничній сфері отримується просто перетворенням z вектора: pos = (qx, qy, qz, qw) * (0, 0, 1, 0) * (-qx, -qy, -qz, qw) = (qx, qy, qz, qw) * (qy, -qx, qw, qz) = (2 (qy * qw + qz * qx), 2 (qz * qy-qw * qx), (qz ^ 2 + qw ^ 2) - (qx ^ 2 + qy ^ 2), 0), так(2(qy*qw+qz*qx), 2(qz*qy-qw*qx), (qz^2+qw^2)-(qx^2+qy^2))були б координати "перетвореного" користувача на одиничній сфері (а щоб отримати координати довільної сфери, звичайно, ви просто помножите їх на радіус сфери); подібні обчислення працюють для інших осей, щоб визначити, наприклад, напрямок обличчя користувача.


Саме того, що я хочу досягти. Я просто не міг придумати правильний спосіб вийти з кватерніона орієнтації. Використовуючи те, що ви надали, я можу написати Move()процедуру, але щоб отримати нормалізовану вісь (тобто мою позицію), я б просто прийняв (sin(qx),sin(qy),sin(qw)) * r?
azz

@Der не точно - я оновлю своє повідомлення з деталями, але коротка версія полягає в тому, що ви використовуєте ваш кватерніон для перетворення одиничного вектора, наприклад (0,0,1), звичайним v -> qvq <sup> -1 </sup> операція; той факт, що ви перетворюєте простий вектор, означає, що (природно) тут є скорочення, але кінцеві координати є квадратичними у значеннях вашого кватерніона, а не лінійними.
Стівен Стадницький

1

Я думаю, ви хочете щось подібне до цього http://www.youtube.com/watch?v=L2YRZbRSD1k

Я розробив це для 48-годинної ігрової майстерності ... тут ви можете завантажити код ... http://archive.globalgamejam.org/2011/evil-god

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

    // To add movement
    protected override void LocalUpdate(float seconds)
    {
        Creature.Alfa += Direction.X * seconds * Speed;
        Creature.Beta += Direction.Y * seconds * Speed;            
    }


    // To calculate position
       World.Planet.GetCartesian(Alfa, Beta, out Position); // as you do
       Matrix PositionMatrix = Matrix.CreateTranslation(Position) * World.Planet.RotationMatrix;           
       LastPositionAbsolute = PositionAbsolute;
       Vector3 Up = PositionAbsolute = Vector3.Transform(Vector3.Zero, PositionMatrix);           
       Up.Normalize();
       // This is to add and offset to the creature model position
       PositionAbsolute += Up * 8;  
      // calculate new forward vector if needed

       if ((PositionAbsolute - LastPositionAbsolute).Length() > 0.1f) {
           Forward = PositionAbsolute - LastPositionAbsolute;
           Forward.Normalize();
       }

       // Calculate the world transform with position, forward vector and up vector
       Matrix LocalWorld = Matrix.CreateWorld(PositionAbsolute, Forward, Up); 

       Transform = Matrix.CreateScale(Scale * ScaleFactor) * LocalWorld;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.