OpenGL mendapatkan garis besar dari beberapa objek yang tumpang tindih

10

Saya hanya punya ide untuk game saya yang sedang berjalan yang dibuat dengan opengl di c ++: Saya ingin memiliki garis besar (5-6 piksel) pada beberapa objek yang tumpang tindih ketika pemain memenangkan sesuatu.

Saya pikir cara terbaik adalah dengan menggunakan buffer stensil tetapi beberapa jam saya mencoba melakukan render stensil di luar layar dan saya tidak dapat mencapai hasil apa pun jadi mungkin. ada beberapa teknik lain!

Inilah yang ingin saya dapatkan:

masukkan deskripsi gambar di sini

Ada ide?

nkint
sumber
Gunakan filter deteksi tepi, isi tepi dengan garis-garis berwarna tebal, kemudian ekstrak gambar yang diberikan dari bentuk dan overlay di atas lapisan garis berwarna?
Shotgun Ninja
apa maksudmu dengan filter deteksi tepi? shader? filter pemrosesan gambar? seperti OpenCV (render ke tekstur, menerapkan filter ke tekstur, mendorong kembali tekstur yang dimodifikasi)?
nkint
Saya tidak punya ide; Saya tidak terlalu berpengalaman dalam rendering 3d untuk memulai.
Shotgun Ninja
apakah Anda memiliki beberapa contoh buffer stensil seperti ini? Saya pikir menggunakan penyangga stensil akan menjadi cara yang lebih bersih tetapi saya tidak dapat membuat penyangga stensil berfungsi
nkint

Jawaban:

4
  1. Mengaktifkan dan menghapus buffer stensil.
  2. Gambar objek, atur buffer stensil. Objek bisa semi-transparan dll.
  3. Sekarang atur mode stensil untuk hanya menulis piksel di mana stensil tidak diatur.
  4. Dan menggambar setiap objek lagi, sedikit ditingkatkan, dalam warna batas yang diinginkan dan tanpa tekstur.
  5. Nonaktifkan buffer stensil.

Berikut adalah kode yang diadaptasi dari beberapa kode stensil webGL yang telah saya kerjakan:

// drawing will set stencil stencil
    gl.enable(gl.STENCIL_TEST);
    gl.stencilFunc(gl.ALWAYS,1,1);
    gl.stencilOp(gl.KEEP,gl.KEEP,gl.REPLACE);
    gl.stencilMask(1);
    gl.clearStencil(0);
    gl.clear(gl.STENCIL_BUFFER_BIT);
// draw objects
for(var object in objects)
  objects[object].draw();
// set stencil mode to only draw those not previous drawn
    gl.stencilFunc(gl.EQUAL,0,1);
    gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP);
    gl.stencilMask(0x00);
// draw object halo
for(var object in objects)
  objects[object].drawHalo(1.1,red); // each mesh should be individually scaled e.g. by 1.1
// done
    gl.disable(gl.STENCIL_TEST);

Saya pikir saya telah menggunakan pendekatan ini dalam game RTS untuk menggambar lingkaran cahaya di sekitar unit yang dipilih, tapi itu sudah lama sekali dan saya tidak ingat apakah ada gotcha dan semua nuansa.

Akan
sumber
apakah Anda memiliki beberapa contoh buffer stensil seperti ini? Saya pikir menggunakan penyangga stensil akan menjadi cara yang lebih bersih tetapi saya tidak dapat membuat penyangga stensil berfungsi
nkint
7
Perhatikan bahwa rendering objek yang sedikit ditingkatkan tidak akan menghasilkan ketebalan garis yang seragam. Tepi yang lebih jauh akan lebih tipis. Jika Anda menjelaskan hal ini saat menskala objek, objek panjang yang merentang ke kejauhan akan memiliki ketebalan yang tidak seragam. Ada sedikit lebih banyak efek ini untuk mendapatkan garis yang bagus dan rata.
Sean Middleditch
2
Lebih baik daripada hanya meningkatkan objek adalah menulis shader titik yang mengimbangi setiap titik jarak pendek sepanjang normalnya. Itu bekerja cukup baik untuk benda halus, tetapi itu akan menghasilkan retakan pada tepi yang keras. Anda dapat mencoba membangun mesh dengan serangkaian normals alternatif yang dihaluskan ke mana-mana dan lihat di mana hal itu membuat Anda.
Nathan Reed
2

Mulailah dengan menemukan semua kelompok objek, di mana sekelompok objek adalah kumpulan objek yang tumpang tindih. Deteksi tabrakan standar harus melakukan pekerjaan. Tetapkan warna unik untuk masing-masing grup. Warna apa pun akan berhasil.

Jadikan semua objek Anda sebagai warna solid, menggunakan warna grup, menjadi tekstur.

Buat tekstur garis baru dengan dimensi yang sama dengan target render. Memindai melalui setiap texel dari target render dan menentukan apakah warnanya berbeda dengan setiap texel di sekitarnya. Jika ya, ubah texel yang sesuai dalam tekstur garis ke warna garis yang Anda inginkan.

Akhirnya, ambil garis besar tekstur ini dan render di atas gambar yang ingin Anda gambar di layar (Anda tentu saja bisa melakukan ini pada saat yang sama dengan deteksi tepi dalam shader fragmen dan hindari membuat tekstur tepi di pertama tempat).

Jika Anda melakukan langkah ini pada cpu dengan menggunakan for loop untuk melewati texels target render, maka ini akan sangat lambat, tetapi mungkin cukup baik untuk menguji dan bahkan digunakan dalam beberapa kasus. Untuk menggunakan ini dalam waktu nyata Anda sebaiknya menangani ini dalam shader.

Sebuah shader fragmen untuk melakukan deteksi tepi ini mungkin terlihat seperti ini;

precision mediump float;

uniform sampler2D s_texture;

varying vec2 v_texCoord;

void main()
{
    gl_FragColor = vec4(0.0);

    vec4 baseColor = texture2D(s_texture, v_texCoord);
    gl_FragColor += baseColor - texture2D(s_texture, top);
    gl_FragColor += baseColor - texture2D(s_texture, topRight);
    gl_FragColor += baseColor - texture2D(s_texture, right);
    gl_FragColor += baseColor - texture2D(s_texture, bottomRight);
    gl_FragColor += baseColor - texture2D(s_texture, bottom);
    gl_FragColor += baseColor - texture2D(s_texture, bottomLeft);
    gl_FragColor += baseColor - texture2D(s_texture, left);
    gl_FragColor += baseColor - texture2D(s_texture, topLeft);
}

Di mana nilai kedua dalam pencarian tekstur2D adalah koordinat 2d relatif terhadap v_texCoord. Anda akan menerapkan ini dengan merender target render pertama sebagai tekstur pada quad layar penuh. Ini mirip dengan bagaimana Anda akan menerapkan efek buram layar penuh seperti guassian blur.

Alasan untuk menggunakan target render pertama dengan warna solid adalah hanya untuk memastikan bahwa tidak ada perbedaan antara objek yang berbeda yang tumpang tindih. Jika Anda hanya melakukan deteksi tepi pada gambar layar, Anda mungkin akan menemukan juga mendeteksi tepi pada tumpang tindih (dengan asumsi objek memiliki warna / tekstur / pencahayaan yang berbeda).

OriginalDaemon
sumber
2
maaf tapi apa maksudmu dengan "Memindai setiap texel"? a untuk loop meskipun setiap piksel? di cpu? jadi itu seperti: render dengan warna solid ke tekstur, transfer gambar ke cpu, lakukan pemindaian, letakkan lagi di tekstur? atau melakukannya dalam shader?
nkint
Lebih disukai melakukannya dalam shader dengan merender layar penuh quad menggunakan target render sebagai tekstur, dengan cara yang sama untuk melakukan efek blur pasca proses, tetapi Anda bisa membuatnya bekerja pada cpu pertama dengan for loop, hanya untuk melihat jika itu bekerja dengan cukup baik.
OriginalDaemon