Saya mengembangkan game dengan medan seperti Minecraft yang terbuat dari balok. Karena rendering dasar dan pemuatan chunk dilakukan sekarang, saya ingin mengimplementasikan pemilihan blok.
Karena itu saya perlu mencari tahu blok apa yang dihadapi kamera orang pertama. Saya sudah mendengar tentang tidak memproyeksikan seluruh adegan tetapi saya memutuskan untuk tidak melakukannya karena kedengarannya gila dan tidak akurat. Mungkin saya entah bagaimana bisa melemparkan sinar ke arah tampilan, tetapi saya tidak tahu cara memeriksa tabrakan dengan blok di data voxel saya. Tentu saja perhitungan ini harus dilakukan pada CPU karena saya perlu hasil untuk melakukan operasi logika permainan.
Jadi bagaimana saya bisa mengetahui blok mana yang ada di depan kamera? Jika lebih disukai, bagaimana saya bisa melemparkan sinar dan memeriksa tabrakan?
sumber
Jawaban:
Ketika saya memiliki masalah ini saat mengerjakan Cubes saya , saya menemukan makalah "Algoritma Traversal Fast Voxel untuk Ray Tracing" oleh John Amanatides dan Andrew Woo, 1987 yang menjelaskan algoritma yang dapat diterapkan untuk tugas ini; itu akurat dan hanya perlu satu perulangan loop per voxel berpotongan.
Saya telah menulis implementasi dari bagian-bagian yang relevan dari algoritma kertas dalam JavaScript. Implementasi saya menambahkan dua fitur: memungkinkan menentukan batas jarak raycast (berguna untuk menghindari masalah kinerja serta mendefinisikan 'jangkauan' terbatas), dan juga menghitung wajah masing-masing voxel yang dimasukkan oleh sinar.
origin
Vektor input harus diskalakan sedemikian sehingga panjang sisi voxel adalah 1. Panjangdirection
vektor tidak signifikan tetapi dapat mempengaruhi akurasi numerik algoritma.Algoritma beroperasi dengan menggunakan representasi sinar yang parameter
origin + t * direction
,. Untuk setiap sumbu koordinat, kami melacakt
nilai yang kita akan memiliki jika kita mengambil langkah yang cukup untuk menyeberangi batas voxel sepanjang sumbu yang (yaitu mengubah bagian integer dari koordinat) dalam variabeltMaxX
,tMaxY
dantMaxZ
. Kemudian, kita mengambil langkah (menggunakan variabelstep
dantDelta
) di sepanjang sumbu mana yang memiliki paling sedikittMax
- yaitu batas voxel mana yang paling dekat.Tautan permanen ke versi sumber ini di GitHub .
sumber
function intbounds(s,ds) { return (ds > 0? Math.ceil(s)-s: s-Math.floor(s)) / Math.abs(ds); }
. KarenaInfinity
lebih besar dari semua angka, saya tidak berpikir Anda perlu menjaga ds menjadi 0 di sana juga.1/ds
menyebabkan salah satu sumbu lainnya bertambah. Cara mengatasinya adalah menulisintfloor
untuk memeriksa apakah keduanyads
negatif dans
merupakan nilai integer (mod mengembalikan 0), dan mengembalikan 0,0 dalam kasus itu.Mungkin melihat ke dalam algoritma garis Bresenham , terutama jika Anda bekerja dengan blok-unit (seperti kebanyakan gim minecraftish cenderung).
Pada dasarnya ini membutuhkan dua poin, dan melacak garis yang tidak terputus di antara mereka. Jika Anda melemparkan vektor dari pemain ke jarak pengambilan maksimum, Anda dapat menggunakan ini, dan posisi pemain sebagai poin.
Saya memiliki implementasi 3D dalam python di sini: bresenham3d.py .
sumber
Untuk menemukan blok pertama di depan kamera, buat loop for yang loop dari 0 ke jarak maksimum. Kemudian, gandakan vektor maju kamera dengan penghitung dan periksa apakah blokir pada posisi itu solid. Jika ya, maka simpan posisi blok untuk digunakan nanti dan hentikan perulangan.
Jika Anda juga ingin dapat menempatkan balok, memetik wajah tidak lebih sulit. Cukup putar kembali dari blok dan temukan blok kosong pertama.
sumber
Saya membuat posting di Reddit dengan implementasi saya , yang menggunakan Algoritma Line Bresenham. Berikut ini contoh bagaimana Anda akan menggunakannya:
Inilah implementasinya sendiri:
sumber