Untuk Vertex Buffer Steaming, Multiple glBufferSubData VS Orphaning?


8

Saya belajar OpenGL baru-baru ini. Dalam game, kita perlu memperbarui posisi objek game secara teratur, dan mereka akan keluar masuk layar terus-menerus. Jadi itu berarti dalam rendering kita perlu memperbarui buffer vertex cukup sering juga.

Dalam konteks OpenGL, salah satu cara intuitif adalah menggunakan glBufferSubData untuk memperbarui yang berubah.

Tetapi saya juga membaca secara online sebuah trik yang disebut Orphaning yang menciptakan data buffer baru dan mengunggah seluruh data simpul ke dalamnya.

Juga karena menyatakan biaya chagnes dan biaya unggah, beberapa glBufferSubData juga mungkin lebih mahal.

Ini pertanyaan saya,

  1. Metode mana yang lebih baik?
  2. Apakah warung benar-benar penting dalam kasus ini?
  3. Apakah perubahan negara dan biaya pengunggahan benar-benar penting dalam kasus ini?

Terima kasih!


Mengapa Anda ingin mengunggah ulang geometri ketika Anda sebenarnya hanya dapat memperbarui matriks? dengan kata lain Anda tidak perlu mengunggah kembali simpul saat hanya transformasi yang perlu diubah.
concept3d

@ concept3d Ya, Anda benar! Saya membuat kesalahan saat menulis deskripsi masalah. Terima kasih telah mengingatkan saya tentang itu! Saya sudah memperbarui deskripsi.
YiFeng

Jawaban:


9

Ini adalah pertanyaan kompleks dengan banyak detail kecil yang sangat penting, kinerjanya akan bervariasi berdasarkan platform dan aplikasi. Jadi, Anda harus membuat profil untuk kemungkinan kemacetan sebelum berinvestasi dalam optimasi.

Yang mengatakan, pertama, saya menganggap Anda harus mengurangi unggahan dan pembaruan sebanyak yang Anda bisa, misalnya menggunakan instancing.

Kedua, perhatikan bahwa GPU tidak dapat mentransfer buffer dan render secara bersamaan, sehingga semua perintah OpenGL dalam antrian perintah diproses secara berurutan oleh perangkat. Ada berbagai cara untuk menyalin data dan / atau membuatnya tersedia untuk digunakan oleh GPU.

Ada berbagai cara untuk mengalirkan data ke GPU

1- glBufferDataatau glBufferSubDatametode

Menggunakan glBufferDataatau glBufferSubDataseperti memcpy. Anda melewati pointer dan operasi DMA mungkin dilakukan, saya katakan mungkin karena memori mungkin disematkan dalam memori CPU dan digunakan langsung oleh GPU tanpa benar-benar transfer memori ke GPU terjadi, tergantung pada flag penggunaan (GL_STREAM). Menurut pendapat Anda harus mencoba ini pada awalnya karena lebih mudah untuk diterapkan.

2- mendapatkan pointer ke memori internal menggunakan glMapBuffer

Jika hal di atas tidak cukup baik untuk Anda gunakan glMapBuffer, Anda mendapatkan pointer ke memori internal, dan Anda dapat menggunakan pointer ini untuk mengisi buffer secara langsung, ini bagus untuk operasi membaca dan menulis file, karena Anda dapat langsung memetakan data file ke memori GPU daripada menyalin ke buffer temp terlebih dahulu. Jika Anda tidak ingin memetakan seluruh buffer yang dapat Anda gunakan glMapBufferRangeyang dapat digunakan untuk memetakan sebagian buffer.

Salah satu triknya adalah membuat buffer besar, gunakan bagian pertama untuk rendering dan bagian kedua untuk memperbarui.

3- Buffer Yatim Piatu

Mengenai buffer orphaning ini dapat dilakukan menggunakan glBufferData dengan null dan parameter yang sama. Pengemudi akan mengembalikan blok memori setelah tidak digunakan. Dan akan digunakan oleh panggilan glBufferData berikutnya (tidak ada memori baru akan dialokasikan).

Semua metode yang disebutkan menyebabkan banyak sinkronisasi yang mahal, sekali lagi GPU tidak dapat mentransfer buffer dan render pada saat yang sama.

4- Unsynchronized Buffers

Metode tercepat (dan paling sulit untuk mendapatkan yang benar) adalah dengan menggunakan buffer tanpa sinkronisasi, Anda dapat menggunakan GL_MAP_UNSYNCHRONIZED_BITflag glMapBufferRange, masalahnya adalah tidak ada sinkronisasi yang dilakukan, jadi kami mungkin mengunggah data ke buffer yang mulai digunakan, dan karenanya mengacaukan semuanya. Anda dapat menggunakan beberapa buffer dengan bit yang tidak disinkronkan untuk mempermudah.


0

Saya melakukannya dengan cara lain. Mungkin ada sesuatu yang salah di sana. Beberapa hal berbahaya tersembunyi.

(Saya menggunakan C # + OpenTK.GameWindow)

Untuk instancing objek saya menggunakan Array Buffer Object terpisah untuk set matriks model untuk setiap instance. Di dalam simpul yang dibagikan:

#version 400
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 normal;
layout (location = 2) in vec2 texcoord;
layout (location = 4) in mat4 model_matrix;

uniform mat4 proj_matrix, view_matrix;

Dalam kode C # saya matriks disimpan dalam array float float[] mat4_array

Lalu saya ikat array ke Array Buffer Object:

public void bind_data_instances()
{
    GL.BindBuffer(BufferTarget.ArrayBuffer, id_InstanceBO);
    GL.BufferData(BufferTarget.ArrayBuffer, mat4_array.Length * sizeof(float), mat4_array, BufferUsageHint.DynamicDraw);
}

Setiap bingkai matriks model diperbarui. Untuk memperbarui, mat4_arraysaya hanya menelepon:

Buffer.BlockCopy(mat4_array_new, 0, mat4_array, 0, sizeof(float) * mat4_models.Length);

dan membuat adegan. menggunakan GL.DrawElementsInstanced.

Tidak ada panggilan OpenGL tambahan dan berfungsi dengan baik.


Apa tujuan dari memiliki model matriks sebagai atribut vertex?
Anton Duzenko

Ini untuk contoh objek menggambar. Dan ini lebih cepat daripada array yang dilewatkan sebagai variabel seragam.
Dennis
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.