added bahasa indonesia support

pull/336/head
Naufal Adriansyah 3 years ago
parent 1219b6a14e
commit 40faa63560

@ -0,0 +1,49 @@
# Pengenalan
<canvas id="custom" class="canvas" data-fragment-url="cmyk-halftone.frag" data-textures="vangogh.jpg" width="700px" height="320px"></canvas>
Gambar di atas dibuat dengan cara yang berbeda. Yang pertama dibuat oleh tangan Van Gogh dengan mengaplikasikan lapisan di atas lapisan cat. Ini menghabiskan waktu berjam-jam. Yang kedua dibuat dalam waktu sedetik oleh kombinasi 4 matriks dari piksel: satu untuk cyan, satu untuk magenta, satu untuk kuning dan satu untuk hitam. Kunci perbedaannya adalah gambar kedua diproduksi dengan cara non-serial (yang artinya bukan langkah demi langkah, tapi semua dalam waktu yang sama).
Buku ini membahas tentang teknik komputasi revolusioner, *shader fragment*, yang membawa gambar yang dihasilkan secara digital ke level berikutnya. Anda bisa menganggapnya setara dengan Gutenberg Press untuk grafis.
![Gutenberg's press](gutenpress.jpg)
Shader fragment (fragment shader) memberi kendali penuh atas piksel yang ditampilkan di layar dengan kecepatan super cepat. Inilah sebabnya mengapa mereka digunakan dalam semua jenis kasus, dari filter video di ponsel hingga video game 3D yang luar biasa.
![Journey by That Game Company](journey.jpg)
Dalam bab-bab berikut anda akan menemukan betapa luar biasa cepat dan kuatnya teknik ini dan bagaimana menerapkannya pada pekerjaan profesional dan pribadi Anda.
## Untuk siapakah buku ini?
Buku ini ditulis untuk coders kreatif, developer dan insinyur game yang memiliki pengalaman coding, pengetahuan dasar tentang aljabar linier dan trigonometri, dan yang ingin membawa pekerjaan mereka ke tingkat kualitas grafis baru yang menarik. (Jika Anda ingin mempelajari cara membuat kode, saya sangat menyarankan Anda memulai dengan [Processing](https://processing.org/) dan kembali lagi nanti jika Anda sudah merasa nyaman dengannya.)
Buku ini akan mengajarkan anda cara menggunakan dan mengintegrasikan shader ke proyek anda, mengimprovisasi performanya dan kualitas grafis. Karena GLSL (OpenGL Shading Language) shader dapat dikompilasi dan berjalan di berbagai platform, anda dapat menerapkan apa yang dipelajari di lingkungan lain yang menggunakan OpenGL, OpenGL ES atau WebGL. Dalam kata lain, anda dapat menerapkan dan menggunakan pengetahuan anda dengan sketsa [Processing](https://processing.org/), aplikasi [openFrameworks](http://openframeworks.cc/), interaktif [Cinder](http://libcinder.org/) [Three.js](http://threejs.org/) website atau permaianan iOS/Android.
## Apa yang diajarkan buku ini?
Buku ini akan berfokus pada penggunaan shader piksel GLSL. Pertama kita akan mendefinisikan apa itu shader; kemudian kita akan belajar bagaimana membuat bentuk, pola, tekstur dan animasi prosedural dengannya. Anda akan mempelajari dasar-dasar bahasa bayangan dan menerapkannya pada skenario yang lebih berguna seperti: pemrosesan gambar (operasi gambar, konvolusi matriks, blur, filter warna, tabel pencarian, dan efek lainnya) dan simulasi (permainan hidup Conway, Gray-Scott's reaksi-difusi, riak air, efek cat air, sel Voronoi, dll.). Menjelang akhir buku kita akan melihat seperangkat teknik lanjutan berdasarkan Ray Marching
*Ada contoh interaktif untuk Anda mainkan di setiap bab.* Saat Anda mengubah kode, Anda akan segera melihat perubahannya. Konsepnya bisa abstrak dan membingungkan, jadi contoh interaktif sangat penting untuk membantu Anda mempelajari materi. Semakin cepat Anda menerapkan konsep, semakin mudah proses pembelajarannya.
Apa yang tidak diajarkan buku ini:
* Ini *bukan* buku OpenGL atau WebGL. OpenGL/webGL adalah subyek yang lebih besar dari GLSL atau fragment shader. Untuk mempelajari lebih lanjut tentang OpenGL/WebGL saya merekomendasikan melihat: [OpenGL Introduction](https://open.gl/introduction), [the 8th edition of the OpenGL Programming Guide](http://www.amazon.com/OpenGL-Programming-Guide-Official-Learning/dp/0321773039/ref=sr_1_1?s=books&ie=UTF8&qid=1424007417&sr=1-1&keywords=open+gl+programming+guide) (yang juga dikenal sebagai Red Book) atau [WebGL: Up and Running](http://www.amazon.com/WebGL-Up-Running-Tony-Parisi/dp/144932357X/ref=sr_1_4?s=books&ie=UTF8&qid=1425147254&sr=1-4&keywords=webgl)
* Ini *bukan* buku matematika. Meskipun kita akan membahas nomor algoritma dan teknik yang mengandalkan pemahaman aljabar linier dan trigonometri, kita tidak akan menjelaskannya secara detail. Untuk pertanyaan mengenai matematika, saya merekomendasikan menyimpan salah satu dari buku: [3rd Edition of Mathematics for 3D Game Programming and computer Graphics](http://www.amazon.com/Mathematics-Programming-Computer-Graphics-Third/dp/1435458869/ref=sr_1_1?ie=UTF8&qid=1424007839&sr=8-1&keywords=mathematics+for+games) atau [2nd Edition of Essential Mathematics for Games and Interactive Applications](http://www.amazon.com/Essential-Mathematics-Games-Interactive-Applications/dp/0123742978/ref=sr_1_1?ie=UTF8&qid=1424007889&sr=8-1&keywords=essentials+mathematics+for+developers).
## Apa yang dibutuhkan untuk memulai?
Tidak banyak! Jika anda memiliki browser modern yang dapat melakukan WebGL (seperti Chrome, Firefox atau Safari) dan koneksi internet, klik tombol "Next" di akhir halaman untuk memulai.
Sebagai alternatif, berdasarkan apa yang anda miliki atau apa yang Anda butuhkan dari buku ini, Anda dapat:
- [Membuat versi offline dari buku ini](https://thebookofshaders.com/appendix/00/)
- [Menjalankan contoh di Raspberry Pi tanpa browser](https://thebookofshaders.com/appendix/01/)
- [Membuat PDF untuk dicetak](https://thebookofshaders.com/appendix/02/)
- Cek [repositori Github](https://github.com/patriciogonzalezvivo/thebookofshaders) menyelesaikan masalah dan berbagi kode.

@ -0,0 +1,49 @@
# Memulai
## Apa itu fragment shader?
Di bab sebelumnya kita menggambarkan shader sebagai persamaan dari mesin cetak Gutenberg untuk grafis. Mengapa? dan yang paling penting: apa itu shader?
![From Letter-by-Letter, Right: William Blades (1891). To Page-by-page, Left: Rolt-Wheeler (1920).](print.png)
Jika anda sudah memiliki pengalaman membuat gambar dengan komputer, anda tau bahwa dalam proses itu anda menggambar suatu lingkaran, lalu segi empat, garis, beberapa segitiga sampai anda menyusun gambar yang anda inginkan. Proses tersebut sangatlah sama dengan menulis sebuah huruf atau buku oleh tangan - itu adalah sekumpulan instruksi yang melakukan satu tugas demi tugas lainnya.
Shader juga merupakan sekumpulan instruksi, tetapi instruksi tersebut dijalankan sekaligus untuk setiap piksel di layar. Artinya, kode yang Anda tulis harus berperilaku berbeda bergantung pada posisi piksel di layar. Seperti jenis pres, program Anda akan berfungsi sebagai fungsi yang menerima posisi dan mengembalikan warna, dan saat dikompilasi, program akan berjalan sangat cepat.
![Chinese movable type](typepress.jpg)
## Mengapa shader cepat?
Untuk menjawab ini, saya mempersembahkan keajaiban *proses paralel (parallel processing)*
Bayangkan CPU di komputermu sebagai pipa industri besar, dan setiap tugas sebagai sesuatu yang melewatinya - seperti jalur pabrik. Beberapa tugas lebih besar dari yang lain, yang berarti mereka membutuhkan lebih banyak waktu dan energi untuk menyelesaikannya. Kami mengatakan mereka membutuhkan lebih banyak daya pemrosesan. Karena arsitektur komputer, pekerjaan terpaksa dijalankan secara seri; setiap pekerjaan harus diselesaikan satu per satu. Komputer modern biasanya memiliki kelompok empat prosesor yang bekerja seperti pipa ini, menyelesaikan tugas satu demi satu agar semuanya berjalan lancar. Setiap pipa juga dikenal sebagai *thread*.
![CPU](00.jpeg)
Permainan video dan aplikasi grafis lainnya membuathkan banyak kekuatan pemrosesan dibandingkan program lain. Karena konten grafis mereka harus melakukan operasi piksel demi piksel yang sangat banyak. Setiap piksel pada layar harus dihitung, dan dalam permainan 3D geometri dan perspektif harus dihitung dengan baik.
Mari kembali ke metafora pipa dan tugas kita. Setiap piksel pada layar mempresentasikan sebuah tugas kecil. Secara individual setiap tugas piksel bukanlah sebuah isu untuk CPI, tapi (dan disinilah masalahnya) tugas kecil harus selesai untuk setiap piksel pada layar! Yang artinya dalam layar 800x600 jadul, 480,000 pixel harus diproses per frame yang artinya 14,400,000 perhitungan per detik! Ya! Itu masalah yang cukup besar untuk membebani mikroprosesor secara berlebihan. Dalam layar retina 2880x1800 modern yang berjalam 60 frame per detik perhitungan tersebut menjadi 311,040,000 perhitungan per detik. Bagaimanakah insinyur grafis memecahkan masalah ini?
![](03.jpeg)
Inilah saat proses paralel menjadi solusi terbaik, alih-alih memiliki beberapa mikroprosesor yang besar dan kuat, atau *pipa*, akan lebih cerdas jika memiliki banyak mikroprosesor kecil yang berjalan secara paralel pada waktu yang sama. Itulah yang dimaksud dengan Graphic Processor Unit (GPU).
![GPU](04.jpeg)
Bayangkan mikroprosesor kecil sebagai tabel pipa, dan data setiap piksel sebagai bola pingpong. 14.400.000 bola pingpong per detik dapat menghalangi hampir semua pipa. Tetapi tabel pipa kecil berukuran 800x600 yang menerima 30 gelombang 480.000 piksel per detik dapat ditangani dengan mulus. Ini berfungsi sama pada resolusi yang lebih tinggi - semakin banyak perangkat keras paralel yang Anda miliki, semakin besar aliran yang dapat dikelola.
"Kekuatan super" lain dari GPU adalah fungsi matematika khusus yang dipercepat melalui perangkat keras, sehingga operasi matematika yang rumit diselesaikan secara langsung oleh microchip dan bukan oleh perangkat lunak. Itu berarti operasi trigonometri dan matriks ekstra cepat - secepat listrik bisa berjalan.
## Apa itu GLSL?
GLSL kependekan dari OpenGL Shading Language, yang mana adalah spesifik standar dari program shader yang akan anda lihat dalam bab-bab berikutnya. Ada jenis shader lainnya bergantung pada perangkat keras dan sistem operasi. Di sini kita akan bekerja dengan spesifikasi openGL yang diatur oleh [Khronos Group](https://www.khronos.org/opengl/). Memahami sejarah OpenGL dapat membantu untuk memahami sebagian besar konvensi anehnya, untuk itu saya sarankan untuk melihat: [openglbook.com/chapter-0-preface-what-is-opengl.html](http://openglbook.com/chapter-0-preface-what-is-opengl.html)
## Mengapa Shader terkenal menyakitkan?
Seperti kata paman Ben "dengan kekuatan yang besar, muncul tanggung jawab yang besar" dan perhitungan paralel mengikuti aturan ini; desain arsitektur GPU yang kuat hadir dengan batasan dan batasannya sendiri.
Agar dapat berjalan secara paralel, setiap pipa, atau thread, harus independen dari setiap thread lainnya. Kami mengatakan bahwa thread *buta* terhadap apa yang dilakukan thread lainnya. Batasan ini menyiratkan bahwa semua data harus mengalir ke arah yang sama. Jadi, tidak mungkin untuk memeriksa hasil thread lain, mengubah data masukan, atau meneruskan hasil thread ke thread lain. Mengizinkan komunikasi thread-to-thread membuat integritas data berisiko.
Juga GPU membuat mikro-prosesor paralel (pipa) terus-menerus sibuk; segera setelah mendapatkan bebas, mereka menerima informasi baru untuk diproses. Tidak mungkin untaian mengetahui apa yang dilakukannya di momen sebelumnya. Itu bisa berupa menggambar tombol dari UI sistem operasi, lalu merender sebagian langit dalam game, lalu menampilkan teks email. Setiap utas tidak hanya **buta** tetapi juga **tanpa memori**. Selain abstraksi yang diperlukan untuk mengkodekan fungsi umum yang mengubah hasil piksel demi piksel tergantung pada posisinya, batasan buta dan tanpa memori membuat shader tidak terlalu populer di kalangan programmer pemula.
Jangan khawatir! Pada bab-bab berikut, kita akan mempelajari langkah demi langkah bagaimana beralih dari komputasi bayangan sederhana ke lanjutan. Jika Anda membaca ini dengan browser modern, Anda akan senang bermain dengan contoh interaktif. Jadi jangan tunda lagi keseruannya dan tekan *Next >>* untuk beralih ke kode!

@ -0,0 +1,53 @@
## Hello World
Biasanya contoh "Hello World" adalah langkah pertama untuk mempelajari bahasa baru. Ini sebuah program satu baris sederhana yang menampilkan pesan sambutan yang antusias dan menyatakan peluang di depan.
Dalam rendering teks, GPU adalah tugas yang terlalu rumit untuk langkah pertama, sebagai gantinya kami akan memilih warna sambutan yang cerah untuk meneriakkan antusiasme kami!
<div class="codeAndCanvas" data="hello_world.frag"></div>
Jika anda membaca buku ini dalam browser, blok kode sebelumnya itu interaktif. Itu maksudnya anda dapat mengklik dan mengganti bagain manapun dari kode itu yang ingin anda jelajahi. Perubahan akan segera diperbarui berkat arsitektur GPU yang mengompilasi dan menggantikan shader * dengan cepat *. Cobalah dengan mengubah nilai pada baris 8.
Meskipun kode sederhana ini tidak terlihat banyak, kita kita dapat menyimpulkan pengetahuan substansial darinya:
1. Bahasa Shader memiliki satu fungsi `main` yang mengembalikan warna pada akhir. Ini sama seperti C.
2. Warna piksel terakhir disimpan ke variabel global yang disediakan `gl_FragColor`.
3. Bahasa beraneka C ini telah membuat *variabel* (seperti `gl_FragColor`), *fungsi* dan *tipe*. Dalam hal ini kita baru saja diperkenalkan dengan `vec4` yang merupakan singkatan dari vektor empat dimensi presisi floating point. Nanti kita akan melihat lebih banyak tipe seperti `vec3` dan` vec2` bersama dengan yang populer: `float`,`int` dan `bool`.
4. Jika kita melihat lebih dekat ke tipe `vec4` kita dapat menyimpulkan bahwa empat argumen menanggapi saluran MERAH, HIJAU, BIRU dan ALPHA. Kita juga dapat melihat bahwa nilai-nilai ini *dinormalisasi*, yang berarti nilainya berubah dari `0.0` ke` 1.0`. Nanti, kita akan belajar bagaimana menormalkan nilai membuatnya lebih mudah untuk * memetakan * nilai antar variabel.
5. *Fitur C* penting lainnya yang dapat kita lihat dalam contoh ini adalah keberadaan makro praprosesor. Makro adalah bagian dari langkah pra-kompilasi. Dengan mereka dimungkinkan untuk `#define` variabel global dan melakukan beberapa operasi bersyarat dasar (dengan `#ifdef` dan `#endif`). Semua perintah makro dimulai dengan hashtag (`#`). Pra-kompilasi terjadi tepat sebelum mengkompilasi dan menyalin semua panggilan ke `#defines` dan centang `#ifdef` (ditentukan) dan kondisional `#ifndef` (tidak ditentukan). Dalam "Hello World!" Contoh di atas, kita hanya menyisipkan baris 2 jika `GL_ES` ditentukan, yang sebagian besar terjadi ketika kode dikompilasi pada perangkat seluler dan browser.
6. Tipe float sangatlah penting dalam shader, jadi tingkat presisi sangat tinggi. Presisi yang lebih rendah artinya semakin cepat waktu renderingnya, tapi dengan biaya kualitas. Anda dapat memilih-milih dan menentukan presisi setiap variabel menggunakan floating point. Dalam baris kedua ('precision mediump float;') kita menyetel seluruh float ke presisi medium. Tetapi kita dapat memilih untuk menyetel mereka ke presisi rendah (`precision lowp float`) atau tinggi (`precision highp float;`).
7. Yang terakhir, dan mungkin yang terpenting, detailnya bahwa spesifikasi GLSL tidak menjamin bahwa variabel akan otomatis ditransmisikan. Apa maksudnya? Pabrikan memiliki pendekatan berbeda untuk mengakselerasikan proses kartu grafis tapi merka dipaksa untuk menjamin spesifikasi minimum. Transmisi otomatis bukan salah satunya. Dalam "Hello World!" contoh `vec4` memiliki ketepatan titik mengambang dan untuk itu diharapkan akan ditetapkan dengan `floats`. Jika Anda ingin membuat kode yang konsisten dan tidak menghabiskan waktu berjam-jam untuk men-debug layar putih, biasakan untuk meletakkan titik (`.`) di float Anda. Kode semacam ini tidak akan selalu berfungsi:
```glsl
void main() {
gl_FragColor = vec4(1,0,0,1); // ERROR
}
```
Sekarang kita telah menjelaskan elemen paling relevan dari "halo dunia!" program, saatnya untuk mengklik blok kode dan mulai menantang semua yang telah kita pelajari. Anda akan melihat bahwa pada kesalahan, program akan gagal untuk dikompilasi, menampilkan layar putih. Ada beberapa hal yang menarik untuk dicoba, misalnya:
* Mencoba mengganti floats dengan integers, kartu grafis anda mungkin akan atau mungkin tidak akan mentolenransi perilaku ini.
* Mencoba untuk mengkomentari baris 8 dan tidak memberi nilai piksel apa pun pada fungsi.
* Mencoba membuat fungsi terpisah yang mengembalikan spesisif warna dan menggunakannya dalam `main()`. Sebagai petunjuk, ini adalah kode yang mengembalikan warna merah:
```glsl
vec4 red(){
return vec4(1.0,0.0,0.0,1.0);
}
```
* Ada banyak cara untuk membangun tipe `vec4`, coba untuk menemukan jalan lain. Berikut ini adalah salah satu contohnya:
```glsl
vec4 color = vec4(vec3(1.0,0.0,1.0),1.0);
```
Meskipun contoh ini tidak terlalu seru, ini adalah contoh dasar - kita mengubah seluruh piksel dalam kanvas menjadi warna tertentu yang sama. Dalam bab berikutnya kita akan melihat bagaimana cara mengubah warna piksel dengan menggunakan dua tipe input: ruang (tempat piksel pada layar) dan waktu (jumlah detik semenjak halaman dimuat).

@ -0,0 +1,58 @@
## Variabel Seragam (Uniform)
Sejauh ini kita telah melihat bagaimana GPU memanajemen thread paralel dalam jumlah yang besar, masing-masing bertanggung jawab untuk menetapkan warna ke sebagian kecil dari total gambar. Meskipun setiap thread itu buta satu sama lain, kita harus bisa untuk mengirim masukan dari CPU untuk seluruh thread. Karena arsitektur dari kartu grafis, masukan ini akan menjadi sama/seragam (*uniform*) ke semua thread dan harus disetel sebagai *hanya baca*. Dengan kata lain, setiap utas menerima data yang sama yang dapat dibaca tetapi tidak dapat diubah.
Masukan ini dinamakan `uniform` dan tersedia di sebagian besar tipe yang didukung: `float`, `vec2`, `vec3`, `vec4`, `mat2`, `mat3`, `mat4`, `sampler2D` and `samplerCube`. Uniform ditentukan dengan jenis yang sesuai di bagian atas shader tepat setelah menetapkan presisi floating point default.
```glsl
#ifdef GL_ES
precision mediump float;
#endif
uniform vec2 u_resolution; // Canvas size (width,height)
uniform vec2 u_mouse; // mouse position in screen pixels
uniform float u_time; // Time in seconds since load
```
Anda bisa menggambarkan uniform seperti jembatan kecil antara CPU dan GPU. Namanya akan bervariasi dari implementasi ke implementasi, tetapi dalam rangkaian contoh ini saya selalu meneruskan: `u_time` (waktu dalam detik sejak shader dimulai),` u_resolution` (ukuran billboard tempat shader ditarik) dan `u_mouse` (posisi mouse di dalam billboard dalam piksel). Saya mengikuti konvensi meletakkan `u_` sebelum nama seragam agar eksplisit tentang sifat variabel ini tetapi Anda akan menemukan semua jenis nama untuk seragam. Misalnya [ShaderToy.com] (https://www.shadertoy.com/) menggunakan seragam yang sama tetapi dengan nama berikut:
```glsl
uniform vec3 iResolution; // viewport resolution (in pixels)
uniform vec4 iMouse; // mouse pixel coords. xy: current, zw: click
uniform float iTime; // shader playback time (in seconds)
```
Cukup bicaranya, mari melihat uniform dalam aksi. Dalam kode berikut kita menggunakan `u_time` - jumlah detik sejak shader mulai berjalan - bersama dengan fungsi sinus untuk menganimasikan transisi jumlah warna merah di papan iklan.
<div class="codeAndCanvas" data="time.frag"></div>
Seperti yang anda lihat, GLSL memilki banyak kejutan. GPU memiliki fungsi sudut akselerasi perangkat keras, trigonometri, dan eksponensial. Beberapa fungsi diantaranya adalah: [`sin()`](../glossary/?search=sin), [`cos()`](../glossary/?search=cos), [`tan()`](../glossary/?search=tan), [`asin()`](../glossary/?search=asin), [`acos()`](../glossary/?search=acos), [`atan()`](../glossary/?search=atan), [`pow()`](../glossary/?search=pow), [`exp()`](../glossary/?search=exp), [`log()`](../glossary/?search=log), [`sqrt()`](../glossary/?search=sqrt), [`abs()`](../glossary/?search=abs), [`sign()`](../glossary/?search=sign), [`floor()`](../glossary/?search=floor), [`ceil()`](../glossary/?search=ceil), [`fract()`](../glossary/?search=fract), [`mod()`](../glossary/?search=mod), [`min()`](../glossary/?search=min), [`max()`](../glossary/?search=max) dan [`clamp()`](../glossary/?search=clamp).
Sekarang ini waktunya untuk bermain dengan kode di atas lagi.
* Perlambat frekuensinya sampai warnanya berubah menjadi tak terlihat.
* Percepat sampai anda melihat warna tanpa berkedip.
* Bermainlah dengan tiga saluran (RGB) dalam frekuensi yang berbeda untuk mendapatkan pola dan perilaku yang menarik.
## gl_FragCoord
Dengan cara yang sama GLSL memberi kita keluaran bawaan, `vec4 gl_FragColor`, GLSL juga memberi kita masukan default,` vec4 gl_FragCoord`, yang menyimpan koordinat layar dari *piksel* atau *fragmen layar* tempat thread aktif berfungsi di. Dengan `vec4 gl_FragCoord`, kita tahu di mana sebuah thread bekerja di dalam billboard. Dalam hal ini kita tidak menyebutnya `seragam` karena akan berbeda dari utas ke utas, sebaliknya` gl_FragCoord` disebut *bervariasi*.
<div class="codeAndCanvas" data="space.frag"></div>
Dalam kode di atas kita menormalisasi kordinat dari fragment dengan membaginya dengan total resolusi billboard. Dengan melakukan ini nilainya akan berada diantara `0.0` dan `0.1`, yang memudahkan untuk memetakan nilai X dan Y ke saluran MERAH dan HIJAU.
Di Shader, kita tidak memiliki terlalu banyak sumber daya untuk debugging selain memberikan warna yang kuat ke variabel dan mencoba memahaminya. Anda akan menemukan bahwa terkadang pengkodean dalam GLSL sangat mirip dengan meletakkan kapal di dalam botol. Sama-sama keras, indah, dan memuaskan.
![](08.png)
Sekarang waktunya untuk mencoba dan menantang pemahaman kita terhadap kode ini.
* Bisakah anda mengatakan di mana kordinat `(0.0, 0.0)` pada kanvas kita?
* Bagaimana dengan `(1.0, 0.0)`, `(0.0, 1.0)`, `(0.5, 0.5)` and `(1.0, 1.0)`?
* Dapatkah Anda mengetahui cara menggunakan `u_mouse` dengan mengetahui bahwa nilainya dalam piksel dan BUKAN nilai yang dinormalisasi? Bisakah Anda menggunakannya untuk memindahkan warna?
* Dapatkah Anda membayangkan cara yang menarik untuk mengubah pola warna ini menggunakan koordinat `u_time` dan` u_mouse`?
Setelah melakukan latihan ini, Anda mungkin bertanya-tanya di mana lagi Anda bisa mencoba kekuatan shader baru Anda. Pada bab berikut, kita akan melihat cara membuat alat shader Anda sendiri di three.js, Processing, dan openFrameworks.

@ -0,0 +1,229 @@
## Menjalankan Shader
Sebagai bagian dari konstruksi buku ini dan latihan seniku, aku membuat ekosistem alat untuk membuat, menampilkan, berbagi, dan mengkurasi shader. Alat ini bekerja secara konsisten di Linux, MacOS, Windows dan [Raspberry Pi](https://www.raspberrypi.org/) dan browser tanpa harus mengubah kodenya.
## Menjalankan Shader pada Browser
**Tampilan**: seluruh contoh langsung dalam buku ini ditampilkan menggunakan [glslCanvas](https://github.com/patriciogonzalezvivo/glslCanvas) yang membuat proses menjalankan shader mandiri sangat mudah.
```html
<canvas class="glslCanvas" data-fragment-url=“yourShader.frag" data-textures=“yourInputImage.png” width="500" height="500"></canvas>
```
Seperti yang dapat anda lihat, hanya membutuhkan elemen `kanvas` dengan `class="glslCanvas"` dan url shader anda dalam `data-fragment-url`. Pelajari lebih lanjut tentang itu [di sini](https://github.com/patriciogonzalezvivo/glslCanvas).
Jika anda seperti saya, anda mungkin akan menjalankan shader langsung dari kosol, dalam kasus tersebut anda harus melihat [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer). Aplikasi ini memperbolehkan anda untuk menggabungkan shader ke skrip `bash` atau pipeline unix dan menggunakannya sama mirip [ImageMagick](http://www.imagemagick.org/script/index.php). [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer) juga merupakan cara yang bagus untuk menkompilasi shader pada [Raspberry Pi](https://www.raspberrypi.org/), yang mana merupakan alasan [openFrame.io](http://openframe.io/) menggunakan itu untuk menampilkan artwork shader. Pelajari lebih lanjut tentang aplikasi ini [di sini](https://github.com/patriciogonzalezvivo/glslViewer)
```bash
glslViewer yourShader.frag yourInputImage.png —w 500 -h 500 -s 1 -o yourOutputImage.png
```
**Membuat**: untuk menerangi pengalaman pengkodean shader, saya membuat editor online bernama [glslEditor](https://github.com/patriciogonzalezvivo/glslEditor). Editor ini disematkan pada contoh langsung buku, ini membawa serangkaian widget praktis untuk membuat pengalaman abstrak bekerja dengan kode glsl lebih nyata. Anda juga dapat menjalankannya sebagai aplikasi web mandiri dari [editor.thebookofshaders.com/](http://editor.thebookofshaders.com/). Pelajari lebih lanjut tentang itu [di sini](https://github.com/patriciogonzalezvivo/glslEditor).
![](glslEditor-01.gif)
Jika anda memilih untuk mengerjakannya offline menggunakan [SublimeText](https://www.sublimetext.com/) anda dapat memasang [paket untuk glslViewer](https://packagecontrol.io/packages/glslViewer). Pelajari lebih lanjut [di sini](https://github.com/patriciogonzalezvivo/sublime-glslViewer).
![](glslViewer.gif)
**Bagikan**: online editor ([editor.thebookofshaders.com/](http://editor.thebookofshaders.com/)) dapat membagikan shader anda! Baik versi yang disematkan maupun yang berdiri sendiri memiliki tombol ekspor tempat Anda bisa mendapatkan URL unik untuk shader Anda. Juga memiliki kemampuan untuk mengekspor langsung ke [openFrame.io](http://openframe.io/).
![](glslEditor-00.gif)
**Kurasi**: Berbagi kode Anda adalah awal dari Anda membagikan shader sebagai karya seni! Selain opsi untuk mengekspor ke [openFrame.io](http://openframe.io/), saya membuat alat untuk mengkurasi shader Anda ke galeri yang dapat disematkan di situs mana pun, namanya [glslGallery](https://github.com/patriciogonzalezvivo/glslGallery). Pelajari lebih lanjut [di sini](https://github.com/patriciogonzalezvivo/glslGallery).
![](glslGallery.gif)
## Menjalankan Shader pada Framework Favoritmu
Dalam kasus kamu mempunyai pengalaman dalam pemrograman pada framework seperti: [Processing](https://processing.org/), [Three.js](http://threejs.org/) or [OpenFrameworks](http://openframeworks.cc/), anda mungkin tertarik untuk mencoba shader pada platform yang nyaman bagi anda. Contoh berikut adalah cara untuk menyetel shader pada beberapa framework terkenal denggan uniform yang sama yag akan kita gunakan di seluruh buku ini, (Dalan [Repositori Bithub Bab ini](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/04), anda akan menemukan kode sumber lengkap untuk 3 framework ini).
### Dan **Three.js**
Ricardo Cabello yang brilian dan sangat rendah hati (alias [MrDoob](https://twitter.com/mrdoob)) telah berkembang bersama dengan [kontributor lainnya](https://github.com/mrdoob/three.js/graphs/contibutors) mungkin salah satu kerangka kerja paling terkenal untuk WebGL, yang disebut [Three.js](http://threejs.org/). Anda akan menemukan banyak contoh, tutorial dan buku yang mengajarkan Anda bagaimana menggunakan perpustakaan JavaScript ini untuk membuat grafik 3D yang keren.
Di bawah ini adalah contoh HTML dan JS yang Anda butuhkan untuk memulai shader di three.js. Perhatikan skrip `id="fragmentShader`, di sinilah Anda dapat menyalin shader yang Anda temukan di buku ini.
```html
<body>
<div id="container"></div>
<script src="js/three.min.js"></script>
<script id="vertexShader" type="x-shader/x-vertex">
void main() {
gl_Position = vec4( position, 1.0 );
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
uniform vec2 u_resolution;
uniform float u_time;
void main() {
vec2 st = gl_FragCoord.xy/u_resolution.xy;
gl_FragColor=vec4(st.x,st.y,0.0,1.0);
}
</script>
<script>
var container;
var camera, scene, renderer;
var uniforms;
init();
animate();
function init() {
container = document.getElementById( 'container' );
camera = new THREE.Camera();
camera.position.z = 1;
scene = new THREE.Scene();
var geometry = new THREE.PlaneBufferGeometry( 2, 2 );
uniforms = {
u_time: { type: "f", value: 1.0 },
u_resolution: { type: "v2", value: new THREE.Vector2() },
u_mouse: { type: "v2", value: new THREE.Vector2() }
};
var material = new THREE.ShaderMaterial( {
uniforms: uniforms,
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent
} );
var mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
container.appendChild( renderer.domElement );
onWindowResize();
window.addEventListener( 'resize', onWindowResize, false );
document.onmousemove = function(e){
uniforms.u_mouse.value.x = e.pageX
uniforms.u_mouse.value.y = e.pageY
}
}
function onWindowResize( event ) {
renderer.setSize( window.innerWidth, window.innerHeight );
uniforms.u_resolution.value.x = renderer.domElement.width;
uniforms.u_resolution.value.y = renderer.domElement.height;
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
uniforms.u_time.value += 0.05;
renderer.render( scene, camera );
}
</script>
</body>
```
### Dalam **Processing**
Dimulai oleh [Ben Fry](http://benfry.com/) dan [Casey Reas](http://reas.com/) pada 2001, [Processing](https://processing.org/) adalah lingkungan yang sangat sederhana dan kuat untuk mengambil langkah pertama Anda dalam kode (setidaknya untuk saya). [Andres Colubri](https://codeanticode.wordpress.com/) telah membuat pembaruan penting pada openGL dan video dalam Processing, membuatnya lebih mudah dari sebelumnya untuk menggunakan dan bermain dengan GLSL shader dalam lingkungan yang ramah ini. Pemrosesan akan mencari shader bernama `"shader.frag"` di folder `data` sketsa. Pastikan untuk menyalin contoh yang Anda temukan di sini ke dalam folder itu dan ganti nama file.
```cpp
PShader shader;
void setup() {
size(640, 360, P2D);
noStroke();
shader = loadShader("shader.frag");
}
void draw() {
shader.set("u_resolution", float(width), float(height));
shader.set("u_mouse", float(mouseX), float(mouseY));
shader.set("u_time", millis() / 1000.0);
shader(shader);
rect(0,0,width,height);
}
```
Agar shader bekerja pada versi sebelum 2.1, Anda perlu menambahkan baris berikut di awal shader Anda: `#define PROCESSING_COLOR_SHADER`. Sehingga terlihat seperti ini:
```glsl
#ifdef GL_ES
precision mediump float;
#endif
#define PROCESSING_COLOR_SHADER
uniform vec2 u_resolution;
uniform vec3 u_mouse;
uniform float u_time;
void main() {
vec2 st = gl_FragCoord.st/u_resolution;
gl_FragColor = vec4(st.x,st.y,0.0,1.0);
}
```
Untuk informasi lebih lanjut mengenai shader dalam Processing lihatlah [tutorial ini](https://processing.org/tutorials/pshader/).
### Dalam **openFrameworks**
Setiap orang memiliki tempat yang mereka rasa nyaman, dalam kasus saya, itu masih [komunitas openFrameworks](http://openframeworks.cc/). Framework C++ ini membungkus OpenGL dan library C++ open source lainnya. Dalam banyak hal, ini sangat mirip dengan Pemrosesan, tetapi dengan komplikasi yang jelas saat berurusan dengan kompiler C++. Dengan cara yang sama seperti Processing, openFrameworks akan mencari file shader Anda di folder data, jadi jangan lupa untuk menyalin file `.frag` yang ingin Anda gunakan dan ubah namanya saat Anda memuatnya.
```cpp
void ofApp::draw(){
ofShader shader;
shader.load("","shader.frag");
shader.begin();
shader.setUniform1f("u_time", ofGetElapsedTimef());
shader.setUniform2f("u_resolution", ofGetWidth(), ofGetHeight());
ofRect(0,0,ofGetWidth(), ofGetHeight());
shader.end();
}
```
Jika Anda ingin menggunakan set lengkap seragam yang berisi spesifikasi GlslViewer dan GlslCanvas dengan cara yang lebih sederhana di OpenFrameworks, saya sarankan menggunakan addon [ofxShader](https://github.com/patriciogonzalezvivo/ofxshader) yang juga akan memiliki dukungan untuk beberapa buffer, material shader, hotreload, dan konversi otomatis untuk OpenGL ES di Raspberry Pi. Dan kode Anda akan sesederhana melakukannya
```cpp
//--------------------------------------------------------------
void ofApp::setup(){
ofDisableArbTex();
sandbox.allocate(ofGetWidth(), ofGetHeight());
sandbox.load("grayscott.frag");
}
//--------------------------------------------------------------
void ofApp::draw(){
sandbox.render();
sandbox.draw(0, 0);
}
```
Untuk informasi lebih lanjut mengenai shader dalam openFrameworks lihatlah [tutorial bagus ini](https://processing.org/tutorials/pshader/).
### Dalam **Blender**
[GlslTexture](https://github.com/patriciogonzalezvivo/glslTexture) adalah addon yang memperbolehkan menghasilkan tekstur menggunakan shader GLSL secara terprogram dan kompatibel sepenuhnya dengan sandbox lainnya di bab ini. Bagaimana itu bekerja:
1. Operator Search: `F3` (atau `SpaceBar` tergantung pada setup). Cari `GlslTexture`
![](blender/00.png)
2. Ganti ukuran `width` and `height` dan berkas sumber `Source` (dapat menggunakan path file eksternal).
![](blender/01.png)
3. Gunakan gambar pada materialmu. Nama gambar akan berdasarkan pada nama file sumber.
![](blender/02.png)
4. Pergi ke Text Editor (atau eksternal editor jika file sumbermu di luar) dan edit shadernya. Ini akan memuat ulang.
![](blender/03.png)

@ -0,0 +1,140 @@
# Menggambar Secara Algoritmik
## Shaping functions
Bab ini harusnya dinamakan "Pelajaran pagar Pak Miyagi". Sebelumnya, kita memetakan posisi dari *x* dan *y* yang dinormaliasasikan ke saluran *merah* dan *hijau*. Intinya kita membuat sebuah fungsi yang mengambil vektor dua dimensi (x dan y) dan mengembalikan vektor empat dimensi (r, g, b dan a). Tapi sebelum kita melangkah lebih jauh mentransformasikan data antar dimensi, kita harus mulai dari yang sederhana... jauh lebih sederhana. Maksudnya memahami bagaiman membuat fungsi satu dimensi. Semakin banyak energi dan waktu yang anda habiskan untuk mempelajari dan menguasainya, semakin kuat karate shader Anda.
![The Karate Kid (1984)](mr_miyagi.jpg)
Struktur kode berikut ini akan menjadi pagar kita. Di dalamnya, kami memvisualisasikan nilai yang dinormalisasi dari koordinat *x* (`st.x`) dalam dua cara: satu dengan kecerahan (amati gradien yang bagus dari hitam ke putih) dan yang lainnya dengan memplot garis hijau di atas (dalam dalam hal ini nilai * * diberikan langsung ke *y*). Jangan terlalu fokus pada fungsi plot, kita akan membahasnya lebih detail sebentar lagi.
<div class="codeAndCanvas" data="linear.frag"></div>
**Catatan Singkat**: Konstruktor jenis `vec3`" memahami "bahwa Anda ingin menetapkan tiga saluran warna dengan nilai yang sama, sementara` vec4` memahami bahwa Anda ingin membuat vektor empat dimensi dengan satu plus tiga dimensi nilai keempat (dalam hal ini nilai yang mengontrol alpha atau opacity). Lihat misalnya baris 19 dan 25 di atas.
Kode ini adalah pagar Anda; penting untuk mengamati dan memahaminya. Anda akan kembali lagi dan lagi ke ruang ini antara *0,0* dan *1,0*. Anda akan menguasai seni memadukan dan membentuk garis ini.
Hubungan satu-ke-satu antara *x* dan *y* (atau kecerahan) dikenal sebagai *interpolasi linier*. Dari sini kita dapat menggunakan beberapa fungsi matematika untuk *bentuk (shape)* garis. Misalnya kita dapat menaikkan *x* menjadi pangkat 5 untuk membuat garis * melengkung *.
<div class="codeAndCanvas" data="expo.frag"></div>
Menarik bukan? Pada baris 22 coba eksponen berbeda: 20.0, 2.0, 1.0, 0.0, 0.2 dan 0.02 misalnya. Memahami hubungan antara nilai dan eksponen ini akan sangat membantu. Menggunakan jenis fungsi matematika ini di sana-sini akan memberi Anda kontrol ekspresif atas kode Anda, semacam akupunktur data yang memungkinkan Anda mengontrol aliran nilai.
[`pow()`](../glossary/?search=pow) adalah fungsi asli di GLSL dan masih banyak lagi lainnya. Kebanyakan dari mereka diakselerasi pada tingkat perangkat keras, yang berarti jika mereka digunakan dengan cara yang benar dan dengan kebijaksanaan mereka akan membuat kode Anda lebih cepat.
Ganti fungsi power pada baris 22. Coba yang lain seperti: [`exp()`](../glossary/?search=exp), [`log()`](../ glossary/?search=log) dan [`sqrt()`](../glossary/?search=sqrt). Beberapa dari fungsi ini lebih menarik saat Anda bermain dengannya menggunakan PI. Anda dapat melihat pada baris 8 bahwa saya telah menetapkan makro yang akan menggantikan penggunaan `PI` dengan nilai` 3.14159265359`.
### Step dan Smoothstep
GLSL juga memiliki beberapa fungsi interpolasi asli unik yang diakselerasi dengan perangkat keras.
Interpolasi [`step()`](../glossary/?search=step) menerima dua parameter. Yang pertama adalah batas atau ambang, sedangkan yang kedua adalah nilai yang ingin kita periksa atau lewati. Setiap nilai di bawah batas akan mengembalikan `0.0` sementara semua yang di atas batas akan mengembalikan` 1.0`.
Coba ubah nilai ambang batas ini pada baris 20 kode berikut.
<div class="codeAndCanvas" data="step.frag"></div>
Fungsi unik lainnya dikenal sebagai [`smoothstep()`](../glossary/?search=smoothstep). Diberikan rentang dua angka dan nilai, fungsi ini akan menginterpolasi nilai antara rentang yang ditentukan. Dua parameter pertama adalah untuk awal dan akhir transisi, sedangkan yang ketiga adalah untuk nilai yang akan diinterpolasi.
<div class="codeAndCanvas" data="smoothstep.frag"></div>
Pada contoh sebelumnya, pada baris 12, perhatikan bahwa kita telah menggunakan smoothstep untuk menggambar garis hijau pada fungsi `plot()`. Untuk setiap posisi sepanjang sumbu *x* fungsi ini membuat *lonjakan* pada nilai *y* tertentu. Bagaimana? Dengan menghubungkan dua [`smoothstep()`](../glossary/?search=smoothstep) bersama-sama. Perhatikan fungsi berikut, ganti untuk baris 20 di atas dan anggap sebagai potongan vertikal. Latar belakangnya terlihat seperti garis, bukan?
```glsl
float y = smoothstep(0.2,0.5,st.x) - smoothstep(0.5,0.8,st.x);
```
### Sinus dan Kosinus
Saat Anda ingin menggunakan beberapa matematika untuk menganimasikan, membentuk, atau mencampurkan nilai, tidak ada yang lebih baik daripada berkawan dengan sinus dan cosinus.
Kedua fungsi trigonometri dasar ini bekerja sama untuk membuat lingkaran yang berguna seperti pisau tentara Swiss milik MacGyver. Penting untuk mengetahui bagaimana mereka berperilaku dan dengan cara apa mereka dapat digabungkan. Singkatnya, diberi sudut (dalam radian) mereka akan mengembalikan posisi yang benar dari * x * ([cosinus](../glossary/?search=cos)) dan *y* ([sinus](../glosarium/?search=sin)) dari sebuah titik di tepi lingkaran dengan jari-jari yang sama dengan 1. Tapi, fakta bahwa mereka kembali atau
![](sincos.gif)
Meskipun sulit untuk mendeskripsikan semua hubungan antara fungsi trigonometri dan lingkaran, animasi di atas melakukan pekerjaan yang bagus dalam merangkum hubungan ini secara visual.
<div class="simpleFunction" data="y = sin(x);"></div>
Perhatikan baik-baik gelombang sinus ini. Perhatikan bagaimana nilai *y* mengalir dengan mulus antara +1 dan -1. Seperti yang kita lihat pada contoh waktu di bab sebelumnya, Anda dapat menggunakan perilaku ritmis [`sin()`](../ glossary/?search=sin) untuk menghidupkan properti. Jika Anda membaca contoh ini di browser, Anda akan melihat bahwa Anda dapat mengubah kode dalam rumus di atas untuk melihat bagaimana wave berubah. (Catatan: jangan lupa titik koma di akhir baris.)
Cobalah latihan berikut dan perhatikan apa yang terjadi:
* Tambahkan waktu (`u_time`) ke *x* sebelum menghitung `sin`. Internalisasikan **gerakan** di sepanjang *x*.
* Kalikan *x* dengan `PI` sebelum menghitung `sin`. Perhatikan bagaimana kedua fase **menyusut** sehingga setiap siklus berulang setiap 2 bilangan bulat.
* Kalikan waktu (`u_time`) dengan *x* sebelum menghitung `sin`. Lihat bagaimana **frekuensi** antar fase menjadi semakin terkompresi. Perhatikan bahwa u_time mungkin sudah menjadi sangat besar, membuat grafik sulit dibaca.
* Tambahkan 1,0 ke [`sin(x)`](../ glossary /?search=sin). Lihat bagaimana semua gelombang **dipindahkan** ke atas dan sekarang semua nilai berada di antara 0,0 dan 2,0.
* Kalikan [`sin (x)`](../ glossary/?search=sin) dengan 2.0. Lihat bagaimana **amplitudo** berlipat ganda.
* Hitung nilai absolut ([`abs()`](../glossary/?search=abs)) dari `sin(x)`. Ini terlihat seperti jejak bola **yang memantul**.
* Ekstrak hanya bagian pecahan ([`fract()`](../glossary/?search=fract)) dari resultan [`sin(x)`](../glossary/?search=sin).
* Tambahkan bilangan bulat yang lebih tinggi ([`ceil()`](../glossary/?search=ceil)) dan bilangan bulat yang lebih kecil ([`floor()`](../glossary/?search=floor)) dari resultan dari [`sin (x)`](../glossary/?search=sin) untuk mendapatkan gelombang digital nilai 1 dan -1.
### Beberapa fungsi yang berguna ekstra
Di akhir latihan terakhir kami memperkenalkan beberapa fungsi baru. Sekarang saatnya untuk bereksperimen dengan masing-masing dengan menghapus komentar baris di bawah satu per satu. Kenali fungsi-fungsi ini dan pelajari bagaimana perilakunya. Saya tahu, Anda bertanya-tanya ... mengapa? Pencarian Google cepat tentang "seni generatif" akan memberi tahu Anda. Ingatlah bahwa fungsi-fungsi ini adalah pagar kami. Kami menguasai gerakan dalam satu dimensi, naik turun. Sebentar lagi, waktunya untuk dua, tiga, dan empat dimensi!
![Anthony Mattox (2009)](anthony-mattox-ribbon.jpg)
<div class="simpleFunction" data="y = mod(x,0.5); // return x modulo of 0.5
//y = fract(x); // return only the fraction part of a number
//y = ceil(x); // nearest integer that is greater than or equal to x
//y = floor(x); // nearest integer less than or equal to x
//y = sign(x); // extract the sign of x
//y = abs(x); // return the absolute value of x
//y = clamp(x,0.0,1.0); // constrain x to lie between 0.0 and 1.0
//y = min(0.0,x); // return the lesser of x and 0.0
//y = max(0.0,x); // return the greater of x and 0.0 "></div>
### Fungsi membentuk lanjutan
[Golan Levin](http://www.flong.com/) memiliki dokumentasi hebat tentang fungsi pembentukan yang lebih kompleks yang sangat membantu. Mem-portingnya ke GLSL adalah langkah yang sangat cerdas, untuk mulai membangun resource cuplikan kode Anda sendiri.
* Funsi Pembentukan polinomial: [www.flong.com/archive/texts/code/shapers_poly](http://www.flong.com/archive/texts/code/shapers_poly/)
* Fungsi Pembentuan eksponensial: [www.flong.com/archive/texts/code/shapers_exp](http://www.flong.com/archive/texts/code/shapers_exp/)
* Fungsi Pembentukan Lingkaran & Elips: [www.flong.com/archive/texts/code/shapers_circ](http://www.flong.com/archive/texts/code/shapers_circ/)
* Bezier dan Fungsi Pembentukan Parametrik lainnya: [www.flong.com/archive/texts/code/shapers_bez](http://www.flong.com/archive/texts/code/shapers_bez/)
<div class="glslGallery" data="160414041542,160414041933,160414041756" data-properties="clickRun:editor,hoverPreview:false"></div>
Seperti koki yang mengumpulkan rempah-rempah dan bahan-bahan eksotis, seniman digital dan pembuat kode kreatif sangat menyukai mengerjakan fungsi pembentukan mereka sendiri.
[Iñigo Quiles] (http://www.iquilezles.org/) memiliki banyak koleksi [fungsi yang berguna](http://www.iquilezles.org/www/articles/functions/functions.htm). Setelah membaca [artikel ini (http://www.iquilezles.org/www/articles/functions/functions.htm) lihat terjemahan berikut dari fungsi-fungsi ini ke GLSL. Perhatikan perubahan kecil yang diperlukan, seperti meletakkan "." (titik) pada bilangan floating point dan menggunakan nama GLSL untuk fungsi *C*; misalnya alih-alih `powf()` gunakan `pow()`:
<div class="glslGallery" data="05/impulse,05/cubicpulse,05/expo,05/expstep,05/parabola,05/pcurve" data-properties="clickRun:editor,hoverPreview:false"></div>
Untuk menjaga motivasi Anda tetap tinggi, berikut adalah contoh elegan (dibuat oleh [Danguafer](https://www.shadertoy.com/user/Danguafer)) dalam menguasai karate fungsi-pembentukan.
<iframe width="800" height="450" frameborder="0" src="https://www.shadertoy.com/embed/XsXXDn?gui=true&t=10&paused=true" allowfullscreen></iframe>
Di bab berikutnya kami akan mulai menggunakan gerakan baru kami. Pertama dengan mencampurkan warna dan kemudian menggambar bentuk.
#### Latihan
Lihatlah tabel persamaan yang dibuat oleh [Kynd](http://www.kynd.info/log/). Lihat bagaimana dia menggabungkan fungsi dan propertinya untuk mengontrol nilai antara 0,0 dan 1,0. Sekarang saatnya Anda berlatih dengan mereplikasi fungsi-fungsi ini. Ingat, semakin banyak Anda berlatih semakin baik karate Anda nantinya.
![Kynd - www.flickr.com/photos/kynd/9546075099/ (2013)](kynd.png)
#### Untuk kotak peralatan Anda
Berikut beberapa alat yang akan memudahkan Anda untuk memvisualisasikan jenis fungsi tersebut.
* Grapher: jika Anda memiliki komputer MacOS, ketik `grapher` di sorotan Anda dan Anda akan dapat menggunakan alat yang sangat berguna ini.
![OS X Grapher (2004)](grapher.png)
* [GraphToy](http://www.iquilezles.org/apps/graphtoy/): sekali lagi[Iñigo Quilez](http://www.iquilezles.org) membuat alat untuk memvisualisasikan funsi GLSL dalam WebGL.
![Iñigo Quilez - GraphToy (2010)](graphtoy.png)
* [Shadershop](http://tobyschachman.com/Shadershop/): alat menakjubkan ini dibuat oleh [Toby Schachman](http://tobyschachman.com/) akan mengajarkan anda cara untuk membentuk funsi komplek dalam visual yang luar biasa dan jalan yang intuitif.
![Toby Schachman - Shadershop (2014)](shadershop.png)

@ -0,0 +1,144 @@
![Paul Klee - Color Chart (1931)](klee.jpg)
## Warna
Kami tidak memiliki banyak kesempatan untuk membicarakan jenis vektor GLSL. Sebelum melangkah lebih jauh, penting untuk mempelajari lebih lanjut tentang variabel-variabel ini dan subjek warna adalah cara yang bagus untuk mengetahuinya lebih lanjut.
Jika Anda terbiasa dengan paradigma pemrograman berorientasi objek, Anda mungkin memperhatikan bahwa kami telah mengakses data di dalam vektor seperti `struct` biasa mirip-C.
```glsl
vec3 red = vec3(1.0,0.0,0.0);
red.x = 1.0;
red.y = 0.0;
red.z = 0.0;
```
Mendefinisikan warna menggunakan notasi *x*, *y* dan *z* bisa membingungkan dan menyesatkan, bukan? Itulah mengapa ada cara lain untuk mengakses informasi yang sama ini, tetapi dengan nama yang berbeda. Nilai dari `.x`,` .y` dan `.z` juga bisa disebut` .r`, `.g` dan` .b`, dan `.s`,` .t` dan `.p `. (`.s`,` .t` dan `.p` biasanya digunakan untuk koordinat spasial suatu tekstur, yang akan kita lihat di bab selanjutnya.) Anda juga dapat mengakses data dalam vektor dengan menggunakan posisi indeks , `[0]`, `[1]` dan `[2]`.
Baris berikut menunjukkan semua cara untuk mengakses data yang sama:
```glsl
vec4 vector;
vector[0] = vector.r = vector.x = vector.s;
vector[1] = vector.g = vector.y = vector.t;
vector[2] = vector.b = vector.z = vector.p;
vector[3] = vector.a = vector.w = vector.q;
```
Cara berbeda untuk menunjuk ke variabel di dalam vektor hanyalah tata nama yang dirancang untuk membantu Anda menulis kode yang jelas. Fleksibilitas yang tertanam dalam bahasa shading ini merupakan pintu bagi Anda untuk mulai berpikir secara bergantian tentang warna dan koordinat ruang.
Fitur hebat lainnya dari jenis vektor di GLSL adalah bahwa properti dapat digabungkan dalam urutan apa pun yang Anda inginkan, yang memudahkan untuk mentransmisikan dan mencampur nilai. Kemampuan ini disebut *swizzle*.
```glsl
vec3 yellow, magenta, green;
// Making Yellow
yellow.rg = vec2(1.0); // Assigning 1. to red and green channels
yellow[2] = 0.0; // Assigning 0. to blue channel
// Making Magenta
magenta = yellow.rbg; // Assign the channels with green and blue swapped
// Making Green
green.rgb = yellow.bgb; // Assign the blue channel of Yellow (0) to red and blue channels
```
#### Untuk kotak alat Anda
Anda mungkin tidak terbiasa memilih warna dengan angka - ini bisa sangat berlawanan dengan intuisi. Beruntung bagi Anda, ada banyak program pintar yang memudahkan pekerjaan ini. Temukan yang sesuai dengan kebutuhan Anda, lalu latih untuk memberikan warna dalam format `vec3` atau` vec4`. Misalnya, berikut adalah template yang saya gunakan di [Spectrum](http://www.eigenlogik.com/spectrum/mac):
```
vec3({{rn}},{{gn}},{{bn}})
vec4({{`rn}},{{gn}},{{bn}},1.0)
```
### Mencampur warna
Sekarang setelah Anda mengetahui bagaimana warna didefinisikan, sekarang saatnya untuk mengintegrasikannya dengan pengetahuan kita sebelumnya. Di GLSL ada fungsi yang sangat berguna, [`mix()`](../glossary/?search=mix), yang memungkinkan Anda mencampur dua nilai dalam persentase. Bisakah Anda menebak berapa kisaran persentasenya? Ya, nilai antara 0,0 dan 1,0! Yang sempurna untuk Anda, setelah berjam-jam berlatih gerakan karate Anda dengan pagar - sekarang saatnya menggunakannya!
![](mix-f.jpg)
Periksa kode berikut pada baris 18 dan lihat bagaimana kita menggunakan nilai absolut gelombang sin dari waktu ke waktu untuk mencampur `colorA` dan` colorB`.
<div class="codeAndCanvas" data="mix.frag"> </div>
Pamerkan keahlian Anda dengan:
* Buat transisi ekspresif antar warna. Pikirkan emosi tertentu. Warna apa yang paling mewakili itu? Bagaimana tampilannya? Bagaimana cara memudar? Pikirkan emosi lain dan warna yang cocok untuknya. Ubah warna awal dan akhir kode di atas agar sesuai dengan emosi tersebut. Kemudian animasikan transisi menggunakan fungsi pembentuk. Robert Penner mengembangkan serangkaian fungsi pembentukan yang populer untuk animasi komputer yang dikenal sebagai [fungsi pelonggaran](http://easings.net/), Anda dapat menggunakan [contoh ini](../edit.php#06/easing.frag) sebagai penelitian dan inspirasi tetapi hasil terbaik akan datang dari membuat transisi Anda sendiri.
### Bermain dengan gradien
Fungsi [`mix ()`](../glossary/?search=mix) memiliki lebih banyak hal untuk ditawarkan. Alih-alih satu `float`, kita bisa meneruskan tipe variabel yang cocok dengan dua argumen pertama, dalam kasus kita` vec3`. Dengan melakukan itu kita mendapatkan kendali atas persentase pencampuran dari setiap saluran warna individual, `r`,` g` dan `b`.
![](mix-vec.jpg)
Lihat contoh berikut. Seperti contoh di bab sebelumnya, kami mengaitkan transisi ke koordinat *x* yang dinormalisasi dan memvisualisasikannya dengan garis. Saat ini semua saluran berada di jalur yang sama.
Sekarang, hapus komentar pada baris nomor 25 dan lihat apa yang terjadi. Kemudian coba hapus komentar pada baris 26 dan 27. Ingatlah bahwa baris memvisualisasikan jumlah `colorA` dan` colorB` yang akan digabungkan per saluran.
<div class = "codeAndCanvas" data = "gradient.frag"> </div>
Anda mungkin mengenali tiga fungsi pembentuk yang kami gunakan pada baris 25 hingga 27. Mainkanlah dengan mereka! Saatnya bagi Anda untuk menjelajahi dan memamerkan keahlian Anda dari bab sebelumnya dan membuat gradien yang menarik. Coba latihan berikut:
![William Turner - The Fighting Temeraire (1838)](turner.jpg)
* Buat gradien yang menyerupai matahari terbenam William Turner
* Menganimasikan transisi antara matahari terbit dan terbenam menggunakan `u_time`.
* Bisakah Anda membuat pelangi menggunakan apa yang telah kita pelajari sejauh ini?
* Gunakan fungsi `step()` untuk membuat bendera warna-warni.
### HSB
Kita tidak dapat berbicara tentang warna tanpa berbicara tentang ruang warna. Seperti yang mungkin Anda ketahui, ada beberapa cara berbeda untuk mengatur warna selain dengan saluran merah, hijau dan biru.
[HSB](http://en.wikipedia.org/wiki/HSL_and_HSV) adalah singkatan dari Hue, Saturation and Brightness (atau Value) dan merupakan organisasi warna yang lebih intuitif dan berguna. Luangkan waktu sejenak untuk membaca fungsi `rgb2hsv()` dan `hsv2rgb()` pada kode berikut.
Dengan memetakan posisi pada sumbu x ke Hue dan posisi pada sumbu y ke Brightness, kita mendapatkan spektrum warna yang terlihat bagus. Distribusi warna spasial ini bisa sangat berguna; lebih intuitif untuk memilih warna dengan HSB dibandingkan dengan RGB.
<div class = "codeAndCanvas" data = "hsb.frag"> </div>
### HSB dalam koordinat kutub
HSB awalnya dirancang untuk direpresentasikan dalam koordinat kutub (berdasarkan sudut dan jari-jari), bukan koordinat kartesius (berdasarkan x dan y). Untuk memetakan fungsi HSB kita ke koordinat kutub, kita perlu mendapatkan sudut dan jarak dari pusat billboard ke koordinat piksel. Untuk itu kita akan menggunakan fungsi [`length()`](../glossary/?search=length) dan [`atan(y, x)`](../glossary/?search=atan) (yaitu versi GLSL dari `atan2(y, x)`) yang umum digunakan.
Saat menggunakan fungsi vektor dan trigonometri, `vec2`,` vec3`, dan `vec4` dianggap sebagai vektor meskipun keduanya mewakili warna. Kami akan mulai memperlakukan warna dan vektor dengan cara yang sama, bahkan Anda akan menemukan fleksibilitas konseptual ini sangat memberdayakan.
**Catatan:** Jika Anda bertanya-tanya, ada lebih banyak fungsi geometris selain [`panjang`](../glossary/?search=length) seperti: [`distance()`](../glossary/?search=distance), [`dot()`](../glossary/?search=dot), [`cross`](../glossary/?search=cross), [`normalize()`](../glossary/?search=normalize), [`faceforward()`](../glossary/?search=faceforward), [`reflect()`](../glossary/?search=reflect) and [`refract()`](../glossary/?search=refract). Also GLSL has special vector relational functions such as: [`lessThan()`](../glossary/?search=lessThan), [`lessThanEqual()`](../glossary/?search=lessThanEqual), [`greaterThan()`](../glossary/?search=greaterThan), [`greaterThanEqual()`](../glossary/?search=greaterThanEqual), [`equal()`](../glossary/?search=equal) dan [`notEqual()`](../glossary/?search=notEqual).
Setelah kita mendapatkan sudut dan panjang, kita perlu "menormalkan" nilainya ke kisaran antara 0,0 hingga 1,0. Pada baris 27, [`atan(y, x)`](../glossary/?search=atan) akan mengembalikan sudut dalam radian antara -PI dan PI (-3.14 hingga 3.14), jadi kita perlu membagi angka ini oleh `TWO_PI` (didefinisikan di bagian atas kode) untuk mendapatkan nilai antara -0,5 hingga 0,5, yang dengan penambahan sederhana kita ubah ke kisaran yang diinginkan dari 0,0 hingga 1,0. Jari-jari akan mengembalikan maksimum 0,5 (karena kita menghitung jarak dari pusat viewport) jadi kita perlu menggandakan jarak ini (dengan mengalikan dua) untuk mendapatkan maksimum 1,0.
Seperti yang Anda lihat, permainan kami di sini adalah tentang mengubah dan memetakan rentang ke 0,0 hingga 1,0 yang kami sukai.
<div class = "codeAndCanvas" data = "hsb-colorwheel.frag"> </div>
Coba latihan berikut:
* Ubah contoh kutub untuk mendapatkan roda warna yang berputar, seperti ikon mouse menunggu.
* Gunakan fungsi pembentukan bersama dengan fungsi konversi dari HSB ke RGB untuk memperluas nilai rona tertentu dan mengecilkan sisanya.
![William Home Lizars - Spektrum merah, biru dan kuning, dengan spektrum matahari (1834)](spectrums.jpg)
* Jika Anda melihat lebih dekat pada roda warna yang digunakan pada pemilih warna (lihat gambar di bawah), mereka menggunakan spektrum yang berbeda sesuai dengan ruang warna RYB. Misalnya, warna kebalikan dari merah harus hijau, tetapi dalam contoh kita itu adalah cyan. Dapatkah Anda menemukan cara untuk memperbaikinya agar terlihat persis seperti gambar berikut? [Petunjuk: ini adalah momen yang tepat untuk menggunakan fungsi pembentukan.]
![](colorwheel.png)
* Baca [buku Josef Albers 'Interaction of Color](http://www.goodreads.com/book/show/111113.Interaction_of_Color) dan gunakan contoh shader berikut sebagai latihan.
<div class = "glslGallery" data = "160505191155,160505193939,160505200330,160509131554,160509131509,160509131420,160509131240" data-properties = "clickRun: editor, openFrameIcon: false, showAuthor: false"> </div>
#### Catatan tentang fungsi dan argumen
Sebelum melompat ke bab berikutnya, mari kita berhenti dan mundur. Kembali dan lihat fungsi di contoh sebelumnya. Anda akan melihat `in` sebelum jenis argumen. Ini adalah [*qualifier*](http://www.shaderific.com/glsl-qualifiers/#inputqualifier) dan dalam hal ini menetapkan bahwa variabel hanya-baca. Dalam contoh mendatang kita akan melihat bahwa dimungkinkan juga untuk mendefinisikan argumen sebagai `out` atau` inout`. Yang terakhir ini, `inout`, secara konseptual mirip dengan meneruskan argumen dengan referensi yang akan diberikan kami kemungkinan untuk memodifikasi variabel yang dilewatkan.
```glsl
int newFunction(in vec4 aVec4, // read-only
out vec3 aVec3, // write-only
inout int aInt); // read-write
```
Anda mungkin tidak percaya, tetapi sekarang kami memiliki semua elemen untuk membuat gambar yang keren. Pada bab selanjutnya kita akan belajar bagaimana menggabungkan semua trik kita untuk membuat bentuk geometris dengan * memadukan * ruang. Ya ... *memadukan* ruang.

@ -0,0 +1,223 @@
![Alice Hubbard, Providence, United States, ca. 1892. Photo: Zindman/Freemont.](froebel.jpg)
## Bentuk
Akhirnya! Kami telah membangun keterampilan untuk saat ini! Anda telah mempelajari sebagian besar fondasi, jenis, dan fungsi GLSL. Anda telah mempraktikkan persamaan pembentuk Anda berulang kali. Sekaranglah waktunya untuk menggabungkan semuanya. Anda siap untuk tantangan ini! Dalam bab ini Anda akan belajar cara menggambar bentuk sederhana dengan cara prosedural paralel.
### Persegi panjang
Bayangkan kita memiliki kertas grid seperti yang kita gunakan di kelas matematika dan pekerjaan rumah kita adalah menggambar persegi. Ukuran kertas adalah 10x10 dan persegi seharusnya 8x8. Apa yang akan kamu lakukan?
![](grid_paper.jpg)
Anda akan mengecat semuanya kecuali baris pertama dan terakhir dan kolom pertama dan terakhir, bukan?
Bagaimana ini berhubungan dengan shader? Setiap kotak kecil dari kertas kisi kami adalah thread (piksel). Setiap kotak kecil mengetahui posisinya, seperti koordinat papan catur. Di bab sebelumnya, kita memetakan *x* dan *y* ke saluran warna *merah* dan *hijau*, dan kita belajar cara menggunakan wilayah dua dimensi yang sempit antara 0,0 dan 1,0. Bagaimana kita bisa menggunakan ini untuk menggambar kotak di tengah di tengah papan reklame kita?
Mari kita mulai dengan membuat sketsa pseudocode yang menggunakan pernyataan `if` di atas bidang spasial. Prinsip untuk melakukan ini sangat mirip dengan bagaimana kita memikirkan skenario kertas grid.
```glsl
uniform vec2 u_resolution;
void main(){
vec2 st = gl_FragCoord.xy/u_resolution.xy;
vec3 color = vec3(0.0);
// Each result will return 1.0 (white) or 0.0 (black).
float left = step(0.1,st.x); // Similar to ( X greater than 0.1 )
float bottom = step(0.1,st.y); // Similar to ( Y greater than 0.1 )
// The multiplication of left*bottom will be similar to the logical AND.
color = vec3( left * bottom );
gl_FragColor = vec4(color,1.0);
}
```
Fungsi [`step()`](../glossary/?search=step) akan mengubah setiap piksel di bawah 0,1 menjadi hitam (`vec3(0,0)`) dan sisanya menjadi putih (`vec3(1.0)`). Perkalian antara `left` dan` bottom` berfungsi sebagai operasi logika `AND`, di mana keduanya harus bernilai 1,0 untuk mengembalikan 1,0. Ini menggambar dua garis hitam, satu di bagian bawah dan yang lainnya di sisi kiri kanvas.
![](rect-01.jpg)
Pada kode sebelumnya kami mengulangi struktur untuk setiap sumbu (kiri dan bawah). Kita dapat menyimpan beberapa baris kode dengan meneruskan dua nilai secara langsung ke [`step()`](../glossary/?search=step) alih-alih satu. Itu terlihat sperti ini:
```glsl
vec2 borders = step(vec2(0.1),st);
float pct = borders.x * borders.y;
```
Sejauh ini, kita hanya menggambar dua garis tepi (kiri bawah) dari persegi panjang kita. Mari lakukan dua lainnya (kanan atas). Lihat kode berikut:
<div class="codeAndCanvas" data="rect-making.frag"></div>
Hapus tanda komentar *baris 21-22* dan lihat bagaimana kita membalik koordinat `st` dan ulangi fungsi [`step()`](../glossary/?search=step) yang sama. Dengan begitu, `vec2(0.0,0.0)` akan berada di pojok kanan atas. Ini adalah persamaan digital dengan membalik halaman dan mengulangi prosedur sebelumnya.
![](rect-02.jpg)
Perhatikan bahwa dalam *baris 18 dan 22* semua sisinya akan dikalikan. Ini sama dengan menulis:
```glsl
vec2 bl = step(vec2(0.1),st); // bottom-left
vec2 tr = step(vec2(0.1),1.0-st); // top-right
color = vec3(bl.x * bl.y * tr.x * tr.y);
```
Menarik kan? Teknik ini adalah tentang penggunaan [`step()`](../glossary/?search=step) dan perkalian untuk operasi logika dan membalik koordinat.
Sebelum melanjutkan, cobalah latihan berikut:
* Ubah ukuran dan proporsi persegi panjang.
* Lakukan percobaan dengan kode yang sama tetapi menggunakan [`smoothstep ()`](../glossary/?search=smoothstep) daripada [`step()`](../glossary/?search=step). Perhatikan bahwa dengan mengubah nilai, Anda dapat beralih dari tepi yang buram ke tepi halus yang elegan.
* Lakukan implementasi lain yang menggunakan [`floor()`](../glossary/?search=floor).
* Pilih implementasi yang paling Anda sukai dan buat fungsinya yang dapat Anda gunakan kembali di masa mendatang. Jadikan fungsi Anda fleksibel dan efisien.
* Buat fungsi lain yang hanya menggambar garis bentuk persegi panjang.
* Menurut Anda, bagaimana Anda dapat memindahkan dan menempatkan persegi panjang yang berbeda di papan iklan yang sama? Jika Anda tahu caranya, tunjukkan keahlian Anda dengan membuat komposisi persegi panjang dan warna-warni yang menyerupai lukisan [Piet Mondrian](http://en.wikipedia.org/wiki/Piet_Mondrian).
![Piet Mondrian - Tableau (1921)](mondrian.jpg)
### Lingkaran
Sangat mudah untuk menggambar kotak pada kertas kisi dan persegi panjang pada koordinat kartesius, tetapi lingkaran memerlukan pendekatan lain, terutama karena kita memerlukan algoritme "per piksel". Salah satu solusinya adalah dengan * memetakan ulang * koordinat spasial sehingga kita dapat menggunakan fungsi [`step()`](../glossary/?search=step) untuk menggambar lingkaran.
Bagaimana? Mari kita mulai dengan kembali ke kelas matematika dan kertas kisi, di mana kita membuka kompas ke jari-jari lingkaran, menekan salah satu titik kompas di tengah lingkaran dan kemudian menelusuri tepi lingkaran dengan putaran sederhana.
![](compass.jpg)
Menerjemahkan ini ke shader di mana setiap kotak pada kertas kisi adalah piksel menyiratkan * menanyakan * setiap piksel (atau thread) apakah itu di dalam area lingkaran. Kami melakukan ini dengan menghitung jarak dari piksel ke pusat lingkaran.
![](circle.jpg)
Ada beberapa cara untuk menghitung jarak tersebut. Yang termudah menggunakan fungsi [`distance()`](../glossary/?search=distance), yang secara internal menghitung [`length()`](../glossary/?search=length) dari perbedaan antara dua titik (dalam kasus kami koordinat piksel dan pusat kanvas). Fungsi `length()` tidak lain adalah jalan pintas dari [persamaan sisi miring](http://en.wikipedia.org/wiki/Hypotenuse) yang menggunakan akar kuadrat ([`sqrt()`](../glosarium/?search=sqrt)) secara internal.
![](hypotenuse.png)
Anda dapat menggunakan [`distance()`](../glossary/?search=distance), [`length()`](../glossary/?search=length) atau [`sqrt()`](../glossary/?search=sqrt) untuk menghitung jarak ke pusat billboard. Kode berikut berisi tiga fungsi ini dan fakta yang tidak mengejutkan bahwa masing-masing mengembalikan hasil yang persis sama.
* Baris komentar dan hapus komentar untuk mencoba berbagai cara untuk mendapatkan hasil yang sama.
<div class="codeAndCanvas" data="circle-making.frag"></div>
Pada contoh sebelumnya kami memetakan jarak ke tengah papan reklame dengan kecerahan warna piksel. Semakin dekat sebuah piksel ke tengah, nilai yang lebih rendah (lebih gelap) dimilikinya. Perhatikan bahwa nilainya tidak terlalu tinggi karena dari pusat (`vec2(0,5, 0,5)`) jarak maksimum hampir tidak melebihi 0,5. Renungkan peta ini dan pikirkan:
* Apa yang dapat Anda simpulkan darinya?
* Bagaimana kita bisa menggunakan ini untuk menggambar lingkaran?
* Ubah kode di atas untuk memuat seluruh gradien melingkar di dalam kanvas.
### Bidang jarak
Kita juga bisa menganggap contoh di atas sebagai peta ketinggian, di mana lebih gelap berarti lebih tinggi. Gradien menunjukkan kepada kita sesuatu yang mirip dengan pola yang dibuat oleh kerucut. Bayangkan diri Anda berada di atas kerucut itu. Jarak horizontal ke tepi kerucut adalah 0,5. Ini akan konstan ke segala arah. Dengan memilih tempat untuk “memotong” kerucut, Anda akan mendapatkan permukaan lingkaran yang lebih besar atau lebih kecil.
![](jarak-bidang.jpg)
Pada dasarnya kami menggunakan interpretasi ulang ruang (berdasarkan jarak ke pusat) untuk membuat bentuk. Teknik ini dikenal sebagai "bidang jarak" dan digunakan dalam berbagai cara dari garis font hingga grafik 3D.
Coba latihan berikut:
* Gunakan [`step()`](../glossary/?search=step) untuk mengubah semua yang di atas 0,5 menjadi putih dan semua yang di bawah menjadi 0,0.
* Membalikkan warna latar belakang dan latar depan.
* Menggunakan [`smoothstep()`](../glossary/?search=smoothstep), bereksperimenlah dengan nilai yang berbeda untuk mendapatkan batas halus yang bagus di lingkaran Anda.
* Setelah Anda puas dengan implementasinya, buatlah fungsinya yang dapat Anda gunakan kembali di masa mendatang.
* Tambahkan warna pada lingkaran.
* Bisakah Anda menganimasikan lingkaran Anda untuk tumbuh dan menyusut, menirukan detak jantung? (Anda bisa mendapatkan inspirasi dari animasi di bab sebelumnya.)
* Bagaimana dengan memindahkan lingkaran ini? Bisakah Anda memindahkannya dan menempatkan lingkaran yang berbeda dalam satu papan iklan?
* Apa yang terjadi jika Anda menggabungkan bidang jarak bersama menggunakan fungsi dan operasi yang berbeda?
```glsl
pct = distance(st,vec2(0.4)) + distance(st,vec2(0.6));
pct = distance(st,vec2(0.4)) * distance(st,vec2(0.6));
pct = min(distance(st,vec2(0.4)),distance(st,vec2(0.6)));
pct = max(distance(st,vec2(0.4)),distance(st,vec2(0.6)));
pct = pow(distance(st,vec2(0.4)),distance(st,vec2(0.6)));
```
* Buat tiga komposisi menggunakan teknik ini. Jika dianimasikan, bahkan lebih baik!
#### Untuk kotak alat Anda
Dalam hal daya kompthreadi, fungsi [`sqrt()`](../glossary/?search=sqrt) - dan semua fungsi yang bergantung padanya - bisa jadi mahal. Berikut adalah cara lain untuk membuat bidang jarak melingkar dengan menggunakan perkalian [`dot()`](../glossary/?search=dot).
<div class="codeAndCanvas" data="circle.frag"></div>
### Properti yang berguna dari Bidang Jarak
![Zen garden](zen-garden.jpg)
Bidang jarak dapat digunakan untuk menggambar hampir semua hal. Jelas, semakin kompleks suatu bentuk, semakin rumit persamaannya, tetapi setelah Anda memiliki rumus untuk membuat bidang jarak dari bentuk tertentu, sangat mudah untuk menggabungkan dan / atau menerapkan efek padanya, seperti tepi halus dan beberapa garis tepi . Karenanya, kolom jarak menjadi populer dalam rendering font, seperti [Label GL Kotak Peta](https://blog.mapbox.com/drawing-text-with-signed-distance-fields-in-mapbox-gl-b0933af6f817), [Matt DesLauriers](https://twitter.com/mattdesl) [Font Desain Material](http://mattdesl.svbtle.com/material-design-on-the-gpu) dan [seperti yang di jelaskan di Bab 7 di buku Phone 3D Programming, OReilly](http://chimera.labs.oreilly.com/books/1234000001814/ch07.html#ch07_id36000921).
Perhatikan kode berikut.
<div class="codeAndCanvas" data="rect-df.frag"></div>
Kita mulai dengan memindahkan sistem koordinat ke tengah dan menyusutkannya menjadi dua untuk memetakan kembali nilai posisi antara -1 dan 1. Juga pada *baris 24* kita memvisualisasikan nilai bidang jarak menggunakan [`fract()`](../glossary/?search=fract) berfungsi memudahkan untuk melihat pola yang mereka buat. Pola bidang jarak berulang seperti cincin di taman Zen.
Mari kita lihat rumus bidang jarak pada *baris 19 *. Di sana kita menghitung jarak ke posisi pada `(.3, .3)` atau `vec3 (.3)` di keempat kuadran (itulah yang [`abs()`](../glossary/?search=abs) melakukannya di sana).
Jika Anda menghapus komentar *baris 20*, Anda akan melihat bahwa kami menggabungkan jarak ke empat titik ini menggunakan [`min()`](../glossary/?search=min) ke nol. Hasilnya menghasilkan pola baru yang menarik.
Sekarang coba hapus komentar *baris 21*; kita melakukan hal yang sama tetapi menggunakan fungsi [`max()`](../glossary/?search=max). Hasilnya adalah persegi panjang dengan sudut membulat. Perhatikan bagaimana cincin bidang jarak semakin halus semakin jauh dari pusat.
Selesaikan tanda komentar *baris 27 hingga 29* satu per satu untuk memahami perbedaan penggunaan pola bidang jarak.
### Bentuk kutub
![Robert Mangold - Untitled (2008)](mangold.jpg)
Pada bab tentang warna kita memetakan koordinat kartesian ke koordinat kutub dengan menghitung *radius* dan *sudut* dari setiap piksel dengan rumus berikut:
```glsl
vec2 pos = vec2(0.5)-st;
float r = length(pos)*2.0;
float a = atan(pos.y,pos.x);
```
Kami menggunakan bagian dari rumus ini di awal bab untuk menggambar lingkaran. Kami menghitung jarak ke pusat menggunakan [`length()`](../glossary/?search=length). Sekarang kita tahu tentang bidang jarak, kita dapat mempelajari cara lain untuk menggambar bentuk menggunakan koordinat kutub.
Teknik ini sedikit membatasi tetapi sangat sederhana. Ini terdiri dari mengubah jari-jari lingkaran tergantung pada sudut untuk mencapai bentuk yang berbeda. Bagaimana cara kerja modulasi? Ya, menggunakan fungsi pembentukan!
Di bawah ini Anda akan menemukan fungsi yang sama dalam grafik kartesius dan dalam contoh shader koordinat kutub (antara * baris 21 dan 25 *). Hapus tanda komentar fungsi satu per satu, perhatikan hubungan antara satu sistem koordinat dan sistem koordinat lainnya.
<div class="simpleFunction" data="y = cos(x*3.);
//y = abs(cos(x*3.));
//y = abs(cos(x*2.5))*0.5+0.3;
//y = abs(cos(x*12.)*sin(x*3.))*.8+.1;
//y = smoothstep(-.5,1., cos(x*10.))*0.2+0.5;"></div>
<div class="codeAndCanvas" data="polar.frag"></div>
Cobalah untuk:
* Animasikan bentuk-bentuk ini.
* Gabungkan berbagai fungsi pembentukan untuk *memotong lubang* dalam bentuk untuk membuat bunga, kepingan salju, dan roda gigi.
* Gunakan fungsi `plot()` yang kami gunakan di *Shaping Functions Chapter* untuk menggambar kontur saja.
### Menggabungkan kekuatan
Sekarang kita telah mempelajari cara memodulasi jari-jari lingkaran sesuai dengan sudut menggunakan [`atan()`](../glossary/?search=atan) untuk menggambar berbagai bentuk, kita dapat mempelajari cara menggunakan `atan()` dengan bidang jarak dan menerapkan semua trik dan efek yang mungkin dilakukan dengan bidang jarak.
Triknya akan menggunakan jumlah tepi poligon untuk membuat bidang jarak menggunakan koordinat kutub. Lihat [kode berikut](http://thndl.com/square-shaped-shaders.html) dari [Andrew Baldwin](https://twitter.com/baldand).
<div class="codeAndCanvas" data="shapes.frag"></div>
* Menggunakan contoh ini, buat fungsi yang memasukkan posisi dan jumlah sudut dari bentuk yang diinginkan dan mengembalikan nilai bidang jarak.
* Campurkan bidang jarak bersama-sama menggunakan [`min()`](../glossary/?search=min) dan [`max()`](../glossary/?search=max).
* Pilih logo geometris untuk direplikasi menggunakan bidang jarak.
Selamat! Anda telah berhasil melewati bagian yang sulit! Beristirahatlah dan biarkan konsep ini menyelesaikan - menggambar bentuk sederhana dalam Pemrosesan itu mudah tetapi tidak di sini. Dalam bentuk gambar tanah shader dipelintir, dan dapat melelahkan untuk beradaptasi dengan paradigma baru pengkodean ini.
Di bagian akhir bab ini, Anda akan menemukan tautan ke [PixelSpirit Deck](https://patriciogonzalezvivo.github.io/PixelSpiritDeck/) setumpuk kartu ini akan membantu Anda mempelajari fungsi SDF baru, menyusunnya ke dalam desain dan menggunakannya di shader Anda. Dek memiliki kurva belajar progresif, jadi mengambil satu kartu sehari dan mengerjakannya akan mendorong dan menantang keterampilan Anda selama berbulan-bulan.
Sekarang Anda tahu cara menggambar bentuk, saya yakin ide-ide baru akan muncul di benak Anda. Di bab berikut, Anda akan mempelajari cara memindahkan, memutar, dan mengatur skala bentuk. Ini akan memungkinkan Anda membuat komposisi!

@ -0,0 +1,102 @@
## Matriks 2D
<canvas id="custom" class="canvas" data-fragment-url="matrix.frag" width="700px" height="200px"></canvas>
### Translasi
Pada bab sebelumnya kita telah mempelajari cara membuat beberapa bentuk - trik untuk memindahkan bentuk tersebut adalah dengan memindahkan sistem koordinat itu sendiri. Kita bisa mencapainya hanya dengan menambahkan vektor ke variabel ```st``` yang berisi lokasi setiap fragmen. Ini menyebabkan seluruh sistem koordinat ruang bergerak.
![](translate.jpg)
Ini lebih mudah dilihat daripada dijelaskan, jadi lihat sendiri:
* Hapus komentar baris 35 dari kode di bawah ini untuk melihat bagaimana ruang itu sendiri bergerak.
<div class="codeAndCanvas" data="cross-translate.frag"></div>
Sekarang coba latihan berikut:
* Menggunakan ```u_time``` bersama dengan fungsi pembentuk memindahkan tanda silang kecil dengan cara yang menarik. Telusuri kualitas gerakan tertentu yang Anda minati dan cobalah melakukan gerakan silang dengan cara yang sama. Merekam sesuatu dari "dunia nyata" terlebih dahulu mungkin berguna - bisa saja gelombang datang dan pergi, gerakan pendulum, bola yang memantul, mobil yang sedang melaju, sepeda yang berhenti.
### Rotasi
Untuk memutar objek kita juga perlu memindahkan seluruh sistem ruang. Untuk itu kita akan menggunakan [matriks] (http://en.wikipedia.org/wiki/Matrix_%28mathematics%29). Matriks adalah kumpulan angka yang terorganisir dalam kolom dan baris. Vektor dikalikan dengan matriks mengikuti sekumpulan aturan yang tepat untuk mengubah nilai vektor dengan cara tertentu.
[![Wikipedia entry for Matrix (mathematics) ](matrixes.png)](https://en.wikipedia.org/wiki/Matrix)
GLSL memiliki dukungan native untuk dua, tiga, dan empat dimensi matriks: [```mat2```](../ glossary/?search=mat2) (2x2), [```mat3```](../glosarium/?search=mat3) (3x3) dan [``` mat4```](../glossary/?search=mat4) (4x4). GLSL juga mendukung perkalian matriks (```*```) dan fungsi spesifik matriks ([```matrixCompMult()```](../glossary/?search=matrixCompMult)).
Berdasarkan bagaimana matriks berperilaku, dimungkinkan untuk membangun matriks untuk menghasilkan perilaku tertentu. Misalnya kita dapat menggunakan matriks untuk menerjemahkan vektor:
![](3dtransmat.png)
Menariknya, kita bisa menggunakan matriks untuk memutar sistem koordinat:
![](rotmat.png)
Perhatikan kode berikut untuk fungsi yang menyusun matriks rotasi 2D. Fungsi ini mengikuti [rumus] (http://en.wikipedia.org/wiki/Rotation_matrix) di atas untuk vektor dua dimensi untuk memutar koordinat di sekitar titik ```vec2(0.0)```.
```glsl
mat2 rotate2d(float _angle){
return mat2(cos(_angle),-sin(_angle),
sin(_angle),cos(_angle));
}
```
Menurut cara kita menggambar bentuk, ini bukanlah yang kita inginkan. Bentuk silang kami digambar di tengah kanvas yang sesuai dengan posisi ```vec2(0,5)```. Jadi, sebelum kita memutar ruang kita perlu memindahkan bentuk dari `center` ke koordinat ```vec2(0.0)```, putar spasi, lalu pindahkan kembali ke tempat semula.
![](rotate.jpg)
Itu terlihat seperti kode berikut:
<div class="codeAndCanvas" data="cross-rotate.frag"></div>
Coba latihan berikut:
* Hapus tanda komentar baris 45 kode diatas dan perhatikan apa yang terjadi.
* Komentari terjemahan sebelum dan sesudah rotasi, pada baris 37 dan 39, dan amati konsekuensinya.
* Gunakan rotasi untuk meningkatkan animasi yang Anda simulasi dalam latihan penerjemahan.
### Skala
Kami telah melihat bagaimana matriks digunakan untuk menerjemahkan dan memutar objek di ruang angkasa. (Atau lebih tepatnya untuk mentransformasikan sistem koordinat untuk memutar dan memindahkan objek.) Jika Anda telah menggunakan perangkat lunak pemodelan 3D atau fungsi matriks push dan pop dalam Pemrosesan, Anda akan tahu bahwa matriks juga dapat digunakan untuk menskalakan ukuran sebuah obyek.
![](scale.png)
Mengikuti rumus sebelumnya, kita bisa mengetahui cara membuat matriks penskalaan 2D:
```glsl
mat2 scale(vec2 _scale){
return mat2(_scale.x,0.0,
0.0,_scale.y);
}
```
<div class="codeAndCanvas" data="cross-scale.frag"></div>
Cobalah latihan berikut untuk memahami lebih dalam cara kerjanya.
* Hapus komentar baris 42 kode di atas untuk melihat koordinat spasi sedang diskalakan.
* Lihat apa yang terjadi jika Anda mengomentari terjemahan sebelum dan sesudah penskalaan pada baris 37 dan 39.
* Coba gabungkan matriks rotasi bersama dengan matriks skala. Ketahuilah bahwa urutan itu penting. Kalikan dengan matriks terlebih dahulu lalu kalikan vektornya.
* Sekarang setelah Anda tahu cara menggambar berbagai bentuk, dan memindahkan, memutar, dan menskalakannya, sekarang saatnya membuat komposisi yang bagus. Mendesain dan membuat [UI atau HUD palsu (tampilan kepala ke atas)](https://www.pinterest.com/patriciogonzv/huds/). Gunakan contoh ShaderToy berikut oleh [Ndel](https://www.shadertoy.com/user/ndel) untuk inspirasi dan referensi.
<iframe width="800" height="450" frameborder="0" src="https://www.shadertoy.com/embed/4s2SRt?gui=true&t=10&paused=true" allowfullscreen></iframe>
### Kegunaan lain untuk matriks: Warna YUV
[YUV](http://en.wikipedia.org/wiki/YUV) adalah ruang warna yang digunakan untuk pengkodean analog foto dan video yang memperhitungkan jangkauan persepsi manusia untuk mengurangi bandwidth komponen chrominance.
Kode berikut adalah kesempatan menarik untuk menggunakan operasi matriks di GLSL untuk mengubah warna dari satu mode ke mode lainnya.
<div class="codeAndCanvas" data="yuv.frag"></div>
Seperti yang Anda lihat, kami memperlakukan warna sebagai vektor dengan mengalikannya dengan matriks. Dengan cara itu kita "memindahkan" nilai-nilai itu.
Dalam bab ini kita telah mempelajari bagaimana menggunakan transformasi matriks untuk memindahkan, memutar dan menskalakan vektor. Transformasi ini akan sangat penting untuk membuat komposisi dari bentuk yang telah kita pelajari di bab sebelumnya. Di bab selanjutnya kita akan menerapkan semua yang telah kita pelajari untuk membuat pola prosedural yang indah. Anda akan menemukan bahwa pengulangan dan variasi pengkodean bisa menjadi praktik yang menarik.

@ -0,0 +1,120 @@
## Pola
Karena program shader dijalankan oleh piksel demi piksel tidak peduli seberapa banyak Anda mengulang bentuk, jumlah kalkulasi tetap konstan. Ini berarti bahwa shader fragmen sangat cocok untuk pola ubin.
[ ![Nina Warmerdam - The IMPRINT Project (2013)](warmerdam.jpg) ](../edit.php#09/dots5.frag)
Dalam bab ini kita akan menerapkan apa yang telah kita pelajari sejauh ini dan mengulanginya di sepanjang kanvas. Seperti pada bab-bab sebelumnya, strategi kita akan didasarkan pada perkalian koordinat ruang (antara 0,0 dan 1,0), sehingga bentuk yang kita gambar di antara nilai 0,0 dan 1,0 akan diulang untuk membuat kisi.
*"Grid menyediakan kerangka kerja di mana intuisi dan penemuan manusia dapat beroperasi dan dapat menumbangkan. Dalam kekacauan pola alam memberikan batasan dan janji ketertiban. Dari pola awal pada tembikar hingga mosaik geometris di pemandian Romawi, orang sudah lama menggunakan kisi-kisi untuk meningkatkan kehidupan mereka dengan dekorasi. "* [*10 PRINT*, Mit Press, (2013)](http://10print.org/)
Pertama mari kita ingat fungsi [```fract()```](../glossary/?search=fract). Ini mengembalikan bagian pecahan dari sebuah angka, membuat ```fract()``` pada dasarnya adalah modulo dari satu ([```mod(x, 1.0)```](../glossary/?search=mod)). Dengan kata lain, [```fract()```](../glossary/?search=fract) mengembalikan angka setelah titik mengambang. Variabel sistem koordinat kami yang dinormalisasi (```st```) sudah berubah dari 0,0 menjadi 1,0 sehingga tidak masuk akal untuk melakukan sesuatu seperti:
```glsl
void main(){
vec2 st = gl_FragCoord.xy/u_resolution;
vec3 color = vec3(0.0);
st = fract(st);
color = vec3(st,0.0);
gl_FragColor = vec4(color,1.0);
}
```
Tetapi jika kita meningkatkan skala sistem koordinat yang dinormalisasi - katakanlah tiga - kita akan mendapatkan tiga urutan interpolasi linier antara 0-1: yang pertama antara 0-1, yang kedua untuk floating point antara 1-2 dan yang ketiga satu untuk floating point antara 2-3.
<div class="codeAndCanvas" data="grid-making.frag"></div>
Sekarang saatnya menggambar sesuatu di setiap subruang, dengan menghapus komentar pada baris 27. (Karena kita mengalikan dengan sama dalam x dan y, rasio aspek ruang tidak berubah dan bentuk akan seperti yang diharapkan.)
Cobalah beberapa latihan berikut untuk mendapatkan pemahaman yang lebih dalam:
* Kalikan spasi dengan angka yang berbeda. Coba dengan nilai floating point dan juga dengan nilai x dan y yang berbeda.
* Buat fungsi yang dapat digunakan kembali dari trik ubin ini.
* Bagilah ruang menjadi 3 baris dan 3 kolom. Temukan cara untuk mengetahui di kolom dan baris mana utas tersebut dan gunakan itu untuk mengubah bentuk yang ditampilkan. Cobalah untuk membuat pertandingan tic-tac-toe.
### Menerapkan matriks di dalam pola
Karena setiap subdivisi atau sel adalah versi yang lebih kecil dari sistem koordinat yang dinormalisasi yang telah kita gunakan, kita dapat menerapkan transformasi matriks padanya untuk menerjemahkan, memutar, atau menskalakan ruang di dalamnya.
<div class="codeAndCanvas" data="checks.frag"></div>
* Pikirkan cara-cara menarik untuk menghidupkan pola ini. Pertimbangkan untuk membuat animasi warna, bentuk, dan gerakan. Buat tiga animasi berbeda.
* Buat kembali pola yang lebih rumit dengan menyusun berbagai bentuk.
[![](diamondtiles-long.png)](../edit.php#09/diamondtiles.frag)
* Gabungkan berbagai lapisan pola untuk membuat [Pola Tartan Skotlandia] Anda sendiri [Scottish Tartan Patterns](https://www.google.com/search?q=scottish+patterns+fabric&tbm=isch&tbo=u&source=univ&sa=X&ei=Y1aFVfmfD9P-yQTLuYCIDA&ved=0CB4QsAQ&biw=1399&bih=799#tbm=isch&q=Scottish+Tartans+Patterns).
[ ![Vector Pattern Scottish Tartan By Kavalenkava](tartan.jpg) ](http://graphicriver.net/item/vector-pattern-scottish-tartan/6590076)
### Pola offset
Jadi katakanlah kita ingin meniru dinding bata. Melihat ke dinding, Anda dapat melihat setengah bata pada x di setiap baris lainnya. Bagaimana kita bisa melakukannya?
![](brick.jpg)
Sebagai langkah pertama kita perlu mengetahui apakah baris utas kita adalah bilangan genap atau ganjil, karena kita dapat menggunakannya untuk menentukan apakah kita perlu mengimbangi x di baris itu.
____kita harus memperbaiki dua paragraf berikutnya ini bersama-sama____
Untuk menentukan apakah utas kita berada di baris ganjil atau genap, kita akan menggunakan [```mod()```](../glossary/?search=mod) dari ```2.0``` dan kemudian lihat apakah hasilnya di bawah ```1.0``` atau tidak. Perhatikan rumus berikut dan hapus tanda komentar pada dua baris terakhir.
<div class="simpleFunction" data="y = mod(x,2.0);
// y = mod(x,2.0) < 1.0 ? 0. : 1. ;
// y = step(1.0,mod(x,2.0));"></div>
Seperti yang Anda lihat, kita dapat menggunakan [operator ternary](https://en.wikipedia.org/wiki/%3F:) untuk memeriksa apakah [```mod()```](../glossary/?search=mod) dari ```2.0``` berada di bawah ```1.0``` (baris kedua) atau serupa kita bisa menggunakan [```step()```](../glossary/?search=step) fungsi yang melakukan operasi yang sama, tetapi lebih cepat. Mengapa? Meskipun sulit untuk mengetahui bagaimana setiap kartu grafis mengoptimalkan dan mengkompilasi kodenya, dapat diasumsikan bahwa fungsi built-in lebih cepat daripada fungsi non-built-in. Setiap kali Anda dapat menggunakan fungsi bawaan, gunakanlah!
Jadi sekarang setelah kita memiliki rumus angka ganjil, kita dapat menerapkan offset ke baris ganjil untuk memberikan efek *bata* pada ubin kita. Baris 14 dari kode berikut adalah tempat kita menggunakan fungsi untuk "mendeteksi" baris ganjil dan memberinya offset setengah unit pada ```x```. Perhatikan bahwa untuk baris genap, hasil dari fungsi kita adalah ```0.0```, dan mengalikan ```0.0``` dengan offset ```0.5``` menghasilkan offset ```0.0```. Tapi pada baris ganjil kita mengalikan hasil dari fungsi kita, ```1.0```, dengan offset ```0.5```, yang menggerakkan sumbu ```x``` dari sistem koordinat dengan ```0,5```.
Sekarang coba hapus komentar pada baris 32 - ini memperluas rasio aspek dari sistem koordinat untuk meniru aspek "bata modern". Dengan menghapus komentar pada baris 40 Anda dapat melihat bagaimana sistem koordinat terlihat dipetakan menjadi merah dan hijau.
<div class="codeAndCanvas" data="bricks.frag"></div>
* Coba animasikan ini dengan menggerakkan offset menurut waktu.
* Buat animasi lain di mana baris genap pindah ke kiri dan baris ganjil pindah ke kanan.
* Dapatkah Anda mengulangi efek ini tetapi dengan kolom?
* Coba gabungkan offset pada sumbu ```x``` dan ```y``` untuk mendapatkan sesuatu seperti ini:
<a href="../edit.php#09/marching_dots.frag"><canvas id="custom" class="canvas" data-fragment-url="marching_dots.frag" width="520px" height="200px"></canvas></a>
## Ubin Truchet
Sekarang setelah kita belajar bagaimana mengetahui apakah sel kita berada di baris atau kolom genap atau ganjil, dimungkinkan untuk menggunakan kembali satu elemen desain tergantung pada posisinya. Pertimbangkan kasus [Truchet Tiles](http://en.wikipedia.org/wiki/Truchet_tiles) di mana satu elemen desain dapat disajikan dalam empat cara berbeda:
![](truchet-00.png)
Dengan mengubah pola di seluruh ubin, Anda dapat membuat serangkaian desain kompleks yang tak terbatas.
![](truchet-01.png)
Perhatikan baik-baik fungsi ```rotateTilePattern()```, yang membagi ruang menjadi empat sel dan menetapkan sudut rotasi untuk masing-masing sel.
<div class="codeAndCanvas" data="truchet.frag"></div>
* Beri komentar, hapus komentar, dan duplikat baris 69 hingga 72 untuk membuat desain baru.
* Ubah segitiga hitam dan putih untuk elemen lain seperti: setengah lingkaran, kotak atau garis yang diputar.
* Buat kode pola lain di mana elemen diputar sesuai dengan posisinya.
* Buat pola yang mengubah properti lainnya sesuai dengan posisi elemen.
* Pikirkan hal lain yang belum tentu merupakan pola di mana Anda dapat menerapkan asas-asas dari bagian ini. (Contoh: heksagram I Ching)
<a href="../edit.php#09/iching-01.frag"><canvas id="custom" class="canvas" data-fragment-url="iching-01.frag" width="520px" height="200px"></canvas></a>
## Membuat aturan Anda sendiri
Membuat pola prosedural adalah latihan mental dalam menemukan elemen minimal yang dapat digunakan kembali. Praktik ini sudah tua; Kita sebagai spesies telah lama menggunakan kisi dan pola untuk menghias tekstil, lantai, dan batas benda: dari pola berkelok-kelok di Yunani kuno, hingga desain kisi Cina, kesenangan akan pengulangan dan variasi menangkap imajinasi kita. Luangkan waktu untuk melihat [dekoratif](https://archive.org/stream/traditionalmetho00chririch#page/130/mode/2up) [pola](https://www.pinterest.com/patriciogonzv/paterns/) dan lihat bagaimana seniman dan desainer memiliki sejarah panjang dalam menavigasi tepi halus antara keteraturan yang dapat diprediksi dan kejutan variasi dan kekacauan. Dari pola geometris Arab, hingga desain kain Afrika yang indah, ada banyak sekali pola yang dapat dipelajari.
![Franz Sales Meyer - A handbook of ornament (1920)](geometricpatters.png)
Dengan bab ini kami mengakhiri bagian tentang Gambar Algoritmik. Dalam bab-bab berikut kita akan belajar bagaimana membawa beberapa entropi ke shader kita dan menghasilkan desain generatif.

@ -0,0 +1,92 @@
# Desain generatif
Tidaklah mengherankan bahwa setelah begitu banyak pengulangan dan keteraturan, penulis terpaksa membuat kekacauan.
## Acak
[![Ryoji Ikeda - test pattern (2008) ](ryoji-ikeda.jpg) ](http://www.ryojiikeda.com/project/testpattern/#testpattern_live_set)
Keacakan adalah ekspresi entropi maksimal. Bagaimana kita bisa menghasilkan keacakan di dalam lingkungan kode yang tampaknya dapat diprediksi dan kaku?
Mari kita mulai dengan menganalisis fungsi berikut:
<div class="simpleFunction" data="y = fract(sin(x)*1.0);"></div>
Di atas kami mengekstraksi konten pecahan dari gelombang sinus. Nilai [```sin()```](../glossary/?search=sin) yang berfluktuasi antara ```-1.0``` dan ```1.0``` telah dipotong di belakang floating point , mengembalikan semua nilai positif antara ```0,0``` dan ```1,0```. Kita dapat menggunakan efek ini untuk mendapatkan beberapa nilai pseudo-random dengan "memecah" gelombang sinus ini menjadi potongan-potongan yang lebih kecil. Bagaimana? Dengan mengalikan resultan dari [```sin(x)```](../glossary/?search=sin) dengan angka yang lebih besar. Silakan klik fungsi di atas dan mulai tambahkan beberapa angka nol.
Pada saat Anda masuk ke ```100000.0``` (dan persamaannya terlihat seperti ini: ```y = fract(sin(x)*100000.0)```) Anda tidak dapat membedakan gelombang sinus lebih. Granularitas bagian pecahan telah merusak aliran gelombang sinus menjadi kekacauan acak semu.
## Mengontrol kekacauan
Menggunakan acak bisa jadi sulit; keduanya terlalu kacau dan terkadang tidak cukup acak. Perhatikan grafik berikut. Untuk membuatnya, kami menggunakan fungsi ```rand()``` yang diimplementasikan persis seperti yang kami jelaskan di atas.
Melihat lebih dekat, Anda dapat melihat puncak gelombang [```sin()```](../glossary/?search=sin) di ```-1.5707``` dan ```1.5707``` . Saya yakin Anda sekarang mengerti mengapa - di situlah maksimum dan minimum gelombang sinus terjadi.
Jika melihat lebih dekat pada distribusi acak, Anda akan melihat bahwa terdapat konsentrasi di sekitar tengah dibandingkan dengan tepi.
<div class="simpleFunction" data="y = rand(x);
//y = rand(x)*rand(x);
//y = sqrt(rand(x));
//y = pow(rand(x),5.);"></div>
Beberapa waktu yang lalu [Pixelero](https://pixelero.wordpress.com) menerbitkan [artikel menarik tentang distribusi acak](https://pixelero.wordpress.com/2008/04/24/various-functions-and-various-distributions-with-mathrandom/). Saya telah menambahkan beberapa fungsi yang dia gunakan pada grafik sebelumnya untuk Anda mainkan dan lihat bagaimana distribusinya dapat diubah. Hapus tanda komentar pada fungsinya dan lihat apa yang terjadi.
Jika Anda membaca [artikel Pixelero](https://pixelero.wordpress.com/2008/04/24/various-functions-and-various-distributions-with-mathrandom/), penting untuk diingat bahwa Fungsi ``` rand()``` adalah deterministik acak, juga dikenal sebagai pseudo-random. Yang artinya misalnya ```rand (1.)``` akan selalu mengembalikan nilai yang sama. [Pixelero](https://pixelero.wordpress.com/2008/04/24/various-functions-and-various-distributions-with-mathrandom/) merujuk ke fungsi ActionScript ```Math.random ()``` yang non-deterministik; setiap panggilan akan mengembalikan nilai yang berbeda.
## 2D Acak
Sekarang setelah kita memiliki pemahaman yang lebih baik tentang keacakan, saatnya untuk menerapkannya dalam dua dimensi, ke sumbu ```x``` dan ```y```. Untuk itu diperlukan suatu cara untuk mengubah vektor dua dimensi menjadi nilai floating point satu dimensi. Ada cara berbeda untuk melakukan ini, tetapi fungsi [```dot()``](../glossary/?search=dot) sangat membantu dalam kasus ini. Ini mengembalikan satu nilai float antara ```0.0``` dan ```1.0``` tergantung pada penyelarasan dua vektor.
<div class="codeAndCanvas" data="2d-random.frag"></div>
Perhatikan baris 13 sampai 15 dan perhatikan bagaimana kita membandingkan ```vec2 st``` dengan vektor dua dimensi lainnya (```vec2(12.9898,78.233)```).
* Coba ubah nilai pada baris 14 dan 15. Lihat bagaimana pola acak berubah dan pikirkan tentang apa yang bisa kita pelajari dari ini.
* Kaitkan fungsi acak ini ke interaksi mouse (```u_mouse```) dan waktu (```u_time```) untuk lebih memahami cara kerjanya.
## Menggunakan kekacauan
Acak dalam dua dimensi sangat mirip dengan noise TV, bukan? Ini adalah bahan mentah yang sulit digunakan untuk membuat gambar. Mari belajar bagaimana memanfaatkannya.
Langkah pertama kita adalah menerapkan grid padanya; menggunakan fungsi [```floor()```](../glossary/?search=floor) kita akan menghasilkan tabel integer sel. Perhatikan kode berikut, khususnya baris 22 dan 23.
<div class="codeAndCanvas" data="2d-random-mosaic.frag"></div>
Setelah menskalakan ruang sebesar 10 (pada baris 21), kami memisahkan bilangan bulat koordinat dari bagian pecahan. Kami terbiasa dengan operasi terakhir ini karena kami telah menggunakannya untuk membagi spasi menjadi sel-sel yang lebih kecil dari ```0.0``` menjadi ```1.0```. Dengan mendapatkan bilangan bulat dari koordinat kami mengisolasi nilai umum untuk wilayah piksel, yang akan terlihat seperti sel tunggal. Kemudian kita dapat menggunakan bilangan bulat umum tersebut untuk mendapatkan nilai acak untuk area tersebut. Karena fungsi acak kita bersifat deterministik, nilai acak yang dikembalikan akan konstan untuk semua piksel di sel itu.
Hapus tanda komentar pada baris 29 untuk melihat bahwa kita mempertahankan bagian mengambang dari koordinat, jadi kita masih bisa menggunakannya sebagai sistem koordinat untuk menggambar sesuatu di dalam setiap sel.
Menggabungkan dua nilai ini - bagian bilangan bulat dan bagian pecahan dari koordinat - akan memungkinkan Anda untuk mencampur variasi dan urutan.
Lihatlah port GLSL dari ```10 PRINT CHR $ (205.5 + RND (1)) yang terkenal ini; : Generator labirin GOTO 10```.
<div class="codeAndCanvas" data="2d-random-truchet.frag"></div>
Di sini saya menggunakan nilai acak sel untuk menggambar garis dalam satu arah atau yang lain menggunakan fungsi ```truchetPattern ()``` dari bab sebelumnya (baris 41 hingga 47).
Anda bisa mendapatkan pola menarik lainnya dengan menghapus tanda komentar pada blok garis antara 50 hingga 53, atau menganimasikan pola dengan menghapus komentar pada baris 35 dan 36.
## Master Acak
[Ryoji Ikeda](http://www.ryojiikeda.com/), komposer elektronik dan seniman visual Jepang, telah menguasai penggunaan random; Sulit untuk tidak tersentuh dan terpesona oleh karyanya. Penggunaannya atas keacakan dalam media audio dan visual dipalsukan sedemikian rupa sehingga bukan kekacauan yang mengganggu melainkan cerminan dari kompleksitas budaya teknologi kita.
<iframe src="https://player.vimeo.com/video/76813693?title=0&byline=0&portrait=0" width="800" height="450" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
Lihatlah karya [Ikeda](http://www.ryojiikeda.com/) dan coba latihan berikut:
* Buat baris sel yang bergerak (dalam arah berlawanan) dengan nilai acak. Hanya tampilkan sel dengan nilai yang lebih cerah. Buat kecepatan baris berfluktuasi seiring waktu.
<a href="../edit.php#10/ikeda-00.frag"><canvas id="custom" class="canvas" data-fragment-url="ikeda-00.frag" width="520px" height="200px"></canvas></a>
* Demikian pula buat beberapa baris tetapi masing-masing dengan kecepatan dan arah yang berbeda. Kaitkan posisi mouse ke ambang batas sel yang akan ditampilkan.
<a href="../edit.php#10/ikeda-03.frag"><canvas id="custom" class="canvas" data-fragment-url="ikeda-03.frag" width="520px" height="200px"></canvas></a>
* Buat efek menarik lainnya.
<a href="../edit.php#10/ikeda-04.frag"><canvas id="custom" class="canvas" data-fragment-url="ikeda-04.frag" width="520px" height="200px"></canvas></a>
Menggunakan acak secara estetika bisa menjadi masalah, terutama jika Anda ingin membuat simulasi yang terlihat natural. Acak terlalu kacau dan sangat sedikit hal yang terlihat ```acak()``` dalam kehidupan nyata. Jika Anda melihat pada pola hujan atau grafik saham, yang keduanya cukup acak, keduanya tidak seperti pola acak yang kita buat di awal bab ini. Alasannya? Nah, nilai acak tidak memiliki korelasi di antara mereka apa pun, tetapi sebagian besar pola alami memiliki ingatan tentang keadaan sebelumnya.
Di bab berikutnya, kita akan belajar tentang noise, cara yang halus dan *terlihat alami* untuk menciptakan kekacauan komputasi.

@ -0,0 +1,218 @@
![NASA / WMAP science team](mcb.jpg)
## Noise
Waktunya istirahat! kita telah bermain dengan fungsi acak yang terlihat seperti derau putih TV, kepala kita masih berputar memikirkan shader, dan mata kita lelah. Waktunya jalan-jalan keluar!
kita merasakan udara di kulit kita, matahari di wajah kita. Dunia adalah tempat yang hidup dan kaya. Warna, tekstur, suara. Saat kita berjalan kita tidak dapat menghindari memperhatikan permukaan jalan, bebatuan, pepohonan dan awan.
![](texture-00.jpg)
![](texture-01.jpg)
![](texture-02.jpg)
![](texture-03.jpg)
![](texture-04.jpg)
![](texture-05.jpg)
![](texture-06.jpg)
Ketidakpastian tekstur ini bisa disebut "acak", tetapi tidak terlihat seperti acak yang kita mainkan sebelumnya. “Dunia nyata” adalah tempat yang kaya dan kompleks! Bagaimana kita bisa memperkirakan variasi ini secara komputasi?
Ini adalah pertanyaan yang coba dipecahkan oleh [Ken Perlin](https://mrl.nyu.edu/~perlin/) pada awal 1980-an ketika dia ditugaskan untuk menghasilkan tekstur yang lebih realistis untuk film "Tron". Menanggapi itu, dia datang dengan algoritma suara *pemenang Oscar* yang elegan. (Bukan masalah besar.)
![Disney - Tron (1982)](tron.jpg)
Berikut ini bukanlah algoritma derau Perlin klasik, tetapi ini adalah titik awal yang baik untuk memahami cara menghasilkan derau.
<div class="simpleFunction" data="
float i = floor(x); // integer
float f = fract(x); // fraction
y = rand(i); //rand() is described in the previous chapter
//y = mix(rand(i), rand(i + 1.0), f);
//y = mix(rand(i), rand(i + 1.0), smoothstep(0.,1.,f));
"></div>
Dalam baris ini kita melakukan sesuatu yang mirip dengan apa yang kita lakukan di bab sebelumnya. kita membagi bilangan mengambang kontinu (```x```) menjadi komponen bilangan bulat (```i```) dan pecahan (```f```). kita menggunakan [```floor()```](../glossary/?search=floor) untuk mendapatkan ```i``` dan [```fract()```](../glosarium/?search=fract) untuk mendapatkan ```f```. Kemudian kita menerapkan ```rand()``` ke bagian integer dari ```x```, yang memberikan nilai acak unik untuk setiap integer.
Setelah itu Anda melihat dua baris yang diberi komentar. Yang pertama menginterpolasi setiap nilai acak secara linier.
```glsl
y = mix(rand(i), rand(i + 1.0), f);
```
Lanjutkan dan hapus komentar pada baris ini untuk melihat tampilannya. kita menggunakan penyimpanan nilai [```fract()` ``](../glossary/?search=fract) di `f` hingga [```mix() ```](../glossary/?search=mix) dua nilai acak.
Pada poin di buku ini, kita telah belajar bahwa kita bisa melakukan lebih baik daripada interpolasi linier, bukan?
Sekarang coba hapus komentar pada baris berikut, yang menggunakan interpolasi [```smoothstep()```](../glossary/?search=smoothstep) alih-alih yang linier.
```glsl
y = mix(rand(i), rand(i + 1.0), smoothstep(0.,1.,f));
```
Setelah menghapus komentar, perhatikan bagaimana transisi antara puncak menjadi mulus. Dalam beberapa implementasi noise, Anda akan menemukan bahwa programmer lebih suka membuat kode kurva kubik mereka sendiri (seperti rumus berikut) daripada menggunakan [```smoothstep()```](../glossary/?search=smoothstep).
```glsl
float u = f * f * (3.0 - 2.0 * f ); // custom cubic curve
y = mix(rand(i), rand(i + 1.0), u); // using it in the interpolation
```
*Keacakan halus* ini adalah pengubah permainan untuk insinyur atau seniman grafis - ini memberikan kemampuan untuk menghasilkan gambar dan geometri dengan perasaan organik. Algoritma noise Perlin telah diterapkan berulang kali dalam berbagai bahasa dan dimensi untuk membuat karya yang memukau untuk semua jenis penggunaan kreatif.
![Robert Hodgin - Written Images (2010)](robert_hodgin.jpg)
Sekarang giliran Anda:
* Buat fungsi ```float noise(float x)``` Anda sendiri.
* Gunakan fungsi noise Anda untuk menganimasikan bentuk dengan memindahkannya, memutarnya, atau menskalakannya.
* Buat komposisi animasi dari beberapa bentuk 'menari' bersama menggunakan noise.
* Bangun bentuk "yang terlihat organik" menggunakan fungsi noise.
* Setelah Anda memiliki "makhluk" Anda, cobalah untuk mengembangkannya lebih jauh menjadi karakter dengan memberinya gerakan tertentu.
## Noise 2D
![](02.png)
Sekarang kita tahu bagaimana melakukan noise dalam 1D, sekarang saatnya beralih ke 2D. Dalam 2D, alih-alih melakukan interpolasi antara dua titik garis (```fract(x)``` dan ```fract(x)+1.0```), kita akan melakukan interpolasi di antara empat sudut persegi luas bidang (```fract(st)```, ```fract(st)+vec2(1.,0.)```, ```fract(st)+vec2(0.,1.)``` dan ```fract(st)+vec2(1.,1.)```).
![](01.png)
Demikian pula, jika kita ingin mendapatkan noise 3D, kita perlu melakukan interpolasi antara delapan sudut kubus. Teknik ini adalah tentang interpolasi nilai acak, itulah sebabnya disebut **noise nilai**.
![](04.jpg)
Seperti contoh 1D, interpolasi ini tidak linier tetapi kubik, yang dengan mulus menginterpolasi setiap titik di dalam kisi persegi kita.
![](05.jpg)
Perhatikan fungsi noise berikut.
<div class="codeAndCanvas" data="2d-noise.frag"></div>
Kita mulai dengan menskalakan ruang dengan 5 (baris 45) untuk melihat interpolasi antara kotak dari kisi. Kemudian di dalam fungsi noise kita membagi ruang menjadi sel. kita menyimpan posisi integer sel bersama dengan posisi pecahan di dalamn sel. kita menggunakan posisi integer untuk menghitung koordinat empat penjuru dan mendapatkan nilai acak untuk masing-masing (baris 23-26). Akhirnya, pada baris 35 kita melakukan interpolasi antara 4 nilai acak dari sudut menggunakan posisi pecahan yang kita simpan sebelumnya.
Sekarang giliranmu. Coba latihan berikut:
* Ubah pengali baris 45. Cobalah untuk menghidupkannya.
* Pada tingkat zoom berapa noise mulai terlihat seperti acak lagi?
* Pada tingkat zoom apakah noise tidak terlihat?
* Cobalah untuk menghubungkan fungsi noise ini ke koordinat mouse.
* Bagaimana jika kita memperlakukan gradien noise sebagai bidang jarak? Buatlah sesuatu yang menarik dengannya.
* Sekarang setelah Anda mencapai kendali atas keteraturan dan kekacauan, inilah saatnya untuk menggunakan pengetahuan itu. Buat komposisi persegi panjang, warna, dan derau yang menyerupai kerumitan lukisan [Mark Rothko](http://en.wikipedia.org/wiki/Mark_Rothko).
![Mark Rothko - Three (1950)](rothko.jpg)
## Menggunakan Noise dalam Desain Generatif
Algoritme noise pada awalnya dirancang untuk memberikan *je ne sais quoi* alami pada tekstur digital. Implementasi 1D dan 2D yang telah kita lihat sejauh ini adalah interpolasi antara nilai *acak*, itulah sebabnya disebut **Noise Nilai**, tetapi ada lebih banyak cara untuk mendapatkan noise ...
[ ![Inigo Quilez - Value Noise](value-noise.png) ](../edit.php#11/2d-vnoise.frag)
Seperti yang Anda temukan di latihan sebelumnya, noise nilai cenderung terlihat "kotak-kotak". Untuk mengurangi efek blok ini, pada tahun 1985 [Ken Perlin](https://mrl.nyu.edu/~perlin/) mengembangkan implementasi lain dari algoritme yang disebut **Gradient Noise**. Ken menemukan cara menginterpolasi *gradien* acak daripada nilai. Gradien ini adalah hasil dari fungsi acak 2D yang mengembalikan arah (diwakili oleh ```vec2```), bukan nilai tunggal (```float```). Klik pada gambar berikut untuk melihat kode dan cara kerjanya.
[ ![Inigo Quilez - Gradient Noise](gradient-noise.png) ](../edit.php#11/2d-gnoise.frag)
Luangkan waktu sejenak untuk melihat kedua contoh oleh [Inigo Quilez](http://www.iquilezles.org/) dan perhatikan perbedaan antara [value noise](https://www.shadertoy.com/view/ lsf3WH) dan [noise gradien](https://www.shadertoy.com/view/XdXGW8).
Seperti seorang pelukis yang memahami cara kerja pigmen pada catnya, semakin banyak yang kita ketahui tentang penerapan noise, semakin baik kita dapat menggunakannya. Misalnya, jika kita menggunakan implementasi noise dua dimensi untuk memutar ruang tempat garis lurus dirender, kita dapat menghasilkan efek swirly berikut yang terlihat seperti kayu. Sekali lagi Anda dapat mengklik gambar untuk melihat seperti apa kodenya.
[ ![Splatter texture](splatter-long.png) ](../edit.php#11/splatter.frag)
```glsl
color += smoothstep(.15,.2,noise(st*10.)); // Black splatter
color -= smoothstep(.35,.4,noise(st*10.)); // Holes on splatter
```
Cara lain untuk mendapatkan pola menarik dari noise adalah dengan memperlakukannya seperti bidang jarak dan menerapkan beberapa trik yang dijelaskan dalam [bab Bentuk](../07/).
[ ![Splatter texture](splatter-long.png) ](../edit.php#11/splatter.frag)
```glsl
color += smoothstep(.15,.2,noise(st*10.)); // Black splatter
color -= smoothstep(.35,.4,noise(st*10.)); // Holes on splatter
```
Cara ketiga menggunakan fungsi derau adalah memodulasi bentuk. Ini juga membutuhkan beberapa teknik yang kita pelajari di [bab tentang bentuk] (../ 07 /).
<a href="../edit.php#11/circleWave-noise.frag"><canvas id="custom" class="canvas" data-fragment-url="circleWave-noise.frag" width="300px" height="300"></canvas></a>
Untuk Anda berlatih:
* Pola generatif lain apa yang dapat Anda buat? Bagaimana dengan granit? marmer? magma? air? Temukan tiga gambar tekstur yang Anda minati dan terapkan secara algoritme menggunakan noise.
* Gunakan noise untuk memodulasi bentuk.
* Bagaimana dengan menggunakan noise untuk gerakan? Kembali ke [bab Matrix] (../08/). Gunakan contoh terjemahan yang menggerakkan "+", dan terapkan beberapa gerakan *acak* dan *gangguan* padanya.
* Buat Jackson Pollock generatif.
![Jackson Pollock - Number 14 gray (1948)](pollock.jpg)
## Peningkatan Noise
Peningkatan oleh Perlin ke noise non-simpleks aslinya **noise Simpleks**, adalah penggantian kurva Hermite kubik ( _f(x) = 3x^2-2x^3_, yang identik dengan fungsi [```smoothstep()```](../glossary/?search=smoothstep)) dengan kurva interpolasi kuintik ( _f(x) = 6x^5-15x^4+10x^3_ ). Hal ini membuat kedua ujung kurva lebih "rata" sehingga setiap tepi jahitan dengan anggun dengan ujung berikutnya. Dengan kata lain, Anda mendapatkan transisi yang lebih berkelanjutan antar sel. Anda dapat melihatnya dengan menghapus komentar rumus kedua pada contoh grafik berikut (atau lihat [dua persamaan berdampingan di sini] (https://www.desmos.com/calculator/2xvlk5xp8b)).
<div class="simpleFunction" data="
// Cubic Hermite Curve. Same as SmoothStep()
y = x*x*(3.0-2.0*x);
// Quintic interpolation curve
//y = x*x*x*(x*(x*6.-15.)+10.);
"></div>
Perhatikan bagaimana ujung kurva berubah. Anda dapat membaca lebih lanjut tentang ini di [Ken's own words](http://mrl.nyu.edu/~perlin/paper445.pdf)
## Noise Simpleks
Bagi Ken Perlin, keberhasilan algoritmanya tidak cukup. Dia pikir itu bisa bekerja lebih baik. Di Siggraph 2001 dia mempresentasikan "gangguan simpleks" di mana dia mencapai peningkatan berikut dari algoritme sebelumnya:
* Algoritme dengan kompleksitas komputasi yang lebih rendah dan perkalian yang lebih sedikit.
* noise yang berskala ke dimensi yang lebih tinggi dengan biaya komputasi yang lebih sedikit.
* Suara tanpa artefak arah.
* noise dengan gradien yang terdefinisi dengan baik dan berkelanjutan yang dapat dihitung dengan cukup murah.
* Algoritme yang mudah diterapkan di perangkat keras.
Saya tahu apa yang Anda pikirkan ... "Siapa pria ini?" Ya, karyanya luar biasa! Tapi serius, bagaimana dia meningkatkan algoritme? Nah, kita melihat bagaimana untuk dua dimensi dia menginterpolasi 4 titik (sudut persegi); jadi kita bisa menebak dengan benar bahwa untuk [tiga (lihat implementasinya di sini)](../edit.php#11/3d-noise.frag) dan empat dimensi kita perlu menginterpolasi 8 dan 16 poin. Baik? Dengan kata lain untuk dimensi N Anda perlu menginterpolasi 2 ke titik N(2^N) dengan mulus. Tetapi Ken dengan cerdas memperhatikan bahwa meskipun pilihan yang jelas untuk bentuk pengisi ruang adalah persegi, bentuk paling sederhana dalam 2D adalah segitiga sama sisi. Jadi dia mulai dengan mengganti kisi kuadrat (kita baru saja belajar cara menggunakannya) untuk kisi simpleks segitiga sama sisi.
![](simplex-grid-00.png)
Bentuk simpleks untuk dimensi N adalah bentuk dengan sudut N + 1. Dengan kata lain, satu sudut lebih sedikit untuk dihitung dalam 2D, 4 sudut lebih sedikit dalam 3D dan 11 sudut lebih sedikit dalam 4D! Itu peningkatan yang sangat besar!
Dalam dua dimensi, interpolasi terjadi serupa dengan noise biasa, dengan menginterpolasi nilai sudut suatu bagian. Namun dalam hal ini, dengan menggunakan grid simpleks, kita hanya perlu melakukan interpolasi dari jumlah 3 sudut saja.
![](simplex-grid-01.png)
Bagaimana jaringan simpleks dibuat? Dalam langkah brilian dan elegan lainnya, kisi simpleks dapat diperoleh dengan membagi sel-sel dari kisi bersudut 4 biasa menjadi dua segitiga sama kaki dan kemudian memiringkannya hingga setiap segitiga sama sisi.
![](simplex-grid-02.png)
Kemudian, seperti yang [Stefan Gustavson gambarkan dalam makalah ini](http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf): _"... dengan melihat bagian bilangan bulat dari koordinat yang ditransformasikan (x, y) untuk titik yang ingin kita evaluasi, kita dapat dengan cepat menentukan sel mana dari dua sederhana yang berisi titik. Dengan juga membandingkan besaran x dan y, kita dapat menentukan apakah titik tersebut ada di simplex atas atau bawah , dan melintasi tiga titik sudut yang benar. "_
Dalam kode berikut, Anda dapat menghapus komentar baris 44 untuk melihat bagaimana kisi miring, dan kemudian menghapus komentar baris 47 untuk melihat bagaimana kisi simpleks dapat dibangun. Perhatikan bagaimana pada baris 22 kita membagi persegi miring menjadi dua segitiga sama sisi hanya dengan mendeteksi jika ```x > y``` (segitiga "bawah ") atau````y > x``` (segitiga "atas").
<div class="codeAndCanvas" data="simplex-grid.frag"></div>
Semua peningkatan ini menghasilkan mahakarya algoritmik yang dikenal sebagai **Simplex Noise**. Berikut ini adalah implementasi GLSL dari algoritma ini yang dibuat oleh Ian McEwan dan Stefan Gustavson (dan disajikan dalam [makalah ini](http://webstaff.itn.liu.se/~stegu/jgt2012/article.pdf)) yang terlalu rumit untuk tujuan pendidikan, tetapi Anda akan dengan senang hati mengekliknya dan melihat bahwa itu kurang samar dari yang Anda harapkan, dan kodenya pendek dan cepat.
[ ![Ian McEwan of Ashima Arts - Simplex Noise](simplex-noise.png) ](../edit.php#11/2d-snoise-clear.frag)
Yah... cukup teknis, inilah saatnya Anda menggunakan sumber daya ini dengan cara ekspresif Anda sendiri:
* Renungkan bagaimana setiap implementasi noise terlihat. Bayangkan mereka sebagai bahan mentah, seperti batu marmer untuk pematung. Apa yang dapat Anda katakan tentang "perasaan" yang dimiliki masing-masing? Tutup mata Anda untuk memicu imajinasi Anda, seperti saat Anda ingin menemukan bentuk di awan. Apa yang kamu lihat? Anda diingatkan tentang apa? Menurut Anda, setiap implementasi noise dapat dibuat menjadi apa? Ikuti nyali Anda dan cobalah untuk mewujudkannya dalam kode.
* Buat shader yang memproyeksikan ilusi aliran. Seperti lampu lava, tetesan tinta, air, dll.
<a href="../edit.php#11/lava-lamp.frag"><canvas id="custom" class="canvas" data-fragment-url="lava-lamp.frag" width="520px" height="200px"></canvas></a>
* Gunakan Simplex Noise untuk menambahkan tekstur pada karya yang telah Anda buat.
<a href="../edit.php#11/iching-03.frag"><canvas id="custom" class="canvas" data-fragment-url="iching-03.frag" width="520px" height="520px"></canvas></a>
Dalam bab ini kita telah memperkenalkan beberapa kendali atas kekacauan. Itu bukanlah pekerjaan yang mudah! Menjadi ahli penyok noise membutuhkan waktu dan usaha.
Dalam bab-bab berikut, kita akan melihat beberapa teknik terkenal untuk menyempurnakan keterampilan Anda dan memaksimalkan noise Anda untuk merancang konten generatif berkualitas dengan shader. Sampai saat itu nikmati waktu di luar sambil merenungkan alam dan polanya yang rumit. Kemampuan Anda untuk mengamati membutuhkan dedikasi yang sama (atau mungkin lebih) daripada keterampilan membuat Anda. Pergilah keluar dan nikmati sisa hari ini!
<p style = "text-align: center; font-style: italic;"> "Bicaralah dengan pohon, bertemanlah dengannya." Bob Ross
</p>

@ -0,0 +1,192 @@
![](dragonfly.jpg)
## Noise Seluler
Pada tahun 1996, enam belas tahun setelah Kebisingan asli Perlin dan lima tahun sebelum Kebisingan Simplex, [Steven Worley menulis makalah berjudul "A Cellular Texture Basis Function"](http://www.rhythmiccanvas.com/research/papers/worley.pdf). Di dalamnya, ia menjelaskan teknik tekstur prosedural yang sekarang banyak digunakan oleh komunitas grafis.
Untuk memahami prinsip di baliknya kita perlu mulai berpikir dalam **iterasi**. Mungkin Anda tahu apa artinya: ya, mulailah menggunakan loop ```untuk```. Hanya ada satu tangkapan dengan loop ```untuk``` di GLSL: angka yang kami periksa harus berupa konstanta (```const```). Jadi, tidak ada loop dinamis - jumlah iterasi harus diperbaiki.
Mari kita lihat contohnya.
### Poin untuk bidang jarak
Noise Seluler didasarkan pada bidang jarak, jarak ke yang terdekat dari serangkaian titik fitur. Katakanlah kita ingin membuat bidang jarak dari 4 titik. Apa yang harus kita lakukan? Nah, **untuk setiap piksel kami ingin menghitung jarak ke titik terdekat**. Itu berarti kita perlu mengulangi semua titik, menghitung jaraknya ke piksel saat ini dan menyimpan nilai untuk yang terdekat.
```glsl
float min_dist = 100.; // A variable to store the closest distance to a point
min_dist = min(min_dist, distance(st, point_a));
min_dist = min(min_dist, distance(st, point_b));
min_dist = min(min_dist, distance(st, point_c));
min_dist = min(min_dist, distance(st, point_d));
```
![](cell-00.png)
Ini tidak terlalu elegan, tetapi berhasil. Sekarang mari kita implementasikan ulang menggunakan array dan loop ```for```.
```glsl
float m_dist = 100.; // minimum distance
for (int i = 0; i < TOTAL_POINTS; i++) {
float dist = distance(st, points[i]);
m_dist = min(m_dist, dist);
}
```
Perhatikan bagaimana kita menggunakan loop ```for``` untuk mengulang melalui larik titik dan melacak jarak minimum menggunakan [```min()```](../glossary/?search=min) fungsi. Berikut adalah implementasi kerja singkat dari gagasan ini:
<div class="codeAndCanvas" data="cellnoise-00.frag"></div>
Dalam kode di atas, salah satu titik ditetapkan ke posisi mouse. Mainkan dengan itu sehingga Anda bisa mendapatkan ide intuitif tentang bagaimana kode ini berperilaku. Kemudian coba ini:
- Bagaimana Anda bisa menghidupkan poin lainnya?
- Setelah membaca [bab tentang bentuk](../07/), bayangkan cara menarik menggunakan bidang jarak ini!
- Bagaimana jika Anda ingin menambahkan lebih banyak titik ke bidang jarak ini? Bagaimana jika kita ingin menambah / mengurangi poin secara dinamis?
### Tile dan Iterasi
Anda mungkin memperhatikan bahwa loop ```for``` dan *array* tidak terlalu berteman baik dengan GLSL. Seperti yang kami katakan sebelumnya, loop tidak menerima batas dinamis pada kondisi keluarnya. Selain itu, melakukan iterasi melalui banyak contoh akan mengurangi kinerja shader Anda secara signifikan. Itu berarti kita tidak dapat menggunakan pendekatan langsung ini untuk poin dalam jumlah besar. Kita perlu menemukan strategi lain, yang memanfaatkan arsitektur pemrosesan paralel dari GPU.
![](cell-01.png)
Salah satu cara untuk mengatasi masalah ini adalah dengan membagi ruang menjadi tile. Tidak setiap piksel perlu memeriksa jarak ke setiap titik, bukan? Mengingat fakta bahwa setiap piksel berjalan di utasnya sendiri, kita dapat membagi ruang menjadi sel, masing-masing dengan satu titik unik untuk diperhatikan. Selain itu, untuk menghindari penyimpangan di tepi antar sel, kita perlu memeriksa jarak ke titik di sel tetangga. Itulah gagasan cemerlang utama dari [makalah Steven Worley](http://www.rhythmiccanvas.com/research/papers/worley.pdf). Pada akhirnya, setiap piksel hanya perlu memeriksa sembilan posisi: titik selnya sendiri dan titik di 8 sel di sekitarnya. Kami sudah membagi ruang menjadi sel di bab-bab tentang: [pola](../09/), [acak](../10/) dan [noise](../11/), jadi semoga Anda sudah terbiasa dengan teknik ini sekarang.
```glsl
// Scale
st *= 3.;
// Tile the space
vec2 i_st = floor(st);
vec2 f_st = fract(st);
```
Jadi apa rencananya? Kami akan menggunakan koordinat petak (disimpan dalam koordinat bilangan bulat, ```i_st```) untuk membangun posisi acak suatu titik. Fungsi ```random2f``` yang akan kita gunakan menerima ```vec2``` dan memberi kita ```vec2``` dengan posisi acak. Jadi, untuk setiap tile kita akan memiliki satu titik fitur dalam posisi acak di dalam tile.
```glsl
vec2 point = random2(i_st);
```
Setiap piksel di dalam petak itu (disimpan dalam koordinat float, ```f_st```) akan memeriksa jaraknya ke titik acak itu.
```glsl
vec2 diff = point - f_st;
float dist = length(diff);
```
Hasilnya akan terlihat seperti ini:
<a href="../edit.php#12/cellnoise-01.frag"><img src="cellnoise.png" width="520px" height="200px"></img></a>
Kami masih perlu memeriksa jarak ke titik-titik di tile sekitarnya, bukan hanya yang ada di tile saat ini. Untuk itu kita perlu **iterasi** melalui tile tetangga. Tidak semua tile, hanya yang tepat di sekitar tile saat ini. Artinya, dari petak ```-1``` (kiri) ke ```1``` (kanan) dalam sumbu ```x``` dan ```-1``` (bottom) menjadi ```1``` (atas) dalam sumbu ```y```. Wilayah 3x3 dengan 9 petak dapat diiterasi menggunakan pengulangan ```for``` ganda seperti ini:
```glsl
for (int y= -1; y <= 1; y++) {
for (int x= -1; x <= 1; x++) {
// Neighbor place in the grid
vec2 neighbor = vec2(float(x),float(y));
...
}
}
```
![](cell-02.png)
Sekarang, kita dapat menghitung posisi titik pada masing-masing tetangga di loop ganda ```for``` dengan menambahkan offset tile tetangga ke koordinat tile saat ini.
```glsl
...
// Random position from current + neighbor place in the grid
vec2 point = random2(i_st + neighbor);
...
```
Selebihnya adalah tentang menghitung jarak ke titik itu dan menyimpan yang terdekat dalam variabel yang disebut ```m_dist``` (untuk jarak minimum).
```glsl
...
vec2 diff = neighbor + point - f_st;
// Distance to the point
float dist = length(diff);
// Keep the closer distance
m_dist = min(m_dist, dist);
...
```
Kode di atas terinspirasi oleh [artikel ini oleh Inigo's Quilez](http://www.iquilezles.org/www/articles/smoothvoronoi/smoothvoronoi.htm) di mana dia berkata:
*"... mungkin perlu diperhatikan bahwa ada trik bagus dalam kode ini di atas. Sebagian besar implementasi di luar sana mengalami masalah presisi, karena mereka menghasilkan titik acak mereka dalam ruang" domain "(seperti ruang "dunia" atau "objek "), yang dapat secara sewenang-wenang jauh dari asalnya. Seseorang dapat menyelesaikan masalah memindahkan semua kode ke tipe data presisi lebih tinggi, atau dengan menjadi sedikit pintar. Implementasi saya tidak menghasilkan poin dalam ruang "domain", tetapi di "sel "spasi: setelah bagian bilangan bulat dan pecahan dari titik bayangan diekstraksi dan oleh karena itu sel tempat kami bekerja diidentifikasi, yang kami pedulikan adalah apa yang terjadi di sekitar sel ini, yang berarti kami dapat membuang semua bagian bilangan bulat dari koordinat kami semua bersama-sama, menyimpan banyak bit presisi. Faktanya, dalam implementasi voronoi biasa, bagian bilangan bulat dari koordinat titik hanya meniadakan ketika titik fitur acak per sel dikurangi dari titik bayangan. Dalam penerapan di atas, kami bahkan tidak membiarkan tongkat itu lation terjadi, karena kita memindahkan semua komputasi ke ruang "sel". Trik ini juga memungkinkan seseorang untuk menangani kasus di mana Anda ingin voronoi-shade seluruh planet - seseorang dapat dengan mudah mengganti input menjadi presisi ganda, melakukan perhitungan floor() dan fract(), dan pergi floating point dengan sisa perhitungan tanpa membayar biaya untuk mengubah seluruh implementasi menjadi presisi ganda. Tentu saja, trik yang sama berlaku untuk pola Perlin Noise (tetapi saya belum pernah melihatnya diterapkan atau didokumentasikan di mana pun)."*
Rekapitulasi: kami membagi ruang menjadi tile; setiap piksel akan menghitung jarak ke titik di tile mereka sendiri dan 8 tile sekitarnya; simpan jarak terdekat. Hasilnya adalah bidang jarak yang terlihat seperti contoh berikut:
<div class="codeAndCanvas" data="cellnoise-02.frag"></div>
Jelajahi lebih jauh dengan:
- Penskalaan ruang dengan nilai yang berbeda.
- Dapatkah Anda memikirkan cara lain untuk menghidupkan poin?
- Bagaimana jika kita ingin menghitung titik ekstra dengan posisi mouse?
- Cara lain apa untuk membangun bidang jarak ini yang dapat Anda bayangkan, selain ```m_dist=min(m_dist, dist);```?
- Pola menarik apa yang dapat Anda buat dengan bidang jarak ini?
Algoritma ini juga dapat diinterpretasikan dari perspektif titik dan bukan piksel. Dalam hal itu dapat digambarkan sebagai: setiap titik tumbuh hingga menemukan area tumbuh dari titik lain. Ini mencerminkan beberapa aturan pertumbuhan di alam. Bentuk kehidupan dibentuk oleh ketegangan antara kekuatan dalam untuk berkembang dan tumbuh, dan batasan oleh kekuatan luar. Algoritme klasik yang menyimulasikan perilaku ini dinamai [Georgy Voronoi] (https://en.wikipedia.org/wiki/Georgy_Voronoy).
![](monokot_root.jpg)
### Algoritma Voronoi
Membuat diagram Voronoi dari kebisingan seluler tidak sesulit kelihatannya. Kami hanya perlu *menyimpan* beberapa informasi tambahan tentang titik persis yang paling dekat dengan piksel. Untuk itu kita akan menggunakan ```vec2``` yang disebut ```m_point```. Dengan menyimpan arah vektor ke pusat titik terdekat, bukan hanya jarak, kita akan "menyimpan" pengenal "unik" dari titik tersebut.
```glsl
...
if( dist < m_dist ) {
m_dist = dist;
m_point = point;
}
...
```
Perhatikan bahwa dalam kode berikut ini kita tidak lagi menggunakan ```min``` untuk menghitung jarak terdekat, tetapi pernyataan ```if``` biasa. Mengapa? Karena sebenarnya kita ingin melakukan sesuatu yang lebih setiap kali muncul titik dekat baru, yaitu menyimpan posisinya (baris 32 sampai 37).
<div class="codeAndCanvas" data="vorono-00.frag"></div>
Perhatikan bagaimana warna sel yang bergerak (terikat pada posisi mouse) berubah warna sesuai dengan posisinya. Itu karena warna ditetapkan menggunakan nilai (posisi) titik terdekat.
Seperti yang kami lakukan sebelumnya, sekarang adalah waktu untuk meningkatkan ini, beralih ke [pendekatan makalah Steven Worley](http://www.rhythmiccanvas.com/research/papers/worley.pdf). Coba terapkan sendiri. Anda dapat menggunakan bantuan contoh berikut dengan mengkliknya. Perhatikan bahwa pendekatan asli Steven Worley menggunakan sejumlah variabel poin fitur untuk setiap tile, lebih dari satu di sebagian besar tile. Dalam implementasi perangkat lunaknya di C, ini digunakan untuk mempercepat loop dengan membuat keluar lebih awal. Loop GLSL tidak mengizinkan jumlah variabel iterasi, jadi Anda mungkin ingin tetap menggunakan satu titik fitur per tile.
<a href="../edit.php#12/vorono-01.frag"><canvas id="custom" class="canvas" data-fragment-url="vorono-01.frag" width="520px" height="200px"></canvas></a>
Setelah Anda mengetahui algoritme ini, pikirkan kegunaan yang menarik dan kreatif untuknya.
![Extended Voronoi - Leo Solaas (2011)](solas.png)
![Cloud Cities - Tomás Saraceno (2011)](saraceno.jpg)
![Accretion Disc Series - Clint Fulkerson](accretion.jpg)
![Vonoroi Puzzle - Reza Ali (2015)](reza.png)
### Meningkatkan Voronoi
Pada tahun 2011, [Stefan Gustavson mengoptimalkan algoritme Steven Worley ke GPU](http://webstaff.itn.liu.se/~stegu/GLSL-cellular/GLSL-cellular-notes.pdf) dengan hanya melakukan iterasi melalui matriks 2x2 alih-alih 3x3. Ini mengurangi jumlah pekerjaan secara signifikan, tetapi dapat membuat artefak dalam bentuk diskontinuitas di tepi antara tile. Lihat contoh berikut.
<div class="glslGallery" data="12/2d-cnoise-2x2,12/2d-cnoise-2x2x2,12/2d-cnoise,12/3d-cnoise" data-properties="clickRun:editor,openFrameIcon:false"></div>
Kemudian pada tahun 2012 [Inigo Quilez menulis artikel tentang cara membuat perbatasan Voronoi yang tepat](http://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm).
<a href="../edit.php#12/2d-voronoi.frag"><img src="2d-voronoi.gif" width="520px" height="200px"></img></a>
Eksperimen Inigo dengan Voronoi tidak berhenti sampai di situ. Pada tahun 2014 dia menulis artikel bagus ini tentang apa yang dia sebut [voro-noise](http://www.iquilezles.org/www/articles/voronoise/voronoise.htm), sebuah fungsi yang memungkinkan perpaduan bertahap antara noise biasa dan voronoi . Dalam kata-katanya:
*"Terlepas dari kesamaan ini, kenyataannya adalah bahwa cara grid digunakan di kedua pola berbeda. Noise interpolates/rata-rata nilai acak (seperti dalam noise nilai) atau gradien (seperti dalam noise gradien), sementara Voronoi menghitung jarak ke titik fitur terdekat. Sekarang, interpolasi halus-bilinear dan evaluasi minimum adalah dua operasi yang sangat berbeda, atau... benarkah? Bisakah keduanya digabungkan dalam metrik yang lebih umum? Jika demikian, pola Noise dan Voronoi bisa jadi dilihat sebagai kasus tertentu dari generator pola berbasis jaringan yang lebih umum?"*
<a href="../edit.php#12/2d-voronoise.frag"><canvas id="custom" class="canvas" data-fragment-url="2d-voronoise.frag" width="520px" height="200px"></canvas></a>
Sekarang saatnya bagi Anda untuk melihat lebih dekat pada berbagai hal, terinspirasi oleh alam, dan menemukan cara Anda sendiri dalam menggunakan teknik ini!
![Deyrolle glass film - 1831](DeyrolleFilm.png)
<div class="glslGallery" data="12/metaballs,12/stippling,12/cell,12/tissue,12/cracks,160504143842" data-properties="clickRun:editor,openFrameIcon:false"></div>

@ -0,0 +1,111 @@
![Due East over Shadequarter Mountain - Matthew Rangel (2005) ](rangel.jpg)
## Gerak Pecahan Brownian
Noise cenderung memiliki arti yang berbeda bagi orang yang berbeda. Musisi akan menganggapnya dalam istilah suara yang mengganggu, komunikator sebagai interferensi, dan astrofisikawan sebagai radiasi latar gelombang mikro kosmik. Konsep-konsep ini membawa kita kembali ke alasan fisik di balik keacakan di dunia sekitar kita. Namun, mari kita mulai dengan sesuatu yang lebih mendasar, dan lebih sederhana: gelombang dan propertinya. Gelombang adalah fluktuasi dari waktu ke waktu pada beberapa properti. Gelombang audio adalah fluktuasi tekanan udara, gelombang elektromagnetik adalah fluktuasi medan listrik dan magnet. Dua karakteristik penting dari sebuah gelombang adalah amplitudo dan frekuensinya. Persamaan untuk gelombang linier sederhana (satu dimensi) terlihat seperti ini:
<div class="simpleFunction" data="
float amplitude = 1.;
float frequency = 1.;
y = amplitude * sin(x * frequency);
"></div>
* Coba ubah nilai frekuensi dan amplitudo untuk memahami bagaimana perilakunya.
* Dengan menggunakan fungsi pembentukan, coba ubah amplitudo dari waktu ke waktu.
* Dengan menggunakan fungsi pembentukan, coba ubah frekuensi dari waktu ke waktu.
Dengan melakukan dua latihan terakhir Anda telah berhasil "memodulasi" gelombang sinus, dan Anda baru saja membuat gelombang AM (amplitudo termodulasi) dan FM (frekuensi termodulasi). Selamat!
Sifat lain yang menarik dari gelombang adalah kemampuannya untuk menjumlahkan, yang secara resmi disebut superposisi. Beri komentar/hapus komentar dan atur baris berikut. Perhatikan bagaimana tampilan keseluruhan berubah saat kita menambahkan gelombang dengan amplitudo dan frekuensi yang berbeda secara bersamaan.
<div class="simpleFunction" data="
float amplitude = 1.;
float frequency = 1.;
y = sin(x * frequency);
float t = 0.01*(-u_time*130.0);
y += sin(x*frequency*2.1 + t)*4.5;
y += sin(x*frequency*1.72 + t*1.121)*4.0;
y += sin(x*frequency*2.221 + t*0.437)*5.0;
y += sin(x*frequency*3.1122+ t*4.269)*2.5;
y *= amplitude*0.06;
"></div>
* Percobaan dengan mengubah frekuensi dan amplitudo untuk gelombang tambahan.
* Apakah mungkin membuat dua gelombang membatalkan satu sama lain? Akan terlihat seperti apa?
* Apakah mungkin menambahkan gelombang sedemikian rupa sehingga mereka akan memperkuat satu sama lain?
Dalam musik, setiap not dikaitkan dengan frekuensi tertentu. Frekuensi untuk nada-nada ini mengikuti pola yang kita sebut skala, di mana penggandaan atau separuh frekuensi sesuai dengan lompatan satu oktaf.
Sekarang, mari gunakan noise Perlin sebagai ganti gelombang sinus! Derau Perlin dalam bentuk dasarnya memiliki tampilan dan nuansa umum yang sama dengan gelombang sinus. Amplitudo dan frekuensinya agak bervariasi, tetapi amplitudonya tetap cukup konsisten, dan frekuensi dibatasi pada kisaran yang cukup sempit di sekitar frekuensi tengah. Ini tidak teratur seperti gelombang sinus, dan lebih mudah untuk membuat tampilan acak dengan merangkum beberapa versi skala noise. Dimungkinkan juga untuk membuat sejumlah gelombang sinus tampak acak juga, tetapi dibutuhkan banyak gelombang berbeda untuk menyembunyikan sifat berkala dan teraturnya.
Dengan menambahkan iterasi yang berbeda dari noise (*oktaf*), di mana kami secara berturut-turut meningkatkan frekuensi dalam langkah-langkah reguler (*lacunaritas*) dan menurunkan amplitudo (*penguatan/gain*) dari **noise** kita dapat memperoleh perincian yang lebih halus di noise dan dapatkan detail yang lebih halus. Teknik ini disebut "Gerak Pecahan Brownian" (*GPB*), atau sederhananya "gangguan fraktal", dan dalam bentuk yang paling sederhana dapat dibuat dengan kode berikut:
<div class="simpleFunction" data="// Properties
const int octaves = 1;
float lacunarity = 2.0;
float gain = 0.5;
//
// Initial values
float amplitude = 0.5;
float frequency = 1.;
//
// Loop of octaves
for (int i = 0; i < octaves; i++) {
&#9;y += amplitude * noise(frequency*x);
&#9;frequency *= lacunarity;
&#9;amplitude *= gain;
}"></div>
* Ubah jumlah oktaf secara bertahap untuk mengulang dari 1 ke 2, 4, 8 dan 10. Lihat apa yang terjadi.
* Jika Anda memiliki lebih dari 4 oktaf, coba ubah nilai lacunarity.
* Juga dengan> 4 oktaf, ubah nilai penguatan dan lihat apa yang terjadi.
Perhatikan bagaimana dengan setiap oktaf tambahan, kurva tampaknya menjadi lebih detail. Perhatikan juga kemiripan diri sementara lebih banyak oktaf ditambahkan. Jika Anda memperbesar kurva, bagian yang lebih kecil terlihat hampir sama dengan keseluruhannya, dan setiap bagian terlihat kurang lebih sama seperti bagian lainnya. Ini adalah properti penting dari fraktal matematika, dan kami mensimulasikan properti itu dalam loop kami. Kami tidak membuat fraktal *benar*, karena kami menghentikan penjumlahan setelah beberapa iterasi, tetapi secara teoritis, kami akan mendapatkan fraktal matematika yang sebenarnya jika kami membiarkan loop berlanjut selamanya dan menambahkan komponen noise dalam jumlah tak terbatas. Dalam grafik komputer, kita selalu memiliki batasan hingga detail terkecil yang dapat kita selesaikan, misalnya ketika objek menjadi lebih kecil dari piksel, jadi tidak perlu membuat jumlah tak terbatas untuk membuat tampilan fraktal. Terkadang banyak istilah mungkin diperlukan, tetapi tidak pernah dalam jumlah yang tak terbatas.
Kode berikut adalah contoh bagaimana GPB dapat diimplementasikan dalam dua dimensi untuk membuat pola yang tampak fraktal:
<div class='codeAndCanvas' data='2d-fbm.frag'></div>
* Kurangi jumlah oktaf dengan mengubah nilai pada baris 37
* Modifikasi lacunarity dari GPB di baris 47
* Jelajahi dengan mengubah keuntungan di baris 48
Teknik ini biasanya digunakan untuk membangun lanskap prosedural. Kemiripan diri dari GPB sangat cocok untuk pegunungan, karena proses erosi yang menciptakan gunung bekerja dengan cara yang menghasilkan jenis kemiripan diri ini di berbagai skala. Jika Anda tertarik dengan penggunaan ini, Anda harus membaca [artikel hebat ini oleh Inigo Quiles tentang noise tingkat lanjut](http://www.iquilezles.org/www/articles/morenoise/morenoise.htm).
![Blackout - Dan Holdsworth (2010)](holdsworth.jpg)
Menggunakan teknik yang kurang lebih sama, juga memungkinkan untuk mendapatkan efek lain seperti yang dikenal sebagai **turbulensi**. Ini pada dasarnya adalah GPB, tetapi dibangun dari nilai absolut dari suara yang ditandatangani untuk menciptakan lembah yang tajam dalam fungsinya.
```glsl
for (int i = 0; i < OCTAVES; i++) {
value += amplitude * abs(snoise(st));
st *= 2.;
amplitude *= .5;
}
```
<a href="../edit.php#13/turbulence.frag"><img src="turbulence-long.png" width="520px" height="200px"></img></a>
Anggota lain dari kelompok algoritme ini adalah **punggungan**, di mana lembah tajam dibalik untuk membuat punggungan tajam:
```glsl
n = abs(n); // create creases
n = offset - n; // invert so creases are at top
n = n * n; // sharpen creases
```
<a href="../edit.php#13/ridge.frag"><img src="ridge-long.png" width="520px" height="200px"></img></a>
Varian lain yang dapat membuat variasi yang berguna adalah dengan menggandakan komponen noise bersama-sama daripada menambahkannya. Menarik juga untuk menskalakan fungsi noise berikutnya dengan sesuatu yang bergantung pada istilah sebelumnya dalam loop. Ketika kita melakukan hal-hal seperti itu, kita menjauh dari definisi fraktal yang ketat dan menuju bidang "multifaktal" yang relatif tidak dikenal. Multifraktal tidak didefinisikan secara matematis secara ketat, tetapi itu tidak membuatnya kurang berguna untuk grafik. Faktanya, simulasi multifraktal sangat umum dalam perangkat lunak komersial modern untuk pembuatan medan. Untuk bacaan lebih lanjut, Anda dapat membaca bab 16 dari buku "Texturing and Modeling: a Prosedural Approach" (edisi ke-3), oleh Kenton Musgrave. Sayangnya, buku itu sudah tidak dicetak lagi sejak beberapa tahun lalu, tetapi Anda masih dapat menemukannya di perpustakaan dan di pasar barang bekas. (Ada versi PDF dari edisi pertama yang tersedia untuk dibeli secara online, tetapi jangan membelinya - ini hanya membuang-buang uang. Ini dari tahun 1994, dan tidak berisi barang pemodelan medan apa pun dari edisi ke-3.)
### Warping Domain
[Inigo Quiles menulis artikel menarik](http://www.iquilezles.org/www/articles/warp/warp.htm) tentang bagaimana mungkin menggunakan GPB untuk membengkokkan ruang dari GPB. Pikiran bertiup, kan? Ini seperti mimpi di dalam mimpi Inception.
![ f(p) = fbm( p + fbm( p + fbm( p ) ) ) - Inigo Quiles (2002)](quiles.jpg)
Contoh yang kurang ekstrem dari teknik ini adalah kode berikut di mana bungkus digunakan untuk menghasilkan tekstur seperti awan ini. Perhatikan bagaimana properti kemiripan diri tetap ada dalam hasil.
<div class='codeAndCanvas' data='clouds.frag'></div>
Warping tekstur koordinat dengan noise dengan cara ini bisa sangat berguna, sangat menyenangkan, dan sangat sulit untuk dikuasai. Ini adalah alat yang ampuh, tetapi membutuhkan sedikit pengalaman untuk menggunakannya dengan baik. Alat yang berguna untuk ini adalah menggeser koordinat dengan turunan (gradien) noise. [Artikel terkenal oleh Ken Perlin dan Fabrice Neyret disebut "noise aliran"](http://evasion.imag.fr/Publications/2001/PN01/) didasarkan pada gagasan ini. Beberapa implementasi modern noise Perlin menyertakan varian yang menghitung fungsi dan gradien analitiknya. Jika gradien "benar" tidak tersedia untuk fungsi prosedural, Anda selalu dapat menghitung perbedaan hingga untuk memperkirakannya, meskipun ini kurang akurat dan melibatkan lebih banyak pekerjaan.

@ -0,0 +1,113 @@
<canvas id="custom" class="canvas" data-fragment-url="src/moon/moon.frag" data-textures="src/moon/moon.jpg" width="350px" height="350px"></canvas>
# The Book of Shaders
*oleh [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) dan [Jen Lowe](http://jenlowe.net/)*
Panduan langkah demi langkah untuk melalui semesta Fragment Shaders yang abstrak dan kompleks.
<div class="header">
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=B5FSVSHGEATCG" style="float: right;"><img src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif" alt=""></a>
</div>
## Konten
* [Pengenalan](00/)
* Memulai
* [Apa itu shader?](01/)
* [“Hello world!”](02/)
* [Uniforms](03/)
* [Menjalankan shader](04/)
* Menggambar secara algoritmik
* [Funsi Membentuk](05/)
* [Warna](06/)
* [Bentuk](07/)
* [Matriks](08/)
* [Pola](09/)
* Desain generatif
* [Acak](10/)
* [Noise](11/)
* [Noise seluler](12/)
* [Gerak Pecahan Brownian](13/)
* Fraktal
* Pemrosesan gambar
* Tekstur
* Operasi Gambar
* Konvolusi Kernel
* Filter
* Efek lainnya
* Simulasi
* Pingpong
* Conway
* Riak
* Warna air
* Reaksi difusi
* Grafik 3D
* Cahaya
* Peta-normal
* Peta benjolan
* Ray berbaris
* Peta lingkungan (bulat dan kubus)
* Merefleksikan dan membiaskan
* [Lampiran:](appendix/) Cara lain untuk menggunakan buku ini
* [Bagaimana saya mendapatkan buku ini secara offline?](appendix/00/)
* [Bagaimana cara menjalankan contoh di Raspberry Pi?](appendix/01/)
* [Bagaimana mencetak buku ini?](appendix/02/)
* [Bagaimana saya bisa berkolaburasi?](appendix/03/)
* [An introduction for those coming from JS](appendix/04/) oleh [Nicolas Barradeau](http://www.barradeau.com/)
* [Galeri contoh](examples/)
* [Glosarium](glossary/)
## Tentang Penulis
[Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) (1982, Buenos Aires, Argentina) adalah seorang artis dan developer yang tinggal di New York. Dia menjelajahi ruang interstisial antara organik dan sintetis, analog dan digital, individu dan kolektif. Dalam karyanya ia menggunakan kode sebagai bahasa ekspresif dengan tujuan untuk mengembangkan bersama menjadi lebih baik.
Patricio mempelajari dan mempraktikkan psikoterapi dan terapi seni ekspresif. Dia memegang gelar MFA dalam Desain & Teknologi dari Parsons The New School, tempat dia sekarang mengajar. Saat ini dia bekerja sebagai Graphic Engineer di Mapzen membuat alat pemetaan openSource.
<div class="header"> <a href="http://patriciogonzalezvivo.com/" target="_blank">WebSite</a> - <a href="https://twitter.com/patriciogv" target="_blank">Twitter</a> - <a href="https://github.com/patriciogonzalezvivo" target="_blank">GitHub</a> - <a href="https://vimeo.com/patriciogv" target="_blank">Vimeo</a> - <a href="https://www.flickr.com/photos/106950246@N06/" target="_blank"> Flickr</a></div>
[Jen Lowe](http://jenlowe.net/) adalah seorang ilmuwan data independen dan komunikator data di Datatelling tempat dia mengumpulkan orang + angka + kata. Dia mengajar di program SVA's Design for Social Innovation, mendirikan School for Poetic Computation, mengajar Matematika untuk Seniman di NYU ITP, meneliti di Lab Desain Informasi Spasial di Universitas Columbia, dan menyumbangkan ide di White House Office of Science and Technology Policy. Dia berbicara di SXSW dan Eyeo. Karyanya telah diliput oleh The New York Times dan Fast Company. Penelitian, penulisan, dan ceramahnya mengeksplorasi janji dan implikasi data dan teknologi di masyarakat. Dia memiliki gelar B.S. dalam Matematika Terapan dan Magister Ilmu Informasi. Seringkali berlawanan, dia selalu berada di sisi cinta.
<div class="header"> <a href="http://jenlowe.net/" target="_blank">WebSite</a> - <a href="https://twitter.com/datatelling" target="_blank">Twitter</a> - <a href="https://github.com/datatelling" target="_blank">GitHub</a></div>
## Ucapan Terima Kasih
Terima kasih kepada [Scott Murray](http://alignedleft.com/) untuk nasihat dan inspirasi.
Terima kasih kepada [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo), [Nicolas Barradeau](https://twitter.com/nicoptere), [Karim Naaji](http://karim.naaji.fr/) untuk kontribusi dengan dukungan, ide bagus dan kode.
Terima kasih kepada [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo) dan [Sawako](https://twitter.com/sawakohome) untuk [terjemahan Bahasa Jepang (日本語訳)](?lan=jp)
Terima kasih kepada [Tong Li](https://www.facebook.com/tong.lee.9484) dan [Yi Zhang](https://www.facebook.com/archer.zetta?pnref=story) untuk [terjemahan Bahasa China (中文版)](?lan=ch)
Terima kasih kepada [Jae Hyun Yoo](https://www.facebook.com/fkkcloud) untuk [terjemahan Bahasa Korea (한국어)](?lan=kr)
Terima kasih kepada [Nahuel Coppero (Necsoft)](http://hinecsoft.com/) untuk terjemahan [Bahasa Spanyol (español)](?lan=es)
Terima kasih kepada [Raphaela Protásio](https://github.com/Rawphs) dan [Lucas Mendonça](https://github.com/luuchowl) untuk terjemahan [terjemahan Bahasa Portugis](?lan=pt)
Terima kasih kepada [Nicolas Barradeau](https://twitter.com/nicoptere) and [Karim Naaji](http://karim.naaji.fr/) for the French [translation (français)](?lan=fr)
Terima kasih kepada [Andrea Rovescalli](https://www.earove.info) untuk terjemahan [Bahasa Italia (italiano)](?lan=it)
Terima kasih kepada [Michael Tischer](http://www.mitinet.de) untuk terjemahan [Bahasa Jerman (deutsch)](?lan=de)
Terima kasih kepada [Sergey Karchevsky](https://www.facebook.com/sergey.karchevsky.3) untuk terjemahan [Bahasa Rusia (russian)](?lan=ru)
Terima kasih kepada [Andy Stanton](https://andy.stanton.is/) untuk perbaikan dan improvisasi [the pdf/epub export pipeline](https://thebookofshaders.com/appendix/02/)
Terima kasih kepada semua orang yang telah percaya pada proyek ini dan [telah berkontribusi dalam perbaikan](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) atau donasi.
## Dapatkan bagian baru
Daftar untuk surat berita atau [follow di Twitter](https://twitter.com/bookofshaders)
<form style="border:1px solid #ccc;padding:3px;text-align:center;" action="https://tinyletter.com/thebookofshaders" method="post" target="popupwindow" onsubmit="window.open('https://tinyletter.com/thebookofshaders', 'popupwindow', 'scrollbars=yes,width=800,height=600');return true"><a href="https://tinyletter.com/thebookofshaders"><p><label for="tlemail">Masukann alamat email</label></p></a><p><input type="text" style="width:140px" name="email" id="tlemail" /></p><input type="hidden" value="1" name="embed"/><input type="submit" value="Subscribe" /><p><a href="https://tinyletter.com" target="_blank"></a></p></form>

@ -0,0 +1,33 @@
## Bagaimana saya mendapatkan buku ini secara offline?
Katakanlah anda sedang berada di perjalanan jauh dan anda ingin mempelajari beberapa shader, Dalam kasus itu anda dapat membuat salinan lokal dari buku ini di komputermu dan berjalan di server lokal.
Untuk itu anda membutuhkan PHP, Python 3 dan Git Client. Pada komputer MacOS dan Raspberry Pi, Python sudah terpasang secara bawaan tapi anda tetap harus menginstall git client:
Pada **MacOSX**, pastikan mempunyai [homebrew](http://brew.sh/) yang terpasang dan terminal lakukanlah:
```bash
brew update
brew upgrade
brew install git php
```
Pada **Raspberry Pi**, anda harus mempunyai [Raspbian](https://www.raspberrypi.org/downloads/raspbian/), sebuah distribusi Linux berbasis Debian yang dibuat untuk Raspberry Pi dan lakukanlah:
```bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git-core glslviewer php
```
Setelah semua terpasang, anda hanya perlu melakukan:
```bash
cd ~
git clone --recursive https://github.com/patriciogonzalezvivo/thebookofshaders.git
cd thebookofshaders
git submodule foreach git submodule init && git submodule update
php -S localhost:8000
```
Lalu di browser anda kunjungi ['http://localhost:8000/'](http://localhost:8000/)

@ -0,0 +1,18 @@
## Bagaimana cara menjalankan contoh di Raspberry Pi?
Beberapa tahun yang lalu, asumsikan bahwa setiap orang memiliki komputer dengan unit pemrosesan grafis adalah hal yang mustahil. Sekarang, sebagian besar komputer memiliki GPU, tetapi masih merupakan standar yang tinggi untuk persyaratan di bengkel atau kelas, misalnya.
Terima Kasih kepada [Raspberry Pi Foundation](http://www.raspberrypi.org/) sebuah jenis baru dari generasi komputer yang kecil dan murah (sekitar $35/Rp500,000 satunya) telah menemukan jalannya ke kelas. Yang terpenting untuk tujuan buku ini, [Raspberry Pi](http://www.raspberrypi.org/) hadir dengan GPU Broadcom yang layak yang dapat diakses langsung dari konsol. Saya membuat [panggilan alat pengkodean langsung GLSL fleksibel **glslViewer**](https://github.com/patriciogonzalezvivo/glslViewer) yang menjalankan semua contoh dalam buku ini. Program ini juga memiliki kemampuan untuk memperbarui secara otomatis ketika pengguna menyimpan perubahan pada kode mereka. Apa artinya ini? Anda dapat mengedit shader dan setiap kali Anda menyimpannya, shader akan dikompilasi ulang dan dirender untuk Anda.
Dengan membuat salinan lokal dari repositori buku ini (lihat bagian di atas) dan [`glslViewer` diinstal](https://github.com/patriciogonzalezvivo/glslViewer), pengguna dapat menjalankan contoh dengan` glslviewer`. Juga dengan menggunakan flag `-l` mereka dapat membuat contoh di sudut layar sementara mereka memodifikasinya dengan editor teks apa pun (seperti `nano`, `pico`, `vi`, `vim` atau` emacs`) . Ini juga berfungsi jika pengguna terhubung melalui ssh/sftp.
Untuk memasang dan mengatur semua ini pada Raspberry Pi setelah memasang [Raspbian](https://www.raspberrypi.org/downloads/raspbian/), sebuah distribusi Linux berbasis Debian yang dibuat untuk Raspberry Pi, ketik perintah berikut:
```bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git-core glslviewer
cd ~
git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git
cd thebookofshaders
```

@ -0,0 +1,70 @@
## Bagaimana mencetak buku ini?
Katakanlah anda tidak ingin melihat atau berinteraksi dengan contoh dan Anda hanya ingin buku teks mode lama yang bagus yang dapat Anda baca di pantai atau dalam perjalanan Anda ke kota. Dalam hal ini, Anda dapat mencetak buku ini.
#### Memasang glslViewer
Untuk mencetak buku ini anda terlebih dahulu harus menguraikannya. Untuk itu anda akan membutuhkan [`glslViewer`](https://github.com/patriciogonzalezvivo/glslViewer) sebuah alat shader konsol yang akan mengkompilasi dan mengubah contoh shader ke gambar.
Pada **MacOSX**, pastikan mempunyai [homebrew](http://brew.sh/) yang terpasang dan terminal lakukanlah:
```bash
brew install glslviewer
```
Pada **Raspberry Pi**, anda harus mempunyai [Raspbian](https://www.raspberrypi.org/downloads/raspbian/), sebuah distribusi Linux berbasis Debian yang dibuat untuk Raspberry Pi dan lakukanlah:
```bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git-core glslviewer
```
#### Memasang Python 3, Latex Engine dan Pandoc
Untuk mengurai bab Markdown ke Latex dan kemudian ke berkas PDF, kita akan menggunakan Xetex Letex Engine dan Pandoc
Pada **MacOSX**:
Unduh dan Pasang MacTeX dengan:
```bash
brew cask install mactex-no-gui
```
Kemudian pasang [Pandoc](http://johnmacfarlane.net/pandoc/) dan Python 3 dengan:
```bash
brew install pandoc python
```
Pada **Raspberry Pi** (Raspbian):
```bash
sudo apt-get install texlive-xetex pandoc python2.7
```
#### Compile the book into a pdf and print it
Sekarang anda sudah mempunya apa yang dibutuhkan, waktunya untuk mengkloning [repositori buku ini](https://github.com/patriciogonzalezvivo/thebookofshaders)) dan kompilasi buku ini:
Untuk itu buka terminal sekali lagi dan ketik:
```bash
cd ~
git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git
cd thebookofshaders
make clean pdf
```
Jika semua berjalan lancar, anda akan melihat berkas `book.pdf` yang bisa anda baca di perangkat favorit atau dicetak.
#### Kompilasi buku menjadi epub untuk digunakan dengan e-reader
```bash
cd ~
git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git
cd thebookofshaders
make clean epub
```
`Book.epub` yang dihasilkan dapat digunakan secara langsung, atau diubah menjadi file` .mobi` untuk digunakan dengan Kindle dengan menggunakan konverter, misalnya Calibre.

@ -0,0 +1,61 @@
## Bagaimana saya bisa berkolaburasi?
Terima kasih telah bersedia untuk berkolaborasi! Ada banyak cara yang bisa anda lakukan:
- Menerjemahkan konten
- Mengimprovisasi [bagian glosarium (```glossary/```)](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/glossary)
- Menyunting konten
- Membagikan contoh shadermu melalui [editor on-line](http://editor.thebookofshaders.com/)
### Menerjemahkan Konten
Buku ini dibuat dalam bahasa [Markdown](ttps://daringfireball.net/projects/markdown/syntax) jadi ini sangat mudah untuk disunting dan dikerjakan.
1. Mulailah dengan membuka repositori [Github di ```github.com/patriciogonzalezvivo/thebookofshaders```](https://github.com/patriciogonzalezvivo/thebookofshaders). Lihatlah file dan folder di dalamnya. Anda akan melihat bahwa isinya ada di ```README.md``` dan file lain dengan huruf kapital seperti: ```TITLE.md```, ```SUMMARY.md```, dll. Perhatikan juga bahwa terjemahan di-host dalam file dengan nama yang diakhiri dengan dua huruf yang merujuk pada bahasanya, mis .: ```README-jp.md```, ```README-es.md```, dll.
2. Fork repositori dan klon di komputer Anda.
3. Gandakan konten file yang ingin diterjemahkan. Ingatlah untuk menambahkan dua huruf yang mengacu pada bahasa yang Anda terjemahkan ke file yang akan anda kerjakan.
4. Terjemahkan baris demi baris konten (lihat **Catatan terjemahan**).
5. Uji (lihat **Pengujian**).
6. Push ke fork github anda sendiri untuk kemudian buatlah [Pull Request](https://help.github.com/articles/using-pull-requests/)
#### Catatan Terjemahan
Jangan menghapus atau mengubah contoh yang disematkan, seperti:
```html
<div class="codeAndCanvas" data="grid-making.frag"></div>
```
or
```html
<div class="simpleFunction" data="y = mod(x,2.0);"></div>
```
#### Pengujian
Mulai jalankan server lokal PHP di dalam folder repositori lokal:
```bash
php -S localhost:8000
```
Kemudian dalam browser cari ```localhost:8000```, pergi ke bab yang ingin diterjemahkan dan tambahkan ```?lan=``` diikuti dengan dua huruf yang anda gunakan untuk menandai bahasa yang anda terjemahkan.
### Mengimprovisasi bagian glosarium
Bagian ini dibawah pengembangan. Kami senang untuk mendengar idemu pada cara untuk membuat alat yang bersahabat untuk semua.
### Menyunting konten
Kita semua manusia. Jika anda melihat sesuatu, lakukanlah sesuatu, buat Pull Request atau buka/buat isu. Terima Kasih!
### Membagikan contoh shadermu
Anda akan melihat banyak tautan ke [editor on-line](http://editor.thebookofshaders.com/) dan contoh yang disematkan darinya.
Setelah anda membuat sesuatu yang membuat anda bangga, klik "Export" (atau ikon ```⇪```) dan kemudian salin "URL to code...", kirim ke [@bookofshaders](https://twitter.com/bookofshaders) atau [@kyndinfo](https://twitter.com/kyndinfo). Kami sangat menantikan untuk melihatnya dan menambahkannya ke [bagian galeri contoh](https://thebookofshaders.com/examples/)

@ -0,0 +1,15 @@
# Lampiran
1. [Bagaimana saya mendapatkan buku ini secara offline?](00/)
2. [Bagaimana cara menjalankan contoh di Raspberry Pi?](01/)
3. [Bagaimana mencetak buku ini?](02/)
4. [Bagaimana saya bisa berkolaburasi?](03/)
5. [An introduction for those coming from JS](04/) by [Nicolas Barradeau](http://www.barradeau.com/)
6. [An introduction for vectors](05/) by ...
7. [An introduction to interpolation](06) by ...

@ -0,0 +1,5 @@
# Galeri Contoh
<p class="gallery_author">Dibuat oleh <a href="https://www.kynd.info">kynd</a>(<a href="https://twitter.com/kyndinfo">@kyndinfo</a>) dan Patricio Gonzalez Vivo(<a href="https://twitter.com/patriciogv">@patriciogv</a>)</p>
Ini adalah kumpulan contoh yang diekstrak dari bab-bab buku ini bersama dengan shader bersama yang disumbangkan oleh pembaca lain menggunakan [editor on-line](http://editor.thebookofshaders.com/). Jangan ragu untuk menjelajahi dan menyesuaikannya sedikit demi sedikit. Setelah Anda memiliki sesuatu yang Anda banggakan, klik "Export" dan kemudian salin "URL ke kode ...". Kirimkan ke [@bookofshaders](https://twitter.com/bookofshaders) atau [@kyndinfo](https://twitter.com/kyndinfo). Kami sangat menantikan untuk melihatnya!
Loading…
Cancel
Save