Apa teknik rendering yang akan saya gunakan untuk menggambar efek drop shadow untuk kartu dalam permainan kartu?

13

Jenis algoritma naungan apa yang mungkin digunakan untuk membuat bayangan seperti ini? masukkan deskripsi gambar di sini

yang saya buat adalah serupa tetapi semuanya dilakukan dengan API gambar 2D yang didukung oleh OpenGL sehingga tidak ada koordinat Z.

Selain itu, untuk tangan itu sendiri, saya benar-benar ingin mendapatkan nuansa teduh seperti terlihat di sini: masukkan deskripsi gambar di sini

Saya hanya tidak yakin bagaimana mencapai tampilan yang teduh dekat dengan itu.

Jumlah kartu pasti akan berubah dan kartu-kartu itu terlempar ke atas meja jadi saya tidak bisa menggunakan jenis peta jenis apa pun.

Algoritma macam apa yang harus saya perhatikan (selain dari blur yang saya tahu harus saya lakukan?)

Terima kasih

Memperbarui

Saya membuat permainan kartu 2D. Saya ingin menambahkan dropshadows offset dari kartu, sedikit seperti:

masukkan deskripsi gambar di sini

Cara saya berpikir untuk melakukannya adalah:

  • Pertahankan tekstur yang ukurannya sama dengan backbuffer.
  • Gambarlah persegi panjang gelap sebagai kartu darurat untuk tekstur itu.

  • Memburamkan tekstur itu.

  • Tarik kartu saya ke tekstur itu.
  • Lakukan pencahayaan tambahan pada kartu.
  • Gambarlah tekstur ini ke backbuffer.

Pertanyaan saya adalah:

  • Apakah ini cara yang tepat untuk melakukan ini?

  • Apakah ada cara untuk melakukannya tanpa render ke tekstur (menjaga bitmap
    sebesar backbuffer)?

  • Apakah aman untuk mengasumsikan bahwa ukuran tekstur maksimum tidak akan
    dilampaui oleh ukuran backbuffer? (Maksud saya adalah, jika backbuffer
    adalah 2000x3000, apakah aman untuk mengatakan bahwa saya dapat membuat tekstur dalam
    memori video sebesar itu?

Terima kasih

jmasterx
sumber
1
Poin estetika pada masalah kedua Anda: itu tidak benar-benar mungkin jika Anda benar-benar memegang kartu-kartu itu di tangan Anda. Kartu-kartu yang saling bersebelahan tidak saling membayangi satu sama lain. Tidak, kecuali Anda memegang banyak dari mereka. Anda tidak dapat benar-benar memegang kartu seperti yang digambarkan dalam gambar itu; kartu-kartu itu terlihat seperti dipisahkan oleh beberapa milimeter; mereka tidak datar terhadap satu sama lain. Aku tidak akan khawatir tentang itu.
Nicol Bolas

Jawaban:

18

Saya pikir semua orang memberikan solusi terlalu rumit untuk masalah ini ..

masukkan deskripsi gambar di sini

Jadi pertama-tama, kita memiliki kartu (atau apa pun yang ingin Anda gambar), digambarkan di sini oleh (a). Selanjutnya, kami mengambil salinannya, mengisinya hitam dan menjalankan gaussian blur di atasnya (b). Semua ini terjadi di photoshop atau apa pun alat seni favorit Anda.

Selanjutnya, dalam gim, ketika kita ingin menggambar kartu, pertama menggambar gambar hitam kabur dengan campuran multiplicative (atau alfa), mengimbangi sedikit arah, dan kemudian menggambar kartu di atas itu. Voila.

Untuk tipuan lebih lanjut, Anda dapat berganti-ganti antara bayangan dan pembuatan kartu untuk mendapatkan efek seperti (d), atau pertama menggambar semua bayangan dan kemudian kartu, seperti dalam (e) (Saya mewarnai kartu dalam kasus (e) untuk menunjukkan bahwa mereka masih terpisah =)

Sebaiknya jangan menggunakan hitam murni (atau alfa penuh) untuk bayangan untuk membuat bayangan transparan yang lebih halus.

Jari Komppa
sumber
2
+1 untuk melakukan bayangan di luar permainan. Anda juga bisa mengambil langkah lebih jauh dan memodifikasi di mana bayangan ditempatkan jika ada cahaya di tempat kejadian.
FrenchyNZ
+1, ilustrasi yang bagus. Selain itu, dalam kasus E Anda dapat menggunakan render bayangan gelap di atas meja dan semi-terang pada kartu dengan stensil. Itu akan lebih rumit, tetapi efeknya akan lebih baik :)
Kromster mengatakan mendukung Monica
2

Yang pertama tidak terlalu sulit. Jika Anda merender saluran alfa untuk kartu Anda (yang bisa sesederhana hitam untuk piksel dengan kartu di dalamnya, dan putih untuk transparan), Anda dapat melakukan segala jenis blur yang Anda inginkan pada saluran alpha saja, dan kemudian diimbangi dan gunakan itu untuk mengontrol pencahayaan meja. (Agaknya, jika Anda tidak memiliki buffer-Z, Anda harus terlebih dahulu membuat saluran alpha offscreen di suatu tempat, kemudian melakukan tabel dengan mask, kemudian membuat kartu yang sebenarnya.)

Yang kedua mirip SSAO (oklusi ambien layar-ruang). Teknik itu membutuhkan koordinat Z. Namun, jika Anda tidak memiliki sudut yang berbeda antara kartu (yang saya kira jika Anda tidak memiliki Z-buffer), Anda mungkin dapat melakukan perkiraan yang cukup baik dengan membuat drop shadow (seperti yang pertama) untuk setiap kartu. kartu. Namun, kinerjanya bisa sedikit rumit — setiap pesawat akan membutuhkan saluran alfa kabur untuk semua pesawat di atasnya, dan jika ada banyak kartu di atas meja, itu bisa berarti beberapa render lintasan.

John Calsbeek
sumber
SSAO berlebihan =) Sangat sulit untuk mengetahui teknik membayangi apa yang digunakan tanpa melihat contoh animasi. Jika kartu selalu jatuh dalam urutan itu dan spasi di atas satu sama lain akan lebih mudah untuk pra-membuat bayangan, tetapi Anda tidak akan pernah tahu tanpa melihat permainan dalam aksi.
Patrick Hughes
0

Bisakah Anda tidak membuat peta bayangan? Ubah adegan menjadi fbo. Simpan hanya nilai kedalaman dan lakukan pemeriksaan nilai kedalaman normal di shader untuk melihat apakah bayangan harus ditampilkan atau tidak.

Joey Green
sumber
Saya tidak menggunakan Buffer Z, tidak ada 'kedalaman'.
jmasterx
0

Proses berikut ini tidak memerlukan target render di luar layar. Namun, dengan melakukan hal itu, ia mendapatkan persyaratan bahwa tabel harus diambil terlebih dahulu . Atau setidaknya, tidak ada yang ditarik pada piksel yang akan dicakup tabel sebelum tabel ditarik. Ini juga mensyaratkan bahwa tabel itu sendiri menjadi satu, tunggal, bagian yang tidak tumpang tindih: sebuah gambar.

Selain itu, framebuffer Anda membutuhkan komponen alfa.

  1. Dapatkan gambar skala abu-abu dari sebuah kartu. Buat menjadi kabur di sekitar tepinya, mungkin memperluas ukurannya. Ini adalah gambar kartu bayangan Anda. Perhatikan bahwa ini adalah gambar saluran tunggal. Saat Anda mengakses tekstur ini di shader Anda, Anda harus memastikan bahwa Anda memasukkan nilai tunggal dalam komponen alpha. Ini bisa dilakukan di shader Anda atau di tempat lain.

    Nilai 0,0 pada gambar berarti tidak ada bayangan. Nilai 1,0 pada gambar berarti bayangan total . Itu benar-benar gelap gulita. Anda mungkin menginginkan nilai 0,5 atau lebih sebagai warna tergelap Anda.

  2. Bersihkan layar sedemikian rupa sehingga alpha diatur ke nol .

  3. Sebelum merender apa pun (atau setidaknya apa pun yang akan ditampilkan "di bawah" tabel), untuk setiap kartu, render tekstur fuzzy, diimbangi dari posisi aktual kartu (tetapi dengan orientasi yang sama). Output warna oleh shader harus Konfigurasi konfigurasi untuk ini seharusnya (dalam bahasa OpenGL):

    glBlendEquation(GL_MAX);

    Mode campuran ini digunakan untuk menjaga bayangan yang tumpang tindih agar tidak bertambah gelap atau terang. Ini hanya mengambil nilai paling gelap yang ditulis ke piksel itu. Seharusnya terlihat cukup baik.

    Anda juga harus menggunakan masker tulis warna untuk mematikan penulisan warna.

  4. Berikan meja. Saat melakukannya, Blending harus diatur sebagai berikut:

    glBlendEquation(GL_ADD);
    glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ZERO);

Jika batasan terlalu ketat untuk Anda, maka Anda harus menggunakan target render. Ini dilakukan sebagai berikut:

  1. Buat gambar kartu bayangan seperti sebelumnya.

  2. Pertama, berikan bayangannya. Bind the shadow framebuffer (yang hanya perlu menjadi gambar saluran tunggal, jika perangkat keras Anda dapat merender ke salah satunya). Hapus nilainya menjadi nol.

  3. Untuk setiap kartu, render gambar kartu bayangan, offset seperti sebelumnya. Shader Anda harus menuliskan nilai yang sama untuk keempat komponen warna keluaran. Modus campuran lagi harus glBlendEquation(GL_MAX).

  4. Beralih kembali ke framebuffer biasa. Gambarlah semua yang Anda inginkan untuk dibayangi.

  5. Sekarang gambar quad layar penuh dengan gambar bayangan yang kami render. Shader harus menyimpan texel yang diambil dari bayangan gambar di alfa output; RGB tidak relevan. Mode campuran harus:

    glBlendEquation(GL_ADD);
    glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
Nicol Bolas
sumber
Pada metode pertama, saya pikir Anda lupa langkah 5: nonaktifkan blending dan render kartu. Juga, perlu dicatat bahwa metode pertama tidak memungkinkan Anda untuk mendapatkan bayangan antar-kartu seperti yang terlihat pada tangkapan layar kedua OP.
Nathan Reed
@NathanReed: Saya pikir dia tahu cara mematikannya sendiri. Juga, "bayangan antar-kartu" tidak masuk akal, seperti yang saya tunjukkan dalam komentar saya di bawah pertanyaan.
Nicol Bolas
1
Ini mungkin tidak secara realistis menggambarkan bagaimana Anda benar-benar memegang kartu, tetapi terlihat keren! Itu tidak benar-benar "masuk akal" untuk kartu melayang di atas meja seperti yang mereka lakukan pada tembakan pertama, baik ...
Nathan Reed
0

Saya akan menggunakan buffer stensil. Kosongkan ke 1 (sebaiknya pada saat yang sama saat Anda membersihkan kedalaman), gambarkan meja Anda. Kemudian aktifkan uji stensil, gambar bayang-bayang menggunakan tekstur persegi panjang buram, bertambah jika stensil dan kedalaman melewati, tidak melakukan apa-apa jika stensil gagal, tidak ada jika kedalaman gagal, dan atur fungsi stensil Anda menjadi GL_EQUAL (ref 1, mask 0xff), nonaktifkan uji stensil . (Saya belum sepenuhnya menguji ini tetapi ini berasal dari kode yang tidak sama dan harus berfungsi dengan baik; Anda mungkin perlu mengubah params). Kemudian gambar semuanya.

Panggilannya adalah:

glEnable (GL_STENCIL_TEST);
glStencilFunc (GL_EQUAL, 1, 2);
glStencilOp (GL_KEEP, GL_KEEP, GL_INCR);

// draw shadow textures

glDisable (GL_STENCIL_TEST);

Satu-satunya waktu yang dapat menyebabkan masalah adalah jika Anda memiliki dua tepi buram yang sedikit tumpang tindih; jika tidak, tidak perlu apa-apa lebih dari apa yang ditawarkan OpenGL 1.1 dasar dan akan bekerja pada semua perangkat keras (mungkin kartu 3DFX yang sudah ada, yang saya anggap Anda tidak terlalu khawatir tentang dukungan ...)

Alternatif kedua, yang seharusnya bekerja dengan sangat baik di gim non-kinerja-kritis, adalah glCopyTexSubImage2D. Itu akan bekerja dengan tekstur yang lebih kecil daripada backbuffer juga dan juga didukung dengan baik pada semua perangkat keras (itu bagian dari OpenGL 1.1 dan Doom 3 yang menggunakannya, sehingga Anda dapat mengharapkan dukungan menjadi sangat baik).

Pengaturan dasar akan seperti ini:

  • Warna yang jelas menjadi hitam.
  • Nonaktifkan penulisan kedalaman (meskipun metode ini tidak memerlukan buffer kedalaman, sehingga Anda dapat mengabaikan bagian itu karena Anda tidak menggunakannya).
  • Atur viewport dengan dimensi yang sama dengan tekstur Anda.
  • Gambar kartu sebagai geometri yang diisi putih.
  • glCopyTexSubImage2D untuk tekstur Anda.
  • Alihkan viewport kembali ke ukuran jendela penuh.
  • Gambarkan meja seperti biasa.
  • Gambar tekstur sebagai quad campuran fullscreen, menggunakan shader untuk mengaburkannya dan membalikkan warna.
  • Gambar semuanya.

Itu juga harus bekerja dengan sangat baik, ini sedikit lebih intensif daripada metode buffer stensil tetapi menangani kasus yang tumpang tindih dengan benar dan - seperti yang saya katakan - saya pikir permainan seperti game Anda akan memiliki kekuatan GPU untuk dibakar, bahkan pada low-end kartu.

Maximus Minimus
sumber