Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Game Development
  2. WebGL

Membina Shaders Dengan Babylon.js dan WebGL: Teori dan Contoh

by
Difficulty:AdvancedLength:LongLanguages:
Sponsored Content

This sponsored post features a product relevant to our readers while meeting our editorial guidelines for being objective and educational.

Malay (Melayu) translation by Seurion (you can also view the original English article)

Dalam nota utama Hari 2 of//Build 2014 (lihat 2: 24-2: 28), penginjil Microsoft Steven Guggenheimer dan John Shewchuk membuktikan bagaimana sokongan Oculus Rift telah ditambahkan ke Babylon.js. Dan salah satu perkara penting untuk demo ini adalah kerja yang kami lakukan pada shader tertentu untuk mensimulasikan kanta, seperti yang anda dapat lihat dalam gambar ini:

Lens simulation image

Saya juga membentangkan sesi dengan Frank Olivier dan Ben Constable mengenai grafik pada IE dan Babylon.js.

Ini membawa saya kepada salah satu soalan yang sering ditanya oleh orang-orang tentang Babylon.js: "Apa yang anda maksudkan oleh shaders?" Oleh itu dalam jawatan ini, saya akan menerangkan kepada anda bagaimana kerja shaders, dan berikan beberapa contoh jenis shaders yang biasa.

Teori

Sebelum memulakan eksperimen, kita mesti terlebih dahulu melihat bagaimana keadaan bekerja secara dalaman.

Apabila berurusan dengan 3D yang dipercepatkan perkakasan, kami membincangkan dua CPU: CPU utama dan GPU. GPU adalah sejenis CPU yang sangat khusus.

GPU ialah mesin negara yang anda gunakan menggunakan CPU. Sebagai contoh CPU akan mengkonfigurasi GPU untuk menjadikan garis bukan segitiga. Atau ia akan menentukan ketelusan, dan sebagainya.

Apabila semua negeri ditetapkan, CPU akan menentukan apa yang akan diberikan—geometri, yang terdiri daripada senarai mata (dipanggil simpang dan disimpan ke dalam array yang dipanggil penyokong vertex), dan senarai indeks (muka, atau segitiga, disimpan dalam array yang dipanggil penimbal indeks).

Langkah akhir untuk CPU adalah untuk menentukan bagaimana untuk menjadikan geometri, dan untuk tugas khusus ini, CPU akan menentukan shader untuk GPU. Shaders adalah sekeping kod yang akan dilaksanakan oleh GPU untuk setiap nada dan piksel yang ia perlu buat.

Mula-mula, beberapa perbendaharaan kata: fikirkan titik puncak (titik apabila terdapat beberapa daripada mereka) sebagai "titik" dalam persekitaran 3D (yang bertentangan dengan titik dalam persekitaran 2D).

Terdapat dua jenis shaders: shader, dan pixel (atau fragmen) shaders.

Talian Paip Grafik

Sebelum menggali ke dalam shaders, mari ambil langkah. Untuk membuat piksel, GPU akan mengambil geometri yang ditakrifkan oleh CPU dan akan melakukan yang berikut:

Menggunakan penimbal indeks, tiga simpul dikumpulkan untuk menentukan segitiga: penimbal indeks mengandungi senarai indeks verteks. Ini bermakna setiap penyertaan dalam penimbal indeks adalah bilangan puncak dalam penyangga puncak. Ini benar-benar berguna untuk mengelakkan simpulan berganda.

Sebagai contoh, penimbal indeks berikut adalah senarai dua muka: [1 2 3 1 3 4]. Wajah pertama mengandungi titik 1, titik 2 dan titik 3. Wajah kedua mengandungi titik 1, sudut 3 dan puncak 4. Jadi terdapat empat titik dalam geometri ini:

Chart showing four vertices

Shader vertex diterapkan pada setiap bahagian segi tiga. Matlamat utama shader vertex adalah untuk menghasilkan piksel untuk setiap puncak (unjuran pada skrin 2D dari puncak 3D):

vertex shader is applied on each vertex of the triangle

Menggunakan tiga piksel ini (yang menentukan segitiga 2D pada skrin), GPU akan menyerap semua nilai yang dilampirkan pada piksel (sekurang-kurangnya kedudukannya), dan piksel shader akan digunakan pada setiap piksel yang dimasukkan ke dalam segitiga 2D untuk menghasilkan warna untuk setiap piksel:

pixel shader will be applied on every pixel included into the 2D triangle

Proses ini dilakukan untuk setiap muka yang ditentukan oleh penimbal indeks.

Jelas sekali, disebabkan sifatnya selari, GPU dapat memproses langkah ini untuk banyak wajah secara serentak, dan dengan itu mencapai prestasi yang sangat baik.

GLSL

Kami baru saja melihat bahawa untuk menjadikan segitiga, GPU memerlukan dua shaders: shader vertex dan shader pixel. Shader ini ditulis menggunakan bahasa yang dipanggil GLSL (Grafik Bahasa Shader Language). Ia kelihatan seperti C.

Untuk Internet Explorer 11, kami telah membangunkan pengkompil untuk mengubah GLSL ke HLSL (High Level Shader Language), yang merupakan bahasa shader DirectX 11. Ini membolehkan IE11 untuk memastikan kod shader selamat (anda tidak mahu menggunakan WebGL untuk menetapkan semula komputer anda!):

Flow chart of transforming GLSL to HLSL

Berikut adalah contoh shader vertex biasa:

Struktur Shader Vertex

Shader vertex mengandungi perkara berikut:

  • Atribut: Suatu atribut mentakrifkan bahagian puncak. Secara lalai, satu titik harus sekurang-kurangnya mengandungi kedudukan (vector3: x, y, z). Tetapi sebagai pemaju, anda boleh memutuskan untuk menambah maklumat lanjut. Contohnya, dalam bekas shader, terdapat vector2 bernama uv (koordinat tekstur yang membolehkan kita menggunakan tekstur 2D pada objek 3D).
  • Seragam: Seragam adalah pemboleh ubah yang digunakan oleh shader dan ditakrifkan oleh CPU. Satu-satunya seragam yang ada di sini ialah matriks yang digunakan untuk memproyeksikan kedudukan puncak (x, y, z) ke skrin (x, y).
  • Berbeza: Pemboleh ubah berbeza adalah nilai yang dibuat oleh shader vertex dan dihantar kepada shader piksel. Di sini, shader vertex akan menghantar nilai vUV (salinan ringkas uv) ke piksel shader. Ini bermakna bahawa piksel ditakrifkan di sini dengan koordinat kedudukan dan tekstur. Nilai-nilai ini akan diinterpolasi oleh GPU dan digunakan oleh shader piksel.
  • utama: Fungsi yang dinamakan utama() ialah kod yang dilaksanakan oleh GPU untuk setiap puncak dan sekurang-kurangnya menghasilkan nilai untuk gl_position (kedudukan pada skrin puncak semasa).

Kita dapat lihat dalam contoh kami bahawa shader sudut adalah agak mudah. Ia menghasilkan pembolehubah sistem (bermula dengan gl_) bernama gl_position untuk menentukan kedudukan piksel yang berkaitan, dan ia menetapkan pembolehubah yang berbeza-beza yang disebut vUV.

Voodoo Di Sebalik Matriks

Dalam shader kita mempunyai matriks bernama worldViewProjection. Kami menggunakan matriks ini untuk memproyeksikan kedudukan puncak kepada pemboleh ubah gl_position. Itu sejuk, tetapi bagaimana kita dapat nilai matriks ini? Ia adalah seragam, jadi kita harus menentukannya di sebelah CPU (menggunakan JavaScript).

Ini adalah salah satu bahagian kompleks melakukan 3D. Anda mesti memahami matematik kompleks (atau anda perlu menggunakan enjin 3D, seperti Babylon.js, yang akan kita lihat kemudian).

Matriks worldViewProjection adalah gabungan tiga matriks berbeza:

The worldViewProjection matrix is the combination of three different matrices

Menggunakan matriks yang terhasil membolehkan kita dapat mengubah simpang 3D ke piksel 2D sambil mengambil kira sudut pandangan dan segala yang berkaitan dengan kedudukan/skala/putaran objek semasa.

Ini adalah tanggungjawab anda sebagai pemaju 3D: untuk mencipta dan mengekalkan matriks ini sehingga kini.

Kembali ke Shaders

Apabila shader vertex dilaksanakan pada setiap puncak (tiga kali, maka) kita mempunyai tiga piksel dengan gl_position yang betul dan nilai vUV. GPU kemudian akan menghimpunkan nilai-nilai ini pada setiap piksel yang terdapat dalam segitiga yang dihasilkan oleh piksel ini.

Kemudian, bagi setiap piksel, ia akan melaksanakan shader piksel:

Struktur Shader Pixel (atau Fragment)

Struktur shader piksel adalah sama dengan shader vertex:

  • Berbeza: Pemboleh ubah berbeza adalah nilai yang dibuat oleh shader vertex dan dihantar kepada shader piksel. Di sini, piksel shader akan menerima nilai vUV dari shader vertex.
  • Seragam: Seragam adalah pemboleh ubah yang digunakan oleh shader dan ditakrifkan oleh CPU. Satu-satunya pakaian seragam yang kami ada di sini adalah sampler, yang merupakan alat yang digunakan untuk membaca warna tekstur.
  • utama: Fungsi yang dinamakan utama ialah kod yang dilaksanakan oleh GPU untuk setiap piksel dan sekurang-kurangnya harus menghasilkan nilai untuk gl_FragColor (warna piksel semasa).

Shader pixel ini agak mudah: Ia membaca warna dari tekstur yang menggunakan koordinat tekstur dari shader vertex (yang seterusnya mendapatnya dari puncak).

Adakah anda mahu melihat hasil shader tersebut? Ini dia:

Ini sedang diberikan dalam masa nyata; anda boleh menyeret bola dengan tetikus anda.

Untuk mencapai hasil ini, anda harus berurusan dengan banyak kod WebGL. Sesungguhnya, WebGL adalah API yang sangat kuat tetapi benar-benar tahap rendah, dan anda perlu melakukan segala-galanya sendiri, daripada mewujudkan buffer untuk menentukan struktur puncak. Anda juga perlu melakukan semua matematik dan menetapkan semua negeri dan mengendalikan memuatkan tekstur dan sebagainya ...

Terlalu Susah? BABYLON.ShaderMaterial to the Rescue

Saya tahu apa yang anda fikirkan: shaders benar-benar sejuk, tetapi saya tidak mahu mengganggu dengan paip dalaman WebGL atau bahkan dengan matematik.

Dan semudah itu! Ini adalah permintaan yang sah, dan itulah sebabnya saya buat Babylon.js.

Biarkan saya membentangkan kepada anda kod yang digunakan oleh demo sfera roll sebelumnya. Pertama sekali, anda memerlukan laman web yang mudah:

Anda akan melihat bahawa shaders ditakrifkan oleh <script>  tags. Dengan Babylon.js anda juga boleh menentukannya dalam fail berasingan( .fx) fail.

Anda boleh mendapatkan Babylon.js di sini atau di repo GitHub kami. Anda mesti menggunakan versi 1.11 atau lebih tinggi untuk mendapatkan akses ke BABYLON.StandardMaterial.

Dan akhirnya kod JavaScript utama adalah yang berikut:

Anda dapat melihat bahawa saya menggunakan BABYLON.ShaderMaterial untuk menyingkirkan semua beban menyusun, menghubungkan dan mengendalikan shaders.

Apabila anda membuat BABYLON.ShaderMaterial, anda perlu menentukan elemen DOM yang digunakan untuk menyimpan shader atau nama asas fail di mana shader itu. Sekiranya anda memilih untuk menggunakan fail, anda mesti membuat fail untuk setiap shader dan menggunakan corak nama fail berikut: basename.vertex.fx dan basename.fragment.fx. Kemudian anda perlu membuat bahan seperti ini:

Anda juga harus menentukan nama mana-mana atribut dan pakaian seragam yang anda gunakan. Kemudian, anda boleh menetapkan secara langsung nilai seragam dan sampler anda menggunakan setTexture, setFloat, setFloats, setColor3, setColor4, setVector2, setVector3, setVector4, dan setMatrix fungsi.

Cukup mudah, kan?

Adakah anda ingat matriks worldViewProjection sebelumnya? Menggunakan Babylon.js dan BABYLON.ShaderMaterial, anda tidak perlu risau! The BABYLON.ShaderMaterial secara automatik akan mengira ia untuk anda kerana anda mengisytiharkannya dalam senarai pakaian seragam.

BABYLON.ShaderMaterial juga boleh mengendalikan matriks berikut untuk anda:

  • dunia
  • pandangan
  • unjuran
  • worldview
  • worldviewProjection

Tidak perlu lagi untuk matematik. Sebagai contoh, setiap kali anda melaksanakan sphere.rotation.y = 0.05, matriks dunia sfera dihasilkan untuk anda dan dihantar ke GPU.

CYOS: Buat Shader Anda Sendiri

Jadi, mari kita pergi lebih besar dan buat halaman di mana anda secara automatik boleh membuat shaders anda sendiri dan melihat hasilnya dengan serta-merta. Halaman ini akan menggunakan kod yang sama yang telah dibahas sebelum ini, dan akan menggunakan objek BABYLON.ShaderMaterial untuk mengkompilasi dan melaksanakan shader yang akan anda buat.

Saya menggunakan editor kod ACE untuk CYOS. Ini adalah editor kod yang luar biasa dengan penyerlah sintaks. Jangan ragu untuk melihatnya di sini. Anda boleh mencari CYOS di sini.

Menggunakan kotak combo pertama, anda akan dapat memilih shaders yang telah ditentukan sebelumnya. Kami akan melihat setiap daripada mereka selepas itu.

Anda juga boleh menukar mesh (objek 3D) yang digunakan untuk mempratonton shaders anda menggunakan kotak kombo kedua.

Butang Compile digunakan untuk membuat BABYLON.ShaderMaterial baru dari shaders anda. Kod yang digunakan oleh butang ini adalah yang berikut:

Secara kejam mudah, kan? Bahan ini siap untuk menghantar tiga matriks pra-dihitung (dunia, worldView dan worldviewProjection). Verteks akan datang dengan kedudukan, koordinat biasa dan tekstur. Dua tekstur juga sudah dimuatkan untuk anda:

amiga texture
amiga.jpg
ref texture
ref.jpg

Dan akhirnya, di sini adalahLoop yang membuat saya mengemas kini dua pakaian seragam yang mudah:

  • satu dipanggil masa untuk mendapatkan beberapa animasi lucu
  • satu yang dipanggil kameraPosition untuk mendapatkan kedudukan kamera ke dalam shaders anda (yang akan berguna untuk persamaan pencahayaan)

Terima kasih kepada kerja yang kami lakukan pada Windows Phone 8.1, anda juga boleh menggunakan CYOS pada Windows Phone anda (ini sentiasa masa yang baik untuk membuat shader):

CYOS on Windows Phone

Shader Asas

Oleh itu mari kita mulakan dengan shader pertama yang ditakrifkan pada CYOS: shader asas.

Kita sudah tahu shader ini. Ia mengira gl_position dan menggunakan koordinat tekstur untuk mengambil warna untuk setiap piksel.

Untuk mengira kedudukan piksel, kita hanya perlu matriks worldViewProjection dan kedudukan vertex:

Koordinat tekstur (uv) dihantar tidak diubah suai kepada shader piksel.

Sila ambil perhatian bahawa kami perlu menambah terapung beretama ketepatan; pada baris pertama untuk kedua-dua sudut dan piksel shader kerana Chrome memerlukannya. Ia mendefinisikan bahawa, untuk prestasi yang lebih baik, kita tidak menggunakan nilai terapung yang tepat.

Shader piksel adalah lebih mudah, kerana kita hanya perlu menggunakan koordinat tekstur dan mengambil warna tekstur:

Kami melihat sebelumnya bahawa seragam teksturSampler dipenuhi dengan tekstur "amiga", jadi hasilnya adalah berikut:

Basic Shader result

Black and White Shader

Sekarang mari kita teruskan dengan shader baru: shader hitam dan putih.

Matlamat shader ini adalah menggunakan sebelumnya tetapi dengan mod rendering "hitam dan putih sahaja". Untuk berbuat demikian, kita boleh menyimpan shader vertex yang sama, tetapi shader piksel mesti diubah sedikit.

Pilihan pertama yang kita ada hanyalah mengambil satu komponen, seperti yang hijau:

Seperti yang anda lihat, bukan menggunakan .rgb (operasi ini dipanggil swizzle), kami menggunakan .ggg.

Tetapi jika kita mahukan kesan hitam dan putih yang benar-benar tepat, ia akan menjadi idea yang lebih baik untuk mengira kecerahan (yang mengambil kira semua komponen warna):

Operasi titik (atau produk dot) dikira seperti ini:

Hasil = v0.x * v1.x + v0.y * v1.y + v0.z * v1.z

Jadi dalam kes kami:

luminance = r * 0.3 g * 0.59 b * 0.11 (nilai ini didasarkan pada fakta bahawa mata manusia lebih masuk akal untuk hijau)

Bunyi sejuk, bukan?

Black and white shader result

Shader Shader

Sekarang mari kita beralih kepada shader yang lebih kompleks: shad shading sel.

Yang satu ini akan memerlukan kita untuk mendapatkan kedudukan puncak dan kedudukan puncak dalam piksel shader. Oleh itu, shader sudut akan kelihatan seperti ini:

Sila ambil perhatian bahawa kami juga menggunakan matriks dunia, kerana kedudukan dan normal disimpan tanpa sebarang perubahan dan kita mesti menggunakan matriks dunia untuk mengambil kira putaran objek.

Shader piksel adalah seperti berikut:

Matlamat shader ini adalah untuk mensimulasikan cahaya, dan bukannya mengira teduhan halus kita akan mempertimbangkan bahawa cahaya akan dikenakan mengikut ambang kecerahan tertentu. Sebagai contoh, jika intensiti cahaya adalah antara 1 (maksimum) dan 0.95, warna objek (diambil daripada tekstur) akan digunakan secara langsung. Sekiranya intensiti antara 0.95 dan 0.5, warna akan dilemahkan oleh faktor 0.8, dan sebagainya.

Oleh itu, terdapat empat langkah utama dalam shader ini:

  • Pertama, kita mengisytiharkan had dan tahap pemalar.
  • Kemudian, kita perlu mengira pencahayaan menggunakan persamaan Phong (kita mengandaikan bahawa cahaya tidak bergerak):

Keamatan cahaya per piksel bergantung kepada sudut antara arah normal dan cahaya.

  • Kemudian kita mendapatkan warna tekstur untuk piksel.
  • Dan akhirnya kita periksa ambang dan memohon tahap ke warna.

Hasilnya kelihatan seperti objek kartun:

Cell shading shader result

Phong Shader

Kami menggunakan sebahagian daripada persamaan Phong pada shader sebelumnya. Oleh itu, mari kita gunakan semuanya sekarang.

Shader sudut jelas mudah di sini, kerana segala-galanya akan dilakukan dalam shader pixel:

Menurut persamaan, anda mesti mengira bahagian tersebar dan spekular dengan menggunakan arah cahaya dan normal verteks:

Kami sudah menggunakan bahagian ricih di shader sebelumnya, jadi di sini kita hanya perlu menambah bahagian spekular. Gambar ini dari artikel Wikipedia menerangkan cara shader berfungsi:

Diffuse plus Specular equals Phong Reflection
By Brad Smith aka Rainwarrior.

Hasilnya pada bidang kami:

Phong shader result

Buang Shader

Untuk shader pembuang, saya ingin memperkenalkan konsep baru: kata kunci membuang. Shader ini akan membuang setiap piksel bukan merah dan akan mencipta ilusi objek "digali".

Shader vertex adalah sama seperti yang digunakan oleh shader asas:

Shader piksel perlu menguji warna dan gunakan buang apabila, sebagai contoh, komponen hijau terlalu tinggi:

Hasilnya lucu:

Discard shader result

Wave Shader

Kami telah bermain banyak dengan shaders piksel, tetapi saya juga ingin menunjukkan kepada anda bahawa kita boleh melakukan banyak perkara dengan shaders vertex.

Untuk shader gelombang, kami akan menggunakan semula shad piksel Phong.

Shader vertex akan menggunakan seragam yang dipanggil masa untuk mendapatkan beberapa nilai animasi. Menggunakan seragam ini, shader akan menjana gelombang dengan kedudukan 'vertices':

Sine digunakan untuk position.y, dan hasilnya adalah berikut:

Wave shader result

Pemetaan Persekitaran Sfera

Yang satu ini sebahagian besarnya diilhami oleh tutorial ini. Saya akan membiarkan anda membaca artikel yang sangat baik dan bermain dengan shader yang berkaitan.

Spherical environment mapping shader

Fresnel Shader

Saya ingin menamatkan artikel ini dengan kegemaran saya: shader Fresnel.

Shader ini digunakan untuk memohon keamatan yang berbeza mengikut sudut antara arah paparan dan normal vertex.

Shader vertex adalah sama dengan yang digunakan oleh shader shader, dan kita boleh dengan mudah mengira istilah Fresnel dalam shader piksel kami (kerana kita mempunyai kedudukan normal dan kamera, yang boleh digunakan untuk menilai arah paparan):

Fresnel Shader result

Shader Anda?

Anda kini lebih bersedia untuk membuat shader anda sendiri. Rasa bebas menggunakan ulasan di sini atau di forum Babylon.js untuk berkongsi eksperimen anda!

Jika anda ingin pergi lebih jauh, berikut adalah beberapa pautan berguna:

Dan beberapa lagi pembelajaran yang saya buat pada subjek ini:

Atau, mundur, siri pembelajaran pasukan kami di JavaScript:

Dan tentu saja, anda sentiasa dialu-alukan gunakan beberapa alat percuma kami dalam membina pengalaman web anda yang seterusnya: Komuniti Visual Studio, Percubaan Azure, dan alat ujian silang pelayar untuk Mac, Linux, atau Windows

Artikel ini adalah sebahagian daripada web dev tech siri dari Microsoft. Kami teruja untuk berkongsi Microsoft Edge dan enjin baharu rendering EdgeHTML dengan anda. Dapatkan mesin percuma atau uji jauh dari Mac, iOS, Android atau peranti Windows anda@ http://dev.modern.ie/.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.