Rotasi sewenang-wenang tentang Sphere


12

Saya sedang mengkode seorang mekanik yang memungkinkan pengguna untuk bergerak di sekitar permukaan bola. Posisi pada bola saat ini disimpan sebagai thetadan phi, di mana thetasudut antara sumbu z dan proyeksi xz dari posisi saat ini (yaitu rotasi sekitar sumbu y), dan phimerupakan sudut dari sumbu y ke posisi. Saya menjelaskannya dengan buruk, tetapi pada dasarnya 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;

Saya percaya ini akurat, namun saya bisa saja salah. Saya harus bisa bergerak dalam arah dua dimensi semu yang semena-mena di sekitar permukaan bola pada titik asal ruang dunia dengan jari-jari r. Misalnya, memegang Wharus bergerak di sekitar bola dalam arah ke atas relatif terhadap orientasi pemain.

Saya percaya saya harus menggunakan Quaternion untuk mewakili posisi / orientasi pada bola, tetapi saya tidak bisa memikirkan cara yang tepat untuk melakukannya. Geometri bulat bukan setelan kuat saya.

Intinya, saya perlu mengisi blok berikut:

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;
    }
}

Apa yang harus terjadi jika pemain mencapai kutub? Saya perhatikan Anda menulis "arah ke atas", apakah Anda benar - benar berarti "ke atas" (yaitu, jauh dari permukaan bola), "lurus ke depan" atau "ke arah kutub utara" (dua yang terakhir adalah sama jika pemain tidak dapat mengubah orientasi mereka dan "di depan mereka" atau "di atas" di layar selalu utara)?
Martin Sojka

Mungkin itu kata-kata yang buruk. Pemain seharusnya tidak meninggalkan permukaan bola, dan tidak harus menyadari sumbu kardinal. Jadi ketika Anda bergerak "ke atas", Anda bergerak di sepanjang permukaan bola dalam arah ke atas relatif terhadap orientasi pemain. mis. Jika Anda berada di (r, 0,0) dan menekan ke atas, Anda akan menuju ke kutub z +, tetapi jika Anda terus berjalan Anda harus membungkus dan terus berjalan.
azz

Masih ada satu pertanyaan lagi: Dapatkah pemain mengubah orientasi (putar "kiri" dan "kanan")?
Martin Sojka

Mungkin contoh yang lebih baik dari apa yang saya tuju: Pemain yang (1,1,1)memegang kiri akan berputar di sekitar bola, melewati (~1.2,0,~-1.2), lalu (-1,-1,-1), lalu (~-1.2,0,~1.2)dan kembali ke (1,1,1).
azz

1
Jika Anda berniat untuk selalu melacak thetadan phiketika posisi Anda diperbarui, Anda membuat masalah Anda menjadi tidak perlu. Jauh lebih mudah untuk hanya menghitung 2 sumbu rotasi setiap frame (salah satunya (yaw) tidak pernah berubah) dan di Vector3.Transormsekitar bola. Ini akan menyederhanakan masalah Anda tetapi akan menyebabkan Anda memutuskan koneksi dengan phi& theta.
Steve H

Jawaban:


5

Sebenarnya, ternyata Anda tidak bisa memilikinya 'dua arah': jika niat Anda adalah untuk tidak memiliki rasa 'orientasi absolut' di bola (yaitu, jika para pemain tidak selalu eg menghadap ke arah kutub ), maka Anda harus memiliki gagasan tentang orientasi pemain. Ini karena, bertentangan dengan apa yang mungkin dikatakan oleh intuisi, gerakan di bola tidak persis seperti gerakan di pesawat, bahkan tidak secara lokal (cukup); lengkungan intrinsik bola berarti bahwa pemain dapat mengambil tindakan yang akan memutar diri mereka sendiri!

Untuk contoh paling ekstrim dari apa yang saya bicarakan, bayangkan bahwa pemain mulai pada titik di khatulistiwa (untuk kenyamanan kita akan membayangkan wajah jam dipetakan ke khatulistiwa dari atas, dan menempatkan pemain pada jam 6 ), menghadap 'atas' - yaitu, menuju Kutub Utara. Misalkan pemain berjalan sampai ke Kutub Utara; maka mereka akan menghadap langsung ke titik 12:00. Sekarang, biarkan pemain bergerak langsung ke kanan, dari Kutub Utara kembali ke khatulistiwa; mereka akan berakhir pada titik jam 3 - tetapi karena wajah mereka tidak berubah ketika mereka bergerak ke kanan(Idenya adalah bahwa wajah mereka tidak berubah tidak peduli bagaimana mereka bergerak), mereka masih akan menghadapi titik jam 12 - mereka sekarang menghadapi sepanjang garis katulistiwa! Sekarang, biarkan mereka bergerak 'mundur' kembali ke titik awal (jam 6); maka mereka masih akan menghadap ke garis khatulistiwa, jadi mereka akan menghadap ke arah jam 3 - hanya bergerak di sepanjang bola tanpa pernah mengubah orientasi 'pribadi' mereka telah menyebabkan mereka berputar dari menghadap ke arah kutub utara ke menghadap ke garis khatulistiwa! Dalam arti tertentu, ini adalah penjabaran dari yang lama 'seorang pemburu bergerak satu mil ke selatan, satu mil ke barat dan kemudian satu mil ke utara' lelucon - tetapi di sini kita mengambil keuntungan dari lengkungan bola untuk menghasilkan perubahan arah. Perhatikan bahwa efek yang sama masih terjadi bahkan pada skala yang jauh lebih kecil;

Untungnya, angka empat melakukan (seperti yang Anda catat sendiri) menangani situasi ini; karena angka empat mewakili rotasi sewenang-wenang, itu secara efektif mewakili 'titik plus orientasi' sewenang-wenang di bola: bayangkan mulai dengan 'triaksi' di titik asal dan berikan beberapa rotasi acak, lalu gerakkan satu unit ke arah mana pun sumbu diputar ' Titik sumbu Z; sedikit pemikiran akan meyakinkan Anda bahwa ini membawa Anda ke titik di unit bola dengan beberapa 'orientasi' (yaitu, beberapa pengaturan sumbu X dan Y dari triaksi Anda), dan bahwa Anda bisa mendapatkan setiap titik + orientasi pada unit sphere dengan cara ini (cukup tetapkan sumbu Z Anda untuk menunjuk sepanjang garis dari titik asal melalui titik Anda pada bola, lalu bawa triaksi Anda kembali ke titik asal di sepanjang garis itu). Apalagi, karena penggandaan angka empat sesuai dengan komposisi rotasi, setiap operasi yang Anda gambarkan dapat diwakili dengan mengalikan 'orientasi Anda saat ini' dengan angka empat yang dipilih secara tepat: khususnya, karena angka empat (unit) angka empat (qx, qy, qz, qw) berarti 'memutar tentang sumbu (qx, qy, qz) oleh arccos (qw)', lalu (tergantung pada pilihan spesifik sistem koordinat Anda, dan membiarkan c_a menjadi cos (alpha) dan s_a menjadi sin (alpha)) dua dari tiga angka empat M_x = (s_a, 0, 0, c_a), M_y = (0, s_a, 0, c_a), dan M_z = (0, 0, s_a, c_a) akan mewakili 'rotate (yaitu bergerak) ke arah I 'Saya saat ini dihadapkan oleh alpha' dan 'putar ke arah orthogonal dengan yang saya sedang hadapi oleh alpha'. (Yang ketiga dari empat angka tersebut akan mewakili 'putar karakter saya tentang porosnya sendiri'Cur_q = M_x * Cur_qjika pemain telah menekan ke atas, atau Cur_q = M_y * Cur_qjika pemain menekan ke kanan (atau mungkin sesuatu seperti Cur_q = M_yinv * Cur_qjika pemain menekan ke kiri, di mana M_yinv adalah 'kebalikan' dari angka empat M_y, mewakili rotasi dengan cara lain). Perhatikan bahwa Anda harus berhati-hati di 'sisi' mana Anda menerapkan rotasi, apakah untuk pra-kelahiran atau pascamultiply; sejujurnya, mungkin paling mudah untuk menyelesaikannya dengan coba-coba, mencoba penggandaan dan melihat mana yang berhasil.

Beralih dari angka empat yang diperbarui ke titik di bola (dan ke orientasi karakter Anda) juga relatif mudah: dengan korespondensi paragraf terakhir, yang harus Anda lakukan adalah menggunakan angka empat Anda berdasarkan vektor (1, 0,0), (0,1,0) dan (0,0,1) dari frame Anda melalui operasi 'rotate vector by quaternion' v → qvq -1 (di mana perkalian di sini adalah angka empat dikalikan dan kami mengidentifikasi vektor v = (x, y, z) dengan 'angka empat yang merosot' (x, y, z, 0)). Misalnya, posisi pada unit sphere didapat dengan hanya mentransformasikan vektor 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), jadi(2(qy*qw+qz*qx), 2(qz*qy-qw*qx), (qz^2+qw^2)-(qx^2+qy^2))akan menjadi koordinat dari pengguna yang 'ditransformasikan' pada unit sphere (dan untuk mendapatkan koordinat pada sphere yang sewenang-wenang, tentu saja, Anda hanya akan mengalikannya dengan radius sphere); perhitungan serupa bekerja untuk sumbu lainnya, untuk menentukan misalnya arah menghadap pengguna.


Justru apa yang ingin saya raih. Saya hanya tidak bisa memikirkan cara yang benar untuk mendapatkan posisi keluar dari angka empat orientasi. Dengan menggunakan apa yang Anda berikan, saya dapat menulis Move()prosedur, tetapi untuk mendapatkan sumbu yang dinormalisasi (yaitu posisi saya), apakah saya akan mengambilnya (sin(qx),sin(qy),sin(qw)) * r?
Azz

@Tidak tepat - saya akan memperbarui posting saya dengan detail, tetapi versi singkatnya adalah bahwa Anda menggunakan angka empat Anda untuk mengubah vektor satuan, misalnya (0,0,1), oleh v biasa -> qvq <sup> -1 </sup> operasi; fakta bahwa Anda mengubah vektor sederhana berarti bahwa (secara alami) ada jalan pintas di sini, tetapi koordinat terakhir kuadratik dalam nilai angka empat Anda, bukan linear.
Steven Stadnicki

1

Saya pikir Anda menginginkan sesuatu yang mirip dengan http://www.youtube.com/watch?v=L2YRZbRSD1k ini

Saya mengembangkannya untuk gamejam 48jam ... Anda dapat memuat kode di sini ... http://archive.globalgamejam.org/2011/evil-god

Saya menggunakan sesuatu yang mirip dengan kode Anda untuk mendapatkan 3D coords ... tapi saya memutar planet ini dan pemain berada di posisi yang sama, saya pikir Anda tertarik pada gerakan makhluk, apakah ini:

    // 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;
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.