Bagaimana menghapus jitter dari input gerak?

9

Saya menulis mod Minecraft yang mendukung input dari Razer Hydra . Ini adalah sepasang pengontrol gerakan (satu untuk setiap tangan) yang memberikan informasi posisi dan rotasi yang sangat akurat.

Untuk keperluan pertanyaan ini, memutar pengontrol kanan pada sumbu Y menyebabkan karakter pemain terlihat kiri atau kanan (menguap), dan memutar pada sumbu X membuat pemain melihat ke atas dan ke bawah (pitch).

Input dari controller dipetakan langsung ke heading karakter. Jika pengontrol diputar 30 derajat ke kiri, karakter berubah 30 derajat ke kiri.

Masalahnya adalah input "kegugupan". Jika saya mencoba menahan pengontrol dengan diam, heading karakter bergerak tidak menentu dalam kerucut yang sangat kecil (mungkin 1 derajat).

Ini mungkin disebabkan oleh tangan saya yang goyah, karena data pengendali tampaknya tepat.

Saya mencoba memfilter input dengan rata-rata data dari frame X terakhir, tetapi ini membuat input tampak seperti mentega.

Pertanyaan saya adalah: Bagaimana saya bisa memfilter data rotasi untuk menghilangkan jitter tanpa kehilangan presisi?

Apel
sumber
apakah Anda mempertimbangkan untuk mengabaikan perubahan gerakan yang sangat kecil?
Philipp
1
Razer Hyrdra ini menarik ... pertama kali saya mendengarnya, bahkan lebih menarik adalah menulis mod Minecraft untuk melengkapinya ... Asumsi saya adalah: Sama seperti gambar pixelated, untuk "mengurangi noise" yang Anda butuhkan untuk mengaburkan gambar ... Pada dasarnya Anda bisa hidup dengan gambar pixelated atau hidup dengan gambar buram ... Saya merasa seperti ini adalah prinsip yang sama, Anda harus memilih yang Anda suka, goyah game atau kurang presisi ... ... Itulah yang saya pikirkan ...
Luke San Antonio Bialecki
1
Anda bisa memanfaatkan yang terbaik dari keduanya. Selalu simpan yang terakhir katakan 50 frame. Tetapi rata-rata hanya beberapa frame, tergantung pada jumlah gerakan input. Untuk gerakan besar, hanya mengandalkan mengatakan 5 frame terakhir dan untuk gerakan kecil (jika tidak jittering) bergantung pada 30 frame terakhir.
danijar
@sharethis Itu ide yang menarik. Saya mungkin akhirnya menerapkan sesuatu seperti itu. Jitter bukan masalah begitu input melewati ambang tertentu, jadi saya hanya bisa rata-rata input kecil untuk menghapus jitter, dan tidak rata-rata apa pun untuk input besar.
Apel

Jawaban:

8

Masalah lag-vs-responsif ini adalah situasi dengan hampir semua pengontrol gerakan, apakah sesuatu seperti Hydra, Wii Remote, Kinect, atau PlayStation Move.

Masalahnya adalah ini:

Saat aliran input masuk, Anda membuat keputusan berdasarkan kerangka demi kerangka tentang apakah akan mempercayai data input atau tidak; apakah tren yang Anda lihat sekarang akan terus berlanjut dalam data yang Anda terima selusin milidetik dari sekarang. Misalnya, jika ada perubahan tiba-tiba ke kanan frame ini, Anda tidak tahu apakah itu benar-benar data input (dan karenanya Anda harus menindaklanjutinya) atau apakah itu hanya jitter (dan karenanya Anda harus mengabaikannya). Apa pun yang Anda pilih, jika nanti Anda menemukan bahwa Anda salah, Anda mengizinkan jitter input untuk memasukkannya ke dalam gim Anda (dalam kasus pertama), atau memperkenalkan lag ke dalam gim Anda (dalam kasus terakhir).

Tidak ada solusi yang baik untuk ini. Solusi "benar" untuk menentukan apakah input itu nyata atau jitter perlu mengetahui apa yang akan dilakukan aliran input di masa depan, serta apa yang dilakukan di masa lalu. Kami tidak bisa melakukan itu di game, karena alasan yang jelas. Jadi tidak, tidak ada cara untuk menyaring data rotasi untuk menghapus jitter tanpa kehilangan presisi, dalam konteks permainan yang bekerja dengan memasukkan data secara real-time.

Saya telah melihat pabrikan besar merekomendasikan bahwa pengembang menangani masalah ini dengan meminta pemain menahan tombol sambil memutar kontrol, sehingga gim dapat mematikan kode anti-jitter pada saat itu, sehingga tidak tertinggal. (Saya tidak merekomendasikan ini, tapi ini satu pendekatan).

Saya telah melihat beberapa pustaka middleware input gerak yang menangani masalah ini dengan memperkenalkan penundaan buatan pada input - ada buffer seperempat detik yang memasukkan data input, dan game Anda hanya mendengar tentang input tersebut seperempat detik kemudian, sehingga perpustakaan dapat memuluskan kegelisahan untuk Anda, dengan mengetahui apa yang terjadi sebelum dan sesudah "hadiah" dari sudut pandang permainan. Itu bekerja dengan baik, selain dari memperkenalkan seperempat detik keterlambatan untuk semuanya. Tapi itu salah satu cara untuk menyelesaikan masalah, dan itu bisa melakukan pekerjaan yang luar biasa untuk secara akurat mewakili gerakan dengan jitter dihapus, dengan mengorbankan kelambatan konstan.

Tetapi tanpa terlalu ekstrem, masih ada beberapa hal yang dapat kita lakukan untuk memberikan perilaku yang jauh lebih baik, meskipun kita tahu bahwa akan selalu ada "skenario terburuk" yang berperilaku dengan cara yang tidak ideal.

Wawasan inti adalah bahwa kita hanya benar-benar peduli tentang jitter ketika controller sebagian besar diam, dan kita hanya benar-benar peduli tentang lag ketika controller sedang dipindahkan. Jadi strategi kita harus mencoba untuk menangani hal-hal sehingga kita memiliki kelambatan ketika controller diam, dan memiliki jitter ketika controller bergerak.

Berikut adalah dua cara yang mungkin untuk melakukan itu:

Salah satu pendekatan umum adalah sistem "terkunci / tidak terkunci", di mana Anda melacak orientasi perangkat, dan jika itu tidak berubah untuk sementara waktu (setengah detik atau lebih), Anda 'mengunci' orientasi itu, tidak mengambil tindakan berdasarkan orientasi yang dilaporkan perangkat hingga cukup berbeda untuk 'membuka kembali'. Ini benar-benar dapat memadamkan jitter berbasis orientasi, tanpa memperkenalkan jeda ketika orientasi secara aktif berubah. Mungkin ada sedikit lag sebelum kode memutuskan perlu beralih ke mode "tidak terkunci", tetapi akan jauh lebih baik daripada memiliki lag di mana-mana.

Pendekatan lain adalah rata-rata bersama-sama memasukkan data dari bingkai. Poin penting di sini adalah hanya rata-rata bersama data input dari frame di mana data input samar-samar serupa - Ini berarti bahwa kegelisahan kecil akan menjadi kabur dan melunak, tetapi perubahan yang lebih besar tidak menjadi kabur, karena data mereka tidak cukup mirip dengan data dari frame sebelumnya.

Ada cara lain untuk mendapatkan efek serupa juga. Wawasan inti adalah bahwa Anda tidak dapat memiliki non-jitter dan non-lag dalam game real-time Anda secara bersamaan, karena untuk melakukan itu akan membutuhkan pengetahuan tentang masa depan. Jadi, Anda perlu memilih kapan harus membiasakan perilaku kontrol Anda ke arah menerima jitter dan kapan untuk bias itu terhadap menerima lag, untuk membuat pengalaman keseluruhan seburuk mungkin.

Trevor Powell
sumber
Saya baru saja mengirim jawaban, bisakah Anda memberikan pendapat Anda tentang solusi saya?
Apel
2

Saya mengembangkan perangkat lunak yang mengubah input gerak menjadi input mouse yang responsif dan tepat, serta memelihara situs web yang mencoba membantu pengembang mengimplementasikan sendiri solusi yang sama baiknya. Saya biasanya menyarankan terhadap ambang gerakan, meskipun itu tergantung seberapa banyak respon dan presisi yang diinginkan pemain, saya senang itu bekerja untuk Anda dalam situasi Anda. Tetapi di sini saya akan menawarkan solusi yang berbeda:

Saya menggunakan sesuatu yang disebut Soft Tiered Smoothing . Idenya adalah bahwa kita mengalihkan input melalui algoritma penghalusan yang berbeda tergantung pada besarnya kecepatan gyro saat ini (dalam praktiknya, salah satu dari algoritma penghalusan itu hanya "tanpa perataan"). Itu bagian "berjenjang". Bagian "lunak" adalah kita benar-benar dapat dengan lancar membagi input antara berbagai algoritma perataan tergantung pada bagaimana perbandingannya dengan 2 ambang batas.

Ini mempertahankan perpindahan dengan benar dan tidak menambahkan jeda apa pun pada gerakan cepat.

Dalam praktiknya, Anda memiliki dua ambang batas. Ketika besarnya kecepatan input kurang dari ambang bawah, kami menggunakan algoritma perataan sederhana (rata-rata di beberapa frame). Ketika lebih besar dari ambang lainnya, kami tidak menggunakan algoritma perataan sama sekali. Namun dalam kasus ini, kami masih meneruskan nol ke algoritma penghalusan batas bawah.

Ketika kecepatan input berada di antara dua ambang batas, kami membagi input di antara kedua algoritma tersebut.

Berikut cuplikan dari artikel di atas:

GetSoftTieredSmoothedInput(Vec2 input, float threshold1, float threshold2) {
    // this will be length(input) for vectors
    float inputMagnitude = Abs(input);

    float directWeight = (inputMagnitude - threshold1) / (threshold2 - threshold1);
    directWeight = clamp(directWeight, 0, 1);

    return GetDirectInput(input * directWeight) +
        GetSmoothedInput(input * (1.0 - directWeight));
}

GetDirectInput hanya mengembalikan apa yang diberikan kepadanya, tetapi itu untuk menunjukkan bahwa algoritma perataan lain dapat digunakan di sini. GetSmoothedInput mengambil kecepatan dan mengembalikan kecepatan yang diperhalus.

Dengan Soft Tiered Smoothing tidak ada smoothing diterapkan pada gerakan yang disengaja jelas (di atas ambang batas yang lebih besar), ada smoothing diterapkan untuk menutupi sejumlah kecil jitter, yang juga akan mempengaruhi gerakan sangat kecil, tetapi ketika Anda mendapatkan ambang Anda dengan benar, itu tidak terlalu nyata. Dan ada transisi yang sangat mulus antara keduanya (tanpanya, jitter sebenarnya dapat diperkuat).

Sementara jawaban lain benar untuk mengatakan bahwa sulit untuk mengenali jitter ketika input diterima, juga benar bahwa jitter hampir selalu memiliki kecepatan sangat rendah, dan jeda input yang datang dengan smoothing jauh lebih tidak terlihat untuk input kecepatan rendah. .

Seperti yang disebutkan dalam artikel ini, ini digunakan di beberapa tempat di perangkat open source saya JoyShockMapper , sebuah mapper input yang mengubah input gyro menjadi input mouse. Bahkan untuk orang yang menggunakan alat remapping lain seperti Steam atau reWASD, beberapa menggunakan JoyShockMapper pada saat yang sama hanya untuk kontrol gyro-nya.

Jawaban ini mengasumsikan input diberikan dalam kecepatan sudut (yang umum dengan pengendali yang memiliki kontrol gerak), bukan orientasi absolut (yang kedengarannya seperti yang diberikan Razer Hydra kepada Anda). Dengan orientasi absolut, harapan saya adalah Anda dapat menggunakan perbedaan antara orientasi saat ini dan orientasi yang dilaporkan sebelumnya untuk mendapatkan kecepatan, tetapi saya tidak tahu pasti apakah itu akan berfungsi serta dengan pengendali yang melaporkan sendiri kecepatan sudut .

Solusi perataan yang umum ketika Anda berurusan dengan posisi / orientasi absolut daripada kecepatan adalah dengan menyisipkan ke arah orientasi tujuan Anda dari waktu ke waktu - ini dijelaskan secara sangat membantu dalam artikel Gamasutra ini.. Ini juga bisa digunakan dengan Soft Tiered Smoothing. Anda akan menghitung besarnya kecepatan menggunakan perbedaan antara input ini dan input yang dilaporkan sebelumnya. Anda akan menerapkan perbedaan orientasi antara frame ini dan frame terakhir dikalikan dengan nilai "directWeight" Anda seperti yang dihitung dalam cuplikan di atas. Langkah terakhir adalah menambahkan input yang dihaluskan, tetapi karena cara pemulusan orientasi yang diinterpolasi bekerja, Anda hanya menerapkan perubahan orientasi yang diinterpolasi seperti biasa - itu tidak perlu mempertimbangkan "bobot langsung" sama sekali. Atur saja orientasi target Anda (inilah yang Anda interpolasi ke arah dengan pemulusan yang dijelaskan dalam artikel Gamasutra) ke orientasi apa pun yang Anda dapatkan dari perangkat, dan interpolasi orientasi Anda ke arah itu seperti yang dijelaskan dalam artikel itu.

Jibb Smart
sumber
1

Rasanya aneh menjawab pertanyaan saya sendiri, tetapi saya pikir saya sudah menemukan solusi saya.

//Pseudo-Java

update()
{
    //deltaYaw is the change in yaw of the controller since last update
    //yawBuffer is initialized to zero, and only modified here
    //coneAngle is the stabilizing cone

    deltaYaw = getData().yaw;

    yawBuffer += deltaYaw;
    if (abs(yawBuffer) >= coneAngle)
    {
        player.yaw += (abs(yawBuffer)-coneAngle) * sign(yawBuffer);
        yawBuffer = coneAngle * sign(yawBuffer);
    }
}

Alih-alih memodifikasi heading pemain secara langsung, saya hanya "mendorong" kerucut dari sudut tertentu (dalam kasus saya, 2,5 derajat). Saya membuat demo HTML5 kecil dari teknik ini.

Setelah Anda mulai mendorong kerucut, ada nol delay dan presisi penuh. Namun, jika Anda mendorong kerucut ke kiri, dan kemudian ingin membidik ke kanan, Anda harus bergerak melintasi sudut penuh kerucut untuk melihat efeknya.

Jadi itu memecahkan masalah keterlambatan temporal dan perataan yang mengerikan, tetapi memperkenalkan masalah baru dari ambang batas pergerakan. Namun, jika kerucut penstabil disetel dengan benar, ambang tidak akan terlihat.

Apel
sumber
Ini sepertinya cara lain yang masuk akal untuk melakukannya. Dulu ada camcorder (mahal) yang menstabilkan gambar mereka menggunakan pendekatan ini; itu memberi Anda ketepatan saat Anda melanjutkan gerakan dalam satu arah, tetapi memiliki kelambatan saat Anda mengubah arah. Jika itu bekerja dengan baik untuk gim Anda, maka benar-benar melakukannya. Anda tidak akan menemukan solusi tunggal yang paling cocok untuk setiap game; itu selalu merupakan tradeoff di mana Anda harus mempertimbangkan sisi-bawah dari setiap pendekatan terhadap kebutuhan spesifik dari game tertentu yang Anda buat. :)
Trevor Powell