Untuk rendering voxel, apa yang lebih efisien: VBO pra-dibuat atau shader geometri?

26

Diberikan array voxel yang cukup statis, apa yang lebih efisien: menggunakan CPU untuk pra-menghasilkan VBO untuk membuat wajah voxel (mengabaikan bentuk rendering yang lebih canggih seperti marching cubes untuk saat ini) atau menggunakan shader geometri pada GPU untuk menghasilkan wajah dengan cepat?

Saya tidak begitu khawatir tentang memperbarui voxel yang berubah, tetapi tentu saja itu adalah manfaat dari versi GPU karena Anda tidak harus membangun kembali VBO. Juga, pendekatan GS terasa sedikit lebih modern :)

Di sisi lain, saya belum melihat detail tentang bagaimana sebenarnya GS bekerja dengan pipa rasterisasi di GPU modern. Apakah ini menghasilkan simpul menjadi semacam stream-cache atau apakah simpul ditulis ke memori GPU normal di antaranya? Jika itu yang terakhir, maka on-the-fly menghasilkan dapat mengurangi bandwidth yang tersedia dan kekuatan pemrosesan dari sisa tugas GPU yang saya kira dan kemudian akan lebih bermanfaat untuk melakukannya pada CPU ..

Bjorn Wesen
sumber

Jawaban:

9

Saya sedang memikirkan adegan jenis minecraft, di mana voxel yang Anda maksud adalah dunia balok yang sebenarnya dirender menggunakan poligon:

Jika Anda menggunakan geometri shader akan sulit untuk menghindari memiliki tiga wajah (atau apa pun) per voxel.

Jika Anda memiliki banyak blok yang berdekatan yang memiliki tekstur yang sama maka Anda dapat menggunakan ubin tekstur untuk memiliki segitiga yang jauh lebih sedikit di strip Anda (degenerasi) dalam pendekatan VBO. Maksud saya, jika ada bidang rumput voxel besar 6x6 yang rata dan rata, Anda bisa menggambar seluruh bagian atasnya hanya dalam 2 segitiga daripada 64.

Dengan pendekatan GS Anda tidak dapat melakukan pemusnahan sepele wajah yang disumbat oleh voxel yang berdekatan yang sangat mudah dengan pendekatan VBO.

Saya belum mencoba pendekatan GS, tetapi saya bisa mengatakan bahwa pendekatan VBO dengan menggabungkan pengulangan ubin yang berdekatan bekerja dengan sangat baik. Saya menemukan mengacaukan dengan indeks elemen menjadi lebih lambat daripada hanya mengulangi simpul. Jika Anda membagi dunia Anda menjadi kubus kecil yang bagus, Anda biasanya dapat menggunakan hanya satu byte per komponen per simpul dan bahkan mengemas info tekstur dan normals (wajah pada kubus sejajar sumbu hanya memiliki 3 kemungkinan normal) dll menjadi byte keempat untuk membuat 4 byte per titik yang bagus dan cepat.

Saya telah menggunakan VBO terpisah untuk masing-masing dari 6 wajah - Anda hanya perlu menggambar paling banyak 3 dari mereka jelas. Ini cocok dengan tekstur yang berbeda yang biasanya digunakan pada bagian atas voxels bergaya minecraft. Karena untuk setiap set yang normal dan yang demikian itu seragam.

Dengan menggunakan pixmaps ubin vertikal di atlas dengan GL_REPEATpada sumbu horizontal dan memiliki versi diputar 90-derajat dari pixmap di atlas yang sama saya menemukan saya dapat menggambar sejumlah besar blok yang tampaknya berbeda menggunakan VBO yang sama dalam panggilan yang sama. Dalam contoh 6x6 area rumput, saya akan membaginya menjadi 12 segitiga karena saya hanya mengulang pada satu dimensi di atlas saya.

Saya sebagian besar telah mendapatkan ini untuk bekerja pada ujung yang sangat rendah dari chip grafis terintegrasi dan ponsel, di mana GS adalah sesuatu yang saya bisa mimpikan suatu hari bermain dengan.

Akan
sumber
3
Anda hanya perlu menggambar paling banyak 3 wajah per voxel, tetapi Anda mungkin perlu menggambar wajah yang berbeda untuk setiap voxel tergantung pada sudut pandangnya sehingga pengoptimalannya tidak semudah itu bukan? VBO pra-dibuat akan berisi lebih dari satu voxel. Jika sudut pandang Anda berada di antara voxel, Anda akan melihat sisi timur satu dan sisi barat lainnya. Satu-satunya cara ini akan membantu adalah bahwa Anda dapat dengan mudah menyisihkan wajah yang sebenarnya menghadap ke belakang, tetapi kasus terburuk adalah Anda masih membuat 5 dari 6 sisi dalam sekelompok voxels. Jika sudut pandang Anda berada di luar batas aksial VBO, maka Anda hanya perlu membuat 3 sisi.
Bjorn Wesen
Spot on Bjorn, itu bisa dilakukan. (Tapi saya membuat VBO untuk blok seperlunya dan mempertimbangkan kembali apa yang telah saya buat ketika kamera bergerak, daripada memiliki seluruh dunia di VBO setiap saat; jadi saya punya waktu alami untuk membuat pilihan ini)
Will
10

Bagaimana dengan opsi ketiga, menggunakan array instances? Pada dasarnya Anda menggambar banyak banyak kotak (terbuat dari kubus 8-simpul sederhana) dengan satu panggilan undian, sumber posisi (dan data lainnya) sebagai atribut per-instance dari voxel-data VBO (menggunakan glVertexAttribDivisorOpenGL, saya yakin DX juga memilikinya). Ini mungkin lebih cepat daripada pendekatan geometri shader meskipun kode aplikasi (non-shader) harus sangat mirip, karena saya ingat geometri shaders memiliki reputasi karena lambat, walaupun saya tidak memiliki pengalaman dengan mereka (atau instancing) karena saya masih duduk pada 2.1 perangkat keras.

Tapi bagaimanapun, baik geometri shaders atau array yang dipasang harus lebih cocok daripada geometri voxel yang dibangun CPU, terutama ketika data voxel dapat berubah. Dalam hubungannya dengan umpan balik transformasi (aliran keluaran dalam DX?) Anda mungkin dapat mengatur beberapa teknik culling berbasis GPU yang baik.

Kata Chris Reinstate Monica
sumber
Ya ini adalah solusi terbaik untuk masalah ini. Mengapa tidak terjadi pada saya? :)
Notabene
Setelah beberapa percobaan saya harus memberi tahu Anda bahwa geometri panggang mengalahkan setiap instances dengan margin yang lebar. Saya belum mencoba shader geometri.
Jari Komppa
@JariKomppa dapatkah Anda menguraikan apa yang Anda maksud dengan geometri panggang?
Steven Lu
Contoh-contoh yang sudah diterjemahkan sebelumnya dan disalin ke satu jala tunggal. Seperti memiliki satu jala yang mewakili seratus kubus atau apa pun.
Jari Komppa
@JariKomppa Saya telah melihat hasil yang sama, di mana membuat mesh jauh lebih cepat. Namun pada gtx 680 opsi instancing tampaknya bekerja lebih cepat, aneh.
Levi H
1

Versi geometri shader terdengar jauh lebih baik bagi saya. Anda hanya dapat memiliki titik vbo dan membangun kotak dengan cepat (titik input, aliran segitiga output). Ini akan cepat (bahkan lebih cepat jika Anda akan menggunakan unit tessellation dalam model shader 5 eq. DX11) dan akan sangat mengurangi bandwidth, ini akan menjadi solusi yang bagus dan bersih.

Tentang GS. Itu diletakkan antara vertex shader dan pixel shader dan memodifikasi aliran vertex (primitif) yang dihasilkan. Sementara vertex shader hanya bekerja pada simpul, geometri shader bekerja pada primitif keseluruhan. Output dari aliran ini hanya pergi ke pixel shader (dan dirasterisasi sebelum itu tentunya :)) dan tidak ada cara untuk menyimpannya. (Mungkin oleh beberapa rendering gila untuk tekstur dan kemudian menguraikannya ... tapi tidak ada kemungkinan sederhana yang nyata)

Catatan kinerja: Anda harus dapat melakukan semuanya dalam geometri shader dan melewati (hanya data) shader vertex. Tapi itu bukan cara terbaik. Lebih baik (lebih cepat) adalah melakukan sebagian besar kemungkinan transformasi pada vertex shader dan mencoba meminimalkan program geometri shader. Jangan takut untuk menggunakan siklus jika Anda membutuhkannya (untuk pembuatan kotak misalnya). Compiler akan membuka gulungannya untuk Anda.

Notabene
sumber
2
Mungkin ide yang baik untuk memeriksa voksel yang berdekatan dalam geometri dan / atau shader verteks dan membuang simpul atau melewati wajah jika tersumbat. Jika tidak, solusi GS akan meningkatkan bandwidth yang digunakan sebagai gantinya.
Tamschi
Bandwith tidak akan menjadi masalah besar (dari pengalaman saya), tapi tentu saja itu benar. Dan Anda tidak dapat mencari di primitif lain di GS (apakah saya tahu :)).
Notabene
@Tamschi: ya masalah ini terjadi pada saya setelah menulis pertanyaan ini .. untuk versi CPU, voxels di tengah padatan ditekan, tetapi ini mungkin tidak mungkin pada GPU tanpa pra-lewati dengan berapa jumlah yang berarti differencing ..
Bjorn Wesen
1
Anda dapat mengikat vertex buffer ke isamplerBuffer atau seragam usamplerBuffer di shader, lalu lakukan pencarian dengan tekstur (name_of_uniform, index). Pilihan lain adalah mengikat buffer ke array yang seragam, yang memberi Anda lebih banyak kebebasan dalam format vertex apa yang ingin Anda gunakan.
Tamschi