### README (README.md) # The Book of Shaders *by [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) and [Jen Lowe](http://jenlowe.net/)* This is a gentle step-by-step guide through the abstract and complex universe of Fragment Shaders.
## Contents * [About this book](00/) * Getting started * [What is a shader?](01/) * [“Hello world!”](02/) * [Uniforms](03/) * [Running your shader](04/) * Algorithmic drawing * [Shaping functions](05/) * [Colors](06/) * [Shapes](07/) * [Matrices](08/) * [Patterns](09/) * Generative designs * [Random](10/) * [Noise](11/) * [Cellular noise](12/) * [Fractional brownian motion](13/) * Fractals * Image processing * Textures * Image operations * Kernel convolutions * Filters * Other effects * Simulation * Pingpong * Conway * Ripples * Water color * Reaction diffusion * 3D graphics * Lights * Normal-maps * Bump-maps * Ray marching * Environmental-maps (spherical and cube) * Reflect and refract * [Appendix:](appendix/) Other ways to use this book * [How can I navigate this book offline?](appendix/00/) * [How to run the examples on a Raspberry Pi?](appendix/01/) * [How to print this book?](appendix/02/) * [How can I collaborate?](appendix/03/) * [An introduction for those coming from JS](appendix/04/) by [Nicolas Barradeau](http://www.barradeau.com/) * [Examples Gallery](examples/) * [Glossary](glossary/) ## About the Authors [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) (1982, Buenos Aires, Argentina) is a New York based artist and developer. He explores interstitial spaces between organic and synthetic, analog and digital, individual and collective. In his work he uses code as an expressive language with the intention of developing a better together. Patricio studied and practiced psychotherapy and expressive art therapy. He holds an MFA in Design & Technology from Parsons The New School, where he now teaches. Currently he works as a Graphic Engineer at Mapzen making openSource mapping tools. [Jen Lowe](http://jenlowe.net/) is an independent data scientist and data communicator at Datatelling where she brings together people + numbers + words. She teaches in SVA's Design for Social Innovation program, cofounded the School for Poetic Computation, taught Math for Artists at NYU ITP, researched at the Spatial Information Design Lab at Columbia University, and contributed ideas at the White House Office of Science and Technology Policy. She's spoken at SXSW and Eyeo. Her work has been covered by The New York Times and Fast Company. Her research, writing, and speaking explore the promises and implications of data and technology in society. She has a B.S. in Applied Math and a Master's in Information Science. Often oppositional, she's always on the side of love. ## Acknowledgements Thanks [Scott Murray](http://alignedleft.com/) for the inspiration and advice. Thanks [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo), [Nicolas Barradeau](https://twitter.com/nicoptere), [Karim Naaji](http://karim.naaji.fr/) for contributing with support, good ideas and code. Thanks [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo) and [Sawako](https://twitter.com/sawakohome) for the [Japanese translation (日本語訳)](?lan=jp) Thanks [Tong Li](https://www.facebook.com/tong.lee.9484) and [Yi Zhang](https://www.facebook.com/archer.zetta?pnref=story) for the [Chinese translation (中文版)](?lan=ch) Thanks [Jae Hyun Yoo](https://www.facebook.com/fkkcloud) and [June Kim](https://github.com/rlawns324) for the Korean [translation (한국어)](?lan=kr) Thanks Nahuel Coppero (Necsoft) for the Spanish [translation (español)](?lan=es) Thanks [Raphaela Protásio](https://github.com/Rawphs) and [Lucas Mendonça](https://github.com/luuchowl) for the Portuguese [translation (portugues)](?lan=pt) Thanks [Nicolas Barradeau](https://twitter.com/nicoptere) and [Karim Naaji](http://karim.naaji.fr/) for the French [translation (français)](?lan=fr) Thanks [Andrea Rovescalli](https://www.earove.info) for the Italian [translation (italiano)](?lan=it) Thanks [Michael Tischer](http://www.mitinet.de) for the German [translation (deutsch)](?lan=de) Thanks [Sergey Karchevsky](https://www.facebook.com/sergey.karchevsky.3) for the Russian [translation (russian)](?lan=ru) Thanks [Vu Phuong Hoang](https://www.facebook.com/vuphuonghoang88) for the Vietnamese [translation (Tiếng Việt)](?lan=vi) Thanks [Wojciech Pachowiak](https://github.com/WojtekPachowiak) for the Polish [translation (polski)](?lan=pl) Thanks [Manoylov Andriy](https://twitter.com/ManoylovAC) for the Ukrainian [translation (український переклад)](?lan=ua) Thanks [Batuhan Dev](https://batudev.framer.website/portfolio) for the Turkish [translation (Türkçe)](?lan=tr) Thanks [Andy Stanton](https://andy.stanton.is/) for fixing and improving [the pdf/epub export pipeline](https://thebookofshaders.com/appendix/02/) Thanks to everyone who has believed in this project and [contributed with fixes](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) or donations. ## Get new chapters Sign up for the news letter or follow it on [Twitter](https://twitter.com/bookofshaders) / Mastodon / [Discord](shader.zone) ## LICENSE Copyright (c) Patricio Gonzalez Vivo, 2015 - http://patriciogonzalezvivo.com/ All rights reserved. --- ### Docker Compose.Yml (docker-compose.yml) version: '3.5' services: web: image: php:7.0-apache volumes: - .:/var/www/html/ ports: - "8000:80" --- ### README Ch (README-ch.md) # The Book of Shaders *by [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/)* 这是一本关于 Fragment Shaders(片段着色器)的入门指南,它将一步一步地带你领略其中的纷繁与抽象。 ## 关于翻译 这本书是 Patricio 的 the Book of Shaders 的中文翻译。我们希望借此将 Shader 这个有趣有益的工具介绍给更多国人。能力所限,不免有误,如有翻译不当,也请多多指出。 感谢 Patricio 对我们的翻译的信任和支持。 ## 目录 * [关于这本书](00/?lan=ch) * 开始 * [什么是片段着色器(Fragment Shader)?](01/?lan=ch) * [“Hello world!”](02/?lan=ch) * [Uniforms值](03/?lan=ch) * [运行你的 shader](04/?lan=ch) * 用算法绘画 * [造型函数](05/?lan=ch) * [颜色](06/?lan=ch) * [形状](07/?lan=ch) * [矩阵](08/?lan=ch) * [图案](09/?lan=ch) * 生成设计 * [随机](10/?lan=ch) * [噪声](11/?lan=ch) * [网格噪声](12/?lan=ch) * [分形布朗运动](13/?lan=ch) * 分形 * 图像处理: * 纹理 * 图像处理 * 卷积核 * 滤镜 * 其他效果 * 模拟 * 乒乓 * Conway生命游戏 * 水波 * 水彩 * 反应扩散 * 3D 图形 * 灯光 * 法线贴图 * 凹凸贴图 * 光线跟踪(Ray marching) * 环境贴图 (spherical and cube) * 折射和反射 * [附录:](appendix/?lan=ch) 其他阅读本书的方式 * [如何离线阅读此书?](appendix/00/?lan=ch) * [如何在树莓派上运行示例程序?](appendix/01/?lan=ch) * [如何打印这本书](appendix/02/?lan=ch) * [我怎样共创这本书](appendix/03/?lan=ch) * [给那些从JS语言过来的人的介绍](appendix/04/?lan=ch) by [Nicolas Barradeau](http://www.barradeau.com/) * [example gallery](examples/?lan=ch) * [词汇表](glossary/?lan=ch) ## 关于作者 [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) (1982, 布宜诺斯艾利斯, 阿根廷) 是一个驻地纽约的艺术家、开发者。他致力于探索有机和人造、模拟信号和数字信号、个体和整体之间的空间。他用代码这种富有表达力的语言来创造更美好的事物。 Patricio 研习和实践精神疗法(psychotherapy)和表达性艺术治疗(expressive art therapy)。他毕业于 Parsons 的设计与科技专业,且目前执教于此。目前他作为 Mapzen 的图形开发工程师制作一些开源的 mapping tool。 ## 关于译者 * [tornote](https://github.com/tornoteli) 翻译 00-05 及第 11 章。 * [Artrustee](https://github.com/Artrustee) 翻译 06-10 章。 后续章节作者仍在撰写中,如果感兴趣可以在 github 上查看部分后续章节代码。 ## 致谢 感谢我的妻子 [Jen Lowe](http://www.datatelling.com/), 感谢她无条件的支持、帮助以及编辑此书。 感谢 [Scott Murray](http://alignedleft.com/) 给予的启发和建议。 感谢 [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo) 和 [Sawako](https://twitter.com/sawakohome) 的 [日文版翻译(日本語訳)](?lan=jp) 感谢 [Tong Li](https://www.facebook.com/tong.lee.9484) 和 [Yi Zhang](https://www.facebook.com/archer.zetta?pnref=story) 的 [中文版(Chinese)](?lan=ch) 翻译。 感谢 [Jae Hyun Yoo](https://www.facebook.com/fkkcloud) 的 [韩文版 (한국어)](?lan=kr) 翻译。 感谢 Nahuel Coppero (Necsoft) 的 [西班牙语(español)](?lan=es) 翻译。 感谢 [Manoylov Andriy](https://twitter.com/ManoylovAC) 的 [乌克兰语(українська)](?lan=ua) 翻译。 感谢 [Karim Naaji](http://karim.naaji.fr/) 在代码和想法上的支持和贡献。 感谢所有相信这个项目的人[contributed with fixes](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) 以及大家的捐赠. ## 获取新的章节 注册以获得最新章节, 或 在 [Twitter](https://twitter.com/bookofshaders) / Mastodon / [Discord](shader.zone) 上关注: --- ### README De (README-de.md) # The Book of Shaders *von [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) und [Jen Lowe](http://jenlowe.net/)* Dies ist eine behutsame Schritt-für-Schritt-Einführung in die komplexe und vielfach abstrakte Welt der Fragment Shader. ## Inhalt * [Über dieses Buch](00/?lan=de) * Jetzt geht’s los * [Was ist ein Shader?](01/?lan=de) * [“Hallo Welt!”](02/?lan=de) * [Uniforms](03/?lan=de) * [Ausführung Deiner Shader](04/?lan=de) * Algorithmisches Zeichnen * [Formgebende Funktionen](05/?lan=de) * [Farben](06/?lan=de) * [Formen](07/?lan=de) * [Matrizen](08/?lan=de) * [Muster](09/?lan=de) * Generative Designs * [Zufall](10/?lan=de) * [Rauschen](11/?lan=de) * [Zelluläres Rauschen](12/?lan=de) * [Gebrochene Brownsche Bewegung](13/?lan=de) * Fraktale * Bildverarbeitung * Texturen * Bildbearbeitungsfunktionen * Kernel Verwindungen * Filter * Weitere Effekte * Simulationen * Pingpong * Conway * Wellen * Wasserfarben * Reaktionsausbreitung * 3D Grafiken * Licht * Normal Mapping * Bump-Mapping * Ray Marching * Environmental-Maps (sphärisch und kubisch) * Reflektionen und Ablenkungen * [Anhang:](appendix/?lan=de) Weitere Wege zur Nutzung dieses Buches * [Wie kann ich dieses Buch offline lesen?](appendix/00/?lan=de) * [Wie lasse ich die Beispielprogramme auf einem Raspberry Pi ablaufen?](appendix/01/?lan=de) * [Wie drucke ich dieses Buch aus?](appendix/02/?lan=de) * [Wie kann ich zu diesem Buch beitragen?](appendix/03/?lan=de) * [Eine Einführung für alle, die von JavaScript kommen](appendix/04/?lan=de) von [Nicolas Barradeau](http://www.barradeau.com/) (Englisch) * [Beispielgalerien](examples/) * [Glossar](glossary/) (Englisch) ## Über die Autoren [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) (1982, Buenos Aires, Argentinien) ist ein Künstler und Entwickler, der in New York lebt. Er erforscht die Räume zwischen organisch und synthetisch, analog und digital, einzeln und zusammen. In seinen Arbeiten nutzt er Programmcode als Ausdrucksform, um das Zusammenwirken von Menschen zu verbessern. Patricio hat Psychologie studiert, außerdem kunstorientiertes Handeln (die sogenannte Expressive Arts Therapy). Er hat einen MFA-Abschluss in Design und Technologie von der Parsons New School For Design, wo er auch unterrichtet. Zur Zeit arbeitet Patricio als Grafikingenieur bei der Firma Mapzen und entwickelt dort Open-Source-Werkzeuge für die Computer-Kartographie. [Jen Lowe](http://jenlowe.net/) ist eine unabhängige Datenwissenschaftlerin und Datenkommunikatorin bei der Firma Datatelling, wo sie Menschen, Zahlen und Sprache zusammenführt. Sie unterrichtet an der SVA das Fach Design for Social Innovation, hat die Schule für „Poetic Computation“ mitbegründet, Mathematik für Künstler an der New Yorker ITP-Universität unterrichtet, Forschungen am „Spatial Information Design Lab“ der Columbia Universität durchgeführt und Beiträge für das „White House Office of Science and Technology“ geliefert, das den US-Präsidenten in Fragen des technischen Fortschritts berät. Als Sprecherin ist Jen auf Konferenzen wie der SXSW und der Eyeo aufgetreten. Von ihren Arbeiten hat unter anderem die New York Times, sowie das Magazin FastCompany berichtet. Ihre Forschungsarbeiten, Publikationen und Vorträge kreisen um die Versprechungen und Folgen von Daten und Technologien für die gesellschaftliche Entwicklung. Sie hat einen Bachelor in angewandter Mathematik und einen Master in Informatik. Obwohl man angesichts dieser Biographie vielleicht etwas anderes vermuten könnte, schlägt sich Jen immer auf die Seite der Liebe. ## Danksagungen Dank an [Scott Murray](http://alignedleft.com/) für die Inspirationen und Ratschläge. Dank an [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo), [Nicolas Barradeau](https://twitter.com/nicoptere) und [Karim Naaji](http://karim.naaji.fr/) für ihre Unterstützung, Anregungen und Programmcode. Dank an [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo) und [Sawako](https://twitter.com/sawakohome) für die [japanische Übersetzung des Textes (日本語訳)](?lan=jp) Dank an [Tong Li](https://www.facebook.com/tong.lee.9484) und [Yi Zhang](https://www.facebook.com/archer.zetta?pnref=story) für die [chinesische Übersetzung des Textes (中文版)](?lan=ch) Dank an [Jae Hyun Yoo](https://www.facebook.com/fkkcloud) für die [koreanische Übersetzung des Textes (한국어)](?lan=kr) Dank an Nahuel Coppero (Necsoft) für die [spanische Übersetzung des Textes (español)](?lan=es) Dank an [Nicolas Barradeau](https://twitter.com/nicoptere) und [Karim Naaji](http://karim.naaji.fr/) für die [französische Übersetzung des Textes (français)](?lan=fr) Dank an [Andrea Rovescalli](https://www.earove.info) für die [italienische Übersetzung des Textes (italiano)](?lan=it) Dank an [Michael Tischer](http://www.mitinet.de) für die [deutsche Übersetzung des Textes](?lan=de) Dank an [Manoylov Andriy](https://twitter.com/ManoylovAC) für die [ukrainische Übersetzung des Textes (українська)](?lan=ua) Und natürlich Danke an alle, die an dieses Projekt geglaubt, dafür gespendet oder durch Hinweise und Korrekturen [daran mitgewirkt haben](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors). ## Hol Dir die neuen Kapitel Melde Dich für den Newsletter an oder folge uns auf [Twitter](https://twitter.com/bookofshaders) / Mastodon / [Discord](shader.zone) --- ### README Es (README-es.md) # The Book of Shaders *por [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/)* Esta es una guía paso a paso a través del abstracto y complejo universo de los Fragment Shaders. ## Contenidos * [Acerca de este libro](00/?lan=es) * Comenzando * [¿Qué es un shader?](01/?lan=es) * [“Hola Mundo!”](02/?lan=es) * [Uniforms](03/?lan=es) * [Ejecutando tu shader](04/?lan=es) * Dibujando con algoritmos * [Funciones de forma](05/?lan=es) * [Colores](06/?lan=es) * [Formas](07/) * [Matrices](08/) * [Patrones](09/) * Diseños generativos * [Random](10/) * [Noise](11/) * Movimiento browniano * Fractales * Procesamiento de imágenes * Texturas * Operaciones de Imagen * Convoluciones de Kernel * Filtros * Otros efectos * Simulación * Pingpong * Conway * Ripples * Water color * Reaction diffusion * Gráficos 3D * Luces * Normal-maps * Bump-maps * Ray marching * Environmental-maps (esféricas y cúbicas) * Reflección y refracción * [Apéndice:](appendix/) Otras formas de usar este libro * [¿Cómo puedo ver el libro offline?](appendix/) * [¿Cómo puedo correr los ejemplos en una Raspberry Pi?](appendix/) * [¿Cómo imprimir este libro?](appendix/) * [Galería de ejemplos](examples/) * [Glosario](glossary/) ## Acerca del autor [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) (1982, Buenos Aires, Argentina) es un artista y desarrollador que actualmente reside en New York. Explora los espacios que convergen entre lo orgánico y lo sintético, lo analógico y lo digital, lo individual y lo colectivo. En su trabajo utiliza el código como un lenguaje expresivo con la intención de lograr algo superador. Patricio estudió y ejerció psicoterapia y terapia de artes expresivas. Tiene un MFA en diseño y tecnología de la Parsons The New School, donde hoy da clases. Actualmente el trabaja como Graphic Engineer en Mapzen, creando herramientas open source para trabajar con mapas. ## Agradecimientos Gracias a mi esposa [Jen Lowe](http://www.datatelling.com/), por su apoyo incondicional, su ayuda y el tiempo dedicado editando este libro. Gracias a [Scott Murray](http://alignedleft.com/) por inspirarme y aconsejarme. Gracias a [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo) y a [Sawako](https://twitter.com/sawakohome) por la [Traducción al japonés (日本語訳).](?lan=jp) Gracias a [Tong Li](https://www.facebook.com/tong.lee.9484) y a [Yi Zhang](https://www.facebook.com/archer.zetta?pnref=story)por la [Traducción al chino (中文版).](?lan=ch) Gracias a [Jae Hyun Yoo](https://www.facebook.com/fkkcloud) por la [Traducción al coreano (한국어).](?lan=kr) Gracias a [Manoylov Andriy](https://twitter.com/ManoylovAC) por la [traducción al ucraniano (українська)](?lan=ua) Gracias a [Karim Naaji](http://karim.naaji.fr/) por su contribución, su apoyo, su código y sus buenas ideas. Gracias a todos los que creyeron en este proyecto y [contribuyeron con sus aportes](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) o donaciones. ## ¿Cómo conseguir los nuevos capítulos? Suscribirse al newsletter o seguirnos en [Twitter](https://twitter.com/bookofshaders) / Mastodon / [Discord](shader.zone) --- ### README Fr (README-fr.md) # The Book of Shaders *par [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) et [Jen Lowe](http://jenlowe.net/)* Ceci est un guide étape-par-étape à travers le monde abstrait et complexe des Fragment Shaders. ## Contenu * [A propos de ce livre](00/?lan=fr) * Pour commencer * [Qu'est ce qu'un shader?](01/?lan=fr) * [“Hello world!”](02/?lan=fr) * [Les uniforms](03/?lan=fr) * [Exécuter votre shader](04/?lan=fr) * Le dessin algorithmique * [Les fonctions](05/?lan=fr) * [Les couleurs](06/?lan=fr) * [Les formes](07/?lan=fr) * [Les matrices](08/?lan=fr) * [Les motifs](09/?lan=fr) * Le design génératif * [L'aléatoire](10/?lan=fr) * [Le bruit](11/?lan=fr) * [Le bruit cellulaire](12/?lan=fr) * [Fractional Brownian Motion](13/?lan=fr) * Les Fractals * Traitement d'image: * Textures * Convolution * Filtres * Effets * Simulation * Pingpong * Conway * Ondes * Aquarelle * Réaction-Diffusion * 3D graphics * Lumières * Normales * Environment-maps (spherical and cube) * Bump * Ray marching * Réflection & réfraction * [Annexes :](appendix/?lan=fr) Autres manières d'utiliser ce livre * [Comment puis-je consulter ce livre hors-ligne ?](appendix/00/?lan=fr) * [Comment exécuter les exemples sur un Raspberry Pi ?](appendix/01/?lan=fr) * [Comment imprimer ce livre ?](appendix/02/?lan=fr) * [Comment puis-je contribuer à ce livre?](appendix/03/?lan=fr) * [Une introduction pour ceux qui viennent de JS](appendix/04/?lan=fr) de [Nicolas Barradeau](http://www.barradeau.com/) * [Galerie d'exemples](examples/) * [Glossaire](glossary/) ## A propos de l'auteur [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) (1982, Buenos Aires, Argentine) est un artiste et développeur installé à New York. Il explore les espaces interstitiels entre l'organique et le synthétique, l'analogique et le numérique, l'individuel et le collectif. Dans son travail, il utilise le code comme un langage expressif avec l'intention de développer un mieux-vivre ensemble. Patricio a étudié et a pratiqué la psychothérapie et l'art-thérapie. Il détient un MFA en Design & Technologie de Parsons The New School, où il enseigne maintenant. Actuellement il travaille comme ingénieur graphique pour Mapzen, travaillant sur des outils cartographiques openSource. ## Remerciements Merci à ma femme [Jen Lowe](http://www.datatelling.com/), pour son support sans faille, son aide et son temps passé à la révision de ce livre. Merci à [Scott Murray](http://alignedleft.com/) pour l'inspiration et les conseils. Merci à [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo) et [Sawako](https://twitter.com/sawakohome) pour la [traduction (日本語訳)](?lan=jp) japonaise Merci à [Tong Li](https://www.facebook.com/tong.lee.9484) et [Yi Zhang](https://www.facebook.com/archer.zetta?pnref=story) pour la [traduction (中文版)](?lan=ch) chinoise Merci à [Jae Hyun Yoo](https://www.facebook.com/fkkcloud) pour la [traduction (한국어)](?lan=kr) coréenne Merci à [Manoylov Andriy](https://twitter.com/ManoylovAC) pour la [traduction (українська)](?lan=ua) l'ukrainien Merci à [Karim Naaji](http://karim.naaji.fr/) qui a contribué par son support, ses bonnes idées et son code. Merci à tous ceux qui ont cru en ce projet et à ceux qui ont [contributé aux corrections](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) ou qui ont fait des dons. ## De nouveaux chapitres Abonnez-vous à la newsletter ou suivez-nous sur [Twitter](https://twitter.com/bookofshaders) / Mastodon / [Discord](shader.zone) --- ### README Id (README-id.md) # 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. ## 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. [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. ## 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) 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 [Naufal Adriansyah](https://www.facebook.com/naufal.adrna08) untuk terjemahan [Bahasa Indonesia](?lan=id) Terima kasih kepada [Manoylov Andriy](https://twitter.com/ManoylovAC) untuk terjemahan [Bahasa Ukraina (українська)](?lan=ua) 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) / Mastodon / [Discord](shader.zone) --- ### README It (README-it.md) # The Book of Shaders *di [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) e [Jen Lowe](http://jenlowe.net/)* Questa è una guida passo passo attraverso l'universo astratto e complesso dei Fragment Shaders. ## Contenuto * [A proposito di questo libro](00/?lan=it) * Introduzione * [Che cosa è uno shader?](01/?lan=it) * ["Ciao mondo!"](02/?lan=it) * [Uniforms](03/?lan=it) * [Eseguite il vostro shader](04/?lan=it) * Disegno algoritmico * [Le funzioni di forma](05/?lan=it) * [Colori](06/?lan=it) * [Figure](07/?lan=it) * [Matrici](08/?lan=it) * [Motivi](09/?lan=it) * Progettazione generativa * [Random](10/?lan=it) * [Rumore](11/?lan=it) * Rumore cellulare * Moto browniano frazionario * Frattali * Trattamento delle immagini: * Textures * Operazioni d'immagine * Convoluzioni di Kernel * Filtri * Altri effetti * Simulazione * Pingpong * Conway * Increspature * Acquerello * Reazione-diffusione * Grafica 3D * Luci * Normal-maps * Bump-maps * Ray marching * Environmental-maps (sferiche e cubiche) * Riflesso e rifrazione * [Appendice:](appendix/) Altri modi per utilizzare questo libro * [Come posso consultare questo libro offline?](appendix/00/?lan=it) * [Come posso eseguire gli esempi su un Raspberry Pi?](appendix/01/?lan=it) * [Come posso stampare questo libro?](appendix/02/?lan=it) * [Come posso collaborare a questo libro?](appendix/03/?lan=it) * [Un'introduzione per chi proviene da JS](appendix/04/) di [Nicolas Barradeau](http://www.barradeau.com/) * [Galleria d'esempi](examples/) * [Glossario](glossary/) ## A proposito dell'autore [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) (1982, Buenos Aires, Argentina) è un artista e sviluppatore con sede a New York. Esplora lo spazio interstiziale fra organico e sintetico, analogico e digitale, individuale e collettivo. Nel suo lavoro usa il codice come un linguaggio espressivo con l'intenzione di creare un migliore vivere insieme. Patricio studiò e praticò la psicoterapia e l'arteterapia. Ha conseguito un MFA in Design e Tecnologia alla Parsons The New School dove ora insegna. Attualmente lavora come Ingegnere Grafico alla Mapzen realizzando strumenti cartografici openSource. [Jen Lowe](http://jenlowe.net/) è una scienziata indipendente e comunicatrice di dati alla Datatelling dove riunisce persone + numeri + parole. Insegna alla SVA's Design per il programma di Social Innovation, ha co-fondato la School for Poetic Computation, ha insegnato Matematica per Artisti al NYU ITP, ha fatto della ricerca al Spatial Information Design Lab presso la Columbia University, e ha contribuito con idee alla White House Office of Science and Technology Policy. Ha parlato al SXSW e Eyeo. Il suo lavoro è stato trattato dal The New York Times and Fast Company. La sua ricerca, i suoi scritti e la sue dissertazioni esplorano le promesse e le implicazioni dei dati e della tecnologia nella società. Ha una laurea triennale in Matematica Applicata e una laurea specialistica in Scienze Informatiche. Spesso combattiva, è sempre dalla parte dell'amore. ## Ringraziamenti Grazie a [Scott Murray](http://alignedleft.com/) per l'ispirazione e i consigli. Grazie a [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo), a [Nicolas Barradeau](https://twitter.com/nicoptere), a [Karim Naaji](http://karim.naaji.fr/) per aver contribuito con il loro sostegno, con delle buone idee e con del codice. Grazie a [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo) e a [Sawako](https://twitter.com/sawakohome) per la [traduzione giapponese (日本語訳)](?lan=jp) Grazie a [Tong Li](https://www.facebook.com/tong.lee.9484) e a [Yi Zhang](https://www.facebook.com/archer.zetta?pnref=story) per la [traduzione cinese (中文版)](?lan=ch) Grazie a [Jae Hyun Yoo](https://www.facebook.com/fkkcloud) per la [traduzione (한국어)](?lan=kr) coreana Grazie a Nahuel Coppero (Necsoft) per la [traduzione (español)](?lan=es) spagnola Grazie a [Nicolas Barradeau](https://twitter.com/nicoptere) e a [Karim Naaji](http://karim.naaji.fr/) per la [traduzione (français)](?lan=fr) francese Grazie a [Andrea Rovescalli](https://www.earove.info) per la [traduzione](?lan=it) italiana Grazie a [Manoylov Andriy](https://twitter.com/ManoylovAC) per la [traduzione ucraina (українська)](?lan=ua) Grazie a tutti coloro i quali hanno creduto in questo progetto e [contribuito con correzioni](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) o donazioni. ## Come ottenere i nuovi capitoli? Iscriviti alla newsletter o seguici su [Twitter](https://twitter.com/bookofshaders) / Mastodon / [Discord](shader.zone) --- ### README Jp (README-jp.md) # The Book of Shaders [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/)、[Jen Lowe](http://jenlowe.net/)著 この本はフラグメントシェーダーについてのガイドブックです。難解で複雑なフラグメントシェーダーの世界を、一歩一歩わかりやすくご案内します。 ## 翻訳について この文書はPatricio Gonzalez VivoのThe Book of Shaderの日本語訳です。 技術的な内容はできる限り正確に伝えるように心がけていますが、その他の部分では言葉を補ったり簡略化したり、表現を変えている部分もあります。英語が得意な方はぜひ原文もお読みください。 フィードバックには[githubのレポジトリ](https://github.com/patriciogonzalezvivo/thebookofshaders)をご利用ください。 ## 目次 * [イントロダクション](00/?lan=jp) * 初めの一歩 * [シェーダーとは?](01/?lan=jp) * [ハロー・ワールド!](02/?lan=jp) * [ユニフォーム変数](03/?lan=jp) * [シェーダーを使う](04/?lan=jp) * アルゴリズムで絵を描く * [シェイピング関数](05/?lan=jp) * [色について](06/?lan=jp) * [形について](07/?lan=jp) * [二次元行列](08/?lan=jp) * [パターン](09/?lan=jp) * Generative designs * [ランダム](10/?lan=jp) * [ノイズ](11/?lan=jp) * [セルラーノイズ](12/?lan=jp) * [Fractional brownian motion](13/) * Fractals * Image processing: * Textures * Image operations * Kernel convolutions * Filters * Others effects * Simulation * Pingpong * Conway * Ripples * Water color * Reaction diffusion * Voronoi * 3D graphics * Lights * Normal-maps * Bump-maps * Ray marching * Environmental-maps (spherical and cube) * Reflect and refract * [Appendix:](appendix/) Other ways to use this book * [How can I navigate this book offline?](appendix/) * [How to run the examples on a Raspberry Pi?](appendix/) * [How to print this book?](appendix/) * [Examples Gallery](examples/) * [Glossary](glossary/) ## 著者について [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/)(1982年、アルゼンチン、ブエノスアイレス生) はニューヨーク在住のアーティスト/開発者です。有機的なものと人工的なもの、アナログとデジタル、個人と集団の狭間を探求し、プログラミングコードを表現手段としてより良い共存のあり方を模索しています。 Patricioは心理療法(psychotherapy)と表現療法(expressive art therapy)に精通しており、パーソンズ美術大学でデザイン&テクノロジーのMFA(Master of Fine Arts - 美術系の修士に相当)を取得しています。現在は[Mapzen](https://mapzen.com/)でグラフィックエンジニアとしてオープンソースのマッピングツールの開発に携わっています。 ## 訳者について [この人](http://www.kynd.info) が翻訳しました。冒険野郎マクガイバーは見たことがありません。一部[助っ人](http://troncolon.com/)の力も借りています。 ## 謝辞 妻の[Jen Lowe](http://www.datatelling.com/)はこの本の編集のために時間を割き、献身的にサポートしてくれました。ありがとう。 インスピレーションとアドバイスを与えてくれた[Scott Murray](http://alignedleft.com/)、日本語訳を担当してくれた[Kynd](https://twitter.com/kyndinfo)、素晴らしいアイデアとコードで貢献してくれた[Karim Naaji](http://karim.naaji.fr/) にも感謝します。 [(українська) ウクライナ語](?lan=ua)の翻訳をしてくれた [Manoylov Andriy](https://twitter.com/ManoylovAC) にも感謝します。 そして最後に、このプロジェクトを応援し[改善の手助けをしてくれた方々](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors)、寄付をくださったすべての皆様に感謝を述べたいと思います。 ## アップデートのお知らせ ニュースレターにサインアップするか [Twitter](https://twitter.com/bookofshaders) / Mastodon / [Discord](shader.zone) をフォローしてください。日本語版の更新は[訳者のアカウント](https://twitter.com/kyndinfo)でもお知らせします。 --- ### README Kr (README-kr.md) # The Book of Shaders *by [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/)* 이것은 황량하게 넓고 복잡한 Fragment Shader의 세계를 한단계씩 살펴보는 지침서입니다. ## 번역에 대하여 이 문서는 Patricio Gonzalez Vivo의 The Book of Shader의 한국어 번역입니다. ## 차례 * [이 책에 대하여](00/?lan=kr) * 시작하기 앞서 * [쉐이더란 무엇인가?](01/?lan=kr) * [“헬로 월드!”](02/?lan=kr) * [유니폼](03/?lan=kr) * [쉐이더 실행하기](04/?lan=kr) * Algorithmic drawing * [모양 그리기](05/?lan=kr) * [색에 대해](06/?lan=kr) * [형태에 대해](07/?lan=kr) * [행렬](08/?lan=kr) * [패턴](09/?lan=kr) * Generative designs * [랜덤](10/?lan=kr) * [노이즈](11/?lan=kr) * [셀룰러 노이즈](12/?lan=kr) * [분수 브라운운동](13/?lan=kr) * 프랙탈 * Image processing: * Textures * Image operations * Kernel convolutions * Filters * Others effects * Simulation * Pingpong * Conway * Ripples * Water color * Reaction diffusion * 3D graphics * Lights * Normal-maps * Bump-maps * Ray marching * Environmental-maps (spherical and cube) * Reflect and refract * [부록:](appendix/) 이 책을 활용하는 다른 방법들 * [이 책을 오프라인(off-line)으로 보는 방법](appendix/00/) * [라즈베리 파이에서 예제를 실행하는 방법](appendix/01/) * [이 책을 인쇄하는법](appendix/02/) * [Collaborator로 기여하기](appendix/03/) * [JS 사용자분들을 위한 안내서](appendix/04/) by [Nicolas Barradeau](http://www.barradeau.com/) * [예제 갤러리](examples/) * [용어집](glossary/) ## 저자 소개 [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) (1982, 부에노스 아이레스, 아르헨티나) 는 뉴욕 기반의 아티스트 겸 개발자이다. 그는 유기적요소와 인공적요소, 아날로그와 디지털, 단일적요소와 집단적요소 사이를 탐험한다. 그는 사람들과 함께 개발하기위해 코드를 표현요소로 사용해 작업을 한다. Patricio는 심리치료 및 표현예술을 공부했다. 그는 파슨스대학에서 디자인 및 기술 석사학위를 보유하고 있고 그곳에서 학생을 가르치고 있다. 또한 그는 현재 Mapzen에서 그래픽스 엔지니어로 맵을 만드는 오픈소스툴을 개발중에 있다. [Jen Lowe](http://jenlowe.net/) 은 Datatelling에서 사람+숫자+단어를 한데 모으는 데이터과학자이자 커뮤니케이터다. 그녀는 SVA의 사회혁신 프로그램 설계를 강의하고, 시적연산학교를 공동 설립했으며, NYU ITP에서 아티스트를 위한 수학을 가르쳤고, 컬럼비아 대학교의 공간 정보 디자인 연구소에서 연구했으며, 백악관 과학기술 정책실에서 아이디어를 기여했다. 그녀는 SXSW와 Eyeo에서 연설해왔다. 그녀의 작품은 뉴욕타임즈와 패스트 컴퍼니에서 보도 되었다. 그녀의 연구, 글쓰기 및 연설은 사회에서 데이터와 기술의 약속과 시사점을 탐구한다. 그녀는 응용수학 학사, 정보과학 석사 학위를 가지고 있다. 그녀는 종종 저항적이면서도 항상 사랑의 편에 선다. ## 감사의 표시 영감과 격려를 아끼지 않는 [Scott Murray](http://alignedleft.com/)에게 감사를 표합니다. 좋은 아이디어와 코드를 제공해주는 [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo), [Nicolas Barradeau](https://twitter.com/nicoptere), [Karim Naaji](http://karim.naaji.fr/)에게 감사를 표합니다. 일본어 번역을 맡고 있는 [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo) 와 [Sawako](https://twitter.com/sawakohome) 에게 감사를 표합니다. [Japanese translation (日本語訳)](?lan=jp) 중국어 번역을 맡고 있는 [Tong Li](https://www.facebook.com/tong.lee.9484) 와 [Yi Zhang](https://www.facebook.com/archer.zetta?pnref=story) 에게 감사를 표합니다. [Chinese translation (中国的翻译)](?lan=ch) 한국어 번역을 맡고 있는 [유재현](https://www.facebook.com/fkkcloud) 과 [김준](https://github.com/rlawns324) 에게 감사를 표합니다. [Korean translation (한국어)](?lan=kr) 스페인어 번역을 맡고 있는 Nahuel Coppero (Necsoft) 에게 감사를 표합니다. [Español translation](?lan=es) 포르투갈어 번역을 맡고 있는 [Raphaela Protásio](https://github.com/Rawphs) 와 [Lucas Mendonça](https://github.com/luuchowl) 에게 감사를 표합니다. [Portugues translation](?lan=pt) 프랑스어 번역을 맡고 있는 [Nicolas Barradeau](https://twitter.com/nicoptere) 와 [Karim Naaji](http://karim.naaji.fr/) 에게 감사를 표합니다. [Français translation](?lan=fr) 이탈리아어 번역을 맡고 있는 [Andrea Rovescalli](https://www.earove.info) 에게 감사를 표합니다. [Italiano translation](?lan=it) 독일어 번역을 맡고 있는 [Michael Tischer](http://www.mitinet.de) 에게 감사를 표합니다.[Deutsch translation](?lan=de) 러시아어 번역을 맡고 있는 [Sergey Karchevsky](https://www.facebook.com/sergey.karchevsky.3) 에게 감사를 표합니다. [Russian translation](?lan=ru) 러시아어 번역을 맡고 있는 [Manoylov Andriy](https://twitter.com/ManoylovAC) 에게 감사를 표합니다. [Ukrainian translation (українська)](?lan=ua) [pdf/epub 배포](https://thebookofshaders.com/appendix/02/) 수정 및 개선을 맡고 있는 [Andy Stanton](https://andy.stanton.is/) 에게 감사를 표합니다. 이 프로젝트를 격려해주시고 기부해주신 모든 분들께 감사를 드립니다. [Contributed with fixes](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) ## 새로운 챕터 업데이트 받기 뉴스 업데이트를 위해 팔로우 해주세요. follow it on [Twitter](https://twitter.com/bookofshaders) / Mastodon / [Discord](shader.zone) --- ### README Pl (README-pl.md) # The Book of Shaders *autorstwa [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) i [Jen Lowe](http://jenlowe.net/)* Łagodny, krok po kroku przewodnik przez abstrakcyjny i złożony świat Fragment Shaderów. ## Spis treści * [O książce](00/?lan=pl) * Wprowadzenie * [Czym jest shader?](01/?lan=pl) * ["Witaj świecie!"](02/?lan=pl) * [Uniformy](03/?lan=pl) * [Uruchomienie shaderu](04/?lan=pl) * Rysowanie algorytmiczne * [Shaping functions](05/?lan=pl) * [Kolory](06/?lan=pl) * [Kształty](07/?lan=pl) * [Macierze](08/?lan=pl) * [Wzorce](09/?lan=pl) * Design generatywny * [Random](10/?lan=pl) * [Noise](11/?lan=pl) * [Cellular noise](12/?lan=pl) * [Fractal Brownian Motion](13/?lan=pl) * Fraktale * Image processing * Textures * Image operations * Kernel convolutions * Filters * Other effects * Simulation * Pingpong * Conway * Ripples * Water color * Reaction diffusion * 3D graphics * Lights * Normal-maps * Bump-maps * Ray marching * Environmental-maps (spherical and cube) * Reflect and refract * [Dodatek:](appendix/?lan=pl) Inne sposoby korzystania z tej książki * [Jak mogę korzystać z tej książki offline?](appendix/00/?lan=pl) * [Jak uruchomić przykłady na Raspberry Pi?](appendix/01/?lan=pl) * [Jak wydrukować tę książkę?](appendix/02/?lan=pl) * [Jak mogę pomóc?](appendix/03/?lan=pl) * [Wprowadzenie dla biegłych w JavaScript](appendix/04/?lan=pl) by [Nicolas Barradeau](http://www.barradeau.com/) * [Galeria przykładów](examples/?lan=pl) * [Glosariusz](glossary/?lan=pl) ## O autorach [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) (1982, Buenos Aires, Argentyna) jest nowojorskim artystą i developerem. Bada granice między organicznym a syntetycznym, analogowym a cyfrowym, indywidualnym i kolektywnym. W swojej pracy używa kodu jako ekspresywnego języka, z intencją rozwijania współpracy międzyludzkiej. Patricio studiował i praktykował psychoterapię oraz arteterapię. Otrzymał tytuł magistra sztuk pięknych w Design & Technology od Parsons The New School, gdzie aktualnie uczy. Obecnie pracuje jako inżynier graficzny w Mapzen, gdzie tworzy opensource'owe narzędzia do kartografii komputerowej. [Jen Lowe](http://jenlowe.net/) jest niezależną data scientist i komunikatorką danych w Datatelling, gdzie łączy ludzi + liczby + słowa. Uczy w ramach programu Design for Social Innovation na SVA, współzałożyła School for Poetic Computation, uczyła matematyki dla artystów w NYU ITP, była badaczką w Spatial Information Design Lab na Uniwersytecie Columbia oraz zgłaszała swoje pomysły do Office of Science and Technology Policy Białego Domu. Przemawiała na SXSW i w Eyeo. Jej pracę opisywały The New York Times i Fast Company. Jej działalność badawcza, pisarska i mównicza eksplorują obietnice oraz implikacje danych i technologii dla społeczeństwa. Obroniła tytuły licencjata matematyki stosowanej oraz magistra informatyki. Często opozycyjna, ale zawsze po stronie miłości. ## Podziękowania Podziękowania dla [Scott Murray](http://alignedleft.com/) za porady i inspirację. Podziękowania dla [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo), [Nicolas Barradeau](https://twitter.com/nicoptere), [Karim Naaji](http://karim.naaji.fr/) za wsparcie, dobre pomysły i kod. Podziękowania dla [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo) i [Sawako](https://twitter.com/sawakohome) za japońskie [tłumaczenie (日本語訳)](?lan=jp) Podziękowania dla [Tong Li](https://www.facebook.com/tong.lee.9484) i [Yi Zhang](https://www.facebook.com/archer.zetta?pnref=story) za chińskie [tłumaczenie (中文版)](?lan=ch) Podziękowania dla [Jae Hyun Yoo](https://www.facebook.com/fkkcloud) i [June Kim](https://github.com/rlawns324) za koreańskie [tłumaczenie (한국어)](?lan=kr) Podziękowania dla Nahuel Coppero (Necsoft) za hiszpańskie [tłumaczenie (español)](?lan=es) Podziękowania dla [Raphaela Protásio](https://github.com/Rawphs) i [Lucas Mendonça](https://github.com/luuchowl) za portugalskie [tłumaczenie (portugues)](?lan=pt) Podziękowania dla [Nicolas Barradeau](https://twitter.com/nicoptere) i [Karim Naaji](http://karim.naaji.fr/) za francuskie [tłumaczenie (français)](?lan=fr) Podziękowania dla [Andrea Rovescalli](https://www.earove.info) za włoskie [tłumaczenie (italiano)](?lan=it) Podziękowania dla [Michael Tischer](http://www.mitinet.de) za niemieckie [tłumaczenie (deutsch)](?lan=de) Podziękowania dla [Sergey Karchevsky](https://www.facebook.com/sergey.karchevsky.3) za rosyjskie [tłumaczenie (russian)](?lan=ru) Podziękowania dla [Vu Phuong Hoang](https://www.facebook.com/vuphuonghoang88) za wietnamskie [tłumaczenie (Tiếng Việt)](?lan=vi) Podziękowania dla [Wojciecha Pachowiaka](https://github.com/WojtekPachowiak) za polskie [tłumaczenie (polski)](?lan=pl) Podziękowania dla [Manoylov Andriy](https://twitter.com/ManoylovAC) za ukraińskie [tłumaczenie (українська)](?lan=ua) Podziękowania dla [Andy Stanton](https://andy.stanton.is/) za naprawę i usprawnienie funkcji [eksportu pdf/epub ](https://thebookofshaders.com/appendix/02/) Podziękowania dla każdego, kto [współtworzy](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) ten projekt poprzez swoje rady, korekty lub finansowe wsparcie. ## Zdobądź nowe rozdziały Zapisz się do newslettera lub obserwuj na [Twitter](https://twitter.com/bookofshaders) / Mastodon / [Discord](shader.zone) --- ### README Pt (README-pt.md) # The Book of Shaders *por [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) e [Jen Lowe](http://jenlowe.net/)* Este é um guia passo-a-passo pelo universo abstrato e complexo de Fragment Shaders. ## Conteúdo * [Sobre este livro](00/?lan=pt) * Início * [O que é um shader?](01/?lan=pt) * [“Olá mundo!”](02/?lan=pt) * [Uniforms](03/?lan=pt) * [Executando seu shader](04/?lan=pt) * Desenho algorítmico * [Funções de forma](05/?lan=pt) * [Cores](06/?lan=pt) * [Formas](07/?lan=pt) * [Matrizes](08/?lan=pt) * [Padrões](09/?lan=pt) * Design generativo * [Aleatório](10/?lan=pt) * [Noise](11/) * [Cellular noise](12/) * [Movimento browniano fracionário](13/) * Fractais * Processamento de imagem * Texturas * Operações de imagem * Convoluções do kernel * Filtros * Outros efeitos * Simulação * Pingpong * Conway * Ondulações * Aquarela * Reação-Difusão * Gráficos em 3D * Luzes * Normal-maps * Bump-maps * Ray marching * Environmental-maps (esférico e cúbico) * Reflexão e refração * [Apêndice:](appendix/) Outras formas de usar este livro * [Como eu posso ler este livro offline?](appendix/00/) * [Como eu posso rodar os exemplos em um Raspberry Pi?](appendix/01/) * [Como imprimir este livro?](appendix/02/) * [Como eu posso colaborar?](appendix/03/) * [Uma introdução para quem é familiarizado com JS](appendix/04/) por [Nicolas Barradeau](http://www.barradeau.com/) * [Galeria de exemplos](examples/) * [Glossário](glossary/) ## Sobre os autores [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) (1982, Buenos Aires, Argentina) é um artista e desenvolvedor residente em New York. Ele explora os espaços intersticiais entre o orgânico e sintético, analógico e digital, individual e coletivo. Em seu trabalho utiliza código como linguagem expressiva com a intenção de desenvolver uma melhor conexão entre as pessoas. Patricio estudou e praticou psicoterapia e terapia de arte expressiva. Ele possui MFA em Design & Technologia pela Parsons The New School, onde hoje leciona. Atualmente trabalha como Engenheiro Gráfico na Mapzen, criando ferramentas open source de mapeamento. [Jen Lowe](http://jenlowe.net/) é uma cientista de dados independente e comunicadora de dados na Datatelling, onde une pessoas + números + palavras. Ela leciona no SVA's Design for Social Innovation program, co-fundou a School for Poetic Computation, ensinou Math for Artists na NYU ITP, pesquisou no Spatial Information Design Lab na Columbia University, e contribuiu com ideias na White House Office of Science and Technology Policy. Ela discursou no SXSW e Eyeo. Seu trabalho foi coberto pelo The New York Times e Fast Company. Sua pesquisa, escritos, e palestras exploram as promessas e implicações dos dados e da technologia na sociedade. Ela é bacharel em Matemática Aplicada e mestre em Ciência da Informação. Frequentemente oposicionista, ela está sempre do lado do amor. ## Acknowledgements Obrigado [Scott Murray](http://alignedleft.com/) pela inspiração e conselhos. Obrigado [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo), [Nicolas Barradeau](https://twitter.com/nicoptere), [Karim Naaji](http://karim.naaji.fr/) por contribuir com apoio, boas ideias e código. Obrigado [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo) e [Sawako](https://twitter.com/sawakohome) pela [tradução em Japonês (日本語訳)](?lan=jp) Obrigado [Tong Li](https://www.facebook.com/tong.lee.9484) e [Yi Zhang](https://www.facebook.com/archer.zetta?pnref=story) pela [tradução em Chinês (中文版)](?lan=ch) Obrigado [Jae Hyun Yoo](https://www.facebook.com/fkkcloud) pela [tradução em Koreano (한국어)](?lan=kr) Obrigado Nahuel Coppero (Necsoft) pela [tradução em Espanhol (español)](?lan=es) Obrigado [Nicolas Barradeau](https://twitter.com/nicoptere) e [Karim Naaji](http://karim.naaji.fr/) pela [tradução em Francês (français)](?lan=fr) Obrigado [Andrea Rovescalli](https://www.earove.info) pela [tradução em Italiano (italiano)](?lan=it) Obrigado [Michael Tischer](http://www.mitinet.de) pela [tradução em Alemão (deutsch)](?lan=de) Obrigado [Sergey Karchevsky](https://www.facebook.com/sergey.karchevsky.3) pela [tradução em Russo (russian)](?lan=ru) Obrigado [Manoylov Andriy](https://twitter.com/ManoylovAC) pela [tradução em Ucraniano (українська)](?lan=ua) Obrigado [Andy Stanton](https://andy.stanton.is/) por corrigir e melhorar [a pipeline para exportar pdf/epub](https://thebookofshaders.com/appendix/02/) Obrigado a todos que acreditaram neste projeto e [contribuíram com correções](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) ou doações. ## Receba novos capítulos Assine a newsletter ou nos siga no [Twitter](https://twitter.com/bookofshaders) / Mastodon / [Discord](shader.zone) --- ### README Ru (README-ru.md) # The Book of Shaders *[Патрицио Гонзалес Виво](http://patriciogonzalezvivo.com/) и [Джен Лав](http://jenlowe.net/)* Пошаговое руководство по абстрактной и сложной вселенной фрагментных шейдеров. ## Содержание * [Об этой книге](00/?lan=ru) * Введение * [Что такое шейдер?](01/?lan=ru) * [“Hello world!”](02/?lan=ru) * [Uniform-переменные](03/?lan=ru) * [Запуск шейдера](04/?lan=ru) * Алгоритмическое рисование * [Формообразующие функции](05/?lan=ru) * [Цвета](06/?lan=ru) * [Фигуры](07/?lan=ru) * [Матрицы](08/?lan=ru) * [Узоры](09/?lan=ru) * Генеративный дизайн * [Беспорядок](10/?lan=ru) * [Шум](11/?lan=ru) * [Клеточный шум](12/?lan=ru) * [Фрактальное броуновское движение](13/?lan=ru) * Фракталы * Обработка изображений * Текстуры * Операции над изображениями * Свёртка с ядром * Фильтры * Другие эффекты * Симуляция * Пинг-понг * Игра «Жизнь» Конвея * Рябь * Вода * Реакционно-диффузная модель * 3D-графика * Освещение * Карты нормалей * Карты высот * Ray marching * Карты окружения (сферические и кубические) * Отражение и преломление * [Приложение:](appendix/?lan=ru) Другие варианты использования этой книги * [Как читать книгу оффлайн?](appendix/00/?lan=ru) * [Как запустить примеры на Raspberry Pi?](appendix/01/?lan=ru) * [Как напечатать книгу?](appendix/02/?lan=ru) * [Как принять участие в создании книги?](appendix/03/?lan=ru) * [Введение для JavaScript-программистов](appendix/04/?lan=ru) ([Николя Баррадо](http://www.barradeau.com/)) * [Примеры](examples/?lan=ru) * [Глоссарий](glossary/) ## Об авторах [Патрицио Гонзалес Виво](http://patriciogonzalezvivo.com/) (1982, Буэнос Айрес, Аргентина) - художник и разработчик, живущий в Нью-Йорке. Он исследует многообразие пространств между природным и рукотворным, аналоговым и цифровым, индивидуальным и коллективным. В своей работе он использует код как средство выразительности, делая этот мир лучше. Патрицио изучал и практиковал психотерапию и арт-терапию. Он получил степень магистра наук и искусств в области дизайна и технологии в Parsons The New School, где в настоящее время преподаёт. Сейчас он работает инженером по графике в Mapzen, где создаёт картографический инструментарий с открытым исходным кодом. [Джен Лав](http://jenlowe.net/) собирает воедино людей, числа и слова, работая независимым исследователем данных в Datatelling. Она преподаёт в Нью-Йоркской школе изобразительного искусства по программе социальных инноваций, является соучредителем Школы поэтических коммуникаций, преподавала математику для художников в NYU ITP, занималась исследованиями в Лаборатории пространственного дизайна в Университете Колумбии, вносила предложения в офис Белого дома по науке и технологиям. Выступала на SXSW и Eyeo. Её работы освещались в The New York Times и Fast Company. Её исследования, публикации и доклады затрагивают перспективы и последствия развития технологий обработки данных для общества. Имеет степень бакалавра в области прикладной математики и степень магистра в области информатики. ## Благодарности Спасибо [Скотту Мюррею](http://alignedleft.com/) за вдохновение и советы. Спасибо [Кеничи Йонеде (Kynd)](https://twitter.com/kyndinfo), [Николя Баррадо](https://twitter.com/nicoptere) и [Кариму Нааджи](http://karim.naaji.fr/) за поддержку, хорошие идеи и код. Спасибо [Кеничи Йонеде (Kynd)](https://twitter.com/kyndinfo) и [Савако](https://twitter.com/sawakohome) за [японский перевод (日本語訳)](?lan=jp) Спасибо [Тонь Ли](https://www.facebook.com/tong.lee.9484) и [И Жань](https://www.facebook.com/archer.zetta?pnref=story) за [китайский перевод (中文版)](?lan=ch) Спасибо [Ча Хьюн Ю](https://www.facebook.com/fkkcloud) за [корейский перевод (한국어)](?lan=kr) Спасибо [Науэлю Копперо (Necsoft)](http://hinecsoft.com/) за [испанский перевод (español)](?lan=es) Спасибо [Николя Баррадо](https://twitter.com/nicoptere) и [Кариму Нааджи](http://karim.naaji.fr/) за [французский перевод (français)](?lan=fr) Спасибо [Андреа Ровескалли](https://www.earove.info) за [итальянский перевод (italiano)](?lan=it) Спасибо [Майклу Тишеру](http://www.mitinet.de) за [немецкий перевод (deutsch)](?lan=de) Спасибо [Сергею Карчевскому](https://www.facebook.com/sergey.karchevsky.3) за [русский перевод](?lan=ru) Спасибо [Андрею Манойлову](https://twitter.com/ManoylovAC) за [украинский перевод](?lan=ua) Спасибо всем кто поверил в этот проект и поддержал его [исправлениями](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) или пожертвованиями. ## Новые параграфы Чтобы получать оповещение о новых параграфах, подпишитесь на почтовую рассылку или [Твиттер](https://twitter.com/bookofshaders) / Mastodon / [Discord](shader.zone) --- ### README Tr (README-tr.md) # The Book of Shaders *[Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) ve [Jen Lowe](http://jenlowe.net/) tarafından* Bu, Fragment Shader'ların soyut ve karmaşık evrenine adım adım, nazik bir rehberdir. ## İçindekiler * [Bu kitap hakkında](00/?lan=tr) * Başlarken * [Shader nedir?](01/?lan=tr) * [“Merhaba dünya!”](02/?lan=tr) * [Uniform'lar](03/?lan=tr) * [Shader'ınızı çalıştırma](04/?lan=tr) * Algoritmik çizim * [Şekillendirme fonksiyonları](05/?lan=tr) * [Renkler](06/?lan=tr) * [Şekiller](07/?lan=tr) * [Matrisler](08/?lan=tr) * [Desenler](09/?lan=tr) * Üretken tasarımlar * [Rastgelelik (Random)](10/?lan=tr) * [Gürültü (Noise)](11/?lan=tr) * [Hücresel gürültü](12/?lan=tr) * [Fraktal Brownian hareketi](13/?lan=tr) * Fraktallar * Görüntü işleme * Dokular (Textures) * Görüntü işlemleri * Kernel konvolüsyonları * Filtreler * Diğer efektler * Simülasyon * Pingpong * Conway * Dalgalanmalar * Suluboya * Reaksiyon difüzyonu * 3D grafikler * Işıklar * Normal haritaları * Kabartma haritaları (Bump-maps) * Işın yürütme (Ray marching) * Çevresel haritalar (küresel ve küp) * Yansıma ve kırılma * [Ek:](appendix/?lan=tr) Bu kitabı kullanmanın diğer yolları * [Bu kitapta çevrimdışı nasıl gezinebilirim?](appendix/00/?lan=tr) * [Örnekleri bir Raspberry Pi üzerinde nasıl çalıştırırım?](appendix/01/?lan=tr) * [Bu kitabı nasıl yazdırırım?](appendix/02/?lan=tr) * [Nasıl katkıda bulunabilirim?](appendix/03/?lan=tr) * [JS'den gelenler için bir giriş](appendix/04/?lan=tr) - [Nicolas Barradeau](http://www.barradeau.com/) tarafından * [Örnekler Galerisi](examples/) * [Sözlük](glossary/) ## Yazarlar Hakkında [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) (1982, Buenos Aires, Arjantin), New York merkezli bir sanatçı ve geliştiricidir. Organik ve sentetik, analog ve dijital, bireysel ve kolektif arasındaki ara alanları keşfeder. Çalışmalarında kodu, birlikte daha iyi bir gelecek geliştirme niyetiyle etkileyici bir dil olarak kullanır. Patricio psikoterapi ve dışavurumcu sanat terapisi okumuş ve uygulamıştır. Parsons The New School'dan Tasarım ve Teknoloji alanında yüksek lisans derecesine sahiptir ve şu anda orada ders vermektedir. Halen Mapzen'de açık kaynak haritalama araçları yapan bir Grafik Mühendisi olarak çalışmaktadır. [Jen Lowe](http://jenlowe.net/), insanları + sayıları + kelimeleri bir araya getirdiği Datatelling'de bağımsız bir veri bilimcisi ve veri iletişimcisidir. SVA'nın Sosyal İnovasyon için Tasarım programında ders vermekte, School for Poetic Computation'ın kurucu ortaklığını yapmış, NYU ITP'de Sanatçılar için Matematik dersi vermiş, Columbia Üniversitesi'ndeki Uzamsal Bilgi Tasarım Laboratuvarı'nda araştırmalar yapmış ve Beyaz Saray Bilim ve Teknoloji Politikası Ofisi'nde fikirlere katkıda bulunmuştur. SXSW ve Eyeo'da konuşmalar yapmıştır. Çalışmaları The New York Times ve Fast Company tarafından ele alınmıştır. Araştırmaları, yazıları ve konuşmaları verinin ve teknolojinin toplumdaki vaatlerini ve etkilerini araştırmaktadır. Uygulamalı Matematik alanında lisans ve Bilgi Bilimi alanında yüksek lisans derecesine sahiptir. Genellikle muhalif olsa da, her zaman sevgiden yanadır. ## Teşekkürler İlham ve tavsiyeler için [Scott Murray](http://alignedleft.com/)'ye teşekkürler. Destekleri, iyi fikirleri ve kod katkıları için [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo), [Nicolas Barradeau](https://twitter.com/nicoptere), [Karim Naaji](http://karim.naaji.fr/)'ye teşekkürler. [Japonca çeviri (日本語訳)](?lan=jp) için [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo) ve [Sawako](https://twitter.com/sawakohome)'ya teşekkürler. [Çince çeviri (中文版)](?lan=ch) için [Tong Li](https://www.facebook.com/tong.lee.9484) ve [Yi Zhang](https://www.facebook.com/archer.zetta?pnref=story)'a teşekkürler. Korece [çeviri (한국어)](?lan=kr) için [Jae Hyun Yoo](https://www.facebook.com/fkkcloud) ve [June Kim](https://github.com/rlawns324)'e teşekkürler. İspanyolca [çeviri (español)](?lan=es) için Nahuel Coppero (Necsoft)'ya teşekkürler. Portekizce [çeviri (portugues)](?lan=pt) için [Raphaela Protásio](https://github.com/Rawphs) ve [Lucas Mendonça](https://github.com/luuchowl)'ya teşekkürler. Fransızca [çeviri (français)](?lan=fr) için [Nicolas Barradeau](https://twitter.com/nicoptere) ve [Karim Naaji](http://karim.naaji.fr/)'ye teşekkürler. İtalyanca [çeviri (italiano)](?lan=it) için [Andrea Rovescalli](https://www.earove.info)'ye teşekkürler. Almanca [çeviri (deutsch)](?lan=de) için [Michael Tischer](http://www.mitinet.de)'e teşekkürler. Rusça [çeviri (russian)](?lan=ru) için [Sergey Karchevsky](https://www.facebook.com/sergey.karchevsky.3)'ye teşekkürler. Vietnamca [çeviri (Tiếng Việt)](?lan=vi) için [Vu Phuong Hoang](https://www.facebook.com/vuphuonghoang88)'a teşekkürler. Lehçe [çeviri (polski)](?lan=pl) için [Wojciech Pachowiak](https://github.com/WojtekPachowiak)'a teşekkürler. Ukraynaca [çeviri (український переклад)](?lan=ua) için [Manoylov Andriy](https://twitter.com/ManoylovAC)'ye teşekkürler. Türkçe [çeviri (Türkçe)](?lan=tr) için [Batuhan Dev](https://batudev.framer.website/portfolio)'e teşekkürler. [PDF/epub dışa aktarma hattını](https://thebookofshaders.com/appendix/02/?lan=tr) düzelttiği ve geliştirdiği için [Andy Stanton](https://andy.stanton.is/)'a teşekkürler. Bu projeye inanan ve [düzeltmelerle](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) veya bağışlarla katkıda bulunan herkese teşekkürler. ## Yeni bölümleri alın Haber bültenine kaydolun veya [Twitter](https://twitter.com/bookofshaders) / Mastodon / [Discord](shader.zone) üzerinden takip edin. ## LİSANS Telif Hakkı (c) Patricio Gonzalez Vivo, 2015 - http://patriciogonzalezvivo.com/ Tüm hakları saklıdır. --- ### README Vi (README-vi.md) # The Book of Shaders *Tác giả: [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) và [Jen Lowe](http://jenlowe.net/)* Quyển sách này sẽ hướng dẫn người đọc khám phá dần vũ trụ trừu tượng và phức tạp của Fragment Shader. ## Nội dung * [Lời nói đầu](00/?lan=vi) * Giới thiệu * [Shader là gì?](01/?lan=vi) * [“Hello world!”](02/?lan=vi) * [Uniform](03/?lan=vi) * [Chạy thử shader](04/?lan=vi) * Các thuật toán hình học * [Các hàm số cơ bản (Hàm hình dạng - Shape function)](05/?lan=vi) * [Màu sắc](06/?lan=vi) * [Hình dạng](07/?lan=vi) * [Ma trận](08/?lan=vi) * [Mẫu hoa văn (Pattern)](09/?lan=vi) * Các thiết kế ngẫu nhiên * [Ngẫu nhiên](10/?lan=vi) * [Nhiễu (Noise)](11/?lan=vi) * [Nhiễu mô phỏng tế bào (Cellular noise)](12/?lan=vi) * [Chuyển động Brown (Fractional Brownian motion)](13/?lan=vi) * Phân dạng (Fractals) * Xử lý ảnh * Ảnh vân bề mặt (Texture) * Các phép toán xử lý ảnh * Tích chập (Kernel convolution) * Bộ lọc (Filter) * Các hiệu ứng khác * Mô phỏng * Bóng bàn (Pingpong) * Tiến trình sống của Conway * Gợn sóng * Màu nước * Mô hình Phản ứng-Khuếch tán (Reaction-Diffusion) * Đồ hoạ 3 chiều * Ánh sáng * Giả lập chi tiết bề mặt bằng vector pháp tuyến (Normal map) * Giả lập chi tiết bề mặt từ mặt cong (Bump map) * Dò tia quang học (Ray marching) * Ánh xạ từ môi trường bằng mặt cầu hoặc khối lập phương (Environmental map) * Phản xạ và khúc xạ * [Phụ lục:](appendix/?lan=vi) Các cách khác để đọc và đóng góp cho quyển sách này * [Làm thế nào để đọc quyển sách này mà không cần Internet ?](appendix/00/?lan=vi) * [Làm thế nào để chạy thử ví dụ trên Raspberry Pi ?](appendix/01/?lan=vi) * [Làm thế nào để in quyển sách này ?](appendix/02/?lan=vi) * [Làm thế nào để góp sức cho quyển sách này ?](appendix/03/?lan=vi) * [Giới thiệu cho người đã biết Javascript](appendix/04/?lan=vi) từ [Nicolas Barradeau](http://www.barradeau.com/) * [Thư viện các ví dụ](examples/?lan=vi) * [Chú giải](glossary/?lan=vi) ## Tác giả [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com/) (sinh năm 1982 tại Buenos Aires, Argentina) là artist kiêm developer ở New York。 Anh ấy khám phá sự giao thoa giữa hữu cơ và vô cơ, analog và kỹ thuật số, cá nhân và tập thể. Trong công việc, anh ấy dùng code như một cách đóng góp tạo nên những điều tốt đẹp hơn cho cộng đồng. Patricio đã học tập và công tác trong ngành tâm lý trị liệu và nghệ thuật biểu cảm. Anh ấy có bằng Thạc sỹ ngành Thiết kế và Công nghệ từ trường Parson The New School, cũng là nơi anh ấy đang giảng dạy. Hiện tại, anh ấy là Kỹ sư đồ hoạ tại Mapzen để phát triển các công cụ cho openSource. [Jen Lowe](http://jenlowe.net/) là một nhà khoa học dữ liệu độc lập ở Datatelling, nơi mà cô ấy khám phá mối liên hệ giữa con người với chữ số và ngôn từ. Cô ấy hiện đang giảng dạy ở khoa Thiết kế của trường Mỹ thuật New York theo chương trình Social Innovation. Cô ấy đã cùng sáng lập ra School for Poetic Computation, dạy môn Toán chuyên ngành nghệ thuật ở khoa Sau Đại Học của trường New York, công tác tại phòng nghiên cứu Spatial Information Design tại Đại học Columbia và còn đóng góp nhiều ý tưởng cho Văn phòng Nhà Trắng về các chính sách Khoa học công nghệ. Cô ấy đã từng thuyết trình ở SXSW và Eyeo. Sản phẩm của cô ấy đã xuất hiện trên trang bìa của tờ The New York Times và Fast Company. Công việc nghiên cứu, sáng tác và thuyết trình của cô ấy chủ yếu khai thác đề tài về tiềm năng và ý nghĩa của việc áp dụng các thành tựu của ngành dữ liệu và công nghệ cho cộng đồng. Cô ấy có bằng Cử nhân khoa học ngành Toán ứng dụng và bằng Thạc sỹ ngành Khoa học thông tin. Nhưng cô ấy cũng là một người hay mơ mộng. ## Lời cảm ơn Cảm ơn [Scott Murray](http://alignedleft.com/) vì niềm cảm hứng và những lời khuyên. Cảm ơn [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo), [Nicolas Barradeau](https://twitter.com/nicoptere), [Karim Naaji](http://karim.naaji.fr/) vì đã hỗ trợ cả về ý tưởng lẫn code. Cảm ơn [Kenichi Yoneda (Kynd)](https://twitter.com/kyndinfo) và [Sawako](https://twitter.com/sawakohome) vì [Bản dịch tiếng Nhật (日本語訳)](?lan=jp) Cảm ơn [Tong Li](https://www.facebook.com/tong.lee.9484) và [Yi Zhang](https://www.facebook.com/archer.zetta?pnref=story) vì [Bản dịch tiếng Trung (中文版)](?lan=ch) Cảm ơn [Jae Hyun Yoo](https://www.facebook.com/fkkcloud) vì [Bản dịch tiếng Hàn (한국어)](?lan=kr) Cảm ơn Nahuel Coppero (Necsoft) vì [Bản dịch tiếng Tây Ban Nha (español)](?lan=es) Cảm ơn [Raphaela Protásio](https://github.com/Rawphs) và [Lucas Mendonça](https://github.com/luuchowl) vì [Bản dịch tiếng Bồ Đào Nha (portugues)](?lan=pt) Cảm ơn [Nicolas Barradeau](https://twitter.com/nicoptere) và [Karim Naaji](http://karim.naaji.fr/) vì [Bản dịch tiếng Pháp (français)](?lan=fr) Cảm ơn [Andrea Rovescalli](https://www.earove.info) vì [Bản dịch tiếng Ý (italiano)](?lan=it) Cảm ơn [Michael Tischer](http://www.mitinet.de) vì [Bản dịch tiếng Đức (deutsch)](?lan=de) Cảm ơn [Sergey Karchevsky](https://www.facebook.com/sergey.karchevsky.3) vì [Bản dịch tiếng Nga (russian)](?lan=ru) Cảm ơn [Vu Phuong Hoang](https://github.com/DancingPhoenix88) và [Minh-Phuc Bui](https://github.com/phucbm) vì [Bản dịch tiếng Việt](?lan=vi) Cảm ơn [Manoylov Andriy](https://twitter.com/ManoylovAC) vì [Bản dịch tiếng Ukraina (українська)](?lan=ua) Cảm ơn [Andy Stanton](https://andy.stanton.is/) vì đã sửa lỗi và cải tiến [cách export quyển sách ra định dạng pdf/epub](https://thebookofshaders.com/appendix/02/?lan=vi) Cảm ơn tất cả mọi người đã tin tưởng, [cùng sửa lỗi](https://github.com/patriciogonzalezvivo/thebookofshaders/graphs/contributors) và quyên góp cho dự án này. ## Thông báo khi có chương mới Đăng ký nhận thư định kỳ hoặc theo dõi trên [Twitter](https://twitter.com/bookofshaders) / Mastodon / [Discord](shader.zone) --- ### .Travis.Yml (.travis.yml) language: python python: - 2.7 install: - sudo apt-get install cmake xorg-dev libglu1-mesa-dev texlive-xetex texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended pandoc imagemagick - # Install glfw - git clone https://github.com/glfw/glfw.git ~/glfw - cd ~/glfw - cmake . - make - sudo make install - cd - - # Install glslViewer - git clone http://github.com/patriciogonzalezvivo/glslViewer ~/glslViewer - cd ~/glslViewer - make - sudo make install - cd - before_script: - export DISPLAY=:99.0 - sh -e /etc/init.d/xvfb start - sleep 3 # give xvfb some time to start - rm -rf 12 13 14 15 16 17 18 # ugly ... script: - make && [ -e book.pdf ] --- ### 00/README (00/README.md) # Introduction The images above were made in different ways. The first one was made by Van Gogh's hand applying layer over layer of paint. It took him hours. The second was produced in seconds by the combination of four matrices of pixels: one for cyan, one for magenta, one for yellow and one for black. The key difference is that the second image is produced in a non-serial way (that means not step-by-step, but all at the same time). This book is about the revolutionary computational technique, *fragment shaders*, that is taking digitally generated images to the next level. You can think of it as the equivalent of Gutenberg's press for graphics. Fragment shaders give you total control over the pixels rendered on the screen at a super fast speed. This is why they're used in all sort of cases, from video filters on cellphones to incredible 3D video games. In the following chapters you will discover how incredibly fast and powerful this technique is and how to apply it to your professional and personal work. ## Who is this book for? This book is written for creative coders, game developers and engineers who have coding experience, a basic knowledge of linear algebra and trigonometry, and who want to take their work to an exciting new level of graphical quality. (If you want to learn how to code, I highly recommend you start with [Processing](https://processing.org/) and come back later when you are comfortable with it.) This book will teach you how to use and integrate shaders into your projects, improving their performance and graphical quality. Because GLSL (OpenGL Shading Language) shaders compile and run on a variety of platforms, you will be able to apply what you learn here to any environment that uses OpenGL, OpenGL ES or WebGL. In other words, you will be able to apply and use your knowledge with [Processing](https://processing.org/) sketches, [openFrameworks](http://openframeworks.cc/) applications, [Cinder](http://libcinder.org/) interactive installations, [Three.js](http://threejs.org/) websites or iOS/Android games. ## What does this book cover? This book will focus on the use of GLSL pixel shaders. First we'll define what shaders are; then we'll learn how to make procedural shapes, patterns, textures and animations with them. You'll learn the foundations of shading language and apply it to more useful scenarios such as: image processing (image operations, matrix convolutions, blurs, color filters, lookup tables and other effects) and simulations (Conway's game of life, Gray-Scott's reaction-diffusion, water ripples, watercolor effects, Voronoi cells, etc.). Towards the end of the book we'll see a set of advanced techniques based on Ray Marching. *There are interactive examples for you to play with in every chapter.* When you change the code, you will see the changes immediately. The concepts can be abstract and confusing, so the interactive examples are essential to helping you learn the material. The faster you put the concepts into motion the easier the learning process will be. What this book doesn't cover: * This *is not* an OpenGL or webGL book. OpenGL/webGL is a bigger subject than GLSL or fragment shaders. To learn more about OpenGL/webGL I recommend taking a look at: [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) (also known as the red book) or [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) * This *is not* a math book. Although we will cover a number of algorithms and techniques that rely on an understanding of algebra and trigonometry, we will not explain them in detail. For questions regarding the math I recommend keeping one of the following books nearby: [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) or [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). ## What do you need to start? Not much! If you have a modern browser that can do WebGL (like Chrome, Firefox or Safari) and a internet connection, click the “Next” Chapter button at the end of this page to get started. Alternatively, based on what you have or what you need from this book you can: - [Make an off-line version of this book](https://thebookofshaders.com/appendix/00/) - [Run the examples on a Raspberry Pi without a browser](https://thebookofshaders.com/appendix/01/) - [Make a PDF of the book to print](https://thebookofshaders.com/appendix/02/) - Check the [GitHub repository](https://github.com/patriciogonzalezvivo/thebookofshaders) of this book to help resolve issues and share code. --- ### 00/README Ch (00/README-ch.md) # 关于这本书 ## 引言 上面两幅图是由不同的方式制成的。第一张是梵高一层一层徒手画出来的,需要花费些时间。第二张则是用 4 个像素矩阵分秒钟生成的:一个青色,一个品红,一个黄色,和一个黑色矩阵。关键的区别在于第二张图是用非序列方式实现的(即不是一步一步实现,而是多个同时进行)。 这本书是关于这个革命性的计算机技术,片段着色器(fragment shaders),它将数字生成的图像提到了新的层次。你可以把它看做当年的古腾堡印刷术。 Fragment shaders(片段着色器)可以让你控制像素在屏幕上的快速渲染。这就是它在各种场合被广泛使用的原因,从手机的视频滤镜到酷炫的的3D视频游戏。 在接下来的章节你会发现这项技术是多么难以置信地快速和强大,还有如何将它应用到专业的和个人的作品中。 ## 这本书是为谁而写的? 这本书是写给有代码经验和线性代数、三角学的基本知识的创意编程者、游戏开发者和工程师的,还有那些想要提升他们的作品的图像质量到一个令人激动的新层次的人。(如果你想要学习编程,我强烈推荐你先学习[Processing](https://processing.org/),等你玩起来processing,再回来看这个)。 这本书会教你如何使用 shaders(着色器)并把它整合进你的项目里,以提升作品的表现力和图形质量。因为GLSL(OpenGL的绘制语言)的shaders 在很多平台都可以编译和运行,你将可以把在这里学的运用到任何使用OpenGL, OpenGL ES 和 WebGL 的环境中。也就是说,你将可以把学到的知识应用到[Processing](https://processing.org/),[openFrameworks](http://openframeworks.cc/),[Cinder](http://libcinder.org/),[Three.js](http://threejs.org/)和iOS/Android游戏中。 ## 这本书包含哪些内容? 这本书专门关于 GLSL pixel shaders。首先我们会给出shaders的定义;然后我们会学习如何制作程序里的形状,图案,材质,和与之相关的动画。你将会学到基础的着色语言并把它们应用到有用的情景中,比如:图像处理(图像运算,矩阵卷积,模糊,颜色滤镜,查找表及其他效果)和模拟(Conway 的生命游戏,Gray-Scott 反应扩散,水波,水彩效果,Voronoi 细胞等等)。到书的最后我们将看到一系列基于光线跟踪(Ray Marching)的进阶技术。 **每章都会有可以玩的交互的例子。**当你改动代码的时候,你会立刻看到这些变化。一些概念可能会晦涩难懂,而这些可交互的例子会对你学习这些材料非常有益。你越快把这些代码付诸实践,你学习的过程就会越容易。 这本书里不包括的内容有: * 这**不是**一本 openGL 或 webGL 的书。OpenGL/webGL 是一个比GLSL 或 fragment shaders 更大的主题。如果你想要学习 openGL/webGL 推荐看: [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) (也被叫做红宝书) 或 [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) 。 * 这**不是**一本数学书。虽然我们会涉及到很多关于线代和三角学的算法和技术,但我们不会详细解释它。关于数学的问题我推荐手边备一本:[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) 或 [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)。 ## 开始学习需要什么准备? 没什么。如果你有可以运行 WebGL 的浏览器(像Chrome,Firefox或Safari)和网络,点击页面底端的“下一章”按钮就可以开始了。 此外,基于你有的条件或需求你可以: * [制作一个离线版的本书](https://thebookofshaders.com/appendix/00/?lan=ch) * [用不带浏览器的树莓派来运行书中示例](https://thebookofshaders.com/appendix/01/?lan=ch) * [做一个PDF版的书用于打印](https://thebookofshaders.com/appendix/02/?lan=ch) * 用[github仓库](https://github.com/patriciogonzalezvivo/thebookofshaders)来帮助解决问题和分享代码 --- ### 00/README De (00/README-de.md) # Einleitung Die oben abgebildeten Grafiken wurden auf verschiedene Weise erstellt. Die linke Abbildung stammt aus den Händen des Malers Van Gogh, der die Farben in stundenlanger Arbeit Schicht für Schicht mit einem Pinsel aufgetragen hat. Die rechte Abbildung wurde dagegen innerhalb von wenigen Sekunden mit Hilfe von vier Pixelmatrizen erzeugt: eine für cyan, eine für magenta, eine für gelb und eine für schwarz. Der entscheidende Unterschied ist, dass das zweite Bild nicht seriell erstellt wurde, also nicht Schritt für Schritt, sondern parallel, alle Punkte zur gleichen Zeit. Dieses Buch handelt von der Rechentechnik mit dem Namen *Fragment-Shader*, die die digitale Erzeugung von Bildern revolutioniert und zu neuen Höhen geführt hat. Man kann ihre Erfindung ein wenig vergleichen mit dem Schritt von der manuellen Vervielfältigung einzelner Grafiken und Dokumente hin zur massenhaften Replikation durch Gutenbergs Druckerpresse. Fragment-Shader ermöglichen die vollständige Kontrolle über alle Bildpunkte, die als Grafik auf dem Bildschirm erscheinen. Und das mit ungeheurer Geschwindigkeit. Deshalb wird diese Technik mittlerweile in vielen Bereichen der Computergrafik angewandt, von Videofiltern auf Smartphones bis hin zu beeindruckenden 3D-Videospielen. Die folgenden Kapitel zeigen Dir, wie unglaublich schnell und leistungsfähig diese Technik ist und wie Du sie im Rahmen von privaten und beruflichen Projekten einsetzen kannst. ## Für wen ist dieses Buch geeignet? Dieses Buch wendet sich an kreative Programmierer, Spieleentwickler und Ingenieure, die bereits Programmiererfahrung und grundlegende Kenntnisse in den Bereichen linearen Algebra und Trigonometrie haben. (Falls Du erst noch programmieren lernen möchtest, empfehle ich Dir, mit [Processing](https://processing.org/) zu beginnen und anschließend mit diesem Buch fortzufahren.) Dieses Buch zeigt Dir, wie Du Shader in Deinen Projekten einsetzen kannst und wie Du die Qualität und die Geschwindigkeit von Shadern verbesserst. GLSL-Shader (GLSL steht für „OpenGL Shading Language“) lassen sich auf einer Vielzahl von Hardwareplattformen und Betriebssystemen kompilieren und ausführen. Dadurch kannst Du das erlernte Wissen in jeder Umgebung einsetzen, die OpenGL, OpenGL ES oder WebGL benutzt. In anderen Worten, Du kannst Dein Know-how u.a. beim Malen mit [Processing](https://processing.org/), bei Anwendungen für [openFrameworks](http://openframeworks.cc/), interaktiven Installationen mit [Cinder](http://libcinder.org/), Webseiten mit [Three.js](http://threejs.org/) oder bei Spielen für iOS und Android nutzen. ## Welchen Aspekten widmet sich dieses Buch? Dieses Buch behandelt hauptsächlich den Umgang mit GLSL-Pixel-Shadern. Zunächst erklären wir, was Shader sind, dann wenden wir uns der algorithmischen Erzeugung von Formen, Mustern, Texturen und Animationen zu. Du lernst die Grundlagen der Programmiersprache für OpenGL-Shader kennen und erfährst, wie man sie für konkrete Zwecke nutzt. Dazu zählt die Bildbearbeitung (Bildmanipulationen, Matrizenoperationen, Blurfilter, Farbfilter und weitere Effekte), sowie Simulationen (Conways Game of Life, Reaktion und Diffusion von Chemikalien nach Gray-Scott, Erzeugung von Wasserwellen, die Nachbildung des Malens mit Wasserfarben, Erzeugung von Voronoi-Zellen und mehr). Gegen Ende vom Buch lernst Du mehrere fortgeschrittene Techniken kennen, die mithilfe einer Technik namens *Ray-Marching* beeindruckende 2D-Grafiken aus 3D-Daten generiert werden. *In jedem Kapitel gibt es interaktive Beispiele, mit denen Du vieles ausprobieren kannst.* Sobald du etwas am Programmcode änderst, erscheinen die daraus resultierenden Veränderungen an der erzeugten Grafik sofort. Die vorgestellten Konzepte sind teilweise abstrakt und auf den ersten Blick vielleicht ein wenig verwirrend. Aber mithilfe der interaktiven Beispiele kannst Du den Lernstoff leicht nachvollziehen. Je mehr Du ausprobierst, desto einfacher wird Dir das Lernen fallen. Was dieses Buch nicht behandelt: * Dies *ist kein* Buch über OpenGL oder WebGL. OpenGL und WebGL sind ein umfassenderes Thema als GLSL- oder Fragment-Shader. Wenn Du mehr über OpenGL oder WebGL lernen möchtest, empfehle ich Dir die folgenden Materialien: [OpenGL Einführung (Englisch)](https://open.gl/introduction), [Die achte Ausgabe des „OpenGL Programming Guide“ (Englisch)](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) (auch bekannt als das „Red Book“) oder [„WebGL: Up and Running“ (Englisch)](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) * Das vorliegende Werk *ist außerdem kein* Mathematik-Buch. Obwohl wir bei vielen Techniken und Algorithmen auf Algebra und Trigonometrie zurückgreifen, werden die mathematischen Grundlagen nicht an jeder Stelle vollständig in allen Details erklärt. Bei Fragen dazu empfehle ich Dir eines der folgenden Bücher: [Dritte Ausgabe von „Mathematics for 3D Game Programming and Computer Graphics“ (Englisch)](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) oder [Zweite Ausgabe von „Essential Mathematics for Games and Interactive Applications“ (Englisch)](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). ## Was benötigst Du, um loszulegen? Nicht viel! Wenn Du auf Deinem Rechner, Smartphone oder Tablet einen modernen Webbrowser hast, der WebGL unterstützt (etwa Chrome, Firefox oder Safari), und eine Internetverbindung besteht, dann drücke einfach auf die Schaltfläche für das nächste Kapitel am Ende dieser Seite. Alternativ kannst Du auch: - [Eine Offline-Fassung von diesem Buch erstellen](https://thebookofshaders.com/appendix/?lan=de) - [Die Beispielprogramme aus diesem Buch direkt auf einem RaspberryPi ausführen (ohne Internet-Browser)](https://thebookofshaders.com/appendix/?lan=de) - [Eine druckbare PDF-Datei mit diesem Buch erzeugen](https://thebookofshaders.com/appendix/?lan=de) - Die [Github-Seite von diesem Buch](https://github.com/patriciogonzalezvivo/thebookofshaders) nutzen, um Fehler zu melden und Programmcode mit anderen Lesern zu teilen. --- ### 00/README Es (00/README-es.md) # Introducción Las imágenes que aparecen arriba fueron creadas de diferentes formas. La primera fue hecha por la mano de Van Gogh, aplicando capa por capa la pintura. Le tomó horas pintarla. La segunda fue producida en segundos mezclando cuatro matrices de pixeles: una para el cyan, otra para el magenta, otra para el amarillo y otra para el negro. La diferencia clave entre ambas es que la segunda imagen fue hecha de una manera no serializada (es decir que el proceso no fue paso a paso, sino de manera simultánea). Este libro trata sobre una técnica computacional revolucionaria, que lleva a las imágenes generadas digitalmente a un nuevo nivel, los *fragment shaders*. Esta revolución es comparable a lo que fue en su momento la imprenta de Gutemberg para la gráfica. Los fragment shaders te dan un control total sobre los pixeles renderizados en la pantalla, a una super velocidad. Este es el motivo por el que se usa en todo tipo de casos, desde filtros de video, hasta increíbles videojuegos en 3D. En los próximos capítulos descubrirás cuán increíblemente rápida y poderosa es esta técnica, y cómo incorporarla a tu trabajo personal o profesional. ## ¿Para quién es este libro? Este libro está escrito para creative coders, desarrolladores de videojuegos e ingenieros que tengan alguna experiencia con la programación, un conocimiento básico de álgebra lineal y trigonometría, y que quieran llevar su trabajo a un nuevo y emocionante nivel gráfico. (Si te interesa aprender a programar, te recomiendo comenzar con [Processing](https://processing.org/) y volver cuando te sientas cómodo). Este libro te enseñará a integrar shaders en tus proyectos, mejorando la performance y la calidad gráfica. Como los shaders GLSL (OpenGL Shading Language) se pueden compilar y correr en diferentes plataformas, podrás aplicar lo que aprendas aquí en cualquier entorno que use OpenGL, OpenGL ES o WebGL. En otras palabras podrás utilizarlo en sketches de [Processing](https://processing.org/), aplicaciones de [openFrameworks](http://openframeworks.cc/), instalaciones interactivas con [Cinder](http://libcinder.org/), incluso en web o en juegos iOS/Android con [Three.js](http://threejs.org/). ## ¿Qué temas se tratan en este libro? Este libro se enfoca en el uso de los pixel shaders GLSL. Primero definiremos qué son los shaders; luego aprenderemos a crear formas procedurales, patrones, texturas y animaciones con ellos. Aprenderás los fundamentos básicos del lenguaje y cómo aplicarlos en escenarios más útiles cómo: el procesamiento de imágenes (operaciones de imagen, convoluciones de matrices, desenfocado, filtros de color, lookup tables y otros efectos) y simulaciones (El juego de la vida de Conway, la reacción-difusión de Gray-Scott, ondas de agua, efecto de acuarela, celdas de Voronoi, etc). Hacia el final del libro veremos un conjunto de técnicas avanzadas basadas en ray marching. *Habrá ejemplos interactivos en cada uno de los capítulos para que puedas jugar con ellos.* Cuando modifiques el código, podrás ver al instante los cambios reflejados en la pantalla. Los conceptos expuestos pueden ser abstractos y confusos, por lo que los ejemplos interactivos son esenciales para comprender el material. Cuanto más rápido pongamos manos a la obra en el código, mejor lo entenderemos. Que cosas no vas a encontrar en este libro: * Este *no es* un libro sobre OpenGL o webGL. OpenGL/webGL son temas mucho más grandes que GLSL o el uso fragment shaders. Si estás interesado en aprender openGL/webGL te recomiendo mirar: [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) (también conocido como el libro rojo) o [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) * Este *no es* un libro de matemáticas. A pesar de que cubriremos un número de algoritmos y técnicas que están íntimimante relacionados con el álgebra y la trigonometría, no las explicaremos en profundidad. Si tienes alguna duda con respecto a la matemática empleada en este libro te recomiendo tener cerca alguno de estos libros: [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) o [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). ## ¿Qué necesito para comenzar? ¡No mucho! Si tienes algún navegador que cuente con WebGL (como por ejemplo Chrome, Firefox o Safari) y una conexión a internet, solo necesitas hacer clic en "Siguiente" para poder comenzar. Alternativamente, dependiendo cuales sean tus necesidades puedes: - [Crear una versión offline del libro](https://thebookofshaders.com/appendix/) - [Correr los ejemplos en una Raspberry Pi sin un navegador](https://thebookofshaders.com/appendix/) - [Crear un PDF del libro para imprimir.](https://thebookofshaders.com/appendix/) - Usar el [repositorio on-line](https://github.com/patriciogonzalezvivo/thebookofshaders) y ayudarnos a resolver problemas y compartir código. --- ### 00/README Fr (00/README-fr.md) # Introduction Les images ci-dessus ont été créees de différentes manières. La première est un tableau de Van Gogh, réalisée en appliquant des couches de peinture successives. Cela lui a pris des jours, voire des semaines. La seconde est réalisée en temps réel en combinant 4 matrices de pixels ; une pour le cyan, une pour le magenta, une pour le jaune et une pour le noir. La différence principale entre ces deux images (hormis le medium), est que la seconde n'est pas sérielle ; elle n'est pas créée par étapes successives mais d'un bloc grâce à un shader. Ce livre parle d'une technique, les *shaders*, qui permet à l'imagerie numérique de s'affranchir de la plupart des contraintes. On peut comparer l'avènement des *shaders* à l'avancée qu'a représenté la presse de Guntenberg à son époque. Les shaders donnent un contrôle total sur les pixels de l'écran à une vitesse très élevée. C'est pourquoi ils sont utilisés dans une grande variété de domaines allant des filtres photo et vidéo, aux téléphones mobiles jusqu'aux jeux vidéos 3D. Au fil des chapitres, vous découvrirez à quel point les shaders sont efficaces et comment vous pourrez vous en servir pour vos projets personnels et/ou professionnels. ## A qui s'adresse ce livre ? Ce livre est écrit pour les *creative coders*, les développeurs de jeux, les ingénieurs et les curieux ayant une expérience avec le code, des connaissances basiques en algèbre linéaire et en trigonométrie et désireux d'améliorer la qualité graphique de leurs productions. Si vous n'avez aucune connaissance en programmation, nous vous recommandons vivement de commencer par apprendre le langage [Processing](https://processing.org/) puis de revenir à ce livre lorsque vous vous sentirez plus à l'aise. Ce livre vous montrera comment utiliser et intégrer des shaders dans vos projets, comment améliorer leurs performances et leur rendu graphique. Du fait que les shaders GLSL (OpenGL Shading Language) peuvent être compilés sur diverses plateformes, il vous sera possible de réutiliser ce que vous aurez appris ici dans n'importe quel environnement utilisant OpenGL, OpenGL ES ou WebGL. Autrement dit, vous pourrez réutiliser vos connaissances sur des plateformes comme [Processing](https://processing.org/), [openFrameworks](http://openframeworks.cc/), [Cinder](http://libcinder.org/), [Three.js](http://threejs.org/) ou iOS et Android. ## Que contient ce livre ? Ce livre se concentre sur l'utilisation des shaders GLSL. Premièrement, nous définirons ce que sont les shaders; puis nous apprendrons à dessiner des formes, des textures et des motifs de manière procédurale. Vous apprendrez les bases du langage de shading avant de les utiliser sur des cas concrets comme le traitement d'image (transformations, convolution, flou, filtres et autres effets), les simulations (le jeu de la vie de Conway, la réaction diffusion de Gray-Scott, les ondulations sur un plan d'eau, les cellules de Voronoi, etc.). Enfin nous aborderons les techniques avancées basées sur le Ray Marching. *Chaque chapitre comporte des exemples interactifs, n'hésitez pas à jouer avec!* Lorsque vous éditez le code des exemples, le shader est recompilé et - s'il est valide - vous verrez le résultat instantanément. Les concepts paraîssent souvent abstraits et peuvent laisser perplexe, les exemples sont donc là pour vous aider à mieux comprendre ce qui se passe. Nous sommes partisans de l'apprentissage par l'exemple, n'hésitez pas à vous approprier les extraits de codes, quitte à les casser en les modifiants (plusieurs fois s'il le faut). Ce que ce livre n'est pas : * Ce *n'est pas* un livre sur openGL ou webGL. OpenGL/webGL sont des sujets plus profonds que GLSL ou les shaders. Si vous voulez en savoir plus, les liens suivants vous aideront : [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) (alias "the red book") ou [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) * Ce *n'est pas* un livre de maths. Même si le livre contient un certain nombre de notions et d'algorithmes nécessitant des connaissances en algèbre et en trigonométrie, nous ne rentrerons pas dans le détail. Pour toute question relative aux maths, vous pouvez consulter un de ces livres et le garder près de vous : [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) ou [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). ## Bien démarrer Si vous avez un navigateur récent (comme Chrome, Firefox ou Safari) et une connexion internet, il vous suffira de cliquer sur "Next" en bas de page pour commencer l'aventure. Cela étant et selon ce que vous voulez faire de ce livre, vous pouvez : - [Créer une copie locale de ce livre pour le consulter hors-ligne](https://thebookofshaders.com/appendix/?lan=fr) - [Lancer les exemples directement sur Raspberry Pi, sans navigateur](https://thebookofshaders.com/appendix/?lan=fr) - [Créer un PDF du livre pour l'imprimer](https://thebookofshaders.com/appendix/?lan=fr) - Consulter le [dépôt GitHub](https://github.com/patriciogonzalezvivo/thebookofshaders) du livre pour y contribuer ou partager du code. --- ### 00/README Id (00/README-id.md) # Pengenalan 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. 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. 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. --- ### 00/README It (00/README-it.md) # Introduzione Le immagini qui sopra sono state realizzate in modi diversi. La prima è stata dipinta a mano da Van Gogh, aggiungendo strati di pittura uno dopo l'altro. Gli ci vollero ore. La seconda è stata prodotta in qualche secondo dalla combinazione di quattro matrici di pixel: una per il ciano, una per il magenta, una per il giallo e una per il nero. La differenza principale è che la seconda immagine è prodotta in modo non seriale (cioè non passo-passo, ma tutta allo stesso tempo). Questo libro tratta della tecnica di calcolo rivoluzionario, i *fragment shaders*, che sta portando a un livello successivo le immagini generate digitalmente. Lo si può pensare come l'equivalente della stampa di Gutenberg per la grafica. I fragment shaders danno un controllo totale sui pixel, che sono resi sullo schermo a una super velocità. Questo è il motivo per cui sono utilizzati in molteplici applicazioni, dai filtri video sui cellulari ad incredibili videogiochi 3D. Nei capitoli seguenti scopriremo quanto veloce e potente sia questa tecnica e come poterla applicare al vostro lavoro professionale e personale. ## Per chi è questo libro? Questo libro è scritto per programmatori creativi, sviluppatori di giochi e ingegneri che hanno esperienza di programmazione, una conoscenza di base di algebra lineare e di trigonometria, e che vogliono portare il loro lavoro ad un livello di qualità grafica ancora più emozionante. (Se si vuole imparare a programmare, vi raccomando di iniziare con [Processing](https://processing.org/) e tornare più tardi, quando avrete maggiore dimestichezza.) Questo libro vi insegnerà come utilizzare e integrare shader nei vostri progetti, migliorando le loro prestazioni e la qualità grafica. Poiché gli GLSL (OpenGL Shading Language) shaders compilano e si eseguono su una grande varietà di piattaforme, si potrà applicare ciò che si impara qui a qualsiasi framework che utilizza OpenGL, OpenGL ES o WebGL. In altre parole, si sarà in grado di applicare e utilizzare la propria conoscenza negli sketches di [Processing](https://processing.org/), nelle applicazioni di [openFrameworks](http://openframeworks.cc/), nelle installazioni interattive di [Cinder](http://libcinder.org/), nei siti web con [Three.js](http://threejs.org/) o nei giochi iOS / Android. ## Di che cosa tratta questo libro? Questo libro si concentrerà su l'uso dei pixel shaders GLSL. Per prima cosa definiremo cosa sono gli shaders; poi impareremo come fare, grazie a loro, forme procedurali, motivi, texture e animazioni. Imparerete le basi del linguaggio shading ed ad applicarlo a scenari più utili, quali: l'elaborazione di immagini (operazioni di immagine, convoluzioni di matrici, sfocature, filtri colorati, tabelle di associazione e altri effetti) e simulazioni (il gioco della vita di Conway, la reazione-diffusione di Gray-Scott, le increspature d'acqua, gli effetti acquerello, le celle di Voronoi, etc.). Verso la fine del libro vedremo un insieme di tecniche avanzate basate sul Ray Marching. *In ogni capitolo, ci sono degli esempi interattivi per imparare divertendosi. * Quando si modifica il codice, vedrete immediatamente sullo schermo i cambiamenti. I concetti possono essere astratti e confusi, perciò gli esempi interattivi sono essenziali per aiutarvi a capire gli argomenti trattati. Più velocemente i concetti si mettono in pratica e più facilmente si imparerà. Di cosa non tratta questo libro: * Questo * non è * un libro su OpenGL o WebGL. OpenGL / WebGL è un soggetto più vasto di GLSL o dei fragment shaders. Per ulteriori informazioni su OpenGL / WebGL vi consiglio di dare un'occhiata a: [OpenGL Introduzione](https://open.gl/introduction), [l'ottava edizione della guida sulla programmazione OpenGL](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) (noto anche come il libro rosso) o [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). * Questo * non è* un libro di matematica. Anche se ci occuperemo di una serie di algoritmi e di tecniche che si basano su una comprensione dell'algebra e della trigonometria, non spiegheremo tutto in dettaglio. Per domande riguardanti la matematica vi consiglio di tenere vicino uno dei seguenti libri: [La terza edizione di Matematica per la programmazione di giochi 3D e la computer Grafica](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) o [La seconda edizione di Matematica Essenziale per Giochi e Applicazioni Interattive](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). ## Cosa ti serve per iniziare? Non tanto! Se si dispone di un browser moderno che può far girare WebGL (come Chrome, Firefox o Safari) e una connessione Internet, fai clic sul bottone "Next" alla fine di questa pagina per iniziare. In alternativa, in base a ciò di cui avete bisogno, è possibile: - [Creare versione offline di questo libro](https://thebookofshaders.com/appendix/) - [Eseguire gli esempi su un Raspberry Pi senza navigatore](https://thebookofshaders.com/appendix/) - [Fare un PDF del libro da stampare](https://thebookofshaders.com/appendix/) - Utilizzare la [repository on-line](https://github.com/patriciogonzalezvivo/thebookofshaders) per aiutare a risolvere i problemi e per condividere il codice. --- ### 00/README Jp (00/README-jp.md) # イントロダクション 上の2枚の画像は全く異なる方法で作られたものです。1枚目の画像はゴッホが時間をかけて絵の具を塗り重ねて描いたものです。2枚目はシアン、マゼンタ、イエロー、ブラックの4色の網点の組み合わせでほんの短い時間で生み出されました。2枚目の画像は手順を重ねるのではなく、すべての点が同時に描かれているという大きな違いがあります。 この本はフラグメントシェーダーという、デジタル映像を次の次元へと誘う革命的な計算処理技術についての本です。フラグメントシェーダーは印刷にとってのグーテンベルグの活版技術に匹敵すると考えることもできます。 フラグメントシェーダーを使うと画面に表示されるピクセルをとても高速に、かつ自由にコントロールすることができます。そのためこの技術はスマートフォンで映像にフィルターをかけることから、驚くようなクオリティの3Dゲームまで、様々な用途に使われています。 この後につづく章ではフラグメントシェーダーがどれだけ高速でパワフルな技術かについて、またシェーダーを仕事や個人的なプロジェクトで使う方法について説明します。 ## 想定される読者 この本はプログラムの経験と基本的な線形代数や三角関数の知識があり、ワンランク上のグラフィックを目指すクリエイティブコーダー、ゲームデベロッパーなどの開発者に向けて書かれています。もしコーディングについて学びたい場合は[Processing](https://processing.org/)をまず勉強して戻ってくることをお勧めします。 この本ではフラグメントシェーダーをプロジェクトに組み込む方法、パフォーマンスやグラフィックのクオリティを改善する方法を学ぶことができます。GLSL (OpenGL Shading Language, OpenGLシェーダー言語)は様々なプラットフォーム上でコンパイルして走らせることができるので、ここで学習したことはOpenGL、OpenGL ESまたはWebGLが使えるのできるどんな環境でも生かすことができます。 たとえば、[Processing](https://processing.org/)のスケッチ、 [openFrameworks](http://openframeworks.cc/)で作ったアプリケーション、 [Cinder](http://libcinder.org/)で作ったインスタレーション、 [Three.js](http://threejs.org/)を用いたウェブサイトやiOS/Androidのゲームなどが対象です。 ## この本で取り上げること この本では主にGLSLのフラグメントシェーダーについて説明します。シェーダーとは何かの定義から始まり、プログラムを用いて形や模様、質感や動きを作る方法を学びます。シェーダー言語の基礎とともに、畳み込み、ぼかし、カラーフィルター、ルックアップテーブルなどの画像処理技術、コンウェイのライフゲーム、グレイ=スコットの反応拡散系、水の波紋、水彩、ボロノイ図のようなシミュレーションなど、より実践的に活用する方法についても学習します。さらにレイマーチングに基づく高度なテクニックにも触れます。 どの章にも実際に動かせるサンプルがついています。サンプルのコードを書き換えれば結果をその場で見ることもできます。難解なコンセプトも、実際に試してみることでよりスムーズに理解できるでしょう。 この本で取り上げないこと * この本はOpenGLやWebGLの本ではありません。OpenGL、WebGLはGLSLやフラグメントシェーダーを含むより広範なトピックです。もしOpenGL、WebGLについてもっと学びたい場合は下記のWebページや本をお勧めします。 - [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) (赤本) - [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) * この本は数学の本ではありません。代数や三角関数が必要なアルゴリズムやテクニックもとりあげますが、数学についての詳しい説明は省略します。数学的な概念について知りたい場合は下記の本を手元に置いておくと良いでしょう。 - [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) - [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). ## 必要なもの Chrome、FirefoxやSafariなどWebGLの使える今時のブラウザーとインターネットさえあれば始められます。ページの最後にある「Next」をクリックして先に進みましょう。 もし必要な場合は下記もご覧ください。(訳注:いまのところ英語のみです。そのうち翻訳します) - [Make an off-line version of this book](https://thebookofshaders.com/appendix/) - [Run the examples on a Raspberry Pi without a browser](https://thebookofshaders.com/appendix/) - [Make a PDF of the book to print](https://thebookofshaders.com/appendix/) - Use the [on-line repository](https://github.com/patriciogonzalezvivo/thebookofshaders) to help resolve issues and share code. --- ### 00/README Kr (00/README-kr.md) # Introduction 위에 두 이미지는 다른 방법을 통해 만들어졌다. 첫번째것은 반 고흐가 직접 레이어 위에 레이어를 쌓는 방식으로 만들어졌다. 제법 시간이 걸렸을것이다. 두번째것은 몇초 안되는 시간안에 픽셀들의 행렬연산 4개를 통해 만들어 졌다: 한개는 cyan색, 다른 한개는 magenta색, 또 다른 한개는 yellow, 그리고 마지막것은 black. 중요한점은 두번째 이미지는 그림을 부분마다 따로 그려나가게 아니라 그림의 다른 모든 부분이 한번에 그려졌다는 것이다. 이 책은, *fragment shaders*, 라는 디지털 그림 제작과정을 다음 레벨로 이끌어낼 혁신적인 컴퓨팅 기술에 대한 것이다. 바로 그래픽 인더스트리의 구텐베르크 인쇄술인것이다. Fragment shader는 매우 빠른 속도로 스크린에 렌더되는 픽셀들을 완전히 컨트롤 할수 있는 능력을 준다. 핸드폰의 비디오 필터나, AAA 3D 비디오 같은 미디어에서 쓰이는 이유도 이것때문이다. 앞으로 맞이할 챕터들은 독자가 이 강력하고 바른 기술을 스스로 습득하고, 자신의 작업에 적용할수 있는 길을 보여줄것이다. ## 누구를 위한 책인가? 이 책은 삼각함수와 선형대수학에 대한 기본이해가 있고 작업에 있어 그래픽 요소를 극대화 시키려는 creative coder, 게임 개발자, 그래픽 엔지니어들을 위한 책이다. (만약 본인이 코딩입문자라면 이 링크를 보고, [Processing](https://processing.org/) 코딩이 익숙해졌을때쯤 다시 돌아와 이책을 보길 권한다.) 이책은 독자들에게 쉐이더를 프로젝트에 어떻게 쓰는지와, 이를 통한 퍼포먼스 향상과 퀄리티를 높이는 방법들을 보여줄것이다. GLSL (OpenGL Shading Language) 쉐이더들은 OpenGL, OpenGL ES 혹은 WebGL을 가진 환경에서 컴파일되고 실행될것이다. 한마디로, 이것에 대한 기술을 [Processing](https://processing.org/) 스켓치파일들, [openFrameworks](http://openframeworks.cc/) 어플들, [Cinder](http://libcinder.org/) 설치미술들, [Three.js](http://threejs.org/) 웹사이트들 또는 iOS/Android 게임들에 적용할수 있다는 것이다. ## 어떤 내용들을 다루나? 이책은 GLSL pixel shader를 메인으로 다룬다. 먼저, 쉐이더가 무엇인지 알아보고, 절차적(procedural) 모양, 패턴, 텍스쳐, 애니메이션등에 응용해볼것이다. 쉐이딩 랭기지의 기본에 대해 다지게 되고, 여러 분야에 적용해볼수 있도록 유도하는데 예를들면: 이미지 처리(이미지 여산, 메트릭스 회선, blurs, color filters, 룩업테이블과 기타 효과들)와 시뮬레이션 (Conway's game of life, Gray-Scott's reaction-diffusion, water ripples, 물감 효과, Voronoi cells등등)이 그 좋은 예이다. 책의 막바지에는 Ray Marching과 같은 고급기술도 소개를 한다. *각 챕터는 인터엑티브한 예제들로 구성되어 있다.* 예제들의 코드를 변경하면, 바로 그에 대한 결과를 볼수 있다. 컨셉자체가 추상적이거나 난해할수도 있기에, 이런 인터엑티브 예제가 이해하는데 큰 도움이 될거라고 믿는다. 컨셉에 대한 예제를 많이 가지고 놀아볼수록 그에 대한 이해역시 빨리 될거라고 생각한다. 이책이 다루지 않는 부분: * 이책은 openGL이나 webGL서적이 아니다. openGL/webGL은 GLSL이나 fragment shader보다 훨씬 더 큰 주제이다. 그런것들에 대해 좀더 싶히 공부하고 싶다면: [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) (빨간책이라고도 알려진) 이나 [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) 등을 추천한다. * 이책은 수학색이 아니라. 물론 여러 종류의 알고리즘과 대수학과, 삼각함수에 기댄 수학수식이 많이 이용되지만, 그런것들에 대해 자세히 설명하지는 않을 것이다. 수학에 대한 질문은 : [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) 를 보거나, [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) 등을 참고하기 바란다. ## 시작하기 위해 무엇을 해야하나? 필요한것은 따로 없다! 근대 브라우져를 이용하고 있다면, WebGL이 서포트 될것이고 (구글 크롬이나 파이어폭스, 사파리), 인터넷만 있으면 된다! (지금 보고 있지만) 페이지 최하단에 있는 "Next"버튼을 눌러 다음챕터로 가면 시작이다. 아니면 , 다음과 같은 방법으로도 이 책을 접할수 있다: - [이책의 오프라인 버젼](https://thebookofshaders.com/appendix/) - [Raspberry Pi에서 브라우져 없이 예제들 돌리기](https://thebookofshaders.com/appendix/) - [이책의 PDF버젼 만들기](https://thebookofshaders.com/appendix/) - 또는 [온라인 리포](https://github.com/patriciogonzalezvivo/thebookofshaders) 이슈들을 답하거나, 올려주세요. --- ### 00/README Pl (00/README-pl.md) # Wprowadzenie Powyższe obrazy zostały stworzone na różne sposoby. Pierwszy z nich stworzył Van Gogh, aplikując farbę warstwa po warstwie. Zajęło mu to godziny. Drugi stworzono poprzez połączenie czterech macierzy pikseli odpowiadających kolorom: cyjan, magenta, żółty i czarny. Kluczową różnicę stanowi fakt, że drugi obraz stworzony został natychmiastowo (przez komputer), a nie seryjnie, krok po kroku (przez malarza). Ta książka jest o rewolucyjnej technice obliczeniowej, tzw. *fragment shaderach* (zwanych też *pixel shaderami*), które wznoszą cyfrowo generowane obrazy na wyższy poziom. Możesz o nich myśleć jak o ekwiwalencie maszyny drukarskiej Gutenberga dla zastosowań graficznych. Fragment shadery dają ci pełnię kontroli nad błyskawicznym renderowaniem pikseli na ekranie. Właśnie dlatego są one używane w przeróżnych sytuacjach: od filtrów wideo w telefonach do niesamowitych trójwymiarowych gier wideo. W następujących rozdziałach odkryjesz jak niewiarygodnie szybkie i potężne są te techniki i jak zastosować je w twojej pracy zawodowej i osobistej. ## Dla kogo jest ta książka? Ta książka jest napisana dla osób zainteresowanych *creative coding*iem, game developerów i inżynierów, którzy posiadają doświadczenie programistyczne, podstawową wiedzę z algebry liniowej i trygonometrii, i którzy chcą podnieść jakość swoich prac graficznych na wyższy poziom. (Jeżeli chcesz nauczyć się programować, polecam zacząć od [Processing](https://processing.org/) i wrócić, gdy opanujesz go do komfortowego poziomu.) Ta książka nauczy cię jak używać shadery w celu polepszenia wydajności i wyglądu twoich projektów. Ponieważ shadery GLSL (OpenGL Shading Language) kompilują i uruchamiają się na różnorodnych platformach, będziesz w stanie zaaplikować tutaj zdobytą wiedzę do jakiegokolwiek środowiska wykorzystującego OpenGL, OpenGL ES lub WebGL. Innymi słowy, będziesz w stanie wykorzystać tę wiedzę przy tworzeniu szkiców z [Processing](https://processing.org/), aplikacji z [openFrameworks](http://openframeworks.cc/), interaktywnych instalacji z [Cinder](http://libcinder.org/) czy stron internetowych z [Three.js](http://threejs.org/) i gier iOS/Android. ## Jaki materiał pokrywa ta książka? Ta książka skupia się na użyciu fragment shaderów GLSL. Najpierw zdefiniujemy czym shadery są; potem dowiemy się jak, z ich pomocą, tworzyć proceduralne kształty, wzory, tekstury i animacje. Nauczysz się podstaw języka shadingowego i jego przydatnych aplikacji w przetwarzaniu obrazów (operacje na obrazach, sploty macierzowe, rozmycia, filtry koloru, "lookup tables" i inne efekty) czy symulacji ("Gra w życie" Conwaya, model reakcji-dyfuzji Graya-Scotta, plusk wody, efekt akwareli, komórki Voronoi, itp.). Pod koniec książki zobaczymy kilka zaawansowanych technik opartych o Ray Marching. *W każdym rozdziale znajdziesz interaktywne przykłady do wypróbowania.* Kiedy zmodyfikujesz kod, natychmiastowo zobaczysz zmiany. Zagadnienia mogą być abstrakcyjne i mylące, więc takie interaktywne przykłady stanowią konieczną pomoc w zrozumieniu materiału. Im szybciej złapiesz praktykę, tym prostsza będzie dalsza nauka. Materiał, którego ta książka nie pokrywa: * To *nie jest* książka o OpenGL lub WebGL. OpenGL/WebGL jest większym tematem niż GLSL czy fragment shadery. Jeśli chcesz wiedzieć więcej o OpenGL i WebGL, polecam zajrzeć do [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) (zwana również "czerwoną książką") lub [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) * To *nie jest* książka do nauki matematyki. Choć opisane są w niej algorytmy i techniki, które opierają się na zrozumieniu algebry i trygonometrii, to nie będziemy ich szczegółowo tłumaczyć. Z pytaniami dotyczącymi matematyki polecam zajrzeć do następujących książek: [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) lub [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). ## Co potrzeba, żeby zacząć? Niewiele! Jeśli masz współczesną przeglądarkę, która obsługuje WebGL (jak Chrome, Firefox czy Safari) i połączenie internetowe, to kliknij "Dalej" na dole strony, aby zacząć. Alternatywnie, w zależności od tego, co masz albo co potrzebujesz od tej książki, możesz: - [Stworzyć wersję offline tej książki](https://thebookofshaders.com/appendix/00/?lan=pl) - [Uruchomić przykłady na Raspberry Pi bez przeglądarki](https://thebookofshaders.com/appendix/01/?lan=pl) - [Stworzyć wersję PDF tej książki do wydrukowania](https://thebookofshaders.com/appendix/02/?lan=pl) - Sprawdź [repozytorium GitHub](https://github.com/patriciogonzalezvivo/thebookofshaders) tej książki, by pomóc w rozwiązywaniu problemów (issues) i podzielić się swoim kodem. --- ### 00/README Pt (00/README-pt.md) # Introduction As imagens acima foram feitas de maneiras diferentes. A primeira foi feita pela mão do Van Gogh, aplicando-se camada a camada de tinta. Levou horas. A segunda foi produzida em segundos pela combinação de quatro matrizes de pixel: uma para ciano, uma para magenta, um para amarelo e outro pra preto. A diferença chave é que a segunda imagem é produzida de forma não-serial (ou seja, não foi passo a passo, mas todos ao mesmo tempo). Este livro é sobre a técnica computacional revolucionária, *fragment shaders*, que está levando imagens geradas digitalmente a um nível mais alto. Você pode pensar nisso como sendo o equivalente à impressa de Gutenberg para gráficos. Fragment shaders te dão controle total sobre os pixels rendereizados na tela, em velocidade super. É por isso que eles são usados para todas as finalidades, desde filtros de vídeo em celulares até videogames 3D incríveis. Nos capítulos seguintes, você vai descobrir o quão incrivelmente rápida e poderosa é essa técnica, e como aplicá-la para seu trabalho pessoal e profissional. ## Para quem é este livro? Este livro é escrito para programadores criativos, desenvolvedores de jogos e engenheiros que têm experiência em codificação, um conhecimento básico de álgebra linear e trigonometria, e quem quiser levar seu trabalho a um novo nível excitante de qualidade gráfica (se você quer aprender como programar, eu recomendo fortemente que comece com o [Processing](https://processing.org/) e volte mais tarde quando estiver comfortável com isso.). Este livro vai te ensinar como usar e integrar shaders em seus projetos, melhorando a qualidade gráfica e performance. Devido ao fato de shaders GLSL (OpenGL Shading Language) compilarem e rodarem em grande variedade de plataformas, você vai poder aplicar o que aprendeu aqui para qualquer ambiente que usar OpenGL, OpenGL ES ou WebGL. Em outras palavras, você vai poder aplicar e usar seu conhecimento com sketches do [Processing](https://processing.org/), aplicações [openFrameworks](http://openframeworks.cc/) , instalações interativas [Cinder](http://libcinder.org/) , websites [Three.js](http://threejs.org/) ou jogos iOS/Android. ## O que este livro cobre? Este livro vai focar no uso de shaders de pixel em GLSL. Primeiro vamos definir o que são os shaders; então vamos aprender como fazer formas proceduralmente, padrões, texturas e animações com eles. Você vai aprender as fundações da linguagem de shaders e como aplicar em cenários mais úteis, como: processamento de imagens (operações com imagens, convoluções de matrizes, blurs, filtros de cores, tabelas de lookup, e outros efeitos) e simulações (jogo da vida de Conway, reação e difusão de Gray-Scott, ondas em água, efeitos de cores de água, células de Voroni, etc). Em direção ao fim do livro, vamos ver um conjunto de técnicas avançadas baseadas em Ray Marching. *Existem exemplos interativos para você brincar em cada capítulo.* Quando você muda o código, vai ver as mudanças imediatamente. os conceitos podem ser abstratos e confusos, então os exemplos interativos são essenciais para ajudá-lo a aprender o material. Quanto mais rápido você colocar os conceitos em movimento, mais fácil será o processo de aprendizagem. O que esse livro não cobre: * Este *não é* um livro de openGL ou webGL. OpenGL/webGL é um assunto maior que GLSL ou fragment shaders. Para aprender mais sobre openGL/webGL eu recomendo dar uma olhada em: [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) (também conhecido como o livro vermelho) ou [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) * Este *não é* um livro de matemática. Embora venhamos a cobrir um bom número de algoritmos e técnicas que se baseiam no entendimento de álgebra e trigonometria, não vamos explicá-los em detalhes. Para questões relacionadas com matemática eu recomendo que você tenha um desses livros por perto: [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) ou [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). ## O que você precisa para começar? Não muito! Se você tem um browser moderno que possa rodar WebGL (como Chrome, Firefox ou Safari) e uma conexão à internet, clique no botão para o próximo capítulo no fim desta página para começar. Alternativamente, baseado no que você tem, ou no que você precisa deste livro você pode: - [Fazer uma versão offline deste livro](https://thebookofshaders.com/appendix/00/) - [Rodar os exemplos em um Raspberry Pi sem um browser](https://thebookofshaders.com/appendix/01/) - [Fazer um PDF do livro para imprimir](https://thebookofshaders.com/appendix/02/) - Checar o [repositório GitHub](https://github.com/patriciogonzalezvivo/thebookofshaders) deste livro para ajudar a resolver questões e compartilhar código. --- ### 00/README Tr (00/README-tr.md) # Giriş Yukarıdaki görüntüler farklı şekillerde oluşturuldu. İlki, Van Gogh'un eliyle katman katman boya uygulayarak yapıldı. Saatlerini aldı. İkincisi ise saniyeler içinde, piksellerden oluşan dört matrisin kombinasyonuyla üretildi: biri camgöbeği (cyan), biri macenta (magenta), biri sarı (yellow) ve biri siyah (black) için. Temel fark, ikinci görüntünün seri olmayan bir şekilde (yani adım adım değil, hepsi aynı anda) üretilmesidir. Bu kitap, dijital olarak üretilen görüntüleri bir sonraki seviyeye taşıyan devrim niteliğindeki hesaplama tekniği olan *fragment shader*'lar hakkındadır. Bunu grafikler için Gutenberg'in matbaasının eşdeğeri olarak düşünebilirsiniz. Fragment shader'lar, ekranda işlenen pikseller üzerinde süper hızlı bir şekilde tam kontrol sağlar. Bu nedenle, cep telefonlarındaki video filtrelerinden inanılmaz 3D video oyunlarına kadar her türlü durumda kullanılırlar. İlerleyen bölümlerde bu tekniğin ne kadar inanılmaz derecede hızlı ve güçlü olduğunu ve bunu profesyonel ve kişisel çalışmalarınıza nasıl uygulayacağınızı keşfedeceksiniz. ## Bu kitap kimin için? Bu kitap, kodlama deneyimi olan, temel lineer cebir ve trigonometri bilgisine sahip ve çalışmalarını heyecan verici yeni bir grafik kalitesi seviyesine taşımak isteyen yaratıcı kodlayıcılar, oyun geliştiricileri ve mühendisler için yazılmıştır. (Eğer kodlamayı öğrenmek istiyorsanız, [Processing](https://processing.org/) ile başlamanızı ve kendinizi rahat hissettiğinizde daha sonra buraya geri dönmenizi şiddetle tavsiye ederim.) Bu kitap size shader'ları projelerinize nasıl kullanacağınızı ve entegre edeceğinizi, performanslarını ve grafik kalitelerini nasıl artıracağınızı öğretecektir. GLSL (OpenGL Gölgelendirme Dili) shader'ları çeşitli platformlarda derlenip çalıştığından, burada öğrendiklerinizi OpenGL, OpenGL ES veya WebGL kullanan herhangi bir ortama uygulayabileceksiniz. Başka bir deyişle, bilginizi [Processing](https://processing.org/) eskizleri, [openFrameworks](http://openframeworks.cc/) uygulamaları, [Cinder](http://libcinder.org/) interaktif kurulumları, [Three.js](http://threejs.org/) web siteleri veya iOS/Android oyunları ile uygulayabilir ve kullanabilirsiniz. ## Bu kitap neyi kapsıyor? Bu kitap GLSL piksel shader'larının kullanımına odaklanacaktır. Önce shader'ların ne olduğunu tanımlayacağız; sonra onlarla prosedürel şekiller, desenler, dokular ve animasyonlar yapmayı öğreneceğiz. Gölgelendirme dilinin temellerini öğrenecek ve bunu daha yararlı senaryolara uygulayacaksınız: görüntü işleme (görüntü operasyonları, matris konvolüsyonları, bulanıklaştırma, renk filtreleri, arama tabloları ve diğer efektler) ve simülasyonlar (Conway'in hayat oyunu, Gray-Scott'ın reaksiyon-difüzyonu, su dalgalanmaları, suluboya efektleri, Voronoi hücreleri, vb.). Kitabın sonuna doğru Ray Marching'e dayalı bir dizi ileri teknik göreceğiz. *Her bölümde oynamanız için interaktif örnekler bulunmaktadır.* Kodu değiştirdiğinizde, değişiklikleri hemen göreceksiniz. Kavramlar soyut ve kafa karıştırıcı olabilir, bu nedenle interaktif örnekler materyali öğrenmenize yardımcı olmak için çok önemlidir. Kavramları ne kadar hızlı harekete geçirirseniz öğrenme süreci o kadar kolay olacaktır. Bu kitabın kapsamadığı konular: * Bu bir OpenGL veya webGL kitabı *değildir*. OpenGL/webGL, GLSL veya fragment shader'lardan daha büyük bir konudur. OpenGL/webGL hakkında daha fazla bilgi edinmek için şunlara göz atmanızı öneririm: [OpenGL Introduction](https://open.gl/introduction), [OpenGL Programming Guide'ın 8. baskısı](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) (kırmızı kitap olarak da bilinir) veya [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) * Bu bir matematik kitabı *değildir*. Cebir ve trigonometri anlayışına dayanan bir dizi algoritma ve tekniği ele alacak olsak da, bunları ayrıntılı olarak açıklamayacağız. Matematik ile ilgili sorularınız için şu kitaplardan birini yakınınızda bulundurmanızı öneririm: [Mathematics for 3D Game Programming and Computer Graphics 3. Baskı](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) veya [Essential Mathematics for Games and Interactive Applications 2. Baskı](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). ## Başlamak için neye ihtiyacınız var? Fazla bir şeye değil! WebGL yapabilen modern bir tarayıcınız (Chrome, Firefox veya Safari gibi) ve bir internet bağlantınız varsa, başlamak için bu sayfanın sonundaki “Sonraki” Bölüm düğmesine tıklayın. Alternatif olarak, sahip olduklarınıza veya bu kitaptan neye ihtiyacınız olduğuna bağlı olarak şunları yapabilirsiniz: - [Bu kitabın çevrimdışı bir sürümünü yapın](https://thebookofshaders.com/appendix/00/?lan=tr) - [Örnekleri tarayıcı olmadan bir Raspberry Pi üzerinde çalıştırın](https://thebookofshaders.com/appendix/01/?lan=tr) - [Kitabın yazdırılabilir bir PDF'ini oluşturun](https://thebookofshaders.com/appendix/02/?lan=tr) - Sorunları çözmeye yardımcı olmak ve kod paylaşmak için bu kitabın [GitHub deposunu](https://github.com/patriciogonzalezvivo/thebookofshaders) kontrol edin. --- ### 00/README Vi (00/README-vi.md) # Giới thiệu Hai bức ảnh trên đây được tạo ra bằng những cách khác nhau. Bức đầu tiên được vẽ bởi Van Gogh bằng nhiều lớp sơn chồng lên nhau. Nó đã ngốn của ông ấy hàng giờ đồng hồ. Bức thứ hai được tạo ra trong chớp mắt từ 4 ma trận điểm ảnh: một cho màu xanh (Cyan), một cho màu hồng (Magenta), một cho màu vàng (Yellow) và một cho màu đen (Black). Điểm khác biệt chính là: các lớp của bức tranh thứ hai được tạo ra đồng thời chứ không phải tuần tự. Quyển sách này nói về một kỹ thuật mang tính cách mạng trong Đồ họa Máy tính, *fragment shader*, giúp nâng tầm đồ hoạ kỹ thuật số lên một tầm cao mới. Bạn có thể nghĩ sức ảnh hưởng của nó tương đương với cỗ máy in của Gutenberg khi xưa vậy. Fragment shader cho bạn toàn quyền kiểm soát các điểm ảnh được render trên màn hình cực kỳ nhanh chóng. Đó là lí do tại sao nó được dùng trong mọi lĩnh vực của Đồ hoạ máy tính, từ các bộ lọc video trên điện thoại di động tới các trò chơi điện tử 3D đáng kinh ngạc. Ở các chương tiếp theo, bạn sẽ khám phá ra kỹ thuật này nhanh và mạnh kinh khủng tới mức nào, và làm thế nào để áp dụng nó vào công việc. ## Quyển sách này dành cho những ai ? Quyển sách này được viết cho các kỹ sư và lập trình viên sáng tạo, những người đã có kinh nghiệm lập trình và kiến thức cơ bản về Giải tích và Lượng giác, và cho những ai muốn nâng tầm chất lượng đồ hoạ trong tác phẩm của mình. (Nếu bạn muốn học lập trình, tôi khuyên bạn nên bắt đầu từ trang web [Processing](https://processing.org/) rồi quay lại đây khi đã cảm thấy đủ kiến thức. Quyển sách này sẽ chỉ cho bạn cách dùng các shader và cách áp dụng shader vào các dự án để cải thiện hiệu năng cũng như chất lượng đồ hoạ. Vì các shader viết bằng GLSL (viết tắt của OpenGL Shading Language) sẽ được biên dịch và chạy trên rất nhiều nền tảng khác nhau, bạn có thể ứng dụng những gì học được ở đây cho bất kỳ môi trường nào sử dụng OpenGL, OpenGL ES hoặc WebGL. Cụ thể, bạn có thể ứng dụng những kiến thức này cho các bản vẽ [Processing](https://processing.org/), các ứng dụng [openFrameworks](http://openframeworks.cc/), các cỗ máy [Cinder](http://libcinder.org/) tương tác được, các website sử dụng [Three.js](http://threejs.org/) hay các trò chơi trên iOS/Android. ## Nội dung của quyển sách này là gì ? Quyển sách này sẽ tập trung vào việc sử dụng các pixel shader viết bằng GLSL. Đầu tiên ta sẽ định nghĩa thế nào là shader, rồi mới học cách tạo các hình, mẫu, ảnh bằng Toán học và làm chúng chuyển động bằng shader. Bạn sẽ được học các kiến thức nền tảng của shader và áp dụng chúng vào các chuyên ngành khác như: Xử lý ảnh (Các phép toán xử lý ảnh, ma trận chập, làm mờ, bộ lọc, bảng quy chiếu và các hiệu ứng khác), mô phỏng (Mô phỏng tiến trình sống theo phương pháp Conway, mô hình Phản ứng - Khuếch tán của Gray-Scott, các gợn sóng trên mặt nước, hiệu ứng màu nước, nhiễu Voronoi, vân vân ...). Tới cuối quyển sách, ta sẽ nói về các kỹ thuật cao cấp hơn dựa trên thuật toán Dò tia - Ray Marching. *Tất cả các chương đều có các ví dụ tương tác được để bạn khám phá.* Khi bạn sửa code, bạn sẽ thấy thay đổi ngay lập tức. Các khái niệm có thể hơi trừu tượng và dễ gây nhầm lẫn, nên các ví dụ tương tác được sẽ rất cần thiết để hỗ trợ bạn học. Bạn nắm vững các khái niệm càng nhanh thì bạn học càng dễ. Những nội dung nằm ngoài phạm vi của quyển sách: * Đây *không phải* sách nói về OpenGL hay WebGL. OpenGL/WebGL là chủ đề rộng lớn hơn cả GLSL và fragment shader. Để tìm hiểu thêm về OpenGL/WebGL, tôi khuyên bạn nên đọc [Giới thiệu OpenGL](https://open.gl/introduction), [Hướng dẫn lập trình OpenGL - xuất bản lần 8](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) (còn được biết tới với tên gọi là The Red Book) hoặc [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) * Đây *không phải* sách Toán. Mặc dù ta có đề cập tới một vài thuật toán và kỹ thuật liên quan tới Giải tích và Lượng giác, nhưng chúng tôi sẽ không giải thích chúng một cách chi tiết. Để tiện giải đáp các thắc mắc về Toán, tôi khuyên bạn nên có một trong số các quyển sách sau: [Ứng dụng Toán trong lập trình và đồ hoạ máy tính - xuất bản lần 3](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) hoặc [Kiến thức Toán cần thiết cho lập trình Game và Ứng dụng real-time](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). ## Bạn cần gì để bắt đầu ? Chỉ vài thứ thôi! Nếu bạn có trình duyệt có thể xử lý WebGL (như Chrome, Firefox hoặc Safari) và kết nối Internet, click nút _"Next >>>"_ ở cuối trang này để bắt đầu ngay. Hoặc, tuỳ theo bạn có gì và cần gì từ quyển sách, bạn có thể: - [Tạo quyển sách phiên bản không cần Internet](https://thebookofshaders.com/appendix/00/?lan=vi) - [Chạy các ví dụ trên Raspberry Pi mà không cần trình duyệt](https://thebookofshaders.com/appendix/01/?lan=vi) - [Tạo phiên bản PDF của sách để in](https://thebookofshaders.com/appendix/02/?lan=vi) - Xem [repository trên GitHub](https://github.com/patriciogonzalezvivo/thebookofshaders) của quyền sách này để giúp sửa và chia sẻ code. --- ### 01/README (01/README.md) # Getting started ## What is a fragment shader? In the previous chapter we described shaders as the equivalent of the Gutenberg press for graphics. Why? And more importantly: what's a shader? If you already have experience making drawings with computers, you know that in that process you draw a circle, then a rectangle, a line, some triangles until you compose the image you want. That process is very similar to writing a letter or a book by hand - it is a set of instructions that do one task after another. Shaders are also a set of instructions, but the instructions are executed all at once for every single pixel on the screen. That means the code you write has to behave differently depending on the position of the pixel on the screen. Like a type press, your program will work as a function that receives a position and returns a color, and when it's compiled it will run extraordinarily fast. ## Why are shaders fast? To answer this, I present the wonders of *parallel processing*. Imagine the CPU of your computer as a big industrial pipe, and every task as something that passes through it - like a factory line. Some tasks are bigger than others, which means they require more time and energy to deal with. We say they require more processing power. Because of the architecture of computers the jobs are forced to run in a series; each job has to be finished one at a time. Modern computers usually have groups of four processors that work like these pipes, completing tasks one after another to keep things running smoothly. Each pipe is also known as a *thread*. Video games and other graphic applications require a lot more processing power than other programs. Because of their graphic content they have to do huge numbers of pixel-by-pixel operations. Every single pixel on the screen needs to be computed, and in 3D games geometries and perspectives need to be calculated as well. Let's go back to our metaphor of the pipes and tasks. Each pixel on the screen represents a simple small task. Individually each pixel task isn't an issue for the CPU, but (and here is the problem) the tiny task has to be done to each pixel on the screen! That means in an old 800x600 screen, 480,000 pixels have to processed per frame which means 14,400,000 calculations per second! Yes! That’s a problem big enough to overload a microprocessor. In a modern 2880x1800 retina display running at 60 frames per second that calculation adds up to 311,040,000 calculations per second. How do graphics engineers solve this problem? This is when parallel processing becomes a good solution. Instead of having a couple of big and powerful microprocessors, or *pipes*, it is smarter to have lots of tiny microprocessors running in parallel at the same time. That’s what a Graphic Processor Unit (GPU) is. Picture the tiny microprocessors as a table of pipes, and the data of each pixel as a ping pong ball. 14,400,000 ping pong balls a second can obstruct almost any pipe. But a table of 800x600 tiny pipes receiving 30 waves of 480,000 pixels a second can be handled smoothly. This works the same at higher resolutions - the more parallel hardware you have, the bigger the stream it can manage. Another “super power” of the GPU is special math functions accelerated via hardware, so complicated math operations are resolved directly by the microchips instead of by software. That means extra fast trigonometrical and matrix operations - as fast as electricity can go. ## What is GLSL? GLSL stands for OpenGL Shading Language, which is the specific standard of shader programs you'll see in the following chapters. There are other types of shaders depending on hardware and Operating Systems. Here we will work with the OpenGL specs regulated by [Khronos Group](https://www.khronos.org/opengl/). Understanding the history of OpenGL can be helpful for understanding most of its weird conventions, for that I recommend taking a look at: [openglbook.com/chapter-0-preface-what-is-opengl.html](http://openglbook.com/chapter-0-preface-what-is-opengl.html) ## Why are Shaders famously painful? As Uncle Ben said “with great power comes great responsibility,” and parallel computation follows this rule; the powerful architectural design of the GPU comes with its own constraints and restrictions. In order to run in parallel every pipe, or thread, has to be independent from every other thread. We say the threads are *blind* to what the rest of the threads are doing. This restriction implies that all data must flow in the same direction. So it’s impossible to check the result of another thread, modify the input data, or pass the outcome of a thread into another thread. Allowing thread-to-thread communications puts the integrity of the data at risk. Also the GPU keeps the parallel micro-processor (the pipes) constantly busy; as soon as they get free they receive new information to process. It's impossible for a thread to know what it was doing in the previous moment. It could be drawing a button from the UI of the operating system, then rendering a portion of sky in a game, then displaying the text of an email. Each thread is not just **blind** but also **memoryless**. Besides the abstraction required to code a general function that changes the result pixel by pixel depending on its position, the blind and memoryless constraints make shaders not very popular among beginning programmers. Don't worry! In the following chapters, we will learn step-by-step how to go from simple to advanced shading computations. If you are reading this with a modern browser, you will appreciate playing with the interactive examples. So let's not delay the fun any longer and press *Next >>* to jump into the code! --- ### 01/Notes (01/notes.md) ### Scott M * You say “pipes” and also “threads”. This is a small thing but I wonder if you can reconcile those metaphors. I think in terms of threads, but “pipes” makes more sense with your illustration. Also works better with the concept of a “pipeline” or “graphics/rendering pipeline”. ### Nicolas B * clearly answer the "what is a fragment shader?" question in some sort of recap paragraph. * beef up explanations around the compilation step (a brief overview will do). --- ### 01/README De (01/README-de.md) # Einstieg ## Was ist ein Fragment-Shader? Im vorangegangenen Kapitel haben wir Fragment-Shader als eine Art Gutenbergsche Druckerpresse für Computergrafiken beschrieben. Nun, wie kommen wir darauf? Und was genau soll ein Shader sein? Falls Du schon Erfahrung mit der Erstellung von Computergrafiken gesammelt hast, kennst Du bestimmt die folgende Vorgehensweise: Man malt per Programmbefehl Kreise, Rechtecke, Dreiecke und Linien, damit auf dem Bildschirm nach und nach die gewünschte Grafik entsteht. Dieser Vorgang ähnelt von Hand einen Brief oder Buch zu verfassen. Es handelt sich um eine Folge von Anweisungen (den Zeichenoperationen), die Schritt für Schritt abgearbeiet werden müssen. Auch Shader sind nur eine Abfolge von Anweisungen, doch werden diese Anweisungen alle gleichzeitig für jeden Bildpunkt (Pixel) in der Grafik ausgeführt. Das bedeutet also, dass das von Dir geschriebene Shader-Programm die Grafik abhängig von der sich ändernden Position eines einzelnen Bildpunkts beschreiben muss. Der Shader arbeitet dabei als eine Funktion, die die Koordinaten des jeweiligen Bildpunktes erhält und als Ergebnis die Farbe für diesen Bildpunkt zurückliefert. Ist der Shader einmal kompiliert, läuft dieser Prozess unglaublich schnell und für sehr viele Bildpunkte gleichzeitig ab. ## Warum arbeiten Shader schnell? Diese Frage beantwortet sich, wenn wir uns das Prinzip der *parallelen Verarbeitung* anschauen. Stelle Dir den Prozessor in Deinem Computer als eine große Pipeline vor und jede zu bearbeitende Aufgabe als etwas, das durch die Pipeline fließt - wie an einem Fließband innerhalb einer Fabrik. Einige Aufgaben sind größer als andere, weshalb ihre Abarbeitung mehr Zeit und mehr Energie in Anspruch nimmt. Wir sagen dann, diese Aufgaben benötigen mehr „Prozessorleistung“. Der Aufbau des Computers zwingt die verschiedenen Aufgaben dazu, eine nach der anderen durch die Pipeline zu strömen. Die nächste Aufgabe ist an der Reihe, sobald die vorangehende Aufgabe erfolgreich abgearbeitet wurde. Moderne Prozessoren verfügen in der Regel über mehrere Kerne (typischerweise zwei, vier oder acht), von denen jeder wie eine Pipeline arbeitet, so dass mehrere Ströme von Aufgaben (engl. „Threads“) gleichzeitig abgearbeitet werden können. Videospiele und leistungsstarke Grafikanwendungen benötigen in der Regel wesentlich mehr Prozessorleistung als andere Computerprogramme. Weil sie grafikorientiert arbeiten, müssen diese Programme eine enorme Anzahl an Pixel-Operationen ausführen. Jeder einzelne Bildpunkt muss individuell berechnet werden, und bei 3D-Anwendungen kommen noch perspektivische Verzerrungen sowie das Spiel von Licht und Schatten hinzu. Kommen wir noch einmal auf das Bild einer Pipeline zurück. Jeder einzelne Bildpunkt verkörpert eine Rechenaufgabe, die durch die Pipeline abgearbeitet werden muss. Einzeln genommen macht das nicht viel Arbeit - der enorme Aufwand entsteht erst durch die schiere Masse an Pixeln auf dem Bildschirm. Schon bei einer Auflösung von 800 x 600 Bildpunkten müssen pro Bild 480.000 Pixels berechnet werden. Für eine flüssige Darstellung mit 30 Bildern pro Sekunde ergeben sich also bereits 14.400.000 Berechnungen pro Sekunde. Das ist eine Dimension, bei der auch moderne Prozessoren an ihre Grenzen stoßen. Und bei einem hochauflösenden Retina-Display mit 2880 x 1800 Bildpunkten und einer Wiederholrate von 60 Bildern pro Sekunde kommen sogar 311.040.000 Berechnungen pro Sekunde zusammen. Fragt sich also, wie ein Computersystem dies bewältigen kann? Hier kommt die gleichzeitige - parallele - Berechnung möglichst vieler Bildpunkte ins Spiel. An die Stelle weniger großer und immens leistungsfähiger Pipelines (sprich: Mikroprozessoren) treten viele kleine, einfachere Prozessoren, die parallel arbeiten. Sie bilden den Kern einer sogenannten „Graphic Processing Unit“, kurz GPU. Stelle Dir eine solche GPU wie ein Feld aus lauter Pipelines vor - eine neben der anderen. Jeder Bildpunkt entspricht einem Tischtennisball, der durch eine solche Pipeline hindurchmuss. 14.400.000 Bälle pro Sekunde sind wahrscheinlich zu viel für jede einzelne noch so dicke Pipeline. Hat man aber ein Feld aus 800 x 600 kleinen Pipelines, muss jede nur 30 Bälle pro Sekunde verarbeiten, damit man eine flüssige Darstellung auf dem Bildschirm erhält. Und das ist durchaus machbar. Gleiches gilt für höhere Auflösungen und größere Bildwiederholraten: Je mehr Pipelines parallel arbeiten, desto mehr Bildpunkte können sie pro Zeiteinheit bewältigen. Die enorme Leistung einer solchen GPU rührt aber auch aus einer anderen Quelle: Viele für die Grafikberechnung unverzichtbare mathematische Operationen lassen sich direkt in der Hardware, in jeder einzelnen Pipeline, parallel ausführen. Es wird also keine zusätzliche Software benötigt, um diese Berechnungen in mehreren Schritten aus einfachen Grundoperationen zusammenzusetzen. Das gilt beispielsweise für die wichtigen trigonometrischen Funktionen und für Matrizenoperationen. Das bringt die Darstellung zusätzlich auf Trab. ## Was ist GLSL? GLSL ist die Abkürzung für „OpenGL Shading Language“, einem weit verbreiteten Standard für Shader-Programme, mit dem sich die folgenden Kapitel beschäftigen. Es gibt auch andere Arten von Shadern, je nach Grafikhardware und Betriebssystem. Wir orientieren uns hier an der wichtigen OpenGL-Spezifikation, die von der [Khronos Gruppe](https://www.khronos.org/opengl/) erarbeitet wurde. Wenn man die Geschichte von OpenGL kennt, kann man einige der teilweise etwas merkwürdigen Konstrukte und Konventionen besser verstehen. Allen Interessierten empfehle ich deshalb einen Blick auf [openglbook.com/chapter-0-preface-what-is-opengl.html](http://openglbook.com/chapter-0-preface-what-is-opengl.html). ## Warum sind Shader so anspruchsvoll? Mein reicher Onkel Willi aus Amerika sagte früher immer zu mir: „Denk dran, Junge, unglaublich viel Power bedeutet immer auch unglaublich viel Verantwortung“. Dies gilt in gewisser Weise auch für das Feld des „Parallel Computings“. Die enorme Leistungsfähigkeit moderner GPUs erzeugt ihre eigenen Regeln und Abhängigkeiten. Und die wollen beachtet werden, damit wir nicht über das Ziel hinausschießen. Damit jede Pipeline innerhalb der GPU parallel an ihrer Aufgabe arbeiten kann, muss sie unabhängig von den anderen Pipelines sein. Sie ist quasi blind dafür, was die anderen gerade tun. Dies bringt u.a. die Einschränkung mit sich, dass alle Daten nur in eine Richtung fließen können. Es ist praktisch unmöglich, auf die Ergebnisse einer anderen Pipeline einzugehen, deren Ergebnis abzurufen und damit eine dritte Pipeline zu füttern. Außerdem hält die GPU ihre zahlreichen Mikroprozessoren (Pipelines) ständig beschäftigt. Sobald eine Pipeline mit der Berechnung der Farbe für einen Bildpunkt fertig ist, wird sie auch schon mit dem nächsten Bildpunkt „gefüttert“. Aus Sicht des Shader-Programms gibt es quasi kein Vorher und Nachher, sondern immer nur den aktuell zu berechnenden Bildpunkt. Das Shader-Programm in jeder Pipeline ist also nicht nur blind für alle anderen, sondern auch ohne Erinnerung für das Gewesene. Das ist ein Teil der Herausforderung, die die Entwicklung von Shadern bei Programmieranfängern nicht unbedingt beliebt macht. Aber keine Angst! In den folgenden Kapiteln werden wir uns Schritt für Schritt von einfachen Shadern hin zu komplexen Shadern voran arbeiten. Sofern Du diesen Text mit einem modernen Browser liest, wirst Du ganz einfach mit den zahlreichen interaktiven Beispielprogrammen experimentieren können. Also, lass uns gleich anfangen, indem Du auf die „*Next*“-Schaltfläche unten auf der Seite klickst. --- ### 01/README Es (01/README-es.md) # Comenzando ## Qué es un fragment shader? En el capítulo anterior comparamos a los shaders con la invención de la imprenta de Gutenberg. ¿Por qué? Y más importante: ¿Qué es un shader? Si ya tienes experiencia dibujando con computadoras, sabrás que en ese proceso dibujas un círculo, luego un rectángulo, una línea, algunos triángulos, hasta que por fin compones la imagen que querías. Ese proceso es muy similar a escribir una carta o un libro a mano, es un conjunto de instrucciones, una tarea después de la otra. Los shaders son también un conjunto de instrucciones, pero estas son ejecutadas todas al mismo tiempo por cada pixel de la pantalla. Eso significa que el código que escribes tiene que comportarse de manera diferente dependiendo de su posición en la pantalla. Como una prensa tipográfica, tu programa trabajará como una función que recibe posición y devuelve color, y que al ser compilada se ejecutará a una velocidad extraordinaria. ## Por qué son rápidos los shaders? Para responder esto hay que hablar de las maravillas del *parallel processing*. Imagina que tu CPU es un gran tubo industrial y que cada tarea pasa por ahí como si fuese una linea de producción. Algunas tareas son más grandes que otras, esto quiere decir que algunas consumen más tiempo y energía que el resto. Solemos decir que estas tareas requieren más tiempo de proceso. Debido a la arquitectura de las computadoras estas tareas son forzadas a correr en serie; cada trabajo debe ser terminado, uno después del otro. Las computadoras modernas usualmente cuentan con un grupo de procesadores que trabajan como estos tubos, completando tareas, una después de la otra. Cada uno de estos tubos es también conocido como *thread*. Los videojuegos y otras aplicaciones gráficas requieren mucho más tiempo de proceso que otros programas. Debido a su contenido gráfico es necesario hacer muchas operaciones numéricas por pixel. Cada pixel de la pantalla necesita ser computado, y en el caso de los videojuegos en 3D también hay que calcular las geometrías y las perspectivas. Volvamos a pensar en la metáfora de los tubos y las tareas. Cada pixel de la pantalla representa una pequeña tarea a realizar. Individualmente cada tarea no es un gran problema para el CPU, pero (y aquí está el problema) ¡Esta pequeña tarea deberá ser ejecutada por cada pixel! Eso significa que en una antigua pantalla de 800x600 pixeles ¡Tendremos que procesar 480000 pixeles por frame, es decir 14400000 cálculos por segundo! ¡Sí! Ese es un problema lo suficientemente grande como para sobrecargar al microprocesador. En una pantalla retina display moderna de 2880x1800 pixeles, corriendo a 60 frames por segundo, los cálculos aumentarían a 311040000 por segundo. ¿Cómo hicieron los ingenieros gráficos para solucionar este problema? Aquí es donde procesar en paralelo se vuelve una buena solución. En vez de tener un par de procesadores grandes y poderosos, o *tubos*, es mucho más inteligente tener muchos pequeños procesadores funcionando en paralelo al mismo tiempo. Eso es la GPU (Graphic Processor Unit). Imagina que los pequeños procesadores conforman una mesa de tuberías, y que la información de cada pixel es una pelota de ping pong. 14400000 pelotas de ping pong en un segundo pueden obstruir a cualquier tubería, pero si en cambio es una mesa de 800x600 tuberías y recibe 30 olas de 480000 pixeles por segundo, se puede manejar de una manera fluída sin problemas. Esto funciona de la misma manera con resoluciones más grandes, cuanto más hardware en paralelo tengas, es mayor el flujo de pixeles que se puede manejar. Otro "superpoder" de la GPU es que algunas funciones matemáticas especiales son aceleradas vía hardware, la matemática más compleja es solucionada directamente en el microchip en vez resolverlo en el software. Eso signfica que tendremos una velocidad extra en cálculos trigonométricos u operaciones de matrices que irán tan rápido como la electricidad. ## ¿Qué es GLSL? GLSL es la sigla de openGL Shading Language, que es el standard específico de shaders que veremos en los próximos capítulos. Hay otros tipos de shaders que varían dependiendo del hardware y del sistema operativo. Aquí trabajaremos con las especificaciones reguladas por el [Khronos Group](https://www.khronos.org/opengl/). Entender la historia de OpenGL puede ser útil para comprender la mayoría de las convenciones raras, te recomiendo echarle un vistazo a: [openglbook.com/chapter-0-preface-what-is-opengl.html](http://openglbook.com/chapter-0-preface-what-is-opengl.html) ## ¿Por qué los shaders tienen mala reputación? Como dijo el tio Ben "un gran poder conlleva una gran responsabilidad", y la computación paralela sigue esta regla; el poderoso diseño de arquitectura de la GPU viene con sus propias limitaciones y restricciones. Para que cada tubo, o thread, pueda correr en paralelo es necesario que cada uno sea independiente del otro. Es decir que los threads son *ciegos* y no saben lo que los demás threads están haciendo. Esta restricción implica que toda la información debe fluir en la misma dirección, por lo tanto es imposible conocer el resultado de otro thread. Permitir la comunicación entre threads pondría en riesgo la integridad de los datos. Además la GPU deja constantemente ocupados a los micro-procesadores (los tubos); tan pronto como terminan una tarea reciben nueva información para procesar. Es imposible para cada thread saber lo que estaba haciendo en el momento previo. Se podría dibujar un botón de una UI de un sistema operativo, luego renderizar una porción del cielo de un videojuego, y a continuación mostrar el texto de un mail. Cada thread no solamente es **ciego** sino que **tampoco tiene memoria**. Más allá de la abstracción necesaria para poder crear una función que cambie de resultado pixel a pixel, dependiendo de su posición, la incapacidad de ver a los demás threads y la falta de memoria, hacen que los shaders no sean muy populares entre los programadores principiantes. ¡No te preocupues! En los próximos capítulos aprenderemos paso a paso, desde los shaders más sencillos a los casos más avanzados. Si estás leyendo esto desde un navegador moderno, vas a poder jugar con los ejemplos interactivos. No esperes más y presiona *Siguiente >>* para ir al próximo capítulo. --- ### 01/README Fa (01/README-fa.md) # شروع ## فرگمنت شیدر چیست؟ در قسمت قبل شیدر ها را معادل دستگاه گوتنبرگ برای گرافیک توصیف کردیم. چرا؟ و مهم تر اینکه: شیدر چیست؟ اگر تجربه نقاشی در کامپیوتر را داشته باشید میدانید که در این فرایند، دایره، مستطیل و خط هارا یکی پس از دیگری میکشید تا شکل مورد نظر خود را نهایی کنید، این فرایند شبیه نوشتن کتاب است، در واقع این کار ها مجموعه ای از دستور العمل ها هستند که وظایف را یکی پس از دیگری انجام میدهند. شیدر ها هم مجموعه ای از دستورالعمل ها هستند، اما دستورالعمل هایی که به یکباره برای هر پیکسل روی صفحه اجرا میشود. این بدان معناست، کدی که مینویسید بسته به موقعیت پیکسل روی صفحه نمایش باید رفتار متفاوتی انجام دهد. برنامه شما مانند تابعی کار میکند که موقعیت را دریافت میکند و یک رنگ را بر میگرداند، زمانی که کد شما کامپایل میشود، این عملیات بسیار سریع انجام میشود. ## چرا شیدر ها سریع هستند؟ برای پاسخ به این سوال من شگفتی پردازش موازی را به شما معرفی میکنم. پردازه مرکزی(CPU) رایانه خود را به عنوان یک لوله بزرگ صنعتی در نظر بگیرید، و هر تسکی را مانند چیزی که از داخل آن عبور میکند بپندارید. بعضی تسک ها بزرگ تر از بقیه هستند پس زمان و انرژی بیشتری برای پردازش آن ها نیاز است. به نوعی میگوییم این نوع تسک ها به قدرت پردازش بالاتری نیاز دارند. به دلیل معماری رایانه ها تسک ها مجبور هستند به صورت سری اجرا شوند، تسک ها باید یک به یک تمام شوند. رایانه های مدرن معمولا دارای گروه های چهارتایی از پردازنده ها هستند، که مانند این لوله ها کار میکنند و وظایف را یکی پس از دیگری انجام میدهد تا کار ها بدون مشکل انجام شود، هر لوله را به عنوان یک ترد(thread) هم میشناسند. بازی های ویدئویی و سایر برنامه های گرافیکی به پردازش بیشتری نسبت به برنامه های معمول نیاز دارند. به دلیل محتویات زیاد، آن ها باید باید مقادیر زیادی عملیات پیکسل به پیکسل انجام دهند. هر یک از پیکسل ها باید محاسبه شوند، همچنین در بازی های سه بعدی باید عملیات های بیشتری مثل محاسبات هندسی و پرسپکتیو هم انجام شود. بیایید به استعاره خود در مورد لوله ها و تسک ها برگردیم، هر پیکسل رو صفحه نمایش یک تسک کوچک و ساده را نشان میدهد، به طور جداگانه تسک هر پیکسل برای CPU مسئله ای نیست. اما اینکه این تسک های کوچک باید برای هر پیکسل انجام شود برای CPU مشکل ساز است. این یعنی در صفحات قدیمی 800x600 باید 480,000 پیکسل در هر فریم پردازش شود که به معنی 14,400,000 محاسبه در ثانیه است! بله این مقدار به قدری بزرگ هست که یک ریزپردازنه را سرریز کند. در یک نمایشگر مدرن 2880x1800 با نرخ 60 فریم بر ثانیه، این محاسبات به 311,040,000 محاسبه در ثانیه میرسد. چگونه مهندسان گرافیک این مشکل را حل میکنند؟ این زمانی است که پردازش موازی به یک راه حل خوب تبدیل میشود، منطقی است که به جای داشتن چند ریز پردازنده بزرگ یا قدرتمند(لوله)، ریزپردازنده های کوچکتری و بیشتری به صورت موازی کار کنند.واحد پردازنده گرافیکی(GPU) همین طور عمل میکند. ریز پردازنده های کوچک را مانند جدولی از لوله ها وداده های هر پیکسل را مانند یک توپ تصور کنید، 14,400,000 توپ میتواند هر لوله ای را مسدود کند، اما میتوان یک جدول از 800x600 لوله کوچک را که 30 موج 480,000 تایی پیکسل در ثانیه دریافت میکند را به راحتی کنترل کرد. در وضوح بالاتر هم به همین صورت عمل میکند. هرچه سخت افزار های موازی بیشتری داشته باشید، به همان نسبت جریان بیشتری را میتوانید مدیریت کنید. از دیگر قدرت های فوق العاده GPU عملکرد های ویژه ریاضی آن است که از طریق سخت افزار سریع تر میشود، یعنی این عملیات ریاضی به جای استفاده از نرم افزار مستقیما توسط میکرو تراشه حل میشوند، به عبارتی عملکرد های مثلثاتی و ماتریسی به سرعت الکتریسیته میتوانند سریع باشند. ## GLSL چیست؟ مخفف OpenGL Shading Language است. که استانداردی خاص از برنامه های شیدر هست و در فصل بعدی خواهید دید. بسته به سخت افزار و سیستم عامل ها انواع دیگر شیدر نیز وجود دارند. در اینجا ما با OpenGL تنظیم شده توسط گروه Khronos کار خواهیم کرد. دانستن تاریخچه OpenGL میتواند به درک بیشتر قرار داد های عجیب و غریب آن مفید باشد، برای همین توصیه میکنیم نگاهی به این موضوع داشته باشید: [openglbook.com/chapter-0-preface-what-is-opengl.html](http://openglbook.com/chapter-0-preface-what-is-opengl.html) ## چرا شیدر ها به دردناک بودن معروفند؟ همانطور که عمو بن گفت:"قدرت زیاد، با مسئولیت بزرگی همراه است"، و محاسبه موازی ازین قاعده پیروی میکند، طراحی معماری قوی GPU محدودیت ها و خصوصیات مخصوص به خودش را دارد. برای این که به صورت موازی هر لوله یا ترد اجرا شود. باید از هر ترد دیگری مستقل باشد، ترد ها نسبت به آنچه بقیه ترد ها انجام میدهد نا آگاه هستند. این محدودیت نشان میدهد که همه داده ها باید در یک جهت جریان داشته باشند. پس بررسی نتیجه یک ترد دیگر، اصلاح داده های ورودی و یا انتقال نتیجه یک ترد به ترد دیگر غیر ممکن است. اگر به ترد ها اجازه ارتباط داده شود، یکپارچگی داده ها در معرض خطر قرار خواهد گرفت. همچنین GPU پردازنده های موازی را به طور مداوم مشغول نگه میدارد، به محض اینکه آزاد میشوند، داده های جدید برای پردازش دریافت میکنند. برای یک ترد غیر ممکن است که بداند که لحظه قبلی چه کاری انجام داده. عملیات قبلی آن میتواند کشیدن یک دکمه برای UI سیستم عامل بوده باشد یا رندر یک آسمان در بازی ویدئویی. هر ترد نه تنها کور(Blind) است(نا آگاه از عملیات ترد های دیگر) بلکه بی حافظه نیز هست. علاوه بر دانستن مفهوم نحوه کد نویسی بر اساس موقعیت هر پیکسل، این کور بودن و بی حافظه بودن، باعث میشود، شیدر ها در میان برنامه نویسان تازه محبوبیت نداشته باشد. نگران نباش در فصل های بعد، گام به گام یاد خواهیم گرفت چگونه محاسبات ساده تا پیشرفته شیدر را انجام دهیم. اگر از مرورگر های مدرن استفاده میکنی، میتوانی از مثال های تعاملی هم استفاده کنی، برای شروع روی کلید بعدی بزن. --- ### 01/README Fr (01/README-fr.md) # Bien démarrer ## Qu'est-ce qu'un fragment shader ? Au chapitre précédent, nous avons décrit les shaders comme l'équivalent de l'avènement de la presse par Gutenberg pour l'impression. Pourquoi cette comparaison mais surtout : Qu'est-ce qu'un shader ? Si vous avez déjà eu une expérience dans la réalisation de dessins avec un ordinateur, vous savez qu'il faut dessiner un cercle, puis un rectangle, une ligne, quelques triangles jusqu'à pouvoir composer l'image que l'on souhaite. Ce processus est très similaire à l'écriture d'une lettre ou d'un livre voire à la peinture, c'est un ensemble d'instructions, exécutées en série, l'une après l'autre. Les shaders sont également des ensembles d'instructions, mais à la différence des API de dessin classiques, *toutes les instructions sont exécutées sur chaque pixel de l'écran*. Cela signifie que le code va devoir se comporter différemment selon la position du pixel sur l'écran. Comme la presse d'imprimerie, votre programme est une fonction à laquelle on passe une position et qui nous renvoie une couleur et une fois compilé, ce programme peut s'exécuter extrêmement rapidement. ## Pourquoi les shaders sont rapides ? Pour répondre à cela, je présente les merveilles du *traitement en parallèle*. Imaginez le CPU de votre ordinateur comme un *tuyau* et chacune des opérations que vous lui demandez d'exécuter comme quelque chose qui passe par ce tuyau - comme dans une usine. Certaines opérations seront sans doute plus importantes que d'autres et demanderont plus de temps et d'énergie pour être traitées. On dit qu'elles nécessitent plus de ressources ou de puissance de calcul. Du fait de l'architecture des ordinateurs, les opérations sont exécutées en série; chaque opération doit être terminée avant que le CPU puisse traiter la suivante. Les ordinateurs récents ont généralement plusieurs processeurs qui jouent le rôle de *tuyaux*, ce qui permet d'exécuter les opérations une après l'autre tout en gardant une certaine fluidité. Ces tuyaux sont ce que l'on appelle des *threads*. Les jeux vidéos et autres applications graphiques demandent beaucoup plus de puissance de calcul que les autres programmes. Par nature, ils demandent de grandes quantités d'opérations au pixel, chaque changement d'image demande de recalculer l'ensemble des pixels de l'écran. Dans les applications 3D, on doit également mettre à jour les modèles, les textures, les transformations etc. ce qui rajoute encore plus de charge au CPU. Revenons à notre métaphore des tuyaux et des opérations. Chaque pixel à l'écran représente une simple petite opération. En soi, le traitement d'une opération n'est pas un problème pour le CPU, mais (et c'est ici que se trouve le problème) il faut appliquer cette petite opération sur chaque pixel à l'écran ! Par exemple, sur un vieux moniteur ayant une résolution de 800x600, 480 000 pixels ont besoin d'être traités par *frame* ce qui équivaut à 14 600 000 calculs par seconde ! C’est une opération assez importante pour surcharger un microprocesseur. Sur un écran rétina moderne ayant une résolution de 2880x1800 cadencé à 60 *frames* par seconde, cela représente un total de 311 040 000 calculs par seconde. Comment les ingénieurs graphiques résolvent-ils ce problème? C'est là qu'intervient le traitement parallèle (parallel processing). Au lieu d'avoir quelques gros et puissants microprocesseurs, ou *tuyaux*, on préfère avoir de nombreux petits microprocesseurs qui tournent en parallèle et simultanément. C'est l'essence même du GPU (Graphics Processing Unit). Imaginez ces petits microprocesseurs comme une trame de tuyaux, et les données de chaque pixel comme des balles de ping-pong. 14 400 000 balles de ping-pong par seconde pourraient obstruer presque n'importe quel tuyau. Mais une trame de 800x600 petits tuyaux recevant 30 vagues de 480 000 balles de ping-pong par seconde peuvent traiter la charge facilement. Et ça marche également pour des résolutions plus élevées; plus le matériel est capable de traiter d'informations en parallèle, plus il pourra traiter des flux importants. Un autre *pouvoir magique* du GPU c'est l'accélération matérielle de certaines fonctions mathématiques. Certaines fonctions souvent complexes seront traitées directement par le matériel au lieu de passer par la couche logicielle. Ce qui signifie que certaines opérations mathématiques un peu complexes comme les transformations de matrices et les opérations trigonométriques seront traitées extrêmement rapidement - à la vitesse de l'électricité. ## Qu'est ce que le GLSL ? GLSL est l'acronyme de "OpenGL Shading Language" (où GL signifie Graphics Library), c'est une norme servant à écrire les programmes de shaders que nous aborderons dans les chapitres suivants. Il existe d'autres types de shaders, selon les plateformes et le matériel utilisé, nous nous concentrerons sur OpenGL, dont les spécifications sont faites par [Khronos Group](https://www.khronos.org/opengl/). Comprendre l'histoire d'OpenGL peut être utile pour comprendre certaines conventions un peu bizarres, si cela vous intéresse, vous pouvez vous reporter à [openglbook.com/chapter-0-preface-what-is-opengl.html](http://openglbook.com/chapter-0-preface-what-is-opengl.html). ## Pourquoi les gens tremblent en entendant le mot Shader ? Comme dit *Uncle Ben* dans Spiderman: "with great power comes great responsibility", le traitement parallèle ne déroge pas à cette règle et aussi puissante que soit la programmation GPU, elle apporte un cortège de contraintes et de restrictions. Pour fonctionner en parallèle, il faut que chaque thread soit indépendant des autres. On dit que le thread est *aveugle* à ce que font les autres threads. Cette restriction implique que toutes les données doivent aller dans le même sens. Il est donc impossible de vérifier le résultat d’un autre thread, de modifier les données d’entrée ou de transmettre le résultat d’un thread à un autre. Autoriser la communication entre threads au moment de l'exécution pourrait compromettre l'intégrité des données en cours de traitement. Il faut également savoir que le GPU s'assure que tous ses microprocesseurs (les tuyaux) sont actifs en permanence; dès qu'un thread a fini son traitement, le GPU lui ré-assigne une opération à traiter. Le thread ne garde aucune trace de ce qu'il faisait la fois précédente. S'il était en train de dessiner le pixel d'un bouton sur une interface graphique, sa tâche suivante pourra être de rendre un bout du ciel dans un jeu, puis de rendre un bout de texte sur un mail. Donc un thread est non seulement **aveugle** mais aussi **amnésique**. En plus du niveau d'abstraction requis pour coder une fonction générique qui saura rendre une image entière uniquement à partir de la variation d'une position, les deux contraintes des threads, cécité et amnésie, rendent la programmation de shaders assez impopulaire auprès des programmeurs débutants. Mais n'ayez crainte ! Au cours des chapitres suivants, nous aborderons les problèmes étape par étape et passerons d'un simple shader à des shaders plus avancés. Si vous lisez ceci dans un navigateur récent, vous apprécierez de pouvoir manipuler les exemples interactifs et beaucoup de ce qui vient d'être dit deviendra plus clair. Sans plus attendre, jetons nous dans le vif du sujet. Appuyez sur *Next >>* pour plonger dans le code ! --- ### 01/README Id (01/README-id.md) # 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? 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. ## 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*. 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? 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). 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 thread 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! --- ### 01/README It (01/README-it.md) # Introduzione ## Che cosa è un fragment shader? Nel capitolo precedente abbiamo descritto lo shader come l'equivalente della stampa di Gutenberg per la grafica. Perché? O meglio ancora: che cosa è uno shader? Se hai già fatto disegni al computer, saprai che si inizia disegnando un cerchio, poi un rettangolo, una linea, alcuni triangoli fino a comporre l'immagine desiderata. Questo processo è molto simile a scrivere una lettera o un libro a mano - in altre parole è un insieme di istruzioni, che eseguono un compito uno dopo l'altro. Gli shaders si possono considerare allo stesso modo un insieme di istruzioni, che sono eseguite tutte nello stesso momento per ogni singolo pixel sullo schermo. Ciò significa che il codice scritto deve comportarsi in modo diverso a seconda della posizione del pixel sullo schermo. Come nel processo della pressa tipografica, il tuo programma riceverà una posizione e restituirà un colore. Quando il codice è compilato, verrà eseguito a velocità straordinaria. ## Perché gli shaders sono così veloci? Per rispondere a questa domanda, vi presento le meraviglie del *calcolo parallelo*. Immaginate la CPU del computer come un grande tubo industriale, e ogni compito come qualcosa che passa attraverso di esso - come in una linea di produzione. Alcuni compiti sono più grandi di altri, il che significa che richiedono più tempo ed energia. Diciamo che necessitano una maggiore potenza di elaborazione. A causa dell'architettura dei computer alcuni compiti sono costretti ad essere eseguiti in serie; ogni compito deve essere completato, uno dopo l'altro. I computer moderni hanno solitamente gruppi di quattro processori che funzionano come questi tubi, eseguendo i compiti uno dopo l'altro per avere le cose funzionanti senza intoppi. Ogni tubo è anche conosciuto come *thread*. I videogiochi e le altre applicazioni grafiche richiedono molta più potenza di elaborazione rispetto ad altri programmi. A causa del loro contenuto grafico devono fare un gran numero di operazioni per pixel. Ogni singolo pixel sullo schermo deve essere calcolato, e nei giochi 3D le geometrie e le prospettive devono essere calcolate allo stesso tempo. Torniamo alla nostra metafora dei tubi e dei compiti. Ogni pixel sullo schermo rappresenta un piccolo compito da realizzare. Individualmente ogni compito non è un problema per la CPU, ma (e qui sta il problema) il piccolo compito deve essere fatto per ogni pixel sullo schermo! Ciò significa che in un vecchio schermo 800x600, 480000 pixel devono elaborati per frame cioè 14400000 calcoli al secondo! Si! Questo è un problema abbastanza grande capace di sovraccaricare un microprocessore. In un moderno schermo retina 2880x1800 in esecuzione a 60 fotogrammi al secondo si possono raggiungere fino a 311040000 calcoli al secondo. Come fanno gli ingegneri grafici a risolvere questo problema? E' in questo caso che il calcolo parallelo diventa una buona soluzione. Invece di avere un paio di grandi e potenti microprocessori, o *tubi*, è più intelligente avere parecchi minuscoli microprocessori che funzionano in parallelo allo stesso tempo. Questo è la Graphic Processor Unit (GPU). Immaginate i minuscoli microprocessori come un tavolo di tubi, ed i dati di ciascun pixel come una pallina da ping pong. 14400000 palline da ping pong in un secondo possono ostacolare qualsiasi tubo. Ma un tavolo di 800x600 piccoli tubi che riceve 30 ondate di 480000 pixel al secondo si può gestire senza problemi. Tutto ciò funziona anche a risoluzioni più elevate - più si possiede hardware in parallelo, più grande è il flusso che si può gestire. Un altro "super potere" della GPU è che alcune speciali funzioni matematiche sono accelerate via hardware, in modo tale che le operazioni matematiche complesse sono risolte direttamente dai microchip invece che da un software. Ciò significa che avremo una velocità extra nel calcolo trigonometrico e nelle operazioni fra matrici, una velocità pari a quella dell'elettricità. ## Che cosa è GLSL? GLSL è l'acronimo di openGL Shading Language, che è lo standard specifico dei programmi shaders che vedrete nei prossimi capitoli. Ci sono altri tipi di shaders a seconda del hardware e dei sistemi operativi. Qui lavoreremo con le specifiche openGL regolate dal [Khronos Group](https://www.khronos.org/opengl/). Comprendere la storia di OpenGL può essere utile per capire la maggior parte delle sue strane convenzioni, per questo vi consiglio di dare un'occhiata a: [openglbook.com/chapter-0-preface-what-is-opengl.html](http://openglbook.com/chapter-0-preface-what-is-opengl.html) ## Perché gli Shaders hanno notoriamente una brutta fama? Come disse lo zio Ben "con un grande potere derivano grandi responsabilità", e il calcolo parallelo segue questa regola; la potente progettazione architettonica della GPU comporta specifici vincoli e restrizioni. Affinché ogni tubo, o thread, venga eseguito in parallelo, è necessario che sia indipendente l'uno dall'altro. Diciamo i thread sono *ciechi* e non vedono ciò che gli altri thread stanno facendo. Questa restrizione implica che tutti i dati debbano affluire nella stessa direzione. Quindi è impossibile controllare il risultato di un altro thread, modificare i dati di input, o passare il risultato di un thread a un altro thread. Permettere la comunicazione fra thread metterebbe a rischio l'integrità dei dati. Anche la GPU mantiene costantemente occupati i micro-processore paralleli (i tubi); non appena sono liberi ricevono nuove informazioni da elaborare. E' quindi impossibile per un thread sapere che cosa stava facendo nel momento precedente. Potrebbe disegnare un bottone dell'UI del sistema operativo, subito dopo rendere una porzione di cielo in un videogioco e poi visualizzare il testo di una e-mail. Ogni thread non è solo **cieco ** ma anche **senza memoria**. Oltre all'astrazione necessaria per programmare una funzione generica che cambia il risultato pixel per pixel, a seconda della sua posizione, i vincoli ciechi e senza memoria non rendono gli shaders molto popolari tra i programmatori debuttanti. Non preoccuparti! Nei capitoli seguenti, impareremo passo-passo a partire dai semplici shaders fino a quelli avanzati. Se stai leggendo questo libro con un navigatore moderno, potrai giocare con gli esempi interattivi. Quindi non aspettare altro tempo e clicca su *Next >>* per iniziare il divertimento! --- ### 01/README Pl (01/README-pl.md) # Początki ## Czym jest fragment shader? W poprzednim rozdziale nazwaliśmy shadery ekwiwalentem prasy drukarskiej Gutenberga dla grafiki. Dlaczego? A co ważniejsze: czym jest shader? Jeżeli masz doświadczenie w rysowaniu z użyciem komputera (np. w *Paint*), to wiesz, że proces ten polega na rysowaniu kółek, prostokątów, linii oraz trójkątów do momentu skomponowania pożądanego obrazu. Proces ten jest bardzo podobny do pisania listów lub książek odręcznie - jest to zbiór instrukcji wykonujących zadanie po zadaniu. Shader również jest zbiorem instrukcji, ale wykonywanych równocześnie dla każdego piksela na ekranie. Oznacza to, że kod, który piszesz musi działać inaczej w zależności od pozycji piksela na ekranie. Podobnie jak maszyna drukarska, twój program będzie działał jak funkcja matematyczna otrzymująca pozycję piksela i zwracająca jego kolor. Po skompilowaniu twój program będzie działał błyskawicznie. ## Dlaczego shadery są szybkie? Aby odpowiedzieć na pytanie, omówmy cud *przetwarzania równoległego* (ang. *parallel processing*) Wyobraź sobie procesor twojego komputera jako potok przetwarzania (ang. "pipeline"), przez który przechodzą różnorakie zadania (jak na linii produkcyjnej w fabryce). Niektóre zadania są większe od innych, co oznacza, że wymagają więcej czasu i energii. Mówimy wtedy, że wymagają więcej *mocy obliczeniowej* (ang. *processing power*). Ze względu na architekturę współczesnych komputerów, zadania te wykonują się seryjnie (jeden po drugim) - każde zadanie musi poczekać, dopóki poprzednie zadanie nie zostanie ukończone. Jednakże, współczesne komputery posiadają zwykle więcej niż jedną jednostkę przetwarzającą (np. 2, 4 lub 8 rdzeni procesora), które funkcjonują jak pomniejsze potoki przetwarzania. Każdy taki pomniejszy potok nazywany jest również *wątkiem* (ang. *thread*). Gry wideo i inne aplikacje graficzne wymagają zdecydowanie więcej mocy obliczeniowej niż większość programów, gdyż muszą wykonywać ogromne ilości operacji piksel po pikselu. Nie dość, że każdy pojedynczy piksel musi być obliczony, to w przypadku gier 3D dochodzą do tego obliczenia geometryczne i obliczenie perspektywy. Wróćmy do naszej metafory potoku przetwarzania. Każdy piksel na ekranie reprezentuje proste zadanie. Indywidualnie zadania te nie stanowią problemu dla CPU, jednak sytuacja zmienia się, gdy takie zadanie musi być wykonane dla każdego piksela na ekranie. Oznacza to, że na starym monitorze 800x600 na jedną klatkę przypada 480.000 obliczeń, co oznacza 14.400.000 obliczeń na jedną sekundę! Właśnie tak! Skala problemu może przeciążyć mikroprocesor. Co więcej, na współczesnym monitorze 2560x1440 przy 60 FPS osiągamy 221.356.800 obliczeń na sekundę. Jak inżynierowie graficzni rozwiązują ten problem? Z pomocą przychodzi przetwarzanie równoległe. Zamiast kilku dużych, potężnych mikroprocesorów (potoków) lepiej mieć wiele małych mikroprocesorów działających równolegle. Tak właśnie działa procesor graficzny (GPU) w karcie graficznej. Wyobraź sobie mały mikroprocesor jako tablicę rur (spójrz na obrazek powyżej), a dane jako piłeczki ping pongowe. 14.400.000 piłeczek ping pongowych na sekundę może zablokować prawie każdą pojedynczą rurę. Ale tabela 800x600 malutkich rur przyjmująca co sekundę 30 fal po 480.000 piłeczek poradzi sobie z nimi bez problemu. Tak samo działa to na wyższych rozdzielczościach - im więcej równolegle pracującego hardware'u, tym większy potok, z którym GPU sobie poradzi. Inną "super umiejętnością" GPU jest fakt, że złożone funkcje matematyczne wykonywane są bezpośrednio na poziomie hardware'u przez mikroczipy, a nie przez software. Skutkiem tego są super szybkie operacje trygonometryczne i macierzowe. ## Czym jest GLSL? GLSL oznacza "Open**GL** **S**hading **L**anguage" i stanowi standard pisania shaderów, który zobaczysz w następnych rozdziałach tej książki. W zależności od hardware'u i systemu operacyjnego wyróżnia się też inne rodzaje shaderów. Tutaj skupimy się na specyfikacji OpenGL uregulowanej przez [Khronos Group](https://www.khronos.org/opengl/). Zrozumienie historii OpenGL może pomóc w zrozumieniu wielu dziwnych konwencji; w tym celu polecam zajrzeć do: [openglbook.com/chapter-0-preface-what-is-opengl.html](http://openglbook.com/chapter-0-preface-what-is-opengl.html). ## Dlaczego shadery budzą postrach? Jak to mówią: "with great power comes great responsibility". Stosuje się to również do obliczeń równoległych - potężne rozwiązania architektoniczne w GPU wiążą się również z pewnymi ograniczeniami. Aby wątki mogły działać równolegle, muszą być od siebie niezależne. Mówimy, że wątki są *ślepe* na to, co robi reszta wątków. Ograniczenie to implikuje, że dane muszą "płynąć w tę samą stronę" - nie jest możliwe sprawdzić dane wyjściowe innego wątku, zmodyfikować jego dane wejściowe albo przekazać dane wyjściowe jednego wątku jako dane wejściowe innego. Poza tym GPU odpowiada za to, żeby każdy wątek miał coś do roboty, i żeby otrzymał dane potrzebne do wykonania tej roboty. Trzeba też pamiętać, że nie jest możliwe, aby wątek wiedział, co robił sekundę temu - mógł rysować przycisk w UI systemu operacyjnego, a potem renderować fragment nieba w grze wideo, a jeszcze potem wyświetlać treść maila. Każdy wątek jest nie tylko **ślepy**, ale również **bez pamięci**. Te cechy sprawiają, że pisanie shaderów nie cieszy się dużą popularnością wśród początkujących programistów. Ale nie martw się! W następnych rozdziałach nauczymy się, krok po kroku, prostych i zaawansowanych obliczeń shadingowych. Jeżeli czytasz to we współczesnej przeglądarce, to z pewnością docenisz zabawę z interaktywnymi przykładami. Ale nie przedłużajmy! Naciśnij *Next>>* aby przejść dalej. --- ### 01/README Pt (01/README-pt.md) # Começando ## O que é um fragment shader? No capítulo anterior descrevemos shaders como o equivalente dos avanços trazidos pela prensa de Gutenberg. Por que? E mais importante: o que é um shader? Se você já tem experiência em desenhar em computadores, você sabe que nesse processo você desenha um círculo, depois um retângulo, uma linha, alguns triângulos até você finalmente compor a imagem desejada. O processo é muito similar a escrever uma carta ou livro à mão, um conjunto de instruções que executam uma tarefa atrás de outra. Shaders são também um conjunto de instruções, mas as instruções são executadas todas ao mesmo tempo para cada pixel da tela. Isso significa que o código que você escreve têm que se comportar de maneira diferente, dependendo da posição do pixel na tela. Como uma prensa tipográfica, seu programa funcionará como uma função que recebe uma posição e retorna a respectiva cor, e, quando esse programa é compilado, ele será executado extraordinariamente rápido. ## Por que shaders são rápidos? Para responder essa pergunta, eu apresento as maravilhas do *processamento paralelo*. Imagine a CPU do seu computador como um grande tubo (ou ducto) industrial, e cada tarefa como algo que passa por ele - como uma linha de produção. Algumas tarefas são maiores que outras, o que signica que elas requerem mais tempo e energia que as outras. Digamos que elas requerem mais poder de processamento. Por causa da arquitetura dos computadores, as tarefas são forçadas a serem executadas em série; cada tarefa é finalizada uma de cada vez. Computadores modernos geralmente tem grupos de quatro processadores para trabalhar com tais tubos, completando as tarefas sequencialmente e mantendo a linha de produção em movimento. Cada tubo é também conhecido como *thread*. Video games e outras aplicações gráficas requerem muito mais poder de processamento que outros programas. Por causa de seu conteúdo gráfico, eles precisam fazer um número enorme de operações pixel-por-pixel. Cada pixel da tela precisa ser computado, e em jogos em 3D geometrias e perspectivas também precisam ser calculadas. Vamos voltar para a nossa metáfora de tubos e tarefas. Cada pixel da tela representa uma tarefa pequena e simples. Individualmente, cada tarefa deste tipo não é um problema para o CPU, mas (e aqui mora o perigo) a pequena tarefa precisa ser repetida para cada pixel na tela! Isso significa que em uma tela antiga de 800x600, 480.000 pixels precisam ser processados pada cada frame, o que totaliza em 14.400.000 cálculos por segundo! Sim! Isso é um problema grande o suficiente para sobrecarregar um microprocessador. Em uma tela moderna com retina display medindo 2880x1800, executando a 60 frames por segundo, esse cálculo resulta em até 311.040.000 cálculos por segundo. Como engenheiros gráficos resolvem esse problema? Neste caso, processamento em paralelo se torna uma boa solução. Em vez de ter alguns microprocessadores grandes e poderosos, ou *tubos*, é mais inteligente ter um monte de minúsculos microprocessadores rodando em paralelo ao mesmo tempo. Isso é o que a Unidade de Processamento Gráfico (Graphic Processor Unit ou GPU) é. Imagine os minúsculos microprocessadores como uma mesa de tubos, e os dados de cada pixel como uma bola de ping-pong. 14.400.000 bolas de ping-pong por segundo podem obstruir quase qualquer tubo. Mas a mesa com 800x600 pequenos tubos recebendo 30 ondas de 480.000 pixels por segundo pode manejar esse fluxo tranquilamente. Funciona do mesmo jeito em resoluções maiores - quanto mais hardware em paralelo você tem, maior o fluxo que eles podem manejar. Outro "super poder" da GPU são funções matemáticas especiais aceleradas via hardware, logo operações matemáticas mais complicadas são resolvidas diretamente pelos microchips em vez do software. Isso resulta em operações trigonométricas e matriciais extra rápidas - tão rápidas quanto a eletricidade. ## O que é GLSL? GLSL é a sigla de openGL Shading Language, o que é o padrão específico de shader que você verá nos próximos capítulos. Existem outros tipos de shaders, dependendo do hardware ou sistemas operacionais. Aqui trabalharemos com as especificações do openGL, reguladas por [Khronos Group](https://www.khronos.org/opengl/). Entender a história do OpenGL pode ser útil se compreender a maior parte das estranhas convenções, para isso eu te recomendo a dar uma olhada em: [openglbook.com/chapter-0-preface-what-is-opengl.html](http://openglbook.com/chapter-0-preface-what-is-opengl.html) ## Por que shaders têm uma má reputação? Como disse o Tio Ben “com grandes poderes vêm grandes responsabilidades” e computação em paralelo segue essa regra; o poderoso design aquitetônico da GPU vem com suas próprias limitações e restrições. Para cada tubo - ou thread - ser executado em paralelo, eles têm que ser independentes de outras threads. Podemos dizer que threads são *cegas* com relação ao que as outras threads estão fazendo. Essa restrição faz com que todos os dados devem fluir na mesma direção. Deste modo é impossível checar o resultado de outra thread, modificar o input de dados ou passar o resultado de uma thread para outra. Permitir comunicação entre as threads coloca a integridade dos dados em risco. Além disso, a GPU mantém os microprocessadores (os tubos) constantemente ocupados; assim que eles ficam livres eles recebem novas informações para serem processadas. É impossível para uma thread saber o que ela estava fazendo num momento anterior. Isso poderia ser desenhar um botão para a UI do sistema operacional, depois renderizar uma porção do céu em um jogo, seguido de mostrar o texto de um email. Cada thread não é só **cega** como **sem memória**. Apesar da abstração requerida para programar uma função genérica que muda o resultado pixel por pixel dependendo da posição do mesmo, as limitações desta cegueira e falta de memória faz com que os shaders não sejam muito populares entre programadores iniciantes. Não se preocupe! Nos capítulos seguintes aprenderemos passo-a-passo a trabalhar com shaders com exemplos que vão de simples a avançados. Se você está lendo este livro em um navegador moderno, você pode poderá brincar com os exemplos interativos. Então clique em *Next >>* e mãos à obra! --- ### 01/README Tr (01/README-tr.md) # Başlarken ## Fragment shader nedir? Önceki bölümde shader'ları, grafikler için Gutenberg matbaasının eşdeğeri olarak tanımlamıştık. Neden? Ve daha da önemlisi: shader nedir? Bilgisayarla çizim yapma konusunda zaten deneyiminiz varsa, bu süreçte istediğiniz görüntüyü oluşturana kadar bir daire, sonra bir dikdörtgen, bir çizgi, bazı üçgenler çizdiğinizi bilirsiniz. Bu süreç, elle mektup veya kitap yazmaya çok benzer - birbiri ardına tek bir görevi yerine getiren talimatlar kümesidir. Shader'lar da bir talimatlar kümesidir, ancak talimatlar ekrandaki her bir piksel için aynı anda yürütülür. Bu, yazdığınız kodun pikselin ekrandaki konumuna bağlı olarak farklı davranması gerektiği anlamına gelir. Bir matbaa baskısı gibi, programınız bir konum alan ve bir renk döndüren bir fonksiyon olarak çalışacak ve derlendiğinde olağanüstü hızlı çalışacaktır. ## Shader'lar neden hızlıdır? Bunu cevaplamak için size *paralel işlemenin* mucizelerini sunuyorum. Bilgisayarınızın CPU'sunu büyük bir endüstriyel boru ve her görevi de içinden geçen bir şey olarak hayal edin - bir fabrika hattı gibi. Bazı görevler diğerlerinden daha büyüktür, bu da onlarla başa çıkmak için daha fazla zaman ve enerji gerektirdiği anlamına gelir. Daha fazla işlem gücü gerektirdiklerini söyleriz. Bilgisayarların mimarisi nedeniyle işler bir seri halinde çalışmaya zorlanır; her işin teker teker bitirilmesi gerekir. Modern bilgisayarlar genellikle bu borular gibi çalışan dört işlemci grubuna sahiptir ve işlerin sorunsuz yürümesini sağlamak için görevleri birbiri ardına tamamlarlar. Her boru aynı zamanda bir *iş parçacığı* (thread) olarak da bilinir. Video oyunları ve diğer grafik uygulamaları, diğer programlardan çok daha fazla işlem gücü gerektirir. Grafik içerikleri nedeniyle çok sayıda piksel bazlı işlem yapmak zorundadırlar. Ekrandaki her bir pikselin hesaplanması gerekir ve 3D oyunlarda geometrilerin ve perspektiflerin de hesaplanması gerekir. Borular ve görevler metaforumuza geri dönelim. Ekrandaki her piksel basit ve küçük bir görevi temsil eder. Bireysel olarak her piksel görevi CPU için bir sorun değildir, ancak (ve işte sorun burada) bu küçük görevin ekrandaki *her piksel* için yapılması gerekir! Bu, eski bir 800x600 ekranda kare başına 480.000 pikselin işlenmesi gerektiği, yani saniyede 14.400.000 hesaplama anlamına gelir! Evet! Bu, bir mikroişlemciyi aşırı yükleyecek kadar büyük bir sorundur. Saniyede 60 kare hızında çalışan modern bir 2880x1800 retina ekranda bu hesaplama saniyede 311.040.000 hesaplamaya ulaşır. Grafik mühendisleri bu sorunu nasıl çözüyor? İşte bu noktada paralel işleme iyi bir çözüm haline gelir. Birkaç büyük ve güçlü mikroişlemciye veya *boruya* sahip olmak yerine, aynı anda paralel çalışan çok sayıda küçük mikroişlemciye sahip olmak daha akıllıcadır. Grafik İşlemci Birimi (GPU) işte budur. Küçük mikroişlemcileri bir boru masası ve her pikselin verisini bir ping pong topu olarak hayal edin. Saniyede 14.400.000 ping pong topu neredeyse her boruyu tıkayabilir. Ancak saniyede 480.000 piksellik 30 dalgayı alan 800x600 küçük borudan oluşan bir masa sorunsuz bir şekilde idare edilebilir. Bu, daha yüksek çözünürlüklerde de aynı şekilde çalışır - ne kadar çok paralel donanımınız varsa, o kadar büyük bir akışı yönetebilir. GPU'nun bir diğer “süper gücü” de donanım üzerinden hızlandırılan özel matematik fonksiyonlarıdır, böylece karmaşık matematik işlemleri yazılım yerine doğrudan mikroçipler tarafından çözülür. Bu, ekstra hızlı trigonometrik ve matris işlemleri anlamına gelir - elektriğin gidebileceği kadar hızlı. ## GLSL nedir? GLSL, OpenGL Shading Language (OpenGL Gölgelendirme Dili) anlamına gelir ve sonraki bölümlerde göreceğiniz shader programlarının özel standardıdır. Donanım ve İşletim Sistemlerine bağlı olarak başka shader türleri de vardır. Burada [Khronos Group](https://www.khronos.org/opengl/) tarafından düzenlenen OpenGL spesifikasyonlarıyla çalışacağız. OpenGL'in tarihini anlamak, garip kurallarının çoğunu anlamak için yararlı olabilir, bunun için şuna bir göz atmanızı öneririm: [openglbook.com/chapter-0-preface-what-is-opengl.html](http://openglbook.com/chapter-0-preface-what-is-opengl.html) ## Shader'lar neden meşhur derecede acı vericidir? Ben Amca'nın dediği gibi “büyük güç büyük sorumluluk getirir” ve paralel hesaplama da bu kurala uyar; GPU'nun güçlü mimari tasarımı kendi kısıtlamaları ve sınırlamalarıyla birlikte gelir. Paralel çalışabilmek için her borunun veya iş parçacığının diğer tüm iş parçacıklarından bağımsız olması gerekir. İş parçacıklarının diğer iş parçacıklarının ne yaptığına *kör* olduğunu söyleriz. Bu kısıtlama, tüm verilerin aynı yönde akması gerektiği anlamına gelir. Bu nedenle başka bir iş parçacığının sonucunu kontrol etmek, girdi verilerini değiştirmek veya bir iş parçacığının sonucunu başka bir iş parçacığına aktarmak imkansızdır. İş parçacıklarının birbirleriyle iletişim kurmasına izin vermek verilerin bütünlüğünü riske atar. Ayrıca GPU, paralel mikro işlemcileri (boruları) sürekli meşgul tutar; serbest kalır kalmaz işlemek için yeni bilgiler alırlar. Bir iş parçacığının bir önceki anda ne yaptığını bilmesi imkansızdır. İşletim sisteminin arayüzünden bir düğme çiziyor, sonra bir oyunda gökyüzünün bir bölümünü oluşturuyor, sonra bir e-postanın metnini görüntülüyor olabilir. Her iş parçacığı sadece **kör** değil, aynı zamanda **hafızasızdır**. Konumuna bağlı olarak sonucu piksel piksel değiştiren genel bir fonksiyon kodlamak için gereken soyutlamanın yanı sıra, kör ve hafızasız kısıtlamalar shader'ları başlangıç seviyesindeki programcılar arasında pek popüler kılmaz. Endişelenmeyin! Sonraki bölümlerde, basit gölgelendirme hesaplamalarından ileri seviye hesaplamalara adım adım nasıl geçileceğini öğreneceğiz. Bunu modern bir tarayıcıyla okuyorsanız, interaktif örneklerle oynamaktan keyif alacaksınız. Öyleyse eğlenceyi daha fazla ertelemeyelim ve koda atlamak için *Sonraki >>* düğmesine basalım! --- ### 01/README Ua (01/README-ua.md) # Вступ ## Що таке фрагментний шейдер? У попередньому розділі ми описали шейдери як еквівалент пресу Гутенберга для графіки. Чому? І що ще важливіше: що таке шейдер? Якщо у вас уже є досвід малювання за допомогою комп'ютера, то ви знаєте, що в цьому процесі ви, умовно кажучи, спочатку малюєте коло, потім прямокутник, лінію, ще кілька трикутників і так далі, доки не отримаєте потрібне зображення. Цей процес дуже схожий на написання листа чи книги від руки – це набір інструкцій, які послідовно виконують одне завдання за іншим. Шейдери також є набором інструкцій, але вони виконуються одночасно для кожного пікселя на екрані. Це означає, що код, який ви пишете, має поводити себе по-різному залежно від положення пікселя на екрані. Подібно до печатного преса, ваша програма працюватиме як функція, яка отримує координати пікселя та повертає колір. Після компіляції вона працюватиме надзвичайно швидко. ## Чому шейдери швидкі? Щоб відповісти на це питання, я розповім про чудеса *паралельних обчислень*. Уявіть центральний процесор вашого комп'ютера у вигляді великої промислової труби, а кожне завдання як щось, що проходить крізь неї, як через фабричну лінію. Деякі завдання більші за інші, а це означає, що для їх вирішення потрібно більше часу та енергії. В комп'ютерному сенсі ми скажемо, що їм потрібна більша обчислювальна потужність. Через особливості архітектури комп'ютерів завдання виконуються послідовно, тобто по черзі. Сучасні комп'ютери зазвичай мають групи з кількох процесорів, які працюють як ці труби, виконуючи завдання одне за одним, щоб забезпечити безперебійну роботу. Кожна подібна труба також називається *потоком*. Відеоігри та інші графічні програми вимагають набагато більшої обчислювальної потужності, ніж інші програми. Через свій графічний контент їм доводиться виконувати величезну кількість попіксельних операцій. Необхідно обчислити кожен окремий піксель на екрані, а в 3D-іграх також потрібно обчислити усю геометрію і перспективу. Повернемося до нашої метафори про труби та завдання. Кожен піксель на екрані представляє просте маленьке завдання. Окремо такі завдання не є проблемою для CPU, але проблема в тому, що кожне крихітне завдання потрібно виконати для кожного пікселя на екрані! Це означає, що на старому екрані з роздільною здатністю 800x600 потрібно обробляти 480 000 пікселів на 1 кадр оновлення, що становить близько 14 400 000 обчислень за секунду! О, так! Це достатньо велика проблема, щоб перенавантажити мікропроцесор. У сучасному дисплеї Retina 2880x1800, що оновлюється зі швидкістю 60 кадрів на секунду, ця кількість обчислень за секунду складе 311 040 000. Як інженери графічних систем розв'язують цю проблему? Ось коли паралельні обчислення стають хорошим рішенням. Замість того, щоб мати пару великих і потужних мікропроцесорів, або *труб*, розумніше мати багато маленьких мікропроцесорів, що працюють паралельно. Саме так і влаштовано графічний процесор (GPU). Уявіть крихітні мікропроцесори у вигляді столу із труб, а дані кожного пікселя як кульку для пінг-понгу. 14 400 000 кульок для пінг-понгу за секунду можуть закупорити майже будь-яку трубу. Але стіл з крихітними трубками розміром 800x600, зможе спокійно прийняти 30 хвиль по 480 000 пікселів за секунду і працюватиме безперебійно. Те ж саме і з прикладом вищої роздільної здатності - чим більше у вас обладнання, що працює паралельно, тим більшим потоком воно зможе керувати. Ще одна "суперздатність" графічного процесора — це спеціальні математичні функції, прискорені за допомогою апаратного забезпечення. Тож складні математичні операції вирішуються безпосередньо мікрочіпами, а не програмним забезпеченням. Це означає надшвидкі тригонометричні та матричні операції - настільки швидкі, наскільки швидко може рухатися електрика. ## Що таке GLSL? GLSL розшифровується як OpenGL Shading Language і є спеціальним стандартом шейдерних програм, які ви побачите в наступних розділах. Залежно від апаратного забезпечення та операційної системи існують різні типи шейдерів. Ми працюватимемо зі специфікаціями OpenGL, які регулює [Khronos Group](https://www.khronos.org/opengl/). Розуміння історії OpenGL може бути корисним для розуміння більшості його дивних конвенцій. Для цього я рекомендую переглянути наступне посилання: [openglbook.com/chapter-0-preface-what-is-opengl.html](http://openglbook.com/chapter-0-preface-what-is-opengl.html) ## Чому шейдери такі болючі? Як сказав дядько Бен, "з великою силою приходить велика відповідальність" і паралельні обчислення дотримуються цього правила. Потужний архітектурний дизайн графічного процесора має власні обмеження. Щоб працювати паралельно, кожен канал або потік має бути незалежним від будь-якого іншого потоку. Ми кажемо, що потоки *сліпі* стосовно того, що роблять інші потоки. Це обмеження означає, що всі дані повинні рухатись в одному напрямку. Тому неможливо перевірити результат іншого потоку, змінити вхідні дані або передати результат одного потоку в інший потік. Спроба дозволу міжпотокових зв'язків ставить під загрозу цілісність даних. Крім того, GPU підтримує свої мікропроцесори (труби) постійно зайнятими. Як тільки вони звільняються, вони отримують нову інформацію для обробки. Потоку неможливо дізнатися, що він робив у попередній момент. Це могло бути малювання кнопки інтерфейсу операційної системи, потім рендеринг частини неба із гри, а потім зображення тексту електронного листа. Кожен потік є не лише **сліпим**, а й **безпам'ятним**. Окрім абстракції, необхідної для кодування загальної функції, яка змінює результат в залежності від положення пікселя, сліпота і безпам'ятство роблять шейдери не дуже популярними серед програмістів-початківців. Не хвилюйтесь! У наступних розділах ми крок за кроком розглянемо шейдерні обчислення від простого до складного. Якщо ви читаєте книгу в сучасному браузері, то оціните можливість взаємодії з інтерактивними прикладами. Тож давайте більше не відкладати веселощі та натискайте на посилання *Next >>*, щоб перейти до програмування! --- ### 01/README Vi (01/README-vi.md) # Mở đầu ## Fragment shader là gì? Ở chương trước, tôi đã mô tả shader tương đương với cỗ máy in của Gutenberg nhưng cho ngành đồ hoạ. Tại sao? Và quan trọng hơn: shader là gì? Nếu bạn đã từng vẽ trên máy tính, bạn biết rằng để có được hình mình muốn, bạn phải vẽ hình tròn, hình chữ nhật rồi vài đường thẳng, vài hình tam giác. Quá trình đó không khác gì việc viết từng chữ một - đó là một loạt các chỉ dẫn để máy tính thực hiện lần lượt. Shader cũng là một tập hợp các chỉ dẫn, nhưng các chỉ dẫn đó sẽ được thực thi cùng lúc cho từng điểm ảnh trên màn hình. Điều đó có nghĩa là code bạn viết phải xử lý khác nhau tuỳ theo vị trí của điểm ảnh trên màn hình. Giống như máy rập chữ, chương trình của bạn sẽ hoạt động như một hàm nhận vị trí của điểm ảnh rồi trả về màu của điểm ảnh đó. Chương trình đó chạy rất rất nhanh. ## Làm cách nào shader lại chạy nhanh tới vậy? Để trả lời câu hỏi này, tôi xin giới thiệu với bạn sự kỳ diệu của việc *xử lý song song*. Hãy tưởng tượng CPU là một dây chuyền công nghiệp lớn, và mọi tác vụ đi qua dây chuyền là một khâu. Có vài khâu đồ sộ hơn các khâu khác, tức là chúng cần nhiều thời gian và năng lượng hơn để xử lý. Ta nói chúng cần nhiều năng lực xử lý hơn. Kiến trúc của máy tính khiến mỗi khâu phải thực hiện tuần tự; khâu này kết thúc rồi mới đến khâu tiếp theo. Máy tính hiện đại thường có tới 4 bộ xử lý tương tự như 4 dây chuyền sản xuất này, lần lượt thực thi từng tác vụ nhỏ. Mỗi dây chuyền nhỏ trong đó gọi là một *thread*. Các trò chơi điện tử và các ứng dụng đồ hoạ cần nhiều năng lực xử lý hơn hẳn các phần mềm khác. Vì các nội dung đồ hoạ của chúng yêu cầu thực hiện rất nhiều phép toán, cho từng điểm ảnh một. Mỗi điểm ảnh trên màn hình đều phải được tính đến, còn trong các trò chơi 3 chiều thì cả các vật thể lẫn các góc camera cũng phải được tính luôn. Quay trở lại phép so sánh về dây chuyền và tác vụ. Mỗi điểm ảnh trên màn hình đại diện cho 1 tác vụ nhỏ. Bản thân từng tác vụ không phải là vấn đề lớn với CPU, nhưng (vấn đề ở đây là) các tác vụ bé xíu này lại phải được thực thi cho từng điểm ảnh trên cả màn hình. Có nghĩa là trên màn hình cũ có độ phân giải 800x600, có tới 480.000 điểm ảnh cần phải được xử lý mỗi khung hình, tương đương với 14.400.000 phép tính mỗi giây! Đúng thế! Đó chính là điều khiến bộ vi xử lý bị quá tải. Còn ở màn hình retina thời hiện đại có độ phân giải 2880x1800 hiển thị 60 khung hình một giây, thì số phép tính mỗi giây lên tới 311.040.000. Bằng cách nào mà các kỹ sư đồ hoạ giải quyết được vấn đề này? Đây là lúc mà xử lý song song trở thành một giải pháp tốt. Thay vì phải trang bị vài bộ vi xử lý to lớn và mạnh mẽ, hoặc *các dây chuyền*, sẽ là thông minh hơn nếu để cho hàng loạt các bộ vi xử lý tí hon chạy song song. Và đó chính là việc mà các bộ xử lý đồ hoạ (GPU) làm. Hình dung các bộ vi xử lý tí hon là hàng loạt những ống xếp dọc và kết lại với nhau thành một cái bàn, còn dữ liệu của mỗi điểm ảnh là một quả bóng bàn. Nhét 14.400.000 quả bóng bàn vào một ống đơn lẻ trong một giây sẽ rất khó. Nhưng khi rất nhiều ống xếp thành hàng 800x600 thì có thể đưa 480.000 quả bóng bàn chui qua tới 30 lần một giây một cách dễ dàng. Độ phân giải cao hơn cũng tương tự - phần cứng càng có năng lực xử lý song song thì khối lượng công việc mà nó có thể giải quyết lại lớn hơn. Một "siêu năng lực" khác của GPU là các hàm Toán học được tối ưu bằng phần cứng, nên các phép toán phức tạp sẽ được xử lý trực tiếp trên phần cứng thay vì phần mềm. Điều đó có nghĩa là các phép tính lượng giác và ma trận sẽ được tính cực kỳ nhanh - như điện luôn. ## GLSL là gì? GLSL là viết tắt của OpenGL Shading Language, là một quy chuẩn để viết các shader mà ta sẽ dùng ở các chương tới. Có nhiều loại shader phụ thuộc vào phần cứng và hệ điều hành. Ở đây chúng ta sẽ sử dụng quy chuẩn của [Khronos Group](https://www.khronos.org/opengl/). Hiểu về lịch sử hình thành của OpenGL sẽ giúp ích trong việc vượt qua được một số rào cản kỳ lạ của nó, vì thế tôi khuyên bạn nên xem qua: [openglbook.com/chapter-0-preface-what-is-opengl.html](http://openglbook.com/chapter-0-preface-what-is-opengl.html) ## Shader nổi tiếng khó nhằn, sao lại thế? Như chú Ben (một nhân vật trong phim Spider Man) nói "Quyền lực càng cao, trách nhiệm càng lớn", và việc tính toán song song cũng tuân thủ quy tắc này; thiết kế kiến trúc rất mạnh mẽ của GPU cũng đi kèm với các ràng buộc và giới hạn. Để các dây chuyền, tức các thread, có thể chạy song song, thì chúng phải độc lập. Có thể nói rằng các thread bị **mù** khi không thể biết được các thread khác đang làm gì. Giới hạn này dẫn tới việc toàn bộ dữ liệu phải đi theo 1 chiều. Nên thread này không thể biết kết quả của thread kia hay thay đổi dữ liệu đầu vào hoặc lấy dữ liệu đầu ra của một thread nọ để chuyển cho một thread khác nữa. Việc cho phép các thread liên thông với nhau (thread-to-thread) sẽ gây rủi ro cho tính toàn vẹn của dữ liệu. Và GPU cũng luôn khiến cho các bộ vi xử lý (các dây chuyền) của mình phải bận rộn; cứ dây chuyền nào xong việc thì sẽ nhận được thông tin mới để xử lý tiếp. Nên mỗi thread còn chẳng biết nó vừa hoàn thành xong việc gì. Nó có thể vừa mới vẽ xong 1 nút bấm trên giao diện của hệ điều hành, rồi vẽ một phần bầu trời trong 1 trò chơi nào đó, sau đó lại phải hiển thị nội dung của 1 cái email. Mỗi thread không chỉ bị **mù** mà còn **mất trí nhớ** nữa. Bên cạnh việc viết code shader khá trừu tượng do phải viết một hàm dùng chung cho mọi điểm ảnh nhưng kết quả thì phụ thuộc vào vị trí của điểm ảnh đó, thì các ràng buộc về việc bị mù và mất trí nhớ ở trên cũng là nguyên do khiến cho shader không được biết đền nhiều bởi các lập trình viên mới vào nghề. Nhưng đừng lo! Ở các chương tới, ta sẽ học từng bước một, từ đơn giản tới phức tạp. Nếu bạn đang đọc trên một trình duyệt đời mới, bạn có thể sẽ thích tương tác với các ví dụ. Đừng trì hoãn sự sung sướng nữa mà hãy click nút *Next >>* để nhảy thẳng vào code nào! --- ### 01/TITLE Gr (01/TITLE-gr.md) # Ξεκινώντας ## Τί είναι ένας fragment shader (φωτοσκιαστής τεμαχίων); --- ### 02/README (02/README.md) ## Hello World Usually the "Hello world!" example is the first step to learning a new language. It's a simple one-line program that outputs an enthusiastic welcoming message and declares opportunities ahead. In GPU-land rendering text is an overcomplicated task for a first step, instead we'll choose a bright welcoming color to shout our enthusiasm! If you are reading this book in a browser the previous block of code is interactive. That means you can click and change any part of the code you want to explore. Changes will be updated immediately thanks to the GPU architecture that compiles and replaces shaders *on the fly*. Give it a try by changing the values on line 8. Although these simple lines of code don't look like a lot, we can infer substantial knowledge from them: 1. Shader Language has a single `main` function that returns a color at the end. This is similar to C. 2. The final pixel color is assigned to the reserved global variable `gl_FragColor`. 3. This C-flavored language has built in *variables* (like `gl_FragColor`), *functions* and *types*. In this case we've just been introduced to `vec4` that stands for a four dimensional vector of floating point precision. Later we will see more types like `vec3` and `vec2` together with the popular: `float`, `int` and `bool`. 4. If we look closely to the `vec4` type we can infer that the four arguments respond to the RED, GREEN, BLUE and ALPHA channels. Also we can see that these values are *normalized*, which means they go from `0.0` to `1.0`. Later, we will learn how normalizing values makes it easier to *map* values between variables. 5. Another important *C feature* we can see in this example is the presence of preprocessor macros. Macros are part of a pre-compilation step. With them it is possible to `#define` global variables and do some basic conditional operation (with `#ifdef` and `#endif`). All the macro commands begin with a hashtag (`#`). Pre-compilation happens right before compiling and copies all the calls to `#defines` and check `#ifdef` (is defined) and `#ifndef` (is not defined) conditionals. In our "hello world!" example above, we only insert the line 2 if `GL_ES` is defined, which mostly happens when the code is compiled on mobile devices and browsers. 6. Float types are vital in shaders, so the level of *precision* is crucial. Lower precision means faster rendering, but at the cost of quality. You can be picky and specify the precision of each variable that uses floating point. In the second line (`precision mediump float;`) we are setting all floats to medium precision. But we can choose to set them to low (`precision lowp float;`) or high (`precision highp float;`). 7. The last, and maybe most important, detail is that GLSL specs don’t guarantee that variables will be automatically casted. What does that mean? Manufacturers have different approaches to accelerate graphics card processes but they are forced to guarantee minimum specs. Automatic casting is not one of them. In our “hello world!” example `vec4` has floating point precision and for that it expects to be assigned with `floats`. If you want to make good consistent code and not spend hours debugging white screens, get used to putting the point (`.`) in your floats. This kind of code will not always work: ```glsl void main() { gl_FragColor = vec4(1,0,0,1); // ERROR } ``` Now that we've described the most relevant elements of our "hello world!" program, it's time to click on the code block and start challenging all that we've learned. You will note that on errors, the program will fail to compile, showing a white screen. There are some interesting things to try, for example: * Try replacing the floats with integers, your graphic card may or may not tolerate this behavior. * Try commenting out line 8 and not assigning any pixel value to the function. * Try making a separate function that returns a specific color and use it inside `main()`. As a hint, here is the code for a function that returns a red color: ```glsl vec4 red(){ return vec4(1.0,0.0,0.0,1.0); } ``` * There are multiple ways of constructing `vec4` types, try to discover other ways. The following is one of them: ```glsl vec4 color = vec4(vec3(1.0,0.0,1.0),1.0); ``` Although this example isn't very exciting, it is the most basic example - we are changing all the pixels inside the canvas to the same exact color. In the following chapter we will see how to change the pixel colors by using two types of input: space (the place of the pixel on the screen) and time (the number of seconds since the page was loaded). --- ### 02/Notes (02/notes.md) ### Scott * After reading 1–7 I understand that there is some relationship between shader language and C, but I’m not sure what it is. Can you tell us explicitly? Is GLSL (shader language) C? Is GLSL a subset of C? * In point #5 you explain preprocessor macros, but you don’t explain why you used one here. You probably don’t want to go off topic just yet, but I would appreciate a sidebar or brief comment explaining why you are including special handling for GL_ES. (My mind goes: Interesting, but why is mobile OpenGL different from non-mobile?) * Point #6: I hope later in the book you will show us an example of how changing float precision affects things visually. (I sense it’s important, but don’t see how yet, and I recognize it is too soon to address it here.) * Point #7: I had to read this two times to get that you meant including the period (.) is casting. I haven’t used C, so I didn’t understand that. I am used to Processing/Java-style casting, like: ``` (float) 1 == 1.0 ``` * I figured out that vec4() is a vector with 4 values, but perhaps you could make that explicit somewhere. --- ### 02/README Ch (02/README-ch.md) ## Hello World “Hello world!”通常都是学习一个新语言的第一个例子。这是一个非常简单,只有一行的程序。它既是一个热情的欢迎,也传达了编程所能带来的可能性。 然而在 GPU 的世界里,第一步就渲染一行文字太难了,所以我们改为选择一个鲜艳的欢迎色,来吧躁起来! 如果你是在线阅读这本书的话,上面的代码都是可以交互的。你可以点击或者改动代码中任何一部分,尽情探索。多亏 GPU 的架构,shader 会**飞速**地编译和更新,这使得你的改动都会立刻出现在你眼前。试试改动第 8 行的值,看会发生什么。 尽管这几行简单的代码看起来不像有很多内容,我们还是可以据此推测出一些知识点: 1. shader 语言 有一个 ```main``` 函数,会在最后返回颜色值。这点和 C 语言很像。 2. 最终的像素颜色取决于预设的全局变量 ```gl_FragColor```。 3. 这个类 C 语言有内建的**变量**(像```gl_FragColor```),**函数**和**数据类型**。在本例中我们刚刚介绍了```vec4```(四分量浮点向量)。之后我们会见到更多的类型,像 ```vec3``` (三分量浮点向量)和 ```vec2``` (二分量浮点向量),还有非常著名的:```float```(单精度浮点型), ```int```(整型) 和 ```bool```(布尔型)。 4. 如果我们仔细观察 ```vec4``` 类型,可以推测这四个变元分别响应红,绿,蓝和透明度通道。同时我们也可以看到这些变量是**规范化**的,意思是它们的值是从0到1的。之后我们会学习如何规范化变量,使得在变量间**map**(映射)数值更加容易。 5. 另一个可以从本例看出来的很重要的类 C 语言特征是,预处理程序的宏指令。宏指令是预编译的一部分。有了宏才可以 ```#define``` (定义)全局变量和进行一些基础的条件运算(通过使用 ```#ifdef``` 和 ```#endif```)。所有的宏都以 ```#``` 开头。预编译会在编译前一刻发生,把所有的命令复制到 ```#defines``` 里,检查```#ifdef``` 条件句是否已被定义, ```#ifndef``` 条件句是否没有被定义。在我们刚刚的“hello world!”的例子中,如果定义了```GL_ES```这个变量,才会插入运行第2行的代码,这个通常用在移动端或浏览器的编译中。 6. ```float```类型在 shaders 中非常重要,所以**精度**非常重要。更低的精度会有更快的渲染速度,但是会以质量为代价。你可以选择每一个浮点值的精度。在第一行(```precision mediump float;```)我们就是设定了所有的浮点值都是中等精度。但我们也可以选择把这个值设为“低”(```precision lowp float;```)或者“高”(```precision highp float;```)。 7. 最后可能也是最重要的细节是,GLSL 语言规范并不保证变量会被自动转换类别。这句话是什么意思呢?显卡的硬件制造商各有不同的显卡加速方式,但是却被要求有最精简的语言规范。因而,自动强制类型转换并没有包括在其中。在我们的“hello world!”例子中,```vec4``` 精确到单精度浮点,所以应被赋予 ```float``` 格式。但是如果你想要代码前后一致,不要之后花费大量时间 debug 的话,最好养成在 ```float``` 型数值里加一个 ```.``` 的好习惯。如下这种代码就可能不能正常运行: ```glsl void main() { gl_FragColor = vec4(1,0,0,1); // 出错 } ``` 现在我们已经基本讨论完了“hello world!”例子中所有主要的内容,是时候点击代码,检验一下我们所学的知识了。你会发现出错时程序会编译失败,只留一个寂寞的白屏。你可以试试一些好玩的小点子,比如说: * 把单精度浮点值换成整型数值,猜猜你的显卡能不能容忍这个行为。 * 试试把第八行注释掉,不给函数赋任何像素的值。 * 尝试另外写个函数,返回某个颜色,然后在 ```main()``` 里面使用这个函数。给个提示,这个函数应该长这样: ```glsl vec4 red(){ return vec4(1.0,0.0,0.0,1.0); } ``` * 有很多种构造 ```vec4``` 类型的方式,试试看其他方式。下面就是其中一种方式: ```glsl vec4 color = vec4(vec3(1.0,0.0,1.0),1.0); ``` 尽管这个例子看起来不那么刺激,它却是最最基础的 —— 我们把画布上的每一个像素都改成了一个确切的颜色。在接下来的章节中我们将会看到如何用两种输入源来改变像素的颜色:空间(依据像素在屏幕上的位置)和时间(依据页面加载了多少秒)。 --- ### 02/README De (02/README-de.md) ## Hallo Welt Beim Erlernen einer neuen Programmiersprache beginnt man häufig mit dem berühmten „Hello world!“-Beispiel. Dabei handelt es sich um einen simplen Einzeiler, der die Meldung „Hello world!“ auf den Bildschirm bringt - als Gruß an die Welt und als Ausdruck der Vorfreude auf die kommenden Möglichkeiten. In der Welt der Shader-Programmierung ist die Textausgabe eine zu komplizierte Angelegenheit, um gleich damit zu beginnen. Stattdessen wollen wir eine leuchtende Farbe als Willkommensgruß auf den Bildschirm zaubern. Falls Du dieses Buch in einem Internet-Browser liest, ist der obige Programmcode interaktiv. Du kannst in das Listing hineinklicken und jeden Teil des Programmcodes ändern. Deine Änderungen werden sofort innerhalb der Zeichenfläche sichtbar, weil der Shader-Code automatisch kompiliert und ausgeführt wird. Versuche es doch einfach einmal, indem Du die Zahlenwerte in der *Programmzeile 8* änderst. Obwohl diese wenigen, einfachen Programmzeilen noch nicht nach viel aussehen, können wir daraus bereits einige Erkenntnisse gewinnen: 1. Shader-Programme verfügen über genau eine ```main```-Funktion, die an ihrem Ende einen Farbcode zurückliefert. Das erinnert stark an die Programmiersprache C, nur dass es dort nicht immer um Farbcodes geht. 2. Der berechnete Farbwert wird für die Rückgabe in die reservierte globale Variable ```gl_FragColor``` eingetragen. 3. Die stark von C beeinflusste Programmiersprache für Shader verfügt über eingebaute *Variablen* (so wie ```gl_FragColor```), *Funktionen* und *Datentypen*. Im obigen Beispiel sehen wir bereits den Datentyp ```vec4```, der einen vierdimensionalen Vektor aus Fließkommazahlen repräsentiert. Im weiteren Verlauf des Buches werden wir noch die Typen ```vec3``` und ```vec2``` kennen lernen, ebenso die wichtigen Typen ```float```, ```int``` und ```bool```. 4. Wenn wir uns den ```vec4``` Datentyp im obigen Beispiel genau anschauen, können wir bereits erahnen, dass die vier Zahlenwerte für die Farbkanäle Rot, Grün, Blau und Alpha (ein Maß für die Deckkraft) stehen. Außerdem erkennen wir, dass diese Werte offensichtlich normalisiert sind, sich also zwischen ```0.0``` und ```1.0``` bewegen. Später werden wir noch sehen, dass es uns diese Normalisierung vereinfacht, die Inhalte von Variablen auf Farbwerte *abzubilden*. 5. Eine weiteres aus C bekanntes Element sind die Präprozessor-Makros, die auch in unserem obigen Beispiel auftauchen. Mit ihrer Hilfe lassen sich Konstanten definieren (```#define```) und konditionale Festlegungen treffen (mit ```#ifdef``` und ```#endif```). Alle diese Makrobefehle beginnen mit einer Raute (```#```). Ihre Auswertung erfolgt als erster Schritt noch vor der eigentlichen Kompilierung des Shaders. Das Ergebnis dieser Auswertung bestimmt jeweils, welche Zeilen und Ausdrücke tatsächlich in den Programmcode einfließen, der anschließend kompiliert wird. In unserem obigen Beispiel wird die *Programmzeile 2* beispielsweise nur dann übernommen, wenn das Symbol ```GL_ES``` definiert ist. Dies ist in der Regel nur in Umgebungen auf mobilen Geräten der Fall, d.h. wenn das obige Programm beispielsweise auf einem Smartphone kompiliert wird, ist die Zeile 2 darin vorhanden und wirkt sich entsprechend aus. Beim Kompilieren auf einem Laptop oder PC taucht die Zeile 2 aber gar nicht auf, weil dort auch das Symbol ```GL_ES``` nicht definiert ist. 6. Fließkomma-Datentypen sind ganz entscheidend für die Berechnungen innerhalb von Shadern. Deshalb spielt die *Genauigkeit* dieser Operationen eine wichtige Rolle. Eine geringere Genauigkeit bedeutet weniger Aufwand und geht deshalb mit einer schnelleren Berechnung einher. Der Preis dafür sind allerdings Einbußen bei der Qualität der Berechnungen. Wenn man will, kann man die Genauigkeit jeder einzelnen Fließkommavariablen genau festlegen. Meist unterscheidet man jedoch grundsätzlich, je nach den Möglichkeiten der Plattform, auf der ein Shader zur Ausführung kommen soll. So setzen wir hier in der zweiten Programmzeile die Genauigkeit auf Medium (```precision mediump float;```), wenn der Shader auf einem Mobilgerät kompiliert wird. Darüber hinaus gibt es noch die Genauigkeitsstufen „niedrig“ (```precision lowp float;```) und „hoch“ (```precision highp float;```). Letzteres ist auf vielen Plattformen die Vorgabe, sofern wir nichts Anderes festlegen. 7. Die letzte und für die Praxis vielleicht wichtigste Erkenntnis aus dem obigen Programmcode ist, dass wir Fließkommawerte immer mit einem Punkt („.“) versehen sollten, auch wenn der Nachkommateil leer bleibt (Null ist). Denn sonst macht der Compiler möglicherweise Integer-Werte (Ganzzahlen) daraus, und das kann während der Ausführung des Shaders zu hässlichen Programmfehlern führen. Die Zeichenfläche bleibt dann einfach weiß, weil es nicht weitergeht. Wenn du guten und auf vielen Shader-Plattformen ausführbaren Code entwickeln möchtest, gewöhne Dir die Kennzeichnung als Fließkommazahl durch den Punkt am besten gleich an. Denn der folgende Programmcode wird beispielsweise auf einigen Shader-Plattformen funktionieren, auf anderen hingegen nicht: ```glsl void main() { gl_FragColor = vec4(1,0,0,1); // potenzielle Fehlerquelle! } ``` So, wo wir nun die wichtigen Elemente unseres kleinen „Hello world!“-Programms beschrieben haben, ist es an der Zeit, mit Veränderungen am Programmcode zu experimentieren. Du wirst feststellen, dass sich das Programm bei Syntaxfehlern oder unbekannten Befehlen weigert, zu kompilieren, und die Zeichenfläche deshalb weiß bleibt. Es gibt einige interessante Dinge, die Du direkt einmal ausprobieren kannst, beispielsweise: * Versuche, die Fließkommazahlen durch Ganzzahlen zu ersetzen. Dann wirst Du unmittelbar feststellen, ob Deine aktuelle Umgebung/Grafikkarte damit umgehen kann. * Versuche, die *Programmzeile 8* auszukommentieren, und schau was passiert, wenn der Code dadurch keinen Farbwert zurückliefert. * Versuche, eine zusätzliche Funktion in den Programmcode einzufügen, die eine von Dir gewählte Farbe zurückliefert und rufe diese Funktion innerhalb von ```main()``` auf. Dazu ein Tipp: Hier folgt der Programmcode für eine Funktion, die Rot zurückliefert: ```glsl vec4 red(){ return vec4(1.0,0.0,0.0,1.0); } ``` * Es gibt verschiedene Wege, um einen Wert vom Typ ```vec4``` zu konstruieren. Versuche, weitere Wege zu entdecken. So geht es zum Beispiel auch: ```glsl vec4 color = vec4(vec3(1.0,0.0,1.0),1.0); ``` Obwohl dieses „Hello world!“-Programm noch nicht so wahnsinnig aufregend daherkommt, ist es doch das simpelste Beispiel aus der Welt der Shader. Wir beeinflussen damit die Farbe aller Bildpunkte innerhalb unserer Zeichenfläche. In den nun folgenden Kapiteln werden wir die Farbe der einzelnen Bildpunkte aufgrund von zwei unterschiedlichen Arten von Eingabewerten steuern: Ihrer Position (d.h. die Lage des zu bearbeitenden Pixels innerhalb der Zeichenfläche) und der Zeit (d.h. der Zeitspanne, die seit dem Laden einer Seite vergangen ist). --- ### 02/README Es (02/README-es.md) ## Hola mundo Usualmente el "Hola mundo" es el primer ejemplo con el que se aprende un lenguaje de programación. Se trata de una simple linea de código que imprime un entusiasta mensaje de bienvenida. En el mundo de las GPU renderizar texto es una tarea complicada para ser el primer paso, por lo tanto nosotros vamos a imprimir un brillante color de bienvenida para mostrar nuestro entusiasmo. Si estás leyendo este libro en un navegador, el código anterior es interactivo, eso significa que puedes hacer clic y cambiar cualquier línea de código para explorar cómo funciona. Los cambios se reflejaran automáticamente gracias a que la arquitectura de la GPU se encarga de compilar y reemplazar los shaders al instante. Intenta modificar el contenido de la línea 6. Aunque estas simples líneas de código no parezcan mucho, podemos inferir mucha información importante de ellas: 1. Los shaders tienen una función ```main``` principal que devuelven un color al final. Esto es muy similar a C. 2. El color final del pixel es guardado en la variable global reservada ```gl_FragColor```. 3. Este lenguaje similar a C tiene *variables* reservadas (como ```gl_FragColor```), *funciones* y *tipos de variables*. En este caso vemos que existe ```vec4``` que es un tipo de variable de 4 dimensiones de punto flotante. Más adelante veremos otros tipos de variables como ```vec3``` y ```vec2``` junto con las populares: ```float```, ```int``` y ```bool```. 4. Si miramos detenidamente el ```vec4``` podemos inferir que los cuatro argumentos pasados son el canal RED (rojo), el canal GREEN (verde), el canal BLUE (azul) y el canal ALPHA (transparencia). Además podemos ver que los valores se encuentran *normalizados*, eso significa que van desde ```0.0``` a ```1.0```. Más adelante aprenderemos que normalizar valores vuelve mucho más fácil nuestro trabajo con las variables. 5. Otra *función de C* que vemos en el ejemplo son los macros al preprocesador. Los macros son parte del proceso de precompilado. Con ellos es posible definir variables globales (con ```#define```) y hacer operaciones condicionales básicas ( con ```#ifdef``` y ```#endif```). Todos los comandos macro comienzan con un numeral (```#```). La pre-compilación sucede en el momento previo a la compilación y chequea todos los ```#defines```, y los condicionales ```#ifdef``` (está definido) y ```#ifndef``` (no está definido). En nuestro ejemplo, el "Hola mundo", solamente insertamos la segunda línea de código si ```GL_ES``` está definida, que la mayoría de las veces se encuentra definida cuando el código es compilado en mobile o en navegadores. 6. Los valores flotantes son vitales en los shaders, ya que el nivel de *precisión* es crucial. A menor precisión mayor velocidad de render, pero peor calidad. Podemos ser meticulosos y especificar la precisión de cada variable que use punto flotante. En la primera línea (```precision mediump float;```) estamos ajustando todos los valores flotantes a una precisión media. Pero podríamos configurarlos en low (```precision lowp float;```) o high (```precision highp float;```). 7. El último detalle, y quizá el más importante, es que las especificaciones de GLSL no garantizan que las variables sean automáticamente convertidas. ¿Qué significa eso? Los manufacturadores de GPU tienen diferentes estrategias para acelerar los gráficos pero están forzados a entregar especificaciones mínimas, por lo que la conversión automática de variables no es algo importante. Si queremos que nuestro código sea consistente y no pasar horas depurando pantallas blancas, tenemos que acostumbrarnos a usar el punto ( ```.``` ) en los flotantes. Este código no siempre funcionará: ```glsl void main() { gl_FragColor = vec4(1,0,0,1); // ERROR } ``` Ahora que ya describimos los elementos más importantes de nuestro "Hola mundo", es hora de hacer clic en el código y poner en práctica nuestros conocimientos aprendidos. Notarás que cuando hay errores, el programa no compilará, y mostrará una pantalla blanca. Aqui hay algunas cosas interesantes que puedes probar, por ejemplo: * Intenta modificar los flotantes y poner enteros, es posible que tu placa de video no tolere esto. * Prueba comentar la línea 6 y no asignar ningún valor a la función. * Intenta crear una función separada que devuelva un color específico y usalo dentro del ```main()```. Una pista, aqui está el código que usaríamos para devolver el color rojo: ```glsl vec4 red(){ return vec4(1.0,0.0,0.0,1.0); } ``` * Hay muchas formas de construir un ```vec4```, intenta descubrir nuevas formas de hacerlo. La siguiente es un ejemplo: ```glsl vec4 color = vec4(vec3(1.0,0.0,1.0),1.0); ``` Mas alla de que el ejemplo no sea muy emocionante, es el ejemplo más básico que podemos crear - estamos cambiando todos los pixeles de la pantalla al mismo tiempo y asignándole a todos el mismo color. En el siguiente capítulo veremos cómo cambiar los colores de los pixeles utilizando dos tipos de entradas: espacio (la posición del pixel en la pantalla) y tiempo (el número de segundos desde que la página fue cargada). --- ### 02/README Fa (02/README-fa.md) ## Hello World معمولا عبارت "Hello World" مثالی از اولین قدم برای یادگیری یک زبان جدید است. در مورد ما ارائه یک متن کار پیچیده ای برای قدم اول است، در عوض یک رنگ روشن را به عنوان شور و شوق اولین کدمان اجرا میکنیم! اگر این کتاب را در یک مرورگر مدرن میخوانید، کد بالا قابل تغییر است، تغییرات شما بلافاصله کامپایل و به شما نمایش داده میشوند، سعی کنید خط 8 را تغییر دهید. البته این خطوط ساده به نظر نمیرسند، اما میتوان مفاهیم قابل توجهی از آنها استباط کرد: 1. برنامه نویسی شیدر یک عملکرد اصلی 'main' دارد، که در انتها یک رنگ برمیگرداند. شبیه زبان C. 2. رنگ نهایی پیکسل به متغیر گلوبال gl_FragColor اختصاص داده شده است. 3. این زبان شبه C با متغیر ها و تابع های مختلف ساخته شده و استفاده میشود. در این مورد ما با vect4 آشنا شدیم که مخفف یک بردار 4 بعدی با دقت شناور(float) است. انواع بیشتری ازین متغیر ها مانند vect2, vect3 و bool, int, float در آینده خواهیم دید. 4. اگر به vect4 دقت کنیم مییابیم این 4 آرگومان به کانال های RGBA پیکسل مورد نظر پاسخ میدهند. همچنین این مقادیر نرمال شده اند یعنی بین 0تا1(نه بین 0 تا 255)، بعدا خواهیم آموخت چگونه نرمال سازی مقادیر، ترسیم مقادیر بین متغیر ها را آسان میکند. 5. یکی از دیگر ویژگی های مشابه C مثال بالا وجود ماکرو ها هستند. با استفاده از آنان میتوان متغیر های جهانی را تعریف کرد و یا برخی عملیات شرطی اساسی را انجام داد(ifdef and #endif#). تمام دستورات کلان(ماکرو) با هشتگ شروع میشوند. ماکرو ها قبل از کامپایل اجرا میشوند، شرایط را بررسی میکند(ifdef and #endif#) و ارجاعات به defines# را کپی میکند. مثلا در مثال بالا ما خط 2 را در صورت تعریف GL_ES وارد میکنیم. که معمولا در هنگام کامپایل این کد در تلفن های همراه و مرورگر ها اتفاق میافتد. 6. شناور ها(float) در شیدر ها حیاتی هستند، بنابراین سطح دقت بسیار مهم است. دقت پایین تر به معنای رندر سریع تر است، همچنین کیفیت کمتر. میتوانید مثل من خط دو مثال بالا متغیر های شناور را با دقت متوسط درنظر بگیرید(precision mediump float)، همچنین میتوانید متغیر شناور با دقت پایین(precision lowp float) یا بالا(precision highp float)هم میتوان در نظر گرفت. 7. آخرین و شاید مهمترین نکته در مثال بالا اینکه در GLSL تضمین نمیشود که متغیر ها به طور خودکار تغییر نوع داده(casting) رویشان اعمال شود. این به چه معناست؟ تولید کنندگان رویکرد های مختلفی برای سرعت بخشیدن روند پردازش کارت های گرافیکی دارند، و مجبورند حداقل مشخصات را تضمین کنند. کستینگ ازین رویکرد ها نیست. در مثال بالا vect4 دارای نقطه شناور است و برای آن انتظار میرود که به متغیر های شناور انتساب شود. اگر میخواهید کد سازگار خوبی ایجاد کنید و ساعت ها وقت صرف دیبگ کردن آن نکنید، عادت کنید در float ها از نقطه(.) استفاده کنید. ```glsl void main() { gl_FragColor = vec4(1,0,0,1); // ERROR } ``` اکنون که مهم ترین عناصر مثال بالا را با هم مرور کردیم، وقت آن است که روی کد کلیک کنید و چیز هایی که یاد گرفتیم را پیاده کنیم. توجه کنید که در صورت خطا برنامه صفحه سفید را به شما نشان میدهد. بعضی چیز های جالب وجود دارد که باید امتحان کنید، مثلا: * شناور ها را با اعداد صحیح(int) جایگزین کنید، کارت گرافیک شما معلوم نیست بتواند این کد را اجرا کند یا خیر. * سعی کنید خط 8 را کامنت کنید و هیچ مقدار پیکسلی به تابع اختصاص ندهید. * سعی کنید یک تابع جداگانه ایجاد کنید که رنگ خاصی را برگرداند و از آن داخل main استفاده کنید، به عنوان یک راهنمایی در اینجا کد مربوط به تابعیست که رنگ قرمز را بر میگرداند. ```glsl vec4 red(){ return vec4(1.0,0.0,0.0,1.0); } ``` * روش ها مختلفی برای ساخت vect4 وجود دارد، سعی کنید راه های دیگر را پیدا کنید، یکی از آن ها به این صورت است: ```glsl vec4 color = vec4(vec3(1.0,0.0,1.0),1.0); ``` اگرچه این مثال خیلی هیجان انگیز نیست، اما ابتدایی ترین مثال است. ما تمام پیکسل های داخل کنوس(canvas) را به یک رنگ تغییر دادیم. در فصل بعد نحوه تغییر رنگ پیکسل را با استفاده از دو نوع ورودی دیگر میبینیم. فضا(محل و مختصات پیکسل روی صفحه) و زمان(مقدار زمان از لحظه بارگیری صفحه بر حسب ثانیه). --- ### 02/README Fr (02/README-fr.md) ## Hello World Généralement le "Hello World!" est la première étape dans l'apprentissage d'un nouveau langage. Il s'agit d'un programme court qui renvoie un message enthousiaste et fait miroiter un avenir radieux. Au pays du GPU, afficher du texte est une tâche extrêmement complexe pour une première étape, à la place nous allons choisir une couleur chatoyante pour déchaîner notre enthousiasme ! Si vous lisez ceci dans un navigateur récent, le bloc précédent est interactif. Cela signifie que vous pouvez cliquer et éditer le code.Les modifications seront mises à jour immédiatement grâce à l'architecture GPU qui compile et remplace les shaders *à la volée*. Vous pouvez essayer de changer les valeurs de la ligne 8. Si ce programme paraît simple, nous pouvons déjà faire quelques observations intéressantes : 1. Ça ressemble à du C, un shader possède une fonction `main` dont le seul but est d'assigner une couleur. 2. La couleur du pixel est assignée à une variable globale réservée `gl_FragColor`. 3. Ce langage aux allures de C, possède des *variables* (comme `gl_FragColor`), des *fonctions* et des *types*. Dans cet exemple, nous venons de voir le type `vec4` qui représente un vecteur de chiffres à virgule flottante (`float`) à 4 dimensions. Plus tard nous verrons d'autres types comme `vec3` & `vec2` avec les plus communs comme : `float`, `int` & `bool`. 4. Si l'on regarde `vec4` de plus près, on peut déduire que les 4 arguments correspondent aux 4 canaux: `RED`, `GREEN`, `BLUE` & `ALPHA` du pixel. On note également que les valeurs sont *normalisées*, ce qui signifie qu'elles vont de `0.0` à `1.0`. Plus tard, nous verrons comment la normalisation des valeurs facilite la mise en correspondance (*map*) des valeurs avec des variables. 5. Une autre caractéristique du C importante que nous pouvons voir dans cet exemple est la présence de macros de préprocesseur. Les macros font partie de l'étape de pré-compilation, elles permettent de définir (`#define`) des variables globales et de faire des opérations conditionnelles de base (avec `#ifdef` & `#endif`). Toutes les macros commencent par un hashtag (`#`). La pré-compilation se produit - comme son nom l'indique - avant la compilation du shader, elle copie et renseigne tous les `#define` et vérifie les inclusions conditionnelles `#ifdef` (si défini) et `#ifndef` (si non défini). Dans l'exemple ci-dessus, nous n'insérons la ligne 2 que si `GL_ES` est défini, ce qui se produit principalement lorsque le code est compilé sur mobile ou dans un navigateur. 6. Le type `float` est vital dans les shaders, donc le niveau de *précision* des nombres flottants est crucial. Une précision basse permet un rendu plus rapide mais une qualité moindre et inversement, une précision élevée permet un meilleur rendu au prix de performances réduites. On peut spécifier la précision de chaque variable se servant de, ligne 2, `precision mediump float;`, nous assignons la précision *medium* à tous les flottants de l'application. Nous pourrions leur donner une valeur basse (`precision lowp float;`) ou haute (`precision highp float;`). 7. La dernière remarque, probablement la plus importante, est que les spécifications GLSL ne garantissent pas que les variables seront *castées* automatiquement. Qu'est-ce que cela veut dire ? Les fabricants ont des approches différentes pour accélérer leurs cartes graphiques mais ils doivent toutefois se conformer au minimum à un ensemble de spécifications communes. Le casting automatique des variables ne fait pas partie des spécifications. Dans notre exemple, `vec4` attend des `floats` et rien d'autre. Si vous voulez obtenir un code homogène et éviter de passer des heures à débugger un écran blanc, prenez l'habitude de mettre des points (`.`) dans vos floats. Ce genre de code ne marchera pas toujours : ```glsl void main() { gl_FragColor = vec4(1,0,0,1); // ERROR } ``` Alors que celui ci à de plus grandes chances de marcher : ```glsl void main() { gl_FragColor = vec4(1., .0, 0., 1.); // BETTER } ``` Notez que le point peut être placé avant ou après un *0*. Maintentant que nous avons passé en revue quelques éléments importants du programme "Hello World!", il est temps de cliquer sur le bloc de code et de mettre en application ce que nous venons d'apprendre. Vous remarquerez que le programme ne se recompilera pas tant qu'il restera des erreurs. Voici quelques idées intéressantes à tester : * Essayez de remplacer les *float* par des *int* la carte graphique vous autorisera ou non à le faire. * Essayez de commenter (`//`) la ligne 8, ce qui n'assignera aucune valeur au pixel. * Essayez de créer une fonction qui retourne une couleur en dehors de `main()` et essayez de l'utiliser pour assigner la valeur de `gl_FragColor` dans `main()`. Pour vous aider, voici le code d'une fonction qui retourne une couleur rouge : ```glsl vec4 red() { return vec4(1.0,0.0,0.0,1.0); } ``` * On peut construire un `vec4` de plusieurs façons, essayez de découvrir d'autres manières. Par exemple: ```glsl vec4 color = vec4(vec3(1.0,0.0,1.0),1.0); ``` Bien que cet exemple ne soit pas très excitant, c'est le plus basique qui soit - nous donnons à l'ensemble des pixels de l'image la même couleur. Dans le chapitre suivant, nous verrons comment changer cette couleur en fonction de 2 facteurs : l'espace (l'emplacement du pixel à l'écran) et le temps (le nombre de secondes écoulées depuis le chargement de la page). --- ### 02/README Id (02/README-id.md) ## 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! 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). --- ### 02/README It (02/README-it.md) ## Ciao Mondo Di solito l'esempio "Ciao Mondo!" è il primo passo per imparare un nuovo linguaggio. Si tratta di un semplice programma di una riga che visualizza un messaggio entusiastico di benvenuto. Nel mondo GPU rendere un testo è un esercizio troppo complicato per un primo passo, perciò sceglieremo un colore brillante di benvenuto per mostrare il nostro entusiasmo! Se stai leggendo questo libro in un navigatore, noterai che il precedente blocco di codice è interattivo. Ciò significa che è possibile fare click e modificare qualsiasi parte del codice per capire come funziona. Le modifiche verranno aggiornate immediatamente grazie all'architettura GPU che compila e sostituisce gli shaders *al volo*. Prova per esempio a cambiare i valori della linea 6. Anche se queste semplici righe di codice non sembrano essere molto importanti, possiamo trarre molte informazioni: 1. Gli Shaders hanno una unica funzione ```main``` che alla fine restituisce un colore. Questa caratteristica è molto simile al linguaggio C. 2. Il colore finale dei pixel viene assegnato a una variabile globale riservata ```gl_FragColor```. 3. Questo linguaggio è simile al C e ha *variabili* built-in (come ```gl_FragColor```), *funzioni* e *tipi*. In questo esempio abbiamo introdotto ```vec4``` che è un vettore a virgola mobile(float) di quattro dimensioni. Più avanti incontreremo altri tipi come ```vec3``` e ```vec2``` insieme ai più popolari: ```float```, ```int``` e ```bool```. 4. Se analizziamo il tipo ```vec4``` possiamo dedurre che i quattro argomenti corrispondono ai canali ROSSO, VERDE, BLU e ALFA. Inoltre possiamo notare che questi valori sono *normalizzati*, il che significa che vanno da ```0.0``` a ```1.0```. In seguito, impareremo che normalizzare i valori rendere più facile *mapparli* fra le variabili. 5. Un'altra importante *caratteristica del C* che si può vedere in questo esempio è la presenza di macro del preprocessore. Le macro sono parte di una fase di pre-compilazione. Con loro è possibile ```#define``` variabili globali e fare alcune funzioni condizionali di base (con ```#ifdef``` e ```#endif```). Tutti i comandi macro iniziano con un hashtag (```#```). La pre-compilazione avviene appena prima di compilare lo shader e copia tutte le chiamate a ```#defines``` e verifica ```#ifdef``` (è definito) e ```#ifndef``` (non è definito) nel caso di chiamate condizionali . Nel nostro esempio precedente "Ciao mondo!", abbiamo inserito solo la linea 2 per verificare se ```GL_ES``` è definito, chiamata che avviene soprattutto quando il codice viene compilato su dispositivi mobili e browser. 6. I tipi float sono vitali negli shader, dove il livello di *precisione* è fondamentale. Precisione inferiore significa resa più veloce, ma a scapito della qualità. Si può essere pignoli e specificare la precisione di ogni variabile che utilizza la virgola mobile. Nella prima riga (```precision mediump float;```) stiamo definendo tutti i float a media precisione. Ma possiamo impostare la loro precisione a un livello basso (```precision lowp float;```) o alto (```precision highp float;```). 7. L'ultimo, e forse più importante, dettaglio è che le specifiche GLSL non garantiscono che le variabili siano convertite automaticamente. Cosa significa? I produttori delle carte grafiche hanno differenti approcci per accelerare i processi delle carte grafiche, ma sono costretti a garantire delle specifiche minime. La conversione automatica non è una di queste. Nel nostro esempio "Ciao mondo", ```vec4``` ha precisione in virgola mobile e per questo ci si aspetta dei ```floats```. Se si vuole realizzare un codice omogeneo e non passare ore a fare il debug di schermi bianchi, abituatevi a mettere il punto ( ```.``` ) all'interno dei vostri float. Questo tipo di codice non funziona sempre: ```glsl void main() { gl_FragColor = vec4(1,0,0,1); // ERRORE } ``` Ora che abbiamo descritto gli elementi più rilevanti del nostro programma "ciao mondo!", è il momento di cliccare sul blocco di codice e iniziare a mettere alla prova tutto quello che abbiamo imparato. Noterete che in caso di errore, il programma non sarà in grado di compilare e mostrerà uno schermo bianco. Ci sono alcune cose interessanti da provare, per esempio: * Provate a sostituire i float con degli integer, la vostra scheda grafica potrebbe o non accettare questo comportamento. * Commentate la linea 6 e non assegnate alcun valore ai pixel della funzione. * Provate a fare una funzione separata che restituisce un colore specifico e utilizzarla all'interno del ```main()```. Piccolo suggerimento, ecco il codice per una funzione che restituisce un colore rosso: ```glsl vec4 red(){ return vec4(1.0,0.0,0.0,1.0); } ``` * Ci sono diversi modi per costruire dei tipi ```vec4```, prova a scoprire gli altri modi. Per esempio: ```glsl vec4 color = vec4(vec3(1.0,0.0,1.0),1.0); ``` Anche se questo esempio non è molto eccitante, è il più elementare possibile - stiamo cambiando tutti i pixel all'interno del canvas con il medesimo colore. Nel prossimo capitolo vedremo come cambiare i colori dei pixel utilizzando due tipi di input: spazio (cioè la posizione dei pixel sullo schermo) e il tempo (cioè il numero di secondi da quando la pagina è stata caricata). --- ### 02/README Jp (02/README-jp.md) ## ハロー・ワールド! 新しいプログラミング言語を学ぶときはたいてい最初に「Hello World」を表示します。一行のシンプルなプログラムで新しい世界に高らかにご挨拶というわけです。 しかしGPUの世界で文字を書くのは第一歩にしてはかなりの大仕事です。代わりに鮮やかな色でこの熱意を表現することにしましょう。 もしこの本をブラウザーで読んでいるのであれば、上のサンプルコードをクリックして好きなところを編集することができます。GPUは変更した内容を反映してコードをコンパイルし、シェーダーを即座に置き換えます。試しに6行目の値を書き換えてみましょう。 一見シンプルなコードですが、ここから多くのことが読み取れます。 1. C言語と同じように、シェーダー言語は結果として色を返す```main()```関数を持っています。 2. 最終的なピクセルの色は、予約語として確保されたグローバル変数、```gl_FragColor```に割り当てられます。 3. このCによく似た言語には(```gl_FragColor```のような)組み込みの「変数」や「関数」、「型」があります。このサンプルでは浮動小数点精度を持つ4次元ベクトル ```vec4``` 型が使われています。またこの後、```vec3```、```vec2``` のような型や、おなじみの ```float```、```int```、```bool``` なども登場します。 4. ```vec4```型をよく見ると、4つの引数はそれぞれ赤(Red)、緑(Green)、青(Blue)、透過度(Alpha)の各チャンネルに対応していることが分かるでしょう。またこれらの値が正規化されている(normalized)、つまり ```0.0``` から ```1.0``` の値をとることも読み取れます。後ほど、値が正規化されていると変数間の写像に便利であることを学びます。 5. プリプロセッサマクロが使えるのも、このサンプルから読み取れるもう一つの大事な「C言語的」特徴です。マクロはコンパイルの前に処理されます。マクロを使うとグローバル変数を定義(```#define```)したり、```#ifdef``` と ```#endif``` を使って場合分けを行うことができます。全てのマクロの命令はハッシュタグ(```#```)で始まります。コンパイルの直前には全ての ```#define``` の呼び出しが置き換えられ、```#ifdef``` や ```#ifndef``` といった条件文のチェックが行なわれます。上のサンプルでは、```GL_ES``` が定義されているときにだけ2行目のコードを挿入します。```GL_ES``` は多くの場合、モバイル機器やブラウザー上でコンパイルされたことを意味します。 6. 浮動小数点型はシェーダーに不可欠で、その精度はとても重要な意味を持ちます。精度が低いとレンダリングが速くなる代わりに品質が下がります。もしこだわりたければ、GLSLでは浮動小数点を使うそれぞれの変数ごとに精度を指定できます。一行目の ```precision mediump float;``` は、全ての浮動小数点型の変数に中レベルの精度を指定しています。より低い精度(```precision lowp float;```)や高い精度(```precision highp float;```)を選ぶこともできます。 7. 最後に、そしておそらく一番大切なことですが、GLSLの仕様では変数の自動的な型変換は保証されていません。どういうことでしょう。メーカーは色々な方法でグラフィックカードを高速化しようとしますが、同時に最低限の仕様を満たす必要があります。自動的な型変換はこの最低限の仕様には含まれていません。上のサンプルでは ```vec4``` 型は浮動小数点精度を持っているので、```float``` 型の値が割り当てられることになっています。コードの一貫性を保ち、真っ白な画面で何時間もデバッグするのを避けるために、浮動小数点型の値には小数点(```.```)を使うことを習慣にしましょう。下記のようなコードはうまく動くとは限りません。 (訳注:gl_FragColorはGLSL1.3から非推奨になりました。以降のバージョンでは開発者が自由に名前をつけることができます。この本のサンプルは1.2以前のバージョンで書かれているため、gl_FragColorを出力用の変数として用います) ```glsl void main() { gl_FragColor = vec4(1,0,0,1); // ERROR } ``` さて、冒頭のサンプルで大事なことはほとんど説明しました。そろそろコードをクリックして、学んだことをひととおり試してみましょう。エラーが起きたときはプログラムがコンパイルに失敗し真っ白な画面が表示されます。 次のような例を試すと面白いでしょう。 * 浮動小数点型を整数型に置き換えてみましょう。グラフィックカードによって、そのまま動くこともエラーになることもあります。 * 6行目をコメントアウトして好きな値を関数に割り当ててみましょう。 * 特定の色を返す別の関数を用意して ```main()``` 関数の中で使ってみましょう。ヒント:下記のコードは赤色を返す関数です。 ```glsl vec4 red(){ return vec4(1.0,0.0,0.0,1.0); } ``` * ```vec4```型の変数を生成するには幾つかの方法があります。他の方法を見つけてみましょう。下記はひとつの例です。 ```glsl vec4 color = vec4(vec3(1.0,0.0,1.0),1.0); ``` この章のサンプルはさほど面白くはありませんが、キャンバス上のピクセルを全て同じ色に変える、最も基礎的な例です。この後に続く章ではピクセルの色を2種類の入力、空間(画面上のピクセルの位置)と時間(ページがロードされてから経過した秒数)を使って変化させる方法を学びます。 --- ### 02/README Pl (02/README-pl.md) ## Witaj świecie! Zazwyczaj przykład "Hello world!" stanowi pierwszy krok przy nauce nowego języka. Jest to prosty jednolinijkowy program, który zwraca pełną entuzjazmu wiadomość powitalną i tym samym zapowiada nadchodzące przygody. W świecie GPU renderowanie tekstu jest jednak zbyt skomplikowanym zadaniem dla żółtodzioba. Zamiast tego wybierzemy jasny, serdeczny kolor by wykrzyczeć naszą ekscytację! Jeżeli czytasz tę książkę w przeglądarce, powyższy blok kodu jest interaktywny. Oznacza to, że możesz edytować dowolną linijkę kodu w celach eksploracyjnych. Shader kompiluje się na bieżąco, więc zmiany widoczne będą natychmiast. Spróbuj pozmieniać wartości w linijce 8. Choć kod jest prosty, to możemy wyciągnąć z niego ważne wnioski: 1. Podobnie jak w C, GLSL ma jedną funkcje `main`. Pod koniec zwraca ona kolor. 2. Finalny kolor piksela przypisywany jest do zarezerowanej zmiennej globalnej `gl_FragColor`. 3. Ten C-podobny język ma wbudowane *zmienne* (jak `gl_FragColor`), *funkcje* i *typy*. W aktualnym przykładzie występuje jedynie typ `vec4`, oznaczający czterowymiarowy wektor zmiennoprzecinkowy (ang. "float vector"). Później zobaczymy również takie typy jak `vec3`, `vec2` oraz znajome `float`, `int` i `bool`. 4. Patrząc na typ `vec4`, możemy wywnioskować, że jego cztery argumenty odnoszą się do kanałów CZERWONEGO, ZIELONEGO, NIEBIESKIEGO i ALPHA. Widać też, że jego wartości są *znormalizowane*, więc znajdują się w zakresie od `0.0` do `1.0`. Później zobaczymy, jak normalizowanie wartości pomaga w *mapowaniu* wartości między zakresami. 5. Kolejną ważną C-podobną własnością w tym przykładzie jest obecność makr preprocessora. Dzięki nim można definiować zmienne globalne za pomocą `#define` oraz operacje warunkowe za pomocą `#ifdef` ("if defined"), `#ifndef` ("if not defined") i `#endif`. Wszystkie makra zaczynają się od płotka `#` i ewaluowane są podczas procesu prekompilacji poprzedzającego kompilację. W naszym powyższym przykładzie linijka 2 kompilowana jest tylko wtedy, gdy zmienna `GL_ES` jest zdefiniowana (co występuje na urządzeniach mobilnych i w przeglądarkach). 6. Typy zmiennoprzecinkowe są kluczowe w shaderach, więc ich poziom precyzji (ang. *precision*) ma ogromne znaczenie. Niższa precyzja oznacza szybsze renderowanie, ale kosztem jakości. Możesz być wybredny i określać precyzję każdej zmiennej zmiennoprzecinkowej z osobna. W linijce 2 (`precision mediump float;`) ustawiamy średnią precyzję zmiennych zmiennoprzecinkowych ("mediump", bo "medium precision"). Możemy też ustawić ją jako niską (`precision lowp float;`) lub wysoką (`precision highp float;`). 7. Ostatni i chyba najważniejszy szczegół specyfikacji GLSL: nie ma gwarancji, że zmienne będą automatycznie castowane (np. z `int` do `float` przy dzieleniu liczby 5 przez 2). Producenci GPU mogą stosować przeróżne optymalizacje w kartach graficznych, ale muszą przy tym przestrzegać pewnych wytycznych. Automatyczne castowanie nie jest jednym z nich. W naszym przykładzie `vec4` ma precyzję zmiennoprzecinkową i dlatego jego argumenty wymagają `float`ów. Przyzwyczaj się do stawiania kropek (`.`) we `float`ach (`1.` lub `1.0`, a nie `1`), jeżeli nie chcesz spędzić godzin przy debugowaniu. Poniższy kod nie zawsze będzie, zatem, działał: ```glsl void main() { gl_FragColor = vec4(1,0,0,1); // ERROR } ``` Czas na ćwiczenia! Pamiętaj, że w wypadku błędu kompilacji pokaże się informacje o błędzie i linijce w której wystąpił, a kanwa zmieni kolor na biały. * Spróbuj zamienić `float`y na `int`y. Jeśli kod się nie kompiluje, to widocznie twoja karta graficzna tego nie toleruje * Zakomentuj linię 8 * Stwórz osobną funkcję, która zwraca dowolny kolor i użyj jej w `main()`. Wskazówka: poniższy kod zwraca kolor czerwony: ```glsl vec4 red(){ return vec4(1.0,0.0,0.0,1.0); } ``` * Jest wiele sposobów tworzenia typu `vec4` - spróbuj je znaleźć. Jeden z nich wygląda tak: ```glsl vec4 color = vec4(vec3(1.0,0.0,1.0),1.0); ``` Choć przykład ten nie jest zbyt ekscytujący, stanowi ważną podstawę. W następnych rozdziałach zobaczymy, jak zmienić kolor piksela z pomocą inputu przestrzennego (położenie piksela na ekranie) i temporalnego (okres czasu od momentu załadowania się strony). --- ### 02/README Pt (02/README-pt.md) ## Olá mundo Geralmente o exemplo "Olá mundo" é o primeiro passo ao aprender uma nova linguagem. É um programa de uma linha de código que retorna uma entusiástica mensagem de boas vindas e declara as oportunidades que nos aguarda. No mundo da GPU, renderizar texto é uma tarefa muito complicada para ser o primeiro passo, portanto usaremos uma cor brilhante cor de boas-vindas para representar nosso entusiasmo! Se você está lendo este livro em um navegador, o bloco de código acima é interativo. Isso significa que você pode clicar e modificar qualquer parte do código em que você quiser explorar sua funcionalidade. As mudanças serão atualizadas imediatamente graças à arquitetura da GPU que compila e substitui os shaders *instantaneamente*. Experimente modificar os valores da linha 8. Embora essas simples linhas de código não parecem ser tão interessantes, podemos inferir muita coisa sobre elas: 1. Linguagem de shader Shader Language possui uma função principal - `main` - que retorna uma cor. Isto é similar a C. 2. A cor final do pixel é atribuída pela variável global reservada `gl_FragColor`. 3. Essa linguagem similar a C tem *variáveis* nativas (como `gl_FragColor`), *funções* e *tipos*. Nesse caso vemos `vec4`, que representa um vetor em quatro dimensões com precisão de ponto flutuante. Mais adiante veremos outros tipos como `vec3` e `vec2` além dos populares: `float`, `int` and `bool`. 4. Se observarmos o tipo `vec4` podemos inferir que os quatro argumentos correspondem aos canais RED (vermelho), GREEN (verde), BLUE (azul) e ALPHA (alfa). Também vemos que esses valores são *normalizados*, ou seja, eles vão de `0.0` a `1.0`. Mais tarde aprenderemos como normalizar valores facilitam o seu *mapeamento* entre variáveis. 5. Outra importante *característica de C* que podemos ver neste exemplo é a presença de macros de preprocessador. Macros são parte do passo de pré-compilação. Com eles podemos definir variáveis globais (com `#define`) e fazer operações condicionais básicas (com `#ifdef` e `#endif`). Todos os comandos de macros começam com uma hashtag (`#`). A pré-compilação acontece logo antes da compilação e copia todas as chamadas para condicionais `#define` e checa `#ifdef` (está definido) e `#ifndef` (não está definido). Em nosso exemplo "Olá mundo" acima nós inserimos na linha 2 se `GL_ES` for definido, o que provavelmente acontece quando o código é compilado em celulares e navegadores. 6. Tipos float são vitais em shaders, então o nível de *precisão* é crucial. Menor precisão maior a velocidade de renderização, porém a qualidade é afetada. Você pode ser meticuloso e especificar a precisão para cada variável que usa ponto flutuante. Na primeira linha (`precision mediump float;`) estamos ajustando todos os floats para precisão média. Mas podemos ajustá-las para baixa (`precision lowp float;`) ou alta (`precision highp float;`) também. 7. O final, e talvez mais importante detalhe é que a especificação da GLSL não garante que as variáveis serão automaticamente convertidas. O que isso significa? Fabricantes têm soluções para acelerar os processos da placa gráfica mas eles são forçados a garantir as especificações mínimas. Conversão automática não está entre delas. Em nosso exemplo "olá mundo!" `vec4` tem precisão de ponto flutuante e por isso ele espera ser convertido com `floats`. Se você quiser escrever código de maneira consistente e não gastar horas investigando telas em branco, se acostume a colocar um ponto (`.`) em seus flutuantes (floats). Esse tipo de código às vezes não funcionará: ```glsl void main() { gl_FragColor = vec4(1,0,0,1); // ERROR } ``` Agora que descrevemos os elementos mais relevantes em nosso programa "Olá mundo!", chegou a hora de clicar no bloco de código e começar a aplicar o que aprendemos até agora. Você notará que, quando houver um erro, o programa não compilará e renderizará uma tela em branco. Têm algumas coisas interessantes que você pode tentar, por exemplo: * Tente substituir flutuantes (floats) por números inteiros (integers), pode ser que a sua placa gráfica não ofeça suporte. * Tente comentar a linha 8 e não atribuir nenhum valor nessa função. * Tente escrever outra função à parte que retorna uma cor específica e a utilize em `main()`. Dica: aqui está o código para uma função que retorna a cor vermelho: ```glsl vec4 red(){ return vec4(1.0,0.0,0.0,1.0); } ``` * Existem múltiplas maneiras diferentes para construir tipos `vec4`, tente descobrir outras maneiras. Este é um deles: ```glsl vec4 color = vec4(vec3(1.0,0.0,1.0),1.0); ``` Apesar deste exemplo não ser tão empolgante, ele é o exemplo mais básico - estamos modificando todos os pixels da tela ao mesmo tempo e atribuindo a eles a mesma cor. No próximo capítulo veremos como mudar as cores dos pixels usando dois tipos de entrada (input): espaço (a posição do pixel na tela) e tempo (o número de segundos desde que a página foi carregada). --- ### 02/README Tr (02/README-tr.md) ## Merhaba Dünya Genellikle "Merhaba dünya!" örneği yeni bir dili öğrenmenin ilk adımıdır. Hevesli bir karşılama mesajı veren ve önünüzdeki fırsatları ilan eden basit, tek satırlık bir programdır. GPU diyarında metin render etmek (ekrana çizdirmek) ilk adım için aşırı karmaşık bir görevdir, bunun yerine hevesimizi haykırmak için parlak bir karşılama rengi seçeceğiz! Bu kitabı bir tarayıcıda okuyorsanız, önceki kod bloğu interaktiftir. Yani keşfetmek istediğiniz kodun herhangi bir yerine tıklayıp değiştirebilirsiniz. Değişiklikler, shader'ları *anında* derleyen ve değiştiren GPU mimarisi sayesinde hemen güncellenecektir. 8. satırdaki değerleri değiştirerek deneyin. Bu basit kod satıraları çok gibi görünmese de, onlardan önemli bilgiler çıkarabiliriz: 1. Shader Dili, sonunda bir renk döndüren tek bir `main` fonksiyonuna sahiptir. Bu C'ye benzer. 2. Son piksel rengi, ayrılmış global değişken `gl_FragColor`'a atanır. 3. Bu C-tadındaki dil, yerleşik *değişkenlere* (`gl_FragColor` gibi), *fonksiyonlara* ve *türlere* sahiptir. Bu durumda, kayan nokta hassasiyetli dört boyutlu bir vektör anlamına gelen `vec4` ile tanıştık. Daha sonra `vec3` ve `vec2` gibi türleri ve popüler olanları göreceğiz: `float`, `int` ve `bool`. 4. `vec4` türüne yakından bakarsak, dört argümanın KIRMIZI (RED), YEŞİL (GREEN), MAVİ (BLUE) ve ALFA (ALPHA) kanallarına yanıt verdiğini çıkarabiliriz. Ayrıca bu değerlerin *normalize* edildiğini, yani `0.0` ile `1.0` arasında gittiklerini görebiliriz. Daha sonra, değerleri normalize etmenin değişkenler arasında değerleri *eşlemeyi* (map) nasıl kolaylaştırdığını öğreneceğiz. 5. Bu örnekte görebileceğimiz bir diğer önemli *C özelliği* de önişlemci makrolarının varlığıdır. Makrolar, derleme öncesi bir adımın parçasıdır. Onlarla global değişkenleri `#define` etmek ve bazı temel koşullu işlemleri (`#ifdef` ve `#endif` ile) yapmak mümkündür. Tüm makro komutları bir hashtag (`#`) ile başlar. Derleme öncesi işlem, derlemeden hemen önce gerçekleşir ve tüm `#defines` çağrılarını kopyalar ve `#ifdef` (tanımlıysa) ve `#ifndef` (tanımlı değilse) koşullarını kontrol eder. Yukarıdaki "merhaba dünya!" örneğimizde, 2. satırı yalnızca `GL_ES` tanımlıysa ekliyoruz; bu da çoğunlukla kod mobil cihazlarda ve tarayıcılarda derlendiğinde olur. 6. Float türleri shader'larda hayati önem taşır, bu nedenle *hassasiyet* (precision) seviyesi çok önemlidir. Düşük hassasiyet daha hızlı render anlamına gelir, ancak kalite pahasına. Seçici olabilir ve kayan nokta kullanan her değişkenin hassasiyetini belirleyebilirsiniz. İkinci satırda (`precision mediump float;`) tüm float'ları orta hassasiyete ayarlıyoruz. Ancak bunları düşük (`precision lowp float;`) veya yüksek (`precision highp float;`) olarak ayarlamayı da seçebiliriz. 7. Son ve belki de en önemli ayrıntı, GLSL spesifikasyonlarının değişkenlerin otomatik olarak dönüştürüleceğini (cast) garanti etmemesidir. Bu ne anlama geliyor? Üreticilerin grafik kartı işlemlerini hızlandırmak için farklı yaklaşımları vardır ancak minimum spesifikasyonları garanti etmek zorundadırlar. Otomatik dönüştürme bunlardan biri değildir. "Merhaba dünya!" örneğimizde `vec4` kayan nokta hassasiyetine sahiptir ve bu nedenle kendisine `float` atanmasını bekler. İyi ve tutarlı bir kod yazmak ve beyaz ekranlarda hata ayıklamak için saatler harcamak istemiyorsanız, float'larınıza nokta (`.`) koymaya alışın. Bu tür bir kod her zaman çalışmayacaktır: ```glsl void main() { gl_FragColor = vec4(1,0,0,1); // HATA } ``` "Merhaba dünya!" programımızın en alakalı unsurlarını tanımladığımıza göre, kod bloğuna tıklayıp öğrendiklerimizi zorlamaya başlamanın zamanı geldi. Hatalarda programın derlenemeyeceğini ve beyaz bir ekran göstereceğini fark edeceksiniz. Denenecek bazı ilginç şeyler var, örneğin: * Float'ları tam sayılarla (integer) değiştirmeyi deneyin, grafik kartınız bu davranışı tolere edebilir veya etmeyebilir. * 8. satırı yoruma almayı ve fonksiyona herhangi bir piksel değeri atamamayı deneyin. * Belirli bir renk döndüren ayrı bir fonksiyon yapmayı ve bunu `main()` içinde kullanmayı deneyin. İpucu olarak, işte kırmızı bir renk döndüren bir fonksiyonun kodu: ```glsl vec4 red(){ return vec4(1.0,0.0,0.0,1.0); } ``` * `vec4` türlerini oluşturmanın birden fazla yolu vardır, diğer yolları keşfetmeye çalışın. Aşağıdakilerden biri bunlardan biridir: ```glsl vec4 color = vec4(vec3(1.0,0.0,1.0),1.0); ``` Bu örnek çok heyecan verici olmasa da, en temel örnektir - tuvalin (canvas) içindeki tüm pikselleri aynı tam renge değiştiriyoruz. Sonraki bölümde, piksel renklerini iki tür girdi kullanarak nasıl değiştireceğimizi göreceğiz: uzay (pikselin ekrandaki yeri) ve zaman (sayfa yüklendiğinden beri geçen saniye sayısı). --- ### 02/README Vi (02/README-vi.md) ## Hello World Thông thường thì ví dụ "Hello World!" sẽ là bước đầu tiên khi học một ngôn ngữ lập trình mới. Đó là một chương trình đơn giản, in ra 1 dòng chữ chào đón. Ở địa-bàn-của-GPU thì việc vẽ các ký tự chữ số là bước khởi đầu có phần quá phức tạp, thay vào đó chúng tôi chọn sẽ tô một màu tươi sáng lên màn hình để chào đón các bạn một cách nồng nhiệt nhất! Nếu bạn đang đọc trên trình duyệt thì đoạn code phía trên có thể sửa được đấy. Điều đó có nghĩa là bạn có thể sửa bất kỳ phần nào bạn muốn. Thay đổi sẽ được cập nhật ngay lập tức nhờ vào kiến trúc GPU có khả năng biên dịch và cập nhật shader *thời gian thực*. Hãy thử thay đổi các giá trị ở dòng 8. Dù chỉ có vài dòng code đơn giản thôi, nhưng ta có thể thu được nhiều thứ từ chúng lắm đấy: 1. Ngôn ngữ Shader có 1 hàm `main` trả về mã màu. Tương tự như ngôn ngữ C. 2. Màu cuối cùng của mỗi điểm ảnh được lưu vào biến toàn cục là `gl_FragColor`. 3. Ngôn ngữ nhìn-như-C này có sẵn vài *biến* (như `gl_FragColor`), *hàm* và *kiểu dữ liệu*. Trong trường hợp này, ta đã được giới thiệu về kiểu `vec4` lưu dữ liệu của một vector 4 chiều với độ chính xác của số thực. Sau này ta sẽ thấy các kiểu tương tự như `vec3` và `vec2` cũng như các kiểu dữ liệu phổ biến khác như: `float`, `int` và `bool`. 4. Nếu tinh ý, bạn sẽ nhận ra `vec4` lưu giá trị của 4 kênh đỏ (RED), xanh lá (GREEN), xanh dương (BLUE) và độ trong suốt (ALPHA). Và bạn cũng sẽ nhận thấy các giá trị này đã được chuẩn hoá **(normalized)**, có nghĩa là giá trị chỉ nằm trong khoảng từ `0.0` tới `1.0`. Sau này ta sẽ thấy các giá trị được chuẩn hoá sẽ giúp việc ánh xạ từ biến này sang biến kia trở nên dễ dàng như thế nào. 5. Một tính năng quan trọng khác (học từ ngôn ngữ C) ở trong ví dụ này là sự xuất hiện của các macro, chúng sẽ được xử lý ngay trước khi code được biên dịch. Bằng cách sử dụng macro, ta có thể `#define` các biến toàn cục và một vài thao tác điều kiện cơ bản (với `#ifdef` và `#endif`). Tất cả các lệnh macro đều được bắt đầu bằng ký hiệu hashtag (`#`). Ngay trước khi biên dịch, tất cả các lệnh điều kiện như `#ifdef` (nếu có macro) và `#ifndef` (nếu không có macro) sẽ được kiểm tra. Ở ví dụ "Hello World!" này, ta chỉ kiểm tra xem macro `GL_ES` có tồn tại không mà thôi. Macro này có tồn tại trên hầu hết các thiết bị điện thoại di động và trình duyệt, tức là dòng lệnh số 2 sẽ chỉ có tác dụng trên các nền tảng này. 6. Các kiểu dữ liệu số thực là yếu tố sống còn trong shader, nên việc quy định mức độ chính xác của chúng là tối quan trọng. Độ chính xác thấp đồng nghĩa với việc dựng hình nhanh hơn và đánh đổi lấy chất lượng thấp hơn. Bạn có thể tỉ mỉ điều chỉnh độ chính xác cho từng biến nếu muốn. Ở dòng 2 (`precision mediump float;`) ta đã quy định mức độ chính xác của toàn bộ các số thực ở mức trung bình. Nhưng cũng có thể giảm xuống mức thấp (`precision lowp float;`) hoặc tăng lên mức cao (`precision highp float;`). 7. Điều cuối cùng, có thể là quan trọng nhất, GLSL không đảm bảo các biến sẽ được chuyển đổi sang kiểu phù hợp. Điều đó nghĩa là gì ? Các nhà sản xuất có các cách tiếp cận khác nhau để tăng tốc card xử lý đồ hoạ của riêng họ nhưng đều phải tuân thủ các yêu cầu tối thiểu. Mà tự chuyển đổi kiểu dữ liệu thì không nằm trong số các yêu cầu bắt buộc đó. Trong ví dụ "Hello World!" của ta, `vec4` có độ chính xác của số thực nên giá trị mà nó lưu giữ nên có kiểu là `float`. Nếu bạn muốn viết code có độ ổn định cao mà không phải tốn hàng giờ ngồi debug trước màn hình trắng tinh, thì hãy làm quen với việc viết thêm dấu chấm (`.`) sau các số thực, nó giúp GPU biết đang phải xử lý một số thực. Đoạn code dưới đây không phải lúc nào cũng chạy đúng: ```glsl void main() { gl_FragColor = vec4(1,0,0,1); // LỖI } ``` Ta vừa mới mô tả những yếu tố cơ bản nhất trong chương trình "Hello World!", giờ là lúc để tự sửa code và bắt đầu áp dụng những gì mới được học. Bạn sẽ nhận ra nếu có lỗi thì chương trình không thể biên dịch được còn màn hình sẽ hiển thị màu trắng. Hãy thử vài thứ thú vị sau xem sao: * Thử thay số thực bằng số nguyên, có thể card đồ hoạ của bạn vẫn chấp nhận đó * Thử comment dòng số 8 và không lưu lại bất kỳ giá trị điểm ảnh nào * Thử tạo một hàm mới chỉ trả về duy nhất một màu cố định và gọi hàm đó trong hàm `main()`. Gợi ý, đây là ví dụ một hàm trả về màu đỏ: ```glsl vec4 red(){ return vec4(1.0,0.0,0.0,1.0); } ``` * Có nhiều cách khởi tạo kiểu `vec4`, sau đây là 1 trong số chúng: ```glsl vec4 color = vec4(vec3(1.0,0.0,1.0),1.0); ``` Dù ví dụ này không hấp dẫn lắm, nhưng nó là ví dụ cơ bản nhất - ta đã đổi màu của toàn bộ canvas sang một màu cố định. Ở chương tới ta sẽ tìm cách đổi màu điểm ảnh dựa theo vị trí của nó và thời điểm mà trang web được load nữa. --- ### 02/SUMMARY (02/SUMMARY.md) Usually the "Hello world!" example is the first step to learning a new language. In GPU-land rendering text is an overcomplicated task for a first step, instead we'll choose a bright welcoming color to shout our enthusiasm! --- ### 03/README (03/README.md) ## Uniforms So far we have seen how the GPU manages large numbers of parallel threads, each one responsible for assigning the color to a fraction of the total image. Although each parallel thread is blind to the others, we need to be able to send some inputs from the CPU to all the threads. Because of the architecture of the graphics card those inputs are going to be equal (*uniform*) to all the threads and necessarily set as *read only*. In other words, each thread receives the same data which it can read but cannot change. These inputs are called `uniform` and come in most of the supported types: `float`, `vec2`, `vec3`, `vec4`, `mat2`, `mat3`, `mat4`, `sampler2D` and `samplerCube`. Uniforms are defined with the corresponding type at the top of the shader right after assigning the default floating point precision. ```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 ``` You can picture the uniforms like little bridges between the CPU and the GPU. The names will vary from implementation to implementation but in this series of examples I’m always passing: `u_time` (time in seconds since the shader started), `u_resolution` (billboard size where the shader is being drawn) and `u_mouse` (mouse position inside the billboard in pixels). I’m following the convention of putting `u_` before the uniform name to be explicit about the nature of this variable but you will find all kinds of names for uniforms. For example [ShaderToy.com](https://www.shadertoy.com/) uses the same uniforms but with the following names: ```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) ``` Enough talking, let's see the uniforms in action. In the following code we use `u_time` - the number of seconds since the shader started running - together with a sine function to animate the transition of the amount of red in the billboard. As you can see GLSL has more surprises. The GPU has hardware accelerated angle, trigonometric and exponential functions. Some of those functions are: [`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) and [`clamp()`](../glossary/?search=clamp). Now it is time again to play with the above code. * Slow down the frequency until the color change becomes almost imperceptible. * Speed it up until you see a single color without flickering. * Play with the three channels (RGB) in different frequencies to get interesting patterns and behaviors. ## gl_FragCoord In the same way GLSL gives us a default output, `vec4 gl_FragColor`, it also gives us a default input, `vec4 gl_FragCoord`, which holds the screen coordinates of the *pixel* or *screen fragment* that the active thread is working on. With `vec4 gl_FragCoord`, we know where a thread is working inside the billboard. In this case we don't call it `uniform` because it will be different from thread to thread, instead `gl_FragCoord` is called a *varying*. In the above code we *normalize* the coordinate of the fragment by dividing it by the total resolution of the billboard. By doing this the values will go between `0.0` and `1.0`, which makes it easy to map the X and Y values to the RED and GREEN channel. In shader-land we don’t have too many resources for debugging besides assigning strong colors to variables and trying to make sense of them. You will discover that sometimes coding in GLSL is very similar to putting ships inside bottles. It is equally hard, beautiful and gratifying. Now it is time to try and challenge our understanding of this code. * Can you tell where the coordinate `(0.0, 0.0)` is in our canvas? * What about `(1.0, 0.0)`, `(0.0, 1.0)`, `(0.5, 0.5)` and `(1.0, 1.0)`? * Can you figure out how to use `u_mouse`, knowing that the values are in pixels and NOT normalized values? Can you use it to move colors around? * Can you imagine an interesting way of changing this color pattern using `u_time` and `u_mouse` coordinates? After doing these exercises you might wonder where else you can try your new shader-powers. In the following chapter we will see how to make your own shader tools in three.js, Processing, and openFrameworks. --- ### 03/Notes (03/notes.md) #### Scott * For these uniforms: ``` 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 ```` …what determines these variable names? Are these set by you, so I could change them, or are these determined by the graphics card, GLSL, or something else? * This list of GLSL-supported functions is super. Maybe you could link to a comprehensive list here, too. • In "Slow down the frequency until the color change becomes almost imperceptible" took me a minute to figure out the right place to do that. I ended up writing: ``` gl_FragColor = vec4( abs(sin(u_time * 0.4)) ,0.0,0.0,1.0); ``` I mention it because I felt this is the first place where you might lose some people. Consider giving a little more guidance with this instruction. * So gl_FragCoord is a varying, so it doesn’t have to be declared. But uniforms do have to be declared before you can use them? Is that right? * Starting in this example, I need to be told what the components of a vec4() are. It looks like you are using vec4.x and vec4.y. But you didn’t introduce these. What other options do I have? * Also I would want the fields of gl_FragCoord explained. You used gl_FragCoord.xy but didn’t explain it. I assume it’s a vec2 with the x and y values, of course. Come to think of it, it is crazy that you can write: gl_FragCoord.xy / u_resolution and have that return a vec2! In Processing you have to use something like vector.divide(). Maybe it would be worth explaining a bit what your line of code above does? Does it really divide both the X and Y values by u_resolution? NOTES: uniform vec2 u_resolution; // vec2(500.0,500.0) uniform vec2 u_mouse; uniform float u_time; void main() { // X Y // gl_FragCoord.xy = vec2(0.0,0.0); // / / // vec2(500.0,500.0); vec2 st = gl_FragCoord.xy/u_resolution; // ST -> vec2(0.0,0.0) to vec2(1.0,1.0) // RED GREEN BLUE ALPHA gl_FragColor = vec4(st.x, st.y, 0.0, 1.0); } ### Nicolas * >You can picture the uniforms like little bridges between the CPU and the GPU a 'one-way'' bridges that is :) I translated it to: >We can picture the uniforms as small one-way bridges from the CPU (our main program) to the GPU (where the shader will be executed). * >In the same way GLSL gives us a default output, ```vec4 gl_FragColor```, it also gives us a default input, ```vec4 gl_FragCoord```, which holds the screen coordinates of the *pixel* or *screen fragment* that the active thread is working on. I developped a bit more to disambiguate pixel & fragment, I think it's an important step, the first time we meet the word fragment _for real_ * I've stressed the fact that gl_FragCoord is implicitly declared so that people don't panic when they don't find it in the new code sample :) also those are reserved names, so I stressed the fact that you can't use them as var names in your custom code. --- ### 03/README De (03/README-de.md) ## Uniforms Wir haben bereits gesehen, wie die GPU eine große Anzahl von parallelen Aufgaben (engl. *Threads*) verwaltet. Jeder Thread übernimmt die Berechnung des Farbwerts für einen Pixel, also für einen kleinen Teil der gesamten Grafik. Obwohl er dabei blind für die anderen Threads ist, muss es einen Weg geben, wie die CPU bestimmte Daten an alle Threads übermitteln kann. Aufgrund der Architektur einer Grafikkarte müssen diese Daten für alle ausgeführten Threads einheitlich (engl. *uniform*) und nur lesbar (engl. *read-only*) sein. Jeder Thread erhält also die gleichen Daten, die er nicht verändern kann. Man bezeichnet diese Daten deshalb als ```uniform```. Es gibt sie in den wichtigsten Datentypen, die GLSL unterstützt: ```float```, ```vec2```, ```vec3```, ```vec4```, ```mat2```, ```mat3```, ```mat4```, ```sampler2D``` und ```samplerCube```. Uniforms werden gemeinsam mit ihrem jeweiligen Datentyp am Anfang eines Shader-Programms definiert, sofern man darauf Bezug nehmen möchte. Dies geschieht in der Regel gleich nachdem man die gewünschte Genauigkeit für alle Fließkommaoperationen in dem Programm festgelegt hat. ```glsl #ifdef GL_ES precision mediump float; #endif uniform vec2 u_resolution; // Groesse der Malfläche (canvas) in Pixeln (Breite, Hoehe) uniform vec2 u_mouse; // Mausposition über der Malfleache in Pixeln (X, Y) uniform float u_time; // Zeit in Sekunden seit dem Start des Bildaufbaus ``` Man kann sich Uniforms als eine Brücke zwischen der CPU und der GPU vorstellen. Ihre Bezeichnung hängt von der jeweiligen Implementation der GLSL-Umgebung ab. Im Rahmen dieses Buches verwenden wir die folgenden Namen: ```u_time``` , ```u_resolution``` und ```u_mouse```. Wir folgen damit der Konvention, die Variablennamen jeweils mit dem Präfix ```u_``` beginnen zu lassen, damit sie im Programmcode deutlich als Uniforms erkennbar sind. In anderen Umgebungen für die Entwicklung von Shadern tragen sie andere Namen, wie beispielsweise bei [ShaderToy.com](https://www.shadertoy.com/). Dort heißt es: ```glsl uniform vec3 iResolution; // Groesse der Malflaeche uniform vec4 iMouse; // Mausposition uniform float iTime; // Zeit seit dem Start ``` Aber nun genug geredet. Lass uns die Uniforms in Aktion betrachten. Der folgende Programmcode nutzt ```u_time``` - die Anzahl der Sekunden, seitdem der Shader gestartet wurde - in Verbindung mit einer Sinus-Funktion, um die Intensität der Rotfärbung der Malfläche pulsieren zu lassen. Wie Du siehst, hält GLSL noch einige Überraschungen bereit. Die GPU unterstützt in der Hardware realisierte Winkel-, Trigonometrie- und Exponential-Funktionen. Hier einige dieser Funktionen in der Übersicht: [```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) sowie [```clamp()```](../glossary/?search=clamp). Nun ist es an der Zeit, mit dem obigen Shader zu experimentieren. * Versuche, die Frequenz zu verlangsamen, mit der sich die Rotfärbung ändert, bis dieser Prozess kaum noch wahrnehmbar ist. * Beschleunige die Frequenz, bis man fast nur noch eine Farbe sieht. * Experimentiere mit periodischen Änderungen auch in den anderen Farbkanälen (Grün und Blau), so dass sich interessante Farbspiele und Muster ergeben. ## gl_FragCoord So, wie GLSL das Resultat eines Shader-Durchlaufs standardmäßig in der Variable ```vec4 gl_FragColor``` erwartet, liefert es uns auch standardmäßig einen Eingabewert: Die Koordinate des jeweils zu bearbeitenden Bildpunkts in der Variable ```vec4 gl_FragCoord```. Im Englischen spricht man in diesem Zusammenhang auch von einem *screen fragment*, weil es sich nur um einen kleinen Teil der Zeichenfläche handelt, eben ein „Fragment“. Diese Variable kann man nicht als ```uniform``` bezeichnen, weil ihr Inhalt bzw. ihr Wert mit jedem Shader-Durchlauf variiert. Man spricht deshalb auch von einem *varying*. Im obigen Programmcode *normalisieren* wir zunächst die Koordinate des zu bearbeitenden Fragments, indem wir sie durch die Auflösung der Zeichenfläche teilen. Auf diese Weise bilden wir die *X-* und *Y-Ordinate* jeweils auf den Wertebereich zwischen ```0.0``` und ```1.0``` ab. Das erleichtert es uns, diese Ordinaten auf Farbwerte für den Rot- und den Grün-Kanal zu übertragen. Schließlich müssen sich diese Farbwerte in GLSL auch immer jeweils zwischen ```0.0``` und ```1.0``` bewegen. In der Welt der Shader-Programmierung haben wir nicht so viele Möglichkeiten zum Debugging, abgesehen davon, dass wir dem gerade berechneten Bildpunkt intensive Farbtöne zuweisen können. Das entstehende Bild lässt dann Rückschlüsse auf die Abläufe innerhalb des Shaders zu. Du wirst im Laufe dieses Buches entdecken, dass die Shader-Programmierung manchmal dem Versuch gleicht, ein Modellschiff in eine Flasche zu pressen. Denn das ist gleichermaßen schwierig, aber auch schön anzusehen und in jedem Fall lohnend. Jetzt ist es an der Zeit für eine kleine Herausforderung in Bezug auf das Verständnis des obigen Programmcodes. * Kannst du ausmachen, wo sich die Koordinate ```(0.0,0.0)``` innerhalb unserer Zeichenfläche befindet? * Und wo liegen wohl die Koordinaten ```(1.0,0.0)```, ```(0.0,1.0)```, ```(0.5,0.5)``` und ```(1.0,1.0)```? Die Farben der jeweiligen Bildpunkte verraten es Dir! * Gelingt es Dir, die aktuelle Mausposition aus dem Uniform ```u_mouse``` einzubeziehen? Denke daran, dass sich die Angaben in diesem Uniform auf Pixel beziehen und zunächst nicht normalisiert sind. Kannst Du den Programmcode so gestalten, dass die erzeugten Farben auf die Mausbewegung reagieren? * Fällt Dir ein Weg ein, wie man die Farbgestaltung auf interessante Weise durch die Einbeziehung von ```u_time``` und ```u_mouse``` dynamisieren kann? Nach all diesen Übungen fragst Du Dich vielleicht, wo Du Deine neuen Shader-Kenntnisse sonst noch ausprobieren kannst. Im folgenden Kapitel zeigen wir, wie man Shader in *three.js*, *Processing* und *openFrameworks* zum Laufen bringt. --- ### 03/README Es (03/README-es.md) ## Uniforms Hasta ahora hemos visto como la GPU maneja grandes números de threads en paralelo, cada uno responsable de asignar un color a una fracción de la pantalla. A pesar de que cada thread no conoce a los otros, necesitamos poder enviarle valores de entrada desde la CPU a todos los threads. Debido a la arquitectura de la GPU todos esos valores van a ser iguales (*uniform*) para todos los threads y de sólo lectura. En otras palabras, cada thread recibe las misma información y puede leerla pero no modificarla. Estas entradas se llaman ```uniform``` y vienen en diferentes tipos: ```float```, ```vec2```, ```vec3```, ```vec4```, ```mat2```, ```mat3```, ```mat4```, ```sampler2D``` y ```samplerCube```. Los uniforms son definidos con sus correspondientes tipos, al principio del código, luego de definir la precisión del punto flotante. ```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 ``` Podemos imaginar que los uniforms son como pequeños puentes entre la CPU y la GPU. Los nombres varían dependiendo de cada implementación, en esta serie de ejemplos estoy usando ```u_time``` (tiempo en segundos desde que shaders comenzó a correr), ```u_resolution``` (el tamaño de la ventana donde se está dibujando el shader) y ```u_mouse``` (la posición del mouse dentro de la ventana en pixeles). Estoy siguiendo la convención de utilizar ```u_``` antes del nombre del uniform, para ser explícito respecto a la naturaleza de la variable, pero encontrarás diferentes nombre de uniforms. Por ejemplo [ShaderToy.com](https://www.shadertoy.com/) utiliza las mismas uniforms pero con los siguientes nombres: ```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) ``` Ya hemos hablado mucho, vamos a ver los uniforms en acción. En el código siguiente usamos ```u_time``` - el número de segundos desde que el shader comenzó a ejecutarse - junto con una función del seno para animar en transición la cantidad de rojo en la pantalla. Como puedes ver, GLSL tiene más sorpresas. La GPU tiene funciones de ángulo, de trigonometría y exponenciales, que son aceleradas por hardware: [```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) y [```clamp()```](../glossary/?search=clamp). Es hora de jugar con el código de arriba: * Reduce la frecuencia del cambio hasta que sea prácticamente imperceptible. * Acelera la frecuencia hasta que dejes de ver el parpadeo. * Juega con los canales de colores (RGB) en diferentes frecuencias, para obtener patrones y comportamientos interesantes. ## gl_FragCoord De la misma forma que GLSL nos da por default la variable reservada ```vec4 gl_FragColor```, también nos da ```vec4 gl_FragCoord``` que guarda la coordenada del *pixel* o *screen fragment* del thread actual. Con ```vec4 gl_FragCoord``` podemos saber el lugar en la pantalla en el que el thread está actualmente trabajando. En este caso, esta variable no es un ```uniform``` porque será diferente en cada uno de los threads, las variables que cambian en cada thread, como ```gl_FragCoord```, son *varying*. En el código de arriba *normalizamos* la coordenada del fragment, dividiéndolo por la resolución total de la ventana. Una vez que hicimos este proceso, la posición va de 0.0 a 1.0, lo que vuelve mucho más fácil de usar estos valores en los canales RED (rojo) y GREEN (verde). En el mundo de los shaders no tenemos muchas herramientas para hacer debug más allá de asignar colores e intentar encontrarles el sentido. Muchas veces verás que programar en GLSL es como poner barcos dentro de botellas, cuanto más complicado, más hermoso y gratificante es. Es hora de poner en práctica los conocimientos aprendidos. * ¿Podrías decir dónde está nuestro ```(0.0,0.0)``` en la pantalla? * ¿Y dónde está ```(1.0,0.0)```, ```(0.0,1.0)```, ```(0.5,0.5)``` y ```(1.0,1.0)```? * ¿Puedes imaginar cómo usar ```u_mouse``` sabiendo que los valores están en pixeles y no están normalizados? ¿Podrías usarlo para mover los colores? * ¿Te imaginas alguna forma interesante de combinar ```u_time``` y ```u_mouse``` para generar patrones ? Luego de hacer estos ejercicios seguramente te preguntarás que más puedes hacer con los superpoderes que los shaders te dan. En el próximo capítulo veremos como crear tus propios shaders en three.js, Processing y openFrameworks. --- ### 03/README Fa (03/README-fa.md) ## یونیفرم ها تاکنون دیدیم که GPU چگونه تعداد زیادی ترد موازی را مدیریت میکند. هر کدام از آن ها وظیفه تخصیص رنگ، به جزئی(fragment) از تصویر را دارند. با اینکه هر ترد موازی نسبت به دیگران کور است، اما باید بتوانیم از CPU ورودی هایی به همه ترد ها ارسال کنیم. به دلیل معماری کارت گرافیک، این ورودی ها برای همه ترد ها یکسان هستند و فقط بصورت خواندنی(read only). به عبارتی هر ترد اطلاعات مشابهی را دریافت میکند که میتواند بخواند، اما نمیتواند تغییر دهد. به این ورودی ها یونیفرم(uniform) گفته میشود. و معمولا به صورت تایپ های مقابل استفاده میشوند: float, vect2, vect3, vect4, mat2, mat3, mat4, sampler2D, samplerCube. یونیفرم ها در بالای شیدر، پس از تعریف دقت نقطه شناور پیشفرض تعریف میشوند. ```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 ``` یونیفرم ها را میتوان مانند پل های کوچک بین CPU و GPU تصور کرد. نام ها در محیط های مختلف ممکن از تفاوت داشته باشند، اما در این مجموعه از مثال ها همیشه این نام ها ثابتند: u_time(زمان بر حسب ثانیه از شروع شیدر)، u_resolution(اندازه کنوس، جایی که شیدر کشیده میشود) و u_mouse(موقعیت ماوس در داخل کنوس بر حسب پیکسل). من این قرار داد را دنبال میکنم که قبل یونیفرم ها u_ بگذارم، اما شکل های دیگری هم ممکن است به چشمتان بخورد، مثلا [ShaderToy.com](https://www.shadertoy.com/) از همین یونیفرم ها اما به شکل زیر استفاده کرده است: ```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) ``` صحبت کردن کافیست بیایید یونیفرم ها را در عمل ببینیم. در کد زیر ما از u_time استفاده میکنیم. یعنی تعداد ثانیه از زمانی که شیدر شروع شده است را به همراه عملکرد سینوس برای تحریک مقدار قرمز به کار گرفتیم. همانطور که میبینید GLSL سورپرایز های بیشتری دارد. GPU دارای عملکرد های زاویه شتاب همچنین توابع نمایی و مثلثاتی هست. برخی ازین توابع عبارتند از: [`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) و [`clamp()`](../glossary/?search=clamp). اکنون زمان آن است که دوباره با کد بازی کنیم. * فرکانس را کم کنید تا زمانی که تغییر رنگ نامحسوس شود. * سرعت را آنقدر زیاد کنید که یک رنگ بدون پرش ببینید. * با سه کانال RGB در فرکانس های مختلف بازی کنید تا الگو ها و رفتار های جالبی ببینید. ## gl_FragCoord به همان صورت که GLSL به ما یک خروجی vec4 gl_FragColor میدهد، همچنین یک ورودی پیشفرض در نظر دارد. vec4 gl_FragCoord که مختصات پیکسل ها در صفحه و یا قطعه صفحه ای که ترد روی آن کار میکند را نگه میدارد، با vec4 gl_FragCoord، میتوانیم بفهمیم یک ترد کجای بیلبورد کار میکند. در این مورد ما آن را یونیفرم صدا نمیزنیم، بلکه به gl_FragCoord یک varying میگوییم. در مثال بالا ما با تقسیم gl_FragCoord بر u_resolution مختصات نرمالایز شده(بین 0 و 1) را در st ذخیره میکنیم. با این کار به راحتی میتوان مقادیر x را به قرمز و مقادیر y را به سبز مپ کرد. در شیدر نویسی منابع زیادی برای دیباگ کردن نداریم، خواهید فهمید که گاهی اوقات کد نویسی در GLSL مانند قراردادن کشتی در داخل بطری است. به همان اندازه سخت زیبا و خوشایند. اکنون وقت آن است درک خود را در مورد این کد به چالش بکشیم. * میتوانید بگویید مختصات (0.0،0.0) در کنوس کجاست؟ * در مورد (1.0, 0.0), (0.0, 1.0), (0.5, 0.5), (1.0, 1.0) چطور؟ * آیا میتوانید نحوه استفاده از u_mouse را بیابید و مقدار واقعی در پیکسل نه نرمالایز شده آن را بفهمید؟ از آن برای جابه جایی رنگ ها میتوانید استفاده کنید؟ * آیا میتوانید روش جالبی برای تغییر این الگوی رنگ با استفاده از u_time و u_mouse تصور کنید؟ بعد از انجام این تمرینات، ممکن است کنجکاو باشید که در کجا ها میتوانید از توانایی شیدر نویسی خود استفاده کنید. در قسمت بعد خواهید دید که چگونه میتوان ابزار های شیدر نویسی خود را در three.js, Processing و یا openFrameworks بسازید. --- ### 03/README Fr (03/README-fr.md) ## Uniforms Jusqu'à présent, nous avons vu comment le GPU gère un ensemble de threads parallèles dont le but est d'assigner la couleur d'une partie de l'image finale. Bien que chaque thread soit *aveugle*, nous devons être capables de passer certaines valeurs depuis le CPU vers le GPU et les threads en question. Du fait de l'architecture des cartes graphiques, ces valeurs vont devoir être également (ou *uniform*-ément) distribuées sur tous les threads et - comme décrit au chapitre 1 - utilisées en *lecture seule*. Autrement dit, _tous les threads reçoivent les mêmes données, chacun peut les lire mais pas les modifier_. Ces données s'appellent des `uniform` et peuvent prendre les types suivants : `float`, `vec2`, `vec3`, `vec4`, `mat2`, `mat3`, `mat4`, `sampler2D` et `samplerCube`. Les uniforms se définissent généralement en haut du shader, juste après avoir défini la précision des floats (et autres macros de prétraitement). ```glsl #ifdef GL_ES precision mediump float; #endif uniform vec2 u_resolution; // taille du Canvas (x:largeur en pixels, y:hauteur en pixels) uniform vec2 u_mouse; // position de la souris (x,y) sur le canvas en pixels uniform float u_time; // temps écoulé depuis le lancement du shader ``` On peut se représenter les uniforms comme de petits ponts à sens unique allant du CPU (notre programme principal) au GPU (là où sera exécuté le shader). Les noms peuvent varier selon les implémentations et les plateformes mais dans les exemples suivants, nous utiliserons toujours : `u_time` (le temps écoulé depuis le lancement du shader), `u_resolution` (la taille du canvas sur lequel le shader est exécuté) et `u_mouse` (la position de la souris à l'intérieur du canvas). Le fait de préfixer les noms des uniforms par `u_` est une convention de nommage assez répandue, ça permet de reconnaître facilement le type de cette variable mais ce n'est pas une obligation. Par exemple [ShaderToy.com](https://www.shadertoy.com/) utilise les mêmes uniforms avec les noms suivants : ```glsl uniform vec3 iResolution; // taille du canvas (en pixels) uniform vec4 iMouse; // position de la souris. xy: courant, zw: au click uniform float iTime; // temps écoulé depuis le lancement du shader (en secondes) ``` Notez qu'ils utilisent un `i` au lieu de notre `u_`. Assez parlé, voyons ce que les uniforms peuvent faire. Dans l'exemple suivant, nous utilisons l'uniform la valeurs absolue (`abs(valeur)`) d'une fonction de sinus (`sin(valeur)`) qui prend `u_time` - le temps écoulé Depuis le lancement du shader - comme argument pour animer la quantité de rouge que nous dessinons sur le canvas. La fonction de sinus attend un angle comme argument, en utilisant le temps (valeur qui ne cesse de croître), on obtient une valeur qui va osciller infiniment entre `-1.` et `1.`. La valeur *absolue* d'une fonction de sinus sera quant à elle toujours comprise entre `0.` et `1.` donc notre valeur de rouge oscillera entre `0.` et `1.`. On peut constater que ça va vite (par rapport au même traitement sur le CPU), cela vient de l'*accélération matérielle*. En effet, au chapitre 1 nous avons vu que les GPU implémentent parfois l'accélération *matérielle* de certaines opérations, certaines fonctions trigonométriques telles que : [`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) er [`clamp()`](../glossary/?search=clamp), sont donc exécutées _matériellement_ et peuvent aller très (très) vite. Essayons de jouer avec le code ci dessus. * Ralentissez la fréquence jusqu'à ce que le changement de couleur deviennent imperceptible. * Accélérez la fréquence jusqu'à voir une couleur unique sans clignotement. * Donnez des fréquences différentes aux trois canaux (RGB) pour obtenir des motifs et des comportements intéressants. ## gl_FragCoord De la même manière que la fonction main() du shader expose la variable de sortie : `vec4 gl_FragColor`, elle nous donne accès à une variable d'entrée `vec4 gl_FragCoord` qui contient les coordonnées à l'écran du *pixel*. Ce *pixel* s'appelle en fait un *screen fragment*, qui donne son nom au *fragment shader*. Le *screen fragment* ou plus simplement *fragment* est le _pixel en train d'être traité par le thread_. La variable `vec4 gl_FragCoord`, nous donne donc accès à l'emplacement _physique_ (à l'écran) du pixel sur lequel le thread est en train de travailler. Cette variable n'est pas une *uniform* puisqu'elle ne conserve pas la même valeur d'un thread à l'autre, chaque pixel ayant par définition des coordonnées uniques. La variable `gl_FragCoord` s'appelle *varying* puisqu'elle va *varier* d'un thread sur l'autre, c'est la seconde _famille_ de variables qu'on peut utiliser dans un shader. Cette variable est déclarée *implicitement* dans les _vertex-shader_ et passée systématiquement à notre *fragment-shader*, autrement dit, elle est toujours là mais inutile de la chercher dans le code ci dessous. Deuxième chose importante, `gl_FragColor`, `gl_FragCoord` et tous les noms de fonctions (`sin()`, `abs()`, etc.) sont des noms réservés ; on ne peut pas s'en servir pour créer nos variables. Dans le code ci-dessus, nous *normalisons* les coordonnées du *fragment* en les divisant par la taille du canvas. En *normalisant* les coordonnées, elles vont se retrouver comprises entre `0.0` et `1.0` ce qui permet de *mapper* facilement les valeurs X et Y du *fragment* vers les canaux rouges et verts (R et G) de la couleur de sortie (`gl_FragColor`). Au pays des shaders, nous avons peu de moyen de débugger une application à part assigner des valeurs criardes aux fragments et essayer de comprendre ce qui se passe. Vous découvrirez que parfois, coder un shader c'est comme de fabriquer un tout petit bateau dans une bouteille, c'est dur, c'est beau et c'est gratifiant. Voyons ce que nous avez appris et compris du code. * Pouvez dire où se trouvent les coordonnées XY `(0.0, 0.0)` sur notre canvas ? * A votre avis où se trouvent les coordonnées`(1.0, 0.0)`, `(0.0, 1.0)`, `(0.5, 0.5)` et `(1.0, 1.0)` ? * Pouvez vous déduire comment utiliser l'uniform `u_mouse` sachant que ses valeurs sont passées au shader en _pixels_ et ne sont pas normalisées ? * Pouvez vous utiliser `u_mouse` pour changer les couleurs ? * Pouvez vous inventer une manière intéressante de combiner `u_time` et `u_mouse` pour créer un motif ? Après ces petits exercices, vous vous demandez sans doute où exercer vos nouveaux talents. Au chapitre suivant, nous verrons comment fabriquer nos propres outils dans Three.js, Processing et OpenFrameworks. --- ### 03/README Gr (03/README-gr.md) ## Uniforms Μέχρι τώρα έχουμε δει πως η GPU διαχειρίζεται μεγάλο πλήθος από παράλληλα threads (νήματα), όπου το καθένα είναι υπεύθυνο να αναθέσει σε κάθε τμήμα της τελικής εικόνας το χρώμα του. Αν και κάθε παράλληλο thread είναι τυφλό προς τα υπόλοιπα, χρειάζεται να μπορούμε να στείλουμε κάποιες εισόδους από τη CPU (ΚΜΕ) σε όλα τα threads. Εξ' αιτίας της αρχιτεκτονικής της κάρτας γραφικών, αυτές οι έισοδοι θα είναι ίδιες (uniform - ομοιόμορφες) για όλα τα threads, και κατ' ανάγκη είναι *μόνο για ανάγνωση (read only)*. Με άλλα λόγια, κάθε thread παίρνει τα ίδια δεδομένα τα οποία μπορεί να διαβάσει αλλά όχι και να αλλάξει. Αυτές οι είσοδοι λέγονται `uniform` και υπάρχουν για τους περισσότερους από τους υποστηριζόμενους τύπους: `float`, `vec2`, `vec3`, `vec4`, `mat2`, `mat3`, `mat4`, `sampler2D` και `samplerCube`. Τα uniforms ορίζονται μαζί με τον αντίστοιχο τύπο στην κορυφή του shader, αμέσως μετά την ανάθεση της ακρίβειας κινητής υποδιαστολής (default floating point precision). ```glsl #ifdef GL_ES precision mediump float; #endif uniform vec2 u_resolution; // Μέγεθος καμβά (πλάτος, ύψος) uniform vec2 u_mouse; // θέση του mouse σε συντεταγμένες οθόνης (σε pixels) uniform float u_time; // Χρόνος σε δευτερόλεπτα (seconds) από τη φόρτωση της σελίδας ``` Μπορούμε να φανταστούμε τα uniforms σαν μικρές γέφυρες ανάμεσα στην CPU και τη GPU. Τα ομόματα θα διαφέρουν από υλοποίηση σε υλοποίηση, αλλά σε αυτά τα παραδείγματα πάντα τα περνάω σαν: `u_time` (χρόνος σε δευτερόλεπτα από τη στιγμή που ξεκίνησε ο shader), `u_resolution` (μέγεθος του πίνακα όπου ζωγραφίζεται ο shader) και `u_mouse` (θέση του mouse μέσα στον πίνακα σε pixels). Ακολουθώ τη σύμβαση να προσθέτω `u_` πριν από το όνομα του uniform ώστε να είμαι σαφής ως προς τη φύση της μεταβλητής, αλλά θα συναντήσετε όλων των ειδών τα ονόματα για uniforms. Για παράδειγμα, το [ShaderToy.com](https://www.shadertoy.com/) χρησιμοποιεί τα ίδια uniforms αλλά με τα ακόλουθα ονόματα: ```glsl uniform vec3 iResolution; // ανάλυση του viewport (περιοχή "θέασης") (σε pixels) uniform vec4 iMouse; // συντεταγμένες του mouse σε pixel. xy: τρέχουσα θέση, zw: θέση click uniform float iTime; // χρόνος εκτέλεσης (playback) του shader (σε seconds) ``` Αλλά αρκετά με τα λόγια, ας δούμε τα uniforms στην πράξη. Στον ακόλουθο κώδικα χρησιμοποιούμε το `u_time` - τον αριθμό δευτερολέπτων από τη στιγμή που ο shaders άρχισε να εκτελείται - σε συνδυασμό με μια ημιτονοειδή συνάρτηση για να δώσουμε κίνηση στη μεταβολή του κόκκινου στον πίνακα. Όπως βλέπετε, η GLSL έχει κι άλλες εκπλήξεις. Η GPU υποστηρίζει σε hardware συναρτήσεις γωνίας, τριγωνομετρικές και εκθετικές. Μερικές από αυτές τις συναρτήσεις είναι: [`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) και [`clamp()`](../glossary/?search=clamp). Ώρα να παίξουμε πάλι με τον παραπάνω κώδικα. * Επιβραδύνετε τη συχνότητα μέχρι η αλλαγή χρώματος σχεδόν να μη γίνεται αντιληπτή. * Επιταχύνετέ τη μέχρι να βλέπετε ένα ενιαίο χρώμα που δε θα τρεμοσβήνει (flicker). * Παίξτε με τα τρία κανάλια (RGB) σε διαφορετικές συχνότητες για να πάρετε ενδιαφέροντες συνδυασμούς και συμπεριφορές. ## gl_FragCoord Κατά τον ίδιο τρόπο που η GLSL μας δίνει μια προκαθορισμένη (default) έξοδο, `vec4 gl_FragColor`, μας δίνει και μια προκαθορισμένη είσοδο, `vec4 gl_FragCoord`, η οποία περιέχει τις συντεταγμένες οθόνης του *pixel* ή *τεμάχιου οθόνης - screen fragment* στο οποίο δουλεύει το ενεργό thread. Με το `vec4 gl_FragCoord`, ξέρουμε που δουλεύει ένα thread μέσα στον πίνακα. Σε αυτή την περίπτωση δεν το ονομάζουμε `uniform` γιατί θα είναι διαφορετικό από το ένα thread στο άλλο, αντίθετα, το `gl_FragCoord` λέγεται *varying*. Στον παραπάνω κώδικα *κανονικοποιούμε (normalize)* τις συντεταγμένες του fragment (τεμαχίου) διαιρώντας το με τη συνολική ανάλυση του πίνακα. Με αυτό τον τρόπο, οι τιμές θα βρίσκονται μεταξύ `0.0` και `1.0`, κάτι που το κάνει εύκολο να αντιστοιχίσουμε τις τιμές X και Y στα κανάλια RED (κόκκινο) και GREEN (πράσινο). Στον κόσμο των shaders, δεν έχουμε και πολλές δυνατότητες για debugging (διόρθωση σφαλμάτων) πέρα από το να αναθέτουμε έντονα χρώματα σε μεταβλητές και να προσπαθούμε να βγάλουμε άκρη από αυτά. Θα ανακαλύψετε πως κάποιες φορές το να προγραμματίζετε σε GLSL είναι πολύ παρόμοιο με το να φτιάχνει κανείς καραβάκια μέσα σε μπουκάλια. Είναι εξ' ίσου δύσκολο, όμορφο και ευχάριστο. Ώρα να δοκιμάσουμε να τσεκάρουμε πόσο έχουμε κατανοήσει αυτό τον κώδικα. * Μπορείτε να βρείτε που στον καμβά μας βρίσκονται οι συντεταγμένες `(0.0, 0.0)`; * Ή οι συντεταγμένες `(1.0, 0.0)`, `(0.0, 1.0)`, `(0.5, 0.5)` και `(1.0, 1.0)`; * Μπορείτε να βρείτε πως να χρησιμοποιήσετε το `u_mouse` γνωρίζοντας πως οι τιμές είναι σε pixels και ΟΧΙ κανονικοποιημένες; Μπορείτε να το χρησιμοποιήσετε για να κινήστε τα χρώματα; * Μπορείτε να επινοήσετε έναν ενδιαφέροντα τρόπο να αλλάζετε το χρωματικό συνδυασμό χρησιμοποιώντας τις συντεταγμένες `u_time` και `u_mouse`? Αφού ολοκληρώσετε αυτές τις ασκήσεις, θα αναρωτηθείτε ίσως πού αλλού μπορείτε να χρησιμοποιήστε τις νέες σας shaderοδυνάμεις. Στο επόμενο κεφάλαιο θα δούμε πως να φτιάξετε τα δικά σας εργαλεία shaders σε three.js, Processing, και openFrameworks. --- ### 03/README Id (03/README-id.md) ## 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. 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*. 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. 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. --- ### 03/README It (03/README-it.md) ## Uniforms Finora abbiamo visto come la GPU gestisce un gran numero di thread paralleli, ciascuno responsabile nell'assegnazione d'un colore ad una frazione dell'immagine totale. Sebbene ogni thread parallelo è cieco nei confronti degli altri, dobbiamo essere in grado d'inviare alcuni input dalla CPU a tutti i thread. A causa dell'architettura della scheda grafica tali input saranno uguali (*uniform*) per tutti i thread e necessariamente impostati come di *sola lettura*. In altre parole, ogni thread riceve gli stessi dati che possono essere letti ma non possono essere cambiati. Questi input sono chiamati ```uniform``` e sono disponibili nella maggior parte di tipi supportati: ```float```, ```vec2```, ```vec3```, ```vec4```, ```mat2```, ```mat3```, ```mat4```, ```sampler2D``` e ```samplerCube```. Gli Uniforms sono definiti con i rispettivi tipi, all'inizio del codice, dopo aver definito la precisione della virgola mobile. ```glsl #ifdef GL_ES precision mediump float; #endif uniform vec2 u_resolution; // dimensione del Canvas (larghezza, altezza) uniform vec2 u_mouse; // posizione del mouse (x,y) in pixels uniform float u_time; // tempo in secondi da quando lo shader è iniziato ``` È possibile immaginare gli uniforms come piccoli ponti tra la CPU e la GPU. I nomi variano da applicazione ad applicazione, ma in questa serie di esempi userò: ```u_time``` (tempo in secondi da quando lo shader è iniziato), ```u_resolution``` (la dimensione della finestra in cui lo shader è in corso d'elaborazione) e ```u_mouse``` (la posizione in pixel del mouse all'interno della finestra). Seguirò la convenzione di mettere ```u_``` prima del nome degli uniforms per essere espliciti sulla natura di questa variabile, ma incontrerete varie nomenclature per gli uniforms. Per esempio [ShaderToy.com](https://www.shadertoy.com/) utilizza gli stessi uniforms, ma con i seguenti nomi: ```glsl uniform vec3 iResolution; // dimensione del Canvas (in pixels) uniform vec4 iMouse; // posizione del mouse in pixels. xy: corrente, zw: click uniform float iTime; // tempo (in secondi) da quando lo shader è iniziato ``` Ma ora basta chiacchiere, vediamo gli uniforms in azione. Nel seguente codice utilizziamo ```u_time``` - il numero di secondi da quando lo shader è iniziato - insieme ad una funzione seno per animare con una transizione la quantità di rosso sullo schermo. Come potete vedere GLSL ha molte sorprese. La GPU ha funzioni trigonometriche ed esponenziali, che sono accelerate dall'hardware. Alcune di queste funzioni sono: [```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) and [```clamp()```](../glossary/?search=clamp). Ora è il momento di giocare con il codice qui sopra. * Rallentate la frequenza fino a quando il cambiamento di colore diventa quasi impercettibile. * Aumentate la frequenza fino a vedere un solo colore, senza sfarfallio. * Date tre frequenze differenti ai tre canali (RGB) per ottenere motivi e comportamenti interessanti. ## gl_FragCoord Allo stesso modo GLSL ci dà un output di default, ```vec4 gl_FragColor```, ma anche un input di default, ```vec4 gl_FragCoord```, che contiene le coordinate sullo schermo del *pixel* o del *screen fragment* del thread attivo. Con ```vec4 gl_FragCoord```, sappiamo dove un thread sta lavorando all'interno dello schermo. In questo caso la variabile non è un ```uniform``` perché sarà diversa da thread a thread. Le variabili che cambiano in ogni thread, come ```gl_FragCoord```, sono chiamate *varying*. Nel codice qui sopra *normalizziamo* le coordinate del fragment dividendole per la risoluzione totale dello schermo. In questo modo i valori andranno tra ```0.0``` e ```1.0```, una tecnica che rende facile mappare i valori X e Y per i canali ROSSO e VERDE. Nel mondo degli shaders non abbiamo troppe risorse per il debug a parte l'assegnazione di colori intensi alle variabili e cercare di trovargli un senso. Scoprirete che a volte programmando in GLSL è come mettere una nave all'interno di una bottiglia: un processo difficile, bello e gratificante. Ora è il momento di mettere in pratica gli insegnamenti che abbiamo imparato. * Sapreste dire dove è la coordinata ```(0.0,0.0)``` sul nostro schermo? * E dove sono ```(1.0,0.0)```, ```(0.0,1.0)```, ```(0.5,0.5)``` e ```(1.0,1.0)```? * Riuscite ad immaginare come usare ```u_mouse``` sapendo che i valori sono espressi in pixel e NON in valori normalizzati? Sapresti usare ```u_mouse``` per muovere i colori? * Sapreste trovare un modo interessante per cambiare questo pattern grafico utilizzando ```u_time``` e le coordinate ```u_mouse```? Dopo aver fatto questi esercizi, ci si potrebbe chiedere dove si potrebbero provare i nuovi super poteri che gli shader ci hanno dato. Nel prossimo capitolo vedremo come creare i vostri shader in Three.js, Processing e openFrameworks. --- ### 03/README Jp (03/README-jp.md) ## ユニフォーム変数 ここまで、GPUが沢山のスレッドを並列に処理する様子を見てきました。それぞれのスレッドは画像の各部分への色の割り当てを受け持っています。シェーダーではスレッド間の情報のやりとりを行うことはできませんが、CPUからそれぞれのスレッドに入力を送ることはできます。グラフィックカードは全てのスレッドにまったく同じ入力を、読み取り専用で送るように設計されています。それぞれのスレッドは同じデータを受け取り、それを書き換えることはできません。(訳注:英語の”uniform”には均一な、一様な、という意味があります) これらの入力は ```uniform``` 変数と呼ばれGLSLでサポートされているほとんどの型が使えます。サポートされている型には ```float```、```vec2```、```vec3```、```vec4```、```mat2```、```mat3```、```mat4```、```sampler2D```、```samplerCube``` などがあります。 uniform変数はシェーダーの冒頭、浮動小数点精度の設定の後に型指定付きで定義します。 ```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 ``` uniform変数はCPUとGPUの間の小さな架け橋だと考えることができます。変数の名前は実装次第で変わりますが、この本のサンプルでは一貫して```u_time```(シェーダーが開始してから経過した秒数)、```u_resolution```(シェーダーが描画する領域の大きさ)、```u_mouse```(描画領域の中のマウスの位置)を渡すことにします。ここでは変数の種類を示すためにuniform変数の名前は ```u_``` で始めるという慣例に従っていますが、他の場所では異なる名前が使われているのも見かけることでしょう。 例えば[ShaderToy.com](https://www.shadertoy.com/)では同じ意味を持つuniform変数に下記の名前が付けられています。 ```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) ``` (訳注:uniform変数は開発者が自由に名前を決めることができ、上で挙げられている用途以外にも自由に使うことができます。C、JavascriptなどのCPUで走るプログラムからは、シェーダー側で決めた変数の名前を指定して値を渡すことができます) 説明はこれくらいにしてuniform変数を実際に使ってみましょう。下記のコードでは、```u_time```(シェーダーが実行を始めてからの秒数)をサイン関数と組み合わせて使い、赤い画面の色を変化させています。 GPUの驚くべき機能の1つには、角度や三角関数、指数関数などがハードウェア上で高速に処理されることが挙げられます。サポートされる関数には [```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)、[```clamp()```](../glossary/?search=clamp) などがあります。 さて、また上のコードで色々と実験をしてみましょう。 * 色が変わる頻度を下げて、変化にほとんど気がつかなくなるまで遅くしてみましょう。 * 変化のスピードを上げて、点滅がなくなりひとつの色に見えるまで速くしてみましょう。 * 3つのチャンネル(rgb)の変化の頻度を別々に変えて、面白いパターンを作ってみましょう。 ## gl_FragCoord デフォルトの出力として ```vec4 gl_FragColor``` を使うことができるのと同様に、GLSLにはデフォルトの入力として画面上の「フラグメント」、つまりピクセルの位置を表す ```vec4 gl_FragCoord``` が用意されています。```vec4 gl_FragCoord``` を使うとスレッドが描画領域内のどこで作業をしているかを知ることができます。この ```gl_FragCoord```はスレッドごとに異なる値を持っているためuniform変数とは呼ばず、代わりにvarying変数と呼びます。 上のサンプルではフラグメントの座標を描画領域全体のサイズで割ることによって正規化しています。こうすると座標値の範囲が ```0.0``` から ```1.0``` の間に収まるため、簡単にx座標とy座標の値をr(赤)とg(緑)のチャンネルに対応させることができます。 シェーダーの世界ではデバッグに使える手段は限られています。判別しやすい色を変数の値に割り当てて確認するのは数少ない方法の一つです。GLSLのコーディングは時としてガラス瓶の中に船の模型を組み立てるのに似ています。どちらも同じくらい難しいですが、結果は美しく達成感があるものです。 それでは、サンプルが理解できているか確かめてみましょう。 * 座標 ```(0.0,0.0)``` が描画領域のどこを指すかわかりますか? * ```(1.0,0.0)```、```(0.0,1.0)```、```(0.5,0.5)```、```(1.0,1.0)``` はどうでしょう? * ```u_mouse``` の使い方はわかりますか? ```u_mouse``` の値は正規化されていないことに注意してください。この変数を使って色を変化させることはできますか? * ```u_time``` と ```u_mouse``` の座標を使って色のパターンを自由に変化させてみましょう。 さて、課題を終えたところで、このシェーダーの力を他にどこで使うことができるのか興味が湧いているのではないでしょうか。 次の章ではオリジナルのシェーダーをthree.js、Processing、openFrameworkで使う方法について説明します。 --- ### 03/README Pl (03/README-pl.md) ## Uniformy Do tej pory widzieliśmy jak GPU zarządza wieloma równoległymi wątkami, z których każdy odpowiada za kolor części renderowanego obrazu. Choć wątki nie komunikują się między sobą, to jednak muszą jakoś otrzymywać input z CPU. Ze względu na architekturę karty graficznej taki input musi być jednakowy (ang. "*uniform*") dla wszystkich wątków i, z konieczności, tylko do odczytu (ang. "read-only"). Innymi słowy, każdy wątek otrzymuje takie same dane, które może odczytać, ale nie nadpisać, zmienić. Inputy te nazywamy `uniform`ami i mogą być większości wspieranych typów: `float`, `vec2`, `vec3`, `vec4`, `mat2`, `mat3`, `mat4`, `sampler2D` i `samplerCube`. Uniformy definiowane są zwykle na górze shaderu zaraz po przypisaniu domyślnej precyzji floatów. ```glsl #ifdef GL_ES precision mediump float; #endif uniform vec2 u_resolution; // wielkość/rozdzielczość kanwy (szerokość, wysokość) uniform vec2 u_mouse; // pozycja myszy na kanwie (wyrażona w pikselach) uniform float u_time; // czas w sekundach od załadowania shadera ``` Wyobraź sobie te uniformy jak małe mosty między CPU i GPU. Ich nazwy bywają różne, ale w tej książce używam: `u_time`, `u_resolution` i `u_mouse` (przeczytaj komentarze w kodzie, aby wiedzieć, co robią). Podążam za konwencją dodawania `u_` przed nazwą uniformów, aby było wiadomo, że nie są to zwykłe zmienne, ale ostatecznie jest to kwestia gustu. Przykładowo, [ShaderToy.com](https://www.shadertoy.com/) używa takich samych uniformów, ale z następującym nazewnictwem: ```glsl uniform vec3 iResolution; // rozdzielczość obszaru widoku (w pikselach) uniform vec4 iMouse; // współrzędne piksela myszy: xy – bieżąca pozycja, zw – kliknięcie uniform float iTime; // czas działania shadera (w sekundach) ``` (zwróć uwagę, że `iResolution` jest typu `vec3`, a `iMouse` typu `vec4`; uniformy te zawierają po prostu dodatkowe informacje, np.: stosunek szerokości do wysokości pikseli na ekranie, czy któryś z przycisków myszy został kliknięty albo czy jest przytrzymywany) Koniec gadania, czas zobaczyć uniformy w akcji. W poniższym kodzie używamy `u_time` (liczby sekund od uruchomienia shadera) razem z funkcją sinus, aby stworzyć animację przejścia od koloru czerwonego do czarnego. Jak widać GLSL skrywa wiele niespodzianek, na przykład w postaci specjalnych, zaimplementowanych w hardwarze, funkcji trygonometryczne czy wykładniczych. Tutaj podaję część z nich: [`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) i [`clamp()`](../glossary/?search=clamp). Pobawmy się powyższym kodem: * Zmniejsz częstotliwość tak bardzo, aby zmiany koloru stały się niezauważalne. * Zwiększ częstotliwość do takiego stopnia, aby ujrzeć stały kolor bez migotania. * Wstaw funkcje sinusoidalne o różnych częstotliwościach do pozostałych kanałów (zielonego i niebieskiego), aby uzyskać ciekawe efekty. ## gl_FragCoord GLSL daje nam nie tylko domyślny output `vec4 gl_FragColor`, ale również domyślny input w postaci `vec4 gl_FragCoord`, który przechowuje współrzędne *piksela* (inaczej: *fragmentu*), nad którym aktualnie pracuje wątek - dzięki `vec4 gl_FragCoord` wiemy, gdzie wątek pracuje wewnątrz kanwy. Nie nazywamy go `uniform`em, ponieważ jego wartość *różni się* między wątkami. Zamiast tego `gl_FragCoord` nazywamy *varying* (z ang. "zmieniający się", "różniący się"). W powyższym kodzie, *normalizujemy* współrzędne fragmentu poprzez podzielenie go przez rozdzielczość kanwy. W ten sposób otrzymujemy wartości z przedziału od `0.0` do `1.0`, co ułatwia zmapowanie współrzędnych x i y do, odpowiednio, czerwonego i zielonego kanału. W świecie shaderów nie mamy zbyt dużo sposóbów debuggowania poza przypisywaniem jaskrawych kolorów do zmiennych i wyciągania wniosków o działaniu shadera, na podstawie tego, co widzimy. Odkryjesz, że programowanie GLSL jest często jak wkładanie miniaturowych statków do butelki - jest to trudne, ale też piękne i satysfakcjonujące. Czas przetestować nasze rozumienie kodu: * Czy jesteś w stanie powiedzieć, gdzie na naszej kanwie znajduje się fragment o znormalizowanych współrzędnych `(0.0, 0.0)`? * Co z fragmentami o znormalizowanych współrzędnych `(1.0, 0.0)`, `(0.0, 1.0)`, `(0.5, 0.5)` i `(1.0, 1.0)`? * Czy jesteś w stanie użyć uniforma `u_mouse` wiedząc, że wartości są nieznormalizowane? Spróbuj użyć go do manipulacji kolorem za pomocą ruchów myszki. * Czy jesteś sobie w stanie wyobrazić ciekawy sposób zmieniania koloru, łącząc współrzędne `u_mouse` z `u_time`? Po wykonaniu tych ćwiczeń, zapewne zastanawiasz się, gdzie jeszcze można użyć twoich nowych shaderowych mocy. W następnym rozdziale zobaczymy, jak stworzyć swój własny shader w three.js, Processing i openFrameworks. --- ### 03/README Pt (03/README-pt.md) ## Uniforms Até agora, vimos como a GPU lida um grande número de threads em paralelo, cada uma sendo responsável por atribuir a cor a uma porção da imagem. Apesar de cada thread paralela não saber da existência das outras, precisamos ser capazes de enviá-las algumas entradas (inputs) da CPU. Devido à arquitetura das placas de vídeo, essas entradas serão iguais (*uniform*) para todas as threads e necessariamente determinadas como *somente leitura*. Em outras palavras, cada thread recebe os mesmos dados, os quais se podem ler mas não podem se alterar. Essas entradas são chamamadas de `uniform` e podem ser de tipos diferentes, como: `float`, `vec2`, `vec3`, `vec4`, `mat2`, `mat3`, `mat4`, `sampler2D` e `samplerCube`. Uniformes são definidas com o tipo correspondente no começo do código, logo após atribuir a precisão padrão de pontos flutuantes, ```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 ``` Imagine os uniforms como pequenas pontes entre a CPU e a GPU. Os nomes variam dependendo da implementação, mas nessa série de exemplos estarei sempre usando: `u_time` (tempo em segundos desde que o shader foi iniciado), `u_resolution` (tamanho da tela onde o shader está sendo desenhado) and `u_mouse` (posição em pixels do mouse dentro da tela). Estarei seguindo a convenção ao colocar `u_` antes do nome da uniform para evidenciar a natureza desta variável mas você encontrará outros tipos de nomenclatura para uniforms. Por exemplo [ShaderToy.com](https://www.shadertoy.com/) utiliza os mesmos uniforms mas com os seguintes nomes: ```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) ``` Chega de conversa, vamos ver os uniforms em ação. No código abaixo, usamos `u_time` - o número de segundos desde que o shader começou a ser executado - junto com uma função de seno para animar a transição da quantidade de vermelho na tela. Como você pode ver, GLSL tem mais surpresas. A GPU tem funções angulares, trigonométricas e exponenciais aceleradas pelo hardware. Algumas dessas funções são: [`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) e [`clamp()`](../glossary/?search=clamp). Agora é novamente a hora de experimentar com o código acima. * Diminua a frequência até a mudança de cor se tornar quase imperceptível. * Aumente a velocidade até que seja possível ver somente uma cor sem oscilações. * Experimente alterar os valores dos três canais de cores (RGB) em diferentes frequências a fim de obter padrões e comportamentos interessantes. ## gl_FragCoord Da mesma maneira que GLSL nos dá um output padrão, `vec4 gl_FragColor`, ele também nos dá um input padrão, `vec4 gl_FragCoord`, que possui as coordenadas de um *pixel* ou *screen fragment* com que a thread ativa está processando. Com `vec4 gl_FragCoord` podemos saber onde a thread está trabalhando dentro da tela. Neste caso, não chamaremos isso de `uniform` porque seu valor será diferente para cada thread, logo `gl_FragCoord` é chamada de *varying*. No código acima nós *normalizamos* as coordenadas do fragmento ao dividi-las pela resolução total da tela. Fazendo isso, os valores serão entre `0.0` e `1.0`, o que facilita mapear os valores de X e Y para os canais RED e GREEN. No mundo dos shaders, não temos muitos recursos para depurar bugs além de atribuir uma cor marcante às variáveis e tentar entender o que está acontecendo com as mesmas. Você descobrirá que, às vezes, programar em GLSL é bem similar a construir navios dentro de garrafas. É igualmente difícil, bonito e gratificante. Agora é a hora de tentar e desafiar a nossa compreensão desse código. * Você pode dizer onde a coordenada `(0.0, 0.0)` está em nossa tela? * E quanto `(1.0, 0.0)`, `(0.0, 1.0)`, `(0.5, 0.5)` e `(1.0, 1.0)`? * Você pode adivinhar como se usa o uniform `u_mouse`, sabendo que os valores são em pixel e NÃO em valores normalizados? Você pode usá-lo para mover as cores ao longo da tela? * Você consegue imaginar uma maneira interessante para mudar esse padrão de cor usando `u_time` e as coordenadas de `u_mouse`? Após completar estes exercícios, você talvez se pergunte onde mais você pode aplicar seu novo superpoder de shader. No próximo capítulo veremos como fazer as nossas próprias ferramentas de shader em three.js, Processing, e openFrameworks. --- ### 03/README Ru (03/README-ru.md) ## Uniform-переменные В предыдущей главе мы увидели каким образом GPU управляет большим количеством параллельных потоков, каждый из которых отвечает за назначение цвета небольшой части изображения. Каждый из параллельных потоков не знает о состоянии остальных, но всё же нам бывает нужно передавать входные данные от CPU ко всем потокам одновременно. Из-за особенностей архитектуры графических карт, все такие входные данные будут одинаковыми для всех потоков (однородными, *uniform*) и доступными *только для чтения*. Другими словами, каждый поток принимает на вход одни и те же данные, которые он может прочитать и не может перезаписать. Эти входы называются однородными (`uniform`) и могут иметь практически любой из поддерживаемых типов: `float`, `vec2`, `vec3`, `vec4`, `mat2`, `mat3`, `mat4`, `sampler2D` и `samplerCube`. Uniform-переменные с указанием своих типов объявляются вначале шейдера сразу после указания точности по умолчанию. ```glsl #ifdef GL_ES precision mediump float; #endif uniform vec2 u_resolution; // Размер изображения (ширина, высота) uniform vec2 u_mouse; // Положение курсора мыши в пикселях uniform float u_time; // Время в секундах с момента загрузки ``` Uniform-переменные можно представлять себе как маленькие мостики между CPU и GPU. Имена могут изменяться от примера к примеру, но в этой серии примеров я всегда передаю следующее: `u_time` (время в секундах с момента запуска шейдера), `u_resolution` (размер изображения) и `u_mouse` (положение мыши на изображении, выраженное в пикселях). Я буду писать `u_` вначале имён uniform-переменных, чтобы их происхождение было обозначено явно, но на практике вы столкнётесь с самыми разными именами uniform-переменных. Например, [ShaderToy.com](https://www.shadertoy.com/) объявляет эти же переменные со следующими именами: ```glsl uniform vec3 iResolution; // разрешение области изображения (в пикселях) uniform vec4 iMouse; // координаты мыши в пикселях. xy - текущие, zw - клик uniform float iGlobalTime; // время работы шейдера (секунды) ``` Хватит слов, давайте посмотрим на юниформы в действии. В следующем коде мы используем `u_time` (количество секунд с момента запуска шейдера) в комбинации с функцией синуса чтобы анимировать изменение количества красного цвета на экране. Как видите, GLSL содержит ещё много сюрпризов. GPU аппаратно ускоряет угловые, тригонометрические и экспоненциальные функции. Вот некоторые из них: [`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) и [`clamp()`](../glossary/?search=clamp). Настало время поиграть с кодом выше. * Уменьшите частоту так, чтобы изменение цвета стало почти незаметным. * Увеличивайте её до тех пор, пока не увидите сплошной цвет без мерцания. * Поиграйтесь с каналами RGB на различных частотах, чтобы добиться какого-нибудь интересного поведения. ## gl_FragCoord Подобно тому, как GLSL объявляет выходное значение `vec4 gl_FragColor` по умолчанию, он так же предоставляет вход `vec4 gl_FragCoord`, содержащий координаты *пикселя* или *фрагмента экрана*, над которым работает данный поток. С помощью `vec4 gl_FragCoord` мы можем узнать где именно поток работает внутри изображения. В данном случае мы не называем входное значение однородным, потому что оно меняется от потока к потоку и называется изменяющимся (*varying*). В коде выше мы нормализуем координаты фрагмента, разделяя их на разрешение изображения. В результате значения переходят в диапазон между `0.0` и `1.0`, что упрощает отображение значений X и Y на красный и зелёный каналы. В мире шейдеров у нас нет нормальных отладочных инструментов, поэтому приходится задавать переменным яркие цвета и пытаться извлечь из них смысл. Вы увидите, что иногда программирование на GLSL похоже на засовывание корабля в бутылку. Оно столь же сложно, сколь красиво и захватывающе. Настало время проверить наше понимание приведённого выше кода. * Укажите где находятся координаты `(0.0, 0.0)` на изображении. * Как насчёт `(1.0, 0.0)`, `(0.0, 1.0)`, `(0.5, 0.5)` и `(1.0, 1.0)`? * Догадайтесь как использовать `u_mouse`, зная, что координаты даны в пикселях и НЕ нормализованы. Можете ли вы изменять цвета с помощью этой переменной? * Придумайте какой-нибудь интересный способ изменения цветов с помощью `u_time` и `u_mouse`. После выполнения этих упражнения у вас скорее всего возникнет вопрос: где ещё можно применить мощь шейдеров? В следующей главе вы научитесь создавать шейдерные инструменты на three.js, Processing, и openFrameworks. --- ### 03/README Tr (03/README-tr.md) ## Uniform'lar Şimdiye kadar GPU'nun, her biri görüntünün toplamının bir kısmına renk atamaktan sorumlu olan çok sayıda paralel iş parçacığını nasıl yönettiğini gördük. Her paralel iş parçacığı diğerlerine kör olsa da, CPU'dan tüm iş parçacıklarına bazı girdiler gönderebilmemiz gerekir. Grafik kartının mimarisi nedeniyle bu girdiler tüm iş parçacıkları için eşit (*uniform*) olacak ve zorunlu olarak *salt okunur* (read only) olarak ayarlanacaktır. Başka bir deyişle, her iş parçacığı okuyabileceği ancak değiştiremeyeceği aynı verileri alır. Bu girdilere `uniform` denir ve desteklenen çoğu türde gelirler: `float`, `vec2`, `vec3`, `vec4`, `mat2`, `mat3`, `mat4`, `sampler2D` ve `samplerCube`. Uniform'lar, varsayılan kayan nokta hassasiyetini atadıktan hemen sonra shader'ın en üstünde ilgili türle tanımlanır. ```glsl #ifdef GL_ES precision mediump float; #endif uniform vec2 u_resolution; // Tuval boyutu (genişlik,yükseklik) uniform vec2 u_mouse; // ekran piksellerinde fare konumu uniform float u_time; // Yüklemeden bu yana saniye cinsinden süre ``` Uniform'ları CPU ve GPU arasındaki küçük köprüler gibi hayal edebilirsiniz. İsimler uygulamadan uygulamaya değişecektir ancak bu örnek serisinde her zaman şunları iletiyorum: `u_time` (shader başladığından beri saniye cinsinden süre), `u_resolution` (shader'ın çizildiği pano boyutu) ve `u_mouse` (pano içindeki fare konumu piksel cinsinden). Bu değişkenin doğası hakkında açık olmak için uniform adından önce `u_` koyma kuralını izliyorum, ancak her türlü uniform adı bulacaksınız. Örneğin [ShaderToy.com](https://www.shadertoy.com/) aynı uniform'ları kullanır ancak şu isimlerle: ```glsl uniform vec3 iResolution; // görüntü alanı çözünürlüğü (piksel cinsinden) uniform vec4 iMouse; // fare piksel koordinatları. xy: geçerli, zw: tıklama uniform float iTime; // shader oynatma süresi (saniye cinsinden) ``` Yeterince konuştuk, uniform'ları eylem halinde görelim. Aşağıdaki kodda, panodaki kırmızı miktarının geçişini canlandırmak için bir sinüs fonksiyonuyla birlikte `u_time`'ı - shader çalışmaya başladığından beri geçen saniye sayısını - kullanıyoruz. Gördüğünüz gibi GLSL'in daha fazla sürprizi var. GPU, donanım hızlandırmalı açı, trigonometrik ve üstel fonksiyonlara sahiptir. Bu fonksiyonlardan bazıları şunlardır: [`sin()`](../glossary/?search=sin&lan=tr), [`cos()`](../glossary/?search=cos&lan=tr), [`tan()`](../glossary/?search=tan&lan=tr), [`asin()`](../glossary/?search=asin&lan=tr), [`acos()`](../glossary/?search=acos&lan=tr), [`atan()`](../glossary/?search=atan&lan=tr), [`pow()`](../glossary/?search=pow&lan=tr), [`exp()`](../glossary/?search=exp&lan=tr), [`log()`](../glossary/?search=log&lan=tr), [`sqrt()`](../glossary/?search=sqrt&lan=tr), [`abs()`](../glossary/?search=abs&lan=tr), [`sign()`](../glossary/?search=sign&lan=tr), [`floor()`](../glossary/?search=floor&lan=tr), [`ceil()`](../glossary/?search=ceil&lan=tr), [`fract()`](../glossary/?search=fract&lan=tr), [`mod()`](../glossary/?search=mod&lan=tr), [`min()`](../glossary/?search=min&lan=tr), [`max()`](../glossary/?search=max&lan=tr) ve [`clamp()`](../glossary/?search=clamp&lan=tr). Şimdi yukarıdaki kodla oynama zamanı. * Renk değişimi neredeyse algılanamaz hale gelene kadar frekansı yavaşlatın. * Titreşmeden tek bir renk görene kadar hızlandırın. * İlginç desenler ve davranışlar elde etmek için üç kanalla (RGB) farklı frekanslarda oynayın. ## gl_FragCoord GLSL'in bize varsayılan bir çıktı olan `vec4 gl_FragColor`'ı vermesi gibi, bize varsayılan bir girdi olan `vec4 gl_FragCoord`'ı da verir; bu, aktif iş parçacığının üzerinde çalıştığı *pikselin* veya *ekran parçasının* ekran koordinatlarını tutar. `vec4 gl_FragCoord` ile bir iş parçacığının panonun neresinde çalıştığını biliriz. Bu durumda buna `uniform` demiyoruz çünkü iş parçacığından iş parçacığına farklı olacaktır, bunun yerine `gl_FragCoord`'a *varying* (değişen) denir. Yukarıdaki kodda, parçanın koordinatını panonun toplam çözünürlüğüne bölerek *normalize* ediyoruz. Bunu yaparak değerler `0.0` ve `1.0` arasına gelecektir, bu da X ve Y değerlerini KIRMIZI ve YEŞİL kanala eşlemeyi kolaylaştırır. Shader diyarında, değişkenlere güçlü renkler atamak ve onlardan bir anlam çıkarmaya çalışmak dışında hata ayıklama (debugging) için çok fazla kaynağımız yoktur. Bazen GLSL'de kodlamanın şişelerin içine gemi koymaya çok benzediğini keşfedeceksiniz. Aynı derecede zor, güzel ve tatmin edicidir. Şimdi bu kod hakkındaki anlayışımızı deneme ve zorlama zamanı. * `(0.0, 0.0)` koordinatının tuvalimizin neresinde olduğunu söyleyebilir misiniz? * Peki ya `(1.0, 0.0)`, `(0.0, 1.0)`, `(0.5, 0.5)` ve `(1.0, 1.0)`? * Değerlerin piksel cinsinden olduğunu ve normalize EDİLMEDİĞİNİ bilerek `u_mouse`'u nasıl kullanacağınızı bulabilir misiniz? Renkleri hareket ettirmek için kullanabilir misiniz? * `u_time` ve `u_mouse` koordinatlarını kullanarak bu renk desenini değiştirmenin ilginç bir yolunu hayal edebilir misiniz? Bu alıştırmaları yaptıktan sonra yeni shader güçlerinizi başka nerede deneyebileceğinizi merak edebilirsiniz. Sonraki bölümde three.js, Processing ve openFrameworks'te kendi shader araçlarınızı nasıl yapacağınızı göreceğiz. --- ### 03/README Ua (03/README-ua.md) ## Uniforms Раніше ми побачили, яким чином графічний процесор керує великою кількістю паралельних потоків, кожен з яких відповідає за призначення кольору частці загального зображення. Хоча кожен паралельний потік закритий для інших, ми повинні мати можливість надсилати деякі вхідні дані від CPU до всіх потоків. Через архітектуру відеокарти ці вхідні дані будуть однаковими (*uniform* - *уніфікованими*, *однорідними*) для всіх потоків і доступними *лише для читання*. Іншими словами, кожен потік отримує ті ж самі дані, які він може читати, але не може змінювати. Ці вхідні дані називаються `uniform` та мають більшість підтримуваних типів: `float`, `vec2`, `vec3`, `vec4`, `mat2`, `mat3`, `mat4`, `sampler2D` і `samplerCube `. Uniform-змінні визначаються з відповідним типом у верхній частині шейдера відразу після встановлення точності для float-значень. ```glsl #ifdef GL_ES precision mediump float; #endif uniform vec2 u_resolution; // Розмір полотна (ширина, висота) uniform vec2 u_mouse; // Положення курсору на екрані uniform float u_time; // Час у секундах з моменту запуску коду ``` Ви можете уявити uniform-змінні як маленькі містки між CPU та GPU. Назви для змінних можуть відрізнятися від реалізації до реалізації, але в цій серії прикладів я завжди передаю: `u_time` (час у секундах із моменту запуску шейдера), `u_resolution` (розмір зображення де застосовується шейдер) і `u_mouse` (положення курсору всередині зображення, що вимірюється у пікселях). Я дотримуюся конвенції з префіксом `u_` перед назвою uniform-змінних, щоб чітко означити природу таких змінних, але насправді ви можете зустріти різні назви. Наприклад, [ShaderToy.com](https://www.shadertoy.com/) використовує ті ж самі змінні, але з наступними назвами: ```glsl uniform vec3 iResolution; // роздільна здатність області зображення, у пікселях (viewport resolution) uniform vec4 iMouse; // піксельні координати курсору. xy - поточні, zw - клік uniform float iTime; // час роботи шейдера (у секундах) ``` Досить розмов, подивимося на уніформи в дії. У наведеному нижче коді ми використовуємо `u_time` — кількість секунд із моменту запуску шейдера — разом із синус-функцією, щоб анімувати зміни у кількості червоного кольору на екрані. Як ви бачите, GLSL має ще багато сюрпризів. GPU має апаратне прискорення для кутових, тригонометричних та експоненціальних функцій. Ось деякі з цих функцій: [`sin()`](../glossary/?lan=ua&search=sin), [`cos()`](../glossary/?lan=ua&search=cos), [`tan()`](../glossary/?lan=ua&search=tan), [`asin()`](../glossary/?lan=ua&search=asin), [`acos()`](../glossary/?lan=ua&search=acos), [`atan()`](../glossary/?lan=ua&search=atan), [`pow()`](../glossary/?lan=ua&search=pow), [`exp()`](../glossary/?lan=ua&search=exp), [`log()`](../glossary/?lan=ua&search=log), [`sqrt()`](../glossary/?lan=ua&search=sqrt), [`abs()`](../glossary/?lan=ua&search=abs), [`sign()`](../glossary/?lan=ua&search=sign), [`floor()`](../glossary/?lan=ua&search=floor), [`ceil()`](../glossary/?lan=ua&search=ceil), [`fract()`](../glossary/?lan=ua&search=fract), [`mod()`](../glossary/?lan=ua&search=mod), [`min()`](../glossary/?lan=ua&search=min), [`max()`](../glossary/?search=max) and [`clamp()`](../glossary/?lan=ua&search=clamp). Настав час знову пограти з наведеним вище кодом. * Уповільнюйте частоту, щоб зміна кольору стала майже непомітною. * Пришвидшуйте, поки не побачите один колір без мерехтіння. * Пограйтеся із RGB-каналами та різними частотами для них, щоб отримати якусь цікаву поведінку. ## gl_FragCoord Подібно до того як GLSL, за замовчуванням, дає нам вихідні дані `vec4 gl_FragColor`, він також дає нам вхідні дані за замовчуванням, `vec4 gl_FragCoord`, що містять екранні координати *пікселя* або *фрагменту екрана*, з якими працює активний потік. За допомогою `vec4 gl_FragCoord` ми знаємо, де саме працює поточний потік всередині зображення. У цьому випадку ми не називаємо його `uniform`, тому що він буде відрізнятися від потоку до потоку, натомість `gl_FragCoord` називається *varying* (змінливим). У наведеному вище коді ми *нормалізуємо* координати фрагмента, розділивши їх на роздільну здатність зображення. У результаті цього отримані значення будуть змінюватися у діапазоні від `0.0` до `1.0`, що полегшує зіставлення X і Y значень з ЧЕРВОНИМ і ЗЕЛЕНИМ каналами. У світі шейдерів ми не маємо зручних інструментів для зневаджування програми, тому інколи доводиться призначати змінним якісь яскраві кольори, щоб за їх допомогою спробувати дістати потрібну інформацію. Ви виявите, що кодування на GLSL іноді дуже схоже на розміщення корабля у пляшку. Це однаково важко, красиво і захопливо. Тепер настав час перевірити наше розуміння цього коду. * Чи можете ви сказати, де знаходиться координата `(0.0, 0.0)` на нашому полотні? * А як щодо `(1.0, 0.0)`, `(0.0, 1.0)`, `(0.5, 0.5)` і `(1.0, 1.0)`? * Чи можете ви зрозуміти, як використати змінну `u_mouse`, знаючи, що її значення вказані в пікселях і НЕ нормалізовані? Чи зможете за її допомогою і руху курсору змінювати кольори? * Чи можете ви вигадати цікавий спосіб для зміни кольорів за допомогою координат `u_time` і `u_mouse`? Після виконання цих вправ ви можете поставити собі питання: де ще можна спробувати можливості шейдерів. У наступному розділі ми розглянемо, як створити власні шейдерні інструменти у three.js, Processing і openFrameworks. --- ### 03/README Vi (03/README-vi.md) ## Uniform Tới giờ ta đã biết cách mà GPU xử lý 1 số lượng lớn các thread song song, mỗi cái chịu trách nhiệm đổi màu cho 1 vùng trong cả màn hình. Dù mỗi thread không biết các thread khác đang làm gì, ta vẫn phải gửi dữ liệu từ CPU tới cho từng thread. Kiến trúc của GPU yêu cầu dữ liệu gửi cho các thread phải giống nhau (*uniform*) và không được thay đổi (*read only*). Các dữ liệu đầu vào này được gọi là `uniform` và hỗ trợ hầu hết các kiểu dữ liệu cơ bản như: `float`, `vec2`, `vec3`, `vec4`, `mat2`, `mat3`, `mat4`, `sampler2D` và `samplerCube`. Uniform được định nghĩa cùng với kiểu dữ liệu tương ứng, ở phần trên cùng của code shader, ngay sau khi quy định độ chính xác của các số thực. ```glsl #ifdef GL_ES precision mediump float; #endif uniform vec2 u_resolution; // Kích thước canvas (Rộng, cao) uniform vec2 u_mouse; // Vị trí con trỏ chuột trong canvas uniform float u_time; // Thời gian hiện tại tính từ lúc load xong shader ``` Bạn có thể hình dung uniform giống như các cầu nối giữa CPU và GPU. Tên của các biến có thể thay đổi theo từng chương trình nhưng trong quyển sách này tôi sẽ luôn dùng: `u_time` (thời gian hiện tại tính từ lúc load xong shader), `u_resolution` (kích thước vùng mà shader sẽ vẽ) và `u_mouse` (vị trí con trỏ chuột trong vùng được vẽ). Tôi dùng quy tắc thêm tiền tố `u_` vào trước các tên biến để đánh dấu các uniform. Ví dụ code trên [ShaderToy.com](https://www.shadertoy.com/) cũng sử dụng quy tắc riêng: ```glsl uniform vec3 iResolution; // Kích thước canvas uniform vec4 iMouse; // Vị trí con trỏ chuột trong canvas (xy=vị trí hiện tại, zw=vị trí click) uniform float iTime; // Thời gian hiện tại tính từ lúc load xong shader ``` Hãy xem thực tế uniform làm việc như thế nào. Ở đoạn code dưới đây tôi dùng `u_time` - thời gian hiện tại tính bằng giây, kể từ lúc load xong shader - với hàm sine để kiểm soát sắc đỏ trong canvas theo thời gian. GLSL có nhiều điều thú vị. Phần cứng của GPU giúp tăng tốc các hàm lượng giác và luỹ thừa: [`sin()`](../glossary/?lan=vi&search=sin), [`cos()`](../glossary/?lan=vi&search=cos), [`tan()`](../glossary/?lan=vi&search=tan), [`asin()`](../glossary/?lan=vi&search=asin), [`acos()`](../glossary/?lan=vi&search=acos), [`atan()`](../glossary/?lan=vi&search=atan), [`pow()`](../glossary/?lan=vi&search=pow), [`exp()`](../glossary/?lan=vi&search=exp), [`log()`](../glossary/?lan=vi&search=log), [`sqrt()`](../glossary/?lan=vi&search=sqrt), [`abs()`](../glossary/?lan=vi&search=abs), [`sign()`](../glossary/?lan=vi&search=sign), [`floor()`](../glossary/?lan=vi&search=floor), [`ceil()`](../glossary/?lan=vi&search=ceil), [`fract()`](../glossary/?lan=vi&search=fract), [`mod()`](../glossary/?lan=vi&search=mod), [`min()`](../glossary/?lan=vi&search=min), [`max()`](../glossary/?lan=vi&search=max) và [`clamp()`](../glossary/?lan=vi&search=clamp). Chúng rất nhanh. Cùng sửa đoạn code trên nào. * Hãy giảm tần suất đổi màu xuống sao cho việc đổi màu khó có thể nhận ra được * Hãy tăng tần suất đổi màu tới khi bạn chỉ nhìn thấy 1 màu duy nhất nhấp nháy liên tục * Hãy thay đổi mỗi kênh RGB với một tần suất khác nhau, bạn sẽ thấy các kết quả rất bất ngờ ## gl_FragCoord Tương tự như biến lưu trữ giá trị output trong GLSL, `vec4 gl_FragColor`, ta cũng có biến lưu trữ giá trị input, `vec4 gl_FragCoord`, là toạ độ của điểm ảnh (*pixel*) hoặc một vùng điểm ảnh (*screen fragment*) mà thread này đang xử lý. Ta biết rằng giá trị của `vec4 gl_FragCoord` khác nhau giữa từng thread, nên nó không phải là uniform. Ở đoạn code trên ta chuẩn hoá *(normalize)* toạ độ của từng fragment bằng cách chia nó cho kích thước của canvas. Bằng cách này, giá trị nhận được sẽ luôn nằm trong khoảng từ `0.0` tới `1.0`, và sẽ khiến việc ánh xạ sang sắc độ RED và GREEN dễ hơn. Trong shader ta không có nhiều cách để debug lắm bên cạnh việc thử dùng một màu rất chói để kiểm tra. Code shader thi thoảng cũng giống như dựng một chiếc thuyền bên trong một cái chai, rất khó nhưng đẹp và khiến ta thoả mãn. Giờ là lúc để thử xem ta hiểu code tới đâu. * Bạn có biết toạ độ `(0.0, 0.0)` nằm ở đâu trên canvas không? * Vậy còn `(1.0, 0.0)`, `(0.0, 1.0)`, `(0.5, 0.5)` và `(1.0, 1.0)`? * Bạn có thể sử dụng `u_mouse` để lấy giá trị điểm ảnh CHƯA chuẩn hoá *(normalize)*? Bạn có thể dùng nó để thay đổi màu khi di chuyển con trỏ chuột? * Bạn có tưởng tượng được cách nào để tạo ra các mảng màu hay ho bằng cách sử dụng `u_time` và `u_mouse` không? Sau khi làm các bài tập này, bạn có thể sẽ thắc mắc mình có thể sử dụng năng-lực-shader mới này của mình ở đâu nữa. Ở chương tới ta sẽ xem làm thế nào để tạo shader bằng three.js, Processing, và openFrameworks. --- ### 03/SUMMARY Pt (03/SUMMARY-pt.md) Aprenda como usar variáveis Uniform. Variáveis uniform, ou simplesmente *uniformes* são as variáveis que carregam informação acessível igualmente de todas as threads do seu shader. O [editor GSLS](http://editor.thebookofshaders.com/) tem três uniformes setados para você. ```glsl uniform vec2 u_resolution; // Tamanho do canvas (largura,altura) uniform vec2 u_mouse; // posição do mouse em pixels da tela uniform float u_time; // Tempo em segundos desde carregamento ``` --- ### 03/SUMMARY (03/SUMMARY.md) Learn how to use Uniform variables. Uniform variables, or simply *uniforms* are the variables that carry information equally accessible from all of the threads of your shader. The [GSLS editor](http://editor.thebookofshaders.com/) has three uniforms set up for you. ```glsl 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 ``` --- ### 04/README (04/README.md) ## Running your shader As part of the construction of this book and my art practice I made an ecosystem of tools to create, display, share and curate shaders. These tools work consistently across Linux, MacOS, Windows and [Raspberry Pi](https://www.raspberrypi.org/) and browsers without the need of changing your code. ## Running your shaders on the browser **Display**: all live examples in this book are displayed using [glslCanvas](https://github.com/patriciogonzalezvivo/glslCanvas) which makes the process of running standalone shader incredibly easy. ```html ``` As you can see, it just needs a `canvas` element with `class="glslCanvas"` and the url to your shader in the `data-fragment-url`. Learn more about it [here](https://github.com/patriciogonzalezvivo/glslCanvas). If you are like me, you will probably want to run shaders directly from the console, in that case you should check out [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer). This application allows you to incorporate shaders into your `bash` scripts or unix pipelines and use it in a similar way to [ImageMagick](http://www.imagemagick.org/script/index.php). Also [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer) is a great way to compile shaders on your [Raspberry Pi](https://www.raspberrypi.org/), which is the reason [openFrame.io](http://openframe.io/) uses it to display shader artwork. Learn more about this application [here](https://github.com/patriciogonzalezvivo/glslViewer). ```bash glslViewer yourShader.frag yourInputImage.png —w 500 -h 500 -E screenshot,yourOutputImage.png ``` **Create**: in order to illuminate the experience of coding shaders I made an online editor called [glslEditor](https://github.com/patriciogonzalezvivo/glslEditor). This editor is embedded on the book's live examples, it brings a series of handy widgets to make more tangible the abstract experience of working with glsl code. You can also run it as a standalone web application from [editor.thebookofshaders.com/](http://editor.thebookofshaders.com/). Learn more about it [here](https://github.com/patriciogonzalezvivo/glslEditor). If you prefer to work offline using [SublimeText](https://www.sublimetext.com/) you can install this [package for glslViewer](https://packagecontrol.io/packages/glslViewer). Learn more about it [here](https://github.com/patriciogonzalezvivo/sublime-glslViewer). **Share**: the online editor ([editor.thebookofshaders.com/](http://editor.thebookofshaders.com/)) can share your shaders! Both the embedded and standalone version have an export button where you can get an unique URL's to your shader. Also it has the ability to export directly to an [openFrame.io](http://openframe.io/). **Curate**: Sharing your code is the beginning of you sharing your shader as artwork! Beside the option to export to [openFrame.io](http://openframe.io/) I made a tool to curate your shaders into a gallery that can be embedded on any site, it’s name is [glslGallery](https://github.com/patriciogonzalezvivo/glslGallery). Learn more [here](https://github.com/patriciogonzalezvivo/glslGallery). ## Running your shaders on your favorite framework In case you already have experience programming in a framework like: [Processing](https://processing.org/), [Three.js](http://threejs.org/), [OpenFrameworks](http://openframeworks.cc/) or [SFML](https://www.sfml-dev.org/), you're probably excited to try shaders on these platforms you feel comfortable with. The following are examples of how to set shaders in some popular frameworks with the same uniforms that we are going to use throughout this book. (In the [GitHub repository for this chapter](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/04), you'll find the full source code for these three frameworks.) ### In **Three.js** The brilliant and very humble Ricardo Cabello (aka [MrDoob](https://twitter.com/mrdoob) ) has been developing along with other [contributors](https://github.com/mrdoob/three.js/graphs/contributors) probably one of the most famous frameworks for WebGL, called [Three.js](http://threejs.org/). You will find a lot of examples, tutorials and books that teach you how to use this JavaScript library to make cool 3D graphics. Below is an example of the HTML and JS you need to get started with shaders in three.js. Pay attention to the `id="fragmentShader"` script, here is where you can copy the shaders you find in this book. ``` /* Detailed source-code truncated for AI context efficiency. */ ``` ### In **Processing** Started by [Ben Fry](http://benfry.com/) and [Casey Reas](http://reas.com/) in 2001, [Processing](https://processing.org/) is an extraordinarily simple and powerful environment in which to take your first steps in code (it was for me at least). [Andres Colubri](https://codeanticode.wordpress.com/) has made important updates to the OpenGL and video in Processing, making it easier than ever to use and play with GLSL shaders in this friendly environment. Processing will search for the shader named `"shader.frag"` in the `data` folder of the sketch. Be sure to copy the examples you find here into that folder and rename the 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); } ``` In order for the shader to work on versions previous to 2.1, you need to add the following line at the beginning of your shader: `#define PROCESSING_COLOR_SHADER`. So that it looks like this: ```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); } ``` For more information about shaders in Processing check out this [tutorial](https://processing.org/tutorials/pshader/). ### In **openFrameworks** Everybody has a place where they feel comfortable, in my case, that’s still the [openFrameworks community](http://openframeworks.cc/). This C++ framework wraps around OpenGL and other open source C++ libraries. In many ways it's very similar to Processing, but with the obvious complications of dealing with C++ compilers. In the same way as Processing, openFrameworks will search for your shader files in the data folder, so don’t forget to copy the `.frag` files you want to use and change the name when you load them. ```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(); } ``` If you want to use the full set of uniforms contain on the specs of GlslViewer and GlslCanvas in a more simple way on OpenFrameworks I recommend using the [ofxShader](https://github.com/patriciogonzalezvivo/ofxshader) addon which will also have support for multiple buffers, material shaders, hotreload and automatic conversion for OpenGL ES in the Raspberry Pi. And your code will be as simple as doing ```cpp //-------------------------------------------------------------- void ofApp::setup(){ ofDisableArbTex(); sandbox.allocate(ofGetWidth(), ofGetHeight()); sandbox.load("grayscott.frag"); } //-------------------------------------------------------------- void ofApp::draw(){ sandbox.render(); sandbox.draw(0, 0); } ``` For more information about shaders in openFrameworks go to this [excellent tutorial](http://openframeworks.cc/ofBook/chapters/shaders.html) made by [Joshua Noble](http://thefactoryfactory.com/). --- ### 04/README Ch (04/README-ch.md) ## 运行你的 shader 我制作了一套工具生态系统,用于创建、显示、分享与使用 shader,以此作为本书结构及我艺术实践的一部分。这些工具是跨平台的,无需更改代码就能在 Linux、MacOS、Windows、[树莓派](https://www.raspberrypi.org/) 和浏览器上表现一致。 ## 在浏览器上运行你的 shader **显示**: 本书中所有实例都可以用 [glslCanvas](https://github.com/patriciogonzalezvivo/glslCanvas) 来显示,这样一来,运行独立的 shader 程序就变得非常简单. ```html ``` 如你所见, 只需要创建一个类名为 `class="glslCanvas"` 的 `canvas` 元素,并将你的 shader 链接放在 `data-fragment-url` 中. 在 [这里](https://github.com/patriciogonzalezvivo/glslCanvas) 可以了解更多. 你可能会像我一样想要从命令行直接运行 shader,那你需要看看 [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer)。这个应用程序可以将 shader 放到 `bash` 脚本或 unix 管道里,并且像 [ImageMagick](http://www.imagemagick.org/script/index.php) 一样使用它。此外,[glslViewer](https://github.com/patriciogonzalezvivo/glslViewer) 也是一个在 [树莓派](https://www.raspberrypi.org/) 上编译 shader 的好办法, 这就是 [openFrame.io](http://openframe.io/) 用它来展示shader 作品的原因。在 [这里](https://github.com/patriciogonzalezvivo/glslViewer) 可以了解该应用程序的更多信息。 ```bash glslViewer yourShader.frag yourInputImage.png —w 500 -h 500 -s 1 -o yourOutputImage.png ``` **创建**: 为了介绍 shader 编码的经验,我制作了在线编辑器 [glslEditor](https://github.com/patriciogonzalezvivo/glslEditor)。本书的实例中内嵌了这个编辑器。这个编辑器有很多好用的小组件,使编写 glsl 代码的体验更加直观。你也可以在 [editor.thebookofshaders.com/](http://editor.thebookofshaders.com/) 上将其作为独立的 Web 应用运行。在 [这里](https://github.com/patriciogonzalezvivo/glslEditor) 了解更多。 如果你更喜欢用 [SublimeText](https://www.sublimetext.com/) 离线编程,你可以安装 [package for glslViewer](https://packagecontrol.io/packages/glslViewer)。 在 [这里](https://github.com/patriciogonzalezvivo/sublime-glslViewer) 了解更多. **分享**: 在线编辑器 ([editor.thebookofshaders.com/](http://editor.thebookofshaders.com/)) 可以分享你的 shader!内嵌版和独立版都有导出按钮,你可以通过这个按钮获得 shader 的唯一链接。编辑器也可以直接将 shader 导出到 [openFrame.io](http://openframe.io/)。 **使用**: 分享代码只是分享 shader 作品的开始!除了导出到 [openFrame.io](http://openframe.io/),我还制作了使用 shader 的工具 [glslGallery](https://github.com/patriciogonzalezvivo/glslGallery),它可以将 shader 放入画廊中,以便嵌入到任何网站. 在 [这里](https://github.com/patriciogonzalezvivo/glslGallery) 了解更多. ## 在你喜欢的框架上运行你的 shader 如果你使用过这些这些框架: [Processing](https://processing.org/), [Three.js](http://threejs.org/), [OpenFrameworks](http://openframeworks.cc/) 或 [SFML](https://www.sfml-dev.org/), 你可能更愿意在你觉得舒服的这些平台上编写 shader。下面将会介绍在这些框架中,用本书范式编写 shader 的方法。 (在 [本章节的 GitHub 仓库中](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/04), 你能找到这三个框架的完整源码.) ### **Three.js** 为人谦逊而非常有才华的 Ricardo Cabello (也就是 [MrDoob](https://twitter.com/mrdoob) )和许多[贡献者](https://github.com/mrdoob/three.js/graphs/contributors) 一起搭了可能是 WebGL 最知名的平台,[Three.js](http://threejs.org/)。你可以找到无数程序示例,教程,书籍,教你如何用这个 JavaScript 库做出酷炫的 3D 图像。 下面是一个你需要的例子,教你用 three.js 玩转 shader。注意 ```id="fragmentShader"```脚本,你要把下面的代码拷到里面。 下面是一个 HTML 和 JS 的示例, ``` /* Detailed source-code truncated for AI context efficiency. */ ``` ### **Processing** 2001年由[Ben Fry](http://benfry.com/) 和 [Casey Reas](http://reas.com/) 创建,[Processing](https://processing.org/)是一个极其简约而强大的环境,非常适合初尝代码的人(至少对于我来是这样)。关于 OpenGL 和视频,[Andres Colubri](https://codeanticode.wordpress.com/)为 Processing 平台做了很重要的更新,使得环境非常友好,玩 GLSL shader 比起以前大大容易了。Processing 会在你的 sketch 的 ```data``` 文件夹搜索名为 ```"shader.frag"``` 的文件。记得把这里的示例代码拷到你的文件夹里然后重命名 shader。 ```processing 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); } ``` 在 2.1 版之前的版本运行 shader,你需要在你的 shader 文件开头添加以下代码: ```#define PROCESSING_COLOR_SHADER```。所以它应该看起来是这样: ```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); } ``` 更多 Processing 的 shader 教程戳 [tutorial](https://processing.org/tutorials/pshader/)。 ### **openFrameworks** 每个人都有自己的舒适区,我的则是[openFrameworks community](http://openframeworks.cc/)。这个 C++ 框架打包了 OpenGL 和其他开源 C++ 库。在很多方面它和 Processing 非常像,但是明显和 C++ 编译器打交道一定比较麻烦。和 Processing 很像地,openFrameworks 会在你的 data 文件夹里寻找 shader 文件,所以不要忘记把你的后缀 ```.frag``` 的文件拷进去,加载的时候记得改名。 ```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(); } ``` 关于 shader 在 openFrameworks 的更多信息请参考这篇[excellent tutorial](http://openframeworks.cc/ofBook/chapters/shaders.html),作者是 [Joshua Noble](http://thefactoryfactory.com/)。 --- ### 04/README De (04/README-de.md) ## Ausführung Deiner Shader Beim Schreiben dieses Buches und im Rahmen meiner künstlerischen Tätigkeit habe ich eine Sammlung von Tools entwickelt, mit deren Hilfe man Shader programmieren, anzeigen, teilen und kuratieren kann. Dieses Tools laufen auf Linux Desktops, Rechnern mit MacOS, dem [Raspberry Pi](https://www.raspberrypi.org/) und auf Internet-Browsern. Sie sorgen dafür, dass Du Deine Shader dort nutzen kannst, ohne etwas an deren Programmcode verändern zu müssen. **Anzeige**: Alle Live-Beispiele in diesem Buch werden mit [glslCanvas](https://github.com/patriciogonzalezvivo/glslCanvas) angezeigt. Dieses Tool macht es unglaublich einfach, Shader ohne weitere Umstände im Internet-Browser auszuführen. ```html ``` Wie Du oben siehst, benötigt man lediglich ein ```canvas``` HTML-Element mit der Klassenzuweisung ```class="glslCanvas"``` und eine URL als Verweis auf Deine Shader-Datei im Attribut ```data-fragment-url```. Mehr darüber kannst Du [hier](https://github.com/patriciogonzalezvivo/glslCanvas) erfahren. Vielleicht geht es Dir wie mir, und Du möchtest Deine Shader direkt aus der Kommandozeile starten. In diesem Fall solltest Du Dir einmal den [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer) anschauen. Diese Anwendung ermöglicht es Dir, Shader aus ```bash```-Skripten oder aus der Unix-Pipeline heraus zu starten, ganz ähnlich wie dies mit [ImageMagick](http://www.imagemagick.org/script/index.php) möglich ist. Außerdem bietet der [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer) eine großartige Möglichkeit, Shader auf Deinem [Raspberry Pi](https://www.raspberrypi.org/) zu kompilieren. Das ist auch der Grund, warum das Projekt [openFrame.io](http://openframe.io/) dieses Tool für die Präsentation von Computerkunst nutzt. Mehr über diese Anwendung kannst Du [hier](https://github.com/patriciogonzalezvivo/glslViewer) erfahren. ```bash glslViewer deinShader.frag deineEingabeGrafik.png -w 500 -h 500 -s 1 -o deineAusgabeGrafik.png ``` **Entwickeln**: Um die Entwicklung von Shadern im Internet-Browser zu ermöglichen, habe ich einen Online-Editor mit dem Namen [glslEditor](https://github.com/patriciogonzalezvivo/glslEditor) entwickelt. Dieser Editor kommt bei den Live-Beispielen in diesem Buch zum Einsatz. Er bringt eine Reihe praktischer Widgets mit, die Dich beim Experimentieren mit dem Shader-Code unterstützen. Du kannst diesen Editor auch als eigenständige Web-Anwendung über die URL [editor.thebookofshaders.com/](http://editor.thebookofshaders.com/) ausführen lassen. Mehr über diesen Editor erfährst Du [hier](https://github.com/patriciogonzalezvivo/glslEditor). Wenn Du lieber offline statt online mit [SublimeText](https://www.sublimetext.com/) arbeitest, kannst Du dieses [Paket für den glslViewer](https://packagecontrol.io/packages/glslViewer) installieren. Mehr darüber erfährst Du [hier](https://github.com/patriciogonzalezvivo/sublime-glslViewer). **Teilen**: Du kannst Deine Shader direkt aus dem Online-Editor ([editor.thebookofshaders.com/](http://editor.thebookofshaders.com/)) heraus mit anderen teilen. Sowohl die eingebettete als auch die eigenständige Variante des Editors verfügen über eine *Export*-Schaltfläche. Sie liefert Dir eine einzigartige URL als Referenz auf Deinen Shader. Diese URL kannst Du dann an andere weitergeben. Außerdem bietet der Editor die Möglichkeit, Deine Shader zur Veröffentlichung direkt an das Projekt [openFrame.io](http://openframe.io/) zu senden. **Kuratieren**: Deinen Shader-Code mit anderen zu teilen ist nur der Anfang. Du kannst Deine Shader auch als Werke der Computerkunst veröffentlichen. Jenseits der Weitergabe an das Projekt [openFrame.io](http://openframe.io/), habe ich ein Tool entwickelt, mit dem man Shader-Programme in eine Galerie innerhalb einer Webseite einbetten kann. Der Name dieses Tools lautet passenderweise [glslGallery](https://github.com/patriciogonzalezvivo/glslGallery). Mehr darüber erfährst Du [hier](https://github.com/patriciogonzalezvivo/glslGallery). ## Ausführen von Shadern in Deiner bevorzugten Umgebung Falls Du bereits Erfahrung mit der Programmierung in einer Umgebung wie [Processing](https://processing.org/), [three.js](http://threejs.org/), [OpenFrameworks](http://openframeworks.cc/) oder [SFML](https://www.sfml-dev.org/) gesammelt hast, möchtest Du Deine Shader vielleicht in dieser Umgebung ausführen lassen. Die folgenden Codebeispiele zeigen Dir, wie man Shader unter Verwendung der gleichen Uniforms, die wir in diesem Buch verwenden, in diesen Umgebungen ausführen kann. (In der [GitHub-Ablage dieses Kapitels](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/04) findest Du den gesamten Sourcecode für die Einbindung von Shadern unter den drei genannten Umgebungen.) ### Ausführung unter **three.js** Der brillante und äußerst bescheidene Ricardo Cabello (aka [MrDoob](https://twitter.com/mrdoob) ) hat zusammen mit [Gleichgesinnten](https://github.com/mrdoob/three.js/graphs/contributors) eines der wahrscheinlich populärsten Frameworks für WebGL mit dem Namen [three.js](http://threejs.org/) entwickelt. Du findest dort viele Beispiele, Tutorials und Bücher, die Dir zeigen, wie Du diese JavaScript-Bibliothek zur Erstellung cooler 3D-Grafiken nutzen kannst. Hier folgt ein Beispiel für den HTML- und JS-Code, den Du für Deine ersten Experimente mit Shadern unter *three.js* benötigst. Bitte beachte das Script unter dem HTML-Tag ```id="fragmentShader"```. Dort kannst Du Deine Shader aus dem vorliegenden Buch einfügen. ``` /* Detailed source-code truncated for AI context efficiency. */ ``` ### In **Processing** Ursprünglich im Jahre 2001 von [Ben Fry](http://benfry.com/) und [Casey Reas](http://reas.com/) entwickelt, verkörpert [Processing](https://processing.org/) eine unglaublich einfache und gleichzeitig leistungsfähige Umgebung für Deinen Einstieg in das Thema „Programmierung“. (Auch ich habe so angefangen.) [Andres Colubri](https://codeanticode.wordpress.com/) hat wichtige Erweiterungen für die Einbeziehung von openGL und Videofunktionen in Processing entwickelt. Sie machen es ganz einfach, in dieser Umgebung mit GLSL-Shadern zu arbeiten. Processing sucht dazu einfach nach einem Shader mit dem Namen ```shader.frag``` in dem Unterverzeichnis ```data``` Deines Zeichenblocks („sketch“). Stelle einfach sicher, dass Du die Beispiele aus dem vorliegenden Buch unter diesem Dateinamen in dem genannten Verzeichnis ablegst. ```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); } ``` Damit Dein Shader auch unter Versionen von Processing kleiner 2.1 läuft, musst Du lediglich die folgende Programmzeile an den Anfang Deines Shaders stellen: ```#define PROCESSING_COLOR_SHADER```. Das sieht dann so aus: ```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); } ``` Mehr Informationen über den Einsatz von Shadern in Processing findest Du auch in diesem [Tutorial](https://processing.org/tutorials/pshader/). ### In **openFrameworks** Jeder hat einen Platz, an dem er oder sie sich besonders wohl fühlt. Bei mir ist das die [openFrameworks Gemeinschaft](http://openframeworks.cc/). Diese C++-Umgebung ermöglicht die bequeme Einbindung von OpenGL und weiteren Open Source C++-Bibliotheken. In vielerlei Hinsicht ähnelt sie der Arbeit mit Processing, nur dass man es hier mit C++ und C++-Compilern zu tun hat. Genau wie Processing sucht *openFrameworks* nach Deinen Shader-Dateien im ```DATA```-Unterverzeichnis. Deshalb vergiss nicht, Deine ```.frag```-Dateien dorthin zu kopieren und den Dateinamen entsprechend anzupassen, wenn Du diese Dateien ausführen willst. ```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(); } ``` Weitere Informationen über die Verwendung von Shadern in *openFrameworks* findest Du in diesem [exzellenten Tutorial](http://openframeworks.cc/ofBook/chapters/shaders.html), das von [Joshua Noble](http://thefactoryfactory.com/) verfasst wurde. --- ### 04/README Es (04/README-es.md) ## Ejecutando tu shader En este punto seguro estás entusiasmado con poder probar shaders en las plataformas en las que te sientes cómodo. En los siguientes ejemplos veremos como agregarlos en algunos frameworks populares con las mismas uniforms con las que estamos trabajando en este libro. (En el [repositorio de GitHub de este capítulo](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/04) encontrarás el código completo de estos ejemplos.) **Nota 1**: En caso de que no quieras utilizar los shaders en los siguientes frameworks pero quieras hacerlo fuera del navegador, puedes descargar y compilar [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer). Este programa corre en MacOS y en Raspberry Pi, permite ejecutar directamente los ejemplos desde la terminal. **Nota 2**: Si no quieres usar WebGl con tus shaders y no te interesan los frameworks siguientes, puedes usar [glslCanvas](https://github.com/patriciogonzalezvivo/glslCanvas). Esta herramienta fue diseñada para este libro, pero se volvió tan útil que he terminado usándola en muchos proyectos. ### En **Three.js** El brillante y humilde Ricardo Cabello (también conocido como [MrDoob](https://twitter.com/mrdoob)) ha estado desarrollando junto con otros [contribuidores](https://github.com/mrdoob/three.js/graphs/contributors) probablemente el framework más conocido de WebGL, llamado [Three.js](http://threejs.org/). Encontrarás muchos ejemplos, libros y tutoriales para aprender a hacer cosas geniales en 3D con JavaScript. Aqui abajo hay un ejemplo del HTML y JS necesario para poder empezar a utilizar shaders con three.js. Presta atención al script```id="fragmentShader"```, aquí es donde puedes copiar los ejemplos de este libro. ``` /* Detailed source-code truncated for AI context efficiency. */ ``` ### En **Processing** Iniciado por [Ben Fry](http://benfry.com/) y [Casey Reas](http://reas.com/) en 2001, [Processing](https://processing.org/) es un extraordinario y poderoso entorno en el que se puede aprender los primeros pasos con el código (al menos así fue para mí). [Andrés Colubri](https://codeanticode.wordpress.com/) ha hecho importantes cambios a la parte de OpenGL y video, logrando que sea más fácil y amigable utilizar shaders GLSL. Processing buscará el archivo ```"shader.frag"``` en la carpeta ```data``` del sketch. En ese archivo debes poner los ejemplos que encuentres en este libro. ```processing 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); } ``` Para hacer funcionar el shader en versiones previas a la 2.1, necesitas agregar la siguiente línea al comienzo de tu shader: ```#define PROCESSING_COLOR_SHADER```. Así es como quedaría: ```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); } ``` Para más información sobre shaders en processing puedes chequear este [tutorial](https://processing.org/tutorials/pshader/). ### En **openFrameworks** Todos tienen un lugar en el que se sienten más cómodos, en mi caso, todavía sigue siendo [openFrameworks](http://openframeworks.cc/). Este framework en C++ engloba openGL y otras librerías open source. En muchos puntos es muy parecido a Processing, pero con las complicaciones obvias de trabajar con los compiladores de C++. De la misma forma que Processing, openFrameworks buscará tus shaders en archivos de la carpeta data, no te olvides de copiar los archivos ```.frag``` que quieres usar y cambiar el nombre cuando los cargas. ```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(); } ``` Para más información sobre shaders en openFrameworks ve a este [excelente tutorial](http://openframeworks.cc/ofBook/chapters/shaders.html) creado por [Joshua Noble](http://thefactoryfactory.com/). --- ### 04/README Fr (04/README-fr.md) ## Exécuter vos shaders Pour les besoins de ce livre comme pour ma pratique artistique, j'ai créé un écosystème d'outils permettant de créer, d'afficher, de partager et d'organiser mes shaders. Ces outils fonctionnent de la même manière sur Linux Desktop, MacOS, [Raspberry Pi](https://www.raspberrypi.org/) et dans les navigateurs sans avoir besoin d'altérer le code. **Affichage** : tous les exemples de ce livre sont affichés dans la page grâce à [glslCanvas](https://github.com/patriciogonzalezvivo/glslCanvas) qui facilite grandement la fabrication et l'affichage de shaders autonomes. ```html ``` Comme vous pouvez le voir, il suffit de créer un élément `canvas` auquel on applique la classe `class="glslCanvas"` et de lui passer l'url du fragment shader dans `data-fragment-url`. Pour en savoir plus, [vous pouvez lire ceci](https://github.com/patriciogonzalezvivo/glslCanvas). Si vous êtes comme moi, vous aurez sans doute envie de lancer vos shaders en lignes de commandes, dans ce cas vous devriez jeter un oeil à [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer). Cette application permet d'incorporer un shader dans un script `bash` ou un pipeline Unix et de l'utiliser comme [ImageMagick](http://www.imagemagick.org/script/index.php). [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer) est aussi un bon moyen de compiler vos shaders sur un [Raspberry Pi](https://www.raspberrypi.org/) et c'est la raison pour laquelle [openFrame.io](http://openframe.io/) l'utilise pour afficher les oeuvres. Pour en savoir plus, [cliquez ici](https://github.com/patriciogonzalezvivo/glslViewer). ```bash glslViewer yourShader.frag yourInputImage.png —w 500 -h 500 -E screenshot,yourOutputImage.png ``` **Création** : pour améliorer l'expérience de programmation des shaders, j'ai créé un éditeur disponible ici : [glslEditor](https://github.com/patriciogonzalezvivo/glslEditor). L'éditeur est embarqué dans les exemples de ce livre, il met à disposition une série de petits widgets qui rendent l'édition du code GLSL plus tangible et moins abstraite. Vous pouvez également le lancer dans une fenêtre de navigateur à cette adresse [editor.thebookofshaders.com](http://editor.thebookofshaders.com/). Pour en savoir plus, [cliquez ici](https://github.com/patriciogonzalezvivo/glslEditor). Si vous préférez travailler avec [SublimeText](https://www.sublimetext.com/) vous pouvez installer le [package pour glslViewer](https://packagecontrol.io/packages/glslViewer). Pour en savoir plus, [cliquez ici](https://github.com/patriciogonzalezvivo/sublime-glslViewer). **Partager** : l'éditeur en ligne ([editor.thebookofshaders.com](http://editor.thebookofshaders.com/)) vous permet de partager vos shaders ! La version autonome comme la version en ligne de l'éditeur permettent de sauver votre shader en ligne et d'obtenir une url unique. Il est également possible d'exporter le shader pour qu'il fonctionne sur [openFrame.io](http://openframe.io/). **Organiser** : pouvoir partager ses shaders est une bonne chose, en plus de l'export vers [openFrame.io](http://openframe.io/), j'ai fait un outil permettant d'organiser vos shaders dans une galerie et d'intégrer cette galerie dans n'importe quel site. Il s'appelle [glslGallery](https://github.com/patriciogonzalezvivo/glslGallery), pour en savoir plus, [cliquez ici](https://github.com/patriciogonzalezvivo/glslGallery). ## Lancer vos shaders depuis votre plateforme favorite Si vous avez déjà programmé à l'aide de frameworks/APIs comme : [Processing](https://processing.org/), [Three.js](http://threejs.org/), [OpenFrameworks](http://openframeworks.cc/) ou [SFML](https://www.sfml-dev.org/), vous êtes sans doute impatients de tester vos shaders dans ces environnements. Les exemples suivants montrent comment intégrer les shaders sur ces plateformes en conservant les conventions de nommage que nous utiliserons dans ce livre. Vous retrouverez le code source complet sur le [dépôt GitHub de ce chapitre](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/04). ### Dans **Three.js** L'humble et brilliant Ricardo Cabello (alias [MrDoob](https://twitter.com/mrdoob)) a développé avec d'autres [contributeurs](https://github.com/mrdoob/three.js/graphs/contributors), l'un des frameworks WebGL les plus utilisés : [Three.js](http://threejs.org/). Il existe de nombreuses ressources pour apprendre à se servir de ce framework JavaScript. L'exemple ci-dessous, vous donne le code nécessaire pour utiliser un shader dans Three.js. Notez bien la balise de script appelée `id="fragmentShader"`, c'est là qu'il faudra coller le code que vous trouverez dans ce livre. ``` /* Detailed source-code truncated for AI context efficiency. */ ``` ### Dans **Processing** Initié par [Ben Fry](http://benfry.com/) et [Casey Reas](http://reas.com/) en 2001, [Processing](https://processing.org/) est un framework Java extraordinairement simple et très puissant qui vous aidera à faire vos premiers pas dans le code créatif (ça a été mon cas). [Andres Colubri](https://codeanticode.wordpress.com/) a contribué des mises à jour importantes concernant OpenGL et la gestion vidéo dans Processing. Ces ajouts simplifient énormément l'intégration des shaders GLSL dans l'environnement de développement. Processing va chercher le shader appelé `"shader.frag"` dans le dossier `data` du sketch. Assurez vous de copier les exemples du livre dans ce dossier et de les renommer correctement. ```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); } ``` Pour que le shader fonctionne dans les versions antérieures à Processing 2.1, il faut ajouter la ligne suivante : `#define PROCESSING_COLOR_SHADER` au début du shader. Il devrait ressembler à cela : ```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); } ``` Pour en savoir plus sur les shaders dans Processing, vous pouvez vous reporter à ce [tutoriel](https://processing.org/tutorials/pshader/). ### Dans **openFrameworks** Chacun a sa zone de confort, pour moi, cela reste [la communité openFrameworks](http://openframeworks.cc/). Ce framework C++ intègre OpenGL et d'autres librairies C++ open source. Il est très proche de Processing à ceci près que c'est un langage compilé et qu'il vaut donc mieux être habitué aux compilateurs C++. Comme Processing, openFrameworks va chercher le fichier du shader dans le dossier `data`, donc n'oubliez pas de créer un fichier `.frag`, d'y coller le contenu du shader et de spécifier le nom de ce fichier dans votre programme OF. ```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(); } ``` Pour plus d'informations sur les shader OpenFrameworks, vous pouvez vous reporter à cet [excellent tutoriel](http://openframeworks.cc/ofBook/chapters/shaders.html) écrit par [Joshua Noble](http://thefactoryfactory.com/). --- ### 04/README Gr (04/README-gr.md) ## Εκτελώντας τον shaders σας Σαν μέρος της σύνθεσης αυτού του βιβλίου και της εξάσκησής μου στην πράξη, έφτιαξα ένα οικοσύστημα από εργαλεία ώστε που μπορεί κανείς να δημιουργήσει, να εμφανίσει, να μοιραστεί και να επιμεληθεί τους shaders του. Τα εργαλεία αυτά λειτουργούν ομοιόμορφα σε Linux, MacOS, Windows και [Raspberry Pi](https://www.raspberrypi.org/) και browsers (φυλλομετρητές) χωρίς να χρειάζεται να αλλάξετε τον κώδικά σας. ## Εκτελώντας τους shaders σας σε browser **Εμφάνιση**: όλα τα διαδραστικά παραδείγματα σε αυτό το βιβλίο απεικονίζονται χρησιμοποιώντας [glslCanvas](https://github.com/patriciogonzalezvivo/glslCanvas) το οποίο κάνει τη διαδικασία του να τρέξουμε αυτόνομους shaders εξαιρετικά εύκολη. ```html ``` Όπως βλέπετε, χρειάζεται μόνο ένα `canvas` (HTML) element με `class="glslCanvas"` και το url του shader στο `data-fragment-url`. Μάθετε περισσότερα [εδώ](https://github.com/patriciogonzalezvivo/glslCanvas). Αν είστε σαν εμένα, πιθανόν θα θέλετε να τρέξετε shaders απευθείας από τη γραμμή εντολών, σε αυτή την περίπτωση προτείνω να δείτε το [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer). Αυτή η εφαρμογή σας επιτρέπει να ενσωματώσετε shaders στα scripts (σενάρια εκτέλεσης) σας φλοιού `bash` ή σε pipelines ("σωληνώσεις" εργαλείων) unix και να τα χρησιμοποιήσετε παρόμοια με το [ImageMagick](http://www.imagemagick.org/script/index.php). Επίσης, το [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer) είναι ένας πολύ καλός τρόπος να μεταγλωττίζετε shaders στο [Raspberry Pi](https://www.raspberrypi.org/) σας, ο οποίος είναι και ο λόγος που το [openFrame.io](http://openframe.io/) το χρησιμοποιεί για να εμφανίσει έργα τέχνης με shaders. Βρείτε περισσότερα για αυτή την εφαρμογή [εδώ](https://github.com/patriciogonzalezvivo/glslViewer). ```bash glslViewer yourShader.frag yourInputImage.png —w 500 -h 500 -E screenshot,yourOutputImage.png ``` **Δημιουργία**: προκειμένου να αναδείξω την εμπειρία του να γράφουμε shaders, έφτιαξα ένα online editor (πρόγραμμα επεξεργασίας κειμένου) με όνομα [glslEditor](https://github.com/patriciogonzalezvivo/glslEditor). Αυτός ο editor είναι ενσωματωμένος στα διαδραστικά παραδείγματα του βιβλίου. Μας δίνει ένα σύνολο από χρήσιμα widgets (εργαλεία διεπαφής) ώστε να κάνει πιο "απτή" την αφηρημένη εμπειρία του να δουλεύουμε με κώδικα glsl. Μπορείτε επίσης να τον τρέξετε σαν αυτόνομη εφαρμογή web από εδώ [editor.thebookofshaders.com/](http://editor.thebookofshaders.com/). Μάθετε περισσότερα σχετικά [εδώ](https://github.com/patriciogonzalezvivo/glslEditor). Αν προτιμάτε να δουλεύετε offline με το [SublimeText](https://www.sublimetext.com/) μπορείτε να εγκαταστήσετε αυτό το [πακέτο για τον glslViewer](https://packagecontrol.io/packages/glslViewer). Μάθετε περισσότερα [εδώ](https://github.com/patriciogonzalezvivo/sublime-glslViewer). **Διανομή**: με τον online editor ([editor.thebookofshaders.com/](http://editor.thebookofshaders.com/)) μπορείτε να μοιραστείτε τους shaders σας! Και η online και ενσωματωμένη και η ανεξάρτητη έκδοση έχουν ένα κουμπί export (εξαγωγή) με το οποίο μπορείτε να πάρετε ένα μοναδικό URL για τον shader σας. Επίσης έχει τη δυνατότητα να κάνει export απευθείας σε ένα [openFrame.io](http://openframe.io/). **Επιμέλεια**: Το να μοιραστείτε τον κώδικά σας είναι το πρώτο βήμα προς το να μοιραστείτε τον shader σας σαν έργο τέχνης! Εκτός από την επιλογή να κάνετε export σε [openFrame.io](http://openframe.io/) έφτιαξα ένα εργαλείο με το οποίο μπορείτε να οργανώσετε τους shaders σας σε μια έκθεση που μπορεί να ενσωματωθεί σε οποιοδήποτε site (ιστοχώρο), το όνομά του είναι [glslGallery](https://github.com/patriciogonzalezvivo/glslGallery). Δείτε περισσότερα [εδώ](https://github.com/patriciogonzalezvivo/glslGallery). ## Εκτελώντας τους shaders στο περιβάλλον της προτίμησής σας Αν έχετε ήδη εμπειρία προγραμματισμού σε κάποιο περιβάλλον όπως: [Processing](https://processing.org/), [Three.js](http://threejs.org/), [OpenFrameworks](http://openframeworks.cc/) ή [SFML](https://www.sfml-dev.org/), θα ανυπομονείτε πιθανόν να δοκιμάσετε shaders στις πλατφόρμες με τις οποίες αισθάνεστε οικεία. Τα παρακάτω είναι παραδείγματα για το πως να ορίσετε shaders σε κάποια γνωστά περιβάλλοντα με τα ίδια uniforms τα οποία θα χρησιμοποιήσουμε σε όλο το βιβλίο. (Στο [GitHub repository αυτού του κεφαλαίου](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/04), θα βρείτε ολόκληρο τον κώδικα γι' αυτά τα τρία περιβάλλοντα.) ### Σε **Three.js** Ο ευφυέστατος και πολύ σεμνός Ricardo Cabello (επίσης γνωστός και σαν [MrDoob](https://twitter.com/mrdoob) ) αναπτύσσει ανάμεσα σε άλλους [συνεργάτες](https://github.com/mrdoob/three.js/graphs/contributors) ένα πιθανόν από τα πιο γνωστά περιβάλλοντα για WebGL, που ονομάζεται [Three.js](http://threejs.org/). Θα βρείτε πολλά παραδείγματα, μαθήματα και βιβλία που διδάσκουν πως να χρησιμοποιήσετε αυτή τη βιβλιοθήκη JavaScript για να δημιουργήσετε φοβερά 3D γραφικά. Ακολουθεί ένα παράδειγμα για τις HTML και JS που που χρειάζεστε για να ξεκινήσετε με shaders σε three.js. Δώστε ιδιαίτερη σημασία στο script `id="fragmentShader"`, εδώ είναι που μπορείτε να αντιγράψετε τους shaders που βρίσκετε σε αυτό το βοβλίο. ``` /* Detailed source-code truncated for AI context efficiency. */ ``` ### Σε **Processing** Η [Processing](https://processing.org/) η οποία πρωτοξεκίνησε από τους [Ben Fry](http://benfry.com/) και [Casey Reas](http://reas.com/) το 2001, είναι ένα εξαιρετικά απλό και ισχυρό περιβάλλον για να κάνετε τα πρώτα σας βήματα σε κώδικα (σίγουρα ήταν για 'μένα). Ο [Andres Colubri](https://codeanticode.wordpress.com/) έχει κάνει σπουδαίες ενημερώσεις για την OpenGL και το video στην Processing, καθιστώντας το εκολότερο από ποτέ να παίξει κανείς με GLSL shaders στο φιλικό αυτό περιβάλλον. Η Processing ψάχνει για τον shader με όνομα `"shader.frag"` στον φάκελο `data` του sketch ("σκίτσο" - το project της Processing). Αντιγράψτε τα παραδείγματα που βρίσκετε εδώ σε αυτό τον φάκελο, και μετονομάστε το αρχείο. ```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); } ``` Προκειμένου να δουλέψει ο shader σε εκδόσεις παλιότερες της 2.1, πρέπει να προσθέσετε την παρακάτω γραμμή στην αρχή του shader: `#define PROCESSING_COLOR_SHADER`, έτσι ώστε να δείχνει ως εξής: ```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); } ``` Για περισσότερες πληροφορίες σχετικά με τους shaders σε Processing, δείτε αυτό το [μάθημα](https://processing.org/tutorials/pshader/). ### Σε **openFrameworks** Για τον καθένα υπάρχει ένα μέρος όπου νιώθει άνετα, στην περίπτωσή μου, εξακολουθεί να είναι η [κοινότητα openFrameworks](http://openframeworks.cc/). Αυτή η βιβλιοθήκη C++ παρέχει ένα πλαίσιο αφαίρεσης γύρω απο την OpenGL και άλλες βιβλιοθήκες C++ ανοιχτού κώδικα. Κατά πολλές έννοιες είναι παρόμοια με την Processing, αλλά με τις προφανείς επιπλοκές του να δουλεύει κανείς με μεταγλωττιστές C++. Όμοια με την Processing, η openFrameworks αναζητά τα αρχεία shader στο φάκελο data, οπότε μην παραλείψετε να αντιγράψετε τα αρχεία `.frag` που θέλετε να χρησιμοποιήσετε και να αλλάξετε το όνομά τους όταν τα φορτώνετε. ```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(); } ``` Αν θέλετε να χρησιμοποιήσετε το πλήρες σύνολο απο uniforms που υπάρχουν στον ορισμό των GlslViewer και GlslCanvas με απλούστερο τρόπο σε OpenFrameworks, συνιστώ το addon (πρόσθετο) [ofxShader](https://github.com/patriciogonzalezvivo/ofxshader) το οποίο επίσης υποστηρίζει πολλαπλούς buffers (μνήμη εικόνας), shaders υλικών, hotreload (άμεση επανεκτέλεση) και αυτόματη μετατροπή σε OpenGL ES για το Raspberry Pi. Και ο κώδικάς σας θα απαιτεί μόνο το παρακάτω: ```cpp //-------------------------------------------------------------- void ofApp::setup(){ ofDisableArbTex(); sandbox.allocate(ofGetWidth(), ofGetHeight()); sandbox.load("grayscott.frag"); } //-------------------------------------------------------------- void ofApp::draw(){ sandbox.render(); sandbox.draw(0, 0); } ``` Για περισσότερες πληροφορίες για τους shaders σε openFrameworks δείτε αυτό το [εξαιρετικό μάθημα](http://openframeworks.cc/ofBook/chapters/shaders.html) από τον [Joshua Noble](http://thefactoryfactory.com/). --- ### 04/README Id (04/README-id.md) ## 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 ``` 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 -E screenshot,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). 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). **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/). **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). ## Menjalankan Shader pada Framework Favoritmu Dalam kasus kamu mempunyai pengalaman dalam pemrograman pada framework seperti: [Processing](https://processing.org/), [Three.js](http://threejs.org/), [OpenFrameworks](http://openframeworks.cc/) or [SFML](https://www.sfml-dev.org/), 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. ``` /* Detailed source-code truncated for AI context efficiency. */ ``` ### 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/). --- ### 04/README It (04/README-it.md) ## Eseguite il vostro shader Nell'ambito della realizzazione di questo libro e della mia pratica artistica ho creato un ecosistema di strumenti per creare, visualizzare, condividere e curare gli shaders. Questo strumento funziona in modo coerente su Linux Desktop, MacOS, [Raspberry Pi](https://www.raspberrypi.org/) e browser, senza la necessità di dover cambiare il vostro codice. **Visualizzare**: tutti gli esempi di questo libro vengono visualizzati utilizzando [glslCanvas](https://github.com/patriciogonzalezvivo/glslCanvas) che rende il processo di esecuzione dello shader standalone incredibilmente facile. ```html ``` Come potete vedere, è solo necessario l'elemento ```canvas``` con l'attributo ```class="glslCanvas"``` e l'indirizzo verso il vostro shader nel ```data-fragment-url```. Scoprite di più a proposito [cliccando qui](https://github.com/patriciogonzalezvivo/glslCanvas). Se siete come me, probabilmente vorrete eseguire gli shader direttamente dalla console. In questo caso date un'occhiata a [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer). Questa applicazione consente d'incorporare gli shader nel vostro script ```bash``` o pipelines UNIX e d?utilizzarli in modo simile a [ImageMagick](http://www.imagemagick.org/script/index.php). Anche [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer) è un ottimo modo per compilare gli shader sul [Raspberry Pi](https://www.raspberrypi.org/), motivo per il quale [openFrame.io](http://openframe.io/) lo usa per visualizzare le opere d'arte di tipo shader. Potete trovare ulteriori informazioni su questa applicazione [cliccando qui](https://github.com/patriciogonzalezvivo/glslViewer). ```bash glslViewer yourShader.frag yourInputImage.png —w 500 -h 500 -E screenshot,yourOutputImage.png ``` **Creare**: per migliorare la programmazione degli shader, ho realizzato un editor online chiamato [glslEditor](https://github.com/patriciogonzalezvivo/glslEditor). Questo editor è integrato agli esempi del libro e mette a disposizione una serie di comodi widget per rendere più tangibile il codice astratto GLSL. È anche possibile eseguirlo come un'applicazione standalone web da [editor.thebookofshaders.com/](http://editor.thebookofshaders.com/). Scoprite di più a proposito [cliccando qui](https://github.com/patriciogonzalezvivo/glslEditor). Se si preferisce lavorare offline utilizzando [SublimeText](https://www.sublimetext.com/) è possibile installare questo [pacchetto per glslViewer](https://packagecontrol.io/packages/glslViewer). Scoprite di più [cliccando qui](https://github.com/patriciogonzalezvivo/sublime-glslViewer). **Condividere**: l'editor online ([editor.thebookofshaders.com/](http://editor.thebookofshaders.com/)) può condividere i tuoi shader! Sia la versione standalone che quella integrata hanno un pulsante per esportare con il quale è possibile ottenere un URL unico verso il vostro shader. Avete anche la possibilità d'esportare direttamente verso un [openFrame.io](http://openframe.io/). **Curare**: Condividere il vostro codice è la prima tappa per intendere il vostro shader come un'opera d'arte! Accanto alla possibilità di esportare verso [openFrame.io](http://openframe.io/) ho fatto uno strumento per curare i vostri shader in una galleria che può essere integrata su qualsiasi sito, il suo nome è [glslGallery](https://github.com/patriciogonzalezvivo/glslGallery). Per saperne di più [cliccando qui](https://github.com/patriciogonzalezvivo/glslGallery). ## Eseguire i vostri shader nel vostro framework preferito Nel caso in cui si dispone già di esperienze di programmazione in framework quali: [Processing](https://processing.org/), [Three.js](http://threejs.org/), [OpenFrameworks](http://openframeworks.cc/) o [SFML](https://www.sfml-dev.org/), probabilmente sarete ansiosi di provare gli shader sulle piattaforme su cui vi trovate bene. I seguenti sono esempi di come impostare gli shader in alcuni dei framework più popolari con le stesse uniforms che andremo ad utilizzare in questo libro. (Nella [repository GitHub per questo capitolo](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/04), troverete il codice sorgente completo per questi tre framework.) ### In **Three.js** Il brillante e molto umile Ricardo Cabello (aka [MrDoob](https://twitter.com/mrdoob)) ha sviluppato insieme ad altri [collaboratori](https://github.com/mrdoob/three.js/graphs/contributors), probabilmente uno dei più famosi framework per WebGL, chiamato [Three.js](http://threejs.org/). Troverete un sacco di esempi, tutorial e libri che vi insegneranno come utilizzare questa libreria JavaScript per fare grafica 3D. Di seguito è riportato un esempio di codice HTML e JS per iniziare con gli shader in three.js. Prestate attenzione allo script ```id="fragmentShader"```, qui è dove è possibile copiare gli shader che si trovano in questo libro. ``` /* Detailed source-code truncated for AI context efficiency. */ ``` ### In **Processing** Iniziato da [Ben Fry](http://benfry.com/) e [Casey Reas](http://reas.com/) nel 2001, [Processing](https://processing.org/) è un framework straordinariamente semplice e potente in cui muovere i primi passi nel codice (o almeno lo è stato per me). [Andres Colubri](https://codeanticode.wordpress.com/) ha fatto importanti aggiornamenti a openGL e la gestione video in Processing, rendendo più facile che mai usare e giocare con i GLSL shader. Processing cercherà lo shader chiamato ```"shader.frag"``` nella cartella ```data``` dello sketch. Assicuratevi di copiare gli esempi che trovate qui in quella cartella e rinominate il 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); } ``` Affinché lo shader lavori su versioni precedenti alla 2.1, è necessario aggiungere la seguente riga all'inizio del vostro Shader: ```#define PROCESSING_COLOR_SHADER```. In questo modo dovrebbe assomigliare a: ```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); } ``` Per ulteriori informazioni sugli shader in Processing controllate questo [tutorial](https://processing.org/tutorials/pshader/). ### In **openFrameworks** Ognuno ha un luogo in cui sentirsi a proprio agio e, nel mio caso, è ancora la [comunità di openFrameworks](http://openframeworks.cc/). Questo framework C++ integra OpenGL e altre librerie C++ open source. Per molti aspetti è molto simile a Processing, ma con le ovvie complicazioni dovute ai compilatori C++. Allo stesso modo di Processing, openFrameworks cercherà i tuoi file shader nella cartella dati, quindi non dimenticate di copiare i file ```.frag``` che si desiderano utilizzare e modificate il nome quando li si carica. ```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(); } ``` Per ulteriori informazioni sugli shader in openFrameworks consultate questo [ottimo tutorial](http://openframeworks.cc/ofBook/chapters/shaders.html) fatto da [Joshua Noble](http://thefactoryfactory.com/). --- ### 04/README Kr (04/README-kr.md) ## Running your shader 이 시점에서, 슬슬 익숙하던 플랫폼에 쉐이딩 기술을 써보고 싶을 것이다. 아래는 사람들이 가장 많이 쓰는 플랫폼들에서 쉐이더를, 또 전 챕터에서 본 uniform 형식을 그대로 쓸수 있는 부분이다. (In the [GitHub repository for this chapter](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/04), 이 세개의 플랫폼에 대한 소스코드는 여기서 확인할수 있다.) **Note 1**: 만약 아래의 프레임워크 외에 것에서 구동하고 싶다면, [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer)를 다운받아서 컴파일할수 있다. 터미널에서 구동되므로, MacOS와 RasberryPi등에서도 구동되며, 이책의 예제들은 모두 최적화 되어 있다. **Note 2**: 만약 WebGL에서 쉐이더를 구동하고, 다른 프레임워크를 따로 쓰고 싶지 않다면, [glslCanvas](https://github.com/patriciogonzalezvivo/glslCanvas)를 이용해서 할수 있다. 이 웹 툴은 이 책에 최적화 되어 있고, 실제로 저자가 프로젝트마다 사용하는 툴이기도 하다. ### **Three.js** 에서 Ricardo Cabello (aka [MrDoob](https://twitter.com/mrdoob) ) 가 다른 참여자[참여자](https://github.com/mrdoob/three.js/graphs/contributors)들과 개발한 WebGL을 이용한 프레임 워크인 [Three.js](http://threejs.org/). 많은 예제와, 튜토리얼, 책들이 존재하고, 이를 이용해 여러 3D graphics데모를 만들어 볼수 있다. 아래는 HTML과 JS를 이용해 three.js를 구동하는 예제이다. ```id="fragmentShader"```부분을 보면, 쉐이더가 어디에서 적용되는지 볼수 있다. ``` /* Detailed source-code truncated for AI context efficiency. */ ``` ### **Processing**에서 [Ben Fry](http://benfry.com/) 와 [Casey Reas](http://reas.com/) 에 의해 2001년에 시작되었고, [Processing](https://processing.org/) 는 간단하고 강력한 환경을 제공하고, 초보자들에게 사랑받는 툴이다. (적어도 저자는 그렇게 생각한다고 한다) [Andres Colubri](https://codeanticode.wordpress.com/) 는 프로세싱에서, openGL부분과 비디오 프로세싱부분에 중요한 업데이트를 했고, 이것으로 인해 GLSL 쉐이더를 구동시키기가 한결 편해졌다. 프로세싱은 ```"shader.frag"```라는 파일을 ```data```폴더에서 찾는다. 책에서 예제를 구동할거라면, 이 폴더에 파일을 rename하여 저장하고 사용하면 된다. ```processing 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); } ``` 쉐이더가 2.1 전버젼부터 작동되려면, ```#define PROCESSING_COLOR_SHADER``` 를 쉐이더 제일 위편에 넣어야 작동될것이다. 아래와 같이: ```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); } ``` 더 자세한 사항은 여기서 살펴보기 바란다. [tutorial](https://processing.org/tutorials/pshader/) ### **openFrameworks** 에서 각자 가장 편한 구동 프레임워크가 있을것인데, 저자의 경우는 [openFrameworks community](http://openframeworks.cc/)이다. C++로 이루어진 OpenGL와 유용한 C++라이브러리들을 wrap한 프레임 워크이고, Processing과 제법 흡사하다. Processing과 마찬가지로, openFrameworks도 data폴더에서 shader파일을 서치한다. ```.frag``` 확장자명을 적는것 또한 까먹지 말자. ```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(); } ``` 더 자세한 정보는 [Joshua Noble](http://thefactoryfactory.com/)가 만든 [강좌](http://openframeworks.cc/ofBook/chapters/shaders.html)를 보기 바란다. --- ### 04/README Pl (04/README-pl.md) ## Korzystanie z shaderów W ramach prac nad tą książką stworzyłem ekosystem narzędzi do tworzenia, wyświetlania, udostępniania i organizowania shaderów. Narzędzia te działają, bez konieczności dostosowywania kodu, na systemach Linux, MacOS, Windows i [Raspberry Pi](https://www.raspberrypi.org/) oraz w przeglądarce. ## Korzystanie z shaderów w przeglądarce **Wyświetlaj**: wszystkie interaktywne przykłady w tej książce wyświetlane są dzięki [glslCanvas](https://github.com/patriciogonzalezvivo/glslCanvas), który znacząco ułatwia proces korzystania z shaderów. ```html ``` Jak widać, `glslCanvas` wymaga jedynie elementu `canvas` z `class="glslCanvas"` oraz URL do twojego shadera w `data-fragment-url`. Aby dowiedzieć się więcej, kliknij [tutaj](https://github.com/patriciogonzalezvivo/glslCanvas). Jeśli podobnie jak ja chciałbyś móć korzysatć z shaderów w konsoli, to [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer) powinien cie zainteresować. Aplikacja ta pozwala zintegrować shadery z `bash`owymi skryptami i Unixowymi pipeline'ami, podobnie jak [ImageMagick](http://www.imagemagick.org/script/index.php). Ponadto, [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer) pozwala ci kompilować shadery na [Raspberry Pi](https://www.raspberrypi.org/) - właśnie dlatego [openFrame.io](http://openframe.io/) używa go do wyświetalania swoich shaderowych dział sztuki. Kliknij [tutaj](https://github.com/patriciogonzalezvivo/glslViewer), aby dowiedzieć się więcej. ```bash glslViewer yourShader.frag yourInputImage.png —w 500 -h 500 -E screenshot,yourOutputImage.png ``` **Twórz**: w celu usprawnienia procesu pisania shaderów stworzyłem edytor online [glslEditor](https://github.com/patriciogonzalezvivo/glslEditor). Edytor ten jest wykorzystywany w interaktywnych przykładach tej książki. Dodaje on poręczne widżety, czyniące abstrakcyjne doświadczenie pracy z kodem GLSL bardziej uchwytnym. Możesz również korzystać z niego jako samodzielnej aplikacji webowej pod adresem [editor.thebookofshaders.com/](http://editor.thebookofshaders.com/). Kliknij [tutaj](https://github.com/patriciogonzalezvivo/glslEditor), aby dowiedzieć się więcej. Jeśli preferujesz pracę offline z wykorzystaniem [SublimeText](https://www.sublimetext.com/), [rozszerzenie glslViewer](https://packagecontrol.io/packages/glslViewer) może cie zainteresować. Dowiedz się o nim więcej [tutaj](https://github.com/patriciogonzalezvivo/sublime-glslViewer). **Udostępniaj**: dzięki edytorowi online ([editor.thebookofshaders.com/](http://editor.thebookofshaders.com/)) możesz udstępniać swoje shadery! Zarówno webowa jak i stacjonarna wersja ma funkcję eksportu, generującą unikalny URL do twojego shadera. Ponadto, ma też funkcję bezpośredniego eksportu do [openFrame.io](http://openframe.io/). **Organizuj**: udostępnianie kodu stanowi początek dzielenia się twoimi shaderowymi dziełami! Poza opcją eksportu do [openFrame.io](http://openframe.io/) stworzyłem narzędzie do organizowania twoich shaderów w galerię, którą można wstawić na dowolną stronę internetową; nazywa się [glslGallery](https://github.com/patriciogonzalezvivo/glslGallery). Kliknij [tutaj](https://github.com/patriciogonzalezvivo/glslGallery), aby dowiedzieć się więcej. ## Korzystanie shaderów w twoim ulubionym frameworku Jeżeli programowanie we frameworkach jak [Processing](https://processing.org/), [Three.js](http://threejs.org/), [OpenFrameworks](http://openframeworks.cc/) or [SFML](https://www.sfml-dev.org/) nie jest ci obce, to opcja wypróbowania w nich swoich shaderów zapewne cie zainteresuje. Poniżej znajdziesz przykłady, jak wykorzystać shadery w każdym z nich (z takimi samymi uniformami jak w tej książce). (W [repozytorium GitHub'owym dla tego rozdziału](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/04) znajdziesz pełny kod źródłowy dla tych frameworków. ### W **Three.js** Znakomity i bardzo skromny Ricardo Cabello (aka [MrDoob](https://twitter.com/mrdoob) ) razem z [kontrybutorami](https://github.com/mrdoob/three.js/graphs/contributors) tworzą prawdopodobnie najbardziej popularny framework WebGL'owy zwany [Three.js](http://threejs.org/). Znajdziesz wiele przykładów, tutoriali i książek, które uczą, jak wykorzstać tę JavaScriptową bibliotekę do tworzenia odjazdowej grafiki 3D. Poniżej znajduje się przykład kodu w HTML i JS potrzebny do rozpoczęcia przygody z shaderami w three.js. Zwróć uwage na skrypt z `id="fragmentShader"` - do niego możesz wstawiać kod shaderów, które znajdziesz, przykładowo, w tej książce. ``` /* Detailed source-code truncated for AI context efficiency. */ ``` ### W **Processing** Stworzony przez [Ben Fry](http://benfry.com/) i [Casey Reas](http://reas.com/) w 2001, [Processing](https://processing.org/) jest nadzwyczaj prostym i potężnym środowiskiem, w którym możesz zacząć swoją przygodę z programowaniem (tak było w moim wypadku). [Andres Colubri](https://codeanticode.wordpress.com/) wniósł istotne zmiany do OpenGL i funkcji wideo w Processing, znacząco ułatwiając wykorzystanie w nim shaderów GLSL. Processing szuka pliku `shader.frag` w folderze `data`. Zatem, jeśli chcesz spróbować uruchomić przykłady z tej książki w Processing, to pamiętaj umieścić je w tym folderze i odpowiednio nazwać. ```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); } ``` Aby shader działał na wersjach wcześniejszych niż 2.1, dodaj poniższą linijkę na początku shadera: `#define PROCESSING_COLOR_SHADER`. Powinno to wyglądać tak: ```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); } ``` Jeśli chcesz wiedzieć więcej o sahderach w Processing, sprawdź ten [tutorial](https://processing.org/tutorials/pshader/). ### W **openFrameworks** Każda ma takie miejsce, gdzie czuje się najabrdziej komfortowo. W moim wypadku jest to społeczność [openFrameworks](http://openframeworks.cc/). Ten C++'owy framework jest wrapperem OpenGL i innych open source'owych bibliotek C++. Pod pewnym względem jest całkiem podobny do Processing, ale z dodanym utrudnieniem radzenia sobie z kompilatorami C++. ```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(); } ``` Polecam addon [ofxShader](https://github.com/patriciogonzalezvivo/ofxshader) do openFrameworks, jeśli potrzbujesz takiego zestawu uniformów jak w GlslViewer i GlslCanvas, wsparcia dla "multiple buffering", "material shaders", hot reload'owania oraz automatycznej konwersji do OpenGL ES na Raspberry Pi. Twój kod stanie się tak prosty jak poniżej: ```cpp //-------------------------------------------------------------- void ofApp::setup(){ ofDisableArbTex(); sandbox.allocate(ofGetWidth(), ofGetHeight()); sandbox.load("grayscott.frag"); } //-------------------------------------------------------------- void ofApp::draw(){ sandbox.render(); sandbox.draw(0, 0); } ``` Po więcej informacji na temat shaderów w openFrameworks zajrzyj do znakomitego [tutoriala](http://openframeworks.cc/ofBook/chapters/shaders.html) autorstwa [Joshua Noble](http://thefactoryfactory.com/). --- ### 04/README Pt (04/README-pt.md) ## Rodando o seu shader Como parte da construção deste livro, e minha prática de arte, eu fiz um ecossistema de ferramentas para criar, exibir e realizar curadoria de shaders. Essas ferramentas trabalham consistentemente em Linux, MacOS, [Raspberry Pi](https://www.raspberrypi.org/) e browsers sem a necessidade de mudar seu código. **Exibir**: todos os exemplos ao vivo deste livro são exibidos usando o [glslCanvas](https://github.com/patriciogonzalezvivo/glslCanvas) que faz o processo de executar um shader standalone incrivelmente fácil. ```html ``` Como você pode ver, só precisa de um elemento `canvas` com `class="glslCanvas"` e a url para seu shader no `data-fragment-url`. Aprenda mais sobre isso [aqui](https://github.com/patriciogonzalezvivo/glslCanvas). Se você é como eu, provavelmente vai querer rodar shaders diretamente da console, e nesse caso você deveria dar uma olhada no [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer). Esta aplicação lhe permite incorporar shaders em seus scripts `bash` ou pipelines do unix e usá-los de modo similiar ao [ImageMagick](http://www.imagemagick.org/script/index.php). Também, o [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer) é uma boa forma de compilar shaders no seu [Raspberry Pi](https://www.raspberrypi.org/), razão pela qual o [openFrame.io](http://openframe.io/) o utiliza para exibir artes em shader. Aprenda mais sobre essa aplicação [aqui](https://github.com/patriciogonzalezvivo/glslViewer). ```bash glslViewer yourShader.frag yourInputImage.png —w 500 -h 500 -E screenshot,yourOutputImage.png ``` **Criar**: de modo a trazer mais luz para a experiência de codificação de shaders, eu fiz um editor online chamado [glslEditor](https://github.com/patriciogonzalezvivo/glslEditor). Este editor está embutido nos exemplos ao vivo do livro, e traz uma série de widgets bem convenientes para tornar mais tangível a experiência abstrata de trabalhar com código GLSL. Você também pode executá-lo como uma aplicação web standalone no endereço [editor.thebookofshaders.com/](http://editor.thebookofshaders.com/). Saiba mais sobre isso [aqui](https://github.com/patriciogonzalezvivo/glslEditor). Se você prefere trabalhar offline usando o [SublimeText](https://www.sublimetext.com/) você pode instalar esse [pacote para glslViewer](https://packagecontrol.io/packages/glslViewer). Saiba mais sobre isso [aqui](https://github.com/patriciogonzalezvivo/sublime-glslViewer). **Compartilhar**: o editor online ([editor.thebookofshaders.com/](http://editor.thebookofshaders.com/)) pode compartilhar seus shaders! Tanto a versão embedded quanto standalone têm um botão para exportar, onde você pode obter uma URL única para o seu shader. Eles têm também a capacidade de exportar diretamente para um [openFrame.io](http://openframe.io/). **Curadoria**: Compartilhar o seu código é o começo para você compartilhar seus shaders como artwork! Além da opção de exportar para [openFrame.io](http://openframe.io/) eu fiz uma ferramenta para lhe permitir criar uam curadoria de seus shaders numa galeria que pode ser embutida em qualquer site, e seu nome é [glslGallery](https://github.com/patriciogonzalezvivo/glslGallery). Saiba mais [aqui](https://github.com/patriciogonzalezvivo/glslGallery). ## Rodando seus shaders em seu framework favorito Para o caso de você já ter experiência em programar em um framework como [Processing](https://processing.org/), [Three.js](http://threejs.org/), [OpenFrameworks](http://openframeworks.cc/) ou [SFML](https://www.sfml-dev.org/), você provavelmente está animado para tentar os shaders nessas plataformas que você se sente confortável. Os exemplos a seguir são formas de como configurar os shaders em alguns frameworks populares com os mesmos uniforms que vamos usar ao longo desse livro. (No [Repositório GitHub para esse capítulo](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/04), você encontra o código completo para esses três frameworks.) ### Em **Three.js** O brillhante e humilde Ricardo Cabello (aka [MrDoob](https://twitter.com/mrdoob) ) tem desenvolvido com outros [contribuidores](https://github.com/mrdoob/three.js/graphs/contributors) o que é provavelmente um dos mais famosos frameworks para WebGL, chamado de [Three.js](http://threejs.org/). Você vai encontrar muitos exemplos, tutoriais e livros que ensinam a usar essa biblioteca em JavaScript para fazer gráficos 3D muito legais. Abaixo, um exemplo do HTML e JS que você precisa para começar com shaders em three.js. Preste atenção ao script `id="fragmentShader"`, é aqui que você pode copiar os shaders que encontrar neste livro. ``` /* Detailed source-code truncated for AI context efficiency. */ ``` ### Em **Processing** Iniciado por [Ben Fry](http://benfry.com/) e [Casey Reas](http://reas.com/) em 2001, o [Processing](https://processing.org/) é um ambiente extraordinariamente simples e poderoso para você dar seus primeiros passos no código (pelo menos, pra mim, foi). [Andres Colubri](https://codeanticode.wordpress.com/) tem feito atualizações importantes no openGL e video em Processing, facilitando ainda mais que nunca o uso e diversão com shaders GLSL nesse ambiente amigável. O Processing vai procurar pelo shader chamado `"shader.frag"` na pasta `data`. Tenha certeza de copiar os exemplos que encontrar aqui para essa pasta, e renomear o arquivo. ```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); } ``` De modo a fazer o shader funcionar em versões anteriores à 2.1, você precisa de adicionar a seguinte linha no começo de seu shader: `#define PROCESSING_COLOR_SHADER`. De modo que se pareça com isso: ```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); } ``` Para mais informações sobre os shaders no Processing veja esse [tutorial](https://processing.org/tutorials/pshader/). ### No **openFrameworks** Todo mundo tem um lugar onde se sente confortável, e no meu caso, ainda é a [comunidade openFrameworks](http://openframeworks.cc/). Esse framework C++ envolve o OpenGL e outras bibliotecas opensource C++. De muitas formas, é bem parecida com o Processing, mas com as complicações óbvias de se lidar com compiladores C++. Da mesma forma que o Processing, openFrameworks vai procurar o seu shader no diretório data, então não se esqueça de copiar os arquivos `.frag` que quiser usar, e mudar o nome quando for carregar. ```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(); } ``` Para mais informações sobre shaders em openFrameworks, vá nesse [excelente tutorial](http://openframeworks.cc/ofBook/chapters/shaders.html) feito por [Joshua Noble](http://thefactoryfactory.com/). --- ### 04/README Ru (04/README-ru.md) ## Запуск шейдера В процессе создания этой книги и просто из любви к искусству я создал набор инструментов для создания, отображения, опубликования и сопровождения шейдеров. Эти инструменты работают одинаково на Linux, MacOS, [Raspberry Pi](https://www.raspberrypi.org/) и в браузерах без переписывания кода. **Отображение**: все интерактивные примеры в книге показываются с помощью [glslCanvas](https://github.com/patriciogonzalezvivo/glslCanvas), который делает процесс запуска отдельных шейдеров невероятно простым. ```html ``` Как видите, для этого нужен всего лишь элемент `canvas` с классом `class="glslCanvas"` и URL шейдера в свойстве `data-fragment-url`. Подробнее о нём можно узнать [здесь](https://github.com/patriciogonzalezvivo/glslCanvas). Если вы разделяете мой подход к разработке, вам возможно захочется запускать шейдеры напрямую из консоли, в чём вам поможет [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer). Это приложение позволяет встраивать шейдеры в `bash`-скрипты или конвейер unix, и может использоваться по аналогии с [ImageMagick](http://www.imagemagick.org/script/index.php). Так же, [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer) - отличный способ скомпилировать шейдеры на [Raspberry Pi](https://www.raspberrypi.org/), и поэтому он используется на [openFrame.io](http://openframe.io/) для демонстрации шейдеров. Подробнее с этим приложением можно познакомиться [здесь](https://github.com/patriciogonzalezvivo/glslViewer). ```bash glslViewer yourShader.frag yourInputImage.png —w 500 -h 500 -E screenshot,yourOutputImage.png ``` **Создание**: чтобы сделать опыт создания шейдеров более ярким, я сделал онлайн-редактор [glslEditor](https://github.com/patriciogonzalezvivo/glslEditor). Этот редактор используется для демонстрации интерактивных примеров в книге и предоставляет набор виджетов, делающих абстрактный код на GLSL более осязаемым. Его так же можно запустить в отдельном веб-приложении по адресу [editor.thebookofshaders.com](http://editor.thebookofshaders.com/). Подробнее о редакторе [здесь](https://github.com/patriciogonzalezvivo/glslEditor). Если вы предпочитаете работать оффлайн в редакторе [SublimeText](https://www.sublimetext.com/), вы можете установить [пакет для glslViewer](https://packagecontrol.io/packages/glslViewer). Подробнее [здесь](https://github.com/patriciogonzalezvivo/sublime-glslViewer). **Публикация**: онлайн-редактор ([editor.thebookofshaders.com/](http://editor.thebookofshaders.com/)) может опубликовать ваш шейдер! Как встраиваемая, так и отдельная версия содержат кнопку «экспорт», которая выдаёт уникальные URL каждому шейдеру. Так же есть возможность выгружать шейдеры сразу на [openFrame.io](http://openframe.io/). **Сопровождение**: Публикация кода - это только первый шаг на пути вашего шейдера в качестве художественного произведения. Помимо возможности экспорта на [openFrame.io](http://openframe.io/), я создал инструмент [glslGallery](https://github.com/patriciogonzalezvivo/glslGallery) для размещения шейдеров в галерее, которую можно встроить на любой сайт. Подробнее [здесь](https://github.com/patriciogonzalezvivo/glslGallery). ## Запуск шейдера в вашем любимом фреймворке Если у вас уже есть опыт программирования на таких фреймворках, как [Processing](https://processing.org/), [Three.js](http://threejs.org/), [OpenFrameworks](http://openframeworks.cc/) или [SFML](https://www.sfml-dev.org/), вы можете попробовать шейдеры прямо в них. Ниже показаны способы установки используемых в книге uniform-переменных на некоторых популярных фреймворках. В [репозитории](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/04) этой главы на Гитхабе вы найдёте полный исходный код для этих трёх фреймворков. ### **Three.js** Рикардо Кабелло (aka [MrDoob](https://twitter.com/mrdoob) ) и группа [единомышленников](https://github.com/mrdoob/three.js/graphs/contributors) разработали один из лучших WebGL-фреймворков под названием [Three.js](http://threejs.org/). Там вы найдёте множество примеров, учебных курсов и книг с помощью которых можно создавать крутую 3D-графику на JavaScript. Ниже вы видите минимальный пример HTML и JS-кода, позволяющего начать использовать шейдеры на three.js. Обратите внимание на скрипт с `id="fragmentShader"`. Именно благодаря ему вы можете копировать шейдеры из книги. ``` /* Detailed source-code truncated for AI context efficiency. */ ``` ### **Processing** [Processing](https://processing.org/) - необычайно простая и мощная среда, созданная [Беном Фраем](http://benfry.com/) и [Кэси Рис](http://reas.com/) в 2001 году. Она хорошо подходит для того, чтобы сделать ваши первые шаги в программировании (по крайней мере, так было у меня). [Андре Колубри](https://codeanticode.wordpress.com/) добавил в Processing поддержку OpenGL и видео, из-за чего играть с шейдерами в ней стало проще простого. Processing ищет файл с именем `shader.frag` в папке `data` вашего скетча. Таким образом, вы можете просто скопировать пример отсюда и переименовать файл. ```cpp PShader shader; void setup() { size(640, 360, P2D); noStroke(); shader = loadShader("shader.frag"); shader.set("u_resolution", float(width), float(height)); } void draw() { shader.set("u_mouse", float(mouseX), float(mouseY)); shader.set("u_time", millis() / 1000.0); shader(shader); rect(0,0,width,height); } ``` Чтобы шейдеры запустились на версиях ниже 2.1, добавьте строку `#define PROCESSING_COLOR_SHADER` в начало шейдера. В итоге, код шейдера будет выглядеть примерно так: ```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); } ``` Более подробную информацию о шейдерах в Processing ищите в [этом руководстве](https://processing.org/tutorials/pshader/). ### **openFrameworks** У каждого человека есть место, где ему комфортно, и для меня таковым остаётся [сообщество openFrameworks](http://openframeworks.cc/). Этот C++-фреймворк является обёрткой для OpenGL и других библиотек на C++. Он во многом похож на Processing с поправкой на особенности использования компиляторов языка C++. Как и Processing, openFramework ищет шейдеры в папке `data`, поэтому не забудьте скопировать в него и файлы с расширением `.frag` и переименовывать их перед использованием. ```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(); } ``` За более подробной информацией о шейдерах в openFrameworks обратитесь к [этому руководству](http://openframeworks.cc/ofBook/chapters/shaders.html) от [Joshua Noble](http://thefactoryfactory.com/). --- ### 04/README Tr (04/README-tr.md) ## Shader'ınızı çalıştırma Bu kitabın yapımı ve sanat pratiğimin bir parçası olarak, shader'ları oluşturmak, görüntülemek, paylaşmak ve küratörlüğünü yapmak için bir araç ekosistemi oluşturdum. Bu araçlar Linux, MacOS, Windows ve [Raspberry Pi](https://www.raspberrypi.org/) ile tarayıcılarda, kodunuzu değiştirmenize gerek kalmadan tutarlı bir şekilde çalışır. ## Shader'larınızı tarayıcıda çalıştırma **Görüntüleme**: Bu kitaptaki tüm canlı örnekler, bağımsız shader çalıştırma sürecini inanılmaz derecede kolaylaştıran [glslCanvas](https://github.com/patriciogonzalezvivo/glslCanvas) kullanılarak görüntülenir. ```html ``` Gördüğünüz gibi, sadece `class="glslCanvas"` özelliğine ve `data-fragment-url`'de shader'ınızın URL'sine sahip bir `canvas` öğesine ihtiyaç duyar. Daha fazla bilgi için [buraya](https://github.com/patriciogonzalezvivo/glslCanvas) bakabilirsiniz. Eğer benim gibi biriyseniz, muhtemelen shader'ları doğrudan konsoldan çalıştırmak isteyeceksiniz, bu durumda [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer)'a göz atmalısınız. Bu uygulama, shader'ları `bash` scriptlerinize veya unix aktarım hatlarına dahil etmenizi ve [ImageMagick](http://www.imagemagick.org/script/index.php) ile benzer şekilde kullanmanızı sağlar. Ayrıca [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer), shader'ları [Raspberry Pi](https://www.raspberrypi.org/) üzerinde derlemek için harika bir yoldur; bu nedenle [openFrame.io](http://openframe.io/) shader sanat eserlerini görüntülemek için onu kullanır. Bu uygulama hakkında daha fazla bilgi için [buraya](https://github.com/patriciogonzalezvivo/glslViewer) bakabilirsiniz. ```bash glslViewer yourShader.frag yourInputImage.png —w 500 -h 500 -E screenshot,yourOutputImage.png ``` **Oluşturma**: Shader kodlama deneyimini aydınlatmak için [glslEditor](https://github.com/patriciogonzalezvivo/glslEditor) adında çevrimiçi bir düzenleyici yaptım. Bu düzenleyici kitabın canlı örneklerine gömülüdür ve glsl koduyla çalışmanın soyut deneyimini daha somut hale getirmek için bir dizi kullanışlı widget sunar. Ayrıca bunu [editor.thebookofshaders.com/](http://editor.thebookofshaders.com/) adresinden bağımsız bir web uygulaması olarak da çalıştırabilirsiniz. Daha fazla bilgi için [buraya](https://github.com/patriciogonzalezvivo/glslEditor) bakabilirsiniz. Çevrimdışı çalışmayı tercih ediyorsanız ve [SublimeText](https://www.sublimetext.com/) kullanıyorsanız, bu [glslViewer paketini](https://packagecontrol.io/packages/glslViewer) kurabilirsiniz. Daha fazla bilgi için [buraya](https://github.com/patriciogonzalezvivo/sublime-glslViewer) bakabilirsiniz. **Paylaşma**: Çevrimiçi düzenleyici ([editor.thebookofshaders.com/](http://editor.thebookofshaders.com/)) shader'larınızı paylaşabilir! Hem gömülü hem de bağımsız sürümde, shader'ınıza özgü bir URL almanızı sağlayan bir dışa aktarma düğmesi bulunur. Ayrıca doğrudan bir [openFrame.io](http://openframe.io/)'ya dışa aktarma yeteneğine de sahiptir. **Küratörlük**: Kodunuzu paylaşmak, shader'ınızı bir sanat eseri olarak paylaşmanın başlangıcıdır! [openFrame.io](http://openframe.io/)'ya dışa aktarma seçeneğinin yanı sıra, shader'larınızı herhangi bir siteye gömülebilecek bir galeriye dönüştürmek için [glslGallery](https://github.com/patriciogonzalezvivo/glslGallery) adlı bir araç yaptım. Daha fazla bilgi için [buraya](https://github.com/patriciogonzalezvivo/glslGallery) bakabilirsiniz. ## Shader'larınızı favori framework'ünüzde çalıştırma [Processing](https://processing.org/), [Three.js](http://threejs.org/), [OpenFrameworks](http://openframeworks.cc/) veya [SFML](https://www.sfml-dev.org/) gibi bir framework'te programlama deneyiminiz varsa, muhtemelen rahat hissettiğiniz bu platformlarda shader'ları denemekten heyecan duyarsınız. Aşağıda, bu kitap boyunca kullanacağımız aynı uniform'larla bazı popüler framework'lerde shader'ların nasıl kurulacağına dair örnekler bulunmaktadır. (Bu [bölümün GitHub deposunda](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/04), bu üç framework için tam kaynak kodunu bulacaksınız.) ### **Three.js**'de Parlak ve çok alçakgönüllü Ricardo Cabello (namıdiğer [MrDoob](https://twitter.com/mrdoob)), diğer [katkıda bulunanlarla](https://github.com/mrdoob/three.js/graphs/contributors) birlikte muhtemelen WebGL için en ünlü framework'lerden birini geliştiriyor: [Three.js](http://threejs.org/). Harika 3D grafikler yapmak için bu JavaScript kütüphanesini nasıl kullanacağınızı öğreten birçok örnek, öğretici ve kitap bulacaksınız. Aşağıda, three.js'de shader'larla başlamak için ihtiyacınız olan HTML ve JS örneği yer almaktadır. `id="fragmentShader"` script'ine dikkat edin, bu kitapta bulduğunuz shader'ları buraya kopyalayabilirsiniz. ``` /* Detailed source-code truncated for AI context efficiency. */ ``` ### **Processing**'de 2001 yılında [Ben Fry](http://benfry.com/) ve [Casey Reas](http://reas.com/) tarafından başlatılan [Processing](https://processing.org/), kodlamada ilk adımlarınızı atmak için son derece basit ve güçlü bir ortamdır (en azından benim için öyleydi). [Andres Colubri](https://codeanticode.wordpress.com/), Processing'de OpenGL ve video konusunda önemli güncellemeler yaparak, bu dostane ortamda GLSL shader'larını kullanmayı ve denemeyi her zamankinden daha kolay hale getirdi. Processing, sketch'in `data` klasöründe `"shader.frag"` adlı shader'ı arayacaktır. Burada bulduğunuz örnekleri o klasöre kopyaladığınızdan ve dosya adını değiştirdiğinizden emin olun. ```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); } ``` Shader'ın 2.1'den önceki sürümlerde çalışması için, shader'ınızın başına şu satırı eklemeniz gerekir: `#define PROCESSING_COLOR_SHADER`. Böylece şöyle görünmelidir: ```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); } ``` Processing'de shader'lar hakkında daha fazla bilgi için bu [öğreticiye](https://processing.org/tutorials/pshader/) göz atın. ### **openFrameworks**'de Herkesin rahat hissettiği bir yer vardır, benim için bu hâlâ [openFrameworks topluluğudur](http://openframeworks.cc/). Bu C++ framework'ü OpenGL ve diğer açık kaynak C++ kütüphanelerinin etrafını sarar. Birçok yönden Processing'e çok benzer, ancak C++ derleyicileriyle uğraşmanın bariz karmaşıklıkları vardır. Processing ile aynı şekilde, openFrameworks shader dosyalarınızı data klasöründe arayacaktır, bu yüzden kullanmak istediğiniz `.frag` dosyalarını kopyalayıp yüklerken adını değiştirmeyi unutmayın. ```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(); } ``` GlslViewer ve GlslCanvas spesifikasyonlarında bulunan tüm uniform'ları OpenFrameworks'de daha basit bir şekilde kullanmak istiyorsanız, [ofxShader](https://github.com/patriciogonzalezvivo/ofxshader) eklentisini kullanmanızı öneririm; bu eklenti aynı zamanda birden fazla tampon, malzeme shader'ları, anında yeniden yükleme ve Raspberry Pi'de OpenGL ES için otomatik dönüştürme desteğine de sahip olacaktır. Ve kodunuz şu kadar basit olacaktır: ```cpp //-------------------------------------------------------------- void ofApp::setup(){ ofDisableArbTex(); sandbox.allocate(ofGetWidth(), ofGetHeight()); sandbox.load("grayscott.frag"); } //-------------------------------------------------------------- void ofApp::draw(){ sandbox.render(); sandbox.draw(0, 0); } ``` openFrameworks'te shader'lar hakkında daha fazla bilgi için [Joshua Noble](http://thefactoryfactory.com/) tarafından hazırlanan bu [mükemmel öğreticiye](http://openframeworks.cc/ofBook/chapters/shaders.html) gidin. --- ### 04/README Ua (04/README-ua.md) ## Запуск шейдера У процесі створення цієї книги та моєї художньої практики, я сформував екосистему інструментів для створення шейдерів, їх відображення, спільного використання та керування. Ці інструменти працюють однаково в Linux, MacOS, Windows, [Raspberry Pi](https://www.raspberrypi.org/) та браузерах без необхідності змінювати код. ## Запуск шейдерів у браузері **Відображення**: усі інтерактивні приклади в цій книзі відображаються за допомогою [glslCanvas](https://github.com/patriciogonzalezvivo/glslCanvas), що робить процес запуску автономного шейдера неймовірно простим. ```html ``` Як бачите, для цього потрібен лише елемент `canvas` із відповідним класом `class="glslCanvas"` та URL-адресою вашого шейдера, заданої в атрибуті `data-fragment-url`. Дізнатися більше про це можна [тут](https://github.com/patriciogonzalezvivo/glslCanvas). Якщо ви схожі на мене, ви, ймовірно, захочете запускати шейдери безпосередньо з консолі. У такому випадку вам допоможе [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer). Ця програма дозволяє вам включати шейдери у ваші `bash`-скрипти або unix-конвеєри та використовувати їх подібно до [ImageMagick](http://www.imagemagick.org/script/index.php). Також [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer) є чудовим способом компіляції шейдерів на [Raspberry Pi](https://www.raspberrypi.org/), через що [openFrame.io](http://openframe.io/) використовує його для демонстрації шейдерних робіт. Дізнайтеся більше про цю програму за цим [посиланням](https://github.com/patriciogonzalezvivo/glslViewer). ```bash glslViewer yourShader.frag yourInputImage.png —w 500 -h 500 -E screenshot,yourOutputImage.png ``` **Створення**: щоб покращити досвід кодування шейдерів, я створив онлайн-редактор під назвою [glslEditor](https://github.com/patriciogonzalezvivo/glslEditor). Цей редактор використовується в інтерактивних прикладах книги та пропонує низку зручних віджетів, що робить взаємодію з абстрактним кодом glsl більш відчутним. Ви також можете запустити його як окрему вебпрограму: [editor.thebookofshaders.com](http://editor.thebookofshaders.com/). Дізнатися більше про редактор можна [тут](https://github.com/patriciogonzalezvivo/glslEditor). Якщо ви бажаєте працювати з редактором офлайн за допомогою [SublimeText](https://www.sublimetext.com/), то можете встановити цей [пакет для glslViewer](https://packagecontrol.io/packages/glslViewer). Дізнайтеся більше [тут](https://github.com/patriciogonzalezvivo/sublime-glslViewer). **Експортування**: онлайн-редактор ([editor.thebookofshaders.com](http://editor.thebookofshaders.com/)) може поділитися вашими шейдерами! Як вбудована, так і окрема версія мають кнопку для експорту, за допомогою якої ви можете отримати унікальну URL-адресу свого шейдера. Також є можливість експортувати шейдер безпосередньо в [openFrame.io](http://openframe.io/). **Керування**: експорт коду — початок для того, щоб ви ділилися своїм шейдером у якості художнього витвору! Окрім опції експорту в [openFrame.io](http://openframe.io/), я створив інструмент для керування вашими шейдерами у галереї, яку можна вбудувати у будь-який сайт — [glslGallery](https://github.com/patriciogonzalezvivo/glslGallery). Детальніше [тут](https://github.com/patriciogonzalezvivo/glslGallery). ## Запуск ваших шейдерів у вашому улюбленому фреймворку Якщо у вас уже є досвід програмування в таких фреймворках, як [Processing](https://processing.org/), [Three.js](http://threejs.org/), [OpenFrameworks](http://openframeworks.cc/) або [SFML](https://www.sfml-dev.org/), ви, мабуть, із задоволенням спробуєте шейдери у них. Нижче наведено приклади того, як налаштувати шейдери в деяких популярних фреймворках з вказаними у книзі uniform-змінними. У [GitHub-репозиторії для цього розділу](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/04) ви знайдете повний вихідний код для цих трьох фреймворків. ### **Three.js** Блискучий і дуже скромний Ricardo Cabello (він же [MrDoob](https://twitter.com/mrdoob)) з групою інших [однодумців](https://github.com/mrdoob/three.js/graphs/contributors) розробили один із найвідоміших фреймворків для WebGL під назвою [Three.js](http://threejs.org/). Там ви знайдете безліч прикладів, посібників і книг, які навчать вас, як використовувати цю JS-бібліотеку для створення класної 3D-графіки. Нижче наведено приклад із HTML та JS, які необхідні для початку роботи з шейдерами у three.js. Зверніть увагу на скрипт з `id="fragmentShader"` куди ви можете скопіювати шейдери, знайдені в цій книзі. ``` /* Detailed source-code truncated for AI context efficiency. */ ``` ### **Processing** [Processing](https://processing.org/) започатковано у 2001 році у співпраці між [Ben Fry](http://benfry.com/) та [Casey Reas](http://reas.com/). Фреймворк є надзвичайно простим та потужним середовищем, у якому можна робити свої перші кроки в програмуванні (принаймні так було у мене). [Andres Colubri](https://codeanticode.wordpress.com/) вніс важливі оновлення в Processing для підтримки openGL і відео, що полегшило використання шейдерів GLSL у цьому дружньому середовищі, ніж будь-коли. Processing шукатиме шейдер із назвою `"shader.frag"` у теці `data` вашого скетчу. Тож вам достатньо скопіювати приклади цієї книги у файл із відповідною назвою. ```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); } ``` Щоб шейдер працював у попередніх версіях, нижчих за 2.1, вам потрібно додати рядок `#define PROCESSING_COLOR_SHADER` на початку вашого шейдера. Це виглядатиме так: ```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); } ``` Щоб дізнатися більше про шейдери у Processing, перегляньте цей [посібник](https://processing.org/tutorials/pshader/). ### **openFrameworks** У кожного є місце, де йому комфортно, у моєму випадку таким місцем залишається [спільнота openFrameworks](http://openframeworks.cc/). Цей C++ фреймворк є обгорткою навколо OpenGL та інших бібліотек на C++ з відкритим кодом. Багато в чому він дуже схожий на Processing, але зі своїми особливостями роботи з використанням компіляторів C++. Так само як і Processing, openFrameworks шукатиме ваші файли шейдерів у теці `data`. Тому не забудьте скопіювати код прикладів, які хочете використати, у файли з розширенням `.frag` і покласти їх у згадану теку: ```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(); } ``` Якщо ви хочете використовувати в OpenFrameworks повний набір уніформ, що містяться в специфікаціях GlslViewer і GlslCanvas, простішим способом, я рекомендую використовувати доповнення [ofxShader](https://github.com/patriciogonzalezvivo/ofxshader). Воно також має підтримку кількох буферів, шейдерних матеріалів, гаряче перезавантаження та автоматизацію для OpenGL ES у Raspberry Pi. Ваш код буде таким же простим, як нижче: ```cpp //-------------------------------------------------------------- void ofApp::setup(){ ofDisableArbTex(); sandbox.allocate(ofGetWidth(), ofGetHeight()); sandbox.load("grayscott.frag"); } //-------------------------------------------------------------- void ofApp::draw(){ sandbox.render(); sandbox.draw(0, 0); } ``` Щоб дізнатися більше про шейдери в openFrameworks, перегляньте цей [чудовий посібник](http://openframeworks.cc/ofBook/chapters/shaders.html), створений [Joshua Noble](http://thefactoryfactory.com/). --- ### 04/README Vi (04/README-vi.md) ## Chạy thử shader Trong quá trình hình thành nên quyển sách này tôi đã tạo ra hàng loạt các công cụ có thể viết, hiển thị, chia sẻ và tìm duyệt các shader. Các công cụ này hoạt động giống nhau trên cả Linux, MacOS, Windows, [Raspberry Pi](https://www.raspberrypi.org/) và cả trình duyệt nữa, mà không cần phải chỉnh sửa gì thêm. ## Chạy thử shader trên trình duyệt **Hiển thị**: Toàn bộ ví dụ tương tác được trong quyển sách này đều được hiển thị bằng [glslCanvas](https://github.com/patriciogonzalezvivo/glslCanvas) để preview shader theo cách vô cùng đơn giản. ```html ``` Như bạn thấy, chỉ cần một thẻ `canvas` với `class="glslCanvas"` và URL tới shader ở thuộc tính `data-fragment-url` là đủ. Tìm hiểu thêm tại [đây](https://github.com/patriciogonzalezvivo/glslCanvas). Nếu bạn giống tôi, bạn có thể sẽ muốn preview shader ngay trong console, và trong trường hợp thì bạn nên ngó qua [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer). Ứng dụng này cho phép bạn kết hợp shader với script `bash` hay bất kỳ công cụ dòng lệnh nào của Unix giống như cách mà [ImageMagick](http://www.imagemagick.org/script/index.php) hoạt động. Ngoài ra [glslViewer](https://github.com/patriciogonzalezvivo/glslViewer) cũng là một cách hay để biên dịch shader trên [Raspberry Pi](https://www.raspberrypi.org/), cũng chính là lí do mà [openFrame.io](http://openframe.io/) dùng nó để preview shader. Tìm hiểu thêm về công cụ này tại [đây](https://github.com/patriciogonzalezvivo/glslViewer). ```bash glslViewer yourShader.frag yourInputImage.png —w 500 -h 500 -E screenshot,yourOutputImage.png ``` **Viết shader**: để chia sẻ kinh nghiệm code shader, tôi đã tạo một editor online gọi là [glslEditor](https://github.com/patriciogonzalezvivo/glslEditor). Editor này được nhúng vào các ví dụ trong quyển sách này, nó bổ sung các widget rất tiện cho việc viết code GLSL. Bạn cũng có thể chạy riêng nó như một ứng dụng web ở [editor.thebookofshaders.com/](http://editor.thebookofshaders.com/). Tìm hiểu thêm tại [đây](https://github.com/patriciogonzalezvivo/glslEditor). Nếu bạn thích làm việc offline bằng [SublimeText](https://www.sublimetext.com/) bạn có thể cài đặt [package glslViewer](https://packagecontrol.io/packages/glslViewer). Tìm hiểu thêm tại [đây](https://github.com/patriciogonzalezvivo/sublime-glslViewer). **Chia sẻ**: Bạn có thể chia sẻ shader bằng editor online ([editor.thebookofshaders.com/](http://editor.thebookofshaders.com/))! Cả phiên bản nhúng và chạy độc lập đều có nút bấm export cho bạn một URL tới shader của mình. Nó còn có khả năng export trực tiếp tới [openFrame.io](http://openframe.io/). **Thư viện**: Bên cạnh việc export sang [openFrame.io](http://openframe.io/) Tôi còn tạo ra công cụ để bạn có thể khoe shader của mình trên bất kỳ site nào, tên nó là [glslGallery](https://github.com/patriciogonzalezvivo/glslGallery). Tìm hiểu thêm tại [đây](https://github.com/patriciogonzalezvivo/glslGallery). ## Chạy shader trên framework yêu thích Trong trường hợp bạn đã có kinh nghiệm lập trình với các framework như: [Processing](https://processing.org/), [Three.js](http://threejs.org/), [OpenFrameworks](http://openframeworks.cc/) hay [SFML](https://www.sfml-dev.org/), you có thể sẽ muốn thử shader trên các nền tảng đó. Dưới đây là hướng dẫn sử dụng shader trên các framework phổ biến với các uniform giống như shader được viết trong quyển sách này. (Trong [repository GitHub cho chương này](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/04), bạn có thể tìm thấy mã nguồn hoàn chỉnh của cả 3 framework này). ### Với **Three.js** Ricardo Cabello (hay còn gọi là [MrDoob](https://twitter.com/mrdoob) ), một anh chàng thông minh và khiêm tốn đã phát triển một trong những framework nổi tiếng nhất cho WebGL cùng với các [cộng sự](https://github.com/mrdoob/three.js/graphs/contributors), đó là [Three.js](http://threejs.org/). Bạn sẽ tìm thấy rất nhiều ví dụ, hướng dẫn và sách dạy bạn cách dùng thư viện JavaScript này để tạo nên các tác phẩm đồ hoạ 3D rất ngầu. Dưới đây là một ví dụ về code HTML và JS mà bạn cần để bắt đầu viết shader với three.js. Hãy chú ý tới đoạn `id="fragmentShader"`, đây là nơi mà bạn có thể copy-paste shader từ quyển sách này thay vào đó để thử. ``` /* Detailed source-code truncated for AI context efficiency. */ ``` ### Với **Processing** Bắt đầu bởi [Ben Fry](http://benfry.com/) và [Casey Reas](http://reas.com/) năm 2001, [Processing](https://processing.org/) là môi trường siêu đơn giản mà mạnh mẽ để bắt đầu code shader (ít nhất là với tôi). [Andres Colubri](https://codeanticode.wordpress.com/) đã cải tiến OpenGL và Video trong Processing để khiến cho việc sử dụng GLSL trở nên dễ hơn bao giờ hết. Processing sẽ thực thi file shader có tên `"shader.frag"` trong thư mục `data`. Nếu bạn copy ví dụ ở đây, hãy nhớ đổi tên file cho khớp. ```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); } ``` Để shader hoạt động với các phiên bản trước 2.1, bạn cần thêm dòng sau vào phần đầu của shader: `#define PROCESSING_COLOR_SHADER`. Nó sẽ trông như thế này: ```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); } ``` Để biết thêm về shader trong Processing, hãy xem [hướng dẫn](https://processing.org/tutorials/pshader/). ### Với **openFrameworks** Ai cũng có công cụ mà họ cảm thấy thoải mái nhất, trong trường hợp của tôi thì đó là [openFrameworks](http://openframeworks.cc/). Framework viết bằng C++ này dựa trên OpenGL và một vài thư viện mã nguồn mở khác. Nó rất giống Processing ở nhiều điểm, chỉ khác ở phần biên dịch C++ phức tạp. Giống như Processing, openFrameworks sẽ tìm file shader của bạn để thực thi, nên nếu copy file `.frag` nào ở đây thì đừng quên đổi tên file trong code cho khớp. ```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(); } ``` Nếu bạn muốn sử dụng bộ đầy đủ các uniform trong GlslViewer và GlslCanvas trong openFrameworks một cách đơn giản, tôi xin giới thiệu addon [ofxShader](https://github.com/patriciogonzalezvivo/ofxshader) để hỗ trợ nhiều buffer, chất liệu, hot-reload và tự động chuyển đổi sang OpenGL ES trên Raspberry Pi. Code đơn giản như sau: ```cpp //-------------------------------------------------------------- void ofApp::setup(){ ofDisableArbTex(); sandbox.allocate(ofGetWidth(), ofGetHeight()); sandbox.load("grayscott.frag"); } //-------------------------------------------------------------- void ofApp::draw(){ sandbox.render(); sandbox.draw(0, 0); } ``` Để tìm hiểu thêm về shader trong openFrameworks hãy đọc [bài hướng dẫn tuyệt vời này](http://openframeworks.cc/ofBook/chapters/shaders.html) của [Joshua Noble](http://thefactoryfactory.com/). --- ### 04/Sfml/CMakeLists (04/sfml/CMakeLists.txt) cmake_minimum_required(VERSION 3.15) project(TheBookOfShaders LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(SFML 2.5 COMPONENTS graphics REQUIRED) add_executable(TheBookOfShaders src/main.cpp ) target_link_libraries(TheBookOfShaders sfml-graphics) install(TARGETS TheBookOfShaders RUNTIME DESTINATION .) install(DIRECTORY data DESTINATION .) --- ### 05/README (05/README.md) # Algorithmic drawing ## Shaping functions This chapter could be named "Mr. Miyagi's fence lesson." Previously, we mapped the normalized position of *x* and *y* to the *red* and *green* channels. Essentially we made a function that takes a two dimensional vector (x and y) and returns a four dimensional vector (r, g, b and a). But before we go further transforming data between dimensions we need to start simpler... much simpler. That means understanding how to make one dimensional functions. The more energy and time you spend learning and mastering this, the stronger your shader karate will be. The following code structure is going to be our fence. In it, we visualize the normalized value of the *x* coordinate (`st.x`) in two ways: one with brightness (observe the nice gradient from black to white) and the other by plotting a green line on top (in that case the *x* value is assigned directly to *y*). Don't focus too much on the plot function, we will go through it in more detail in a moment. **Quick Note**: The `vec3` type constructor "understands" that you want to assign the three color channels with the same value, while `vec4` understands that you want to construct a four dimensional vector with a three dimensional one plus a fourth value (in this case the value that controls the alpha or opacity). See for example lines 19 and 25 above. This code is your fence; it's important to observe and understand it. You will come back over and over to this space between *0.0* and *1.0*. You will master the art of blending and shaping this line. This one-to-one relationship between *x* and *y* (or the brightness) is known as *linear interpolation*. From here we can use some mathematical functions to *shape* the line. For example we can raise *x* to the power of 5 to make a *curved* line. Interesting, right? On line 22 try different exponents: 20.0, 2.0, 1.0, 0.0, 0.2 and 0.02 for example. Understanding this relationship between the value and the exponent will be very helpful. Using these types of mathematical functions here and there will give you expressive control over your code, a sort of data acupuncture that let you control the flow of values. [`pow()`](../glossary/?search=pow) is a native function in GLSL and there are many others. Most of them are accelerated at the level of the hardware, which means if they are used in the right way and with discretion they will make your code faster. Replace the power function on line 22. Try other ones like: [`exp()`](../glossary/?search=exp), [`log()`](../glossary/?search=log) and [`sqrt()`](../glossary/?search=sqrt). Some of these functions are more interesting when you play with them using PI. You can see on line 8 that I have defined a macro that will replace any use of `PI` with the value `3.14159265359`. ### Step and Smoothstep GLSL also has some unique native interpolation functions that are hardware accelerated. The [`step()`](../glossary/?search=step) interpolation receives two parameters. The first one is the limit or threshold, while the second one is the value we want to check or pass. Any value under the limit will return `0.0` while everything above the limit will return `1.0`. Try changing this threshold value on line 20 of the following code. The other unique function is known as [`smoothstep()`](../glossary/?search=smoothstep). Given a range of two numbers and a value, this function will interpolate the value between the defined range. The two first parameters are for the beginning and end of the transition, while the third is for the value to interpolate. In the previous example, on line 12, notice that we’ve been using smoothstep to draw the green line on the `plot()` function. For each position along the *x* axis this function makes a *bump* at a particular value of *y*. How? By connecting two [`smoothstep()`](../glossary/?search=smoothstep) together. Take a look at the following function, replace it for line 20 above and think of it as a vertical cut. The background does look like a line, right? ```glsl float y = smoothstep(0.2,0.5,st.x) - smoothstep(0.5,0.8,st.x); ``` ### Sine and Cosine When you want to use some math to animate, shape or blend values, there is nothing better than being friends with sine and cosine. These two basic trigonometric functions work together to construct circles that are as handy as MacGyver’s Swiss army knife. It’s important to know how they behave and in what ways they can be combined. In a nutshell, given an angle (in radians) they will return the correct position of *x* ([cosine](../glossary/?search=cos)) and *y* ([sine](../glossary/?search=sin)) of a point on the edge of a circle with a radius equal to 1. But, the fact that they return normalized values (values between -1 and 1) in such a smooth way makes them an incredible tool. While it's difficult to describe all the relationships between trigonometric functions and circles, the above animation does a beautiful job of visually summarizing these relationships. Take a careful look at this sine wave. Note how the *y* values flow smoothly between +1 and -1. As we saw in the time example in the previous chapter, you can use this rhythmic behavior of [`sin()`](../glossary/?search=sin) to animate properties. If you are reading this example in a browser you will see that you can change the code in the formula above to watch how the wave changes. (Note: don't forget the semicolon at the end of the lines.) Try the following exercises and notice what happens: * Add time (`u_time`) to *x* before computing the `sin`. Internalize that **motion** along *x*. * Multiply *x* by `PI` before computing the `sin`. Note how the two phases **shrink** so each cycle repeats every 2 integers. * Multiply time (`u_time`) by *x* before computing the `sin`. See how the **frequency** between phases becomes more and more compressed. Note that u_time may have already become very large, making the graph hard to read. * Add 1.0 to [`sin(x)`](../glossary/?search=sin). See how all the wave is **displaced** up and now all values are between 0.0 and 2.0. * Multiply [`sin(x)`](../glossary/?search=sin) by 2.0. See how the **amplitude** doubles in size. * Compute the absolute value ([`abs()`](../glossary/?search=abs)) of `sin(x)`. It looks like the trace of a **bouncing** ball. * Extract just the fraction part ([`fract()`](../glossary/?search=fract)) of the resultant of [`sin(x)`](../glossary/?search=sin). * Add the higher integer ([`ceil()`](../glossary/?search=ceil)) and the smaller integer ([`floor()`](../glossary/?search=floor)) of the resultant of [`sin(x)`](../glossary/?search=sin) to get a digital wave of 1 and -1 values. ### Some extra useful functions At the end of the last exercise we introduced some new functions. Now it’s time to experiment with each one by uncommenting the lines below one at a time. Get to know these functions and study how they behave. I know, you are wondering... why? A quick google search on "generative art" will tell you. Keep in mind that these functions are our fence. We are mastering the movement in one dimension, up and down. Soon, it will be time for two, three and four dimensions! ### Advance shaping functions [Golan Levin](http://www.flong.com/) has great documentation of more complex shaping functions that are extraordinarily helpful. Porting them to GLSL is a really smart move, to start building your own resource of snippets of code. * Polynomial Shaping Functions: [www.flong.com/archive/texts/code/shapers_poly](http://www.flong.com/archive/texts/code/shapers_poly/) * Exponential Shaping Functions: [www.flong.com/archive/texts/code/shapers_exp](http://www.flong.com/archive/texts/code/shapers_exp/) * Circular & Elliptical Shaping Functions: [www.flong.com/archive/texts/code/shapers_circ](http://www.flong.com/archive/texts/code/shapers_circ/) * Bezier and Other Parametric Shaping Functions: [www.flong.com/archive/texts/code/shapers_bez](http://www.flong.com/archive/texts/code/shapers_bez/) Like chefs that collect spices and exotic ingredients, digital artists and creative coders have a particular love of working on their own shaping functions. [Iñigo Quiles](http://www.iquilezles.org/) has a great collection of [useful functions](http://www.iquilezles.org/www/articles/functions/functions.htm). After reading [this article](http://www.iquilezles.org/www/articles/functions/functions.htm) take a look at the following translation of these functions to GLSL. Pay attention to the small changes required, like putting the "." (dot) on floating point numbers and using the GLSL name for *C functions*; for example instead of `powf()` use `pow()`: To keep your motivation up, here is an elegant example (made by [Danguafer](https://www.shadertoy.com/user/Danguafer)) of mastering the shaping-functions karate. In the *Next >>* chapter we will start using our new moves. First with mixing colors and then drawing shapes. #### Exercise Take a look at the following table of equations made by [Kynd](http://www.kynd.info/log/). See how he is combining functions and their properties to control the values between 0.0 and 1.0. Now it's time for you to practice by replicating these functions. Remember the more you practice the better your karate will be. #### For your toolbox * [LYGIA](https://lygia.xyz/) is a shader library of reusable functions that can be include easily on your projects. It's very granular, designed for reusability, performance and flexibility. And can be easily be added to any projects and frameworks. It's divided in different sections and it have an entire one for [math operations](https://lygia.xyz/math) * [GraphToy](http://www.iquilezles.org/apps/graphtoy/): once again [Iñigo Quilez](http://www.iquilezles.org) made a tool to visualize GLSL functions in WebGL. --- ### 05/Notes (05/notes.md) ### Scott * _"Essentially we made a function that takes a two dimensional vector (x and y) and returns a four dimensional vector (r, g, b and a)."_ Really? Are you sure that’s what we did? * What is smoothstep()? This example starts to lose me. There are many new elements here. Could you include a step by step walkthrough of this whole example before proceeding to the next part? * Actually, this is the point where you lose me. I want it to be more gradual. It feels like there are 100 new concepts on this one page. ### Nicolas * took the freedom to explain more indepth what interpolation is and why it rocks :) --- ### 05/README Ch (05/README-ch.md) # 算法绘画 ## 造型函数 这一章应该叫做宫城先生的粉刷课(来自电影龙威小子的经典桥段)。之前我们把规范化后的 x,y 坐标映射(map)到了红色和绿色通道。本质上说我们是建造了这样一个函数:输入一个二维向量(x,y),然后返回一个四维向量(r,g,b,a)。但在我们跨维度转换数据之前,我们先从更加…更加简单的开始。我们来建一个只有一维变量的函数。你花越多的时间和精力在这上面,你的 shader 功夫就越厉害。 接下来的代码结构就是我们的基本功。在它之中我们对规范化的 x 坐标(```st.x```)进行可视化。有两种途径:一种是用亮度(度量从黑色到白色的渐变过程),另一种是在顶层绘制一条绿色的线(在这种情况下 x 被直接赋值给 y)。不用过分在意绘制函数,我们马上会更加详细地解释它。 **简注** :```vec3``` 类型构造器“明白”你想要把一个值赋值到颜色的三个通道里,就像 ```vec4``` 明白你想要构建一个四维向量,三维向量加上第四个值(比如颜色的三个值加上透明度)。请参照上面示例的第 19 到 25 行。 这些代码就是你的基本功;遵守和理解它非常重要。你将会一遍又一遍地回到 0.0 到 1.0 这个区间。你将会掌握融合与构建这些代码的艺术。 这些 x 与 y(或亮度)之间一对一的关系称作**线性插值**(linear interpolation)。(译者注:插值是离散函数逼近的重要方法,利用它可通过函数在有限个点处的取值状况,估算出函数在其他点处的近似值。因为对计算机来说,屏幕像素是离散的而不是连续的,计算机图形学常用插值来填充图像像素之间的空隙。)现在起我们可以用一些数学函数来改造这些代码行。比如说我们可以做一个求 x 的 5 次幂的曲线。 很有趣,对吧?试试看把第 22 行的指数改为不同的值,比如:20.0,2.0,1.0,0.0,0.2 或 0.02。理解值和指数之间的关系非常重要。这些数学函数可以让你灵动地控制你的代码,就像是给数据做针灸一样。 [```pow()```](../glossary/?search=pow) (求x的y次幂)是 GLSL 的一个原生函数,GLSL 有很多原生函数。大多数原生函数都是硬件加速的,也就是说如果你正确使用这些函数,你的代码就会跑得更快。 换掉第 22 行的幂函数,试试看[```exp()```](../glossary/?search=exp)(以自然常数e为底的指数函数),[```log()```](../glossary/?search=log)(对数函数) 和 [```sqrt()```](../glossary/?search=sqrt)(平方根函数)。当你用 Pi 来玩的时候有些方程会变得更有趣。在第 5 行我定义了一个宏,使得每当程序调用 ```PI``` 的时候就用 ```3.14159265359``` 来替换它。 ### Step 和 Smoothstep GLSL 还有一些独特的原生插值函数可以被硬件加速。 [```step()```](../glossary/?search=step) 插值函数需要输入两个参数。第一个是极限或阈值,第二个是我们想要检测或通过的值。对任何小于阈值的值,返回 ```0.0```,大于阈值,则返回 ```1.0```。 试试看改变下述代码中第 20 行的值。 另一个 GLSL 的特殊函数是 [```smoothstep()```](../glossary/?search=smoothstep)。当给定一个范围的上下限和一个数值,这个函数会在已有的范围内给出插值。前两个参数规定转换的开始和结束点,第三个是给出一个值用来插值。 在之前的例子中,注意第 12 行,我们用到 smoothstep 在 ```plot()``` 函数中画了一条绿色的线。这个函数会对给出的 x 轴上的每个值,在特定的 y 值处制造一个凹凸形变。如何做到呢?通过把两个 [```smoothstep()```](../glossary/?search=smoothstep) 连接到一起。来看看下面这个函数,用它替换上面的第 20 行,把它想成是一个垂直切割。背景看起来很像一条线,不是吗? ```glsl float y = smoothstep(0.2,0.5,st.x) - smoothstep(0.5,0.8,st.x); ``` ### 正弦和余弦函数 当你想用数学来制造动效,形态或去混合数值,sin 和 cos 就是你的最佳伙伴。 这两个基础的三角函数是构造圆的极佳工具,就像张小泉的剪刀一样称手。很重要的一点是你需要知道它们是如何运转的,还有如何把它们结合起来。简单来说,当我们给出一个角度(这里采用弧度制),它就会返回半径为一的圆上一个点的 x 坐标([cos](../glossary/?search=cos))和 y 坐标([sin](../glossary/?search=sin))。正因为 sin 和 cos 返回的是规范化的值(即值域在 -1 和 1 之间),且如此流畅,这就使得它成为一个极其强大的工具。 尽管描述三角函数和圆的关系是一件蛮困难的事情,上图动画很棒地做到了这一点,视觉化展现了它们之间的关系。 仔细看 sin 曲线。观察 y 值是如何平滑地在 +1 和 -1 之间变化。就像之前章节关于的 time 的例子中,你可以用 [```sin()```](../glossary/?search=sin) 的有节奏的变动给其他东西加动效。如果你是在用浏览器阅读的话你可以改动上述公式,看看曲线会如何变动。(注:不要忘记每行最后要加分号!) 试试下面的小练习,看看会发生什么: * 在 ```sin``` 里让 x 加上时间(```u_time```)。让sin 曲线随 x 轴**动起来**。 * 在 ```sin``` 里用 ```PI``` 乘以 x。注意 sin 曲线上下波动的两部分如何**收缩**了,现在 sin 曲线每两个整数循环一次。 * 在 ```sin``` 里用时间( ```u_time```)乘以 x。观察各阶段的循环如何变得越来越**频繁**。注意 u_time 可能已经变得非常大,使得图像难以辨认。 * 给 [```sin(x)```](../glossary/?search=sin)(注意不是 sin 里的 x)加 1.0。观察曲线是如何向上**移动**的,现在值域变成了 0.0 到 2.0。 * 给 [```sin(x)```](../glossary/?search=sin) 乘以 2.0。观察曲线大小如何**增大**两倍。 * 计算 ```sin(x)``` 的绝对值([```abs()```](../glossary/?search=abs))。现在它看起来就像一个**弹力球**的轨迹。 * 只选取 ```sin(x)``` 的小数部分([```fract()```](../glossary/?search=fract))。 * 使用向正无穷取整([```ceil()```](../glossary/?search=ceil))和向负无穷取整([```floor()```](../glossary/?search=floor)),使得 sin 曲线变成只有 1 和 -1 的电子波。 ### 其他有用的函数 最后一个练习中我们介绍了一些新函数。现在我们来一个一个试一遍。依次取消注释下列各行,理解这些函数,观察它们是如何运作的。你一定在奇怪……为什么要这么做呢?Google 一下“generative art”(生成艺术)你就知道了。要知道这些函数就是我们的栅栏。我们现在控制的是它在一维中的移动,上上下下。很快,我们就可以尝试二维、三维甚至四维了! ### 造型函数进阶 [Golan Levin](http://www.flong.com/) 写过关于更加复杂的造型函数的文档,非常有帮助。把它们引入 GLSL 是非常明智的选择,这将是你的代码的广阔的素材库 * [多项式造型函数(Polynomial Shaping Functions): www.flong.com/archive/texts/code/shapers_poly](http://www.flong.com/archive/texts/code/shapers_poly/) * [指数造型函数(Exponential Shaping Functions): www.flong.com/archive/texts/code/shapers_exp](http://www.flong.com/archive/texts/code/shapers_exp/) * [圆与椭圆的造型函数(Circular & Elliptical Shaping Functions): www.flong.com/archive/texts/code/shapers_circ](http://www.flong.com/archive/texts/code/shapers_circ/) * [贝塞尔和其他参数化造型函数(Bezier and Other Parametric Shaping Functions): www.flong.com/archive/texts/code/shapers_bez](http://www.flong.com/archive/texts/code/shapers_bez/) 就像厨师自主选择辣椒和各种原料,数字艺术家和创意编程者往往钟情于使用他们自己的造型函数。 [Iñigo Quiles](http://www.iquilezles.org/) 收集了一套[有用的函数](http://www.iquilezles.org/www/articles/functions/functions.htm)。在看过[这篇文章](http://www.iquilezles.org/www/articles/functions/functions.htm)后,看看下列函数转换到 GLSL 的样子。注意那些细小的改变,比如给浮点数(float)加小数点“.”,给“C 系函数”换成它们在 GLSL 里的名字,比如不是用 ```powf()``` 而是用 ```pow()```: * [Impulse](../edit.php#05/impulse.frag) * [Cubic Pulse](../edit.php#05/cubicpulse.frag) * [Exponential Step](../edit.php#05/expstep.frag) * [Parabola](../edit.php#05/parabola.frag) * [Power Curve](../edit.php#05/pcurve.frag) 给你们看些东西刺激一下斗志,这里有一个非常优雅的例子(作者是 [Danguafer](https://www.shadertoy.com/user/Danguafer),造型函数的空手道黑带)。 在下一章我们会有一些新的进展。我们会先混合各种颜色,然后画些形状。 #### 练习 来看看 [Kynd](http://www.kynd.info/log/) 帮大家制作的公式表。看他如何结合各种函数及它们的属性,始终控制值的范围在 0.0 到 1.0。好了,现在是你自己练习的时候了!来试试这些函数,记住:熟能生巧。 #### 填充你的工具箱 这里有一些工具可以帮你更轻松地可视化这些函数。 * [GraphToy](http://www.iquilezles.org/apps/graphtoy/):仍然是 [Iñigo Quilez](http://www.iquilezles.org) 为大家做的工具,用于在 WebGL 中可视化 GLSL 函数。 * [LYGIA Shader Library](https://lygia.xyz/) a shader library of reusable functions that can be include easily on your projects. It's very granular, designed for reusability, performance and flexibility. And can be easily be added to any projects and frameworks. --- ### 05/README De (05/README-de.md) # Algorithmisches Zeichnen ## Modellierungsfunktionen Dieses Kapitel könnte auch die Überschrift „Mr. Miyagi's Zaun- Lektion“ tragen, in Anspielung auf den Film „Karate Kid“ aus dem Jahre 1984. Bislang haben wir die normalisierte Position von *x* und *y* auf den *roten* und *grünen* Farbkanal des jeweiligen Punktes abgebildet. Wir haben dazu eine Funktion gebaut, die im Wesentlichen einen zweidimensionalen Vektor (*X* und *Y*) entgegennimmt und einen vierdimensionalen Vektor (*Rot*, *Grün*, *Blau* und *Alpha*) zurückliefert. Aber bevor wir damit fortfahren, Daten zwischen verschiedenen Dimensionen zu transformieren, müssen wir mit einfacheren Aufgaben beginnen. Und zwar mit viel einfacheren Aufgaben. Ich meine damit das Verständnis eindimensionaler Funktionen. Desto mehr Zeit und Energie Du darauf verwendest, desto stärker wird Dein Shader-Karate sein. Die folgende Codestruktur ist unser Zaun, an dem wir in Anlehnung an die Geschichte von „Karate Kid“ üben werden. Wir visualisieren damit den normalisierten Wert der *X-Ordinate* (```st.x```) auf zweierlei Weise: einmal in Form der Helligkeit (beachte den weichen, schrittweisen Übergang von Schwarz zu Weiß) und außerdem indem wir die Werte in Form einer grünen (Funktions-) Linie darstellen (der jeweilige *X-Wert* wird dabei eins-zu-eins auf den *Y-Wert* abgebildet). Halte Dich dabei bitte nicht zu lange mit der *plot()*-Funktion auf, denn darauf werden wir gleich noch im Detail eingehen. **Ein kurzer Hinweis**: Der Konstruktor des ```vec3```-Datentyps „versteht“, wenn Du allen drei Farbkanälen durch die Angabe eines einzigen Parameters diesen einen gleichen Wert zuweisen willst. In diesem Fall erhält man immer einen Grauton zwischen Schwarz ```(0.0, 0.0, 0.0)``` und Weiß ```(1.0, 1.0, 1.0)```. Ebenso versteht der Konstruktor des ```vec4```-Datentyps, wenn Du einen vierdimensionalen Vektor aus einem dreidimensionalen Vektor erzeugen willst. Der dreidimensionale Vektor verkörpert in diesem Fall den *RGB-Farbwert*, der zusätzliche Parameter den Wert für den *Alpha-Kanal*, also die Deckkraft. Dies geschieht hier in den *Programmzeilen 19 und 25*. Dieser Programmcode ist Dein Zaun, an dem Du das Streichen bzw. Malen üben kannst. Es ist wichtig, dass Du Dir den Code genau anschaust und ihn verstehst. Denn die darin enthaltenen Konzepte, wie etwa die Normalisierung von *x* und *y* auf Werte zwischen *0.0* und *1.0*, werden uns weiterhin begleiten. Die hier genutzte Eins-zu-Eins-Abbildung zwischen *x* und *y* (in diesem Fall als Helligkeit genutzt) wird als *lineare Interpolation* bezeichnet. Davon abweichend können wir auch unterschiedliche mathematische Funktionen nutzen, um der Linie eine andere Form zu geben. So können wir zum Beispiel *x hoch 5* einsetzen, um eine geschwungene, steil ansteigende Kurve zu erzeugen. Interessant, nicht wahr? Versuche einfach einmal, in der *Zeile 22* andere Exponenten wie beispielsweise ```20.0```, ```2.0```, ```1.0```, ```0.0```, ```0.2``` und ```0.02``` einzusetzen. Das Verständnis zwischen dem Exponenten und den daraus resultierenden Werten wird Dir sicher weiterhelfen. Schließlich ist es der geschickte Einsatz dieser und anderer mathematischer Funktionen, die Dir bei der Shader-Programmierung unglaubliche Möglichkeiten eröffnen. [```pow()```](../glossary/?search=pow) ist eine eingebaute mathematische Funktion von GLSL. Daneben gibt es noch viele weitere. Die meisten davon können sehr schnell in der Hardware der Grafikkarte ausgeführt werden. Ihr geschickter Einsatz beschleunigt deshalb die Ausführung Deiner Shader. Ersetze die Funktion *pow* in der *Zeile 22* durch eine andere Funktion und beobachte das Resultat. Probiere zum Beispiel die folgenden Funktionen aus: [```exp()```](../glossary/?search=exp), [```log()```](../glossary/?search=log) und [```sqrt()```](../glossary/?search=sqrt). Einige dieser Funktionen erzeugen interessantere Ergebnisse, wenn man sie in Verbindung mit einem Vielfachen oder einem Bruchteil der Kreiszahl *pi* nutzt. In der *Programmzeile 8* findest Du deshalb ein Makro, dass das Symbol ```PI``` innerhalb des Programmcodes durch den zugehörigen Wert ```3.14159265359``` ersetzt. ### Step und Smoothstep GLSL bringt auch einige einzigartige Interpolationsfunktionen mit, die durch die Hardware beschleunigt werden. Die Interpolationsfunktion [```step()```](../glossary/?search=step) nimmt zwei Argumente entgegen: Das erste verkörpert den Schwellenwert, während das zweite Argument den Wert darstellt, der mit diesem Schwellenwert verglichen werden soll. Liegt dieser Wert unterhalb des Schwellenwerts, liefert die Funktion ```0.0``` zurück, bei jedem Wert größer oder gleich dem Schwellenwert hingegen ```1.0```. Ändere im folgenden Programmcode doch einfach einmal den Schwellenwert in *Zeile 20* und beobachte, was dann passiert. Die zweite eingebaute Interpolationsfunktion trägt den Namen [```smoothstep()```](../glossary/?search=smoothstep). Sie interpoliert einen Wert, sofern sich dieser innerhalb eines angegebenen Wertbereichs befindet. Die ersten zwei Argumente stellen dabei die untere und die obere Schwelle dieses Wertebereichs dar, während das dritte Argument den zu interpolierenden Wert verkörpert. Die Funktion liefert ```0.0``` zurück, wenn der zu interpolierende Wert unterhalb des genannten Schwellenwerts liegt, also kleiner als das erste Argument ist. Analog dazu liefert sie ```1.0``` zurück, wenn der zu interpolierende Wert größer als der obere Schwellenwert ist. Befindet sich der zu interpolierende Wert jedoch innerhalb der gegebenen Spanne, wird ein Wert zwischen ```0.0``` und ```1.0``` zurückgeliefert, je nachdem wie nahe sich der Wert am oberen oder unteren Ende der Spanne befindet. Genau in der Mitte lautet das Ergebnis ```0.5```. Wie das folgende Programm zeigt, ist das Ergebnis jedoch nicht vollständig linear, sondern am oberen und unteren Ende des Wertebereichs etwas „abgerundet“. Dadurch wird in den Randbereichen bewusst ein etwas weicherer Übergang erzielt, falls sich weitere interpolierte Werte anschließen. Im obigen Beispiel nutzen wir die ```smoothstep()```-Funktion innerhalb der ```plot()```-Funktion, um die grüne Linie zu erzeugen, die die Ergebnisse aus der Y-Berechnung in *Zeile 20* darstellt. Siehst Du, wie diese grüne Linie nach oben und unten jeweils ein wenig ausfedert und sanft in den Hintergrund übergeht? Das erreichen wir, indem wir in *Zeile 12 und 13* zwei Aufrufe von [```smoothstep()```](../glossary/?search=smoothstep) miteinander verbinden. Schau Dir die folgende Berechnung an und setze sie in die *Zeile 20* ein. ```glsl float y = smoothstep(0.2,0.5,st.x) - smoothstep(0.5,0.8,st.x); ``` Die Formel entspricht dem Vorgehen innerhalb der ```plot()```-Funktion. Sie symbolisiert, wie ```plot()``` genau in der Mitte (auf dem gegebenen Y-Wert) ein volles Grün erzeugt (Rückgabewert ```1.0```), während bei Werten darunter und darüber ein weicher Übergang zur Hintergrundfarbe erfolgt (Rückgabewerte von ```1.0``` langsam absteigend zu ```0.0```). ### Sinus und Cosinus Wenn man mathematische Funktionen nutzen möchte, um Grafiken zu animieren, in eine geschwungene Form zu bringen oder sanft ein- und auszublenden, gibt es nichts Besseres, als sich mit Sinus und Cosinus anzufreunden. Diese beiden trigonometrischen Funktionen sind so praktisch wie ein Schweizer Offiziersmesser, wenn es darum geht, Kreise zu konstruieren. Es ist wichtig zu verstehen, wie sich die beiden Funktionen einzeln verhalten und wie man sie gemeinsam nutzen kann. Kurz gesagt, bei einem gegebenen Winkel (in Form eines Bogenmaßes) liefern sie die korrekte *x*- ([*Cosinus*](../glossary/?search=cos)) und *y*- ([*Sinus*](../glossary/?search=sin)) Ordinate für die Position des zugehörigen Punktes auf einem Einheitskreis mit dem Radius ```1```. Weil die zurückgelieferten Funktionsergebnisse dabei immer dynamisch zwischen ```-1.0``` und ```1.0``` oszillieren, sind diese Funktionen ein ungeheuer praktisches Werkzeug für vielerlei Aufgaben. Es ist nicht ganz leicht, alle Zusammenhänge zwischen trigonometrischen Funktionen auf der einen Seite und Kreisen auf der anderen Seite zu beschreiben. Die obige Animation zeigt jedoch sehr schön die oben zitierte Rolle von *Sinus* und *Cosinus* bei der Erzeugung eines Einheitskreises. Schau Dir die Sinuswelle genau an und beobachte, wie der daraus abgeleitete Wert für die Y-Ordinate auf dem Einheitskreis sanft zwischen ```+1``` und ```-1``` oszilliert. Und mit der Cosinuswelle erzeugen wir die zugehörige X-Ordinate. Wie wir in dem zeitbasierten Beispiel im vorangegangenen Kapitel gesehen haben, lässt sich dieses rhythmische Verhalten von [```sin()```](../glossary/?search=sin) gut nutzen, um bestimmte Werte und Eigenschaften zu animieren. Wenn Du diesen Text in einem Internet-Browser liest, wirst du feststellen, dass Du die obige Formel *y=sin(x);* editieren kannst, um zu sehen, wie sich die Funktionskurve dadurch ändert. (Hinweis: Bitte nicht das Semikolon am Ende der Zeile vergessen, sonst gibt es einen Syntaxfehler.) Probiere die folgenden Übungen aus und beobachte, was daraufhin geschieht: * Addiere die Zeit (```u_time```) zu *x* hinzu, bevor Du aus der Summe den ```sin``` berechnest. Verinnerliche die daraus entstehende **Bewegung** entlang der *x-Achse*. * Multipliziere *x* mit ```PI```, bevor Du den ```sin``` berechnest. Beobachte, wie sich die Phasenlänge auf jeweils 2 Einheiten entlang der X-Achse verkürzt und sich die Schwingung dann wiederholt. Dadurch verdoppelt sich also die Frequenz. * Multipliziere die Zeit (```u_time```) mit *x*, bevor Du daraus den ```sin``` berechnest. Du wirst sehen, wie die einzelnen Wellen so weit zusammengedrückt werden, dass das Ergebnis wie ein unidentifizierbares Rauschen wirkt. * Addiere den Wert ```1.0``` zum Ergebnis von [```sin(x)```](../glossary/?search=sin) hinzu und beobachte, wie sich die Welle dadurch nach oben verschiebt und jeweils zwischen den Werten von ```0.0``` und ```2.0``` oszilliert. * Multipliziere [```sin(x)```](../glossary/?search=sin) mit ```2.0```. Du wirst feststellen, dass sich die Amplitude der Schwingung (die Minimal- und Maximalwerte) verdoppelt. * Lass den absoluten Wert ([```abs()```](../glossary/?search=abs)) von ```sin(x)``` berechnen. Der entstehende Graph erinnert an die Spur eines hüpfenden Balls, nicht wahr? * Lass nur den Nachkommateil ([```fract()```](../glossary/?search=fract)) des Resultats von [```sin(x)```](../glossary/?search=sin) berechnen. * Addiere jeweils den höheren Integer-Wert ([```ceil()```](../glossary/?search=ceil)) von [```sin(x)```](../glossary/?search=sin) und den kleineren Integer-Wert ([```floor()```](../glossary/?search=floor)) von [```sin(x)```](../glossary/?search=sin), um eine digitale Welle zwischen ```1``` und ```-1``` zu erhalten. ### Einige besonders nützliche Funktionen Am Ende der letzten Übung haben wir einige neue Funktionen eingeführt. Jetzt ist es an der Zeit, mit diesen Funktionen zu experimentieren, indem Du Schritt für Schritt die Kommentarzeichen aus den folgenden Programmzeilen entfernst. Lerne diese Funktionen kennen und beobachte, wie sie funktionieren. Du wirst Dich vielleicht fragen, warum? Eine Google-Suche nach „generativer Kunst“ bzw. „generative art“ wird Dir diese Frage schnell beantworten. Denke daran, dass diese Funktionen wie der Zaun aus „Karate Kid“ sind. Noch bewegen wir uns nur in einer Dimension, aufwärts und abwärts. Aber bald schon geht es damit in zwei, drei und vier Dimensionen! ### Fortgeschrittene formgebende Funktionen [Golan Levin](http://www.flong.com/) hat eine großartige Dokumentation über komplexe formgebende Funktionen verfasst, die für unsere Zwecke extrem hilfreich ist. Indem Du einen Teil dieser Funktionen nach GLSL portierst, schaffst Du Dir eine wertvolle Sammlung an Codeschnipseln. * [Polynomische formgebende Funktionen: www.flong.com/archive/texts/code/shapers_poly](http://www.flong.com/archive/texts/code/shapers_poly/) * [Exponentielle formgebende Funktionen: www.flong.com/archive/texts/code/shapers_exp](http://www.flong.com/archive/texts/code/shapers_exp/) * [Kreisförmige & elliptische formgebende Funktionen: www.flong.com/archive/texts/code/shapers_circ](http://www.flong.com/archive/texts/code/shapers_circ/) * [Bezier und andere parametrische formgebende Funktionen: www.flong.com/archive/texts/code/shapers_bez](http://www.flong.com/archive/texts/code/shapers_bez/) Genau wie Küchenchefs Gewürze und exotische Zutaten sammeln, entwickeln Digitalkünstler und kreative Entwickler häufig eine Liebe für bestimmte formgebende Funktionen. [Inigo Quiles](http://www.iquilezles.org/) stellt eine großartige Auswahl an [nützlichen Funktionen](http://www.iquilezles.org/www/articles/functions/functions.htm) vor. Wenn Du [diesen Artikel](http://www.iquilezles.org/www/articles/functions/functions.htm) gelesen hast, dann werfe einen Blick auf die folgenden Übertragungen dieser Funktionen nach GLSL. Beobachte aufmerksam die kleinen, aber erforderlichen Anpassungen wie etwa den Punkt (".") bei Fließkommazahlen und die Umsetzung der Funktionsnamen von C auf GLSL; so heißt es in GLSL beispielsweise ```pow()``` statt ```powf()``` wie in C: Um Deine Motivation zu erhalten, hier ein elegantes Beispiel (entwickelt von [Danguafer](https://www.shadertoy.com/user/Danguafer)) für die Meisterschaft im Karate der formgebenden Funktionen. Im nächsten Kapitel werden wir neue Schrittfolgen für unser „Karate“ lernen. Zunächst beim Mischen von Farben, dann beim Malen von Formen. ####Übung Wirf einen Blick auf die folgende Tabelle mit Gleichungen, die von [Kynd](http://www.kynd.info/log/) erstellt wurde. Schau Dir an, wie er Funktionen und ihre Eigenschaften kombiniert, um Werte zwischen ```0.0``` und ```1.0``` zu erhalten. Jetzt ist ein guter Moment, um mit diesen Funktionen ein wenig zu experimentieren. Denn je mehr Du in dieses Denken hineinwächst, desto besser wird Dein Karate sein. ####Für Deine Werkzeugsammlung Hier kommen einige Tools, die es Dir erleichtern werden, diese Art von Funktionen grafisch zu visualisieren. * [GraphToy](http://www.iquilezles.org/apps/graphtoy/): Einmal mehr ein Werkzeug von [Inigo Quilez](http://www.iquilezles.org), mit dem man GLSL-Funktionen in WebGL darstellen kann. * [LYGIA Shader Library](https://lygia.xyz/) a shader library of reusable functions that can be include easily on your projects. It's very granular, designed for reusability, performance and flexibility. And can be easily be added to any projects and frameworks. --- ### 05/README Es (05/README-es.md) # Dibujando con algoritmos ## Funciones de forma Este capítulo se podría llamar "La lección de la cerca del Sr Miyagi". Anteriormente normalizamos la posición de x e y al canal de rojo y verde. Esencialmente creamos una función que tomaba dos vectores dimensionales (x e y) y devolvía un vector de cuatro dimensiones (rojo, verde, azul y transparencia). Pero antes de ir más lejos, transformando valores entre dimensiones, necesitamos comenzar con algo sencillo... mucho más sencillo. Eso significa comprender las funciones unidimensionales. A mayor tiempo y energía que pongas en aprender esto, mejor será tu karate. El siguiente código va a ser nuestra cerca. Dentro del código visualizamos el valor normalizado de la coordenada *x* (```st.x```) de dos maneras: una visualizando el brillo (observa el bonito gradiente de fondo del negro al blanco) y otra dibujando una línea verde arriba (en este caso el valor de *x* es asignado directamente al valor de *y*). No te enfoques mucho en la función plot, la veremos en detalle en unos momentos. **Nota rápida**: el constructor de ```vec3``` "entiende" que quieres asignar tres colores con la misma variable, mientras que el ```vec4``` entiende que quieres crear un vector tridimensional con un cuarto valor (en este caso el que controla el alpha). Mira por ejemplo la línea 19 y la 25 de arriba. Este código es tu cerca; es importante observarlo y entenderlo. Volverás aquí una y otra vez, a este espacio entre el *0.0* y el *1.0*. Aprenderás el arte de doblar y dar forma a esta línea. Esta relación par entre *x* e *y* (o el brillo) es conocida como *interpolación lineal*. Desde aquí podemos utilizar funciones matemáticas para darle *forma* a esta línea. Por ejemplo podemos elevar *x* a la quinta potencia para generar una línea curva. Interesante ¿No? En la línea 22 puedes probar diferentes exponentes: 20.0, 2.0, 1.0, 0.0, 0.2 o 0.02 por ejemplo. Entender esta relación entre el valor y el exponente nos será muy útil. Usar este tipo de funciones matemáticas aquí y allá nos dará un control expresivo sobre nuestro código, como si fuese un tipo de acupuntura con el que manejas el flujo de los valores. [```pow()```](../glossary/?search=pow) es una función nativa en GLSL y hay muchas más. La mayoría de ellas son aceleradas por hardware, lo que significa que, usadas de la forma correcta, harán tu código mucho más rápido. Reemplaza la función de la línea 19. Prueba otras como: [```exp()```](../glossary/?search=exp), [```log()```](../glossary/?search=log) y [```sqrt()```](../glossary/?search=sqrt). Algunas de estas funciones son mucho más interesantes cuando las usamos con PI. En la línea 8 definí un macro que reemplaza cualquier llamado a ```PI``` por el valor ```3.14159265359```. ### Step y Smoothstep GLSL también cuenta con algunas funciones únicas de interpolación, que también son aceleradas por hardware. La interpolación [```step()```](../glossary/?search=step) recibe dos parámetros. El primero es el límite o umbral, el segundo es el valor que queremos chequear. Cualquier número por debajo del límite devuelve ```0.0``` todo lo que lo supere devuelve ```1.0```. Intenta cambiar el límite en la línea 20 del siguiente código. La otra función única es el [```smoothstep()```](../glossary/?search=smoothstep). Dado un rango de dos números y un valor, esta función interpola el valor entre el rango definido. Los primeros dos parámetros son para el comienzo y el final de la transición, el tercero es el valor a interpolar. En el anterior ejemplo, en la línea 12, hemos usado smoothstep para dibujar una línea verde en la función ```plot()```. Por cada posición en el eje x esta función crea una salto en un valor particular de y. ¿Cómo? Conectando dos [```smoothstep()```](../glossary/?search=smoothstep) juntos. Observa la siguiente función y reemplaza la línea 20 por esta, y piensa en ella como un corte vertical. El fondo se parece a una línea ¿No? ```glsl float y = smoothstep(0.2,0.5,st.x) - smoothstep(0.5,0.8,st.x); ``` ### Seno y Coseno Cuando queremos usar un poco de matemática para animar, dar forma o mezclar valores, no hay nada mejor que ser amigos del seno y del coseno. Estas dos funciones básicas trigonométricas trabajan juntas creando círculos y son más útiles que la navaja suiza de MacGyver. Es importante saber como se comportan y de que forma pueden ser combinadas. En pocas palabras, dado un ángulo (en radianes) devolverán la posición de *x* ([coseno](../glossary/?search=cos)) e y ([seno](../glossary/?search=sin)) de un punto en el borde de un círculo con un radio igual a 1. Como estas funciones devuelven un valor normalizado (entre -1 y 1) y suavizado, terminan siendo una herramienta increíble. Como es difícil describir la relación entre las funciones trigonométricas y los círculos, la hermosa animación de arriba hace el trabajo de explicarlo visualmente. Presta mucha atención a esta curva sinusoidal. Nota como los valores de Y fluyen suavemente entre -1 y 1. Como vimos en el anterior capítulo, podemos utilizar el comportamiento rítmico de [```sin()```](../glossary/?search=sin) para animar propiedades. Si estás leyendo este ejemplo en un navegador, puedes modificar la fórmula que aparece aquí arriba y ver cómo cambia la onda. (Nota: No olvidar el punto y coma al final.) Completa los siguientes ejercicios y presta atención a lo que sucede: * Suma el tiempo (```u_time```) a *x* antes de computar el ```sin```. Observa detenidamente ese **movimiento** a lo largo de *x*. * Multiplica *x* por ```PI``` antes de computar el ```sin```. Nota como las dos fases se **encogen** y cada ciclo se repite dos veces. * Multiplica el tiempo (```u_time```) por *x* antes de computar el ```sin```. Observa como la **frecuencia** entre las fases se comprime más y más. Nota que u_time en un momento pasa a ser un número muy alto y se hace difícil ver el gráfico. * Suma 1.0 a [```sin(x)```](../glossary/?search=sin). Observa como toda la onda es **desplazada** hacia arriba y ahora todos los valores van de 0.0 a 2.0. * Multiplica [```sin(x)```](../glossary/?search=sin) por 2.0. Mira como la **amplitud** duplica su tamaño. * Calcula el valor absoluto ([```abs()```](../glossary/?search=abs)) de ```sin(x)```. Observa como se parece a la trayectoria de una pelota **rebotando**. * Extrae sólo la parte fraccionaria ([```fract()```](../glossary/?search=fract)) del resultado de [```sin(x)```](../glossary/?search=sin). * Suma el mayor entero más cercano ([```ceil()```](../glossary/?search=ceil)) y el menor entero más cercano ([```floor()```](../glossary/?search=floor)) del resultado de [```sin(x)```](../glossary/?search=sin) para obtener la onda digital de 1.0 y -1.0. ### Otras funciones útiles Al final del último ejercicio hemos introducido algunas funciones nuevas. Ahora es el momento de experimentar con cada una descomenteando las siguientes lineas, de a una. Es importante entender estas funciones y estudiar como se comportan. Ya lo sé ¿Para qué? Si buscas rápidamente en Google "Arte Generativo" vas a entender el por qué. Ten en cuenta que estas funciones son nuestra cerca. Estamos dominando el movimiento en una sola dimensión, arriba y abajo. ¡Pronto, será el momento de agregar la segunda, la tercera y la cuarta dimensión! ### Funciones de forma avanzadas [Golan Levin](http://www.flong.com/) tiene en su página documentación muy útil sobre cómo generar formas complejas con funciones. Trasladar estas funciones a GLSL es una muy buena forma de comenzar a generar nuestras propias piezas de código. * [Polynomial Shaping Functions: www.flong.com/archive/texts/code/shapers_poly](http://www.flong.com/archive/texts/code/shapers_poly/) * [Exponential Shaping Functions: www.flong.com/archive/texts/code/shapers_exp](http://www.flong.com/archive/texts/code/shapers_exp/) * [Circular & Elliptical Shaping Functions: www.flong.com/archive/texts/code/shapers_circ](http://www.flong.com/archive/texts/code/shapers_circ/) * [Bezier and Other Parametric Shaping Functions: www.flong.com/archive/texts/code/shapers_bez](http://www.flong.com/archive/texts/code/shapers_bez/) Como los chefs que colectan especias e ingredientes exóticos, los artistas digitales y creative coders tienen un amor particular por crear sus propias funciones de dibujo. [Iñigo Quiles](http://www.iquilezles.org/) tiene una gran colección de [funciones útiles](http://www.iquilezles.org/www/articles/functions/functions.htm). Después de leer [este artículo](http://www.iquilezles.org/www/articles/functions/functions.htm) echa un vistazo a la traducción de esas funciones a GLSL. Presta atención a los pequeños cambios necesarios, como poner "." (punto) en los valores flotantes y usar los nombres en GLSL de las *funciones en C*; por ejemplo en vez de ```powf()``` usamos ```pow()```: * [Impulse](../edit.php#05/impulse.frag) * [Cubic Pulse](../edit.php#05/cubicpulse.frag) * [Exponential Step](../edit.php#05/expstep.frag) * [Parabola](../edit.php#05/parabola.frag) * [Power Curve](../edit.php#05/pcurve.frag) Para que te mantengas motivado, aqui hay un elegante ejemplo (hecho por [Danguafer](https://www.shadertoy.com/user/Danguafer)) de alguien que logró dominar su karate en las funciones. En el *Siguiente >>* capítulo comenzaremos a usar nuevos movimientos. Primero mezclaremos color y luego dibujaremos formas. #### Ejercicio Presta atención a la siguiente tabla de ecuaciones hecha por [Kynd](http://www.kynd.info/log/). Observa como combina las funciones y sus propiedades para controlar los valores de 0.0 a 1.0. Ahora es el momento de practicar replicando estas funciones. Recuerda que cuanto más practiques esto, mejor será tu karate. #### Para tu caja de herramientas Estas son algunas herramientas que te ayudarán a visualizar este tipo de funciones. * [GraphToy](http://www.iquilezles.org/apps/graphtoy/): una vez más [Iñigo Quilez](http://www.iquilezles.org) ha creado una herramienta para visualizar funciones GLSL en WebGL. * [LYGIA Shader Library](https://lygia.xyz/) a shader library of reusable functions that can be include easily on your projects. It's very granular, designed for reusability, performance and flexibility. And can be easily be added to any projects and frameworks. --- ### 05/README Fr (05/README-fr.md) # Dessin Algorithmique ## Fonctions de formes Ce chapitre aurait pu s'appeler "la palissade de monsieur Miyagi" ([pour ceux qui n'étaient pas nés en 1984](https://fr.wikipedia.org/wiki/Karat%C3%A9_Kid_(film,_1984))). Au chapitre précédent, nous avons *mappé* les coordonnées *x* et *y* *normalisées* sur les canaux *rouge* et *vert*. Nous avons créé une *fonction* qui prend un vecteur à deux dimensions (x et y) et retourne un vecteur à quatre dimensions (r, g, b et a). Avant de transformer des données à plusieurs dimensions, il nous faut commencer par des choses simples... beaucoup plus simples. Concrètement, nous devons comprendre commment marchent les fonctions à une dimension. Plus vous passerez de temps à apprendre et à maîtriser ces fonctions, plus votre Karaté-Shader sera redoutable. Le code suivant sera notre palissade. Sur cette palissade, nous visualisons la valeur normalisée de la position *x* (`st.x`) de deux façons : la luminosité (c'est le joli dégradé du noir au blanc en arrière plan) et une ligne verte dessinée par dessus (dans ce cas, la valeur *x* est assignée directement à *y*). Ne vous focalisez pas trop sur la fonction `plot` pour l'instant, nous y reviendrons en détail dans un moment. **Note**: Le constructeur du type `vec3`, un vecteur à 3 dimensions (`r,g,b` ou `x,y,z` ; c'est la même chose), "comprend" que vous allez le construire avec la même valeur pour les trois canaux / dimensions. Il est donc possible d'ecrire `vec3 color = vec3(y);` pour construire un vecteur à 3 dimensions. Ce vecteur aura la valeur `y` assignée à chaque canal / dimension soit : `color.x = color.y = color.z = y` ou `color.r = color.g = color.b = y` (puisqu'on peut accéder aux variables du vecteur des 2 manières). Le constructeur du type `vec4` en revanche, "comprend" que vous allez le construire, soit en passant quatre valeurs dinstinctes : `vec4(0., 0.5, 1., 1.)`, soit en lui passant un `vec3` et un `float` (un nombre) : `vec4(color, 1.)`. Dans notre cas, la valeur du second paramètre (le `float`), permet de gérer l'*opacité* aussi appelé l'*alpha*. Référez vous aux lignes 19 et 25 dans l'exemple ci-dessus pour bien voir la différence de construction des 2 types. Ce code sera votre palissade ; il est important de bien l'observer et de bien le comprendre. Vous reviendrez souvent dans cet espace entre *0.0* et *1.0* pour maîtriser l'art de le transformer et de sculpter cette ligne. La relation entre *x* et *y* (la luminosité du dégradé), s'appelle une *interpolation*. Comme on passe une seule valeur (*y*) à la variable *color*, on obtient un niveau de gris et comme la valeur de *x* est *normalisée*, elle est comprise entre *0.0* et *1.0*, on obtient un dégradé du noir (*x=0.*) au blanc (*x=1.*). L'*interpolation* est un principe fondamental ; elle nous permet de faire passer progressivement une valeur de *A* vers *B* en fonction d'une troisième valeur *T* normalisée entre *0.0* et *1.0*. La ligne verte reflète ce qui se passe lors de l'interpolation, en l'occurrence, c'est une ligne droite puisque *x* passe de *0.0* à *1.0* de façon linéaire (*x* va de *0.0* à *1.0* de façon continue). A partir de là, nous pouvons utiliser des fonctions mathématiques pour *sculpter* la ligne. Par exemple, on peut passer *x* à la puissance 5 pour créer une ligne *courbe*. Intéressant n'est-ce-pas ? A la ligne 19, au lieu de `5.0` essayez différents exposants, par exemple: `20.0`, `2.0`, `1.0`, `0.0`, `0.2` et `0.02`. Comprendre la relation qui existe entre la valeur et l'exposant va nous être très utile. Ce genre de fonction mathématique nous donne un contrôle sur l'*expressivité* du code, c'est une sorte d'acupuncture qui permet de contrôle les flux de valeurs. [`pow()`](../glossary/?search=pow) est une fonction native de GLSL et il y en a de nombreuses autres. La plupart sont accélérées matériellement, ce qui signifie que si on les utilise bien et avec parcimonie, elle permettent au code de s'exécuter plus vite. Essayez de remplacer la fonction `pow()` ligne 19 par: [`exp()`](../glossary/?search=exp), [`log()`](../glossary/?search=log) ou [`sqrt()`](../glossary/?search=sqrt). Certaines de ces fonctions deviennent vraiment intéressantes quand on les utilise avec PI. Vous pouvez voir que j'ai déclaré une macro qui remplacera chaque appel à `PI` par la valeur `3.14159265359`. Par exemple : `sin(st.x * PI)`, produira une parabole, `pow(sin(st.x * PI), 5.)` effectuera un *pincement* de la parabole. ### Step et Smoothstep GLSL propose également des fonctions d'interpolation natives et accélérées matériellement. La fonction [`step()`](../glossary/?search=step) prend 2 paramètres, le premier est une *limite* ou un *seuil* et le second est la valeur à tester. Toute valeur inférieure au *seuil* renverra `0.0` tandis que toute valeur supérieure au *seuil* renverra `1.0`. Essayez de changer la valeur de *seuil* à la ligne 20 du code suivant : L'autre fonction d'interpolation s'appelle [`smoothstep()`](../glossary/?search=smoothstep). Avec deux nombres *A* et *B* et une valeur d'interpolation *T* comprise entre *0.0* et *1.0*, elle nous permet de passer progressivement (et en souplesse) de *A* à *B* en fonction de *T*. Les deux premiers arguments sont les *bornes* (*A* et *B*) et le troisième est la valeur d'interpolation (*T*). Dans l'exemple ci-dessus, ligne 12, vous remarquez qu'on a utilisé `smoothstep()` depuis le début dans la fonction `plot()` qui permet de dessiner la ligne verte. Pour chaque position le long de l'axe des *x*, cette fonction crée une *bosse* à un endroit précis de l'axe des *y*. Comment ? en combinant deux appels à [`smoothstep()`](../glossary/?search=smoothstep). Remplacez la ligne 20 par la fonction suivante et regardez l'arrière plan, on dirait une ligne floutée non ? En rapprochant les valeurs de *seuil* des `smoothstep()` (*0.45, 0.5* et *0.5, 0.55* par exemple), la ligne devient plus fine et moins floue. ```glsl float y = smoothstep(0.2,0.5,st.x) - smoothstep(0.5,0.8,st.x); ``` ### Sinus et Cosinus Le mieux, si vous voulez utiliser les maths pour animer ou passer d'une valeur à une autre, c'est d'être copain avec les sinus et cosinus. Ces deux fonctions trigonométriques combinées permettent de dessiner des cercles qui sont plus utiles que le couteau suisse de MacGyver. Il est important de comprendre ce qu'elles font et comment les combiner. Dans un mouchoir de poche, à partir d'un angle en radians (1 radian = PI / 180), le [cosinus](../glossary/?search=cos) renvoie la position *x* et le [sinus](../glossary/?search=sin) renvoie la position *y* d'un point sur un cercle de rayon 1. Le fait que ces fonctions renvoient des valeurs *normalisées* (entre -1 et 1) de manière très "continue" ou très "souple", en fait un outil indispensable. S'il est difficile de comprendre cette relation entre sinus / cosinus et le cercle unitaire (de rayon 1), l'animation ci-dessus la résume assez bien visuellement. Regardez attentivement cette sinusoïde et surtout comment la valeur *y* oscille entre -1 et 1. Comme nous l'avons vu sur l'exemple du temps au chapitre 3, on peut utiliser cette propriété temporelle de [`sin()`](../glossary/?search=sin) pour animer une valeur. Si vous regardez cet exemple dans un navigateur, vous pouvez changer le code de la formule ci-dessus pour voir comment la sinusoïde change (n'oubliez pas le point-virule en fin de ligne). Essayez les changements suivants et regardez ce qui se passe : * Ajoutez le temps (`u_time`) à *x* avant de calculer `sin`. Retenez ce **mouvement** le long des *x*. * Multipliez *x* par `PI` avant de calculer `sin`. remarquez comme les deux *phases* **rétrécissent** de manière à ce que chaque cycle (tour complet) se répète entre deux valeurs entières. * Multipliez le temps (`u_time`) par *x* avant de calculer `sin`. remarquez comme la **fréquence** entre phases se compresse. Notez qu'`u_time` peut déjà avoir une valeur très élevée, rendant le graphe illisible. * Ajoutez 1.0 à [`sin(x)`](../glossary/?search=sin). Notez que toutes les vagues se **déplacent** vers le haut et comme toutes les valeurs sont maintenant comprises entre 0 et 2. * Multipliez [`sin(x)`](../glossary/?search=sin) par 2.0 et notez comme l'**amplitude** doubles de taille. * Calculez la valeur absolue ([`abs()`](../glossary/?search=abs)) de `sin(x)`, on dirait que le tracé **rebondit**. * Utilisez la partie fractionnelle (uniquement les chiffres après la virgule) ([`fract()`](../glossary/?search=fract)) du résultat de [`sin(x)`](../glossary/?search=sin). * Ajoutez l'entier le plus grand ([`ceil()`](../glossary/?search=ceil)) à l'entier le plus petit ([`floor()`](../glossary/?search=floor)) du résultat de [`sin(x)`](../glossary/?search=sin) pour obtenir des *créneaux* entre -1 et 1. ### Quelques fonctions indispensables A la fin de l'exercice précédent, nous avons présenté quelques nouvelles fonctions, nous allons maintenant les tester. Pour ce faire, décommentez une ligne à la fois dans la liste suivante. Essayez de comprendre comment chacune fonctionne et comment vous pourriez les combiner. Vous vous demandez sans doute mais... pourquoi ? Une petite recherche de "generative art" sur Google vous apportera la réponse. Gardez à l'esprit que ces fonctions sont votre palissade, nous apprenons à maîtriser le mouvement sur une dimension, de bas en haut, puis de haut en bas. Bientôt, nous utiliserons, deux, trois et même quatre dimensions! ### Fonctions de formes avancées [Golan Levin](http://www.flong.com/) a écrit quelques articles très instructifs sur des fonctions plus complexes. Les porter en GLSL est une bonne idée si vous souhaitez construire votre boîte à outils. * Fonctions Polynomiales : [www.flong.com/archive/texts/code/shapers_poly](http://www.flong.com/archive/texts/code/shapers_poly/) * Fonctions Exponentielles : [www.flong.com/archive/texts/code/shapers_exp](http://www.flong.com/archive/texts/code/shapers_exp/) * Fonctions Circulaires & Elliptiques : [www.flong.com/archive/texts/code/shapers_circ](http://www.flong.com/archive/texts/code/shapers_circ/) * Fonctions de Bezier et autres fonctions paramétriques : [www.flong.com/archive/texts/code/shapers_bez](http://www.flong.com/archive/texts/code/shapers_bez/) Comme un chef qui collectionnerait les épices et autres ingrédients exotiques, les artistes digitaux et les codeurs créatifs en particulier aiment travailler leurs propres fonctions de forme. [Iñigo Quiles](http://www.iquilezles.org/) a écrit une liste de [fonctions utiles](http://www.iquilezles.org/www/articles/functions/functions.htm). Après avoir lu [cet article](http://www.iquilezles.org/www/articles/functions/functions.htm) regardez leur traduction en GLSL. Notez bien les petits changements nécessaires, comme le "." (point) sur les floats et l'utilisation des conventions de nommage GLSL pour les fonctions C ; par exemple `powf()` devient `pow()`: * [Impulse](../edit.php#05/impulse.frag) * [Cubic Pulse](../edit.php#05/cubicpulse.frag) * [Exponential Step](../edit.php#05/expstep.frag) * [Parabola](../edit.php#05/parabola.frag) * [Power Curve](../edit.php#05/pcurve.frag) Pour vous motiver, voici un exemple élégant, fait par [Danguafer](https://www.shadertoy.com/user/Danguafer) qui montre le karaté des fonctions de formes. Au prochain chapitre, nous utiliserons ces nouveaux mouvements. D'abord pour mélanger des couleurs, puis pour dessiner des formes. #### Exercices Regardez cette table d'équations, réalisée par [Kynd](http://www.kynd.info/log/). Voyez comme il combine les fonctions et leurs propriétés pour contrôler les variations de valuer entre 0 et 1. A présent, c'est à votre tour de vous entraîner à reproduire ces fonctions. Souvenez vous que plus vous pratiquerez, meilleur sera votre karaté. #### Pour la boîte à outils Voici quelques outils qui simplifient la visualisation des fonctions. * [GraphToy](http://www.iquilezles.org/apps/graphtoy/) : [Iñigo Quilez](http://www.iquilezles.org), encore lui, a créé un outil pour visualiser les fonctions GLSL en WebGL. * [LYGIA Shader Library](https://lygia.xyz/) a shader library of reusable functions that can be include easily on your projects. It's very granular, designed for reusability, performance and flexibility. And can be easily be added to any projects and frameworks. --- ### 05/README Id (05/README-id.md) # 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. 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. **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 *. 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. 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. 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 Meskipun sulit untuk mendeskripsikan semua hubungan antara fungsi trigonometri dan lingkaran, animasi di atas melakukan pekerjaan yang bagus dalam merangkum hubungan ini secara visual. 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! ### 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/) 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()`: Untuk menjaga motivasi Anda tetap tinggi, berikut adalah contoh elegan (dibuat oleh [Danguafer](https://www.shadertoy.com/user/Danguafer)) dalam menguasai karate fungsi-pembentukan. 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. #### Untuk kotak peralatan Anda Berikut beberapa alat yang akan memudahkan Anda untuk memvisualisasikan jenis fungsi tersebut. * [GraphToy](http://www.iquilezles.org/apps/graphtoy/): sekali lagi[Iñigo Quilez](http://www.iquilezles.org) membuat alat untuk memvisualisasikan funsi GLSL dalam WebGL. * [LYGIA Shader Library](https://lygia.xyz/) a shader library of reusable functions that can be include easily on your projects. It's very granular, designed for reusability, performance and flexibility. And can be easily be added to any projects and frameworks. --- ### 05/README It (05/README-it.md) # Disegno Algoritmico ## Funzioni di forma Questo capitolo potrebbe essere chiamato "la lezione del recinto di Mr. Miyagi". In precedenza abbiamo associato la posizione normalizzata di *x* e *y* ai canali *rosso* e *verde*. Fondamentalmente abbiamo creato una funzione che prende un vettore bidimensionale (x e y) e restituisce un vettore quadridimensionale (r, g, b e a). Ma prima di andare avanti nella trasformazione dei dati tra dimensioni, dobbiamo iniziare da qualcosa di più semplice…molto più semplice. Questo significa comprendere come creare funzioni unidimensionali. Maggiori sono l’energia e il tempo che impieghi nel comprendere e nel padroneggiarle, migliore sarà il tuo karate shader. La seguente struttura di codice sarà la nostra recinzione. In questa visualizziamo il valore normalizzato della coordinata *x* (```st.x```) in due modi: uno con la luminosità (osserva il bel gradiente dal nero al bianco) e l’altro tracciando sopra una linea verde (in questo caso il valore di *x* è assegnato direttamente al valore di *y*). Non ti concentrare troppo sulla funzione plot, la vedremo nel dettaglio tra poco. **Nota veloce**: il costruttore di tipo ```vec3``` "capisce" che vuoi assegnare i tre canali di colori allo stesso valore, mentre ```vec4``` capisce che vuoi costruire un vettore a quattro dimensioni con tre unidimensionali più un quarto valore (in questo caso il valore che controlla l’alfa o l’opacità). Guarda, ad esempio, le righe 19 e 25 qui sopra. Questo codice è il tuo recinto; è importante osservarlo e capirlo. Tornerai spesso in questo spazio tra *0.0* e *1.0*. Imparerai l’arte di combinare e modellare questa linea. Questa relazione uno a uno tra *x* e *y* (o la luminosità) è conosciuta come *interpolazione lineare*. A partire da qui, possiamo usare alcune funzioni matematiche per *modellare* la linea. Per esempio, possiamo elevare *x* alla quinta potenza e creare una linea *curva*. Interessante, vero? Alla riga 22 prova esponenti diversi, per esempio: 20.0, 2.0, 1.0, 0.0, 0.2 e 0.02. comprendere questa relazione tra il valore e l’esponente sarà molto utile. Questo genere di funzioni matematiche ci darà un controllo espressivo sul codice, come una specie di agopuntura che permette di controllare il flusso dei valori. [```pow()```](../glossary/?search=pow) è una funzione nativa il GLSL e ce ne sono molte altre. La maggior parte di queste sono accelerate al livello dell’hardware; ciò significa che se esse sono usate in modo appropriato e con discrezione, renderanno il tuo codice molto più veloce. Sostituisci la funzione alla riga 22. Provane altre, come: [```exp()```](../glossary/?search=exp), [```log()```](../glossary/?search=log) e [```sqrt()```](../glossary/?search=sqrt). Alcune di queste funzioni sono più interessanti quando le si utilizza con PI. Puoi vedere alla riga 8, che ho definito un macro che sostituisce qualsiasi chiamata a ```PI``` con valore ```3.14159265359```. ### Step e Smoothstep GLSL ha anche alcune funzioni interpolanti native uniche che sono accelerate dall’hardware. L’interpolazione [```step()```](../glossary/?search=step) riceve due parametri. Il primo è il limite o la soglia, mentre il secondo è il valore che volgiamo controllare. Qualsiasi valore al di sotto del limite tornerà a ```0.0```, mentre tutto ciò al di sopra del limite tornerà a ```1.0```. Prova a cambiare il valore della soglia alla riga 20 del seguente codice. L’altra funzione unica è conosciuta come [```smoothstep()```](../glossary/?search=smoothstep). Data una serie di due numeri e un valore, questa funzione interpolerà il valore tra la serie definita. I primi due parametri sono per l’inizio e la fine della transizione, mentre il terzo è per il valore d’interpolazione. Nell’esempio precedente, alla riga 12, nota che abbiamo usato smoothstep ( ) per disegnare la linea verde sulla funzione ```plot()```. Per ciascuna posizione lungo l’asse *x*, questa funzione crea un *salto* ad un particolare valore di *y*. Come? Collegando tra di loro due [```smoothstep()```](../glossary/?search=smoothstep). Guarda la funzione qui di seguito, sostituiscila alla riga 20 di sopra e pensa ad esso come ad un taglio verticale. Lo sfondo assomiglia ad una linea, vero? ```glsl float y = smoothstep(0.2,0.5,st.x) - smoothstep(0.5,0.8,st.x); ``` ### Seno e coseno. Quando si vuole usare la matematica per animare, modellare o combinare, non c’è nulla di meglio che essere amici del seno e del coseno. Queste due basiche funzioni trigonometriche lavorano congiuntamente per costruire cerchi che sono utili come il coltellino svizzero di MacGyver. È importante sapere come si comportano e in che modo possono essere combinate. In breve: dato un angolo (in radianti), essi ritorneranno alla corretta posizione di *x* ([cosine](../glossary/?search=cos)) e di *y* ([sine](../glossary/?search=sin)) di un punto sul margine del cerchio con raggio uguale a 1. Il fatto che queste funzioni ritornano ai valori normalizzati ( tra -1 e 1) in modo così armonioso e fluido le rende uno strumento incredibile. Mentre è difficile descrivere tutte le relazioni tra le funzioni trigonometriche e i cerchi, le animazioni soprastanti le riassumono molto bene visivamente. Guarda attentamente questa curva sinusoidale. Nota come i valori di *y* ondeggiano dolcemente tra +1 e -1. Come abbiamo visto nell’esempio del tempo nel capitolo precedente, si può usare questo comportamento ritmico di [```sin()```](../glossary/?search=sin) per animare le proprietà. Se stai leggendo questo esempio su un browser, vedrai che puoi cambiare il codice nella formula soprastante per osservare come cambia l’onda. (Nota: non dimenticare il punto e virgola alla fine delle righe). Prova questi esercizi e osserva cosa succede: * Aggiungi tempo (```u_time```) a *x* prima di calcolare ```sin```. Osserva attentamente questo **movimento** lungo *x*. * Moltiplica *x* per ```PI``` prima di calcolare ```sin```. Nota come le due fasi si **restringano** e ciascun ciclo si ripeta tra due valori interi. * Moltiplica tempo (```u_time```) per *x* prima di calcolare ```sin```. Osserva come la **frequenza** tra le fasi diventi sempre più compressa. Nota che u_time può avere già assunto un valore molto grande, rendendo il grafico difficile da leggere. * Aggiungi 1.0 a [```sin(x)```](../glossary/?search=sin). Osserva come tutte le onde siano **dislocate** verso l’alto e adesso tutti i valori siano tra 0.0 e 2.0. * Moltiplica [```sin(x)```](../glossary/?search=sin) per 2.0. Osserva come l’**ampiezza** raddoppi di misura. * Calcola il valore assoluto ([```abs()```](../glossary/?search=abs)) di ```sin(x)```. Sembra la traccia di una palla che **rimbalza**. * Estrai solo la parte frazionaria ([```fract()```](../glossary/?search=fract)) della risultante di [```sin(x)```](../glossary/?search=sin). * Aggiungi il numero intero più elevato ([```ceil()```](../glossary/?search=ceil)) e il più basso ([```floor()```](../glossary/?search=floor)) della risultante di [```sin(x)```](../glossary/?search=sin) per ottenere un’onda digitale dei valori 1 e -1. ### Altre funzioni utili AAl termine dell’ultimo esercizio abbiamo presentato alcune nuove funzioni. È arrivato il momento di provare con ciascuna, decommentando le righe sottostanti, una alla volta. Impara quete funzioni e studia il loro comportamento. Lo so, ti stai chiedendo perché e se cerchi velocemente su Google "arte generativa" capirai subito. Ricorda che queste funzioni sono il nostro recinto. Stiamo controllando il movimento in una dimensione, su e giù. Presto arriverà il momento per due, tre e quattro dimensioni! ### Funzioni di forma avanzate [Golan Levin](http://www.flong.com/) possiede un’ampia documentazione molto utile sulle funzioni di forma complesse. Trasportare queste funzioni in GLSL è un ottimo modo per incominciare a costruire la propria cassetta degli attrezzi per creare codici. * [Polynomial Shaping Functions: www.flong.com/archive/texts/code/shapers_poly](http://www.flong.com/archive/texts/code/shapers_poly/) * [Exponential Shaping Functions: www.flong.com/archive/texts/code/shapers_exp](http://www.flong.com/archive/texts/code/shapers_exp/) * [Circular & Elliptical Shaping Functions: www.flong.com/archive/texts/code/shapers_circ](http://www.flong.com/archive/texts/code/shapers_circ/) * [Bezier and Other Parametric Shaping Functions: www.flong.com/archive/texts/code/shapers_bez](http://www.flong.com/archive/texts/code/shapers_bez/) Come i cuochi collezionano con passione spezie e ingredienti esotici, così gli artisti digitali e i creative coders adorano lavorare sulle proprie funzioni di forma. [Iñigo Quiles](http://www.iquilezles.org/) possiede una grande raccolta di [funzioni molto utili](http://www.iquilezles.org/www/articles/functions/functions.htm). Dopo aver letto [quest'articolo](http://www.iquilezles.org/www/articles/functions/functions.htm), leggi le seguenti traduzioni di queste funzioni in GLSL. Fai attenzione ai piccoli cambiamenti necessari, come mettere "."" (punto) sui valori flessibili, e usare il nome GLSL per le *funzioni in C*; per esempio, invece di ```powf()```, usa ```pow()```: Per mantenere alta la tua motivazione, qui trovi un esempio elegante dell’essere esperti nel karate delle funzioni di forma (creato da [Danguafer](https://www.shadertoy.com/user/Danguafer)). Nel *Prossimo >>* capitolo inizieremo ad usare nuove mosse. Prima mescolando i colori e poi disegnando forme. #### Esercizio Guarda la seguente tabella di equazioni fatta da [Kynd](http://www.kynd.info/log/). Osserva come combini le funzioni e le loro proprietà per controllare i valori tra 0.0 e 1.0. Ora è il tuo momento di fare pratica replicando queste funzioni. Ricordati: più ti eserciti, migliore sarà il tuo karate. #### Per la tua cassetta degli attrezzi Qui trovi alcuni strumenti che ti faciliteranno la visualizzazione di questi tipi di funzione. * [GraphToy](http://www.iquilezles.org/apps/graphtoy/): ancora una volta [Iñigo Quilez](http://www.iquilezles.org) ha creato un mezzo per visualizzare le funzioni GLSL in WebGL. * [LYGIA Shader Library](https://lygia.xyz/) a shader library of reusable functions that can be include easily on your projects. It's very granular, designed for reusability, performance and flexibility. And can be easily be added to any projects and frameworks. --- ### 05/README Jp (05/README-jp.md) # アルゴリズムで絵を描く ## シェイピング関数 この章は[「ミヤギさんの壁塗りレッスン」](https://ja.wikipedia.org/wiki/%E3%83%99%E3%82%B9%E3%83%88%E3%83%BB%E3%82%AD%E3%83%83%E3%83%89)とでもすれば良かったかもしれません。以前の章では正規化したx座標とy座標の値をr(赤)とg(緑)のチャンネルに割り当てました。つまり私たちは既に、2次元のベクトル(x, y)を受け取って4次元のベクトル(r, g, b, a)を返す関数を作ったのです。 しかし、次元をまたいでのデータの変形にさらに深く踏み込む前に、ずっとシンプルなことから修行を始めなければなりません。まずは1次元の関数を理解します。より多くの時間と労力を割いて鍛錬すれば、その分だけあなたのシェーダーカラテは強くなるでしょう。 私たちにとってミヤギさんの壁に当たるものは、下記に示すコードの枠組みです。この枠組みを使って、正規化されたx座標の値を2種類の方法で目に見えるようにしてみます。1つめの方法では色の明るさを使い(黒から白への綺麗なグラデーションを見てください)、2つめでは緑色の線を描画します(ここではx座標の値をそのままy座標に割り当てています)。```plot``` 関数のことは今はあまり気にしないでください。すぐ後で詳しく説明します。 上記のサンプルの20行目と26行目を見てください。 ```vec3``` 型のコンストラクタに値を1つだけ渡すと、コンストラクタは3つの色のチャンネルに同じ値を割りてようとしているのだと解釈します。一方で ```vec4``` は三次元のベクトルともう1つの値(ここではalpha、つまり透明度)で初期化されています。 このコードがミヤギさんの壁です。よく観察して理解しておくことが大切です。この 0.0 から 1.0 の空間には何度も立ち帰ることになるでしょう。そしてあなたはいずれ、色と形を操る技をマスターするのです。 このサンプルのx座標とy座標(または明るさ)の1対1の対応は線形補間と呼ばれています。 ここから私たちは数学的な関数を使って線を形作っていくことになります。例えばxを5乗すれば曲線を作ることができます。 (訳注:ここでは x=0.0 から x=1.0 の間のグラフが一次方程式で書ける、つまりグラフが直線になることを指して線形補完 * Liniear Interpolation*という言葉が使われています。参考:[Wikipedia: 線形補間](https://ja.wikipedia.org/wiki/%E7%B7%9A%E5%BD%A2%E8%A3%9C%E9%96%93)。この章の原文ではInterpolateという単語が複数回登場しますが、厳密な使い方ではない箇所もあるため以下では「補完」という訳語はあてませんでした。興味がある方はコンピュータグラフィックスやアニメーションの世界で補完関数 *Interpolator* がどのように使われているか調べてみましょう。) 面白いでしょう? 19行目の指数(```5.0```)を他の数に変えてみましょう。例えば値を ```20.0```, ```2.0```, ```1.0```, ```0.0```, ```0.2```, ```0.02``` に変えてみます。この値と指数の関係を理解しておくととても役立ちます。この例のように数学的な関数を様々な場面で用いると、コードを表現豊かに操ることができます。鍼で気の流れを操るようにデータの流れを操るのです。 GLSLには多くのネイティブ関数が用意されており、[```pow()```](../glossary/?search=pow) はその中の1つです。ほとんどのネイティブ関数はハードウェアのレベルで高速に処理されるので、適切に使えばより速いコードを書くことができます。 22行目のべき関数を [```exp(st.x) - 1.0```](../glossary/?search=exp), [```log(st.x - 1.0)```](../glossary/?search=log), [```sqrt(st.x)```](../glossary/?search=sqrt) など他の関数で置き換えてみましょう。 ### StepとSmoothstep GLSLには他にも、値を変化させるのに使うことができるネイティブ関数があります。これらもまたハードウェアで高速に処理されます。 [```step()```](../glossary/?search=step) 関数は2つのパラメーターを受け取ります。1つめは境界または閾値で、2つめはこの関数によってチェックされる値です。境界より小さい値には全て ```0.0``` を返し、境界以上の値には ```1.0``` を返します。 下記のコードの20行目の閾値を変えて試してみてください。 もう1つ、[```smoothstep()```](../glossary/?search=smoothstep)と呼ばれる関数があります。2つの数値からなる範囲ともう1つの値を受け取ると、この関数はその範囲の間で0.0から1.0まで滑らかに変化する数値を返します。最初の2つのパラメータは値の変化の起こる範囲の始まりと終わりで、3つめのパラメータはチェックの対象になる値です。 上記の例の12行目では、[```smoothstep()```](../glossary/?search=smoothstep) が ```plot()``` 関数の中で緑色の線を描画するために使われていますね。この関数をx軸に沿って見ていくと、それぞれの点で特定のyの値に対して急激に高い値を返しています。どうなっているのでしょう。```plot``` 関数は2つの [```smoothstep()```](../glossary/?search=smoothstep) を組み合わせてこれを実現しています。下記の関数を見てください。上の20行目をこの関数で置き換えて、結果を ```plot``` 関数のグラフを垂直に切った断面だと考えてみましょう。背景が線のように見えるでしょう? ```glsl float y = smoothstep(0.2,0.5,st.x) - smoothstep(0.5,0.8,st.x); ``` (訳注:おまけ。```plot``` 関数を理解するには引き算の片側を消して ```smoothstep(0.2,0.5,st.x)``` もしくは ```smoothstep(0.5,0.8,st.x)``` だけにしてみるのも良いと思います。2つのグラフの位置が少しずれていて、引き算をすると真ん中だけが残されるのが分かりますね。20行目の ```smoothstep( pct-0.02, pct, st.y) - smoothstep( pct, pct+0.02, st.y)``` でも同じことを試してみましょう。) ### サインとコサイン 数学を使ってアニメーションや形を作ったり、値を組み合わせたりしたいのであれば、サインとコサインに親しんでおくに越したことはありません。 この2つの基本的な三角関数を一緒に使うと円を作ることができます。これは[冒険野郎マクガイバー](https://ja.wikipedia.org/wiki/%E5%86%92%E9%99%BA%E9%87%8E%E9%83%8E%E3%83%9E%E3%82%AF%E3%82%AC%E3%82%A4%E3%83%90%E3%83%BC)のスイスアーミーナイフ並みに便利です。サインとコサインがどのように振る舞い、どのような組み合わせで使えるのかを知っておくことが大事です。かいつまんで言うと、これらの関数は(ラジアンを単位とする)角度を受け取り、半径を1とする円周上の点のx座標 ([cosine](../glossary/?search=cos)) とy座標([sine](../glossary/?search=sin)) を返します。滑らかに変化する正規化された値(-1から1の間の値)を返す性質のおかげでサインとコサインは非常に便利な道具になります。 三角関数と円の関係について全てを言葉で説明するのは難しいのですが、上のアニメーションはそれを見事に示してくれています。 このサイン波をよく見てください。y座標の値が+1から-1の間をスムーズに上下しているのがわかるでしょう。時間を使った以前のサンプルでも見たとおり、このサインの周期的な動きはアニメーションに使えます。ブラウザ上で読んでいる方は、上のサンプルの数式を書き換えて波の動きを変えてみることができます(行の最後のセミコロンを忘れないようにしてください)。 下記を試して何が起きるか見てみましょう。 * ```sin``` を計算する前に時間の値(```u_time```)をxに足してみましょう。x座標に沿った動きを身につけましょう。 * ```sin``` を計算する前に、xに ```PI``` を掛けてみましょう。波の幅が縮まり、xが 2 進むごとにyが1サイクル上下するのを確認しましょう。 * ```sin```を計算する前に時間の値(```u_time```)をxに掛けてみましょう。周波数が次第に増えて波の幅が狭くなっていく様子を見てください。u_timeが既に大きくなりすぎていてグラフが読めないほどになってしまっているかもしれないので注意してください。(訳注:もしグラフが線ではなく黒い靄のようなノイズになってしまう場合は、一度ページをリロードしてからもう一度試してください。u_timeはページを読み込んでからの累積時間なので、ここまで読み進める間にかなり大きな値になっている可能性があります)。 * ```sin(x)``` に 1.0 を足してみましょう。値が 0.0 から 2.0 の間に収まるように波の位置が上にずれる様子を見てください。 * ```sin(x)``` に 2.0 を掛けてみましょう。振幅が倍になります。 * ```sin(x)``` の絶対値([```abs()```](../glossary/?search=abs))を計算してください。弾むボールの軌跡のように見えるでしょう。 * ```sin(x)``` の値から少数部分だけを取り出してみましょう([```fract()```](../glossary/?search=fract))。 * [```sin(x)```](../glossary/?search=sin) の値を超える最小の整数([```ceil()```](../glossary/?search=ceil))と、それより小さい最大の整数([```floor()```](../glossary/?search=floor))を足して、1 と -1 だけからなるデジタル波を作ってみましょう。 ### 便利な関数あれこれ 上の課題の中ではいくつかの新しい関数を紹介しました。今度は下記のサンプルのコメントを1つ1つ外して実験してみましょう。それぞれの関数がどのような振る舞いをするか調べて理解しておいてください。どうしてこんなことが必要なのかと思っていますね? Googleで「generative art」を検索してみれば答えがわかります。この関数たちは私たちにとってのミヤギさんの壁なのです。今は1次元、上下の動きをマスターしつつあります。すぐに2次元、3次元、そして4次元についても学んでいきます。 ### より高度なシェイピング関数 [Golan Levin](http://www.flong.com/)(Golan Levin)が書いた、より複雑で非常に便利なシェイピング関数についての素晴らしいドキュメントがあります。自分のスニペット集を作るために、これらの関数をGLSLに移植してみると良いでしょう。 * [Polynomial Shaping Functions: www.flong.com/archive/texts/code/shapers_poly](http://www.flong.com/archive/texts/code/shapers_poly/) * [Exponential Shaping Functions: www.flong.com/archive/texts/code/shapers_exp](http://www.flong.com/archive/texts/code/shapers_exp/) * [Circular & Elliptical Shaping Functions: www.flong.com/archive/texts/code/shapers_circ](http://www.flong.com/archive/texts/code/shapers_circ/) * [Bezier and Other Parametric Shaping Functions: www.flong.com/archive/texts/code/shapers_bez](http://www.flong.com/archive/texts/code/shapers_bez/) スパイスや珍しい食材を集めるシェフのように、デジタルアーティストやクリエィティブコーダーは自らシェイピング関数に取り組むのが大好きです。 [Iñigo Quiles](http://www.iquilezles.org/)は便利な関数の[素晴らしいコレクション](http://www.iquilezles.org/www/articles/functions/functions.htm)を持っています。 [この記事](http://www.iquilezles.org/www/articles/functions/functions.htm)をまず読んでから、下記にあるGLSLへ翻訳したバージョンを見てみましょう。浮動小数点の数値に「.(小数点)」を追加したり、Cの関数をGLSL特有の関数名で置き換える、例えば ```powf()``` の代わりに ```pow()``` を使うなどの細かな変更点に注意してください。 * [Impulse](../edit.php#05/impulse.frag) * [Cubic Pulse](../edit.php#05/cubicpulse.frag) * [Exponential Step](../edit.php#05/expstep.frag) * [Parabola](../edit.php#05/parabola.frag) * [Power Curve](../edit.php#05/pcurve.frag) 匠の技を見てモチベーションを上げましょう。[Danguafer](https://www.shadertoy.com/user/Danguafer)の作品です。 次の章では新しい技を使います。まず色の調合から始めて、次に形を描いていきます。 #### 演習 [Kynd](http://www.kynd.info/log/)が作った[数式の表](www.flickr.com/photos/kynd/9546075099/)を見てください。数値と関数をどのように組み合わせて、0.0 から 1.0 の間で値をコントロールしているかを読み取りましょう。実際に関数を置き換えて練習してください。鍛える程にあなたのカラテは強くなります。 #### 便利なツール この種の関数を簡単に視覚化するためのツールをいくつか紹介します。 * [GraphToy](http://www.iquilezles.org/apps/graphtoy/): 先ほども紹介した[Iñigo Quilez](http://www.iquilezles.org)が作った、GLSLの関数をWebGLで視覚化するためのツールです。 * [LYGIA Shader Library](https://lygia.xyz/) a shader library of reusable functions that can be include easily on your projects. It's very granular, designed for reusability, performance and flexibility. And can be easily be added to any projects and frameworks. --- ### 05/README Kr (05/README-kr.md) # Algorithmic drawing ## Shaping functions 이번 챕터는 "미야기씨의 울타리 수업"이라고 표현할수 있겠다. 전에는, 노멀라이즈된 ,*x*와 *y*를 *red*와 *green*채널들에 적용해 보았다. 원래는 2차원 벡터(x and y)를 받아, 4차원 벡터(r, g, b and a)를 리턴하는 함수가 좀더 자연스럽니다. 하지만 지금 이런문제를 해결하기 전에, 간단한것부터 시작해보자... 훨씬더 간단한것부터. 이말은 1차원 함수에 대한 정의에서부터 시작한다. 시간과 에너지를 많이 투자하고 배우고 마스터하려고 하다보면, 우리는 더욱더 강한 쉐이더 카라테를 배울수 있을것이다. 아래 코드는 우리의 울타리가 될것이다. 여기서 우린 *x* 위치정보(```st.x```)의 노멀라이즈된 값을 2가지 방법으로 시각화 하는데: 하나는 밝기로 (검은색에서 흰색으로 잘 묻어져 나가는 색), 다른 하나는 그 위에 초록색 선( *x* 값이 바로 *y* 값에 적용된)으로 나타낼 것이다. 지금은 선을 그리는 함수에 대해 너무 신경쓰지말자. 그부분은 나중에 더 자세히 다루게 될것이다. **퀵노트**: ```vec3``` 타입 생성자는 유저가 세가지 컬러 채널들을 입력하려는 것을 "이해" 한다. 또한, ```vec4``` 타입생성자역시, 3차원 벡터와, 1개의 실수(보통 alpha나 opacity라고 일컫는)로 이루어진 4차원 벡터를 만들려고 한다는 점 또한 이해한다. 라인 19과 25을 위에 코드에서 찾아보라. 이 코드는 다시한번 당신의 울타리이다; 받아들이고 이해하는것이 중요하다. 앞으로도 계쏙 이 *0.0* 에서 *1.0*의 공간을 계속 사용하게 될것이다. 여기서 당신은 블렌딩과, 선그리기를 마스터 해야한다. *x*와 *y* (또는 밝기)의 1:1 대응은 흔히 *선형 보간법* 이라고 알려져 있다. 여기서 우린 수학적 함수로 선을 *그릴수* 있다. 예로, *x*값이 지수로 5를 갖는다면 이 선은 *구부러* 진다. 흥미로운일이지 않은가? 라인 19에서 다른 값들을 시도해보자: 20.0, 2.0, 1.0, 0.0, 0.2, 0.02. 지수를 통해 나오는 값에 대한 상관관계를 이해하는 것은 앞으로 매우 유용한 권법이 될것이다. 이런 종류의 수학적 함수를 코드의 공간에서 이용하는것은 엄청난 표현 컨트롤을 할수 있도록 허용한다. 마치 데이터를 이용한 한방권법이라고 저자는 소개한다. [```pow()```](../glossary/?search=pow) 는 GLSL의 내장형 함수이고 GLSL은 이런 수학함수를 많이 제공한다. 거의 모든 함수들은 하드웨어 레벨에서 구동되도록 '가속화' 되어 있다. 다시말해, 이런 이점을 잘 활용하면 굉장히 빠른 코드를 쓸수 있게 된다. 라인 19의 power 함수를 다른 함수로 교체해보자.: [```exp()```](../glossary/?search=exp), [```log()```](../glossary/?search=log), [```sqrt()```](../glossary/?search=sqrt). 어떤함수들은 인자로 PI값을 넣었을때 재밌는 결과를 내기도 한다. 라인 5에 ```PI```값을 ```3.14159265359```로 define해 둔것을 알수 있다. ### Step and Smoothstep GLSL에는 하드웨어 가속화된 내장 보간법 함수들이 존재한다. [```step()```](../glossary/?search=step) 보간법은 2개의 인자를 받는다. 첫번째것은 경계나, 한계점이고, 두번째것은 체크하거나 넘길 값이다. 어떤값이든 이 한계점보다 낮은 값은 ```0```으로 처리되어 리턴될것이고, 한계점보다 높은 값은 ```1.0```으로 처리되어 리턴될것이다. 라인 20의 한계점 값을 바꾸어 보자. 또 하나의 잘 알려진 함수중 하나는 [```smoothstep()```](../glossary/?search=smoothstep)이다. 두값의 레인지를 주고, 그 사이의 값으로 보간시켜주는 방법이다. 처음 두개의 인자는 레인지의 시작점과 끝점이고, 세번째 인자는 두 점사이에서 보간되고 리턴되는 값이다. 전 예제의 라인 12를 보면, smoothstep을 ```plot()```에 사용하여 초록색 선을 그린것을 알수 있다. 각 *x*값에 대한 *y*값을 *bump*시킨 것으로 표현되고 있는데. 실제로 [```smoothstep()```](../glossary/?search=smoothstep) 를 통해 그려진 쉐이프 A를 같은 방법으로 그려진 쉐이프 B에서 그냥 빼준것이다. 아래 예제를 보고 라인 20과 바꿔보아라. ght? ```glsl float y = smoothstep(0.2,0.5,st.x) - smoothstep(0.5,0.8,st.x); ``` ### Sine과 Cosine 함수 수학으로 애니메이션, 쉐이프등을 만들거나 섞을때는, sine과 cosine만큼 좋은 친구도 없다. 이 두개의 삼각함수로 원을 그리는 유명한 예제를 보면 마치 맥가이버의 스위스 군용 나이프와도 같다. 이들이 왜 이렇게 작동되고, 서로 영향을 주는지 확실히 이해를 해볼 필요가 있다. 요약하자면, 이 함수들로 전해지는 인자값(흔히 radians 값)에 따라, 반지름이 1인 동그라미 모양을 그리는 선 위에 모든 *x* ([cosine](../glossary/?search=cos)) 와 *y* ([sine](../glossary/?search=sin))가 나타내어 진다고 볼수 있다. 그리고, 이 값들은 노멀라이즈된 값(-1 에서 1 사이의 값)으로 리턴되는 이 방식은 굉장히 유용한 툴로 알려져 있다. 삼각함수들과 동그라미에 대한 해석등을 전부 다를수는 없지만, 위에 애니메이션을 통해 이들이 할수 있는 일이 얼마나 간단하고 아름다운지 살펴볼수 있다. 전 챕터의 time 예제에서 봤듯이, sine wave를 통해, *y*값이 얼마나 부드럽게 +1에서 -1으로 이동되는지 확인해보라. [```sin()```](../glossary/?search=sin)의 리드믹한 결과값은 애니메이션에 굉장히 유용하다. 브라우져에서 이 예제를 읽고 있다면 코드를 변경해서 변화를 시도해보자. (노트: 끝에 semicolon은 까먹지 말고 붙히자.) 아래의 예제들을 실행해보고, 어떤일들이 벌어지는지 관찰해보자: * ```sin```을 계산하기 전에 time(```u_time```)을 *x* 적용해보자. *x*에 대한 **움직임**을 습득해보자. * ```sin```을 계산하기 전에 *x*에 ```PI```를 곱해보자. 반복구간이 **좁혀** 지는것을 확인할수 있다. * time (```u_time```) 와 *x*값을 ```sin```에 적용되기 전에 곱해보자. **반복성*이 잦아지는것을 확인할수 있다. u_time이 커지면서 그래프를 점차 읽기 힘들어지게 된다는 것 또한 확인할수 있다. * [```sin(x)```](../glossary/?search=sin)에 1.0을 더해보자. 전체 웨이브가 **이동** 되는 것을 확인할수 있다. 이제 모든 값들은 0.0에서 2.0사이로 구간이 바뀌었다. * [```sin(x)```](../glossary/?search=sin)에 2.0을 곱해보자. 웨이브의 전체적 **강도**가 2배로 변하는 것을 알수 있다. * 절대값([```abs()```](../glossary/?search=abs))을 ```sin(x)```에 적용해보자. 공이 튕기는것 같은 효과를 볼수 있다. * 소수점 구간([```fract()```](../glossary/?search=fract))만 취하고, 이를 [```sin(x)```](../glossary/?search=sin)에 적용해보자. * 올림 ([```ceil()```](../glossary/?search=ceil))된 수나 내림([```floor()```](../glossary/?search=floor))된 수 역시 [```sin(x)```](../glossary/?search=sin)에 적용해보고, -1에서 1값이 어떻게 리턴되는지 살펴보자. ### 키타 유용한 함수들 마지막에 여러 새로운 함수들을 소개했다. 이제 이들을 가지고 하나씩 적용을 해볼차례이다. 하나씩 uncomment를 하면 결과를 확인할수 있을것이다.이들에 대해 샅샅히 파내어 익혀보자. 혹시나 왜그래야 하는지에 대한 의문이 든다면, 좋은 대답중 하나는 "generative art"에 대한 것이다. 이 함수들이 우리의 울타리 하는 것을 생각하자. 우리는 지금 1차원에서 권법을 연마하는 중인것이다. 곧, 2차원, 3차원, 4차원까지 우리는 진입하게 될것이다! ### 고급 쉐이핑 함수들 [Golan Levin](http://www.flong.com/) 는 제법 복잡하지만 굉장히 유용한 쉐이핑 함수들을 잘 정리해 두었다. 이들을 GLSL로 포팅하는것또한 굉장히 유용한 공부방법일 것이다. 자신만의 쉐이핑 펑션 라이브러리를 개설해보자. * [Polynomial Shaping Functions: www.flong.com/archive/texts/code/shapers_poly](http://www.flong.com/archive/texts/code/shapers_poly/) * [Exponential Shaping Functions: www.flong.com/archive/texts/code/shapers_exp](http://www.flong.com/archive/texts/code/shapers_exp/) * [Circular & Elliptical Shaping Functions: www.flong.com/archive/texts/code/shapers_circ](http://www.flong.com/archive/texts/code/shapers_circ/) * [Bezier and Other Parametric Shaping Functions: www.flong.com/archive/texts/code/shapers_bez](http://www.flong.com/archive/texts/code/shapers_bez/) 요리사가 자신만의 요리재료와 소스 노하우를 모으듯, digital artist들이나, creative coder들 역시 그들만의 쉐이핑 펑션을 만드는 버릇을 가져야 할것이다. [Iñigo Quiles](http://www .iquilezles.org/)가 가지고 있는 [useful functions](http://www.iquilezles.org/www/articles/functions/functions.htm)정리는 매우 유용하다. [이 글](http://www.iquilezles.org/www/articles/functions/functions.htm)을 읽고, GLSL로 번역해보는 작업도 해볼수 있다. 조심해야 될 점들은, "."(점)을 실수 뒤에 꼭 넣어야 한다는 점이다. 함수의 이름이 ```powf()``` 에서 ```pow()```등으로 바뀌어 구현되는 점등이다. * [Impulse](../edit.php#05/impulse.frag) * [Cubic Pulse](../edit.php#05/cubicpulse.frag) * [Exponential Step](../edit.php#05/expstep.frag) * [Parabola](../edit.php#05/parabola.frag) * [Power Curve](../edit.php#05/pcurve.frag) 계속 작업이 뜨겁게 진행되는것을 도울수 있게 여기 멋진 작업도 소개해본다. (made by [Danguafer](https://www.shadertoy.com/user/Danguafer)) *다음 >>* 챕터에서 우리는 새로운 동작에 대해 배우게 될것이다. 색에 조합에 대해 배우고, 쉐이프를 창조하는 작업일것이다. #### 연습 아래의 공식 테이블을 한번 살펴보자. [Kynd](http://www.kynd.info/log/) 수학함수들이 서로 어떻게 섞여지는지 살펴보고, 이 값들이 0.0에서 1.0사이에서 어떻게 바뀌어 가는지 보자. 이제 스스로 함수들을 복제하고 조합해볼 차례이다. 기억하자. 연습을 할수록 당신의 카라테가 늘게 될것이라는 것을. #### 당신의 툴박스를 위해 수학함수를 쉽게 시각화 할수있는 툴을 소개해보고자 한다. * [GraphToy](http://www.iquilezles.org/apps/graphtoy/): [Iñigo Quilez](http://www.iquilezles.org)의 GLSL함수들을 WebGL에서 시각화 하는 툴이다. * [LYGIA Shader Library](https://lygia.xyz/) a shader library of reusable functions that can be include easily on your projects. It's very granular, designed for reusability, performance and flexibility. And can be easily be added to any projects and frameworks. --- ### 05/README Pl (05/README-pl.md) # Rysowanie algorytmiczne ## Shaping functions Rozdział ten mógłby się nazywać "lekcja płota Pana Miyagiego". Poprzednio, mapowaliśmy znormalizowane pozycje *x* i *y* do *czerwonego* i *zielonego* kanału. W skróćie, stworzyliśmy fumkcję, która przyjmuje dwuwymiarowy wektor (x i y) i zwraca czterowymiarowy wektor (r, g, b i a). Jednak zanim zagłębimy się w takie transformacje między wymiarami, wypada najpierw opanować tworzenie jednowymiarowych funkcji w pełni. Im więcej czasu spędzisz na szlifowaniu tej umiejętności, tym lepsze będzie twoje "shader karate". Poniższy kod będzie naszym płotem. Wizualizujemy w nim znormalizowaną wartość współrzędnej *x* (`st.x`) w dwojaki sposób: poprzez jasność (zauważ płynny gradient od czerni do bieli) oraz przez rysowanie zielonego wykresu funkcji (w poniższym przykładzie funkcji *x* = *y*). Nie przejmuj się za bardzo funkcją `plot` - wrócimy do niej później. **Krótka uwaga**: Konstruktor typu `vec3` "rozumie", że chcesz przypisać tę samą wartość do każdego z trzech kanałów koloru, natomaist typu `vec4` rozumie, że chcesz stworzyć czterowymiarowy wektor z wektora trójwymiarowego i czwartej wartości (w tym wypadku wartość ta kontroluje alphę, czyli przezroczystość). Spójrz na linjki 19 i 25 powyżej. Kod jest twoim płotem - ważne, żebyś umiał na niego spojrzeć i go zrozumieć. Zakres od *0.0* do *1.0* będzie ci stale towarzyszył. Opanujesz sztukę blendowania (pol. "mieszania", "łączenia") i kształtowania tej linii Tę wzajmnie jednoznaczną (ang. "one-to-one") funkcję między *x* i *y* (lub jasnością) nazywamy *interpolacją liniową*. Możemy użyć funkcji matematycznych by *uformować* tę linię. Przykładowo, możemy podnieść *x* do potęgi 5, aby utworzyć *krzywą* linię. Ciekawe, prawda? W linijce 22 spróbuj użyć następujących wykładników: 20.0, 2.0, 1.0, 0.0, 0.2 lub 0.02. Zrozumienie związków między końcową wartością a wykładnikiem będzie bardzo przydatne. Używanie tego typu funkcji matematycznych tu i tam da ci pełnię kontroli nad twoim kodem. [`pow()`](../glossary/?search=pow) to natywna funkcja w GLSL, więc zaimplementowana jest na poziomie hardware'u, co oznacza większą wydajność. Zastąp funkcję potęgową w linijce 22 inną natywną funkcją. Spróbuj [`exp()`](../glossary/?search=exp), [`log()`](../glossary/?search=log) i [`sqrt()`](../glossary/?search=sqrt). W wypadku funkcji trygonometrycznych warto użyć liczby PI. Jest ona zdefiniowana w 8 linijce za pomocą makra, który zastąpi każde użycie `PI` wartością `3.14159265359`. ### Step i Smoothstep GLSL posiada też unikalne natywne funckje interpolacyjne wykorzystujące akcelerację sprzętową. Funkcja [`step()`](../glossary/?search=step) otrzymuje dwa argumenty. Pierwszy z nich to limit lub próg, natomiast drugi to wartość, którą chcemy porównać z tym progiem. Każda wartość poniżej limitu zwróci `0.0`, natomiast wszystko powyżej limitu zwróci `1.0`. Spróbuj zmienić tę wartość progową w linijce 20 poniższego kodu. Druga unikalna funkcja znana jest jako [`smoothstep()`](../glossary/?search=smoothstep) i otrzymuje trzy argumenty Dwa pierwsze argumenty służą do określenia początku i końca interpolacji (tranzycji/przejścia), natomiast trzeci jest wartością interpolowaną. W poprzednim przykładzie, w linii 12, zauważ, że użyliśmy smoothstep wewnątrz funkcji `plot()` do narysowania zielonej linii. Dla każdej pozycji wzdłuż osi x funkcja ta zwraca odpowiednią wartość y. Jak? Poprzez połączenie ze sobą dwóch [`smoothstep()`](../glossary/?search=smoothstep). Spójrz na poniżśzy fragment kodu (zauważ, że jest analogiczny do kodu w funkcji `plot()`) i wstaw go w linijce 20 powyższego przykładu. Wyobraź sobie, że widoczny wykres o kształcie dzwona (o kształcie rozkładu normalnego) "wędruje" wzdłuż funkcji przekazanej do argumentu `pct` funkcji `plot()`. ```glsl float y = smoothstep(0.2,0.5,st.x) - smoothstep(0.5,0.8,st.x); ``` ### Sinus i Cosinus Kiedy chcesz użyć matematyki do animacji, kształtowania lub blendowania wartości, nie ma nic lepszego niż zaprzyjaźnienie się z sinusem i cosinusem. Te dwie podstawowe funkcje trygonometryczne współpracują ze sobą, aby skonstruować okręgi, które są tak poręczne jak szwajcarski scyzoryk MacGyvera. Warto wiedzieć, jak się zachowują i na jakie sposoby można je łączyć. W skrócie, otrzymawszy kąt (w radianach), zwrócą one współrzędne *x* ([cosinus](../glossary/?search=cos)) i *y* ([sinus](../glossary/?search=sin)) punktu na brzegu okręgu o promieniu równym 1. Jednak fakt, że zwracają one znormalizowane wartości (wartości pomiędzy -1 a 1) w tak płynny sposób, czyni z nich niesamowite narzędzie. Choć trudno opisać wszystkie związki między funkcjami trygonometrycznymi i okręgami, powyższa animacja pięknie je wizualizuje. Przyjrzyj się uważnie powyższej fali sinusoidalnej. Zauważ, jak wartości *y* oscylują płynnie między +1 a -1. Jak widzieliśmy w przykładzie z czasem w poprzednim rozdziale, możesz wykorzystać to rytmiczne zachowanie [`sin()`](../glossary/?search=sin) do animowania dowolnych wartości. Jeśli czytasz ten przykład w przeglądarce, spróbuj zmienić kod w powyższym jedno-linjkowym przykładzie i zaobserwuj, jak zmienia się fala. (Uwaga: nie zapomnij o średniku na końcu linii). Spróbuj następnujących ćwiczeń i zobacz, co się stanie * Dodaj czas (`u_time`) do *x* wewnątrz funkcji `sin`. Zapamiętaj ten **ruch** wzdłuż *x*. * Pomnóż *x* przez `PI` wewnątrz funkcji `sin`. Zauważ, jak okres sinusa **zmniejsza się** do 2. Zwiększyliśmy w ten sposób częstotliwość. * Pomnóż czas (`u_time`) przez *x* wewnątrz funkcji `sin`. Zobacz jak **częstotliwość** zwiększa się, a okres maleje. Możliwe że u_time może być już bardzo duży, co czyni wykres trudnym do odczytania - odśwież stronę i spróbuj ponownie. * Dodaj 1.0 do [`sin(x)`](../glossary/?search=sin). Zobacz jak cała fala jest **przesunięta** w górę i wszystkie wartości są pomiędzy 0.0 a 2.0. * Pomnóż [`sin(x)`](../glossary/?search=sin) przez 2.0. Zobacz jak **amplituda** podwaja się. * Oblicz wartość bezwzględną ([`abs()`](../glossary/?search=abs)) funkcji `sin(x)`. Wygląda to jak ślad **odbijającej się** piłki. * Wyciągnij tylko część ułamkową ([`fract()`](../glossary/?search=fract)) z funkcji [`sin(x)`](../glossary/?search=sin). * Dodaj sufit ([`ceil()`](../glossary/?search=ceil)) oraz podłogę ([`floor()`](../glossary/?search=floor)) z [`sin(x)`](../glossary/?search=sin), aby otrzymać falę cyfrową o wartościach 1 i -1. ### Kilka dodatkowych przydatnych funkcji Pod koniec ostatniego ćwiczenia wprowadziliśmy kilka nowych funkcji. Teraz czas na eksperymentowanie z każdą z nich poprzez odkomentowanie poniższych linii po kolei. Poznaj te funkcje i zbadaj jak się zachowują. Wiem, zastanawiasz się... dlaczego? Szybkie wyszukiwanie w google "generative art" powie Ci to. Pamiętaj, że te funkcje to nasz płot. Opanowujemy ruch w jednym wymiarze, w górę i w dół. Już niedługo przyjdzie czas na dwa, trzy i cztery wymiary! ### Zaawansowane funkcje kształtujące [Golan Levin](http://www.flong.com/) ma świetną dokumentację bardziej złożonych shaping functions, które są niezwykle pomocne. Samodzielene przeniesienie ich do GLSL jest dobrym krokiem w stronę budowania własnego zasobu snippetów kodu. * Wielomianowe shaping fucntions: [www.flong.com/archive/texts/code/shapers_poly](http://www.flong.com/archive/texts/code/shapers_poly/) * Wykładnicze shaping functions: [www.flong.com/archive/texts/code/shapers_exp](http://www.flong.com/archive/texts/code/shapers_exp/) * Kołowe i Eliptyczne shaping functions: [www.flong.com/archive/texts/code/shapers_circ](http://www.flong.com/archive/texts/code/shapers_circ/) * Parametryczne (Beziera) shaping functions: [www.flong.com/archive/texts/code/shapers_bez](http://www.flong.com/archive/texts/code/shapers_bez/) Podobnie jak szefowie kuchni, którzy zbierają przyprawy i egzotyczne składniki, artyści cyfrowi mają szczególne zamiłowanie do pracy nad własnymi shaping functions. [Iñigo Quiles](http://www.iquilezles.org/) ma wspaniałą kolekcję [użytecznych funkcji](http://www.iquilezles.org/www/articles/functions/functions.htm). Po przeczytaniu [tego artykułu](http://www.iquilezles.org/www/articles/functions/functions.htm) spójrz na poniższe tłumaczenie tych funkcji na GLSL. Zwróć uwagę na małe zmiany, jak stawianie "." (kropki) przy liczbach zmiennoprzecinkowych i używanie nazw GLSL dla funkcji z *C* (na przykład zamiast `powf()` użyj `pow()`): Aby podtrzymać twoją motywację, oto elegancki przykład (wykonany przez [Danguafer](https://www.shadertoy.com/user/Danguafer)) ilustrujący opanowanie karate shaping functions. W następnym rozdziale zaczniemy używać naszych nowych sztuczek. Najpierw z mieszaniem kolorów, a potem z rysowaniem kształtów. #### Ćwiczenia Przyjrzyj się poniższej tabeli wzorów wykonanej przez [Kynd](http://www.kynd.info/log/). Zobacz jak łączy on funkcje i ich właściwości, aby kontrolować wartości pomiędzy 0.0 a 1.0. Teraz nadszedł czas, abyś poćwiczył, odtwarzając te funkcje. Pamiętaj im więcej będziesz ćwiczył tym lepsze będzie twoje karate. #### Pomocne narzędzia Oto kilka narzędzi, które ułatwią ci wizualizację tego typu funkcji. * Grapher: jeśli masz komputer z systemem MacOS, wpisz `grapher` w swoim Spotlight, a będziesz mógł użyć tego super poręcznego narzędzia. * [GraphToy](http://www.iquilezles.org/apps/graphtoy/): po raz kolejny [Iñigo Quilez](http://www.iquilezles.org) stworzył narzędzie do wizualizacji funkcji GLSL w WebGL. * [Shadershop](http://tobyschachman.com/Shadershop/): to niesamowite narzędzie stworzone przez [Toby Schachman](http://tobyschachman.com/) nauczy cię jak konstruować złożone funkcje w niesamowicie wizualny i intuicyjny sposób. --- ### 05/README Pt (05/README-pt.md) # Algoritmos de desenho ## Modelagem de funções Este capítulo poderia se chamar "Lição de pintar a cerca com o Sr. Miyagi". Anteriormente, nós mapeamos as posições normalizadas de *x* e *y* para os canais *red* e *green*. Essencialmente, nós criamos uma função que recebe um vetor bidimensional (x e y) e retornamos um com quatro dimensões (vermelho, verde, azul e alpha). Mas antes de irmos além de transformações dos dados entre as dimensões, precisamos fazer algo mais simples... muito mais simples: entender como criar uma função unidimensional. Quanto mais energia e tempo que você gastar dominando isso, mais forte seu karatê de shader será. A estrutura do código a seguir será nossa cerca. Nela, nós visualizaremos os valores normalizados da coordenada *x* (`st.x`) de dois jeitos: uma com a claridade (observe o belo gradiente de branco para preto) e a outra é traçando uma linha verde por cima (neste caso, o valor de *x* será atribuído diretamente a *y*). Não foque tanto na função de traçar, nós a veremos com mais detalhes em alguns minutos. **Nota rápida**: O construtor do tipo `vec3` "entende" que você quer atribuir o mesmo valor aos três canais de cores, enquanto `vec4` entende que você quer construir um vetor quadridimensional usando um vetor tridimensional e também um quarto valor (neste caso, o valor que controlará o alpha ou opacidade). Veja as linhas 19 e 25 acima por exemplo. Este código é a sua cerca: É importante observar e entendê-lo. Você voltará algumas vezes para este espaço entre *0.0* e *1.0*. Aprenderá a arte de mesclar e dar forma a esta linha. Essa relação de um pra um entre *x* e *y* (ou de brilho) é conhecida como *interpolação linear*. A partir daqui, nós usaremos algumas funções matemáticas para dar *forma* a linha. Por exemplo, nós podemos elevar *x* à quinta potência para criar uma linha *curvada*. Interessante, não é? Na linha 22, tente diferentes expoentes: 20.0. 2.0, 1.0, 0.0, 0.2 e 0.02 por exemplo. Entender essa relação entre o valor e o expoente será de grande ajuda. Usar esses tipos de funções matemáticas aqui e ali nos dará um controle significativo do nosso código, uma espécie de acumpultura de dados que permite que você controle a fluência dos valores. [`pow()`](../glossary/?search=pow) é uma função nativa no GLSL e existem muitas outras. A maioria delas são aceleradas em nível de hardware, o que significa que se elas forem usadas da forma certa e com juízo, farão seu código mais rápido. Substitua a função de potência na linha 22. Tente outras como: [`exp()`](../glossary/?search=exp), [`log()`](../glossary/?search=log) e [`sqrt()`](../glossary/?search=sqrt). Algumas destas funções são mais interessantes quando você experimenta utilizando PI. Você pode ver na linha 8 que eu defini uma macro que retornará qualquer chamada de `PI` com o valor de `3.14159265359`. ### Step e smoothstep GLSL também tem algumas exclusivas funções nativas de interpolação que são aceleradas pelo hardware. A interpolação [`step()`](../glossary/?search=step) recebe dois parâmetros. O primeiro é para o limite ou limiar, enquanto o segundo é o valor que nós queremos passar. Qualquer valor abaixo do limite retornará `0.0` e qualquer um acima do limite retornará `1.0`. Experimente mudar este valor de limiar na linha 20 do código a seguir. A outra função exclusiva é conhecida como [`smoothstep()`](../glossary/?search=smoothstep). Dado um intervalo de dois números, está função irá interpolar os valores entre o intervalo definido. Os dois primeiros parâmetros são para o início e o final da transição, enquanto o terceiro é o valor que será interpolado. No exemplo anterior, na linha 12, veja que estamos usando smoothstep para desenhar a linha verde na função `plot()`. Para cada posição dentro do eixo *x*, esta função faz uma *marcação* num valor específico de *y*. Como? Conectando duas [`smoothstep()`](../glossary/?search=smoothstep) juntas. Dê uma olhada na seguinte função, troque a linha 20 acima por esta, e imagine-a como um corte vertical. O fundo se parece com uma linha, certo? ```glsl float y = smoothstep(0.2,0.5,st.x) - smoothstep(0.5,0.8,st.x); ``` ### Seno e Cosseno Quando queremos usar um pouco de matemática para animar, dar forma e mesclar valores, não há nada melhor que ser amigo do seno e cosseno. Essas duas funções trigonométricas básicas trabalham juntas para construir circunferências que são tão úteis como o canivete suíço de MacGyver. É importante entender como elas se comportam e de quais formas elas podem ser combinadas. Em poucas palavras, dado um ângulo (em radianos), elas retornarão a posição correta de *x* ([cosseno](../glossary/?search=cos)) e *y* ([seno](../glossary/?search=sin)) de um ponto na linha de uma circunferência de raio igual a 1. O fato de elas retornarem valores normalizados (que vão de 1 a -1) de maneira suave faz delas, ferramentas incríveis. Enquanto é difícil descrever todas as relações entre as funções trigonométricas e circunferências, a animação acima faz um ótimo trabalho em exemplificar visualmente esta relação. Preste muita atenção nesta onda de seno. Note como o valor de *y* flui suavemente entre +1 e -1. Como vimos nos exemplos de tempo no capítulo anterior, podemos usar esse movimento rítmico do [`sin()`](../glossary/?search=sin) para animar propriedades. Se você estiver lendo este exemplo em um navegador, você verá que você pode alterar o código da fórmula acima para observar como as ondas mudam. (Nota: não se esqueça do ponto e vírgula no final das linhas). Experimente com os seguintes exercícios e veja o que acontece: * Some o tempo (`u_time`) ao *x* antes de calcular o `sin`. Perceba o **movimento** ao longo de *x* * Multiplique *x* por `PI` antes de calcular o `sin`. Veja como a **frequência** entre as fases se torna mais comprimida. * Multiplique *x* pelo tempo (`u_time`) antes de calcular o `sin`. Note que u_time já pode ter se tornado um valor muito grande, o que torna difícil enxergar a linha verde. * Some 1.0 a [`sin(x)`](../glossary/?search=sin). Veja como toda a onda foi **deslocada** para cima e agora seus valores vão de 0.0 a 2.0. * Multiplique [`sin(x)`](../glossary/?search=sin) por 2.0. Veja como a **amplitude** dobra seu tamanho. * Calcule o valor absoluto ([`abs()`](../glossary/?search=abs)) do `sin(x)`. Se parece com o rastro de uma *bola quicando*. * Extraia apenas a parte fracionária ([`fract()`](../glossary/?search=fract)) do resultante do [`sin(x)`](../glossary/?search=sin). * Some o número inteiro mais alto ([`ceil()`](../glossary/?search=ceil)) e o inteiro mais baixo ([`floor()`](../glossary/?search=floor)) do resultante do [`sin(x)`](../glossary/?search=sin) para conseguir uma onda digital de 1 e -1. ### Outras funções úteis No final do último exercício nós apresentamos algumas novas funções. Agora é hora de experimentar cada uma descomentando as linhas abaixo, uma de cada vez. É importante entender o funcionamento e comportamento destas funções. Eu sei, você deve estar se perguntando... Por quê? Uma rápida pesquisa no google de "arte generativa" (ou generative art) te mostrará. Lembre-se que estas funções são a nossa cerca. Nós estamos dominando o movimento em uma dimensão, para cima e para baixo. Logo, usaremos duas, três quatro dimensões! ### Modelando funções avançadas [Golan Levin](http://www.flong.com/) tem uma ótima documentação de modelagem de funções complexas que são de extraordinária ajuda. Portá-las para GLSL é uma excelente forma para começar seu próprio banco de trechos de códigos. * [Polynomial Shaping Functions: www.flong.com/archive/texts/code/shapers_poly](http://www.flong.com/archive/texts/code/shapers_poly/) * [Exponential Shaping Functions: www.flong.com/archive/texts/code/shapers_exp](http://www.flong.com/archive/texts/code/shapers_exp/) * [Circular & Elliptical Shaping Functions: www.flong.com/archive/texts/code/shapers_circ](http://www.flong.com/archive/texts/code/shapers_circ/) * [Bezier and Other Parametric Shaping Functions: www.flong.com/archive/texts/code/shapers_bez](http://www.flong.com/archive/texts/code/shapers_bez/) Como chefs que coletam temperos e ingredientes exóticos, artistas digitais e programadores criativos tem um amor único por trabalhar nas suas próprias funções. [Iñigo Quiles](http://www.iquilezles.org/) tem uma grande coleção de [funções úteis](http://www.iquilezles.org/www/articles/functions/functions.htm). Depois de ler [este artigo](http://www.iquilezles.org/www/articles/functions/functions.htm), dê uma olhada na seguinte na seguinte tradução destas funções para GLSL. Preste atenção nas pequenas mudanças necessárias, como colocar o "." (ponto) nos números de ponto flutuantes ou usar o nome em GLSL para as *Funções em C*; por exemplo, em vez de `powf()`, usamos `pow()`: Para mantermos sua motivação lá em cima, aqui temos um exemplo elegante (feito por [Danguafer](https://www.shadertoy.com/user/Danguafer)) em masterizar o karatê das funções. No *Próximo >>* capítulo, nós começaremos a usar nossos novos movimentos. Primeiro misturando cores e em seguida, desenhando formas. #### Exercício Dê uma olhada na seguinte tabela de equações feita por [Kynd](http://www.kynd.info/log/). Veja como ele está combinando as funções e suas propriedades para controlar os valores entre 0.0 e 1.0. Agora é a hora de você praticar replicando estas funções. Lembre-se que quanto mais você praticar, melhor será o seu karatê de shaders. #### Para sua caixa de ferramentas Aqui temos algumas ferramentas que facilitarão a visualização destes tipos de funções. * [GraphToy](http://www.iquilezles.org/apps/graphtoy/): mais uma vez [Iñigo Quilez](http://www.iquilezles.org) fez uma ferramenta para visualizar funções em GLSL em WebGL. * [LYGIA Shader Library](https://lygia.xyz/) a shader library of reusable functions that can be include easily on your projects. It's very granular, designed for reusability, performance and flexibility. And can be easily be added to any projects and frameworks. --- ### 05/README Tr (05/README-tr.md) # Algoritmik çizim ## Şekillendirme fonksiyonları Bu bölüm "Bay Miyagi'nin çit boyama dersi" olarak adlandırılabilirdi. Daha önce, *x* ve *y*'nin normalize edilmiş konumunu *kırmızı* ve *yeşil* kanallara eşledik. Esasen iki boyutlu bir vektörü (x ve y) alıp dört boyutlu bir vektör (r, g, b ve a) döndüren bir fonksiyon yaptık. Ancak boyutlar arasında veri dönüştürmeye daha ileri gitmeden önce, daha basit başlamamız gerekiyor... çok daha basit. Bu, tek boyutlu fonksiyonlar yapmayı anlamak demektir. Bunu öğrenmeye ve ustalaşmaya ne kadar çok enerji ve zaman harcarsanız, shader karateniz o kadar güçlü olacaktır. Aşağıdaki kod yapısı bizim çitimiz olacak. İçinde, *x* koordinatının (`st.x`) normalize edilmiş değerini iki şekilde görselleştiriyoruz: biri parlaklıkla (siyahtan beyaza güzel gradyanı gözlemleyin) ve diğeri üzerine yeşil bir çizgi çizerek (bu durumda *x* değeri doğrudan *y*'ye atanır). Plot fonksiyonuna fazla odaklanmayın, birazdan daha ayrıntılı inceleyeceğiz. **Hızlı Not**: `vec3` tip yapıcısı, üç renk kanalına aynı değeri atamak istediğinizi "anlar"; `vec4` ise üç boyutlu bir vektörle artı dördüncü bir değerle (bu durumda alfa veya opaklığı kontrol eden değer) dört boyutlu bir vektör oluşturmak istediğinizi anlar. Örneğin yukarıdaki 19. ve 25. satırlara bakın. Bu kod sizin çitinizdir; onu gözlemlemek ve anlamak önemlidir. *0.0* ile *1.0* arasındaki bu alana tekrar tekrar geri döneceksiniz. Bu çizgiyi harmanlama ve şekillendirme sanatında ustalaşacaksınız. *x* ile *y* (veya parlaklık) arasındaki bu bire bir ilişki *doğrusal enterpolasyon* olarak bilinir. Buradan, çizgiyi *şekillendirmek* için bazı matematiksel fonksiyonları kullanabiliriz. Örneğin, *eğri* bir çizgi yapmak için *x*'i 5'in kuvvetine yükseltebiliriz. İlginç, değil mi? 22. satırda farklı üsler deneyin: örneğin 20.0, 2.0, 1.0, 0.0, 0.2 ve 0.02. Değer ile üs arasındaki bu ilişkiyi anlamak çok faydalı olacaktır. Bu tür matematiksel fonksiyonları şurada burada kullanmak, kodunuz üzerinde ifade gücü kontrolü sağlayacaktır — değerlerin akışını kontrol etmenizi sağlayan bir tür veri akupunkturu. [`pow()`](../glossary/?search=pow) GLSL'de yerleşik bir fonksiyondur ve başka birçoğu daha vardır. Çoğu donanım düzeyinde hızlandırılmıştır, bu da doğru şekilde ve ölçülü kullanıldıklarında kodunuzu daha hızlı hale getirecekleri anlamına gelir. 22. satırdaki üs fonksiyonunu değiştirin. Başkalarını deneyin: [`exp()`](../glossary/?search=exp), [`log()`](../glossary/?search=log) ve [`sqrt()`](../glossary/?search=sqrt). Bu fonksiyonlardan bazıları PI ile oynadığınızda daha ilginçtir. 8. satırda, `PI`'nin herhangi bir kullanımını `3.14159265359` değeriyle değiştirecek bir makro tanımladığımı görebilirsiniz. ### Step ve Smoothstep GLSL'de donanım hızlandırmalı bazı benzersiz yerleşik enterpolasyon fonksiyonları da vardır. [`step()`](../glossary/?search=step) enterpolasyonu iki parametre alır. Birincisi sınır veya eşik değeridir, ikincisi ise kontrol etmek veya geçirmek istediğimiz değerdir. Sınırın altındaki herhangi bir değer `0.0` döndürürken, sınırın üstündeki her şey `1.0` döndürür. Aşağıdaki kodun 20. satırındaki bu eşik değerini değiştirmeyi deneyin. Diğer benzersiz fonksiyon [`smoothstep()`](../glossary/?search=smoothstep) olarak bilinir. İki sayı aralığı ve bir değer verildiğinde, bu fonksiyon değeri tanımlanmış aralık arasında enterpolasyon yapar. İlk iki parametre geçişin başlangıcı ve sonu içindir, üçüncüsü ise enterpolasyon yapılacak değer içindir. Önceki örnekte, 12. satırda, `plot()` fonksiyonunda yeşil çizgiyi çizmek için smoothstep kullandığımıza dikkat edin. *x* ekseni boyunca her konum için bu fonksiyon belirli bir *y* değerinde bir *tümsek* oluşturur. Nasıl mı? İki [`smoothstep()`](../glossary/?search=smoothstep)'i birbirine bağlayarak. Aşağıdaki fonksiyona bir bakın, yukarıdaki 20. satırın yerine koyun ve bunu dikey bir kesim olarak düşünün. Arka plan bir çizgiye benziyor, değil mi? ```glsl float y = smoothstep(0.2,0.5,st.x) - smoothstep(0.5,0.8,st.x); ``` ### Sinüs ve Kosinüs Değerleri canlandırmak, şekillendirmek veya harmanlamak için biraz matematik kullanmak istediğinizde, sinüs ve kosinüsle arkadaş olmaktan daha iyi bir şey yoktur. Bu iki temel trigonometrik fonksiyon, MacGyver'ın İsviçre çakısı kadar kullanışlı daireler oluşturmak için birlikte çalışır. Nasıl davrandıklarını ve hangi şekillerde birleştirilebileceklerini bilmek önemlidir. Özetle, bir açı (radyan cinsinden) verildiğinde, yarıçapı 1'e eşit olan bir dairenin kenarındaki bir noktanın *x* ([kosinüs](../glossary/?search=cos)) ve *y* ([sinüs](../glossary/?search=sin)) doğru konumunu döndürürler. Ancak normalize edilmiş değerleri (-1 ile 1 arasında değerler) bu kadar düzgün bir şekilde döndürmeleri, onları inanılmaz bir araç haline getirir. Trigonometrik fonksiyonlar ve daireler arasındaki tüm ilişkileri tanımlamak zor olsa da, yukarıdaki animasyon bu ilişkileri görsel olarak özetleme konusunda harika bir iş çıkarıyor. Bu sinüs dalgasına dikkatle bakın. *y* değerlerinin +1 ile -1 arasında nasıl düzgün bir şekilde aktığını not edin. Önceki bölümdeki zaman örneğinde gördüğümüz gibi, [`sin()`](../glossary/?search=sin)'in bu ritmik davranışını özellikleri canlandırmak için kullanabilirsiniz. Bu örneği bir tarayıcıda okuyorsanız, dalganın nasıl değiştiğini izlemek için yukarıdaki formüldeki kodu değiştirebileceğinizi göreceksiniz. (Not: satırların sonundaki noktalı virgülü unutmayın.) Aşağıdaki alıştırmaları deneyin ve ne olduğunu gözlemleyin: * `sin`'i hesaplamadan önce *x*'e zaman (`u_time`) ekleyin. *x* boyunca bu **hareketi** içselleştirin. * `sin`'i hesaplamadan önce *x*'i `PI` ile çarpın. İki fazın nasıl **küçüldüğünü** ve her döngünün her 2 tam sayıda bir tekrarladığını not edin. * `sin`'i hesaplamadan önce zamanı (`u_time`) *x* ile çarpın. Fazlar arasındaki **frekansın** nasıl giderek daha sıkıştığını görün. u_time'ın zaten çok büyük olabileceğini ve grafiğin okunmasını zorlaştırabileceğini unutmayın. * [`sin(x)`](../glossary/?search=sin)'e 1.0 ekleyin. Tüm dalganın nasıl yukarı **kaydığını** ve şimdi tüm değerlerin 0.0 ile 2.0 arasında olduğunu görün. * [`sin(x)`](../glossary/?search=sin)'i 2.0 ile çarpın. **Genliğin** nasıl iki katına çıktığını görün. * `sin(x)`'in mutlak değerini ([`abs()`](../glossary/?search=abs)) hesaplayın. **Zıplayan** bir topun izine benziyor. * [`sin(x)`](../glossary/?search=sin) sonucunun sadece kesir kısmını ([`fract()`](../glossary/?search=fract)) çıkarın. * [`sin(x)`](../glossary/?search=sin) sonucunun üst tam sayısını ([`ceil()`](../glossary/?search=ceil)) ve alt tam sayısını ([`floor()`](../glossary/?search=floor)) ekleyerek 1 ve -1 değerlerinden oluşan dijital bir dalga elde edin. ### Bazı ekstra faydalı fonksiyonlar Son alıştırmanın sonunda bazı yeni fonksiyonlar tanıttık. Şimdi aşağıdaki satırları teker teker açarak her biriyle deney yapma zamanı. Bu fonksiyonları tanıyın ve nasıl davrandıklarını inceleyin. Biliyorum, merak ediyorsunuz... neden? "Generative art" (üretken sanat) için hızlı bir Google araması size söyleyecektir. Bu fonksiyonların bizim çitimiz olduğunu unutmayın. Tek boyutta harekete, yukarı ve aşağıya hakim oluyoruz. Yakında, iki, üç ve dört boyut zamanı gelecek! ### Gelişmiş şekillendirme fonksiyonları [Golan Levin](http://www.flong.com/)'in olağanüstü derecede faydalı olan daha karmaşık şekillendirme fonksiyonları hakkında harika belgeleri var. Bunları GLSL'ye taşımak, kendi kod parçacığı kaynağınızı oluşturmaya başlamak için gerçekten akıllıca bir hamle. * Polinom Şekillendirme Fonksiyonları: [www.flong.com/archive/texts/code/shapers_poly](http://www.flong.com/archive/texts/code/shapers_poly/) * Üstel Şekillendirme Fonksiyonları: [www.flong.com/archive/texts/code/shapers_exp](http://www.flong.com/archive/texts/code/shapers_exp/) * Dairesel & Eliptik Şekillendirme Fonksiyonları: [www.flong.com/archive/texts/code/shapers_circ](http://www.flong.com/archive/texts/code/shapers_circ/) * Bezier ve Diğer Parametrik Şekillendirme Fonksiyonları: [www.flong.com/archive/texts/code/shapers_bez](http://www.flong.com/archive/texts/code/shapers_bez/) Baharat ve egzotik malzeme toplayan aşçılar gibi, dijital sanatçılar ve yaratıcı kodlayıcılar da kendi şekillendirme fonksiyonları üzerinde çalışmaya özel bir sevgi beslerler. [Iñigo Quiles](http://www.iquilezles.org/)'in harika bir [kullanışlı fonksiyonlar](http://www.iquilezles.org/www/articles/functions/functions.htm) koleksiyonu var. [Bu makaleyi](http://www.iquilezles.org/www/articles/functions/functions.htm) okuduktan sonra, bu fonksiyonların GLSL'ye aşağıdaki çevirisine bir göz atın. Gereken küçük değişikliklere dikkat edin, kayan noktalı sayılara "." (nokta) koymak ve *C fonksiyonları* için GLSL adını kullanmak gibi; örneğin `powf()` yerine `pow()` kullanın: Motivasyonunuzu yüksek tutmak için, şekillendirme fonksiyonları karatesinde ustalaşmanın zarif bir örneği ([Danguafer](https://www.shadertoy.com/user/Danguafer) tarafından yapılmış): *Sonraki >>* bölümde yeni hareketlerimizi kullanmaya başlayacağız. Önce renkleri karıştırarak, sonra şekiller çizerek. #### Alıştırma [Kynd](http://www.kynd.info/log/) tarafından yapılan aşağıdaki denklem tablosuna bir göz atın. Fonksiyonları ve özelliklerini birleştirerek 0.0 ile 1.0 arasındaki değerleri nasıl kontrol ettiğini görün. Şimdi bu fonksiyonları kopyalayarak pratik yapma zamanı. Unutmayın, ne kadar çok pratik yaparsanız karateniz o kadar iyi olacak. #### Araç kutunuz için * [LYGIA](https://lygia.xyz/), projelerinize kolayca dahil edilebilen yeniden kullanılabilir fonksiyonlardan oluşan bir shader kütüphanesidir. Çok ayrıntılıdır, yeniden kullanılabilirlik, performans ve esneklik için tasarlanmıştır. Ve herhangi bir projeye ve framework'e kolayca eklenebilir. Farklı bölümlere ayrılmıştır ve [matematik işlemleri](https://lygia.xyz/math) için tam bir bölümü vardır. * [GraphToy](http://www.iquilezles.org/apps/graphtoy/): yine [Iñigo Quilez](http://www.iquilezles.org) WebGL'de GLSL fonksiyonlarını görselleştirmek için bir araç yaptı. --- ### 05/README Ua (05/README-ua.md) # Алгоритмічне малювання ## Формотворчі функції або функції формування Цей розділ можна було б назвати "Урок з парканом від містера Міягі". Раніше ми зіставляли нормалізоване положення координат *x* і *y* з *червоним* і *зеленим* каналами. По суті, ми створили функцію, яка приймає двовимірний вектор (x і y) та повертає чотиривимірний вектор (r, g, b і a). Але перш ніж перейти до подальшого перетворення даних між вимірами, нам потрібно почати з простіших речей... набагато простіших. З розуміння того, як користуватись одновимірними функціями. Чим більше часу та енергії ви витратите на освоєння цього і відповідну практику, тим сильнішим буде ваше шейдерне карате. Наступний приклад коду буде нашим парканом. У ньому ми візуалізуємо нормалізоване значення координати *x* (`st.x`) двома способами: один за допомогою яскравості (подивіться на гарний градієнт від чорного до білого), а інший шляхом побудови зеленої діагональної лінії зверху (у цьому випадку значення *x* присвоюється безпосередньо до *y*). Поки що не зосереджуйтеся занадто на функції `plot`. Згодом ми розберемося з нею більш детально. **Коротка примітка**: конструктор типу `vec3` "розуміє", що ви хочете призначити одне і те саме значення трьом каналам, тоді як `vec4` розуміє, що ви хочете побудувати чотиривимірний вектор за допомогою одного тривимірного і додаткового четвертого значення. У цьому випадку четверте значення відповідатиме за альфа-канал або непрозорість. Перегляньте ці приклади на рядках 19 і 25. Цей код — ваш паркан. Важливо бачити його і розуміти. Ви знову і знову повертатиметеся до цього простору між *0.0* і *1.0*. Ви опануєте мистецтво змішування та формування подібних ліній. Цей однозначний зв'язок між *x* і *y* (або яскравістю) відомий як *лінійна інтерполяція*. З цього моменту ми можемо використовувати деякі математичні функції для надання лінії певної *форми*, для її формування. Наприклад, ми можемо піднести *x* до 5 степеня, щоб отримати *криву* лінію. Цікаво, правда? У рядку 22 спробуйте різні показники для степеня: наприклад, 20.0, 2.0, 1.0, 0.0, 0.2 і 0.02. Розуміння цього зв'язку між значенням і експонентою буде дуже корисним. Використання подібних типів математичних функцій дасть вам виразний засіб для контролю вашого коду, свого роду акупунктуру даних, яка дозволить вам контролювати потік значень. [`pow()`](../glossary/?lan=ua&search=pow) — одна з багатьох вбудованих функцій GLSL. Більшість із них прискорені на апаратному рівні, а це означає, що якщо вони використовуються належним чином і з обережністю, то ваш код стане швидшим. Замініть функцію `pow` у рядку 22 на якусь іншу, наприклад: [`exp()`](../glossary/?lan=ua&search=exp), [`log()`](../glossary/?lan=ua&search=log) і [`sqrt()`](../glossary/?lan=ua&search=sqrt). Деякі з цих функцій стають цікавіші із використанням числа PI. У рядку 8 ви можете побачити, що я визначив макрос, який замінить будь-яке використання `PI` на значення `3.14159265359`. ### step і smoothstep GLSL має деякі унікальні функції інтерполяції, які також апаратно прискорені. Функція інтерполяції [`step()`](../glossary/?lan=ua&search=step) приймає два параметри. Перший — це межа або поріг, а другий — це значення для якого ми хочемо застосувати функцію. Будь-яке значення нижче порогу поверне `0.0`, а все, що його перевищує — `1.0`. Спробуйте змінити у наступному коді порогове значення, що на рядку 20: Інша унікальна функція називається [`smoothstep()`](../glossary/?lan=ua&search=smoothstep). Функція плавно інтерполює значення у вказаному діапазоні з двох чисел. Перші два параметри призначені для початку та кінця перехідного діапазону, а третій — для значення, яке потрібно інтерполювати. У функції `plot()` на рядку 12 попереднього прикладу, ми використали smoothstep, щоб намалювати зелену лінію. Для кожної позиції вздовж вісі *x* ця функція робить *виступи* у певному значенні *y*. Яким чином? Об'єднавши результат двох функцій [`smoothstep()`](../glossary/?lan=ua&search=smoothstep) разом. Погляньте на наступну функцію, замініть нею рядок 20 вище і подумайте про неї як про вертикальний розріз. Фон схожий на лінію, чи не так? ```glsl float y = smoothstep(0.2,0.5,st.x) - smoothstep(0.5,0.8,st.x); ``` ### Синус і Косинус Коли ви хочете застосувати певну математику для анімації, або при формуванні чи змішуванні значень, немає нічого кращого, ніж товаришувати з синусом і косинусом. Ці дві основні тригонометричні функції працюють у парі при побудові кола, що є настільки ж корисним, як і швейцарський армійський ніж. Важливо знати, як вони поводяться і як їх можна комбінувати. Коротко кажучи, задаючи їм кут у радіанах, вони повертають правильне положення координати *x* ([cos](../glossary/?lan=ua&search=cos)) і *y* ([sin](../glossary/?lan=ua&search=sin)) точки на краю кола з радіусом, рівним 1. А той факт, що вони повертають нормалізовані значення (від -1 до 1), які до того ж достатньо плавні, робить їх неймовірним інструментом. Хоча важко описати всі взаємозв'язки між тригонометричними функціями та колами, наведена вище анімація чудово їх узагальнює. Уважно подивіться на зображену вище синусоїду. Зверніть увагу, як значення *y* плавно змінюються між +1 і -1. Як ми бачили у прикладі зі змінною для часу, що був у попередньому розділі, ви можете використовувати цю ритмічну поведінку [`sin()`](../glossary/?lan=ua&search=sin) для анімації властивостей. Якщо ви читаєте цей приклад у браузері, то можете змінити код у формулі вище, щоб побачити, як змінюється хвиля. (Примітка: не забудьте про крапку з комою в кінці рядка.) Спробуйте виконати наступні вправи та зверніть увагу на те, що відбувається: * Додайте час (`u_time`) до *x* перед обчисленням `sin`. Оцініть **рух** уздовж осі *x*. * Помножте *x* на `PI` перед обчисленням `sin`. Зверніть увагу, як дві фази **скорочуються**, так що кожен цикл повторюється через кожні 2 цілих числа. * Помножте час (`u_time`) на *x* перед обчисленням `sin`. Подивіться, як **частота** між фазами стає все більш і більш стиснутою. Зверніть увагу, що `u_time` до цього моменту може стати вже дуже великим, що ускладнить сприйняття отриманого графіка. * Додайте 1.0 до [`sin(x)`](../glossary/?lan=ua&search=sin). Подивіться, як уся хвиля **змістилася** вгору, і тепер усі значення знаходяться між 0.0 і 2.0. * Помножте [`sin(x)`](../glossary/?lan=ua&search=sin) на 2.0. Подивіться, як **амплітуда** збільшилася вдвічі. * Обчисліть абсолютне значення за допомогою ([`abs()`](../glossary/?lan=ua&search=abs)) `sin(x)`. Графік стане схожим на траєкторію м'яча, що **стрибає**. * Виділіть лише дробову частину від результату [`sin(x)`](../glossary/?lan=ua&search=sin) за допомогою [`fract()`](../glossary/?lan=ua&search=fract). * Додайте результати [`sin(x)`](../glossary/?lan=ua&search=sin), округлені в більшу ([`ceil()`](../glossary/?lan=ua&search=ceil)) та меншу сторони ([`floor()`](../glossary/?lan=ua&search=floor)), щоб отримати цифрову хвилю зі значеннями 1 і -1. ### Деякі додаткові корисні функції Наприкінці останньої вправи ми представили кілька нових функцій. Настав час поекспериментувати з ними. Спробуйте по черзі розкоментувати та випробувати кожну з них. Ознайомтеся з цими функціями та вивчіть, як вони поводяться. Я знаю, вам цікаво... навіщо? Швидкий пошук у Google на тему "генеративне мистецтво" підкаже вам. Майте на увазі, що ці функції є нашим парканом. Ми опановуємо рух в одному вимірі, вгору і вниз. Вже зовсім скоро настане час для двох, трьох і чотирьох вимірів! ### Просунуті формотворчі функції [Golan Levin](http://www.flong.com/) має чудову документацію про складніші формотворчі функції, які є надзвичайно корисними. Перенесення їх на GLSL — це розумний крок, щоб почати створювати власний ресурс з фрагментами коду. * Поліноміальні формотворчі функції: [www.flong.com/archive/texts/code/shapers_poly](http://www.flong.com/archive/texts/code/shapers_poly/) * Експоненціальні формотворчі функції: [www.flong.com/archive/texts/code/shapers_exp](http://www.flong.com/archive/texts/code/shapers_exp/) * Кругові та еліптичні формотворчі функції: [www.flong.com/archive/texts/code/shapers_circ](http://www.flong.com/archive/texts/code/shapers_circ/) * Безьє та інші параметричні функції: [www.flong.com/archive/texts/code/shapers_bez](http://www.flong.com/archive/texts/code/shapers_bez/) Подібно до кухарів, які збирають спеції та екзотичні інгредієнти, цифрові художники та креативні кодери приділяють особливу увагу створенню власних формотворчих функцій. [Iñigo Quiles](http://www.iquilezles.org/) має чудову колекцію [корисних функцій](http://www.iquilezles.org/www/articles/functions/functions.htm). Прочитавши [цю статтю](http://www.iquilezles.org/www/articles/functions/functions.htm), перегляньте на наступні реалізації цих функцій на GLSL. Зверніть увагу на невеликі зміни, які потрібно було внести. Як-от на "." (крапку) для чисел з рухомою крапкою та заміни деяких *C*-функцій на GLSL аналоги: наприклад, замість `powf()` використовується `pow()`. Для підтримки вашої мотивації, ось елегантний приклад опанування карате формотворчих функцій. Автор [Danguafer](https://www.shadertoy.com/user/Danguafer): У наступному розділі ми почнемо використовувати нові карате-рухи. Спочатку почнемо зі змішування кольорів, а потім перейдемо до малювання фігур. #### Вправа Подивіться на наведену нижче таблицю рівнянь, створену за авторства [Kynd](http://www.kynd.info/log/). Подивіться, як він поєднує функції та їхні властивості, щоб контролювати значення між 0.0 та 1.0. Настав час потренуватися, самостійно відтворюючи ці функції. Пам'ятайте, що чим більше ви тренуєтеся, тим краще буде ваше карате. #### До вашого інструментарію Ось кілька інструментів, які полегшать візуалізацію цих типів функцій: * [GraphToy](http://www.iquilezles.org/apps/graphtoy/): вже згаданий [Iñigo Quilez](http://www.iquilezles.org) створив інструмент для візуалізації GLSL-функцій у WebGL. * [Бібліотека шейдерів LYGIA](https://lygia.xyz/) — бібліотека шейдерів із функцій, які можна легко включити та використати у ваших проєктах. Бібліотека дуже атомарна, створена для зручного перевикористання, продуктивності й гнучкості. Може бути легко додана до будь-яких проєктів та фреймворків. --- ### 05/README Vi (05/README-vi.md) # Các thuật toán hình học ## Các hàm số cơ bản (Hàm hình dạng - Shape function) Chương này có thể đặt tên là "bài học sơn hàng rào của ngài Miyagi". Trước đó, ta đã ánh xạ toạ độ *x* và *y* sang các kênh *RED* và *GREEN*. Ta cũng đã tạo ra một hàm nhận một vector 2 chiều (x, y) làm tham số đầu vào và trả ra một vector 4 chiều (r, g, b, a). Nhưng trước khi đi sâu vào việc biến đổi dữ liệu giữa các kiểu thì ta cần bắt đầu từ những thứ đơn giản hơn... rất nhiều. Đó là việc tạo ra các hàm chỉ xử lý vector 1 chiều. Càng bỏ thời gian và công sức học cho thuần thục kỹ năng này, võ karate-shader của bạn sẽ càng cao siêu. Cấu trúc code dưới đây sẽ là hàng rào của chúng ta. Trong đó, ta chuẩn hoá giá trị *x* (`st.x`) bằng 2 cách: một là với cường độ sáng (quan sát gradient từ đen sang trắng) và hai là vẽ đồ thị một đường màu xanh lá đè lên trên (trường hợp này giá trị của *x* được gán trực tiếp cho *y*). Đừng tập trung quá nhiều vào hàm vẽ đồ thị, ta sẽ đi vào chi tiết sau. **Chú thích**: Hàm khởi tạo `vec3` sẽ tự động "nhận ra" bạn muốn gán màu của cả 3 kênh RGB giống nhau ở dòng 19. Còn hàm khởi tạo `vec4` thì "nhận ra" bạn muốn tạo một vector 4 chiều từ một vector 3 chiều kết hợp một số thực nữa dành cho chiều thứ tư, ở dòng 25. Đoạn code này là hàng rào của bạn; nên hãy tập trung quan sát kỹ. Bạn sẽ còn sử dụng khoảng `0.0` và `1.0` này nhiều lần nữa. Bạn sẽ thuần thục kỹ năng tạo nên đồ thị này. Ánh xạ một-một giữa *x* và *y* (phần gradient đen trắng) được gọi là *nội suy tuyến tính (linear interpolation)*. Ta có thể thay các hàm toán học khác để thay đổi hình dáng của đồ thị. Ví dụ ta có thể vẽ đồ thị luỹ thừa 5 của *x* để có được đường cong như hình dưới. Thú vị phải không ? Ở dòng 22, hãy thử các số mũ khác nhau như: 20.0, 2.0, 1.0, 0.0, 0.2 và 0.02 chẳng hạn. Hiểu được mối quan hệ giữa giá trị và số mũ sẽ rất hữu ích. Bằng cách sử dụng các hàm toán học ở đây bạn sẽ nắm rõ hơn về cách điều khiển các đường cong. [`pow()`](../glossary/?lan=vi&search=pow) là hàm có sẵn trong số rất nhiều hàm của GLSL. Hầu hết đều được tăng tốc tính toán bởi phần cứng, có nghĩa là nếu được dùng đúng cách nó sẽ giúp code chạy nhanh hơn. Hãy thay hàm luỹ thừa ở dòng 22 bằng các hàm khác như: [`exp()`](../glossary/?lan=vi&search=exp), [`log()`](../glossary/?lan=vi&search=log) và [`sqrt()`](../glossary/?lan=vi&search=sqrt). Một số hàm sẽ cho kết quả thú vị nếu bạn sử dụng hằng số PI. Ở dòng 8 tôi có định nghĩa macro sẽ thay thế tất cả những chỗ `PI` xuất hiện bằng hằng số `3.14159265359`. ### Step và Smoothstep GLSL cũng có vài hàm số riêng biệt được tăng tốc bởi phần cứng. Hàm [`step()`](../glossary/?lan=vi&search=step) nhận 2 tham số đầu vào. Tham số đầu tiên là một ngưỡng giới hạn nào đó, còn tham số thứ 2 là giá trị mà ta muốn biết có vượt qua ngưỡng giới hạn kia không. Bất kỳ giá trị nào nhỏ hơn ngưỡng sẽ cho kết quả `0.0` và ngược lại, tất cả các giá trị lớn hơn ngưỡng sẽ cho kết quả `1.0`. Hãy thử thay giá trị ở dòng 20 của đoạn code dưới đây. Một hàm tương tự là [`smoothstep()`](../glossary/?lan=vi&search=smoothstep). Tham số đầu vào là 1 khoảng min-max kèm thêm 1 giá trị. Hàm này sẽ nội suy giá trị đó trong khoảng min-max, các giá trị nằm ngoài khoảng này sẽ trở min hoặc max tuỳ theo nó nằm ở phía nào của khoảng đã cho. Ở ví dụ trước, dòng 12, chú ý rằng ta đã dùng hàm `smoothstep` để vẽ đồ thị trong hàm `plot()`. Nếu muốn đồ thị trồi lên ở một đoạn nào đó thì làm thế nào ? Bằng cách ghép hai hàm [`smoothstep()`](../glossary/?lan=vi&search=smoothstep) lại. Hãy thay dòng code dưới đây vào dòng 20. Trông như ta đã chẻ đôi canvas ra phải không ? ```glsl float y = smoothstep(0.2,0.5,st.x) - smoothstep(0.5,0.8,st.x); ``` ### Sin và Cos Khi bạn muốn dùng Toán để tạo chuyển động, tạo hình hay pha trộn các giá trị, không có gì tốt hơn việc làm quen với sin và cos. Hai hàm lượng giác cơ bản này kết hợp với nhau để tạo nên những vòng tròn đa năng như dao gấp quân đội Thuỵ Sỹ của MacGyver vậy. Việc tìm hiểu cách chúng hoạt động và kết hợp với nhau ra sao rất quan trọng. Về cơ bản, cho một góc bất kỳ (đơn vị radian), hai hàm này sẽ cho kết quả là tọa độ *x* ([cos](../glossary/?lan=vi&search=cos)) và *y* ([sin](../glossary/?lan=vi&search=sin)) của 1 điểm trên đường tròn có bán kính bằng 1. Và chính việc kết quả thu được từ 2 hàm này vừa biến thiên một cách mềm mại lại còn luôn được chuẩn hoá sẵn theo cặp và cả đơn lẻ (trong khoảng -1 tới 1) khiến cho 2 hàm này trở thành các công cụ siêu hữu ích. Mặc dù rất khó để mô tả mối liên hệ giữa các hàm lượng giác với đường tròn, nhưng chuyển động đẹp tuyệt trên đây đã làm rất tốt nhiệm vụ mô tả tóm tắt mối liên hệ này. Hãy nhìn thật kỹ đồ thị hình sine. Chú ý cách mà các giá trị *y* biến thiên rất mượt giữa +1 và -1. Như ta đã thấy ở ví dụ có sử dụng thời gian ở chương trước, bạn có thể sử dụng tính chất tuần hoàn này của hàm [`sin()`](../glossary/?lan=vi&search=sin) để áp dụng cho các thuộc tính. Nếu bạn đang đọc trên trình duyệt, bạn có thể sửa đoạn code phía trên để xem các sóng đồ thị thay đổi như thế nào. (Chú ý: Đừng quên dấu chấm phẩy ở cuối dòng.) Hãy thử các thay đổi sau và xem điều gì xảy ra: * Cộng `u_time` với *x* trước khi gọi hàm `sin`. Bạn sẽ thấy sóng đồ thị sẽ dịch chuyển dọc theo trục hoành. * Nhân *x* với `PI` trước khi gọi hàm `sin`. Bạn sẽ thấy 2 chu kỳ bị **co lại** và lặp lại mỗi 2 đơn vị số nguyên. * Nhân `u_time` với *x* trước khi gọi hàm `sin`. Bạn sẽ thấy **tần số (frequency)** giữa các chu kỳ ngày càng ngắn lại. Chú ý rằng u_time càng lớn thì càng khó nhìn rõ đồ thị do các chu kỳ bị co lại rất nhiều. * Cộng 1.0 vào [`sin(x)`](../glossary/?lan=vi&search=sin). Và bạn sẽ thấy toàn bộ sóng được **nâng lên (displaced)** khiến cho giá trị nằm trong khoảng 0.0 và 2.0. * Nhân [`sin(x)`](../glossary/?lan=vi&search=sin) với 2.0. Và bạn sẽ thấy **biên độ (amplitude)** rộng gấp đôi. * Tính giá trị tuyệt đối ([`abs()`](../glossary/?lan=vi&search=abs)) của hàm `sin(x)`. Trông đồ thị sẽ giống như đường đi của quả bóng nảy trên mặt đất. * Tách riêng phần thập phân bằng hàm [`fract()`](../glossary/?lan=vi&search=fract) từ kết quả của [`sin(x)`](../glossary/?lan=vi&search=sin). * Làm tròn lên bằng hàm [`ceil()`](../glossary/?lan=vi&search=ceil) và làm tròn xuống bằng hàm [`floor()`](../glossary/?lan=vi&search=floor) từ kết quả của [`sin(x)`](../glossary/?lan=vi&search=sin) để có được sóng điện tử của các giá trị 1 và -1. ### Các hàm hữu ích khác Chúng tôi vừa mới giới thiệu cho các bạn 1 vài hàm mới. Giờ là lúc thử nghiệm từng hàm một bằng cách uncomment từng dòng dưới đây một. Hãy làm quen với các hàm này. Tôi biết bạn đang thắc mắc... tại sao ? Google nhanh với từ khoá "generative art" sẽ cho bạn câu trả lời. Hãy nhớ rằng các hàm này là hàng rào của chúng ta. Chúng ta đang dần thuần thục với các chuyển động 1 chiều, chỉ có lên và xuống. Sớm thôi, ta sẽ đụng tới các chiều thứ hai, ba và bốn! ### Các hàm nâng cao [Golan Levin](http://www.flong.com/) có tài liệu mô tả rất chi tiết về các hàm phức tạp khác vô cùng hữu ích. Ứng dụng chúng vào GLSL sẽ là một bước đi thông minh để bắt đầu dựng nên thư viện code của chính bạn. * Các hàm đa thức: [www.flong.com/archive/texts/code/shapers_poly](http://www.flong.com/archive/texts/code/shapers_poly/) * Các hàm luỹ thừa: [www.flong.com/archive/texts/code/shapers_exp](http://www.flong.com/archive/texts/code/shapers_exp/) * Các hàm mô phỏng đường tròn và elip: [www.flong.com/archive/texts/code/shapers_circ](http://www.flong.com/archive/texts/code/shapers_circ/) * Đường cong Bezier và các hàm tương tự: [www.flong.com/archive/texts/code/shapers_bez](http://www.flong.com/archive/texts/code/shapers_bez/) Như một đầu bếp đi thu thập các kỳ hoa dị thảo, nghệ sỹ kỹ thuật số và các lập trình viên đồ hoạ cũng sẽ có niềm yêu thích riêng với các hàm nội suy của riêng họ. [Iñigo Quiles](http://www.iquilezles.org/) có 1 bộ sưu tầm các [hàm](http://www.iquilezles.org/www/articles/functions/functions.htm) rất hữu ích. Sau khi đọc [bài báo này](http://www.iquilezles.org/www/articles/functions/functions.htm) hãy xem cách thực thi các hàm đó trong GLSL. Hãy chú ý tới các tiểu tiết như thêm dấu chấm "." vào sau các số thực và sử dụng cách đặt tên hàm của ngôn ngữ C vào GLSL; ví dụ thay vì `powf()` hãy dùng `pow()`: Để tạo động lực cho bạn, đây là 1 ví dụ hoàn hảo (tạo nên bởi [Danguafer](https://www.shadertoy.com/user/Danguafer)) về việc thuần thục môn võ karate-hàm-số. Ở các chương tiếp theo *(Next >>)* chúng ta sẽ học các chiêu mới. Đầu tiên là trộn màu rồi sau đó là vẽ hình. #### Bài tập Hãy nhìn vào bảng các phương trình dưới đây, được tạo bởi [Kynd](http://www.kynd.info/log/). Hãy xem cách mà anh ấy kết hợp các hàm lại với nhau để kiểm soát các giá trị nằm trong khoảng 0.0 và 1.0. Giờ là lúc bạn tập luyện bằng cách dựng lại các hàm này. Hãy nhớ rằng càng luyện tập chăm chỉ bạn sẽ càng giỏi võ. #### Một vài công cụ cho bạn Đây là một vài công cụ sẽ giúp bạn vẽ đồ thị các hàm 1 cách trực quan nhất. * [GraphToy](http://www.iquilezles.org/apps/graphtoy/): Thêm một sản phẩm nữa của [Iñigo Quilez](http://www.iquilezles.org) để minh hoạ các hàm GLSL trên WebGL. * [LYGIA Shader Library](https://lygia.xyz/) a shader library of reusable functions that can be include easily on your projects. It's very granular, designed for reusability, performance and flexibility. And can be easily be added to any projects and frameworks. --- ### 05/SUMMARY (05/SUMMARY.md) Shaping functions is fundamental technique that is recursively used throughout this book that let you control the variation of the value at will. Study how different functions of x are used to create different shapes and try making your own function. --- ### 06/README (06/README.md) ## Colors We haven't had much of a chance to talk about GLSL vector types. Before going further it's important to learn more about these variables and the subject of colors is a great way to find out more about them. If you are familiar with object oriented programming paradigms you've probably noticed that we have been accessing the data inside the vectors like any regular C-like `struct`. ```glsl vec3 red = vec3(1.0,0.0,0.0); red.x = 1.0; red.y = 0.0; red.z = 0.0; ``` Defining color using an *x*, *y* and *z* notation can be confusing and misleading, right? That's why there are other ways to access this same information, but with different names. The values of `.x`, `.y` and `.z` can also be called `.r`, `.g` and `.b`, and `.s`, `.t` and `.p`. (`.s`, `.t` and `.p` are usually used for spatial coordinates of a texture, which we'll see in a later chapter.) You can also access the data in a vector by using the index position, `[0]`, `[1]` and `[2]`. The following lines show all the ways to access the same data: ```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; ``` These different ways of pointing to the variables inside a vector are just nomenclatures designed to help you write clear code. This flexibility embedded in shading language is a door for you to start thinking interchangeably about color and space coordinates. Another great feature of vector types in GLSL is that the properties can be combined in any order you want, which makes it easy to cast and mix values. This ability is called *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 ``` ### Mixing color Now that you know how colors are defined, it's time to integrate this with our previous knowledge. In GLSL there is a very useful function, [`mix()`](../glossary/?search=mix), that lets you mix two values in percentages. Can you guess what the percentage range is? Yes, values between 0.0 and 1.0! Which is perfect for you, after those long hours practicing your karate moves with the fence - it is time to use them! Check the following code at line 18 and see how we are using the absolute values of a sin wave over time to mix `colorA` and `colorB`. Show off your skills by: * Make an expressive transition between colors. Think of a particular emotion. What color seems most representative of it? How does it appear? How does it fade away? Think of another emotion and the matching color for it. Change the beginning and ending color of the above code to match those emotions. Then animate the transition using shaping functions. Robert Penner developed a series of popular shaping functions for computer animation known as [easing functions](http://easings.net/), you can use [this example](../edit.php#06/easing.frag) as research and inspiration but the best result will come from making your own transitions. ### Playing with gradients The [`mix()`](../glossary/?search=mix) function has more to offer. Instead of a single `float`, we can pass a variable type that matches the two first arguments, in our case a `vec3`. By doing that we gain control over the mixing percentages of each individual color channel, `r`, `g` and `b`. Take a look at the following example. Like the examples in the previous chapter, we are hooking the transition to the normalized *x* coordinate and visualizing it with a line. Right now all the channels go along the same line. Now, uncomment line number 25 and watch what happens. Then try uncommenting lines 26 and 27. Remember that the lines visualize the amount of `colorA` and `colorB` to mix per channel. You probably recognize the three shaping functions we are using on lines 25 to 27. Play with them! It's time for you to explore and show off your skills from the previous chapter and make interesting gradients. Try the following exercises: * Compose a gradient that resembles a William Turner sunset * Animate a transition between a sunrise and sunset using `u_time`. * Can you make a rainbow using what we have learned so far? * Use the `step()` function to create a colorful flag. ### HSB We can't talk about color without speaking about color space. As you probably know there are different ways to organize color besides by red, green and blue channels. [HSB](http://en.wikipedia.org/wiki/HSL_and_HSV) stands for Hue, Saturation and Brightness (or Value) and is a more intuitive and useful organization of colors. Take a moment to read the `rgb2hsv()` and `hsv2rgb()` functions in the following code. By mapping the position on the x axis to the Hue and the position on the y axis to the Brightness, we obtain a nice spectrum of visible colors. This spatial distribution of color can be very handy; it's more intuitive to pick a color with HSB than with RGB. ### HSB in polar coordinates HSB was originally designed to be represented in polar coordinates (based on the angle and radius) instead of cartesian coordinates (based on x and y). To map our HSB function to polar coordinates we need to obtain the angle and distance from the center of the billboard to the pixel coordinate. For that we will use the [`length()`](../glossary/?search=length) function and [`atan(y,x)`](../glossary/?search=atan) (which is the GLSL version of the commonly used `atan2(y,x)`). When using vector and trigonometric functions, `vec2`, `vec3` and `vec4` are treated as vectors even when they represent colors. We will start treating colors and vectors similarly, in fact you will come to find this conceptual flexibility very empowering. **Note:** If you were wondering, there are more geometric functions besides [`length`](../glossary/?search=length) like: [`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) and [`notEqual()`](../glossary/?search=notEqual). Once we obtain the angle and length we need to “normalize” their values to the range between 0.0 to 1.0. On line 27, [`atan(y,x)`](../glossary/?search=atan) will return an angle in radians between -PI and PI (-3.14 to 3.14), so we need to divide this number by `TWO_PI` (defined at the top of the code) to get values between -0.5 to 0.5, which by simple addition we change to the desired range of 0.0 to 1.0. The radius will return a maximum of 0.5 (because we are calculating the distance from the center of the viewport) so we need to double this range (by multiplying by two) to get a maximum of 1.0. As you can see, our game here is all about transforming and mapping ranges to the 0.0 to 1.0 that we like. Try the following exercises: * Modify the polar example to get a spinning color wheel, just like the waiting mouse icon. * Use a shaping function together with the conversion function from HSB to RGB to expand a particular hue value and shrink the rest. * If you look closely at the color wheel used on color pickers (see the image below), they use a different spectrum according to RYB color space. For example, the opposite color of red should be green, but in our example it is cyan. Can you find a way to fix that in order to look exactly like the following image? [Hint: this is a great moment to use shaping functions.] * Read [Josef Albers' book Interaction of Color](http://www.goodreads.com/book/show/111113.Interaction_of_Color) and use the following shaders examples as practice. #### Note about functions and arguments Before jumping to the next chapter let’s stop and rewind. Go back and take look at the functions in previous examples. You will notice `in` before the type of the arguments. This is a [*qualifier*](http://www.shaderific.com/glsl-qualifiers/#inputqualifier) and in this case it specifies that the variable is read only. In future examples we will see that it is also possible to define arguments as `out` or `inout`. This last one, `inout`, is conceptually similar to passing an argument by reference which will give us the possibility to modify a passed variable. ```glsl int newFunction(in vec4 aVec4, // read-only out vec3 aVec3, // write-only inout int aInt); // read-write ``` You may not believe it but now we have all the elements to make cool drawings. In the next chapter we will learn how to combine all our tricks to make geometric forms by *blending* the space. Yep... *blending* the space. #### For your toolbox * [LYGIA's color shader functions ](https://lygia.xyz/color) are set of reusable functions to manipulate colors in GLSL. It includes functions to convert between color spaces, to blend colors, to create gradients, and to apply color transformations. It's very granular library, designed for reusability, performance and flexibility. And it can be easily be added to any projects and frameworks. --- ### 06/Notes (06/notes.md) Add some references and ideas from this IQ article: http://iquilezles.org/www/articles/palettes/palettes.htm ### nicolas * struct exist in GLSL : this is valid ```precision mediump float; struct my_struct { vec4 color; }; uniform my_struct u_colors[2]; void main(void) { gl_FragColor = u_colors[0].color; } ``` [source](https://github.com/KhronosGroup/WebGL/blob/master/sdk/tests/conformance/glsl/misc/shader-with-array-of-structs-uniform.html) [NICO] note: I had previously associated the name *accessor* to 'the way one can access the properties of an object'. we can use those **accessors** independently ; the following code creates a clone *newColor* of the *color* vector by using a different accessor for each property. ```glsl vec4 color = vec4( 1.,0.,0.5,1. ); vec4 newColor = vec4( color[0], color.g, color.z, color.q ); ``` It is possible to combine the properties by **concatenating** different accessors: if we need to use the ```.r```, ```.g``` and ```.b``` values of a 4 dimensions vector but don't need the ```.a``` (alpha) value, we can write: ```glsl vec4 color = vec4( 1.,0.,0.5,1. ); vec4 newColor = vec4( color.rgb, 1.0 ); ``` Which is the same as cloning each property ```.r```, ```.g``` and ```.b``` from ```color``` individually and dropping the last (```.a```). In this case, ```color.rgb``` is interpreted as a vector of type ```vec3``` that contains the values ```.r```, ```.g``` and ```.b``` of the original ```vec4``` vector *color*. The same goes for: ```glsl vec4 color = vec4( 1.,0.,0.5,1. ); vec3 newColor = vec3( color.xy, 1.0 ); ``` We use the values ```.x``` and ```.y``` from *color* to build a vector *newColors* of type ```vec3``` which ```.r``` and ```.g``` values will be the same as the *color* vector and ```.b``` value will be ```1.0```. Last but not least, the order in which you **concatenate** the accessors matters. If you want to build a vector from another vector but want to reverse the order of the properties, here's how you can write it: ```glsl vec3 color = vec3( 1.0, 0.0, 0.5 ); vec3 newColor = color.bgr; ``` the *newColor* vector will copy *color*'s properties but instead of copying them in the "regular" order: ```.r```, ```.g``` and ```.b```, it will copy them in the order defined by the concatenation: ```.b```, ```.g``` and ```.r```. ```glsl color.r => 1.0 color.g => 0.0 color.b => 0.5 and newColor.r => 0.5 newColor.g => 0.0 newColor.b => 1.0 ``` On a side note, you can reuse the same accessor mutiple times and in whatever order in a concatenated accessor: ```glsl color.rrr => vec3( 1.0 ) color.rrg => vec3( 1.0, 1.0, 0.0) color.bgg => vec3( 0.5, 0.0, 0.0) etc. ``` This results in the fact that, if the following is true: ```glsl color.rgba = color.xyzw = color.stpq ``` these statements are not necessarily true: ```glsl color.rgba != color.argb != color.rbga != color.abgr etc. color.xyzw != color.wxyz != color.xzyw != color.wzyx etc. color.stpq != color.qstp != color.sptq != color.qpts etc. ``` This is a powerful feature ; it allows to store the data in compact forms and manipulate them in very flexible ways. Let's see a use case of the *compactness*: say you want to describe a rectangle, you can do so by using 2 ```vec2``` describing respectively the top left corner and the bottom right corner or you can instead, use a single ```vec4``` which ```.xy``` **accessor** will return a ```vec2``` describing the top left corner, and which ```.zw``` **accessor** will return a ```vec2``` describing the bottom right corner. [/NICO] These different ways of pointing to the variables inside a vector are just nomenclatures designed to help you write clear code. This flexibility embedded in shading language is a door for you to start thinking interchangably about color and space coordinates. [NICO] rephrased this: Another great feature of vector types in GLSL is that the properties can be combined in any order you want, which makes it easy to cast and mix values. This ability is called *swizzle*. to: Concatenation or *swizzle* gets really interesting when we need to cast and mix values. The following example show you how to *swizzle* properties between vectors. [/NICO] --- ### 06/README Ch (06/README-ch.md) ## 颜色 我们目前为止还未涉及到GLSL的向量类型。在我们深入向量之前,学习更多关于变量和色彩主题是一个了解向量类型的好方法。 若你熟悉面向对象的编程范式(或者说编程思维模式),你一定注意到我们以一种类C的 ```struct```的方式访问向量数据的内部分量。 ```glsl vec3 red = vec3(1.0,0.0,0.0); red.x = 1.0; red.y = 0.0; red.z = 0.0; ``` 以x,y,z定义颜色是不是有些奇怪?正因如此,我们有其他方法访问这些变量——以不同的名字。```.x```, ```.y```, ```.z```也可以被写作```.r```, ```.g```, ```.b``` 和 ```.s```, ```.t```, ```.p```。(```.s```, ```.t```, ```.p```通常被用做后面章节提到的贴图空间坐标)你也可以通过使用索引位置```[0]```, ```[1]``` 和 ```[2]```来访问向量. 下面的代码展示了所有访问相同数据的方式: ```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; ``` 这些指向向量内部变量的不同方式仅仅是设计用来帮助你写出干净代码的术语。着色语言所包含的灵活性为你互换地思考颜色和坐标位置。 GLSL中向量类型的另一大特点是可以用你需要的任意顺序简单地投射和混合(变量)值。这种能力被(形象地)称为:**鸡尾酒**。 ```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 ``` ### 混合颜色 现在你了解到如何定义颜色,是时候将先前所学的整合一下了!在GLSL中,有个十分有用的函数:[```mix()```](../glossary/?search=mix),这个函数让你以百分比混合两个值。猜下百分比的取值范围?没错,0到1!完美!学了这么久的基本功,是时候来用一用了! 看下下列代码中的第18行,这里展示了我们如果是用随时间变化的sin绝对值来混合 ```colorA``` 和 ```colorB```。 试着来 show 一下你所学到的: * 给颜色赋予一个有趣的过渡。想想某种特定的感情。哪种颜色更具代表性?他如何产生?又如何褪去?再想想另外的一种感情以及对应的颜色。然后改变上诉代码中的代表这种情感的开始颜色和结束颜色。Robert Penner 开发了一些列流行的计算机动画塑形函数,被称为[缓动函数](http://easings.net/)。你可以研究这些[例子](../edit.php#06/easing.frag)并得到启发,但最好你还是自己写一个自己的缓动函数。 ### 玩玩渐变 [```mix()```](../glossary/?search=mix) 函数有更多的用处。我们可以输入两个互相匹配的变量类型而不仅仅是单独的 ```float``` 变量,在我们这个例子中用的是 ```vec3```。这样我们便获得了混合颜色单独通道 ```.r```,```.g``` 和 ```.b```的能力。 试试下面的例子。正如前面一个例子,我们用一条线来可视化根据单位化x坐标的过渡。现在所有通道都按照同样的线性变换过渡。 现在试试取消25行的注释,看看会发生什么。然后再试试取消26行和27行。记住直线代表了```colorA``` 和 ```colorB```每个通道的混合比例。 你可能认出了我们用在25行到27行的造型函数。试着改写他们!是时候把前几张的内容结合起来探索一些新的渐变。试试下列挑战: * 创作一个渐变来代表 William Turner的落日。 * 用 ```u_time``` 做个一日出和日落的动画。 * 能用我们所学的做一道彩虹吗? * 用 ```step()``` 函数在做一个五彩的旗子。 ### HSB 我们不能脱离色彩空间来谈论颜色。正如你所知,除了rgb值,有其他不同的方法去描述定义颜色。 [HSB](http://en.wikipedia.org/wiki/HSL_and_HSV) 代表色相,饱和度和亮度(或称为值)。这更符合直觉也更有利于组织颜色。稍微花些时间阅读下面的 ```rgb2hsv()``` 和 ```hsv2rgb()``` 函数。 将x坐标(位置)映射到Hue值并将y坐标映射到明度,我们就得到了五彩的可见光光谱。这样的色彩空间分布实现起来非常方便,比起RGB,用HSB来拾取颜色更直观。 ### 极坐标下的HSB HSB原本是在极坐标下产生的(以半径和角度定义)而并非在笛卡尔坐标系(基于xy定义)下。将HSB映射到极坐标我们需要取得角度和到像素屏中点的距离。由此我们运用 [```length()```](../glossary/?search=length) 函数和 [```atan(y,x)```](../glossary/?search=atan) 函数(在GLSL中通常用atan(y,x))。 当用到矢量和三角学函数时,```vec2```, ```vec3``` 和 ```vec4```被当做向量对待,即使有时候他们代表颜色。我们开始把颜色和向量同等的对待,事实上你会慢慢发现这种理念的灵活性有着相当强大的用途。 **注意**:如果你想了解,除length()以外的诸多几何函数,例如:[```distance()```](../glossary/?search=distance), [```dot()```](../glossary/?search=dot), [```cross```](../glossary/?search=cross), [```normalize()```](../glossary/?search=normalize), [```faceforward()```](../glossary/?search=faceforward), [```reflect()```](../glossary/?search=reflect) 和 [```refract()```](../glossary/?search=refract)。 GLSL也有与向量相关的函数:[```lessThan()```](../glossary/?search=lessThan), [```lessThanEqual()```](../glossary/?search=lessThanEqual), [```greaterThan()```](../glossary/?search=greaterThan), [```greaterThanEqual()```](../glossary/?search=greaterThanEqual), [```equal()```](../glossary/?search=equal) and [```notEqual()```](../glossary/?search=notEqual)。 一旦我们得到角度和长度,我们需要单位化这些值:0.0到1.0。在27行,[```atan(y,x)```](../glossary/?search=atan) 会返回一个介于-PI到PI的弧度值(-3.14 to 3.14),所以我们要将这个返回值除以 ```TWO_PI```(在code顶部定义了)来得到一个-0.5到0.5的值。这样一来,用简单的加法就可以把这个返回值最终映射到0.0到1.0。半径会返回一个最大值0.5(因为我们计算的是到视口中心的距离,而视口中心的范围已经被映射到0.0到1.0),所以我们需要把这个值乘以二来得到一个0到1.0的映射。 正如你所见,这里我们的游戏都是关于变换和映射到一个0到1这样我们乐于处理的值。 来挑战下下面的练习吧: * 把极坐标映射的例子改成选择色轮,就像“正忙”的鼠标图标。 * 把造型函数整合进来,来让HSB和RGB的转换中强调某些特定值并且弱化其他的。 * 如果你仔细观察用来拾色的色轮(见下图),你会发现它用一种根据RYB色彩空间的色谱。例如,红色的对面应该是绿色,但在我们的例子里是青色。你能找到一种修复的方式来让它看起来和下图一样么?[提示:这是用塑形函数的好机会!] #### 注意函数和变量 在进入下一章之前让我们停下脚步回顾下。复习下之前例子的函数。你会注意到变量类型之前有个限定符 ```in```,在这个 [*qualifier*](http://www.shaderific.com/glsl-qualifiers/#inputqualifier) (限定符)例子中它特指这个变量是只读的。在之后的例子中我们会看到可以定义一个 ```out``` 或者 ```inout```变量。最后这个 ```inout```,再概念上类似于参照输入一个变量,这意味着我们有可能修改一个传入的变量。 ```glsl int newFunction(in vec4 aVec4, // read-only out vec3 aVec3, // write-only inout int aInt); // read-write ``` 或许你还不相信我们可以用所有这些元素来画一些炫酷的东西。下一章我们会学习如何结合所有这些技巧通过融合 (*blending*) 空间来创造几何形状。没错。。。融合(*blending*) 空间。 --- ### 06/README De (06/README-de.md) ## Farben Wir hatten bislang noch wenig Gelegenheit, um über die Vektortypen von GLSL zu sprechen. Bevor es mit anderen Inhalten weitergeht, ist es wichtig, mehr über diese Variablentypen zu erfahren. Das Thema „Farben“ bietet sich dafür an. Falls Du mit den Konzepten der objektorientierten Programmierung vertraut bist, ist Dir vielleicht schon aufgefallen, dass wir die verschiedenen Elemente innerhalb eines Vektors wie eine gewöhnliche ```struct``` in C ansprechen. ```glsl vec3 red = vec3(1.0,0.0,0.0); red.x = 1.0; red.y = 0.0; red.z = 0.0; ``` Die Festlegung von Farben über die Komponenten *x*, *y* und *z* wirkt auf den ersten Blick etwas merkwürdig, nicht wahr? Aus diesem Grund gibt es weitere Möglichkeiten, um auf diese Elemente zuzugreifen. Die Inhalte von ```.x```, ```.y``` und ```.z``` können auch als ```.r```, ```.g``` und ```.b```, sowie als ```.s```, ```.t``` und ```.p``` angesprochen werden (```.s```, ```.t``` und ```.p``` werden typischerweise für die Raumkoordinaten von Texturen genutzt, wie wir in späteren Kapiteln noch sehen werden). Darüber hinaus lassen sich die Elemente eines Vektors auch über ihre Index-Position als ```[0]```, ```[1]``` und ```[2]``` ansprechen. Die folgenden Programmzeilen zeigen die unterschiedlichen Ansätze, um jeweils auf die gleichen Vektorinhalte zuzugreifen: ```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; ``` Tatsächlich handelt es sich bei den unterschiedlichen Namen nur um verschiedene Bezeichner für jeweils ein und dieselbe Sache. Die Namen sollen Dir helfen, verständlichen Code zu schreiben, je nachdem, wofür ein Vektor gerade zum Einsatz kommt (Farben, Koordinaten, Raumpunkte etc.) Ein weiteres praktisches Merkmal der Vektortypen in GLSL ist die Möglichkeit, ihre Eigenschaften in beliebiger Weise zu kombinieren. Das macht es besonders einfach, Werte zu tauschen und in andere Datentypen zu konvertieren. Diese Fähigkeit wird im Englischen als *swizzle* bezeichnet, was so viel wie „umrühren“ oder „mischen“ bedeutet. ```glsl vec3 yellow, magenta, green; // Zusammenruehren von Gelb yellow.rg = vec2(1.0); // Zuweisung von 1. an den Rot- und den Gruen-Kanal von yellow yellow[2] = 0.0; // Zuweisung von 0. an den Blau-Kanal von yellow // Zusammenruehren von Magenta magenta = yellow.rbg; // Zuweisung von yellow an magenta bei gleichzeitigem Tausch der Kanaele fuer Blau und Gruen // Zusammenruehren von Gruen green.rgb = yellow.bgb; // Zuweisung des Blau-Kanals von yellow an den Rot- und Blau-Kanal von green ``` ### Mischen von Farben Jetzt, wo Du weißt, wie man Farben definiert, wird es Zeit, dies mit unserem bisher gesammelten Wissen zu verknüpfen. In GLSL gibt es eine äußerst praktische Funktion mit dem Namen [```mix()```](../glossary/?search=mix), über die man zwei Werte in Form von Prozentangaben mischen kann. Vielleicht kannst Du Dir bereits denken, wie diese Prozentangaben auszusehen haben? Genau, als Werte zwischen ```0.0``` und ```1.0```! Das passt doch perfekt, nachdem Du schon so viel Zahlen-Karate am Zaun geübt hast. Es ist an der Zeit, Dein Wissen umzusetzen. Lenke Dein Augenmerk im folgenden Programm besonders auf die *Zeile 18*. Schau Dir genau an, wie hier die absoluten Werte aus einer *Sinusfunktion* genutzt werden, um zeitabhängig und mit unterschiedlichen Verhältnissen die Farben aus den Variablen ```colorA``` und ```colorB``` zu mischen. Jetzt zeige Deine Fähigkeiten, indem Du: * Einen ausdrucksstarken Übergang zwischen den Farben konstruierst. Denke an ein bestimmtes Gefühl, eine impulsive menschliche Regung. Welche Farbe vermag dieses Gefühl wohl am besten auszudrücken? Und wie soll sich diese Farbe entwickeln, um anschließend wieder zu verschwinden? Animiere den Übergang mit Hilfe formgebender Funktionen. Robert Penner hat eine Reihe populärer Übergangsfunktionen für Computeranimationen entwickelt, die als [easing functions](http://easings.net/) bekannt sind. Du kannst für Deine Nachforschungen und als Inspiration auf [dieses Beispiel](../edit.php#06/easing.frag) zurückgreifen. Aber die besten Ergebnisse erzielst Du natürlich, wenn Du Deine ganz eigenen Übergänge kreierst. ### Das Spiel mit Farbverläufen Die [```mix()```](../glossary/?search=mix)-Funktion hat noch mehr zu bieten. Anstelle eines einzelnen Werts vom Typ ```float```, können wir auch einen Datentyp übergeben, der zu den ersten beiden Argumenten passt. In unserem Fall ist das ein ```vec3```. Dadurch gewinnen wir die Kontrolle über das Mischen in allen drei Farbkanälen *Rot*, *Grün* und *Blau* (```r```, ```g``` und ```b```). Wirf nun einen Blick auf das folgende Beispiel. Wie schon bei den Beispielen im letzten Kapitel verbinden wir den Übergang auch hier mit dem normalisierten Wert der *X-Ordinate* und visualisieren ihn als eine Linie. Im ersten Schritt folgen die Übergänge in allen drei Farbkanälen derselben Linie. Lösche jetzt die Kommentarzeichen aus der *Programmzeile 25*, damit diese ebenfalls ausgeführt wird. Dann schau, was daraufhin geschieht. Entferne anschließend auch die Kommentarzeichen vor den *Zeilen 26 und 27*. Achte darauf, dass diese drei Zeilen jeweils das Mischverhältnis für die *Rot-*, *Grün*, und *Blau-Kanäle* zwischen den Farben aus den Variablen ```colorA``` und ```colorB``` festlegen. Vielleicht erkennst Du die drei formgebenden Funktionen in den *Zeilen 25 bis 27* wieder. Experimentiere mit ihnen. Es ist an der Zeit, dass Du die erlernten Fähigkeiten aus dem letzten Kapitel nutzt, um interessante Farbverläufe zu produzieren. Probiere die folgenden Übungen aus: * Erzeuge einen Farbverlauf, der an den Sonnenuntergang bei William Turner erinnert. * Animiere einen Übergang zwischen Sonnenaufgang und Sonnenuntergang mit Hilfe von ```u_time```. * Kannst Du mit Hilfe des bislang Erlernten einen Regenbogen entstehen lassen? * Nutze die ```step()```-Funktion, um eine farbenfrohe Flagge zu erzeugen. ### HSB Beim Thema „Farben“ kommen wir nicht an dem Konzept der „Farbräume“ vorbei. Wie Du vielleicht weißt, gibt es unterschiedliche Möglichkeiten, Farben zu beschreiben, jenseits ihrer Auftrennung in *Rot-*, *Grün-* und *Blau-Anteile* (sprich: Kanäle). [HSB](https://de.wikipedia.org/wiki/HSV-Farbraum) steht für *Hue* (dt. Farbwert), *Saturation* (dt. Farbsättigung) und *Brightness* (dt. absolute Helligkeit). Dieses Farbsystem ist intuitiver und in vielen Fällen auch praktischer, wenn es um die Festlegung von Farben geht. Nimm Dir einen Moment Zeit, um die Konvertierungsfunktionen ```rgb2hsv()``` und ```hsv2rgb()``` im folgenden Programmcode zu studieren. Indem wir die Position auf der *X-Achse* auf den Farbwert und die Position auf der *Y-Achse* auf die Helligkeit abbilden, erhalten wir ein hübsches Spektralbild. Diese räumliche Verteilung der Farben kann sehr praktisch sei, wenn es um die Auswahl einer Farbe für einen bestimmten Zweck geht. ### HSB in Polarkoordinaten Das *HSB-Farbmodell* wurde ursprünglich entwickelt, um Farben in Polarkoordinaten (bestehend aus einem *Winkel* und einem *Radius*) auszudrücken und nicht als kartesische Koordinaten (bestehend aus einer *X-* und einer *Y-Ordinate*). Um unsere ```HSB```-Funktion mit Polarkoordinaten arbeiten zu lassen, müssen wir den Winkel und die Entfernung des jeweiligen Bildpunktes von der Mitte der Zeichenfläche berechnen. Dafür nutzen wir die [```length()```](../glossary/?search=length)-Funktion, sowie die Funktion [```atan(y,x)```](../glossary/?search=atan) (das ist die GLSL-Variante der in vielen Programmiersprachen verfügbaren Funktion ```atan2(y,x)``` zur Berechnung des Arkustangens). Bei der Nutzung von Vektor- und Trigonometrie-Funktionen werden Variablen der Datentypen ```vec2```, ```vec3``` und ```vec4``` wie Vektoren behandelt, auch wenn sie tatsächlich Farben verkörpern. Wir beginnen hier also, Farben und Vektoren gleichermaßen zu bearbeiten - eine Flexibilität, die sich noch als äußerst praktisch und weitreichend erweisen wird. **Hinweis:** Nur, falls Du Dich fragst: Abgesehen von [```length```](../glossary/?search=length) gibt es noch viele weitere geometrische Funktionen. Dazu gehören beisielsweise: [```distance()```](../glossary/?search=distance), [```dot()```](../glossary/?search=dot), [```cross```](../glossary/?search=cross), [```normalize()```](../glossary/?search=normalize), [```faceforward()```](../glossary/?search=faceforward), [```reflect()```](../glossary/?search=reflect) und [```refract()```](../glossary/?search=refract). Außerdem bietet GLSL vergleichende Funktionen für Vektoren wie [```lessThan()```](../glossary/?search=lessThan), [```lessThanEqual()```](../glossary/?search=lessThanEqual), [```greaterThan()```](../glossary/?search=greaterThan), [```greaterThanEqual()```](../glossary/?search=greaterThanEqual), [```equal()```](../glossary/?search=equal) und [```notEqual()```](../glossary/?search=notEqual). Nachdem wir den Winkel und die Entfernung (Länge) berechnet haben, müssen wir diese Werte normalisieren, indem wir sie auf den Wertebereich zwischen ```0.0``` und ```1.0``` abbilden. In der *Programmzeile 27* liefert der Aufruf von [```atan(y,x)```](../glossary/?search=atan) den Winkel als Bogenmaß zwischen *-PI* und *PI* (```-3.14``` bis ```3.14```) zurück. Deshalb müssen wir dieses Ergebnis durch ```TWO_PI``` (Zweimal *PI*, als Konstante oben im Programm definiert) teilen. Wir erhalten dadurch Werte zwischen ```-0.5``` und ```0.5```, die wir durch einfache Addition von ```0.5``` auf den benötigten Wertebereich zwischen ```0.0``` und ```1.0``` abbilden. Allerdings werden wir hier als Ergebnis immer maximal ```0.5``` erhalten, weil wir ja die Entfernung von der Mitte der Zeichenfläche berechnen. Deshalb müssen wir dieses Ergebnis noch mit ```2``` multiplizieren, damit wir maximal auf den Wert von ```1.0``` kommen. Wie Du siehst, dreht sich also auch hier das ganze Spiel darum, Werte zwischen ```0.0``` und ```1.0``` zu erzielen, mit denen wir so gerne arbeiten. Probiere die folgenden Übungen aus: * Verändere das obige Programmbeispiel so, dass sich das Farbrad dreht, wie der Mauszeiger bei einer länger währenden Operation. * Nutze eine formgebende Funktion in Verbindung mit der Konvertierungsfunktion von *HSB* nach *RGB*, um einen bestimmten Farbwert in den Vordergrund zu rücken und die anderen Farben „klein“ zu halten. * Wenn Du Dir das Farbrad auf Farbauswahlfeldern (wie in der folgenden Abbildung) genau anschaust, erkennst Du, dass diese einen *RYB-Farbraum* repräsentieren. Die gegenüberliegende Farbe von Rot sollte z.B. Grün sein, doch in unserem obigen Beispielprogramm erscheint dort Zyan. Gelingt es Dir, einen Weg zu finden, damit unser Beispielprogramm das gleiche Farbbild liefert, wie auf der Abbildung unten? (Ein Tipp: Das ist der perfekte Moment, um eine passende formgebende Funktion zum Einsatz zu bringen.) * Lies [Josef Albers Buch: „Interaction of Color“](http://www.goodreads.com/book/show/111113.Interaction_of_Color) und klicke die folgenden Shader an, um aus deren Programmcode zu lernen. #### Ein Hinweis zu Funktionen und ihren Argumenten Bevor wir zum nächsten Kapitel springen, lass und kurz innehalten und einen Schritt zurückgehen. Schau Dir noch einmal die Funktionen aus den letzten Beispielprogrammen an. Vielleicht fällt Dir das Schüsselwort ```in``` im Kopf einer Funktion vor dem jeweiligen Argument auf. Es handelt sich dabei um einen sogenannten [*qualifier*](http://www.shaderific.com/glsl-qualifiers/#inputqualifier), der in diesem Fall festlegt, dass der jeweilige Parameter von der Funktion nur ausgelesen und nicht überschrieben werden kann. In kommenden Programmbeispielen werden wir sehen, dass Parameter auch als ```out``` oder ```inout``` gekennzeichnet werden können. ```inout``` entspricht dabei der Übergabe eines Arguments „by reference“, so dass Änderungen an diesem Parameter auch an den Aufrufer und in die von ihm eingesetzte Variable zurückfließen. ```glsl int newFunction(in vec4 aVec4, // nur auslesbar out vec3 aVec3, // nicht initalisiert, nur beschreibbar inout int aInt); // lesen und schreiben, Aenderungen fliessen zum Aufrufer zurueck ``` Du hast vielleicht nicht damit gerechnet, aber jetzt haben wir bereits alle Elemente beisammen, um aufregende Grafiken zu erstellen. Im nächsten Kapitel werden wir lernen, wie man alle unsere kleinen Tricks nutzen kann, um den Raum richtig in Wallung zu bringen. Ja, du hast richtig gehört. Genau darum geht's. --- ### 06/README Es (06/README-es.md) ## Colores No hemos tenido oportunidad todavía de hablar sobre los tipos de vectores en GLSL. Antes de ir más lejos, es importante entender cómo funcionan estas variables, hablar de colores es una buena forma de entenderlos. Si te encuentras familiarizado con la programación orientada a objetos, probablemente te habrás dado cuenta que estamos accediendo a los valores de los vectores, como si fuese un ```struct``` de C. ```glsl vec3 red = vec3(1.0,0.0,0.0); red.x = 1.0; red.y = 0.0; red.z = 0.0; ``` Definir los colores usando *x*, *y* y *z* puede ser muy confuso y engañoso. Es por eso que hay otras formas de acceder a esos valores, con nombres diferentes. Los valores de ```.x```, ```.y``` y ```.z```, se pueden llamar también ```.r```, ```.g``` y ```.b```, o también ```.s```, ```.t``` y ```.p``` (```.s```, ```.t``` y ```.p``` son usados para coordenadas espaciales de texturas, lo veremos en otro capítulo). También podemos acceder a un valor de los vectores, usando índices de posición,```[0]```, ```[1]``` y ```[2]```. En las siguientes lineas puedes ver todas las formas de acceder al mismo valor. ```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; ``` Las diferentes formas de acceder a las variables son sólo nomenclaturas diseñadas para que el código sea más claro. Esta flexibilidad de los shaders, es una puerta de entrada para poder relacionar el color con las coordenadas en el espacio. Otra estupenda funcionalidad de los vectores en GLSL, es que las propiedades se pueden combinar en el orden que quieras, lo que hace muy sencillo manipular y mezclar valores. Esta habilidad es conocida como *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 ``` ### Mezclando color Ahora que sabes como se definen los colores, es hora de integrar esto con lo que aprendimos previamente. En GLSL hay una función muy útil, [```mix()```](../glossary/?search=mix), que te permite mezclar dos valores en porcentaje. ¿Puedes adivinar cuál es el rango de porcentaje? ¡Si, valores de 0.0 a 1.0! Lo cual es perfecto para ti, porque luego de esas largas horas practicando tus movimientos de karate en la cerca. ¡Ahora es el momento de usar esos conocimientos! Echa un vistazo al siguiente código en la línea 18 y observa cómo estamos usando los valores absolutos de una onda sinusoidal para mezclar ```colorA``` y ```colorB```. Demuestra tus habilidades: * Crea una transición expresiva entre dos colores. Piensa en una emoción en particular. ¿Qué color es el más representativo de esa emoción? ¿Cómo aparece? ¿Cómo se desvanece? Piensa en otra emoción y el color que la represente. Cambia los colores del código de arriba por los de tus emociones. Luego anima las transiciones utilizando las funciones de forma. Robert Penner desarrolló una serie de funciones de forma populares, conocidas como [easing functions](http://easings.net/), puedes usar [este ejemplo](../edit.php#06/easing.frag) como investigación o inspiración, pero los mejores resultados saldrán cuando crees tus propias transiciones. ### Jugando con gradientes La función [```mix()```](../glossary/?search=mix) tiene mucho para ofrecer. En vez de usar un sólo ```float```, podemos pasarle variables en los dos primeros argumentos, en nuestro caso un ```vec3```. Haciendo esto podemos controlar los porcentajes de cada canal de color, ```r```, ```g``` y ```b```. Mira el siguiente ejemplo, como en los del capítulo anterior, estamos conectando la transición normalizada de la coordenada *x* y visualizándola con una línea. Ahora todos los canales van por la misma línea. Ahora descomenta la línea 25 y mira lo que sucede. Luego descomenta las líneas 26 y 27. Recuerda que con las líneas visualizamos la cantidad de ```colorA``` y ```colorB``` a mezclar por cada canal. Probablemente reconoces las tres funciones de forma que usamos en las líneas 25 y 27. ¡Juega con ellas! Es hora de mezclar y explorar lo aprendido en el capítulo previo para crear gradientes interesantes. Prueba hacer los próximos ejercicios: * Crea un gradiente que se parezca a un atardecer de William Turner. * Crea una transición entre el atardecer y el amanecer usando ```u_time```. * ¿Puedes crear un arcoíris con lo que hemos aprendido hasta ahora? * Usa la función ```step()``` para crear una bandera colorida. ### HSB No podemos hablar de color sin mencionar el espacio de color. Probablemente sabes que hay diferentes formas de organizar un color más allá de usar los canales de rojo, verde y azul. [HSB](http://en.wikipedia.org/wiki/HSL_and_HSV) significa Hue (tono), Saturation (saturación) y Brightness (brillo o valor), es una forma útil y más intuitiva de organizar el color. Tomate un momento para leer las funciones ```rgb2hsv()``` y ```hsv2rgb()``` del código siguiente. Conectando la posición del eje x al tono y la posición del eje y al brillo podemos obtener este bonito espectro del color visible. La distribución espacial del color puede sernos muy útil; es más intuitivo seleccionar un color usando HSB que con RGB. ### HSB en coordenadas polares HSB fue originalmente diseñado para ser representado en coordenadas polares (basadas en el ángulo y el radio) en vez de coordenadas cartesianas (basadas en x e y). Para asociar nuestra función HSB a coordenadas polares necesitamos obtener el ángulo y la distancia del centro de la ventana. Para hacer eso usaremos la función [```length()```](../glossary/?search=length) y [```atan(y,x)```](../glossary/?search=atan) (que es la versión en GLSL del comunmente usado ```atan2(y,x)```). Cuando usamos vectores y funciones trigonométricas, ```vec2```, ```vec3``` y ```vec4``` son tratados como vectores, incluso cuando representan colores. Comenzaremos a tratar a los colores y a los vectores de una manera similar, de hecho te darás cuenta que es un concepto muy poderoso y flexible. **Nota:** Si te preguntabas si había más funciones geométricas además de [```length```](../glossary/?search=length): [```distance()```](../glossary/?search=distance), [```dot()```](../glossary/?search=dot), [```cross```](../glossary/?search=cross), [```normalize()```](../glossary/?search=normalize), [```faceforward()```](../glossary/?search=faceforward), [```reflect()```](../glossary/?search=reflect) y [```refract()```](../glossary/?search=refract). También GLSL tiene funciones relacionadas a los vectores como: [```lessThan()```](../glossary/?search=lessThan), [```lessThanEqual()```](../glossary/?search=lessThanEqual), [```greaterThan()```](../glossary/?search=greaterThan), [```greaterThanEqual()```](../glossary/?search=greaterThanEqual), [```equal()```](../glossary/?search=equal) y [```notEqual()```](../glossary/?search=notEqual). Una vez que obtenemos el ángulo y la longitud, necesitamos "normalizar" sus valores al rango de 0.0 a 1.0. En la línea 27, [```atan(y,x)```](../glossary/?search=atan) devolverá el angulo en radianes entre -PI y PI (-3.14 a 3.14), por lo que necesitamos dividir este número por ```TWO_PI``` (declarado arriba en nuestro código) para obtener valores de -0.5 a 0.5, que con una simple suma podemos transformar al rango deseado de 0.0 a 1.0. El radio devolverá un máximo de 0.5 (porque estamos calculando la distancia desde el centro del viewport) por lo tanto necesitamos duplicar este rango (multiplicándolo por dos) para obtener un máximo de 1.0. Como podrás notar, todo se trata de transformar y manipular rangos de 0.0 a 1.0. Intenta resolver los próximos ejercicios: * Modifica el ejemplo polar, para obtener una rueda que gire, como el ícono de cargando. * Usa una función de forma junto con la conversión de HSB a RGB para expandir un color en particular y encoger el resto. * Si miras detenidamente el círculo cromático usado en los goteros de color (ver la imagen de abajo), usan un espectro diferente, se trata del RYB. Por ejemplo, el opuesto del color rojo, debería ser el verde, pero en nuestro ejemplo es el cyan. ¿Podrías encontrar la forma de igualarlo para que luzca igual a la siguiente imagen? [Pista: este es un buen momento para usar funciones de forma.] #### Nota acerca de las funciones y los argumentos Antes de saltar al próximo capítulo, detengámosnos y retrocedamos. Volvamos a ver las funciones en los ejemplos previos. Notaras el ```in``` antes del tipo de argumento. Este es un [*qualifier*](http://www.shaderific.com/glsl-qualifiers/#inputqualifier) y en este caso indica que la variable es de solo lectura. En ejemplos futuros veremos que es posible definir argumentos como ```out``` o ```inout```. Este último, ```inout```, es conceptualmente similar a pasar un argumento por referencia, lo que nos da la posibilidad de modificar la variable pasada. ```glsl int newFunction(in vec4 aVec4, // read-only out vec3 aVec3, // write-only inout int aInt); // read-write ``` Seguramente no me crees, pero ya tenemos todos los elementos necesarios para crear dibujos geniales. En el próximo capítulo aprenderemos a combinar todos nuestros trucos para crear formas geométricas *mezclando* el espacio. Si... *mezclando* el espacio. --- ### 06/README Fa (06/README-fa.md) ## رنگ ها خیلی زمان زیادی برای صحبت در مورد بردار های GLSL نداریم، اما قبل از ادامه دادن، یادگیری آنان مهم است و رنگ ها راهی خوب برای فهمیدن و کسب اطلاعات بیشتر در مورد آنان است. آگر با برنامه نویسی شی گرا آشنا هستید مشاهده کردید که ما مانند ساختار های استراکت زبان C به مقادیر داخل بردار ها دسترسی داریم. ```glsl vec3 red = vec3(1.0,0.0,0.0); red.x = 1.0; red.y = 0.0; red.z = 0.0; ``` تعریف مقادیر رنگ با x, y, z میتواند گمراه کننده باشد، برای همین روش های دیگری برای دسترسی به این مقادیر وجود دارند، مقادیر x ,y ,z را میتوان با r ,g ,b هم صدا زد. و حتی s, t, p (معمولا برای مختصات فضای یک تکستچر ازین نام ها استفاده میشود، در فصل بعدی خواهید دید). حتی با مکان مقدار مورد نظرتان هم میتوان از آنان استفاده کرد مثلا [1] , [2], [3]. مقدار های داخل هر خط در مثال زیر با هم برابر هستند: ```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; ``` این روش های مختلف برای دسترسی به داده ها، برای کمک به شما در نوشتن کد های واضح تر است. این منعطف بودن زبان شیدر ها دریچه ای برای شماست که در مورد مختصات رنگ و فضا تفکر کنید. از دیگر ویژگی های GLSL این است که میتوان، این مقادیر را به هر ترتیبی استفاده کرد. این ویژگی باعث میشود، مقادیر به راحتی ترکیب شوند.اسم این قابلیت 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 ``` ### ترکیب رنگ ها اکنون که میدانید رنگ ها چگونه تعریف میشوند، وقت آن است، از دانش های قبلیمان استفاده کنیم. در GLSL فانکشن مفیدی به نام [mix()](../glossary/?search=mix) وجود دارد، که به شما این امکان را میدهد دو مقدار را با درصد خاصی با هم مخلوط کنید. آیا میتوانید حدس بزنید دامنه مقدار چقدر است؟ بله بین 0.0 تا 1.0 . بعد از تمرین های گذشته که آن ها هم با اعداد بین 0 تا 1 مرتبط بودند. وقت آن است دوباره از آنان استفاده کنید. به خط 18 نگاه بیاندازید که چگونه، از قدر مطلق مقادیر سینوس برا ترکیب رنگ A و B استفاده شده است. مهارت های خود را توسط نکته زیر به نمایش بگزارید: * ِیک طیف رنگی ایجاد کنید. به یک احساس خاص فکر کنید. چه رنگی به ذهنتان میآید؟ چگونه محو و ظاهر میشود؟ به احساسی دیگر و رنگ متناسب با آن فکر کنید. ابتدا و انتهای کد بالا را تغییر دهید تا با آن احساس مطابقت داشته باشد، سپس این طیف را با استفاده از توابع دیگر متحرک کنید. رابرت پنر مجموعه توابع شکل دهی معروفی را برای انیمیشن و متحرک سازی ایجاد کرده است، که به عنوان توابع ease شناخته میشوند [easing functions](http://easings.net/), میتوانید از [این مثال](../edit.php#06/easing.frag) برای آموزش و الهام استفاده کنید، اما قطعا بهترین نتیجه، نتیجه کار خودتان است. ### بازی با گرادیان ها فانکشن [`mix()`](../glossary/?search=mix) قابلیت های بیشتری دارد. به جای یک عدد شناور، میتوان یک متغیر که مطابق دو آرگومان اول باشد را ، به آن منتقل کنیم, در مثال ما یک vector 3 هست. با این کار قابلیت کنترل هر یک از کانال های r, g و b را داریم. به مثال زیر نگاه بیاندازید. مانند مثال های فصل قبل، ما مختصات x را به صورت نرمالایز شده استفاده و آن را با یک خط نشان میدهیم. در حال حاضر تمام کانال ها از آن خط عبور میکنند. حال خط 25 را از حالت کامنت خارج کنید و تغییرات را مشاهده کنید، برای خط های 26 و 27 هم نیز همین کار را انجام دهید. یادتان باشد مقدار خط، نشان دهنده ترکیب رنگ های A,B بر حسب هر کانال است. احتمالا سه تابع شکل دهی را در خطوط 25 تا 27 تشخیص داده اید. با آنها بازی کنید. وقت آن است که مهارت های فصل قبل را کاوش کرده و به نمایش بگذارید، سعی کنید شیب های گوناگون و جالب تری ایجاد کنید. تمرینات زیر را امتحان کنید: * گرادیانی شبیه غروب خورشید ویلیام ترنر بسازید. * با استفاده از `u_time` انتقال بین طلوع و غروب را متحرک کنید. * آیا با استفاده از آنچه تا کنون یاد گرفته اید، میتوانید رنگین کمان بسازید؟ * از تابع `step()` برای ساخت پرچم های رنگا رنگ استفاده کنید. ### HSB برای آشنایی بیشتر با رنگ ها، با فضای رنگ ها باید آشنا شویم. همانطور که میدانید علاوه بر کانال های R, G, B روش های دیگری برای سازماندهی رنگ وجود دارد. [HSB](http://en.wikipedia.org/wiki/HSL_and_HSV) مخفف رنگ، اشباع، و روشنایی است، که یک سازماندهی مفید تر برای رنگ هاست. به توابع rgb2hsv() و hsv2rgb() در کد زیر دقت کنید. با نگاشت موقعیت x با مقدار Hue(رنگ) و مقدار y به روشنایی، طیف خوبی از رنگ ها قابل مشاهده اند. این نوع توزیع فضایی رنگ میتواند بسیار مفید باشد. انتخاب رنگ با HSB نسبت به RGB ملموس تر است. ### HSB در مختصات قطبی HSB در ابتدا برای مختصاب قطبی(بر اساس زاویه و شعاع) به جای مختصات دکارتی طراحی شده است. برای ترسیم عملکرد HSB در مختصات قطبی، نیاز به فاصله و زاویه از مرکز بیلبورد تا مختصات پیکسل مورد نظر داریم. برای این منظور نیاز به استفاده از تابع [`length()`](../glossary/?search=length) و تابع [`atan(y,x)`](../glossary/?search=atan) داریم. هنگام استفاده از بردار ها مثل vect2, 3, 4 حتی اگر نمایانگر رنگ باشند، باز هم به عنوان بردار با آنان رفتار میشود. ما در مورد رنگ ها و بردار ها به طور مشابه رفتار میکنیم، شما خواهید دید این انعطاف پذیری مفهمومی بسیار مفید است. ** نکته:** توابع هندسی بیشتری علاوه بر [`length`](../glossary/?search=length) وجود دارند مانند: [`distance()`](../glossary/?search=distance), [`dot()`](../glossary/?search=dot), [`cross`](../glossary/?search=cross), [`normalize()`](../glossary/?search=normalize), [`faceforward()`](../glossary/?search=faceforward), [`reflect()`](../glossary/?search=reflect) و [`refract()`](../glossary/?search=refract). همچنین GLSL دارای توابع مخصوص برداری هستند مانند:: [`lessThan()`](../glossary/?search=lessThan), [`lessThanEqual()`](../glossary/?search=lessThanEqual), [`greaterThan()`](../glossary/?search=greaterThan), [`greaterThanEqual()`](../glossary/?search=greaterThanEqual), [`equal()`](../glossary/?search=equal) و [`notEqual()`](../glossary/?search=notEqual). وقتی مقدار طول و زاویه را بدست آوردیم باید آن هارا بین 0.0 و 1.0 نرمالایز کنیم. در خط 27, [`atan(y,x)`](../glossary/?search=atan) زاویه ای بین PI و _PI (-3.14 تا 3.14) برمیگرداند, پس باید آنان را بر `TWO_PI` تقسیم کنیم(در بالای کد تعریف شده است) تا مقداری بین 0.5 و -0.5 بدست بیاوریم, که میتوان آن را به راحتی به بازه 0.0 تا 1.0 تبدیل کرد. ماکسیمم مقدار شعاعی که میتوان به دست آورد 0.5 است، چون شعاع را از وسط صفحه محاسبه میکنیم، پس باید این بازه را در 2 ضرب تا مقدار ماکسیمم یک را بتوان از آن گرفت. همانطور که میبینید همه چیز حول انتقال و مپ کردن در بازه 0.0 و 1.0 است، همانطور که ما دوست داریم. تمرین های زیر را امتحان کنید: * مختصات قطبی را تغییر دهید که مثال بالا به دور محورش بچرخد، مانند آیکون انتظار موس. * برای گسترش مقدار یک رنگ خاص و فشرده کردن بقیه، از یک تابع شکل دهی به همرا تبدیل HSB به RGB استفاده کنید. * اگر با دقت به چرخ رنگی که در برنامه های انتخاب رنگ استفاده میشود نگاه کنید، آنان از فضای رنگی دیگری یعنی، RYB استفاده میکنند، برای مثال رنگ روبروی قرمز در تصویر زیر سبز است، اما در مثال بالا روبروی قرمز فیروزه ای است. آیا میتواید با استفاده از توابع شکل دهی، مثال بالا را مانند شکل زیر کنید؟ * کتاب [Josef Albers' book Interaction of Color](http://www.goodreads.com/book/show/111113.Interaction_of_Color) را بخوانید ، همچین شیدر های زیر را برای تمرین مرور کنید. #### نکته در مورد توابع و آرگومان ها قبل از رفتن به فصل بعدی، بایستی به عقب برگردیم، و توابع مثال های قبل را ببینیم. متوجه in قبل از آرگومان های ورودی تابع شدید؟. آن یک [*qualifier*](http://www.shaderific.com/glsl-qualifiers/#inputqualifier)است و در این حالت مشخص میکند، متغیر فقط خواندنی است. در مثال های آینده میبینیم که آرگومان ها را به عنوان `out` و یا `inout` هم میتوان مشخص کرد. آخری یعنی, `inout` مشابه انتقال آرگومان از طریق رفرنس است، که امکان تغییر یک متغیر عبور داده شده را میدهد. ```glsl int newFunction(in vec4 aVec4, // read-only out vec3 aVec3, // write-only inout int aInt); // read-write ``` شاید باورتان نشود اما هم اکنون تمام عناصر لازم جهت کشیدن تصاویر باحال را دارید. در فصل بعدی خواهیم آموخت چگونه با ترکیب فضا، همه ترفند های خود را برای ساخت فرم های هندسی ترکیب کنیم --- ### 06/README Fr (06/README-fr.md) ## Couleurs Jusqu'ici, nous avons manipulé des vecteurs mais nous n'avons pas encore pris le temps de voir comment marchent ces variables. Avant d'aller plus loin, il est important d'en savoir plus sur ces variables. Aborder la couleur est un bon moyen de se pencher sur la question. Si vous connaissez la Programmation Orientée Objet, vous aurez remarqué que nous accédons aux données des vecteurs comme on le ferait avec des `struct` en C, grâce à des **accesseurs / mutateurs** (**getters / setters** en anglais). Bien que cette pratique soit méconnue, il est possible d'utiliser des `struct` en GLSL, [plus d'informations ici](https://github.com/KhronosGroup/WebGL/blob/master/sdk/tests/conformance/glsl/misc/shader-with-array-of-structs-uniform.html). ```glsl vec3 red = vec3(1.0,0.0,0.0); red.x = 1.0; red.y = 0.0; red.z = 0.0; ``` Dans l'exemple ci dessus, *x*, *y* et *z* permettent d'**accéder** aux 3 valeurs contenues dans l'objet `red` de type `vec3`, ce sont les **accesseurs** aux propriétés de `red`. Définir une couleur avec *x*, *y* et *z* peut être un peu déroutant, c'est pourquoi il existe différentes manières d'accéder aux valeurs des propriétés des vecteurs. Les valeurs de `.x`, `.y` et `.z` peuvent être récupérées avec les **accesseurs** `.r`, `.g` et `.b`, ou `.s`, `.t` et `.p`. (`.s`, `.t` et `.p` sont généralement utilisées pour encoder les coordonnées spatiales des textures, nous verrons ça dans les chapitres suivants). Il est également possible d'accéder aux valeurs des propriétés des vecteurs par leur position d'index dans l'objet: `[0]`, `[1]` and `[2]`. Les lignes suivantes montrent les différentes manières d'accéder aux données : ```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; ``` On peut les utiliser ces **accesseurs** de façon indépendante ; le code suivant crée un clone *newColor* du vecteur *color* en utilisant chaque fois un accesseur différent. ```glsl vec4 color = vec4( 1.,0.,0.5,1. ); vec4 newColor = vec4( color[0], color.g, color.z, color.q ); ``` Il est possible de combiner les propriétés en **concaténant** les accesseurs : si on veut exploiter les valeurs `.r`, `.g` et `.b` d'un vecteur 4 sans se soucier de `.a` (l'alpha), on peut écrire : ```glsl vec4 color = vec4( 1.,0.,0.5,1. ); vec4 newColor = vec4( color.rgb, 1.0 ); ``` Ce qui revient à cloner chaque proriété `.r`, `.g` et `.b` du vecteur `color` sauf la dernière `.a`. Dans ce cas, `color.rgb` est interprété comme un vecteur de type `vec3` et il contient les valeurs `.r`, `.g` et `.b` du `vec4` *color*. De même, si on écrit: ```glsl vec4 color = vec4( 1.,0.,0.5,1. ); vec3 newColor = vec3( color.xy, 1.0 ); ``` On va utiliser les valeurs `.x` et `.y` de *color* pour construire un `vec3` dont les valeurs `.r` et `.g` seront les mêmes que les valeurs `.r` et `.g` du vecteur *color* et où la valeur `.b` sera `1.0`. Dernière chose, l'ordre dans lequel on **concatène** les accesseurs est important. Si on veut construire un vecteur à partir d'un autre mais en inversant l'ordre des propriétés, on peut l'écrire comme suit : ```glsl vec3 color = vec3( 1.0, 0.0, 0.5 ); vec3 newColor = color.bgr; ``` le vecteur *newColor* va copier les propriétés de *color* mais au lieu de les copier dans l'ordre "normal":`.r`, `.g` et `.b`, il va les copier dans l'ordre inverse: `.b`, `.g` et `.r`. ```glsl color.r = 1.0 color.g = 0.0 color.b = 0.5 // et newColor.r = 0.5 newColor.g = 0.0 newColor.b = 1.0 ``` Il en découle que si les déclarations suivantes sont équivalentes : ```glsl color.rgba = color.xyzw = color.stpq ``` Ces déclarations ne le sont pas : ```glsl color.rgba != color.argb != color.rbga != color.abgr // etc. color.xyzw != color.wxyz != color.xzyw != color.wzyx // etc. color.stpq != color.qstp != color.sptq != color.qpts // etc. ``` C'est une fonctionnalité très puissante ; elle permet de stocker les informations dans un format compact. Un exemple d'utilisation, si on veut décrire un rectangle, on peut se servir soit de 2 `vec2` décrivant respectivement le coin supérieur gauche et le coin inférieur droit, ou bien, utiliser un seul `vec4` dont l'**accesseur** `.xy` renverra un `vec2` décrivant le coin supérieur gauche, et l'**accesseur** `.zw` renverra un `vec2` décrivant le coin inférieur droit. Ces différentes manière d'accéder aux variables à l'intérieur des vecteurs sont simplement là pour nous aider à écrire un code lisible. Cette souplesse d'utilisation est le point d'entrée qui vous permettra de penser aux espaces cartésiens (le "vrai" espace) et colorimétriques de façon interchangeable. La concaténation prend tout son sens lorsqu'on veut pouvoir combiner des vecteurs dans un ordre arbitraire pour les mélanger (cette propriété s'appelle le *swizzle*). ```glsl vec3 jaune, magenta, vert; // crée le jaune jaune.rg = vec2(1.0); // Assigne 1. au canaux rouges et vert du vecteur jaune jaune[2] = 0.0; // Assigne 0. au canal bleu du vecteur jaune // crée le magenta magenta = jaune.rbg; // Assigne the valeur en intervertissant le vert et le bleu ( rbg au lieu de rgb ) // crée le vert vert.rgb = jaune.bgb; // Assigne le canal bleu du jaune (0) aux canaux rouges et bleus ``` ### Mélanger les couleurs A présent que nous savons définir les couleurs, il est temps de les utiliser avec ce que nous avons déjà appris. En GLSL, il existe une fonction extrêmement utile [`mix()`](../glossary/?search=mix), qui permet de mélanger deux valeurs en fonction d'un pourcentage. Comme vu au chapitre précédent, `mix()` permet d'interpoler entre 2 valeurs grâce à une troisième valeur T. Exactement comme `smoothstep()` à la différence que cette fois, la fonction `mix()` prend en argument des vecteurs au lieu de *floats*. Pouvez vous deviner ce que devra être le pourcentage ? Evidemment, une valeur normalisée entre *0.0* et *1.0* ! Ce qui nous va très bien, après tout ce temps passé sur la palissade du chapitre précédent, il est enfin temps de frapper ! Observez la ligne 18: notez que nous utilisons la valeur absolue (`abs()`) d'une fonction de sinus (`sin()`) prenant le temps en argument pour contrôler le mélange entre `colorA` et `colorB`. Montrez de quoi vous êtes capable : * Créez une transition expressive entre les couleurs. Pensez à une émotion en particulier. * Quelle couleur représente le mieux cette émotion ? Comment apparaît-elle ? Comment disparaît-elle ? * Pensez à une autre émotion et à la couleur correspondante, changez les couleur A et B dans le code puis utilisez les fonctions de formes pour opérer la transition. Robert Penner a développé une série de fonctions destinées à créer des animations, connues sous le nom d'[easing functions](http://easings.net/). Vous pouvez utiliser [cet exemple](../edit.php#06/easing.frag) comme base de recherche mais les meilleures transitions seront celles que vous ferez vous mêmes. ### Jouer avec les dégradés La fonction [`mix()`](../glossary/?search=mix) peut faire plus. Au lieu de passer un seul `float` pour faire l'interpolation, nous pouvons passer successivement plusieurs valeurs de transition. Dans l'exemple suivant, nous passons les valeurs `r`, `g` et `b` d'un `vec3` (`pct` pour *pourcentage*) pour contrôler le mélange des canaux. Regardez l'exemple suivant. Comme au chapitre précédent, nous branchons la valeur de transition sur la valeur normalisée de *x* et nous la visualisons par une ligne. Au début, rien d'exceptionnel, le dégradé est linéaire sur les trois canaux. A présent, décommentez la ligne 25 et regardez ce qui se passe, puis décommentez les lignes 26 et 27. Rappelez vous que les lignes représentent la quantité de mélange entre `colorA` et `colorB` par canal de couleur. Vous aurez sans doute reconnu les 3 fonctions de forme du chapitre précédent aux lignes 25, 26, 27. A vous de jouer ! Il est temps d'explorer et de créer des dégradés intéressants en ré-utilisant ce que nous avons vu au chapitre précédent. Essayez les exercices suivants : * Composez un dégradé qui ressemble au coucher de soleil ci-dessus. * Animez une transition entre lever et coucher de soleil en utilisant `u_time`. * Pouvez vous créer un arc-en-ciel avec ce que vous avez appris jusqu'à présent ? * Utilisez la fonction `step()` pour créer un drapeau. ### HSB On ne peut pas parler de couleur sans parler d'espace colorimétrique. Vous le savez sans doute, il existe plusieurs façons d'organiser les canaux rouge, vert, bleu. [HSB](http://en.wikipedia.org/wiki/HSL_and_HSV) signifie "Hue, Saturation, Brightness (ou Value)" soit en bon français "Teinte, Saturation, Luminosité", c'est une manière plus intuitive d'organiser les couleurs. Prenez un instant pour lire et essayer de comprendre les méthodes `rgb2hsv()` et `hsv2rgb()` dans le code suivant. En indexant la Teinte (Hue) sur la position en *x* et la Luminosité (Brigthness) sur la position en *y*, nous obtenons un spectre des couleurs complet. Cette distribution spatiale des couleurs peut être très pratique ; il est plus simple de choisir une couleur dans un espace HSB que dans un espace RGB. ### HSB et coordonnées polaires A l'origine, HSB a été conçu pour être représenté dans un système de coordonnées polaires. Par opposition à un système de coordonnées cartésien décrit par 2 axes *X* et *Y* orthogonaux, un système de coordonnées polaires, est décrit par des *angles* et des *rayons*. Pour dessiner notre fonction HSB, nous devons obtenir la position du centre du canvas de manière à connaître l'*angle* et la *distance* de chaque fragment au centre. Pour cela nous allons utiliser la méthode [`length()`](../glossary/?search=length) et [`atan(y,x)`](../glossary/?search=atan) qui est l'équivalent GLSL de la méthode `atan2(y,x)`. Lorsqu'on utilise des vecteurs avec des fonctions trigonométriques les variables de type `vec2`, `vec3` et `vec4` sont considérées comme des vecteurs géométriques même si elles représentent des couleurs. Nous commencerons à traiter les couleurs et les vecteurs géométriques de façon similaire, en fait, vous devriez comprendre assez vite que cette flexibilité d'utilisation est une force. **Note :** Si vous vous demandez s'il existe d'autres fonctions géométriques que [`length`](../glossary/?search=length) comme : [`distance()`](../glossary/?search=distance), [`dot()`](../glossary/?search=dot), [`cross`](../glossary/?search=cross), [`normalize()`](../glossary/?search=normalize), [`faceforward()`](../glossary/?search=faceforward), [`reflect()`](../glossary/?search=reflect) et [`refract()`](../glossary/?search=refract), la réponse est oui. GLSL expose également des méthodes pour comparer les vecteurs entres eux : [`lessThan()`](../glossary/?search=lessThan), [`lessThanEqual()`](../glossary/?search=lessThanEqual), [`greaterThan()`](../glossary/?search=greaterThan), [`greaterThanEqual()`](../glossary/?search=greaterThanEqual), [`equal()`](../glossary/?search=equal) et [`notEqual()`](../glossary/?search=notEqual). Une fois que nous avons récupéré l'angle entre le centre et le fragment en cours, nous devons le normaliser. Ligne 27, [`atan(y,x)`](../glossary/?search=atan) nous retourne un angle en radians compris entre *-PI* et *PI* (~-3.14 to ~3.14), pour le normaliser, nous devons diviser cet angle par *2 x PI*, la macro `TWO_PI` en début de code nous permet de stocker cette valeur. En divisant l'angle par `TWO_PI`, nous obtenons un chiffre compris entre *-0.5* (`-PI / TWO_PI`) et *0.5* (`PI / TWO_PI`) auquel il nous suffit d'ajouter 0.5 pour qu'il soit compris entre *0.0* et *1.0*. Le rayon (la distance du centre au fragment) retournera une valeur max de 0.5 en *x* et en *y* (parce que nous calculons la distance depuis le centre du canvas), nous devons donc doubler cette valeur (en la multipliant par 2) pour obtenir un *rayon* compris entre *0.0* et *1.0*. Vous voyez que tout est question de ramener les valeurs dans l'espace entre *0.0* et *1.0*, un espace *normalisé*. Essayez les exercices suivants : * Modifiez l'exemple des coordonnées polaires pour faire tourner les couleurs. * Utilisez les fonctions de formes avec les fonctions de conversion HSB vers RGB pour étendre une valeur de teinte spécifique et rétrécir le reste. * Si vous regardez attentivement la roue des couleurs qu'utilisent les sélecteurs de couleurs (voir l'image ci-dessous), ils affichent un spectre différent basé sur du RYB. Par exemple, la couleur opposée au rouge devrait être le vert mais dans nos exemples, c'est le Cyan. Pouvez vous trouver un moyen d'arranger ça de manière à obtenir exactement le meme rendu que sur l'image ? Indice: c'est un bon moment pour vous servir des fonctions de formes. * Lisez [le livre de Josef Albers : L'Interaction des Couleurs](http://www.goodreads.com/book/show/111113.Interaction_of_Color) et servez vous des exemples suivants pour vous entraîner à reproduire ses exemples. #### A propos des fonctions et des arguments Avant de passer au chapitre suivant, attardons nous un peu sur les fonctions du dernier exemple. Vous remarquerez un `in` avant les types des arguments. C'est ce qu'on appelle un [*qualifier*](http://www.shaderific.com/glsl-qualifiers/#inputqualifier) et dans ce cas précis, cela signifie que la variable est en lecture seule. Dans les exemples suivants, nous verrons qu'il est également possible de donner les *qualifiers* `out` et `inout` aux variables passées aux fonctions. Cette dernière, `inout`, est équivalente à passer un argument *par référence* en C ; cela nous donne la possibilité de modifier la valeur de la variable passée en argument. ```glsl int newFunction(in vec4 aVec4, // lecture seule out vec3 aVec3, // écriture seule inout int aInt); // lecture / écriture ``` Vous ne le savez pas encore et vous pourriez ne pas le croire mais nous avons à présent tout ce qu'il nous faut pour dessiner à peu près n'importe quoi. Au prochain chapitre, nous verrons comment combiner ces techniques pour *mélanger* l'espace. Oui... *mélanger* l'espace ! --- ### 06/README Id (06/README-id.md) ## 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 ``` ### 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! Periksa kode berikut pada baris 18 dan lihat bagaimana kita menggunakan nilai absolut gelombang sin dari waktu ke waktu untuk mencampur `colorA` dan` colorB`."Talk to the tree, make friends with it." Bob Ross
#### For your toolbox * [LYGIA's generative functions ](https://lygia.xyz/generative) are a set of reusable functions to generate patterns in GLSL. It's a great resource to learn how to use randomness and noise to create generative art. It's very granular library, designed for reusability, performance and flexibility. And it can be easily be added to any projects and frameworks. --- ### 11/Notes (11/notes.md) ### nicolas * L78 replace `fract()` with `floor()` to match the prvious definition --- ### 11/README Ch (11/README-ch.md) ## Noise 噪声 稍事休息,我们来转换一下思路。我们已经玩过了看起来像电视白噪音的 random 函数,尽管脑子里还在嗡嗡地转着 shader,但是已经眼花缭乱了。是时候出去走走了。 我们感知得到浮动在皮肤上的空气,晒在脸上的阳光。世界如此生动而丰富。颜色,质地,声音。当我们走在路上,不免会注意到路面、石头、树木和云朵的表面的样子。 这些纹理的不可预测性可以叫做“random"(随机),但是它们看起来不像是我们之前玩的 random。「真实世界」是如此的丰富而复杂!我们如何才能才能用计算机模拟这些多样的纹理呢? 这就是 [Ken Perlin](https://mrl.nyu.edu/~perlin/) 想要解答的问题。在20世纪80年代早期,他被委任为电影 “Tron”(电子世界争霸战)制作现实中的纹理。为了解决这个问题,他想出了一个优雅的算法,且获得了**奥斯卡奖**(名副其实)。 下面这个并不是经典的 Perlin noise 算法,但是这是一个理解如何生成 noise 的好的出发点。 这和之前章节我们做的事情很像。我们把单精度浮点 ```x``` 分割成它的整数部分 ```i``` 和小数部分 ```f``` 。我们用 [```floor()```](.../glossary/?search=floor) 获取 ```i```,用 [```fract()```](.../glossary/?search=fract) 获取 ```f```。然后我们 ```rand()``` x 的整数部分,即根据这个整数生成一个随机值。 在这之后有两个被注释掉的语句。第一句的作用是线性插值。 ```glsl y = mix(rand(i), rand(i + 1.0), f); ``` 试试取消这句的注释,看一下会变成什么样子。注意我们储存在 `f` 中的 [```fract()```](.../glossary/?search=fract) 值[```mix()```](.../glossary/?search=mix)了两个随机值。 到本书的这个部分,我们知道我们可以比比线性插值做得更好,不是吗?现在试试取消第二句的注释。第二句用 [```smoothstep()```](.../glossary/?search=smoothstep)进行插值。 ```glsl y = mix(rand(i), rand(i + 1.0), smoothstep(0.,1.,f)); ``` 在取消注释后,注意顶点的变化如何变得顺滑了起来。在一些 noise 的应用中你会发现程序员喜欢用他们自己的**三次多项式函数**(比如下面的例子),而不是用 [```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 ``` 这种 smooth randomness(平滑后的随机值)是一个图形工程师或者说艺术家的制胜法宝——它能生成非常有机的图像或几何形态。Perlin 的 noise 算法被无数次用到各种语言和各种维度的设计中,制作出无数迷人的作品。 现在轮到你了: * 写你自己的 ```float noise(float x)``` 函数。 * 用你的 noise 函数为图形制作动效,可以移动,旋转或改变大小。 * 用 noise 让一群图形一起“跳舞”。 * 用 noise 制做有机的形态。 * 创作一个“生物”,给它添加更多独特的动作,使其成为独特的角色。 ## 2D Noise 现在我们知道了如何在一维使用 noise,是时候进入二维世界了。在 2D 中,除了在一条线的两点(```fract(x)``` 和 ```fract(x)+1.0```)中插值,我们将在一个平面上的方形的四角(```fract(st)```, ```fract(st)+vec2(1.,0.)```, ```fract(st)+vec2(0.,1.)``` 和 ```fract(st)+vec2(1.,1.)```)中插值。 同样,如果我们想要在三维中使用 noise,就需要在一个立方体的8个角中插值。这个技术的重点在于插入随机值,所以我们叫它 **value noise**。 就像一维的那个例子,这个插值不是线性的,而是三次方的,它会平滑地在方形网格中插入点。 让我们来看一下这个方程。 我们先把空间大小变成五倍(第 45 行)以便看清栅格间的插值。然后在 noise 函数中我们把空间分成更小的单元。我们把它的整数部分和非整数部分都储存在这个单元里。我们计算整数位置的顶点的坐标,并给每个顶点生成一个随机值(第 23 - 26 行)。最后,在第 35 行用我们之前储存的小数位置的值,在四个顶点的随机值之间插值。 现在又到你了。试试下面的练习: * 改变第 45 行的乘数。添加动态试试。 * 缩放到什么程度会让 noise 再度变得像 random? * 缩放到什么程度就看不出来 noise 了? * 试试看把 noise 函数和鼠标位置连起来。 * 如果我们把 noise 的斜率处理成距离场(distance field)会怎么样?用它来做点有趣的事情。 * 现在你已经可以在混沌和有序之间进行一些操控了,是时候把这些知识用起来了。用长方形,色彩,和 noise 做一幅 [Mark Rothko](http://en.wikipedia.org/wiki/Mark_Rothko) 的复杂的画作吧。 ## 生成式设计中的 noise 应用 Noise 算法的设计初衷是将难以言说的自然质感转化成数字图像。在目前我们看到的一维和二维的实践中,都是在random *values*(随机值)之间插值,所以它们才被叫做 **Value Noise**,但是还有很多很多获取 noise 的方法…… [ ](../edit.php#11/2d-vnoise.frag) 如你所见,value noise 看起来非常“块状”。为了消除这种块状的效果,在 1985 年 [Ken Perlin](https://mrl.nyu.edu/~perlin/) 开发了另一种 noise 算法 **Gradient Noise**。Ken 解决了如何插入随机的 *gradients*(梯度、渐变)而不是一个固定值。这些梯度值来自于一个二维的随机函数,返回一个方向(```vec2``` 格式的向量),而不仅是一个值(```float```格式)。点击下面的图片查看代码,看这个函数是如何运作的。 [ ](../edit.php#11/2d-gnoise.frag) 花一分钟来看看 [Inigo Quilez](http://www.iquilezles.org/) 做的两个例子,注意 [value noise](https://www.shadertoy.com/view/lsf3WH) 和 [gradient noise](https://www.shadertoy.com/view/XdXGW8)的区别。 就像一个画家非常了解画上的颜料是如何晕染的,我们越了解 noise 是如何运作的,越能更好地使用 noise。比如,如果我们要用一个二维的 noise 来旋转空间中的直线,我们就可以制作下图的旋涡状效果,看起来就像木头表皮一样。同样地,你可以点击图片查看代码。 [ ](../edit.php#11/wood.frag) ```glsl pos = rotate2d( noise(pos) ) * pos; // 旋转空间 pattern = lines(pos,.5); // 画直线 ``` 另一种用 noise 制作有趣的图案的方式是用 distance field(距离场)处理它,用用 [第七章](../07/)提到的招数。 [ ](../edit.php#11/splatter.frag) ```glsl color += smoothstep(.15,.2,noise(st*10.)); // 黑色的泼溅点 color -= smoothstep(.35,.4,noise(st*10.)); // 泼溅点上的洞 ``` 第三种方法是用 noise 函数来变换一个形状。这个也需要我们在[第七章](../07/)学到的技术。 给你的练习: * 你还能做出什么其他图案呢?花岗岩?大理石?岩浆?水?找三种你感兴趣的材质,用 noise 加一些算法把它们做出来。 * 用 noise 给一个形状变形。 * 把 noise 加到动作中会如何?回顾[第八章](../08/)。用移动 “+” 四处跑的那个例子,加一些 random 和 noise 进去。 * 用代码生成波洛克(Jackson Pollock)的画。 ## Simplex Noise 对于 Ken Perlin 来说他的算法所取得的成功是远远不够的。他觉得可以更好。在 2001 年的 Siggraph(译者注:Siggraph是由美国计算机协会「计算机图形专业组」组织的计算机图形学顶级年度会议)上,他展示了 “simplex noise”,simplex noise 比之前的算法有如下优化: * 它有着更低的计算复杂度和更少乘法计算。 * 它可以用更少的计算量达到更高的维度。 * 制造出的 noise 没有明显的人工痕迹。 * 有着定义得很精巧的连续的 gradients(梯度),可以大大降低计算成本。 * 特别易于硬件实现。 我知道你一定在想:“这人是谁?”是的,他的工作非常杰出!但是说真的,他是如何优化算法的呢?我们已经知道在二维中他是如何在四个点(正方形的四个角)之间插值的;所以没错你已经猜到了,对于三维[(这里有个示例)](../edit.php#11/3d-noise.frag)和四维我们需要插入 8 个和 16 个点。对吧?也就是说对于 N 维你需要插入 2 的 n 次方个点(2^N)。但是 Ken 很聪明地意识到尽管很显然填充屏幕的形状应该是方形,在二维中最简单的形状却是等边三角形。所以他把正方形网格(我们才刚学了怎么用)替换成了单纯形等边三角形的网格。 这时 N 维的形状就只需要 N + 1 个点了。也就是说在二维中少了 1 个点,三维中少了 4 个,四维中则少了 11 个!巨大的提升! 在二维中插值过程和常规的 noise 差不多,通过在一组点之间插值。但是在这种情况下,改用单纯形网格,我们只需要给总共 3 个点插值。 这个单纯形网格是如何制作的?这是另一个聪明绝顶而十分优雅的做法。可以先把常规的四角网格分成两个等腰三角形,然后再把三角形歪斜成等边三角形。 然后,就像 [Stefan Gustavson 在这篇文献中说的](http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf): **“……通过观察转换后坐标的整数部分,我们就可以快速地判断哪个包含着两个单纯形的单元含有我们所需的点。并且通过比较 x 和 y 的大小,我们就可以判断这个点是在上三角还是下三角中,并且遍历这个正确的三角形。”** 在下面的代码中你可以取消第 44 行的注释,看一看网格是如何歪斜的,然后取消第 47 行的注释,看一看如何建造单纯形网格。注意第 22 行中我们仅仅通过判断 if ```x > y``` (下三角) 还是 ```y > x``` (上三角),就把歪斜过的正方形切成了两个等腰三角形。 另一个 **Simplex Noise** 的优化是把三次 Hermite 函数(Cubic Hermite Curve:_f(x) = 3x^2-2x^3_,和 [```smoothstep()```](.../glossary/?search=smoothstep) 一样)替换成了四次 Hermite 函数( _f(x) = 6x^5-15x^4+10x^3_ )。这就使得函数曲线两端更“平”,所以每个格的边缘更加优雅地与另一个衔接。也就是说格子的过渡更加连续。你可以取消下面例子的第二个公式的注释,亲眼看看其中的变化(或者看[这个例子](https://www.desmos.com/calculator/2xvlk5xp8b))。 注意曲线的末端发生了怎样的变化。你可以阅读 [Ken 自己的解释](http://mrl.nyu.edu/~perlin/paper445.pdf)了解更多。 所有这些进展汇聚成了算法中的杰作 **Simplex Noise**。下面是这个算法在 GLSL 中的应用,作者是 Ian McEwan,以[这篇论文](http://webstaff.itn.liu.se/~stegu/jgt2012/article.pdf)发表,对于我们的教学而言太复杂了,但你可以点开看看,也许没有你想象得那么晦涩难懂。 [ ](../edit.php#11/2d-snoise-clear.frag) 好了,技术细节就说到这里,现在你可以利用它好好自由发挥一下: * 凝神思考每个 noise 的实例的模样。设想它们是你的原材料,就像雕塑家手中的大理石。你觉得每一个带给你怎样不同的“感觉“?眯起你的眼睛释放想象力,就像你在观察云朵的形状的时候那样。你看到了什么?你想起了什么?你觉得每个 noise 生成的图像可以用来做成什么?放开胆量去做吧,用代码实现它。 * 做一个 shader 来表现流体的质感。比如像[熔岩灯](https://en.wikipedia.org/wiki/Lava_lamp?oldformat=true),墨水滴,水,等等。 * 用 Simplex Noise 给你现在的作品添加更多的材质效果。 在本章我们介绍了一些操控混沌的方法。这并不是一件简单的工作!成为 noise 超级大师需要时间和努力。 在下面的章节我们会看到一些很有名的技术,来修葺你的技能树,并且从 noise 中学到更多,并利用 shader 设计出更多优质的生成式艺术作品。在那之前,去外面走走,享受深入思考自然和错综复杂的图案的时光吧。培养洞察力也许需要和动手能力相同(甚至更多)的努力。出门走走享受今天剩余的时光吧!“和树聊聊天吧,和它交个朋友。” Bob Ross
--- ### 11/README De (11/README-de.md) ## Rauschen Im letzten Kapitel haben wir mit Zufallsfunktionen gearbeitet, die wie weißes Rauschen auf dem Fernsehbildschirm wirken. Nach so vielen Shader-Funktionen auf einmal dreht sich Dir bestimmt der Kopf und vielleicht sind auch Deine Augen etwas müde. Jetzt ist ein guter Moment, um einen kleinen Spaziergang zu unternehmen und ein wenig nach Luft zu schnappen. Draußen im Freien spüren wir den Luftzug auf unserer Haut und die Sonne in unserem Gesicht. Die Erde ist ein so lebendiger und vielgestaltiger Ort voller Farben, Texturen und Klängen. Während wir uns in der Natur bewegen, können wir gar nicht anders, als die unterschiedlichen Oberflächen von Straßen, Gestein, Bäumen und Wolken wahrzunehmen. Die Unvorhersehbarkeit dieser Texturen könnte man als „zufällig“ auffassen. Dabei wirken sie so gar nicht wie die Zufallsstrukturen, mit denen wir uns im letzten Kapitel befasst haben. Die Wirklichkeit ist ein so komplexer Ort! Wir kann es uns gelingen, ihr Antlitz mit Hilfe von Algorithmen nachzuahmen? Diese Frage beschäftigte [Ken Perlin](https://mrl.nyu.edu/~perlin/) in den frühen 1980er Jahren, als er den Auftrag erhielt, realistische Texturen für den Hollywood-Film „Tron“ zu erschaffen. Er entwickelte damals eine elegante Vorgehensweise, die als „Noise Algorithmus“ bekannt und sogar mit einem Oskar prämiert wurde (kein Witz). Die folgende Funktion entspricht nicht dem klassischen Noise-Algorithmus von Perlin, aber sie ist ein guter Ausgangspunkt, um die Erzeugung „verrauschter“-Strukturen zu begreifen. In diesen Zeilen gehen wir ähnlich vor, wie im vorangegangenen Kapitel. Wir teilen eine fortlaufende Fließkommazahl (```x```) in ihren ganzzahligen Vorkommateil (```i```) und ihren Nachkommateil (```f```) auf. Wir nutzen dabei [```floor()```](.../glossary/?search=floor), um ```i``` zu erhalten, sowie [```fract()```](.../glossary/?search=fract) für die Berechnung von ```f```. Dann wenden wir ```rand()``` auf den ganzzahligen Teil von ```x``` an, wodurch wir für jede Ganzzahl eine einzigartige Zufallszahl erhalten. Dahinter folgen zwei Programmzeilen, die zunächst auskommentiert sind. Die Erste davon interpoliert zwischen dem Zufallswert (```rand(i)```) und dem Zufallswert von (```rand(i+1)```) (also zwischen zwei ganz unterschiedlichen Zahlen) auf lineare Weise, wobei der Abstand für die Interpolation jeweils durch (```f```) bestimmt wird. ```glsl y = mix(rand(i), rand(i + 1.0), f); ``` Fahre fort, indem Du die Kommentarzeichen für diese Zeile entfernst und Dir das Ergebnis anschaust. An diesem Punkt unseres kleinen GLSL-Kurses wissen wir bereits, dass es noch etwas besseres als eine simple lineare Interpolation gibt, nicht wahr? Entferne deshalb die Kommentarzeichen aus der nächsten Zeile, die [```smoothstep()```](.../glossary/?search=smoothstep) nutzt, um bei der Interpolation weichere Verläufe und Übergänge zu erzielen. ```glsl y = mix(rand(i), rand(i + 1.0), smoothstep(0.,1.,f)); ``` Sobald Du die Kommentarzeichen aus dieser Zeile entfernt hast, erscheint ein anderes Ergebnis. In einigen Implementationen für Rausch-Funktionen verwenden die Autoren lieber ihre eigenen kubischen Kurven an Stelle von [```smoothstep()```](.../glossary/?search=smoothstep), wie etwa im folgenden Beispiel. ```glsl float u = f * f * (3.0 - 2.0 * f ); // kubische Verlaufskurve y = mix(rand(i), rand(i + 1.0), u); // angewandt auf die Interpolation ``` Diese *sanfte Zufälligkeit* ist das entscheidende Merkmal, auf das es vielen Grafikkünstlern ankommt. Erst dadurch wird es möglich, geometrische Formen und Bilder zu erstellen, die so organisch wirken, als kämen sie direkt aus der Natur. Perlins Noise-Algorithmus wurde seit seiner Veröffentlichung immer wieder in ganz unterschiedlichen Programmiersprachen und für verschiedene Dimensionen implementiert. Er hat Grafiker und Grafikkünstler auf der ganzen Welt bei ihren Arbeiten unterstützt. Und nun bist Du dran: * Entwickle Deine eigene ```float noise(float x)```-Funktion. * Nutze Deine Noise-Funktion, um Formen zu animieren, indem Du sie bewegst, rotierst oder skalierst. * Erstelle eine animierte Komposition aus mehreren Formen, die „miteinander“ tanzen, indem Du auf Noise-Funktionen zurückgreifst. * Baue organisch wirkende Formen mit Hilfe der Noise-Funktion. * Sobald Du auf diese Weise eine eigene „Kreatur“ erschaffen hast, versuche ihr Lebendigkeit einzuhauchen, indem Du sie auf ganz charakteristische Weise bewegst. ## 2D-Rauschen Jetzt, wo wir wissen, wie man Rauschen in einer Dimension erzeugt, können wir uns dem zweidimensionalen Rauschen zuwenden. Während wir im eindimensionalen Raum entlang einer Linie zwischen zwei Punkten (```fract(x)``` und ```fract(x)+1.0```) interpolieren, geschieht dies im zweidimensionalen Raum zwischen den vier Eckpunkten eines Vierecks innerhalb einer Ebene (```fract(st)```, ```fract(st)+vec2(1.,0.)```, ```fract(st)+vec2(0.,1.)``` und ```fract(st)+vec2(1.,1.)```). In ähnlicher Weise müssen wir im dreidimensionalen Raum vorgehen. Hier sind es die acht Ecken eines Kubus, zwischen denen es zu interpolieren gilt. Dabei dreht sich alles um die Interpolation von Zufallswerten (engl. random values), weshalb man in diesem Zusammenhang auch von **Value Noise** spricht. Wie schon bei unserem Beispiel für den eindimensionalen Raum, erfolgt die Interpolation auch hier nicht linear, sondern kubisch, damit ein sanfter Verlauf zwischen allen Punkten des viereckigen Rasters entsteht. Schau Dir die folgende Noise-Funktion an. Wir „blasen“ den Raum zunächst auf das Fünffache auf (*Programmzeile 45*), damit wir die Interpolation zwischen den einzelnen Elementen unseres Rasters besser erkennen können. Innerhalb der Noise-Funktion erfolgt dann die Einteilung des Raumes in einzelne Zellen. Wir speichern die Integer-Position der Zelle, ebenso den Nachkommateil für die Position innerhalb der Zelle. Die Integer-Position nutzen wir, um einen Zufallswert für alle vier Eckpunkte der Zelle zu erhalten (*Programmzeilen 23-26*). Schließlich interpolieren wir in der *Programmzeile 35* zwischen den vier zufällig gewählten Eckpunkten auf Basis des Nachkommateils, den wir zuvor gespeichert haben. Jetzt bist Du wieder dran. Versuche Dich an den folgenden Aufgaben: * Ändere den Multiplikationsfaktor in *Programmzeile 45*. Versuche ihn zu animieren. * Versuche herauszufinden, ab welcher Vergrößerungsstufe das Rauschen wieder vollkommen zufällig und unzusammenhängend (chaotisch) wirkt. * Ab welcher Vergrößerungsstufe ist das Rauschen nicht mehr wahrnehmbar? * Versuche die Noise-Funktion sinnvoll mit den Mauskoordinaten in Verbindung zu bringen. * Was wäre, wenn wir den Farbverlauf des Rauschens als Distanzfeld behandeln? Versuche etwas Interessantes damit anzufangen. * Nun, da wir ein gewisses Maß an Kontrolle über Ordnung und Chaos erzielt haben, ist es an der Zeit, dieses Wissen umzusetzen. Erstelle eine Komposition aus Rechtecken, Farben und Rauschen, die an die Struktur eines Kunstwerks von [Mark Rothko](http://de.wikipedia.org/wiki/Mark_Rothko) erinnert. ## Rauschen und seine Verwendung für generative Designs Noise-Algorithmen wurden ursprünglich entwickelt, um digitalen Texturen ein natürliches Aussehen zu verleihen. Die ein- und zweidimensionale Implementation, die wir bislang betrachtet haben, verwendet dafür Interpolationen zwischen Zufallswerten (engl. *random values*), weshalb sie als **Value Noise** bezeichnet wird. Doch es gibt noch andere Verfahren, um Rauschen zu erzeugen. [ ](../edit.php#11/2d-vnoise.frag) Wie die vorangegangenen Abschnitte gezeigt haben, tendiert *Value Noise* zur Erzeugung blockartiger Strukturen. Um diesen Blockeffekt zu reduzieren, hat [Ken Perlin](https://mrl.nyu.edu/~perlin/) im Jahre 1985 einen weiteren Algorithmus mit Namen **Gradient Noise** entwickelt. Ken hatte herausgefunden, wie man zwischen zufälligen Gradienten (Verläufen) interpoliert, anstatt zwischen einfachen Zufallszahlen. Diese Gradienten waren das Ergebnis einer 2D-Zufallsfunktion, die Richtungsvektoren (bei GLSL in Form eines ```vec2```) anstelle einfacher Fließkommazahlen (```float```) zurückliefert. Klicke auf das folgende Bild, um einen Blick auf den dahinterstehenden Programmcode zu werfen und zu verstehen, wie das Ganze funktioniert. [ ](../edit.php#11/2d-gnoise.frag) Nimm Dir einen Moment Zeit, um die beiden folgenden Beispiele von [Inigo Quilez](http://www.iquilezles.org/) zu studieren und richte Deine Aufmerksamkeit dabei besonders auf die Unterschiede zwischen [*Value Noise*](https://www.shadertoy.com/view/lsf3WH) und [*Gradient Noise*](https://www.shadertoy.com/view/XdXGW8). Wie ein Maler, der genau weiß, wie die Farben auf seiner Staffelei miteinander harmonieren, werden auch wir die Noise-Funktionen umso besser nutzen können, je mehr wir deren Vorgehensweise verstehen. Wenn wir beispielsweise eine zweidimensionale Noise-Funktion nutzen, um den Raum zu drehen, während wir gerade Linien zeichnen, entsteht der folgende Dreheffekt, der stark an die Maserung von Holz erinnert. Auch hier kannst Du wieder auf die Grafik klicken, um der den Shader-Code dahinter anzuschauen. [ ](../edit.php#11/wood.frag) ```glsl pos = rotate2d( noise(pos) ) * pos; // drehe den Raum pattern = lines(pos,.5); // zeichne Linien ``` Ein anderer Weg zur Erzeugung interessanter Muster mit Hilfe von Noise-Funktionen besteht in ihrer Behandlung als Distanzfeld und der Anwendung einiger Tricks, die wir im [Kapitel über Formen](../07/) kennengelernt haben. [ ](../edit.php#11/splatter.frag) ```glsl color += smoothstep(.15,.2,noise(st*10.)); // schwarze Spritzer color -= smoothstep(.35,.4,noise(st*10.)); // Löcher in den Spritzern ``` Ein dritter Weg basiert auf der Modulation einer Form mit Hilfe einer Noise-Funktion. Auch dabei kommen einige der Techniken zum Einsatz, die wir im [Kapitel über Formen](../07/) kennengelernt haben. Empfohlene Übungen: * Welche anderen generativen Designs fallen Dir ein? Was ist mit Granitgestein? Marmor? Magma? Wasser? Suche Dir drei Fotos entsprechender Materialien und entwickle die zugehörigen Algorithmen unter Einbeziehung von Noise-Funktionen. * Nutze Noise-Funktionen, um eine Form zu modulieren. * Wie steht es um die Nutzung von Noise-Funktionen für Bewegungsabläufe? Schlage noch einmal im [Kapitel über Matrizenoperationen](../08/) nach. Nutze das dortige Beispiel, in welchem das Kreuz über die Zeichenfläche bewegt wird, und füge dem Ganzen etwas Zufall und Noise hinzu. * Erzeuge ein generatives Design wie bei Jackson Pollocks Bildern. ## Verbesserte Noise-Funktionen Eine Verbesserung von Perlin an seinem ursprünglichen **Non-Simplex Noise**-Algorithmus hin zu einem **Simplex Noise** ist der Ersatz der kubischen Hermite-Funktionn ( _f(x) = 3x^2-2x^3_, die der [```smoothstep()```](.../glossary/?search=smoothstep)-Funktion in GLSL entspricht) durch eine quintische Interpolationsfunktion ( _f(x) = 6x^5-15x^4+10x^3_ ). Diese lässt die Interpolationskurve an ihren Enden flacher werden, so dass sie nahtloser in die nächste Interpolationskurve übergeht. Man erhält dadurch kontinuierlichere Übergänge zwischen den einzelnen Zellen. Du kannst Dir ein Bild davon machen, indem Du die Kommentare an der zweiten Formel in dem folgenden Graphen entfernst. ([Beide Graphen in einem Bild siehst Du auch hier](https://www.desmos.com/calculator/2xvlk5xp8b)). Entscheidend ist wie immer der Bereich zwischen ```0.0``` und ```1.0``` auf der *x-Achse*. Beachte, wie die beiden unterschiedlichen Kurven an ihren Endbereichen voneinander abweichen. Mehr dazu erfährst du in [Ken s eigenen Worten hier](http://mrl.nyu.edu/~perlin/paper445.pdf). ## Simplex Noise Für Ken Perlin war der Erfolg seines ersten Noise-Algorithmus noch nicht genug. Er suchte weiter nach Verbesserungen. Auf der berühmten Grafik-Konferenz *Siggraph* präsentierte er im Jahre 2001 den „Simplex Noise“-Algorithmus, mit dem er die folgenden Optimierungen gegenüber dem Vorgänger erzielte: * Geringerer Rechenaufwand und weniger Multiplikationen. * Ein Rauschen, das sich auch für höhere Dimensionen berechnen lässt, ohne dass der Aufwand ins Astronomische steigt. * Ein Rauschen ohne sichtbare Richtungsartefakte. * Ein Rauschen mit sauber definierten und nahtlosen Übergangen, das sich einfach berechnen lässt. * Ein Algorithmus, der auch in der Hardware einfach zu implementieren ist. Ich weiß, was Du jetzt denkst... „Wow, wer ist dieser Mann?“ Ja, seine Leistungen sind wirklich großartig. Aber mal ganz im Ernst, wie ist es ihm gelungen, seinen Algorithmus zu verbessern? Nun, wir haben gesehen, dass er zur Berechnung des Rauschens in zwei Dimensionen zwischen den vier Eckpunkten eines Vierecks interpoliert. Man darf deshalb zurecht davon ausgehen, dass er für die Berechnung in drei Dimensionen ([eine Implementierung in GLSL findest Du hier](../edit.php#11/3d-noise.frag)) und vier Dimensionen zwischen 8 bzw. 16 einzelnen Eckpunkten interpolieren muss. Korrekt? In anderen Worten: Für die Berechnung des Rauschens in N Dimensionen muss man zwischen *2 hoch N* (_2^N_) verschiedenen Punkten interpolieren. Ken war jedoch aufgefallen, dass die offensichtliche „Bauweise“ für eine flächenfüllende Form zwar fraglos ein Viereck darstellt, die einfachste Form der Abdeckung jedoch mit gleichseitigen Dreiecken erzielt wird. Deshalb ersetzte er das rechtwinklige Gitternetz durch ein Netz aus gleichseitigen Dreiecken. Mit gleichseitigen Dreiecken besteht die einfachste Form für *N Dimensionen* aus einer Konstruktion mit *N+1 Eckpunkten*. Das bedeutet einen Eckpunkt weniger für zweidimensionales Rauschen, vier Eckpunkte weniger für dreidimensionales Rauschen und elf Eckpunkte weniger für vierdimensionales Rauschen. Diese „Ersparnis“ bringt einen enorm reduzierten Rechenaufwand und dadurch einen großen Geschwindigkeitszuwachs mit sich! In zwei Dimensionen erfolgt die Interpolation genau wie bei der Standard Noise-Funktion. Weil wir aber ein gleichseitiges Dreieck nutzen, müssen wir dabei nur drei Punkte einbeziehen. Doch wie wird dieses vereinfachte Gitternetz aufgebaut? In einem weiteren brillanten und äußerst eleganten Schritt, werden die Zellen des viereckigen Gitternetzes jeweils in zwei gleichschenklige Dreiecke (mit jeweils zwei gleich langen Seiten) aufgeteilt. Anschließend wird das Netz so verzerrt, dass alle Dreiecke auch gleichseitig sind (also mit jeweils drei gleich langen Seiten). Denn damit lässt sich am einfachsten interpolieren. Anschließend fahren wir fort, wie es [Stefan Gustavson in seinen Ausführungen beschreibt](http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf): "*... indem wir uns die ganzzahligen Anteile der transformierten Koordinaten (x,y) des zu berechnenden Punktes anschauen, denn darüber können wir leicht feststellen, zu welchen zwei Dreiecken der Punkt gehört. Indem wir die Werte von x und y vergleichen, erfahren wir, ob sich der Punkt in dem oberen oder in dem unteren Dreieck befindet. So können wir die drei korrekten Eckpunkte in die Berechnung einbeziehen.*“ Im folgenden Programmcode kannst Du die Kommentarzeichen aus der *Programmzeile 44* entfernen, um zu sehen, wie das Gitternetz gezerrt wird. Und sobald Du die Kommentierung von *Zeile 47* aufhebst, erkennst Du die Aufteilung der Fläche in gleichschenklige Dreiecke. Beachte, wie wir in *Zeile 22* das verzerrte Rechteck einfach in zwei gleichseitige Dreiecke aufteilen, indem wir testen, ob ```x > y``` ist („unteres“ Dreieck) oder ```y > x``` („oberes“ Dreieck). All diese Verbesserungen münden in das Meisterwerk, das als **Simplex Noise**-Algorithmus bekannt ist. Der folgende Programmcode ist eine Implementation dieses Algorithmus in GLSL, die von Ian McEwan und Stefan Gustavson entwickelt wurde ([hier nachzulesen](http://webstaff.itn.liu.se/~stegu/jgt2012/article.pdf)). Für unsere Lernzwecke ist diese theoretische Erklärung vielleicht etwas zu aufwändig. Allerdings wirst Du beim Anklicken der Grafik und einem Blick auf den dahinterstehenden Programmcode feststellen, dass dieser weniger kryptisch daherkommt, als Du vielleicht erwartet hast. Außerdem ist der Code vergleichsweise kompakt und kann schnell ausgeführt werden. [ ](../edit.php#11/2d-snoise-clear.frag) Nun aber genug der technischen Spitzfindigkeiten. Es ist an der Zeit, dass Du den Simplex Noise-Algorithmus als eine wertvolle Ressource im Rahmen Deiner eigenen Projekte zum Einsatz bringst: * Versuche das Besondere an den verschiedenen Implementationen von Noise zu erkennen. Stelle Sie Dir wie Rohmaterialien vor, aus denen ein Bildhauer seine Skulptur herausschält. Wie fühlen sich die unterschiedlichen Ergebnisse für Dich an? Verziehe beim Betrachten deine Augen, um der Vorstellungskraft Raum zu geben, so wie Du die Wolken nach Mustern absuchst. Was erkennst Du? Woran erinnert es Dich? Was könnte man wohl mit den verschiedenen Noise-Implementationen anstellen? Höre auf Deine innere Stimme und probiere es einfach aus! * Entwickle einen Shader, der die Illusion einer Strömung von Flüssigkeiten erweckt. Etwa wie bei einer Lava-Lampe, Tintentropfen, Wasser etc. * Nutze den Simplex Noise-Algorithmus um Deinen bisherigen Arbeiten mehr Textur zu verleihen. In diesem Kapitel haben wir versucht, Kontrolle über das Chaos zu erlangen. Das war keine leichte Aufgabe. Es braucht seine Zeit, um ein Meister des Rauschens und der Raumkrümmung zu werden. In den folgenden Kapiteln werden wir einige bekannte Techniken aufgreifen, mit Denen Du deine Fähigkeiten weiter verbessern kannst. Bis dahin genieße ein wenig Zeit draußen an der frischen Luft und lasse Dich von den Mustern und Strukturen der Natur inspirieren. Denn Deine Fähigkeiten zur Beobachtung müssen ähnlich gut entwickelt sein, wie Deine Programmierfähigkeiten. Vielleicht sogar noch besser. Genieße die wertvolle Zeit abseits des Computers!"Sprich mit den Bäumen und werdet Freunde." Bob Ross
--- ### 11/README Fa (11/README-fa.md) ## نویز وقت استراحت است! با تابع های رندومی که مانند برفک ها تلویزیون بودند کار کردیم و هنوز سرمان گیح میرود و چشمانامان خسته شده است:) وقتش هست که کمی قدم بزنیم! ما روی پوست خود هوا و خوشید را روی صورتمان حس میکنیم. جهان اینگونه زنده و غنی است. رنگ ها، صدا ها و بافت ها. وقتی راه میرویم نمیتوانیم از سطوح جاده و سنگ ها و درختان و ابرها چشم پوشی کنیم. به غیر قابل پیش بینی بودن این رنگ ها رندوم گفته میشود. اما مانند رندومی که در دروس قبلی کار کردیم نیستند. جهان جایی غنی و پیچیده است! چگونه میتوان این تنوع را از نظر محاسباتی پیاده سازی کرد؟ این سوالی بود که [Ken Perlin](https://mrl.nyu.edu/~perlin/) قصد داشت در اوایل دهه 1980 آن را حل کند، وقتی که وظیفه داشت بافتی واقعی تر برای فیلم ترون ایجاد کند. برای این منظور اون الگوریتمی ایجاد کرد که موجب برنده شدن جایزه اسکار شد. کد زیر نمونه اصلی نویز پرلین نیست اما برای شروع و درک این مبحث مناسب است. در این خطوط کاری مشابه قسمت های قبلی میکنیم. ما عدد ادامه دار یعنی (```x```) را تبیدل به اعداد صحیح یعنی (```i```) و مقدار کسری اش (```f```) میکنیم. از [```floor()```](../glossary/?search=floor) برای ساخت ```i``` و [```fract()```](../glossary/?search=fract) برای ساخت ```f``` استفاده میکنیم. بعد تابع ```rand()``` را به قسمت صحیح ```x``` اعمال میکنیم, که در نتیجه یک عدد رندوم خاص برای هر مقدار صحیح میدهد. بعد از این ها ما دو خط کامنت شده داریم. اولی بین دو تابع رندوم بصورت خطی عمل درون یابی انجام میدهد.. ```glsl y = mix(rand(i), rand(i + 1.0), f); ``` این خط را از حالت کامت خارج کنید و ببینید چه شکلی میشود. از مقادیر [```fract()```](../glossary/?search=fract) ذخیره شده در `f` برای [```mix()```](../glossary/?search=mix) درون یابی بین دو مقدار رندوم استفاده میکنیم. اما میتوانیم کاری بهتر از درون یابی خطی انجام دهیم. حالا خطی که از[```smoothstep()```](../glossary/?search=smoothstep) استفاده میکند را از حالت کامنت خارج کنید. ```glsl y = mix(rand(i), rand(i + 1.0), smoothstep(0.,1.,f)); ``` در این کد میبیندی که انتقال بین قله ها نرم تر صورت گرفته است.در برخی پیاده سازی های نویز برنامه نویسان تمایل دارند نویز مکعبی خود را پیاده سازی کنند (مانند فرمول زیر) به جای استفاده از [```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 ``` این رندوم نرم یک عنصر اساسی برای مهندسان گرافیک و آرتیست ها است و این امکان را میدهد که تصاویر و اشکال با حسی اورگانیک ساخته شوند. الگوریتم نویز پرلین بار ها در زبان ها و ابعاد مختلف پیاده سازی شده است تا قطعاتی مسحور کننده برای انواع استفاده های خلاقانه بسازد. حالا نوبت شماست: * تابع نویز ```float noise(float x)``` مخصوص خودتان را بسازید. * از تابع نویز خود برای انیمیت کردن، تغییر زاویه و اندازه شکل استفاده کنید. * یک ترکیب متحرک از اشیایی بسازید که در حال رقصیدن باشند. * یک شکل خاص و استثنایی با استفاده از نویز بسازید. * هنگامی که شکلتان را ساختید سعی کنید با اضافه کردن حرکتی خاص آن را بیشتر به یک شخصیت تبدیل کنید. ## نویز دو بعدی حال که میدانیم چگونه در یک بعد نویز بسازیم, وقتش است به سراغ دو بعدی ها برویم. در دو بعدی, به جای درون یابی بین دو نقظه از یک خط (```fract(x)``` و ```fract(x)+1.0```), باید بین 4 گوشه یک صفحه درون یابی کنیم (```fract(st)```, ```fract(st)+vec2(1.,0.)```, ```fract(st)+vec2(0.,1.)``` و```fract(st)+vec2(1.,1.)```). به طور مشابه، اگر بخواهیم نویز سه بعدی ایجاد کنیم باید بین 8 گوشه یک مکعب درون یابی کنیم. این تکنیک تمام در مورد درون یابی بین مقادیر است، به همین علت هم به آن نویز مقدار گفته میشود. مانند مثال یک بعدی، این درون یابی بطور خطی نیست بلکه بصورت cubic است، به طوری که هر نقطه داخل محدوده مان را درون یابی میکند. به این تابع نویز نگاهی بیاندازید. اول فضا را 5 برابر کردیم(در خط 45) تا درون یابی بین مربع هاقابل مشاهده باشند. سپس در تابع نویز, فضا را مانند سلول هایی در نظر گرفتیم. همچنین مقدار صحیح سلول ها و مقدار کسری سلول ها را ذخیره کرده ایم. از مختصاصت صحیح برای محاسبه مقادیر رندوم گوشه ها استفاده میکنیم، برای هر گوشه مقداری را بدست میآوریم(در خطوط 23 تا 26) در نهایت در خط 35 با استفاده از مقادیر کسری هر سلول، درون یابی بین چهار گوشه را انجام میدهیم. حالا نوبت شماست، این تمرین ها را انجام دهید: * در خط 45 ضرب را تغییر دهید. سعی کنید آن متحرک کنید. * در چه مرحله از زوم دوباره نویز شبیه رندوم میشود؟ * تا چه مقداری از زوم نویز محسوس نیست؟ * سعی کنید این تابع نویز را با مختصات موس پیوند بزنید. * چه میشود اگر طیف نویز را مثل یک میدان فیلد در نظر بگیریم؟ یک کار جالب با آن انجام دهید. * حال که بین نظم و هرج و مرج به کنترلی رسیدیم، وقتش است از دانشمان اسفاده کنیم. ترکیبی از مستطیل ها درست کنید, سعی کنید رنگ بندی و پیچیدگی های نقاشی [Mark Rothko](http://en.wikipedia.org/wiki/Mark_Rothko) را بوجود آورید. ## استفاده از نویز در طراحی ها مولد الگوریتم های نویز برای طبیعی تر جلوه دادن تصاویر بوجود آمدند. نویز های یک بعدی و دو بعدی که فعلا دیدیم، درون یابی بین چند مقدار بودند، به همین علت هم به آنان نویز مقدار گفته میشود، اما روش های دیگری نیز برای ساختن نویز وجود دارد. [ ](../edit.php#11/2d-vnoise.frag) همانطور که در تمرین های قبلی متوجه شدید, نویز های مقدار تمایل به تکه تکه بودن بلاکی دارند." برای کاهش تکه تکه ای بودن نویز, در 1985 [کن پرلین](https://mrl.nyu.edu/~perlin/) نوعی دیگر از الگوریتم نویز را به نام Gradient Noise خلق کرد. اون فهمید چگونه بجای مقادیر، بین شیب ها یا همان Gradient ها درون یابی کند. این گرادیان ها نتیجه یک رندوم دو بعدی که جهت را (represented by a ```vec2```) به جای یک مقدار (```float```) برمیگرداند است. بر روی عکس پایین کلیک کنید و ببیند که چگونه کار میکند. [ ](../edit.php#11/2d-gnoise.frag) چند دقیقه به مثال های [Inigo Quilez](http://www.iquilezles.org/) و به تفاوت بین این دو نویز [value noise](https://www.shadertoy.com/view/lsf3WH) و [gradient noise](https://www.shadertoy.com/view/XdXGW8) توجه کنید. مانند نقاش که میداند رنگ دانه ها چگونه عمل میکنند، ما نیز هرچه بیشتر در مورد نحوه پیاده سازی نویز بدانیم، بهتر میتوانیم از آن استفاده کنیم. برای مثال, اگر ما از نویز دوبعدی برای چرخش فضای در جایی که خط های مستقیم رندر شده اند استفاده کنیم، میتوانیم افکت چرخشی زیر که شبیه تکستچر چوب است را پیاده سازی کنیم. میتوانید با کلیک روی تصویر زیر کد آن را مشاهده کنید [ ](../edit.php#11/wood.frag) ```glsl pos = rotate2d( noise(pos) ) * pos; // rotate the space pattern = lines(pos,.5); // draw lines ``` راه جالب دیگر برای ساخت پترن، رفتار کردن با انان به عنوان فیلد فاصله است. چند ترفند [Shapes chapter](../07/) را میتوان روی آن پیاده کنید. [ ](../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 ``` راه دیگر اسفاده از نویز ها تعدیل کردن اشکال است. که نیاز به استفاده از تکنیک هایی دارد که در فصل [chapter about shapes](../07/) یاد گرفتیم. برای تمرین: * چه پترن های مولد دیگری میتوانید بسازید؟ سنگ گرانیت؟ مرمر؟ گدازه؟ آب؟ سه تصویر دلخواه را که میخواهید با نویز پیاده سازی کنید انتخاب و سعی کنید با استفاده از الگوریتم ها آنان را پیاده سازی کنید. * از نویز برای تعدیل یک شی استفاده کنید. * اگر از نویز برای حرکت و جنبش استفاده کنیم چه? نگاهی به فصل [Matrix chapter](../08/) بیاندازید. از تابع انتقالی که "+" را میچرخواند استفاده کنید, و نویز و رندوم به آن اضافه کنید. * سعی کنید یکی از اثر های Jackson Pollock را بازسازی کنید. ## بهبود نویز یکی از بهبود های پریل برای نویز ساده اش، تعویض منحنی cubic Hermite ( _f(x) = 3x^2-2x^3_ , که مانند [```smoothstep()```](../glossary/?search=smoothstep) هست) با منحنی quintic interpolation ( _f(x) = 6x^5-15x^4+10x^3_ ) است. این کار باعث میشود دو انتهای منحنی مسطح تر باشند، پس هر حاشیه با ظرافت بیشتر و بهتری به مرز بعدی متصل میشود . به زبان دیگر, یک انتقال مداوم و نرم تر بین سلول ها خواهید داشت. میتوانید در مثال زیر این دو را با هم مقایسه کنید (یا [دو معادله را در اینجا مشاهده کنید](https://www.desmos.com/calculator/2xvlk5xp8b)). دقت کنید چگونه انتهای بردار ها تغییر میکند. برای اطلاعات بیشتر در این زمینه [Ken's own words](http://mrl.nyu.edu/~perlin/paper445.pdf). ## Simplex نویز برای پرلین، موفقیت این الگوریتم کافی نبود. او فکر میکرد بهتر از این ها میتواند انجام دهد. در جشنواره سیگراف سال 2001 او samplex noise را معرفی کرد، که منجرب به این پیشرفت ها نسبت به الگوریتم قبلی شده بود: * الگوریتم با پیچیدگی محاسباتی و عملیات ضرب کمتر. * نویزی که با ابعاد بالاتر و همزمام هزینه کمتر قابل اجرا بود. * نویزی بدون مصنوعات جهت دار. * نویزری با گرادیانت(شیب) های مشخص و مداوم که بسیار ارزان قابل محاسبه است. * الگوریتم به راحتی روی سخت افزار قابل اجرا است. میدانم الان چه فکری میکنید... "این مرد دیگر کیست؟" بله، کار های او فوق العادست! اما جدا, چگونه الگوریتم را تقویت کرد؟ ، خب دیده بودیم چگونه در دو بعد بین 4 نقطه درون یابی میکردیم (گوشه های مربع); پس میتوان حدس زد برای [سه بعد (پیاده سازی شده در اینجا)](../edit.php#11/3d-noise.frag) و چهار بعدی ما به 8 و 16 نقطه برای درون یابی نیاز داریم. درست است؟ به عبارتی برای n بعد به دو بتوان n درون یابی نیاز داریم. بن این موضوع را متوجه شده بود، واضح است که راحترین شکل برای پر کردن فضا مربع است, ام ساده ترین شکل دو بعدی، مثلث متساوی الاضلاع است. پس شروع به تعویض صفحه مختصات مربعی (که یاد گرفتیم چگونه کار میکند) با یک مختصات ساده شده مثلث متساوی الاضلاع کرد. ساده ترین شکل در فضای n بعدی، شکلی است با n+1 گوشه. در نتیجه نقاط کمتر برای درون یابی در دوبعدی و سه بعدی و چهار بعدی مورد استفاده قرار میگیرد! این یک بهبود بزرگ است! در دوبعدی این درون یابی شبیه الگوریتم نویز معمولی است، همان درون یابی مقدار گوشه ها. با این تفاوت که، با استفاده از مختصات ساده شده، کافیست بین سه نقطه درون یابی کنیم. مختصات ساده شده تا به اینجا چگونه بود؟ در یک اقدام هوشمندانه دیگر این مختصات ساده را میتوان از صفحه بندی معمولی 4 گوشه ای بدست آورد. به طوری که هر 4 گوشیه شامل دو مثلث متقارن هستن و با کج کردن آن ها میتوان آنان را به مثلث متساوی الاضلاع تبدیل کرد. Stefan Gustavson, [در این مقله میگوید:](http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf): _".با نظر به قسمت های صحیح مختصات تبدیل شده برای نقطه ای که میخواهیم ارزیابی کنیم، میتوانیم سریع محاسبه کنیم که کدام سلول حاوی نقطه مورد نظر اسj. il]kdk fh lrhdsi lrhndv x,y میتوانیم تعیین کنیم که آیا این تقطه بالای سلول است یا پایین آن."_ در مثال زیر خط 44 را از حالت کامنت در بیاورید تا ببنید مختصات چگونه کشیده میشود, و بعد خط 47 را از حالت کامنت خارج کنید تا ببنید صفحه بندی simplex چگونه ساخته میشود. توجه کنید که چگونه در خط 22 مربع کج شده را به دو مثلث متساوی الاضلاع تقسیم میکنیم، ان هم فقط با استفاده از if ```x > y``` (مثلث پایینی) or ```y > x``` (مثلث بالایی). نتیجه تمام این پیشرفت ها الگوریتمی شد به نام Simplex Noise. در ادامه بصورت GLSL این الگوریتم توسط Ian McEwan وStefan Gustavson پیاده سازی شده است (ارائه شده [در این مقاله](http://webstaff.itn.liu.se/~stegu/jgt2012/article.pdf)) که البته برای مقاصد آموزشی بیش از حد پیچیده است,البته خوشحال باشید در کد زیر به صورت ساده تر و سریع تر این الگوریتم قابل مشاهده است. [ ](../edit.php#11/2d-snoise-clear.frag) خب بحث های تکنیک دیگر کافیست, حال زمان آن است از این منابع برای کار های خود استفاده کنید: * نگاه کنید که هر نویز به چه شکلی هست. آن ها را به مانند ماده اولیه ای مثل سنگ مرمر برای مجسمه ساز تصور کنید. چه نظری در مورد هر کدام دارید؟ چه حسی به شما میدهند? چشم هایتان بمالید و تخیلاتتان را تحریک کنید، مانند زمانی که میخواهید اشکالی از ابر ها پیدا کنید. چه چیزی میبینید? شما را یاد چه می اندازد? چه تصوری میتوانید بکنید که از هر جزئ نویز چه میتوان ساخت? دنبال ندای درونتان بروید و سعی کنید کد آن را پیاده کنید. * شیدری بسازید که توهم جریان را نشان دهد. مثل چراغ لاوا, قطره جوهر, آب, و غیره. * از Simplex Noise برای اضافه کردن تکتچر به کار هایی که تا امروز کرده اید استفاده کنید. در این فصل مباحثی در مورد کنترل هرج و مرج داشتیم. کار راحتی نبود! حرفه ای شدن در نویز های زمان و تمرین زیادی میطلبد. در فصل بعدی برخی دیگر از تکنیک های شناخته شده برای تکمیل مهارت های تان و استفاده بیش از پیش از نویز ها برای طراحی شیدر های با کیفیت را خواهیم دید. تا آن زمان از الگو های پیچیده نویز لذت ببرید. توانایی مشاهده شما نیز به اندازه مهارت ساختن، نیاز به تمرین دارد، بیرون بروید و از بقیه روز لذت ببرید!"Talk با درختان حرف بزنید و با آنان دوست شوید." Bob Ross
--- ### 11/README Fr (11/README-fr.md) ## Bruit Il est temps de faire une pause ! Nous avons joué avec des fonctions aléatoires qui ressemblaient au bruit blanc d'une télévision. On a encore la tête qui tourne en pensant aux shaders et nos yeux sont fatigués. Il est grand temps de sortir faire un tour ! Nous sentons l'air sur notre peau, le soleil dans les yeux, le monde est tellement vibrant et coloré. Les couleurs, les textures, les sons. Pendant notre balade, nous ne pouvons nous empêcher de remarquer la surface de la route, les rochers, les arbres et les nuages. Le côté imprévisible des variations de ces textures pourrait s'apparenter à de l'aléatoire mais elles semblent loin des fonctions aléatoires que nous avons vues juste avant. Le monde est tellement complexe, comment pouvons nous programmer un shader pour nous rapprocher de cette immense variété ? Cette question fut posée à [Ken Perlin](https://mrl.nyu.edu/~perlin/) en 1980 quand il fut missionné pour trouver un moyen de générer des textures plus réalistes pour le film "Tron". Le résultat de ses recherches fut un élégant algorithme de *bruit* qui fut récompensé par un Oscar (rien que ça). Ce qui suit n'est pas l'algorithme de Perlin mais il donne les clés pour comprendre comment générer du *bruit* à partir de valeurs aléatoires. Nous commençons par quelque chose d'assez proche de ce que nous avons fait au chapitre précédent. Nous récupérons les parties entières (```i```) et fractionnelles (```f```) de ```x```. Nous utilisons [```floor()```](.../glossary/?search=floor) pour obtenir ```i``` et [```fract()```](.../glossary/?search=fract) pour obtenir ```f```. Ensuite nous appelons ```rand()``` sur la partie entière de ```x```, ce qui renvoie une valeur unique par entier. Après quoi, vous voyez deux lignes commentées, la première fait une interpolation linéaire entre les deux valeurs ```rand(i)``` et ```rand(i+1)``` ```glsl y = mix(rand(i), rand(i + 1.0), f); ``` Décommentez cette ligne pour voir ce que ça donne. Nous utilisons la partie fractionnelle `f` pour mélanger ([```mix()```](.../glossary/?search=mix)) les deux valeurs aléatoires. Nous savons qu'il existe différentes manières d'interpoler des valeurs entre 0 et 1. Décommentez la ligne suivante qui utilise un [```smoothstep()```](.../glossary/?search=smoothstep) pour calculer l'interpolation au lieu de l'interpolation linéaire. ```glsl y = mix(rand(i), rand(i + 1.0), smoothstep(0.,1.,f)); ``` Vous devriez constater que la transition entre pics est beaucoup plus souple. Dans certaines implémentations, vous verrez que les programmeurs préfèrent parfois coder leur propre fonction cubique (comme la formule suivante) au lieu d'utiliser [```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 ``` Cet *aléatoire lissé* change tout pour les artistes et les designers ; il permet de générer des images au rendu plus naturel. L'algorithme de Perlin a été implémenté dans tous les langages et en plusieurs dimensions pour créer toutes sortes de motifs. A votre tour : * Créez votre propre fonction ```float noise(float x)```. * Utilisez la pour animer une forme sur la scène, la faire pivoter ou la redimensionner. * Faites *danser* plusieurs formes avec cette fonction de *bruit*. * Construisez des formes organiques avec une fonction de bruit. * Une fois que vous avez une *créature*, essayez de la développer en lui donnant des mouvements particuliers. ## Bruit 2D A présent que nous savons faire un bruit sur une dimension, passons à la 2D. En 2D, au lieu d'interpoler entre deux points sur une ligne, (```floor(x)``` et ```floor(x)+1.0```), nous allons interpoler entre les quatre coins d'un carré du plan: ```floor(st)```, ```floor(st)+vec2(1.,0.)```, ```floor(st)+vec2(0.,1.)``` et ```floor(st)+vec2(1.,1.)```. De la même façon que si nous voulons un bruit en 3D, nous devrons créer une interpolation entre les huit coins d'un cube. Cette technique se base sur l'interpolation de valeurs c'est pourquoi on l'appelle **bruit de valeurs** (*value noise*). Comme dans l'exemple à une dimension, nous n'utiliserons pas une interpolation linéaire mais cubique qui nous permettra de lisser les interpolations dans notre grille carrée. Regardez la fonction de bruit suivante : Nous commençons par redimensionner l'espace en le multipliant par 5 (ligne 45), de manière à mieux voir les interpolations de la grille. Ensuite, dans la fonction de bruit, nous subdivisons l'espace en cellules. Nous récupérons les valeurs entières et fractionnelles de la cellule. La valeur entière nous permet de créer les valeurs aléatoires des quatre coins du carré (lines 23-26). Enfin, ligne 35, nous interpolons entre les quatre valeurs aléatoires des coins en utilisant la valeur fractionnelle du fragment dans la cellule. A votre tour, essayez les choses suivantes : * Changez le multiplicateur ligne 45, essayez de l'animer. * A quel niveau de zoom le bruit commence-t'il à ressembler à de l'aléatoire ? * A quel niveau de zoom le bruit devient-il imperceptible ? * Essayez de brancher la souris pour ajuster le niveau de zoom. * Que se passe-t'il si on utilise le dégradé du bruit comme un champ de distances ? Essayez de trouver un usage intéressant. * Maintenant que vous contrôlez un peu mieux l'ordre et le chaos, essayez d'utiliser tout ce que vous savez pour créer une composition de rectangles, de couleurs et bruit ressemblant à une peinture de [Mark Rothko](http://en.wikipedia.org/wiki/Mark_Rothko). ## Utilisation du bruit dans le design génératif Les algorithmes de bruit ont été inventés pour apporter une touche plus naturelle aux textures digitales. Les implémentations 1D et 2D que nous avons vues jusqu'à présent étaient des interpolations entre *valeurs* aléatoires, d'où leur nom de **bruit de valeurs** (*value noise*), mais il existe d'autres manières de créer un bruit... [ ](../edit.php#11/2d-vnoise.frag) Comme vous l'avez découvert dans les exercices précédents, les **bruits de valeurs** (*value noise*) paraissent souvent *crénelés*. Pour atténuer le crénelage, [Ken Perlin](https://mrl.nyu.edu/~perlin/) développe en 1985 une autre implémentation de son algorithme appelée **Bruit de Gradient**. Ken a trouvé comment interpoler des *dégradés* plutôt que des valeurs. Ces dégradés sont le résultat d'une fonction aléatoire 2D qui renvoie une direction (représentée par un ```vec2```) au lieu de renvoyer une valeur de type ```float``` (un chiffre). Cliquez sur le lien ci dessous pour de plus amples informations sur l'algorithme. [ ](../edit.php#11/2d-gnoise.frag) Prenez un moment pour comparer ces deux exemples par [Inigo Quilez](http://www.iquilezles.org/) et soyez attentifs aux différences entre [bruit de valeurs](https://www.shadertoy.com/view/lsf3WH) et [bruit de gradient](https://www.shadertoy.com/view/XdXGW8). Comme un peintre qui comprend comment marchent les pigments, plus vous en saurez sur les différentes implémentations de bruit, mieux vous saurez vous en servir. Par exemple, si on utilise un bruit 2D pour faire pivoter un espace sur lequel on rend des lignes droites, on obtiendra le motif suivant qui ressemble à du bois. Cliquez sur les exemples pour voir à quoi ressemble le code : [ ](../edit.php#11/wood.frag) ```glsl pos = rotate2d( noise(pos) ) * pos; // fait pivoter l'espace pattern = lines(pos,.5); // puis dessine des lignes ``` Une autre approche pour créer des motifs consiste à les considérer comme des *champs de distances* et à leur appliquer différents traitements décrits au [chapitre des formes](../07/?lan=fr). [ ](../edit.php#11/splatter.frag) ```glsl color += smoothstep(.15,.2,noise(st*10.)); // éclaboussure noire color -= smoothstep(.35,.4,noise(st*10.)); // 'trou' dans l'éclaboussure ``` Une troisième approche consiste consiste à moduler une forme. Cela fait également appel aux techniques vues au [chapitre des formes](../07/?lan=fr). Entraînement : * Quel autre motif génératif pouvez vous faire avec du bruit ? Marbre ? Magma ? Eau ? Trouvez des images de textures qui vous intéressent et implémentez les avec du bruit. * Modulez une forme avec du bruit. * Peut-on utiliser du bruit pour donner du mouvement ? Retournez au [chapitre des transformations](../08/?lan=fr). Utilisez l'exemple des translations qui déplace la croix et appliquez lui de l'*aléatoire* et du *bruit*. * Créez un Pollock génératif. ## Bruit simplexe (Simplex Noise) Malgré son succès, Ken Perlin n'était toujours pas satisfait de son algorithme, il pensait qu'il pouvait aller plus vite. Au Siggraph 2001, il présenta le *bruit simplexe* qui lui permit d'apporter les améliorations suivantes: * Un algorithme ayant une complexité computationnelle moindre et moins de multiplications. * Un bruit qui passe aux dimensions supérieures avec un coût computationnel moindre. * Un bruit sans artefacts directionnels. * Un bruit bien défini, avec des dégradés continus et pouvant se calculer à moindre frais. * Un algorithme facile à implémenter matériellement. Je sais ce que vous pensez... "Mais qui est cet homme ?!" Oui, son travail est fantastique ! Mais concrètement, comment a-t'il amélioré l'algorithme ? Bien, nous avons vu comment, pour 2 dimensions, il interpolait entre les valeurs de 4 points (les quatre coins d'un carré). Donc on peut imaginer que pour [trois (voir implémentation ici)](../edit.php#11/3d-noise.frag) et quatre dimensions, nous aurons besoin de 8 et 16 valeurs pour faire nos interpolations. En d'autres mots, pour N dimensions, il nous faudra 2 puissance N (2^N) valeurs à interpoler. Ken a remarqué que, bien qu'on pense immédiatement au carré comme forme de remplissage pour un espace 2D, la forme 2D la plus simple est le triangle équilatéral. Il commença donc à remplacer la grille carrée (dont nous venons de nous servir) par une trame de triangles équilatéraux. La forme [simplexe](https://fr.wikipedia.org/wiki/Simplexe) pour N dimensions est une forme à N + 1 points. Donc pour calculer un bruit à l'aide d'un simplexe 2D, il faut 3 points, pour un bruit simplexe 3D, il en faut 4, et pour un bruit 4D, il en faut 5. en regard des 4 coins du carré, des 8 points du cube et des 16 de l'hypercube, le bénéfice est considérable ! En deux dimensions, l'interpolation se comporte comme dans un bruit *normal*, en interpolant les valeurs des coins d'un cellule. A la différence qu'ici, en utilisant une trame de simplexes, nous devons uniquement interpoler entre 3 valeurs. Comment fabrique-t'on la trame de simplexes? Encore une trouvaille brillante, la trame de simplexes s'obtient en subdivisant les cellules d'une grille carrée en 2 triangles isocèles puis en leur appliquant un **cisaillement** (**skewing**) pour les rendre équilatéraux. Puis, comme [Stefan Gustavson l'explique dans sa publication](http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf) : _"... by looking at the integer parts of the transformed coordinates (x,y) for the point we want to evaluate, we can quickly determine which cell of two simplices that contains the point. By also comparing the magnitudes of x and y, we can determine whether the point is in the upper or the lower simplex, and traverse the correct three corner points."_ Dans le code suivant, vous pouvez décommenter la ligne 44 pour voir comment la grille est *cisaillée* (*skewed*) et la ligne 47 pouvoir comment la trame de simplexes est construite. Notez comment, ligne 22, nous divisons le carré cisaillé en deux triangles équilatéraux en détectant simplement si ```x > y``` (triangle du "bas") ou si ```y > x``` (triangle du "haut"). Une autre amélioration apportée par Perlin avec le **bruit simplexe** est le remplacement de la spline cubique d'Hermite ( _f(x) = 3x^2-2x^3_ , qui est ce que fait un [```smoothstep()```](.../glossary/?search=smoothstep)) par une spline Quintique d'Hermite ( _f(x) = 6x^5-15x^4+10x^3_ ). Ce changement a pour effet de rendre les bords des courbes plus *plats* et permet une sutture invisible entre cellules. Pour voir le principe, décommentez la seconde formule de l'exemple suivant ([ou regardez les 2 équations côte à côte ici](https://www.desmos.com/calculator/2xvlk5xp8b)). Remarquez comme le début et la fin de la courbe changent vers 0 et 1. Vous pouvez [en lire plus sur le site de Ken Perlin](http://mrl.nyu.edu/~perlin/paper445.pdf). Ces améliorations ont conduit à cette *oeuvre d'art* algorithmique qu'est le *bruit simplexe*. Ci-dessous vous trouverez une implémentation de cet algorithm par Ian McEwan (décrite dans [cette publication](http://webstaff.itn.liu.se/~stegu/jgt2012/article.pdf)) qui sera peut-être un peu difficile d'accès mais qui vous permettra de réaliser qu'au fond c'est moins compliqué qu'il n'y paraît. [ ](../edit.php#11/2d-snoise-clear.frag) Bon... assez parlé technique, il est temps d'utiliser cette ressource de façon créative : * Observez chaque implémentation du bruit, imaginez que ce sont des matériaux bruts, comme un bloc de marbre pour un sculpteur. Que pouvez-vous dire de l'impression que chacun "dégage" ? Plissez les yeux pour vous aider, comme quand vous regardez les nuages. Que voyez vous ? Qu'est ce que ça vous rappelle ? Quelles utilisations potentielles voyez vous pour chaque type de bruit ? Essayez de concrétiser ces idées. * Créez un shader qui donne l'illusion d'un flux ; une lava-lamp, des goutes d'encre, de l'eau, etc. * Utilisez le bruit simplexe pour texturer un de vos exercices précédents : Dans ce chapitre, nous avons appris à contrôler le chaos et ce n'était pas chose aisée ! Devenir **Maître du Bruit** demande temps et énergie. Dans les chapitre suivants, nous verrons d'autres techniques pour perfectionner vos talents et obtenir le maximum de vos fonctions de bruit pour enrichir vos shaders. D'ici là, prenez le temps de contempler la nature et les motifs qu'elle vous offre. La capacité d'observation est au moins aussi importante (sinon plus) que la capacité de recréer ces motifs. Sortez et profitez du reste de votre journée !"Parler à l'arbre, s'en faire un ami." Bob Ross
--- ### 11/README Id (11/README-id.md) ## 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. 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.) Berikut ini bukanlah algoritma derau Perlin klasik, tetapi ini adalah titik awal yang baik untuk memahami cara menghasilkan derau. 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. 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 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.)``` /* Detailed source-code truncated for AI context efficiency. */ ```vec2```), bukan nilai tunggal (```float```). Klik pada gambar berikut untuk melihat kode dan cara kerjanya. [ ](../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. [ ](../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/). [ ](../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 /). 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. ## 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()``` /* Detailed source-code truncated for AI context efficiency. */ ```x > y``` (segitiga "bawah ") atau````y > x``` (segitiga "atas"). 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. [ ](../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. * Gunakan Simplex Noise untuk menambahkan tekstur pada karya yang telah Anda buat. 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!"Bicaralah dengan pohon, bertemanlah dengannya." Bob Ross
--- ### 11/README It (11/README-it.md) ## Rumore È tempo di fare una pausa! Abbiamo giocato con le funzioni random che sembrano creare del rumore bianco di una televisione, la testa ci gira ancora solo al pensiero degli shader e i nostri occhi sono stanchi. È ora di andare a fare una passeggiata! Sentiamo l'aria sulla nostra pelle, il sole in faccia. Il mondo è un posto così vivido e ricco: colori, texture, suoni. Mentre camminiamo, non possiamo evitare di notare la superficie delle strade, rocce, alberi e nuvole. L'imprevedibilità di queste texture potrebbe essere intesa come "random", ma non sembrano di certo il risultato delle funzioni random che abbiamo sperimentato in precedenza. Il "mondo reale" è un posto così ricco e complesso! Come possiamo approssimare questa varietà computazionale? Questa è stata la domanda che [Ken Perlin](https://mrl.nyu.edu/~perlin/) stava cercando di risolvere nei prima anni '80 quando gli fu commissionato di generare delle texture più realistiche per il film "Tron". Il risultato delle sue ricerche fu un elegante algoritmo di rumore *vincitore del premio Oscar*. (Non disperatevi.) Quanto segue non è il classico algoritmo di Perlin, ma è un buon punto di partenza per capire come generare del rumore. In queste righe stiamo facendo qualcosa di simile a quello che abbiamo fatto nel capitolo precedente. Stiamo suddividendo un numero floating continuo (```x```) nel suo intero (```i```) e nelle componenti frazionarie (```f```). Usiamo [```floor()```](../glossary/?search=floor) per ottenere ```i``` e [```fract()```](../glossary/?search=fract) per ottenere ```f```. Poi applichiamo ```rand()``` per la parte intera di ```x```, che dà un valore random unico a ogni integer. Dopo di che si osservino le due righe commentate. La prima interpola ogni valore random in modo lineare. ```glsl y = mix(rand(i), rand(i + 1.0), f); ``` Andate avanti e rimuovete il commento di questa linea per vedere che cosa succede. Utilizziamo la parte frazionale `f` per mischiare ([```mix()```](../glossary/?search=mix)) i due valori random. A questo punto del libro, abbiamo imparato che possiamo fare meglio d'una interpolazione lineare, giusto? Ora provate a decommentare la riga seguente, che utilizza una interpolazione [```smoothstep()```](../glossary/?search=smoothstep) invece di una lineare. ```glsl y = mix(rand(i), rand(i + 1.0), smoothstep(0.,1.,f)); ``` Tolto il commento, si noti che la transizione tra i picchi diventa armoniosa. In alcune implementazioni del rumore, troverete che i programmatori preferiscono creare le proprie curve cubiche (come la seguente formula) invece di utilizzare la funzione [```smoothstep()```](../glossary/?search=smoothstep). ```glsl float u = f * f * (3.0 - 2.0 * f ); // curva cubica personalizzata y = mix(rand(i), rand(i + 1.0), u); // e con un'interpolazione ``` Questo *casualità armoniosa* è un punto di svolta per gli ingegneri grafici o artisti perché fornisce la capacità di generare delle immagini e delle geometrie con un tocco organico. L'Algoritmo del Rumore di Perlin è stato implementato più e più volte in diversi linguaggi e spazio dimensionale per ottenere ogni tipo di uso creativo. Ora è il vostro turno: * Create la vostra funzione ```float noise(float x)```. * Utilizzate la funzione di rumore per animare una forma geometrica spostandola, ruotandola o ridimensionandola. * Fate 'ballare' diverse forme geometriche usando il rumore. * Costruite forme "organiche" utilizzando la funzione di rumore. * Una volta che avete la vostra "creatura", cercate di svilupparla ulteriormente assegnandogli un particolare movimento. ## Rumore 2D Ora che sappiamo come creare il rumore in una dimensione, è il momento di passare alla 2D. Nelle due dimensioni, invece di interpolare tra due punti di una linea (```fract(x)``` e ```fract(x)+1.0```), interpoleremo tra i quattro angoli di un piano quadrato (```fract(st)```, ```fract(st)+vec2(1.,0.)```, ```fract(st)+vec2(0.,1.)``` e ```fract(st)+vec2(1.,1.)```). Allo stesso modo, se si vuole ottenere del rumore 3D dobbiamo interpolare tra gli otto angoli di un cubo. Questa tecnica consiste nell'interpolazione di valori random, che è il motivo per cui si chiama **rumore del valore** (**value noise**) . Come per l'esempio 1D, questa interpolazione non è lineare, ma cubica, e interpola senza problemi tutti i punti all'interno di una griglia quadrata. Date un'occhiata alla seguente funzione di rumore. Iniziamo scalando lo spazio di 5 (linea 45) per vedere l'interpolazione tra i quadrati della griglia. Poi all'interno della funzione rumore suddividiamo lo spazio in celle. Memorizziamo la posizione "integer" della cella insieme alle posizioni frazionarie all'interno della cella. Usiamo la posizione dell'integer per calcolare le coordinate dei quattro angoli e ottenere un valore random per ciascuno di essi (linee 23-26). Infine, alla linea 35 interpoliamo tra i 4 valori random degli angoli utilizzando le posizioni frazionarie che abbiamo ricavato in precedenza. Ora è il vostro turno. Provate i seguenti esercizi: * Cambiate il moltiplicatore alla linea 45. Provate ad animarlo. * A quale livello di zoom il rumore comincia a sembrare di nuovo random? * A che livello di zoom il rumore è impercettibile? * Provate a collegare questa funzione rumore alle coordinate del mouse. * Che cosa succede se utilizziamo il gradiente del rumore come un campo di distanza? Fatene qualcosa di interessante. * Ora che avete raggiunto un certo controllo sull'ordine e il caos, è il momento di utilizzare tale conoscenza. Effettuate una composizione di rettangoli, colori e rumore che assomiglia a un dipinto di [Mark Rothko](https://it.wikipedia.org/wiki/Mark_Rothko). ## Usare il Rumore nella Progettazione Generativa Gli algoritmi di rumore sono stati originariamente progettati per dare un naturale *je ne sais quoi* alle texture digitali. Le implementazioni 1D e 2D che abbiamo visto fino ad ora erano interpolazioni tra *valori random*, che è il motivo per cui sono chiamate **valore di rumore**, ma ci sono altri modi per ottenere il rumore... [ ](../edit.php#11/2d-vnoise.frag) Come avete scoperto negli esercizi precedenti, il valore del rumore tende a sembrare a dei "blocchi". Per ridurre questo effetto, nel 1985 [Ken Perlin](https://mrl.nyu.edu/~perlin/) ha sviluppato un'altra implementazione dell'algoritmo denominato **Rumore di Gradiente** (**Gradient Noise**). Ken aveva capito come interpolare dei *gradienti* random invece che dei valori. Questi gradienti sono stati il risultato d'una funzione random 2D che restituisce le direzioni (rappresentata da un ```vec2```) al posto di singoli valori (```float```). Clicca sull'immagine seguente per vedere il codice e come funziona. [ ](../edit.php#11/2d-gnoise.frag) Guardate questi due esempi di [Inigo Quilez](http://www.iquilezles.org/) e prestate attenzione alle differenze tra il [valore del rumore](https://www.shadertoy.com/view/lsf3WH) e il [gradiente del rumore](https://www.shadertoy.com/view/XdXGW8). Come un pittore che capisce come i pigmenti funzionano, più sappiamo sulle varie implementazioni del rumore e meglio saremo in grado di usarle. Ad esempio, se si usa un'implementazione del rumore in due dimensioni per ruotare lo spazio in cui sono visualizzate delle linee rette, otterremo il seguente effetto visuale che sembra del legno. Anche in questo caso è possibile fare clic sull'immagine per vedere il codice. [ ](../edit.php#11/wood.frag) ```glsl pos = rotate2d( noise(pos) ) * pos; // ruota lo spazio pattern = lines(pos,.5); // disegna delle linee ``` Un altro modo per ottenere dal rumore dei pattern interessanti è quello di trattarlo come un campo di distanza e applicare alcuni dei trucchi descritti nel [capitolo sulle Figure](../07/). [ ](../edit.php#11/splatter.frag) ```glsl color += smoothstep(.15,.2,noise(st*10.)); // schizzo nero color -= smoothstep(.35,.4,noise(st*10.)); // buchi sugli schizzi ``` Un terzo modo di utilizzare la funzione di rumore è di modulare una forma. Questo richiede anche alcune delle tecniche che abbiamo imparato nel [capitolo sulle figure](../07/). Per la vostra pratica: * Quali altri pattern generativi si possono fare? Che dire del granito? marmo? magma? acqua? Trovate tre immagini di texture di vostro interesse e come poterle realizzare algoritmicamente usando il rumore. * Utilizzate il rumore per modulare una forma. * Cosa succede se usate il rumore per il movimento? Tornate al [capitolo sulle Matrici](../08/). Utilizzate l'esempio per traslare il "+", e applicateci alcuni movimenti *random* e derivati dal *rumore*. * Fate un dipinto generativo alla Jackson Pollock. ## Rumore Simplesso Per Ken Perlin il successo del suo algoritmo non è stato sufficiente. Ha pensato che avrebbe potuto funzionare meglio. Al Siggraph 2001 ha presentato il "rumore simplesso", in cui ha ottenuto i seguenti miglioramenti rispetto al precedente algoritmo: * Un algoritmo con una minore complessità computazionale e un minor numero di moltiplicazioni. * Un rumore in grado di scalare a dimensioni superiori con meno costo computazionale. * Un rumore senza artefatti direzionali. * Un rumore con gradienti ben definiti e continui che possono essere calcolati abbastanza facilmente. * Un algoritmo che è facile da implementare sull'hardware. So cosa state pensando... "Chi è costui?" Sì, il suo lavoro è fantastico! Ma sul serio, come ha fatto a migliorare l'algoritmo? Beh, abbiamo visto come per le due dimensioni ha interpolato 4 punti (angoli di un quadrato); allo stesso modo possiamo indovinare che per [tre (vedi un'implementazione qui)](../edit.php#11/3d-noise.frag) e quattro dimensioni abbiamo bisogno di interpolare rispettivamente 8 e 16 punti. Giusto? In altre parole per N dimensioni è necessario interpolare agevolmente dai 2 agli N punti(2^N). Ma Ken ha elegantemente notato che, anche se il quadrato è la scelta ovvia per riempire lo spazio, la figura più semplice in 2D è il triangolo equilatero. Così ha iniziato a sostituire la griglia quadrata (abbiamo appena appreso come usarla) per una griglia simplessa di triangoli equilateri. La figura simplessa per N dimensioni è una figura con N + 1 angoli. In altre parole, un angolo in meno da calcolare in 2D, 4 in meno in 3D e 11 in meno in 4D! Questo è un enorme miglioramento! In due dimensioni l'interpolazione avviene in modo simile al rumore regolare, interpolando i valori degli angoli di una sezione. Ma in questo caso, utilizzando una griglia simplessa, abbiamo solo bisogno di interpolare la somma di 3 angoli. Come è fatta la griglia simplessa? Con un'altra mossa brillante ed elegante, la griglia simplessa può essere ottenuta suddividendo le celle di una regolare griglia a 4 angoli in due triangoli isosceli e poi distorcendola finché ogni triangolo sia equilatero. Poi, come [Stefan Gustavson descrive in questo articolo](http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf): _".. cercando le parti intere delle coordinate trasformate (x,y) per il punto che vogliamo valutare, siamo in grado di determinare rapidamente quale cella di due simplessi contiene il punto. Confrontando anche le grandezze di x e y, siamo in grado di determinare se il punto è nel simplesso più alto o più basso, e percorrere i tre punti d'angolo corretti."_ Nel seguente codice è possibile rimuovere il commento alla linea 44 per vedere come la griglia è distorta, e poi rimuovere il commento alla linea 47 per vedere come una griglia simplessa può essere costruita. Notate come alla linea 22 stiamo suddividendo il quadrato distorto in due triangoli equilateri semplicemente controllando se ```x > y``` (triangolo "inferiore") oppure ```y > x``` (triangolo "superiore"). Un altro miglioramento introdotto da Perlin con il **Rumore Simplesso**, è la sostituzione della Curva Cubica di Hermite ( _f(x) = 3x^2-2x^3_ , che è identica alla funzione [```smoothstep()```](../glossary/?search=smoothstep) ) con una Curva Quintica di Hermite ( _f(x) = 6x^5-15x^4+10x^3_ ). In questo modo entrambe le estremità della curva sono più "piatte" così che ogni limite si unisce con grazia con quello successivo. In altre parole si ottiene una transizione più continua tra le celle. Si può osservare ciò decommentando la seconda formula nel seguente esempio grafico (o osservando le [due equazioni fianco a fianco cliccando qui](https://www.desmos.com/calculator/2xvlk5xp8b)). Si noti come le estremità della curva cambino. Si può leggere di più a proposito [sul sito di Ken](http://mrl.nyu.edu/~perlin/paper445.pdf). Tutti questi miglioramenti si traducono in un capolavoro algoritmico noto come **Rumore Simplesso**. La seguente è una implementazione GLSL di questo algoritmo fatta da Ian McEwan(e presentato in [questo articolo](http://webstaff.itn.liu.se/~stegu/jgt2012/article.pdf)) che è troppo complicata per scopi didattici, ma sarete felici di fare un clic su di esso e vedere che è meno criptica di quanto si possa pensare. [ ](../edit.php#11/2d-snoise-clear.frag) Beh... direi che abbiamo avuto abbastanza tecnicismi, è il momento d'utilizzare queste risorse in modo creativo: * Osservate ogni implementazione del rumore. Immaginatele come delle materie grezze, come delle rocce di marmo per uno scultore. Che cosa si può dire a proposito delle "sensazione" che ci trasmettono? Chiudete gli occhi per far scattare la vostra immaginazione, come quando si cercano delle forme in una nuvola. Cosa vedi? Cosa ricorderai? Che cosa si potrebbe creare da ogni implementazione del rumore? Seguite le vostre ispirazioni e cercate di realizzarle con il codice. * Fate uno shader che crea l'illusione di un flusso. Come una lampada di lava, gocce d'inchiostro, dell'acqua, ecc. * Utilizzate il rumore simplesso per aggiungere delle texture a dei lavori precedenti. In questo capitolo abbiamo preso controllo sul caos. Non è stato un lavoro facile! Diventare un maestro del rumore richiede tempo e impegno. Nei capitoli seguenti vedremo alcune tecniche ben note per perfezionare le proprie competenze e ottenere di più dal vostro rumore per progettare del contenuto generativo di qualità. Fino ad allora godetevi un po' di tempo all'aria aperta, contemplate la natura e i suoi pattern complicati. La capacità d'osservazione è altrettanto importante (se non di più) rispetto a quella di creare dei pattern. Andate fuori e godetevi il resto della giornata!"Parla con l'albero, per farsi un amico." Bob Ross
--- ### 11/README Pl (11/README-pl.md) ## Noise (pol. "szum") Czas na przerwę! Bawiliśmy się losowymi funkcjami, które wyglądają jak szum telewizyjny (tzw. "szum biały", ang. "white noise"), w głowie wciąż się kręci od myślenia o shaderach, a oczy są po prostu zmęczone. Czas wyjść na spacer! Czujemy powietrze na skórze, słońce na twarzy. Świat jest tak żywym i bogatym miejscem. Kolory, tekstury, dźwięki. Podczas spaceru widzimy powierzchnię dróg, skał, drzew i chmur. Nieprzewidywalność tych tekstur można by nazwać "losową", ale nie przypominają one losowości, z którą bawiliśmy się wcześniej. "Prawdziwy świat" jest tak bogatym i złożonym miejscem! Jak możemy zamodelować tę różnorodność obliczeniowo? To było pytanie, które [Ken Perlin](https://mrl.nyu.edu/~perlin/) próbował rozwiązać we wczesnych latach 80-tych, kiedy otrzymał zlecenie wygenerowania bardziej realistycznych tekstur do filmu "Tron". W odpowiedzi na to wymyślił elegancki algorytm szumu, za który później otrzymał Oskara. Poniższy kod nie jest klasycznym algorytmem szumu Perlina, ale jest dobrym punktem wyjścia do zrozumienia sposobu generowania szumu. W tych liniach robimy coś podobnego do tego, co robiliśmy w poprzednim rozdziale. Dzielimy ciągłą liczbę zmiennoprzecinkową (``x``) na jej składowe całkowitą (``i``) i ułamkową (``f``). Używamy [``floor()``](../glossary/?search=floor) aby uzyskać ``i`` oraz [``fract()``](../glossary/?search=fract) aby uzyskać ``f``. Następnie stosujemy ``rand()`` do części całkowitej ``x``, co daje unikalną wartość losową dla każdej liczby całkowitej. Spójrz na dwie skomentowane linie. Pierwsza z nich interpoluje liniowo każdą wartość losową. ```glsl y = mix(rand(i), rand(i + 1.0), f); ``` Odkomentuj tę linię, aby zobaczyć jak to wygląda. Używamy `f` do interpolacji liniowej dwóch sąsiadujących wartości losowych za pomocą funkcji [``mix()``](../glossary/?search=mix). Nauczyliśmy się, że możemy zrobić coś lepszego niż interpolacja liniowa, prawda? Spróbuj teraz odkomentować kolejną drugą linię, która używa interpolacji [``smoothstep()``](../glossary/?search=smoothstep) zamiast liniowej. ```glsl y = mix(rand(i), rand(i + 1.0), smoothstep(0.,1.,f)); ``` Po odkomentowaniu zauważ, jak przejście między szczytami staje się gładkie. W niektórych implementacjach szumu można zauważyć, że programiści wolą kodować własne krzywe sześcienne (ang. "cubic curves") (jak w kodzie poniżej) zamiast używać [``smoothstep()``](../glossary/?search=smoothstep). ```glsl float u = f * f * (3.0 - 2.0 * f ); // spersonalizowana funkcja sześcienna y = mix(rand(i), rand(i + 1.0), u); // interpolacja z jej pomocą ``` Ta *płynna losowość* jest przełomem dla programistów grafiki i artystów - daje możliwość generowania organicznych obrazów i geometrii. Algorytm Szumu Perlina był wielokrotnie implementowany w różnych językach i wymiarach, aby móc tworzyć hipnotyzujące dzieła w celach kreatywnych. Teraz twoja kolej: * Stwórz własną funkcję ``float noise(float x)``. * Użyj swojej funkcji szumu do animowania kształtu poprzez przesuwanie go, obracanie lub skalowanie. * Zrób animowaną kompozycję kilku kształtów "tańczących" razem przy użyciu szumu. * Skonstruuj "organicznie wyglądające" kształty używając funkcji noise. ## Szum 2D Teraz, gdy wiemy jak zrobić szum w 1D, czas przejść do 2D. W 2D zamiast interpolować między dwoma punktami linii (``rand(x)`` i ``rand(x)+1.0``), będziemy interpolować pomiędzy czterema narożnikami kwadratowego obszaru płaszczyzny (``rand(st)``, ``rand(st)+vec2(1.,0.)``, ``rand(st)+vec2(0.,1.)`` oraz ``rand(st)+vec2(1.,1.)``). Podobnie, jeśli chcemy uzyskać szum 3D musimy interpolować pomiędzy ośmioma rogami sześcianu. W tej technice chodzi o interpolację losowych wartości ang. (ang. "random **value**s"), dlatego nazywa się ją **value noise**. Podobnie jak w przykładzie 1D, interpolacja ta nie jest liniowa, ale sześcienna, więc płynnie interpoluje wszelkie punkty wewnątrz naszego kwadratowego obszaru. Przyjrzyj się następującej funkcji szumu. Zaczynamy od przeskalowania przestrzeni o 5 (linia 45). Następnie wewnątrz funkcji szumu dzielimy przestrzeń na kafellki. Przechowujemy pozycję kafelka jako cześć całkowitą oraz pozycje wewnątrz kafelka jako część ułamkową. Używamy części całkowitej do obliczenia współrzędnych czterech narożników, otrzymując losową wartość dla każdego z nich (linie 23-26). Na koniec, w linii 35 interpolujemy pomiędzy 4 losowymi wartościami narożników używając części ułamkowej. Teraz twoja kolej. Spróbuj wykonać następujące ćwiczenia: * Zmień mnożnik w linii 45. Spróbuj go zanimować. * Przy jakim poziomie powiększenia szum zaczyna znowu wyglądać kompletnie losowo (jak, wspomniany na początku rozdziału, biały szum)? * Przy jakim poziomie powiększenia szum jest niezauważalny? * Spróbuj podpiąć tę funkcję szumu do współrzędnych myszy. * A gdyby tak potraktować gradient szumu jako pole odległości? Zrób z tym coś ciekawego. * Teraz, gdy osiągnąłeś już pewną kontrolę nad porządkiem i chaosem, czas wykorzystać tę wiedzę. Stwórz kompozycję z prostokątów, kolorów i szumu, która przypomina nieco złożoność obrazu [Marka Rothko](http://en.wikipedia.org/wiki/Mark_Rothko). ## Szum a design generatywny Algorytmy szumu zostały pierwotnie zaprojektowane w celu nadania naturalnego *je ne sais quoi* cyfrowym teksturom. Implementacje 1D i 2D, które widzieliśmy do tej pory, były interpolacjami pomiędzy losowymi *wartościami*, dlatego nazywane są **Value Noise**, ale istnieje więcej sposobów na uzyskanie szumu... [ ](../edit.php#11/2d-vnoise.frag) Jak odkryłeś w poprzednich ćwiczeniach, value noise ma tendencję do wyglądania "blokowo". Aby zmniejszyć ten blokowy efekt, w 1985 roku [Ken Perlin](https://mrl.nyu.edu/~perlin/) opracował inną implementację algorytmu o nazwie **Gradient Noise**. Ken wymyślił jak interpolować losowe *gradienty* zamiast wartości. Gradienty te były wynikiem funkcji losowej 2D, która zwraca kierunki (reprezentowane przez ``vec2``) zamiast pojedynczych wartości (``float``). Kliknij na poniższy obrazek, aby zobaczyć kod i sposób jego działania. [ ](../edit.php#11/2d-gnoise.frag) Poświęć chwilę na przyjrzenie się tym dwóm przykładom autorstwa [Inigo Quilez](http://www.iquilezles.org/) i zwróć uwagę na różnice pomiędzy [value noise](https://www.shadertoy.com/view/lsf3WH) a [gradient noise](https://www.shadertoy.com/view/XdXGW8). Podobnie jak malarz, który rozumie, jak działają pigmenty jego farb, im więcej wiemy o implementacjach szumu, tym lepiej będziemy mogli z nich korzystać. Na przykład, jeśli użyjemy dwuwymiarowej implementacji szumu do obrócenia przestrzeni, w której renderowane są linie proste, możemy uzyskać następujący drewno-podobny efekt. Ponownie możesz kliknąć na obrazek, aby zobaczyć, jak wygląda kod. [ ](../edit.php#11/wood.frag) ```glsl pos = rotate2d( noise(pos) ) * pos; // obracanie przestrzeni pattern = lines(pos,.5); // rysowanie linii ``` Innym sposobem na uzyskanie ciekawych wzorów z szumu jest potraktowanie go jak pola odległości i zastosowanie niektórych sztuczek opisanych w rozdziale [Kształty](../07/). [ ](../edit.php#11/splatter.frag) ```glsl color += smoothstep(.15,.2,noise(st*10.)); // Czarny rozprysk color -= smoothstep(.35,.4,noise(st*10.)); // Dziury w rozprysku ``` Trzecim sposobem wykorzystania funkcji szumu jest modulowanie kształtu. To również wymaga pewnych technik, które poznaliśmy w [rozdziale o kształtach](../07/). Do poćwiczenia: * Jaki inny wzór generatywny możesz stworzyć? Co z granitem? marmurem? magmą? wodą? Znajdź trzy zdjęcia interesujących Cię tekstur i zaimplementuj je algorytmicznie za pomocą szumu. * Użyj szumu do modulacji kształtu. * A co z wykorzystaniem szumu do ruchu? Wróć do rozdziału [Macierze](../08/). Użyj przykładu z translacją kształtu "+" i zastosuj do niego kilka *losowych* i *szumowych* ruchów. * Zrób generatywnego Jacksona Pollocka. ## Lepszy szum Ulepszenie oryginalnego szumu Perlina, zwane **Simplex Noise**, polega na zastąpieniu sześciennej krzywej Hermite'a ( _f(x) = 3x^2-2x^3_ , która jest identyczna z funkcją [``smoothstep()``](../glossary/?search=smoothstep)) kwintową krzywą interpolacyjną ( _f(x) = 6x^5-15x^4+10x^3_ ). Dzięki temu oba końce krzywej są bardziej "płaskie", więc każda granica z wdziękiem zszywa się z następną. Innymi słowy, otrzymujesz bardziej ciągłe przejście między komórkami. Możesz to zobaczyć, odkomentowując drugą formułę w poniższym przykładzie wykresu (lub zobacz [dwa równania obok siebie tutaj](https://www.desmos.com/calculator/2xvlk5xp8b)). Zauważ, jak zmieniają się końce krzywej. Więcej na ten temat możesz usłyszeć [z ust Kena Perlina](http://mrl.nyu.edu/~perlin/paper445.pdf). ## Simplex Noise Dla Kena Perlina sukces jego algorytmu nie był wystarczający. Uważał, że może on działać lepiej. Na Siggraph 2001 zaprezentował "simplex noise", w którym osiągnął następujące ulepszenia w stosunku do poprzedniego algorytmu: * Algorytm o mniejszej złożoności obliczeniowej i mniejszej liczbie mnożeń. * Szum, który skaluje się do wyższych wymiarów przy mniejszym koszcie obliczeniowym. * Szum bez artefaktów kierunkowych. * Szum z dobrze zdefiniowanymi i ciągłymi gradientami, o niskim koszcie obliczeniowym. * Algorytm, który jest łatwy do zaimplementowania w hardware'rze. Wiem, co myślisz... "Kim jest ten człowiek?" Tak, jego praca jest fantastyczna! Ale poważnie, w jaki sposób ulepszył ten algorytm? Cóż, widzieliśmy jak dla dwóch wymiarów interpolował 4 punkty (rogi kwadratu); możemy więc poprawnie zgadnąć, że dla [trzech (zobacz implementację tutaj)](../edit.php#11/3d-noise.frag) i czterech wymiarów musimy interpolować 8 i 16 punktów. Prawda? Innymi słowy dla N wymiarów musisz płynnie interpolować 2 do N punktów (2^N). Ale Ken sprytnie zauważył, że chociaż oczywistym wyborem dla kształtu wypełniającego przestrzeń jest kwadrat, najprostszym kształtem w 2D jest trójkąt równoboczny. Zaczął więc od zastąpienia siatki kwadratowej (niedawno nauczyliśmy się jej używać) siatką trójkątów równobocznych (inaczej zwaną *siatką sympleksową*). Kształt dla N wymiarów to kształt z N + 1 wierzchołkami. Innymi słowy jeden wierzchołek mniej do obliczenia w 2D, 4 wierzchołki mniej w 3D i 11 wierzchołków mniej w 4D! To ogromna poprawa! W dwóch wymiarach interpolacja odbywa się podobnie do zwykłego szumu, poprzez interpolację wartości wierzchołków odcinka. Ale w tym przypadku, dzięki zastosowaniu siatki sympleksowej, musimy tylko interpolować sumę 3 wierzchołków. Jak powstaje siatka sympleksowa? W kolejnym błyskotliwym i eleganckim posunięciu, można ją uzyskać poprzez podział kwadratowych kafelków na dwa trójkąty równoramienne, a następnie przekrzywienia ich, aż każdy trójkąt będzie równoboczny. Proces ten szerzej opisany jest w [artykule Stefana Gustavsona](http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf). W poniższym kodzie możesz odkomentować linię 44, aby zobaczyć jak siatka jest przekrzywiona, a następnie odkomentować linię 47, aby zobaczyć siatkę simpleksową. Zauważ jak w linii 22 dzielimy przekrzywiony kwadrat na dwa trójkąty równoboczne poprzez wykrycie czy ``x > y`` (dolny" trójkąt) lub ``y > x`` (górny" trójkąt). Wszystkie te ulepszenia skutkują algorytmicznym arcydziełem, jakim jest **Simplex Noise**. Poniżej znajduje się implementacja GLSL tego algorytmu wykonana przez Iana McEwana i Stefana Gustavsona (i przedstawiona w [tym artykule](http://webstaff.itn.liu.se/~stegu/jgt2012/article.pdf)), która w celach edukacyjnych jest nadmiernie skomplikowana , ale przekonasz się, że jest też mniej enigmatyczna niż można by się spodziewać, a kod jest krótki i szybki. [ ](../edit.php#11/2d-snoise-clear.frag) Cóż... dość technicznych rozważań, czas na wykorzystanie tego narzędzia we własny, ekspresyjny sposób: * Kontempluj, jak wygląda każda implementacja szumu. Wyobraź sobie je jako surowy materiał, jak marmurowy kamień dla rzeźbiarza. Co możesz powiedzieć o "uczuciu", jakie ma każda z nich? Zmruż oczy, aby uruchomić wyobraźnię, tak jak wtedy, gdy chcesz znaleźć kształty w chmurze. Co widzisz? Co ci się przypomina? W co każda implementacja szumu mogłaby zostać przeobrażana? Podążając za swoją intuicją, spróbuj zrealizować to w kodzie. * Zrób shader, który tworzy iluzję przepływu. Jak lampa lawowa, krople atramentu, woda itp. * Użyj Simplex Noise, aby dodać trochę tekstury do pracy, którą już wykonałeś. W tym rozdziale wprowadziliśmy pewną kontrolę nad chaosem. Nie była to łatwa praca! Zostanie zaklinaczem chaosu wymaga czasu i wysiłku. W następnych rozdziałach zobaczymy kilka dobrze znanych technik, które pozwolą ci udoskonalić swoje umiejętności i wydobyć więcej z szumu, aby zaprojektować wysokiej jakości generatywne dzieła za pomocą shaderów. Do tego czasu ciesz się czasem na zewnątrz, kontemplując naturę i jej zawiłe wzory. Twoja umiejętność obserwacji wymaga równego (a może nawet większego) poświęcenia niż twoje umiejętności tworzenia. Wyjdź na zewnątrz i ciesz się resztą dnia!"Talk to the tree, make friends with it." Bob Ross
--- ### 11/README Pt (11/README-pt.md) ## Noise (Ruído) Chegou a hora de um intervalo! Nós estamos explorando todas essas funções de aleatório que se parecem com ruído branco de TV, nossa cabeça ainda está rodando pensando em shaders, nossos olhos estão cansados. Hora de dar uma volta! Nós sentimos o ar em nossa pele, o sol em nosso rosto. O mundo é um lugar vívido e rico. Cores, texturas, sons. Enquanto nós caminhamos, nós não conseguimos evitar perceber a superfície das estradas, das pedras, árvores e nuvens. A imprevisibilidade dessas texturas podem ser chamadas de "aleatório", mas elas não se parecem com o mesmo aleatório que estávamos explorando antes. O "mundo real" é um lugar tão rico e complexo! Como podemos aproximar computacionalmente essa variedade. Essa é o mistério que [Ken Perlin](https://mrl.nyu.edu/~perlin/) tentava resolver nos começo dos anos 80, quando ele foi contratado para gerar texturas mais realistas para o filme "Tron". Em resposta a isso, ele criou um elegante algoritmo *Vencedor de Oscar* de Noise (Ruído). O que vem a seguir não é o algoritmo clássico de Perlin Noise, mas é um bom ponto de partida para entender como gerar ruído. Nessas linhas, nós estamos fazendo algo similar com o que nós fizemos no capítulo anterior. Estamos subdividindo um número flutuante contínuo (```x```) nos componentes: inteiro (```i```) e um fracionária (```f```). Nós usamos [```floor```](../glossary/?search=floor) para obter ```f```. Então nós aplicamos ```rand()``` na parte inteira de ```x```, que nos retorna um valor aleatório único para cada inteiro. Após isso, você vê duas linhas comentadas. A primeira interpola cada valor aleatório de forma linear. ```glsl y = mix(rand(i), rand(i + 1.0), f); ``` Vá em frente e descomente estas linhas para ver o resultado. Nós usamos o valor [```fract()```](../glossary/?search=fract) armazenado em `f` para [```mix()```](../glossary/?search=mix) (interpolar) os dois valores aleatórios. A esta altura do livro, nós já aprendemos que podemos fazemos melhor que apenas uma interpolação linear, certo? Agora, experimente descomentar a linha seguinte, que usa uma interpolação de [```smoothstep()```](../glossary/?search=smoothstep) em vez de uma linear. ```glsl y = mix(rand(i), rand(i + 1.0), smoothstep(0.,1.,f)); ``` Depois de descomentá-la, perceba como a transição entre os picos se suaviza. Em algumas implementações de noise, você perceberá que os programadores preferem escrever as próprias curvas cúbicas (como esta na fórmula seguinte) em vez de usar [```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 ``` Esta *suavização alatória* é um divisor de águas para engenheiros gráficos ou artistas - ela nos proporciona a habilidade de gerar imagens e geometria com um sentimento orgânico. O algoritmo de Perlin Noise foi implementado repetidas vezes em diversas linguagens e dimensões para criar peças hipnotizantes para todos os tipos de uso criativo. Agora é a sua vez: * Faça sua própria função ```float noise(float x)```. * Use sua função de Noise para animar uma forma se movendo, rotacioná-la ou alterar sua escala. * Faça uma composição animada com múltiplas formas 'dançando' juntas utilizando noise. * Construa uma forma de aparência "orgânica" utilizando a função de noise. * Depois de conceber sua "criatura", tente ir além em transformá-la em um personagem ao atribuí-la um movimento próprio. ## Noise 2D Agora que nós sabemos como fazer Noise em 1D, está na hora de partirmos para 2D. Em 2D, em vez de interpolar entre dois pontos de uma linha (```fract(x)``` e ```fract(x)+1.0```), nós vamos interpolar entre quatro vértices de uma área quadrada de um plano (```fract(st)```, ```fract(st)+vec2(1.,0.)```, ```fract(st)+vec2(0.,1.)``` e ```fract(st)+vec2(1.,1.)```). Analogicamente, se nós quisermos obter um ruído 3D, nós precisamos interpolá-lo entre os oito vértices do cubo. Esta técnica é tudo uma questão de interpolar valores, por isso é chamada **Ruído de Valor**. Como no exemplo 1D, esta interpolação não é linear, mas cúbica, na qual suavemente se interpola qualquer ponto dentro de nossa grade quadrada. Dê uma olhada na seguinte função noise. Nós começamos alterando a escala do espaço por 5 para que se possa ver a interpolação entre os quadrados da grade. Então, dentro da função noise, nós subdividimos o espaço em células. Nós armazenamos a posição inteira ao longo da célula com a posição fracionária de dentro da célula. Nós usamos a posição inteira para calcular as quatro coordenadas dos cantos e obtemos um valor aleatório para cada uma (linhas 23-26). Por último, na linha 35, interpolamos entre os 4 valores aleatórios dos cantos usando a posição fracionária que armazenamos antes. Agora é a sua vez. Tente os seguintes exercícios: * Mude o multiplicador na linha 45. Tente animá-lo. * Em qual nível de zoom o Noise começa a se parecer como Random novamente? * Em qual nível de zoom o Noise é imperceptível? * Tente associar a função de noise com as coordenadas do mouse. * Agora, e se nós tratarmos o gradiente do Noise como um campo de distância? Faça algo interessante a partir disso. * Agora que conseguimos obter controle sobre a ordem e o caos, é hora de usar nosso conhecimento. Faça uma composição com retângulos, cores e ruído que nos lembre um pouco da complexidade de uma pintura de [Mark Rothko](http://en.wikipedia.org/wiki/Mark_Rothko). ## Utilizando Noise em Designs Generativos Algoritmos de noise foram originalmente desenhados para nos retornar um natural *je ne sais quoi* em texturas digitais. As implementações 1D e 2D que nós vimos até agora são interpolações entre *valores* aleatórios, por essa razão são chamados **Ruído de Valor**, mas existem muitas outras formas de obter ruído... [ ](../edit.php#11/2d-vnoise.frag) Como você percebeu nos últimos exercícios, valores ruidosos tendem a parecer "quadriculados". Para diminuir esse efeito, em 1985 [Ken Perlin](https://mrl.nyu.edu/~perlin/) desenvolveu outra implementação do algoritmo chamado **Ruído de Gradiente**. Ken descobriu como interpolar *gradientes* aleatórios ao invés de valores. Estes gradientes são o resultado de uma função aleatória 2D que retorna direções (representadas por um ```vec2```) em vez de valores únicos (```float```). Clique na seguinte imagem para ver o código e como essa técnica funciona. [ ](../edit.php#11/2d-gnoise.frag) Tome um minuto para olhar estes dois exemplos por [Inigo Quilez](http://www.iquilezles.org/) e preste atenção para as diferenças entre [value noise](https://www.shadertoy.com/view/lsf3WH) e [gradient noise](https://www.shadertoy.com/view/XdXGW8). Como um pintor que entende como os pigmentos de suas pinturas funcionam, quanto mais sabermos sobre as implementações de noise, melhor nós poderemos usá-las. Por exemplo, se nós usarmos uma implementação de noise bidimensional para rotacionar o espaço onde linhas retas são renderizadas, nós podemos reproduzir o seguinte efeito de redemoinho que nos lembra madeira. Você pode clicar na imagem para ver como esse código se parece. [ ](../edit.php#11/wood.frag) ```glsl pos = rotate2d( noise(pos) ) * pos; // rotate the space pattern = lines(pos,.5); // draw lines ``` Um outro jeito de se interessar por padrões de ruído, é tratá-los como um campo de distância e aplicar alguns truques descritos no [capítulo Formas](../07/). [ ](../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 ``` Uma terceira forma é usar as funções de noise para modular uma forma. Essa forma também pode requerer algumas técnicas que aprendemos no [capítulo sobre formas](../07/). Para você praticar: * Quais outros padrões generativos você pode fazer? Que tal granito? Mármore? Magma? Água? Encontre três fotos de textura que você tem interesse em implementá-los algoritmicamente usando noise. * Use noise para modular uma forma. * E quanto a usar noise para movimento? Volte ao [capítulo Matrizes](../08/). Use o exemplo de translação que circunda o "+" e aplique um pouco de movimentos *random* e *noise* e ele. * Faça um generativo Jackson Pollock. ## Melhorando o noise Uma melhoria por Perlin em seu noise non-simplex original **Simplex Noise**, é a substituição da curva cúbica Hermite ( _f(x) = 3x^2-2x^3_ , que é idêntica à função [```smoothstep()```](../glossary/?search=smoothstep)) com uma interpolação da curva quíntica ( _f(x) = 6x^5-15x^4+10x^3_ ). Isso faz com que ambos finais da curva sejam mais "achatados" então cada borda graciosamente se costurem com a próxima. Em outras palavras, você obtém uma transição mais contínua entre as células. Você pode observar isso ao descomentar a segunda fórmula no seguinte exemplo gráfico (ou ver as [duas equações lado a lado aqui](https://www.desmos.com/calculator/2xvlk5xp8b)). Note como o fim das curvas mudam. Você pode ler mais sobre isso nas [próprias palavras de Ken](http://mrl.nyu.edu/~perlin/paper445.pdf). ## Simplex noise Para Ken Perlin, o sucesso de seu algoritmo não foi o suficiente, ele acreditava que podia ser mais performático. Na Siggraph de 2001, ele apresentou o "simplex noise", onde ele obteve o seguinte avanço sobre o algoritmo anterior: * Um algoritmo com menor complexidade computacional e menos multiplicações. * Um Noise que se escalona para maiores dimensões com menos custo computacional. * Um Noise sem artefatos de direção. * Um Noise com gradientes bem-definido e contínuos que podem ser computados a um baixo custo. * Um algoritmo que é fácil de implementar em hardware. Eu sei o que você está pensando... "Quem é este homem?!" Sim, seu trabalho é fantástico! Mas falando sério, como ele melhorou o algoritmo? Bem, nós vimos como interpolar os 4 pontos para duas dimensões (cantos de um quadrado); Então podemos convenientemente perceber que para três [(ver a implementação aqui)](../edit.php#11/3d-noise.frag) e quatro dimensões nós precisamos interpolar 8 e 16 pontos. Certo? Em outras palavras, para N dimensões, nós precisamos interpolar suavemente 2 elevado a N pontos (2^N). Mas Ken espertamente notou que apesar de uma escolha óbvia de uma forma para o preenchimento espacial fosse o quadrado, a forma mais simples em 2D é o triângulo equilátero. Então ele começou a trocar a grade quadriculada (que acabamos de aprender a usar) por uma grade simplex de triângulos equiláteros. A forma simplex para N dimensões é a forma com N + 1 vértices. Em outras palavras, um canto a menos para computar em 2D, 4 cantos a menos em 3D e 11 menos cantos em 4D! Isso é um grande aperfeiçoamento. Em duas dimensões, a interpolação acontece de forma similar a um noise comum, ao interpolar os valores dos cantos para cada seção. Mas neste caso, ao usar uma grade simples, nós apenas precisamos interpolar a soma de 3 cantos. Como uma grade simplex é feita? Em outro brilhante e elegante movimento, a grade simplex pode ser obtida por subdividir as células de uma grade de 4 cantos em dois triângulos isósceles e então incliná-los até que cada triângulo se torne equilátero. Então, como [Stefan Gustavson descreve em seu artigo](http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf): _"...Ao olhar para as partes inteiras das coordenadas transformadas (x,y) para o ponto que queremos avaliar, nós podemos rapidamente determinar qual célula das dois simplexos contém o ponto. Também, ao comparar as magnitudes de x e y, nós podemos determinar se o ponto está no simplex superior ou inferior, e cruzar os três pontos corretos."_ No código a seguir, você pode comentar a linha 44 para ver como a grade está inclinada, e então descomentar a linha 47 para ver como uma grade simplex pode ser construída. Note na linha 22 como estamos subdividindo o quadrado inclinado em dois triângulos equiláteros apenas detectando se ```x > y``` (triângulo "inferior") ou ```y > x``` (triângulo "superior"). Todas essas melhorias resultam em uma obra-prima conhecida como **Simplex Noise**. A seguir, temos uma implementação GLSL deste algoritmo feita por Ian McEwan e Stefan Gustavson (e apresentada [neste artigo](http://webstaff.itn.liu.se/~stegu/jgt2012/article.pdf)) que é complicado demais para propósitos educacionais, mas você ficará feliz em clicar e ver que é menos enigmático que você esperava, o código é curto e rápido. [ ](../edit.php#11/2d-snoise-clear.frag) Bom... Chega de detalhes técnicos, está na hora de você usar esses recursos na sua própria maneira de se expressar: * Contemple como cada implementação de noise se parece. Imagine elas como uma matéria crua, como uma pedra de mármore para um escultor. O que você pode dizer sobre o "sentimento" que cada uma tem? Feche seus olhos para ativar sua imaginação, como se você quisesse encontrar formas em uma nuvem, o que você vê? De quê você se lembra? Em que você imagina que cada implementação de noise pode ser feita? Sigua sua coragem e tente criá-la em código. * Faça um shader que projeta a ilusão de fluidez. Como um abajur de lava, pingos de tinta, água, etc. * Use o Simplex Noise para adicionar algumas texturas a um trabalho que você tenha feito. Neste capítuo, nós introduzimos um controle sobre o caos. Não foi uma tarefa fácil! Se tornar um mestre de dobra de noise toma tempo e esfoço. Nos capítulos a seguir, nós veremos algumas técnicas conhecidas para aperfeiçoar suas habilidades de noise para criar designs generativo com shaders. Até então, aproveite um tempo do lado de fora, contemplando a natureza e seus padrões intrínsecos. Sua habilidade em observar precisa de uma dedicação igual (ou talvez maior) do que suas habilidades de construção. Vá lá fora e aproveite o resto do seu dia!"Converse com a árvore, faça amizade com ela." Bob Ross
--- ### 11/README Tr (11/README-tr.md) ## Gürültü (Noise) Mola zamanı! TV beyaz gürültüsüne benzeyen rastgele fonksiyonlarla oynuyorduk, shader'lar hakkında düşünmekten kafamız hâlâ dönüyor ve gözlerimiz yoruldu. Yürüyüşe çıkma zamanı! Cildimizdeki havayı, yüzümüzdeki güneşi hissediyoruz. Dünya çok canlı ve zengin bir yer. Renkler, dokular, sesler. Yürürken yolların, kayaların, ağaçların ve bulutların yüzeyini fark etmekten kaçınamıyoruz. Bu dokuların öngörülemezliğine "rastgele" denilebilir, ama daha önce oynadığımız rastgeleye benzemiyor. "Gerçek dünya" çok zengin ve karmaşık bir yer! Bu çeşitliliğe hesaplamalı olarak nasıl yaklaşabiliriz? Bu, [Ken Perlin](https://mrl.nyu.edu/~perlin/)'in 1980'lerin başında "Tron" filmi için daha gerçekçi dokular üretmekle görevlendirildiğinde çözmeye çalıştığı soruydu. Buna yanıt olarak, zarif bir *Oscar ödüllü* gürültü algoritması geliştirdi. (Küçük bir şey.) Aşağıdaki klasik Perlin gürültü algoritması değildir, ancak gürültü üretmeyi anlamak için iyi bir başlangıç noktasıdır. Bu satırlarda önceki bölümde yaptığımıza benzer bir şey yapıyoruz. Sürekli bir kayan sayıyı (```x```) tam sayı (```i```) ve kesirli (```f```) bileşenlerine ayırıyoruz. ```i```'yi elde etmek için [```floor()```](../glossary/?search=floor) ve ```f```'yi elde etmek için [```fract()```](../glossary/?search=fract) kullanıyoruz. Sonra ```x```'in tam sayı kısmına ```rand()``` uyguluyoruz, bu da her tam sayı için benzersiz bir rastgele değer veriyor. Bundan sonra iki yorum satırı görüyorsunuz. Birincisi her rastgele değeri doğrusal olarak enterpolasyon yapar. ```glsl y = mix(rand(i), rand(i + 1.0), f); ``` Devam edin ve bunun nasıl göründüğünü görmek için bu satırın yorumunu kaldırın. İki rastgele değeri [```mix()```](../glossary/?search=mix) etmek için `f`'de saklanan [```fract()```](../glossary/?search=fract) değerini kullanıyoruz. Kitabın bu noktasında, doğrusal enterpolasyondan daha iyisini yapabileceğimizi öğrendik, değil mi? Şimdi doğrusal yerine [```smoothstep()```](../glossary/?search=smoothstep) enterpolasyonu kullanan aşağıdaki satırın yorumunu kaldırmayı deneyin. ```glsl y = mix(rand(i), rand(i + 1.0), smoothstep(0.,1.,f)); ``` Yorumunu kaldırdıktan sonra, tepeler arasındaki geçişin nasıl düzgünleştiğine dikkat edin. Bazı gürültü uygulamalarında programcıların [```smoothstep()```](../glossary/?search=smoothstep) kullanmak yerine kendi kübik eğrilerini (aşağıdaki formül gibi) kodlamayı tercih ettiğini göreceksiniz. ```glsl float u = f * f * (3.0 - 2.0 * f ); // özel kübik eğri y = mix(rand(i), rand(i + 1.0), u); // enterpolasyonda kullanma ``` Bu *düzgün rastgelelik*, grafik mühendisleri veya sanatçılar için ezber bozucudur — organik hissiyatla görüntüler ve geometriler üretme yeteneği sağlar. Perlin'in Gürültü Algoritması, her türlü yaratıcı kullanım için büyüleyici eserler yapmak üzere farklı dillerde ve boyutlarda tekrar tekrar uygulanmıştır. Şimdi sıra sizde: * Kendi ```float noise(float x)``` fonksiyonunuzu yapın. * Bir şekli taşıyarak, döndürerek veya ölçekleyerek canlandırmak için gürültü fonksiyonunuzu kullanın. * Gürültü kullanarak birkaç şeklin birlikte 'dans ettiği' animasyonlu bir kompozisyon yapın. * Gürültü fonksiyonunu kullanarak "organik görünümlü" şekiller oluşturun. * "Yaratığınızı" elde ettikten sonra, ona belirli bir hareket atayarak bir karaktere dönüştürmeye çalışın. ## 2B Gürültü Artık 1B'de gürültüyü nasıl yapacağımızı bildiğimize göre, 2B'ye geçme zamanı. 2B'de bir çizginin iki noktası arasında (```rand(x)``` ve ```rand(x)+1.0```) enterpolasyon yapmak yerine, bir düzlemin kare alanının dört köşesi arasında enterpolasyon yapacağız (```rand(st)```, ```rand(st)+vec2(1.,0.)```, ```rand(st)+vec2(0.,1.)``` ve ```rand(st)+vec2(1.,1.)```). Benzer şekilde, 3B gürültü elde etmek istiyorsak bir küpün sekiz köşesi arasında enterpolasyon yapmamız gerekir. Bu teknik tamamen rastgele değerlerin enterpolasyonuyla ilgilidir, bu yüzden **değer gürültüsü** (value noise) olarak adlandırılır. 1B örneğinde olduğu gibi, bu enterpolasyon doğrusal değil, kübiktir; kare ızgaramızın içindeki herhangi bir noktayı düzgünce enterpolasyon yapar. Aşağıdaki gürültü fonksiyonuna bir bakın. Izgaranın kareleri arasındaki enterpolasyonu görmek için uzayı 5'le ölçekleyerek (45. satır) başlıyoruz. Sonra gürültü fonksiyonunun içinde uzayı hücrelere ayırıyoruz. Hücrenin tam sayı konumunu ve hücre içindeki kesirli konumları saklıyoruz. Tam sayı konumunu dört köşenin koordinatlarını hesaplamak ve her biri için rastgele bir değer elde etmek için kullanıyoruz (23-26 arası satırlar). Son olarak, 35. satırda daha önce sakladığımız kesirli konumları kullanarak köşelerin 4 rastgele değeri arasında enterpolasyon yapıyoruz. Şimdi sıra sizde. Aşağıdaki alıştırmaları deneyin: * 45. satırın çarpanını değiştirin. Canlandırmayı deneyin. * Hangi yakınlaştırma seviyesinde gürültü tekrar rastgele görünmeye başlar? * Hangi yakınlaştırma seviyesinde gürültü algılanamaz hale gelir? * Bu gürültü fonksiyonunu fare koordinatlarına bağlamayı deneyin. * Ya gürültünün gradyanını bir mesafe alanı olarak ele alırsak? Onunla ilginç bir şey yapın. * Artık düzen ve kaos üzerinde biraz kontrol elde ettiğinize göre, bu bilgiyi kullanmanın zamanı. Bir [Mark Rothko](http://en.wikipedia.org/wiki/Mark_Rothko) tablosunun karmaşıklığına benzeyen dikdörtgenler, renkler ve gürültüden oluşan bir kompozisyon yapın. ## Üretken Tasarımlarda Gürültü Kullanma Gürültü algoritmaları başlangıçta dijital dokulara doğal bir *je ne sais quoi* vermek için tasarlandı. Şimdiye kadar gördüğümüz 1B ve 2B uygulamalar rastgele *değerler* arasında enterpolasyonlardı, bu yüzden **Değer Gürültüsü** olarak adlandırılırlar, ancak gürültü elde etmenin daha fazla yolu var... [ ](../edit.php#11/2d-vnoise.frag) Önceki alıştırmalarda keşfettiğiniz gibi, değer gürültüsü "bloklu" görünme eğilimindedir. Bu bloklu efekti azaltmak için 1985'te [Ken Perlin](https://mrl.nyu.edu/~perlin/) **Gradyan Gürültüsü** adlı başka bir algoritma uygulaması geliştirdi. Ken, değerler yerine rastgele *gradyanları* enterpolasyon yapmanın yolunu buldu. Bu gradyanlar, tek değerler (```float```) yerine yönler (bir ```vec2``` ile temsil edilen) döndüren 2B rastgele fonksiyonun sonucuydu. Kodu ve nasıl çalıştığını görmek için aşağıdaki görüntüye tıklayın. [ ](../edit.php#11/2d-gnoise.frag) [Inigo Quilez](http://www.iquilezles.org/) tarafından yapılan bu iki örneğe bir dakika ayırıp bakın ve [değer gürültüsü](https://www.shadertoy.com/view/lsf3WH) ile [gradyan gürültüsü](https://www.shadertoy.com/view/XdXGW8) arasındaki farklara dikkat edin. Boyalarının pigmentlerinin nasıl çalıştığını anlayan bir ressam gibi, gürültü uygulamaları hakkında ne kadar çok bilirsek, onları o kadar iyi kullanabiliriz. Örneğin, düz çizgilerin oluşturulduğu uzayı döndürmek için iki boyutlu bir gürültü uygulaması kullanırsak, ahşaba benzeyen aşağıdaki kıvrımlı efekti üretebiliriz. Yine kodu görmek için görüntüye tıklayabilirsiniz. [ ](../edit.php#11/wood.frag) ```glsl pos = rotate2d( noise(pos) ) * pos; // uzayı döndür pattern = lines(pos,.5); // çizgiler çiz ``` Gürültüden ilginç desenler elde etmenin başka bir yolu, onu bir mesafe alanı olarak ele almak ve [Şekiller bölümünde](../07/) açıklanan bazı numaraları uygulamaktır. [ ](../edit.php#11/splatter.frag) ```glsl color += smoothstep(.15,.2,noise(st*10.)); // Siyah sıçrama color -= smoothstep(.35,.4,noise(st*10.)); // Sıçramadaki delikler ``` Gürültü fonksiyonunu kullanmanın üçüncü bir yolu, bir şekli modüle etmektir. Bu da [şekiller bölümünde](../07/) öğrendiğimiz bazı teknikleri gerektirir. Pratik yapmanız için: * Başka hangi üretken deseni yapabilirsiniz? Ya granit? Mermer? Magma? Su? İlginizi çeken üç doku resmi bulun ve gürültü kullanarak algoritmik olarak uygulayın. * Bir şekli modüle etmek için gürültü kullanın. * Ya hareket için gürültü kullanmak? [Matris bölümüne](../08/) geri dönün. "+"'yı hareket ettiren öteleme örneğini kullanın ve ona bazı *rastgele* ve *gürültü* hareketleri uygulayın. * Üretken bir Jackson Pollock yapın. ## İyileştirilmiş Gürültü Perlin'in orijinal simpleks olmayan gürültüsüne yaptığı iyileştirme olan **Simpleks Gürültüsü**, kübik Hermite eğrisinin ( _f(x) = 3x^2-2x^3_ , [```smoothstep()```](../glossary/?search=smoothstep) fonksiyonuyla aynıdır) quintic enterpolasyon eğrisiyle ( _f(x) = 6x^5-15x^4+10x^3_ ) değiştirilmesidir. Bu, eğrinin her iki ucunu daha "düz" yapar, böylece her sınır bir sonrakiyle zarif bir şekilde birleşir. Başka bir deyişle, hücreler arasında daha sürekli bir geçiş elde edersiniz. Aşağıdaki grafik örneğinde ikinci formülün yorumunu kaldırarak bunu görebilirsiniz (veya [iki denklemi yan yana burada görün](https://www.desmos.com/calculator/2xvlk5xp8b)). Eğrinin uçlarının nasıl değiştiğine dikkat edin. Daha fazlasını [Ken'in kendi sözleriyle](http://mrl.nyu.edu/~perlin/paper445.pdf) okuyabilirsiniz. ## Simpleks Gürültüsü Ken Perlin için algoritmasının başarısı yeterli değildi. Daha iyi performans gösterebileceğini düşündü. Siggraph 2001'de önceki algoritmaya göre aşağıdaki iyileştirmeleri elde ettiği "simpleks gürültüsünü" sundu: * Daha düşük hesaplama karmaşıklığı ve daha az çarpma içeren bir algoritma. * Daha düşük hesaplama maliyetiyle daha yüksek boyutlara ölçeklenen bir gürültü. * Yönsel artefaktları olmayan bir gürültü. * İyi tanımlanmış ve sürekli gradyanlara sahip, oldukça ucuza hesaplanabilen bir gürültü. * Donanımda uygulanması kolay bir algoritma. Ne düşündüğünüzü biliyorum... "Bu adam kim?" Evet, çalışması harika! Ama cidden, algoritmayı nasıl iyileştirdi? İki boyut için 4 noktayı (bir karenin köşelerini) enterpolasyon yaptığını gördük; bu yüzden [üç boyut (burada bir uygulamayı görün)](../edit.php#11/3d-noise.frag) ve dört boyut için 8 ve 16 noktayı enterpolasyon yapmamız gerektiğini doğru tahmin edebiliriz. Başka bir deyişle N boyut için 2'nin N'inci kuvveti (2^N) noktayı düzgünce enterpolasyon yapmanız gerekir. Ancak Ken, uzay dolduran şekil için bariz seçenek kare olsa da, 2B'deki en basit şeklin eşkenar üçgen olduğunu zekice fark etti. Bu yüzden kare ızgarayı (nasıl kullanacağımızı yeni öğrendiğimiz) eşkenar üçgenlerden oluşan bir simpleks ızgara ile değiştirmeye başladı. N boyut için simpleks şekli, N + 1 köşeli bir şekildir. Başka bir deyişle 2B'de bir köşe daha az, 3B'de 4 köşe daha az ve 4B'de 11 köşe daha az hesaplama! Bu büyük bir iyileştirme! İki boyutta enterpolasyon, normal gürültüye benzer şekilde, bir bölümün köşelerinin değerlerini enterpolasyon yaparak gerçekleşir. Ancak bu durumda, bir simpleks ızgara kullanarak, sadece 3 köşenin toplamını enterpolasyon yapmamız gerekir. Simpleks ızgarası nasıl yapılır? Başka parlak ve zarif bir hamlede, simpleks ızgarası, normal 4 köşeli bir ızgaranın hücrelerini iki ikizkenar üçgene bölerek ve sonra her üçgen eşkenar olana kadar eğerek elde edilebilir. Sonra, [Stefan Gustavson'un bu makalede anlattığı gibi](http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf): _"...değerlendirmek istediğimiz nokta için dönüştürülmüş koordinatların (x,y) tam sayı kısımlarına bakarak, noktayı içeren iki simpleksten hangisini hızlıca belirleyebiliriz. x ve y'nin büyüklüklerini de karşılaştırarak, noktanın üst veya alt simplekste olup olmadığını belirleyebilir ve doğru üç köşe noktasını gezebiliriz."_ Aşağıdaki kodda ızgaranın nasıl eğildiğini görmek için 44. satırın yorumunu kaldırabilir, ardından bir simpleks ızgaranın nasıl oluşturulabileceğini görmek için 47. satırın yorumunu kaldırabilirsiniz. 22. satırda eğilmiş kareyi sadece ```x > y``` ("alt" üçgen) veya ```y > x``` ("üst" üçgen) tespit ederek iki eşkenar üçgene böldüğümüze dikkat edin. Tüm bu iyileştirmeler **Simpleks Gürültüsü** olarak bilinen algoritmik bir başyapıtla sonuçlanır. Aşağıdaki, Ian McEwan ve Stefan Gustavson tarafından yapılan bu algoritmanın GLSL uygulamasıdır ([bu makalede](http://webstaff.itn.liu.se/~stegu/jgt2012/article.pdf) sunulmuştur) ve eğitim amaçları için aşırı karmaşıktır, ancak tıklayıp beklediğinizden daha az şifreli olduğunu ve kodun kısa ve hızlı olduğunu görmekten mutlu olacaksınız. [ ](../edit.php#11/2d-snoise-clear.frag) Yeterince teknik detay... şimdi bu kaynağı kendi ifade biçiminizde kullanma zamanı: * Her gürültü uygulamasının nasıl göründüğünü düşünün. Onları ham malzeme olarak, bir heykeltıraş için mermer kaya gibi hayal edin. Her birinin sahip olduğu "his" hakkında ne söyleyebilirsiniz? Bir bulutta şekiller bulmak istediğinizdeki gibi gözlerinizi kısın ve hayal gücünüzü tetikleyin. Ne görüyorsunuz? Size neyi hatırlatıyor? Her gürültü uygulamasının neye dönüştürülebileceğini hayal edin? İçgüdülerinizi takip edin ve kodda gerçekleştirmeyi deneyin. * Akış illüzyonu yansıtan bir shader yapın. Lav lambası, mürekkep damlaları, su vb. gibi. * Daha önce yaptığınız bir çalışmaya doku eklemek için Simpleks Gürültüsü kullanın. Bu bölümde kaos üzerinde biraz kontrol sağladık. Kolay bir iş değildi! Gürültü bükme ustası olmak zaman ve çaba gerektirir. Sonraki bölümlerde becerilerinizi mükemmelleştirmek ve shader'larla kaliteli üretken içerik tasarlamak için gürültünüzden daha fazlasını elde etmek üzere bazı iyi bilinen teknikleri göreceğiz. O zamana kadar, dışarıda doğayı ve karmaşık desenlerini düşünerek biraz zaman geçirmenin keyfini çıkarın. Gözlem yeteneğiniz, yapma becerileriniz kadar (veya muhtemelen daha fazla) özveri gerektirir. Dışarı çıkın ve günün geri kalanının keyfini çıkarın!"Ağaçla konuş, onunla arkadaş ol." Bob Ross
#### Araç kutunuz için * [LYGIA'nın üretken fonksiyonları](https://lygia.xyz/generative), GLSL'de desenler üretmek için yeniden kullanılabilir fonksiyonlar kümesidir. Üretken sanat yaratmak için rastgelelik ve gürültüyü nasıl kullanacağınızı öğrenmek için harika bir kaynaktır. Yeniden kullanılabilirlik, performans ve esneklik için tasarlanmış çok ayrıntılı bir kütüphanedir. Ve herhangi bir projeye ve framework'e kolayca eklenebilir. --- ### 11/README Vi (11/README-vi.md) ## Nhiễu Sau một hồi vật lộn với các hàm ngẫu nhiên nhìn như màn hình TV hỏng, ít nhiều thì ta cũng sẽ quay cuồng và hoa mắt, giờ thì cùng nghỉ ngơi và dạo chơi tí nhé. Ta cảm nhận được gió thổi qua da, nắng ấm rọi lên mặt. Thế giới quả là sống động. Màu sắc, họa tiết rồi cả âm thanh nữa. Hãy nhìn bề mặt của những con đường, hòn đá, ngọn cây và cả những đám mây nữa. họa tiết khó đoán của những bề mặt này có thể coi là "ngẫu nhiên", nhưng tuyệt nhiên không giống như sự lộn xộn ở chương trước. Thế giới thực quả là rất phức tạp ! Làm sao để ta lột tả được sự đa dạng đó bằng máy tính đây ? Đó cũng chính là câu hỏi mà [Ken Perlin](https://mrl.nyu.edu/~perlin/) đã đi tìm câu trả lời suốt những năm đầu thập niên 80, khi ông chịu trách nhiệm tạo ra các họa tiết tự nhiên hết mức có thể cho bộ phim "Tron". Và kết quả là ông đã nhận được một *giải Oscar* với thuật toán tạo nhiễu của mình. Đoạn code dưới đây không hẳn là thuật toán tạo nhiễu Perlin cổ điển, nhưng là một bước đệm tốt để bắt đầu. Trông na ná như những gì ta đã làm ở chương trước. Ta tách riêng phần nguyên và phần thập phân của số thực ```x``` vào hai biến ```i``` và ```f``` bằng hai hàm [```floor()```](../glossary/?lan=vi&search=floor) và [```fract()```](../glossary/?lan=vi&search=fract). Sau đó chỉ sinh số ngẫu nhiên từ phần nguyên, kết quả sẽ giống nhau cho dù bạn có chạy bao nhiêu lần đi chăng nữa. Hai dòng cuối đã bị comment đi. Dòng đầu tiên sẽ nội suy tuyến tính 2 giá trị ngẫu nhiên ở 2 ô liên tiếp. ```glsl y = mix(rand(i), rand(i + 1.0), f); ``` Hãy uncomment xem đồ thị thay đổi thế nào. Tôi dùng chính phần thập phân có được từ hàm [```fract()```](../glossary/?lan=vi&search=fract) và lưu trong biến `f` phía trên, để quyết định tỉ lệ nội suy giữa 2 số dùng hàm [```mix()```](../glossary/?lan=vi&search=mix). Nếu bạn đã đọc tới đây, hẳn là bạn đã biết chúng ta có những cách nội suy khác ngoài tuyến tính phải không ? Hãy thử uncomment dòng cuối cùng trong đoạn phía trên, tôi đã dùng hàm [```smoothstep()```](../glossary/?lan=vi&search=smoothstep) thay cho nội suy tuyến tính đó. ```glsl y = mix(rand(i), rand(i + 1.0), smoothstep(0.,1.,f)); ``` Bạn sẽ thấy các đỉnh bớt nhọn hơn. Ở rất nhiều thuật toán sinh nhiễu, bạn sẽ để ý thấy các lập trình viên thường sử dụng đường cong của riêng họ (ví dụ công thức dưới đây), thay vì dùng hàm [```smoothstep()```](../glossary/?lan=vi&search=smoothstep). ```glsl float u = f * f * (3.0 - 2.0 * f ); // công thức đường cong bậc 3 với tham số riêng y = mix(rand(i), rand(i + 1.0), u); // dùng kết quả để xác định tỉ lệ nội suy ``` *Sự ngẫu nhiên có chuyển tiếp rất êm* này thực sự là một cuộc cách mạng cho kỹ sư đồ hoạ và cả hoạ sỹ nữa - nó cho ta khả năng sinh ra các ảnh và hình khối có cảm giác hết sức tự nhiên. Thuật toán sinh nhiễu của Perlin (Perlin Noise) đã được code đi code lại trên các ngôn ngữ lập trình khác nhau để tạo nên vô vàn tác phẩm mê hoặc có tính sáng tạo cao. Giờ tới lượt bạn: * Hãy tự tạo một hàm ```float noise(float x)``` của riêng mình. * Dùng chính hàm sinh nhiễu đó để di chuyển, quay hoặc thu phóng một hình vẽ. * Kết hợp nhiều hình để xem chúng nhảy múa trên màn hình. * Vẽ một sinh vật gì đó "trông tự nhiên". * Khi đã có sinh vật của mình rồi, hãy thổi hồn cho nó bằng cách thêm 1 chuyển động nhé. ## Nhiễu 2 chiều Trên đây là cách tạo nhiễu 1 chiều, giờ hãy thử 2 chiều xem sao. Thay vì nội suy giữa 2 điểm ```fract(x)``` và ```fract(x)+1.0```, ở không gian 2 chiều, ta sẽ nội suy giữa 4 đỉnh của một tứ giác (```fract(st)```, ```fract(st)+vec2(1.,0.)```, ```fract(st)+vec2(0.,1.)``` và ```fract(st)+vec2(1.,1.)```). Tương tự như vậy, nếu ta muốn sinh nhiễu 3 chiều thì sẽ phải nội suy giữa 8 đỉnh của một khối lập phương (có thể vát). Kỹ thuật này hoàn toàn dựa trên phép nội suy giữa các điểm ngẫu nhiên cố định (value), nó được gọi là **value noise**. Và cũng giống như phần sinh nhiễu 1 chiều, nếu sử dụng hàm nội suy bậc 3 (cubic) thay vì tuyến tính, thì ta sẽ thu được nhiễu rất mịn. Hãy xem hàm sinh nhiễu dưới đây: Đầu tiên ta tạo lưới 5x5 (dòng 45) để nhìn rõ vùng chuyển tiếp giữa các ô. Trong hàm sinh nhiễu, ta xác định toạ độ của mỗi ô (số nguyên) để sinh số ngẫu nhiên đại diện cho 4 đỉnh (dòng từ 23 tới 26). Cuối cùng ở dòng 35 ta nội suy cả 4 giá trị dựa vào phần thập phân. Giờ tới lượt bạn: * Thử các kích thước lưới khác (dòng 45), và chuyển động nếu được * Kích thước lớn tới đâu thì nhiễu trông giống như ngẫu nhiên * Với kích thước nào thì không thể nhận ra nhiễu nữa * Thử kết hợp hàm sinh nhiễu với toạ độ con trỏ chuột * Nếu ta coi dải màu gradient sinh ra bởi nhiễu như là 1 distance field thì sao nhỉ ? Thử làm một cái gì đó hay ho với ý tưởng này xem sao. * Giờ thì bạn kiểm soát được cả trật tự lẫn sự hỗn loạn ở một mức độ nào đó rồi, hãy thử xem bạn hiểu sâu tới đâu nhé. Hãy dùng nhiều hình chữ nhật với màu sắc khác nhau và nhiễu để mô phỏng lại bức tranh của [Mark Rothko](http://en.wikipedia.org/wiki/Mark_Rothko). ## Ứng dụng nhiễu vào các thiết kế ngẫu nhiên Các thuật toán sinh nhiễu ban đầu được thiết kế để thổi hồn vào các bức tranh kỹ thuật số. Các thuật toán 1 chiều và 2 chiều ta thấy trong chương này đều chỉ nội suy giữa các số ngẫu nhiên có sẵn, nên được gọi là **Value Noise**, nhưng còn nhiều cách khác để sinh nhiễu ... [ ](../edit.php#11/2d-vnoise.frag) Ở ví dụ phía trên, ta có thể thấy nhiễu sinh bởi nội suy trông như bị "vỡ ảnh". Để loại bỏ hiệu ứng này, [Ken Perlin](https://mrl.nyu.edu/~perlin/) đã phát minh ra một thuật toán khác năm 1985 gọi là **Gradient Noise**. Ken tìm ra cách để nội suy giữa các dải màu gradient thay vì giữa các số cố định. Các dải màu này lại lại kết quả của một hàm sinh nhiễu 2 chiều khác. Click vào ảnh dưới đây để xem code của mẫu thiết kế này. [ ](../edit.php#11/2d-gnoise.frag) Hãy dành một chút thời gian để quan sát 2 ví dụ sau của [Inigo Quilez](http://www.iquilezles.org/) để so sánh sự khác nhau giữa [value noise](https://www.shadertoy.com/view/lsf3WH) và [gradient noise](https://www.shadertoy.com/view/XdXGW8). Nếu một hoạ sỹ phải nắm rất rõ cách kết hợp màu trong các bức tranh, thì ta cũng phải hiểu tường tận các cách sinh nhiễu khác nhau thì mới tận dụng được. Ví dụ, nếu ta dùng nhiễu hai chiều để bẻ cong canvas đang có rất nhiều đường thẳng song song, ta có thể tạo nên vân bề mặt trông giống như gỗ vậy. Bạn có thể click vào ảnh dưới đây để xem code. [ ](../edit.php#11/wood.frag) ```glsl pos = rotate2d( noise(pos) ) * pos; // xoay trục toạ độ theo nhiễu pattern = lines(pos,.5); // vẽ các đường thẳng ``` Một cách khác để tạo nên các họa tiết thú vị từ nhiễu là coi nó như 1 distance field và áp dụng các kỹ thuật được mô tả ở [Chương Hình dạng](../07/?lan=vi). [ ](../edit.php#11/splatter.frag) ```glsl color += smoothstep(.15,.2,noise(st*10.)); // Các giọt bắn color -= smoothstep(.35,.4,noise(st*10.)); // Các vũng bắn ``` Cách thứ ba là dùng hàm sinh nhiễu để khiến các hình vẽ chuyển động. Để làm được thì ta cũng cần tới vài kỹ thuật được nhắc tới ở [Chương Hình dạng](../07/?lan=vi). Để tập luyện: * Bạn còn có thể tạo nên các hoa văn ngẫu nhiên nào nữa ? Vân đá ? Mắc ma ? Mặt nước ? Hãy tìm ảnh của những vân bề mặt bạn thích rồi dùng thuật toán để vẽ lại. * Dùng nhiễu để bóp méo hình vẽ. * Dùng nhiễu để di chuyển hình vẽ. Hãy quay lại [Chương Ma trận](../08/?lan=vi) và sửa code di chuyển hình chữ thập để áp dụng thêm nhiễu nhằm tạo ra những chuyển động khó đoán hơn. * Vẽ lại bức tranh dưới đây của Jackson Pollock. ## Nhiễu cải tiến Perlin đã tự cải tiến thuật toán sinh nhiễu ban đầu của ông để tạo ra **Simplex Noise**, bằng cách thay thế đường cong Hermite( _f(x) = 3x^2-2x^3_ , cho kết quả giống với hàm [```smoothstep()```](../glossary/?lan=vi&search=smoothstep)) bằng một đường cong bậc 5 (quintic) có công thức _f(x) = 6x^5-15x^4+10x^3_. Công thức nội suy này khiến cho hai đầu đường cong phẳng hơn và che được sự chuyển tiếp giữa 2 ô. Bạn có thể kiểm chứng điều đó bằng cách uncomment công thức thứ 2 ở đoạn code dưới đây ([hoặc so sánh 2 phương trình cạnh nhau](https://www.desmos.com/calculator/2xvlk5xp8b)) Chú ý hai đầu của đồ thị để dễ so sánh. Bạn có thể tìm hiểu thêm bằng [nghiên cứu của chính Ken](http://mrl.nyu.edu/~perlin/paper445.pdf). ## Simplex Noise Đối với Ken Perlin thì sự thành công của thuật toán sinh nhiễu là chưa đủ, ông ấy nghĩ rằng có thể làm tốt hơn nữa. Ở hội nghị Siggraph 2001 ông đã thuyết trình thuật toán mới cải tiến hơn thuật toán cũ, gọi là "simplex noise": * Hiệu quả hơn với ít phép tính hơn và độ phức tạp cũng thấp hơn. * Sinh nhiễu ở các không gian nhiều chiều yêu cầu ít dữ liệu hơn thuật toán cũ. * Các điểm ảnh dọc theo trục toạ độ không còn bị lộ nữa (vì quá gần với các điểm nội suy nên thường có giá trị tương đương) * Các dải màu gradient dùng để sinh nhiễu có thể được tính rất nhanh và dễ kiểm soát * Phần cứng có thể hỗ trợ để tối ưu thuật toán này dễ dàng Tôi biết bạn đang tự hỏi ... "Đây là cao nhân phương nào?" Đúng vậy, các sản phẩm của ông thật siêu đẳng! Nhưng nói một cách nghiêm túc thì ông tự cải tiến thuật toán bằng cách nào ? Đầu tiên ông ấy quan sát cách sinh nhiễu ở không gian 2 chiều và thấy cần dùng 4 đỉnh, ở không gian 3 chiều sẽ cần 8 đỉnh và 4 chiều thì cần 16 đỉnh. Vậy là để sinh nhiễu ở không gian N chiều thì ta sẽ cần 2^N đỉnh. Và Ken đã nhanh chóng nhận ra rằng một tứ giác 4 đỉnh đâu phải hình học đơn giản nhất ở không gian 2 chiều đâu, đó phải là [hình tam giác](../edit.php#11/3d-noise.frag) mới đúng. Và nếu muốn lấp đầy không gian bằng một lưới các tam giác thì tam giác đều sẽ giúp việc code đơn giản hơn. Ý tưởng cải tiến chỉ có vậy. Và để sinh nhiễu cho không gian N chiều, ta sẽ chỉ cần N + 1 đỉnh. So với thuật toán cũ, thuật toán mới này giúp ta tiết kiệm 1 đỉnh ở không gian 2 chiều, 4 đỉnh ở không gian 3 chiều và 11 đỉnh ở không gian 4 chiều! Số lượng phép tính được cắt bớt cực kỳ nhiều. Quả là một cải tiến vượt bậc. Lúc này, để tính toán giá trị nhiễu tại một điểm ảnh, ta chỉ cần mix giá trị ngẫu nhiên tại 3 đỉnh. Vậy để tạo ra lưới tam giác (simplex grid) này thì làm thế nào ? Lại thêm một nước đi sáng suốt và tinh tế nữa, chỉ bằng cách chia đôi mỗi ô vuông ở lưới dạng bảng thông thường thành 2 nửa tam giác, rồi xô nghiêng (skew) cả lưới tới khi 3 cạnh của mỗi tam giác bằng nhau là được. [Stefan Gustavson đã mô tả thuật toán này trong báo cáo của ông](http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf) như sau: _"...chỉ cần kiểm tra phần nguyên trong toạ độ (x,y) của điểm ảnh ta cần tô màu, ta có thể nhanh chóng xác định nó ở ô vuông nào trong lưới dạng bảng. Rồi cũng chỉ cần so sánh x với y là ta biết được điểm ảnh nằm ở tam giác nào trong ô vuông đó, cuối cùng chỉ cần nội suy giá trị giữa 3 đỉnh tam giác là xong."_ Trong đoạn code dưới đây, bạn có thể uncomment dòng 44 để thấy lưới vuông bị xô nghiêng như thế nào, và uncomment tiếp dòng 47 để thấy một lưới tam giác được hình thành. Ở dòng 22, chỉ với một phép so sánh đơn giản ```x > y```, ta có thể xác định được điểm ảnh nằm ở tam giác nào trong số 2 tam giác tạo thành mỗi ô vuông. Các cải tiến này đã góp phần tạo nên một thuật toán kiệt tác gọi là **Simplex Noise**. Hình vẽ dưới đây được tạo bởi chính thuật toán này trong GLSL bởi Ian McEwan và Stefan Gustavson (và được mô tả trong [báo cáo này](http://webstaff.itn.liu.se/~stegu/jgt2012/article.pdf)) với một mức độ phức tạp quá tầm với một dự án giáo dục như thế này, nhưng nếu bạn click vào hình thì sẽ thấy ngạc nhiên là code rất ngắn gọn và tối ưu. [ ](../edit.php#11/2d-snoise-clear.frag) Chà... lý thuyết thế đủ rồi nhỉ, giờ hãy xắn tay áo lên nào: * Hãy chiêm ngưỡng các vân bề mặt tuyệt đẹp của thiên nhiên và nghĩ xem có thể dùng thuật toán sinh nhiễu nào để mô phỏng không. Nếu cần thì cứ nheo mắt lại mà tưởng tượng như lúc đoán xem các đám mây có hình gì ấy. * Tạo shader mô phỏng một dòng chảy, như dòng dung nham, giọt mực, dòng nước ... * Sử dụng Simplex Noise để thêm vân bề mặt vào một hình vẽ nào đó bạn đã tạo ra. Ở chương này chúng tôi đã giới thiệu một vài kỹ thuật giúp kiểm soát sự hỗn loạn. Không dễ chút nào! Để trở thành một noise-bender thành thạo tốn rất nhiều thời gian và công sức. Ở các chương tiếp theo ta sẽ thấy một vài kỹ thuật nổi tiếng khác giúp bạn hoàn thiện bộ kỹ năng của mình để bắt đầu thiết kế ra những tác phẩm có chất lượng cao bằng shader. Cho tới lúc đó, hãy tận hưởng thiên nhiên và cố gắng tìm ra các họa tiết ẩn giấu từ Mẹ Trái Đất nhé. Kỹ năng quan sát của bạn ít ra cũng phải tương đồng với kỹ năng chế tác. Hãy thư giãn nhé!"Hãy làm bạn và nói chuyện với cái cây" - Bob Ross
--- ### 11/SUMMARY Pt (11/SUMMARY-pt.md) Como podemos criar texturas com aparência mais natural como a superfície de estradas, pedras, árvores e nuvens? O ruído é a resposta. Desde que Ken Perlin inventou seu primeiro algoritmo de ruído nos anos 80, a técnica vem sendo usada extensivamente na computação gráfica e simulações. Mesmo se você nunca ouviu falar desse nome, é impossível que não tenha visto. Vamos dar uma olhada passo a passo em como a função é construída e funciona. Podemos também cobrir uma versão mais eficiente do algoritmo chamado ruído simplex. --- ### 11/SUMMARY (11/SUMMARY.md) How can we create more natural looking textures like surface of the roads, rocks, trees and clouds? Noise function is the answer. Since Ken Perlin invented his first noise algorithm in 80s, the technique has been extensively used throughout computer graphics and simulations. Even if you have never heard of the name, it's not possible you have never seen it. Let's look step by step at how the function is built and works. We also cover more efficient version of the algorithm called simplex noise. --- ### 12/README (12/README.md) ## Cellular Noise In 1996, sixteen years after Perlin's original Noise and five years before his Simplex Noise, [Steven Worley wrote a paper called “A Cellular Texture Basis Function”](http://www.rhythmiccanvas.com/research/papers/worley.pdf). In it, he describes a procedural texturing technique now extensively used by the graphics community. To understand the principles behind it we need to start thinking in terms of **iterations**. Probably you know what that means: yes, start using ```for``` loops. There is only one catch with ```for``` loops in GLSL: the number we are checking against must be a constant (```const```). So, no dynamic loops - the number of iterations must be fixed. Let's take a look at an example. ### Points for a distance field Cellular Noise is based on distance fields, the distance to the closest one of a set of feature points. Let's say we want to make a distance field of 4 points. What do we need to do? Well, **for each pixel we want to calculate the distance to the closest point**. That means that we need to iterate through all the points, compute their distances to the current pixel and store the value for the one that is closest. ```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)); ``` This is not very elegant, but it does the trick. Now let's re-implement it using an array and a ```for``` loop. ```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); } ``` Note how we use a ```for``` loop to iterate through an array of points and keep track of the minimum distance using a [```min()```](../glossary/?search=min) function. Here's a brief working implementation of this idea: In the above code, one of the points is assigned to the mouse position. Play with it so you can get an intuitive idea of how this code behaves. Then try this: - How can you animate the rest of the points? - After reading [the chapter about shapes](../07/), imagine interesting ways to use this distance field! - What if you want to add more points to this distance field? What if we want to dynamically add/subtract points? ### Tiling and iteration You probably notice that ```for``` loops and *arrays* are not very good friends with GLSL. Like we said before, loops don't accept dynamic limits on their exit condition. Also, iterating through a lot of instances reduces the performance of your shader significantly. That means we can't use this direct approach for large amounts of points. We need to find another strategy, one that takes advantage of the parallel processing architecture of the GPU. One way to approach this problem is to divide the space into tiles. Not every pixel needs to check the distance to every single point, right? Given the fact that each pixel runs in its own thread, we can subdivide the space into cells, each one with one unique point to watch. Also, to avoid aberrations at the edges between cells we need to check for the distances to the points on the neighboring cells. That's the main brillant idea of [Steven Worley's paper](http://www.rhythmiccanvas.com/research/papers/worley.pdf). At the end, each pixel needs to check only nine positions: their own cell's point and the points in the 8 cells around it. We already subdivide the space into cells in the chapters about: [patterns](../09/), [random](../10/) and [noise](../11/), so hopefully you are familiar with this technique by now. ```glsl // Scale st *= 3.; // Tile the space vec2 i_st = floor(st); vec2 f_st = fract(st); ``` So, what's the plan? We will use the tile coordinates (stored in the integer coordinate, ```i_st```) to construct a random position of a point. The ```random2f``` function we will use receives a ```vec2``` and gives us a ```vec2``` with a random position. So, for each tile we will have one feature point in a random position within the tile. ```glsl vec2 point = random2(i_st); ``` Each pixel inside that tile (stored in the float coordinate, ```f_st```) will check their distance to that random point. ```glsl vec2 diff = point - f_st; float dist = length(diff); ``` The result will look like this:
We still need to check the distances to the points in the surrounding tiles, not just the one in the current tile. For that we need to **iterate** through the neighbor tiles. Not all tiles, just the ones immediately around the current one. That means from ```-1``` (left) to ```1``` (right) tile in ```x``` axis and ```-1``` (bottom) to ```1``` (top) in ```y``` axis. A 3x3 region of 9 tiles can be iterated through using a double ```for``` loop like this one:
```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));
...
}
}
```
Now, we can compute the position of the points on each one of the neighbors in our double ```for``` loop by adding the neighbor tile offset to the current tile coordinate.
```glsl
...
// Random position from current + neighbor place in the grid
vec2 point = random2(i_st + neighbor);
...
```
The rest is all about calculating the distance to that point and storing the closest one in a variable called ```m_dist``` (for minimum distance).
```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);
...
```
The above code is inspired by [this article by Inigo's Quilez](http://www.iquilezles.org/www/articles/smoothvoronoi/smoothvoronoi.htm) where he said:
*"... it might be worth noting that there's a nice trick in this code above. Most implementations out there suffer from precision issues, because they generate their random points in "domain" space (like "world" or "object" space), which can be arbitrarily far from the origin. One can solve the issue moving all the code to higher precision data types, or by being a bit clever. My implementation does not generate the points in "domain" space, but in "cell" space: once the integer and fractional parts of the shading point are extracted and therefore the cell in which we are working identified, all we care about is what happens around this cell, meaning we can drop all the integer part of our coordinates away all together, saving many precision bits. In fact, in a regular voronoi implementation the integer parts of the point coordinates simply cancel out when the random per cell feature points are subtracted from the shading point. In the implementation above, we don't even let that cancelation happen, cause we are moving all the computations to "cell" space. This trick also allows one to handle the case where you want to voronoi-shade a whole planet - one could simply replace the input to be double precision, perform the floor() and fract() computations, and go floating point with the rest of the computations without paying the cost of changing the whole implementation to double precision. Of course, same trick applies to Perlin Noise patterns (but i've never seen it implemented nor documented anywhere)."*
Recapping: we subdivide the space into tiles; each pixel will calculate the distance to the point in their own tile and the surrounding 8 tiles; store the closest distance. The result is a distance field that looks like the following example:
Explore this further by:
- Scaling the space by different values.
- Can you think of other ways to animate the points?
- What if we want to compute an extra point with the mouse position?
- What other ways of constructing this distance field can you imagine, besides ```m_dist = min(m_dist, dist);```?
- What interesting patterns can you make with this distance field?
This algorithm can also be interpreted from the perspective of the points and not the pixels. In that case it can be described as: each point grows until it finds the growing area from another point. This mirrors some of the growth rules in nature. Living forms are shaped by this tension between an inner force to expand and grow, and limitations by outside forces. The classic algorithm that simulates this behavior is named after [Georgy Voronoi](https://en.wikipedia.org/wiki/Georgy_Voronoy).
### Voronoi Algorithm
Constructing Voronoi diagrams from cellular noise is less hard than what it might seem. We just need to *keep* some extra information about the precise point which is closest to the pixel. For that we are going to use a ```vec2``` called ```m_point```. By storing the vector direction to the center of the closest point, instead of just the distance, we will be "keeping" a "unique" identifier of that point.
```glsl
...
if( dist < m_dist ) {
m_dist = dist;
m_point = point;
}
...
```
Note that in the following code that we are no longer using ```min``` to calculate the closest distance, but a regular ```if``` statement. Why? Because we actually want to do something more every time a new closer point appears, namely store its position (lines 32 to 37).
Note how the color of the moving cell (bound to the mouse position) changes color according to its position. That's because the color is assigned using the value (position) of the closest point.
Like we did before, now is the time to scale this up, switching to [Steven Worley's paper's approach](http://www.rhythmiccanvas.com/research/papers/worley.pdf). Try implementing it yourself. You can use the help of the following example by clicking on it. Note that Steven Worley's original approach uses a variable number of feature points for each tile, more than one in most tiles. In his software implementation in C, this is used to speed up the loop by making early exits. GLSL loops don't allow variable number of iterations, so you probably want to stick to one feature point per tile.
Once you figure out this algorithm, think of interesting and creative uses for it.
### Improving Voronoi
In 2011, [Stefan Gustavson optimized Steven Worley's algorithm to GPU](http://webstaff.itn.liu.se/~stegu/GLSL-cellular/GLSL-cellular-notes.pdf) by only iterating through a 2x2 matrix instead of 3x3. This reduces the amount of work significantly, but it can create artifacts in the form of discontinuities at the edges between the tiles. Take a look to the following examples.
Later in 2012 [Inigo Quilez wrote an article on how to make precise Voronoi borders](http://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm).
Inigo's experiments with Voronoi didn't stop there. In 2014 he wrote this nice article about what he calls [voro-noise](http://www.iquilezles.org/www/articles/voronoise/voronoise.htm), a function that allows a gradual blend between regular noise and voronoi. In his words:
*"Despite this similarity, the fact is that the way the grid is used in both patterns is different. Noise interpolates/averages random values (as in value noise) or gradients (as in gradient noise), while Voronoi computes the distance to the closest feature point. Now, smooth-bilinear interpolation and minimum evaluation are two very different operations, or... are they? Can they perhaps be combined in a more general metric? If that was so, then both Noise and Voronoi patterns could be seen as particular cases of a more general grid-based pattern generator?"*
Now it's time for you to look closely at things, be inspired by nature and find your own take on this technique!
#### For your toolbox
* [LYGIA's generative functions ](https://lygia.xyz/generative) are a set of reusable functions to generate patterns in GLSL. It's a great resource to learn how to use randomness and noise to create generative art. It's very granular library, designed for reusability, performance and flexibility. And it can be easily be added to any projects and frameworks.
---
### 12/README De (12/README-de.md)
## Zelluläres Rauschen
Im Jahre 1996, 16 Jahre nach Veröffentlichung von Perlins ursprünglichem Noise-Algorithmus und fünf Jahre vor der Erfindung des Simplex Noise-Algorithmus, schrieb Steven Worley einen Artikel mit dem Titel [„Eine Basisfunktion für zelluläre Texturen“](http://www.rhythmiccanvas.com/research/papers/worley.pdf). Darin beschreibt er eine Technik zur prozeduralen Texturierung von Flächen, die heute im Bereich der Computergrafik nicht mehr wegzudenken ist.
Um das Prinzip hinter diesem Verfahren zu verstehen, müssen wir die Abläufe aus dem Blickwinkel von **Iterationen** betrachten. Als Programmierer kannst Du Dir vielleicht denken, was das bedeutet: Ja, genau, es geht um Schleifen und um den Einsatz des ```for```-Befehls. Allerdings gibt es da einen wichtigen Aspekt in GLSL: Die Anzahl der Schleifendurchläufe muss durch eine Konstante (```const```) vorgegeben sein. Sie ist also nicht dynamisch, sondern steht grundsätzlich von vornherein fest.
Lass uns dazu am besten ein Beispiel anschauen.
### Punkte für ein Distanzfeld
Zelluläres Rauschen basiert auf Distanzfeldern, konkret auf der Berechnung der Entfernung zum nächstgelegenen Bezugspunkt aus einer gegebenen Menge von Punkten. Lass uns annehmen, wir wollten ein Distanzfeld aus vier Punkten erzeugen. Was benötigen wir dafür? Nun, **für jeden zu berechnenden Bildpunkt auf unserer Zeichenfläche wollen wir die Entfernung zum nächstgelegenen der vier Bezugspunkte berechnen **. Das bedeutet, dass wir alle vier Bezugspunkte durchlaufen, ihre Entfernung zum aktuell bearbeiteten Pixel berechnen und uns die kleinste dieser Entfernungen merken müssen.
```glsl
float min_dist = 100.; // speichert die kleineste Entf. zu einem der 4 Bezugspunkte
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));
```
Diese Lösung ist natürlich nicht besonders elegant, aber sie erfüllt ihren Zweck. Lass uns das Ganze nun mit Hilfe eines Arrays und einer ```for```-Schleife realisieren.
```glsl
float m_dist = 100.; // speichert die minimale Entfernung
for (int i = 0; i < TOTAL_POINTS; i++) {
float dist = distance(st, points[i]);
m_dist = min(m_dist, dist);
}
```
Beachte, wie wir hier die ```for```-Schleife einsetzen, um ein Array mit Bezugspunkten zu durchlaufen, und die bislang kleinste Entfernung mit Hilfe der [```min()```](../glossary/?search=min)-Funktion festhalten. Hier folgt eine vollständige Umsetzung dieses Ansatzes in GLSL.
In dem obigen Shader wird einer der Bezugspunkte des Distanzfelds auf die Mausposition über der Zeichenfläche gesetzt. Fahre mit der Maus über die Fläche und spiele ein wenig damit herum. So bekommst Du am besten eine Vorstellung davon, wie der Code funktioniert. Probiere anschließend folgendes aus:
- Gelingt es Dir, die Position der anderen Bezugspunkte zu animieren?
- Nachdem Du [das Kapitel über Formen](../07/?lan=de) ja vermutlich bereits gelesen hast, stelle Dir einen interessanten Weg vor, was man mit dem vorliegenden Distanzfeld anstellen könnte.
- Was muss man tun, um das Distanzfeld um weitere Bezugspunkte zu erweitern? Wie können wir dynamisch einzelne Bezugspunkte hinzufügen oder entfernen?
### Kachelung und Wiederholung
Vielleicht ist Dir schon klargeworden, dass ```for``` Schleifen und *Arrays* nicht die besten Freunde von GLSL sind. Wie schon gesagt: Schleifen in GLSL akzeptieren keine variablen Limite für die Anzahl der Durchläufe. Außerdem verlangsamen vielfache Schleifendurchläufe die Ausführung Deiner Shader spürbar, da Schleifen nicht vorzeitig beendet werden können. Das hat zur Folge, dass dieser Ansatz für Distanzfelder mit einer Vielzahl von Bezugspunkten untauglich ist. Wir müssen einen anderen Weg wählen, einen, der einen Vorteil aus der Parallelverarbeitung der GPU zieht.
Ein Ansatz, um sich dieser Herausforderung zu stellen, ist die Unterteilung der Zeichenfläche in einzelne Kacheln bzw. Zellen. Nicht jeder Pixel muss die Entfernung zu allen Punkten des Distanzfeldes überprüfen. Manche sind auf jeden Fall zu weit entfernt, um ein Minima zu liefern. Dies gilt beispielsweise für alle Zellen, die nicht direkt an die aktuelle Zelle angrenzen.
Weil die Farbe für jeden Pixel in einem eigenen Thread berechnet wird, können wir die Zeichenfläche in einzelne Zellen unterteilen - jede mit einem Bezugspunkt.
Um Anomalien an den Schnittflächen zwischen den Zellen zu vermeiden, müssen wir jeweils die Entfernung zum Bezugspunkt der benachbarten Zellen überprüfen. Das ist im Wesentlichen die brillante Idee hinter dem [Ansatz von Steven Worley](http://www.rhythmiccanvas.com/research/papers/worley.pdf).
Letztendlich muss jeder Pixel nur die Entfernung zu neun Bezugspunkten berechnen: Dem seiner eigenen Zelle und jene der acht umliegenden Zellen. Alle anderen Zellen sind zu weit entfernt.
Wir haben bereits in den Kapiteln über [Muster](../09/?lan=de), [Generative Designs](../10/?lan=de) und [Rauschen](../11/?lan=de) gesehen, wie man die Zeichenfläche in einzelne Zellen unterteilt, von daher bist Du mit diesem Prinzip wahrscheinlich schon vertraut.
```glsl
// den Raum aufblaehen ...
st *= 3.;
// ... und in Zellen unterteilen
vec2 i_st = floor(st);
vec2 f_st = fract(st);
```
Also, wie lautet der Plan? Wir werden die Koordinate der Kachel/Zelle (die in dem Integer-Vektor ```i_st``` gespeichert ist) nutzen, um einen zufälligen Punkt zu erzeugen. Wir setzen dafür die ```random2f```-Funktion ein, die einen ```vec2``` als Parameter erhält und einen ```vec2``` mit einer Zufallsposition zurückliefert. So erhalten wir für jede Zelle einen Bezugspunkt mit einer zufälligen Position innerhalb der Zelle.
```glsl
vec2 point = random2(i_st);
```
Der jeweils zu zeichnende Bildpunkt innerhalb der Zelle (gespeichert in dem Fließkommavektor ```f_st```) wird seine Entfernung zu diesem zufällig gewählten Bezugspunkt berechnen.
```glsl
vec2 diff = point - f_st;
float dist = length(diff);
```
Das Ergebnis sieht dann wie folgt aus:
Aber wir wollen ja zusätzlich noch die Entfernung zu den Bezugspunkten in den umliegenden Zellen einbeziehen. Dafür müssen wir diese Zellen **durchlaufen**. Aber nicht alle, sondern nur die unmittelbar angrenzenden. Das heißt die Zellen mit den Abständen von ```-1``` (links) bis ```1``` (rechts) entlang der ```x```-Achse, sowie die Zellen mit den Abständen von ```-1``` (unten) bis ```1``` (oben) entlang der ```y```-Achse. Dieser Bereich von 3x3 Zellen lässt sich leicht mit Hilfe einer doppelten ```for```-Schleife abarbeiten, so wie im Folgenden gezeigt:
```glsl
for (int y= -1; y <= 1; y++) {
for (int x= -1; x <= 1; x++) {
// benachbarte Zelle innerhalb des Rasters
vec2 neighbor = vec2(float(x),float(y));
...
}
}
```
Nun können wir die Bezugspunkte aus jeder der benachbarten Zellen in unserer doppelten ```for```-Schleife berechnen, indem wir den Versatz aus der Variablen ```neighbour``` zu den Koordinaten der aktuellen Zelle addieren.
```glsl
...
// Zufallsposition von der aktuellen + der benachbarten Zelle im Raster
vec2 point = random2(i_st + neighbor);
...
```
Dann bleibt nur noch, die Entfernung vom aktuell zu zeichnenden Punkt zu dem jeweiligen Bezugspunkt zu berechnen und die geringste Entfernung in der Variablen ```m_dist``` (für „minimale Distanz“) zu speichern.
```glsl
...
vec2 diff = neighbor + point - f_st;
// Entfernung zu diesem Punkt
float dist = length(diff);
// die kleinste Entfernung speichern
m_dist = min(m_dist, dist);
...
```
Der obige Programmcode wurde durch einen [Artikel von Inigo Quilez](http://www.iquilezles.org/www/articles/smoothvoronoi/smoothvoronoi.htm) inspiriert. Dort schreibt er:
„... es ist vielleicht interessant darauf hinzuweisen, dass in dem obigen Code ein netter Trick steckt. Die meisten Implementationen dieses Algorithmus leiden unter einer schlechten Präzision der Berechnungen, weil sie die zufälligen Bezugspunkte auf den gesamten Koordinatenraum beziehen, so dass die Koordinaten sehr weit vom Ursprung entfernt sind. Man kann dagegen ansteuern, indem man Variablentypen mit besonders hoher Genauigkeit verwendet, was sich jedoch negativ auf die Geschwindigkeit der Berechnungen auswirkt. Oder man macht es etwas cleverer, indem man die Koordinaten nicht auf den gesamten Koordinatenraum bezieht, sondern auf die Ebene der einzelnen Zellen: Sobald der ganzzahlige Teil und der Nachkommateil des zu zeichnenden Punktes berechnet sind und dadurch die Zelle feststeht, in der sich der Punkt befindet, beschäftigen wir uns nur noch damit, was um diese Zelle herum geschieht. Dadurch müssen wir uns nicht mehr um den ganzzahligen Teil der Koordinaten kümmern, wodurch man viele Bits bei den weiteren Berechnungen einspart. Tatsächlich steuern bei herkömmlichen Voronoi-Implementierungen die ganzzahligen Anteile der Punktkoordinaten ebenfalls dem Wert 0 entgegen, sobald die zufälligen Bezugspunkte der Zellen vom aktuell zu zeichnenden Punkt abgezogen werden. In der obigen Implementation lassen wir es gar nicht erst so weit kommen, weil wir alle Koordinatenberechnungen auf den Raum der Zellen beziehen. Mit diesem Trick kann man sogar einen ganzen Planeten mit derartig geformten Voronoi-Zellen überziehen, indem man die Punktkoordinaten einfach in doppelter Fließkommagenauigkeit darstellt, die Berechnungen von ```floor()``` und ```fract()``` durchführt, und dann mit einfacher Fließkommagenauigkeit fortfährt. So erspart man sich den (Zeit-) Aufwand, die gesamte Berechnung mit doppelter Fließkommagenauigkeit auszuführen. Natürlich kann man diesen Trick auch auf Perlins Noise-Algorithmus anwenden (allerdings habe ich noch nie ein solche Implementation gesehen). “
Um es noch einmal zusammenzufassen: Wir unterteilen den Raum in einzelne Zellen. Für jeden zu zeichnenden Punkt berechnen wir die kleinste Entfernung zum Bezugspunkt seiner Zelle bzw. zu den Bezugspunkten der acht umliegenden Zellen. Als Ergebnis erhalten wir ein Distanzfeld, so wie in dem folgenden Beispiel:
Experimentiere damit, indem Du:
- den Raum in mehr Zellen aufteilst.
- Dir andere Möglichkeiten ausdenkst, um die Bezugspunkte zu animieren.
- einen der Bezugspunkte durch die aktuelle Mausposition ersetzt.
- über andere Wege nachdenkst, um das Distanzfeld zu berechnen, abseits von ```m_dist = min(m_dist, dist);```.
- untersuchst, welche anderen interessanten Muster sich über dieses Distanzfeld erzeugen lassen.
Man kann diesen Algorithmus nicht nur aus der Perspektive der jeweils zu zeichnenden Pixel betrachten, sondern auch aus Sicht der Bezugspunkte. In diesem Fall lässt sich der Algorithmus so beschreiben: Jeder Bezugspunkt wächst aus seiner Mitte heraus, bis er an die Grenzen eines anderen wachsenden Bezugspunktes stößt. Das spiegelt das Wachstum biologischer Zellen in der Natur wieder. Lebendige Organismen werden von dieser Spannung zwischen dem inneren Antrieb zum Wachstum und äußeren Begrenzungen geformt. Der klassische Algorithmus, der dieses Verhalten nachahmt, ist nach [Georgi Feodosjewitsch Woronoi, engl „Georgy Voronoi“](https://de.wikipedia.org/wiki/Voronoi-Diagramm) benannt.
### Der Voronoi-Algorithmus
Die Erzeugung von Voronoi-Diagrammen auf Basis von zellulärem Rauschen ist weniger kompliziert, als es vielleicht erscheint. Wir müssen nur zusätzliche Informationen über den Bezugspunkt *festhalten*, der dem zu zeichnenden Punkt am nächsten liegt. Dafür verwenden wir eine Variable vom Typ ```vec2``` mit dem Namen ```m_point```. Darin speichern wir den Vektor zum nächstgelegenen Bezugspunkt und nicht einfach nur dessen Entfernung. So behalten wir ein eindeutiges Identifikationsmerkmal für diesen Punkt.
```glsl
...
if( dist < m_dist ) {
m_dist = dist;
m_point = point;
}
...
```
Bitte beachte, dass wir in dem folgenden Programmcode die geringste Entfernung nicht mehr mit Hilfe der ```min```-Funktion berechnen, sondern einen herkömmlichen ```if```-Befehl einsetzen. Warum wir das tun? Weil wir diesmal etwas mehr unternehmen wollen, sobald ein neuer näherliegender Punkt auftaucht, nämlich seine Position speichern (*Programmzeilen 32 bis 37*).
Du wirst sehen, dass die Farbe der beweglichen Zelle (die dem Mauszeiger folgt) auf Basis ihrer Position wechselt. Die Ursache dafür ist, dass hier die Farbe aufgrund des Wertes (der Position) des nächstgelegenen Bezugspunktes zugewiesen wird.
Genau wie zuvor ist es nun an der Zeit, das Ganze zu erweitern, indem wir zu dem Algorithmus aus dem [Papier von Steven Worley](http://www.rhythmiccanvas.com/research/papers/worley.pdf) übergehen. Versuche doch einmal selbst, diesen Algorithmus zu implementieren. Du kannst dabei auf das folgende Beispiel zurückgreifen, indem Du darauf klickst.
Bitte beachte, dass der ursprüngliche Ansatz von Steven Worley eine variable Anzahl von Bezugspunkten für jede Zelle vorsieht. In seiner Implementation des Algorithmus in C nutzt er dies für einen zeitigen Abbruch der Schleife. Schleifen in GLSL erlauben jedoch keinen vorzeitigen Ausstieg oder eine variable Anzahl von Schleifendurchläufen, deshalb wirst Du vielleicht besser bei einem Bezugspunkt pro Zelle bleiben.
Sobald Du die Funktionsweise dieses Algorithmus verstanden hast, kannst Du über interessante und kreative Einsatzmöglichkeiten nachdenken.
### Verbesserung des Voronoi-Algorithmus
Im Jahre 2011 hat [Stefan Gustavson eine Optimierung von Steven Worleys Algorithmus für GPUs](http://webstaff.itn.liu.se/~stegu/GLSL-cellular/GLSL-cellular-notes.pdf) vorgeschlagen, bei der nur noch eine 2x2 Matrix benachbarter Zellen untersucht wird, an Stelle der bisherigen 3x3 Matrix. Das reduziert den Rechenaufwand für jeden Punkt deutlich, kann aber zur Artefakten durch unsaubere Übergänge an den Grenzen der Zellen führen. Schau Dir die folgenden Beispiele an.
Im Jahre 2012 präsentierte [Inigo Quilez einen interessanten Artikel über die Erzeugung präziser Voronoi-Abgrenzungen](http://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm).
Inigos Experimente zu diesem Thema hörten damit nicht auf. Im Jahr 2014 verfasste er einen schönen Beitrag über das, was er als [Voro-Noise, dt. „Voro-Rauschen“](http://www.iquilezles.org/www/articles/voronoise/voronoise.htm) bezeichnet - eine Funktion, die einen graduellen Übergang zwischen normalem Rauschen und Voronoi-Rauschen ermöglicht. Er schrieb:
„Abgesehen von ihrer Ähnlichkeit ist es entscheidend, dass das Raster aus Zellen in beiden Mustern unterschiedlich verwendet wird. Interpoliertes Rauschen mit Zufallswerten (wie bei Value-Noise) oder mit Gradienten (wie bei Gradient-Noise) unterscheidet sich von Voronoi, wo es auf die Entfernung zum nächstgelegenen Bezugspunkt ankommt. Schließlich sind die bilineare Interpolation und die Minima-Berechnung zwei ganz unterschiedliche Operationen, nicht wahr? Doch vielleicht kann man sie in einem größeren Rahmen vereinigen? Sollte das möglich sein, könnte man sowohl Rauschmuster als auch Voronoi-Muster als Spezialfälle eines allgemeineren rasterbasierten Mustergenerators betrachten.“
Nun ist die Zeit gekommen, dass Du Dir die Dinge genau anschaust, Dich von der Natur inspirieren lässt und Deine eigene Nutzungsmöglichkeiten dieser Techniken entdeckst!
---
### 12/README Fr (12/README-fr.md)
## Bruit Cellulaire
En 1996, seize ans après le *Bruit de Perlin* et cinq ans avant le *Bruit Simplex*, [Steven Worley a publié un papier : “Une function pour les textures cellulaires”](http://www.rhythmiccanvas.com/research/papers/worley.pdf).
Il y décrit une technique de texture procédurale amplement utilisée de nos jours par la communauté des développeurs graphiques.
Pour comprendre le principe qui sous-tend l'algorithme, nous devons réfléchir en termes d'itérations.
### Un champ de distances pour quelques points
Imaginons que nous voulions faire un champ de distance à quatre points.
De quoi aurions nous besoin ? Pour faire court, **pour chaque pixel, trouver la distance au point le plus proche**.
Ce qui signifie qu'il va nous falloir itérer sur tous les points et conserver la distance au point le plus proche.
```glsl
float m_dist = 1.; // distance minimum
for (int i = 0; i < TOTAL_POINTS; i++) {
float dist = distance(st, points[i]);
m_dist = min(m_dist, dist);
}
```
Pour ce faire, nous pouvons utiliser une boucle `for` pour itérer sur un tableau de points et conserver la distance minimum en nous servant de la fonction [```min()```](../glossary/?search=min).
Voici une implémentation sommaire :
Notez que dans l'exemple ci dessus, l'un des points utilise la position de la souris.
Jouez avec pour vous donner une meilleure idée de comment ça marche puis essayez ceci :
* Comment animer les reste des points ?
* Après avoir lu le [chapitre sur les formes](../07/?lan=fr), imaginez des façons intéressantes d'utiliser un champ de distances.
* comment ajouter plus de points au champ de distances ? Que se passe-t'il si on souhaite ajouter/enlever des points dynamiquement ?
### Pavage et itérations
vous avez sans doute remarqué que les boucles `for` et l'utilisation de *tableaux* n'est pas recommandée en GLSL.
Les boucles n'accpetent pas d'arguments dynamiques, itérer sur un grand nombre d'entrées ralentit considérablement l'exécution du shader, nous devons donc changer de stratégie.
Une façon d'aborder le problème est de diviser l'espace en *tuiles* (**tiles**) ou *cellules*.
Au fond, tous les pixels n'ont pas besoin de tester l'ensemble des points n'est ce pas ?
Ils ont simplement besoin de vérifier les points qui sont proches d'eux.
C'est l'idée principale [de la publication de Steven Worley](http://www.rhythmiccanvas.com/research/papers/worley.pdf).
Nous avons déjà subdivisé l'espace en cellules au chapitres des [motifs](../09/?lan=fr), de [l'aléatoire](../10/?lan=fr) et du [bruit](../11/?lan=fr).
Vous devriez être un peu plus familier avec cette technique.
```glsl
// échelle (nombre de cellules)
st *= 3.;
// variables utilisées pour paver le plan
vec2 i_st = floor(st);
vec2 f_st = fract(st);
```
Quel plan ? Nous allons nous servir des coordonnées des cellules (stockées dans la partie entières `i_st`) pour constuire la position de nos points.
La méthode ```random2f``` recevra un ```vec2``` et nous retournera un ```vec2```.
Donc chaque cellule contiendra un point à une position aléatoire dans la cellule.
```glsl
vec2 point = random2(i_st);
```
A l'intérieur de chaque cellule, tous les fragments (à l'aide de la partie fractionelle de ```f_st```, `fract(st)` ) vont mesurer la distance à ce point.
```glsl
vec2 diff = point - f_st;
float dist = length(diff);
```
Ca ressemblera à :
Nous devons également calculer la distance aux points des cellules adjacentes ;
en effet, il se pourrait que le point le plus proche du fragment en cours d'évaluation se trouves dans une cellule voisine.
Pour cela, nous allons itérer sur les cellules voisines, pas toutes les cellules, juste les cellules adjacentes.
Soit de ```-1``` (gauche) à ```1``` (droite) cellules en ```x``` et de ```-1``` (bas) à ```1``` (haut) en ```y```.
Ce qu'on appelle un *kernel de 3x3*, sur lequel on peut itérer grâce à deux boucles `for` imbriquées telle que celle-ci.
```glsl
for (int y= -1; y <= 1; y++) {
for (int x= -1; x <= 1; x++) {
// cellules voisines
vec2 neighbor = vec2(float(x),float(y));
...
}
}
```
Nous pouvons prévoir la position des points des cellules adjacentes en ajoutant les deltas `x` et `y` de la boucle `for` aux indices de la cellule courante.
On peut s'en servir pour calculer la position du point de la cellule en cours de traitement dans la boucle grâce à la méthode `random2()` décrite plus haut.
```glsl
...
// Random position from current + neighbor place in the grid
vec2 point = random2(i_st + neighbor);
...
```
Pour le reste, il suffit de calculer la distance entre ce point et le fragment et de conserver le minimum dans une variable ```m_dist``` (*minimal distance*).
```glsl
...
vec2 diff = neighbor + point - f_st;
// Distance au point
float dist = length(diff);
// conserve la distance la plus courte
m_dist = min(m_dist, dist);
...
```
Le code ci-dessus s'inspire de cet [article d'Inigo Quilez](http://www.iquilezles.org/www/articles/smoothvoronoi/smoothvoronoi.htm) où il dit :
*"... it might be worth noting that there's a nice trick in this code above. Most implementations out there suffer from precision issues, because they generate their random points in "domain" space (like "world" or "object" space), which can be arbitrarily far from the origin. One can solve the issue moving all the code to higher precision data types, or by being a bit clever. My implementation does not generate the points in "domain" space, but in "cell" space: once the integer and fractional parts of the shading point are extracted and therefore the cell in which we are working identified, all we care about is what happens around this cell, meaning we can drop all the integer part of our coordinates away all together, saving many precision bits. In fact, in a regular voronoi implementation the integer parts of the point coordinates simply cancel out when the random per cell feature points are subtracted from the shading point. In the implementation above, we don't even let that cancelation happen, cause we are moving all the computations to "cell" space. This trick also allows one to handle the case where you want to voronoi-shade a whole planet - one could simply replace the input to be double precision, perform the floor() and fract() computations, and go floating point with the rest of the computations without paying the cost of changing the whole implementation to double precision. Of course, same trick applies to Perlin Noise patterns (but i've never seen it implemented nor documented anywhere)."*
En résumé : on subdivise l'espace en cellules, chaque fragment va calculer sa distance au point dans sa cellule ainsi qu'aux 8 cellules adjacentes et conserver la plus courte.
Le champ de distance final est visible dans l'exemple suivant :
Explorez en essayant les choses suivantes :
* Redimensionner l'espace avec différentes valeurs.
* Pouvez vous penser à d'autres manières d'animer les points ?
* Comment pouvons ajouter un point supplémentaire comme la position de la souris ?
* Quelles autres manières de construire ce champ de distance (à part `m_dist = min(m_dist, dist);`) vous viennent à l'esprit ?
* Imaginez quelques motifs à faire avec ce champ de distanes ?
Cet algorithme peut également être interprété du point de vue des points au lieu des pixels.
Dans ce cas, on peut le décrire comme : chaque point grossit jusqu'à ce qu'il recouvre le rayon d'un autre point.
Ce qui reflète certaines règles de croissance de la nature, les formes de vie sont formées par la tension entre une force intérieure d'expansion et des forces contraires venues de l'extérieur.
L'algorithme canonique de ce genre de formes a été trouvé par [Georgy Voronoi](https://en.wikipedia.org/wiki/Georgy_Voronoy) et porte maintenant son nom.
### L'algorithme de Voronoi
Construire un diagramme de Voronoi à partir d'un bruit cellulaire est plus simple qu'il n'y paraît.
Il nous faut simplement conserver certaines informations en plus ; nous allons conerver le point le plus proche dans un ```vec2``` appelé ```m_point```.
```glsl
...
if( dist < m_dist ) {
m_dist = dist;
m_point = point;
}
...
```
Notez que nous n'utilisons plus la fonction ```min``` pour conserver la distance au point le plus proche mais que nous nous servons d'une condition ```if```.
Pourquoi ? Parce que nous avons besoin de modifier la référence au point le plus proche (```m_point```) à chaque fois qu'un point est plus proche que le précédent (lignes 32 à 37).
Notez également que la couleur de la cellule (branchée sur la position de la souris) change en fonction de sa position.
C'est parce que la couleur est déterminée par la valeur (la position) du point le plus proche.
Pour aller plus loin, nous pouvons à présent ré-utiliser l'algorithme de [Steven Worley](http://www.rhythmiccanvas.com/research/papers/worley.pdf).
Essayez de l'implémenter seul, vous pouvez vous appuyer sur l'exemple suivant en cliquant dessus.
Après quoi, vous pouvez réfléchir à des utilisations créatives de cet algorithme.
Voici quelques pistes :
### Améliorer Voronoi
En 2011, [Stefan Gustavson a optimisé l'algorithme de Steven Worley sur le GPU](http://webstaff.itn.liu.se/~stegu/GLSL-cellular/GLSL-cellular-notes.pdf) en n'utilisant que des kernels de 2x2 au lieu de 3x3.
Cela amoindrit la charge de manière significative mais peut créer des artefacts et des discontinuités. Visibles dans l'exemple suivant:
Plus tard, en 2012 [Inigo Quilez a écrit un article expliquant comment trouver des frontières précises](http://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm).
Inigio ne s'est pas arrété là et en 2014, il a écrit un article sur ce qu'il a appelé le [voro-noise](http://www.iquilezles.org/www/articles/voronoise/voronoise.htm) ; une exploration combinant bruit et cellules de Voronoi.
Je cite :
*"Despite this similarity, the fact is that the way the grid is used in both patterns is different. Noise interpolates/averages random values (as in value noise) or gradients (as in gradient noise), while Voronoi computes the distance to the closest feature point. Now, smooth-bilinear interpolation and minimum evaluation are two very different operations, or... are they? Can they perhaps be combined in a more general metric? If that was so, then both Noise and Voronoi patterns could be seen as particular cases of a more general grid-based pattern generator?"*
Il est temps de revenir à la nature, d'être inspiré par elle et de trouver votre propre voie au travers de cette technique.
---
### 12/README Id (12/README-id.md)
## 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));
```
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:
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.
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:
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));
...
}
}
```
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:
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).
### 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).
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.
Setelah Anda mengetahui algoritme ini, pikirkan kegunaan yang menarik dan kreatif untuknya.
### 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.
Kemudian pada tahun 2012 [Inigo Quilez menulis artikel tentang cara membuat perbatasan Voronoi yang tepat](http://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm).
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?"*
Sekarang saatnya bagi Anda untuk melihat lebih dekat pada berbagai hal, terinspirasi oleh alam, dan menemukan cara Anda sendiri dalam menggunakan teknik ini!
---
### 12/README Pl (12/README-pl.md)
## Cellular Noise (pol. "szum komórkowy")
W 1996 roku, szesnaście lat po oryginalnym algorytmie szumu Perlina i pięć lat przed jego Simplex Noise, [Steven Worley napisał pracę zatytułowaną "A Cellular Texture Basis Function"](http://www.rhythmiccanvas.com/research/papers/worley.pdf). Opisuje w niej technikę teksturowania proceduralnego, która jest obecnie szeroko stosowana przez grafików.
Aby zrozumieć jej zasady, musimy zacząć myśleć w kategoriach **iteracji**. Zapewne wiesz, co to oznacza: używanie pętli ``for``. Jest tylko jeden haczyk z pętlami ``for`` w GLSL: warunek, który sprawdzamy musi być stałą (``const``). Tak więc nie ma dynamicznych pętli - liczba iteracji musi być stała.
Przyjrzyjmy się przykładowi.
### Punkty w polu odległości
Cellular Noise opiera się na polach odległości, a dokładniej odległości do najbliższego ze zbioru punktów. Załóżmy, że chcemy stworzyć pole odległości składające się z 4 punktów. Co musimy zrobić? Cóż, **dla każdego piksela chcemy obliczyć odległość do najbliższego punktu**. Oznacza to, że musimy iterować po wszystkich punktach, obliczać ich odległości do bieżącego piksela i przechować odległość do tego najbliższego.
```glsl
float min_dist = 100.; // Zmienna przechowująca odległość do najbliższego punktu
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));
```
Nie jest to zbyt eleganckie, ale załatwia sprawę. Teraz zaimplementujmy go ponownie, używając tablicy i pętli ``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);
}
```
Zauważ, jak używamy pętli ``for`` do iteracji po tablicy punktów i funkcji [``min()``](../glossary/?search=min) do śledzenia odległości do najbliższego punktu. Oto krótka działająca implementacja tego pomysłu:
W powyższym kodzie jeden z punktów jest przypisany do pozycji myszy. Pobaw się nim, abyś mógł zrozumieć intuicję stojącą za tym kodem. Następnie spróbuj ćwiczeń:
- Jak można animować pozostałe punkty?
- Po przeczytaniu [rozdziału o kształtach](../07/), wyobraź sobie ciekawe sposoby wykorzystania tego pola odległości!
- Co, jeśli chcemy dodać więcej punktów do tego pola odległości? Co jeśli chcemy dynamicznie dodawać/odejmować punkty?
### Kafelkowanie i iteracja
Zapewne zauważyłeś, że pętle ``for`` i tablice nie są zbyt dobrymi przyjaciółmi GLSL. Jak już wspomnieliśmy, pętle nie akceptują dynamicznych warunków wyjścia. Ponadto, iteracja przez wiele instancji znacznie zmniejsza wydajność twojego shadera. Oznacza to, że nie możemy użyć tego prostego, brute-force'owego podejścia dla dużych ilości punktów. Musimy znaleźć inną strategię, taką, która wykorzystuje architekturę przetwarzania równoległego GPU.
Jednym ze sposobów podejścia do tego problemu jest podzielenie przestrzeni na rozłączne obszary/komórki. Nie każdy piksel musi sprawdzać odległość do każdego punktu, prawda? Biorąc pod uwagę fakt, że każdy piksel działa w swoim własnym wątku, możemy podzielić przestrzeń na komórki, z których każda ma jeden unikalny punkt do oglądania. Ponadto, aby uniknąć aberracji na krawędziach między komórkami musimy sprawdzić odległości do punktów w sąsiednich komórkach. Jest to główna idea [artykułu Stevena Worleya](http://www.rhythmiccanvas.com/research/papers/worley.pdf). Ostatecznie każdy piksel musi sprawdzić tylko dziewięć pozycji: punkt własnej komórki i punkty w 8 komórkach wokół niego. Dzieliliśmy już przestrzeń na komórki w rozdziałach o: [wzorach kafelkowych](../09/), [losowości](../10/) i [szumie](../11/), więc mam nadzieję, że jesteś już zaznajomiony z tą techniką.
```glsl
// skalowanie
st *= 3.;
// dzielenie przestrzeni na kafelki
vec2 i_st = floor(st);
vec2 f_st = fract(st);
```
Jaki jest więc plan? Użyjemy współrzędnych kafelka (przechowywanych w części całkowitej, ``i_st``) do skonstruowania losowej pozycji punktu. Funkcja ``random2f``, której użyjemy, przyjmuje ``vec2`` i zwraca ``vec2`` z losową pozycją (o wartościach z zakresu od 0.0 do 1.0). Tak więc, dla każdego kafla będziemy mogli otrzymać jeden punkt losowo położony wewnątrz tego kafla.
```glsl
vec2 point = random2(i_st);
```
Każdy piksel wewnątrz tego kafla (przechowywany w części ułamkowej, ``f_st``) sprawdzi swoją odległość do tego nowego, losowego punktu.
```glsl
vec2 diff = point - f_st;
float dist = length(diff);
```
Wynik będzie wyglądał tak:
Musimy też sprawdzić odległości do punktów w okolicznych kafelkach, a nie tylko do tego w bieżącym kafelku. W tym celu **iterujemy** po sąsiednich kafelkach. Nie po wszystkich kafelkach, tylko po tych bezpośrednio otaczających bieżącego. Czyli od ``-1`` (lewy) do ``1`` (prawy) na osi ``x`` oraz od ``-1`` (dolny) do ``1`` (górny) na osi ``y``. Region 3x3 składający się z 9 kafelków może być iterowany przy użyciu podwójnej pętli ``for``, jak poniżej:
```glsl
for (int y= -1; y <= 1; y++) {
for (int x= -1; x <= 1; x++) {
// Względne położenie sąsiadującego kafelka
vec2 neighbor = vec2(float(x),float(y));
...
}
}
```
Teraz możemy obliczyć położenie punktów w każdym z sąsiadujących kafelków z pomocą podwójnej pętli ``for``, dodając przesunięcie sąsiedniego kafelka (``neighbor``) do współrzędnej bieżącego kafelka (``i_st``).
```glsl
...
// Losowe położenie punktu wewnątrz sąsiedniego kafelka
vec2 point = random2(i_st + neighbor);
...
```
Reszta polega na obliczeniu odległości do każdego z sąsiednich punktów i zapisaniu najmniejszej odległości w zmiennej o nazwie ``m_dist`` (z ang. "minimal distance").
```glsl
...
vec2 diff = neighbor + point - f_st;
// Odległość do punktu
float dist = length(diff);
// Zachowaj mniejszą odległość
m_dist = min(m_dist, dist);
...
```
Powyższy kod jest inspirowany [artykułem Inigo Quileza](http://www.iquilezles.org/www/articles/smoothvoronoi/smoothvoronoi.htm), w którym zauważa, jak problemy z precyzją bitową mogą być uniknięte poprzez przejście do stosowanej już przez nas przestrzeni kafelkowej (w przeciwieństwie do robienia obliczeń w domyślnych współrzędnych, niepodzielonych na części całkowite i ułamkowe):
Podsumowując: dzielimy przestrzeń na kafelki; każdy piksel liczy odległość do punktu w swoim własnym kafelku i odległość do punktów z otaczających go 8 kafelków; przechowuje najbliższą odległość. Wynikiem jest pole odległości, które wygląda jak w poniższym przykładzie:
Eksploruj tę ideę dalej:
- Przeskaluj przestrzeń o różne wartości.
- Czy możesz wymyślić inne sposoby animacji punktów?
- Co jeśli chcemy obliczyć dodatkowy punkt z pozycji myszy?
- Jakie inne sposoby konstruowania tego pola odległości możesz sobie wyobrazić, poza ``m_dist = min(m_dist, dist);``?
- Jakie ciekawe wzory można stworzyć za pomocą tego pola odległości?
Algorytm ten można również interpretować z perspektywy punktów, a nie bieżących pikseli. W takim przypadku można go opisać jako: każdy punkt rośnie, dopóki nie znajdzie rosnącego obszaru innego punktu. Odzwierciedla to niektóre z zasad wzrostu w naturze. Żywe formy kształtowane są przez napięcie między wewnętrzną siłą do rozszerzania się i wzrostu oraz zewnętrznymi siłami ograniczającymi. Klasyczny algorytm symulujący to zachowanie nazwany został za [Georgy Voronoi](https://en.wikipedia.org/wiki/Georgy_Voronoy).
### Algorytm Voronoi
Konstruowanie diagramów Voronoi z szumu komórkowego jest mniej trudne niż mogłoby się wydawać. Musimy tylko *zachować* pewną dodatkową informację o punkcie, który jest najbliżej bieżącego piksela. Do tego celu użyjemy ``vec2`` o nazwie ``m_point`` (z ang. "minimal point"). Przechowując wektor od bieżącego piksela do najbliższego punktu (zamiast samej odległości) będziemy "przechowywać" "unikalny" identyfikator tego punktu.
```glsl
...
if( dist < m_dist ) {
m_dist = dist;
m_point = point;
}
...
```
Zauważ, że w poniższym kodzie nie używamy już ``min`` do obliczania najbliższej odległości, ale zwykłegpo warunku ``if``. Dlaczego? Ponieważ chcemy zrobić coś więcej za każdym razem, gdy pojawi się nowy bliższy punkt, a mianowicie zapisać jego pozycję (linie 32 do 37).
Zauważ, jak kolor ruchomej komórki (związanej z pozycją myszy) zmienia kolor w zależności od jej położenia. To dlatego, że kolor jest przypisywany przy użyciu wartości (pozycji) najbliższego punktu.
Podnieśmy poprzeczkę, przechodząc na podejście z [artykułu Stevena Worleya](http://www.rhythmiccanvas.com/research/papers/worley.pdf). Spróbuj zaimplementować to samodzielnie. Możesz skorzystać z pomocy poniższego przykładu, klikając na niego. Zauważ, że oryginalne podejście Stevena Worleya używa zmiennej liczby punktów dla każdego kafla, więcej niż jeden w większości kafli. W tej jego nie-shaderowej implementacji (bo w C, a nie w GLSL) pomaga to przyspieszyć pętlę poprzez wczesne jej opuszczanie. Pętle GLSL nie pozwalają na zmienną liczbę iteracji, więc prawdopodobnie chcesz trzymać się jednego punktu na kafelek.
Gdy już rozgryziesz ten algorytm, pomyśl o ciekawych i kreatywnych jego zastosowaniach.
### Ulepszenie Voronoi
W 2011 roku [Stefan Gustavson zoptymalizował algorytm Stevena Worleya](http://webstaff.itn.liu.se/~stegu/GLSL-cellular/GLSL-cellular-notes.pdf) pod GPU, iterując tylko przez macierz 2x2 zamiast 3x3. To znacznie zmniejsza ilość pracy, ale może tworzyć artefakty w postaci nieciągłości na krawędziach między kafelkami. Przyjrzyj się poniższym przykładom.
Później w 2012 roku [Inigo Quilez napisał artykuł o tym, jak zrobić Voronoi z ostrymi granicami](http://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm).
Eksperymenty Inigo z Voronoi nie skończyły się na tym. W 2014 roku napisał artykuł o tym, co nazywa [voro-noise](http://www.iquilezles.org/www/articles/voronoise/voronoise.htm). Jest to funkcja, która pozwala na stopniowe interpolowanie między zwykłym szumem a Voronoi. Jego słowami:
*"Pomimo tego podobieństwa, faktem jest, że sposób użycia kafelkowania w obu metodach jest inny. Szum interpoluje/uśrednia wartości losowe (jak w Value Noise) lub gradienty (jak w Gradient Noise), podczas gdy Voronoi oblicza odległość do najbliższego punktu w kafelku. Interpolacja dwuliniowa* (ang. "bilinear") *i wartość minimalna to dwie bardzo różne operacje, ale czy na pewno? Czy można je połączyć w bardziej ogólną metrykę? Gdyby tak było, to zarówno szum jak i Voronoi mogłyby być postrzegane jako szczególne przypadki bardziej ogólnego generatora wzorów kafelkowych?"*.
Teraz nadszedł czas, abyś przyjrzał się bliżej rzeczom, zainspirował się naturą i znalazł swoje własne ujęcie tej techniki!
---
### 12/README Pt (12/README-pt.md)
## Cellular Noise (Ruído Celular)
Em 1996, dezesseis anos após o Noise original de Perlin e cinco anos antes de seu Noise Simplex, [Steven Worley escreveu um artigo chamado “A Cellular Texture Basis Function” (Uma Função de Base de Textura Celular)](http://www.rhythmiccanvas.com/research/papers/worley.pdf). Neste, ele descreve uma técnica procedimental de texturizar amplamente usada pela comunidade gráfica.
Para entender os princípios por trás disto, nós precisamos começar a pensar em termos de **iterações**. Provavelmente, você sabe o que isso significa: sim, começar a usar laços de repetição ```for```. Há apenas uma questão com laços de repetição ```for``` em GLSL: o número de vezes que estamos verificando deve ser uma constante (```const```). Logo, sem laços dinâmicos - o número de iterações deve ser fixo.
Vamos dar uma olhada em um exemplo.
### Pontos para um campo de distância
Ruídos celulares são baseados em campos de distância, a distância para o ponto mais próximo de um conjunto de pontos. Vamos dizer que nós queremos criar um campo de distância de 4 pontos. O que nós devemos fazer? Bem, **para cada píxel, nós queremos calcular a distância para o ponto mais próximo**. Que significa que nós precisamos iterar por todos os pontos, computar suas distâncias para o píxel atual e armazenar o valor para o mais próximo.
```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));
```
Isso não é muito elegante, mas resolve. Agora, vamos reimplementá-lo usando um array e um laço ```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);
}
```
Veja como nós usamos o laço ```for``` para iterar pelo array de pontos e encontrar a menor distância usando uma função [```min()```](../glossary/?search=min). Aqui está uma breve implementação funcional desta ideia:
No código acima, um ou mais pontos estão atribuídos à posição do mouse. Interaja com ele para pegar uma ideia mais intuitiva de como o código se comporta. Então, responda:
- Como você pode animar o resto dos pontos?
- Depois de ler [o capítulo sobre formas](../07/), imagine formas interessantes de usar este campo de distância!
-E se você quiser adicionar mais pontos ao campo de distância? E se nós quisermos dinamicamente adicionar/subtrair pontos?
### Tiles e Iteração
Você provavelmente percebeu que laços ```for``` e *arrays* não se dão bem com GLSL. Como mencionamos antes, laços não aceitam limites dinâmicos em sua condição de saída. Além disso, iterar por muitas instâncias, reduz a performance do shader significativamente. O que significa que nós não podemos usar essa abordagem diretamente para grandes quantidades de pontos. Nós precisamos encontrar outra estratégia, uma que tira vantagem sobre o arquitetura de processamento paralelo da GPU.
Uma forma de abordar este problema é dividindo o espaço em tiles. Cada píxel não precisa checar a distância de cada ponto, certo? Considerando o fato de cada píxel rodar em sua própria thread, nós podemos subdividir o espaço em células, cada uma com um único ponto para observar. Também, para evitar artefatos nas arestas entre as células, nós precisamos verificar as distâncias para os pontos das células vizinhas. Esta é a genial ideia do [artigo de Steven Worley](http://www.rhythmiccanvas.com/research/papers/worley.pdf). No final, cada píxel precisa verificar apenas nove posições: o ponto da própria célula e os pontos das 8 células ao seu redor. Nós já subdividimos o espaço em células no capítulo sobre [padrões], (../09/), [aleatório](../10/) e [noise](../11/), então você provavelmente já está familiarizado com essa técnica.
```glsl
// Scale
st *= 3.;
// Tile the space
vec2 i_st = floor(st);
vec2 f_st = fract(st);
```
Então, qual é o plano? Nós usaremos as coordenadas do tile (armazenadas na coordenada inteira ```i_st```) para construirmos uma posição aleatória de um ponto. A função ```random2f``` que nós usaremos recebe um ```vec2``` e nos retorna um ```vec2``` com uma posição aleatória. Então, para cada tile, nós teremos um ponto respectivo em uma posição aleatória dentro do tile.
```glsl
vec2 point = random2(i_st);
```
Cada píxel dentro do tile (armazenado em coordenadas float, ```f_st```) verificará sua distância para um ponto aleatório.
```glsl
vec2 diff = point - f_st;
float dist = length(diff);
```
O resultado se parecerá com a seguinte imagem:
Ainda precisamos verificar a distância dos pontos nos tiles ao redor, não apenas o atual. Para isso, nós precisamos **iterar** por seus tiles vizinhos. Não todos os tiles, apenas os que estão imediatamente ao redor do atual. Que compreende do tile ```-1``` (esquerda) a ```1``` (direita) no eixo ```x``` e ```-1```(inferior) e ```1``` (superior) no eixo ```y```. Podemos iterar em uma região 3x3 de 9 tiles através de um laço ```for``` duplo como esse:
```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));
...
}
}
```
Agora, nós podemos estimar a distância dos pontos para cada um dos vizinhos em nosso laço ```for``` duplo, ao adicionar o deslocamento do tile vizinho às coordenadas do tile atual.
```glsl
...
// Random position from current + neighbor place in the grid
vec2 point = random2(i_st + neighbor);
...
```
O resto é calcular a distância daquele ponto e armazenar a menor em uma variável chamada ```m_dist``` (para distância mínima).
```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);
...
```
O código acima foi inspirado por [este artigo de Inigo Quilez](http://www.iquilezles.org/www/articles/smoothvoronoi/smoothvoronoi.htm) onde ele diz:
*"... Pode valer a pena perceber que existe um truque excelente no código acima. A maioria das implementações por aí sofrem com problemas de precisão, porque eles geram seus pontos aleatórios no espaço "domínio" (como espaço "mundo" ou espaço "objeto"), que podem ser longe da origem. Pode-se resolver este problema ao aumentar a precisão dos dados, ou sendo um pouco esperto. Minha implementação não gera os pontos em um espaço "domínio", mas em espaço "célula": uma vez que as partes inteira e fracionária do ponto desejado são extraídas e a célula em que estamos trabalhando, identificada, todos nós nos importamos com o que acontece ao redor desta célula, assim nós podemos nos livrar de todas as partes inteiras de uma vez, nós economizando bits de precisão. De fato, em uma implementação de voronoi usual, as partes inteiras das coordenadas do ponto simplesmente se cancelam quando o aleatório pelos pontos da respectiva célula são subtraídos do ponto em questão. Em minha implementação acima, nós nem ao menos deixamos esse cancelamento acontecer, pois estamos movendo todos os cálculos para o espaço "célula". Estudo truque também permite que lidemos com os casos nos quais queremos usar voronoi para desenhar um planeta inteiro - poderíamos simplesmente substituir a entra para ser precisão double, realizar os cálculos de floor() e fract(), e então mudarmos para ponto-flutuante para os próximos cálculos sem pagarmos o custo de trocar toda implementação para precisão double. Naturalmente, alguns truques se aplicam ao ruído Perlin (ainda que eu não tenha visto isto documentado ou implementado)."*
Recapitulando: nós subdividimos o espaço em tiles; cada píxel calculará a distância do ponto do seu próprio tile e dos 8 ao seu redor; armazenará a menor distância. O resultado será um campo de distância que se parece com o exemplo a seguir:
Vá além ao:
- Transformar a escala no espaço para diferentes valores.
- Você consegue pensar em outras formas de animar os pontos?
- E se quisermos calcular um ponto extra com a posição do mouse?
- Quais são as outras formas de construir este campo de distância, você consegue pensar em uma além de ```m_dist = min(m_dist, dist);```?
- Que padrões interessantes você pode criar com este campo de distância?
O algoritmo pode também ser interpretado pela perspectiva do ponto e não dos píxeis. Neste caso, ele pode ser descrito como: cada ponto cresce até que ele encontre a área de crescimento de outro ponto. Isso reflete algumas leis de crescimento na natureza. Formas de vida são moldadas por essa tensão entre a força interior de crescer e se expandir e as limitações das forças externas. O clássico algoritmo que simula este comportamento foi nomeado em homenagem a [Georgy Voronoi](https://en.wikipedia.org/wiki/Georgy_Voronoy).
### O Algoritmo de Vonoroi
Construindo diagramas a partir de ruído celular é menos complicado do que parece. Nós apenas precisamos *manter* algumas informações extras sobre o ponto que é o mais próximo de cada píxel. Para isso, nós vamos usar um ```vec2``` chamado ```m_point```. Ao armazenar a direção do vetor até o centro do ponto mais próximo, ao invés de apenas a distância, nós "manteremos" um "único" identificador para aquele ponto.
```glsl
...
if( dist < m_dist ) {
m_dist = dist;
m_point = point;
}
...
```
Veja que no código a seguir que não estamos mais usando ```min``` para calcular a distância do ponto mais próximo, mas um ```if```. Por quê? Porque nós queremos fazer algo toda a vez que um ponto mais próximo aparecer, armazenar sua posição (linhas 32 a 37).
Veja como a cor do movimento celular (vinculada à posição do mouse) muda sua cor de acordo com a sua posição. Isso acontece porque a cor é atribuída usando o valor (posição) do ponto mais próximo.
Como nós fizemos antes, agora é hora de ir além, mudar para a abordagem do artigo de Steven Worley](http://www.rhythmiccanvas.com/research/papers/worley.pdf). Tente implementá-lo sozinho. Você pode usar a ajuda dos seguintes exemplos clicando neles. Veja que a abordagem original de Steven Worley usa um número variável de pontos para cada tile, mais de um em sua maioria. Em sua implementação em C, isso é usado para acelerar o laço ao fazer uma saída antecipada. Laços em GLSL não permitem um número variavel de iterações, então você provavelmente vai querer manter um ponto por tile.
Depois que você pensar neste algoritmo, pense em seus vários usos interessantes e criativos.
### Melhorando Voronoi
Em 2011, [Stefan Gustavson otimizou o algoritmo de Steven Worley para GPU](http://webstaff.itn.liu.se/~stegu/GLSL-cellular/GLSL-cellular-notes.pdf) ao iterar por uma matriz de 2x2 ao invés de 3x3. Isso reduz a quantidade de trabalho significativamente, mas pode criar artefatos em forma de descontinuidades nas arestas entre os tiles. Dê uma olhada no seguinte exemplo.
Mais tarde em 2012 [Inigo Quilez escreveu um artigo sobre como criar bordas mais precisas em Voronoi](http://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm).
Os experimentos de Inigo com Voronoi não pararam aí. Em 2014, ele escreveu um excelente artigo sobre o que ele chama [voro-noise](http://www.iquilezles.org/www/articles/voronoise/voronoise.htm), uma função que permite uma mesclagem gradual entre o ruído comum e voronoi. Em suas palavras:
*"Apesar de sua similaridade, o fato é que a forma que a grade é usada em ambos padrões é diferente. O ruído interpola valores aleatórios (como ruído de valor) ou gradiente (como em ruído de gradiente), enquanto Voronoi calcula a distância de um respectivo ponto. Agora, a interpolação bilinear e a verificação da menor distância são duas operações diferentes, ou.... elas são? Poderiam elas serem combinadas em uma métrica mais geral? Se sim, então tanto Ruído como Voronoi podem ser vistos como casos particulares de um gerador de padrão baseado em grade mais geral?"*
Agora, é hora de você dar uma olhada nas coisas, se inspire pela natureza e encontre a sua própria forma de usar esta técnica!
---
### 12/README Tr (12/README-tr.md)
## Hücresel Gürültü
1996'da, Perlin'in orijinal Gürültüsünden on altı yıl sonra ve Simpleks Gürültüsünden beş yıl önce, [Steven Worley "A Cellular Texture Basis Function" adlı bir makale yazdı](http://www.rhythmiccanvas.com/research/papers/worley.pdf). Bu makalede, grafik topluluğu tarafından artık yaygın olarak kullanılan prosedürel bir dokulama tekniği tanımladı.
Arkasındaki prensipleri anlamak için **yineleme** açısından düşünmeye başlamamız gerekir. Muhtemelen bunun ne anlama geldiğini biliyorsunuzdur: evet, ```for``` döngülerini kullanmaya başlayın. GLSL'de ```for``` döngülerinin tek bir tuhaflığı var: kontrol ettiğimiz sayı sabit (```const```) olmalıdır. Yani dinamik döngü yok — yineleme sayısı sabitlenmelidir.
Bir örneğe bakalım.
### Mesafe alanı için noktalar
Hücresel Gürültü, mesafe alanlarına dayanır; bir dizi özellik noktasından en yakın olanına olan mesafe. Diyelim ki 4 noktanın mesafe alanını yapmak istiyoruz. Ne yapmamız gerekir? **Her piksel için en yakın noktaya olan mesafeyi hesaplamak** istiyoruz. Bu, tüm noktalar arasında yinelememiz, mevcut piksele olan mesafelerini hesaplamamız ve en yakın olanın değerini saklamamız gerektiği anlamına gelir.
```glsl
float min_dist = 100.; // Bir noktaya en yakın mesafeyi saklayan değişken
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));
```
Bu çok zarif değildir, ama işi görür. Şimdi bir dizi ve ```for``` döngüsü kullanarak yeniden uygulayalım.
```glsl
float m_dist = 100.; // minimum mesafe
for (int i = 0; i < TOTAL_POINTS; i++) {
float dist = distance(st, points[i]);
m_dist = min(m_dist, dist);
}
```
Bir nokta dizisi arasında yineleme yapmak ve [```min()```](../glossary/?search=min) fonksiyonu kullanarak minimum mesafeyi takip etmek için ```for``` döngüsünü nasıl kullandığımıza dikkat edin. İşte bu fikrin kısa bir çalışan uygulaması:
Yukarıdaki kodda noktalardan biri fare konumuna atanmıştır. Bu kodun nasıl davrandığı hakkında sezgisel bir fikir edinmek için onunla oynayın. Sonra şunu deneyin:
- Geri kalan noktaları nasıl canlandırabilirsiniz?
- [Şekiller bölümünü](../07/) okuduktan sonra, bu mesafe alanını kullanmanın ilginç yollarını hayal edin!
- Ya bu mesafe alanına daha fazla nokta eklemek isterseniz? Ya dinamik olarak nokta eklemek/çıkarmak istesek?
### Döşeleme ve yineleme
Muhtemelen ```for``` döngülerinin ve *dizilerin* GLSL ile çok iyi arkadaş olmadığını fark etmişsinizdir. Daha önce söylediğimiz gibi, döngüler çıkış koşullarında dinamik sınırlar kabul etmez. Ayrıca birçok örnek arasında yineleme yapmak shader'ınızın performansını önemli ölçüde azaltır. Bu, büyük miktarda nokta için bu doğrudan yaklaşımı kullanamayacağımız anlamına gelir. GPU'nun paralel işleme mimarisinden yararlanan başka bir strateji bulmamız gerekir.
Bu soruna yaklaşmanın bir yolu, uzayı döşemelere bölmektir. Her pikselin her bir noktaya olan mesafeyi kontrol etmesi gerekmiyor, değil mi? Her piksel kendi iş parçacığında çalıştığı göz önüne alındığında, uzayı hücrelere bölebiliriz; her biri izlenecek benzersiz bir noktaya sahiptir. Ayrıca, hücreler arasındaki kenarlardaki sapmaları önlemek için komşu hücrelerdeki noktalara olan mesafeleri de kontrol etmemiz gerekir. [Steven Worley'nin makalesinin](http://www.rhythmiccanvas.com/research/papers/worley.pdf) ana parlak fikri budur. Sonuçta, her pikselin yalnızca dokuz konumu kontrol etmesi gerekir: kendi hücresinin noktası ve etrafındaki 8 hücredeki noktalar. Uzayı zaten şu bölümlerde hücrelere ayırdık: [desenler](../09/), [rastgelelik](../10/) ve [gürültü](../11/), bu yüzden umarız bu tekniğe artık aşinasınızdır.
```glsl
// Ölçekleme
st *= 3.;
// Uzayı döşeleme
vec2 i_st = floor(st);
vec2 f_st = fract(st);
```
Plan nedir? Döşeme koordinatlarını (tam sayı koordinatında saklanan, ```i_st```) bir noktanın rastgele konumunu oluşturmak için kullanacağız. Kullanacağımız ```random2f``` fonksiyonu bir ```vec2``` alır ve bize rastgele bir konuma sahip bir ```vec2``` verir. Böylece her döşeme için döşemenin içinde rastgele bir konumda bir özellik noktası olacaktır.
```glsl
vec2 point = random2(i_st);
```
O döşemenin içindeki her piksel (float koordinatında saklanan, ```f_st```) o rastgele noktaya olan mesafesini kontrol edecektir.
```glsl
vec2 diff = point - f_st;
float dist = length(diff);
```
Sonuç şöyle görünecektir:
Yine de sadece mevcut döşemedeki değil, çevreleyen döşemelerdeki noktalara olan mesafeleri de kontrol etmemiz gerekir. Bunun için komşu döşemeler arasında **yinelememiz** gerekir. Tüm döşemeler değil, sadece mevcut olanın hemen çevresindekiler. Yani ```x``` ekseninde ```-1``` (sol) ile ```1``` (sağ) döşeme ve ```y``` ekseninde ```-1``` (alt) ile ```1``` (üst) arasında. 9 döşemelik 3x3'lük bir bölge, şöyle bir çift ```for``` döngüsüyle yinelenebilir:
```glsl
for (int y= -1; y <= 1; y++) {
for (int x= -1; x <= 1; x++) {
// Izgaradaki komşu yeri
vec2 neighbor = vec2(float(x),float(y));
...
}
}
```
Şimdi, çift ```for``` döngümüzde komşu döşeme ofsetini mevcut döşeme koordinatına ekleyerek komşuların her birindeki noktaların konumunu hesaplayabiliriz.
```glsl
...
// Mevcut + komşu ızgara yerinden rastgele konum
vec2 point = random2(i_st + neighbor);
...
```
Gerisinin tamamı, o noktaya olan mesafeyi hesaplama ve en yakın olanı ```m_dist``` (minimum mesafe) adlı bir değişkende saklama ile ilgilidir.
```glsl
...
vec2 diff = neighbor + point - f_st;
// Noktaya olan mesafe
float dist = length(diff);
// Daha yakın mesafeyi tut
m_dist = min(m_dist, dist);
...
```
Yukarıdaki kod, [Inigo Quilez'in bu makalesinden](http://www.iquilezles.org/www/articles/smoothvoronoi/smoothvoronoi.htm) ilham almıştır.
Özetleyecek olursak: uzayı döşemelere ayırırız; her piksel kendi döşemesindeki ve çevresindeki 8 döşemedeki noktaya olan mesafeyi hesaplar; en yakın mesafeyi saklar. Sonuç, aşağıdaki örneğe benzeyen bir mesafe alanıdır:
Daha fazla keşfedin:
- Uzayı farklı değerlerle ölçekleyin.
- Noktaları canlandırmanın başka yollarını düşünebilir misiniz?
- Ya fare konumuyla ekstra bir nokta hesaplamak istesek?
- ```m_dist = min(m_dist, dist);``` dışında bu mesafe alanını oluşturmanın hangi diğer yollarını hayal edebilirsiniz?
- Bu mesafe alanıyla hangi ilginç desenleri yapabilirsiniz?
Bu algoritma, piksellerin değil noktaların perspektifinden de yorumlanabilir. Bu durumda şöyle tarif edilebilir: her nokta, başka bir noktanın büyüyen alanını bulana kadar büyür. Bu, doğadaki bazı büyüme kurallarını yansıtır. Yaşayan formlar, genişleme ve büyüme iç gücü ile dış güçlerin sınırlamaları arasındaki bu gerilim tarafından şekillendirilir. Bu davranışı simüle eden klasik algoritma, [Georgy Voronoi](https://en.wikipedia.org/wiki/Georgy_Voronoy) adını taşır.
### Voronoi Algoritması
Hücresel gürültüden Voronoi diyagramları oluşturmak göründüğünden daha az zordur. Sadece piksele en yakın olan kesin nokta hakkında bazı ek bilgileri *saklamamız* gerekir. Bunun için ```m_point``` adlı bir ```vec2``` kullanacağız. En yakın noktanın merkezine olan vektör yönünü sadece mesafe yerine saklayarak, o noktanın "benzersiz" bir tanımlayıcısını "saklayacağız".
```glsl
...
if( dist < m_dist ) {
m_dist = dist;
m_point = point;
}
...
```
Aşağıdaki kodda en yakın mesafeyi hesaplamak için artık ```min``` kullanmadığımızı, normal bir ```if``` ifadesi kullandığımızı not edin. Neden? Çünkü daha yakın yeni bir nokta göründüğünde aslında daha fazlasını yapmak, yani konumunu saklamak (32-37 arası satırlar) istiyoruz.
Hareket eden hücrenin (fare konumuna bağlı) renginin konumuna göre nasıl değiştiğine dikkat edin. Bu, rengin en yakın noktanın değeri (konumu) kullanılarak atanmasından kaynaklanır.
Daha önce yaptığımız gibi, şimdi bunu ölçeklendirmenin, [Steven Worley'nin makalesinin yaklaşımına](http://www.rhythmiccanvas.com/research/papers/worley.pdf) geçmenin zamanı. Kendiniz uygulamayı deneyin. Tıklayarak aşağıdaki örneğin yardımını alabilirsiniz.
Bu algoritmayı anladıktan sonra, ilginç ve yaratıcı kullanımlar düşünün.
### Voronoi'yi İyileştirme
2011'de, [Stefan Gustavson Steven Worley'nin algoritmasını GPU için optimize etti](http://webstaff.itn.liu.se/~stegu/GLSL-cellular/GLSL-cellular-notes.pdf), 3x3 yerine sadece 2x2 matris üzerinde yineleme yaparak. Bu, iş miktarını önemli ölçüde azaltır, ancak döşemeler arasındaki kenarlarda süreksizlik şeklinde artefaktlar oluşturabilir. Aşağıdaki örneklere bakın.
Daha sonra 2012'de [Inigo Quilez kesin Voronoi sınırları yapma hakkında bir makale yazdı](http://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm).
Inigo'nun Voronoi deneyleri burada bitmedi. 2014'te [voro-noise](http://www.iquilezles.org/www/articles/voronoise/voronoise.htm) dediği şey hakkında güzel bir makale yazdı, normal gürültü ile voronoi arasında kademeli bir harmanlama sağlayan bir fonksiyon. Kendi sözleriyle:
*"Bu benzerliğe rağmen, gerçek şu ki ızgaranın her iki desende kullanılma şekli farklıdır. Gürültü rastgele değerleri (değer gürültüsünde olduğu gibi) veya gradyanları (gradyan gürültüsünde olduğu gibi) enterpolasyon yapar/ortalar, Voronoi ise en yakın özellik noktasına olan mesafeyi hesaplar. Şimdi, düzgün çift doğrusal enterpolasyon ve minimum değerlendirme çok farklı iki işlemdir, veya... öyle midir? Belki daha genel bir metrikte birleştirilebilirler mi? Eğer öyleyse, hem Gürültü hem de Voronoi desenleri, daha genel bir ızgara tabanlı desen oluşturucunun özel durumları olarak görülebilir mi?"*
Şimdi yakından bakma, doğadan ilham alma ve bu tekniğe kendi yaklaşımınızı bulma zamanı!
#### Araç kutunuz için
* [LYGIA'nın üretken fonksiyonları](https://lygia.xyz/generative), GLSL'de desenler üretmek için yeniden kullanılabilir fonksiyonlar kümesidir. Üretken sanat yaratmak için rastgelelik ve gürültüyü nasıl kullanacağınızı öğrenmek için harika bir kaynaktır. Yeniden kullanılabilirlik, performans ve esneklik için tasarlanmış çok ayrıntılı bir kütüphanedir. Ve herhangi bir projeye ve framework'e kolayca eklenebilir.
---
### 12/README Ua (12/README-ua.md)
## Клітинний шум
У 1996 році, через шістнадцять років після оригінального шуму Перліна та за п’ять років до його симплексного шуму, Steven Worley написав статтю під назвою [“Базова функція клітинної текстури”](http://www.rhythmiccanvas.com/research/papers/worley.pdf). У ній він описує техніку процедурного текстурування, яка зараз широко використовується графічною спільнотою.
Щоб зрозуміти принципи, що лежать в її основі, нам потрібно почати думати в термінах **ітерацій**. Напевно, ви розумієте, що це означає використання циклів ```for```. У циклах ```for``` в GLSL є лише одна заковика: число, яке використовується у перевірці лічильника, має бути константою ([```const```](../glossary/?lan=ua&search=const)). Отже, ніяких динамічних циклів — кількість ітерацій має бути фіксованою.
Давайте розглянемо приклад.
### Точки у полі відстаней
Клітинний шум базується на полях відстаней, що розташовані до найближчої точки з певного набору. Скажімо, ми хочемо створити поле відстаней з 4 точок. Що нам потрібно зробити? **Для кожного пікселя ми хочемо обчислити відстань до найближчої точки**. Це означає, що нам потрібно виконати ітерацію по всім точкам, обчислити до них відстані від поточного пікселя та зберегти значення до найближчої.
```glsl
float min_dist = 100.; // змінна для збереження відстані до найближчої точки
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));
```
Не дуже елегантно, але робить свою справу. Тепер реалізуємо цей підхід за допомогою масиву та циклу ```for```:
```glsl
float m_dist = 100.; // мінімальна відстань
for (int i = 0; i < TOTAL_POINTS; i++) {
float dist = distance(st, points[i]);
m_dist = min(m_dist, dist);
}
```
Зверніть увагу, як ми використовуємо цикл ```for```, щоб перебирати масив точок і відстежувати мінімальну відстань за допомогою функції [```min()```](../glossary/?lan=ua&search=min). Ось коротка робоча реалізація цієї ідеї:
У наведеному вище коді одна з точок прив'язана до положення курсору. Пограйте з прикладом, щоб отримати краще інтуїтивне уявлення щодо поведінки програми. Потім спробуйте наступне:
- Як анімувати решту точок?
- Прочитавши [розділ про фігури](../07/?lan=ua), уявіть цікаві способи використання з цим полем відстаней!
- Як додати більше точок до цього поля відстаней? Що можна зробити для динамічного додавання або видалення точок?
### Замощення та ітерація
Ви, мабуть, помітили, що цикли ```for``` та *масиви* не дуже дружать з GLSL. Як ми вже говорили раніше, місцеві цикли не здатні на динамічну кількість ітерацій. Крім того, велика кількість ітерацій значно знижує продуктивність вашого шейдера. Це означає, що ми не можемо використовувати цей прямолінійний підхід для великої кількості точок. Нам потрібно знайти іншу стратегію, яка буде використовувати переваги архітектури GPU з її паралельними обчисленнями.
Один з підходів до розв'язання цієї проблеми — це розділення простору на плитки. Кожному пікселю не обов'язково перевіряти відстань до кожної окремої точки, чи не так? Враховуючи той факт, що кожен піксель працює у власному потоці, ми можемо розділити простір на комірки, кожна з яких матиме одну унікальну точку для спостереження. Крім того, щоб уникнути аберацій на межах між комірками, нам потрібно перевірити відстань до точок лише у сусідніх клітинах. Це і є головною чудовою ідеєю у [статті Steven Worley](http://www.rhythmiccanvas.com/research/papers/worley.pdf). Зрештою, кожен піксель має перевірити лише дев’ять позицій: точку своєї клітини та точки у 8 клітинах навколо неї. Ми вже поділяли простір на комірки в розділах про: [патерни](../09/?lan=ua), [випадковість](../10/?lan=ua) та [шум](../11/?lan=ua), тож, сподіваюся, ви вже знайомі з цією технікою.
```glsl
// Масштаб
st *= 3.;
// Розділ простору на плитки
vec2 i_st = floor(st);
vec2 f_st = fract(st);
```
Отже, який план? Ми будемо використовувати координати клітини-плитки, збережені в цілочисельній координаті ```i_st```, щоб побудувати випадкову позицію точки. Функція ```random2f```, яку ми будемо використовувати, отримує на вхід ```vec2``` та повертає нам також ```vec2``` з випадковою для даної клітини координатою. Таким чином, для кожної плитки ми матимемо одну особливу точку у випадковому місці цієї плитки.
```glsl
vec2 point = random2(i_st);
```
Кожен піксель усередині плитки, з координатою збереженою у змінній ```f_st```, перевірятиме свою відстань до випадкової точки, про яку ми говорили раніше.
```glsl
vec2 diff = point - f_st;
float dist = length(diff);
```
Результат буде виглядати так:
Нам все ще потрібно перевірити відстані до точок у навколишніх клітинах, а не лише на поточній. Для цього нам потрібно **ітерувати** сусідні клітини. Не всі клітини, а лише ті, що знаходяться безпосередньо навколо поточної. Тобто від ```-1``` клітини ліворуч, до ```+1``` клітини праворуч по осі ```x``` та від ```-1``` клітини знизу до ```+1``` клітини зверху по осі ```y```. Цю ділянку розміром 3x3 із 9 клітин можна обійти за допомогою подвійного циклу ```for```:
```glsl
for (int y= -1; y <= 1; y++) {
for (int x= -1; x <= 1; x++) {
// Сусідня позиція клітини у сітці
vec2 neighbor = vec2(float(x), float(y));
...
}
}
```
Тепер у вкладеному циклі ```for``` ми можемо обчислити положення наших випадкових точок у кожній сусідній клітині, додаючи зміщення сусідньої клітини до координат поточної.
```glsl
...
// Положення випадкової точки у сусідній плитці
vec2 point = random2(i_st + neighbor);
...
```
Решта зводиться до обчислення відстаней до цієї точки та збереження найближчої у змінну ```m_dist```.
```glsl
...
vec2 diff = neighbor + point - f_st;
// Відстань до точки
float dist = length(diff);
// Збереження ближчої дистанції
m_dist = min(m_dist, dist);
...
```
Наведений вище код створено на основі [статті Inigo's Quilez](http://www.iquilezles.org/www/articles/smoothvoronoi/smoothvoronoi.htm), де він писав:
*"... варто зазначити, що у наведеному вище коді є гарний трюк. Більшість реалізацій страждають від проблем із точністю, оскільки вони генерують свої випадкові точки в просторі "домену" (наприклад, у "глобальному" просторі чи просторі "об'єкта"), який може бути як завгодно далеко від початку координат. Проблему можна вирішити, перемістивши весь код до типів даних з вищою точністю, або проявивши трохи кмітливості. Моя реалізація генерує точки не в просторі "домену", а в просторі "комірки": як тільки із фрагментного пікселя отримано цілу та дробову частини, а значить визначено клітину, в якій ми працюємо, нас цікавитиме лише те, що відбувається навколо цієї клітини, а не весь простір. Тобто ми можемо відкинути цілочисельну частину значення наших координат та зберегти кілька біт точності. Насправді у звичайній реалізації діаграми Вороного, цілі частини координат точки просто скасовуються, коли випадкові точки клітини віднімаються від поточної шейдерної точки. У реалізації вище ми не робимо цього, оскільки переносимо всі обчислення в простір "комірки". Цей підхід дозволяє накласти діаграму Вороного хоч на цілу планету — достатньо просто подвоїти точність для вхідних даних, виконати для них обчислення з floor() і fract(), а решту обчислень проводити вже зі звичайною точністю для float, не витрачаючи обчислювальні ресурси на зміну всієї реалізації до подвійної точності. Звісно, той самий трюк можна застосувати й до підходів з шумом Перліна, але я ніколи не бачив подібну реалізацію чи опис подібного алгоритму)."*
Підсумовуючи: розбиваємо простір на клітини. Кожен піксель обчислює відстань до точки у власній клітині та навколишніх 8 клітинах, зберігаючи найближчу відстань. В результаті маємо поле відстаней, що виглядає як на прикладі нижче:
Дослідіть цей приклад глибше:
- Масштабуйте простір різними значеннями.
- Вигадайте інші способи анімації точок.
- Що потрібно зробити для обчислення додаткової точки у положенні курсору?
- Які інші способи побудови цього поля відстаней ви можете собі уявити, окрім ```m_dist = min(m_dist, dist);```?
- Які цікаві візерунки можна зробити за допомогою цього поля відстаней?
Цей алгоритм також можна інтерпретувати з точки зору точок, а не пікселів. У цьому випадку його можна описати таким чином: кожна точка росте, доки не натрапить на область росту іншої точки. Ця поведінка відображає деякі правила росту в природі. Живі організми формуються через цю напругу між внутрішньою силою зростання й розширення та обмеженнями зовнішніх сил. Класичний алгоритм, який імітує таку поведінку, названий на честь [Георгія Вороного](https://en.wikipedia.org/wiki/Georgy_Voronoy).
### Алгоритм Вороного
Побудувати діаграми Вороного з клітинного шуму не так складно, як може здатися. Нам просто потрібно *зберегти* додаткову інформацію про найближчу точку до пікселя. Для цього ми використаємо змінну ```m_point``` типу ```vec2```. Зберігаючи вектор напрямку до найближчої точки замість відстані, ми "отримаємо" "унікальний" ідентифікатор цієї точки.
```glsl
...
if ( dist < m_dist ) {
m_dist = dist;
m_point = point;
}
...
```
Зауважте, що в наступному коді, для обчислення найближчої відстані ми використовуємо звичайний оператор ```if``` замість функції ```min```. Чому? Тому що, при знаходженні нової найближчої точки, ми хочемо зробити додаткову дію і зберегти її координати (рядки 32-37).
Зверніть увагу, як колір рухомої комірки, прив'язаної до положення курсору, змінює колір відповідно до його положення. Це тому, що колір визначається залежно від позиції найближчої точки.
Як і у попередніх прикладах, настав час збільшити масштаби, скориставшись підходом зі [статті за авторства Steven Worley](http://www.rhythmiccanvas.com/research/papers/worley.pdf). Спробуйте реалізувати його самостійно. Ви можете скористатися допомогою наступного прикладу, клацнувши на нього. Зауважте, що оригінальний підхід від Steven Worley використовує змінну кількість точок для кожної клітини, більш ніж одну у більшості випадків. У його програмній реалізації на мові C це використовується для прискорення циклу завдяки раннім виходам із нього. Цикли GLSL не дозволяють змінювати кількість ітерацій, тому вам, ймовірно, доведеться використовувати лише одну точку на клітину.
Розібравшись із цим алгоритмом, подумайте про цікаві та креативні способи його використання.
### Поліпшення діаграми Вороного
У 2011 році [Stefan Gustavson оптимізував алгоритм Steven Worley для GPU](https://web.archive.org/web/20220530233245/https://weber.itn.liu.se/~stegu/GLSL-cellular/GLSL-cellular-notes.pdf), обходячи лише матрицю 2x2 замість 3x3. Це значно зменшує обсяг роботи, але може створювати артефакти у вигляді розривів на краях між клітинами. Подивіться на наступні приклади:
Пізніше у 2012 році [Inigo Quilez написав статтю про створення точних меж для комірок Вороного](http://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm).
На цьому експерименти Inigo з Вороним не закінчилися. У 2014 році він написав чудову статтю про функцію [voro-noise](http://www.iquilezles.org/www/articles/voronoise/voronoise.htm), яка дозволяє поступово змішувати звичайний шум з комірками Вороного. Ось вирізка з його слів:
*"Попри схожість, сітка в обох патернах використовується по різному. Шум інтерполює/усереднює випадкові значення (як у шумі значення) або градієнти (як у градієнтному шумі), тоді як алгоритм Вороного обчислює відстань до найближчої опорної точки. Плавна білінійна інтерполяція та обчислення мінімума — дві дуже різні операції чи... ні? Чи можна їх об’єднати у більш загальну метрику? Якщо так, то шум та патерни Вороного можна розглядати як окремі випадки більш загального генератора патернів на основі регулярної сітки?»*
Настав час придивитися до навколишніх речей, надихнутися природою, знайти власну ідею та спробувати сили у цій техніці!
---
### 12/README Vi (12/README-vi.md)
## Nhiễu mô phỏng tế bào (Cellular noise)
Vào năm 1996, mười sáu năm sau khi thuật toán sinh nhiễu đầu tiên của Perlin được công bố, và năm năm sau khi Thế giới biết đến thuật toán Simplex Noise của ông, [Steven Worley đã viết một báo cáo khoa học với tên gọi "Vân bề mặt mô phỏng tế bào" (A Cellular Texture Basis Function)](http://www.rhythmiccanvas.com/research/papers/worley.pdf). Trong nghiên cứu của mình, ông ấy đã mô tả một kỹ thuật sinh vân bề mặt mà giờ đây được sử dụng rộng khắp bởi cộng đồng đồ hoạ.
Để hiểu được các nguyên lý đằng sau, ta cần tư duy theo kiểu **duyệt (iteration)**. Có thể bạn nghe thấy quen quen, đúng, ta đã suy nghĩ tương tự khi sử dụng vòng lặp ```for``` rồi. Có một hạn chế về vòng lặp ```for``` trong GLSL, đó là: số vòng lặp phải cố định.
Hãy cùng nhìn một ví dụ.
### Các điểm trong một distance field
Nhiễu mô phỏng tế bào (Cellular noise) dựa trên distance field, khoảng cách tới một trong số những đỉnh gần nhất. Giả sử ta muốn tạo một distance field có 4 đỉnh. Ta phải làm gì ? **Với mỗi điểm ảnh, tính khoảng cách tới đỉnh gần nhất**. Điều đó có nghĩa là ta cần phải duyệt qua tất cả các đỉnh, tính khoảng cách từ điểm ảnh tới từng đỉnh một và lưu lại khoảng cách gần nhất.
```glsl
float min_dist = 100.; // Biến lưu lại khoảng cách gần nhất
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));
```
Nhìn thì không tinh tế lắm nhưng được việc. Giờ hãy chuyển đoạn code kia thành một vòng lặp nhé.
```glsl
float m_dist = 100.; // khoảng cách nhỏ nhất
for (int i = 0; i < TOTAL_POINTS; i++) {
float dist = distance(st, points[i]);
m_dist = min(m_dist, dist);
}
```
Chú ý cách tôi dùng vòng lặp ```for``` để duyệt qua mảng chứa vị trí từng đỉnh, và lưu lại khoảng cách nhỏ nhất bằng hàm [```min()```](../glossary/?lan=vi&search=min). Đoạn code dưới đây làm đúng như vậy:
Trong đoạn code phía trên, một trong các đỉnh là vị trí của con trỏ chuột. Di chuyển con trỏ chuột để có minh hoạ trực quan về thuật toán này nhé. Sau đó hãy thử nghĩ:
- Làm sao để di chuyển các đỉnh còn lại ?
- Sau khi đọc [Chương hình dạng](../07/?lan=vi), hãy nghĩ ra các cách khác để sử dụng distance field
- Nếu muốn thêm nhiều đỉnh hơn thì làm thế nào ? Nếu muốn tự do thêm bớt đỉnh thì sao ?
### Vòng lặp duyệt các phần tử
Bạn có thể đã nhận ra vòng lặp ```for``` và *mảng* không phải là bạn tốt của GLSL. Như tôi đã nói trước đó, vòng lặp yêu cầu cố định số vòng lặp ngay từ đầu. Ngoài ra thì việc duyệt từng phần tử cũng khiến code shader chậm hơn đáng kể. Điều đó có nghĩa là nếu có nhiều đỉnh ta không thể dùng cách này. Ta phải tìm một chiến thuật khác, sao cho tận dụng được ưu thế về kiến trúc tính toán song song của GPU.
Một giải pháp được đưa ra là chia nhỏ không gian thành nhiều phần. Đâu nhất thiết phải tính khoảng cách của từng điểm ảnh với tất cả các đỉnh, phải không ? Giả sử mỗi điểm ảnh được xử lý trên một thread riêng, ta có thể chia canvas thành nhiều ô, mỗi ô chỉ có 1 đỉnh trong đó, gọi là nhân. Để tránh lỗi ở phần biên giới giữa các ô, ta sẽ cần tính khoảng cách của các pixel trong mỗi ô với nhân của các ô lân cận nữa. Đó chính là ý tưởng chủ đạo trong [nghiên cứu của Steven Worley](http://www.rhythmiccanvas.com/research/papers/worley.pdf). Tóm lại, mỗi điểm ảnh chỉ cần tính khoảng cách với tối đa 9 nhân: 1 nhân ở cùng ô với điểm ảnh, và 8 nhân ở các ô xung quanh. Ta cũng đã biết cách chia nhỏ canvas thành nhiều ô ở các chương trước khi bàn về: [Mẫu họa tiết](../09/?lan=vi), [Sự ngẫu nhiên](../10/?lan=vi) và [Nhiễu](../11/?lan=vi), nên tôi hy vọng bạn đã thuần thục kỹ năng này rồi.
```glsl
// Phóng to
st *= 3.;
// Chia nhỏ
vec2 i_st = floor(st);
vec2 f_st = fract(st);
```
Vậy, kế hoạch là gì ? Ta sẽ dùng toạ độ hàng cột (phần nguyên) của mỗi ô (lưu trong ```i_st```) để sinh một cặp số ngẫu nhiên, chính là vị trí của nhân trong ô đó. Hàm ```random2```
nhận một ```vec2``` và trả về một ```vec2``` gồm 2 số ngẫu nhiên, chính là để thực hiện việc sinh ra một nhân có vị trí ngẫu nhiên trong ô này.
```glsl
vec2 point = random2(i_st);
```
Mỗi điểm ảnh trong ô này sẽ tính khoảng cách từ toạ độ của chính nó (lưu trong ```f_st```) với nhân.
```glsl
vec2 diff = point - f_st;
float dist = length(diff);
```
Kết quả thu được như sau:
Ta sẽ cần tính thêm khoảng cách tới nhân của các ô xung quanh nữa. Để làm được việc đó, ta cần *duyệt* qua các ô xung quanh, tức là các ô nằm trong phạm vi 3x3 có toạ độ X và Y trong khoảng [-1, 1] so với ô hiện tại. Ta có thể dùng 2 vòng lặp ```for``` lồng nhau để làm việc đó:
```glsl
for (int y= -1; y <= 1; y++) {
for (int x= -1; x <= 1; x++) {
// Các ô liền kề trong lưới
vec2 neighbor = vec2(float(x),float(y));
...
}
}
```
Hãy nhớ rằng các hàm ngẫu nhiên không thật sự ngẫu nhiên, vì thế ta có thể biết vị trí của nhân ở một ô bất kỳ bằng cách gọi lại hàm random2 với tham số giống như ở chính ô đó vậy.
```glsl
...
// Tính vị trí nhân ở ô liền kề
vec2 point = random2(i_st + neighbor);
...
```
Phần còn lại chỉ là tính khoảng cách với các nhân và lưu lại khoảng cách nhỏ nhất vào biến ```m_dist```.
```glsl
...
vec2 diff = neighbor + point - f_st;
// Khoảng cách tới nhân
float dist = length(diff);
// Lưu khoảng cách nhỏ nhất
m_dist = min(m_dist, dist);
...
```
Đoạn code trên lấy cảm hứng từ [một bài báo của Inigo's Quilez](http://www.iquilezles.org/www/articles/smoothvoronoi/smoothvoronoi.htm) mà trong đó ông có viết:
*"... đoạn code trên có thể cải tiến hơn nữa chỉ nhờ một mẹo nhỏ. Các đoạn code tương tự có rủi ro về sai số, vì vị trí nhân được lưu là toạ độ tuyệt đối. Ta có thể sử dụng các kiểu dữ liệu có độ chính xác cao hơn để khắc phục, nhưng còn cách khác hay hơn. Code của tôi không dùng toạ độ tuyệt đối mà chỉ dùng toạ độ tương đối trong mỗi ô thôi: sau khi tách được phần nguyên và phần thập phân, việc sinh vị trí ngẫu nhiên của nhân được thực hiện giống nhau trong mọi ô, vì thế mà phần nguyên không còn cần thiết nữa, tiết kiệm rất nhiều không gian bộ nhớ. Thực tế thì ở các đoạn code sinh voronoi thông thường, tuy sử dụng toạ độ tuyệt đối nhưng nó vẫn phải đảm bảo nằm trong ô, tức là vẫn có ràng buộc gián tiếp về toạ độ tương đối. Còn ở đoạn code trên, ta thậm chí không cần quan tâm tới ràng buộc đó, bởi toạ độ được sinh ra chắc chắn sẽ nằm trong ô. Mẹo nhỏ này có thể áp dụng cả trong trường hợp số lượng điểm ảnh khổng lồ - ta sẽ cần sử dụng kiểu dữ liệu double có khoảng giá trị lớn hơn float, nhưng ngay sau khi tách được phần thập phân, ta chỉ cần làm việc với phần thập phân lưu bằng một biến float là đủ. Tất nhiên là mẹo này cũng có thể áp dụng cho Perlin noise (nhưng tôi chưa từng thấy nó được implement hay mô tả theo cách này)."*
Tóm tắt: Ta chia canvas thành nhiều ô, mỗi ô có một nhân; mỗi điểm ảnh sẽ tính khoảng cách tới nhân trong ô tương ứng và cả 8 ô xung quanh; lưu lại khoảng cách nhỏ nhất. Kết quả thu được là 1 distance field trông như sau:
Hãy thử vài thứ phức tạp hơn:
- Chia canvas thành lưới có kích thước khác
- Làm thế nào để di chuyển các nhân trong mỗi ô ?
- Nếu ta coi vị trí của con trỏ chuột là một nhân thì sao ?
- Nếu không dùng công thức ```m_dist = min(m_dist, dist);``` thì còn cách nào khác để tìm khoảng cách gần nhất không ?
- Dùng distance field này tạo được các họa tiết nào ?
Thuật toán này cũng có thể được mô tả theo cách khác, thay vì bắt đầu bằng các điểm ảnh ta sẽ lấy các nhân làm cơ sở. Cụ thể như sau: Mỗi nhân sẽ tự lan rộng vùng ảnh hưởng ra xung quanh tới khi chạm với các vùng ảnh hưởng khác. Trong tự nhiên thì nhiều loài động thực vật trưởng thành theo cách này. Các hình thái sinh vật sống được hình thành bởi hai tác động chính: một là nội lực đẩy từ bên trong ra khiến nó ngày càng sinh sôi và lớn hơn, hai là ngoại lực từ bên ngoài kiềm chế mức độ sinh trưởng lẫn nhau. Thuật toán mô phỏng theo quan sát này được đặt tên theo nhà toán học đã định nghĩa nó, đó là [Georgy Voronoi](https://en.wikipedia.org/wiki/Georgy_Voronoy).
### Thuật toán Voronoi
Việc tạo ra sơ đồ Voronoi từ cellular noise không khó như hình dung. Ta chỉ cần *tốn thêm ít bộ nhớ* để lưu các thông tin. Để làm điều đó ta sẽ dùng một biến kiểu ```vec2``` có tên là ```m_point```. Bằng cách lưu lại hướng từ điểm ảnh tới nhân gần nhất, thay vì chỉ có thông tin về khoảng cách, ta còn xác định cả đỉnh gần nhất luôn.
```glsl
...
if( dist < m_dist ) {
m_dist = dist;
m_point = point;
}
...
```
Trong đoạn code dưới đây, tôi không dùng hàm ```min``` nữa mà dùng lệnh ```if``` cơ bản. Vì tôi không chỉ muốn lưu lại khoảng cách gần nhất mà còn muốn biết nhân gần nhất nữa (dòng 32 tới 37).
Nếu bạn di chuyển con trỏ chuột trong canvas, bạn sẽ thấy con trỏ chuột cũng được tính là một nhân. Tôi làm vậy để bạn có thể hiểu hơn về thuật toán này. Thậm chí, màu của các pixel sẽ thay đổi theo toạ độ con trỏ chuột.
Giờ hãy chuyển qua thuật toán tương tự được [mô tả trong báo cáo của Steven Worley](http://www.rhythmiccanvas.com/research/papers/worley.pdf). Bạn hãy tự code thuật toán này. Bạn cũng có thể tham khảo đoạn code dưới đây bằng cách click vào ảnh minh hoạ. Thuật toán ban đầu của Steven Worley có nhiều nhân trong một ô thay vì chỉ có một nhân, nhưng vì ông dùng ngôn ngữ C để lập trình, nên có thể thay đối số vòng lặp tuỳ ý. GLSL không cho phép điều đó, nên ta sẽ giới hạn số nhân ở mỗi ô là 1.
Khi bạn đã hiểu thuật toán này rồi, hãy nghĩ ra cách để tận dụng nó.
### Cải tiến Voronoi
Năm 2011, [Stefan Gustavson đã cải tiến thuật toán của Steven Worley cho GPU](http://webstaff.itn.liu.se/~stegu/GLSL-cellular/GLSL-cellular-notes.pdf) chỉ bằng cách duyệt qua ma trận 2x2 thay vì 3x3. Điều này giúp giảm số lượng phép tính đáng kể, nhưng cũng dễ làm cho các cạnh không đồng đều. Hãy thử nhìn các ví dụ sau:
Khoảng cuối năm 2012, [Inigo Quilez đã đăng một bài báo về cách vẽ các đường viền Voronoi một cách chính xác](http://www.iquilezles.org/www/articles/voronoilines/voronoilines.htm).
Thí nghiệm của Inigo với Voronoi không chỉ dừng lại ở đó. Vào năm 2014, ông đã công bố một nghiên cứu thú vị mà ông gọi là [voro-noise](http://www.iquilezles.org/www/articles/voronoise/voronoise.htm), một hàm có khả năng chuyển tiếp giữa nhiễu ngẫu nhiên và Voronoi. Trong báo cáo đó ông có viết:
*"Dù cả hai thuật toán sinh nhiễu đều dùng hệ thống lưới nhưng cách dùng rất khác nhau. Value noise thì nội suy giữa các đỉnh có giá trị đi kèm ngẫu nhiên, Gradient noise thì nội suy giữa các dải màu ngẫu nhiên, còn Voronoi thì tính khoảng cách tới các đỉnh ngẫu nhiên. Nếu cả nội suy có lọc bilinear và công thức xác định khoảng cách gần nhất có thể tổng quát hoá thành một phép toán thì cả nhiễu thông thường và sơ đồ Voronoi sẽ được quy về 2 trường hợp của cùng một thuật toán sinh họa tiết trên một lưới xác định phải không ?"*
Bạn hãy quan sát thật kỹ thế giới xung quanh, thiên nhiên đầy nhiệm màu và sẽ giúp bạn tự tìm ra kỹ thuật sinh nhiễu của riêng mình !
---
### 13/README (13/README.md)
## Fractal Brownian Motion
Noise tends to mean different things to different people. Musicians will think of it in terms of disturbing sounds, communicators as interference and astrophysicists as cosmic microwave background radiation. These concepts bring us back to the physical reasons behind randomness in the world around us. However, let's start with something more fundamental, and more simple: waves and their properties. A wave is a fluctuation over time of some property. Audio waves are fluctuations in air pressure, electromagnetical waves are fluctuations in electrical and magnetic fields. Two important characteristics of a wave are its amplitude and frequency. The equation for a simple linear (one-dimensional) wave looks like this:
* Try changing the values of the frequency and amplitude to understand how they behave.
* Using shaping functions, try changing the amplitude over time.
* Using shaping functions, try changing the frequency over time.
By doing the last two exercises you have managed to "modulate" a sine wave, and you just created AM (amplitude modulated) and FM (frequency modulated) waves. Congratulations!
Another interesting property of waves is their ability to add up, which is formally called superposition. Comment/uncomment and tweak the following lines. Pay attention to how the overall appearance changes as we add waves of different amplitudes and frequencies together.
* Experiment by changing the frequency and amplitude for the additional waves.
* Is it possible to make two waves cancel each other out? What will that look like?
* Is it possible to add waves in such a way that they will amplify each other?
In music, each note is associated with a specific frequency. The frequencies for these notes follow a pattern which we call a scale, where a doubling or halving of the frequency corresponds to a jump of one octave.
Now, let's use Perlin noise instead of a sine wave! Perlin noise in its basic form has the same general look and feel as a sine wave. Its amplitude and frequency vary somewhat, but the amplitude remains reasonably consistent, and the frequency is restricted to a fairly narrow range around a center frequency. It's not as regular as a sine wave, though, and it's easier to create an appearance of randomness by summing up several scaled versions of noise. It is possible to make a sum of sine waves appear random as well, but it takes many different waves to hide their periodic, regular nature.
By adding different iterations of noise (*octaves*), where we successively increment the frequencies in regular steps (*lacunarity*) and decrease the amplitude (*gain*) of the **noise** we can obtain a finer granularity in the noise and get more fine detail. This technique is called "fractal Brownian Motion" (*fBM*), or simply "fractal noise", and in its simplest form it can be created by the following code:
* Progressively change the number of octaves to iterate from 1 to 2, 4, 8 and 10. See what happens.
* When you have more than 4 octaves, try changing the lacunarity value.
* Also with >4 octaves, change the gain value and see what happens.
Note how with each additional octave, the curve seems to get more detail. Also note the self-similarity while more octaves are added. If you zoom in on the curve, a smaller part looks about the same as the whole thing, and each section looks more or less the same as any other section. This is an important property of mathematical fractals, and we are simulating that property in our loop. We are not creating a *true* fractal, because we stop the summation after a few iterations, but theoretically speaking, we would get a true mathematical fractal if we allowed the loop to continue forever and add an infinite number of noise components. In computer graphics, we always have a limit to the smallest details we can resolve, for example when objects become smaller than a pixel, so there is no need to make infinite sums to create the appearance of a fractal. A lot of terms may be needed sometimes, but never an infinite number.
The following code is an example of how fBm could be implemented in two dimensions to create a fractal-looking pattern:
* Reduce the number of octaves by changing the value on line 37
* Modify the lacunarity of the fBm on line 47
* Explore by changing the gain on line 48
This technique is commonly used to construct procedural landscapes. The self-similarity of the fBm is perfect for mountains, because the erosion processes that create mountains work in a manner that yields this kind of self-similarity across a large range of scales. If you are interested in this use, you should definitely read [this great article by Inigo Quiles about advanced noise](http://www.iquilezles.org/www/articles/morenoise/morenoise.htm).
Using more or less the same technique, it's also possible to obtain other effects like what is known as **turbulence**. It's essentially an fBm, but constructed from the absolute value of a signed noise to create sharp valleys in the function.
```glsl
for (int i = 0; i < OCTAVES; i++) {
value += amplitude * abs(snoise(st));
st *= 2.;
amplitude *= .5;
}
```
Another member of this family of algorithms is the **ridge**, where the sharp valleys are turned upside down to create sharp ridges instead:
```glsl
n = abs(n); // create creases
n = offset - n; // invert so creases are at top
n = n * n; // sharpen creases
```
Another variant which can create useful variations is to multiply the noise components together instead of adding them. It's also interesting to scale subsequent noise functions with something that depends on the previous terms in the loop. When we do things like that, we are moving away from the strict definition of a fractal and into the relatively unknown field of "multifractals". Multifractals are not as strictly defined mathematically, but that doesn't make them less useful for graphics. In fact, multifractal simulations are very common in modern commercial software for terrain generation. For further reading, you could read chapter 16 of the book "Texturing and Modeling: a Procedural Approach" (3rd edition), by Kenton Musgrave. Sadly, that book is out of print since a few years back, but you can still find it in libraries and on the second hand market. (There's a PDF version of the 1st edition available for purchase online, but don't buy that - it's a waste of money. It's from 1994, and it doesn't contain any of the terrain modeling stuff from the 3rd edition.)
### Domain Warping
[Inigo Quiles wrote this other fascinating article](http://www.iquilezles.org/www/articles/warp/warp.htm) about how it's possible to use fBm to warp a space of a fBm. Mind blowing, Right? It's like the dream inside the dream of Inception.
A less extreme example of this technique is the following code where the wrap is used to produce this clouds-like texture. Note how the self-similarity property is still present in the result.
Warping the texture coordinates with noise in this manner can be very useful, a lot of fun, and fiendishly difficult to master. It's a powerful tool, but it takes quite a bit of experience to use it well. A useful tool for this is to displace the coordinates with the derivative (gradient) of the noise. [A famous article by Ken Perlin and Fabrice Neyret called "flow noise"](http://evasion.imag.fr/Publications/2001/PN01/) is based on this idea. Some modern implementations of Perlin noise include a variant that computes both the function and its analytical gradient. If the "true" gradient is not available for a procedural function, you can always compute finite differences to approximate it, although this is less accurate and involves more work.
#### For your toolbox
* [LYGIA's generative functions ](https://lygia.xyz/generative) are a set of reusable functions to generate patterns in GLSL. It's a great resource to learn how to use randomness and noise to create generative art. It's very granular library, designed for reusability, performance and flexibility. And it can be easily be added to any projects and frameworks.
---
### 13/Notes (13/notes.md)
https://docs.google.com/spreadsheets/d/194IVZR_xLVsw5H0zJZ7CWuimOQA_n8KU2eeIZBDwIH0/edit#gid=0
http://heman.readthedocs.org/en/latest/generate.html#archipelagos
http://amd-dev.wpengine.netdna-cdn.com/wordpress/media/2012/10/Tatarchuk-Noise(GDC07-D3D_Day).pdf
http://www.campi3d.com/External/MariExtensionPack/help/MARI%20Extension%20Pack.html?Understandingsomebasicnoiseterms.html
http://www.gamedev.net/page/resources/_/technical/graphics-programming-and-theory/white-paper-procedural-terrain-generation-with-r2452
http://www.iquilezles.org/www/articles/warp/warp.htm
http://www.iquilezles.org/www/articles/morenoise/morenoise.htm
https://github.com/NVIDIAGameWorks/OpenGLSamples/blob/master/samples/es3aep-kepler/TerrainTessellation/assets/shaders/noise.glsl
---
### 13/README De (13/README-de.md)
## Gebrochene Brownsche Bewegung
Rauschen kann für Menschen ganz unterschiedliche Dinge bedeuten, je nachdem, wen man danach fragt. Musiker denken bei diesem Stichwort an schlechte Klangqualität, Funkspezialisten an unerwünschte Überlagerungen und Astrophysiker an die kosmische Hintergrundstrahlung im Mikrowellenbereich. Diese Vorstellungen führen uns zurück zu den physikalischen Grundlagen des Zufälligen in unserer Welt.
Doch lass uns erst einmal mit etwas ganz Einfachem und Fundamentalem beginnen: Mit den Eigenschaften von Wellen. Eine Welle steht für die Schwankung einer bestimmten Eigenschaft im Verlauf der Zeit. Audiowellen sind Schwankungen des Luftdrucks, elektromagnetische Wellen sind Schwankungen elektrischer und magnetischer Felder. Zwei spezifische Merkmale von Wellen sind ihre Amplitude (die Intensität ihres Ausschlags) und ihre Frequenz (die Häufigkeit, mit der sich die Welle in einer bestimmten Zeit wiederholt). Die Formel für eine einfache lineare Welle (in einer Dimension) sieht so aus:
* Verändere in der obigen Formel doch einfach mal die Werte für die Variablen ```amplitude``` und ```frequenz``` und beobachte, was dann geschieht.
* Versuche eine formgebende Funktion in die Formel einzubringen, so dass sich die Amplitude im Verlauf der Zeit ändert.
* Versuche das Gleiche, aber diesmal für eine Änderung der Frequenz im Laufe der Zeit.
Mit den letzten beiden Übungen modulierst Du die Sinuswelle. So erhältst Du einmal eine amplitudenmodulierte Welle (AM) und einmal eine frequenzmodulierte Welle (FM).
Ein weiteres interessantes Merkmal von Wellen kann man beobachten, wenn man mehrere Wellen addiert. Dabei entsteht ein Phänomen, das als „Überlagerung“ bekannt ist. Kommentiere in dem folgenden Beispiel einzelne Zeilen aus bzw. wieder ein und verändere die verschiedenen Faktoren für die Frequenz und die Amplitude. Verschaffe Dir einen Eindruck davon, wie sich das Gesamtbild auf diese Weise ändert.
* Experimentiere mit Veränderungen der Amplitude und der Frequenz bei den hinzuaddierten Wellen.
* Gelingt es Dir, zwei Wellen zu erschaffen, die sich gegenseitig aufheben? Wie würde das aussehen?
* Ist es möglich, Wellen auf eine bestimmte Art und Weise zu addieren, so dass sie sich gegenseitig verstärken?
In der Musik steht jede Note für eine bestimmte Frequenz. Reiht man die Frequenzen der Noten einer Tonleiter aneinander, so ergibt sich ein charakteristisches Muster. Die Halbierung bzw. Verdoppelung der Frequenz entspricht dabei jeweils dem Sprung um eine Oktave nach unten bzw. oben.
Okay, lass uns die Sinuswelle nun durch Perlins Rauschfunktion ersetzen. Diese hat in ihrer einfachsten Form ein ähnliches Erscheinungsbild wie die Sinuswelle. Zwar sind die Frequenz und die Amplitude von Perlins Rauschfunktion nicht konstant, aber die Amplitude bleibt zumindest weitgehend gleich und die Frequenz schwankt nur in einem schmalen Bereich rund um die Basisfrequenz. Perlins Rauschfunktion ist dadurch nicht so gleichförmig wie eine Sinuswelle. So wird es einfacher, den Eindruck von Zufälligkeit zu erzielen, indem man mehrere dieser Funktionen erst skaliert und dann addiert. Zwar ist dies grundsätzlich auch mit Sinuswellen möglich. Doch benötigt man dann eine größere Anzahl einzelner Wellen, um den eigentlich so regelmäßigen und periodischen Charakter der zugrundeliegenden Sinuswelle zu verbergen.
Indem wir das Ergebnis mehrerer Rauschfunktionen (*oktaven*) addieren, wobei wir schrittweise die Frequenz durch Multiplikation um einen gleichbleibenden Faktor (*porositaet*) steigern und die Amplitude dieser Zuwächse verringern (*zuwachs* < 1.0), verleihen wir unserem Rauschen eine feinere Granularität mit mehr Details. Diese Technik ist als „Gebrochene Brownsche Bewegung“ (engl.: „fractal Brownian motion“), kurz *fBm*, oder auch einfach als „frakturiertes Rauschen“ (engl.: „fractal noise“) bekannt. In ihrer simpelsten Form kann man sie mit Hilfe des folgenden Codes erzeugen:
* Erhöhe die Anzahl der Oktaven schrittweise von 1 auf 2, 4, 8 und 10 und beobachte, was dann geschieht.
* Sobald Du mehr als 4 Oktaven durchläufst, ändere den Wert für die Porosität.
* Ändere dann (bei *oktaven > 4*) auch den Wert für den Zuwachs, um die Auswirkungen zu beobachten.
Fällt Dir auf, dass der Funktionsgraph mit jeder zusätzlichen Oktave an Details gewinnt? Außerdem wächst die Selbstähnlichkeit: Der Kurvenverlauf in den einzelnen kleinen Abschnitten ähnelt immer mehr dem Verlauf im Großen. Dies ist ein wichtiges Merkmal mathematischer „Fraktale“ und wir simulieren dies hier durch die Oktaven-Schleife. Zwar erzeugen wir kein echtes Fraktal, weil wir die Aufsummierung nach einigen Schleifendurchläufen stoppen. Wenn wir die Schleife aber unendlich fortsetzen und immer weitere Rausch-Komponenten hinzufügen würden, erhielten wir tatsächlich ein vollständiges Fraktal.
Im Bereich der Computergrafik existieren immer Beschränkungen in der Hinsicht, wie fein wir einzelne Details auflösen können. Werden die Objekte beispielsweise kleiner als ein Pixel, macht es gar keinen Sinn mehr, weiterzurechnen. Manchmal bedarf es einer großen Anzahl an Schleifendurchläufen für hochauflösende Details, aber eine endlose Anzahl an Schleifendurchläufen und Details sind grundsätzlich nicht sinnvoll.
Der folgende Programmcode liefert ein Beispiel dafür, wie man eine fBm in zwei Dimensionen implementieren kann, um ein Muster ähnlich einem Fraktal zu erzeugen:
* Reduziere die Anzahl der Oktaven, indem Du den Wert der Konstanten in *Zeile 37* änderst.
* Ändere die Porosität der fBm in *Zeile 47*.
* Untersuche die Auswirkungen, wenn Du die Verstärkung in *Zeile 48* veränderst.
Diese Technik wird in der Computergrafik häufig angewandt, um auf prozedurale Weise künstliche Landschaften zu erzeugen. Die Selbstähnlichkeit als Merkmal einer fBm ist perfekt für die Erzeugung von Bergen, Bergketten und ihren Tälern geeignet. Schließlich erzeugt die Erosion, die diese Strukturen in der Natur hervorbringt, ebenfalls eine Selbstähnlichkeit in mehreren unterschiedlichen Größenordnungen – im Großen wie im Kleinen. Falls Dich das Thema interessiert, empfehle ich Dir diesen [hervorragenden Beitrag von Inigo Quiles über hochentwickeltes Rauschen](http://www.iquilezles.org/www/articles/morenoise/morenoise.htm).
Mit mehr oder weniger derselben Technik lassen sich auch andere Effekte nachahmen, beispielsweise **Turbulenzen**. Dies geschieht mit einer fBm, wobei allerdings der Absolutwert einer vorzeichenbehafteten Rauschfunktion genutzt wird, um starke Täler zu erzeugen.
```glsl
for (int i = 0; i < OKTAVEN; i++) {
value += amplitude * abs(snoise(st));
st *= 2.;
amplitude *= .5;
}
```
Ein weiteres Mitglied aus dieser Familie von Funktionen ist der **Bergrücken**, bei dem die tiefen Täler nach oben gekehrt werden, um scharfe Bergrücken bzw. Bergkämme zu erzeugen:
```glsl
n = abs(n); // erzeuge eine Falte
n = offset - n; // hole den Faltenboden nach oben
n = n * n; // intensiviere die Ausbuchtung
```
Eine andere Variante dieses Verfahrens mit interessanten Ergebnissen besteht in der Multiplikation der einzelnen Rauschelemente anstelle der Addition. Man kann außerdem die Skalierung nicht gleichförmig mit jeder Detailebene (jedem Schleifendurchlauf) fortsetzen, sondern von den Ergebnissen vorheriger Schleifendurchläufe abhängig machen. Damit verlässt man allerdings die Welt klassischer Fraktale und dringt in das noch wenig erforschte Feld der „Multifraktale“ vor. Diese sind mathematisch nicht streng definiert, aber das macht sie für die Computergrafik nicht weniger nützlich. Tatsächlich werden Multifraktale bereits vielfältig in Software für die künstliche Erzeugung von Landschaftsstrukturen eingesetzt.
Falls Dich dieses Thema interessiert, kannst Du darüber z.B. in Kapitel 16 des Buches „Texturing and Modeling: a Procedural Approach“ (dritte Auflage) von Kenton Musgrave, mehr erfahren. Leider ist das Buch seit einigen Jahren vergriffen, aber man findet es noch in Bibliotheken und auf dem Gebrauchtmarkt. (Eine PDF-Version der ersten Auflage wird im Internet verkauft, aber die stammt von 1994 und enthält leider noch nicht die hier empfohlenen Kapitel.)
### Raumkrümmung
[Inigo Quiles hat einen weiteren faszinierenden Artikel](http://www.iquilezles.org/www/articles/warp/warp.htm) darüber verfasst, wie man ein fBm einsetzen kann, um einen Raum aus fBm zu verzerren. Abgefahren, nicht wahr? Das ist wie ein Traum über einen Traum, in dem es richtig rundgeht.
Ein etwas weniger extremes Beispiel für diese Technik liefert der folgende Programmcode, wo mit Hilfe der Verzerrung wolkenartige Strukturen erzeugt werden. Auch hier spielt das Merkmal der Selbstähnlichkeit wiederum eine wichtige Rolle.
Die Texturkoordinaten mit Hilfe einer Rauschfunktion auf diese Weise zu verzerren, kann sehr nützlich sein und tolle Resultate liefern, es ist aber auch nicht ganz einfach zu beherrschen. Als hilfreiches Werkzeug erweist sich dabei der Ersatz der Koordinaten durch eine Ableitung (den Gradienten) der Rauschfunktion. [Ein berühmter Artikel von Ken Perlin und Fabrice Neyret mit dem Titel „flow noise“](http://evasion.imag.fr/Publications/2001/PN01/) erläutert diesen Ansatz.
Einige moderne Implementationen von Perlins Noise-Algorithmus berechnen sowohl den Funktionswert als auch den Verlauf. Wenn der konkrete Verlauf im Rahmen der prozeduralen Berechnung nicht verfügbar ist, kann man immer noch eine begrenzte Anzahl von Differenzen berechnen, um sich dem Verlauf anzunähern, auch wenn dies mehr Arbeit bedeutet und keine ganz exakten Ergebnisse liefert.
---
### 13/README Fr (13/README-fr.md)
## Fractional Brownian Motion
Le bruit peut avoir plusieurs significations selon les personnes. Les musiciens le trouveront dérangeant, les communicants le considèrent comme une interférence et les astrophysiciens comme un rayonnement cosmique.
Toutes ces qualifications, nous ramènent à l'ancrage *physique* du bruit dans notre environnement. Commençons toutefois par quelque chose de plus simple et de plus fondamental ; les ondes et leurs propriétés.
Une onde peut être considérée comme la variation d'une propriété dans le temps ; le son est une variation de la pression de l'air au fil du temps, une onde électro-magnétique est la fluctuation dans le temps d'un champs électrique et magnétique, etc.
Les deux caractéristiques importantes d'une onde sont sa *fréquence* et son *amplitude*.
L'équation d'une onde à une dimension peut s'écrire comme suit :
* Essayez de changer les valeurs de fréquence et d'amplitude pour comprendre leurs effets.
* À l'aide des fonctions de formes, faites varier l'amplitude au fil du temps.
* Faites de même avec la fréquence.
Félicitations ! En suivant les deux dernières instructions, vous avez réussi à "moduler" l'onde et à créer une modulation de fréquence (FM) et d'amplitude (AM), et oui, exactement comme des ondes radio !
Une seconde propriété intéressante des ondes est leur capacité à s'additionner, ce qu'on appelle la superposition.
Commentez/décommentez et jouez avec les les lignes suivantes en vous intéressant à la forme que prend l'onde lorsqu'on la combine à d'autres.
* Changez les valeurs de fréquence et d'amplitude des ondes additionnelles.
* Pouvez vous créer deux ondes qui s'annulent ? A quoi ressemblera l'onde finale ?
* Est-il possible d'additionner des ondes de manière à ce qu'elles s'amplifient l'une l'autre ?
En musique, chaque note est associée à une fréquence particulière. Les fréquences correspondent aux _notes_ de musique et doubler ou diviser par deux une fréquence permet de changer d'_octave_.
Utilisons à présent un bruit de Perlin au lieu d'une sinusoïde !
Un bruit de Perlin de base ressemble globalement à une sinusoïde.
Son amplitude et sa fréquence varient un peu mais l'amplitude reste globalement la même tandis que la fréquence
reste cantonnée dans une zone restreinte autour de la fréquence centrale.
Cependant, ce n'est pas une sinusoïde régulière et il est plus simple d'atteindre un résultat pseudo-aléatoire
en ajoutant plusieurs versions du bruit à différentes échelles (amplitudes).
Il est possible d'obtenir le même résultat avec des sinusoïdes mais il est nécessaire de combiner un nombre d'ondes important pour masquer leur nature périodique.
En ajoutant différentes itérations du **bruit** (différents *octaves*),
dont on augmente la fréquence (la *lacunarité*) et dont on réduit l'amplitude (le *gain*), on obtient une granularité
qui nous permet de préserver les détails fins d'un bruit.
Cette technique s'appelle "Fractional Brownian Motion" (*FBM*) ou simplement *bruit fractal*.
Voici un exemple d'implémentation :
* Changez progressivement le nombre d'octaves de 1 à 10 et regardez ce qui se produit.
* Au delà de 4 octaves, changez la valeur de lacunarité.
* Toujours au delà de 4 octaves, changez le gain et observez le résultat.
Notez comment, à chaque nouvel octave, la courbe semble gagner en détail.
Notez également lors de l'ajout d'octaves que lorsqu'on zoome sur la courbe, les plus petits éléments ressemblent à l'ensemble et inversement ; c'est ce qu'on appelle l'*auto-similarité* !
C'est une propriété importante des fractales et nous la simulons dans notre boucle.
Nous ne créons pas une fractale à proprement parler puisque nous arrêtons l'ajout de bruit après quelques itérations mais d'un point de vue théorique,
si nous pouvions laisser la boucle tourner indéfiniment et ajouter une somme infinies de bruits, nous obtiendrions une courbe fractale.
Dans un shader, la finesse du détail est limitée par la résolution écran ; si le résultat devient plus petit qu'un pixel, il n'ya pas vraiment de raison (ni de moyen) de le représenter à l'écran.
Nous avons donc pas besoin de boucles infinies pour obtenir une apparence fractale, il faut parfois un grand nombre d'itérations mais jamais une infinité.
Le code suivant est un exemple d'implémentation de **FBM** en 2 dimensions :
* Réduisez le nombre d'octaves en changeant la ligne 37
* Changez la lacunarité du FBM à la ligne 47
* Changez le gain ligne 48
Cette technique est communément utilisée pour créer des terrains procéduraux.
L'*auto-similarité* du FBM se prête bien au rendu de montagnes : le processus d'érosion qui donne leur forme aux montagnes
produit le même genre de motifs auto-similaires à grande échelle.
Si le sujet vous intéresse, nous vous invitons à lire [cet article d'Inigo Quiles sur les techniques de bruit avancées](http://www.iquilezles.org/www/articles/morenoise/morenoise.htm).
Le principe du **FBM** peut être amendé pour obtenir différents effets comme par exemple cette **turbulence**.
On part de la structure de notre FBM mais au lieu d'accumuler la valeur signée (+/-) du bruit, on accumule sa valeur absolue (+) ce qui crée des *vallées* et des *collines*.
```glsl
for (int i = 0; i < OCTAVES; i++) {
value += amplitude * abs(snoise(st));
st *= 2.;
amplitude *= .5;
}
```
Une seconde variante dite *ridge noise* (bruit de *crête* ou d'*arête*) consiste à inverser les vallées :
```glsl
n = abs(n); // create creases
n = offset - n; // invert so creases are at top
n = n * n; // sharpen creases
```
Une autre variante consiste à multiplier les valeurs de bruit au lieu de les additionner.
Il est intéressant de modifier l'échelle d'une itération de bruit en fonction du bruit de l'itération precédente.
En faisant ce genre de chose, nous nous éloignons du monde des fractales et entrons dans le monde méconnu des *multifractales*.
Les *multifractales* ne sont pas aussi clairement définies mathématiquement que les fractales ce qui ne nous empêche pas de nous en servir dans les shaders.
Les simulations *multifractales* sont d'ailleurs très répandues dans les logiciels de génération de terrain.
Vous trouverez plus d'informations sur ce sujet au chapitre 16 de *"Texturing and Modeling: a Procedural Approach"* (3ème édition), de Kenton Musgrave.
Malheureusement le livre n'est plus édité depuis quelques années déjà mais vous le trouverez en bibliothèque ou d'occasion.
Il est possible d'acheter un PDF de la première édition en ligne mais ça ne vaut pas le coup ; elle date de 1994 et ne contient aucune information sur la génération de terrain.
### Domain Warping
[Inigo Quiles a également écrit cet article fascinant](http://www.iquilezles.org/www/articles/warp/warp.htm) sur le fait de "plier" ou "recouvrir" (*wrap*) l'espace d'un FBM à l'aide d'un FBM.
Ce serait le *rêve dans le rêve* d'Inception :
Le code suivant est une variation moins spectaculaire de cette technique, on utilise le *wrapping* (pliage, recouvrement, emballage) pour créer une sorte de nuage.
Notez la part que joue l'*auto-similarité* dans le résultat final :
Le fait de *wrapper* (plier, recouvrir, emballer) ainsi les coordonnées de textures peut être extrêmement utile, relativement amusant et terriblement dur à maîtriser.
C'est un outil puissant qui demande beaucoup de pratique pour être correctement utilisé.
["Flow noise", un célèbre article de Ken Perlin et Fabrice Neyret](http://evasion.imag.fr/Publications/2001/PN01/) explique comment utiliser les dérivées (ou dégradés) du bruit pour atteindre ce résultat.
Les implémentations récentes du bruit de Perlin se servent à la fois de la fonction et de sa dérivée.
Si la *vraie* dérivée n'est pas disponible, on peut toujours se rabattre sur les différences finies pour l'approcher bien que ce soit moins précis et demande plus de travail.
---
### 13/README Id (13/README-id.md)
## 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:
* 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.
* 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:
* 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:
* 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).
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;
}
```
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
```
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.
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.
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.
---
### 13/README Jp (13/README-jp.md)
# 非整数ブラウン運動
ノイズという言葉は人によって違う物事を意味します。ミュージシャンであれば雑音のことを、コミュニケーションを仕事にする人であれば余計な干渉のことを、天体物理学者であれば宇宙マイクロ波背景放射のことを考えるでしょう。これらの概念は、世の中のランダムな現象の背後にある物理的な原因について考えさせてくれます。でも、まずはもっと根本的でシンプルなことから始めましょう。波とその特性についてです。波とは時間の上で起こる、ある特性を持った振動です。音波とは空気圧における振動、電磁波は電界、磁界における振動です。
波の2つ重要な性質に振幅(amplitude)と周波数(frequency)があります。単純な一次元の波を表す式はこのようになります。
* 波の性質について理解を深めるため、振幅と周波数の値を変えてみましょう。
* シェイピング関数を使って振幅を時間とともに変化させてみましょう。
* シェイピング関数を使って周波数を時間とともに変化させてみましょう。
2番目と3番目の演習をすることであなたはサイン波を「モデュレート」させて、AM波(amplitude modulated)とFM波(frequency modulated)を作り出したことになります。
波の興味深い特性の1つに、重ね合わせができるということがあります。下記のコードをコメントアウトしたり数値を変えたりしてみましょう(訳注: ```y +=``` で始まる行で試してください)。
* 重ね合わされている波の振幅や周波数を変えて実験してみましょう。
* 2つの波を互いに打ち消し合わせることはできますか。どのように見えるでしょう。
* 2つの波を、お互いを強め合うように重ね合わせることはできますか。
音楽では、それぞれの音程は特定の周波数に対応しています。これら音程の周波数は音階と呼ばれるパターンに従って並べられ、1オクターブごとに2倍または半分になります。
さて、サイン波の代わりにパーリンノイズを使ってみましょう。パーリンノイズの基本的な形状はサイン波(訳注:サイン波を重ね合わせたもの)に似た見た目をしています。振幅と周波数はいくらか変化しますが、振幅は比較的安定しており、周波数の変化はある値を中央値とした狭い範囲に制限されています。一方でパーリンノイズはサイン波ほど規則正しくはありません。幾つかのスケールを変えたノイズを重ね合わせればより不規則な見た目を作り出すのも簡単です。サイン波を重ね合わせたものをランダムに見せることも可能ですが、周期的で規則正しい性質を隠すにはたくさんの異なる波を重ねる必要があります。
周波数を一定の割合で増加させる(lacunarity)と同時に振幅を減らしながら(gain)ノイズを(octaveの数だけ)繰り返し重ねることで、より粒度の細かいディテールを持ったノイズを作り出すことができます。このテクニックは「非整数ブラウン運動(fBM)」または単に「フラクタルノイズ」と呼ばれていて、最も単純な形は下記のコードのようになります。
* 1から2、4、8、10と ```octave``` の値を徐々に変化させて何が起きるか観察してみましょう。
* ```octave``` の値が4より大きい状態で ```lacunarity``` の値を変化させてみましょう。
* 同じく ```octave``` の値が4より大きい状態で ```gain``` の値を変化させてみましょう。
```octave``` を増やすと曲線のディテールがより細かくなることに注目してください。また、その際の自己相似性にも注意しましょう。曲線を拡大しても、細かな部分の形が全体の形と同じになっているように見えます。また、拡大した部分は多かれ少なかれ他の部分と似ています。これは数学的なフラクタルの重要な性質で、私たちはこの性質をループの中でシミュレートしているのです。ここではシミュレーションは数回の繰り返しの後で打ち切られているので本当の意味でのフラクタルを作り出しているわけではありません。しかし理論上では、ループを永遠に繰り返して無限にノイズを重ね合わせれば、本当に数学的なフラクタルを得ることができるでしょう。コンピュータグラフィクスでは常に処理できる細かさに限界があります。例えばピクセルより小さなものは見えないので、フラクタルな見た目を作り出すのに無限回の足し算を行う必要はありません。たくさんの繰り返しが必要になることはあるかもしれませんが、無限回になることは決してありません。
下記のコードは2次元のfBMを実装してフラクタル状の模様を作り出した例です。
* 37行目の ```octave``` を減らしてみましょう。
* 47行目の ```lacunarity``` を変化させてみましょう。
* 48行目の ```gain``` を変えて試してみましょう。
このテクニックはプログラムで地形を作り出すのによく用いられています。fBMの自己相似性は、山を形づくる侵食過程の自己相似性に似ているため、山脈の形を再現するのに最適です。もし興味があればInigo Quilesによる[高度なノイズ](http://www.iquilezles.org/www/articles/morenoise/morenoise.htm)についての素晴らしい記事を読むと良いでしょう。
同様のテクニックを使って「乱流(turbulence)」と呼ばれる効果を作り出すこともできます。基本的にはfBMなのですが、鋭い谷間を作り出すために符号付きノイズ(signed noise)の絶対値を用いています。
```glsl
for (int i = 0; i < OCTAVES; i++) {
value += amplitude * abs(snoise(st));
st *= 2.;
amplitude *= .5;
}
```
同じ仲間のアルゴリズムに「尾根(ridge)」があります。深い谷が上下逆さまにされて鋭い尾根を作り出しています。
```glsl
n = abs(n); // create creases
n = offset - n; // invert so creases are at top
n = n * n; // sharpen creases
```
他の便利な仲間には、ノイズを足し算する代わりに掛け合わせたものがあります。ノイズ関数をそれまでのループの結果に応じてスケールさせても面白いでしょう。こうすると厳密なフラクタルから離れて、より謎めいた「マルチフラクタル」の世界に足を踏み入れることになります。マルチフラクタルはフラクタルほどは数学的に厳密に定義されていませんが、だからと言って役に立たないというわけではありません(訳注:厳密に定義されてないというより、より一般化された概念なのでもっといろんなものを含んじゃうよ、という感じだと思います)。実際にマルチフラクタルシミュレーションは地形生成に用いる現代の商用ソフトで一般的に用いられています。より深く知りたければKenton Musgraveによる「[Texturing and Modeling: a Procedural Approach (3rd edition)](https://www.amazon.co.jp/Texturing-Modeling-Third-Procedural-Approach/dp/1558608486)」を読むと良いでしょう。残念なことにこの本は数年前に絶版になってしまいましたが、図書館や中古で見つけることができるでしょう(第1版のPDF版はオンラインで手に入りますが買わないように。お金の無駄です。1994年に出版されたもので、第3版に載っている地形生成についての部分は含まれていません)。
### ドメインワーピング
Inigo Quilesはこの[興味をそそる記事](http://www.iquilezles.org/www/articles/warp/warp.htm)でfBMを使ってfBMの空間を歪める方法について書いています。ぶっ飛んでますね。インセプションに出てくる夢の中の夢のようです。
下記はこのテクニックのもう少しおとなしいサンプルです。空間の歪みが雲のようなテクスチャを作り出すのに使われています。ここでもまた自己相似性が見られることに注目してください。
このようにテクスチャ座標を歪める技はとても便利で、楽しく、しかし非道なほどマスターするのが難しいものです。とても強力なツールですが使いこなすにはかなりの経験が必要です。便利なテクニックとしてノイズの微分(勾配)を用いて座標をずらす方法があります。Ken PerlinとFabrice Neyretによる「[flow noise](http://evasion.imag.fr/Publications/2001/PN01/) 」という記事はこのアイデアに基づくものです。最近のパーリンノイズの実装の幾つかは、その関数の値と解析的な勾配の両方を計算してくれます。もしある関数について本物の勾配が得られない場合でも常に、手間がかかり正確さに劣りますが、差分法を用いて近似することができます。
(訳注:要するにノイズの値そのものではなくその微分を使うという話です。微分が直接計算できない場合は微妙にずらした2点の値を計算して差分をとることで近似することができます。この辺りはもう少し説明が必要ですね。参考になるかわかりませんがこの[サンプル](https://thebookofshaders.com/edit.php?log=161119153749)では ```normal``` 関数の中で少し座標をずらしてノイズの値を計算して比較することで傾きを計算しています。)
---
### 13/README Pl (13/README-pl.md)
## Fractal Brownian Motion (pol. "fraktalne ruchy Browna")
Szum zwykle oznacza różne rzeczy dla różnych ludzi. Muzycy będą myśleć o nim w kategoriach przeszkadzających dźwięków, komunikatorzy jako o zakłóceniach, a astrofizycy jako o kosmicznym mikrofalowym promieniowaniu tła. Te koncepcje sprowadzają nas z powrotem do fizycznych przyczyn losowości w otaczającym nas świecie. Zacznijmy jednak od czegoś bardziej podstawowego i prostszego: od fal i ich właściwości. Fala jest fluktuacją w czasie jakiejś właściwości. Fale dźwiękowe to fluktuacje ciśnienia powietrza, fale elektromagnetyczne to fluktuacje pola elektrycznego i magnetycznego. Dwie ważne cechy fali to jej amplituda i częstotliwość. Równanie dla prostej liniowej (jednowymiarowej) fali wygląda tak:
* Spróbuj zmienić wartości częstotliwości i amplitudy, aby zrozumieć, jak się zachowują.
* Używając shaping functions, spróbuj zmienić amplitudę w czasie.
* Używając shaping functions, spróbuj zmienić częstotliwość w czasie.
Wykonując dwa ostatnie ćwiczenia udało Ci się "zmodulować" sinusoidę i właśnie stworzyłeś fale AM (modulowane amplitudą, ang. "amplitude modulated") i FM (modulowane częstotliwością, ang. "frequency modulated"). Gratulacje!!!
Inną ciekawą właściwością fal jest ich zdolność do sumowania się, co formalnie nazywa się superpozycją. Skomentuj/odkomentuj i zmodyfikuj poniższe linijki. Zwróć uwagę, jak zmienia się ogólny wygląd wykresu, gdy dodajemy do siebie fale o różnych amplitudach i częstotliwościach.
* Eksperymentuj, zmieniając częstotliwość i amplitudę dla dodatkowych fal.
* Czy jest możliwe, aby dwie fale wzajemnie się zniosły? Jak to będzie wyglądało?
* Czy można dodać fale w taki sposób, że będą się one wzajemnie wzmacniać?
W muzyce każda nuta jest związana z określoną częstotliwością. Układ częstotliwości tych nut nazywamy skalą, gdzie podwojenie lub zmniejszenie częstotliwości o połowę odpowiada skokowi o jedną oktawę.
Teraz użyjmy szumu Perlina zamiast sinusoidy! Szum Perlina w swojej podstawowej formie wygląda podobnie do sinusoidy. Jego amplituda i częstotliwość różnią się nieco, ale amplituda pozostaje w miarę stała, a częstotliwość jest ograniczona do dość wąskiego zakresu wokół częstotliwości środkowej. Szum nie jest jednak tak regularny jak sinusoida, tym bardziej, gdy zsumujemy jego kilka przeskalowanych wersji. Można sprawić, że suma fal sinusoidalnych również będzie wyglądać na przypadkową, ale potrzeba wielu różnych fal, aby ukryć ich okresową, regularną naturę.
Poprzez dodanie różnych iteracji szumu (*octaves*, pol. "oktawy"), gdzie kolejno zwiększamy częstotliwości w regularnych krokach (*lacunarity*, pol. "lakunarność") i zmniejszamy amplitudę (*gain*, pol. "wzmocnienie"), otrzymamy szum bardziej granularny, zawierający więcej detali. Technikę tę nazwywamy "fractal Brownian Motion" (*fBM*) lub, po prostu "fractal noise" (pol. "szum fraktalny"). W swojej najprostszej postaci, możemy go stworzyć w następujący sposób:
* Stopniowo zmieniaj liczbę oktaw z 1 do 2, 4, 8 i 10. Zobacz, co się stanie.
* Gdy masz więcej niż 4 oktawy, spróbuj zmienić wartość `lacunarity`.
* Również przy >4 oktawach zmień wartość `gain` i zobacz, co się stanie.
Zauważ, że z każdą dodatkową oktawą krzywa wydaje się być bardziej szczegółowa. Zauważ też, że w miarę dodawania kolejnych oktaw występuje efekt samopodobieństwa - jeśli powiększysz krzywą, powiększona część wygląda mniej więcej tak samo jak całość, a każda powiększona część wygląda mniej więcej tak samo jak każda inna. Jest to ważna właściwość fraktali matematycznych, a my symulujemy tę właściwość w naszej pętli. Nie tworzymy *prawdziwego* fraktala, ponieważ zatrzymujemy sumowanie po kilku iteracjach, ale teoretycznie rzecz biorąc, uzyskalibyśmy prawdziwy fraktal matematyczny, gdybyśmy pozwolili pętli trwać w nieskończoność i dodawali nieskończoną liczbę składowych szumu. W grafice komputerowej zawsze mamy limit najmniejszych szczegółów, które możemy wyrenderować, gdyż obiekty stają się mniejsze niż piksel, więc nie ma potrzeby wykonywania nieskończonych sum, aby stworzyć wygląd fraktala. Czasami może być potrzebna duża ilość iteracji, ale nigdy nieskończona liczba.
Poniższy kod jest przykładem tego, jak fBm może być zaimplementowany w dwóch wymiarach, aby stworzyć wzór wyglądający jak fraktal:
* Zmniejsz liczbę oktaw poprzez zmianę wartości w linii 37
* Zmodyfikuj `lacunarity` fBm w linii 47
* Eksploruj zmianę `gain` na linii 48
Ta technika jest powszechnie używana do konstruowania proceduralnych krajobrazów. Samopodobieństwo fBm jest idealne dla gór, ponieważ procesy erozji, które tworzą góry, działają w sposób, który daje ten rodzaj samopodobieństwa w dużym zakresie skal. Jeśli jesteś zainteresowany tym zastosowaniem, powinieneś koniecznie przeczytać [ten świetny artykuł Inigo Quilesa o zaawansowanym szumie](http://www.iquilezles.org/www/articles/morenoise/morenoise.htm).
Używając mniej więcej tej samej techniki, możliwe jest również uzyskanie innych efektów, takich jak **turbulencja**. Jest to w zasadzie fBm, ale skonstruowane z wartości bezwzględnej szumu (wariantu zwracającego również ujemne wartości), aby stworzyć ostre doliny w funkcji.
```glsl
for (int i = 0; i < OCTAVES; i++) {
value += amplitude * abs(snoise(st));
st *= 2.;
amplitude *= .5;
}
```
Innym członkiem tej rodziny algorytmów jest **ridge** (pol. "grzbiet"), w którym ostre doliny są odwrócone do góry nogami, tworząc zamiast nich ostre grzbiety:
```glsl
n = abs(n); // Stwórz doliny
n = offset - n; // Odwróć doliny, aby powstały grzbiety
n = n * n; // Zaostrz grzbiety
```
Innym użytecznym wariantem jest mnożenie składowych szumu zamiast ich dodawania. Interesujące jest również skalowanie kolejnych funkcji szumu za pomocą czegoś, co zależy od poprzednich terminów w pętli. Kiedy robimy takie rzeczy, odchodzimy od ścisłej definicji fraktala i wchodzimy w stosunkowo nieznaną dziedzinę "multifraktali". Multifraktale nie są tak ściśle zdefiniowane matematycznie, ale to nie czyni ich mniej użytecznymi dla grafiki. W rzeczywistości symulacje multifraktalne są bardzo powszechne we współczesnym komercyjnym oprogramowaniu do generowania terenu. Aby przeczytać więcej, możesz przeczytać rozdział 16 książki "Texturing and Modeling: a Procedural Approach" (3. edycja), autorstwa Kentona Musgrave. Niestety, książka ta jest już od kilku lat niedostępna w druku, ale wciąż można ją znaleźć w bibliotekach i na rynku wtórnym. (Istnieje wersja PDF pierwszego wydania dostępna do kupienia online, ale nie kupuj jej - to strata pieniędzy. Jest z 1994 roku i nie zawiera żadnych rzeczy związanych z modelowaniem terenu z 3. edycji).
### Warping (pol. "zakrzywianie")
[Inigo Quiles napisał też inny fascynujący artykuł](http://www.iquilezles.org/www/articles/warp/warp.htm) o tym jak można użyć fBm do zakrzywienia przestrzeni fBm. Zdumiewające, prawda? To jak sen wewnątrz snu o Incepcji.
Mniej ekstremalnym przykładem tej techniki jest następujący kod, w którym zakrzywienie jest używane do wytworzenia tekstury przypominającej chmury. Zauważ, że właściwość samopodobieństwa jest nadal obecna.
Zakrzywianie współrzędnych tekstury za pomocą szumu może być bardzo użyteczne, daje dużo frajdy, ale jest diabelnie trudne do opanowania. Jest to potężne narzędzie, ale potrzeba sporo doświadczenia, aby dobrze je wykorzystać. Przydatnym wariantem jest też przemieszczanie współrzędnych za pomocą pochodnej (gradientu) szumu. [Na tym pomyśle opiera się słynny artykuł Kena Perlina i Fabrice'a Neyreta o nazwie "flow noise"](http://evasion.imag.fr/Publications/2001/PN01/). Niektóre nowoczesne implementacje szumu Perlina zawierają wariant, który oblicza zarówno funkcję, jak i jej gradient. Jeśli gradient nie istnieje, zawsze możesz obliczyć skończone różnice (różnica między sąsiadującymi pikselami), aby go przybliżyć, chociaż jest to mniej dokładne i wymaga więcej pracy.
---
### 13/README Pt (13/README-pt.md)
## Movimento Browniano Fracionário
O ruído pode ter um significado diferente para diferentes pessoas. Músicos pensarão em sons irritantes, comunicadores como interferência e astrofísicos como radiação em micro-ondas cósmicas. Estes conceitos nos trazem às explicações físicas por trás da aleatoriedade do mundo em nossa volta. Entretanto, vamos começar por algo mais fundamental e simples: ondas e suas propriedades. Uma onda é uma flutuação de alguma propriedade pelo tempo. Ondas de som são flutuações sobre a pressão do ar, ondas eletromagnéticas são flutuações em campos elétricos e magnéticos. Duas importantes características de onda são sua amplitude e sua frequência. A equação para uma simples onda linear (unidimensional) tem este aspecto.
* Experimente alterar os valores de frequência e amplitude para entender como eles se comportam.
* Usando modelagem de funções, tente alterar a amplitude ao longo do tempo.
* Usando modelagem de funções, tente alterar a frequência ao longo do tempo.
Ao fazer estes últimos exercícios, você conseguiu "modular" uma onda de seno, e você acabou de criar ondas AM (amplitude modulada) e FM (frequência modulada). Parabéns!
Outra interessante propriedade das ondas é a habilidade de se somarem, formalmente chamada de superposição. Comente/descomente e ajuste as linhas a seguir. Preste atenção em como sua aparência em geral se altera conforme nós adicionamos ondas de diferentes amplitudes e frequências juntas.
* Experimente alterar a frequência e amplitude das ondas adicionais.
* É possível fazer com que duas ondas se cancelem?
* É possível adicionar ondas de uma forma que elas possam se amplificar?
Em música, cada nota é associada com uma frequência específica. As frequências para estas notas seguem um padrão que chamamos de escala, onde dobrando ou diminuindo pela metade, a frequência corresponde a um salto de uma oitava.
Agora, vamos usar o ruído Perlin em vez de uma onda de seno! Ruído Perlin em sua forma básica se assemelha muito a uma onda de seno. Sua amplitude e frequência variam, mas a amplitude se mantém razoavelmente consistente, e a frequência é restrita a um curto intervalo ao redor da frequência central. Não é uniforme como uma onda de seno, no entanto, e é mais fácil de criar uma aparência de aleatoriedade ao somar diversas versões em diferentes escalas. Também possível criar uma soma de ondas de seno se parecerem com aleatório, mas é preciso muitas ondas diferentes para esconder a sua natureza periódica e regular.
Ao adicionar diferentes iterações ao ruído (*oitavas*), onde nós sucessivamente incrementamos as frequências em passos regulares (*lacunaridade*) e diminuímos a amplitude (*ganho*) do **ruído**, nós podemos obter uma granularidade no ruídos e ganhando detalhes mais finos. Esta técnica é chamada "Movimento browniano fracionário" (*fBM*), ou simplesmente "ruído fractal", sua forma mais simples pode ser criada com o seguinte código:
* Progressivamente mude o número de oitavas para iterar de 1 para 2, 4, 8 e 10. Veja o que acontece.
* Quando você ter mais do que 4 oitavas, tente mudar o valor de lacunaridade.
* Também, com mais de 4 oitavas, mude o valor gain(ganho) e veja o que acontece.
Veja como cada oitava adicional, a curva se parece mais detalhada. Também veja que a auto-similaridade enquanto mais oitavas são adicionadas. Se você se aproximar da curva, uma parte pequena se parecerá com o todo, e cada seção se parece mais ou menos igual a qualquer outra seção. Esta é uma importante propriedade dos fractais matemáticos, e nós estamos simulando esta propriedade em nosso loop. Nós não estamos criando um *verdadeiro* fractal, porque nós pararíamos nossa simulação depois de algumas iterações, mas, teoricamente falando, nós obteríamos um verdadeiro fractal se nós permitíssemos que o laço continuasse para sempre adicionando um infinito número de ruídos componentes. Em computação gráfica, nós sempre temos um limite do que nós podemos determinar, por exemplo, quando um objeto se torna menor que um píxel, então não há necessidade de criar somas infinitas para criar a aparência de um fractal. As vezes, muitos termos podem ser necessários, mas nunca um número infinito.
O código a seguir é um exemplo de como fBm pode ser implementado em duas dimensões para criar um padrão parecido com um fractal:
* Reduza o número de oitavas ao trocar os valores na linha 37
* Modifique a lacunaridade do fBm na linha 47
* Experimente mudar o Ganho(gain) na linha 48.
Esta técnica é regularmente usada na criação de paisagens procedimentais. A auto-similaridade do fBm é perfeita para montanhas, porque o processo de erosão cria montanhas que funcionam de um jeito que produzem esse tipo de auto-similaridade por um largo intervalo de escalas. Se você está interessado nisso, você definitivamente deveria ler [este ótimo artigo por Inigo Quilez sobre ruído avançado](http://www.iquilezles.org/www/articles/morenoise/morenoise.htm).
Usando mais ou menos a mesma técnica, é possível obter outros efeitos como o que é conhecido como **turbulência**. É essencialmente um fBm, mas construída com valores absolutos de um ruído sinalizado para criar vales afiados na função.
```glsl
for (int i = 0; i < OCTAVES; i++) {
value += amplitude * abs(snoise(st));
st *= 2.;
amplitude *= .5;
}
```
Outro membro desta família de algoritmos é o *cume* (ridge), onde os vales afiados são virados de ponta-cabeça para criar cumes afiados.
```glsl
n = abs(n); // create creases
n = offset - n; // invert so creases are at top
n = n * n; // sharpen creases
```
Outra variante pode criar variações úteis é multiplicando os componentes do ruído juntos ao invés de somá-los. Também é interessante alterarmos a escala de funções de ruído subsequentes com algo que dependa dos termos anteriores do nosso laço. Quando nós fazemos operações assim, nós estando nos afastando de uma definição estrita de fractal e entrando relativamente em um campo desconhecido de "multifractais". Multifractais não são estritamente matematicamente definidos, mas não significa que que os torna menos úteis em gráficos. De fato, simulações multifractais são muito comuns em comerciais modernos para gerar terrenos. Para ir além, você pode ler o capítulo 16 do livro "Texturing and Modeling: A procedural approach" (Texturizando e Modelando: Uma Abordagem Procedimental) - 3ª edição, por Kenton Musgrave. Infelizmente, este livro está fora de impressão há alguns anos, mas nós ainda podemos encontrá-lo em bibliotecas e em mercados de segunda-mão. (Tem uma versão em PDF da primeira edição disponível para venda online, mas não a compre - É um desperdício de dinheiro. É de 1994, e não contém o tópico de modelagem de terreno da terceira edição).
## Domain Warping (Empenamento de Domínio)
[Inigo Quilez escreveu outro artigo fascinante](http://www.iquilezles.org/www/articles/warp/warp.htm) sobre como é possível usarmos o fBm para distorcer um espaço de um fBm. Surpreendente, não é? É como um sonho dentro de um sonho em A Origem (Inception).
Uma exemplo menos extremo desta técnica está nas seguintes linhas de código, onde o empenamento é usado para produzir estas texturas parecidas com nuvem. Veja como a propriedade de auto-similaridade está presente no resultado.
Empenar as coordenadas da textura com um ruído pode ser muito útil e divertido, entretanto, diabolicamente difícil de dominar. É uma ferramenta poderosa, mas requer um pouco de experiência pra usá-la bem. Uma ferramenta útil para isso é deslocar as coordenadas com as derivadas (gradiente) do ruído. [Um artigo famoso de Ken Perlin e Fabrice Neyret chamado "flow noise"](http://evasion.imag.fr/Publications/2001/PN01/) é baseado nesta ideia. Algumas implementações modernas do ruído Perlin incluem a variante que calcula tanto a função como seu gradiente analítico. Se o "verdadeiro" gradiente não estiver disponível para nossa função procedimental, você sempre pode calcular as diferenças finitas para se aproximar dele, apesar de ser menos preciso e envolver mais trabalho.
---
### 13/README Tr (13/README-tr.md)
## Fraktal Brown Hareketi
Gürültü, farklı insanlar için farklı şeyler ifade eder. Müzisyenler onu rahatsız edici sesler açısından düşünür, iletişimciler parazit olarak ve astrofizikçiler kozmik mikrodalga arka plan radyasyonu olarak. Bu kavramlar bizi çevremizdeki dünyadaki rastgeleliğin arkasındaki fiziksel nedenlere geri götürür. Ancak daha temel ve daha basit bir şeyle başlayalım: dalgalar ve özellikleri. Dalga, bazı özelliklerin zaman içindeki dalgalanmasıdır. Ses dalgaları hava basıncındaki dalgalanmalardır, elektromanyetik dalgalar elektrik ve manyetik alanlardaki dalgalanmalardır. Bir dalganın iki önemli özelliği genliği ve frekansıdır. Basit bir doğrusal (tek boyutlu) dalganın denklemi şöyle görünür:
* Nasıl davrandıklarını anlamak için frekans ve genlik değerlerini değiştirmeyi deneyin.
* Şekillendirme fonksiyonlarını kullanarak genliği zamanla değiştirmeyi deneyin.
* Şekillendirme fonksiyonlarını kullanarak frekansı zamanla değiştirmeyi deneyin.
Son iki alıştırmayı yaparak bir sinüs dalgasını "modüle etmeyi" başardınız ve az önce AM (genlik modülasyonlu) ve FM (frekans modülasyonlu) dalgalar yarattınız. Tebrikler!
Dalgaların bir diğer ilginç özelliği, resmi olarak süperpozisyon olarak adlandırılan, toplanabilme yetenekleridir. Aşağıdaki satırları yorum yapın/yorumdan çıkarın ve ayarlayın. Farklı genliklere ve frekanslara sahip dalgaları bir araya getirdikçe genel görünümün nasıl değiştiğine dikkat edin.
* Ek dalgalar için frekans ve genliği değiştirerek denemeler yapın.
* İki dalganın birbirini iptal etmesi mümkün mü? Bu nasıl görünür?
* Dalgaları birbirini güçlendirecek şekilde eklemek mümkün mü?
Müzikte her nota belirli bir frekansla ilişkilendirilir. Bu notaların frekansları, gam adını verdiğimiz bir deseni izler; burada frekansın iki katına çıkması veya yarıya inmesi bir oktav atlamaya karşılık gelir.
Şimdi sinüs dalgası yerine Perlin gürültüsünü kullanalım! Perlin gürültüsü temel formunda sinüs dalgasıyla aynı genel görünüm ve histe sahiptir. Genliği ve frekansı bir ölçüde değişir, ancak genlik makul ölçüde tutarlı kalır ve frekans bir merkez frekans etrafında oldukça dar bir aralıkla sınırlıdır. Bir sinüs dalgası kadar düzenli değildir ve gürültünün birkaç ölçeklenmiş versiyonunu toplayarak rastgelelik görünümü oluşturmak daha kolaydır. Sinüs dalgalarının toplamını da rastgele göstermek mümkündür, ancak periyodik, düzenli doğalarını gizlemek için birçok farklı dalga gerekir.
Frekansları düzenli adımlarla (*lacunarity*) art arda artırdığımız ve **gürültünün** genliğini (*gain*) azalttığımız, gürültünün farklı yinelemelerini (*oktavlar*) ekleyerek daha ince bir ayrıntı düzeyi elde edebilir ve daha ince detaylar alabiliriz. Bu teknik "fraktal Brown hareketi" (*fBM*) veya basitçe "fraktal gürültüsü" olarak adlandırılır ve en basit formunda aşağıdaki kodla oluşturulabilir:
* Yinelenecek oktav sayısını 1'den 2, 4, 8 ve 10'a kademeli olarak değiştirin. Ne olduğunu görün.
* 4'ten fazla oktavınız olduğunda, lacunarity değerini değiştirmeyi deneyin.
* Yine 4'ten fazla oktavla, gain değerini değiştirin ve ne olduğunu görün.
Her ek oktavla eğrinin nasıl daha fazla detay kazandığına dikkat edin. Ayrıca daha fazla oktav eklendikçe öz-benzerliğe de dikkat edin. Eğriye yakınlaştırırsanız, daha küçük bir kısım bütünle aşağı yukarı aynı görünür ve her bölüm diğer herhangi bir bölümle aşağı yukarı aynı görünür. Bu, matematiksel fraktalların önemli bir özelliğidir ve biz döngümüzde bu özelliği simüle ediyoruz.
Aşağıdaki kod, fraktal görünümlü bir desen oluşturmak için fBm'nin iki boyutta nasıl uygulanabileceğinin bir örneğidir:
* 37. satırdaki değeri değiştirerek oktav sayısını azaltın
* 47. satırda fBm'nin lacunarity'sini değiştirin
* 48. satırda gain'i değiştirerek keşfedin
Bu teknik genellikle prosedürel manzaralar oluşturmak için kullanılır. fBm'nin öz-benzerliği dağlar için mükemmeldir, çünkü dağları oluşturan erozyon süreçleri geniş bir ölçek aralığında bu tür bir öz-benzerlik veren bir şekilde çalışır. Bu kullanımla ilgileniyorsanız, [Inigo Quiles'in gelişmiş gürültü hakkındaki bu harika makalesini](http://www.iquilezles.org/www/articles/morenoise/morenoise.htm) kesinlikle okumalısınız.
Aşağı yukarı aynı tekniği kullanarak **türbülans** olarak bilinen başka efektler elde etmek de mümkündür. Özünde bir fBm'dir, ancak fonksiyonda keskin vadiler oluşturmak üzere işaretli gürültünün mutlak değerinden oluşturulmuştur.
```glsl
for (int i = 0; i < OCTAVES; i++) {
value += amplitude * abs(snoise(st));
st *= 2.;
amplitude *= .5;
}
```
Bu algoritma ailesinin bir diğer üyesi, keskin vadilerin bunun yerine keskin sırtlar oluşturmak üzere ters çevrildiği **sırt**tır (ridge):
```glsl
n = abs(n); // kıvrımlar oluştur
n = offset - n; // kıvrımları üstte olacak şekilde ters çevir
n = n * n; // kıvrımları keskinleştir
```
Yararlı varyasyonlar oluşturabilecek bir diğer değişken, gürültü bileşenlerini toplamak yerine çarpmaktır. Sonraki gürültü fonksiyonlarını döngüdeki önceki terimlere bağlı bir şeyle ölçeklemek de ilginçtir. Böyle şeyler yaptığımızda, fraktalın katı tanımından uzaklaşıp nispeten bilinmeyen "multifraktal" alanına geçiyoruz.
### Alan Bükme (Domain Warping)
[Inigo Quiles bu diğer büyüleyici makaleyi yazdı](http://www.iquilezles.org/www/articles/warp/warp.htm), bir fBm'nin uzayını bir fBm ile bükmenin nasıl mümkün olduğu hakkında. Akıl patlatıcı, değil mi? Inception'daki rüyanın içindeki rüya gibi.
Bu tekniğin daha az aşırı bir örneği, bulutlara benzer doku üretmek için kaydırmanın (wrap) kullanıldığı aşağıdaki koddur. Sonuçta öz-benzerlik özelliğinin hâlâ mevcut olduğuna dikkat edin.
Doku koordinatlarını bu şekilde gürültüyle kaydırmak çok faydalı, çok eğlenceli ve ustalaşması çok zor olabilir. Güçlü bir araçtır, ancak iyi kullanmak için oldukça fazla deneyim gerektirir. Bunun için faydalı bir araç, koordinatları gürültünün türevi (gradyanı) ile kaydırmaktır. [Ken Perlin ve Fabrice Neyret tarafından yazılan "flow noise" başlıklı ünlü makale](http://evasion.imag.fr/Publications/2001/PN01/) bu fikre dayanır.
#### Araç kutunuz için
* [LYGIA'nın üretken fonksiyonları](https://lygia.xyz/generative), GLSL'de desenler üretmek için yeniden kullanılabilir fonksiyonlar kümesidir. Üretken sanat yaratmak için rastgelelik ve gürültüyü nasıl kullanacağınızı öğrenmek için harika bir kaynaktır. Yeniden kullanılabilirlik, performans ve esneklik için tasarlanmış çok ayrıntılı bir kütüphanedir. Ve herhangi bir projeye ve framework'e kolayca eklenebilir.
---
### 13/README Vi (13/README-vi.md)
## Chuyển động Brown (Fractal Brownian motion)
Nói về nhiễu, mỗi người sẽ có một suy nghĩ khác nhau. Các nhạc công sẽ nghĩ về những tiếng ồn khó chịu, các nhà vật lý thiên văn học thì nghĩ tới bức xạ nền vi sóng vũ trụ, còn trong giao tiếp thì nhiễu dùng để chỉ các yếu tố gây mất tập trung. Các khái niệm này đưa chúng ta trở lại với môn Vật lý phổ thông để giải thích những tính chất đằng sau sự ngẫu nhiên. Tuy nhiên, hãy bắt đầu với thứ gì đó cơ bản hơn: Sóng và các tính chất của nó. Một sóng sự dao động của một vài thuộc tính vật lý theo thời gian. Sóng âm là sự dao động của áp suất không khí, sóng điện từ là dao động trong điện trường và từ trường. Hai tính chất quan trọng của sóng là biên độ và tần số. Phương trình sóng tuyến tính (một chiều) nhìn như sau:
* Hãy thử thay đổi giá trị của biên độ và tần số để xem đồ thị thay đổi tương ứng như thế nào.
* Thay đổi biên độ theo thời gian bằng các hàm hình dạng
* Thay đổi tần số theo thời gian bằng các hàm hình dạng
Người dịch: Nếu mỗi khi tăng tần số bạn lại giảm biên độ một đại lượng tương ứng, bạn sẽ thấy "một phiên bản thu nhỏ" của sóng ban đầu, như đoạn code dưới đây. Bạn có thể dùng [GraphToy](http://www.iquilezles.org/apps/graphtoy/) để vẽ từng sóng này rời nhau, bạn sẽ thấy rõ hơn. Các họa tiết nhìn giống nhau chỉ khác về kích thước như vậy được gọi là Fractal.
Hai yêu cầu cuối sẽ giúp bạn thuần thục hơn trong kỹ năng kiểm soát (modulate) sóng sin, và hai sóng mà bạn vừa tạo ra có tên gọi riêng, đó là AM (Amplitude Modulated) và FM (Frequency Modulated). Chúc mừng nhé !
Một đặc điểm khác cũng thú vị không kém của các sóng là chúng có thể cộng dồn và chồng chất lên nhau. Hãy comment/Uncomment và sửa các dòng code sau và chú ý vào sự thay đổi của đồ thị khi ta chồng các sóng có biên độ và tần số khác nhau.
* Hãy thử thêm bớt từng sóng.
* Có thể tạo hai sóng triệt tiêu lẫn nhau không ? Nếu có thì trông chúng như thế nào ?
* Có thể tạo hai sóng hoàn toàn khuếch đại lẫn nhau không ? Nếu có thì trông chúng như thế nào ?
Trong âm nhạc, mỗi nốt nhạc tương ứng với một tần số. Những tần số này tuân theo một pattern mà ta gọi là gam / âm giai, khi tăng gấp đôi hoặc giảm một nửa tần số ta được các nốt nhạc ở một quãng tám ngay trên và dưới các nốt ban đầu.
Giờ hãy dùng Perlin noise thay vì sóng sin. Perlin noise ở dạng cơ bản nhất nhìn cũng na ná sóng sin. Dù cho biên độ và tần số của nó có sai số đi nữa, biên độ vẫn có mức ổn định chấp nhận được còn tần số thì bị giới hạn để chỉ dao động quanh mốc tần số trung tâm. Tuy không phổ biến như sóng sin, nhưng, nếu chồng nhiều sóng nhiễu lên ta có thể tạo nên sự ngẫu nhiên mong muốn. Còn nếu chồng các sóng sin lên nhau mà vẫn muốn tạo ra sự ngẫu nhiên thì sẽ tốn khá nhiều công để che giấu tần số.
Thay vì dùng các sóng nhiễu giống hệt nhau, ta sẽ dùng các cấp fractal của sóng. Cứ mỗi lần chồng thêm một sóng nhiễu (tức thêm một *quãng tám - octaves*), ta sẽ tăng tần số bằng cách nhân với một đại lượng cố định (*lacunarity*) và giảm biên độ cũng bằng cách nhân với một đại lượng cố định (*gain*), kết quả thu được là sóng nhiễu ngày càng chi tiết hơn. Kỹ thuật này gọi là chuyển động Brown - "fractal Brownian Motion" (*fBm*), hoặc đơn giản là nhiễu phân dạng - "fractal noise", có thể sinh bởi đoạn code sau:
* Hãy thử thay đổi giá trị của quãng tám từ 1 lên 2, 4, 8, 10 và xem đồ thị thay đổi ra sao.
* Với số quãng tám lớn hơn 4, hãy thử thay đổi giá trị lacunarity.
* Cũng với số quãng tám lớn hơn 4, hãy thử thay đổi giá trị gain.
Bạn sẽ dễ dàng nhận ra cứ chồng thêm một quãng tám, đồ thị lại càng chi tiết hơn. Mỗi cấp sóng nhiễu được thêm vào lại giống như một phiên bản tí hon của cấp trước đó. Đó là một tính chất quan trọng của phân dạng (fractal) trong Toán học. Thực ra thì ta không tạo ra một phân dạng *thực thụ*, vì số vòng lặp giới hạn, nhưng về lý thuyết thì điều đó có thể với một vòng lặp vô hạn. Trong lĩnh vực đồ họa máy tính thì ta luôn phải đánh đổi sự chi tiết với số lượng phép tính cần thực hiện. Trong trường hợp này, nếu sự thay đổi của đồ thị nhỏ hơn kích thước của một điểm ảnh thì việc tiếp tục chồng thêm quãng tám là không cần thiết nữa.
Dưới đây là ví dụ tôi dùng fBm trong không gian 2 chiều để tạo nên họa tiết phân dạng:
* Hãy thử giảm số quãng tám ở dòng 37
* Hãy thử sửa tham số lacunarity ở dòng 47
* Hãy thử sửa tham số gain ở dòng 48
Kỹ thuật này rất hay được sử dụng để tạo nên các địa hình ngẫu nhiên. Tính chất tương tự của các cấp fractal trong fBm vô cùng thích hợp để mô tả các ngọn núi, vì quá trình ăn mòn để tạo nên các ngọn núi cũng được mô phỏng bằng chính đặc tính này. Nếu bạn thích chủ đề này, tôi đặc biệt giới thiệu [nghiên cứu tuyệt vời này của Inigo Quiles về nhiễu cao cấp](http://www.iquilezles.org/www/articles/morenoise/morenoise.htm).
Sử dụng các kỹ thuật tương tự, ta có thể tạo nên hiệu ứng **nhiễu loạn - turbulence**. Thực ra nó chính là fBm nhưng sử dụng các giá trị tuyệt đối của nhiễu để tạo nên các hố sâu, gọi là thung lũng.
```glsl
for (int i = 0; i < OCTAVES; i++) {
value += amplitude * abs(snoise(st));
st *= 2.;
amplitude *= .5;
}
```
Một thành viên khác trong họ thuật toán này là **dãy núi - ridge**, chỉ khác là thay vì có các thung lũng sâu, ta có các dãy núi dựng đứng:
```glsl
n = abs(n); // tạo các rãnh thung lũng
n = offset - n; // đảo ngược thung lũng thành đỉnh núi
n = n * n; // tăng góc nghiêng của các đỉnh núi
```
Một biến thể khác để tạo ra các sóng nhiễu đa dạng hơn, đó là nhân giá trị của các vị trí tương ứng trên các sóng nhiễu lại với nhau, thay vì cộng dồn. Và các cấp sóng fractal có thể được scale dựa vào cấp trước đó, những sóng kết quả sẽ được gọi là "multifractal". Tuy các sóng "multifractal" không chặt chẽ về mặt Toán học lắm, nhưng điều đó không làm giảm tính hữu dụng của chúng trong đồ họa máy tính. Thực tế thì chúng rất hay được sử dụng ở các phần mềm thương mại giúp sinh ra các loại địa hình khác nhau. Để tìm hiểu thêm, bạn có thể đọc chương 16 của quyển "Texturing and Modeling: a Procedural Approach" (lần xuất bản thứ 3), được viết bởi Kenton Musgrave. Rất tiếc là bản in của quyển sách này đã hết sạch từ vài năm trước rồi, nhưng bạn vẫn có thể tìm mượn ở thư viện hoặc mua lại sách cũ. (Tuy rằng có phiên bản PDF được rao bán trên mạng nhưng bạn đừng phí tiền mua nó, bởi đó là phiên bản cũ từ năm 1994, không hề đề cập tới việc sinh địa hình tự động mà tôi nhắc tới ở đây).
### Bẻ cong không gian
[Inigo Quiles có đăng một nghiên cứu thú vị](http://www.iquilezles.org/www/articles/warp/warp.htm) về cách dùng fBm để bẻ cong không gian (tức hệ tọa độ) của một fBm khác. Xoắn não thật sự luôn. Chẳng khác gì những giấc mơ lồng nhau trong bộ phim Inception cả.
Một ví dụ dễ thở hơn của kỹ thuật này được thực hiện bởi đoạn code dưới đây, để sinh ra các họa tiết mô phỏng những đám mây. Nếu để ý bạn sẽ đặc tính tương tự nhiều cấp (self-similarity) vẫn có trong họa tiết sau cùng.
Việc bẻ công hệ tọa độ của texture bằng nhiễu rất có ích lại còn hay ho nữa, nhưng rất khó để sử dụng thành thạo nếu không kiên trì tập luyện.
Một kỹ thuật khác cũng hay được dùng là dùng nhiễu để can thiệp vào dải gradient khi blend giữa các đỉnh (xét về mặt Toán học, đó chính là đạo hàm của phương trình sóng). Đây là [một bài nghiên cứu của Ken Perlin và Fabrice Neyret về "flow noise"](http://evasion.imag.fr/Publications/2001/PN01/) dựa trên ý tưởng này. Một vài phiên bản code hiện tại của Perlin noise đã tính cả sóng nhiễu và tích phân của dải màu gradient luôn. Nếu thông tin về dải màu "chi tiết" không được cung cấp thì bạn hoàn toàn có thể dùng phương pháp sai phân hữu hạn để tính xấp xỉ, dù cho kết quả sẽ không được chính xác tuyệt đối và cũng hơi mất công nữa.
---
### 14/README (14/README.md)
## Fractals
Coming soon ...
In the meantime, you can check out some examples with fractals on the [shadertoy.com](https://www.shadertoy.com/results?query=fractals) platform:
[Basic Fractal](https://www.shadertoy.com/view/Mss3Wf)
[Mandelbrot - distance](https://www.shadertoy.com/view/lsX3W4)
[Mandelbrot - smooth](https://www.shadertoy.com/view/4df3Rn)
[Mandelbrot: Power Transitioning](https://www.shadertoy.com/view/lls3D7)
[IFS - brute force](https://www.shadertoy.com/view/lss3zs)
[Julia - Distance 1](https://www.shadertoy.com/view/Mss3R8)
[Julia - Distance 3](https://www.shadertoy.com/view/4dXGDX)
[Julia - Traps 2](https://www.shadertoy.com/view/4dfGRn)
[Fractal Wheel 2.0](https://www.shadertoy.com/view/llfGD2)
[Koch Snowflake again](https://www.shadertoy.com/view/Mlf3RX)
---
### 14/README Pt (14/README-pt.md)
## Fractais
https://www.shadertoy.com/view/lsX3W4
https://www.shadertoy.com/view/Mss3Wf
https://www.shadertoy.com/view/4df3Rn
https://www.shadertoy.com/view/Mss3R8
https://www.shadertoy.com/view/4dfGRn
https://www.shadertoy.com/view/lss3zs
https://www.shadertoy.com/view/4dXGDX
https://www.shadertoy.com/view/XsXGz2
https://www.shadertoy.com/view/lls3D7
https://www.shadertoy.com/view/XdB3DD
https://www.shadertoy.com/view/XdBSWw
https://www.shadertoy.com/view/llfGD2
https://www.shadertoy.com/view/Mlf3RX
---
### 14/README Tr (14/README-tr.md)
## Fraktallar
Yakında gelecek...
Bu arada, [shadertoy.com](https://www.shadertoy.com/results?query=fractals) platformunda fraktallarla ilgili bazı örneklere göz atabilirsiniz:
[Temel Fraktal](https://www.shadertoy.com/view/Mss3Wf)
[Mandelbrot - mesafe](https://www.shadertoy.com/view/lsX3W4)
[Mandelbrot - düzgün](https://www.shadertoy.com/view/4df3Rn)
[Mandelbrot: Güç Geçişi](https://www.shadertoy.com/view/lls3D7)
[IFS - kaba kuvvet](https://www.shadertoy.com/view/lss3zs)
[Julia - Mesafe 1](https://www.shadertoy.com/view/Mss3R8)
[Julia - Mesafe 3](https://www.shadertoy.com/view/4dXGDX)
[Julia - Tuzaklar 2](https://www.shadertoy.com/view/4dfGRn)
[Fraktal Çark 2.0](https://www.shadertoy.com/view/llfGD2)
[Koch Kar Tanesi tekrar](https://www.shadertoy.com/view/Mlf3RX)
---
### 14/README Ua (14/README-ua.md)
## Фрактали
Coming soon ...
А поки що можете подивитися приклади з фракталами на платформі [shadertoy.com](https://www.shadertoy.com/results?query=fractals):
[Basic Fractal](https://www.shadertoy.com/view/Mss3Wf)
[Mandelbrot - distance](https://www.shadertoy.com/view/lsX3W4)
[Mandelbrot - smooth](https://www.shadertoy.com/view/4df3Rn)
[Mandelbrot: Power Transitioning](https://www.shadertoy.com/view/lls3D7)
[IFS - brute force](https://www.shadertoy.com/view/lss3zs)
[Julia - Distance 1](https://www.shadertoy.com/view/Mss3R8)
[Julia - Distance 3](https://www.shadertoy.com/view/4dXGDX)
[Julia - Traps 2](https://www.shadertoy.com/view/4dfGRn)
[Fractal Wheel 2.0](https://www.shadertoy.com/view/llfGD2)
[Koch Snowflake again](https://www.shadertoy.com/view/Mlf3RX)
---
### 15/README (15/README.md)
# Image processing
## Textures
Graphic cards (GPUs) have special memory types for images. Usually on CPUs images are stored as arrays of bytes but GPUs store images as ```sampler2D``` which is more like a table (or matrix) of floating point vectors. More interestingly, the values of this *table* of vectors are continuous. That means that values between pixels are interpolated in a low level.
In order to use this feature we first need to *upload* the image from the CPU to the GPU, to then pass the ```id``` of the texture to the right [```uniform```](../05). All that happens outside the shader.
Once the texture is loaded and linked to a valid ```uniform sampler2D``` you can ask for specific color value at specific coordinates (formatted on a [```vec2```](index.html#vec2.md) variable) using the [```texture2D()```](index.html#texture2D.md) function which will return a color formatted on a [```vec4```](index.html#vec4.md) variable.
```glsl
vec4 texture2D(sampler2D texture, vec2 coordinates)
```
Check the following code where we load Hokusai's Wave (1830) as ```uniform sampler2D u_tex0``` and we call every pixel of it inside the billboard:
If you pay attention you will note that the coordinates for the texture are normalized! What a surprise right? Textures coordinates are consistent with the rest of the things we had seen and their coordinates are between 0.0 and 1.0 which match perfectly with the normalized space coordinates we have been using.
Now that you have seen how we correctly load a texture, it is time to experiment to discover what we can do with it, by trying:
* Scaling the previous texture by half.
* Rotating the previous texture 90 degrees.
* Hooking the mouse position to the coordinates to move it.
Why you should be excited about textures? Well first of all forget about the sad 255 values for channel; once your image is transformed into a ```uniform sampler2D``` you have all the values between 0.0 and 1.0 (depending on what you set the ```precision``` to ). That's why shaders can make really beautiful post-processing effects.
Second, the [```vec2()```](index.html#vec2.md) means you can get values even between pixels. As we said before the textures are a continuum. This means that if you set up your texture correctly you can ask for values all around the surface of your image and the values will smoothly vary from pixel to pixel with no jumps!
Finally, you can set up your image to repeat in the edges, so if you give values over or lower of the normalized 0.0 and 1.0, the values will wrap around starting over.
All these features make your images more like an infinite spandex fabric. You can stretch and shrink your texture without noticing the grid of bytes they are originally composed of or the ends of it. To experience this take a look at the following code where we distort a texture using [the noise function we already made](../11/).
## Texture resolution
Above examples play well with squared images, where both sides are equal and match our squared billboard. But for non-squared images things can be a little more tricky, and unfortunately centuries of pictorial art and photography found more pleasant to the eye non-squared proportions for images.
How we can solve this problem? Well we need to know the original proportions of the image to know how to stretch the texture correctly in order to have the original [*aspect ratio*](http://en.wikipedia.org/wiki/Aspect_ratio). For that the texture width and height are passed to the shader as an ```uniform```, which in our example framework are passed as an ```uniform vec2``` with the same name of the texture followed with proposition ```Resolution```. Once we have this information on the shader we can get the aspect ratio by dividing the ```width``` for the ```height``` of the texture resolution. Finally by multiplying this ratio to the coordinates on ```y``` we will shrink this axis to match the original proportions.
Uncomment line 21 of the following code to see this in action.
* What we need to do to center this image?
## Digital upholstery
You may be thinking that this is unnecessarily complicated... and you are probably right. Also this way of working with images leaves enough room to different hacks and creative tricks. Try to imagine that you are an upholster and by stretching and folding a fabric over a structure you can create better and new patterns and techniques.
This level of craftsmanship links back to some of the first optical experiments ever made. For example on games *sprite animations* are very common, and is inevitably to see on it reminiscence to [phenakistoscope](https://en.wikipedia.org/wiki/Phenakistiscope), [zoetrope](https://en.wikipedia.org/wiki/Zoetrope) and [praxinoscope](https://en.wikipedia.org/wiki/Praxinoscope).
This could seem simple but the possibilities of modifying textures coordinates are enormous. For example:
Now is your turn:
* Can you make a kaleidoscope using what we have learned?
* Way before [Oculus](https://en.wikipedia.org/wiki/Oculus_Rift) or [google cardboard](https://en.wikipedia.org/wiki/Google_Cardboard), stereoscopic photography was a big thing. Could you code a simple shader to re-use these beautiful images?
* What other optical toys can you re-create using textures?
In the next chapters we will learn how to do some image processing using shaders. You will note that finally the complexity of shader makes sense, because it was in a big sense designed to do this type of process. We will start doing some image operations!
---
### 15/NOTES (15/NOTES.md)
No tile images
https://www.shadertoy.com/view/4tsGzf
https://www.shadertoy.com/view/lt2GDd
---
### 15/README Ch (15/README-ch.md)
# 图像处理
## 纹理
显卡(GPU)有特殊的图像存储类型。在中央处理器(CPU)上,图像往往储存成字节数组,但在GPU上图像却往往储存成```sampler2D``` (二维采样器)。它们更像是一个由浮点向量组成的表格(或矩阵)。更有意思的是,这张*表格*中向量们的值是连续的。这意味着邻近像素点的值之间是用较低级别的插值出来的。
为了用到这一特性,我们首先要把图像从CPU*上传*到GPU,然后再把纹理的```id```(序列号)传给对应的[```uniform```](../05)。这一切流程发生在着色器之外。
一旦纹理(texture)加载好了并且链接上了一个有效的```uniform sampler2D```,你就可以用[```texture2D()```](index.html#texture2D.md)函数获取特定坐标(用二维向量[```vec2```](index.html#vec2.md)类型表示)对应的颜色值(用四维向量[```vec4```](index.html#vec4.md)类型表示)。
```glsl
vec4 texture2D(sampler2D texture, vec2 coordinates)
```
在下面的代码中,我们将《神奈川冲浪里》(1830)以```uniform sampler2D u_tex0```为类型和名字加载了进来,并且我们在显示平面(billboard)中调用了它的每个像素:
如果你注意观察,你会发现纹理的坐标是归一化的!这真的是个惊喜,不是吗?纹理坐标和我们已然熟识的东西是一致的。它们的坐标总是在0.0和1.0之间。这意味着它和我们使用的归一化空间坐标完美吻合。
现在既然你已经了解了如何正确的加载纹理,是时候来试验性地探索我们究竟能用这一技巧做些什么了。快试试下面这些:
* 把纹理缩小到原先的一半。
* 把原先的纹理旋转90度。
* 将鼠标位置赋值给纹理坐标来移动纹理。
为什么你应该对纹理感到兴奋?首先,忘掉每个通道只有可怜的255个值吧;一旦你的图像被转换成了一个```uniform sampler2D```,所有的值都会在0.0和1.0的区间范围内(小数精度取决于你设置的```precision```)。这就是为什么着色器可以实现非常漂亮的后期处理效果。
其次,[```vec2()```](index.html#vec2.md)类型意味着你甚至可以获取到像素之间的值。如前所述,纹理是连续体(continuum)。也就是说,如果正确地设置好了你的纹理,你可以获取纹理图像上的任意值,而这些值在像素点之间是平滑过渡的,不会出现跳变!
最后,你可以把图像设置为在边缘处重复。这样的话,在你获取坐标在0.0到1.0这个归一化区间之外的值时,返回值会从另一边的边缘开始循环往复。
所有这些功能会让你的图像越发像是无限延展的化纤面料。你可以拉扯、伸缩你的纹理而无需注意它们原始的数据究竟是什么样的。要体验这一点,看看下面的代码吧,其中我们使用[我们先前创建的噪声函数](../11/)来扭曲纹理。
## 纹理分辨率
上述的种种示例仅展现了长宽相等的方形图像匹配方形显示平面(billboard)的情形。而至于非正方形图像,事情就没那么简单了。不幸的是,几个世纪以来的绘画艺术和摄影艺术发现非正方形比例的图像更令人赏心悦目。
我们该如何解决这个问题呢?我们需要知道这一图像的原始比例,才好在放大或缩小纹理的时候正确地保持它原始的[*宽高比*](http://en.wikipedia.org/wiki/Aspect_ratio)。为此,纹理的宽和高是以```uniform```的形式传递进着色器的——在我们的示例框架里是以纹理名后跟```Resolution```的```uniform vec2```传递进来的。一旦着色器里有了这些信息,我们就可以将纹理分辨率的```width```除以```height```来获得纹理的宽高比。最后,把这个比例和```y```坐标相乘,我们就可以实现伸缩这根轴来让纹理匹配其原始比例。
取消 21 行的注释来实操一下吧。
* 如果要这张图片居中显示,我们应该怎么做呢?
## 数字装潢(Digital upholstery)
你可能会觉得这未免太复杂了……呃,你大概率是对的。但这种对待图像的方式给了各种“奇技淫巧”足够的发挥空间。试想,你是一名室内装潢师,通过拉伸和折叠布料,你可以创造出更好的新图案和新技巧。
这种水平的工艺可以追溯到最早的一些光学实验。例如,游戏里很常见的*精灵动画*(*sprite animations*),你不可避免地会在它身上看到[费纳奇镜(phenakistoscope)](https://en.wikipedia.org/wiki/Phenakistiscope)、[走马盘(zoetrope)](https://en.wikipedia.org/wiki/Zoetrope)和[旋转活动视镜(praxinoscope)](https://en.wikipedia.org/wiki/Praxinoscope)的影子。
这看似简单,但修改纹理坐标可以带来巨大的可能性。例如:
现在轮到你了:
* 你能活学活用,做出万花筒效果吗?
* 在[Oculus](https://en.wikipedia.org/wiki/Oculus_Rift)和[谷歌Cardboard](https://en.wikipedia.org/wiki/Google_Cardboard)之前,立体摄影就已经很流行了。你能编写一个简单的着色器来重新使用这些美丽的图像吗?
* 你还可以使用纹理操作来重现哪些其他的光学玩具?
在下一章中,我们将学习如何使用着色器进行一些图像处理。你会注意到着色器的复杂性最终是有意义的,因为它很大程度上是为这一过程而生的。我们将开始做一些图像操作!
---
### 15/README Pt (15/README-pt.md)
# Processamento de imagens
## Texturas
Placas gráficas (GPUs) têm tipos especiais de memórias para imagens. Geralmente, nas CPUs as imagens são armazenadas como arrays de bytes, mas as GPUs armazenam as imagens como ```sampler2D```, o que é mais como uma tabela (ou matriz) de vetores de ponto flutuante. Mais interessante ainda, os valores dessa *tabela* de vetores são contínuos. Isso quer dizer que os valores entre os pixels são interpolados em baixo nível.
Para usar essa característica, primeiro precisamos fazer um *upload* da imagem da CPU para a GPU, para então passar o```id``` da textura para o [```uniform```](../05) correto. Tudo isso acontece fora do shader.
Uma vez que a textura esteja carregada e linkada a um ```uniform sampler2D``` válido, você pode solicitar valores específicos de cores em coordenadas específicas (formatadas em uma variiável [```vec2```](index.html#vec2.md)) usanto a função [```texture2D()```](index.html#texture2D.md) que vai retornar uma cor formatada em uma variável [```vec4```](index.html#vec4.md).
```glsl
vec4 texture2D(sampler2D texture, vec2 coordinates)
```
Verifique o seguinte código onde carregamos a Onda de Hokusai (1830) como um ```uniform sampler2D u_tex0``` e chamamos cada pixel dela dentro da tela:
Se você prestar atenção, vai notar que as coordenadas da textura estão normalizadas! Que surpresa, certo? As coordenadas das texturas são consistentes com o resto das coisas que já vimos e suas coordenadas estão entre 0.0 e 1.0, o que combina perfeitamente com o espaço normalizado de coordenadas que temos usado.
Agora que você já viu como carregamos uma textura de forma correta, é hora de fazer experiências, para descobrir o que podemos fazer com isso, tentando:
* Escalar a textura anterior, pela metade.
* Rotacionar a textura anterior em 90 graus.
* Ligar a posição do mouse às coordenadas, e movê-la.
Por que você deveria estar anomado com as texturas? Bem, antes de tudo, esqueça os 255 valores tristes para o canal, uma vez que sua imagem esteja transformada em um ```uniform sampler2D``` você terá todos os valores entre 0.0 e 1.0 (dependendo do que você setar na ```precision```). É por isso que as os shaders podem fazer efeitos realmente lindos pós-processament.
Em segundo lugar, o [```vec2()```](index.html#vec2.md) significa que você pode pegar os valores entre os pixels. Como dizemos antes, as texturas são um continuum. Isso quer dizer que se você configurar sua textura corretamente, você pode pedir valores em torno de toda a superfície de sua imagem, e os valores vão variar suavemente de pixel a pixel, sem pulos!
Por fim, você pode setar sua imagem para repetir nas bordas, então você pode dar valores além ou menores que os normalizados 0.0 e 1.0, os valores vão dar a volta e recomeçar.
Todas essas características fazem suas imagens mais como uma fábrica infinita. Você pode esticar e encolher sua textura sem notar a grade de bytes de que elas são compostas originalmente, ou o fim dela. Para experimentar isso, dê uma olhada no seguinte código, onde nós distorcemos uma textura usando a [função de ruído que já fizemos](../11/).
## Resolução de Texturas
Os exemplos acima rodam bem com imagens quadradas, onde os dois lados são iguais e combinam uma tela quadrada. Mas para imagens não-quadradas, as coisas podem ser um pouco mais complicadas, e infelizmente, séculos de art de imagens e fotos descobriram ser mais agradáveis aos olhos as proporções não-quadradas.
Como podemos resolver este problema? Bem, precisamos saber as proporções originais da imagem para saber como esticar a textura corretamente, de forma a ter o [*aspect ratio*](http://en.wikipedia.org/wiki/Aspect_ratio) (proporção da tela) original. Para isso, a largura e altura da textura são passados para o shader como um ```uniform``` que, no nosso framework de exemplo são passados como um ```uniform vec2``` com o mesmo nome da textura seguida da proposição ```Resolution```. Uma vez que temos essa informação no shader, podemos pegar o aspect ratio dividindo-se o ```width``` (largura) pelo ```height``` (altura) da resolução da textura. Finalmente, multiplicando-se essa taxa com as coordenadas em ```y``` vamos encolher esse eixo para combinar com as proporções originais.
Descomente a linha 21 do código a seguir para ver isso em ação.
* O que precisamos fazer para centralizar essa imagem?
## Estofamento digital
Você deve estar pensando que isso é algo desnecessariamente complicado... e provavelmente está certo. Também, esse modo de trabalhar com imagens deixa espaço suficiente para hacks diferentes e truques criativos. Tente imaginar que você é um estofador e, ao esticar e dobrar um tecido sobre uma estrutura, pode criar padrões e técnicas novas e melhores.
Esse nível de artesanato faz referência a alguns dos primeiros experimentos óticos já feitos. Por exemplo, em *animações de sprites* de jogos, são bem comuns, e é inevitável ver nele uma reminiscência ao fenacistoscópio, ao zootropo e ao praxinoscópio.
Isso poderia parecer simples, mas as possibilidades de modificar coordenadas de texturas são enormes. Por exemplo:
Agora é sua vez:
* Você consegue fazer um caleidoscópio usando o que aprendemos?
* Muito antes do Oculus ou do cardboard do google, a fotografoa estereoscópica era uma coisa incrível. Você poderia programar um shader simples para reutilizar essas lindas imagens?
* Que outros brinquedos óticos você pode recriar usando texturas?
Nos próximos capítulos, você vai aprender como fazer algum processamento em imagens, com os shaders. Vai notar que, finalmente, a complexidade do shaders faz sentido, porque ele foi, de certa forma, projetada para fazer esse tipo de processo. Vamos começar a fazer alguma operação com imagens!
---
### 15/README Tr (15/README-tr.md)
# Görüntü işleme
## Dokular
Grafik kartları (GPU'lar), görüntüler için özel bellek türlerine sahiptir. Genellikle CPU'larda görüntüler bayt dizileri olarak depolanır, ancak GPU'lar görüntüleri kayan nokta vektörlerinin tablosu (veya matrisi) gibi olan ```sampler2D``` olarak depolar. Daha ilginç olarak, bu vektörler *tablosunun* değerleri süreklidir. Bu, pikseller arasındaki değerlerin düşük seviyede enterpolasyon yapıldığı anlamına gelir.
Bu özelliği kullanmak için önce görüntüyü CPU'dan GPU'ya *yüklememiz*, ardından dokunun ```id```'sini doğru [```uniform```](../05)'a geçirmemiz gerekir. Tüm bunlar shader'ın dışında gerçekleşir.
Doku yüklenip geçerli bir ```uniform sampler2D```'ye bağlandıktan sonra, [```texture2D()```](index.html#texture2D.md) fonksiyonunu kullanarak belirli koordinatlarda ([```vec2```](index.html#vec2.md) değişkeni olarak formatlanmış) belirli renk değerini isteyebilirsiniz, bu da [```vec4```](index.html#vec4.md) değişkeni olarak formatlanmış bir renk döndürecektir.
```glsl
vec4 texture2D(sampler2D texture, vec2 coordinates)
```
Hokusai'nin Dalgası'nı (1830) ```uniform sampler2D u_tex0``` olarak yüklediğimiz ve tuvalin içindeki her pikselini çağırdığımız aşağıdaki kodu kontrol edin:
Dikkat ederseniz, doku koordinatlarının normalize edildiğini fark edeceksiniz! Ne sürpriz, değil mi? Doku koordinatları gördüğümüz diğer şeylerle tutarlıdır ve koordinatları, kullandığımız normalize edilmiş uzay koordinatlarıyla mükemmel şekilde eşleşen 0.0 ile 1.0 arasındadır.
Artık bir dokuyu doğru şekilde nasıl yükleyeceğimizi gördüğünüze göre, onunla ne yapabileceğimizi keşfetmek için deney yapma zamanı:
* Önceki dokuyu yarıya ölçekleyin.
* Önceki dokuyu 90 derece döndürün.
* Fare konumunu koordinatlara bağlayarak hareket ettirin.
Dokular hakkında neden heyecanlanmalısınız? Her şeyden önce kanal başına üzücü 255 değeri unutun; görüntünüz ```uniform sampler2D```'ye dönüştürüldüğünde 0.0 ile 1.0 arasındaki tüm değerlere sahip olursunuz (```precision```'a ne ayarladığınıza bağlı olarak). Bu yüzden shader'lar gerçekten güzel son işleme efektleri yapabilir.
İkincisi, [```vec2()```](index.html#vec2.md), pikseller arasında bile değerler elde edebileceğiniz anlamına gelir. Daha önce söylediğimiz gibi dokular bir sürekliliktir. Bu, dokunuzu doğru ayarlarsanız, görüntünüzün yüzeyi boyunca değerler isteyebileceğiniz ve değerlerin pikselden piksele atlamalar olmadan yumuşak bir şekilde değişeceği anlamına gelir!
Son olarak, görüntünüzü kenarlarda tekrarlanacak şekilde ayarlayabilirsiniz, bu nedenle normalize edilmiş 0.0 ve 1.0'ın üstünde veya altında değerler verirseniz, değerler baştan sarılacaktır.
Tüm bu özellikler görüntülerinizi daha çok sonsuz bir kumaş gibi yapar. Dokunuzu, orijinal olarak oluşturuldukları bayt ızgarasını veya sonlarını fark etmeden esnetebilir ve küçültebilirsiniz. Bunu deneyimlemek için [zaten yaptığımız gürültü fonksiyonunu](../11/) kullanarak bir dokuyu bozdurduğumuz aşağıdaki koda bakın.
## Doku çözünürlüğü
Yukarıdaki örnekler her iki tarafın eşit olduğu ve kare tuvalimizle eşleştiği kare görüntülerle iyi çalışır. Ancak kare olmayan görüntüler için işler biraz daha karmaşık olabilir ve ne yazık ki yüzyıllarca süren resim sanatı ve fotoğrafçılık, göze kare olmayan oranların daha hoş geldiğini keşfetmiştir.
Bu sorunu nasıl çözebiliriz? Dokuyu orijinal [*en-boy oranına*](http://en.wikipedia.org/wiki/Aspect_ratio) sahip olacak şekilde doğru germek için görüntünün orijinal oranlarını bilmemiz gerekir. Bunun için dokunun genişliği ve yüksekliği shader'a ```uniform``` olarak geçirilir, örnek framework'ümüzde dokunun adıyla aynı adlı ```uniform vec2```'ler ```Resolution``` son ekiyle geçirilir. Bu bilgiyi shader'da elde ettikten sonra, doku çözünürlüğünün ```genişliğini``` ```yüksekliğine``` bölerek en-boy oranını elde edebiliriz. Son olarak, bu oranı ```y```'deki koordinatlarla çarparak bu ekseni orijinal oranlara uyacak şekilde küçülteceğiz.
Bunu uygulamada görmek için aşağıdaki kodun 21. satırının yorumunu kaldırın.
* Bu görüntüyü ortalamak için ne yapmamız gerekir?
## Dijital döşeme
Bunun gereksiz yere karmaşık olduğunu düşünüyor olabilirsiniz... ve muhtemelen haklısınız. Ayrıca görüntülerle çalışmanın bu yolu, farklı hileler ve yaratıcı numaralar için yeterli alan bırakır. Bir döşemeci olduğunuzu ve bir yapı üzerinde kumaşı gererek ve katlayarak daha iyi ve yeni desenler ve teknikler yaratabileceğinizi hayal edin.
Bu zanaatkarlık seviyesi, şimdiye kadar yapılmış ilk optik deneylerin bazılarına bağlıdır. Örneğin oyunlarda *sprite animasyonları* çok yaygındır ve [fenakistoskop](https://en.wikipedia.org/wiki/Phenakistiscope), [zeotrop](https://en.wikipedia.org/wiki/Zoetrope) ve [praksiskop](https://en.wikipedia.org/wiki/Praxinoscope) anımsatmalarını görmek kaçınılmazdır.
Bu basit görünebilir ama doku koordinatlarını değiştirme olanakları muazzamdır. Örneğin:
Şimdi sıra sizde:
* Öğrendiklerimizle bir kaleydoskop yapabilir misiniz?
* [Oculus](https://en.wikipedia.org/wiki/Oculus_Rift) veya [Google Cardboard](https://en.wikipedia.org/wiki/Google_Cardboard)'dan çok önce, stereoskopik fotoğrafçılık büyük bir şeydi. Bu güzel görüntüleri yeniden kullanmak için basit bir shader kodlayabilir misiniz?
* Dokular kullanarak başka hangi optik oyuncakları yeniden yaratabilirsiniz?
Sonraki bölümlerde shader'lar kullanarak bazı görüntü işleme yapmayı öğreneceğiz. Shader'ın karmaşıklığının nihayet mantıklı olduğunu göreceksiniz, çünkü geniş anlamda bu tür işlemleri yapmak için tasarlanmıştır. Bazı görüntü operasyonları yapmaya başlayacağız!
---
### 15/README Ua (15/README-ua.md)
# Обробка зображень
## Текстури
Графічні карти (GPU) мають для зображень спеціальні типи пам’яті. Зазвичай CPU зберігають зображення у вигляді масиву байтів, а GPU зберігають зображення як ```sampler2D```, що більше схоже на таблицю (або матрицю) векторів типу float. Що ще цікавіше, значення цієї *таблиці* векторів безперервні. Це означає, що значення між пікселями інтерполюються на низькому рівні.
Щоб скористатися цим функціоналом, нам спочатку потрібно *завантажити* зображення з CPU на GPU, а потім передати ```id``` текстури до відповідної [```uniform```](../05/?lan=ua)-змінної. Початкове завантаження зображення відбувається поза шейдером.
Після того, як текстуру завантажено та прив'язано до змінної через ```uniform sampler2D```, ви можете отримати конкретне значення кольору у певних координатах типу [```vec2```](../glossary/?lan=ua&search=vec2) за допомогою функції [```texture2D()```](../glossary/?lan=ua&search=texture2D) яка поверне колір типу [```vec4```](../glossary/?lan=ua&search=vec4).
```glsl
vec4 texture2D(sampler2D texture, vec2 coordinates)
```
Перегляньте наступний код, у якому ми завантажуємо зображення [Хвилі Хокусая (1830)](https://en.wikipedia.org/wiki/The_Great_Wave_off_Kanagawa) як ```uniform sampler2D u_tex0```, отримуємо та відображаємо кожен її піксель всередині полотна:
Якщо ви звернете увагу, то помітите, що координати для текстури нормалізовані! Який сюрприз, правда? Координати текстур консистентні з нормалізованими координатами простору, що також знаходяться в діапазоні від 0.0 до 1.0.
Тепер, коли ви побачили, як правильно завантажувати текстуру, настав час поекспериментувати та дізнатися, що можна з нею зробити:
* Змініть масштаб текстури вдвічі.
* Поверніть текстуру на 90 градусів.
* Прив'яжіть координати до позиції курсору, щоб переміщати зображення.
Чому ви повинні бути в захваті від текстур? По-перше, забудьте про сумні 255 значень для кожного каналу. Як тільки ваше зображення перетворено на ```uniform sampler2D```, ви працюватимете у діапазоні значень від 0.0 до 1.0. Ось чому шейдери можуть створювати дійсно красиві ефекти постобробки.
По-друге, за допомогою координат [```vec2```](../glossary/?lan=ua&search=vec2) ви можете отримати значення кольору текстури навіть між пікселями. Як ми вже говорили раніше, значення текстури є континуумом. Це означає, що ви можете отримувати значення вашого зображення по всій його поверхні. Ці значення плавно змінюватимуться від пікселя до пікселя без стрибків!
Нарешті, ви можете налаштувати шейдер для повторення вашого зображення вздовж полотна. Наприклад, при використанні значень, що менше або більше від нормалізованих 0.0 та 1.0 ви можете "загорнути" їх у цей самий діапазон та знову отримати кольори в межах зображення.
Усі ці можливості роблять ваші зображення схожими на нескінченну тканину спандекс. Ви можете розтягувати та звужувати свою текстуру, не зважаючи на сітку байтів, з яких вона складалася початково. Щоб відчути це, подивіться на наступний код, де ми деформуємо текстуру за допомогою [функції шуму, з попередніх розділів](../11/?lan=ua).
## Роздільна здатність текстури
Наведені вище приклади добре працюють з квадратними зображеннями, де обидві сторони рівні та збігаються з нашим квадратним полотном. Але для неквадратних зображень все може бути трохи складніше. Століття художнього мистецтва та фотографії знайшли для зображень більш приємні для ока неквадратні пропорції.
Як ми можемо розв'язати цю проблему? Щоб дізнатися як правильно розтягнути текстуру, нам потрібно знати оригінальні пропорції зображення, що дозволить отримати його [*співвідношення сторін*](http://en.wikipedia.org/wiki/Aspect_ratio). Для цього ширина та висота текстури також передаються шейдеру через ```uniform```, який у нашому прикладі буде мати тип ```vec2```. Ми надали цій змінній таку саму назву як і для текстури, але з доповненням ```Resolution```. Отримавши цю інформацію, ми можемо отримати у шейдері співвідношення сторін, поділивши ```ширину``` на ```висоту```. Нарешті, помноживши це співвідношення на координату ```y```, ми змінимо цю вісь таким чином, щоб вона відповідала бажаним пропорціям.
Розкоментуйте рядок 21 наступного коду, щоб побачити це в дії:
* Поміркуйте, що потрібно зробити, щоб відцентрувати це зображення по центру полотна?
## Цифрова оббивка
Ви можете подумати, що все це трохи ускладнено... й, напевно, матимете рацію. Але такий спосіб роботи з зображеннями залишає достатньо місця для різних хитрощів та творчих прийомів. Спробуйте уявити, що ви робите оббивку, а натягуючи та огортаючи тканину поверх конструкції, ви можете створювати нові патерни та цікавіші результати.
Подібний рівень ремісництва нагадує деякі з перших оптичних експериментів. Наприклад, в іграх дуже поширена *спрайтова анімація*, що навіває спогади про [фенакістископ](https://en.wikipedia.org/wiki/Phenakistiscope), [зоотроп](https://en.wikipedia.org/wiki/Zoetrope) та [праксиноскоп](https://en.wikipedia.org/wiki/Praxinoscope).
Виглядає просто, але можливості для зміни текстурних координат просто величезні.
Тепер ваша черга:
* Спробуйте зробити калейдоскоп:
* Задовго до [Oculus](https://en.wikipedia.org/wiki/Oculus_Rift) та [google cardboard](https://en.wikipedia.org/wiki/Google_Cardboard) стереоскопічна фотографія була неабиякою справою. Чи можете ви закодувати простий шейдер, щоб повторно використати ці чудові зображення?
* Які ще оптичні іграшки можна відтворити за допомогою текстур?
У наступних розділах ми побачимо як за допомогою шейдерів можна обробляти зображення, виконуючи певні операції. Зрештою шейдери не в останню чергу розроблені саме для цього.
---
### 16/README (16/README.md)
## Image operations
Below you will see some examples with images where you can play around and uncomment some lines to see the corresponding results.
### Invert
### Add, Subtract, Multiply and others
### PS Blending modes
---
### 16/README Tr (16/README-tr.md)
## Görüntü işlemleri
Aşağıda görüntülerle oynayabileceğiniz ve karşılık gelen sonuçları görmek için bazı satırları yorumdan çıkarabileceğiniz örnekleri göreceksiniz.
### Tersine çevirme
### Toplama, Çıkarma, Çarpma ve diğerleri
### PS Harmanlama modları
---
### 16/README Ua (16/README-ua.md)
## Операції із зображеннями
Нижче ви побачите кілька прикладів із зображеннями, де ви можете пограти зі значеннями та розкоментувати певні рядки, щоб побачити відповідний результат.
### Інвертування
Розкоментуйте рядок 18:
### Додавання, віднімання, множення та інші варіанти
В даному шейдері завантажено два зображення, які розташовано один над одним. По черзі розкоментовуйте рядки 22-27 та спостерігайте за результатами поєднання цих зображень залежно від операції. Перш ніж розкоментувати рядок, поміркуйте над тим який має бути результат і чому:
### Режими змішування як у Photoshop
---
### Appendix/README (appendix/README.md)
# Appendix
1. [How can I navigate this book off-line?](00/)
2. [How to run the examples on a Raspberry Pi?](01/)
3. [How to print this book?](02/)
4. [How can I collaborate with this book?](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 ...
---
### Appendix/README Ch (appendix/README-ch.md)
# 附录
1. [如何离线阅读此书?](00/)
2. [如何在树莓派上运行示例程序?](01/)
3. [如何打印这本书?](02/)
4. [我怎样共创这本书?](03/)
5. [给那些从JS语言过来的人的介绍](04/) [Nicolas Barradeau](http://www.barradeau.com/)著
6. [向量导论](05/) by ...
7. [插值导论](06) by ...
---
### Appendix/README De (appendix/README-de.md)
# Appendix
1. [Wie kann ich dieses Buch offline lesen?](00/?lan=de)
2. [Wie kann ich die Beispielprogramme auf einem Raspberry Pi ausführen?](01/?lan=de)
3. [Wie kann ich dieses Buch ausdrucken?](02/?lan=de)
4. [Wie kann ich zu diesem Buch beitragen?](03/?lan=de)
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 ...
---
### Appendix/README Fr (appendix/README-fr.md)
# Annexes
1. [Comment puis-je consulter ce livre hors-ligne ?](00/?lan=fr)
2. [Comment exécuter les exemples sur un Raspberry Pi ?](01/?lan=fr)
3. [Comment imprimer ce livre ?](02/?lan=fr)
4. [Comment puis-je contribuer à ce livre?](03/?lan=fr)
5. [Une introduction pour ceux qui viennent de JS](04/?lan=fr) de [Nicolas Barradeau](http://www.barradeau.com/)
6. [Une introduction aux vecteurs](05/?lan=fr) de ...
7. [Une introduction à l'interpolation](06/?lan=fr) de ...
---
### Appendix/README Id (appendix/README-id.md)
# 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 ...
---
### Appendix/README Pl (appendix/README-pl.md)
# Dodatek
1. [Jak mogę nawigować po tej książce w trybie off-line?](00/)
2. [Jak uruchomić przykłady na Raspberry Pi?](01/)
3. [Jak wydrukować tę książkę?](02/)
4. [Jak współpracować przy tworzeniu tej książki?](03/)
5. [Wprowadzenie dla osób pochodzących z JS](04/) autorstwa [Nicolas Barradeau](http://www.barradeau.com/)
6. [Wprowadzenie dla wektorów](05/) autorstwa ...
7. [Wprowadzenie do interpolacji](06) przez ...
---
### Appendix/README Ru (appendix/README-ru.md)
# Приложение
1. [Как читать книгу оффлайн?](00/?lan=ru)
2. [Как запустить примеры на Raspberry Pi?](01/?lan=ru)
3. [Как напечатать книгу?](02/?lan=ru)
4. [Как принять участие в создании книги?](03/?lan=ru)
5. [Введение для JavaScript-программистов](04/?lan=ru) ([Николя Баррадо](http://www.barradeau.com/))
6. [Введение в векторную алгебру](05/)
7. [Введение в интерполяцию](06)
---
### Appendix/README Tr (appendix/README-tr.md)
# Ek
1. [Bu kitapta çevrimdışı nasıl gezinirim?](00/)
2. [Örnekleri Raspberry Pi'da nasıl çalıştırırım?](01/)
3. [Bu kitabı nasıl yazdırabilirim?](02/)
4. [Bu kitaba nasıl katkıda bulunabilirim?](03/)
5. [JS'den gelenler için giriş](04/) - [Nicolas Barradeau](http://www.barradeau.com/)
6. [Vektörlere giriş](05/) - ...
7. [Enterpolasyona giriş](06) - ...
---
### Appendix/README Ua (appendix/README-ua.md)
# Додаток
1. [Як користуватись книгою офлайн?](00/?lan=ua)
2. [Як запустити приклади на Raspberry Pi?](01/?lan=ua)
3. [Як надрукувати цю книгу?](02/?lan=ua)
4. [Як прийняти участь у розвитку книги?](03/?lan=ua)
5. [Вступ для тих, хто прийшов із JS](04/?lan=ua) від [Nicolas Barradeau](http://www.barradeau.com/)
6. [Введення до векторів](05/?lan=ua)
7. [Введення в інтерполяцію](06/?lan=ua)
---
### Appendix/README Vi (appendix/README-vi.md)
# Phụ lục
1. [Làm thế nào để đọc quyển sách này mà không cần Internet ?](00/?lan=vi)
2. [Làm thế nào để chạy thử ví dụ trên Raspberry Pi ?](01/?lan=vi)
3. [Làm thế nào để in quyển sách này ?](02/?lan=vi)
4. [Làm thế nào để góp sức cho quyển sách này ?](03/?lan=vi)
5. [Giới thiệu cho người đã biết Javascript](04/?lan=vi) từ [Nicolas Barradeau](http://www.barradeau.com/)
6. [Giới thiệu về vector](05/?lan=vi) từ ...
7. [Giới thiệu về nội suy](06?lan=vi) từ ...
---
### Appendix/00/README (appendix/00/README.md)
## How can I navigate this book off-line?
Let’s say you have a long trip and you want to use it to teach yourself some shaders. In that case you can make a local copy of this book on your computer and run a local server.
For that you only need PHP, Python 3 and a git client. On MacOS and Raspberry Pi computers Python is installed by default but you still need to install PHP and a git client. For that:
On **MacOSX** be sure to have [homebrew](http://brew.sh/) installed and then on your terminal do:
```bash
brew update
brew upgrade
brew install git php
```
On **Raspberry Pi** you need to get [Raspbian](https://www.raspberrypi.org/downloads/raspbian/), a Debian-based Linux distribution made for Raspberry Pi and then do:
```bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git-core glslviewer php
```
Once you have everything installed you just need to do:
```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
```
Then open your browser to [`http://localhost:8000/`](http://localhost:8000/)
---
### Appendix/00/README De (appendix/00/README-de.md)
## Wie kann ich dieses Buch offline lesen?
Nehmen wir einmal an, Du gehst auf eine längere Reise und möchtest Dich unterwegs in die Shader-Programmierung einarbeiten. In diesem Fall könntest Du eine Kopie dieses Buches auf Deinen Rechner laden und diese über einen lokalen Server anzeigen lassen.
Alles, was Du dafür benötigst, ist Python 3 und ein Client-Programm für GIT. Auf Computern mit MacOS und auf dem RaspberryPi ist Python standardmäßig bereits vorinstalliert. Dort musst Du lediglich den GIT-Client zusätzlich installieren.
Unter **MacOSX** benötigst Du dafür [homebrew](http://brew.sh/). Sobald das Paket installiert ist, kannst Du in einem Terminal-Fenster folgendes eingeben:
```bash
brew update
brew upgrade
brew install git
```
Auf einem **RaspberryPi** gibst Du folgendes ein:
```bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git-core glslviewer
```
Hast Du alles beisammen, musst Du lediglich folgende Befehle aufrufen, um das *Book of Shaders* per GIT auf Deinen Rechner zu laden und den Server zur Anzeige des Inhalts zu starten:
```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
```
Nutze dann den vorinstallierten Internet-Browser auf Deinem Rechner zur Anzeige des Buches durch Eingabe folgender URL [```http://localhost:8000/```](http://localhost:8000/)
---
### Appendix/00/README Fr (appendix/00/README-fr.md)
## Comment puis-je consulter ce livre hors-ligne ?
Disons que vous vous préparez à partir pour un long voyage et que vous souhaitez le mettre à profit pour apprendre quelques shaders. Dans ce cas, pourquoi pas créer une copie locale de ce livre sur votre ordinateur et lancer un serveur local.
Pour cela, vous n'avez besoin que de PHP, Python 3 et d'un client git. Sur les ordinateurs MacOS et Raspberry Pi, Python est installé par défaut, mais vous il vous reste à installer PHP et un client git. Pour cela :
Sous **MacOSX**, assurez-vous d'avoir [homebrew](http://brew.sh/) installé et ensuite dans votre terminal :
```bash
brew update
brew upgrade
brew install git php
```
Sur votre **Raspberry Pi**, vous devez installer [Raspbian](https://www.raspberrypi.org/downloads/raspbian/), une distribution Linux basée sur Debian conçu pour Raspberry Pi, puis lancer :
```bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git-core glslviewer php
```
Une fois que vous avez tout installé, il vous suffit d'exécuter les commandes :
```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
```
Enfin, ouvrez dans votre navigateur l'URL [`http://localhost:8000/`](http://localhost:8000/), et voilà !
---
### Appendix/00/README Id (appendix/00/README-id.md)
## 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/)
---
### Appendix/00/README It (appendix/00/README-it.md)
## Come posso consultare questo libro offline?
Diciamo che si dispone di un lungo viaggio e si desidera usarlo per imparare da soli alcuni shaders. In questo caso è possibile effettuare una copia locale di questo libro sul computer ed eseguire un server locale.
Per questo è necessario solo Python 3 e un client git. Sui computer MacOS e Raspberry Pi, Python è installato di default, ma è comunque necessario installare un client git. Per fare ciò:
Su **MacOSX** siate sicuri di avere installato [homebrew](http://brew.sh/) e quindi sul terminale fate:
```bash
brew update
brew upgrade
brew install git
```
Su **Raspberry Pi** è necessario fare:
```bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git-core glslviewer
```
Una volta che avete installato tutto, non vi resta che fare:
```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
```
Quindi aprite il browser e inserite [```http://localhost:8000/```](http://localhost:8000/)
---
### Appendix/00/README Pl (appendix/00/README-pl.md)
## Jak mogę korzystać z tej książki offline?
Powiedzmy, że masz przed sobą długą podróż i chcesz ją wykorzystać do nauczenia się kilku shaderów. W takim przypadku możesz zrobić lokalną kopię tej książki na swoim komputerze i uruchomić lokalny serwer.
Do tego potrzebujesz tylko PHP, Pythona 3 i Git'a. Na komputerach z systemem macOS i Raspberry Pi Python jest zainstalowany domyślnie, ale musisz jeszcze zainstalować PHP i klienta Git. W tym celu:
Na **MacOSX** musisz mieć zainstalowane [homebrew](http://brew.sh/) by następnie w terminalu uruchomić:
```bash
brew update
brew upgrade
brew install git php
```
Na **Raspberry Pi** potrzebujesz [Raspbian](https://www.raspberrypi.org/downloads/raspbian/), opartej na Debianie dystrybucji Linuxa, by następnie uruchomić:
```bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git-core glslviewer php
```
Gdy masz już wszystko zainstalowane wystarczy uruchomić:
```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
```
Następnie otwórz swoją przeglądarkę na [`http://localhost:8000/`](http://localhost:8000/)
---
### Appendix/00/README Ru (appendix/00/README-ru.md)
## Как читать книгу оффлайн?
Предположим, вы отправились в длительное путешествие, и хотите немного подучить программирование шейдеров за это время. В этом случае вы можете скопировать книгу к себе на компьютер и запустить сервер локально.
Для этого понадобится только PHP, Python 3 и git-клиент. На MacOS и Raspberry Pi Python установлен по умолчанию, но PHP и Git придётся установить следующим образом:
На **MacOSX** убедитесь, что у вас установлен [homebrew](http://brew.sh/) и выполните следующие команды в терминале:
```bash
brew update
brew upgrade
brew install git php
```
На **Raspberry Pi** установите [Raspbian](https://www.raspberrypi.org/downloads/raspbian/) - дистрибутив Linux для Raspberry Pi, основанный на Debian, и выполните:
```bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git-core glslviewer php
```
Когда всё установлено, остаётся последний шаг:
```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
```
Теперь откройте в браузере адрес [`http://localhost:8000/`](http://localhost:8000/)
---
### Appendix/00/README Tr (appendix/00/README-tr.md)
## Bu kitapta çevrimdışı nasıl gezinirim?
Diyelim ki uzun bir yolculuğunuz var ve bunu kendinize shader öğretmek için kullanmak istiyorsunuz. Bu durumda bu kitabın yerel bir kopyasını bilgisayarınıza yapabilir ve yerel bir sunucu çalıştırabilirsiniz.
Bunun için yalnızca PHP, Python 3 ve bir git istemcisine ihtiyacınız var. MacOS ve Raspberry Pi bilgisayarlarında Python varsayılan olarak yüklüdür ancak yine de PHP ve git istemcisi yüklemeniz gerekir. Bunun için:
**MacOSX**'te [homebrew](http://brew.sh/) yüklü olduğundan emin olun ve ardından terminalinizde şunları yapın:
```bash
brew update
brew upgrade
brew install git php
```
**Raspberry Pi**'da, Raspberry Pi için yapılmış Debian tabanlı bir Linux dağıtımı olan [Raspbian](https://www.raspberrypi.org/downloads/raspbian/)'ı edinmeniz ve ardından şunları yapmanız gerekir:
```bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git-core glslviewer php
```
Her şey yüklendikten sonra yapmanız gereken tek şey:
```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
```
Ardından tarayıcınızı [`http://localhost:8000/`](http://localhost:8000/) adresine açın
---
### Appendix/00/README Ua (appendix/00/README-ua.md)
## Як користуватись книгою офлайн?
Припустимо, у вас довга подорож і ви хочете за цей час повчити шейдери. У такому випадку ви можете скопіювати книгу на свій комп'ютер і запустити її на локальному сервері.
Для цього вам потрібні лише PHP, Python 3 і git-клієнт. На комп'ютерах MacOS і Raspberry Pi Python встановлено за замовчуванням, але потрібно ще встановити PHP і git-клієнт. Це можна зробити наступним чином:
Для **MacOSX** переконайтесь, що у вас встановлено [homebrew](http://brew.sh/), після чого в терміналі виконайте наступні команди:
```bash
brew update
brew upgrade
brew install git php
```
На **Raspberry Pi** встановіть [Raspbian](https://www.raspberrypi.org/downloads/raspbian/), дистрибутив Linux для Raspberry Pi на основі Debian, а потім виконайте наступні команди:
```bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git-core glslviewer php
```
Після того, як все буде встановлено, склонуйте проєкт та запустіть локальний сервер:
```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
```
Потім відкрийте у своєму браузері адресу [`http://localhost:8000/`](http://localhost:8000/)
---
### Appendix/00/README Vi (appendix/00/README-vi.md)
## Làm thế nào để đọc quyển sách này mà không cần Internet ?
Giả sử bạn có một chuyến đi dài và muốn tranh thủ học shader. Trong trường hợp đó bạn có thể tạo một bản sao của quyển sách này và hiển thị nó bằng server nội bộ.
Để làm điều đó, bạn chỉ cần có PHP, Python 2.6 và git. Trên các máy MacOS và Raspberry Pi thì Python đã được cài đặt sẵn rồi nhưng bạn vẫn cần cài thêm PHP và git. Cụ thể:
Trên **MacOSX** hãy cài [homebrew](http://brew.sh/) trước rồi mở terminal ra và gõ:
```bash
brew update
brew upgrade
brew install git php
```
Trên **Raspberry Pi** bạn cần cài [Raspbian](https://www.raspberrypi.org/downloads/raspbian/), là một phiên bản Linux dựa trên Debian dành riêng cho Raspberry Pi, sau đó gõ lệnh:
```bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git-core glslviewer php
```
Khi đã cài đặt xong các phần mềm cần thiết, bạn chỉ cần gõ:
```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
```
Rồi truy cập server nội bộ ở địa chỉ [`http://localhost:8000/`](http://localhost:8000/)
---
### Appendix/01/README (appendix/01/README.md)
## How to run the examples on a Raspberry Pi?
A few years ago, assuming that everybody has a computer with a graphical processing unit was a long shot. Now, most computers have a GPU, but it's still a high bar for a requirement in a workshop or class, for example.
Thanks to the [Raspberry Pi Foundation](http://www.raspberrypi.org/) a new type of small and cheap generation of computers (around $35 each) has found its way into classrooms. More importantly for the purposes of this book, the [Raspberry Pi](http://www.raspberrypi.org/) comes with a decent Broadcom GPU that can be accessed directly from the console. I made a [flexible GLSL live coding tool call **glslViewer**](https://github.com/patriciogonzalezvivo/glslViewer) that runs all the examples in this book. This program also has the ability to update automatically when the user saves a change to their code. What does this mean? You can edit the shader and every time you save it, the shader will be re-compile and render for you.
By making a local copy of the repository of this book (see the above section) and having [`glslViewer` installed](https://github.com/patriciogonzalezvivo/glslViewer), users can run the examples with `glslviewer`. Also by using the `-l` flag they can render the example in a corner of the screen while they modify it with any text editor (like `nano`, `pico`, `vi`, `vim` or `emacs`). This also works if the user is connected through ssh/sftp.
To install and set this all up on the Raspberry Pi after installing [Raspbian](https://www.raspberrypi.org/downloads/raspbian/), a Debian-based Linux distribution made for Raspberry Pi, and logging in, type the following commands:
```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
```
---
### Appendix/01/README Ch (appendix/01/README-ch.md)
## 如何在树莓派上运行示例程序?
几年前,假设每个人都有一台有图形处理单元的计算机是一个大胆的想法。 现在,大多数计算机都有 GPU,但对于工作坊或课堂的要求来说,这仍然是个很高的标准。
多亏了 [树莓派基金会](http://www.raspberrypi.org/), 一种新型的小型廉价计算机(每台约35美元)已被引入课堂。更重要的是,就本书的需求而言,[树莓派](http://www.raspberrypi.org/)配备了一个不错的可以直接从控制台访问的Broadcom GPU。我做了一个 [叫作**glslViewer**的灵活的GLSL实时编程工具](https://github.com/patriciogonzalezvivo/glslViewer),它可以运行这本书里全部的示例。当用户保存对其代码的更改时,该编程工具还具有自动更新的能力。这是啥意思? 就是说,你可以编辑着色器,每次保存时,着色器都会重新编译并渲染。
通过制作本书的本地副本(详情见上一章节) 并 [安装好`glslViewer`](https://github.com/patriciogonzalezvivo/glslViewer),用户可以使用`glslviewer`运行示例。此外,通过使用 `-l` 标志,它们可以在你用任何文本编辑器(例如 `nano`, `pico`, `vi`, `vim` 或 `emacs`)来修改代码的时候在屏幕角落渲染示例。如果用户通过ssh或sftp协议连接,这也有效。
在树莓派上装完 [Raspbian](https://www.raspberrypi.org/downloads/raspbian/)——一个为树莓派开发的基于Debian的Linux发行版本——之后,要在树莓派上装好搞好这一切,只需要登陆系统,输入如下指令:
```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
```
---
### Appendix/01/README De (appendix/01/README-de.md)
## Wie kann ich die Beispiele auf einem RaspberryPi ausführen?
Vor wenigen Jahren konnte man noch nicht davon ausgehen, dass jedermann über einen Computer mit einer GPU verfügt. Heutzutage gilt das nicht mehr. Doch im Bereich von Schulen, Universitäten und anderen Weiterbildungseichrichtungen ist dies immer noch eine hohe Anforderung.
Durch das [Raspberry Projekt](http://www.raspberrypi.org/) hat mittlerweile eine neue Generation kleiner und billiger Computer (das Stück ab ca. 40 Euro) ihren Weg in viele Klassenzimmer gefunden. Vor allem verfügt der [RaspberryPi](http://www.raspberrypi.org/) über einen ansehnlichen Grafikchip mit GPU, der direkt aus der Kommandozeile angesprochen werden kann.
Ich habe ein flexibles Werkzeug für die Programmierung von GLSL-Shadern entwickelt, den [**glslViewer**](https://github.com/patriciogonzalezvivo/glslViewer). Damit können alle Beispiele aus diesem Buch ausgeführt werden. Sobald man Veränderungen am aktuellen Shader-Programmcode abspeichert, kompiliert das Programm den Shader erneut und bringt ihn zur Ausführung. Auf dem Bildschirm erscheint daraufhin die aktualisierte Anzeige des Shaders.
Indem Du eine lokale Kopie dieses Buches und seiner Beispielprogramme auf Deinem Rechner anlegst (mehr dazu im vorhergehenden Kapitel) und den [```glslViewer```] (https://github.com/patriciogonzalezvivo/glslViewer) installierst, kannst Du die Beispielprogramme mit dem ```glslviewer``` ausführen. Wenn Du beim Start dieses Programms den Kommandozeilenschalter ```-l``` angibst, erscheint die erzeugte Grafik in einer Ecke des Bildschirms, während Du gleichzeitig den Shader-Programmcode mit einem beliebigen Text-Editor (etwa ```nano```, ```pico```, ```vi```, ```vim``` oder ```emacs```) bearbeitest. Das funktioniert auch, wenn Du mit dem Terminal des RaspberryPi über ssh/sftp verbunden bist.
Um die angesprochenen Tools auf einem RaspberryPi zu installieren, rufe nach dem Start des Betriebssystems und dem Einloggen folgende Befehle über die Kommandozeile auf:
```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
```
---
### Appendix/01/README Fr (appendix/01/README-fr.md)
## Comment exécuter les exemples sur un Raspberry Pi ?
Il y a quelques années, supposer que tout le monde dispose d'un ordinateur doté d'une unité de traitement graphique était ambitieux. Maintenant, la plupart des ordinateurs possèdent un GPU, mais c'est toujours une exigence compliqué dans un atelier ou une classe, par exemple.
Grâce à la [Fondation Raspberry Pi](http://www.raspberrypi.org/), une nouvelle génération d'ordinateurs peu coûteux (environ 30€ l'unité) a trouvé son chemin dans les salles de classe. Plus important encore pour le propos de ce livre, le Raspberry Pi est livré avec un bon GPU Broadcom qui peut être utilisé directement depuis la console. J'ai créé un [outil flexible de développement en temps réel pour GLSL appelé **glslViewer**](https://github.com/patriciogonzalezvivo/glslViewer) qui exécute tous les exemples de ce livre. Ce programme a également la capacité de s'actualiser automatiquement lorsque l'utilisateur enregistre une modification de son code. Qu'est-ce que cela veut dire ? Vous pouvez modifier le shader et chaque fois que vous l'enregistrez, le shader sera re-compilé et rendu pour vous.
En effectuant une copie locale du dépôt git de ce livre (voir la section ci-dessous) et avec [`glslViewer` installé](https://github.com/patriciogonzalezvivo/glslViewer), les utilisateurs peuvent exécuter les exemples avec `glslviewer`. De plus, en utilisant l'option `-l`, ils peuvent lancer les exemples dans un coin de l'écran pendant qu'ils les modifient avec n'importe quel éditeur de texte (comme `nano`, `pico`, `vi`, `vim` ou `emacs`). Cela fonctionne également si l'utilisateur est connecté via ssh/sftp.
Pour installer et configurer tout cela sur Raspberry Pi, après l'installation de [Raspbian](https://www.raspberrypi.org/downloads/raspbian/), une distribution Linux basée sur Debian conçue pour Raspberry Pi, connectez-vous et tapez les commandes suivantes :
```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
```
---
### Appendix/01/README Id (appendix/01/README-id.md)
## 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
```
---
### Appendix/01/README It (appendix/01/README-it.md)
## Come posso eseguire gli esempi su un Raspberry Pi?
Alcuni anni fa, non era del tutto ovvio che tutti disponessero di un computer con una GPU. Ora, nonostante la maggior parte dei computer abbia una carta grafica, non tutti i corsi o classi possono permettersene uno.
Grazie al [progetto Raspberry Pi](http://www.raspberrypi.org/) una nuova generazione di computer piccoli ed economici (circa 35euro ciascuno) ha cominciato a diffondersi nelle aule scolastiche. Ancora più importante ai fini di questo libro, il [Raspberry Pi](http://www.raspberrypi.org/) viene fornito con una scheda GPU Bradcom decente a cui si può accedere direttamente dalla console. Ho creato uno [strumento flessibile per programmare GLSL live chiamato **glslViewer**](https://github.com/patriciogonzalezvivo/glslViewer) capace di far funzionare tutti gli esempi di questo libro. Questo programma è anche capace di aggiornare automaticamente le modifiche che l'utente fa quando le salva. Cosa significa? è possibile modificare lo shader e ogni volta che lo si salva, lo shader sarà ricompilato e visualizzato per voi.
Facendo una copia locale del repository di questo libro (vedi paragrafo precedente) e con [```glslViewer``` installato](https://github.com/patriciogonzalezvivo/glslViewer), gli utenti possono eseguire gli esempi con ```glslviewer```. Inoltre usando il flag ```-l``` si può visualiizare l'esempio in un angolo dello schermo mentre lo si modifica con un qualsiasi editor di testo (come ```nano```, ```pico```, ```vi```, ```vim``` or ```emacs```). Questo funziona anche quando l'utente è collegato tramite ssh/sftp.
Per installare e configurare tutto ciò sul Raspberry Pi, dopo l'installazione del sistema operativo e il login, digitate i seguenti comandi:
```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
```
---
### Appendix/01/README Pl (appendix/01/README-pl.md)
## Jak uruchomić przykłady na Raspberry Pi?
Jeszcze kilka lat temu założenie, że każdy ma komputer z procesorem graficznym było dalekie od prawdy. Teraz większość komputerów ma GPU, ale to wciąż wysoka poprzeczka.
Dzięki [Fundacji Raspberry Pi](http://www.raspberrypi.org/) nowy typ małych i tanich komputerów nowej generacji (około 35 dolarów za sztukę) trafił do sal lekcyjnych. Co ważniejsze dla celów tej książki, [Raspberry Pi](http://www.raspberrypi.org/) jest wyposażone w przyzwoity procesor graficzny Broadcom, do którego można uzyskać dostęp bezpośrednio z konsoli. Stworzyłem [elastyczne narzędzie do kodowania GLSL na żywo o nazwie **glslViewer**](https://github.com/patriciogonzalezvivo/glslViewer), które uruchamia wszystkie przykłady zawarte w tej książce. Program ten automatycznie się odswieża, gdy użytkownik zapisze zmiany w swoim kodzie. Co to oznacza? Możesz edytować shader i za każdym razem, gdy go zapiszesz, shader zostanie ponownie skompilowany i wyrenderowany za Ciebie.
Robiąc lokalną kopię repozytorium tej książki (zobacz poprzedni rozdział) i mając [zainstalowany `glslViewer`](https://github.com/patriciogonzalezvivo/glslViewer), użytkownicy mogą uruchamiać przykłady za pomocą `glslviewer`. Dodając flagę `-l` mogą oni renderować przykład w rogu ekranu, podczas gdy modyfikują go za pomocą dowolnego edytora tekstu (jak `nano`, `pico`, `vi`, `vim` lub `emacs`). Działa to również przy połączeniu przez ssh/sftp.
Aby zainstalować i skonfigurować to wszystko na Raspberry Pi, po zainstalowaniu [Raspbian](https://www.raspberrypi.org/downloads/raspbian/) (dystrybucja Linuksa oparta na Debianie, stworzona dla Raspberry Pi) i zalogowaniu się, wpisz następujące polecenia:
```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
```
---
### Appendix/01/README Ru (appendix/01/README-ru.md)
## Как запустить примеры на Raspberry Pi?
Несколько лет назад было бы слишком опрометчиво предположить, что у каждого есть компьютер с графическим ускорителем. Теперь же большинство компьютеров содержат GPU, но требование обязательного его наличия является завышенным для учебной лаборатории или класса.
Благодаря [Raspberry Pi Foundation](http://www.raspberrypi.org/), в учебных классах появился новый тип небольших и дешёвых компьютеров (около $35 за штуку). Что более важно для данной книги, [Raspberry Pi](http://www.raspberrypi.org/) поставляется с приличным GPU фирмы Broadcom, который доступен напрямую из консоли. Я написал гибкий инструмент для программирования на GLSL в реальном времени под названием [**glslViewer**](https://github.com/patriciogonzalezvivo/glslViewer). С его помощью можно запустить все примеры из этой книги. Эта программа может выполнять обновление автоматически когда пользователь сохраняет изменения в коде. Что это означает? Каждый раз, когда вы сохраняете шейдер в процессе редактирования, он будет перезапущен и перерисует изображение.
Сделав локальную копию репозитория книги (см. [предыдущий параграф](../00/?lan=ru)) и установив [`glslViewer`](https://github.com/patriciogonzalezvivo/glslViewer), вы можете запустить примеры. Используя флаг `-l`, вы можете рендерить примеры в углу экрана прямо во время редактирования любым редактором (`nano`, `pico`, `vi`, `vim` или `emacs`). Это так же работает при подключении по ssh или sftp.
Чтобы установить всё необходимое на Raspberry Pi, после установки [Raspbian](https://www.raspberrypi.org/downloads/raspbian/) и входа в систему, выполните следующие команды:
```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
```
---
### Appendix/01/README Tr (appendix/01/README-tr.md)
## Örnekleri Raspberry Pi'da nasıl çalıştırırım?
Birkaç yıl önce, herkesin grafik işlem birimine sahip bir bilgisayarı olduğunu varsaymak çok iddialıydı. Artık çoğu bilgisayarın GPU'su var, ama yine de bir atölye veya sınıf için yüksek bir gereksinim.
[Raspberry Pi Vakfı](http://www.raspberrypi.org/) sayesinde yeni nesil küçük ve ucuz bilgisayarlar (her biri yaklaşık 35$) sınıflara girmiştir. Bu kitabın amaçları açısından daha da önemli olarak, [Raspberry Pi](http://www.raspberrypi.org/) konsoldan doğrudan erişilebilen düzgün bir Broadcom GPU ile birlikte gelir. Bu kitaptaki tüm örnekleri çalıştıran [**glslViewer** adlı esnek bir GLSL canlı kodlama aracı](https://github.com/patriciogonzalezvivo/glslViewer) yaptım. Bu program ayrıca kullanıcı kodunda bir değişiklik kaydettiğinde otomatik olarak güncelleme yapabilir. Bu ne anlama geliyor? Shader'ı düzenleyebilirsiniz ve her kaydettiğinizde shader yeniden derlenecek ve sizin için render edilecektir.
Bu kitabın deposunun yerel bir kopyasını yaparak (yukarıdaki bölüme bakın) ve [`glslViewer` yükleyerek](https://github.com/patriciogonzalezvivo/glslViewer), kullanıcılar örnekleri `glslviewer` ile çalıştırabilir. `-l` bayrağını kullanarak, örneği herhangi bir metin editörüyle (`nano`, `pico`, `vi`, `vim` veya `emacs` gibi) değiştirirken ekranın bir köşesinde render edebilirler. Bu, kullanıcı ssh/sftp üzerinden bağlıysa da çalışır.
Raspberry Pi'da [Raspbian](https://www.raspberrypi.org/downloads/raspbian/) yükledikten ve giriş yaptıktan sonra tüm bunları kurmak ve ayarlamak için aşağıdaki komutları yazın:
```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
```
---
### Appendix/01/README Vi (appendix/01/README-vi.md)
## Làm thế nào để chạy các ví dụ trên Raspberry Pi ?
Vài năm trước, việc một ai đó sở hữu một chiếc máy tính có card đồ hoạ còn khá hiếm. Giờ thì hầu nhưu máy nào cũng có, nhưng vẫn còn lâu nữa thì các lớp học mới được trang bị đầy đủ.
Nhờ có [Raspberry Pi Foundation](http://www.raspberrypi.org/), một thế hệ máy tính mới rất nhỏ và rẻ (chỉ khoảng 35$ một chiếc) đã ra đời và được trang bị cho các lớp học. Điều quan trọng nhất đối với quyển sách này là, các máy [Raspberry Pi](http://www.raspberrypi.org/) được trang bị GPU đời mới của hãng Broadcom sẽ cho phép truy cập trực tiếp ngay từ cửa sổ dòng lệnh. Tôi đã tạo ra [một công cụ hỗ trợ code GLSL gọi là glslViewer](https://github.com/patriciogonzalezvivo/glslViewer) có thể chạy tất cả các ví dụ trong quyển sách này. Công cụ này còn có khả năng cập nhật hình ảnh tự động, ngay khi bạn sửa code.
Bằng cách tạo một bản sao của quyển sách này ở máy tính của bạn (xem hướng dẫn ở phần trước) và cài đặt [`glslViewer`](https://github.com/patriciogonzalezvivo/glslViewer), bạn có thể chạy các ví dụ với `glslViewer`. Ngoài ra nếu thêm tham số `-l` khi chạy thì một góc màn hình sẽ được dùng để dựng hình ví dụ đó, trong khi bạn có thể dùng bất kỳ chương trình biên soạn nào để sửa code. Nó còn hoạt động ngay cả khi bạn kết nối từ một máy tính khác thông qua ssh/sftp.
Để tạo bản sao của quyển sách và cài glslViewer sau khi đã có [Raspbian](https://www.raspberrypi.org/downloads/raspbian/), gõ các lệnh sau:
```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
```
---
### Appendix/02/README (appendix/02/README.md)
## How to print this book?
Let’s say you don’t want to navigate or interact with the examples and you just want a good old fashion text book which you can read on the beach or on your commute to the city. In that case you can print this book.
#### Installing glslViewer
For printing this book you need first to parse it. For that you will need [`glslViewer`](https://github.com/patriciogonzalezvivo/glslViewer) a console shader tool that will compile and transform the shader examples into images.
In **MacOSX** get sure to have [homebrew](http://brew.sh/) installed and then on your terminal do:
```bash
brew install glslviewer
```
On **Raspberry Pi** you need to get [Raspbian](https://www.raspberrypi.org/downloads/raspbian/), a Debian-based Linux distribution made for Raspberry Pi and then do:
```bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git-core glslviewer
```
#### Installing Python 3, Latex Engine and Pandoc
For parsing the Markdown chapters into Latex and then into a PDF file we will use Xetex Latex Engine and Pandoc.
In **MacOSX**:
Download and Install MacTeX by:
```bash
brew install --cask mactex-no-gui
```
and then install [Pandoc](http://johnmacfarlane.net/pandoc/) and Python 3 by:
```bash
brew install pandoc python
```
On **Raspberry Pi** (Raspbian):
```bash
sudo apt-get install texlive-xetex pandoc python2.7
```
#### Compile the book into a pdf and print it
Now that you have all you need, it is time to clone [the repository of this book](https://github.com/patriciogonzalezvivo/thebookofshaders) and compile the book.
For that open your terminal once again and type:
```bash
cd ~
git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git
cd thebookofshaders
make clean pdf
```
If everything goes well, you will see a `book.pdf` file which you can read on your favorite device or print.
#### Compile the book into an epub for use with an e-reader
```bash
cd ~
git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git
cd thebookofshaders
make clean epub
```
The generated `book.epub` can be used directly, or converted to a `.mobi` file for use with Kindle by using a converter, for example Calibre.
---
### Appendix/02/README Ch (appendix/02/README-ch.md)
## 如何打印这本书?
假设你不想浏览示例或与示例进行交互,而只想要一本绝佳的、老派的、可以在海滩上或通勤到城市的路上阅读的纸质书。在这种情况下,你可以把这本书打印出来。
#### 安装glslViewer
要打印这本书,你首先需要对其进行转换。为此,你会需要 [`glslViewer`](https://github.com/patriciogonzalezvivo/glslViewer)——一个控制台着色器工具,它将编译着色器示例并将其转换为图像。
在 **MacOSX** 上请确保你已经安装了 [homebrew](http://brew.sh/) 然后在你的终端上输入如下指令:
```bash
brew install glslviewer
```
在 **树莓派** 上请确保你已经安装了 [Raspbian](https://www.raspberrypi.org/downloads/raspbian/), 一个为树莓派开发的基于Debian的Linux发行版本,然后执行如下指令:
```bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git-core glslviewer
```
#### 安装Python 3,Latex Engine和Pandoc
为了将 Markdown 章节解析为 Latex,然后转换为PDF文件,我们将使用 Xetex Latex Engine 和 Pandoc。
在 **MacOSX** 上:
下载并安装 MacTeX :
```bash
brew cask install mactex-no-gui
```
然后安装 [Pandoc](http://johnmacfarlane.net/pandoc/) 和 Python 3:
```bash
brew install pandoc python
```
在 **树莓派** (Raspbian)上:
```bash
sudo apt-get install texlive-xetex pandoc python2.7
```
#### 将书编译成pdf并打印
现在您已经拥有了所需的一切,是时候克隆 [本书的库](https://github.com/patriciogonzalezvivo/thebookofshaders) 并编译本书了。
为此,请再次打开你的终端并输入:
```bash
cd ~
git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git
cd thebookofshaders
make clean pdf
```
如果一切顺利,你将看到一个 `book.pdf` 文件,你可以在自己喜欢的设备上阅读或打印该文件。
#### 将书编译成 epub 以供电子阅读器使用
```bash
cd ~
git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git
cd thebookofshaders
make clean epub
```
生成的 `book.epub` 可以直接使用,也可以使用转换器(例如 Calibre)转换为 `.mobi` 文件以供 Kindle 阅读。
---
### Appendix/02/README De (appendix/02/README-de.md)
## Wie kann ich dieses Buch ausdrucken?
Nehmen wir einmal an, Du willst gar nicht mit den Beispielprogrammen in diesem Buch interagieren, sondern den Text wie ein gutes altes Buch im Urlaub oder auf dem täglichen Weg zur Arbeit lesen. In diesem Fall kannst Du Dir den Text einfach ausdrucken.
#### Installation des glslViewer
Um den Text auszudrucken, müssen die verschiedenen Bestandteile des Buches zunächst aufbereitet werden. Dafür benötigst Du den [```glslViewer```](https://github.com/patriciogonzalezvivo/glslViewer), ein Werkzeug für die Kommandozeile, mit dem Du aus den verschiedenen Beispielprogrammen die daraus resultierenden Bilder generieren kannst.
Unter **MacOSX** benötigst Du zunächst [homebrew](http://brew.sh/). Nach dessen Installation kannst Du in einem Terminalfenster folgendes eingeben:
```bash
brew update
brew upgrade
brew tap homebrew/versions
brew install glfw3
cd ~
git clone http://github.com/patriciogonzalezvivo/glslViewer.git
cd glslViewer
make
make install
```
Auf einem **RaspberryPi** gibst Du folgende Befehle ein:
```bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git-core glslviewer
```
#### Installation von Latex und Pandoc
Für den Ausdruck müssen die einzelnen Kapitel zunächst aus dem vorliegenden Textformat (*Markdown*) zunächst nach Latex und anschließend nach PDF konvertiert werden.
Unter **MacOSX**:
Lade und installiere zunächst [basictex inkl. der MacTeX-Erweiterungen](http://www.tug.org/mactex/morepackages.html) und installiere anschließend [Pandoc](http://johnmacfarlane.net/pandoc/), indem Du folgende Kommandos eingibst:
```bash
brew install pandoc
```
Auf einem **RaspberryPi** gibst Du bitte folgende Kommandos ein:
```bash
sudo apt-get install texlive-xetex pandoc
```
#### Das Buch nach PDF umwandeln und ausdrucken
Jetzt, wo Du alle Werkzeuge beisammenhast, ist es an der Zeit, eine Kopie des Buches aus der [Ablage im Internet](https://github.com/patriciogonzalezvivo/thebookofshaders) herunterzuladen und daraus eine PDF-Datei zu erstellen.
Öffne dafür erneut ein Terminalfenster und gib die folgenden Befehle ein:
```bash
cd ~
git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git
cd thebookofshaders
make
```
Wenn alles funktioniert hat, findest Du anschließend die Datei ```book.pdf``` vor, die Du auf Deinem bevorzugten Gerät lesen oder ausdrucken kannst.
---
### Appendix/02/README Fr (appendix/02/README-fr.md)
## Comment imprimer ce livre ?
Disons que vous ne voulez pas naviguer ou interagir avec les exemples et que vous voulez juste un bon livre papier à l'ancienne, que vous pourrez lire sur la plage ou sur votre trajet vers la ville. Dans ce cas, vous pouvez imprimer ce livre.
#### Installation de glslViewer
Pour imprimer ce livre, il faut d'abord l'analyser. Pour cela, vous aurez besoin de [`glslViewer`](https://github.com/patriciogonzalezvivo/glslViewer) un outil en ligne de commande qui compile et transforme les exemples de shaders en images.
Sous **MacOSX**, assurez-vous d'avoir installé [homebrew](http://brew.sh/) et ensuite dans votre terminal :
```bash
brew update
brew upgrade
brew tap homebrew/versions
brew install glfw3
cd ~
git clone http://github.com/patriciogonzalezvivo/glslViewer.git
cd glslViewer
make
make install
```
Sur **Raspberry Pi**, vous devez installer [Raspbian](https://www.raspberrypi.org/downloads/raspbian/), une distribution Linux basée sur Debian conçu pour Raspberry Pi puis de lancer :
```bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git-core glslviewer
```
#### Installation de Python 3, Latex et Pandoc
Pour analyser les chapitres Markdown dans Latex, puis dans un fichier PDF, nous utiliserons Xetex Latex Engine et Pandoc.
Sous **MacOSX**:
Téléchargez et installez [basictex & MacTeX-Additions](http://www.tug.org/mactex/morepackages.html), puis installez [Pandoc](http://johnmacfarlane.net/pandoc/) et Python avec :
```bash
brew install pandoc python2.7
```
Sur **Raspberry Pi** (Raspbian):
```bash
sudo apt-get install texlive-xetex pandoc python2.7
```
#### Compilez le livre dans un document pdf et imprimez-le
Maintenant que vous avez tout ce dont vous avez besoin, il est temps de cloner [le dépôt git de ce livre](https://github.com/patriciogonzalezvivo/thebookofshaders) et de compiler le livre.
Pour cela, ouvrez votre terminal une fois de plus et tapez :
```bash
cd ~
git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git
cd thebookofshaders
make
```
Si tout se passe bien, vous verrez un fichier `book.pdf` que vous pouvez lire sur votre appareil préféré ou imprimer.
---
### Appendix/02/README Id (appendix/02/README-id.md)
## 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 install --cask 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.
---
### Appendix/02/README It (appendix/02/README-it.md)
## Come posso stampare questo libro?
Diciamo che non si vuole navigare o interagire con gli esempi e si desidera solo un buon vecchio libro di testo che si può leggere sulla spiaggia o sul vostro tragitto verso la città. In questo caso è possibile stampare questo libro.
#### Installare glslViewer
Per la stampa di questo libro è necessario in primo luogo trasformarlo. Per questo è necessario [```glslViewer```](https://github.com/patriciogonzalezvivo/glslViewer) uno strumento console per gli shader che compilerà e trasformare gli esempi in immagini.
Su **MacOSX** siate sicuri di avere installato [homebrew](http://brew.sh/) e quindi sul terminale digitate:
```bash
brew update
brew upgrade
brew tap homebrew/versions
brew install glfw3
cd ~
git clone http://github.com/patriciogonzalezvivo/glslViewer.git
cd glslViewer
make
make install
```
Su **Raspberry Pi** è necessario fare:
```bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git-core glslviewer
```
#### Installare Latex Engine e Pandoc
Per trasformare i capitoli Markdown in Latex e poi in un file PDF useremo Xetex Latex Engine e Pandoc.
Su **MacOSX**:
Scarica e Installa [basictex & MacTeX-Additions](http://www.tug.org/mactex/morepackages.html) e poi installa [Pandoc](http://johnmacfarlane.net/pandoc/) facendo:
```bash
brew install pandoc
```
Su **Raspberry Pi**:
```bash
sudo apt-get install texlive-xetex pandoc
```
#### Trasforma il libro in un pdf e stampalo
Ora che avete tutto ciò che serve, è il momento di clonare la [repository di questo libro](https://github.com/patriciogonzalezvivo/thebookofshaders) e compilare il libro.
A tale scopo aprite il terminale e digitate:
```bash
cd ~
git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git
cd thebookofshaders
make
```
Se tutto va bene, si vedrà un file ```book.pdf``` che potete leggere sul vostro dispositivo preferito o stampare.
---
### Appendix/02/README Pl (appendix/02/README-pl.md)
## Jak wydrukować tę książkę?
Powiedzmy, że nie chcesz nawigować ani wchodzić w interakcje z przykładami i chcesz po prostu mieć starą dobrą książkę tekstową, którą możesz czytać na plaży lub podczas dojazdu do miasta. W takim przypadku możesz wydrukować tę książkę.
#### Instalacja programu glslViewer
Aby wydrukować tę książkę, musisz najpierw ją przetworzyć. W tym celu będziesz potrzebował [`glslViewer`](https://github.com/patriciogonzalezvivo/glslViewer) - konsolowego narzędzia do shaderów, które skompiluje i przekształci przykłady shaderów w obrazy.
W **MacOSX** upewnij się, że masz zainstalowany [homebrew](http://brew.sh/), a następnie w terminalu wykonaj:
```bash
brew install glslviewer
```
Na **Raspberry Pi** należy pobrać [Raspbian](https://www.raspberrypi.org/downloads/raspbian/), dystrybucję Linuksa opartą na Debianie, stworzoną dla Raspberry Pi, a następnie wykonać:
```bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git-core glslviewer
```
#### Instalacja Pythona 3, silnika Latex i Pandoc
Do parsowania Markdowna do Latexa, a następnie do pliku PDF użyjemy Xetex Latex Engine i Pandoc.
W **MacOSX**:
Pobierz i zainstalluj MacTeX:
```bash
brew cask install mactex-no-gui
```
a następnie zainstalowuj [Pandoc](http://johnmacfarlane.net/pandoc/) i Python 3 przez:
```bash
brew install pandoc python
```
Na **Raspberry Pi** (Raspbian):
```bash
sudo apt-get install texlive-xetex pandoc python2.7
```
#### Skompiluj książkę do pdf i wydrukuj ją
Teraz, gdy masz już wszystko, czego potrzebujesz, nadszedł czas na sklonowanie [repozytorium tej książki](https://github.com/patriciogonzalezvivo/thebookofshaders) i skompilowanie książki.
W tym celu otwórz jeszcze raz swój terminal i wpisz:
```bash
cd ~
git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git
cd thebookofshaders
make clean pdf
```
Jeśli wszystko pójdzie dobrze, zobaczysz plik `book.pdf`, który możesz przeczytać na swoim ulubionym urządzeniu lub wydrukować.
#### Skompiluj książkę do postaci epub, aby użyć jej w e-czytniku.
```bash
cd ~
git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git
cd thebookofshaders
make clean epub
```
Wygenerowany `book.epub` może być użyty bezpośrednio, lub przekonwertowany, za pomomocą, na przykład, Calibre, na plik `.mobi` do użytku z Kindle.
---
### Appendix/02/README Ru (appendix/02/README-ru.md)
## Как напечатать книгу?
Допустим, вам не нужна навигация по тексту или взаимодействие с примерами, и вы хотите просто почитать книгу на пляже или по пути в город. В таком случае вы можете напечатать книгу.
#### Установка glslViewer
Чтобы напечатать книгу, её нужно сначала распарсить. Для этого потребуется [`glslViewer`](https://github.com/patriciogonzalezvivo/glslViewer) - консольный инструмент, который скомпилирует примеры шейдеров и преобразует их в изображения.
На **MacOSX** убедитесь, что у вас есть [homebrew](http://brew.sh/), и выполните в терминале следующее:
```bash
brew update
brew upgrade
brew tap homebrew/versions
brew install glfw3
cd ~
git clone http://github.com/patriciogonzalezvivo/glslViewer.git
cd glslViewer
make
make install
```
На **Raspberry Pi** установите [Raspbian](https://www.raspberrypi.org/downloads/raspbian/) - дистрибутив Linux для Raspberry Pi, основанный на Debian, и выполните:
```bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git-core glslviewer
```
#### Установка Python 3, Latex Engine и Pandoc
Для разбора Markdown-разметки параграфов в Latex и затем в PDF, воспользуемся Xetex и Pandoc.
На **MacOSX**:
Скачайте и установите [basictex & MacTeX-Additions](http://www.tug.org/mactex/morepackages.html), затем установите [Pandoc](http://johnmacfarlane.net/pandoc/) и Python с помощью команды:
```bash
brew install pandoc python2.7
```
На **Raspberry Pi** (Raspbian):
```bash
sudo apt-get install texlive-xetex pandoc python2.7
```
#### Компиляция книги в pdf и печать
Когда всё необходимое установлено, склонируйте [репозиторий книги](https://github.com/patriciogonzalezvivo/thebookofshaders) и скомпилируйте её:
```bash
cd ~
git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git
cd thebookofshaders
make
```
Если всё прошло хорошо, вы увидите файл `book.pdf`, который можно прочитать на любом устройстве или распечатать.
---
### Appendix/02/README Tr (appendix/02/README-tr.md)
## Bu kitabı nasıl yazdırabilirim?
Diyelim ki örneklerle gezinmek veya etkileşim kurmak istemiyorsunuz ve sadece sahilde veya şehre yolculuğunuzda okuyabileceğiniz güzel eski moda bir ders kitabı istiyorsunuz. Bu durumda bu kitabı yazdırabilirsiniz.
#### glslViewer kurulumu
Bu kitabı yazdırmak için önce onu ayrıştırmanız gerekir. Bunun için shader örneklerini derleyip görüntülere dönüştürecek bir konsol shader aracı olan [`glslViewer`](https://github.com/patriciogonzalezvivo/glslViewer)'a ihtiyacınız olacak.
**MacOSX**'te [homebrew](http://brew.sh/) yüklü olduğundan emin olun ve ardından terminalinizde şunları yapın:
```bash
brew install glslviewer
```
**Raspberry Pi**'da, Raspberry Pi için yapılmış Debian tabanlı bir Linux dağıtımı olan [Raspbian](https://www.raspberrypi.org/downloads/raspbian/)'ı edinip ardından şunları yapmanız gerekir:
```bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git-core glslviewer
```
#### Python 3, Latex Motoru ve Pandoc kurulumu
Markdown bölümlerini Latex'e ve ardından PDF dosyasına ayrıştırmak için Xetex Latex Motorunu ve Pandoc'u kullanacağız.
**MacOSX**'te:
MacTeX'i indirip kurun:
```bash
brew install --cask mactex-no-gui
```
ardından [Pandoc](http://johnmacfarlane.net/pandoc/) ve Python 3'ü kurun:
```bash
brew install pandoc python
```
**Raspberry Pi** (Raspbian)'da:
```bash
sudo apt-get install texlive-xetex pandoc python2.7
```
#### Kitabı pdf'e derleyin ve yazdırın
İhtiyacınız olan her şeye sahip olduğunuza göre, [bu kitabın deposunu](https://github.com/patriciogonzalezvivo/thebookofshaders) klonlamanın ve kitabı derlemenin zamanı geldi.
Bunun için terminalinizi tekrar açın ve yazın:
```bash
cd ~
git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git
cd thebookofshaders
make clean pdf
```
Her şey yolunda giderse, favori cihazınızda okuyabileceğiniz veya yazdırabileceğiniz bir `book.pdf` dosyası göreceksiniz.
#### Kitabı e-okuyucu için epub formatında derleyin
```bash
cd ~
git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git
cd thebookofshaders
make clean epub
```
Oluşturulan `book.epub` doğrudan kullanılabilir veya bir dönüştürücü kullanılarak Kindle ile kullanım için `.mobi` dosyasına dönüştürülebilir, örneğin Calibre.
---
### Appendix/02/README Ua (appendix/02/README-ua.md)
## Як надрукувати цю книгу?
Скажімо, вам не потрібна навігація по тексту чи взаємодія з інтерактивними прикладами, а просто потрібна книга, яку ви зможете читати на пляжі або під час поїздок. У такому випадку ви можете надрукувати її.
#### Встановлення glslViewer
Щоб надрукувати цю книгу, її потрібно спочатку розпарсити. Для цього вам знадобиться [`glslViewer`](https://github.com/patriciogonzalezvivo/glslViewer) - консольний інструмент, який компілює та перетворює приклади шейдерів у зображення.
На **MacOSX** переконайтесь, що у вас встановлено [homebrew](http://brew.sh/) і потім виконайте у терміналі наступну команду:
```bash
brew install glslviewer
```
На **Raspberry Pi** установіть [Raspbian](https://www.raspberrypi.org/downloads/raspbian/) - дистрибутив Linux на основі Debian, створений для Raspberry Pi, а потім виконайте такі дії:
```bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git-core glslviewer
```
#### Встановлення Python 3, Latex Engine і Pandoc
Для розбору розділів Markdown-розмітки у Latex, а потім у PDF-файл, ми будемо використовувати Xetex Latex Engine і Pandoc.
На **MacOSX**:
Завантажте та встановіть MacTeX:
```bash
brew install --cask mactex-no-gui
```
а потім інсталюйте [Pandoc](http://johnmacfarlane.net/pandoc/) і Python 3 за допомогою команди:
```bash
brew install pandoc python
```
На **Raspberry Pi** (Raspbian):
```bash
sudo apt-get install texlive-xetex pandoc python2.7
```
#### Зберіть книгу у pdf-формат та роздрукуйте її
Тепер, коли у вас є все необхідне, настав час клонувати [репозиторій цієї книги](https://github.com/patriciogonzalezvivo/thebookofshaders) та скомпілювати його.
Для цього ще раз відкрийте термінал і виконайте наступні команди:
```bash
cd ~
git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git
cd thebookofshaders
make clean pdf
```
Якщо все пройде добре, ви побачите файл `book.pdf`, який можна прочитати на своєму улюбленому пристрої або роздрукувати.
#### Зберіть книгу в epub-формат для використання з Kindle
```bash
cd ~
git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git
cd thebookofshaders
make clean epub
```
Згенерований файл `book.epub` можна використовувати безпосередньо або конвертувати у формат `.mobi` для використання з Kindle за допомогою конвертера, наприклад Calibre.
---
### Appendix/02/README Vi (appendix/02/README-vi.md)
## Làm thế nào để in quyển sách này
Giả sử bạn không có nhu cầu tương tác với các ví dụ mà chỉ muốn đọc quyển sách theo cách cổ điển như khi đang nằm trên bãi biển hoặc trên tàu điện. Trong trường hợp đó bạn có thể in quyển sách này.
#### Cài đặt glslViewer
Để in quyển sách này đầu tiên phải biên dịch nó đã. Để làm được việc đó thì bạn cần [`glslViewer`](https://github.com/patriciogonzalezvivo/glslViewer) để biến các đoạn code shader thành ảnh minh hoạ.
Trên **MacOSX** nếu đã có [homebrew](http://brew.sh/) thì cần gõ lệnh sau:
```bash
brew install glslviewer
```
Trên **Raspberry Pi** bạn cần cài [Raspbian](https://www.raspberrypi.org/downloads/raspbian/), một phiên bản Linux dựa trên Debian dành riêng cho Raspberry PI rồi gõ lệnh sau:
```bash
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git-core glslviewer
```
#### Cài đặt Python 2.7, Latex Engine và Pandoc
Để biên dịch các chương sách viết theo cú pháp Markdown bằng phần mềm Latex rồi xuất ra định dạng PDF thì bạn cần có Latex Engine và Pandoc.
Trên **MacOSX**:
Tải và cài đặt MacTeX bằng lệnh:
```bash
brew install --cask mactex-no-gui
```
sau đó cài thêm [Pandoc](http://johnmacfarlane.net/pandoc/) và Python 2 bằng lệnh:
```bash
brew install pandoc python@2
```
Trên **Raspberry Pi** (Raspbian):
```bash
sudo apt-get install texlive-xetex pandoc python2.7
```
#### Chuyển đổi quyển sách sang định dạng PDF
Giờ bạn đã có đủ công cụ cần thiết, hãy tạo một bản sao của [quyển sách này](https://github.com/patriciogonzalezvivo/thebookofshaders) và in nó thôi.
Ở cửa sổ terminal, hãy gõ lệnh:
```bash
cd ~
git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git
cd thebookofshaders
make clean pdf
```
Nếu mọi thứ ổn, bạn sẽ thấy file `book.pdf` mà bạn có thể đọc bằng bất kỳ thiết bị nào hoặc in ra.
#### Chuyển đổi quyển sách sang định dạng epub để đọc trên thiết bị kỹ thuật số
```bash
cd ~
git clone https://github.com/patriciogonzalezvivo/thebookofshaders.git
cd thebookofshaders
make clean epub
```
File `book.epub` có thể đọc trực tiếp hoặc cần chuyển sang định dạng `.mobi` để đọc trên Kindle bằng một phần mềm khác như Calibre chẳng hạn.
---
### Appendix/03/README (appendix/03/README.md)
## How can I collaborate with this book?
Thanks for being willing to collaborate! There are plenty of ways you can:
- Translating content
- Improving the [```glossary/``` section](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/glossary)
- Editing content
- Sharing your shaders examples through [the on-line editor](http://editor.thebookofshaders.com/) to
### Translating content
This book is written in [Markdown language](https://daringfireball.net/projects/markdown/syntax) so it's very easy to edit and work on it.
1. Start by going to [github's repository at ```github.com/patriciogonzalezvivo/thebookofshaders```](https://github.com/patriciogonzalezvivo/thebookofshaders). Take a look at the files and folders inside it. You will note that the content is in the ```README.md``` and other files with capital letters like: ```TITLE.md```, ```SUMMARY.md```, etc. Also note that translations are hosted in files with names ending in two letters referencing the language they are for, ex.: ```README-jp.md```, ```README-es.md```, etc.
2. Fork the repository and clone it in your computer.
3. Duplicate the content of the files want to translate. Remember to add to the two letters that makes reference to the language you are translating to the files you will work on.
4. Translate the content line by line (see **Translation notes**).
5. Test it (see **Testing**).
6. Push to your own github fork to then make a [Pull Request](https://help.github.com/articles/using-pull-requests/)
#### Translating notes
Do not erase or modify things the embedded examples, that looks like this:
```html
```
or
```html
```
#### Testing
Start running a local PHP server inside the local repository folder:
```bash
php -S localhost:8000
```
Then in your browser search for ```localhost:8000``` go to the chapter you are translating and add ```?lan=``` followed by the two letters you used to mark the language you are translating to.
For example, if you are translating the chapter ```03``` to french you had been working with the file ```03/README-fr.md``` and you can test it by going to: ```http://localhost:8000/03/?lan=fr```
### Improving the glossary section
This section is under development. We are happy to listen to your ideas on how to make it a friendly tool for all. Send us a message to [@bookofshaders](https://twitter.com/bookofshaders).
### Editing content
We are all humans. If you see something say something and make a Pull Request or open an issue. Thanks!
### Sharing your shaders examples
You will see a lot of links to [the on-line editor](http://editor.thebookofshaders.com/) and embedded instances of it.
Once you code something that makes you proud, click the "Export" (or the ```⇪``` icon) and then copy the "URL to code...". Send it to [@bookofshaders](https://twitter.com/bookofshaders) or [@kyndinfo](https://twitter.com/kyndinfo). We are looking forward to see it and add it to [the example gallery section](https://thebookofshaders.com/examples/).
---
### Appendix/03/README De (appendix/03/README-de.md)
## Wie kann ich zu diesem Buch beitragen?
Schön, dass Du Interesse hast, an diesem Buch mitzuwirken. Zahlreiche Möglichkeiten bieten sich dafür an. Du kannst ...
- Inhalte übersetzen
- Das [```Glossar```](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/glossary) verbessern
- Fehler bereinigen
- Deine eigenen GLSL-Shader über den [Online Editor](http://editor.thebookofshaders.com/) mit anderen teilen
### Inhalte übersetzen
Der Quelltext dieses Buches wurde in [Markdown](https://daringfireball.net/projects/markdown/syntax) verfasst. Dadurch ist es sehr einfach, den Text zu bearbeiten und zu erweitern.
1. Besuche zunächst die Internet-Ablage dieses Buches bei [Github unter ```github.com/patriciogonzalezvivo/thebookofshaders```](https://github.com/patriciogonzalezvivo/thebookofshaders). Verschaffe Dir einen Überblick über die verschiedenen Verzeichnisse und die darin enthaltenen Dateien. Du wirst feststellen, dass die eigentlichen Textinhalte des Buches jeweils in der Datei ```README.md``` und in anderen Dateien enthalten sind, die Großbuchstaben im Namen tragen. Beispiele dafür sind etwa ```TITLE.md```, ```SUMMARY.md``` usw. Die Übersetzungen dieser Texte stecken in Dateien, die am Ende des Namens ein Kürzel für die jeweilige Sprache tragen, also z.B. ```README-jp.md```, ```README-es.md``` usw.
2. Lege einen Fork der Ablage an und klone den Fork auf Deinen Computer.
3. Lege jeweils eine Kopie der Datei an, die Du übersetzen möchtest, und vergiss dabei nicht, das Sprachkürzel im Dateinamen zu ergänzen.
4. Übersetze den Inhalt des Dokuments Zeile für Zeile (siehe dazu auch die **Übersetzungshinweise** unten).
5. Überprüfe den Inhalt hinsichtlich der Rechtschreibung und der korrekten Anzeige im Browser (siehe unten unter **Testen**).
6. Lade die veränderten Dateien in Deinen Fork hoch und setze einen [Pull Request](https://help.github.com/articles/using-pull-requests/) ab.
#### Übersetzungshinweise
Lösche und verändere nichts an der Einbindung der Beispielprogramme innerhalb des Quelltextes. Dieses sehen wie folgt aus:
```html
```
oder
```html
```
#### Testen
Starte auf Deinem lokalen Rechner einen PHP-Server innerhalb des Verzeichnisses, in das Du das Buch geklont hast:
```bash
php -S localhost:8000
```
Rufe dann in Deinem Internet-Browser die URL ```localhost:8000``` auf. Klicke Dich bis zu dem Kapitel durch, an dem Du gerade arbeitest. Füge der angezeigten URL in der Adresszeile des Browsers den Zusatz ```?lan=``` hinzu, gefolgt von dem Sprachenkürzel, das Du bei der Benennung der jeweiligen Datei verwendet hast.
Um ein Beispiel zu nennen: Wenn Du gerade das Kapitel ```03``` ins Französische übersetzt und dabei mit der Datei ```03/README-fr.md``` arbeitest, kannst Du diese Datei anzeigen, indem Du folgende URL eingibst: ```http://localhost:8000/03/?lan=fr```
### Verbesserungen am Glossar
Das Glossar befindet sich noch in Arbeit. Wir freuen uns über Vorschläge, wie man das Glossar zu einem wertvollen Bestandteil des Buches ausbauen kann. Schick uns einfach eine Nachricht an [@bookofshaders](https://twitter.com/bookofshaders).
### Fehler bereinigen
Irren ist menschlich! Wenn Dir ein Fehler auffällt, bereinige die Stelle und setze einfach einen entsprechenden Pull Request auf Github ab, oder eröffnete dort eine Diskussion zu dem Thema. Vielen Dank!
### Teile Deine Shader mit Anderen
Du wirst im Quelltext des Buches bei den Beispielen viele Verweise auf den [Online-Editor](http://editor.thebookofshaders.com/) sehen.
Sobald Du einen Shader entwickelt hast, auf den Du stolz bist, klicke auf die „Export“-Schaltfläche (bzw. das ```⇪```-Symbol) und kopiere anschließend die im Editor angezeigte „URL to code...“. Sende diese URL an [@bookofshaders](https://twitter.com/bookofshaders) oder an [@kyndinfo](https://twitter.com/kyndinfo). Wir freuen uns auf tolle Shader und werden diese gerne unserer [Galerie mit Beispielen](https://thebookofshaders.com/examples/) hinzufügen.
---
### Appendix/03/README Id (appendix/03/README-id.md)
## 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
```
or
```html
```
#### 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/)
---
### Appendix/03/README It (appendix/03/README-it.md)
## Come posso collaborare a questo libro?
Grazie per voler collaborare! Ci sono vari modi per poterlo fare:
- Tradurre i contenuti
- Migliorare la [sezione ```glossario/```](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/glossary)
- Modificare i contenuti
- Condividere i vostri esempi di shaders attraverso[l'editor on-line](http://editor.thebookofshaders.com/)
### Tradurre i contenuti
Questo libro è scritto nel [linguaggio Markdown](https://daringfireball.net/projects/markdown/syntax) quindi è molto facile da modificare e lavorare su di esso.
1. Iniziate andando alla [repository di GitHub ```github.com/patriciogonzalezvivo/thebookofshaders```](https://github.com/patriciogonzalezvivo/thebookofshaders). Date un'occhiata ai file e alle cartelle al suo interno. Si noti che il contenuto è presente nei file ```README.md``` e negli altri con lettere maiuscole come:```TITLE.md```, ```SUMMARY.md```, ecc. Si noti inoltre che le traduzioni sono contenute in file che terminano con due lettere che fanno riferimento alla lingua che sono tradotte, es .: ```README-jp.md```, ```README-es.md```, ecc.
2. Biforcare ("Fork") la repository e clonatela ("Clone") sul vostro computer.
3. Duplicate il contenuto dei file da tradurre. Ricordatevi di aggiungere ai file su cui si sta lavorando le due lettere che fanno riferimento alla lingua che si sta traducendo.
4. Traducete linea per linea i contenuti (vedi **Note di traduzione**).
5. Testate le pagine tradotte (vedi **Test**).
6. Inviate ("Push") i vostri commit alla biforcazione ("Fork") della vostra repository su GitHub, per poi fare un [Pull Request](https://help.github.com/articles/about-pull-requests/)
#### Note di traduzione
Non cancellate o modificate gli esempi integrati alla pagina, che assomigliano a questo codice:
```html
```
oppure
```html
```
#### Testare
Iniziate l'esecuzione di un server locale PHP all'interno della cartella locale:
```bash
php -S localhost:8000
```
Poi, nel tuo browser aprite la pagina ```localhost:8000```, andate al capitolo che state traducendo e aggiungete ```?lan=``` seguito dal codice della lingua in cui state traducendo.
Per esempio se si sta traducendo il capitolo ```03``` in francese, starete lavorando sul file```03/README-fr.md``` e lo si può testare andando alla pagina: ```http://localhost:8000/03/?lan=fr```
### Migliorare la sezione glossario
Questa sezione è in fase di sviluppo. Siamo lieti di ascoltare le vostre idee su come rendere uno strumento intuitivo per tutti. Inviaci un messaggio a [@bookofshaders](https://twitter.com/bookofshaders).
### Modifica il contenuto
Siamo tutti esseri umani. Se vedete qualcosa, ditelo e fate un Pull Request oppure aprite un problema su GitHub. Grazie!
### Condividete i vostri esempi di shaders
Vedrete un sacco di link verso [l'editor on-line](http://editor.thebookofshaders.com/) e verso delle sue istanze integrate alla pagina.
Una volta che si scrive un codice che vi rende orgoglioso, fate clic su "Esporta" (o sull' icona ```⇪```) e quindi copiate l' "URL verso il codice..." ("URL to code..."). Inviatelo a [@bookofshaders](https://twitter.com/bookofshaders) o a [@kyndinfo](https://twitter.com/kyndinfo). Non vediamo l'ora di vederlo e aggiungerlo alla [sezione galleria di esempi](https://thebookofshaders.com/examples/).
---
### Appendix/03/README Pl (appendix/03/README-pl.md)
## Jak mogę pomóc?
Dziękujemy za chęć współpracy! Jest wiele sposobów pomocy:
- Tłumaczenie treści
- Poprawianie [sekcji ```glosariusz/```](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/glossary)
- Edytowanie zawartości
- Dzielenie się swoimi przykładami shaderów poprzez [edytor on-line](http://editor.thebookofshaders.com/)
### Tłumaczenie treści
Ta książka jest napisana w [języku Markdown](https://daringfireball.net/projects/markdown/syntax), więc bardzo łatwo jest ją edytować i pracować nad nią.
1. Zacznij od przejścia do [repozytorium github pod adresem ``github.com/patriciogonzalezvivo/thebookofshaders``](https://github.com/patriciogonzalezvivo/thebookofshaders). Przyjrzyj się znajdującym się w nim plikom i folderom. Zauważysz, że treść znajduje się w pliku ``README.md`` oraz innych plikach z dużymi literami jak: ``TITLE.md``, ``SUMMARY.md``, itd. Zauważ również, że tłumaczenia są hostowane w plikach z nazwami kończącymi się na dwie litery reprezentujące język tłumaczenia, na przykład: ``README-jp.md``, ``README-es.md``, itd.
2. Forkuj repozytorium i sklonuj je w swoim komputerze.
3. Zduplikuj zawartość plików, które chcesz przetłumaczyć. Pamiętaj, aby do plików, nad którymi będziesz pracował, dodać dwie litery nawiązujące do języka, który tłumaczysz.
4. Przetłumacz treść linijka po linijce (patrz **Uwagi dotyczące tłumaczenia**).
5. Przetestuj ją (patrz **Testy**).
6. Pushuj na własny fork githuba, aby następnie zrobić [Pull Request](https://help.github.com/articles/using-pull-requests/)
#### Uwagi dotyczące tłumaczenia
Nie wymazuj ani nie modyfikuj rzeczy w osadzonych przykładach, wyglądających tak:
```html
```
lub
```html
```
#### Testowanie
Rozpocznij uruchamianie lokalnego serwera PHP wewnątrz lokalnego folderu repozytorium:
```bash
php -S localhost:8000
```
Następnie w przeglądarce wyszukaj ``localhost:8000``, przejdź do rozdziału, który tłumaczysz i dodaj ``?lan=``, a następnie dwie litery, których użyłeś do oznaczenia języka, na który tłumaczysz.
Na przykład, jeśli tłumaczysz rozdział ``03`` na język francuski pracowałeś z plikiem ``03/README-fr.md``, to możesz go przetestować wchodząc na: ``http://localhost:8000/03/?lan=fr``
### Ulepszanie glosariusza
Glosariusz jest w trakcie rozwoju. Chętnie wysłuchamy Twoich pomysłów, jak uczynić ją przyjaznym narzędziem dla wszystkich. Wyślij nam wiadomość na adres [@bookofshaders](https://twitter.com/bookofshaders).
### Edycja treści
Wszyscy jesteśmy ludźmi. Jeśli widzisz błąd, daj znać i zrób Pull Request lub otwórz Issue. Dzięki!
### Dzielenie się przykładami shaderów
Zobaczysz wiele linków do [edytora on-line](http://editor.thebookofshaders.com/) i jego osadzonych instancji.
Gdy zakodujesz coś, co sprawi, że będziesz dumny, kliknij "Export" (lub ikonę ``⇪``), a następnie skopiuj "URL to code...". Wyślij go do [@bookofshaders](https://twitter.com/bookofshaders) lub [@kyndinfo](https://twitter.com/kyndinfo). Czekamy na nie i dodamy je do [działu galeria przykładów](https://thebookofshaders.com/examples/).
---
### Appendix/03/README Ru (appendix/03/README-ru.md)
## Как принять участие в создании книги?
Благодарим за ваше желание помочь! Есть множество способов это сделать:
- Перевод
- Доработка [глоссария](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/glossary)
- Редактирование
- Выкладывание ваших шейдеров в общий доступ с помощью [онлайн-редактора](http://editor.thebookofshaders.com/)
### Перевод
Книга написана на языке разметки [Markdown](https://daringfireball.net/projects/markdown/syntax), поэтому с её текстом очень легко работать.
1. Для начала перейдите в репозиторий по адресу [```github.com/patriciogonzalezvivo/thebookofshaders```](https://github.com/patriciogonzalezvivo/thebookofshaders). Осмотрите файлы и каталоги в нём. Легко заметить, что контент находится в файлах ```README.md``` и других файлах, названных заглавными буквами: ```TITLE.md```, ```SUMMARY.md``` и так далее. Так же вы заметите, что переводы находятся в файлах, имена которых заканчиваются двумя буквами, указывающими на язык перевода, например: ```README-jp.md```, ```README-es.md``` и прочие.
2. Форкните репозиторий и склонируйте его к себе на компьютер.
3. Продублируйте содержимое файлов, которые хотите перевести. Не забудьте добавить двухбуквенный код языка, на который переводите.
4. Переведите контент (см. **Примечания о переводе**).
5. Протестируйте (см. **Тестирование**).
6. Сделайте push в ваш собственный форк и затем создайте [пулл-реквест](https://help.github.com/articles/using-pull-requests/) в основной репозиторий.
#### Примечания о переводе
Не удаляйте и не изменяйте встроенные примеры, которые выглядят примерно так:
```html
```
или так:
```html
```
#### Тестирование
Запустите локальный PHP-сервер в папке вашего локального репозитория:
```bash
php -S localhost:8000
```
Теперь в браузере перейдите по адресу ```localhost:8000```, зайдите на переводимую страницу и добавьте в конец адреса строку ```?lan=xx```, где ```xx``` - код языка, на который переводите.
Например, если вы переводите главу ```03``` на французский, значит вы работали над файлом ```03/README-fr.md```, который можно протестировать по адресу ```http://localhost:8000/03/?lan=fr```.
### Доработка глоссария
Этот раздел находится в разработке. Мы рады узнать ваше мнение о том, как сделать из него что-то полезное. Пишите нам на [@bookofshaders](https://twitter.com/bookofshaders).
### Редактирование
Все мы люди. Если вы видите ошибку - сообщите о ней и сделайте пулл-реквест, или откройте issue на гитхабе. Спасибо!
### Выкладывайте ваши шейдеры
Вы увидите множество ссылок на [онлайн-редактор](http://editor.thebookofshaders.com/) и написанный в нём код, встроенный в книгу. Если вы написали что-то стоящее, нажмите «Export» (или иконку ```⇪```) и скопируйте ссылку на код. Отправьте её на [@bookofshaders](https://twitter.com/bookofshaders) или [@kyndinfo](https://twitter.com/kyndinfo). Мы будем рады видеть ваш код и добавить его в [галерею примеров](https://thebookofshaders.com/examples/).
---
### Appendix/03/README Tr (appendix/03/README-tr.md)
## Bu kitaba nasıl katkıda bulunabilirim?
Katkıda bulunmaya istekli olduğunuz için teşekkürler! Birçok yol var:
- İçerik çevirisi
- [```glossary/``` bölümünü](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/glossary) iyileştirme
- İçerik düzenleme
- Shader örneklerinizi [çevrimiçi editör](http://editor.thebookofshaders.com/) aracılığıyla paylaşma
### İçerik çevirisi
Bu kitap [Markdown dilinde](https://daringfireball.net/projects/markdown/syntax) yazılmıştır, bu yüzden düzenlemesi ve üzerinde çalışması çok kolaydır.
1. [```github.com/patriciogonzalezvivo/thebookofshaders``` adresindeki GitHub deposuna](https://github.com/patriciogonzalezvivo/thebookofshaders) giderek başlayın. İçindeki dosya ve klasörlere göz atın. İçeriğin ```README.md``` ve ```TITLE.md```, ```SUMMARY.md``` gibi büyük harfli diğer dosyalarda olduğunu göreceksiniz. Ayrıca çevirilerin, hedef dile referans veren iki harfle biten dosya adlarında barındırıldığını not edin, örn: ```README-jp.md```, ```README-es.md```, vb.
2. Depoyu forklayın ve bilgisayarınıza klonlayın.
3. Çevirmek istediğiniz dosyaların içeriğini çoğaltın. Çevirdiğiniz dile referans veren iki harfi üzerinde çalışacağınız dosyalara eklemeyi unutmayın.
4. İçeriği satır satır çevirin (bkz. **Çeviri notları**).
5. Test edin (bkz. **Test etme**).
6. Kendi GitHub fork'unuza push edin ve ardından bir [Pull Request](https://help.github.com/articles/using-pull-requests/) yapın
#### Çeviri notları
Şöyle görünen gömülü örnekleri silmeyin veya değiştirmeyin:
```html
```
veya
```html
```
#### Test etme
Yerel depo klasörünün içinde yerel bir PHP sunucusu çalıştırmaya başlayın:
```bash
php -S localhost:8000
```
Ardından tarayıcınızda ```localhost:8000``` arayın, çevirdiğiniz bölüme gidin ve ```?lan=``` ardından çevirdiğiniz dili işaretlemek için kullandığınız iki harfi ekleyin.
Örneğin, ```03``` bölümünü Fransızca'ya çeviriyorsanız ```03/README-fr.md``` dosyasıyla çalışmış olacaksınız ve şu adrese giderek test edebilirsiniz: ```http://localhost:8000/03/?lan=fr```
### Sözlük bölümünü iyileştirme
Bu bölüm geliştirme aşamasındadır. Onu herkes için kullanıcı dostu bir araç yapma hakkındaki fikirlerinizi duymaktan mutluluk duyarız. Bize [@bookofshaders](https://twitter.com/bookofshaders) adresinden mesaj gönderin.
### İçerik düzenleme
Hepimiz insanız. Bir şey görürseniz bir şey söyleyin ve bir Pull Request yapın veya bir sorun açın. Teşekkürler!
### Shader örneklerinizi paylaşma
[Çevrimiçi editöre](http://editor.thebookofshaders.com/) ve gömülü örneklerine birçok bağlantı göreceksiniz.
Sizi gururlandıran bir şey kodladığınızda, "Dışa Aktar" (veya ```⇪``` simgesi) düğmesine tıklayın ve ardından "Koda URL..."yi kopyalayın. [@bookofshaders](https://twitter.com/bookofshaders) veya [@kyndinfo](https://twitter.com/kyndinfo) adresine gönderin. Görmeyi ve [örnek galeri bölümüne](https://thebookofshaders.com/examples/) eklemeyi dört gözle bekliyoruz.
---
### Appendix/03/README Ua (appendix/03/README-ua.md)
## Як прийняти участь у розвитку книги?
Дякуємо за бажання співпрацювати! Для цього існує кілька способів:
- Переклад контенту
- Покращення та допрацювання [```глосарію```](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/glossary)
- Редагування контенту
- Діліться своїми прикладами шейдерів через [онлайн-редактор](http://editor.thebookofshaders.com/)
### Переклад контенту
Ця книга написана мовою розмітки [Markdown](https://daringfireball.net/projects/markdown/syntax), тому її дуже легко редагувати та працювати з нею.
1. Для початку перейдіть до github-репозиторію за адресою [```github.com/patriciogonzalezvivo/thebookofshaders```](https://github.com/patriciogonzalezvivo/thebookofshaders). Перегляньте в ньому файли та теки. Ви помітите, що контент знаходиться в ```README.md``` та інших файлах з назвами із великих літер, наприклад: ```TITLE.md```, ```SUMMARY.md``` тощо. Також зауважте, що переклади розміщуються у файлах, імена яких закінчуються додатковими двома літерами, що вказують на мову перекладу, наприклад: ```README-jp.md```, ```README-es.md``` тощо.
2. Зробіть відгалуження репозиторію і клонуйте його на свій комп'ютер.
3. Продублюйте вміст файлів, які потрібно перекласти. Додайте до них двобуквенний код, що буде вказувати на мову для якої ви робите переклад.
4. Перекладіть вміст файлу (див. **Примітки щодо перекладу**).
5. Протестуйте зміни (див. **Тестування**).
6. Зробіть push у ваш власний форк проєкту і створіть [pull request](https://help.github.com/articles/using-pull-requests/)
#### Примітки щодо перекладу
Не видаляйте та не змінюйте вбудовані приклади, які виглядають приблизно так:
```html
```
Або так:
```html
```
#### Тестування
Запустіть локальний PHP-сервер у теці локального репозиторію:
```bash
php -S localhost:8000
```
Тепер у вашому браузері зайдіть на адресу [```localhost:8000```](http://localhost:8000), перейдіть до розділу, який ви перекладаєте, і додайте в кінці адреси такий рядок ```?lan=```, а після нього дві літери для позначення мови перекладу.
Наприклад, якщо ви перекладаєте розділ ```03``` на французьку мову, значить ви працювали з файлом ```03/README-fr.md```, і ви можете перевірити його за адресою: ``` http://localhost:8000/03/?lan=fr```
### Покращення глосарію
Цей розділ знаходиться в розробці. Ми раді вислухати ваші ідеї щодо його покращення, щоб зробити його корисним інструментом для всіх. Надсилайте свої пропозиції на [@bookofshaders](https://twitter.com/bookofshaders).
### Редагування контенту
Ми всі люди. Якщо ви побачите помилку, то сповістіть про неї, зробіть pull-request з виправленням або відкрийте issue. Дякую!
### Діліться своїми прикладами шейдерів
Ви побачите багато посилань на [онлайн-редактор](http://editor.thebookofshaders.com/) і його вбудовані у сторінки приклади з кодом.
Коли ви закодуєте щось корисне чи цікаве, натисніть «Export» (або піктограму ```⇪```) і надішліть його на адресу [@bookofshaders](https://twitter.com/bookofshaders) або [@kyndinfo](https://twitter.com/kyndinfo). Ми будемо раді переглянути його і додати до [галереї прикладів](https://thebookofshaders.com/examples/).
---
### Appendix/03/README Vi (appendix/03/README-vi.md)
## Làm thế nào để đóng góp cho quyển sách này
Cảm ơn bạn vì muốn góp sức! Có rất nhiều cách để làm việc đó:
- Dịch quyển sách sang ngôn ngữ khác
- Cải thiện phần [```Chú giải```](https://github.com/patriciogonzalezvivo/thebookofshaders/tree/master/glossary)
- Biên tập lại nội dung
- Chia sẻ code shader của bạn trên [editor online](http://editor.thebookofshaders.com/)
### Dịch quyển sách sang ngôn ngữ khác
Quyển sách này được viết theo [cú pháp Markdown](https://daringfireball.net/projects/markdown/syntax) nên rất dễ chỉnh sửa.
1. Bạn có thể truy cập [repository ```github.com/patriciogonzalezvivo/thebookofshaders``` trên GitHub](https://github.com/patriciogonzalezvivo/thebookofshaders). Hãy xem các file và thư mục ở đó. Bạn sẽ thấy nội dung của các chương nằm ở các file ```README.md``` và các file có tên viết hoa như: ```TITLE.md```, ```SUMMARY.md```, vân vân. Ngoài ra thì các bản dịch sẽ có file riêng và có tên kết thúc bằng mã ngôn ngữ 2 ký tự, ví dụ: ```README-jp.md```, ```README-es.md```, vân vân.
2. Fork repository này rồi tạo một bản sao trên máy của bạn.
3. Tạo một bản sao cho mỗi file mà bạn muốn dịch. Hãy nhớ thêm mã ngôn ngữ 2 ký tự vào cuối tên file.
4. Dịch nội dung sang ngôn ngữ khác (xem mục **Chú ý khi dịch thuật**).
5. Kiểm tra lại (xem mục **Kiểm tra**).
6. Push lên repository riêng của bạn rồi tạo một [Pull Request](https://help.github.com/articles/using-pull-requests/) vào repository của chúng tôi.
#### Chú ý khi dịch thuật
Không được xoá hoặc thay đổi mã nhúng các ví dụ tương tự như các đoạn mã sau:
```html
```
hoặc
```html
```
#### Kiểm tra
Hãy thử chạy trên server PHP nội bộ của bạn:
```bash
php -S localhost:8000
```
Rồi truy cập ```localhost:8000``` trên trình duyệt và tới chương mà bạn đã dịch rồi thêm đuôi ```?lan=``` kèm mã ngôn ngữ 2 ký tự.
Ví dụ, nếu bạn dịch chương ```03``` sang tiếng Pháp tức là bạn sửa file ```03/README-fr.md``` nên giờ bạn sẽ tự kiểm tra lại tại địa chỉ: ```http://localhost:8000/03/?lan=fr```
### Cải thiện phần chú giải
Phần này vẫn đang được bổ sung. Chúng tôi rất vui lòng lắng nghe các ý tưởng của bạn để khiến nó trở nên dễ hiểu hơn. Hãy gửi tin nhắn tới [@bookofshaders](https://twitter.com/bookofshaders).
### Biên tập nội dung
Chúng ta đều là những người bình thường có nhiều điểm có thể cải thiện hơn nữa. Nếu bạn có gì muốn góp ý, cứ tạo Pull Request hoặc một issue. Cảm ơn!
### Chia sẻ code shader
Bạn sẽ thấy rất nhiều link trỏ tới [editor online](http://editor.thebookofshaders.com/) hoặc các phiên bản nhúng của nó ở quyển sách này.
Nếu bạn hoàn thành 1 đoạn code hay ho nào đó, hãy click nút "Export" (hoặc biểu tượng ```⇪```) rồi copy "URL to code...". Sau đó gửi URL tới [@bookofshaders](https://twitter.com/bookofshaders) hoặc [@kyndinfo](https://twitter.com/kyndinfo). Chúng tôi rất mong chờ được bổ sung nó vào [phần thư viện các ví dụ](https://thebookofshaders.com/examples/).
---
### Appendix/04/README (appendix/04/README.md)
## An introduction for those coming from JS
by [Nicolas Barradeau](http://www.barradeau.com/)
If you're a JavaScript developer, chances are you'll be a bit puzzled when reading the book.
Indeed, there are many differences between manipulating high-level JS and getting down and dirty with shaders.
Yet, as opposed to the underlying assembly language, GLSL is human readable and I'm sure that, once you acknowledge its specificities, you'll quickly be up and running.
I assume you have a prior (be it shallow) knowledge of JavaScript of course, but also of the Canvas API.
If not, don't worry, you'll still be able to get most of this section.
Also, I won't go too much into details and some things may be _half true_, don't expect a "definitive guide" but rather
### A BIG HUG
JavaScript is great at quick prototyping ; you throw a bunch of random, untyped variables and methods, you can dynamically add and remove class members, refresh the page and see if it works,
make changes accordingly, refresh the page, repeat, life is easy.
So you may wonder what is the difference between JavaScript and GLSL.
After all, both run in the browser, both are used to draw a bunch of funky stuff on a screen and to that extent, JS is easier to use.
Well, the main difference is that Javascript is an **interpreted** language while GLSL is a **compiled** language.
A **compiled** program is executed natively on the OS, it is low level and generally fast.
An **interpreted** program requires a [Virtual Machine](https://en.wikipedia.org/wiki/Virtual_machine) (VM) to be executed, it is high level and generally slow.
When a browser (the _JavaScript **VM**_) **executes** or **interprets** a piece of JS, it has no clue about which variable is what and which function does what (with the notable exception of **TypedArrays**).
Therefore it can't optimize anything _upfront_, so it takes some time to read your code, to **infer** (deduce from the usage) the types of your variables and methods
and when possible, it will convert _some_ of your code into assembly code that will execute much faster.
It's a slow, painstaking and insanely complex process, if you're interested in the details, I'd recommend watching how [Chrome's V8 engine works](https://developers.google.com/v8/).
The worst is that every browser optimizes JS its way and the process is _hidden_ from you ; you are powerless.
A **compiled** program is not interpreted ; the OS runs it, if the program is valid, the program is executed.
That's a big change ; if you forget a semicolon at the end of line, your code is invalid, it will not compile: your code won't turn into a program at all.
That's cold but that's what a **shader** is: _a compiled program executed on the GPU_.
Fear not! a **compiler**, the piece of program that makes sure your code is valid, will become your best friend.
The examples of this book and the [companion editor](http://editor.thebookofshaders.com/) are very user friendly.
They'll tell you where and why your program failed to compile, then you'll have to fix things and whenever the shader is ready to compile, it will be displayed instantly.
That's a great way of learning as it's very visual and you can't really break anything.
Last note, a **shader** is made of 2 programs, the **vertex shader** and the **fragment shader**.
In a nutshell, the **vertex shader**, the first program, receives a *geometry* as an input and turns it into series of **pixels** (or *fragments*) then hands them over to the
**fragment shader**, the second program, that will decide which color to paint the pixels.
This book is mostly focused on the latter, in all the examples, the geometry is a simple quadrilateral that covers the whole screen.
SO! ready?
off we go!
### Strong types
When you come from JS or any untyped language, **typing** your variables is an alien concept, making **typing** the hardest step to take towards GLSL.
**Typing**, as the name suggests, means that you'll give a **type** to your variables (and functions of course).
This basically means that the word **`var`** doesn't exist anymore.
The GLSL thought-police erased it from the common tongue and you're not able to speak it because, well... it doesn't exist.
Instead of using the magic word **`var`**, you'll have to _explicitly specify the type of each variable_ you use, then the compiler will only see objects and primitives it knows how to handle efficiently.
The downside when you can't use the **`var`** keyword and must _specify everything_, is that you'll have to know the type of all the variables and know them well.
Rest assured, there are few and they're fairly simple (GLSL is not a Java framework).
Might sound scary but all in all, it's not very different from what you're doing when you code JavaScript ; if a variable is a `boolean`, you'll expect it to store `true` or `false` and nothing else.
If a variable is called `var uid = XXX;`, chances are that you'll store an integer value in there and a `var y = YYY;` _might_ be a reference to a floating point value.
Even better, with **strong types**, you won't waste time wondering if `X == Y` (or was it `typeof X == typeof Y` ? .. or `typeof X !== null && Y...` ... anyway) ; you'll just *know* it and if you don't, the compiler will.
Here are the **scalar types** (a **scalar** describes a quantity) you can use in GLSL: `bool` (Boolean), `int`(Integer), `float`(floating point Number).
There are other types but let's take it easy, the following snippet shows how to declare **`vars`** (yes, I spoke the forbidden word) in GLSL:
```glsl
//a Boolean value:
JS: var b = true; GLSL: bool b = true;
//an Integer value
JS: var i = 1; GLSL: int i = 1;
//a Float value (a Number)
JS: var f = 3.14159; GLSL: float f = 3.14159;
```
Not that hard right? as mentioned above, it even makes things easier when it comes to coding as you don't waste your time checking the type of a given variable.
When in doubt, remember that you're doing this for your program to run immensely faster than in JS.
#### void
There is a `void` type that roughly corresponds to `null`, it is used as the return type of a method that doesn't return anything.
you can't assign it to a variable.
#### boolean
As you know, Booleans are mostly used in conditional tests ; `if( myBoolean == true ){}else{}`.
If the conditional branching is a valid option on the CPU, [the parallel nature](http://thebookofshaders/01/) of GLSL makes it less true.
Using conditionals is even discouraged most of the time, the book explains a couple of alternative techniques to solve this.
#### type casting
As [Boromir](https://en.wikipedia.org/wiki/Boromir) put it, "One does not simply combine Typed primitives". Unlike JavaScript, GLSL will not allow you to perform operations between variables of different types.
This for instance:
```glsl
int i = 2;
float f = 3.14159;
//trying to multiply an integer by a float value
float r = i * f;
```
will not play nice because you're trying to crossbreed a **_cat_** and a **_giraffe_**.
The solution to this is to use **type casting** ; it will _make the compiler believe_ that *`i`* is of type `float` without actually changing the type of *`i`*.
```glsl
//casting the type of the integer variable 'i' into float
float r = float( i ) * f;
```
Which is strictly equivalent to dressing up a **_cat_** in a **_giraffe_ outfit** and will work as expected ( `r` will store the result of `i` x `f`).
It is possible to **cast** any of the above types into any other type, note that casting a `float` to `int` will behave like a `Math.floor()` as it will remove the values behind the floating point.
Casting a `float` or a `int` to `bool` will return `true` if the variable is not equal to zero.
#### constructor
The variable **types** are also their own **class constructor** ; in fact a `float` variable can be thought of as an _`instance`_ of a _`Float`_ class.
This declarations are equally valid:
```glsl
int i = 1;
int i = int( 1 );
int i = int( 1.9995 );
int i = int( true );
```
This may not sound like much for `scalar` types, it's not very different from **casting**, but it will make sense when addressing the *overload* section.
Ok, so these three are the `primitive types`, things you can't live without but of course, GLSL has more to offer.
### Vectors
In Javascript like in GLSL, you'll need more sophisticated ways of handling data, that's where **`vectors`** come in handy.
I suppose that you've already coded a `Point` class in JavaScript to hold together a `x` and a `y` value, the code for this would go like:
```glsl
// 'class' definition:
var Point = function( x, y ){
this.x = x || 0;
this.y = y || 0;
}
//and you would instantiate it like:
var p = new Point( 100,100 );
```
As we've just seen, this is SO wrong at SO many levels! That **`var`** keyword for one, then the horrendous **`this`**, then again **untyped** `x` and `y` values...
No, this is not going to work in shaderland.
Instead, GLSL exposes built-in data structures to hold data together, namely:
* `bvec2`: a 2D Boolean vector, `bvec3`: a 3D Boolean vector, `bvec4`: a 4D Boolean vector
* `ivec2`: a 2D Integer vector, `ivec3`: a 3D Integer vector, `ivec4`: a 4D Integer vector
* `vec2`: a 2D Float vector, `vec3`: a 3D Float vector, `vec4`: a 4D Float vector
You immediately noticed that there's a type of **vector** for each primitive type, clever bunny.
From what we just saw, you can deduce that a `bvec2` will hold two values of type `bool` and a `vec4` will hold four `float` values.
Another thing introduced by vectors is a number of **dimensions**, it doesn't mean that a 2D vector is used when you render 2D graphics and a 3D vector when you do 3D.
What would a 4D vector represent then? (well, actually it is called a tesseract or hypercube)
No, the **dimensions** represent the number and the type of **components** or **variables** stored into the **vector**:
```glsl
// let's create a 2D Boolean vector
bvec2 b2 = bvec2 ( true, false );
// let's create a 3D Integer vector
ivec3 i3 = ivec3( 0,0,1 );
// let's create a 4D Float vector
vec4 v4 = vec4( 0.0, 1.0, 2.0, 1. );
```
`b2` stores two different boolean values, `i3` stores 3 different integer values and `v4` stores 4 different float values.
but how to retrieve those values?
in the case of `scalars`, the answer is obvious ; with `float f = 1.2;`, the variable `f` holds the value `1.2`.
With **vectors** it's a bit different and quite beautiful.
#### accessors
There are different ways of accessing the values
```glsl
// let's create a 4D Float vector
vec4 v4 = vec4( 0.0, 1.0, 2.0, 3.0 );
```
to retrieve the 4 values, you can do the following:
```glsl
float x = v4.x; // x = 0.0
float y = v4.y; // y = 1.0
float z = v4.z; // z = 2.0
float w = v4.w; // w = 3.0
```
nice and easy ; but the following are equally valid ways of accessing your data:
```glsl
float x = v4.x = v4.r = v4.s = v4[0]; // x = 0.0
float y = v4.y = v4.g = v4.t = v4[1]; // y = 1.0
float z = v4.z = v4.b = v4.p = v4[2]; // z = 2.0
float w = v4.w = v4.a = v4.q = v4[3]; // w = 3.0
```
And the clever bunny you are already noticed three things:
* `X`, `Y`, `Z` & `W` are used in 3D programs to represent 3D vectors
* `R`, `G`, `B` & `A` are used to encode colors and alpha
* `[0]`, `[1]`, `[2]` & `[3]` mean that we have a random access array of values
So depending on whether you're manipulating 2D or 3D coordinates, a color with or without an alpha value or simply some random variables, you can pick the most suited **vector** type and size.
Typically 2D coordinates and vectors (in the geometric sense) are stored as a `vec2`, `vec3` or `vec4`, colors as `vec3` or `vec4` if you need opacity but there is no restriction on how to use the vectors.
For instance, if you want to store only one boolean value in a `bvec4`, it's possible, it's just a waste of memory.
**note**: in a shader, color values (`R`, `G`, `B` & `A`) are normalised, they range from 0 to 1 and not from 0 to 0xFF, so you'd rather use a Float `vec4` than an Integer `ivec4` to store them.
Nice already, but there's more!
#### swizzle
It is possible to return more than one value at once ; say you need only the `X` and `Y` values of a `vec4`, in JavaScript, you'd have to write something like:
```glsl
var needles = [0, 1]; // location of 'x' & 'y' in our data structure
var a = [ 0,1,2,3 ]; // our 'vec4' data structure
var b = a.filter( function( val, i, array ) {
return needles.indexOf( array.indexOf( val ) ) != -1;
});
// b = [ 0, 1 ]
//or more literally:
var needles = [0, 1];
var a = [ 0,1,2,3 ]; // our 'vec4' data structure
var b = [ a[ needles[ 0 ] ], a[ needles[ 1 ] ] ]; // b = [ 0, 1 ]
```
Ugly. In GLSL you can retrieve them like so:
```glsl
// create a 4D Float vector
vec4 v4 = vec4( 0.0, 1.0, 2.0, 3.0 );
//and retrieve only the X & Y components
vec2 xy = v4.xy; // xy = vec2( 0.0, 1.0 );
```
What just happened?! when you **concatenate accessors**, GLSL gracefully returns a subset of the values you asked for, in the best suited **vector** format.
Indeed, the vector is a **random access** data structure, like an array in JavaScript if you want.
So not only can you retrieve a subset of your data, but you can also specify the **order** in which you need it, this will invert the values of the components of a vector:
```glsl
// create a 4D Float vector: R,G,B,A
vec4 color = vec4( 0.2, 0.8, 0.0, 1.0 );
//and retrieve the color components in the A,B,G,R order
vec4 backwards = color.abgr; // backwards = vec4( 1.0, 0.0, 0.8, 0.2 );
```
And of course, you can ask the same component multiple times:
```glsl
// create a 4D Float vector: R,G,B,A
vec4 color = vec4( 0.2, 0.8, 0.0, 1.0 );
//and retrieve a GAG vec3 based on the G & A channels of the color
vec3 GAG = color.gag; // GAG = vec4( 0.8, 1.0, 0.8 );
```
This is extremely handy to combine parts of vectors together, extract only the rgb channels of a RGBA color etc.
#### overload everything!
In the types section, I mentioned something about the **constructor** and that's yet again a great feature of GLSL ; **overloading**.
For those who don't know, **overloading** an operator or a function roughly means: _'changing the behaviour of said operator or function depending on the operands/arguments'_.
Overloading is not allowed in JavaScript, so this may be a bit strange at first but I'm sure that once you get used to it, you'll wonder why it is not implemented in JS (short answer, *typing*).
The most basic example of operator overloading goes as follow:
```glsl
vec2 a = vec2( 1.0, 1.0 );
vec2 b = vec2( 1.0, 1.0 );
//overloaded addition
vec2 c = a + b; // c = vec2( 2.0, 2.0 );
```
WHAT? So you can add things that are not numbers?!
Yes, precisely. Of course this applies to all operators (`+`, `-`, `*` & `/`) but that's only the beginning.
Consider the following snippet:
```glsl
vec2 a = vec2( 0.0, 0.0 );
vec2 b = vec2( 1.0, 1.0 );
//overloaded constructor
vec4 c = vec4( a , b ); // c = vec4( 0.0, 0.0, 1.0, 1.0 );
```
We built a `vec4` out of two `vec2`, by doing so, the new `vec4` used the `a.x` and `a.y` as the `X`, `Y` components of `c`.
Then it took `b.x` and `b.y` and used them as the `Z` and `W` components of `c`.
This is what happens when a **function** is overloaded to accept different arguments, in this case, the `vec4` **constructor**.
It means that many **versions** of the same method with a different signature can coexist in the same program, for instance the following declarations are all valid:
```glsl
vec4 a = vec4(1.0, 1.0, 1.0, 1.0);
vec4 a = vec4(1.0);// x, y, z, w all equal 1.0
vec4 a = vec4( v2, float, v4 );// vec4( v2.x, v2.y, float, v4.x );
vec4 a = vec4( v3, float );// vec4( v3.x, v3.y, v3.z, float );
etc.
```
The only thing you should make sure of is to provide enough arguments to feed your **vector**.
Last thing, you are allowed to overload the built-in functions in your program so they can take arguments they were not designed for (this shouldn't happen too often though).
#### more types
Vectors are fun, they're the meat of your shader.
There are other primitives such as Matrices and Texture samplers which will be covered later in the book.
We can also use Arrays. Of course they have to be typed and there are *twists*:
* they have a fixed size
* you can't push(), pop(), splice() etc. and there is no ```length``` property
* you can't initialize them immediately with values
* you have to set the values individually
this won't work:
```glsl
int values[3] = [0,0,0];
```
but this will:
```glsl
int values[3];
values[0] = 0;
values[1] = 0;
values[2] = 0;
```
This is fine when you know your data or have small arrays of values.
If you want a more expressive way of declaring a variable,
there is also a ```struct``` type. These are like _objects_ without methods ;
they allow to store and access multiple variables inside the same object
```glsl
struct ColorStruct {
vec3 color0;
vec3 color1;
vec3 color2;
}
```
then you can set and retrieve the values of _colors_ by doing:
```glsl
//initialize the struct with some values
ColorStruct sandy = ColorStruct( vec3(0.92,0.83,0.60),
vec3(1.,0.94,0.69),
vec3(0.95,0.86,0.69) );
//access a values from the struct
sandy.color0 // vec3(0.92,0.83,0.60)
```
This is syntactic sugar but it can help you write cleaner code, at least code you're more familiar with.
#### statements & conditions
Data structures are nice as such but we _might_ need to iterate or perform conditional tests at some point.
Fortunately for us, the syntax is very close to the JavaScript.
A condition is like:
```glsl
if( condition ){
//true
}else{
//false
}
```
A for loop is usually:
```glsl
const int count = 10;
for( int i = 0; i <= count; i++){
//do something
}
```
or with a float iterator:
```glsl
const float count = 10.;
for( float i = 0.0; i <= count; i+= 1.0 ){
//do something
}
```
Note that ```count``` will have to be defined as a ```constant```.
This means prefixing the type with a ```const``` **qualifier**, we'll cover this in a second.
we also have the ```break``` and ```continue``` statements:
```glsl
const float count = 10.;
for( float i = 0.0; i <= count; i+= 1.0 ){
if( i < 5. )continue;
if( i >= 8. )break;
}
```
Note that on some hardware, ```break``` does not work as expected and the loop doesn't bail out early.
In general, you'll want to keep the iteration count as low as possible and avoid the loops and the conditionals as often as you can.
#### qualifiers
On top of the variable types, GLSL uses **qualifiers**.
Long story short, qualifiers help the compiler know which variable is what.
For instance some data can only be provided by the CPU to the GPU, those are called **attributes** and **uniforms**.
The **attributes** are reserved for the vertex shaders, the **uniforms** can be used in both the vertex and the fragment shaders.
There's also a ```varying``` qualifier used to pass variables between the vertex and the fragment shader.
I won't go too much into details here as we're mostly focused on the **fragment shader** but later in the book, you'll see something like:
```glsl
uniform vec2 u_resolution;
```
See what we did here? We stuck a ```uniform``` qualifier before the type of the variable
This means that the resolution of the canvas we're working on is passed to the shader from the CPU.
The width of the canvas is stored in the x and the height in the y component of the 2D vector.
When the compiler sees a variable preceded by this qualifier, it will make sure that you can't *set* those values at runtime.
The same applied to our ```count``` variable which was the limit of our ```for``` loop:
```glsl
const float count = 10.;
for( ... )
```
When we use a ```const``` qualifier, the compiler will make sure that we set the variable's value only once, otherwise it's not a constant.
There are 3 extra qualifiers that are used in the functions signatures : ```in```, ```out``` and ```inout```.
In JavaScript, when you pass scalar arguments to a function, their value is read-only and if you change their values inside the function,
the changes are not applied to the variable outside the function.
```glsl
function banana( a ){
a += 1;
}
var value = 0;
banana( value );
console.log( value );// > 0 ; the changes are not taken into account outside the function
```
With arguments qualifiers, you can specify the behaviour of the arguments:
* ```in``` will be read-only ( default )
* ```out``` write-only: you can't read the value of this argument but you can set it
* ```inout``` read-write: you can both get and set the value of this variable
Rewriting the banana method in GLSL would look like
```glsl
void banana( inout float a ){
a += 1.;
}
float A = 0.;
banana( A ); //now A = 1.;
```
This is very different from JS and quite powerful too but you don't have to specify the signature qualifiers (the default is read-only).
#### space & coordinates
Final note, in the DOM and the Canvas 2D, we're used to have the Y axis pointing 'down'.
This makes sense in the context of a DOM as it follows the way a web page unrolls ; the navbar at the top, content expanding towards the bottom.
In a WebGL canvas, the Y axis is flipped: Y points 'up'.
This means that the origin, the point (0,0), is located at the bottom left corner of a WebGL context, not at the top left corner like in a 2D Canvas.
The textures coordinates follow this rule which might be counter-intuitive at first.
## And we're done!
Of course we could have gone deeper into the various concepts but as mentioned earlier, this is meant to give a BIG HUG to the newcomers.
It's a quite a lot to ingest but with patience and practice, this will become more and more natural.
I hope you found some of this useful, now what about starting your journey through the book?
---
### Appendix/04/README Pl (appendix/04/README-pl.md)
## Wprowadzenie dla osób przychodzących z JS
przez [Nicolas Barradeau](http://www.barradeau.com/)
Jeśli jesteś programistą JavaScript, prawdopodobnie nieco zaskoczy Cię treść tej książki.
Rzeczywiście, istnieje wiele różnic pomiędzy manipulowaniem wysokopoziomowym kodem JS a zagłębianiem się w świat shaderów.
Jednak w przeciwieństwie do niskopoziomowego języka asemblerowego, GLSL jest czytelny dla człowieka i jestem pewien, że po zrozumieniu jego specyfiki szybko zaczniesz go używać.
Zakładam, że masz podstawową (choć może płytką) wiedzę o JavaScript, ale także o Canvas API.
Jeśli nie, nie martw się – większość tej sekcji będzie dla Ciebie zrozumiała.
Nie będę zagłębiać się zbytnio w szczegóły, a niektóre kwestie mogą być _półprawdziwe_; nie oczekuj "wyczerpującego przewodnika", ale raczej
### WIELKI UŚCISK
JavaScript świetnie nadaje się do szybkiego prototypowania; wrzucasz garść losowych, nieotypowanych zmiennych i metod, możesz dynamicznie dodawać i usuwać członków klas, odświeżać stronę i sprawdzać, czy wszystko działa,
wprowadzać zmiany, odświeżać stronę, powtarzać – życie jest proste.
Możesz się więc zastanawiać, jaka jest różnica między JavaScriptem a GLSL.
W końcu oba działają w przeglądarce, oba służą do rysowania różnych efektownych rzeczy na ekranie i pod tym względem JS jest łatwiejszy w użyciu.
Główna różnica polega jednak na tym, że JavaScript jest językiem **interpretowanym**, podczas gdy GLSL jest językiem **kompilowanym**.
**Kompilowany** program jest wykonywany natywnie przez system operacyjny, jest niskopoziomowy i zazwyczaj szybki.
**Interpretowany** program wymaga [wirtualnej maszyny](https://en.wikipedia.org/wiki/Virtual_machine) (VM) do wykonania, jest wysokopoziomowy i zazwyczaj wolniejszy.
Gdy przeglądarka (czyli _JavaScriptowa **VM**_) **wykonuje** lub **interpretuje** fragment kodu JS, nie wie, jaka zmienna czym jest i jaka funkcja co robi (z wyjątkiem oczywistych przypadków, takich jak **TypedArrays**).
Dlatego nie może nic zoptymalizować _z góry_, więc potrzebuje trochę czasu, aby przeczytać Twój kod, **wywnioskować** (dedukować na podstawie użycia) typy Twoich zmiennych i metod,
a kiedy to możliwe, przekształci _część_ Twojego kodu w kod asemblerowy, który wykona się znacznie szybciej.
To powolny, mozolny i niesamowicie skomplikowany proces – jeśli interesują Cię szczegóły, polecam przyjrzeć się działaniu [silnika V8 w Chrome](https://developers.google.com/v8/).
Najgorsze jest to, że każda przeglądarka optymalizuje JS na swój sposób, a cały proces jest _ukryty_ przed użytkownikiem; jesteś bezsilny.
**Kompilowany** program nie jest interpretowany; system operacyjny go uruchamia, a jeśli program jest poprawny, zostaje wykonany.
To duża zmiana; jeśli zapomnisz o średniku na końcu linii, Twój kod jest niepoprawny i nie skompiluje się: Twój kod w ogóle nie przekształci się w program.
To surowe, ale tak właśnie działa **shader**: _skompilowany program wykonywany na GPU_.
Nie bój się! **Kompilator**, czyli część programu, która dba o to, aby Twój kod był poprawny, stanie się Twoim najlepszym przyjacielem.
Przykłady z tej książki oraz [edytor towarzyszący](http://editor.thebookofshaders.com/) są bardzo przyjazne użytkownikowi.
Powiedzą Ci, gdzie i dlaczego Twój program nie skompilował się, a następnie będziesz musiał wprowadzić poprawki – i za każdym razem, gdy shader będzie gotowy do kompilacji, zostanie on natychmiast wyświetlony.
To świetny sposób na naukę, ponieważ jest bardzo wizualny i tak naprawdę niczego nie możesz zepsuć.
Ostatnia uwaga: **shader** składa się z dwóch programów, **vertex shader** i **fragment shader**.
W skrócie, **vertex shader**, pierwszy program, otrzymuje geometrię jako dane wejściowe i przekształca ją w serię **pikseli** (lub *fragmentów*), które następnie przekazuje do
**fragment shader**, drugiego programu, który decyduje, jaki kolor nadać pikselom.
Ta książka koncentruje się głównie na tym drugim – we wszystkich przykładach geometria to prosty czworobok pokrywający cały ekran.
Więc! Gotowy?
No to ruszamy!
### Silne typowanie
Dla osób przychodzących z JS lub innego języka bez typów, **typowanie** zmiennych jest obcym konceptem, co sprawia, że **typowanie** stanowi najtrudniejszy krok w kierunku nauki GLSL.
**Typowanie**, jak sama nazwa wskazuje, oznacza, że musisz przypisać **typ** każdej zmiennej (oraz funkcjom, oczywiście).
To zasadniczo oznacza, że słowo **`var`** przestaje istnieć.
Polityka myślenia GLSL wymazała je z powszechnego języka i nie jesteś w stanie go używać, ponieważ... po prostu nie istnieje.
Zamiast używać magicznego słowa **`var`**, będziesz musiał _jawnie określić typ każdej używanej zmiennej_, dzięki czemu kompilator będzie widział tylko obiekty i prymitywy, które wie, jak efektywnie obsługiwać.
Minusem braku możliwości użycia słowa **`var`** i konieczności _jawnego określania wszystkiego_ jest to, że musisz znać typ wszystkich zmiennych i dobrze je rozumieć.
Spokojnie – jest ich niewiele, a do tego są dość proste (GLSL nie jest frameworkiem Java).
Może to brzmieć strasznie, ale ogólnie nie różni się to bardzo od tego, co robisz w JavaScript; jeśli zmienna jest typu `boolean`, oczekujesz, że będzie przechowywać `true` lub `false` i nic więcej.
Jeśli zmienna jest zadeklarowana jako `var uid = XXX;`, prawdopodobnie przechowasz w niej wartość całkowitą, a `var y = YYY;` _może_ odnosić się do wartości zmiennoprzecinkowej.
Co więcej, dzięki **silnemu typowaniu** nie będziesz tracił czasu na zastanawianie się, czy `X == Y` (albo czy `typeof X == typeof Y`? ... albo `typeof X !== null && Y...`... w każdym razie) – po prostu będziesz tego wiedział, a jeśli nie, kompilator Cię o tym poinformuje.
Oto **typy skalarne** (**skalar** określa ilość), których możesz używać w GLSL: `bool` (Boolean), `int` (liczba całkowita), `float` (liczba zmiennoprzecinkowa).
Istnieją też inne typy, ale nie ma co się przejmować – poniższy fragment pokazuje, jak deklarować **zmienne (`vars`)** (tak, użyłem zakazanego słowa) w GLSL:
```glsl
// wartość typu Boolean:
JS: var b = true; GLSL: bool b = true;
// wartość typu Integer
JS: var i = 1; GLSL: int i = 1;
// wartość typu Float (liczba)
JS: var f = 3.14159; GLSL: float f = 3.14159;
```
Nie jest to trudne, prawda? Jak wspomniałem, ułatwia to kodowanie, ponieważ nie tracisz czasu na sprawdzanie typu danej zmiennej.
W razie wątpliwości pamiętaj, że robisz to po to, aby Twój program działał o wiele szybciej niż w JS.
#### void
Istnieje typ `void`, który w przybliżeniu odpowiada `null`; jest on używany jako typ zwracany przez funkcję, która nic nie zwraca.
Nie możesz przypisać go do zmiennej.
#### boolean
Jak wiesz, wartości logiczne (Boolean) są najczęściej używane w testach warunkowych, np. `if( myBoolean == true ){}else{}`.
Choć rozgałęzianie warunkowe jest możliwe na CPU, [równoległa natura](http://thebookofshaders/01/) GLSL czyni to mniej sensownym.
Używanie instrukcji warunkowych jest często wręcz zniechęcane – książka przedstawia kilka alternatywnych technik rozwiązania tego problemu.
#### rzutowanie typów
Jak powiedział [Boromir](https://pl.wikipedia.org/wiki/Boromir): "Nie łączy się po prostu otypowanych prymitywów". W przeciwieństwie do JavaScript, GLSL nie pozwala na wykonywanie operacji pomiędzy zmiennymi o różnych typach.
This for instance:
```glsl
int i = 2;
float f = 3.14159;
// próba pomnożenia liczby całkowitej przez wartość zmiennoprzecinkową:
float r = i * f;
```
nie zadziała, ponieważ próbujesz połączyć **_kota_** z **_żyrafą_**.
Rozwiązaniem jest użycie rzutowania typów; to _sprawi, że kompilator uwierzy_, że *`i`* jest typu `float`, nie zmieniając faktycznie typu *`i`*.
```glsl
// rzutowanie typu zmiennej całkowitej 'i' na float:
float r = float( i ) * f;
```
Co jest ściśle równoważne przebraniu **_kota_** w **_żyrafi_ strój** i zadziała zgodnie z oczekiwaniami (`r` będzie wynikiem `i` x `f`).
Można **rzutować** dowolny z wymienionych typów na inny; zauważ, że rzutowanie `float` na `int` działa jak `Math.floor()`, ponieważ usuwa część dziesiętną.
Rzutowanie `float` lub `int` na `bool` zwróci `true`, jeśli wartość zmiennej nie wynosi zero.
#### konstruktor
**Typy** zmiennych są również swoimi własnymi **konstruktorami klas**; w rzeczywistości zmienna typu `float` może być traktowana jako _`instancja`_ klasy _`Float`_.
Następujące deklaracje są równie poprawne:
```glsl
int i = 1;
int i = int( 1 );
int i = int( 1.9995 );
int i = int( true );
```
Może się to nie wydawać znaczące dla typów `skalarnych`, ale nie różni się to zbytnio od **rzutowania** – nabierze sensu, gdy przejdziemy do sekcji dotyczącej *przeciążania*.
Ok, więc te trzy to `typy prymitywne`, rzeczy, bez których nie możesz żyć – ale oczywiście GLSL ma do zaoferowania więcej.
### Wektory
W JavaScript, podobnie jak w GLSL, potrzebujesz bardziej zaawansowanych sposobów obsługi danych, dlatego przydają się **wektory**.
Przypuszczam, że już napisałeś klasę `Point` w JavaScript, która przechowuje razem wartość `x` i `y`, kod wyglądałby mniej więcej tak:
```glsl
// definicja 'klasy':
var Point = function( x, y ){
this.x = x || 0;
this.y = y || 0;
}
// i instancjonowałoby się ją tak:
var p = new Point( 100,100 );
```
Jak właśnie widzieliśmy, to jest TAK niepoprawne na TYLU poziomach! Po pierwsze, użycie słowa kluczowego **`var`**, potem okropne **`this`**, a następnie znowu **nieotypowane** wartości `x` i `y`...
Nie, to nie zadziała w świecie shaderów.
Zamiast tego GLSL udostępnia wbudowane struktury danych, które służą do przechowywania danych razem, mianowicie:
* `bvec2`: 2-wymiarowy wektor Boolean, `bvec3`: 3-wymiarowy wektor Boolean, `bvec4`: 4-wymiarowy wektor Boolean
* `ivec2`: 2-wymiarowy wektor Integer, `ivec3`: 3-wymiarowy wektor Integer, `ivec4`: 4-wymiarowy wektor Integer
* `vec2`: 2-wymiarowy wektor Float, `vec3`: 3-wymiarowy wektor Float, `vec4`: 4-wymiarowy wektor Float
Natychmiast zauważyłeś, że dla każdego typu prymitywnego istnieje odpowiedni **wektor**, spryciarzu.
Z tego, co właśnie widzieliśmy, można wywnioskować, że `bvec2` przechowa dwie wartości typu `bool`, a `vec4` cztery wartości typu `float`.
Inną rzeczą wprowadzoną przez wektory jest liczba **wymiarów**; nie oznacza to, że do renderowania grafiki 2D używasz 2-wymiarowego wektora, a do 3D – 3-wymiarowego.
Co by wtedy reprezentował 4-wymiarowy wektor? (właściwie nazywa się tesseraktem lub hiperkostką)
Nie, **wymiary** oznaczają liczbę oraz typ **składowych** lub **zmiennych** przechowywanych w **wektorze**:
```glsl
// stwórzmy 2-wymiarowy wektor Boolean
bvec2 b2 = bvec2 ( true, false );
// stwórzmy 3-wymiarowy wektor Integer
ivec3 i3 = ivec3( 0,0,1 );
// stwórzmy 4-wymiarowy wektor Float
vec4 v4 = vec4( 0.0, 1.0, 2.0, 1. );
```
`b2` przechowuje dwie różne wartości logiczne, `i3` przechowuje trzy różne wartości całkowite, a `v4` cztery różne wartości zmiennoprzecinkowe.
Ale jak odczytać te wartości?
w przypadku `skalarów` odpowiedź jest oczywista – przy `float f = 1.2`; zmienna `f` przechowuje wartość `1.2`.
W przypadku **wektorów** jest to nieco inne i całkiem piękne.
#### akcesory
Istnieją różne sposoby dostępu do wartości
```glsl
// stwórzmy 4-wymiarowy wektor Float
vec4 v4 = vec4( 0.0, 1.0, 2.0, 3.0 );
```
Aby odczytać te 4 wartości, możesz zrobić następująco:
```glsl
float x = v4.x; // x = 0.0
float y = v4.y; // y = 1.0
float z = v4.z; // z = 2.0
float w = v4.w; // w = 3.0
```
bułka z masłem; ale poniższe sposoby są równie poprawne w dostępie do Twoich danych:
```glsl
float x = v4.x = v4.r = v4.s = v4[0]; // x = 0.0
float y = v4.y = v4.g = v4.t = v4[1]; // y = 1.0
float z = v4.z = v4.b = v4.p = v4[2]; // z = 2.0
float w = v4.w = v4.a = v4.q = v4[3]; // w = 3.0
```
I spryciarzu, już zauważyłeś trzy rzeczy:
* `X`, `Y`, `Z` i `W` są używane w programach 3D do reprezentacji wektorów 3D
* `R`, `G`, `B` i `A` służą do kodowania kolorów oraz kanału alfa
* `[0]`, `[1]`, `[2]` i `[3]` oznaczają, że mamy dostęp do wartości w sposób losowy (tablica indeksowana)
W zależności od tego, czy manipulujesz współrzędnymi 2D czy 3D, kolorem z lub bez kanału alfa, czy też po prostu różnymi zmiennymi, możesz wybrać najbardziej odpowiedni typ i rozmiar **wektora**.
Zazwyczaj współrzędne 2D i wektory (w sensie geometrycznym) przechowywane są jako `vec2`, `vec3` lub `vec4`, kolory jako `vec3` lub `vec4` (jeśli potrzebujesz kanału alfa), ale nie ma ograniczeń co do sposobu użycia wektorów.
Na przykład, jeśli chcesz przechować tylko jedną wartość logiczną w `bvec4`, jest to możliwe, ale to marnotrawstwo pamięci.
**uwaga**: w shaderze wartości kolorów (`R`, `G`, `B` i `A`) są normalizowane, mieszczą się w przedziale od 0 do 1, a nie od 0 do 0xFF, dlatego lepiej użyć Float `vec4` niż Integer `ivec4` do ich przechowywania.
Już nieźle, ale to nie wszystko!
#### swizzle
Można zwrócić więcej niż jedną wartość jednocześnie; powiedzmy, że potrzebujesz tylko składowych `X` i `Y` z `vec4`, w JavaScript musiałbyś napisać coś takiego:
```glsl
var needles = [0, 1]; // pozycja 'x' i 'y' w naszej strukturze danych
var a = [ 0,1,2,3 ]; // nasza struktura danych 'vec4'
var b = a.filter( function( val, i, array ) {
return needles.indexOf( array.indexOf( val ) ) != -1;
});
// b = [ 0, 1 ]
// albo bardziej bezpośrednio:
var needles = [0, 1];
var a = [ 0,1,2,3 ]; // our 'vec4' data structure
var b = [ a[ needles[ 0 ] ], a[ needles[ 1 ] ] ]; // b = [ 0, 1 ]
```
Brzydko. W GLSL możesz je uzyskać w ten sposób:
```glsl
// stwrórz 4-wymiarowy wektor Float
vec4 v4 = vec4( 0.0, 1.0, 2.0, 3.0 );
// i odczytaj tylko 'x' i 'y'
vec2 xy = v4.xy; // xy = vec2( 0.0, 1.0 );
```
Co tu się stało?! Gdy **skonkatenujesz akcesory**, GLSL elegancko zwraca podzbiór wartości, o które prosiłeś, w najbardziej odpowiednim formacie **wektora**.
Rzeczywiście, wektor to struktura danych o **losowym dostępie**, podobna do tablicy w JavaScript.
Tak więc, nie tylko możesz pobrać podzbiór swoich danych, ale także określić **kolejność**, w jakiej mają być zwrócone – może to odwrócić kolejność składowych wektora:
```glsl
// stwórz 4-wymiarowy wektor: R,G,B,A
vec4 color = vec4( 0.2, 0.8, 0.0, 1.0 );
// i odczytaj go w kolejności: A,B,G,R
vec4 backwards = color.abgr; // backwards = vec4( 1.0, 0.0, 0.8, 0.2 );
```
I oczywiście, możesz zapytać o tę samą składową wielokrotnie:
```glsl
// stwórz 4-wymiarowy wektor: R,G,B,A
vec4 color = vec4( 0.2, 0.8, 0.0, 1.0 );
// i odczytaj GAG (Green, Alpha, Green) vec3 z kanałów G i A
vec3 GAG = color.gag; // GAG = vec4( 0.8, 1.0, 0.8 );
```
Jest to niezwykle przydatne, aby łączyć części wektorów, wyodrębniać tylko kanały rgb z koloru RGBA itp.
#### przeciążaj wszystko!
W sekcji o typach wspomniałem o **konstruktorze** i tu mamy kolejną świetną cechę GLSL – **przeciążanie**.
Dla tych, którzy nie wiedzą, **przeciążanie** operatora lub funkcji oznacza mniej więcej: _"zmianę zachowania danego operatora lub funkcji w zależności od operandów/argumentów"_.
Przeciążanie nie jest dozwolone w JavaScript, więc na początku może to wydawać się dziwne, ale jestem pewien, że gdy się do tego przyzwyczaisz, zastanowisz się, dlaczego nie zostało to zaimplementowane w JS (krótka odpowiedź, *typowanie*).
Najprostszy przykład przeciążania operatorów wygląda następująco:
```glsl
vec2 a = vec2( 1.0, 1.0 );
vec2 b = vec2( 1.0, 1.0 );
// przeciążone dodawanie
vec2 c = a + b; // c = vec2( 2.0, 2.0 );
```
CO? Czyli można dodawać rzeczy, które nie są liczbami?!
Tak, dokładnie. Oczywiście dotyczy to wszystkich operatorów (`+`, `-`, `*` oraz `/`), ale to dopiero początek.
Rozważ poniższy fragment:
```glsl
vec2 a = vec2( 0.0, 0.0 );
vec2 b = vec2( 1.0, 1.0 );
// przeciążony konstruktor
vec4 c = vec4( a , b ); // c = vec4( 0.0, 0.0, 1.0, 1.0 );
```
Zbudowaliśmy `vec4` z dwóch `vec2`, przy czym nowy `vec4` użył `a.x` i `a.y` jako składowych `X` i `Y` wektora `c`.
Następnie wziął `b.x` i `b.y` i użył ich jako składowych `Z` i `W`.
Tak właśnie działa przeciążony konstruktor vec4, który akceptuje różne argumenty.
Oznacza to, że wiele wersji tej samej funkcji o różnych sygnaturach może współistnieć w jednym programie, na przykład następujące deklaracje są wszystkie poprawne:
```glsl
vec4 a = vec4(1.0, 1.0, 1.0, 1.0);
vec4 a = vec4(1.0);// x, y, z, w wszystkie są równe 1.0
vec4 a = vec4( v2, float, v4 );// vec4( v2.x, v2.y, float, v4.x );
vec4 a = vec4( v3, float );// vec4( v3.x, v3.y, v3.z, float );
etc.
```
Jedyne, na co musisz zwrócić uwagę, to dostarczenie wystarczającej liczby argumentów, aby wypełnić Twój **wektor**.
Ostatnia rzecz, możesz przeciążać wbudowane funkcje w swoim programie, aby przyjmowały argumenty, dla których nie zostały zaprojektowane (choć nie powinno się to zdarzać zbyt często).
#### inne typy
Wektory są fajne, to sedno Twojego shadera.
Istnieją inne prymitywy, takie jak macierze (Matrices) i próbki tekstur (Texture samplers), które zostaną omówione później w książce.
Możemy także używać tablic (Arrays). Oczywiście muszą być typowane, a przy tym występują pewne pułapki:
* mają ustalony rozmiar
* nie możesz używać metod push(), pop(), splice() itp., a właściwość ```length``` nie istnieje
* nie możesz od razu zainicjalizować ich wartościami
* musisz przypisywać wartości pojedynczo
to nie zadziała:
```glsl
int values[3] = [0,0,0];
```
ale to zadziała:
```glsl
int values[3];
values[0] = 0;
values[1] = 0;
values[2] = 0;
```
To jest w porządku, gdy znasz swoje dane lub masz małe tablice wartości.
Jeśli chcesz bardziej ekspresyjnego sposobu deklaracji zmiennej,
możesz użyć również typu ```struct```. Są one jak _obiekty_ bez metod;
pozwalają przechowywać i uzyskiwać dostęp do wielu zmiennych w jednym obiekcie.
```glsl
struct ColorStruct {
vec3 color0;
vec3 color1;
vec3 color2;
}
```
następnie możesz ustawiać i odczytywać wartości _kolorów_ w następujący sposób:
```glsl
// zainicjuj struct z jakimiś wartościami
ColorStruct sandy = ColorStruct( vec3(0.92,0.83,0.60),
vec3(1.,0.94,0.69),
vec3(0.95,0.86,0.69) );
// odczytaj wartość ze struct
sandy.color0 // vec3(0.92,0.83,0.60)
```
To lukier składniowy, ale może pomóc w pisaniu bardziej przejrzystego kodu, przynajmniej takiego, do którego jesteś przyzwyczajony.
#### instrukcje i warunki
Struktury danych są przydatne, ale może będziesz musiał iterować lub wykonywać testy warunkowe w pewnym momencie.
Na szczęście składnia jest bardzo zbliżona do tej w JavaScript.
Warunek wygląda tak:
```glsl
if( warunek ){
// prawda
}else{
// fałsz
}
```
Pętla for zazwyczaj wygląda tak:
```glsl
const int count = 10;
for( int i = 0; i <= count; i++){
// zrób coś
}
```
lub z iteratorem typu float:
```glsl
const float count = 10.;
for( float i = 0.0; i <= count; i+= 1.0 ){
// zrób coś
}
```
Zauważ, że `count` musi być zdefiniowane jako stała.
Oznacza to, że poprzedzasz typ kwalifikatorem `const`, o czym opowiem za chwilę.
Mamy również instrukcje ```break``` i ```continue```:
```glsl
const float count = 10.;
for( float i = 0.0; i <= count; i+= 1.0 ){
if( i < 5. )continue;
if( i >= 8. )break;
}
```
Miej na uwadze, że na niektórych urządzeniach instrukcja ```break``` może nie działać zgodnie z oczekiwaniami i pętla nie przerwie iteracji wcześniej.
Ogólnie rzecz biorąc, powinieneś utrzymywać liczbę iteracji na możliwie najniższym poziomie i unikać pętli oraz instrukcji warunkowych tak często, jak to możliwe.
#### kwalifikatory
Oprócz typów zmiennych, GLSL używa **kwalifikatorów**.
Krótko mówiąc, kwalifikatory pomagają kompilatorowi zrozumieć, jaka jest rola danej zmiennej.
Na przykład, niektóre dane mogą być dostarczane tylko przez CPU do GPU, nazywamy je **atrybutami** i **uniformami**.
**Atrybuty** są zarezerwowane dla vertex shaderów, a **uniformy** mogą być używane zarówno w vertex, jak i fragment shaderach.
Jest też kwalifikator ```varying```, służący do przekazywania zmiennych między vertex a fragment shaderem.
Nie będę zagłębiać się tutaj w szczegóły, ponieważ skupiamy się głównie na **fragment shaderze**, ale później w książce zobaczysz coś takiego:
```glsl
uniform vec2 u_resolution;
```
Widzisz, co zrobiliśmy? Dodaliśmy kwalifikator ```uniform``` przed typem zmiennej.
Oznacza to, że rozdzielczość kanwy, nad którą pracujemy, jest przekazywana do shadera z CPU.
Szerokość kanwy zapisana jest w komponencie x, a wysokość w komponencie y 2-wymiarowego wektora.
Gdy kompilator napotka zmienną poprzedzoną tym kwalifikatorem, upewni się, że nie możesz zmieniać tych wartości w czasie wykonywania programu.
To samo dotyczy naszej zmiennej ```count```, która była limitem w pętli ```for```:
```glsl
const float count = 10.;
for( ... )
```
Kiedy używamy kwalifikatora ```const```, kompilator upewni się, że wartość zmiennej zostanie ustawiona tylko raz, w przeciwnym razie nie jest to stała.
Istnieją trzy dodatkowe kwalifikatory używane w sygnaturach funkcji: in, out oraz inout.
W JavaScript, gdy przekazujesz prymitywne argumenty do funkcji, ich wartość jest tylko do odczytu, a jeśli zmienisz ich wartość wewnątrz funkcji,
zmiany nie mają wpływu na zmienną poza funkcją.
```glsl
function banana( a ){
a += 1;
}
var value = 0;
banana( value );
console.log( value );// > 0 ; zmiany nie są brane pod uwagę poza funkcją
```
With arguments qualifiers, you can specify the behaviour of the arguments:
* ```in``` will be read-only ( default )
* ```out``` write-only: you can't read the value of this argument but you can set it
* ```inout``` read-write: you can both get and set the value of this variable
Przepisanie funkcji banana do GLSL wyglądałoby tak:
```glsl
void banana( inout float a ){
a += 1.;
}
float A = 0.;
banana( A ); // teraz A = 1.;
```
To bardzo różni się od JS i jest również potężne, ale nie musisz jawnie określać kwalifikatorów w sygnaturze (domyślnie są one tylko do odczytu).
#### przestrzeń i współrzędne
Ostatnia uwaga: w DOM oraz w 2D Canvas jesteśmy przyzwyczajeni, że oś Y wskazuje w dół.
Ma to sens w kontekście DOM, ponieważ odpowiada sposobowi, w jaki rozwija się strona internetowa – pasek nawigacyjny na górze, zawartość rozciągająca się ku dołowi.
W kanwie WebGL oś Y jest odwrócona: Y wskazuje w górę.
Oznacza to, że punkt początkowy, czyli (0,0), znajduje się w lewym dolnym rogu kontekstu WebGL, a nie w lewym górnym, jak ma to miejsce w 2D Canvas.
Współrzędne tekstur podlegają tej zasadzie, co na początku może być nieintuicyjne.
## I to wszystko!
Oczywiście moglibyśmy zagłębić się w różne koncepcje, ale jak wspomniano wcześniej, chodziło o to, aby dać WIELKI UŚCISK nowoprzybyłym.
To sporo materiału do przyswojenia, ale z cierpliwością i praktyką stanie się to coraz bardziej naturalne.
Mam nadzieję, że część z tego okaże się przydatna. A teraz, co powiesz na rozpoczęcie swojej podróży przez tę książkę?
---
### Appendix/04/README Ru (appendix/04/README-ru.md)
## Введение для JavaScript-программистов
автор [Николя Баррадо](http://www.barradeau.com/)
Если вы JavaScript-разработчик, велика вероятность, что вы будете немного озадаченЫ, читая эту книгу. В самом деле, есть множество различий между манипулированием высокоуровневыми абстракциями на JS и ковырянием в шейдерах. Но, в отличие от лежащего на более низком уровне языка ассемблера, GLSL является человекочитаемым, и я уверен, что разобравшись с его особенностями, вы быстро сможете начать его использовать.
Я предполагаю, что у вас есть хотя бы поверхностные знания JavaScript и Canvas API. Если это не так - ничего страшного. Вам всё равно будет интересно читать большую часть этой главы.
Так же, я не буду сильно углубляться в детали, и некоторые вещи могут быть лишь _полуправдой_. Эта глава не является подробным руководством.
JavaScript очень хорош для быстрого прототипирования. Вы можете беспорядочно набросать кучу нетипизированных переменных и методов, динамически добавлять и удалять члены класса, обновить страницу и увидеть как она работает. Затем сделать изменения в соответствии с увиденным, обновить страницу, повторить. Жизнь - простая штука. Так в чём же разница между JavaScript и GLSL? Они оба работают в браузере, оба используются для рисования всяких прикольных штук на экране, и к тому же, JS проще в использовании.
ОСновная разница в том, что JavaScript - **интерпретируемый** язык, в то время как GLSL - **компилируемый**. **Скомпилированная** программа исполняется нативно, она является низкоуровневой и в целом высокопроизводительна. **Интерпретируемая** программа требует [виртуальную машину](https://ru.wikipedia.org/wiki/%D0%92%D0%B8%D1%80%D1%82%D1%83%D0%B0%D0%BB%D1%8C%D0%BD%D0%B0%D1%8F_%D0%BC%D0%B0%D1%88%D0%B8%D0%BD%D0%B0) для своего исполнения, является высокоуровневой и в общем случае более медленной.
Когда браузер (_**виртуальная машина** JavaScript_) **исполняет** или **интерпретирует** кусок кода на JS, он не имеет ни малейшего понятия чем является каждая переменная и что делает каждая функция (за исключением **типизированных массивов**). Поэтому он не может оптимизировать что-либо _наперёд_. Чтение кода браузером занимает какое-то время, чтобы **вывести** (исходя из использования) типы переменных и методов, и, по возможности, преобразовать _часть_ кода в ассемблер, который будет исполняться намного быстрее.
Это медленный, болезненный и до сумасшествия сложный процесс. Если вам интересны подробности, рекомендую посмотреть как [работает движок V8 в Хроме](https://developers.google.com/v8/). Хуже всего то, что браузер оптимизирует JS как ему хочется, и этот процесс _скрыт_ от программиста. Вы бессильны.
**Компилируемая** программа не интерпретируется на ходу. Её запускает операционная система, и она исполняется, если она корректна. Это многое меняет. Если вы забудете точку с запятой в конце строки, ваш код станет некорректным и просто не скомпилируется. Он вообще не превратится в программу.
Это сурово, но это то, чем является **шейдер**: _компилируемая программа для исполнения на GPU_. Не пугайтесь! **Компилятор**, то есть та программа которая проверяет ваш код на корректность, станет вашим лучшим другом. Примеры и [редактор](http://editor.thebookofshaders.com/) в этой книге очень дружественны к пользователю. Она подскажут в каком месте программа не скомпилировалась, и когда после всех правок шейдер будет готов к компиляции, результат его работы будет немедленно отображён. Это отличный способ обучения в силу его наглядности и невозможности что-либо сломать.
И последнее: **шейдер** состоит из двух программ: **вершинного** и **фрагментного** шейдера. Вкратце, вершинный шейдер (первая программа) принимает на вход и преобразовывет *геометрию*, которая затем превращается в последовательность **пикселей** (или **фрагментов**), поступающих на вход второго шейдера. И уже второй шейдер решает в какой цвет нужно покрасить пиксели. Эта книга посвящена именно вторым шейдерам. Во всех примерах геометрия - это прямоугольник, покрывающий всю доступную область.
Готовы?
Поехали!
### Сильная типизация
Когда вы приходите с JS или любого другого нетипизированного языка, **типизирование** переменных является для вас чужеродной концепцией, и это станет сложнейшим шагом при переходе к GLSL. **Типизация**, как легко догадаться, означает, что вам придётся давать **тип** каждой переменной и функции. Отсюда следует, что ключевого слова **`var`** больше не существует. Считайте, что полиция мыслей от GLSL стёрла его из общеупотребимого языка и вы больше не можете его произносить потому что, ну... его не существует.
Вместо использования волшебного слова **`var`** вам придётся _явно указывать тип каждой переменной_, тогда компилятор увидит те объекты и примитивы, с которыми он умеет эффективно обращаться. Обратная сторона невозможности использования ключевого слова **`var`** заключается в том, что вам нужно очень хорошо знать особенности типов всех переменных. Но поверьте, типов в GLSL немного, и они все достаточно просты (GLSL - не Java-фреймворк).
Всё это может выглядеть пугающе, но всё же это не сильно отличается от того, что вы обычно делаете на JS. Например, если переменная булева, то в ней может храниться только `true` или `false`. Если переменная называется `var uid = XXX;`, то в ней вероятно хранится целочисленное значение. Если же она объявлена как `var y = YYY;`, то это _возможно_ ссылка на значение с плавающей точкой. Что ещё лучше, при использовании сильных типов вам не придётся гадать что означает `X == Y`, и означает ли это `typeof X == typeof Y`, или `typeof X !== null && Y...`. В любом случае, вы *знаете* что здесь написано, а если и не знаете, то компилятор знает точно.
Перечислим **скалярные типы** языка GLSL (**скаляр** описывает количество): `bool` (булев тип), `int` (целочисленный) и `float` (значения с плавающей точкой). Есть и другие типы, но пока давайте рассмотрим как объявляются переменные в GLSL:
```glsl
// булево значение
JS: var b = true; GLSL: bool b = true;
// целое значение
JS: var i = 1; GLSL: int i = 1;
// число с плавающей точкой
JS: var f = 3.14159; GLSL: float f = 3.14159;
```
Не очень трудно, правда? Как было замечено выше, такой подход делает программирование проще, так как вы не тратите время на выслеживание типа какой-либо переменной. Всё ещё сомневаетесь? Помните, что это так же делается для того, чтобы ваша программа исполнялась в разы быстрее, чем на JS.
#### void
В GLSL есть тип `void`, который приблизительно соответствует `null`. Он используется в качестве возвращаемого типа для метода, который не возвращает ничего, и вы не можете объявить переменную этого типа.
#### boolean
Как вам известно, булевы значения в основном используются для проверки условий: `if( myBoolean == true ){}else{}`. Условное ветвление очень легко использовать на CPU, но [параллельная природа](http://thebookofshaders/01/?lan=ru) GLSL делает это утверждение не совсем верным. Как правило, использование условных переходов не рекомендуется, и в книге описано несколько способов обойти это ограничение.
#### приведение типов
Как говорил [Боромир](https://ru.wikipedia.org/wiki/%D0%91%D0%BE%D1%80%D0%BE%D0%BC%D0%B8%D1%80), нельзя просто так взять и смешать типизированные примитивы. В отличие от JavaScript, GLSL не позволит вам выполнять операции между переменными различных типов.
Например вот это:
```glsl
int i = 2;
float f = 3.14159;
// попытка умножить целое на значение с плавающей точкой
float r = i * f;
```
не будет работать, потому что вы пытаетесь скрестить **_кошку_** с **_жирафом_**. Проблема решается с помощью **приведения типов**, которое _заставит компилятор поверить_, что *`i`* имеет тип `float`, не меняя фактический тип *`i`*.
```glsl
//приведение типа целочисленной переменной 'i' к float
float r = float( i ) * f;
```
Это в точности как переодевание **_кошки_** в **шкуру _жирафа_**, которое будет работать как и ожидается: в `r` сохранится результат умножения `i` x `f`.
Любой из упомянутых выше типов можно **привести** к любому другому. При этом приведение `float` к `int` будет работать как `Math.floor()`, удаляя числа справа от запятой. Приведение `float` или `int` к булеву типу вернёт `true` если переменная не равна нулю.
#### конструктор
**Типы** переменных так же являются **конструкторами классов** для самих себя. Фактически, переменную типа `float` можно представлять как _`экземпляр`_ класса _`float`_.
Следующие объявления равнозначны:
```glsl
int i = 1;
int i = int( 1 );
int i = int( 1.9995 );
int i = int( true );
```
Для `скалярных` типов это выглядит весьма тривиально, не особо отличаясь от **приведения**, но в этом появится больше смысла когда мы дойдём до раздела о *перегрузках*.
Итак, мы изучили три `примитивных типа`, без которых невозможно обойтись, но в GLSL есть и другие.
### Векторы
Как и JavaScript, в GLSL вам понадобятся более продвинутые способы для манипуляции данными, и здесь **`векторы`** будт очень кстати. Я предполагаю, что вам доводилось писать на JS класс `Point`, который содержит значения `x` и `y`, и выглядит как-то так:
```glsl
// определение:
var Point = function( x, y ){
this.x = x || 0;
this.y = y || 0;
}
// объявление экземпляра:
var p = new Point( 100,100 );
```
Как мы только что видели, этот код жутко неправилен на всех уровнях. Во-первых, это ключевое слово **`var`**, затем это ужасающее **`this`** и **нетипизированные** значения `x` и `y`... Нет, такое явно не будет работать в мире шейдеров.
Вместо этого GLSL предоставляет встроенные структуры для группировки данных:
* `bvec2`: 2D булев вектор, `bvec3`: 3D булев вектор, `bvec4`: 4D булев вектор
* `ivec2`: 2D целочисленный вектор, `ivec3`: 3D целочисленный вектор, `ivec4`: 4D целочисленный вектор
* `vec2`: 2D вектор с плавающей точкой, `vec3`: 3Dвектор с плавающей точкой, `vec4`: 4D вектор с плавающей точкой
Вдумчивый читатель заметит, что каждому примитивному типу соответствует **векторный** тип. Из написанного выше легко вывести, что `bvec2` содержит два булевых значения, а `vec4` будет содержать четыре значения в плавающей точкой.
Так же векторы вводят такую величину, как размерность. Это не означает, что вы должны использовать 2D-вектор при отрисовке 2D-графики и 3D при рисовании 3D-изображений. Для чего в таком случае используется четырёхмерный вектор? (ну, на самом деле это называется «тессеракт» или «гиперкуб»)
Нет, **размерность** указывает на количество **компонентов** или **переменных**, хранимых в **векторе**:
```glsl
// объявляем двумерный булев вектор
bvec2 b2 = bvec2 ( true, false );
// объявляем трёхмерный целочисленный вектор
ivec3 i3 = ivec3( 0,0,1 );
// объявляем четырёхмерный вектор значений с плавающей запятой
vec4 v4 = vec4( 0.0, 1.0, 2.0, 1. );
```
`b2` содержит два различных булевых значения, `i3` содержит 3 различных целых, а `v4` содержит 4 различных значения с плавающей точкой.
Но как обратиться к этим значениям?
В случае скаляров ответ очевиден: при объявлении `float f = 1.2;` переменная `f` содержит значение `1.2`. Для **векторов** всё немного по-другому и выглядит это довольно красиво.
#### доступ к элементам векторов
Есть несколько способов доступа к значениям
```glsl
// объявим четырёхмерный вектор значений с плавающей точкой
vec4 v4 = vec4( 0.0, 1.0, 2.0, 3.0 );
```
четыре его значения можно извлечь следующим образом
```glsl
float x = v4.x; // x = 0.0
float y = v4.y; // y = 1.0
float z = v4.z; // z = 2.0
float w = v4.w; // w = 3.0
```
легко и просто. Ниже приведены равнозначные способы доступа к данным:
```glsl
float x = v4.x = v4.r = v4.s = v4[0]; // x = 0.0
float y = v4.y = v4.g = v4.t = v4[1]; // y = 1.0
float z = v4.z = v4.b = v4.p = v4[2]; // z = 2.0
float w = v4.w = v4.a = v4.q = v4[3]; // w = 3.0
```
Вдумчивый читатель заметил три факта:
* `X`, `Y`, `Z` и `W` как правило используются в программах для представления векторов в пространстве
* `R`, `G`, `B` и `A` используются для кодирования цвета и альфа-канала
* `[0]`, `[1]`, `[2]` и `[3]` означают, что векторы являются массивами с произвольным доступом
В зависимости от того, работаете ли вы с двух- или трёхмерными координатами, цветом с альфа-каналом или без такового, или просто какими-то произвольными значениями, вы можете выбрать наиболее подходящий тип и размерность вектора. Обычно координаты и векторы (в геометрическом смысле слова) хранятся как `vec2`, `vec3` или `vec4`, цвета как `vec3` или `vec4`, но в целом никаких ограничений на использование переменных нет. Например, никто не запрещает вам хранить единственное булево значение как `bvec4`, но это приведёт в излишнему расходу памяти.
**Заметим**, что в шейдерах значения цвета (`R`, `G`, `B`, `A`) нормализованы, то есть лежат в диапазоне от 0 до 1, а не от 0 до 0xFF, поэтому для них лучше использовать вещественный тип `vec4`, а не целочисленный `ivec4`.
Уже лучше, но мы идём далее!
#### перемешивание
Из вектора можно извлечь несколько значений одновременно. Например, если вам нужны только `X` и `Y` из `vec4`, на JavaScript вы бы написали что-то вроде этого:
```glsl
var needles = [0, 1]; // размещение 'x' и 'y' в структуре данных
var a = [ 0,1,2,3 ]; // структура данных 'vec4'
var b = a.filter( function( val, i, array ) {
return needles.indexOf( array.indexOf( val ) ) != -1;
});
// b = [ 0, 1 ]
// или более буквально:
var needles = [0, 1];
var a = [ 0,1,2,3 ]; // структура 'vec4'
var b = [ a[ needles[ 0 ] ], a[ needles[ 1 ] ] ]; // b = [ 0, 1 ]
```
Выглядит уродливо. В GLSL данные можно извлечь вот так:
```glsl
// создаём четырёхмерный вектор с плавающей запятой
vec4 v4 = vec4( 0.0, 1.0, 2.0, 3.0 );
// и извлекаем только X и Y
vec2 xy = v4.xy; // xy = vec2( 0.0, 1.0 );
```
Что это было?! Когда вы составляете воедино методы доступа к полям, GLSL изящно возвращает запрошенное подмножество в виде значения наиболее подходящего типа. Это возможно, потому что вектор является структурой данных с произвольным доступом, прямо как массив в javaScript. Поэтому, можно не только обратиться к подмножеству данных вектора, но и указать **порядок**, в котором нужно обращаться. Следующий код обратит порядок компонентов вектора:
```glsl
// создаём четырёхкомпонентный вектор R,G,B,A
vec4 color = vec4( 0.2, 0.8, 0.0, 1.0 );
// и извлекаем компоненты цвета в порядке A,B,G,R
vec4 backwards = v4.abgr; // backwards = vec4( 1.0, 0.0, 0.8, 0.2 );
```
И конечно же, к одной компоненте можно обратиться многократно:
```glsl
// создаём четырёхкомпонентный вектор R,G,B,A
vec4 color = vec4( 0.2, 0.8, 0.0, 1.0 );
// и извлекаем vec3 с компонентами GAG на основе каналов G и A исходного цвета
vec3 GAG = v4.gag; // GAG = vec4( 0.8, 1.0, 0.8 );
```
Очень удобно составлять части вектора воедино, извлекать только rgb-компоненты из вектора цвета с прозрачностью и т.п.
#### перегрузим всё!
В разделе о типах я упоминал упоминал **конструкторы** и ещё одно великолепное свойство языка GLSL - **перегрузку**. **Перегрузка** оператора или функции означает _изменение поведения этого оператора или функции в зависимости от операндов/аргументов_. В JavsScript нет перегрузки, поэтому вначале она может показаться вам странной, но немного попользовавшись ей, вы зададитесь вопросом, почему же она не реализована в JavaScript (краткий ответ - *типизация*).
Рассмотрим простейший пример перегрузки:
```glsl
vec2 a = vec2( 1.0, 1.0 );
vec2 b = vec2( 1.0, 1.0 );
// перегруженное сложение
vec2 c = a + b; // c = vec2( 2.0, 2.0 );
```
ШТОА? Можно складывать сущности, не являющиеся числами?!
Именно. И конечно же, это применимо ко всем операторам (`+`, `-`, `*` и `/`), и это только начало.
Рассмотрим фрагмент кода:
```glsl
vec2 a = vec2( 0.0, 0.0 );
vec2 b = vec2( 1.0, 1.0 );
// перегруженный конструктор
vec4 c = vec4( a , b ); // c = vec4( 0.0, 0.0, 1.0, 1.0 );
```
Мы соорудили `vec4` из двух `vec2`, используя `a.x` и `a.y` в качестве компонент `X` и `Y` для нового вектора `c`. Затем мы взяли `b.x` и `b.y` в качестве `Z` и `W` для `c`.
Так работает перегрузка функции по набору параметров, в данном случае это **конструктор** `vec4`. Это означает, что несколько **версий** одного и того же метода с различными наборами параметров могут мирно сосуществовать в одной программе. Например, все следующие объявления корректны:
```glsl
vec4 a = vec4(1.0, 1.0, 1.0, 1.0);
vec4 a = vec4(1.0);// x, y, z, w all equal 1.0
vec4 a = vec4( v2, float, v4 );// vec4( v2.x, v2.y, float, v4.x );
vec4 a = vec4( v3, float );// vec4( v3.x, v3.y, v3.z, float );
etc.
```
От вас требуется только подать достаточное количество параметров для заполнения **вектора**.
Наконец, вы можете перегружать встроенные функции для тех типов аргументов, для которых они не были изначально задуманы (но лучше не делать этого слишком часто).
#### нужно больше типов
Векторы прикольные. Они - мышцы вашего шейдера. Но есть и другие типы, например матрицы и текстурные семплеры, о которых будет рассказано ниже.
В GLSL есть массивы. Конечно же, они типизированные, и у них есть несколько отличий от массивов в JS:
* у них фиксированный размер
* вы не можете использовать push(), pop(), splice() и т.п., свойство ```length``` тоже отсутствует
* их нельзя инициализировать значениями при объявлении
* значения нужно задавать по одному
вот это работать не будет:
```glsl
int values[3] = [0,0,0];
```
а вот это заработает:
```glsl
int values[3];
values[0] = 0;
values[1] = 0;
values[2] = 0;
```
Этого хватает, если вы знаете все ваши данные или работаете с небольшими массивами данных. Если вам нужно больше выразительности, вы можете использовать структуры (```struct```). Они похожи на _объекты_ без методов. Они позволяют хранить несколько переменных в одном объекте:
```glsl
struct ColorStruct {
vec3 color0;
vec3 color1;
vec3 color2;
}
```
например, вы можете задавать и извлекать значения _цвета_ следующим образом:
```glsl
// инициализируем структуру
ColorStruct sandy = ColorStruct( vec3(0.92,0.83,0.60),
vec3(1.,0.94,0.69),
vec3(0.95,0.86,0.69) );
// получем доступ к значениям
sandy.color0 // vec3(0.92,0.83,0.60)
```
Это синтаксический сахар, но он может помочь вам писать более чистый, или как минимум более привычный код.
#### выражения и условия
Структуры данных очень полезны, но рано или поздно нам _возможно_ понадобится проходить по массиву или выполнять проверку условия. К счастью, синтаксис для этого очень близок к JavaScript.
Условие выглядит так:
```glsl
if( condition ){
//true
}else{
//false
}
```
Цикл `for` выглядит так:
```glsl
const int count = 10;
for( int i = 0; i <= count; i++){
//do something
}
```
пример переменной цикла с плавающей точкой:
```glsl
const float count = 10.;
for( float i = 0.0; i <= count; i+= 1.0 ){
//do something
}
```
Заметим, что ```count``` должна быть объявлена константой. Это означает, что перед её объявлением должен быть **квалификатор** ```const```, который будет рассмотрен чуть ниже.
Так же нам доступны ключевые слова ```break``` и ```continue```:
```glsl
const float count = 10.;
for( float i = 0.0; i <= count; i+= 1.0 ){
if( i < 5. )continue;
if( i >= 8. )break;
}
```
Имейте ввиду, что на некоторых типах оборудования ```break``` не работает ожидаемым образом и не прерывает цикл заранее.
В целом, старайтесь делать количество итераций как можно меньше, и избегайте циклов и ветвлений как можно чаще.
#### квалификаторы
Помимо типов переменных в GLSL есть **квалификаторы**. Вкратце, квалификаторы сообщают компилятору какая переменная для чего предназначена. Например, некоторые данные для GPU могут приходить только со стороны CPU. Такие данные называются **атрибутами** и **юниформами**. **Атрибуты** встречаются только в вершинных шейдерах, а **юниформы** - и в вершинных, и во фрагментных. Так же есть квалификатор ```varying```, используемый для передачи переменных от вершинного шейдера к фрагментному.
Я не буду сильно углубляться в подробности, ибо мы в основном рассматриваем **фрагментные шейдеры*, но далее в книге вам возможно встретится что-то вроде
```glsl
uniform vec2 u_resolution;
```
Что здесь происходит? Мы задали квалификатор ```uniform``` перед типом переменной, указав, что разрешение изображения передаётся в шейдер из CPU. Ширина изображения находится в `x`-компоненте 2D-вектора, а высота - в `y`-компоненте.
Когда компилятор видит переменную, объявленную с этим квалификатором, он сделает чтобы вы не могли *записать* это значение в рантайме.
То же самое применимо к переменной ```count```, которая была пороговым значением в цикле ```for```:
```glsl
const float count = 10.;
for( ... )
```
Когда мы используем квалификатор ```const```, компилятор не даёт нам перезаписать значение, которое в противном случае не было бы константой.
Ещё три квалификатора используются в сигнатурах функций: ```in```, ```out``` и ```inout```. В JavaScript переданные в функцию аргументы предназначены только для чтения. Их изменение внутри функции не приводит к изменению значений за её пределами.
```glsl
function banana( a ){
a += 1;
}
var value = 0;
banana( value );
console.log( value );// > 0 ; значение за пределами функции не изменилось
```
Используя квалификаторы аргументов, можно изменять их поведение:
* ```in``` предназначен только для чтения (по умолчанию)
* ```out``` только для записи: значение такого аргумента нельзя прочитать, но можно записать
* ```inout``` чтение и запись
Перепишем упомянутый выше метод на GLSL:
```glsl
void banana( inout float a ){
a += 1.;
}
float A = 0.;
banana( A ); // теперь A = 1.;
```
Это поведение сильно отличается от JS и даёт множество возможностей. При этом, не обязательно всегда указывать квалификаторы аргументов. По умолчанию аргументы предназначены только для чтения.
#### пространство и координаты
Напоследок заметим, что в DOM и Canvas 2D ось Y направлена вниз. Это имеет смысл в контексте DOM, ибо соответствует тому, как свёрстана web-страница: навигационная панель наверху, а контент прокручивается вниз. В webgl-элементе ось Y перевёрнута и указывает вверх.
Это означает, что начало координат (точка (0,0)) расположено в левом нижнем, а не в левом верхнем углу контекста. Текстурные координаты так же следуют этому правилу, которое на первый взгляд кажется контринтуитивным.
## На этом всё!
Конечно, мы могли мы углубиться во всяческие детали, но, как было сказано вначале, эта статья писалась как простое введение для новичков. Здесь уже написано достаточно, чтобы переваривать это некоторое время, но с терпением и практикой этот язык будет становиться всё более естественным для вас.
Надеюсь, этот текст был полезен, а потому самое время приступить к основному содержимому книги!
---
### Appendix/04/README Tr (appendix/04/README-tr.md)
## JS'den gelenler için bir giriş
yazan [Nicolas Barradeau](http://www.barradeau.com/)
Eğer bir JavaScript geliştiricisiyseniz, bu kitabı okurken biraz şaşıracaksınız.
Aslında, üst düzey JS'yi manipüle etmek ile shader'larla uğraşmak arasında birçok fark var.
Yine de, altta yatan assembly diline kıyasla GLSL insan tarafından okunabilir ve eminim ki özelliklerini kabul ettikten sonra kısa sürede çalışmaya başlayacaksınız.
JavaScript hakkında önceden (yüzeysel de olsa) bir bilginiz olduğunu varsayıyorum, ama aynı zamanda Canvas API hakkında da.
Değilse, endişelenmeyin, bu bölümün çoğunu yine de anlayabileceksiniz.
Ayrıca çok fazla detaya girmeyeceğim ve bazı şeyler _yarı doğru_ olabilir, "kesin bir kılavuz" beklemeyin, daha çok
### BÜYÜK BİR KUCAKLAMA
JavaScript hızlı prototipleme için harikadır; bir yığın rastgele, tipsiz değişken ve metot fırlatırsınız, dinamik olarak sınıf üyelerini ekleyebilir ve kaldırabilirsiniz, sayfayı yenilersiniz ve çalışıp çalışmadığını görürsünüz,
buna göre değişiklikler yaparsınız, sayfayı yenilersiniz, tekrarlarsınız, hayat kolaydır.
Bu yüzden JavaScript ile GLSL arasındaki farkın ne olduğunu merak edebilirsiniz.
Sonuçta, ikisi de tarayıcıda çalışır, ikisi de ekranda bir sürü eğlenceli şey çizmek için kullanılır ve bu açıdan JS kullanımı daha kolaydır.
Asıl fark, JavaScript'in **yorumlanan** bir dil olması, GLSL'nin ise **derlenen** bir dil olmasıdır.
**Derlenen** bir program işletim sisteminde yerel olarak çalışır, düşük seviyelidir ve genellikle hızlıdır.
**Yorumlanan** bir program çalıştırılmak için bir [Sanal Makine](https://en.wikipedia.org/wiki/Virtual_machine) (VM) gerektirir, yüksek seviyelidir ve genellikle yavaştır.
Bir tarayıcı (_JavaScript **VM**'si_) bir JS parçasını **çalıştırdığında** veya **yorumladığında**, hangi değişkenin ne olduğu ve hangi fonksiyonun ne yaptığı hakkında hiçbir fikri yoktur (dikkate değer istisna **TypedArrays**).
Bu nedenle _önceden_ hiçbir şeyi optimize edemez, bu yüzden kodunuzu okumak, değişkenlerinizin ve metotlarınızın türlerini **çıkarmak** (kullanımdan türetmek) için biraz zaman alır
ve mümkün olduğunda, kodunuzun _bir kısmını_ çok daha hızlı çalışacak assembly koduna dönüştürür.
Yavaş, zahmetli ve çılgınca karmaşık bir süreçtir, detaylarla ilgileniyorsanız, [Chrome'un V8 motorunun nasıl çalıştığını](https://developers.google.com/v8/) izlemenizi öneririm.
En kötüsü, her tarayıcının JS'yi kendi yöntemiyle optimize etmesidir ve süreç sizden _gizlenir_; çaresizsiniz.
**Derlenen** bir program yorumlanmaz; işletim sistemi onu çalıştırır, program geçerliyse çalışır.
Bu büyük bir değişiklik; satır sonundaki noktalı virgülü unutursanız, kodunuz geçersizdir, derlenmez: kodunuz hiçbir şekilde programa dönüşmez.
Bu soğuktur ama bir **shader** budur: _GPU üzerinde çalıştırılan derlenmiş bir program_.
Korkmayın! Kodunuzun geçerli olduğundan emin olan bir **derleyici** en iyi arkadaşınız olacak.
Bu kitabın örnekleri ve [eşlikçi editör](http://editor.thebookofshaders.com/) çok kullanıcı dostudur.
Programınızın nerede ve neden derlenemediğini söylerler, ardından düzeltmeniz gerekir ve shader derlenmeye hazır olduğunda anında görüntülenir.
Bu, çok görsel olduğu ve gerçekten hiçbir şeyi bozamayacağınız için öğrenmenin harika bir yoludur.
Son not, bir **shader** 2 programdan oluşur: **vertex shader** ve **fragment shader**.
Kısaca, **vertex shader**, birinci program, girdi olarak bir *geometri* alır ve onu **piksel** (veya *fragment*) serilerine dönüştürür, ardından bunları
**fragment shader**'a, ikinci programa teslim eder, bu da pikselleri hangi renge boyayacağına karar verir.
Bu kitap ağırlıklı olarak ikincisine odaklanır, tüm örneklerde geometri tüm ekranı kaplayan basit bir dörtgendir.
PEKALA! hazır mısınız?
başlayalım!
### Güçlü tipler
JS veya herhangi bir tipsiz dilden geliyorsanız, değişkenlerinizi **tiplemek** yabancı bir kavramdır, bu da **tiplemeyi** GLSL'ye doğru atılacak en zor adım yapar.
**Tipleme**, adından da anlaşılacağı gibi, değişkenlerinize (ve tabii ki fonksiyonlarınıza) bir **tip** vereceğiniz anlamına gelir.
Bu temelde **`var`** kelimesinin artık var olmadığı anlamına gelir.
GLSL düşünce polisi onu ortak dilden sildi ve siz onu söyleyemezsiniz çünkü, şey... var olmuyor.
Sihirli **`var`** kelimesini kullanmak yerine, _kullandığınız her değişkenin tipini açıkça belirtmeniz_ gerekecek, sonra derleyici yalnızca nasıl verimli bir şekilde ele alacağını bildiği nesneleri ve temel türleri görecektir.
**`var`** anahtar kelimesini kullanamadığınızda ve _her şeyi belirtmeniz_ gerektiğinde dezavantaj, tüm değişkenlerin tipini bilmeniz ve onları iyi bilmeniz gerektiğidir.
Emin olun, sayıları az ve oldukça basitler (GLSL bir Java framework'ü değildir).
Kulağa korkutucu gelebilir ama sonuçta, JavaScript kodlarken yaptığınızdan çok farklı değil; bir değişken `boolean` ise, `true` veya `false` saklamasını beklersiniz ve başka bir şey değil.
Bir değişken `var uid = XXX;` olarak adlandırılmışsa, büyük olasılıkla içinde bir tam sayı değeri saklayacaksınız ve `var y = YYY;` bir kayan noktalı değere referans _olabilir_.
Daha da iyisi, **güçlü tipler** ile `X == Y` mi (yoksa `typeof X == typeof Y` mi? .. yoksa `typeof X !== null && Y...` ... neyse) diye zaman kaybetmezsiniz; sadece *bilirsiniz* ve bilmezseniz, derleyici bilir.
İşte GLSL'de kullanabileceğiniz **skaler tipler** (bir **skaler** bir miktarı tanımlar): `bool` (Boolean), `int`(Tam sayı), `float`(kayan noktalı Sayı).
Başka tipler de var ama sakin olalım, aşağıdaki snippet GLSL'de **`var`**'ların (evet, yasak kelimeyi söyledim) nasıl tanımlanacağını gösterir:
```glsl
//bir Boolean değeri:
JS: var b = true; GLSL: bool b = true;
//bir Tam sayı değeri
JS: var i = 1; GLSL: int i = 1;
//bir Float değeri (bir Sayı)
JS: var f = 3.14159; GLSL: float f = 3.14159;
```
Çok zor değil, değil mi? yukarıda belirtildiği gibi, verilen bir değişkenin tipini kontrol etmekle zaman kaybetmediğiniz için işleri kolaylaştırır bile.
Şüpheye düştüğünüzde, bunu programınızın JS'den çok daha hızlı çalışması için yaptığınızı hatırlayın.
#### void
Kabaca `null`'a karşılık gelen bir `void` tipi vardır, hiçbir şey döndürmeyen bir metodun dönüş tipi olarak kullanılır.
Bir değişkene atayamazsınız.
#### boolean
Bildiğiniz gibi, Boolean'lar çoğunlukla koşullu testlerde kullanılır; `if( myBoolean == true ){}else{}`.
Koşullu dallanma CPU'da geçerli bir seçenek olsa da, GLSL'nin [paralel doğası](http://thebookofshaders/01/) bunu daha az doğru kılar.
Koşullu ifadelerin kullanımı çoğu zaman önerilmez bile, kitap bunu çözmek için birkaç alternatif teknik açıklar.
#### tip dönüştürme
[Boromir](https://en.wikipedia.org/wiki/Boromir)'in dediği gibi, "İnsan Tiplenmiş temel türleri kolayca birleştiremez". JavaScript'in aksine, GLSL farklı tipteki değişkenler arasında işlem yapmanıza izin vermez.
Örneğin:
```glsl
int i = 2;
float f = 3.14159;
//bir tam sayıyı bir float değerle çarpmaya çalışmak
float r = i * f;
```
düzgün çalışmayacaktır çünkü bir **_kedi_** ile bir **_zürafayı_** çaprazlamaya çalışıyorsunuz.
Bunun çözümü **tip dönüştürme** kullanmaktır; bu, *`i`*'nin aslında tipini değiştirmeden _derleyicinin `i`'nin `float` tipinde olduğuna inanmasını sağlar_.
```glsl
//'i' tam sayı değişkeninin tipini float'a dönüştürme
float r = float( i ) * f;
```
Bu, bir **_kediyi_** **_zürafa kostümüne_** sokmakla kesinlikle eşdeğerdir ve beklendiği gibi çalışacaktır ( `r`, `i` x `f`'nin sonucunu saklayacaktır).
Yukarıdaki tiplerin herhangi birini başka herhangi bir tipe **dönüştürmek** mümkündür, `float`'ı `int`'e dönüştürmenin `Math.floor()` gibi davranacağını, kayan noktadan sonraki değerleri kaldıracağını not edin.
Bir `float` veya `int`'i `bool`'a dönüştürmek, değişken sıfıra eşit değilse `true` döndürür.
#### yapıcı
Değişken **tipleri** aynı zamanda kendi **sınıf yapıcılarıdır**; aslında bir `float` değişkeni, bir _`Float`_ sınıfının _`örneği`_ olarak düşünülebilir.
Bu tanımlamalar eşit derecede geçerlidir:
```glsl
int i = 1;
int i = int( 1 );
int i = int( 1.9995 );
int i = int( true );
```
Bu, `skaler` tipler için çok anlam ifade etmeyebilir, **tip dönüştürmeden** çok farklı değildir, ancak *aşırı yükleme* bölümüne değinirken mantıklı olacaktır.
Tamam, bunlar 3 `temel tür`, onsuz yaşayamayacağınız şeyler ama elbette GLSL'nin sunacağı daha fazlası var.
### Vektörler
JavaScript'te olduğu gibi GLSL'de de verileri işlemenin daha karmaşık yollarına ihtiyacınız olacak, işte burada **`vektörler`** devreye girer.
JavaScript'te bir `x` ve `y` değerini bir arada tutmak için bir `Point` sınıfı kodladığınızı varsayıyorum, bunun kodu şöyle olurdu:
```glsl
// 'sınıf' tanımı:
var Point = function( x, y ){
this.x = x || 0;
this.y = y || 0;
}
//ve şöyle örneklendirirdiniz:
var p = new Point( 100,100 );
```
Az önce gördüğümüz gibi, bu PEKÇOK seviyede ÇOK yanlış! Bir kere o **`var`** anahtar kelimesi, sonra korkunç **`this`**, sonra yine **tipsiz** `x` ve `y` değerleri...
Hayır, bu shader dünyasında işe yaramayacak.
Bunun yerine, GLSL verileri bir arada tutmak için yerleşik veri yapıları sunar:
* `bvec2`: 2B Boolean vektör, `bvec3`: 3B Boolean vektör, `bvec4`: 4B Boolean vektör
* `ivec2`: 2B Tam sayı vektör, `ivec3`: 3B Tam sayı vektör, `ivec4`: 4B Tam sayı vektör
* `vec2`: 2B Float vektör, `vec3`: 3B Float vektör, `vec4`: 4B Float vektör
Her temel tür için bir tür **vektör** olduğunu hemen fark ettiniz, zeki tavşan.
Az önce gördüklerimizden, bir `bvec2`'nin iki `bool` tipi değer ve bir `vec4`'ün dört `float` değer tutacağını çıkarabilirsiniz.
Vektörlerin tanıttığı bir diğer şey **boyut** sayısıdır, bu 2B grafik render ederken 2B vektör ve 3B yaparken 3B vektör kullanıldığı anlamına gelmez.
O zaman 4B vektör neyi temsil eder? (aslında buna tesseract veya hiperküp denir)
Hayır, **boyutlar** **vektörde** saklanan **bileşenlerin** veya **değişkenlerin** sayısını ve tipini temsil eder:
```glsl
// bir 2B Boolean vektör oluşturalım
bvec2 b2 = bvec2 ( true, false );
// bir 3B Tam sayı vektör oluşturalım
ivec3 i3 = ivec3( 0,0,1 );
// bir 4B Float vektör oluşturalım
vec4 v4 = vec4( 0.0, 1.0, 2.0, 1. );
```
`b2` iki farklı boolean değer, `i3` 3 farklı tam sayı değer ve `v4` 4 farklı float değer saklar.
ama bu değerleri nasıl alırız?
`skalerler` durumunda, cevap açıktır; `float f = 1.2;` ile, `f` değişkeni `1.2` değerini tutar.
**Vektörlerle** biraz farklı ve oldukça güzeldir.
#### erişimciler
Değerlere erişmenin farklı yolları var
```glsl
// bir 4B Float vektör oluşturalım
vec4 v4 = vec4( 0.0, 1.0, 2.0, 3.0 );
```
4 değeri almak için şunları yapabilirsiniz:
```glsl
float x = v4.x; // x = 0.0
float y = v4.y; // y = 1.0
float z = v4.z; // z = 2.0
float w = v4.w; // w = 3.0
```
güzel ve kolay; ama aşağıdakiler de verilerinize erişmenin eşit derecede geçerli yollarıdır:
```glsl
float x = v4.x = v4.r = v4.s = v4[0]; // x = 0.0
float y = v4.y = v4.g = v4.t = v4[1]; // y = 1.0
float z = v4.z = v4.b = v4.p = v4[2]; // z = 2.0
float w = v4.w = v4.a = v4.q = v4[3]; // w = 3.0
```
Ve zeki tavşan olarak zaten üç şeyi fark ettiniz:
* `X`, `Y`, `Z` & `W` 3B programlarda 3B vektörleri temsil etmek için kullanılır
* `R`, `G`, `B` & `A` renkleri ve alfa değerini kodlamak için kullanılır
* `[0]`, `[1]`, `[2]` & `[3]` rastgele erişimli bir değer dizimiz olduğu anlamına gelir
Yani 2B veya 3B koordinatları, alfa değeri olan veya olmayan bir rengi veya sadece bazı rastgele değişkenleri manipüle etmenize bağlı olarak, en uygun **vektör** tipini ve boyutunu seçebilirsiniz.
Tipik olarak 2B koordinatlar ve vektörler (geometrik anlamda) `vec2`, `vec3` veya `vec4` olarak, renkler opaklığa ihtiyacınız varsa `vec3` veya `vec4` olarak saklanır, ancak vektörlerin nasıl kullanılacağı konusunda kısıtlama yoktur.
Örneğin, bir `bvec4`'te sadece bir boolean değer saklamak isterseniz, mümkündür, sadece bellek israfıdır.
**not**: bir shader'da, renk değerleri (`R`, `G`, `B` & `A`) normalleştirilmiştir, 0 ile 1 arasında değişirler, 0 ile 0xFF arasında değil, bu yüzden onları saklamak için Tam sayı `ivec4` yerine Float `vec4` kullanmanız daha iyi olur.
Güzel, ama daha fazlası var!
#### swizzle
Aynı anda birden fazla değer döndürmek mümkündür; diyelim ki bir `vec4`'ün sadece `X` ve `Y` değerlerine ihtiyacınız var, JavaScript'te şöyle bir şey yazmanız gerekirdi:
```glsl
var needles = [0, 1]; // veri yapımızdaki 'x' & 'y'nin konumu
var a = [ 0,1,2,3 ]; // 'vec4' veri yapımız
var b = a.filter( function( val, i, array ) {
return needles.indexOf( array.indexOf( val ) ) != -1;
});
// b = [ 0, 1 ]
//veya daha gerçek anlamda:
var needles = [0, 1];
var a = [ 0,1,2,3 ]; // 'vec4' veri yapımız
var b = [ a[ needles[ 0 ] ], a[ needles[ 1 ] ] ]; // b = [ 0, 1 ]
```
Çirkin. GLSL'de şöyle alabilirsiniz:
```glsl
// bir 4B Float vektör oluştur
vec4 v4 = vec4( 0.0, 1.0, 2.0, 3.0 );
//ve sadece X & Y bileşenlerini al
vec2 xy = v4.xy; // xy = vec2( 0.0, 1.0 );
```
Ne oldu?! **Erişimcileri birleştirdiğinizde**, GLSL zarif bir şekilde istediğiniz değerlerin bir alt kümesini en uygun **vektör** formatında döndürür.
Gerçekten, vektör isterseniz JavaScript'teki bir dizi gibi **rastgele erişimli** bir veri yapısıdır.
Yani sadece verilerinizin bir alt kümesini almakla kalmaz, aynı zamanda ihtiyacınız olan **sırayı** da belirtebilirsiniz, bu bir vektörün bileşenlerinin değerlerini ters çevirecektir:
```glsl
// bir 4B Float vektör oluştur: R,G,B,A
vec4 color = vec4( 0.2, 0.8, 0.0, 1.0 );
//ve renk bileşenlerini A,B,G,R sırasında al
vec4 backwards = color.abgr; // backwards = vec4( 1.0, 0.0, 0.8, 0.2 );
```
Ve tabii ki aynı bileşeni birden fazla kez isteyebilirsiniz:
```glsl
// bir 4B Float vektör oluştur: R,G,B,A
vec4 color = vec4( 0.2, 0.8, 0.0, 1.0 );
//ve rengin G & A kanallarına dayalı bir GAG vec3 al
vec3 GAG = color.gag; // GAG = vec4( 0.8, 1.0, 0.8 );
```
Bu, vektörlerin parçalarını birleştirmek, bir RGBA rengin sadece rgb kanallarını çıkarmak vb. için son derece kullanışlıdır.
#### her şeyi aşırı yükle!
Tipler bölümünde **yapıcı** hakkında bir şey söylemiştim ve bu yine GLSL'nin harika bir özelliği; **aşırı yükleme**.
Bilmeyenler için, bir operatörü veya fonksiyonu **aşırı yüklemek** kabaca şu anlama gelir: _'söz konusu operatörün veya fonksiyonun davranışını operandlara/argümanlara göre değiştirmek'_.
JavaScript'te aşırı yüklemeye izin verilmez, bu yüzden başta biraz tuhaf gelebilir ama eminim alıştıktan sonra JS'de neden uygulanmadığını merak edeceksiniz (kısa cevap, *tipleme*).
Operatör aşırı yüklemenin en temel örneği şöyledir:
```glsl
vec2 a = vec2( 1.0, 1.0 );
vec2 b = vec2( 1.0, 1.0 );
//aşırı yüklenmiş toplama
vec2 c = a + b; // c = vec2( 2.0, 2.0 );
```
NE? Yani sayı olmayan şeyleri toplayabilir misiniz?!
Evet, kesinlikle. Tabii ki bu tüm operatörler (`+`, `-`, `*` & `/`) için geçerlidir ama bu sadece başlangıç.
Aşağıdaki parçayı düşünün:
```glsl
vec2 a = vec2( 0.0, 0.0 );
vec2 b = vec2( 1.0, 1.0 );
//aşırı yüklenmiş yapıcı
vec4 c = vec4( a , b ); // c = vec4( 0.0, 0.0, 1.0, 1.0 );
```
İki `vec2`'den bir `vec4` oluşturduk, bunu yaparken yeni `vec4`, `a.x` ve `a.y`'yi `c`'nin `X`, `Y` bileşenleri olarak kullandı.
Sonra `b.x` ve `b.y`'yi aldı ve `c`'nin `Z` ve `W` bileşenleri olarak kullandı.
Bu, bir **fonksiyonun** farklı argümanları kabul etmek üzere aşırı yüklenmesidir, bu durumda `vec4` **yapıcısı**.
Bu, aynı metodun farklı imzalara sahip birçok **versiyonunun** aynı programda bir arada var olabileceği anlamına gelir, örneğin aşağıdaki tanımlamaların hepsi geçerlidir:
```glsl
vec4 a = vec4(1.0, 1.0, 1.0, 1.0);
vec4 a = vec4(1.0);// x, y, z, w hepsi 1.0'a eşit
vec4 a = vec4( v2, float, v4 );// vec4( v2.x, v2.y, float, v4.x );
vec4 a = vec4( v3, float );// vec4( v3.x, v3.y, v3.z, float );
vb.
```
Dikkat etmeniz gereken tek şey, **vektörünüzü** beslemek için yeterli argüman sağlamaktır.
Son olarak, programınızda yerleşik fonksiyonları, tasarlanmadıkları argümanları alacak şekilde aşırı yüklemenize izin verilir (yine de bu çok sık olmamalıdır).
#### diğer tipler
Vektörler eğlencelidir, shader'ınızın eti sütüdür.
Matrisler ve Doku örnekleyicileri gibi başka temel türler de vardır, bunlar kitapta daha sonra ele alınacaktır.
Diziler de kullanabiliriz. Elbette tipli olmaları gerekir ve bazı *tuhaflıklar* vardır:
* sabit boyutludurlar
* push(), pop(), splice() vb. yapamazsınız ve ```length``` özelliği yoktur
* değerlerle hemen başlatılamazlar
* değerleri tek tek ayarlamanız gerekir
bu çalışmayacaktır:
```glsl
int values[3] = [0,0,0];
```
ama bu çalışacaktır:
```glsl
int values[3];
values[0] = 0;
values[1] = 0;
values[2] = 0;
```
Verilerinizi bildiğinizde veya küçük değer dizileriniz olduğunda bu iyidir.
Daha ifade edici bir değişken tanımlama yolu istiyorsanız,
bir de ```struct``` tipi var. Bunlar metotları olmayan _nesneler_ gibidir;
aynı nesne içinde birden fazla değişkeni saklamaya ve erişmeye izin verirler
```glsl
struct ColorStruct {
vec3 color0;
vec3 color1;
vec3 color2;
}
```
ardından _colors_ değerlerini şu şekilde ayarlayabilir ve alabilirsiniz:
```glsl
//yapıyı bazı değerlerle başlat
ColorStruct sandy = ColorStruct( vec3(0.92,0.83,0.60),
vec3(1.,0.94,0.69),
vec3(0.95,0.86,0.69) );
//yapıdan bir değere eriş
sandy.color0 // vec3(0.92,0.83,0.60)
```
Bu sözdizimi şekeridir ama daha temiz, en azından daha aşina olduğunuz kod yazmanıza yardımcı olabilir.
#### ifadeler & koşullar
Veri yapıları kendi başlarına güzeldir ama bir noktada yinelememiz veya koşullu testler yapmamız _gerekebilir_.
Neyse ki, sözdizimi JavaScript'e çok yakındır.
Bir koşul şöyledir:
```glsl
if( condition ){
//doğru
}else{
//yanlış
}
```
Bir for döngüsü genellikle:
```glsl
const int count = 10;
for( int i = 0; i <= count; i++){
//bir şey yap
}
```
veya float yineleyici ile:
```glsl
const float count = 10.;
for( float i = 0.0; i <= count; i+= 1.0 ){
//bir şey yap
}
```
```count```'un bir ```sabit``` olarak tanımlanması gerektiğini not edin.
Bu, tipin önüne bir ```const``` **niteleyicisi** eklemek anlamına gelir, bunu bir saniye içinde ele alacağız.
ayrıca ```break``` ve ```continue``` ifadelerimiz var:
```glsl
const float count = 10.;
for( float i = 0.0; i <= count; i+= 1.0 ){
if( i < 5. )continue;
if( i >= 8. )break;
}
```
Bazı donanımlarda ```break```'in beklendiği gibi çalışmadığını ve döngünün erken çıkmadığını unutmayın.
Genel olarak, yineleme sayısını mümkün olduğunca düşük tutmak ve döngülerden ve koşullu ifadelerden mümkün olduğunca kaçınmak isteyeceksiniz.
#### niteleyiciler
Değişken tiplerinin üstüne, GLSL **niteleyiciler** kullanır.
Kısaca, niteleyiciler derleyicinin hangi değişkenin ne olduğunu bilmesine yardımcı olur.
Örneğin bazı veriler yalnızca CPU'dan GPU'ya sağlanabilir, bunlara **attribute** ve **uniform** denir.
**Attribute**'ler vertex shader'lar için ayrılmıştır, **uniform**'lar hem vertex hem de fragment shader'larda kullanılabilir.
Ayrıca vertex ve fragment shader arasında değişken geçirmek için kullanılan bir ```varying``` niteleyicisi de vardır.
Burada çok fazla detaya girmeyeceğim çünkü ağırlıklı olarak **fragment shader**'a odaklanıyoruz ama kitapta daha sonra şöyle bir şey göreceksiniz:
```glsl
uniform vec2 u_resolution;
```
Burada ne yaptığımızı görüyor musunuz? Değişkenin tipinden önce bir ```uniform``` niteleyicisi koyduk
Bu, üzerinde çalıştığımız tuvalin çözünürlüğünün CPU'dan shader'a geçirildiği anlamına gelir.
Tuvalin genişliği x'te ve yüksekliği 2B vektörün y bileşeninde saklanır.
Derleyici bu niteleyicinin önünde bir değişken gördüğünde, çalışma zamanında bu değerleri *ayarlayamayacağınızdan* emin olacaktır.
Aynı şey ```for``` döngümüzün sınırı olan ```count``` değişkenimiz için de geçerlidir:
```glsl
const float count = 10.;
for( ... )
```
Bir ```const``` niteleyicisi kullandığımızda, derleyici değişkenin değerini yalnızca bir kez ayarlamamızı sağlayacaktır, aksi takdirde sabit değildir.
Fonksiyon imzalarında kullanılan 3 ek niteleyici vardır: ```in```, ```out``` ve ```inout```.
JavaScript'te, bir fonksiyona skaler argümanlar geçirdiğinizde, değerleri salt okunurdur ve fonksiyonun içinde değerlerini değiştirirseniz,
değişiklikler fonksiyonun dışındaki değişkene uygulanmaz.
```glsl
function banana( a ){
a += 1;
}
var value = 0;
banana( value );
console.log( value );// > 0 ; değişiklikler fonksiyonun dışında hesaba katılmaz
```
Argüman niteleyicileri ile argümanların davranışını belirtebilirsiniz:
* ```in``` salt okunur olacaktır ( varsayılan )
* ```out``` salt yazılır: bu argümanın değerini okuyamazsınız ama ayarlayabilirsiniz
* ```inout``` okuma-yazma: bu değişkenin değerini hem alabilir hem de ayarlayabilirsiniz
GLSL'de banana metodunu yeniden yazmak şöyle görünür
```glsl
void banana( inout float a ){
a += 1.;
}
float A = 0.;
banana( A ); //artık A = 1.;
```
Bu JS'den çok farklı ve oldukça güçlüdür ama imza niteleyicilerini belirtmek zorunda değilsiniz (varsayılan salt okunurdur).
#### uzay & koordinatlar
Son not, DOM ve Canvas 2D'de Y ekseninin 'aşağı' yönünü göstermesine alışığızdır.
Bu, bir web sayfasının açılma şeklini takip ettiğinden DOM bağlamında mantıklıdır; navigasyon çubuğu üstte, içerik alta doğru genişler.
WebGL tuvalinde Y ekseni ters çevrilmiştir: Y 'yukarı' yönünü gösterir.
Bu, orijinin, (0,0) noktasının, bir 2B Tuvalin sol üst köşesinde olduğu gibi değil, bir WebGL bağlamının sol alt köşesinde yer aldığı anlamına gelir.
Doku koordinatları bu kuralı takip eder ve başlangıçta sezgisel olmayabilir.
## Ve bitti!
Elbette çeşitli kavramların daha derinlerine inebilirdik ama daha önce belirtildiği gibi, bu yeni gelenlere BÜYÜK BİR KUCAKLAMA vermeyi amaçlıyor.
Sindirmesi gereken epeyce şey var ama sabır ve pratikle, bu giderek daha doğal hale gelecektir.
Umarım bunların bir kısmını faydalı bulmuşsunuzdur, şimdi kitaptaki yolculuğunuza başlamaya ne dersiniz?
---
### Appendix/04/README Ua (appendix/04/README-ua.md)
## Вступ для тих, хто прийшов із JS
автор [Nicolas Barradeau](http://www.barradeau.com/)
Якщо ви JavaScript-розробник, швидше за все, ви будете трохи спантеличені, читаючи книгу.
Дійсно, є багато відмінностей між маніпулюванням високорівневим JS і длубанням у менш високорівневих шейдерах.
Проте, на відміну від більш низькорівневої мови асемблера, GLSL є людино-зрозумілою мовою, і я впевнений, що як тільки ви розберетеся з її особливостями, то швидко запрацюєте.
Я припускаю, що ви маєте хоча б поверхневе знання про JavaScript і API Canvas.
Якщо ні, не хвилюйтеся, ви все одно зможете зрозуміти більшу частину цього розділу.
Крім того, я не буду надто вдаватися в подробиці, і деякі речі можуть бути _напівправдою_, тож не розраховувайте на "вичерпний посібник", а радше на ознайомлення.
### Введення для новачків
JavaScript чудово підходить для швидкого прототипування; ви накидуєте купу різноманітних нетипізованих змінних і методів, можете динамічно додавати та видаляти члени класів, оновлювати сторінку і швидко перевіряти чи вона працює.
Потім можна внести нові зміни, оновити сторінку, повторити - легке життя.
Тож ви можете поставити собі питання, у чому різниця між JavaScript і GLSL?
Зрештою, обидва працюють у браузері, обидва використовуються для малювання купи прикольних штук на екрані, і в цьому сенсі JS легше використовувати.
Що ж, головна відмінність полягає в тому, що Javascript є **інтерпретованою** мовою, тоді як GLSL є **компільованою**.
**Скомпільована** програма виконується нативно в ОС, є низькорівневою і загалом швидкою.
**Інтерпретована** програма потребує для свого виконання [віртуальну машину](https://en.wikipedia.org/wiki/Virtual_machine) (VM), є високорівневою і відносно більш повільною.
Коли браузер (_**VM** для JavaScript_) **виконує** або **інтерпретує** фрагмент JS-коду, він ще не має уявлення про те, яка змінна чим являється і яка функція що робить (за винятком **типізованих масивів**).
Тож він не може нічого оптимізувати _наперед_.
Потрібен деякий час, щоб прочитати ваш код, щоб **вивести**, на основі використання, типи ваших змінних та методів і, коли це можливо, перетворити _дещо_ з вашого коду на код асемблера, який виконуватиметься набагато швидше.
Це повільний, кропіткий і шалено складний процес. Якщо вас цікавлять деталі, я рекомендую подивитися, як [працює рушій V8 у Chrome](https://developers.google.com/v8/).
Найгірше те, що кожен браузер оптимізує JS по-своєму, а процес _прихований_ від вас. В цьому плані ви безсилі.
**Компільована** програма не потребує інтерпретації. Операційна система запускає її і якщо програма валідна, вона виконується.
Це велика відмінність. Якщо ви забули крапку з комою в кінці рядка, ваш код вже не валідний та не скомпілюється, він взагалі не перетвориться на програму.
Це суворо, але це те, чим є **шейдер**: _програмою, що компілюється для виконання на GPU_.
Не бійтеся! **Компілятор** який перевіряє правильність вашого коду, стане вашим найкращим другом.
Приклади цієї книги та [редактор коду](http://editor.thebookofshaders.com/) дуже дружні до користувача.
Вони підкажуть вам де і чому не вдалося скомпілювати вашу програму.
Потім, після потрібних виправлень, коли шейдер буде готовий до компіляції, він миттєво зобразить результат своєї роботи. Це чудовий спосіб навчання, оскільки він дуже наочний і безпечний, бо насправді ви нічого не зможете зламати.
Останнє зауваження: **шейдер** складається з 2 програм: **вершинного шейдера** і **фрагментного шейдера**.
Якщо коротко, то **вершинний шейдер** це перша програма, що отримує на вхід *геометрію* та перетворює її на серію **пікселів** (або *фрагментів*).
Потім вона передає їх до **фрагментного шейдера** - другої програми, яка вирішить, яким кольором пофарбувати ці пікселі.
Дана книга здебільшого зосереджена на **фрагментних шейдерах**. У всіх прикладах геометрія є простим чотирикутником, який охоплює весь екран.
Готові?
Поїхали!
### Сильні типи
Коли ви приходите з JS або будь-якої іншої нетипізованої мови, **типізація** змінних являється для вас чужорідною концепцією, що стає найважчим кроком до GLSL.
**Типізація**, як випливає з назви, означає, що вам потрібно надавати **тип** усім своїм змінним і функціям.
Це фактично означає, що слів **`var`** або **`let`** більше не існує.
Поліція думок GLSL стерла їх із загальної мови й ви більше не можете їх використовувати, тому що, ну... їх не існує.
Замість використання чарівного слова **`var`** вам доведеться _явно вказати тип кожної змінної_, яку ви використовуєте, тоді компілятор бачитиме лише ті об'єкти та примітиви, з якими він вміє ефективно поводитися.
Мінус, що ви не можете використовувати ключове слово **`var`** і повинні _явно вказувати всі типи_, полягає в тому, що вам доведеться знати типи усіх змінних і знати їх добре.
Будьте спокійні, їх небагато і вони досить прості (GLSL це вам не Java-фреймворк).
Це може здатися страшним, але загалом це не дуже відрізняється від того, що ви робите на JavaScript. Наприклад, якщо ви маєте `boolean`-змінну, то ви очікуєте, що вона зберігатиме лише `true` або `false` і нічого більше.
Якщо змінна називається `var uid = XXX;`, то в ній вірогідно зберігається цілочисельне значення, а `var y = YYY;` _може_ бути посиланням на значення з рухомою крапкою.
Що ще краще, завдяки **сильним типам** ви не витрачатимете час на роздуми про те, чи `X == Y` (чи `typeof X == typeof Y`?, чи `typeof X !== null && Y...`). Ви просто *знаєте* це, а якщо ні, то компілятор знатиме напевно.
Ось **скалярні типи** (**скаляр** описує величину), які можна використовувати в GLSL: `bool` (булів тип), `int` (ціле число), `float` (число з рухомою крапкою).
Є й інші типи, але не будемо поспішати. Наступний фрагмент показує, як оголосити **`vars`** (так, я використав заборонене слово) у GLSL:
```glsl
// логічне значення
JS: var b = true; GLSL: bool b = true;
// цілочисельне значення
JS: var i = 1; GLSL: int i = 1;
// числове значення з рухомою крапкою
JS: var f = 3.14159; GLSL: float f = 3.14159;
```
Не дуже важко, правда? Як згадувалося вище, це навіть полегшує роботу, оскільки ви не витрачаєте час на перевірку типів даних змінних.
Якщо це здається сумнівним, то пам'ятайте, що ви робите це для того, щоб ваша програма виконувалася набагато швидше, ніж на JS.
#### void
Тип `void` приблизно відповідає `null`. Він використовується в якості типу, який має повертати метод, коли він нічого не повертає.
Ви не можете призначати його змінним.
#### boolean
Як вам відомо, логічні значення здебільшого використовуються в умовних перевірках: "`if (myBoolean == true) {...} else {...}`".
Якщо умовне розгалуження є звичайним підходом для CPU, то для [паралельної природи](http://thebookofshaders/01/?lan=ua) GLSL це твердження є менш правдивим.
Використання умовних галужень навіть не рекомендується у більшості випадків і у книзі показано кілька альтернативних методів для вирішення цього обмеження.
#### приведення типів
Як казав [Боромир](https://en.wikipedia.org/wiki/Boromir), "не можна просто взяти та скомбінувати типізовані примітиви". На відміну від JavaScript, GLSL не дозволить вам виконувати операції між змінними різних типів.
Наприклад, цей код:
```glsl
int i = 2;
float f = 3.14159;
// спроба помножити ціле число на значення з рухомою крапкою
float r = i * f;
```
не спрацює, тому що ви намагаєтеся схрестити **_кота_** і **_жирафа_**.
Проблема вирішується за допомогою **приведення типу**, що _змусить компілятор повірити_, що *`i`* має тип `float` без фактичної зміни типу *`i`*.
```glsl
// приведення типу цілочисельної змінної 'i' до float
float r = float(i) * f;
```
Це як вдягти **_кота_** у **шкіру _жирафа_** і працюватиме належним чином (змінна `r` зберігатиме результат множення `i` на `f`).
Можна **привести** будь-який зі згаданих вище типів до будь-якого іншого. Зауважте, що приведення `float` до `int` поводитиметься як `Math.floor()`, оскільки видалятиме значення після рухомої крапки.
Приведення `float` або `int` до `bool` поверне `true`, якщо змінна не дорівнює нулю.
#### конструктор
**Типи** змінних також є **конструкторами класів** для самих себе. Змінну `float` фактично можна розглядати як _`екземпляр`_ класу _`float`_.
Наступні оголошення рівнозначно валідні:
```glsl
int i = 1;
int i = int(1);
int i = int(1.9995);
int i = int(true);
```
Це може здатися не дуже схожим на `скалярні` типи та не дуже відрізняється від **приведення типів**, але у цьому з'явиться більше сенсу, коли дійдемо до розділу *перевантаження*.
Отже, ми познайомилися з трьома `примітивними типами`, без яких ви не зможете жити, але, звісно, GLSL має й інші.
### Вектори
У Javascript, як і в GLSL, вам знадобляться складніші способи маніпуляції даними, ось де **`вектори`** стануть у пригоді.
Я припускаю, що вам вже доводилося писати клас `Point` на JavaScript, для утримання значень `x` і `y`, що виглядав якось так:
```glsl
// визначення класу:
var Point = function(x, y) {
this.x = x || 0;
this.y = y || 0;
}
// створення екземляру:
var p = new Point(100, 100);
```
Як ми щойно побачили, це ДУЖЕ неправильно на ДУЖЕ багатьох рівнях! По-перше, ключове слово **`var`**, далі жахливе **`this`**, потім знову **нетипізовні** значення `x` і `y`...
Ні, це не запрацює в шейдерленді.
Натомість GLSL надає вбудовані структури даних для їх групування, а саме:
* **`bvec2`**: 2D вектор для bool, **`bvec3`**: 3D вектор для bool, **`bvec4`**: 4D вектор для bool
* **`ivec2`**: 2D вектор для int, **`ivec3`**: 3D вектор для int, **`ivec4`**: 4D вектор для int
* **`vec2`**: 2D вектор для float, **`vec3`**: 3D вектор для float, **`vec4`**: 4D вектор для float
Ви відразу помітили, що для кожного примітиву є відповідний **векторний** тип.
З показаного вище, ви можете зробити висновок, що `bvec2` буде містити два значення типу `bool`, а `vec4` — чотири значення `float`.
Також вектори вводять таку річ як **вимірність** або **розмірність**. Це не означає, що 2D-вектор використовується при малюванні 2D-графіки, а 3D-вектор при малюванні 3D-сцен. Ні!
Що в такому разі буде представляти 4D-вектор? (ну насправді це називається тесерактом або гіперкубом)
**Розмірність** представляє кількість і тип **компонентів** або **змінних**, що зберігаються у **векторі**:
```glsl
// створюємо двовимірний булів вектор
bvec2 b2 = bvec2(true, false);
// створюємо тривимірний цілочисельний вектор
ivec3 i3 = ivec3(0, 0, 1);
// створюємо чотиривимірний вектор з рухомою комою
vec4 v4 = vec4(0.0, 1.0, 2.0, 1.0);
```
`b2` зберігає два різних булевих значення, `i3` - 3 різні цілочисельні значення, а `v4` - 4 різні значення з рухомою комою.
Але як звернутися до цих значень?
У випадку `скалярів` відповідь очевидна: для "`float f = 1.2;`", змінна `f` містить значення `1.2`.
З **векторами** це трохи інакше і доволі красиво.
#### аксесори - доступи до елементів
Існують різні способи доступу до значень
```glsl
// створимо чотиривимірний вектор типу float
vec4 v4 = vec4(0.0, 1.0, 2.0, 3.0);
```
отримати кожне з 4-х значень, можна наступним чином:
```glsl
float x = v4.x; // x = 0.0
float y = v4.y; // y = 1.0
float z = v4.z; // z = 2.0
float w = v4.w; // w = 3.0
```
Просто і легко. Наведені нижче приклади показують інші еквівалентні способи доступу до цих даних:
```glsl
float x = v4.x = v4.r = v4.s = v4[0]; // x = 0.0
float y = v4.y = v4.g = v4.t = v4[1]; // y = 1.0
float z = v4.z = v4.b = v4.p = v4[2]; // z = 2.0
float w = v4.w = v4.a = v4.q = v4[3]; // w = 3.0
```
Кмітливий читач міг помітити три речі:
* `X`, `Y`, `Z`, `W` зазвичай використовуються в 3D-програмах для представлення 3D-векторів
* `R`, `G`, `B`, `A` використовуються для кодування кольорів і альфа-каналу
* `[0]`, `[1]`, `[2]`, `[3]` означає, що ми можемо звертатися до значень через індекси
Тож залежно від того, чи працюєте ви з дво- чи тривимірними координатами, кольором з альфа-каналом чи без нього, або просто з деякими довільними значеннями, ви можете вибрати найбільш відповідний тип і розмірність **вектора**.
Зазвичай двовимірні координати та вектори (в геометричному сенсі) зберігаються як `vec2`, `vec3` або `vec4`, кольори як `vec3` або `vec4`, якщо вам потрібна непрозорість. Але, в цілому, обмежень на те як використовувати вектори немає.
Наприклад, якщо ви хочете зберегти лише одне логічне значення в `bvec4`, це можливо, але буде марною витратою пам'яті.
**Примітка**: у шейдері значення кольорів (`R`, `G`, `B`, `A`) нормалізовані, тобто варіюються в діапазоні від 0 до 1, а не від 0 до 0xFF, тому для них краще використовувати тип float `vec4`, ніж цілочисельний тип `ivec4`.
Вже маємо хороший початок, але рушаймо далі!
#### змішування
З вектора можна отримати більше одного значення за раз. Скажімо, із `vec4` вам потрібні лише значення `X` і `Y`. У JavaScript вам довелося б написати щось подібне:
```glsl
var needles = [0, 1]; // розміщення 'x' і 'y' в нашій структурі даних
var a = [0, 1, 2, 3]; // наша структура даних 'vec4'
var b = a.filter(function(val, i, array) {
return needles.indexOf(array.indexOf(val)) != -1;
});
// b = [0, 1]
// або більш буквально:
var needles = [0, 1];
var a = [0, 1, 2, 3]; // структура даних 'vec4'
var b = [a[needles[0]], a[needles[1]]]; // b = [0, 1]
```
Виглядає потворно. У GLSL ви можете отримати ці дані так:
```glsl
// створюємо 4D-вектор типу float
vec4 v4 = vec4(0.0, 1.0, 2.0, 3.0);
// і одночасно отримуємо лише X та Y
vec2 xy = v4.xy; // xy = vec2(0.0, 1.0);
```
Що це щойно сталося?! Коли ви **об'єднуєте аксесори**, GLSL елегантно повертає підмножину значень, які ви запросили, у найбільш відповідному **векторному** форматі.
Тож тут вектор — це структура даних із **довільним доступом**, схожий на масив як у JavaScript.
Таким чином, ви можете не тільки отримати підмножину ваших даних, але і вказати їх **порядок**, у якому вони вам потрібні. Наступний приклад змінює порядок отримання компонентів вектора:
```glsl
// створюємо чотиривимірний вектор типу float: R,G,B,A
vec4 color = vec4(0.2, 0.8, 0.0, 1.0);
// отримуємо компоненти кольору в порядку A,B,G,R
vec4 backwards = color.abgr; // backwards = vec4(1.0, 0.0, 0.8, 0.2);
```
І, звичайно, ви можете повернути той самий компонент кілька разів:
```glsl
// створюємо чотиривимірний вектор типу float: R,G,B,A
vec4 color = vec4(0.2, 0.8, 0.0, 1.0);
// отримуємо vec3 з компонентами GAG на основі каналів G і A з початкового кольору
vec3 GAG = color.gag; // GAG = vec4(0.8, 1.0, 0.8);
```
Це надзвичайно зручно для об'єднання частин вектору, виділення лише rgb-каналів із кольору RGBA тощо.
#### перевантаження
У розділі типів я згадував про **конструктор** і можливість **перевантаження**.
Для тих, хто не знає, **перевантаження** оператора або функції означає _'зміну поведінки зазначеного оператора або функції залежно від операндів/аргументів'_.
В JavaScript немає перевантаження, тому спочатку воно може здатися трохи дивним, але я впевнений, що як тільки ви звикнете до нього, то будете дивуватися, чому це не реалізовано в JS (коротка відповідь - *типізація*).
Найпростіший приклад перевантаженого оператора виглядає так:
```glsl
vec2 a = vec2(1.0, 1.0);
vec2 b = vec2(1.0, 1.0);
// перевантажене додавання
vec2 c = a + b; // c = vec2(2.0, 2.0);
```
ЩО? Отже, можна додавати сутності, які не є числами?!
Саме так. Також це стосується всіх операторів (`+`, `-`, `*` і `/`), але це тільки початок.
Розглянемо наступний фрагмент:
```glsl
vec2 a = vec2(0.0, 0.0);
vec2 b = vec2(1.0, 1.0);
// перевантажений конструктор
vec4 c = vec4(a, b); // c = vec4(0.0, 0.0, 1.0, 1.0);
```
Ми створили `vec4` з двох `vec2`. Таким чином новий `vec4` використав `a.x` і `a.y` як `X`і `Y` компоненти та `b.x` і `b.y` як `Z` і `W` компоненти для вектора `c`.
Ось що відбувається, коли **функція** перевантажується для прийняття різних аргументів, у попередньому випадку це був **конструктор** `vec4`.
Це означає, що в одній програмі може співіснувати багато **версій** одного і того самого методу з різною сигнатурою. Наприклад, усі наступні оголошення є валідними:
```glsl
vec4 a = vec4(1.0, 1.0, 1.0, 1.0);
vec4 a = vec4(1.0); // x, y, z, w - усі дорівнюють 1.0
vec4 a = vec4(v2, float, v4); // vec4(v2.x, v2.y, float, v4.x);
vec4 a = vec4(v3, float); // vec4(v3.x, v3.y, v3.z, float);
тощо
```
Єдине про що ви повинні попіклуватися, так це про передачу достатньої кількості аргументів для заповнення **вектору**.
Нарешті, ви також можете перевантажувати вбудовані функції у вашій програмі, щоб вони могли приймати аргументи, для яких не були розроблені (хоча це не повинно траплятися занадто часто).
#### більше типів
Вектори прикольні і є основою вашого шейдера.
А ще існують інші примітиви, такі як матриці та текстурні семплери, які будуть розглянуті пізніше в книзі.
Ми також можемо використовувати масиви. Звичайно, їх потрібно типізувати й вони мають свої особливості у порівнянні з JS:
* мають фіксований розмір
* ви не можете використовувати методи push(), pop(), splice() тощо, і немає властивості ```length```
* ви не можете відразу ініціалізувати їх значеннями
* Ви повинні встановити значення індивідуально
Це не спрацює:
```glsl
int values[3] = [0, 0, 0];
```
А ось це спрацює:
```glsl
int values[3];
values[0] = 0;
values[1] = 0;
values[2] = 0;
```
Добре, коли ви знаєте свої дані або маєте невеликі масиви значень.
Якщо вам потрібно більше виразності, то можете скористатися типом ```struct```. Це як _об'єкти_ без методів.
Вони дозволяють зберігати та отримувати доступ до кількох змінних всередині одного об'єкта:
```glsl
struct ColorStruct {
vec3 color0;
vec3 color1;
vec3 color2;
}
```
Ви можете створити та отримати значення _colors_ наступним чином:
```glsl
// ініціалізуємо структуру деякими значеннями
ColorStruct sandy = ColorStruct(
vec3(0.92, 0.83, 0.60),
vec3(1., 0.94, 0.69),
vec3(0.95, 0.86, 0.69)
);
// отримуємо доступ до значень із структури
sandy.color0 // vec3(0.92, 0.83, 0.60)
```
Це синтаксичний цукор, але він може допомогти написати чистіший код, принаймні більш звичний для вас.
#### вирази та умови
Структури даних корисні, але нам _може_ знадобитися можливість для повторення дії або виконання умовних перевірок.
На щастя для нас, синтаксис дуже близький до JavaScript.
Умова виглядає так:
```glsl
if (condition) {
// true
} else {
// false
}
```
Звичайни цикл `for`:
```glsl
const int count = 10;
for (int i = 0; i <= count; i++) {
// do something
}
```
Приклад циклу з ітератором типу float:
```glsl
const float count = 10.;
for (float i = 0.0; i <= count; i += 1.0) {
// do something
}
```
Зауважте, що ```count``` потрібно визначити як ```константу```.
Це означає перед змінною потрібно додати **кваліфікатор** ```const```, який ми розглянемо трохи згодом.
Нам також доступні оператори ```break``` і ```continue```:
```glsl
const float count = 10.;
for (float i = 0.0; i <= count; i += 1.0) {
if (i < 5.) continue;
if (i >= 8.) break;
}
```
Зауважте, що на деяких типах пристроїв ```break``` не працює належним чином і завчасно не перериває виконання циклу.
Загалом, кількість ітерацій має бути якомога меншою, та і в цілому бажано уникати використання циклів і умовних галужень.
#### кваліфікатори
Окрім типів змінних, GLSL використовує **кваліфікатори**.
Коротко кажучи, кваліфікатори допомагають повідомити компілятору призначення змінних.
Наприклад, деякі дані для GPU можуть бути надані тільки від CPU і називаються **атрибутами** та **уніформами**.
**Атрибути** використовуються у вершинних шейдерах, а **уніформи** можна використовувати як у вершинних, так і у фрагментних шейдерах.
Існує також кваліфікатор ```variying```, який використовується для передачі змінних від вершинного шейдеру до фрагментного.
Я не буду вдаватися в деталі, оскільки ми зосереджені на **фрагментних шейдерах**, але далі в книзі ви побачите щось на кшталт:
```glsl
uniform vec2 u_resolution;
```
Бачите, що ми тут зробили? Ми додали кваліфікатор ```uniform``` перед типом змінної.
Це означає, що змінна, яка відповідає за роздільну здатність полотна з яким ми працюємо, передається шейдеру з CPU.
Ширина полотна зберігається в x, а висота в y-компоненті даного 2D-вектора.
Коли компілятор бачить змінну, якій передує цей кваліфікатор, він простежить, щоб ви не могли *змінити* такі значення під час рантайму.
Те саме стосується нашої змінної ```count```, яка слугувала обмеженням для циклу ```for```:
```glsl
const float count = 10.;
for ( ... )
```
Коли ми використовуємо кваліфікатор ```const```, компілятор не дає змогу перезаписувати значення такої змінної, інакше вона не була б константою.
У сигнатурах функцій можуть використовуватися 3 додаткові кваліфікатори: ```in```, ```out``` та ```inout```.
У JavaScript передані до функції значення скалярних аргументів доступні лише для читання. Якщо ви змінюєте їхні значення всередині функції, то ці зміни не застосовуються до змінної поза функцією.
```glsl
function banana(a) {
a += 1;
}
var value = 0;
banana(value);
console.log(value); // 0 - значення за межами функції не змінилося
```
За допомогою кваліфікаторів перед аргументами ви можете вказати їх поведінку:
* ```in``` - лише для читання (за замовчуванням)
* ```out``` - лише для запису: можна змінити, але не можна прочитати значення
* ```inout``` - читання і запис: можна і прочитати й встановити нове значення
Переписаний метод banana у GLSL виглядає так:
```glsl
void banana(inout float a) {
a += 1.;
}
float A = 0.;
banana(A); // тепер A = 1.;
```
Це дуже відрізняється від JS і є досить потужною можливістю, але вам не обов'язково вказувати кваліфікатори аргументів. За замовчуванням вони доступні лише для зчитування.
#### простір і координати
Останнє зауваження: у DOM і Canvas 2D ми звикли, що вісь Y спрямована 'вниз'.
Це має сенс у контексті DOM, оскільки відповідає способу розгортання вебсторінки: панель навігації вгорі, а контент прокручується донизу.
У полотні WebGL вісь Y перевернута і вказує 'вгору'.
Це означає, що початок координат, точка (0, 0), знаходиться в нижньому лівому куті контексту WebGL, а не у верхньому лівому куті, як у 2D Canvas.
Координати текстур також дотримуються цього правила, що спочатку може бути контрінтуїтивним.
## Ось і все!
Звісно, ми б могли більше заглибитися в різноманітні концепції, але, як згадувалося раніше, цей розділ написаний як просте введення для новачків.
Тут вже написано достатньо для того, щоб за деякий час переварити нові знання, але з терпінням і практикою ця мова ставатиме для вас все більш природною.
Сподіваюся, цей матеріал був корисним для вас. А тепер як щодо початку вашої подорожі основною частиною книги?
---
### Appendix/04/README Vi (appendix/04/README-vi.md)
## Giới thiệu cho người đã biết Javascript
Tác giả: [Nicolas Barradeau](http://www.barradeau.com/)
Nếu bạn là developer Javascript, khả năng cao là bạn sẽ thấy hoang mang một chút khi đọc quyển sách này.
Thực tế là có rất nhiều điểm khác biệt khi code JavaScript vốn chỉ là bề nổi, so với việc phải đụng tới shader ở sâu bên dưới tảng băng chìm.
Tuy nhiên, không giống với ngôn ngữ nền tảng là Assembly, GLSL rất gần với ngôn ngữ mà con người có thể hiểu được, và tôi tin rằng một khi bạn đã nắm được các đặc tính của nó thì bạn sẽ bắt kịp rất nhanh thôi.
Coi như bạn đã biết về Javascript và cả Canvas API đi.
Mà nếu có chưa biết mấy thì cũng đừng lo, bạn vẫn sẽ hiểu được phần lớn nội dung của phần này thôi.
Tất nhiên tôi sẽ không đi sâu vào chi tiết và một vài điều tôi nói có thể _không chính xác hoàn toàn_, nên đừng kỳ vọng nó được như "cầm tay chỉ việc" mà hãy coi nó như
### MỘT CÁI ÔM NỒNG ẤM
JavaScript rất thích hợp để thử nghiệm nhanh ; bạn chỉ việc viết vài hàm đơn giản, không có ràng buộc gì về kiểu dữ liệu, tuỳ ý thêm bớt các hàm của class, tải lại trang web là đã thấy ngay kết quả rồi,
sau đó lại sửa một tí, tải lại trang, cứ thế lặp lại, dễ như ăn kẹo.
Thế GLSL thì có gì khác JavaScript chứ.
Suy cho cùng thì cả 2 đều chạy trên trình duyệt mà, chúng đều vẽ một vài thứ lên màn hình đó thôi, mà riêng về khía cạnh đó thì dùng JavaScript dễ hơn.
Ừ thì, điểm khác biệt chính nằm ở chỗ Javascript là một ngôn ngữ **thông dịch (interpreted)** còn GLSL thì là một ngôn ngữ **biên dịch (compiled)**.
Một chương trình **biên dịch** được thực thi trực tiếp bởi hệ điều hành, là một chương trình bậc thấp và thường chạy rất nhanh.
Còn một chương trình **thông dịch** thì lại cần một [Máy ảo (Virtual Machine / VM)](https://en.wikipedia.org/wiki/Virtual_machine) để thực thi, nó là một chương trình bậc cao và thường chậm hơn.
Khi một trình duyệt (chính xác phải là _**máy ảo** JavaScript_ mới đúng) **thực thi** hoặc **thông dịch** một đoạn mã, nó chẳng biết biến nào có ý nghĩa gì hay hàm này sẽ cho kết quả gì (ngoại trừ **TypedArrays**).
Vì thế nó chẳng thể tối ưu bất kỳ cái gì _trước khi thực thi_ cả, nó còn cần thời gian để dịch code của bạn này, rồi thì đoán xem kiểu dữ liệu của các biến là gì này và nếu được thì cố gắng chuyển một phần sang dạng mã Assembly để code chạy nhanh hơn.
Đó là cả một quá trình cồng kềnh, phức tạp và có phần lề mề, nếu bạn hứng thú đi vào chi tiết thì tôi xin giới thiệu tìm hiểu [cách mà trình thông dịch V8 của Chrome hoạt động](https://developers.google.com/v8/).
Điểm tệ nhất đó là, mỗi trình duyệt lại tự tối ưu mã JavaScript theo một cách riêng mà quá trình này _hoàn toàn_ nằm ngoài tầm với của bạn.
Còn một chương trình **biên dịch** thì không như thế ; hệ điều hành thực thi nó, nếu chương trình không có lỗi biên dịch thì cứ thế mà chạy thôi.
Nếu bạn quên một dấu chấm phẩy cuối dòng thì khả năng cao là bạn sẽ được thông báo còn code của bạn thì thậm chí còn chưa được biên dịch thành chương trình cơ.
Hơi phũ, nhưng đó chính là cách mà **shader** hoạt động: _một chương trình được biên dịch để thực thi trên GPU_.
Đừng sợ! Một **trình biên dịch** sẽ là chiến hữu đáng tin cậy nhất của bạn.
Các ví dụ trong quyển sách này và [người đồng hành editor online](http://editor.thebookofshaders.com/) rất thân thiện.
Nó sẽ chỉ ra cho bạn thấy tại sao code của bạn không biên dịch được và bạn phải sửa chỗ nào, và nếu bạn làm đúng thì kết quả hiển thị ngay lập tức luôn.
Đó là một cách tuyệt vời để học vì nó rất trực quan và bạn chẳng phải sợ sẽ làm hỏng cái gì cả.
Điểm lưu ý cuối cùng, một chương trình **shader** được tạo nên bởi 2 chương trình con, đó là **vertex shader** và **fragment shader**.
Về cơ bản thì **vertex shader** sẽ nhận tham số đầu vào là các khối hình học rồi biến chúng thành các **điểm ảnh (pixel)** (hoặc *fragment*) rồi chuyển kết quả cho **fragment shader** xử lý tiếp, vốn công việc chính là tô màu từng điểm ảnh.
Quyển sách này hầu như chỉ tập trung vào chương trình thứ hai. Trong tất cả các ví dụ, khối hình được sử dụng chỉ là một tứ giác lấp đầy cả màn hình.
Vậy! Bạn đã sẵn sàng chưa ?
Tiếp tục nhé!
### Quy định kiểu dữ liệu một cách chặt chẽ
Khi bạn đã quen với JavaScript hay các ngôn ngữ không quan trọng về kiểu dữ liệu, thì việc phải **quy định kiểu dữ liệu** cho mỗi biến là một khái niệm xa lạ, cũng khiến cho nó trở thành rào cản lớn nhất khi làm quen với GLSL.
**Kiểu dữ liệu**, như chính cái tên của nó, có nghĩa là bạn phải chỉ định mỗi biến (và cả hàm nữa) sử dụng kiểu dữ liệu gì.
Về cơ bản thì việc dùng chung một từ khoá **`var`** cho tất cả các biến đã không còn nữa.
GLSL không cho phép điều đó xảy ra nên bạn có muốn cũng không được.
Thay vì dùng từ khoá **`var`** thần thánh, bạn sẽ phải _chỉ đích danh kiểu dữ liệu cho từng biến một_, sau đó thì trình biên dịch sẽ biết chính xác đang phải xử lý cái gì và làm thế nào thì hiệu quả nhất. Nhược điểm của việc này là bạn phải hiểu tất cả các kiểu dữ liệu, mà lại còn phải hiểu tường tận nữa cơ.
May thay, chỉ có một vài kiểu dữ liệu thôi và cũng khá đơn giản nữa.
Nghe thì đáng sợ chứ thực ra nó không quá khác với code JavaScript mà bạn vẫn hay dùng đâu ; nếu một biến có kiểu `boolean` thì bạn sẽ trông đợi nó chỉ lưu trữ một trong hai giá trị `true` hoặc `false` mà thôi.
Nếu một biến được khai báo là `var uid = XXX;`, thì có khả năng đó là một số nguyên còn nếu nó được khai báo là `var y = YYY;` có thể nó trỏ tới một số thực.
Còn với ngôn ngữ **quy định kiểu dữ liệu (strong type)**, bạn sẽ không phí thời gian đoán xem 2 biến đó có cùng kiểu không, bằng các biểu thức `X == Y` (hay `typeof X == typeof Y` ? .. hoặc `typeof X !== null && Y...` ...) ; bạn sẽ biết chắc điều đó đúng hay sai mà kể cả bạn không để ý thì trình biên dịch sẽ làm thay việc đó.
Đây là các **kiểu dữ liệu đơn (scalar)** trong GLSL: `bool` (Đúng sai), `int`(Số nguyên), `float`(Số thực).
Còn vài kiểu nữa nhưng cứ từ từ, đoạn code mẫu dưới đây khai báo các biến (đừng quên **`var`** không tồn tại trong thế giới GLSL nhé):
```glsl
// Khai báo một biến boolean
JavaScript: var b = true; GLSL: bool b = true;
// Khai báo một số nguyên
JavaScript: var i = 1; GLSL: int i = 1;
// Khai báo một số thực
JavaScript: var f = 3.14159; GLSL: float f = 3.14159;
```
Không có gì khó phải không ? Như đã nói ở trên, nó thậm chí còn giúp bạn đỡ đau đầu khi code ấy chứ. Nếu còn nghi ngờ về điều đó thì cứ tạm bỏ qua, chỉ cần biết nó giúp chương trình của bạn chạy nhanh hơn JavaScript nhiều là cũng đủ rồi.
#### void
Có kiểu `void` tương đương với `null`, nó được dùng khi hàm không trả về kết quả gì cả.
Và bạn không thể khai báo biến kiểu này.
#### boolean
Các biến kiểu boolean hầu hết được sử dụng trong các câu lệnh điều kiện như ; `if( myBoolean == true ){}else{}`.
Nếu các nhánh điều kiện rất hay gặp ở CPU, thì [kiến trúc song song của GPU](http://thebookofshaders/01/) lại hạn chế đất diễn của chúng.
Thậm chí việc sử dụng các lệnh điều kiện còn không được khuyến khích ở đa phần các trường hợp, trong quyển sách này có một vài kỹ thuật để xử lý các trường hợp đó.
#### Ép kiểu
Như [Boromir](https://en.wikipedia.org/wiki/Boromir) đã nói, "One does not simply combine Typed primitives". Không như JavaScript, GLSL không cho phép thực hiện các phép toán giữa các toán hạng không cùng kiểu.
Ví dụ sau:
```glsl
int i = 2;
float f = 3.14159;
// thử nhân một số nguyên với một số thực
float r = i * f;
```
sẽ không cho kết quả tốt vì bạn đang cố lai con **_mèo_** với con **_hươu cao cổ_**.
Giải pháp là **ép kiểu (type casting)** ; đoạn code sau sẽ giúp _trình biên dịch tin rằng_ *`i`* cũng có kiểu `float` dù *`i`* vẫn giữ nguyên kiểu vốn có:
```glsl
// ép biến `i` từ kiểu int sang float
float r = float( i ) * f;
```
Điều này giống như việc cho con **_mèo_** mặc đồ của con **_hươu cao cổ_** vậy, và nó sẽ có hiệu quả (`r` sẽ kết quả của phép toán `i` x `f`).
Bạn có thể ép kiểu qua lại giữa tất cả các kiểu phía trên, chú ý là khi chuyển từ số thực sang số nguyên thì phần thập phân sẽ biến mất, tương đương với việc dùng hàm `Math.floor()`. Ép một số thực `float` hoặc một số nguyên `int` sang kiểu `bool` sẽ cho kết quả `true` nếu số đó khác 0.
#### Hàm khởi tạo (constructor)
Kiểu dữ liệu của biến cũng chính là hàm khởi tạo của class tương ứng ; thực tế thì một số thực `float` có thể coi là 1 _`instance`_ của class _`Float`_.
Các lệnh sau đây đều hợp lệ và cho kết quả giống nhau
```glsl
int i = 1;
int i = int( 1 );
int i = int( 1.9995 );
int i = int( true );
```
Trông thì không giống kiểu `scalar` lắm, và cũng na ná **ép kiểu**, nhưng mọi sự sẽ sáng tỏ ở phần *overload*.
OK, vậy là ta đã biết về ba `kiểu dữ liệu cơ bản`, những thứ mà bạn không thể sống nếu thiếu được và đương nhiên là GLSL còn nhiều kiểu khác.
### Vector
Trong cả JavaScript lẫn GLSL, bạn sẽ cần những cách tinh vi hơn để xử lý dữ liệu, và **`vectors`** khi đó rất hữu ích.
Tôi cho rằng bạn đã sử dụng class `Point` trong JavaScript để lưu 2 giá trị `x` và `y` cùng lúc rồi, code sẽ trông thế này:
```glsl
// Khai báo 'class':
var Point = function( x, y ){
this.x = x || 0;
this.y = y || 0;
}
// và bạn sẽ tạo một instance mới như sau
var p = new Point( 100,100 );
```
Như ta thấy, có quá nhiều điểm không hợp lý. Từ khoá **`var`** vồn dùng cho biến thì lại được dùng để khai báo class rồi thì **`this`** chả hiểu ở đâu ra, xong lại `x` với `y` chả biết kiểu dữ liệu gì ...
Kiểu này là không ổn với shader đâu.
Thay vào đó, GLSL có sẵn các cấu trúc dữ liệu để lưu trữ các biến đồng thời, có thể kể ra:
* `bvec2`: Vector boolean 2 chiều, `bvec3`: Vector boolean 3 chiều, `bvec4`: Vector boolean 4 chiều
* `ivec2`: Vector số nguyên 2 chiều, `ivec3`: Vector số nguyên 3 chiều, `ivec4`: Vector số nguyên 4 chiều
* `vec2`: Vector số thực 2 chiều, `vec3`: Vector số thực 3 chiều, `vec4`: Vector số thực 4 chiều
Bạn nhận ra là có đủ các loại **vector** cho mỗi kiểu dữ liệu cơ bản, tuyệt vời ông mặt giời.
Từ giải thích trên đây, ta có thể suy luận được rằng `bvec2` sẽ gồm 2 giá trị kiểu `bool` còn `vec4` sẽ gồm 4 số thực kiểu `float`
Một điểm mới nữa từ vector là các **chiều (dimension)**, không phải bạn dựng hình 2D thì dùng vector 2 chiều còn dựng hình 3D thì dùng vector 3 chiều đâu nhé. Nếu vậy thì vector 4 chiều dùng để dựng hình gì ? (Thực ra thì không gian 4 chiều có tên riêng đấy, là tesseract hoặc khối siêu lập phương - hypercube)
Nhưng không phải thế đâu nhé, từ **chiều** ở đây chỉ nói về số giá trị được lưu giữ trong mỗi **vector** thôi:
```glsl
// tạo một vector boolean 2 chiều
bvec2 b2 = bvec2 ( true, false );
// tạo một vector số nguyên 3 chiều
ivec3 i3 = ivec3( 0,0,1 );
// tạo một vector số thực 4 chiều
vec4 v4 = vec4( 0.0, 1.0, 2.0, 1. );
```
`b2` gồm 2 giá trị boolean, `i3` gồm 3 số nguyên `v4` gồm 4 số thực.
Làm thế nào để sử dụng từng giá trị trong vector?
Với kiểu dữ liệu đơn thì quá đơn giản ; nếu ta có `float f = 1.2;` thì biến `f` sẽ có giá trị `1.2`.
Còn với **vector** thì hơi khác và cũng kỳ diệu hơn một chút.
#### Truy cập
Có nhiều cách để truy cập các giá trị bên trong vector
```glsl
// Đầu tiên hãy tạo một vector số thực 4 chiều
vec4 v4 = vec4( 0.0, 1.0, 2.0, 3.0 );
```
Để lấy từng giá trị trong vector, ta có thể viết:
```glsl
float x = v4.x; // x = 0.0
float y = v4.y; // y = 1.0
float z = v4.z; // z = 2.0
float w = v4.w; // w = 3.0
```
rất dễ dàng, nhưng còn nhiều cách khác cũng cho kết quả tương tự:
```glsl
float x = v4.x = v4.r = v4.s = v4[0]; // x = 0.0
float y = v4.y = v4.g = v4.t = v4[1]; // y = 1.0
float z = v4.z = v4.b = v4.p = v4[2]; // z = 2.0
float w = v4.w = v4.a = v4.q = v4[3]; // w = 3.0
```
Nếu bạn tinh ý thì sẽ nhận ra:
* `X`, `Y`, `Z` và `W` được dùng để mô tả các vector trong đồ hoạ 3D
* `R`, `G`, `B` và `A` được dùng để mô tả các kênh màu và alpha
* `[0]`, `[1]`, `[2]` và `[3]` được dùng như một mảng cố định
Vậy nên tuỳ vào việc bạn đang xử lý các toạ độ 2D hay 3D, màu kèm theo alpha hoặc không, hay một vài con số bất kỳ, bạn có thể tuỳ chọn cách dùng **vector** bạn muốn.
Thường thì các toạ độ 2 chiều và các vector sẽ được lưu bằng các cấu trúc `vec2`, `vec3` hoặc `vec4`, màu sắc thì được lưu trong `vec3` hoặc `vec4` nếu bạn muốn lưu thêm kênh alpha nữa, không có ràng buộc nào cả.
Thậm chí, nếu bạn dùng cả một vector `bvec4` chỉ để lưu 1 giá trị boolean thì cũng được nốt, có điều hơi lãng phí bộ nhớ.
**Chú ý**: Trong shader, các giá trị của các kênh (`R`, `G`, `B`, `A`) đều được chuẩn hoá để nằm trong khoảng [0-1] chứ không phải [0x00-0xFF], vì thế tốt nhất là nên sử dụng vector số thực 4 chiều `vec4` để lưu trữ giá trị màu.
Hay quá phải không, chưa hết đâu nhé!
#### Tráo đổi (swizzle)
Ta có thể lấy ra nhiều hơn một giá trị nữa cơ ; giả sử bạn chỉ cần 2 giá trị `X` và `Y` từ một `vec4`, thì trong JavaScript, bạn sẽ phải làm như sau:
```glsl
var needles = [0, 1]; // vị trí của 'x' và 'y' trong array dưới đây
var a = [ 0,1,2,3 ]; // giả lập `vec4`
var b = a.filter( function( val, i, array ) {
return needles.indexOf( array.indexOf( val ) ) != -1;
});
// b = [ 0, 1 ]
// hoặc trực diện luôn
var needles = [0, 1];
var a = [ 0,1,2,3 ]; // giả lập `vec4`
var b = [ a[ needles[ 0 ] ], a[ needles[ 1 ] ] ]; // b = [ 0, 1 ]
```
Quá cồng kềnh. Hãy xem trong GLSL làm như thế nào:
```glsl
// Tạo một `vec4`
vec4 v4 = vec4( 0.0, 1.0, 2.0, 3.0 );
// rồi chỉ lấy mỗi x và y ra
vec2 xy = v4.xy; // xy = vec2( 0.0, 1.0 );
```
Ủa cái gì vậy ?! Khi bạn **truy cập liên tiếp (concatenate accessors)**, GLSL sẽ trả về tập con của các giá trị bạn muốn, gói gọn trong một **vector** khác.
Thực ra thì vector là một cấu trúc dữ liệu cho phép truy cập ngẫu nhiên, nếu muốn bạn có thể tượng tượng nó giống array bên JavaScript vậy.
Vì thế, bạn không chỉ lấy được 1 tập con mà còn có thể chỉ định **thứ tự từng phần tử** muốn lấy nữa cơ. Đoạn code sau sẽ tráo đổi giá trị của các vector theo thứ tự ngược lại:
```glsl
// Tạo một vector R,G,B,A
vec4 color = vec4( 0.2, 0.8, 0.0, 1.0 );
// Truy cập các gía trị theo thứ tự ngược lại
vec4 backwards = v4.abgr; // backwards = vec4( 1.0, 0.0, 0.8, 0.2 );
```
Hơn thế nữa, chẳng ai ngăn bạn lấy một phần tử nhiều lần:
```glsl
// Tạo một vector R,G,B,A
vec4 color = vec4( 0.2, 0.8, 0.0, 1.0 );
// Và tạo một vector mới chỉ dùng giá trị của kênh G (2 lần) và A
vec3 GAG = v4.gag; // GAG = vec4( 0.8, 1.0, 0.8 );
```
Khă năng này quá ngầu khi phải xử lý vector, ví dụ như khi chỉ muốn lấy các kênh RGB của một màu có đủ RGBA chẳng hạn.
#### Overload tất cả
Ở phần kiểu dữ liệu, tôi đã nhắc tới điều gì đó liên quan tới **hàm khởi tạo (constructor)** và đây lại là 1 tính năng tuyệt vời nữa của GLSL ; **overload**.
Cho ai chưa biết, **overload** là một toán tử hoặc hàm số đại loại sẽ _'tự động thay đổi cách thực thi sao cho khớp với kiểu dữ liệu'_.
JavaScript không có overload, nên bạn có thể thấy nó hơi lạ lúc đầu, nhưng khi đã quen rồi thì bạn sẽ thắc mắc sao JavaScript lại không có tính năng này (ngắn gọn là do không ràng buộc kiểu dữ liệu đó).
Hãy xem ví dụ đơn giản nhất để hiểu overload là gì:
```glsl
vec2 a = vec2( 1.0, 1.0 );
vec2 b = vec2( 1.0, 1.0 );
// overload phép cộng
vec2 c = a + b; // c = vec2( 2.0, 2.0 );
```
HẢ ? Hai giá trị không phải số đơn thuần mà cũng cộng được ?!
Chính xác là thế đó. Tất nhiên là áp dụng cho toàn bộ các toán tử khác (`+`, `-`, `*` & `/`) nữa nhưng đây mới là mở đầu thôi.
Hãy xem đoạn code sau:
```glsl
vec2 a = vec2( 0.0, 0.0 );
vec2 b = vec2( 1.0, 1.0 );
// overload hàm khởi tạo
vec4 c = vec4( a , b ); // c = vec4( 0.0, 0.0, 1.0, 1.0 );
```
Ta vừa mới tạo nên một `vec4` từ 2 `vec2`, bằng cách gán giá trị của `a.x` và `a.y` cho `X`, `Y` của `vec4`, rồi lại gán tiếp `b.x` và `b.y` cho `Z`, `W` của `vec4`
Đây là điều sẽ xảy ra khi một **hàm** được overload để chấp nhận các loại tham số khác nhau, cụ thể trong trường hợp này là hàm khởi tạo của `vec4`.
Điều đó có nghĩa là rất nhiều phiên bản khác nhau của cùng 1 hàm có thể cùng tồn tại, ví dụ các lệnh khai báo sau hoàn toàn hợp lệ:
```glsl
vec4 a = vec4(1.0, 1.0, 1.0, 1.0);
vec4 a = vec4(1.0);// cả 4 giá trị x, y, z, w đều bằng 1.0
vec4 a = vec4( v2, float, v4 );// vec4( v2.x, v2.y, float, v4.x );
vec4 a = vec4( v3, float );// vec4( v3.x, v3.y, v3.z, float );
etc.
```
Điều duy nhất bạn cần bận tâm là đảm bảo hàm tạo có đủ dữ liệu nó cần mà thôi.
Điều cuối cùng, bạn hoàn toàn có thể overload một hàm có sẵn bất kỳ sao cho nó phù hợp với yêu cầu của bạn (cũng không nên lạm dụng quá).
#### Các kiểu dữ liệu khác
Vector thật thú vị, và là vũ khí chính trong code shader.
Còn các cấu trúc dữ liệu khác như Ma trận và Texture sampler sẽ được bàn tới ở phần sau của quyển sách.
Bạn cũng có thể dùng Array. Tất nhiên là phải quy định kiểu rồi và sau đây là một vài điểm đáng lưu tâm:
* Kích thước Array cố định
* Không thể dùng các hàm push(), pop(), splice() vân vân và cũng không có thuộc tính ```length``` luôn nha
* Không thể gán giá trị hàng loạt khi khởi tạo mà phải gán giá trị từng phần tử một
Code như sau sẽ không đúng:
```glsl
int values[3] = [0,0,0];
```
phải như thế này cơ:
```glsl
int values[3];
values[0] = 0;
values[1] = 0;
values[2] = 0;
```
Điều này cũng không quá tệ nếu bạn thật sự cần can thiệp từng phần tử trong array.
Còn nếu muốn đa dạng hơn thì có thể dùng kiểu ```struct```. Chúng giống như các _object_ nhưng không có hàm đi kèm ;
chúng chỉ cho phép đóng gói các biến vào bên trong thôi
```glsl
struct ColorStruct {
vec3 color0;
vec3 color1;
vec3 color2;
}
```
sau đó bạn có thể sử dụng như sau:
```glsl
// Khởi tạo cấu trúc với giá trị nào đó
ColorStruct sandy = ColorStruct( vec3(0.92,0.83,0.60),
vec3(1.,0.94,0.69),
vec3(0.95,0.86,0.69) );
// Truy cập biến trong cấu trúc
sandy.color0 // vec3(0.92,0.83,0.60)
```
Cú pháp kiểu này có thể hơi tự do chút, nhưng nó sẽ giúp bạn viết code rõ ràng hơn hay ít nhất là nhìn dễ hiểu hơn.
#### Các lệnh điều khiển
Cấu trúc dữ liệu hay thật đấy nhưng tới lúc nào đó ta vẫn _có thể_ phải cần tới các lệnh điều khiển.
May mán là cú pháp rất giống với JavaScript.
Ví dụ về lệnh điều kiện:
```glsl
if( condition ){
//true
}else{
//false
}
```
Còn một vòng lặp thì thường giống như:
```glsl
const int count = 10;
for( int i = 0; i <= count; i++){
// làm gì đó
}
```
hoặc với iterator:
```glsl
const float count = 10.;
for( float i = 0.0; i <= count; i+= 1.0 ){
// làm gì đó
}
```
Chú ý là biến ```count``` phải được khai báo là một ```hằng số (constant)```.
Điều đó có nghĩa là ta phải đặt thêm từ khoá ```const``` vào trước như ví dụ dưới đây.
Ngoài ra ta cũng có các lệnh ```break``` và ```continue```:
```glsl
const float count = 10.;
for( float i = 0.0; i <= count; i+= 1.0 ){
if( i < 5. )continue;
if( i >= 8. )break;
}
```
Chú ý là trên một vài nền tảng phần cứng, lệnh ```break``` không hoạt động giống nhau nên vòng lặp vẫn chạy.
Nhìn chung thì bạn nên giữ số vòng lặp càng ít càng tốt và tránh sử dụng các lệnh điều kiện càng nhiều càng tốt.
#### qualifiers
Không chỉ có kiểu dữ liệu mà GLSL còn dùng **qualifier** để giúp trình biên dịch biết mỗi biến có gì đặc biệt.
Ví dụ có những dữ liệu chỉ được truyền từ CPU sang GPU gọi là **attribute** và **uniform**.
Từ khoá **attribute** được dùng trong vertex shader, còn **uniform** được dùng cho cả vertex shader và fragment shader.
Từ khoá ```varying``` để đánh dấu các biến luân chuyển giữa vertex shader và fragment shader.
Tôi sẽ không đi vào chi tiết ở đây vì ta chủ yếu tập trung vào **fragment shader** nhưng ở phần sau của quyển sách, bạn sẽ thấy code tương tự như:
```glsl
uniform vec2 u_resolution;
```
Tôi mới đặt từ khoá ```uniform``` vào trước kiểu dữ liệu của biến khi khai báo đó.
Điều này có nghĩa là CPU sẽ gửi thêm thông tin cho shader thông qua biến này. Cụ thể đó là độ phân giải của canvas, chiều rộng và chiều cao của canvas sẽ được lưu vào biến x và y của một vector 2 chiều.
Khi trình biên dịch thấy một biến có đánh dấu qualifier này, nó sẽ đảm bảo bạn không thể thay đổi giá trị trong shader.
Điều tương tự cũng được áp dụng cho biến ```count``` được dùng để giới hạn số vòng lặp ```for```:
```glsl
const float count = 10.;
for( ... )
```
Khi ta dùng qualifier ```const```, trình biên dịch sẽ đảm bảo rằng giá trị của biến này chỉ được khởi tạo một lần duy nhất, nếu không thì nó không phải là hằng số nữa rồi.
Còn 3 qualifier hay được dùng nữa cho các tham số của hàm là : ```in```, ```out``` và ```inout```.
Trong JavaScript, khi bạn truyền giá trị vào 1 hàm thì mọi thay đổi với giá trị đó chỉ có tác dụng trong hàm chứ không ảnh hưởng gì tới biến bên ngoài.
```glsl
function banana( a ){
a += 1;
}
var value = 0;
banana( value );
console.log( value );// > 0 ; ra khỏi hàm thì value vẫn giữ nguyên giá trị như trước khi gọi hàm
```
Ý nghĩa của 3 qualifier tham số:
* ```in``` không thay đổi giá trị của biến bên ngoài (mặc định cho mọi tham số)
* ```out``` chỉ dùng để lưu giá trị mới mà vẫn giữ nguyên khi đã ra khỏi hàm
* ```inout``` tuỳ ý đọc ghi
Viết lại hàm banana trong GLSL:
```glsl
void banana( inout float a ){
a += 1.;
}
float A = 0.;
banana( A ); // lúc này A = 1.;
```
Điều này rất khác so với JavaScript và cũng rất tiện.
#### Không gian và toạ độ
Chú ý cuối cùng, trong DOM và Canvas 2D, trục Y hướng xuống dưới.
Điều này có lý trong bối cảnh DOM dựng trang web có thể scroll được ; từ trên xuống dưới.
Còn trong canvas của WebGL thì trục Y hướng lên trên.
Điều đó có nghĩa là gốc tọa độ, điểm (0, 0) nằm ở góc dưới cùng bên trái của WebGL canvas, chứ không phải góc trên cùng bên trái như 2D Canvas.
Toạ độ của texture cũng vì thế mà có thể gây lú một chút nếu chưa quen.
## Và thế là hết !
Tất nhiên ta có thể đi sâu hơn vào rất nhiều khái niệm phía trên, nhưng nhớ rằng đây chỉ là lời chào dành cho người mới.
Đúng là có rất nhiều thứ phải tìm hiểu nhưng với sự kiên trì và chăm chỉ thì sẽ quen nhanh thôi.
Tôi hy vọng bạn thấy một vài phần hữu ích ở đây, giờ thì bạn sẵn sàng bắt đầu chuyển phiêu lưu vào quyển sách chưa ?
---
### Examples/README (examples/README.md)
# Examples Gallery
This is a collection of examples extracted from the chapters of this book together with shared shaders kindly donated by other readers using [the on-line editor](http://editor.thebookofshaders.com/). Feel free to explore and tweak them bit by bit. Once you have something you are proud of, click the "Export" and then copy the "URL to code...". Send it to [@bookofshaders](https://twitter.com/bookofshaders) or [@kyndinfo](https://twitter.com/kyndinfo). We are looking forward to see it!
---
### Examples/Featured Examples (examples/featured_examples.md)
---
### Examples/README De (examples/README-de.md)
# Galerie mit ausgewählten Shader Beispielen
Dies ist eine Sammlung von Shader Beispielen aus den verschiedenen Kapiteln dieses Buches. Sie wird ergänzt durch weitere Shader, die von Lesern über den [Online-Editor](http://editor.thebookofshaders.com/) zur Verfügung gestellt wurden.
Du bist herzlich eingeladen, die verschiedenen Shader auszuprobieren, zu erweitern und zu verändern. Und natürlich kannst Du auch ganz neue Shader enwickeln.
Wenn Du Deine Arbeiten anderen Lesern zur Verfügung stellen möchtest, klicke auf die „Export“-Schaltfläche im Editor und kopiere anschließend den Inhalt des Feldes „URL to code...“. Sende diese URL an [@bookofshaders](https://twitter.com/bookofshaders) oder an [@kyndinfo](https://twitter.com/kyndinfo). Wir freuen uns auf Deine Ergebnisse.
---
### Examples/README Id (examples/README-id.md)
# Galeri Contoh
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!
---
### Examples/README Pl (examples/README-pl.md)
# Galeria przykładów
To jest zbiór przykładów wyciągniętych z rozdziałów tej książki, wraz z udostępnionymi shaderami hojnie przekazanymi przez innych czytelników korzystających z [edytora online](http://editor.thebookofshaders.com/). Zachęcamy do eksplorowania i modyfikowania ich krok po kroku. Gdy stworzysz coś, z czego będziesz dumny, kliknij "Export", a następnie skopiuj "URL do kodu...". Prześlij go do [@bookofshaders](https://x.com/bookofshaders) lub [@kyndinfo](https://x.com/kyndinfo). Nie możemy się doczekać, aby to zobaczyć!
---
### Examples/README Ua (examples/README-ua.md)
# Галерея прикладів
Це колекція прикладів, взятих із розділів цієї книги разом із шейдерами, люб'язно наданими іншими читачами за допомогою [онлайн-редактора](http://editor.thebookofshaders.com/). Не соромтеся досліджувати та змінювати їх. Якщо у вас вийде приклад, яким ви пишаєтеся, зробіть експорт своїх роботи та надішліть його на адресу [@bookofshaders](https://twitter.com/bookofshaders) або [@kyndinfo](https://twitter.com/kyndinfo). Ми з нетерпінням чекатимемо!
---
### Examples/README Vi (examples/README-vi.md)
# Thư viện các ví dụ
Đây là một bộ sưu tập các ví dụ được trích từ các chương của quyển sách kèm theo các shader được những độ giả khác đóng góp trên [editor online](http://editor.thebookofshaders.com/). Bạn có thể tự do khám phá và sửa code tuỳ ý. Nếu bạn thấy ưng ý với bất kỳ tác phẩm nào của mình, bạn có thể click nút "Export" và copy "URL to code...". Sau đó gửi tới địa chỉ [@bookofshaders](https://twitter.com/bookofshaders) hoặc [@kyndinfo](https://twitter.com/kyndinfo). Chúng tôi rất mong chờ được bổ sung các tác phẩm của bạn vào thư viện.
---
### Glossary/README (glossary/README.md)
# Glossary
## By theme
* TYPES
[void](./?search=void)
[bool](./?search=bool)
[int](./?search=int)
[float](./?search=float)
[bvec2](./?search=bvec2)
[bvec3](./?search=bvec3)
[bvec4](./?search=bvec4)
[ivec2](./?search=ivec2)
[ivec3](./?search=ivec3)
[ivec4](./?search=ivec4)
[vec2](./?search=vec2)
[vec3](./?search=vec3)
[vec4](./?search=vec4)
[mat2](./?search=mat2)
[mat3](./?search=mat3)
[mat4](./?search=mat4)
[sampler2D](./?search=sampler2D)
[samplerCube](./?search=samplerCube)
[struct](./?search=struct)
* QUALIFIERS
[attribute](./?search=attribute)
[const](./?search=const)
[uniform](./?search=uniform)
[varying](./?search=varying)
[precision](./?search=precision)
[highp](./?search=highp)
[mediump](./?search=mediump)
[lowp](./?search=lowp)
[in](./?search=in)
[out](./?search=out)
[inout](./?search=inout)
* BUILT-IN VARIABLES
[gl_Position](./?search=gl_Position)
[gl_PointSize](./?search=gl_PointSize)
[gl_PointCoord](index.hmtl#gl_PointCoord)
[gl_FrontFacing](./?search=gl_FrontFacing)
[gl_FragCoord](./?search=gl_FragCoord)
[gl_FragColor](./?search=gl_FragColor)
* BUILT-IN CONSTANTS
[gl_MaxVertexAttribs](./?search=gl_MaxVertexAttribs)
[gl_MaxVaryingVectors](./?search=gl_MaxVaryingVectors)
[gl_MaxVertexTextureImageUnits](./?search=gl_MaxVertexTextureImageUnits)
[gl_MaxCombinedTextureImageUnits](./?search=gl_MaxCombinedTextureImageUnits)
[gl_MaxTextureImageUnits](./?search=gl_MaxTextureImageUnits)
[gl_MaxFragmentUniformVectors](./?search=gl_MaxFragmentUniformVectors)
[gl_MaxDrawBuffers](./?search=gl_MaxDrawBuffers)
* ANGLE & TRIGONOMETRY FUNCTIONS
[radians()](./?search=radians)
[degrees()](./?search=degrees)
[sin()](./?search=sin)
[cos()](./?search=cos)
[tan()](./?search=tan)
[asin()](./?search=asin)
[acos()](./?search=acos)
[atan()](./?search=atan)
* EXPONENTIAL FUNCTIONS
[pow()](./?search=pow)
[exp()](./?search=exp)
[log()](./?search=log)
[exp2()](./?search=exp2)
[log2()](./?search=log2)
[sqrt()](./?search=sqrt)
[inversesqrt()](./?search=inversesqrt)
* COMMON FUNCTIONS
[abs()](./?search=abs)
[sign()](./?search=sign)
[floor()](./?search=floor)
[ceil()](./?search=ceil)
[fract()](./?search=fract)
[mod()](./?search=mod)
[min()](./?search=min)
[max()](./?search=max)
[clamp()](./?search=clamp)
[mix()](./?search=mix)
[step()](./?search=step)
[smoothstep()](./?search=smoothstep)
* GEOMETRIC FUNCTIONS
[length()](./?search=length)
[distance()](./?search=distance)
[dot()](./?search=dot)
[cross()](./?search=cross)
[normalize()](./?search=normalize)
[faceforward()](./?search=faceforward)
[reflect()](./?search=reflect)
[refract()](./?search=refract)
* MATRIX FUNCTIONS
[matrixCompMult()](./?search=matrixCompMult)
* VECTOR RELATIONAL FUNCTIONS
[lessThan()](./?search=lessThan)
[lessThanEqual()](./?search=lessThanEqual)
[greaterThan()](./?search=greaterThan)
[greaterThanEqual()](./?search=greaterThanEqual)
[equal()](./?search=equal)
[notEqual()](./?search=notEqual)
[any()](./?search=any)
[all()](./?search=all)
[not()](./?search=not)
* TEXTURE LOOKUP FUNCTIONS
[texture2D()](./?search=texture2D)
[textureCube()](./?search=textureCube)
## Alphabetical
* A
[abs()](./?search=abs)
[acos()](./?search=acos)
[all()](./?search=all)
[any()](./?search=any)
[asin()](./?search=asin)
[atan()](./?search=atan)
[attribute](./?search=attribute)
* B
[bool](./?search=bool)
[bvec2](./?search=bvec2)
[bvec3](./?search=bvec3)
[bvec4](./?search=bvec4)
* C
[ceil()](./?search=ceil)
[clamp()](./?search=clamp)
[const](./?search=const)
[cos()](./?search=cos)
[cross()](./?search=cross)
* D
[degrees()](./?search=degrees)
[dFdx()](./?search=dFdx)
[dFdy()](./?search=dFdy)
[distance()](./?search=distance)
[dot()](./?search=dot)
* E
[equal()](./?search=equal)
[exp()](./?search=exp)
[exp2()](./?search=exp2)
* F
[faceforward()](./?search=faceforward)
[float](./?search=float)
[floor()](./?search=floor)
[fract()](./?search=fract)
* G
[greaterThan()](./?search=greaterThan)
[greaterThanEqual()](./?search=greaterThanEqual)
[gl_FragColor](./?search=gl_FragColor)
[gl_FragCoord](./?search=gl_FragCoord)
[gl_FrontFacing](./?search=gl_FrontFacing)
[gl_PointCoord](index.hmtl#gl_PointCoord)
[gl_PointSize](./?search=gl_PointSize)
[gl_Position](./?search=gl_Position)
[gl_MaxCombinedTextureImageUnits](./?search=gl_MaxCombinedTextureImageUnits)
[gl_MaxDrawBuffers](./?search=gl_MaxDrawBuffers)
[gl_MaxFragmentUniformVectors](./?search=gl_MaxFragmentUniformVectors)
[gl_MaxVaryingVectors](./?search=gl_MaxVaryingVectors)
[gl_MaxVertexAttribs](./?search=gl_MaxVertexAttribs)
[gl_MaxVertexTextureImageUnits](./?search=gl_MaxVertexTextureImageUnits)
[gl_MaxTextureImageUnits](./?search=gl_MaxTextureImageUnits)
* H
[highp](./?search=highp)
* I
[in](./?search=in)
[inout](./?search=inout)
[int](./?search=int)
[inversesqrt()](./?search=inversesqrt)
[ivec2](./?search=ivec2)
[ivec3](./?search=ivec3)
[ivec4](./?search=ivec4)
* L
[length()](./?search=length)
[lessThan()](./?search=lessThan)
[lessThanEqual()](./?search=lessThanEqual)
[log()](./?search=log)
[log2()](./?search=log2)
[lowp](./?search=lowp)
* M
[matrixCompMult()](./?search=matrixCompMult)
[mat2](./?search=mat2)
[mat3](./?search=mat3)
[mat4](./?search=mat4)
[max()](./?search=max)
[mediump](./?search=mediump)
[min()](./?search=min)
[mix()](./?search=mix)
[mod()](./?search=mod)
* N
[normalize()](./?search=normalize)
[not()](./?search=not)
[notEqual()](./?search=notEqual)
* O
[out](./?search=out)
* P
[precision](./?search=precision)
[pow()](./?search=pow)
* R
[radians()](./?search=radians)
[reflect()](./?search=reflect)
[refract()](./?search=refract)
* S
[sampler2D](./?search=sampler2D)
[samplerCube](./?search=samplerCube)
[sign()](./?search=sign)
[sin()](./?search=sin)
[smoothstep()](./?search=smoothstep)
[sqrt()](./?search=sqrt)
[step()](./?search=step)
[struct](./?search=struct)
* T
[tan()](./?search=tan)
[texture2D()](./?search=texture2D)
[textureCube()](./?search=textureCube)
* U
[uniform](./?search=uniform)
* V
[varying](./?search=varying)
[vec2](./?search=vec2)
[vec3](./?search=vec3)
[vec4](./?search=vec4)
[void](./?search=void)
---
### Glossary/README Tr (glossary/README-tr.md)
# Sözlük
## Konuya göre
* TİPLER
[void](./?search=void)
[bool](./?search=bool)
[int](./?search=int)
[float](./?search=float)
[bvec2](./?search=bvec2)
[bvec3](./?search=bvec3)
[bvec4](./?search=bvec4)
[ivec2](./?search=ivec2)
[ivec3](./?search=ivec3)
[ivec4](./?search=ivec4)
[vec2](./?search=vec2)
[vec3](./?search=vec3)
[vec4](./?search=vec4)
[mat2](./?search=mat2)
[mat3](./?search=mat3)
[mat4](./?search=mat4)
[sampler2D](./?search=sampler2D)
[samplerCube](./?search=samplerCube)
[struct](./?search=struct)
* NİTELEYİCİLER
[attribute](./?search=attribute)
[const](./?search=const)
[uniform](./?search=uniform)
[varying](./?search=varying)
[precision](./?search=precision)
[highp](./?search=highp)
[mediump](./?search=mediump)
[lowp](./?search=lowp)
[in](./?search=in)
[out](./?search=out)
[inout](./?search=inout)
* YERLEŞİK DEĞİŞKENLER
[gl_Position](./?search=gl_Position)
[gl_PointSize](./?search=gl_PointSize)
[gl_PointCoord](index.hmtl#gl_PointCoord)
[gl_FrontFacing](./?search=gl_FrontFacing)
[gl_FragCoord](./?search=gl_FragCoord)
[gl_FragColor](./?search=gl_FragColor)
* YERLEŞİK SABİTLER
[gl_MaxVertexAttribs](./?search=gl_MaxVertexAttribs)
[gl_MaxVaryingVectors](./?search=gl_MaxVaryingVectors)
[gl_MaxVertexTextureImageUnits](./?search=gl_MaxVertexTextureImageUnits)
[gl_MaxCombinedTextureImageUnits](./?search=gl_MaxCombinedTextureImageUnits)
[gl_MaxTextureImageUnits](./?search=gl_MaxTextureImageUnits)
[gl_MaxFragmentUniformVectors](./?search=gl_MaxFragmentUniformVectors)
[gl_MaxDrawBuffers](./?search=gl_MaxDrawBuffers)
* AÇI VE TRİGONOMETRİ FONKSİYONLARI
[radians()](./?search=radians)
[degrees()](./?search=degrees)
[sin()](./?search=sin)
[cos()](./?search=cos)
[tan()](./?search=tan)
[asin()](./?search=asin)
[acos()](./?search=acos)
[atan()](./?search=atan)
* ÜSTEL FONKSİYONLAR
[pow()](./?search=pow)
[exp()](./?search=exp)
[log()](./?search=log)
[exp2()](./?search=exp2)
[log2()](./?search=log2)
[sqrt()](./?search=sqrt)
[inversesqrt()](./?search=inversesqrt)
* ORTAK FONKSİYONLAR
[abs()](./?search=abs)
[sign()](./?search=sign)
[floor()](./?search=floor)
[ceil()](./?search=ceil)
[fract()](./?search=fract)
[mod()](./?search=mod)
[min()](./?search=min)
[max()](./?search=max)
[clamp()](./?search=clamp)
[mix()](./?search=mix)
[step()](./?search=step)
[smoothstep()](./?search=smoothstep)
* GEOMETRİK FONKSİYONLAR
[length()](./?search=length)
[distance()](./?search=distance)
[dot()](./?search=dot)
[cross()](./?search=cross)
[normalize()](./?search=normalize)
[faceforward()](./?search=faceforward)
[reflect()](./?search=reflect)
[refract()](./?search=refract)
* MATRİS FONKSİYONLARI
[matrixCompMult()](./?search=matrixCompMult)
* VEKTÖR İLİŞKİSEL FONKSİYONLARI
[lessThan()](./?search=lessThan)
[lessThanEqual()](./?search=lessThanEqual)
[greaterThan()](./?search=greaterThan)
[greaterThanEqual()](./?search=greaterThanEqual)
[equal()](./?search=equal)
[notEqual()](./?search=notEqual)
[any()](./?search=any)
[all()](./?search=all)
[not()](./?search=not)
* DOKU ARAMA FONKSİYONLARI
[texture2D()](./?search=texture2D)
[textureCube()](./?search=textureCube)
## Alfabetik
* A
[abs()](./?search=abs)
[acos()](./?search=acos)
[all()](./?search=all)
[any()](./?search=any)
[asin()](./?search=asin)
[atan()](./?search=atan)
[attribute](./?search=attribute)
* B
[bool](./?search=bool)
[bvec2](./?search=bvec2)
[bvec3](./?search=bvec3)
[bvec4](./?search=bvec4)
* C
[ceil()](./?search=ceil)
[clamp()](./?search=clamp)
[const](./?search=const)
[cos()](./?search=cos)
[cross()](./?search=cross)
* D
[degrees()](./?search=degrees)
[dFdx()](./?search=dFdx)
[dFdy()](./?search=dFdy)
[distance()](./?search=distance)
[dot()](./?search=dot)
* E
[equal()](./?search=equal)
[exp()](./?search=exp)
[exp2()](./?search=exp2)
* F
[faceforward()](./?search=faceforward)
[float](./?search=float)
[floor()](./?search=floor)
[fract()](./?search=fract)
* G
[greaterThan()](./?search=greaterThan)
[greaterThanEqual()](./?search=greaterThanEqual)
[gl_FragColor](./?search=gl_FragColor)
[gl_FragCoord](./?search=gl_FragCoord)
[gl_FrontFacing](./?search=gl_FrontFacing)
[gl_PointCoord](index.hmtl#gl_PointCoord)
[gl_PointSize](./?search=gl_PointSize)
[gl_Position](./?search=gl_Position)
[gl_MaxCombinedTextureImageUnits](./?search=gl_MaxCombinedTextureImageUnits)
[gl_MaxDrawBuffers](./?search=gl_MaxDrawBuffers)
[gl_MaxFragmentUniformVectors](./?search=gl_MaxFragmentUniformVectors)
[gl_MaxVaryingVectors](./?search=gl_MaxVaryingVectors)
[gl_MaxVertexAttribs](./?search=gl_MaxVertexAttribs)
[gl_MaxVertexTextureImageUnits](./?search=gl_MaxVertexTextureImageUnits)
[gl_MaxTextureImageUnits](./?search=gl_MaxTextureImageUnits)
* H
[highp](./?search=highp)
* I
[in](./?search=in)
[inout](./?search=inout)
[int](./?search=int)
[inversesqrt()](./?search=inversesqrt)
[ivec2](./?search=ivec2)
[ivec3](./?search=ivec3)
[ivec4](./?search=ivec4)
* L
[length()](./?search=length)
[lessThan()](./?search=lessThan)
[lessThanEqual()](./?search=lessThanEqual)
[log()](./?search=log)
[log2()](./?search=log2)
[lowp](./?search=lowp)
* M
[matrixCompMult()](./?search=matrixCompMult)
[mat2](./?search=mat2)
[mat3](./?search=mat3)
[mat4](./?search=mat4)
[max()](./?search=max)
[mediump](./?search=mediump)
[min()](./?search=min)
[mix()](./?search=mix)
[mod()](./?search=mod)
* N
[normalize()](./?search=normalize)
[not()](./?search=not)
[notEqual()](./?search=notEqual)
* O
[out](./?search=out)
* P
[precision](./?search=precision)
[pow()](./?search=pow)
* R
[radians()](./?search=radians)
[reflect()](./?search=reflect)
[refract()](./?search=refract)
* S
[sampler2D](./?search=sampler2D)
[samplerCube](./?search=samplerCube)
[sign()](./?search=sign)
[sin()](./?search=sin)
[smoothstep()](./?search=smoothstep)
[sqrt()](./?search=sqrt)
[step()](./?search=step)
[struct](./?search=struct)
* T
[tan()](./?search=tan)
[texture2D()](./?search=texture2D)
[textureCube()](./?search=textureCube)
* U
[uniform](./?search=uniform)
* V
[varying](./?search=varying)
[vec2](./?search=vec2)
[vec3](./?search=vec3)
[vec4](./?search=vec4)
[void](./?search=void)
---
### Glossary/README Ua (glossary/README-ua.md)
# Глосарій
## За темою
* ТИПИ
[void](./?lan=ua&search=void)
[bool](./?lan=ua&search=bool)
[int](./?lan=ua&search=int)
[float](./?lan=ua&search=float)
[bvec2](./?lan=ua&search=bvec2)
[bvec3](./?lan=ua&search=bvec3)
[bvec4](./?lan=ua&search=bvec4)
[ivec2](./?lan=ua&search=ivec2)
[ivec3](./?lan=ua&search=ivec3)
[ivec4](./?lan=ua&search=ivec4)
[vec2](./?lan=ua&search=vec2)
[vec3](./?lan=ua&search=vec3)
[vec4](./?lan=ua&search=vec4)
[mat2](./?lan=ua&search=mat2)
[mat3](./?lan=ua&search=mat3)
[mat4](./?lan=ua&search=mat4)
[sampler2D](./?lan=ua&search=sampler2D)
[samplerCube](./?lan=ua&search=samplerCube)
[struct](./?lan=ua&search=struct)
* КВАЛІФІКАТОРИ
[attribute](./?lan=ua&search=attribute)
[const](./?lan=ua&search=const)
[uniform](./?lan=ua&search=uniform)
[varying](./?lan=ua&search=varying)
[precision](./?lan=ua&search=precision)
[highp](./?lan=ua&search=highp)
[mediump](./?lan=ua&search=mediump)
[lowp](./?lan=ua&search=lowp)
[in](./?lan=ua&search=in)
[out](./?lan=ua&search=out)
[inout](./?lan=ua&search=inout)
* ВБУДОВАНІ ЗМІННІ
[gl_Position](./?lan=ua&search=gl_Position)
[gl_PointSize](./?lan=ua&search=gl_PointSize)
[gl_PointCoord](./?lan=ua&gl_PointCoord)
[gl_FrontFacing](./?lan=ua&search=gl_FrontFacing)
[gl_FragCoord](./?lan=ua&search=gl_FragCoord)
[gl_FragColor](./?lan=ua&search=gl_FragColor)
* ВБУДОВАНІ КОНСТАНТИ
[gl_MaxVertexAttribs](./?lan=ua&search=gl_MaxVertexAttribs)
[gl_MaxVaryingVectors](./?lan=ua&search=gl_MaxVaryingVectors)
[gl_MaxVertexTextureImageUnits](./?lan=ua&search=gl_MaxVertexTextureImageUnits)
[gl_MaxCombinedTextureImageUnits](./?lan=ua&search=gl_MaxCombinedTextureImageUnits)
[gl_MaxTextureImageUnits](./?lan=ua&search=gl_MaxTextureImageUnits)
[gl_MaxFragmentUniformVectors](./?lan=ua&search=gl_MaxFragmentUniformVectors)
[gl_MaxDrawBuffers](./?lan=ua&search=gl_MaxDrawBuffers)
* ТРИГОНОМЕТРИЧНІ ТА КУТОВІ ФУНКЦІЇ
[radians()](./?lan=ua&search=radians)
[degrees()](./?lan=ua&search=degrees)
[sin()](./?lan=ua&search=sin)
[cos()](./?lan=ua&search=cos)
[tan()](./?lan=ua&search=tan)
[asin()](./?lan=ua&search=asin)
[acos()](./?lan=ua&search=acos)
[atan()](./?lan=ua&search=atan)
* ЕКСПОНЕНЦІАЛЬНІ ФУНКЦІЇ
[pow()](./?lan=ua&search=pow)
[exp()](./?lan=ua&search=exp)
[log()](./?lan=ua&search=log)
[exp2()](./?lan=ua&search=exp2)
[log2()](./?lan=ua&search=log2)
[sqrt()](./?lan=ua&search=sqrt)
[inversesqrt()](./?lan=ua&search=inversesqrt)
* ЗАГАЛЬНІ ФУНКЦІЇ
[abs()](./?lan=ua&search=abs)
[sign()](./?lan=ua&search=sign)
[floor()](./?lan=ua&search=floor)
[ceil()](./?lan=ua&search=ceil)
[fract()](./?lan=ua&search=fract)
[mod()](./?lan=ua&search=mod)
[min()](./?lan=ua&search=min)
[max()](./?lan=ua&search=max)
[clamp()](./?lan=ua&search=clamp)
[mix()](./?lan=ua&search=mix)
[step()](./?lan=ua&search=step)
[smoothstep()](./?lan=ua&search=smoothstep)
* ГЕОМЕТРИЧНІ ФУНКЦІЇ
[length()](./?lan=ua&search=length)
[distance()](./?lan=ua&search=distance)
[dot()](./?lan=ua&search=dot)
[cross()](./?lan=ua&search=cross)
[normalize()](./?lan=ua&search=normalize)
[facefoward()](./?lan=ua&search=facefoward)
[reflect()](./?lan=ua&search=reflect)
[refract()](./?lan=ua&search=refract)
* МАТРИЧНІ ФУНКЦІЇ
[matrixCompMult()](./?lan=ua&search=matrixCompMult)
* ФУНКЦІЇ ПОВ'ЯЗАНІ З ВЕКТОРАМИ
[lessThan()](./?lan=ua&search=lessThan)
[lessThanEqual()](./?lan=ua&search=lessThanEqual)
[greaterThan()](./?lan=ua&search=greaterThan)
[greaterThanEqual()](./?lan=ua&search=greaterThanEqual)
[equal()](./?lan=ua&search=equal)
[notEqual()](./?lan=ua&search=notEqual)
[any()](./?lan=ua&search=any)
[all()](./?lan=ua&search=all)
[not()](./?lan=ua&search=not)
* ФУНКЦІЇ ПОВ'ЯЗАНІ З ТЕКСТУРАМИ
[texture2D()](./?lan=ua&search=texture2D)
[textureCube()](./?lan=ua&search=textureCube)
## За алфавітом
* A
[abs()](./?lan=ua&search=abs)
[acos()](./?lan=ua&search=acos)
[all()](./?lan=ua&search=all)
[any()](./?lan=ua&search=any)
[asin()](./?lan=ua&search=asin)
[atan()](./?lan=ua&search=atan)
[attribute](./?lan=ua&search=attribute)
* B
[bool](./?lan=ua&search=bool)
[bvec2](./?lan=ua&search=bvec2)
[bvec3](./?lan=ua&search=bvec3)
[bvec4](./?lan=ua&search=bvec4)
* C
[ceil()](./?lan=ua&search=ceil)
[clamp()](./?lan=ua&search=clamp)
[const](./?lan=ua&search=const)
[cos()](./?lan=ua&search=cos)
[cross()](./?lan=ua&search=cross)
* D
[degrees()](./?lan=ua&search=degrees)
[dFdx()](./?lan=ua&search=dFdx)
[dFdy()](./?lan=ua&search=dFdy)
[distance()](./?lan=ua&search=distance)
[dot()](./?lan=ua&search=dot)
* E
[equal()](./?lan=ua&search=equal)
[exp()](./?lan=ua&search=exp)
[exp2()](./?lan=ua&search=exp2)
* F
[faceforward()](./?lan=ua&search=faceforward)
[float](./?lan=ua&search=float)
[floor()](./?lan=ua&search=floor)
[fract()](./?lan=ua&search=fract)
* G
[greaterThan()](./?lan=ua&search=greaterThan)
[greaterThanEqual()](./?lan=ua&search=greaterThanEqual)
[gl_FragColor](./?lan=ua&search=gl_FragColor)
[gl_FragCoord](./?lan=ua&search=gl_FragCoord)
[gl_FrontFacing](./?lan=ua&search=gl_FrontFacing)
[gl_PointCoord](./?lan=ua&gl_PointCoord)
[gl_PointSize](./?lan=ua&search=gl_PointSize)
[gl_Position](./?lan=ua&search=gl_Position)
[gl_MaxCombinedTextureImageUnits](./?lan=ua&search=gl_MaxCombinedTextureImageUnits)
[gl_MaxDrawBuffers](./?lan=ua&search=gl_MaxDrawBuffers)
[gl_MaxFragmentUniformVectors](./?lan=ua&search=gl_MaxFragmentUniformVectors)
[gl_MaxVaryingVectors](./?lan=ua&search=gl_MaxVaryingVectors)
[gl_MaxVertexAttribs](./?lan=ua&search=gl_MaxVertexAttribs)
[gl_MaxVertexTextureImageUnits](./?lan=ua&search=gl_MaxVertexTextureImageUnits)
[gl_MaxTextureImageUnits](./?lan=ua&search=gl_MaxTextureImageUnits)
* H
[highp](./?lan=ua&search=highp)
* I
[in](./?lan=ua&search=in)
[inout](./?lan=ua&search=inout)
[int](./?lan=ua&search=int)
[inversesqrt()](./?lan=ua&search=inversesqrt)
[ivec2](./?lan=ua&search=ivec2)
[ivec3](./?lan=ua&search=ivec3)
[ivec4](./?lan=ua&search=ivec4)
* L
[length()](./?lan=ua&search=length)
[lessThan()](./?lan=ua&search=lessThan)
[lessThanEqual()](./?lan=ua&search=lessThanEqual)
[log()](./?lan=ua&search=log)
[log2()](./?lan=ua&search=log2)
[lowp](./?lan=ua&search=lowp)
* M
[matrixCompMult()](./?lan=ua&search=matrixCompMult)
[mat2](./?lan=ua&search=mat2)
[mat3](./?lan=ua&search=mat3)
[mat4](./?lan=ua&search=mat4)
[max()](./?lan=ua&search=max)
[mediump](./?lan=ua&search=mediump)
[min()](./?lan=ua&search=min)
[mix()](./?lan=ua&search=mix)
[mod()](./?lan=ua&search=mod)
* N
[normalize()](./?lan=ua&search=normalize)
[not()](./?lan=ua&search=not)
[notEqual()](./?lan=ua&search=notEqual)
* O
[out](./?lan=ua&search=out)
* P
[precision](./?lan=ua&search=precision)
[pow()](./?lan=ua&search=pow)
* R
[radians()](./?lan=ua&search=radians)
[reflect()](./?lan=ua&search=reflect)
[refract()](./?lan=ua&search=refract)
[return](./?lan=ua&search=return)
* S
[sampler2D](./?lan=ua&search=sampler2D)
[samplerCube](./?lan=ua&search=samplerCube)
[sign()](./?lan=ua&search=sign)
[sin()](./?lan=ua&search=sin)
[smoothstep()](./?lan=ua&search=smoothstep)
[sqrt()](./?lan=ua&search=sqrt)
[step()](./?lan=ua&search=step)
[struct](./?lan=ua&search=struct)
* T
[tan()](./?lan=ua&search=tan)
[texture2D()](./?lan=ua&search=texture2D)
[textureCube()](./?lan=ua&search=textureCube)
* U
[uniform](./?lan=ua&search=uniform)
* V
[varying](./?lan=ua&search=varying)
[vec2](./?lan=ua&search=vec2)
[vec3](./?lan=ua&search=vec3)
[vec4](./?lan=ua&search=vec4)
[void](./?lan=ua&search=void)
---
### Glossary/README Vi (glossary/README-vi.md)
# Chú giải
## Xếp theo nhóm
* CÁC KIỂU DỮ LIỆU
[void](./?lan=vi&search=void),
[bool](./?lan=vi&search=bool),
[int](./?lan=vi&search=int),
[float](./?lan=vi&search=float),
[bvec2](./?lan=vi&search=bvec2),
[bvec3](./?lan=vi&search=bvec3),
[bvec4](./?lan=vi&search=bvec4),
[ivec2](./?lan=vi&search=ivec2),
[ivec3](./?lan=vi&search=ivec3),
[ivec4](./?lan=vi&search=ivec4),
[vec2](./?lan=vi&search=vec2),
[vec3](./?lan=vi&search=vec3),
[vec4](./?lan=vi&search=vec4),
[mat2](./?lan=vi&search=mat2),
[mat3](./?lan=vi&search=mat3),
[mat4](./?lan=vi&search=mat4),
[sampler2D](./?lan=vi&search=sampler2D),
[samplerCube](./?lan=vi&search=samplerCube),
[struct](./?lan=vi&search=struct)
* CÁC QUALIFIER
[attribute](./?lan=vi&search=attribute),
[const](./?lan=vi&search=const),
[uniform](./?lan=vi&search=uniform),
[varying](./?lan=vi&search=varying),
[precision](./?lan=vi&search=precision),
[highp](./?lan=vi&search=highp),
[mediump](./?lan=vi&search=mediump),
[lowp](./?lan=vi&search=lowp),
[in](./?lan=vi&search=in),
[out](./?lan=vi&search=out),
[inout](./?lan=vi&search=inout)
* CÁC BIẾN CÓ SẴN
[gl_Position](./?lan=vi&search=gl_Position),
[gl_PointSize](./?lan=vi&search=gl_PointSize),
[gl_PointCoord](index.hmtl#gl_PointCoord),
[gl_FrontFacing](./?lan=vi&search=gl_FrontFacing),
[gl_FragCoord](./?lan=vi&search=gl_FragCoord),
[gl_FragColor](./?lan=vi&search=gl_FragColor)
* CÁC HẰNG SỐ CÓ SẴN
[gl_MaxVertexAttribs](./?lan=vi&search=gl_MaxVertexAttribs),
[gl_MaxVaryingVectors](./?lan=vi&search=gl_MaxVaryingVectors),
[gl_MaxVertexTextureImageUnits](./?lan=vi&search=gl_MaxVertexTextureImageUnits),
[gl_MaxCombinedTextureImageUnits](./?lan=vi&search=gl_MaxCombinedTextureImageUnits),
[gl_MaxTextureImageUnits](./?lan=vi&search=gl_MaxTextureImageUnits),
[gl_MaxFragmentUniformVectors](./?lan=vi&search=gl_MaxFragmentUniformVectors),
[gl_MaxDrawBuffers](./?lan=vi&search=gl_MaxDrawBuffers)
* CÁC HÀM LƯỢNG GIÁC
[radians()](./?lan=vi&search=radians),
[degrees()](./?lan=vi&search=degrees),
[sin()](./?lan=vi&search=sin),
[cos()](./?lan=vi&search=cos),
[tan()](./?lan=vi&search=tan),
[asin()](./?lan=vi&search=asin),
[acos()](./?lan=vi&search=acos),
[atan()](./?lan=vi&search=atan)
* CÁC HÀM LUỸ THỪA
[pow()](./?lan=vi&search=pow),
[exp()](./?lan=vi&search=exp),
[log()](./?lan=vi&search=log),
[exp2()](./?lan=vi&search=exp2),
[log2()](./?lan=vi&search=log2),
[sqrt()](./?lan=vi&search=sqrt),
[inversesqrt()](./?lan=vi&search=inversesqrt)
* CÁC HÀM TOÁN HỌC CƠ BẢN
[abs()](./?lan=vi&search=abs),
[sign()](./?lan=vi&search=sign),
[floor()](./?lan=vi&search=floor),
[ceil()](./?lan=vi&search=ceil),
[fract()](./?lan=vi&search=fract),
[mod()](./?lan=vi&search=mod),
[min()](./?lan=vi&search=min),
[max()](./?lan=vi&search=max),
[clamp()](./?lan=vi&search=clamp),
[mix()](./?lan=vi&search=mix),
[step()](./?lan=vi&search=step),
[smoothstep()](./?lan=vi&search=smoothstep)
* CÁC HÀM HÌNH HỌC
[length()](./?lan=vi&search=length),
[distance()](./?lan=vi&search=distance),
[dot()](./?lan=vi&search=dot),
[cross()](./?lan=vi&search=cross),
[normalize()](./?lan=vi&search=normalize),
[facefoward()](./?lan=vi&search=facefoward),
[reflect()](./?lan=vi&search=reflect),
[refract()](./?lan=vi&search=refract)
* CÁC HÀM MA TRẬN
[matrixCompMult()](./?lan=vi&search=matrixCompMult)
* CÁC HÀM VECTOR
[lessThan()](./?lan=vi&search=lessThan),
[lessThanEqual()](./?lan=vi&search=lessThanEqual),
[greaterThan()](./?lan=vi&search=greaterThan),
[greaterThanEqual()](./?lan=vi&search=greaterThanEqual),
[equal()](./?lan=vi&search=equal),
[notEqual()](./?lan=vi&search=notEqual),
[any()](./?lan=vi&search=any),
[all()](./?lan=vi&search=all),
[not()](./?lan=vi&search=not)
* CÁC HÀM TEXTURE
[texture2D()](./?lan=vi&search=texture2D),
[textureCube()](./?lan=vi&search=textureCube)
## Xếp theo thứ tự từ điển
* A
[abs()](./?lan=vi&search=abs),
[acos()](./?lan=vi&search=acos),
[all()](./?lan=vi&search=all),
[any()](./?lan=vi&search=any),
[asin()](./?lan=vi&search=asin),
[atan()](./?lan=vi&search=atan),
[attribute](./?lan=vi&search=attribute)
* B
[bool](./?lan=vi&search=bool),
[bvec2](./?lan=vi&search=bvec2),
[bvec3](./?lan=vi&search=bvec3),
[bvec4](./?lan=vi&search=bvec4)
* C
[ceil()](./?lan=vi&search=ceil),
[clamp()](./?lan=vi&search=clamp),
[const](./?lan=vi&search=const),
[cos()](./?lan=vi&search=cos),
[cross()](./?lan=vi&search=cross)
* D
[degrees()](./?lan=vi&search=degrees),
[dFdx()](./?lan=vi&search=dFdx),
[dFdy()](./?lan=vi&search=dFdy),
[distance()](./?lan=vi&search=distance),
[dot()](./?lan=vi&search=dot)
* E
[equal()](./?lan=vi&search=equal),
[exp()](./?lan=vi&search=exp),
[exp2()](./?lan=vi&search=exp2)
* F
[faceforward()](./?lan=vi&search=faceforward),
[float](./?lan=vi&search=float),
[floor()](./?lan=vi&search=floor),
[fract()](./?lan=vi&search=fract)
* G
[greaterThan()](./?lan=vi&search=greaterThan),
[greaterThanEqual()](./?lan=vi&search=greaterThanEqual),
[gl_FragColor](./?lan=vi&search=gl_FragColor),
[gl_FragCoord](./?lan=vi&search=gl_FragCoord),
[gl_FrontFacing](./?lan=vi&search=gl_FrontFacing),
[gl_PointCoord](index.hmtl#gl_PointCoord),
[gl_PointSize](./?lan=vi&search=gl_PointSize),
[gl_Position](./?lan=vi&search=gl_Position),
[gl_MaxCombinedTextureImageUnits](./?lan=vi&search=gl_MaxCombinedTextureImageUnits),
[gl_MaxDrawBuffers](./?lan=vi&search=gl_MaxDrawBuffers),
[gl_MaxFragmentUniformVectors](./?lan=vi&search=gl_MaxFragmentUniformVectors),
[gl_MaxVaryingVectors](./?lan=vi&search=gl_MaxVaryingVectors),
[gl_MaxVertexAttribs](./?lan=vi&search=gl_MaxVertexAttribs),
[gl_MaxVertexTextureImageUnits](./?lan=vi&search=gl_MaxVertexTextureImageUnits),
[gl_MaxTextureImageUnits](./?lan=vi&search=gl_MaxTextureImageUnits)
* H
[highp](./?lan=vi&search=highp)
* I
[in](./?lan=vi&search=in),
[inout](./?lan=vi&search=inout),
[int](./?lan=vi&search=int),
[inversesqrt()](./?lan=vi&search=inversesqrt),
[ivec2](./?lan=vi&search=ivec2),
[ivec3](./?lan=vi&search=ivec3),
[ivec4](./?lan=vi&search=ivec4)
* L
[length()](./?lan=vi&search=length),
[lessThan()](./?lan=vi&search=lessThan),
[lessThanEqual()](./?lan=vi&search=lessThanEqual),
[log()](./?lan=vi&search=log),
[log2()](./?lan=vi&search=log2),
[lowp](./?lan=vi&search=lowp)
* M
[matrixCompMult()](./?lan=vi&search=matrixCompMult),
[mat2](./?lan=vi&search=mat2),
[mat3](./?lan=vi&search=mat3),
[mat4](./?lan=vi&search=mat4),
[max()](./?lan=vi&search=max),
[mediump](./?lan=vi&search=mediump),
[min()](./?lan=vi&search=min),
[mix()](./?lan=vi&search=mix),
[mod()](./?lan=vi&search=mod)
* N
[normalize()](./?lan=vi&search=normalize),
[not()](./?lan=vi&search=not),
[notEqual()](./?lan=vi&search=notEqual)
* O
[out](./?lan=vi&search=out)
* P
[precision](./?lan=vi&search=precision),
[pow()](./?lan=vi&search=pow)
* R
[radians()](./?lan=vi&search=radians),
[reflect()](./?lan=vi&search=reflect),
[refract()](./?lan=vi&search=refract)
* S
[sampler2D](./?lan=vi&search=sampler2D),
[samplerCube](./?lan=vi&search=samplerCube),
[sign()](./?lan=vi&search=sign),
[sin()](./?lan=vi&search=sin),
[smoothstep()](./?lan=vi&search=smoothstep),
[sqrt()](./?lan=vi&search=sqrt),
[step()](./?lan=vi&search=step),
[struct](./?lan=vi&search=struct)
* T
[tan()](./?lan=vi&search=tan),
[texture2D()](./?lan=vi&search=texture2D),
[textureCube()](./?lan=vi&search=textureCube)
* U
[uniform](./?lan=vi&search=uniform)
* V
[varying](./?lan=vi&search=varying),
[vec2](./?lan=vi&search=vec2),
[vec3](./?lan=vi&search=vec3),
[vec4](./?lan=vi&search=vec4),
[void](./?lan=vi&search=void)
---
### Glossary/Abs/README (glossary/abs/README.md)
## Abs
Return the absolute value of the parameter.
### Declaration
```glsl
float abs(float x)
vec2 abs(vec2 x)
vec3 abs(vec3 x)
vec4 abs(vec4 x)
```
### Parameters
```x``` specifies the value of which to return the absolute.
### Description
```abs()``` returns the absolute value of ```x```.
### See Also
[sign()](/glossary/?search=sign), [min()](/glossary/?search=min), [max()](/glossary/?search=max), [Chapter 05: Shaping Functions](../05/)
---
### Glossary/Abs/README Pl (glossary/abs/README-pl.md)
## abs
Zwraca wartość bezwzględną z parametru.
### Deklaracja
```glsl
float abs(float x)
vec2 abs(vec2 x)
vec3 abs(vec3 x)
vec4 abs(vec4 x)
```
### Parametry
```x``` określa wartość, z której ma zostać zwrócona wartość bezwzględna.
### Opis
```abs()``` zwraca wartość bezwzględną z x.
### Zobacz też
[sign()](/glossary/?lan=pl&search=sign), [min()](/glossary/?lan=pl&search=min), [max()](/glossary/?lan=pl&search=max), [Rozdział 05: Shaping Functions](../05/?lan=pl)
---
### Glossary/Abs/README Ua (glossary/abs/README-ua.md)
## abs
Повертає абсолютне значення параметра.
### Оголошення
```glsl
float abs(float x)
vec2 abs(vec2 x)
vec3 abs(vec3 x)
vec4 abs(vec4 x)
```
### Параметри
**```x```** — значення, яке потрібно повернути в абсолют.
### Опис
**```abs()```** повертає абсолютне значення **`x`**.
### Дивіться також
[sign()](/glossary/?lan=ua&search=sign), [min()](/glossary/?lan=ua&search=min), [max()](/glossary/?lan=ua&search=max), [Розділ 05: Формотворчі функції](/05/?lan=ua)
---
### Glossary/Abs/README Vi (glossary/abs/README-vi.md)
## Abs
Tính giá trị tuyệt đối của một hoặc nhiều số.
### Các phiên bản
```glsl
float abs(float x)
vec2 abs(vec2 x)
vec3 abs(vec3 x)
vec4 abs(vec4 x)
```
### Các tham số
```x``` số muốn tính giá trị tuyệt đối
### Mô tả
```abs()``` trả về giá trị tuyệt đối của ```x```.
### Tham khảo thêm
[sign()](/glossary/?lan=vi&search=sign), [min()](/glossary/?lan=vi&search=min), [max()](/glossary/?lan=vi&search=max), [Chương 5: Các hàm số cơ bản](../05/?lan=vi)
---
### Glossary/Acos/README (glossary/acos/README.md)
## Acos
Return the arccosine of the parameter
### Declaration
```glsl
float acos(float x)
vec2 acos(vec2 x)
vec3 acos(vec3 x)
vec4 acos(vec4 x)
```
### Parameters
```x``` specifies the value whose arccosine to return.
### Description
```acos()``` returns the angle whose trigonometric cosine is ```x```.
### See Also
[cos()](/glossary/?search=cos), [sin()](/glossary/?search=sin), [asin()](/glossary/?search=asin), [tan()](/glossary/?search=tan), [atan()](/glossary/?search=atan), [Chapter 05: Shaping Functions](/05/)
---
### Glossary/Acos/README Pl (glossary/acos/README-pl.md)
## acos
Zwraca arcus cosinus podanego argumentu
### Deklaracja
```glsl
float acos(float x)
vec2 acos(vec2 x)
vec3 acos(vec3 x)
vec4 acos(vec4 x)
```
### Parametry
```x``` wartość, której arcus cosinus ma zostać zwrócony.
### Opis
```acos()``` zwraca kąt, którego cosinus jest równy ```x```.
### Zobacz też
[cos()](/glossary/?lan=pl&search=cos), [sin()](/glossary/?lan=pl&search=sin), [asin()](/glossary/?lan=pl&search=asin), [tan()](/glossary/?lan=pl&search=tan), [atan()](/glossary/?lan=pl&search=atan), [Rozdział 05: Shaping Functions](/05/?lan=pl)
---
### Glossary/Acos/README Ua (glossary/acos/README-ua.md)
## acos
Повертає арккосинус параметра
### Оголошення
```glsl
float acos(float x)
vec2 acos(vec2 x)
vec3 acos(vec3 x)
vec4 acos(vec4 x)
```
### Параметри
**```x```** — значення, арккосинус якого потрібно повернути.
### Опис
**```acos()```** повертає кут, тригонометричний косинус якого дорівнює **`x`**.
### Дивіться також
[cos()](/glossary/?lan=ua&search=cos), [sin()](/glossary/?lan=ua&search=sin), [asin()](/glossary/?lan=ua&search=asin), [tan()](/glossary/?lan=ua&search=tan), [atan()](/glossary/?lan=ua&search=atan), [Розділ 05: Формотворчі функції](/05/?lan=ua)
---
### Glossary/Acos/README Vi (glossary/acos/README-vi.md)
## Acos
Tính góc lượng giác ứng với giá trị cosine
### Các phiên bản
```glsl
float acos(float x)
vec2 acos(vec2 x)
vec3 acos(vec3 x)
vec4 acos(vec4 x)
```
### Các tham số
```x``` giá trị cosine cần tìm góc lượng giác tương ứng
### Mô tả
```acos()``` góc lượng giác (đơn vị radian) ứng với cosine bằng ```x```.
### Tham khảo thêm
[cos()](/glossary/?lan=vi&search=cos), [sin()](/glossary/?lan=vi&search=sin), [asin()](/glossary/?lan=vi&search=asin), [tan()](/glossary/?lan=vi&search=tan), [atan()](/glossary/?lan=vi&search=atan), [Các hàm số cơ bản (Hàm hình dạng - Shape function)](/05/?lan=vi)
---
### Glossary/All/README (glossary/all/README.md)
## All
Check whether all elements of a boolean vector are true
### Declaration
```glsl
bool any(bvec2 x)
bool any(bvec3 x)
bool any(bvec4 x)
```
### Parameters
```x``` specifies the vector to be tested for truth.
### Description
```all()``` returns true if all elements of ```x``` are ```true``` and ```false``` otherwise. It is functionally equivalent to:
```glsl
bool all(bvec x){ // bvec can be bvec2, bvec3 or bvec4
bool result = true;
int i;
for (i = 0; i < x.length(); ++i)
{
result &= x[i];
}
return result;
}
```
### See Also
[any()](/glossary/?search=any), [not()](/glossary/?search=not)
---
### Glossary/All/README Pl (glossary/all/README-pl.md)
## all
Sprawdza, czy wszystkie elementy wektora logicznego są prawdziwe
### Deklaracja
```glsl
bool all(bvec2 x)
bool all(bvec3 x)
bool all(bvec4 x)
```
### Parametry
```x``` określa wektor, który ma zostać sprawdzony pod kątem prawdy.
### Opis
```all()``` zwraca ```true```, jeśli wszystkie elementy ```x``` są ```true``` i ```false``` w przeciwnym razie. Jest to funkcjonalnie równoważne:
```glsl
bool all(bvec x){ // bvec może być bvec2, bvec3 lub bvec4
bool result = true;
int i;
for (i = 0; i < x.length(); ++i)
{
result &= x[i];
}
return result;
}
```
### Zobacz też
[any()](/glossary/?lan=pl&search=any), [not()](/glossary/?lan=pl&search=not)
---
### Glossary/All/README Ua (glossary/all/README-ua.md)
## all
Перевіряє чи всі елементи логічного вектора істинні
### Оголошення
```glsl
bool any(bvec2 x)
bool any(bvec3 x)
bool any(bvec4 x)
```
### Параметри
**```x```** — вектор, який буде перевірено на істинність.
### Опис
**```all()```** повертає **`true`**, якщо всі елементи **`x`** мають значення **`true`**, інакше повертається **`false`**. Функціонально це еквівалентно до наступного коду:
```glsl
bool all(bvec x) { // bvec може бути bvec2, bvec3 або bvec4
bool result = true;
int i;
for (i = 0; i < x.length(); ++i) {
result &= x[i];
}
return result;
}
```
### Дивіться також
[any()](/glossary/?lan=ua&search=any), [not()](/glossary/?lan=ua&search=not)
---
### Glossary/All/README Vi (glossary/all/README-vi.md)
## All
Kiểm tra xem toàn bộ các thành phần trong 1 vector boolean có cùng bằng true không
### Các phiên bản
```glsl
bool any(bvec2 x)
bool any(bvec3 x)
bool any(bvec4 x)
```
### Các tham số
```x``` vector boolean cần kiểm tra
### Mô tả
```all()``` trả về ```true``` nếu tất cả các thành phần trong vector ```x``` đều bằng ```true``` và trả về ```false``` nếu ngược lại. Tương đương với:
```glsl
bool all(bvec x){ // bvec có thể thay bằng bvec2, bvec3 or bvec4
bool result = true;
int i;
for (i = 0; i < x.length(); ++i)
{
result &= x[i];
}
return result;
}
```
### Tham khảo thêm
[any()](/glossary/?lan=vi&search=any), [not()](/glossary/?lan=vi&search=not)
---
### Glossary/Any/README (glossary/any/README.md)
## Any
Check whether any element of a boolean vector is true
### Declaration
```glsl
bool all(bvec2 x)
bool all(bvec3 x)
bool all(bvec4 x)
```
### Parameters
```x``` specifies the vector to be tested for truth.
### Description
```any()``` returns true if any element of ```x``` is ```true``` and ```false``` otherwise. It is functionally equivalent to:
```glsl
bool any(bvec x) { // bvec can be bvec2, bvec3 or bvec4
bool result = false;
int i;
for (i = 0; i < x.length(); ++i) {
result |= x[i];
}
return result;
}
```
### See Also
[any()](/glossary/?search=any), [not()](/glossary/?search=not)
---
### Glossary/Any/README Pl (glossary/any/README-pl.md)
## any
Sprawdza, czy choć jeden element wektora logicznego jest prawdziwy
### Deklaracja
```glsl
bool all(bvec2 x)
bool all(bvec3 x)
bool all(bvec4 x)
```
### Parametry
```x``` określa wektor, który ma zostać sprawdzony pod kątem prawdy.
### Opis
```all()``` zwraca ```true```, jeśli którykolwiek element ```x``` jest ```true``` i ```false``` w przeciwnym razie. Jest to funkcjonalnie równoważne:
```glsl
bool any(bvec x) { // bvec może być bvec2, bvec3 lub bvec4
bool result = false;
int i;
for (i = 0; i < x.length(); ++i) {
result |= x[i];
}
return result;
}
```
### Zobacz też
[any()](/glossary/?lan=pl&search=any), [not()](/glossary/?lan=pl&search=not)
---
### Glossary/Any/README Ua (glossary/any/README-ua.md)
## any
Перевіряє чи хоча б один елемент булевого вектора має значення true
### Оголошення
```glsl
bool all(bvec2 x)
bool all(bvec3 x)
bool all(bvec4 x)
```
### Параметри
**```x```** — вектор, який буде перевірено на істинність.
### Опис
**```any()```** повертає **`true`**, якщо будь-який елемент **`x`** має значення **`true`**, інакше повертається **`false`**. Функціонально це еквівалентно до наступного коду:
```glsl
bool any(bvec x) { // bvec може бути bvec2, bvec3 або bvec4
bool result = false;
int i;
for (i = 0; i < x.length(); ++i) {
result |= x[i];
}
return result;
}
```
### Дивіться також
[any()](/glossary/?lan=ua&search=any), [not()](/glossary/?lan=ua&search=not)
---
### Glossary/Any/README Vi (glossary/any/README-vi.md)
## Any
Kiểm tra xem có giá trị nào trong 1 vector kiểu boolean bằng true không
### Các phiên bản
```glsl
bool all(bvec2 x)
bool all(bvec3 x)
bool all(bvec4 x)
```
### Các tham số
```x``` vector cần kiểm tra
### Mô tả
```any()``` trả về ```true``` nếu có bất kỳ một giá trị nào trong vector ```x``` bằng ```true```, ngược lại trả về ```false```. Hàm này tương đương với:
```glsl
bool any(bvec x) { // bvec can be bvec2, bvec3 or bvec4
bool result = false;
int i;
for (i = 0; i < x.length(); ++i) {
result |= x[i];
}
return result;
}
```
### Tham khảo thêm
[any()](/glossary/?lan=vi&search=any), [not()](/glossary/?lan=vi&search=not)
---
### Glossary/Asin/README (glossary/asin/README.md)
## Asin
Return the arcsine of the parameter
### Declaration
```glsl
float asin(float x)
vec2 asin(vec2 x)
vec3 asin(vec3 x)
vec4 asin(vec4 x)
```
### Parameters
```x``` specifies the value whose arcsine to return.
### Description
```asin()``` returns the angle whose trigonometric sine is ```x```.
### See Also
[cos](/glossary/?search=cos), [sin](/glossary/?search=sin), [acos](/glossary/?search=acos), [tan](/glossary/?search=tan), [atan](/glossary/?search=atan), [Chapter 05: Shaping Functions](/05/)
---
### Glossary/Asin/README Pl (glossary/asin/README-pl.md)
## asin
Zwraca arcsin parametru
### Deklaracja
```glsl
float asin(float x)
vec2 asin(vec2 x)
vec3 asin(vec3 x)
vec4 asin(vec4 x)
```
### Parametry
```x``` określa wartość, której arcsin ma zostać zwrócony.
### Opis
```asin()``` zwraca kąt, którego sinus trygonometryczny to ```x```.
### Zobacz też
[cos](/glossary/?lan=pl&search=cos), [sin](/glossary/?lan=pl&search=sin), [acos](/glossary/?lan=pl&search=acos), [tan](/glossary/?lan=pl&search=tan), [atan](/glossary/?lan=pl&search=atan), [Rozdział 05: Shaping Functions](/05/?lan=pl)
---
### Glossary/Asin/README Ua (glossary/asin/README-ua.md)
## asin
Повертає арксинус параметра
### Оголошення
```glsl
float asin(float x)
vec2 asin(vec2 x)
vec3 asin(vec3 x)
vec4 asin(vec4 x)
```
### Параметри
**```x```** — значення, арксинус якого потрібно повернути.
### Опис
```asin()``` повертає кут, тригонометричний синус якого дорівнює **`x`**
### Дивіться також
[cos](/glossary/?lan=ua&search=cos), [sin](/glossary/?lan=ua&search=sin), [acos](/glossary/?lan=ua&search=acos), [tan](/glossary/?lan=ua&search=tan), [atan](/glossary/?lan=ua&search=atan), [Розділ 05: Формотворчі функції](/05/?lan=ua)
---
### Glossary/Asin/README Vi (glossary/asin/README-vi.md)
## Asin
Tính góc lượng giác ứng với giá trị sine
### Các phiên bản
```glsl
float asin(float x)
vec2 asin(vec2 x)
vec3 asin(vec3 x)
vec4 asin(vec4 x)
```
### Các tham số
```x``` giá trị sine cần tìm góc lượng giác tương ứng
### Mô tả
```asin()``` trả về góc lượng giác (đơn vị radian) tương ứng với giá trị sine bằng ```x```.
### Tham khảo thêm
[cos](/glossary/?lan=vi&search=cos), [sin](/glossary/?lan=vi&search=sin), [acos](/glossary/?lan=vi&search=acos), [tan](/glossary/?lan=vi&search=tan), [atan](/glossary/?lan=vi&search=atan), [Các hàm số cơ bản (Hàm hình dạng - Shape function)](/05/?lan=vi)
---
### Glossary/Atan/README (glossary/atan/README.md)
## Atan
Return the arc-tangent of the parameters
### Declaration
```glsl
float atan(float y, float x)
vec2 atan(vec2 y, vec2 x)
vec3 atan(vec3 y, vec3 x)
vec4 atan(vec4 y, vec4 x)
float atan(float y_over_x)
vec2 atan(vec2 y_over_x)
vec3 atan(vec3 y_over_x)
vec4 atan(vec4 y_over_x)
```
### Parameters
```y``` specifies the numerator of the fraction whose arctangent to return.
```x``` specifies the denominator of the fraction whose arctangent to return.
```y_over_x``` specifies the fraction whose arctangent to return.
### Description
```atan()``` returns the angle whose trigonometric arctangent is ```y,x``` or ```y_over_x```, depending on which overload is invoked. In the first overload, the signs of ```y``` and ```x``` are used to determine the quadrant that the angle lies in. The values returned by ```atan``` in this case are in the range -PI and PI. Results are undefined if ```x``` is zero.
For the second overload, ```atan()``` returns the angle whose tangent is ```y_over_x```. Values returned in this case are in the range -PI/2 to PI/2.
### See Also
[cos](/glossary/?search=cos), [acos](/glossary/?search=acos), [sin](/glossary/?search=sin), [asin](/glossary/?search=asin), [atan](/glossary/?search=atan), [Chapter 05: Shaping Functions](/05/), [Chapter 06: Color](/06/)
---
### Glossary/Atan/README Pl (glossary/atan/README-pl.md)
## atan
Zwraca arcus tangens parametrów
### Deklaracja
```glsl
float atan(float y, float x)
vec2 atan(vec2 y, vec2 x)
vec3 atan(vec3 y, vec3 x)
vec4 atan(vec4 y, vec4 x)
float atan(float y_over_x)
vec2 atan(vec2 y_over_x)
vec3 atan(vec3 y_over_x)
vec4 atan(vec4 y_over_x)
```
### Parametry
```y``` określa licznik ułamka, którego arcus tangens ma zostać zwrócony.
```x``` określa mianownik ułamka, którego arcus tangens ma zostać zwrócony.
```y_over_x``` określa ułamek, którego arcus tangens ma zostać zwrócony.
### Opis
```atan()``` zwraca kąt, którego trygonometryczny arcus tangens jest równy ```y,x``` lub ```y_over_x```, w zależności od tego, który przeciążenie jest wywoływane. W pierwszym przeciążeniu znaki ```y``` i ```x``` są używane do określenia ćwiartki, w której znajduje się kąt. Wartości zwracane przez ```atan``` w tym przypadku mieszczą się w zakresie -PI i PI. Wyniki są niezdefiniowane, jeśli ```x``` wynosi zero.
Dla drugiego przeciążenia, ```atan()``` zwraca kąt, którego tangens wynosi ```y_over_x```. Wartości zwracane w tym przypadku mieszczą się w zakresie -PI do PI.
### Zobacz też
[cos](/glossary/?lan=pl&search=cos), [acos](/glossary/?lan=pl&search=acos), [sin](/glossary/?lan=pl&search=sin), [asin](/glossary/?lan=pl&search=asin), [atan](/glossary/?lan=pl&search=atan), [Rozdział 05: Shaping Functions](/05/), [Rozdział 06: Kolory](/06/)
[]: # (end)
[]: # (end)
---
### Glossary/Atan/README Ua (glossary/atan/README-ua.md)
## atan
Повертає арктангенс параметрів
### Оголошення
```glsl
float atan(float y, float x)
vec2 atan(vec2 y, vec2 x)
vec3 atan(vec3 y, vec3 x)
vec4 atan(vec4 y, vec4 x)
float atan(float y_over_x)
vec2 atan(vec2 y_over_x)
vec3 atan(vec3 y_over_x)
vec4 atan(vec4 y_over_x)
```
### Параметри
**```y```** — чисельник дробу, арктангенс якого потрібно повернути.
**```x```** — знаменник дробу, арктангенс якого потрібно повернути.
**```y_over_x```** — дріб, арктангенс якого потрібно повернути.
### Опис
**```atan()```** повертає кут, тригонометричний арктангенс якого дорівнює **`y,x`** або **`y_over_x`**, залежно від того, яке саме перевантаження функції викликається.
У першому перевантаженні знаки **`y`** і **`x`** використовуються для визначення квадранта, в якому лежить кут. Значення, які повертає **`atan`** у цьому випадку, знаходяться в діапазоні від -PI до PI. Результати не визначені, якщо **`x`** дорівнює нулю.
Для другого перевантаження **```atan()```** повертає кут, тангенс якого дорівнює **```y_over_x```**. Значення, що повертаються в цьому випадку, знаходяться в діапазоні від -PI до PI.
### Дивіться також
[cos](/glossary/?lan=ua&search=cos), [acos](/glossary/?lan=ua&search=acos), [sin](/glossary/?lan=ua&search=sin), [asin](/glossary/?lan=ua&search=asin), [atan](/glossary/?lan=ua&search=atan), [Розділ 05: Формотворчі функції](/05/?lan=ua), [Розділ 06: Кольори](/06/?lan=ua)
---
### Glossary/Attribute/README (glossary/attribute/README.md)
## Attribute
Vertex attribute data.
### Example
```glsl
attribute vec4 v_color;
```
### Description
```attribute``` read-only variables containing data shared from WebGL/OpenGL environment to the vertex shader.
Because the vertex shader is executed one time for each vertex, attributes are specify per vertex data typically with information such as: space position, color, normal direction and texture coordinates of a vertex.
### See Also
[const](/glossary/?search=const), [uniform](/glossary/?search=uniform), [varying](/glossary/?search=varying), [Chapter 03: Uniforms](/03/)
---
### Glossary/Attribute/README Pl (glossary/attribute/README-pl.md)
## attribute
Dane atrybutów wierzchołka.
### Przykład
```glsl
attribute vec4 v_color;
```
### Opis
`attribute` to zmienne tylko do odczytu, zawierające dane udostępniane z środowiska WebGL/OpenGL do vertex shadera.
Ponieważ vertex shader jest uruchamiany raz dla każdego wierzchołka, atrybuty określają dane specyficzne dla poszczególnych wierzchołków, takie jak: pozycja w przestrzeni, kolor, kierunek wektora normalnego czy współrzędne tekstury.
### Zobacz też
[const](/glossary/?lan=pl&search=const), [uniform](/glossary/?lan=pl&search=uniform), [varying](/glossary/?lan=pl&search=varying), [Rozdział 03: Uniformy](/03/?lan=pl)
---
### Glossary/Attribute/README Ua (glossary/attribute/README-ua.md)
## attribute
Дані атрибутів вершин.
### Приклад
```glsl
attribute vec4 v_color;
```
### Опис
**```attribute```** — змінні доступні лише для читання, що містять дані, які передаються із середовища WebGL/OpenGL у вершинний шейдер.
Оскільки вершинний шейдер виконується один раз для кожної вершини, атрибути визначають дані для кожної вершини, як правило, з такою інформацією, як: положення в просторі, колір, напрямок нормалі та координати текстури вершини.
### Дивіться також
[const](/glossary/?lan=ua&search=const), [uniform](/glossary/?lan=ua&search=uniform), [varying](/glossary/?lan=ua&search=varying), [Розділ 03: Uniforms](/03/?lan=ua)
---
### Glossary/Attribute/README Vi (glossary/attribute/README-vi.md)
## Attribute
Đánh dấu dữ liệu về các đỉnh của mesh.
### Ví dụ
```glsl
attribute vec4 v_color;
```
### Mô tả
```attribute``` đánh dấu dữ liệu về các đỉnh của mesh gửi từ môi trường WebGL/OpenGL cho vertex shader.
Vì vertex shader chỉ thực thi một lần cho mỗi đỉnh, nên các thuộc tính của mỗi đỉnh phải được chỉ đích danh: vị trí, màu sắc, vector pháp tuyến và toạ độ UV.
### Tham khảo thêm
[const](/glossary/?lan=vi&search=const), [uniform](/glossary/?lan=vi&search=uniform), [varying](/glossary/?lan=vi&search=varying), [Chương 03: Uniform](/03/?lan=vi)
---
### Glossary/Bool/README (glossary/bool/README.md)
## Bool
Boolean variable type
### Declaration
```glsl
bool aBool = true;
bool bBool = bool(aInt);
bool cBool = bool(aFloat);
```
### Description
```bool``` data type is either true or false.
### See Also
[void](/glossary/?search=void), [bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [bvec2](/glossary/?search=bvec2), [bvec3](/glossary/?search=bvec3), [bvec4](/glossary/?search=bvec4), [struct](/glossary/?search=struct)
---
### Glossary/Bool/README Pl (glossary/bool/README-pl.md)
## bool
Typ zmiennej logicznej
### Deklaracja
```glsl
bool aBool = true;
bool bBool = bool(aInt);
bool cBool = bool(aFloat);
```
### Opis
`bool` może przyjmować dwie wartości: `true` lub `false`.
### Zobacz też
[void](/glossary/?lan=pl&search=void), [bool](/glossary/?lan=pl&search=bool), [int](/glossary/?lan=pl&search=int), [float](/glossary/?lan=pl&search=float), [bvec2](/glossary/?lan=pl&search=bvec2), [bvec3](/glossary/?lan=pl&search=bvec3), [bvec4](/glossary/?lan=pl&search=bvec4), [struct](/glossary/?lan=pl&search=struct)
---
### Glossary/Bool/README Ua (glossary/bool/README-ua.md)
## bool
Логічний тип даних (також булів, булевий, булівський)
### Приклад
```glsl
bool aBool = true;
bool bBool = bool(aInt);
bool cBool = bool(aFloat);
```
### Опис
**```bool```** — використовується для позначення логічного типу даних. Приймає значення **true** або **false**. Також є одноіменна функція для приведення даних до відповідного типу.
### Дивіться також
[void](/glossary/?lan=ua&search=void), [bool](/glossary/?lan=ua&search=bool), [int](/glossary/?lan=ua&search=int), [float](/glossary/?lan=ua&search=float), [bvec2](/glossary/?lan=ua&search=bvec2), [bvec3](/glossary/?lan=ua&search=bvec3), [bvec4](/glossary/?lan=ua&search=bvec4), [struct](/glossary/?lan=ua&search=struct)
---
### Glossary/Bool/README Vi (glossary/bool/README-vi.md)
## Bool
Kiểu dữ liệu boolean
### Các phiên bản
```glsl
bool aBool = true;
bool bBool = bool(aInt);
bool cBool = bool(aFloat);
```
### Mô tả
```bool``` chỉ nhận 1 trong 2 giá trị đúng hoặc sai
### Tham khảo thêm
[void](/glossary/?lan=vi&search=void), [bool](/glossary/?lan=vi&search=bool), [int](/glossary/?lan=vi&search=int), [float](/glossary/?lan=vi&search=float), [bvec2](/glossary/?lan=vi&search=bvec2), [bvec3](/glossary/?lan=vi&search=bvec3), [bvec4](/glossary/?lan=vi&search=bvec4), [struct](/glossary/?lan=vi&search=struct)
---
### Glossary/Bvec2/README (glossary/bvec2/README.md)
## Bvec2
2 dimensional boolean vector
### Declaration
```glsl
bvec2 aBvec2 = bvec2(true, true);
bvec2 bBvec2 = bvec2(true);
bvec2 cBvec2 = bvec2(aBvec3);
bvec2 dBvec2 = bvec2(aBvec3.x, aBvec3.y);
```
### Description
```bvec2``` is a boolean vector with two components. It can be initialized by:
- Providing a scalar value for each component.
- Providing one scalar value. This value is used for all components.
- Providing a vector of higher dimension. The respective values are used to initialize the components.
### See Also
[bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [bvec2](/glossary/?search=bvec2), [bvec3](/glossary/?search=bvec3), [bvec4](/glossary/?search=bvec4), [ivec2](/glossary/?search=ivec2), [ivec3](/glossary/?search=ivec3), [ivec4](/glossary/?search=ivec4), [vec2](/glossary/?search=vec2), [vec3](/glossary/?search=vec3), [vec4](/glossary/?search=vec4), [mat2](/glossary/?search=mat2), [mat3](/glossary/?search=mat3), [mat4](/glossary/?search=mat4)
---
### Glossary/Bvec2/README Pl (glossary/bvec2/README-pl.md)
## bvec2
2-wymiarowy wektor `bool`owski
### Deklaracja
```glsl
bvec2 aBvec2 = bvec2(true, true);
bvec2 bBvec2 = bvec2(true);
bvec2 cBvec2 = bvec2(aBvec3);
bvec2 dBvec2 = bvec2(aBvec3.x, aBvec3.y);
```
### Opis
`bvec2` to wektor `bool`owski z dwoma komponentami. Można go zainicjalizować:
- Podając wartość skalarną dla każdego komponentu.
- Podając jedną wartośś skalarną. Zostanie ona przypisana do wszystkich komponentów.
- Podając wektor o wyższym wymiarze. Odpowiednie wartości zostaną użyte do inicjalizacji komponentów.
### Zobacz też
[bool](/glossary/?lan=pl&search=bool), [int](/glossary/?lan=pl&search=int), [float](/glossary/?lan=pl&search=float), [bvec2](/glossary/?lan=pl&search=bvec2), [bvec3](/glossary/?lan=pl&search=bvec3), [bvec4](/glossary/?lan=pl&search=bvec4), [ivec2](/glossary/?lan=pl&search=ivec2), [ivec3](/glossary/?lan=pl&search=ivec3), [ivec4](/glossary/?lan=pl&search=ivec4), [vec2](/glossary/?lan=pl&search=vec2), [vec3](/glossary/?lan=pl&search=vec3), [vec4](/glossary/?lan=pl&search=vec4), [mat2](/glossary/?lan=pl&search=mat2), [mat3](/glossary/?lan=pl&search=mat3), [mat4](/glossary/?lan=pl&search=mat4)
---
### Glossary/Bvec2/README Ua (glossary/bvec2/README-ua.md)
## bvec2
2-вимірний булевий вектор
### Оголошення
```glsl
bvec2 aBvec2 = bvec2(true, true);
bvec2 bBvec2 = bvec2(true);
bvec2 cBvec2 = bvec2(aBvec3);
bvec2 dBvec2 = bvec2(aBvec3.x, aBvec3.y);
```
### Опис
**```bvec2```** — булевий вектор з двома компонентами. Способи ініціалізації:
- надання скалярного значення для кожного компонента;
- надання одного скалярного значення, що буде використано для всіх компонентів;
- надання вектора вищої розмірності, де відповідні значення будуть використані для ініціалізації компонентів;
### Дивіться також
[bool](/glossary/?lan=ua&search=bool), [int](/glossary/?lan=ua&search=int), [float](/glossary/?lan=ua&search=float), [bvec2](/glossary/?lan=ua&search=bvec2), [bvec3](/glossary/?lan=ua&search=bvec3), [bvec4](/glossary/?lan=ua&search=bvec4), [ivec2](/glossary/?lan=ua&search=ivec2), [ivec3](/glossary/?lan=ua&search=ivec3), [ivec4](/glossary/?lan=ua&search=ivec4), [vec2](/glossary/?lan=ua&search=vec2), [vec3](/glossary/?lan=ua&search=vec3), [vec4](/glossary/?lan=ua&search=vec4), [mat2](/glossary/?lan=ua&search=mat2), [mat3](/glossary/?lan=ua&search=mat3), [mat4](/glossary/?lan=ua&search=mat4)
---
### Glossary/Bvec2/README Vi (glossary/bvec2/README-vi.md)
## Bvec2
Vector boolean 2 chiều
### Các phiên bản
```glsl
bvec2 aBvec2 = bvec2(true, true);
bvec2 bBvec2 = bvec2(true);
bvec2 cBvec2 = bvec2(aBvec3);
bvec2 dBvec2 = bvec2(aBvec3.x, aBvec3.y);
```
### Mô tả
```bvec2``` vector boolean gồm 2 thành phần. Nó có thể được khởi tạo bằng các cách:
- Chỉ định giá trị của từng thành phần
- Chỉ định 1 giá trị chung cho cả 2 thành phần
- Lấy giá trị từ 1 vector nhiều chiều hơn. Các thành phần sẽ được khởi tạo theo thứ tự.
### Tham khảo thêm
[bool](/glossary/?lan=vi&search=bool), [int](/glossary/?lan=vi&search=int), [float](/glossary/?lan=vi&search=float), [bvec2](/glossary/?lan=vi&search=bvec2), [bvec3](/glossary/?lan=vi&search=bvec3), [bvec4](/glossary/?lan=vi&search=bvec4), [ivec2](/glossary/?lan=vi&search=ivec2), [ivec3](/glossary/?lan=vi&search=ivec3), [ivec4](/glossary/?lan=vi&search=ivec4), [vec2](/glossary/?lan=vi&search=vec2), [vec3](/glossary/?lan=vi&search=vec3), [vec4](/glossary/?lan=vi&search=vec4), [mat2](/glossary/?lan=vi&search=mat2), [mat3](/glossary/?lan=vi&search=mat3), [mat4](/glossary/?lan=vi&search=mat4)
---
### Glossary/Bvec3/README (glossary/bvec3/README.md)
## Bvec3
3 dimensional boolean vector
### Declaration
```glsl
vec3 aBvec3 = bvec3(true, true, true);
vec3 bBvec3 = bvec3(true);
vec3 cBvec3 = bvec3(aBvec4);
vec3 dBvec3 = bvec3(aBvec4.x, aBvec4.y, aBvec4.z);
vec3 eBvec3 = bvec3(aBvec2, aBool);
vec3 fBvec3 = bvec3(aBvec2.x, aBvec2.y, aBool);
```
### Description
```bvec3``` is a boolean vector with three components. It can be initialized by:
- Providing a scalar value for each component.
- Providing one scalar value. This value is used for all components.
- Providing a vector of higher dimension. The respective values are used to initialize the components.
- Providing a combination of vectors and/or scalars. The respective values are used to initialize the vector. The arguments of the constructor must have at least as many components as the vector that is initialized.
### See Also
[bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [bvec2](/glossary/?search=bvec2), [bvec3](/glossary/?search=bvec3), [bvec4](/glossary/?search=bvec4), [ivec2](/glossary/?search=ivec2), [ivec3](/glossary/?search=ivec3), [ivec4](/glossary/?search=ivec4), [vec2](/glossary/?search=vec2), [vec3](/glossary/?search=vec3), [vec4](/glossary/?search=vec4), [mat2](/glossary/?search=mat2), [mat3](/glossary/?search=mat3), [mat4](/glossary/?search=mat4)
---
### Glossary/Bvec3/README Pl (glossary/bvec3/README-pl.md)
## bvec3
3-wymiarowy wektor `bool`owski
### Deklaracja
```glsl
vec3 aBvec3 = bvec3(true, true, true);
vec3 bBvec3 = bvec3(true);
vec3 cBvec3 = bvec3(aBvec4);
vec3 dBvec3 = bvec3(aBvec4.x, aBvec4.y, aBvec4.z);
vec3 eBvec3 = bvec3(aBvec2, aBool);
vec3 fBvec3 = bvec3(aBvec2.x, aBvec2.y, aBool);
```
### Opis
`bvec3` to wektor `bool`owski z trzema komponentami. Można go zainicjalizować:
- Podając wartość skalarną dla każdego komponentu.
- Podając jedną wartość skalarną – zostanie ona przypisana do wszystkich komponentów.
- Podając wektor o wyższym wymiarze – odpowiednie wartości zostaną użyte do inicjalizacji komponentów.
- Podając kombinację wektorów i/lub skalarów – odpowiednie wartości zostaną użyte do inicjalizacji wektora. Argumenty konstruktora muszą zawierać co najmniej tyle komponentów, ile ma inicjalizowany wektor.
### Zobacz też
[bool](/glossary/?lan=pl&search=bool), [int](/glossary/?lan=pl&search=int), [float](/glossary/?lan=pl&search=float), [bvec2](/glossary/?lan=pl&search=bvec2), [bvec3](/glossary/?lan=pl&search=bvec3), [bvec4](/glossary/?lan=pl&search=bvec4), [ivec2](/glossary/?lan=pl&search=ivec2), [ivec3](/glossary/?lan=pl&search=ivec3), [ivec4](/glossary/?lan=pl&search=ivec4), [vec2](/glossary/?lan=pl&search=vec2), [vec3](/glossary/?lan=pl&search=vec3), [vec4](/glossary/?lan=pl&search=vec4), [mat2](/glossary/?lan=pl&search=mat2), [mat3](/glossary/?lan=pl&search=mat3), [mat4](/glossary/?lan=pl&search=mat4)
---
### Glossary/Bvec3/README Vi (glossary/bvec3/README-vi.md)
## Bvec3
Vector boolean 3 chiều
### Các phiên bản
```glsl
vec3 aBvec3 = bvec3(true, true, true);
vec3 bBvec3 = bvec3(true);
vec3 cBvec3 = bvec3(aBvec4);
vec3 dBvec3 = bvec3(aBvec4.x, aBvec4.y, aBvec4.z);
vec3 eBvec3 = bvec3(aBvec2, aBool);
vec3 fBvec3 = bvec3(aBvec2.x, aBvec2.y, aBool);
```
### Mô tả
```bvec3``` vector boolean gồm 3 thành phần. Nó có thể được khởi tạo bằng các cách:
- Chỉ định giá trị của từng thành phần
- Chỉ định 1 giá trị chung cho cả 3 thành phần
- Lấy giá trị từ 1 vector nhiều chiều hơn. Các thành phần sẽ được khởi tạo theo thứ tự.
- Lấy giá trị theo thứ tự lần lượt từ nhiều vector, miễn là đủ 3 thành phần.
### Tham khảo thêm
[bool](/glossary/?lan=vi&search=bool), [int](/glossary/?lan=vi&search=int), [float](/glossary/?lan=vi&search=float), [bvec2](/glossary/?lan=vi&search=bvec2), [bvec3](/glossary/?lan=vi&search=bvec3), [bvec4](/glossary/?lan=vi&search=bvec4), [ivec2](/glossary/?lan=vi&search=ivec2), [ivec3](/glossary/?lan=vi&search=ivec3), [ivec4](/glossary/?lan=vi&search=ivec4), [vec2](/glossary/?lan=vi&search=vec2), [vec3](/glossary/?lan=vi&search=vec3), [vec4](/glossary/?lan=vi&search=vec4), [mat2](/glossary/?lan=vi&search=mat2), [mat3](/glossary/?lan=vi&search=mat3), [mat4](/glossary/?lan=vi&search=mat4)
---
### Glossary/Bvec4/README (glossary/bvec4/README.md)
## Bvec4
4 dimensional boolean vector
### Declaration
```glsl
vec4 aBvec4 = bvec4(true, true, true, true);
vec4 bBvec4 = bvec4(true);
vec4 cBvec4 = bvec4(aBvec2, aBool, aBvec3);
vec4 dBvec4 = bvec4(aBvec2.x, aBvec2.y, aBool, aBvec3.x);
```
### Description
```bvec4``` is a boolean vector with four components. It can be initialized by:
- Providing a scalar value for each component.
- Providing one scalar value. This value is used for all components.
- Providing a combination of vectors and scalars. The respective values are used to initialize the components. The arguments of the constructor must have at least as many components as the vector that is initialized.
### See Also
[bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [bvec2](/glossary/?search=bvec2), [bvec3](/glossary/?search=bvec3), [bvec4](/glossary/?search=bvec4), [ivec2](/glossary/?search=ivec2), [ivec3](/glossary/?search=ivec3), [ivec4](/glossary/?search=ivec4), [vec2](/glossary/?search=vec2), [vec3](/glossary/?search=vec3), [vec4](/glossary/?search=vec4), [mat2](/glossary/?search=mat2), [mat3](/glossary/?search=mat3), [mat4](/glossary/?search=mat4)
---
### Glossary/Bvec4/README Pl (glossary/bvec4/README-pl.md)
## bvec4
4-wymiarowy wektor `bool`owski
### Deklaracja
```glsl
vec4 aBvec4 = bvec4(true, true, true, true);
vec4 bBvec4 = bvec4(true);
vec4 cBvec4 = bvec4(aBvec2, aBool, aBvec3);
vec4 dBvec4 = bvec4(aBvec2.x, aBvec2.y, aBool, aBvec3.x);
```
### Opis
`bvec4` to wektor `bool`owski mający cztery składowe. Można go zainicjalizować:
- Podając osobną wartość skalarną dla każdej składowej.
- Podając jedną wartość skalarną. Wartość ta zostanie użyta dla wszystkich składowych.
- Podając kombinację wektorów i skalarów. Odpowiednie wartości zostaną użyte do inicjalizacji składowych. Argumenty konstruktora muszą mieć przynajmniej tyle składowych, ile wynosi rozmiar inicjalizowanego wektora.
### Zobacz też
[bool](/glossary/?lan=pl&search=bool), [int](/glossary/?lan=pl&search=int), [float](/glossary/?lan=pl&search=float), [bvec2](/glossary/?lan=pl&search=bvec2), [bvec3](/glossary/?lan=pl&search=bvec3), [bvec4](/glossary/?lan=pl&search=bvec4), [ivec2](/glossary/?lan=pl&search=ivec2), [ivec3](/glossary/?lan=pl&search=ivec3), [ivec4](/glossary/?lan=pl&search=ivec4), [vec2](/glossary/?lan=pl&search=vec2), [vec3](/glossary/?lan=pl&search=vec3), [vec4](/glossary/?lan=pl&search=vec4), [mat2](/glossary/?lan=pl&search=mat2), [mat3](/glossary/?lan=pl&search=mat3), [mat4](/glossary/?lan=pl&search=mat4)
---
### Glossary/Bvec4/README Ua (glossary/bvec4/README-ua.md)
## bvec4
4-вимірний булевий вектор
### Оголошення
```glsl
vec4 aBvec4 = bvec4(true, true, true, true);
vec4 bBvec4 = bvec4(true);
vec4 cBvec4 = bvec4(aBvec2, aBool, aBvec3);
vec4 dBvec4 = bvec4(aBvec2.x, aBvec2.y, aBool, aBvec3.x);
```
### Опис
**```bvec4```** — булевий вектор з чотирма компонентами. Способи ініціалізації:
- надання скалярного значення для кожного компонента;
- надання одного скалярного значення, що буде використано для всіх компонентів;
- надання комбінації векторів та/або скалярів. Для ініціалізації вектора використовуються відповідні значення. Аргументи конструктора повинні містити принаймні стільки ж компонентів, скільки ініціалізований вектор.
### Дивіться також
[bool](/glossary/?lan=ua&search=bool), [int](/glossary/?lan=ua&search=int), [float](/glossary/?lan=ua&search=float), [bvec2](/glossary/?lan=ua&search=bvec2), [bvec3](/glossary/?lan=ua&search=bvec3), [bvec4](/glossary/?lan=ua&search=bvec4), [ivec2](/glossary/?lan=ua&search=ivec2), [ivec3](/glossary/?lan=ua&search=ivec3), [ivec4](/glossary/?lan=ua&search=ivec4), [vec2](/glossary/?lan=ua&search=vec2), [vec3](/glossary/?lan=ua&search=vec3), [vec4](/glossary/?lan=ua&search=vec4), [mat2](/glossary/?lan=ua&search=mat2), [mat3](/glossary/?lan=ua&search=mat3), [mat4](/glossary/?lan=ua&search=mat4)
---
### Glossary/Bvec4/README Vi (glossary/bvec4/README-vi.md)
## Bvec4
Vector boolean 4 chiều
### Các phiên bản
```glsl
vec4 aBvec4 = bvec4(true, true, true, true);
vec4 bBvec4 = bvec4(true);
vec4 cBvec4 = bvec4(aBvec2, aBool, aBvec3);
vec4 dBvec4 = bvec4(aBvec2.x, aBvec2.y, aBool, aBvec3.x);
```
### Mô tả
```bvec4``` vector boolean gồm 4 thành phần. Nó có thể được khởi tạo bằng các cách:
- Chỉ định giá trị của từng thành phần
- Chỉ định 1 giá trị chung cho cả 4 thành phần
- Lấy giá trị theo thứ tự lần lượt từ nhiều vector, miễn là đủ 4 thành phần.
### Tham khảo thêm
[bool](/glossary/?lan=vi&search=bool), [int](/glossary/?lan=vi&search=int), [float](/glossary/?lan=vi&search=float), [bvec2](/glossary/?lan=vi&search=bvec2), [bvec3](/glossary/?lan=vi&search=bvec3), [bvec4](/glossary/?lan=vi&search=bvec4), [ivec2](/glossary/?lan=vi&search=ivec2), [ivec3](/glossary/?lan=vi&search=ivec3), [ivec4](/glossary/?lan=vi&search=ivec4), [vec2](/glossary/?lan=vi&search=vec2), [vec3](/glossary/?lan=vi&search=vec3), [vec4](/glossary/?lan=vi&search=vec4), [mat2](/glossary/?lan=vi&search=mat2), [mat3](/glossary/?lan=vi&search=mat3), [mat4](/glossary/?lan=vi&search=mat4)
---
### Glossary/Ceil/README (glossary/ceil/README.md)
## Ceil
Find the nearest integer that is greater than or equal to the parameter
### Declaration
```glsl
float ceil(float x)
vec2 ceil(vec2 x)
vec3 ceil(vec3 x)
vec4 ceil(vec4 x)
```
### Parameters
```x``` specifies the value to evaluate.
### Description
```ceil()``` returns a value equal to the nearest integer that is greater than or equal to ```x```.
### See Also
[floor](/glossary/?search=floor), [fract](/glossary/?search=fract), [mod](/glossary/?search=mod), [Chapter 05: Shaping Functions](/05/)
---
### Glossary/Ceil/README Pl (glossary/ceil/README-pl.md)
## ceil
Znajduje najbliższą liczbę całkowitą, która jest większa lub równa podanemu parametrowi
### Deklaracja
```glsl
float ceil(float x)
vec2 ceil(vec2 x)
vec3 ceil(vec3 x)
vec4 ceil(vec4 x)
```
### Parametry
```x``` określa wartość do ewaluacji
### Opis
```ceil()``` zwraca wartość równą najbliższej liczbie całkowitej, która jest większa bądź równa ```x```.
### Zobacz też
[floor](/glossary/?lan=pl&search=floor), [fract](/glossary/?lan=pl&search=fract), [mod](/glossary/?lan=pl&search=mod), [Rozdział 05: Shaping Functions](/05/?lan=pl)
---
### Glossary/Ceil/README Ua (glossary/ceil/README-ua.md)
## ceil
Знаходить і повертає найближче ціле число, яке більше або дорівнює параметру
### Оголошення
```glsl
float ceil(float x)
vec2 ceil(vec2 x)
vec3 ceil(vec3 x)
vec4 ceil(vec4 x)
```
### Параметри
**```x```** — значення для обробки.
### Опис
**```ceil()```** повертає значення, що дорівнює найближчому цілому числу, яке більше або дорівнює **`x`**.
### Дивіться також
[floor](/glossary/?lan=ua&search=floor), [fract](/glossary/?lan=ua&search=fract), [mod](/glossary/?lan=ua&search=mod), [Розділ 05: Формотворчі функції](/05/?lan=ua)
---
### Glossary/Ceil/README Vi (glossary/ceil/README-vi.md)
## Ceil
Tìm số nguyên lớn hơn hoặc bằng gần nhất (làm tròn lên).
### Các phiên bản
```glsl
float ceil(float x)
vec2 ceil(vec2 x)
vec3 ceil(vec3 x)
vec4 ceil(vec4 x)
```
### Các tham số
```x``` giá trị cần làm tròn
### Mô tả
```ceil()``` làm tròn ```x``` thành số lớn hơn hoặc bằng.
### Tham khảo thêm
[floor](/glossary/?lan=vi&search=floor), [fract](/glossary/?lan=vi&search=fract), [mod](/glossary/?lan=vi&search=mod), [Các hàm số cơ bản (Hàm hình dạng - Shape function)](/05/?lan=vi)
---
### Glossary/Clamp/README (glossary/clamp/README.md)
## Clamp
Constrain a value to lie between two further values
### Declaration
```glsl
float clamp(float x, float minVal, float maxVal)
vec2 clamp(vec2 x, vec2 minVal, vec2 maxVal)
vec3 clamp(vec3 x, vec3 minVal, vec3 maxVal)
vec4 clamp(vec4 x, vec4 minVal, vec4 maxVal)
vec2 clamp(vec2 x, float minVal, float maxVal)
vec3 clamp(vec3 x, float minVal, float maxVal)
vec4 clamp(vec4 x, float minVal, float maxVal)
```
### Parameters
```x``` specifies the value to constrain.
```minVal``` specifies the lower end of the range into which to constrain x.
```maxVal``` specifies the upper end of the range into which to constrain x.
### Description
```clamp()``` returns the value of ```x``` constrained to the range ```minVal``` to ```maxVal```. The returned value is computed as ```min(max(x, minVal), maxVal)```.
### See Also
[min](/glossary/?search=min), [abs](/glossary/?search=abs), [max](/glossary/?search=max)
---
### Glossary/Clamp/README Pl (glossary/clamp/README-pl.md)
## clamp
Ogranicza wartość, aby mieściła się między dwoma skrajnymi wartościami
### Deklaracja
```glsl
float clamp(float x, float minVal, float maxVal)
vec2 clamp(vec2 x, vec2 minVal, vec2 maxVal)
vec3 clamp(vec3 x, vec3 minVal, vec3 maxVal)
vec4 clamp(vec4 x, vec4 minVal, vec4 maxVal)
vec2 clamp(vec2 x, float minVal, float maxVal)
vec3 clamp(vec3 x, float minVal, float maxVal)
vec4 clamp(vec4 x, float minVal, float maxVal)
```
### Parametry
```x``` określa wartość, którą należy ograniczyć.
```minVal``` określa dolną granicę zakresu, w którym będzie ograniczana wartość x.
```maxVal``` określa górną granicę zakresu, w którym będzie ograniczana wartość x.
### Opis
```clamp()``` zwraca wartość ```x``` ograniczoną do zakresu od ```minVal``` do ```maxVal```. Zwrócona wartość obliczana jest jako ```min(max(x, minVal), maxVal)```.
### Zobacz też
[min](/glossary/?lan=pl&search=min), [abs](/glossary/?lan=pl&search=abs), [max](/glossary/?lan=pl&search=max)
---
### Glossary/Clamp/README Ua (glossary/clamp/README-ua.md)
## clamp
Повертає значення в діапазоні між двома обмежувачами
### Оголошення
```glsl
float clamp(float x, float minVal, float maxVal)
vec2 clamp(vec2 x, vec2 minVal, vec2 maxVal)
vec3 clamp(vec3 x, vec3 minVal, vec3 maxVal)
vec4 clamp(vec4 x, vec4 minVal, vec4 maxVal)
vec2 clamp(vec2 x, float minVal, float maxVal)
vec3 clamp(vec3 x, float minVal, float maxVal)
vec4 clamp(vec4 x, float minVal, float maxVal)
```
### Параметри
**```x```** — значення для обмеження.
**```minVal```** — нижня межа діапазону.
**```maxVal```** — верхня межа діапазону.
### Опис
**```clamp()```** повертає значення **`x`** обмежене діапазоном від **`minVal`** до **`maxVal`**. Повернене значення обчислюється як **```min(max(x, minVal), maxVal)```**.
### Дивіться також
[min](/glossary/?lan=ua&search=min), [abs](/glossary/?lan=ua&search=abs), [max](/glossary/?lan=ua&search=max), [Розділ 05: Формотворчі функції](/05/?lan=ua)
---
### Glossary/Clamp/README Vi (glossary/clamp/README-vi.md)
## Clamp
Giới hạn 1 giá trị nằm trong 1 khoảng.
### Các phiên bản
```glsl
float clamp(float x, float minVal, float maxVal)
vec2 clamp(vec2 x, vec2 minVal, vec2 maxVal)
vec3 clamp(vec3 x, vec3 minVal, vec3 maxVal)
vec4 clamp(vec4 x, vec4 minVal, vec4 maxVal)
vec2 clamp(vec2 x, float minVal, float maxVal)
vec3 clamp(vec3 x, float minVal, float maxVal)
vec4 clamp(vec4 x, float minVal, float maxVal)
```
### Các tham số
```x``` giá trị cần giới hạn.
```minVal``` giá trị nhỏ nhất trong khoảng giới hạn
```maxVal``` giá trị lớn nhất trong khoảng giới hạn
### Mô tả
```clamp()``` trả về giá trị ```x``` sau khi đã đảm bảo nó nằm trong khoảng từ ```minVal``` tới ```maxVal```. Cách tính chi tiết: ```min(max(x, minVal), maxVal)```.
### Tham khảo thêm
[min](/glossary/?lan=vi&search=min), [abs](/glossary/?lan=vi&search=abs), [max](/glossary/?lan=vi&search=max)
---
### Glossary/Const/README (glossary/const/README.md)
## Const
Constant qualifier
### Example
```glsl
const float PI = 3.14159265359;
```
### Description
```const``` qualifier can be applied to the declaration of any variable to specify that its value will not be changed.
### See also
[attribute](/glossary/?search=attribute), [uniform](/glossary/?search=uniform), [varying](/glossary/?search=varying)
---
### Glossary/Const/README Pl (glossary/const/README-pl.md)
## const
Kwalifikator stały
### Przykład
```glsl
const float PI = 3.14159265359;
```
### Opis
Kwalifikator ```const``` może być zastosowany do deklaracji dowolnej zmiennej, aby określić, że jej wartość nie ulegnie zmianie.
### Zobacz też
[attribute](/glossary/?lan=pl&search=attribute), [uniform](/glossary/?lan=pl&search=uniform), [varying](/glossary/?lan=pl&search=varying)
---
### Glossary/Const/README Ua (glossary/const/README-ua.md)
## const
Константний кваліфікатор
### Приклад
```glsl
const float PI = 3.14159265359;
```
### Опис
**```const```** — кваліфікатор, який застосується перед оголошенням будь-якої змінної, щоб вказати, що значення цієї змінної не буде і не може бути змінено.
### Дивіться також
[attribute](/glossary/?lan=ua&search=attribute), [uniform](/glossary/?lan=ua&search=uniform), [varying](/glossary/?lan=ua&search=varying)
---
### Glossary/Const/README Vi (glossary/const/README-vi.md)
## Const
Qualifier đánh dấu một hằng số
### Ví dụ
```glsl
const float PI = 3.14159265359;
```
### Mô tả
```const``` khiến cho giá trị của một biến không thể bị thay đổi
### Tham khảo thêm
[attribute](/glossary/?lan=vi&search=attribute), [uniform](/glossary/?lan=vi&search=uniform), [varying](/glossary/?lan=vi&search=varying)
---
### Glossary/Cos/README (glossary/cos/README.md)
## Cos
Return the cosine of the parameter
### Declaration
```glsl
float cos(float angle)
vec2 cos(vec2 angle)
vec3 cos(vec3 angle)
vec4 cos(vec4 angle)
```
### Parameters
```angle``` specify the quantity, in radians, of which to return the cosine.
### Description
```cos()``` returns the trigonometric cosine of angle.
### See Also
[acos](/glossary/?search=acos), [sin](/glossary/?search=sin), [asin](/glossary/?search=asin), [tan](/glossary/?search=tan), [atan](/glossary/?search=atan), [Chapter 05: Shaping Functions](/05/)
---
### Glossary/Cos/README Pl (glossary/cos/README-pl.md)
## cos
Zwraca cosinus podanego parametru
### Deklaracja
```glsl
float cos(float angle)
vec2 cos(vec2 angle)
vec3 cos(vec3 angle)
vec4 cos(vec4 angle)
```
### Parametry
```angle``` określa wartość (w radianach), dla której ma zostać zwrócony cosinus.
### Opis
```cos()``` zwraca trygonometryczny cosinus podanego kąta.
### Zobacz też
[acos](/glossary/?lan=pl&search=acos), [sin](/glossary/?lan=pl&search=sin), [asin](/glossary/?lan=pl&search=asin), [tan](/glossary/?lan=pl&search=tan), [atan](/glossary/?lan=pl&search=atan), [Rozdział 05: Shaping Functions](/05/?lan=pl)
---
### Glossary/Cos/README Ua (glossary/cos/README-ua.md)
## cos
Повертає косинус параметра
### Оголошення
```glsl
float cos(float angle)
vec2 cos(vec2 angle)
vec3 cos(vec3 angle)
vec4 cos(vec4 angle)
```
### Параметри
**```angle```** — величина в радіанах, косинус якої потрібно повернути.
### Опис
**```cos()```** повертає тригонометричний косинус кута.
### Дивіться також
[acos](/glossary/?lan=ua&search=acos), [sin](/glossary/?lan=ua&search=sin), [asin](/glossary/?lan=ua&search=asin), [tan](/glossary/?lan=ua&search=tan), [atan](/glossary/?lan=ua&search=atan), [Розділ 05: Формотворчі функції](/05/?lan=ua)
---
### Glossary/Cos/README Vi (glossary/cos/README-vi.md)
## Cos
Tính hàm cosine của 1 góc lượng giác
### Các phiên bản
```glsl
float cos(float angle)
vec2 cos(vec2 angle)
vec3 cos(vec3 angle)
vec4 cos(vec4 angle)
```
### Các tham số
```angle``` góc lượng giác (đơn vị radian) cần tính cosine
### Mô tả
```cos()``` trả về giá trị cosine tương ứng với góc ```angle```
### Tham khảo thêm
[acos](/glossary/?lan=vi&search=acos), [sin](/glossary/?lan=vi&search=sin), [asin](/glossary/?lan=vi&search=asin), [tan](/glossary/?lan=vi&search=tan), [atan](/glossary/?lan=vi&search=atan), [Các hàm số cơ bản (Hàm hình dạng - Shape function)](/05/?lan=vi)
---
### Glossary/Cross/README (glossary/cross/README.md)
## Cross
Calculate the cross product of two vectors
### Declaration
```glsl
vec3 cross(vec3 x, vec3 y)
```
### Parameters
```x``` specifies the first of two vectors
```y``` specifies the second of two vectors
### Description
```cross()``` returns the cross product of two vectors, ```x``` and ```y```. The input parameters can only be 3-component floating vectors. The cross product is equivalent to the product of the length of the vectors times the sinus of the(smaller) angle between ```x``` and ```y```.
### See Also
[dot()](/glossary/?search=dot)
---
### Glossary/Cross/README Pl (glossary/cross/README-pl.md)
## cross
Oblicza iloczyn wektorowy dwóch wektorów
### Deklaracja
```glsl
vec3 cross(vec3 x, vec3 y)
```
### Parametry
```x``` określa pierwszy z dwóch wektorów
```y``` określa drugi z dwóch wektorów
### Opis
```cross()``` zwraca iloczyn wektorowy dwóch wektorów, ```x``` i ```y```. Parametry wejściowe mogą być wyłącznie 3-składowymi wektorami zmiennoprzecinkowymi. Iloczyn wektorowy jest równoważny iloczynowi długości tych wektorów pomnożonemu przez sinus (mniejszego) kąta między ```x``` i ```y```.
### Zobacz też
[dot](/glossary/?lan=pl&search=dot)
---
### Glossary/Cross/README Ua (glossary/cross/README-ua.md)
## cross
Обчислює перехресний добуток двох векторів
### Оголошення
```glsl
vec3 cross(vec3 x, vec3 y)
```
### Параметри
**```x```** — перший вектор.
**```y```** — другий вектор.
### Опис
**```cross()```** повертає перехресний добуток двох векторів, **`x`** та **`y`**. Вхідними параметрами можуть бути лише 3-компонентні вектори — **`vec3`**. Перехресний добуток еквівалентний добутку довжини векторів на синус (меншого) кута між **`x`** і **`y`**.
### Дивіться також
[dot()](/glossary/?lan=ua&search=dot)
---
### Glossary/Cross/README Vi (glossary/cross/README-vi.md)
## Cross
Tính tích có hướng của 2 vector
### Các phiên bản
```glsl
vec3 cross(vec3 x, vec3 y)
```
### Các tham số
```x``` Vector thứ nhất
```y``` Vector thứ hai
### Mô tả
```cross()``` trả về tích có hướng của hai vector ```x``` và ```y```. Các tham số đầu vào phải là các vector số thực 3 chiều.
### Tham khảo thêm
[dot()](/glossary/?lan=vi&search=dot)
---
### Glossary/Degrees/README (glossary/degrees/README.md)
## Degrees
Convert a quantity in radians to degrees
### Declaration
```glsl
float degrees(float radians)
vec2 degrees(vec2 radians)
vec3 degrees(vec3 radians)
vec4 degrees(vec4 radians)
```
### Parameters
```radians``` specifies the quantity, in radians, to be converted to degrees.
### Description
```degrees()``` converts a quantity, specified in radians into degrees. That is, the return value is ```(180.0*radians)/PI```
### See Also
[radians](/glossary/?search=radians)
---
### Glossary/Degrees/README Pl (glossary/degrees/README-pl.md)
## degrees
Konwertuje wielkość w radianach na stopnie
### Deklaracja
```glsl
float degrees(float radians)
vec2 degrees(vec2 radians)
vec3 degrees(vec3 radians)
vec4 degrees(vec4 radians)
```
### Parametry
```radians``` określa wielkość (w radianach), która ma zostać zamieniona na stopnie.
### Opis
```degrees()``` konwertuje wielkość wyrażoną w radianach na stopnie. Oznacza to, że wartość zwracana to ```(180.0*radians)/PI```.
### Zobacz też
[radians](/glossary/?lan=pl&search=radians)
---
### Glossary/Degrees/README Ua (glossary/degrees/README-ua.md)
## degrees
Конвертує передане значення у градуси
### Оголошення
```glsl
float degrees(float radians)
vec2 degrees(vec2 radians)
vec3 degrees(vec3 radians)
vec4 degrees(vec4 radians)
```
### Параметри
**```radians```** — значення у радіанах, яке потрібно перетворити в градуси.
### Опис
**```degrees()```** перетворює значення, передане в радіанах, у градуси.
Обрахунок по формулі: ```(180.0 * radians) / PI```
### Дивіться також
[radians](/glossary/?lan=ua&search=radians)
---
### Glossary/Degrees/README Vi (glossary/degrees/README-vi.md)
## Degrees
Chuyển đổi góc từ đơn vị radian sang độ
### Các phiên bản
```glsl
float degrees(float radians)
vec2 degrees(vec2 radians)
vec3 degrees(vec3 radians)
vec4 degrees(vec4 radians)
```
### Các tham số
```radians``` góc theo đơn vị radian
### Mô tả
```degrees()``` trả về góc tính bằng độ tương ứng, theo công thức: ```(180.0 * radians)/PI```
### Tham khảo thêm
[radians](/glossary/?lan=vi&search=radians)
---
### Glossary/DFdx/README (glossary/dFdx/README.md)
## DFdx
Return the partial derivative of an argument with respect to x
### Declaration
```glsl
genType dFdx(float x);
```
### Parameters
```p``` specifies the expression of which to take the partial derivative.
### Description
Available only in the fragment shader, ```dFdx``` return the partial derivative of expression ```p``` in ```x```. Derivatives are calculated using local differencing. Expressions that imply higher order derivatives such as ```dFdx(dFdx(n))``` have undefined results, as do mixed-order derivatives such as ```dFdx(dFdy(n))```. It is assumed that the expression ```p``` is continuous and therefore, expressions evaluated via non-uniform control flow may be undefined.
### See Also
[dFdy()](/glossary/?search=dFdy)
---
### Glossary/DFdx/README Pl (glossary/dFdx/README-pl.md)
## dFdx
Zwraca pochodną cząstkową podanego wyrażenia względem x
### Deklaracja
```glsl
genType dFdx(float x);
```
### Parametry
```p``` określa wyrażenie, dla którego chcemy obliczyć pochodną cząstkową.
### Opis
Dostępna wyłącznie w fragment shaderze , ```dFdx``` zwraca pochodną cząstkową wyrażenia ```p``` względem ```x```. Pochodne obliczane są poprzez lokalne różnicowanie. Wyrażenia oznaczające pochodne wyższego rzędu, takie jak ```dFdx(dFdx(n))```, zwracają niezdefiniowane wyniki, podobnie jak mieszane pochodne, np. ```dFdx(dFdy(n))```. Przyjmuje się, że wyrażenie ```p``` jest ciągłe, więc wyrażenia oceniane w warunkowym przepływie sterowania (non-uniform control flow) mogą być niezdefiniowane.
### Zobacz też
[dFdy](/glossary/?lan=pl&search=dFdy)
---
### Glossary/DFdx/README Vi (glossary/dFdx/README-vi.md)
## DFdx
Tính đạo hàm riêng của x
### Các phiên bản
```glsl
genType dFdx( genType p);
```
### Các tham số
```p``` biểu thức cần tính đạo hàm riêng
### Mô tả
Chỉ được dùng trong fragment shader, hàm ```dFdx``` sẽ trả về đạo hàm riêng của biểu thức ```p``` ứng với giá trị```x```. Đạo hàm được tính bằng phương pháp sai phân hữu hạn. Không tính được kết quả của đạo hàm bậc cao như ```dFdx(dFdx(n))```. Giả thiết là biểu thức ```p``` là một hàm liên tục.
### Tham khảo thêm
[dFdy()](/glossary/?lan=vi&search=dFdy)
---
### Glossary/DFdy/README (glossary/dFdy/README.md)
## DFdy
Return the partial derivative of an argument with respect to y
### Declaration
```glsl
genType dFdy(float y);
```
### Parameters
```p``` specifies the expression of which to take the partial derivative.
### Description
Available only in the fragment shader, ```dFdy``` return the partial derivative of expression ```p``` in ```y```. Derivatives are calculated using local differencing. Expressions that imply higher order derivatives such as ```dFdy(dFdy(n))``` have undefined results, as do mixed-order derivatives such as ```dFdy(dFdx(n))```. It is assumed that the expression ```p``` is continuous and therefore, expressions evaluated via non-uniform control flow may be undefined.
### See Also
[dFdx()](/glossary/?search=dFdx)
---
### Glossary/DFdy/README Pl (glossary/dFdy/README-pl.md)
## dFdy
Zwraca pochodną cząstkową podanego wyrażenia względem y
### Deklaracja
```glsl
genType dFdy(float y);
```
### Parametry
```p``` określa wyrażenie, dla którego chcemy obliczyć pochodną cząstkową.
### Opis
Dostępna wyłącznie w fragment shaderze, ```dFdy``` zwraca pochodną cząstkową wyrażenia ```p``` względem ```y```. Pochodne obliczane są poprzez lokalne różnicowanie. Wyrażenia oznaczające pochodne wyższego rzędu, takie jak ```dFdy(dFdy(n))```, zwracają niezdefiniowane wyniki, podobnie jak mieszane pochodne, np. ```dFdy(dFdx(n))```. Przyjmuje się, że wyrażenie ```p``` jest ciągłe, więc wyrażenia oceniane w warunkowym przepływie sterowania (non-uniform control flow) mogą być niezdefiniowane.
### Zobacz też
[dFdx](/glossary/?lan=pl&search=dfdx)
---
### Glossary/DFdy/README Vi (glossary/dFdy/README-vi.md)
## DFdy
Tính đạo hàm riêng của y
### Các phiên bản
```glsl
genType dFdx( genType p);
```
### Các tham số
```p``` biểu thức cần tính đạo hàm riêng
### Mô tả
Chỉ được dùng trong fragment shader, hàm ```dFdy``` sẽ trả về đạo hàm riêng của biểu thức ```p``` ứng với giá trị```x```. Đạo hàm được tính bằng phương pháp sai phân hữu hạn. Không tính được kết quả của đạo hàm bậc cao như ```dFdy(dFdy(n))```. Giả thiết là biểu thức ```p``` là một hàm liên tục.
### Tham khảo thêm
[dFdx()](/glossary/?lan=vi&search=dFdx)
---
### Glossary/Distance/README (glossary/distance/README.md)
## Distance
Calculate the distance between two points
### Declaration
```glsl
float distance(float p0, float p1)
float distance(vec2 p0, vec2 p1)
float distance(vec3 p0, vec3 p1)
float distance(vec4 p0, vec4 p1)
```
### Parameters
```p0``` specifies the first of two points
```p1``` specifies the second of two points
### Description
```distance()``` returns the distance between the two points ```p0``` and ```p1```.
### See Also
[length()](/glossary/?search=length), [normalize()](/glossary/?search=normalize), [Chapter 07: Shapes](/07/)
---
### Glossary/Distance/README Pl (glossary/distance/README-pl.md)
## distance
Oblicza odległość między dwoma punktami
### Deklaracja
```glsl
float distance(float p0, float p1)
float distance(vec2 p0, vec2 p1)
float distance(vec3 p0, vec3 p1)
float distance(vec4 p0, vec4 p1)
```
### Parametry
```p0``` określa pierwszy z dwóch punktów
```p1``` określa drugi z dwóch punktów
### Opis
```distance()``` zwraca odległość pomiędzy dwoma punktami ```p0``` i ```p1```.
### Zobacz też
[length](/glossary/?lan=pl&search=length), [normalize](/glossary/?lan=pl&search=normalize), [Rozdział 07: Kształty](/07/?lan=pl)
---
### Glossary/Distance/README Ua (glossary/distance/README-ua.md)
## distance
Обчислює відстань між двома точками
### Оголошення
```glsl
float distance(float p0, float p1)
float distance(vec2 p0, vec2 p1)
float distance(vec3 p0, vec3 p1)
float distance(vec4 p0, vec4 p1)
```
### Параметри
**```p0```** — перша точка.
**```p1```** — друга точка.
### Опис
**```distance()```** повертає відстань між двома точками **`p0`** і **`p1`**.
### Дивіться також
[length()](/glossary/?lan=ua&search=length), [normalize()](/glossary/?lan=ua&search=normalize), [Розділ 07: Фігури](/07/?lan=ua)
---
### Glossary/Distance/README Vi (glossary/distance/README-vi.md)
## Distance
Tính khoảng cách giữa hai điểm
### Các phiên bản
```glsl
float distance(float p0, float p1)
float distance(vec2 p0, vec2 p1)
float distance(vec3 p0, vec3 p1)
float distance(vec4 p0, vec4 p1)
```
### Các tham số
```p0``` Điểm thứ nhất
```p1``` Điểm thứ hai
### Mô tả
```distance()``` trả về khoảng cách giữa hai điểm ```p0``` và ```p1```.
### Tham khảo thêm
[length()](/glossary/?lan=vi&search=length), [normalize()](/glossary/?lan=vi&search=normalize), [Chương 7: Hình dạng](/07/?lan=vi)
---
### Glossary/Dot/README (glossary/dot/README.md)
## Dot
Calculate the dot product of two vectors
### Declaration
```glsl
float dot(float x, float y)
float dot(vec2 x, vec2 y)
float dot(vec3 x, vec3 y)
float dot(vec4 x, vec4 y)
```
### Parameters
```x``` specifies the first of two vectors
```y``` specifies the second of two vectors
### Description
```dot()``` returns the dot product of two vectors, ```x``` and ```y```. i.e., ```x[0]⋅y[0]+x[1]⋅y[1]+...```
If ```x``` and ```y``` are the same the square root of the dot product is equivalent to the length of the vector. The input parameters can be floating scalars or float vectors. In case of floating scalars the dot function is trivial and returns the product of x and y.
### See Also
[cross()](/glossary/?search=cross), [Chapter 07: Shapes](/07/)
---
### Glossary/Dot/README Pl (glossary/dot/README-pl.md)
## dot
Oblicza iloczyn skalarny (dot product) dwóch wektorów
### Deklaracja
```glsl
float dot(float x, float y)
float dot(vec2 x, vec2 y)
float dot(vec3 x, vec3 y)
float dot(vec4 x, vec4 y)
```
### Parametry
```x``` określa pierwszy z dwóch wektorów
```y``` określa drugi z dwóch wektorów
### Opis
```dot()``` zwraca iloczyn skalarny dwóch wektorów, ```x``` i ```y```, tzn. ```x[0]⋅y[0] + x[1]⋅y[1] + ...```
Jeśli ```x``` i ```y``` są identyczne, wówczas pierwiastek kwadratowy z iloczynu skalarnego jest równoważny długości wektora. Parametry wejściowe mogą być skalarnymi wartościami zmiennoprzecinkowymi lub wektorami zmiennoprzecinkowymi. W przypadku skalarów obliczenia sprowadzają się do pomnożenia ```x``` przez ```y```.
### Zobacz też
[cross](/glossary/?lan=pl&search=cross), [Rozdział 07: Kształty](/07/?lan=pl)
---
### Glossary/Dot/README Ua (glossary/dot/README-ua.md)
## dot
Обчислює скалярний добуток двох векторів
### Оголошення
```glsl
float dot(float x, float y)
float dot(vec2 x, vec2 y)
float dot(vec3 x, vec3 y)
float dot(vec4 x, vec4 y)
```
### Параметри
**```x```** — перший вектор.
**```y```** — другий вектор.
### Опис
**```dot()```** повертає скалярний добуток двох векторів, **`x`** та **`y`**. Тобто: "**```x[0] * y[0] + x[1] * y[1] +...```**"
Якщо **`x`** і **`y`** однакові, квадратний корінь із скалярного добутку еквівалентний довжині вектора. Вхідними параметрами можуть бути скаляри з типом **`float`** або відповідні вектори. У випадку скалярів функція **```dot()```** є тривіальною та повертає добуток **`x`** та **`y`**.
### Дивіться також
[cross()](/glossary/?lan=ua&search=cross), [Розділ 07: Фігури](/07/?lan=ua)
---
### Glossary/Dot/README Vi (glossary/dot/README-vi.md)
## Dot
Tính tích vô hướng của hai vector
### Các phiên bản
```glsl
float dot(float x, float y)
float dot(vec2 x, vec2 y)
float dot(vec3 x, vec3 y)
float dot(vec4 x, vec4 y)
```
### Các tham số
```x``` Vector thứ nhất
```y``` Vector thứ hai
### Mô tả
```dot()``` trả về tích vô hướng của hai vector ```x``` và ```y``` theo công thức ```x[0]⋅y[0]+x[1]⋅y[1]+...```
Nếu ```x``` và ```y``` giống nhau thì căn bậc hai của tích vô hướng sẽ bằng đúng chiều dài của vector.
are the same the square root of the dot product is equivalent to the length of the vector. The input parameters can be floating scalars or float vectors. In case of floating scalars the dot function is trivial and returns the product of x and y.
### Tham khảo thêm
[cross()](/glossary/?lan=vi&search=cross), [Chapter 07: Shapes](/07/)
---
### Glossary/Equal/README (glossary/equal/README.md)
## Equal
Perform a component-wise equal-to comparison of two vectors
### Declaration
```glsl
bvec2 equal(vec2 x, vec2 y)
bvec3 equal(vec3 x, vec3 y)
bvec4 equal(vec4 x, vec4 y)
bvec2 equal(ivec2 x, ivec2 y)
bvec3 equal(ivec3 x, ivec3 y)
bvec4 equal(ivec4 x, ivec4 y)
```
### Parameters
```x``` specifies the first vector to be used in the comparison operation.
```y``` specifies the second vector to be used in the comparison operation.
### Description
```equal()``` returns a boolean vector in which each element ```i``` is computed as ```x[i] == y[i]```.
### See Also
[lessThanEqual()](/glossary/?search=lessThanEqual), [lessThan()](/glossary/?search=lessThan), [greaterThanEqual()](/glossary/?search=greaterThanEqual), [greaterThan()](/glossary/?search=greaterThan), [notEqual()](/glossary/?search=notEqual), [any()](/glossary/?search=any), [all()](/glossary/?search=all), [not()](/glossary/?search=not)
---
### Glossary/Equal/README Ua (glossary/equal/README-ua.md)
## equal
Виконує по-компонентне порівняння двох векторів
### Оголошення
```glsl
bvec2 equal(vec2 x, vec2 y)
bvec3 equal(vec3 x, vec3 y)
bvec4 equal(vec4 x, vec4 y)
bvec2 equal(ivec2 x, ivec2 y)
bvec3 equal(ivec3 x, ivec3 y)
bvec4 equal(ivec4 x, ivec4 y)
```
### Параметри
**```x```** — перший вектор для порівняння.
**```y```** — другий вектор для порівняння.
### Опис
**```equal()```** повертає булів вектор, у якому кожен елемент **`i`** обчислюється як "**```x[i] == y[i]```**".
### Дивіться також
[lessThanEqual()](/glossary/?lan=ua&search=lessThanEqual), [lessThan()](/glossary/?lan=ua&search=lessThan), [greaterThanEqual()](/glossary/?lan=ua&search=greaterThanEqual), [greaterThan()](/glossary/?lan=ua&search=greaterThan), [notEqual()](/glossary/?lan=ua&search=notEqual), [any()](/glossary/?lan=ua&search=any), [all()](/glossary/?lan=ua&search=all), [not()](/glossary/?lan=ua&search=not)
---
### Glossary/Equal/README Vi (glossary/equal/README-vi.md)
## Equal
Thực hiện phép so sánh bằng giữa các cặp giá trị của 2 vector.
### Các phiên bản
```glsl
bvec2 equal(vec2 x, vec2 y)
bvec3 equal(vec3 x, vec3 y)
bvec4 equal(vec4 x, vec4 y)
bvec2 equal(ivec2 x, ivec2 y)
bvec3 equal(ivec3 x, ivec3 y)
bvec4 equal(ivec4 x, ivec4 y)
```
### Các tham số
```x``` Vector thứ nhất.
```y``` Vector thứ hai.
### Mô tả
```equal()``` trả về một vector boolean mà thành phần thứ ```i``` là kết quả của phép so sánh ```x[i] == y[i]```.
### Tham khảo thêm
[lessThanEqual()](/glossary/?lan=vi&search=lessThanEqual), [lessThan()](/glossary/?lan=vi&search=lessThan), [greaterThanEqual()](/glossary/?lan=vi&search=greaterThanEqual), [greaterThan()](/glossary/?lan=vi&search=greaterThan), [notEqual()](/glossary/?lan=vi&search=notEqual), [any()](/glossary/?lan=vi&search=any), [all()](/glossary/?lan=vi&search=all), [not()](/glossary/?lan=vi&search=not)
---
### Glossary/Exp/README (glossary/exp/README.md)
## Exp
Return the natural exponentiation of the parameter
### Declaration
```glsl
float exp(float x)
vec2 exp(vec2 x)
vec3 exp(vec3 x)
vec4 exp(vec4 x)
```
### Parameters
```x``` specifies the value to exponentiate.
### Description
```exp()``` returns the natural exponentiation of ```x```.
### See Also
[log](/glossary/?search=log), [log2](/glossary/?search=log2), [exp2](/glossary/?search=exp2), [Chapter 05: Shaping Functions](/05/)
---
### Glossary/Exp/README Ua (glossary/exp/README-ua.md)
## exp
Повертає експоненту параметра — число Ейлера піднесене до заданого степеня.
Число Ейлера або **`e`** приблизно дорівнює 2.718281828
### Оголошення
```glsl
float exp(float x)
vec2 exp(vec2 x)
vec3 exp(vec3 x)
vec4 exp(vec4 x)
```
### Параметри
**```x```** — степінь до якого потрібно піднести число Ейлера.
### Опис
**```exp()```** повертає число **`e`** піднесене до степеня **`x`**.
### Дивіться також
[log](/glossary/?lan=ua&search=log), [log2](/glossary/?lan=ua&search=log2), [exp2](/glossary/?lan=ua&search=exp2), [Розділ 05: Формотворчі функції](/05/?lan=ua)
---
### Glossary/Exp/README Vi (glossary/exp/README-vi.md)
## Exp
Tính lũy thừa tự nhiên của một số
### Các phiên bản
```glsl
float exp(float x)
vec2 exp(vec2 x)
vec3 exp(vec3 x)
vec4 exp(vec4 x)
```
### Các tham số
```x``` số cần tính lũy thừa tự nhiên.
### Mô tả
```exp()``` trả về kết quả của phép tính e mũ ```x``` (e là cơ số của logarith tự nhiên, xấp xỉ 2.71828)
### Tham khảo thêm
[log](/glossary/?lan=vi&search=log), [log2](/glossary/?lan=vi&search=log2), [exp2](/glossary/?lan=vi&search=exp2), [Các hàm số cơ bản (Hàm hình dạng - Shape function)](/05/?lan=vi)
---
### Glossary/Exp2/README (glossary/exp2/README.md)
## Exp2
Return 2 raised to the power of the parameter
### Declaration
```glsl
float exp2(float x)
vec2 exp2(vec2 x)
vec3 exp2(vec3 x)
vec4 exp2(vec4 x)
```
### Parameters
```x``` specifies the value of the power to which 2 will be raised.
### Description
```exp2()``` returns 2 raised to the power of ```x```.
### See Also
[log](/glossary/?search=log), [log2](/glossary/?search=log2), [exp](/glossary/?search=exp), [Chapter 05: Shaping Functions](/05/)
---
### Glossary/Exp2/README Ua (glossary/exp2/README-ua.md)
## exp2
Повертає число 2 піднесене до заданого степеня.
### Оголошення
```glsl
float exp2(float x)
vec2 exp2(vec2 x)
vec3 exp2(vec3 x)
vec4 exp2(vec4 x)
```
### Параметри
**```x```** — значення степеня, до якого буде піднесено число 2.
### Опис
**```exp2()```** повертає число 2 у степені **`x`**.
### Дивіться також
[log](/glossary/?lan=ua&search=log), [log2](/glossary/?lan=ua&search=log2), [exp](/glossary/?lan=ua&search=exp), [Розділ 05: Формотворчі функції](/05/?lan=ua)
---
### Glossary/Exp2/README Vi (glossary/exp2/README-vi.md)
## Exp2
Hàm 2 mũ x.
### Các phiên bản
```glsl
float exp2(float x)
vec2 exp2(vec2 x)
vec3 exp2(vec3 x)
vec4 exp2(vec4 x)
```
### Các tham số
```x``` số mũ.
### Mô tả
```exp2()``` trả về kết quả của phép tính 2 mũ ```x```.
### Tham khảo thêm
[log](/glossary/?lan=vi&search=log), [log2](/glossary/?lan=vi&search=log2), [exp](/glossary/?lan=vi&search=exp), [Các hàm số cơ bản (Hàm hình dạng - Shape function)](/05/?lan=vi)
---
### Glossary/Faceforward/README (glossary/faceforward/README.md)
## Faceforward
Return a vector pointing in the same direction as another
### Declaration
```glsl
float faceforward(float N, float I, float Nref)
vec2 faceforward(vec2 N, vec2 I, vec2 Nref)
vec3 faceforward(vec3 N, vec3 I, vec3 Nref)
vec4 faceforward(vec4 N, vec4 I, vec4 Nref)
```
### Parameters
```N``` specifies the vector to orient.
```I``` specifies the incident vector.
```Nref``` specifies the reference vector.
### Description
```faceforward()``` orients a vector to point away from a surface as defined by its normal. ```If dot(Nref, I) < 0``` faceforward returns ```N```, otherwise it returns ```-N```.
### See Also
[reflect()](/glossary/?search=reflect), [refract()](/glossary/?search=refract)
---
### Glossary/Faceforward/README Ua (glossary/faceforward/README-ua.md)
## faceforward
Повертає вектор, що вказує в тому ж напрямку, що й інший
### Оголошення
```glsl
float faceforward(float N, float I, float Nref)
vec2 faceforward(vec2 N, vec2 I, vec2 Nref)
vec3 faceforward(vec3 N, vec3 I, vec3 Nref)
vec4 faceforward(vec4 N, vec4 I, vec4 Nref)
```
### Параметри
**```N```** — вектор для орієнтації.
**```I```** — вектор інциденту.
**```Nref```** — опорний вектор.
### Опис
**```faceforward()```** орієнтує вектор так, щоб він був направлений від поверхні, яка визначена її нормаллю. Якщо **```If dot(Nref, I) < 0```** функція повертає **`N`**, інакше **`-N`**.
### Дивіться також
[reflect()](/glossary/?lan=ua&search=reflect), [refract()](/glossary/?lan=ua&search=refract)
---
### Glossary/Faceforward/README Vi (glossary/faceforward/README-vi.md)
## Faceforward
Tìm vector pháp tuyến cùng phía với vector tới so với một bề mặt.
### Các phiên bản
```glsl
float faceforward(float N, float I, float Nref)
vec2 faceforward(vec2 N, vec2 I, vec2 Nref)
vec3 faceforward(vec3 N, vec3 I, vec3 Nref)
vec4 faceforward(vec4 N, vec4 I, vec4 Nref)
```
### Các tham số
```N``` vector pháp tuyến của bề mặt sẽ va chạm (hướng trả về sẽ trùng hướng này hoặc hướng ngược lại)
```I``` vector tới (hướng tới vị trí va chạm với bề mặt).
```Nref``` vector pháp tuyến của bề mặt cần kiểm tra.
### Mô tả
```faceforward()``` trả về hướng của bề mặt (vector pháp tuyến) tại vị trí va chạm với tia tới. Nếu ```dot(Nref, I) < 0``` trả về ```N```, ngược lại trả về ```-N```.
### Tham khảo thêm
[reflect()](/glossary/?lan=vi&search=reflect), [refract()](/glossary/?lan=vi&search=refract)
---
### Glossary/Float/README (glossary/float/README.md)
## Float
Floating-point variable type
### Declaration
```glsl
float aFloat = 1.0;
float bFloat = float(aBool);
float cFloat = float(aInt);
```
### Description
```float``` is used for floating point values.
### See Also
[void](/glossary/?search=void), [bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [bvec2](/glossary/?search=bvec2), [bvec3](/glossary/?search=bvec3), [bvec4](/glossary/?search=bvec4), [struct](/glossary/?search=struct)
---
### Glossary/Float/README Ua (glossary/float/README-ua.md)
## float
Тип даних для чисел з рухомою крапкою
### Приклад
```glsl
float aFloat = 1.0;
float bFloat = float(aBool);
float cFloat = float(aInt);
```
### Опис
**```float```** — використовується для позначення змінних із числами з рухомою крапкою. Також є одноіменна функція для приведення даних до відповідного типу.
### Дивіться також
[void](/glossary/?lan=ua&search=void), [bool](/glossary/?lan=ua&search=bool), [int](/glossary/?lan=ua&search=int), [float](/glossary/?lan=ua&search=float), [vec2](/glossary/?lan=ua&search=vec2), [vec3](/glossary/?lan=ua&search=vec3), [vec4](/glossary/?lan=ua&search=vec4), [struct](/glossary/?lan=ua&search=struct)
---
### Glossary/Float/README Vi (glossary/float/README-vi.md)
## Float
Kiểu dữ liệu số thực.
### Các phiên bản
```glsl
float aFloat = 1.0;
float bFloat = float(aBool);
float cFloat = float(aInt);
```
### Mô tả
```float``` lưu giá trị của số thực, bao gồm cả phần nguyên lẫn phần thập phân.
### Tham khảo thêm
[void](/glossary/?lan=vi&search=void), [bool](/glossary/?lan=vi&search=bool), [int](/glossary/?lan=vi&search=int), [float](/glossary/?lan=vi&search=float), [bvec2](/glossary/?lan=vi&search=bvec2), [bvec3](/glossary/?lan=vi&search=bvec3), [bvec4](/glossary/?lan=vi&search=bvec4), [struct](/glossary/?lan=vi&search=struct)
---
### Glossary/Floor/README (glossary/floor/README.md)
## Floor
Find the nearest integer less than or equal to the parameter
### Declaration
```glsl
float floor(float x)
vec2 floor(vec2 x)
vec3 floor(vec3 x)
vec4 floor(vec4 x)
```
### Parameters
```x``` specifies the value to evaluate.
### Description
```floor()``` returns a value equal to the nearest integer that is less than or equal to ```x```.
### See Also
[ceil](/glossary/?search=ceil), [fract](/glossary/?search=fract), [mod](/glossary/?search=mod), [Chapter 05: Shaping Functions](/05/)
---
### Glossary/Floor/README Ua (glossary/floor/README-ua.md)
## floor
Знаходить і повертає найближче ціле число, яке менше або дорівнює параметру
### Оголошення
```glsl
float floor(float x)
vec2 floor(vec2 x)
vec3 floor(vec3 x)
vec4 floor(vec4 x)
```
### Параметри
**```x```** — значення для обробки.
### Опис
**```floor()```** повертає значення, що дорівнює найближчому цілому числу, яке менше або дорівнює **`x`**.
### Дивіться також
[ceil](/glossary/?lan=ua&search=ceil), [fract](/glossary/?lan=ua&search=fract), [mod](/glossary/?lan=ua&search=mod), [Розділ 05: Формотворчі функції](/05/?lan=ua)
---
### Glossary/Floor/README Vi (glossary/floor/README-vi.md)
## Floor
Tìm số nguyên gần nhất nhỏ hơn hoặc bằng (Làm tròn xuống).
### Các phiên bản
```glsl
float floor(float x)
vec2 floor(vec2 x)
vec3 floor(vec3 x)
vec4 floor(vec4 x)
```
### Các tham số
```x``` số cần làm tròn xuống
### Mô tả
```floor()``` trả về số nguyên gần nhất nhỏ hơn hoặc bằng với ```x```.
### Tham khảo thêm
[ceil](/glossary/?lan=vi&search=ceil), [fract](/glossary/?lan=vi&search=fract), [mod](/glossary/?lan=vi&search=mod), [Các hàm số cơ bản (Hàm hình dạng - Shape function)](/05/?lan=vi)
---
### Glossary/Fract/README (glossary/fract/README.md)
## Fract
Compute the fractional part of the argument
### Declaration
```glsl
float fract(float x)
vec2 fract(vec2 x)
vec3 fract(vec3 x)
vec4 fract(vec4 x)
```
### Parameters
```x``` specifies the value to evaluate.
### Description
```fract()``` returns the fractional part of ```x```. This is calculated as ```x - floor(x)```.
### See Also
[floor](/glossary/?search=floor), [ceil](/glossary/?search=ceil), [mod](/glossary/?search=mod), [Chapter 05: Shaping Functions](/05/)
---
### Glossary/Fract/README Ua (glossary/fract/README-ua.md)
## fract
Повертає дробову частину аргументу
### Оголошення
```glsl
float fract(float x)
vec2 fract(vec2 x)
vec3 fract(vec3 x)
vec4 fract(vec4 x)
```
### Параметри
**```x```** — значення для обробки.
### Опис
**```fract()```** повертає дробову частину від **`x`**. Це обчислюється як **```x - floor(x)```**.
### Дивіться також
[floor](/glossary/?lan=ua&search=floor), [ceil](/glossary/?lan=ua&search=ceil), [mod](/glossary/?lan=ua&search=mod), [Розділ 05: Формотворчі функції](/05/?lan=ua)
---
### Glossary/Fract/README Vi (glossary/fract/README-vi.md)
## Fract
Tách phần thập phân của số thực.
### Các phiên bản
```glsl
float fract(float x)
vec2 fract(vec2 x)
vec3 fract(vec3 x)
vec4 fract(vec4 x)
```
### Các tham số
```x``` số thực cần tách phần thập phân.
### Mô tả
```fract()``` trả về phần thập phân của ```x``` theo công thức ```x - floor(x)```.
### Tham khảo thêm
[floor](/glossary/?lan=vi&search=floor), [ceil](/glossary/?lan=vi&search=ceil), [mod](/glossary/?lan=vi&search=mod), [Các hàm số cơ bản (Hàm hình dạng - Shape function)](/05/?lan=vi)
---
### Glossary/GL ES/README (glossary/GL_ES/README.md)
## GL_ES
### Declaration / Example
### Parameters
### Description
### See Also
---
### Glossary/GL ES/README Vi (glossary/GL_ES/README-vi.md)
## GL_ES
### Các phiên bản / Example
### Các tham số
### Mô tả
### Tham khảo thêm
---
### Glossary/Gl FragColor/README (glossary/gl_FragColor/README.md)
## Gl_FragColor
### Declaration / Example
### Parameters
### Description
### See Also
---
### Glossary/Gl FragColor/README Ua (glossary/gl_FragColor/README-ua.md)
## gl_FragColor
### Оголошення / Приклад
### Параметри
### Опис
### Дивіться також
---
### Glossary/Gl FragColor/README Vi (glossary/gl_FragColor/README-vi.md)
## Gl_FragColor
### Các phiên bản / Example
### Các tham số
### Mô tả
### Tham khảo thêm
---
### Glossary/Gl FragCoord/README (glossary/gl_FragCoord/README.md)
## Gl_FragCoord
### Declaration / Example
### Parameters
### Description
### See Also
---
### Glossary/Gl FragCoord/README Ua (glossary/gl_FragCoord/README-ua.md)
## gl_FragCoord
### Оголошення / Приклад
### Параметри
### Опис
### Дивіться також
---
### Glossary/Gl FragCoord/README Vi (glossary/gl_FragCoord/README-vi.md)
## G_FragCoord
### Các phiên bản / Example
### Các tham số
### Mô tả
### Tham khảo thêm
---
### Glossary/Gl FrontFacing/README (glossary/gl_FrontFacing/README.md)
## Gl_FrontFacing
### Declaration / Example
### Parameters
### Description
### See Also
---
### Glossary/Gl FrontFacing/README Ua (glossary/gl_FrontFacing/README-ua.md)
## gl_FrontFacing
### Оголошення / Приклад
### Параметри
### Опис
### Дивіться також
---
### Glossary/Gl FrontFacing/README Vi (glossary/gl_FrontFacing/README-vi.md)
## Gl_FrontFacing
### Các phiên bản / Example
### Các tham số
### Mô tả
### Tham khảo thêm
---
### Glossary/Gl MaxCombinedTextureImageUnits/README (glossary/gl_MaxCombinedTextureImageUnits/README.md)
## Gl_MaxCombinedTextureImages
### Declaration / Example
### Parameters
### Description
### See Also
---
### Glossary/Gl MaxCombinedTextureImageUnits/README Ua (glossary/gl_MaxCombinedTextureImageUnits/README-ua.md)
## gl_MaxCombinedTextureImages
### Оголошення / Приклад
### Параметри
### Опис
### Дивіться також
---
### Glossary/Gl MaxCombinedTextureImageUnits/README Vi (glossary/gl_MaxCombinedTextureImageUnits/README-vi.md)
## Gl_MaxCombinedTextureImages
### Các phiên bản / Example
### Các tham số
### Mô tả
### Tham khảo thêm
---
### Glossary/Gl MaxDrawBuffers/README (glossary/gl_MaxDrawBuffers/README.md)
## Gl_MaxDrawBuffers
### Declaration / Example
### Parameters
### Description
### See Also
---
### Glossary/Gl MaxDrawBuffers/README Ua (glossary/gl_MaxDrawBuffers/README-ua.md)
## gl_MaxDrawBuffers
### Оголошення / Приклад
### Параметри
### Опис
### Дивіться також
---
### Glossary/Gl MaxDrawBuffers/README Vi (glossary/gl_MaxDrawBuffers/README-vi.md)
## Gl_MaxDrawBuffers
### Các phiên bản / Example
### Các tham số
### Mô tả
### Tham khảo thêm
---
### Glossary/Gl MaxFragmentUniformVectors/README (glossary/gl_MaxFragmentUniformVectors/README.md)
## Gl_MaxFragmentUniformVectors
### Declaration / Example
### Parameters
### Description
### See Also
---
### Glossary/Gl MaxFragmentUniformVectors/README Ua (glossary/gl_MaxFragmentUniformVectors/README-ua.md)
## gl_MaxFragmentUniformVectors
### Оголошення / Приклад
### Параметри
### Опис
### Дивіться також
---
### Glossary/Gl MaxFragmentUniformVectors/README Vi (glossary/gl_MaxFragmentUniformVectors/README-vi.md)
## Gl_MaxFragmentUniformVectors
### Các phiên bản / Example
### Các tham số
### Mô tả
### Tham khảo thêm
---
### Glossary/Gl MaxTextureImageUnits/README (glossary/gl_MaxTextureImageUnits/README.md)
## Gl_MaxTextureImageUnits
### Declaration / Example
### Parameters
### Description
### See Also
---
### Glossary/Gl MaxTextureImageUnits/README Ua (glossary/gl_MaxTextureImageUnits/README-ua.md)
## gl_MaxTextureImageUnits
### Оголошення / Приклад
### Параметри
### Опис
### Дивіться також
---
### Glossary/Gl MaxTextureImageUnits/README Vi (glossary/gl_MaxTextureImageUnits/README-vi.md)
## Gl_MaxTextureImageUnits
### Các phiên bản / Example
### Các tham số
### Mô tả
### Tham khảo thêm
---
### Glossary/Gl MaxVaryingVectors/README (glossary/gl_MaxVaryingVectors/README.md)
## Gl_MaxVaryingVectors
### Declaration / Example
### Parameters
### Description
### See Also
---
### Glossary/Gl MaxVaryingVectors/README Ua (glossary/gl_MaxVaryingVectors/README-ua.md)
## gl_MaxVaryingVectors
### Оголошення / Приклад
### Параметри
### Опис
### Дивіться також
---
### Glossary/Gl MaxVaryingVectors/README Vi (glossary/gl_MaxVaryingVectors/README-vi.md)
## Gl_MaxVaryingVectors
### Các phiên bản / Example
### Các tham số
### Mô tả
### Tham khảo thêm
---
### Glossary/Gl MaxVertexAttribs/README (glossary/gl_MaxVertexAttribs/README.md)
## Gl_MaxVertexAttrbis
### Declaration / Example
### Parameters
### Description
### See Also
---
### Glossary/Gl MaxVertexAttribs/README Ua (glossary/gl_MaxVertexAttribs/README-ua.md)
## gl_MaxVertexAttribs
### Оголошення / Приклад
### Параметри
### Опис
### Дивіться також
---
### Glossary/Gl MaxVertexAttribs/README Vi (glossary/gl_MaxVertexAttribs/README-vi.md)
## Gl_MaxVertexAttrbis
### Các phiên bản / Example
### Các tham số
### Mô tả
### Tham khảo thêm
---
### Glossary/Gl MaxVertexTextureImageUnits/README (glossary/gl_MaxVertexTextureImageUnits/README.md)
## Gl_MaxVertexTextureImageUnits
### Declaration / Example
### Parameters
### Description
### See Also
---
### Glossary/Gl MaxVertexTextureImageUnits/README Ua (glossary/gl_MaxVertexTextureImageUnits/README-ua.md)
## gl_MaxVertexTextureImageUnits
### Оголошення / Приклад
### Параметри
### Опис
### Дивіться також
---
### Glossary/Gl MaxVertexTextureImageUnits/README Vi (glossary/gl_MaxVertexTextureImageUnits/README-vi.md)
## Gl_MaxVertexTextureImageUnits
### Các phiên bản / Example
### Các tham số
### Mô tả
### Tham khảo thêm
---
### Glossary/Gl PointCoord/README (glossary/gl_PointCoord/README.md)
## Gl_PointCoord
### Declaration / Example
### Parameters
### Description
### See Also
---
### Glossary/Gl PointCoord/README Ua (glossary/gl_PointCoord/README-ua.md)
## gl_PointCoord
### Оголошення / Приклад
### Параметри
### Опис
### Дивіться також
---
### Glossary/Gl PointCoord/README Vi (glossary/gl_PointCoord/README-vi.md)
## Gl_PointCoord
### Các phiên bản / Example
### Các tham số
### Mô tả
### Tham khảo thêm
---
### Glossary/Gl PointSize/README (glossary/gl_PointSize/README.md)
## Gl_PointSize
### Declaration / Example
### Parameters
### Description
### See Also
---
### Glossary/Gl PointSize/README Ua (glossary/gl_PointSize/README-ua.md)
## gl_PointSize
### Оголошення / Приклад
### Параметри
### Опис
### Дивіться також
---
### Glossary/Gl PointSize/README Vi (glossary/gl_PointSize/README-vi.md)
## Gl_PointSize
### Các phiên bản / Example
### Các tham số
### Mô tả
### Tham khảo thêm
---
### Glossary/Gl Position/README (glossary/gl_Position/README.md)
## Gl_Position
### Declaration / Example
### Parameters
### Description
### See Also
---
### Glossary/Gl Position/README Ua (glossary/gl_Position/README-ua.md)
## gl_Position
### Оголошення / Приклад
### Параметри
### Опис
### Дивіться також
---
### Glossary/Gl Position/README Vi (glossary/gl_Position/README-vi.md)
## Gl_Position
### Các phiên bản / Example
### Các tham số
### Mô tả
### Tham khảo thêm
---
### Glossary/GreaterThan/README (glossary/greaterThan/README.md)
## GreaterThan
Perform a component-wise greater-than comparison of two vectors
### Declaration
```glsl
bvec2 greaterThan(vec2 x, vec2 y)
bvec3 greaterThan(vec3 x, vec3 y)
bvec4 greaterThan(vec4 x, vec4 y)
bvec2 greaterThan(ivec2 x, ivec2 y)
bvec3 greaterThan(ivec3 x, ivec3 y)
bvec4 greaterThan(ivec4 x, ivec4 y)
```
### Parameters
```x``` specifies the first vector to be used in the comparison operation.
```y``` specifies the second vector to be used in the comparison operation.
### Description
```greaterThan()``` returns a boolean vector in which each element ```i``` is computed as ```x[i] > y[i]```.
### See Also
[lessThanEqual()](/glossary/?search=lessThanEqual), [lessThan()](/glossary/?search=lessThan), [greaterThanEqual()](/glossary/?search=greaterThanEqual), [equal()](/glossary/?search=equal), [notEqual()](/glossary/?search=notEqual), [any()](/glossary/?search=any), [all()](/glossary/?search=all), [not()](/glossary/?search=not)
---
### Glossary/GreaterThan/README Ua (glossary/greaterThan/README-ua.md)
## greaterThan
Виконує по-компонентне порівняння двох векторів на більшість компонентів першого вектора по відношенню до другого
### Оголошення
```glsl
bvec2 greaterThan(vec2 x, vec2 y)
bvec3 greaterThan(vec3 x, vec3 y)
bvec4 greaterThan(vec4 x, vec4 y)
bvec2 greaterThan(ivec2 x, ivec2 y)
bvec3 greaterThan(ivec3 x, ivec3 y)
bvec4 greaterThan(ivec4 x, ivec4 y)
```
### Параметри
**```x```** — перший вектор для порівняння.
**```y```** — другий вектор для порівняння.
### Опис
**```greaterThan()```** повертає булів вектор, у якому кожен елемент **`i`** обчислюється як "**```x[i] > y[i]```**".
### Дивіться також
[lessThanEqual()](/glossary/?lan=ua&search=lessThanEqual), [lessThan()](/glossary/?lan=ua&search=lessThan), [greaterThanEqual()](/glossary/?lan=ua&search=greaterThanEqual), [equal()](/glossary/?lan=ua&search=equal), [notEqual()](/glossary/?lan=ua&search=notEqual), [any()](/glossary/?lan=ua&search=any), [all()](/glossary/?lan=ua&search=all), [not()](/glossary/?lan=ua&search=not)
---
### Glossary/GreaterThan/README Vi (glossary/greaterThan/README-vi.md)
## GreaterThan
Thực hiện phép so sánh lớn hơn với từng cặp giá trị trong 2 vector
### Các phiên bản
```glsl
bvec2 greaterThan(vec2 x, vec2 y)
bvec3 greaterThan(vec3 x, vec3 y)
bvec4 greaterThan(vec4 x, vec4 y)
bvec2 greaterThan(ivec2 x, ivec2 y)
bvec3 greaterThan(ivec3 x, ivec3 y)
bvec4 greaterThan(ivec4 x, ivec4 y)
```
### Các tham số
```x``` Vector thứ nhất
```y``` Vector thứ hai
### Mô tả
```greaterThan()``` trả về một vector boolean mà thành phần thứ ```i``` là kết quả của phép so sánh ```x[i] > y[i]```.
### Tham khảo thêm
[lessThanEqual()](/glossary/?lan=vi&search=lessThanEqual), [lessThan()](/glossary/?lan=vi&search=lessThan), [greaterThanEqual()](/glossary/?lan=vi&search=greaterThanEqual), [equal()](/glossary/?lan=vi&search=equal), [notEqual()](/glossary/?lan=vi&search=notEqual), [any()](/glossary/?lan=vi&search=any), [all()](/glossary/?lan=vi&search=all), [not()](/glossary/?lan=vi&search=not)
---
### Glossary/GreaterThanEqual/README (glossary/greaterThanEqual/README.md)
## GreaterThanEqual
Perform a component-wise greater-than-or-equal comparison of two vectors
### Declaration
```glsl
bvec2 greaterThanEqual(vec2 x, vec2 y)
bvec3 greaterThanEqual(vec3 x, vec3 y)
bvec4 greaterThanEqual(vec4 x, vec4 y)
bvec2 greaterThanEqual(ivec2 x, ivec2 y)
bvec3 greaterThanEqual(ivec3 x, ivec3 y)
bvec4 greaterThanEqual(ivec4 x, ivec4 y)
```
### Parameters
```x``` specifies the first vector to be used in the comparison operation.
```y``` specifies the second vector to be used in the comparison operation.
### Description
```greaterThanEqual()``` returns a boolean vector in which each element ```i``` is computed as ```x[i] ≥ y[i]```.
### See Also
[lessThanEqual()](/glossary/?search=lessThanEqual), [lessThan()](/glossary/?search=lessThan), [greaterThan()](/glossary/?search=greaterThan), [equal()](/glossary/?search=equal), [notEqual()](/glossary/?search=notEqual), [any()](/glossary/?search=any), [all()](/glossary/?search=all), [not()](/glossary/?search=not)
---
### Glossary/GreaterThanEqual/README Ua (glossary/greaterThanEqual/README-ua.md)
## greaterThanEqual
Виконує по-компонентне порівняння двох векторів на більшість або рівність компонентів першого вектора по відношенню до другого
### Оголошення
```glsl
bvec2 greaterThanEqual(vec2 x, vec2 y)
bvec3 greaterThanEqual(vec3 x, vec3 y)
bvec4 greaterThanEqual(vec4 x, vec4 y)
bvec2 greaterThanEqual(ivec2 x, ivec2 y)
bvec3 greaterThanEqual(ivec3 x, ivec3 y)
bvec4 greaterThanEqual(ivec4 x, ivec4 y)
```
### Параметри
**```x```** — перший вектор для порівняння.
**```y```** — другий вектор для порівняння.
### Опис
**```greaterThanEqual()```** повертає булів вектор, у якому кожен елемент **`i`** обчислюється як "**```x[i] ≥ y[i]```**".
### Дивіться також
[lessThanEqual()](/glossary/?lan=ua&search=lessThanEqual), [lessThan()](/glossary/?lan=ua&search=lessThan), [greaterThan()](/glossary/?lan=ua&search=greaterThan), [equal()](/glossary/?lan=ua&search=equal), [notEqual()](/glossary/?lan=ua&search=notEqual), [any()](/glossary/?lan=ua&search=any), [all()](/glossary/?lan=ua&search=all), [not()](/glossary/?lan=ua&search=not)
---
### Glossary/GreaterThanEqual/README Vi (glossary/greaterThanEqual/README-vi.md)
## GreaterThanEqual
Thực hiện phép so sánh lớn-hơn-hoặc-bằng cho từng cặp giá trị giữa hai vector.
### Các phiên bản
```glsl
bvec2 greaterThanEqual(vec2 x, vec2 y)
bvec3 greaterThanEqual(vec3 x, vec3 y)
bvec4 greaterThanEqual(vec4 x, vec4 y)
bvec2 greaterThanEqual(ivec2 x, ivec2 y)
bvec3 greaterThanEqual(ivec3 x, ivec3 y)
bvec4 greaterThanEqual(ivec4 x, ivec4 y)
```
### Các tham số
```x``` Vector thứ nhất.
```y``` Vector thứ hai.
### Mô tả
```greaterThanEqual()``` trả về một vector boolean mà thành phần thứ ```i``` là kết quả của phép so sánh ```x[i] ≥ y[i]```.
### Tham khảo thêm
[lessThanEqual()](/glossary/?lan=vi&search=lessThanEqual), [lessThan()](/glossary/?lan=vi&search=lessThan), [greaterThan()](/glossary/?lan=vi&search=greaterThan), [equal()](/glossary/?lan=vi&search=equal), [notEqual()](/glossary/?lan=vi&search=notEqual), [any()](/glossary/?lan=vi&search=any), [all()](/glossary/?lan=vi&search=all), [not()](/glossary/?lan=vi&search=not)
---
### Glossary/Highp/README (glossary/highp/README.md)
## Highp
### Declaration / Example
### Parameters
### Description
### See Also
---
### Glossary/Highp/README Ua (glossary/highp/README-ua.md)
## highp
Кваліфікатор точності, задається на початку шейдера
### Приклад
```glsl
precision highp float;
precision highp int;
```
### Опис
Кваліфікатор точності оголошує мінімальний діапазон і точність, які повинні використовуватися під час зберігання змінних відповідного типу.
**```highp```** — 32+ біт, діапазон для **`float`** від -2^62 to +2^62, діапазон для **`int`** від -2^16 до 2^16
### Дивіться також
[lowp](/glossary/?lan=ua&search=lowp), [mediump](/glossary/?lan=ua&search=mediump), [precision](/glossary/?lan=ua&search=precision)
---
### Glossary/Highp/README Vi (glossary/highp/README-vi.md)
## Highp
### Các phiên bản / Example
### Các tham số
### Mô tả
### Tham khảo thêm
---
### Glossary/In/README (glossary/in/README.md)
## In
### Declaration / Example
### Parameters
### Description
### See Also
---
### Glossary/In/README Ua (glossary/in/README-ua.md)
## in
Кваліфікатор доступу аргументів. Позначає аргумент лише на читання. Застосовується по замовчуванню.
### Приклад
```glsl
// Кваліфікатор "in" можна не прописувати явно, бо він застосовується по замовчуванню
float updateValue(in float x) {
// ці зміни для змінної "х" відбудуться лише усередині функції
x = x + x; // x = (0.5 + 0.5) = 1.0
return x; // 1.0
}
void main() {
float x = 0.5;
float totalSum = updateValue(x); // totalSum == 1.0
// x == 0.5, оскільки параметр був переданий лише на читання, то після виконання функції його значення залишається як і було
}
```
### Опис
**```in```** — кваліфікатор доступу аргументів, який дозволяє лише читати позначену змінну. Зміни всередині функції не вплинуть на значення переданої змінної поза її межами.
### Дивіться також
[out](/glossary/?lan=ua&search=out), [inout](/glossary/?lan=ua&search=inout)
---
### Glossary/In/README Vi (glossary/in/README-vi.md)
## In
### Các phiên bản / Example
### Các tham số
### Mô tả
### Tham khảo thêm
---
### Glossary/Inout/README (glossary/inout/README.md)
## Inout
### Declaration / Example
### Parameters
### Description
### See Also
---
### Glossary/Inout/README Ua (glossary/inout/README-ua.md)
## inout
Кваліфікатор доступу аргументів. Задає можливість як читати так і змінювати аргумент. Нове значення змінної буде також доступне й за межами функції де відбулася ця зміна.
### Приклад
```glsl
void increment(inout int x) {
x = x + 1;
}
void main() {
int count = 1;
increment(count);
// тепер count == 2, оскільки змінна була передана у функцію із inout кваліфікатором та була оновлена
}
```
### Опис
**```inout```** — кваліфікатор доступу аргументів, який дозволяє як читати так і змінювати позначену змінну. Зміна значення застосується не лише всередині функції, але і поза її межами, як показано у прикладі.
### Дивіться також
[in](/glossary/?lan=ua&search=in), [out](/glossary/?lan=ua&search=out)
---
### Glossary/Inout/README Vi (glossary/inout/README-vi.md)
## Inout
### Các phiên bản / Example
### Các tham số
### Mô tả
### Tham khảo thêm
---
### Glossary/Int/README (glossary/int/README.md)
## Int
Integer data type
### Declaration
```glsl
int aInt = 42;
int bInt = int(aBool);
int cInt = int(aFloat);
```
### Description
```int``` is used for integer values.
### See Also
[void](/glossary/?search=void), [bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [ivec2](/glossary/?search=ivec2), [ivec3](/glossary/?search=ivec3), [ivec4](/glossary/?search=ivec4)
---
### Glossary/Int/README Ua (glossary/int/README-ua.md)
## int
Цілочисельний тип даних
### Приклад
```glsl
int aInt = 42;
int bInt = int(aBool);
int cInt = int(aFloat);
```
### Опис
**```int```** — використовується для позначення змінних із цілочисельними значеннями. Також є одноіменна функція для приведення даних до відповідного типу.
### Дивіться також
[void](/glossary/?lan=ua&search=void), [bool](/glossary/?lan=ua&search=bool), [int](/glossary/?lan=ua&search=int), [float](/glossary/?lan=ua&search=float), [ivec2](/glossary/?lan=ua&search=ivec2), [ivec3](/glossary/?lan=ua&search=ivec3), [ivec4](/glossary/?lan=ua&search=ivec4)
---
### Glossary/Int/README Vi (glossary/int/README-vi.md)
## Int
Kiểu dữ liệu số nguyên.
### Các phiên bản
```glsl
int aInt = 42;
int bInt = int(aBool);
int cInt = int(aFloat);
```
### Mô tả
```int``` lưu giá trị của một số nguyên.
### Tham khảo thêm
[void](/glossary/?lan=vi&search=void), [bool](/glossary/?lan=vi&search=bool), [int](/glossary/?lan=vi&search=int), [float](/glossary/?lan=vi&search=float), [ivec2](/glossary/?lan=vi&search=ivec2), [ivec3](/glossary/?lan=vi&search=ivec3), [ivec4](/glossary/?lan=vi&search=ivec4)
---
### Glossary/Inversesqrt/README (glossary/inversesqrt/README.md)
## Inversesqrt
Return the inverse of the square root of the parameter
### Declaration
```glsl
float inversesqrt(float x)
vec2 inversesqrt(vec2 x)
vec3 inversesqrt(vec3 x)
vec4 inversesqrt(vec4 x)
```
### Parameters
```x``` specifies the value of which to take the inverse of the square root.
### Description
```inversesqrt()``` returns the inverse of the square root of ```x```.
### See Also
[pow](/glossary/?search=pow), [sqrt](/glossary/?search=sqrt), [Chapter 05: Shaping Functions](/05/)
---
### Glossary/Inversesqrt/README Ua (glossary/inversesqrt/README-ua.md)
## inversesqrt
Повертає значення, обернене квадратному кореню з параметра
### Оголошення
```glsl
float inversesqrt(float x)
vec2 inversesqrt(vec2 x)
vec3 inversesqrt(vec3 x)
vec4 inversesqrt(vec4 x)
```
### Параметри
**```x```** — значення, з якого треба взяти обернений квадратний корінь
### Опис
**```inversesqrt()```** повертає значення, обернене квадратному кореню з **`x`**.
### Дивіться також
[pow](/glossary/?lan=ua&search=pow), [sqrt](/glossary/?lan=ua&search=sqrt), [Розділ 05: Формотворчі функції](/05/?lan=ua)
---
### Glossary/Inversesqrt/README Vi (glossary/inversesqrt/README-vi.md)
## Inversesqrt
Phép nghịch đảo căn bậc 2.
### Các phiên bản
```glsl
float inversesqrt(float x)
vec2 inversesqrt(vec2 x)
vec3 inversesqrt(vec3 x)
vec4 inversesqrt(vec4 x)
```
### Các tham số
```x``` số cần tính nghịch đảo căn bậc 2.
### Mô tả
```inversesqrt()``` trả về kết quả của biểu thức ```1 / sqrt(x)```.
### Tham khảo thêm
[pow](/glossary/?lan=vi&search=pow), [sqrt](/glossary/?lan=vi&search=sqrt), [Các hàm số cơ bản (Hàm hình dạng - Shape function)](/05/?lan=vi)
---
### Glossary/Ivec2/README (glossary/ivec2/README.md)
## Ivec2
2 dimensional integer vector
### Declaration
```glsl
bvec2 aIvec2 = ivec2(1, 1);
bvec2 bIvec2 = ivec2(1);
bvec2 cIvec2 = ivec2(aIvec3);
bvec2 dIvec2 = ivec2(aIvec3.x, aIvec3.y);
```
### Description
```ivec2``` is an integer vector with two components. It can be initialized by:
- Providing a scalar value for each component.
- Providing one scalar value. This value is used for all components.
- Providing a vector of higher dimension. The respective values are used to initialize the components.
### See Also
[bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [bvec2](/glossary/?search=bvec2), [bvec3](/glossary/?search=bvec3), [bvec4](/glossary/?search=bvec4), [ivec2](/glossary/?search=ivec2), [ivec3](/glossary/?search=ivec3), [ivec4](/glossary/?search=ivec4), [vec2](/glossary/?search=vec2), [vec3](/glossary/?search=vec3), [vec4](/glossary/?search=vec4), [mat2](/glossary/?search=mat2), [mat3](/glossary/?search=mat3), [mat4](/glossary/?search=mat4)
---
### Glossary/Ivec2/README Ua (glossary/ivec2/README-ua.md)
## ivec2
2-вимірний цілочисельний вектор
### Оголошення
```glsl
bvec2 aIvec2 = ivec2(1, 1);
bvec2 bIvec2 = ivec2(1);
bvec2 cIvec2 = ivec2(aIvec3);
bvec2 dIvec2 = ivec2(aIvec3.x, aIvec3.y);
```
### Опис
**```ivec2```** — цілочисельний вектор із двома компонентами. Способи ініціалізації:
- надання скалярного значення для кожного компонента;
- надання одного скалярного значення, що буде використано для всіх компонентів;
- надання вектора вищої розмірності, де відповідні значення будуть використані для ініціалізації компонентів;
### Дивіться також
[bool](/glossary/?lan=ua&search=bool), [int](/glossary/?lan=ua&search=int), [float](/glossary/?lan=ua&search=float), [bvec2](/glossary/?lan=ua&search=bvec2), [bvec3](/glossary/?lan=ua&search=bvec3), [bvec4](/glossary/?slan=ua&earch=bvec4), [ivec2](/glossary/?lan=ua&search=ivec2), [ivec3](/glossary/?lan=ua&search=ivec3), [ivec4](/glossary/?lan=ua&search=ivec4), [vec2](/glossary/?lan=ua&search=vec2), [vec3](/glossary/?lan=ua&search=vec3), [vec4](/glossary/?lan=ua&search=vec4), [mat2](/glossary/?lan=ua&search=mat2), [mat3](/glossary/?lan=ua&search=mat3), [mat4](/glossary/?lan=ua&search=mat4)
---
### Glossary/Ivec2/README Vi (glossary/ivec2/README-vi.md)
## Ivec2
Vector số nguyên 2 chiều.
### Các phiên bản
```glsl
bvec2 aIvec2 = ivec2(1, 1);
bvec2 bIvec2 = ivec2(1);
bvec2 cIvec2 = ivec2(aIvec3);
bvec2 dIvec2 = ivec2(aIvec3.x, aIvec3.y);
```
### Mô tả
```ivec2``` vector số nguyên gồm 2 thành phần. Nó có thể được khởi tạo bằng các cách:
- Chỉ định giá trị của từng thành phần
- Chỉ định 1 giá trị chung cho cả 2 thành phần
- Lấy giá trị từ 1 vector nhiều chiều hơn. Các thành phần sẽ được khởi tạo theo thứ tự.
### Tham khảo thêm
[bool](/glossary/?lan=vi&search=bool), [int](/glossary/?lan=vi&search=int), [float](/glossary/?lan=vi&search=float), [bvec2](/glossary/?lan=vi&search=bvec2), [bvec3](/glossary/?lan=vi&search=bvec3), [bvec4](/glossary/?lan=vi&search=bvec4), [ivec2](/glossary/?lan=vi&search=ivec2), [ivec3](/glossary/?lan=vi&search=ivec3), [ivec4](/glossary/?lan=vi&search=ivec4), [vec2](/glossary/?lan=vi&search=vec2), [vec3](/glossary/?lan=vi&search=vec3), [vec4](/glossary/?lan=vi&search=vec4), [mat2](/glossary/?lan=vi&search=mat2), [mat3](/glossary/?lan=vi&search=mat3), [mat4](/glossary/?lan=vi&search=mat4)
---
### Glossary/Ivec3/README (glossary/ivec3/README.md)
## Ivec3
3 dimensional integer vector
### Declaration
```glsl
vec3 aIvec3 = ivec3(1, 1, 1);
vec3 bIvec3 = ivec3(1);
vec3 cIvec3 = ivec3(aIvec4);
vec3 dIvec3 = ivec3(aIvec4.x, aIvec4.y, aIvec4.z);
vec3 eIvec3 = ivec3(aIvec2, aInt);
vec3 fIvec3 = ivec3(aIvec2.x, aIvec2.y, aInt);
```
### Description
```ivec3``` is an integer vector with three components. It can be initialized by:
- Providing a scalar value for each component.
- Providing one scalar value. This value is used for all components.
- Providing a vector of higher dimension. The respective values are used to initialize the components.
- Providing a combination of vectors and/or scalars. The respective values are used to initialize the vector. The arguments of the constructor must have at least as many components as the vector that is initialized.
### See Also
[bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [bvec2](/glossary/?search=bvec2), [bvec3](/glossary/?search=bvec3), [bvec4](/glossary/?search=bvec4), [ivec2](/glossary/?search=ivec2), [ivec3](/glossary/?search=ivec3), [ivec4](/glossary/?search=ivec4), [vec2](/glossary/?search=vec2), [vec3](/glossary/?search=vec3), [vec4](/glossary/?search=vec4), [mat2](/glossary/?search=mat2), [mat3](/glossary/?search=mat3), [mat4](/glossary/?search=mat4)
---
### Glossary/Ivec3/README Ua (glossary/ivec3/README-ua.md)
## ivec3
3-вимірний цілочисельний вектор
### Оголошення
```glsl
vec3 aIvec3 = ivec3(1, 1, 1);
vec3 bIvec3 = ivec3(1);
vec3 cIvec3 = ivec3(aIvec4);
vec3 dIvec3 = ivec3(aIvec4.x, aIvec4.y, aIvec4.z);
vec3 eIvec3 = ivec3(aIvec2, aInt);
vec3 fIvec3 = ivec3(aIvec2.x, aIvec2.y, aInt);
```
### Опис
**```ivec3```** — цілочисельний вектор із трьома компонентами. Способи ініціалізації:
- надання скалярного значення для кожного компонента;
- надання одного скалярного значення, що буде використано для всіх компонентів;
- надання вектора вищої розмірності, де відповідні значення будуть використані для ініціалізації компонентів;
- надання комбінації векторів та/або скалярів. Для ініціалізації вектора використовуються відповідні значення. Аргументи конструктора повинні містити принаймні стільки ж компонентів, скільки ініціалізований вектор.
### Дивіться також
[bool](/glossary/?lan=ua&search=bool), [int](/glossary/?lan=ua&search=int), [float](/glossary/?lan=ua&search=float), [bvec2](/glossary/?lan=ua&search=bvec2), [bvec3](/glossary/?lan=ua&search=bvec3), [bvec4](/glossary/?lan=ua&search=bvec4), [ivec2](/glossary/?lan=ua&search=ivec2), [ivec3](/glossary/?lan=ua&search=ivec3), [ivec4](/glossary/?lan=ua&search=ivec4), [vec2](/glossary/?lan=ua&search=vec2), [vec3](/glossary/?lan=ua&search=vec3), [vec4](/glossary/?lan=ua&search=vec4), [mat2](/glossary/?lan=ua&search=mat2), [mat3](/glossary/?lan=ua&search=mat3), [mat4](/glossary/?lan=ua&search=mat4)
---
### Glossary/Ivec3/README Vi (glossary/ivec3/README-vi.md)
## Ivec3
Vector số nguyên 3 chiều.
### Các phiên bản
```glsl
vec3 aIvec3 = ivec3(1, 1, 1);
vec3 bIvec3 = ivec3(1);
vec3 cIvec3 = ivec3(aIvec4);
vec3 dIvec3 = ivec3(aIvec4.x, aIvec4.y, aIvec4.z);
vec3 eIvec3 = ivec3(aIvec2, aInt);
vec3 fIvec3 = ivec3(aIvec2.x, aIvec2.y, aInt);
```
### Mô tả
```ivec3``` vector số nguyên gồm 3 thành phần. Nó có thể được khởi tạo bằng các cách:
- Chỉ định giá trị của từng thành phần
- Chỉ định 1 giá trị chung cho cả 3 thành phần
- Lấy giá trị từ 1 vector nhiều chiều hơn. Các thành phần sẽ được khởi tạo theo thứ tự.
- Lấy giá trị theo thứ tự lần lượt từ nhiều vector, miễn là đủ 3 thành phần.
### Tham khảo thêm
[bool](/glossary/?lan=vi&search=bool), [int](/glossary/?lan=vi&search=int), [float](/glossary/?lan=vi&search=float), [bvec2](/glossary/?lan=vi&search=bvec2), [bvec3](/glossary/?lan=vi&search=bvec3), [bvec4](/glossary/?lan=vi&search=bvec4), [ivec2](/glossary/?lan=vi&search=ivec2), [ivec3](/glossary/?lan=vi&search=ivec3), [ivec4](/glossary/?lan=vi&search=ivec4), [vec2](/glossary/?lan=vi&search=vec2), [vec3](/glossary/?lan=vi&search=vec3), [vec4](/glossary/?lan=vi&search=vec4), [mat2](/glossary/?lan=vi&search=mat2), [mat3](/glossary/?lan=vi&search=mat3), [mat4](/glossary/?lan=vi&search=mat4)
---
### Glossary/Ivec4/README (glossary/ivec4/README.md)
## Ivec4
4 dimensional integer vector
### Declaration
```glsl
vec4 aIvec4 = ivec4(1, 1, 1, 1);
vec4 bIvec4 = ivec4(1);
vec4 cIvec4 = ivec4(aIvec2, aInteger, aIvec3);
vec4 dIvec4 = ivec4(aIvec2.x, aIvec2.y, aInt, aIvec3.x);
```
### Description
```ivec4``` is an integer vector with four components. It can be initialized by:
- Providing a scalar value for each component.
- Providing one scalar value. This value is used for all components.
- Providing a combination of vectors and/or scalars. The respective values are used to initialize the vector. The arguments of the constructor must have at least as many components as the vector that is initialized.
### See Also
[bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [bvec2](/glossary/?search=bvec2), [bvec3](/glossary/?search=bvec3), [bvec4](/glossary/?search=bvec4), [ivec2](/glossary/?search=ivec2), [ivec3](/glossary/?search=ivec3), [ivec4](/glossary/?search=ivec4), [vec2](/glossary/?search=vec2), [vec3](/glossary/?search=vec3), [vec4](/glossary/?search=vec4), [mat2](/glossary/?search=mat2), [mat3](/glossary/?search=mat3), [mat4](/glossary/?search=mat4)
---
### Glossary/Ivec4/README Ua (glossary/ivec4/README-ua.md)
## ivec4
4-вимірний цілочисельний вектор
### Оголошення
```glsl
vec4 aIvec4 = ivec4(1, 1, 1, 1);
vec4 bIvec4 = ivec4(1);
vec4 cIvec4 = ivec4(aIvec2, aInteger, aIvec3);
vec4 dIvec4 = ivec4(aIvec2.x, aIvec2.y, aInt, aIvec3.x);
```
### Опис
**```ivec4```** — цілочисельний вектор із чотирма компонентами. Способи ініціалізації:
- надання скалярного значення для кожного компонента;
- надання одного скалярного значення, що буде використано для всіх компонентів;
- надання комбінації векторів та/або скалярів. Для ініціалізації вектора використовуються відповідні значення. Аргументи конструктора повинні містити принаймні стільки ж компонентів, скільки ініціалізований вектор.
### Дивіться також
[bool](/glossary/?lan=ua&search=bool), [int](/glossary/?lan=ua&search=int), [float](/glossary/?lan=ua&search=float), [bvec2](/glossary/?lan=ua&search=bvec2), [bvec3](/glossary/?lan=ua&search=bvec3), [bvec4](/glossary/?lan=ua&search=bvec4), [ivec2](/glossary/?lan=ua&search=ivec2), [ivec3](/glossary/?lan=ua&search=ivec3), [ivec4](/glossary/?lan=ua&search=ivec4), [vec2](/glossary/?lan=ua&search=vec2), [vec3](/glossary/?lan=ua&search=vec3), [vec4](/glossary/?lan=ua&search=vec4), [mat2](/glossary/?lan=ua&search=mat2), [mat3](/glossary/?lan=ua&search=mat3), [mat4](/glossary/?lan=ua&search=mat4)
---
### Glossary/Ivec4/README Vi (glossary/ivec4/README-vi.md)
## Ivec4
Vector số nguyên 4 chiều
### Các phiên bản
```glsl
vec4 aIvec4 = ivec4(1, 1, 1, 1);
vec4 bIvec4 = ivec4(1);
vec4 cIvec4 = ivec4(aIvec2, aInteger, aIvec3);
vec4 dIvec4 = ivec4(aIvec2.x, aIvec2.y, aInt, aIvec3.x);
```
### Mô tả
```ivec4``` là một vector số nguyên gồm 4 thành phần. Nó có thể được khởi tạo bằng các cách:
- Chỉ định giá trị của từng thành phần
- Chỉ định 1 giá trị chung cho cả 4 thành phần
- Lấy giá trị theo thứ tự lần lượt từ nhiều vector, miễn là đủ 4 thành phần.
### Tham khảo thêm
[bool](/glossary/?lan=vi&search=bool), [int](/glossary/?lan=vi&search=int), [float](/glossary/?lan=vi&search=float), [bvec2](/glossary/?lan=vi&search=bvec2), [bvec3](/glossary/?lan=vi&search=bvec3), [bvec4](/glossary/?lan=vi&search=bvec4), [ivec2](/glossary/?lan=vi&search=ivec2), [ivec3](/glossary/?lan=vi&search=ivec3), [ivec4](/glossary/?lan=vi&search=ivec4), [vec2](/glossary/?lan=vi&search=vec2), [vec3](/glossary/?lan=vi&search=vec3), [vec4](/glossary/?lan=vi&search=vec4), [mat2](/glossary/?lan=vi&search=mat2), [mat3](/glossary/?lan=vi&search=mat3), [mat4](/glossary/?lan=vi&search=mat4)
---
### Glossary/Length/README (glossary/length/README.md)
## Length
Calculate the length of a vector
### Declaration
```glsl
float length(float x)
float length(vec2 x)
float length(vec3 x)
float length(vec4 x)
```
### Parameters
```x``` specifies a vector of which to calculate the length.
### Description
```length()``` returns the length of the vector.
### See Also
[distance()](/glossary/?search=distance), [normalize()](/glossary/?search=normalize), [Chapter 07: Shapes](/07/)
---
### Glossary/Length/README Ua (glossary/length/README-ua.md)
## length
Обчислює довжину вектора
### Оголошення
```glsl
float length(float x)
float length(vec2 x)
float length(vec3 x)
float length(vec4 x)
```
### Параметри
**```x```** — вектор, довжину якого потрібно обчислити.
### Опис
**```length()```** повертає довжину вектора.
### Дивіться також
[distance()](/glossary/?lan=ua&search=distance), [normalize()](/glossary/?lan=ua&search=normalize), [Розділ 07: Фігури](/07/?lan=ua)
---
### Glossary/Length/README Vi (glossary/length/README-vi.md)
## Length
Tính độ dài cuuar vector.
### Các phiên bản
```glsl
float length(float x)
float length(vec2 x)
float length(vec3 x)
float length(vec4 x)
```
### Các tham số
```x``` vector cần tính độ dài
### Mô tả
```length()``` trả về độ dài của vector.
### Tham khảo thêm
[distance()](/glossary/?lan=vi&search=distance), [normalize()](/glossary/?lan=vi&search=normalize), [Chương 07: Hình dạng](/07/?lan=vi)
---
### Glossary/LessThan/README (glossary/lessThan/README.md)
## LessThan
Perform a component-wise less-than comparison of two vectors
### Declaration
```glsl
bvec2 lessThan(vec2 x, vec2 y)
bvec3 lessThan(vec3 x, vec3 y)
bvec4 lessThan(vec4 x, vec4 y)
bvec2 lessThan(ivec2 x, ivec2 y)
bvec3 lessThan(ivec3 x, ivec3 y)
bvec4 lessThan(ivec4 x, ivec4 y)
```
### Parameters
```x``` specifies the first vector to be used in the comparison operation.
```y``` specifies the second vector to be used in the comparison operation.
### Description
```lessThan()``` returns a boolean vector in which each element ```i``` is computed as ```x[i] < y[i]```.
### See Also
[lessThanEqual()](/glossary/?search=lessThanEqual), [greaterThan()](/glossary/?search=greaterThan), [greaterThanEqual()](/glossary/?search=greaterThanEqual), [equal()](/glossary/?search=equal), [notEqual()](/glossary/?search=notEqual), [any()](/glossary/?search=any), [all()](/glossary/?search=all), [not()](/glossary/?search=not)
---
### Glossary/LessThan/README Ua (glossary/lessThan/README-ua.md)
## lessThan
Виконує по-компонентне порівняння двох векторів на меншість компонентів першого вектора по відношенню до другого
### Оголошення
```glsl
bvec2 lessThan(vec2 x, vec2 y)
bvec3 lessThan(vec3 x, vec3 y)
bvec4 lessThan(vec4 x, vec4 y)
bvec2 lessThan(ivec2 x, ivec2 y)
bvec3 lessThan(ivec3 x, ivec3 y)
bvec4 lessThan(ivec4 x, ivec4 y)
```
### Параметри
**```x```** — перший вектор для порівняння.
**```y```** — другий вектор для порівняння.
### Опис
**```lessThan()```** повертає булів вектор, у якому кожен елемент **`i`** обчислюється як "**```x[i] < y[i]```**".
### Дивіться також
[lessThanEqual()](/glossary/?lan=ua&search=lessThanEqual), [greaterThan()](/glossary/?lan=ua&search=greaterThan), [greaterThanEqual()](/glossary/?lan=ua&search=greaterThanEqual), [equal()](/glossary/?lan=ua&search=equal), [notEqual()](/glossary/?lan=ua&search=notEqual), [any()](/glossary/?lan=ua&search=any), [all()](/glossary/?lan=ua&search=all), [not()](/glossary/?lan=ua&search=not)
---
### Glossary/LessThan/README Vi (glossary/lessThan/README-vi.md)
## LessThan
Thực hiện phép so sánh nhỏ-hơn giữa các cặp giá trị của 2 vector.
### Các phiên bản
```glsl
bvec2 lessThan(vec2 x, vec2 y)
bvec3 lessThan(vec3 x, vec3 y)
bvec4 lessThan(vec4 x, vec4 y)
bvec2 lessThan(ivec2 x, ivec2 y)
bvec3 lessThan(ivec3 x, ivec3 y)
bvec4 lessThan(ivec4 x, ivec4 y)
```
### Các tham số
```x``` Vector thứ nhất.
```y``` Vector thứ hai.
### Mô tả
```lessThan()``` trả về một vector boolean mà thành phần thứ ```i``` là kết quả của phép so sánh ```x[i] < y[i]```.
### Tham khảo thêm
[lessThanEqual()](/glossary/?lan=vi&search=lessThanEqual), [greaterThan()](/glossary/?lan=vi&search=greaterThan), [greaterThanEqual()](/glossary/?lan=vi&search=greaterThanEqual), [equal()](/glossary/?lan=vi&search=equal), [notEqual()](/glossary/?lan=vi&search=notEqual), [any()](/glossary/?lan=vi&search=any), [all()](/glossary/?lan=vi&search=all), [not()](/glossary/?lan=vi&search=not)
---
### Glossary/LessThanEqual/README (glossary/lessThanEqual/README.md)
## LessThanEqual
Perform a component-wise less-than-or-equal comparison of two vectors
### Declaration
```glsl
bvec2 lessThanEqual(vec2 x, vec2 y)
bvec3 lessThanEqual(vec3 x, vec3 y)
bvec4 lessThanEqual(vec4 x, vec4 y)
bvec2 lessThanEqual(ivec2 x, ivec2 y)
bvec3 lessThanEqual(ivec3 x, ivec3 y)
bvec4 lessThanEqual(ivec4 x, ivec4 y)
```
### Parameters
```x``` specifies the first vector to be used in the comparison operation.
```y``` specifies the second vector to be used in the comparison operation.
### Description
```lessThanEqual()``` returns a boolean vector in which each element ```i``` is computed as ```x[i] ≤ y[i]```.
### See Also
[lessThan()](/glossary/?search=lessThan), [greaterThan()](/glossary/?search=greaterThan), [greaterThanEqual()](/glossary/?search=greaterThanEqual), [equal()](/glossary/?search=equal), [notEqual()](/glossary/?search=notEqual), [any()](/glossary/?search=any), [all()](/glossary/?search=all), [not()](/glossary/?search=not)
---
### Glossary/LessThanEqual/README Ua (glossary/lessThanEqual/README-ua.md)
## lessThanEqual
Виконує по-компонентне порівняння двох векторів на меншість або рівність компонентів першого вектора по відношенню до другого
### Оголошення
```glsl
bvec2 lessThanEqual(vec2 x, vec2 y)
bvec3 lessThanEqual(vec3 x, vec3 y)
bvec4 lessThanEqual(vec4 x, vec4 y)
bvec2 lessThanEqual(ivec2 x, ivec2 y)
bvec3 lessThanEqual(ivec3 x, ivec3 y)
bvec4 lessThanEqual(ivec4 x, ivec4 y)
```
### Параметри
**```x```** — перший вектор для порівняння.
**```y```** — другий вектор для порівняння.
### Опис
**```lessThanEqual()```** повертає булів вектор, у якому кожен елемент **`i`** обчислюється як "**```x[i] ≤ y[i]```**".
### Дивіться також
[lessThan()](/glossary/?lan=ua&search=lessThan), [greaterThan()](/glossary/?lan=ua&search=greaterThan), [greaterThanEqual()](/glossary/?lan=ua&search=greaterThanEqual), [equal()](/glossary/?lan=ua&search=equal), [notEqual()](/glossary/?lan=ua&search=notEqual), [any()](/glossary/?lan=ua&search=any), [all()](/glossary/?lan=ua&search=all), [not()](/glossary/?lan=ua&search=not)
---
### Glossary/LessThanEqual/README Vi (glossary/lessThanEqual/README-vi.md)
## LessThanEqual
Thực hiện phép so sánh nhỏ-hơn-hoặc-bằng giữa các cặp giá trị của 2 vector.
### Các phiên bản
```glsl
bvec2 lessThanEqual(vec2 x, vec2 y)
bvec3 lessThanEqual(vec3 x, vec3 y)
bvec4 lessThanEqual(vec4 x, vec4 y)
bvec2 lessThanEqual(ivec2 x, ivec2 y)
bvec3 lessThanEqual(ivec3 x, ivec3 y)
bvec4 lessThanEqual(ivec4 x, ivec4 y)
```
### Các tham số
```x``` Vector thứ nhất.
```y``` Vector thứ hai.
### Mô tả
```lessThanEqual()``` trả về một vector boolean mà thành phần thứ ```i``` là kết quả của phép so sánh ```x[i] ≤ y[i]```.
### Tham khảo thêm
[lessThan()](/glossary/?lan=vi&search=lessThan), [greaterThan()](/glossary/?lan=vi&search=greaterThan), [greaterThanEqual()](/glossary/?lan=vi&search=greaterThanEqual), [equal()](/glossary/?lan=vi&search=equal), [notEqual()](/glossary/?lan=vi&search=notEqual), [any()](/glossary/?lan=vi&search=any), [all()](/glossary/?lan=vi&search=all), [not()](/glossary/?lan=vi&search=not)
---
### Glossary/Log/README (glossary/log/README.md)
## Log
Return the natural logarithm of the parameter
### Declaration
```glsl
float log(float x)
vec2 log(vec2 x)
vec3 log(vec3 x)
vec4 log(vec4 x)
```
### Parameters
```x``` specifies the value of which to take the natural logarithm.
### Description
```log()``` returns the natural logarithm of ```x```.
### See Also
[log2](/glossary/?search=log2), [exp](/glossary/?search=exp), [exp2](/glossary/?search=exp2), [Chapter 05: Shaping Functions](/05/)
---
### Glossary/Log/README Ua (glossary/log/README-ua.md)
## log
Повертає натуральний логарифм параметра.
Тобто повертає значення до якого степеня слід піднести число Ейлера, щоб одержати вказане число. Число Ейлера або **`e`** приблизно дорівнює 2.718281828.
### Оголошення
```glsl
float log(float x)
vec2 log(vec2 x)
vec3 log(vec3 x)
vec4 log(vec4 x)
```
### Параметри
**```x```** — значення, яке потрібно взяти в натуральний логарифм.
### Опис
**```log()```** повертає натуральний логарифм числа **`x`**.
### Дивіться також
[log2](/glossary/?lan=ua&search=log2), [exp](/glossary/?lan=ua&search=exp), [exp2](/glossary/?lan=ua&search=exp2), [Розділ 05: Формотворчі функції](/05/?lan=ua)
---
### Glossary/Log/README Vi (glossary/log/README-vi.md)
## Log
Tính logarith tự nhiên của một số
### Các phiên bản
```glsl
float log(float x)
vec2 log(vec2 x)
vec3 log(vec3 x)
vec4 log(vec4 x)
```
### Các tham số
```x``` số cần tính logarith
### Mô tả
```log()``` trả về kết quả của phép tính ```log(x)```.
### Tham khảo thêm
[log2](/glossary/?lan=vi&search=log2), [exp](/glossary/?lan=vi&search=exp), [exp2](/glossary/?lan=vi&search=exp2), [Các hàm số cơ bản (Hàm hình dạng - Shape function)](/05/?lan=vi)
---
### Glossary/Log2/README (glossary/log2/README.md)
## Log2
Return the base 2 logarithm of the parameter
### Declaration
```glsl
float log2(float x)
vec2 log2(vec2 x)
vec3 log2(vec3 x)
vec4 log2(vec4 x)
```
### Parameters
```x``` specifies the value of which to take the base 2 logarithm.
### Description
```log2()``` returns the base 2 logarithm of ```x```.
### See Also
[log](/glossary/?search=log), [exp](/glossary/?search=exp), [exp2](/glossary/?search=exp2), [Chapter 05: Shaping Functions](/05/)
---
### Glossary/Log2/README Ua (glossary/log2/README-ua.md)
## log2
Повертає логарифм числа за основою 2.
Тобто повертає степінь яка необхідна для двійки, щоб отримати передане число.
### Оголошення
```glsl
float log2(float x)
vec2 log2(vec2 x)
vec3 log2(vec3 x)
vec4 log2(vec4 x)
```
### Параметри
**```x```** — значення, яке потрібно взяти за логарифмом з основою 2.
### Опис
**```log2()```** повертає логарифм числа **`x`** з основою 2.
### Дивіться також
[log](/glossary/?lan=ua&search=log), [exp](/glossary/?lan=ua&search=exp), [exp2](/glossary/?lan=ua&search=exp2), [Розділ 05: Формотворчі функції](/05/?lan=ua)
---
### Glossary/Log2/README Vi (glossary/log2/README-vi.md)
## Log2
Tính logarith cơ số 2.
### Các phiên bản
```glsl
float log2(float x)
vec2 log2(vec2 x)
vec3 log2(vec3 x)
vec4 log2(vec4 x)
```
### Các tham số
```x``` giá trị cần tính logarith cơ số 2.
### Mô tả
```log2()``` trả về kết quả của hàm số logarith cơ số 2 của ```x```.
### Tham khảo thêm
[log](/glossary/?lan=vi&search=log), [exp](/glossary/?lan=vi&search=exp), [exp2](/glossary/?lan=vi&search=exp2), [Các hàm số cơ bản (Hàm hình dạng - Shape function)](/05/?lan=vi)
---
### Glossary/Lowp/README (glossary/lowp/README.md)
## Lowp
### Declaration / Example
### Parameters
### Description
### See Also
---
### Glossary/Lowp/README Ua (glossary/lowp/README-ua.md)
## lowp
Кваліфікатор точності, задається на початку шейдера
### Приклад
```glsl
precision lowp float;
precision lowp int;
```
### Опис
Кваліфікатор точності оголошує мінімальний діапазон і точність, які повинні використовуватися під час зберігання змінних відповідного типу.
**```lowp```** — 8+ біт, діапазон для **`float`** від -2 до 2, діапазон для **`int`** від -2^8 до 2^8
### Дивіться також
[mediump](/glossary/?lan=ua&search=mediump), [highp](/glossary/?lan=ua&search=highp), [precision](/glossary/?lan=ua&search=precision)
---
### Glossary/Lowp/README Vi (glossary/lowp/README-vi.md)
## Lowp
### Các phiên bản / Example
### Các tham số
### Mô tả
### Tham khảo thêm
---
### Glossary/Main/README (glossary/main/README.md)
## Main
### Declaration / Example
### Parameters
### Description
### See Also
---
### Glossary/Main/README Ua (glossary/main/README-ua.md)
## main
### Оголошення / Приклад
### Параметри
### Опис
### Дивіться також
---
### Glossary/Main/README Vi (glossary/main/README-vi.md)
## Main
### Các phiên bản / Example
### Các tham số
### Mô tả
### Tham khảo thêm
---
### Glossary/Mat2/README (glossary/mat2/README.md)
## Mat2
2x2 floating point matrix
### Declaration
```glsl
mat2 aMat2 = mat2(1.0, 0.0, // 1. column
0.0, 1.0); // 2. column
mat2 bMat2 = mat2(1.0);
mat2 cMat2 = mat2(aVec2, bVec2);
mat2 dMat2 = mat2(aVec3, aFloat);
```
### Description
```mat2``` data type is compose for a 2x2 matrix of floating point. As you can see above, can be initialize in different ways:
- Providing a value for each component column by column.
- Providing one value that is used for the components on the main diagonal.
- Providing a combination of vectors and scalars.
In the same way data can be accessed component-wise or column by column:
```glsl
mat2 aMat2;
aMat2[1][1] = 1.0;
float aFloat = aMat2[1][1];
aMat2[0] = vec2(1.0);
vec2 aVec2 = aMat2[0];
```
### See Also
[mat3](/glossary/?search=mat3), [mat4](/glossary/?search=mat4), [matrixCompMult()](/glossary/?search=matrixCompMult)
---
### Glossary/Mat2/README Ua (glossary/mat2/README-ua.md)
## mat2
Матриця розміром 2x2 зі значеннями типу float
### Оголошення
```glsl
mat2 aMat2 = mat2(
1.0, 0.0, // 1. column
0.0, 1.0 // 2. column
);
mat2 bMat2 = mat2(1.0);
mat2 cMat2 = mat2(aVec2, bVec2);
mat2 dMat2 = mat2(aVec3, aFloat);
```
### Опис
**```mat2```** — тип даних, що є матрицею розміром 2x2 із значеннями типу **`float`**. Як видно із прикладу вище, ініціалізувати можна різними способами:
- надання значень для кожного компонента стовпець за стовпцем;
- надання одного значення, яке використовується для компонентів на головній діагоналі;
- надання комбінації векторів і скалярів;
Так само можна отримати доступ до даних покомпонентно або стовпець за стовпцем:
```glsl
mat2 aMat2;
aMat2[1][1] = 1.0;
float aFloat = aMat2[1][1];
aMat2[0] = vec2(1.0);
vec2 aVec2 = aMat2[0];
```
### Дивіться також
[mat3](/glossary/?lan=ua&search=mat3), [mat4](/glossary/?lan=ua&search=mat4), [matrixCompMult()](/glossary/?lan=ua&search=matrixCompMult)
---
### Glossary/Mat2/README Vi (glossary/mat2/README-vi.md)
## Mat2
Ma trận số thực 2x2
### Các phiên bản
```glsl
mat2 aMat2 = mat2(1.0, 0.0, // Cột thứ nhất
0.0, 1.0); // Cột thứ hai
mat2 bMat2 = mat2(1.0);
mat2 cMat2 = mat2(aVec2, bVec2);
mat2 dMat2 = mat2(aVec3, aFloat);
```
### Mô tả
```mat2``` là ma trận số thực gồm 2 hàng và 2 cột. Nó có thể được khởi tạo bằng các cách:
- Chỉ định giá trị của từng thành phần
- Chỉ định 1 giá trị chung cho các thành phần trên đường chéo chính
- Chỉ định giá trị từng cột, mỗi cột coi như một ```vec2```
Có thể lấy giá trị của từng thành phần trong ma trận hoặc lấy từng cột:
```glsl
mat2 aMat2;
aMat2[1][1] = 1.0;
float aFloat = aMat2[1][1];
aMat2[0] = vec2(1.0);
vec2 aVec2 = aMat2[0];
```
### Tham khảo thêm
[mat3](/glossary/?lan=vi&search=mat3), [mat4](/glossary/?lan=vi&search=mat4), [matrixCompMult()](/glossary/?lan=vi&search=matrixCompMult)
---
### Glossary/Mat3/README (glossary/mat3/README.md)
## Mat3
3x3 floating point matrix
### Declaration
```glsl
mat3 aMat3 = mat3(1.0, 0.0, 0.0, // 1. column
0.0, 1.0, 0.0, // 2. column
0.0, 0.0, 1.0); // 3. column
mat3 bMat3 = mat3(1.0);
mat3 cMat3 = mat3(aVec3, bVec3, cVec3);
mat3 dMat3 = mat3(aVec4, aVec3, bVec4, aFloat);
```
### Description
```mat3``` data type is compose for a 3x3 matrix of floating point. As you can see above, can be initialize in different ways:
- Providing a value for each component column by column.
- Providing one value that is used for the components on the main diagonal.
- Providing a combination of vectors and scalars.
In the same way data can be accessed component-wise or column by column:
```glsl
mat3 aMat3;
aMat3[2][2] = 1.0;
float aFloat = aMat3[2][2];
aMat3[0] = vec3(1.0);
vec3 aVec3 = aMat3[0];
```
### See Also
[mat2](/glossary/?search=mat2), [mat4](/glossary/?search=mat4), [matrixCompMult()](/glossary/?search=matrixCompMult)
---
### Glossary/Mat3/README Ua (glossary/mat3/README-ua.md)
## mat3
Матриця розміром 3x3 зі значеннями типу float
### Оголошення
```glsl
mat3 aMat3 = mat3(
1.0, 0.0, 0.0, // 1. column
0.0, 1.0, 0.0, // 2. column
0.0, 0.0, 1.0 // 3. column
);
mat3 bMat3 = mat3(1.0);
mat3 cMat3 = mat3(aVec3, bVec3, cVec3);
mat3 dMat3 = mat3(aVec4, aVec3, bVec4, aFloat);
```
### Опис
**```mat3```** — тип даних, що є матрицею розміром 3x3 із значеннями типу **`float`**. Як видно із прикладу вище, ініціалізувати можна різними способами:
- надання значень для кожного компонента стовпець за стовпцем;
- надання одного значення, яке використовується для компонентів на головній діагоналі;
- надання комбінації векторів і скалярів;
Так само можна отримати доступ до даних покомпонентно або стовпець за стовпцем:
```glsl
mat3 aMat3;
aMat3[2][2] = 1.0;
float aFloat = aMat3[2][2];
aMat3[0] = vec3(1.0);
vec3 aVec3 = aMat3[0];
```
### Дивіться також
[mat2](/glossary/?lan=ua&search=mat2), [mat4](/glossary/?lan=ua&search=mat4), [matrixCompMult()](/glossary/?lan=ua&search=matrixCompMult)
---
### Glossary/Mat3/README Vi (glossary/mat3/README-vi.md)
## Mat3
Ma trận số thực 3x3
### Các phiên bản
```glsl
mat3 aMat3 = mat3(1.0, 0.0, 0.0, // Cột thứ 1
0.0, 1.0, 0.0, // Cột thứ 2
0.0, 0.0, 1.0); // Cột thứ 3
mat3 bMat3 = mat3(1.0);
mat3 cMat3 = mat3(aVec3, bVec3, cVec3);
mat3 dMat3 = mat3(aVec4, aVec3, bVec4, aFloat);
```
### Mô tả
```mat3``` là ma trận số thực gồm 3 hàng và 3 cột. Nó có thể được khởi tạo bằng các cách:
- Chỉ định giá trị của từng thành phần
- Chỉ định 1 giá trị chung cho các thành phần trên đường chéo chính
- Chỉ định giá trị từng cột, mỗi cột coi như một ```vec3```
Có thể lấy giá trị của từng thành phần trong ma trận hoặc lấy từng cột:
```glsl
mat3 aMat3;
aMat3[2][2] = 1.0;
float aFloat = aMat3[2][2];
aMat3[0] = vec3(1.0);
vec3 aVec3 = aMat3[0];
```
### Tham khảo thêm
[mat2](/glossary/?lan=vi&search=mat2), [mat4](/glossary/?lan=vi&search=mat4), [matrixCompMult()](/glossary/?lan=vi&search=matrixCompMult)
---
### Glossary/Mat4/README (glossary/mat4/README.md)
## Mat4
4x4 floating point matrix
### Declaration
```glsl
mat4 aMat4 = mat4(1.0, 0.0, 0.0, 0.0, // 1. column
0.0, 1.0, 0.0, 0.0, // 2. column
0.0, 0.0, 1.0, 0.0, // 3. column
0.0, 0.0, 0.0, 1.0); // 4. column
mat4 bMat4 = mat4(1.0);
mat4 cMat4 = mat4(aVec4, bVec4, cVec4, dVec4);
mat4 dMat4 = mat4(aVec4, aVec3, bVec4, cVec4, aFloat);
```
### Description
```mat4``` data type is compose for a 4x4 matrix of floating point. As you can see above, can be initialize in different ways:
- Providing a value for each component column by column.
- Providing one value that is used for the components on the main diagonal.
- Providing a combination of vectors and scalars.
In the same way data can be accessed component-wise or column by column:
```glsl
aMat4[3][3] = 1.0;
float aFloat = aMat4[3][3];
aMat4[0] = vec4(1.0);
vec4 aVec4 = aMat4[0];
```
### See Also
[mat2](/glossary/?search=mat2), [mat3](/glossary/?search=mat3), [matrixCompMult()](/glossary/?search=matrixCompMult)
---
### Glossary/Mat4/README Vi (glossary/mat4/README-vi.md)
## Mat4
Ma trận số thực 4x4
### Các phiên bản
```glsl
mat4 aMat4 = mat4(1.0, 0.0, 0.0, 0.0, // Cột thứ 1
0.0, 1.0, 0.0, 0.0, // Cột thứ 2
0.0, 0.0, 1.0, 0.0, // Cột thứ 3
0.0, 0.0, 0.0, 1.0); // Cột thứ 4
mat4 bMat4 = mat4(1.0);
mat4 cMat4 = mat4(aVec4, bVec4, cVec4, dVec4);
mat4 dMat4 = mat4(aVec4, aVec3, bVec4, cVec4, aFloat);
```
### Mô tả
```mat4``` là ma trận số thực gồm 4 hàng và 4 cột. Nó có thể được khởi tạo bằng các cách:
- Chỉ định giá trị của từng thành phần
- Chỉ định 1 giá trị chung cho các thành phần trên đường chéo chính
- Chỉ định giá trị từng cột, mỗi cột coi như một ```vec4```
Có thể lấy giá trị của từng thành phần trong ma trận hoặc lấy từng cột:
```glsl
aMat4[3][3] = 1.0;
float aFloat = aMat4[3][3];
aMat4[0] = vec4(1.0);
vec4 aVec4 = aMat4[0];
```
### Tham khảo thêm
[mat2](/glossary/?lan=vi&search=mat2), [mat3](/glossary/?lan=vi&search=mat3), [matrixCompMult()](/glossary/?lan=vi&search=matrixCompMult)
---
### Glossary/MatrixCompMult/README (glossary/matrixCompMult/README.md)
## MatrixCompMult
Perform a component-wise multiplication of two matrices
### Declaration
```glsl
mat2 matrixCompMult(mat2 x, mat2 y)
mat3 matrixCompMult(mat3 x, mat3 y)
mat4 matrixCompMult(mat4 x, mat4 y)
```
### Parameters
```x``` specifies the first matrix multiplicand.
```y``` specifies the second matrix multiplicand.
### Description
```matrixCompMult()``` performs a component-wise multiplication of two matrices, yielding a result matrix where each component, ```result[i][j]``` is computed as the scalar product of ```x[i][j]``` and ```y[i][j]```.
### See Also
[Chapter 08: Matrix](../08/)
---
### Glossary/MatrixCompMult/README Ua (glossary/matrixCompMult/README-ua.md)
## matrixCompMult
Виконує покомпонентне множення двох матриць
### Оголошення
```glsl
mat2 matrixCompMult(mat2 x, mat2 y)
mat3 matrixCompMult(mat3 x, mat3 y)
mat4 matrixCompMult(mat4 x, mat4 y)
```
### Параметри
**```x```** — перший матричний множник.
**```y```** — другий матричний множник.
### Опис
**```matrixCompMult()```** виконує покомпонентне множення двох матриць, повертаючи нову матрицю, де кожен компонент **```result[i][j]```** обчислюється як скалярний добуток **```x[i][j]```** та **```y[i][j]```**.
### Дивіться також
[mat2](/glossary/?lan=ua&search=mat2), [mat3](/glossary/?lan=ua&search=mat3), [mat4](/glossary/?lan=ua&search=mat4), [Розділ 08: Матриці](../08/?lan=ua)
---
### Glossary/MatrixCompMult/README Vi (glossary/matrixCompMult/README-vi.md)
## MatrixCompMult
Nhân từng cặp giá trị tương ứng giữa 2 ma trận.
### Các phiên bản
```glsl
mat2 matrixCompMult(mat2 x, mat2 y)
mat3 matrixCompMult(mat3 x, mat3 y)
mat4 matrixCompMult(mat4 x, mat4 y)
```
### Các tham số
```x``` Ma trận thứ nhất.
```y``` Ma trận thứ hai.
### Mô tả
```matrixCompMult()``` trả về ma trận kết quả, với từng thành phần ```result[i][j]``` là kết quả của phép tính ```x[i][j] * y[i][j]```.
### Tham khảo thêm
[Chương 08: Ma trận](../08/?lan=vi)
---
### Glossary/Max/README (glossary/max/README.md)
## Max
Return the greater of two values
### Declaration
```glsl
float max(float x, float y)
vec2 max(vec2 x, vec2 y)
vec3 max(vec3 x, vec3 y)
vec4 max(vec4 x, vec4 y)
vec2 max(vec2 x, float y)
vec3 max(vec3 x, float y)
vec4 max(vec4 x, float y)
```
### Parameters
```x``` specifies the first value to compare.
```y``` specifies the second value to compare.
### Description
```max()``` returns the maximum of the two parameters. It returns ```y``` if ```y``` is greater than ```x```, otherwise it returns ```x```.
### See Also
[min](/glossary/?search=min), [abs](/glossary/?search=abs), [clamp](/glossary/?search=clamp), [Chapter 05: Shaping Functions](/05/)
---
### Glossary/Max/README Ua (glossary/max/README-ua.md)
## max
Повертає більше з двох значень
### Оголошення
```glsl
float max(float x, float y)
vec2 max(vec2 x, vec2 y)
vec3 max(vec3 x, vec3 y)
vec4 max(vec4 x, vec4 y)
vec2 max(vec2 x, float y)
vec3 max(vec3 x, float y)
vec4 max(vec4 x, float y)
```
### Параметри
**```x```** — перше значення для порівняння.
**```y```** — друге значення для порівняння.
### Опис
**```max()```** повертає максимальне значення із двох параметрів. Повертає **`y`**, якщо він більше за **`x`**, інакше повертає **`x`**.
### Дивіться також
[min](/glossary/?lan=ua&search=min), [abs](/glossary/?lan=ua&search=abs), [clamp](/glossary/?lan=ua&search=clamp), [Розділ 05: Формотворчі функції](/05/?lan=ua)
---
### Glossary/Max/README Vi (glossary/max/README-vi.md)
## Max
Tìm giá trị lớn hơn giữa 2 giá trị.
### Các phiên bản
```glsl
float max(float x, float y)
vec2 max(vec2 x, vec2 y)
vec3 max(vec3 x, vec3 y)
vec4 max(vec4 x, vec4 y)
vec2 max(vec2 x, float y)
vec3 max(vec3 x, float y)
vec4 max(vec4 x, float y)
```
### Các tham số
```x``` Giá trị thứ nhất.
```y``` Giá trị thứ hai.
### Mô tả
```max()``` thực hiện phép so sánh giữa từng cặp giá trị trong hai vector ```x``` và ```y``` để chọn ra các số lớn hơn ở mỗi cặp giá trị.
### Tham khảo thêm
[min](/glossary/?lan=vi&search=min), [abs](/glossary/?lan=vi&search=abs), [clamp](/glossary/?lan=vi&search=clamp), [Các hàm số cơ bản (Hàm hình dạng - Shape function)](/05/?lan=vi)
---
### Glossary/Mediump/README (glossary/mediump/README.md)
## Mediump
### Declaration / Example
### Parameters
### Description
### See Also
---
### Glossary/Mediump/README Ua (glossary/mediump/README-ua.md)
## mediump
Кваліфікатор точності, задається на початку шейдера
### Приклад
```glsl
precision mediump float;
precision mediump int;
```
### Опис
Кваліфікатор точності оголошує мінімальний діапазон і точність, які повинні використовуватися під час зберігання змінних відповідного типу.
**```mediump```** — 16+ біт, діапазон для **`float`** від -2^14 to +2^14, діапазон для **`int`** від -2^10 до 2^10
### Дивіться також
[lowp](/glossary/?lan=ua&search=lowp), [highp](/glossary/?lan=ua&search=highp), [precision](/glossary/?lan=ua&search=precision)
---
### Glossary/Mediump/README Vi (glossary/mediump/README-vi.md)
## Mediump
### Các phiên bản / Example
### Các tham số
### Mô tả
### Tham khảo thêm
---
### Glossary/Min/README (glossary/min/README.md)
## Min
Return the lesser of two values
### Declaration
```glsl
float min(float x, float y)
vec2 min(vec2 x, vec2 y)
vec3 min(vec3 x, vec3 y)
vec4 min(vec4 x, vec4 y)
vec2 min(vec2 x, float y)
vec3 min(vec3 x, float y)
vec4 min(vec4 x, float y)
```
### Parameters
```x``` specifies the first value to compare.
```y``` specifies the second value to compare.
### Description
```min()``` returns the minimum of the two parameters. It returns ```y``` if ```y``` is less than ```x```, otherwise it returns ```x```.
### See Also
[max](/glossary/?search=max), [abs](/glossary/?search=abs), [clamp](/glossary/?search=clamp), [Chapter 05: Shaping Functions](/05/)
---
### Glossary/Min/README Ua (glossary/min/README-ua.md)
## min
Повертає менше з двох значень
### Оголошення
```glsl
float min(float x, float y)
vec2 min(vec2 x, vec2 y)
vec3 min(vec3 x, vec3 y)
vec4 min(vec4 x, vec4 y)
vec2 min(vec2 x, float y)
vec3 min(vec3 x, float y)
vec4 min(vec4 x, float y)
```
### Параметри
**```x```** — перше значення для порівняння.
**```y```** — друге значення для порівняння.
### Опис
**```min()```** повертає мінімальне значення із двох параметрів. Повертає **`y`**, якщо він менше за **`x`**, інакше повертає **`x`**.
### Дивіться також
[max](/glossary/?lan=ua&search=max), [abs](/glossary/?lan=ua&search=abs), [clamp](/glossary/?lan=ua&search=clamp), [Розділ 05: Формотворчі функції](/05/?lan=ua)
---
### Glossary/Min/README Vi (glossary/min/README-vi.md)
## Min
Tìm giá trị nhỏ hơn giữa 2 giá trị.
### Các phiên bản
```glsl
float min(float x, float y)
vec2 min(vec2 x, vec2 y)
vec3 min(vec3 x, vec3 y)
vec4 min(vec4 x, vec4 y)
vec2 min(vec2 x, float y)
vec3 min(vec3 x, float y)
vec4 min(vec4 x, float y)
```
### Các tham số
```x``` Giá trị thứ nhất.
```y``` Giá trị thứ hai.
### Mô tả
```min()``` thực hiện phép so sánh giữa từng cặp giá trị trong hai vector ```x``` và ```y``` để chọn ra các số nhỏ hơn ở mỗi cặp giá trị.
### Tham khảo thêm
[max](/glossary/?lan=vi&search=max), [abs](/glossary/?lan=vi&search=abs), [clamp](/glossary/?lan=vi&search=clamp), [Các hàm số cơ bản (Hàm hình dạng - Shape function)](/05/?lan=vi)
---
### Glossary/Mix/README (glossary/mix/README.md)
## Mix
Constrain a value to lie between two further values
### Declaration
```glsl
float mix(float x, float y, float a)
vec2 mix(vec2 x, vec2 y, vec2 a)
vec3 mix(vec3 x, vec3 y, vec3 a)
vec4 mix(vec4 x, vec4 y, vec4 a)
vec2 mix(vec2 x, vec2 y, float a)
vec3 mix(vec3 x, vec3 y, float a)
vec4 mix(vec4 x, vec4 y, float a)
```
### Parameters
```x``` specifies the start of the range in which to interpolate.
```y``` specifies the end of the range in which to interpolate.
```a``` specifies the value to use to interpolate between x and y.
### Description
```mix()``` performs a linear interpolation between ```x``` and ```y``` using ```a``` to weight between them. The return value is computed as ```x×(1−a)+y×a```.
### See Also
[min](/glossary/?search=min), [max](/glossary/?search=max), [Chapter 06: Color](/06/)
---
### Glossary/Mix/README Ua (glossary/mix/README-ua.md)
## mix
Виконує лінійну інтерполяцію між двома значеннями.
### Оголошення
```glsl
float mix(float x, float y, float a)
vec2 mix(vec2 x, vec2 y, vec2 a)
vec3 mix(vec3 x, vec3 y, vec3 a)
vec4 mix(vec4 x, vec4 y, vec4 a)
vec2 mix(vec2 x, vec2 y, float a)
vec3 mix(vec3 x, vec3 y, float a)
vec4 mix(vec4 x, vec4 y, float a)
```
### Параметри
**```x```** — початок діапазону інтерполяції.
**```y```** — кінець діапазону інтерполяції.
**```a```** — процентне значення ваги для інтерполяції, від 0.0 до 1.0.
### Опис
**```mix()```** виконує лінійну інтерполяцію між **`x`** та **`y`** використовуючи **`a`** для зважування між ними. Повернене значення обчислюється як "**```x * (1 − a) + y * a```**".
### Дивіться також
[min](/glossary/?lan=ua&search=min), [max](/glossary/?lan=ua&search=max), [Розділ 06: Кольори](/06/?lan=ua)
---
### Glossary/Mix/README Vi (glossary/mix/README-vi.md)
## Mix
Nội suy tuyến tính giữa 2 giá trị
### Các phiên bản
```glsl
float mix(float x, float y, float a)
vec2 mix(vec2 x, vec2 y, vec2 a)
vec3 mix(vec3 x, vec3 y, vec3 a)
vec4 mix(vec4 x, vec4 y, vec4 a)
vec2 mix(vec2 x, vec2 y, float a)
vec3 mix(vec3 x, vec3 y, float a)
vec4 mix(vec4 x, vec4 y, float a)
```
### Các tham số
```x``` Giá trị nhỏ hơn trong khoảng cần nội suy.
```y``` Giá trị lớn hơn trong khoảng cần nội suy.
```a``` Tỉ lệ nội suy.
### Mô tả
```mix()``` nội suy giá trị giữa ```x``` và ```y``` sử dụng ```a``` làm tỉ lệ nội suy / trọng số. Kết quả của phép tính ```x×(1−a)+y×a```.
### Tham khảo thêm
[min](/glossary/?lan=vi&search=min), [max](/glossary/?lan=vi&search=max), [Chương 6: Màu sắc](/06/?lan=vi)
---
### Glossary/Mod/README (glossary/mod/README.md)
## Mod
Compute value of one parameter modulo another
### Declaration
```glsl
float mod(float x, float y)
vec2 mod(vec2 x, vec2 y)
vec3 mod(vec3 x, vec3 y)
vec4 mod(vec4 x, vec4 y)
vec2 mod(vec2 x, float y)
vec3 mod(vec3 x, float y)
vec4 mod(vec4 x, float y)
```
### Parameters
```x``` specifies the value to evaluate.
```y``` specifies the value to obtain the modulo of.
### Description
```mod()``` returns the value of ```x``` modulo ```y```. This is computed as ```x - y * floor(x/y)```.
### See Also
[floor](/glossary/?search=floor), [fract](/glossary/?search=fract), [ceil](/glossary/?search=ceil), [Chapter 05: Shaping Functions](/05/)
---
### Glossary/Mod/README Ua (glossary/mod/README-ua.md)
## mod
Повертає залишок від ділення першого параметра на другий. Результат має такий самий знак, як і дільник.
### Оголошення
```glsl
float mod(float x, float y)
vec2 mod(vec2 x, vec2 y)
vec3 mod(vec3 x, vec3 y)
vec4 mod(vec4 x, vec4 y)
vec2 mod(vec2 x, float y)
vec3 mod(vec3 x, float y)
vec4 mod(vec4 x, float y)
```
### Параметри
**```x```** — число, для якого потрібно знайти залишок.
**```y```** — число, на яке потрібно виконати ділення.
### Опис
**```mod()```** повертає значення операції модуля **`x`** на **`y`**. Обчислюється як "**```x - y ⋅ floor(x / y)```**".
### Дивіться також
[floor](/glossary/?lan=ua&search=floor), [fract](/glossary/?lan=ua&search=fract), [ceil](/glossary/?lan=ua&search=ceil), [Розділ 05: Формотворчі функції](/05/?lan=ua)
---
### Glossary/Mod/README Vi (glossary/mod/README-vi.md)
## Mod
Phép tính phần dư
### Các phiên bản
```glsl
float mod(float x, float y)
vec2 mod(vec2 x, vec2 y)
vec3 mod(vec3 x, vec3 y)
vec4 mod(vec4 x, vec4 y)
vec2 mod(vec2 x, float y)
vec3 mod(vec3 x, float y)
vec4 mod(vec4 x, float y)
```
### Các tham số
```x``` số bị chia.
```y``` số chia.
### Mô tả
```mod()``` trả về kết quả là phần dư của phép chia ```x``` cho ```y```, theo công thức ```x - y * floor(x/y)```.
### Tham khảo thêm
[floor](/glossary/?lan=vi&search=floor), [fract](/glossary/?lan=vi&search=fract), [ceil](/glossary/?lan=vi&search=ceil), [Các hàm số cơ bản (Hàm hình dạng - Shape function)](/05/?lan=vi)
---
### Glossary/Normalize/README (glossary/normalize/README.md)
## Normalize
Calculate the unit vector in the same direction as the input vector
### Declaration
```glsl
float normalize(float x)
vec2 normalize(vec2 x)
vec3 normalize(vec3 x)
vec4 normalize(vec4 x)
```
### Parameters
```x``` specifies the vector to normalize.
### Description
```normalize()``` returns a vector with the same direction as its parameter, ```x```, but with length 1.
### See Also
[length()](/glossary/?search=length)
---
### Glossary/Normalize/README Ua (glossary/normalize/README-ua.md)
## normalize
Обчислює одиничний вектор у тому ж напрямку, що й вхідний вектор
### Оголошення
```glsl
float normalize(float x)
vec2 normalize(vec2 x)
vec3 normalize(vec3 x)
vec4 normalize(vec4 x)
```
### Параметри
**```x```** — вектор який потрібно нормалізувати.
### Опис
**```normalize()```** повертає вектор із тим же напрямком, що і його параметр **`x`**, але з довжиною 1.
### Дивіться також
[length()](/glossary/?lan=ua&search=length)
---
### Glossary/Normalize/README Vi (glossary/normalize/README-vi.md)
## Normalize
Chuẩn hóa vector.
### Các phiên bản
```glsl
float normalize(float x)
vec2 normalize(vec2 x)
vec3 normalize(vec3 x)
vec4 normalize(vec4 x)
```
### Các tham số
```x``` Vector cần chuẩn hóa.
### Mô tả
```normalize()``` trả về một vector cùng chiều với ```x``` và có độ dài bằng 1.
### Tham khảo thêm
[length()](/glossary/?lan=vi&search=length)
---
### Glossary/Not/README (glossary/not/README.md)
## Not
Logically invert a boolean vector
### Declaration
```glsl
bvec2 not(bvec2 x)
bvec3 not(bvec3 x)
bvec4 not(bvec4 x)
```
### Parameters
```x``` specifies the vector to be inverted.
### Description
```not()``` logically inverts the boolean vector ```x```. It returns a new boolean vector for which each element ```i``` is computed as ```!x[i]```.
### See Also
[any()](/glossary/?search=any), [all()](/glossary/?search=all)
---
### Glossary/Not/README Ua (glossary/not/README-ua.md)
## not
Логічно інвертує булевий вектор
### Оголошення
```glsl
bvec2 not(bvec2 x)
bvec3 not(bvec3 x)
bvec4 not(bvec4 x)
```
### Параметри
**```x```** — вектор, який потрібно інвертувати.
### Опис
**```not()```** логічно інвертує булів вектор **`x`**. Повертає новий булів вектор, для якого кожен елемент **`i`** обчислено як **`!x[i]`**.
### Дивіться також
[any()](/glossary/?lan=ua&search=any), [all()](/glossary/?lan=ua&search=all)
---
### Glossary/Not/README Vi (glossary/not/README-vi.md)
## Not
Phép logic nghịch đảo.
### Các phiên bản
```glsl
bvec2 not(bvec2 x)
bvec3 not(bvec3 x)
bvec4 not(bvec4 x)
```
### Các tham số
```x``` giá trị boolean cần đảo ngược.
### Mô tả
```not()``` đảo ngược ```x```. Kết quả là một vector boolean mà thành phần thứ ```i``` là kết quả của phép logic ```!x[i]```.
### Tham khảo thêm
[any()](/glossary/?lan=vi&search=any), [all()](/glossary/?lan=vi&search=all)
---
### Glossary/NotEqual/README (glossary/notEqual/README.md)
## NotEqual
Perform a component-wise not-equal-to comparison of two vectors
### Declaration
```glsl
bvec2 notEqual(vec2 x, vec2 y)
bvec3 notEqual(vec3 x, vec3 y)
bvec4 notEqual(vec4 x, vec4 y)
bvec2 notEqual(ivec2 x, ivec2 y)
bvec3 notEqual(ivec3 x, ivec3 y)
bvec4 notEqual(ivec4 x, ivec4 y)
```
### Parameters
```x``` specifies the first vector to be used in the comparison operation.
```y``` specifies the second vector to be used in the comparison operation.
### Description
```notEqual()``` returns a boolean vector in which each element ```i``` is computed as ```x[i] != y[i]```.
### See Also
[lessThanEqual()](/glossary/?search=lessThanEqual), [lessThan()](/glossary/?search=lessThan), [greaterThanEqual()](/glossary/?search=greaterThanEqual), [greaterThan()](/glossary/?search=greaterThan), [equal()](/glossary/?search=equal), [any()](/glossary/?search=any), [all()](/glossary/?search=all), [not()](/glossary/?search=not)
---
### Glossary/NotEqual/README Ua (glossary/notEqual/README-ua.md)
## notEqual
Виконує по-компонентне порівняння двох векторів на нерівність
### Оголошення
```glsl
bvec2 notEqual(vec2 x, vec2 y)
bvec3 notEqual(vec3 x, vec3 y)
bvec4 notEqual(vec4 x, vec4 y)
bvec2 notEqual(ivec2 x, ivec2 y)
bvec3 notEqual(ivec3 x, ivec3 y)
bvec4 notEqual(ivec4 x, ivec4 y)
```
### Параметри
**```x```** — перший вектор для порівняння.
**```y```** — другий вектор для порівняння.
### Опис
**```notEqual()```** повертає булів вектор, у якому кожен елемент **`i`** обчислюється як "**```x[i] != y[i]```**".
### Дивіться також
[lessThanEqual()](/glossary/?lan=ua&search=lessThanEqual), [lessThan()](/glossary/?lan=ua&search=lessThan), [greaterThanEqual()](/glossary/?lan=ua&search=greaterThanEqual), [greaterThan()](/glossary/?lan=ua&search=greaterThan), [equal()](/glossary/?lan=ua&search=equal), [any()](/glossary/?lan=ua&search=any), [all()](/glossary/?lan=ua&search=all), [not()](/glossary/?lan=ua&search=not)
---
### Glossary/NotEqual/README Vi (glossary/notEqual/README-vi.md)
## NotEqual
Thực hiện phép so sánh không-bằng giữa các cặp giá trị của 2 vector.
### Các phiên bản
```glsl
bvec2 notEqual(vec2 x, vec2 y)
bvec3 notEqual(vec3 x, vec3 y)
bvec4 notEqual(vec4 x, vec4 y)
bvec2 notEqual(ivec2 x, ivec2 y)
bvec3 notEqual(ivec3 x, ivec3 y)
bvec4 notEqual(ivec4 x, ivec4 y)
```
### Các tham số
```x``` Vector thứ nhất.
```y``` Vector thứ hai.
### Mô tả
```notEqual()``` trả về một vector boolean mà thành phần thứ ```i``` là kết quả của phép so sánh ```x[i] != y[i]```.
### Tham khảo thêm
[lessThanEqual()](/glossary/?lan=vi&search=lessThanEqual), [lessThan()](/glossary/?lan=vi&search=lessThan), [greaterThanEqual()](/glossary/?lan=vi&search=greaterThanEqual), [greaterThan()](/glossary/?lan=vi&search=greaterThan), [equal()](/glossary/?lan=vi&search=equal), [any()](/glossary/?lan=vi&search=any), [all()](/glossary/?lan=vi&search=all), [not()](/glossary/?lan=vi&search=not)
---
### Glossary/Pow/README (glossary/pow/README.md)
## Pow
Return the value of the first parameter raised to the power of the second.
### Declaration
```glsl
float pow(float x, float y)
vec2 pow(vec2 x, vec2 y)
vec3 pow(vec3 x, vec3 y)
vec4 pow(vec4 x, vec4 y)
```
### Parameters
```x``` specifies the value to raise to the power ```y```.
```y``` specifies the power to which to raise ```x```.
### Description
```pow()``` returns the value of ```x``` raised to the ```y``` power.
### See Also
[inversesqrt](/glossary/?search=inversesqrt), [sqrt](/glossary/?search=sqrt), [Chapter 05: Shaping Functions](/05/)
---
### Glossary/Pow/README Ua (glossary/pow/README-ua.md)
## pow
Підносить значення першого параметра в заданому степені другим параметром.
### Оголошення
```glsl
float pow(float x, float y)
vec2 pow(vec2 x, vec2 y)
vec3 pow(vec3 x, vec3 y)
vec4 pow(vec4 x, vec4 y)
```
### Параметри
**```x```** — значення, яке потрібно піднести до степеня **`y`**.
**```y```** — степінь, до якої потрібно піднести **`x`**.
### Опис
**```pow()```** повертає значення **`x`**, зведене до степеня **`y`**.
### Дивіться також
[inversesqrt](/glossary/?lan=ua&search=inversesqrt), [sqrt](/glossary/?lan=ua&search=sqrt), [Розділ 05: Формотворчі функції](/05/?lan=ua)
---
### Glossary/Pow/README Vi (glossary/pow/README-vi.md)
## Pow
Lũy thừa.
### Các phiên bản
```glsl
float pow(float x, float y)
vec2 pow(vec2 x, vec2 y)
vec3 pow(vec3 x, vec3 y)
vec4 pow(vec4 x, vec4 y)
```
### Các tham số
```x``` cơ số.
```y``` số mũ.
### Mô tả
```pow()``` trả về kết quả của phép toán ```x``` mũ ```y```
### Tham khảo thêm
[inversesqrt](/glossary/?lan=vi&search=inversesqrt), [sqrt](/glossary/?lan=vi&search=sqrt), [Các hàm số cơ bản (Hàm hình dạng - Shape function)](/05/?lan=vi)
---
### Glossary/Precision/README (glossary/precision/README.md)
## Precision
### Declaration / Example
### Parameters
### Description
### See Also
---
### Glossary/Precision/README Ua (glossary/precision/README-ua.md)
## precision
Кваліфікатор точності оголошує мінімальний діапазон і точність, які базова реалізація повинна використовувати під час зберігання відповідних змінних.
### Приклад
```glsl
precision lowp float;
precision mediump float;
precision highp float;
precision lowp int;
precision mediump int;
precision highp int;
```
### Значення
**```lowp```** — 8+ біт, діапазон для **`float`** від -2 до 2, діапазон для **`int`** від -2^8 до 2^8
**```mediump```** — 16+ біт, діапазон для **`float`** від -2^14 to +2^14, діапазон для **`int`** від -2^10 до 2^10
**```highp```** — 32+ біт, діапазон для **`float`** від -2^62 to +2^62, діапазон для **`int`** від -2^16 до 2^16
### Дивіться також
[lowp](/glossary/?lan=ua&search=lowp), [mediump](/glossary/?lan=ua&search=mediump), [highp](/glossary/?lan=ua&search=highp)
---
### Glossary/Precision/README Vi (glossary/precision/README-vi.md)
## Precision
### Các phiên bản / Example
### Các tham số
### Mô tả
### Tham khảo thêm
---
### Glossary/Radians/README (glossary/radians/README.md)
## Radians
Convert a quantity in degrees to radians
### Declaration
```glsl
float radians(float degrees)
vec2 radians(vec2 degrees)
vec3 radians(vec3 degrees)
vec4 radians(vec4 degrees)
```
### Parameters
```degrees``` specifies the quantity, in degrees, to be converted to radians.
### Description
```radians()``` converts a quantity, specified in degrees into radians. That is, the return value is ```(PI * degrees)/180```.
### See Also
[degrees](/glossary/?search=degrees)
---
### Glossary/Radians/README Ua (glossary/radians/README-ua.md)
## radians
Конвертує передане значення у радіани
### Оголошення
```glsl
float radians(float degrees)
vec2 radians(vec2 degrees)
vec3 radians(vec3 degrees)
vec4 radians(vec4 degrees)
```
### Параметри
**```degrees```** — значення у градусах, яке потрібно перетворити в радіани.
### Опис
**```radians()```** перетворює значення, передане в градусах, у радіани.
Обрахунок по формулі: ```(PI * degrees) / 180.0```
### Дивіться також
[degrees](/glossary/?lan=ua&search=degrees)
---
### Glossary/Radians/README Vi (glossary/radians/README-vi.md)
## Radians
Chuyển đổi góc từ đơn vị độ sang radian.
### Các phiên bản
```glsl
float radians(float degrees)
vec2 radians(vec2 degrees)
vec3 radians(vec3 degrees)
vec4 radians(vec4 degrees)
```
### Các tham số
```degrees``` góc tính bằng độ, cần quy đổi.
### Mô tả
```radians()``` trả về góc (tính bằng radian) theo công thức ```(PI * degrees)/180```.
### Tham khảo thêm
[degrees](/glossary/?lan=vi&search=degrees)
---
### Glossary/Reflect/README (glossary/reflect/README.md)
## Reflect
Calculate the reflection direction for an incident vector
### Declaration
```glsl
float reflect(float I, float N)
vec2 reflect(vec2 I, vec2 N)
vec3 reflect(vec3 I, vec3 N)
vec4 reflect(vec4 I, vec4 N)
```
### Parameters
```I``` specifies the incident vector.
```N``` specifies the normal vector.
### Description
For a given incident vector ```I``` and surface normal ```N``` reflect returns the reflection direction calculated as ```I - 2.0 * dot(N, I) * N```.
```N``` should be normalized in order to achieve the desired result.
### See Also
[dot()](/glossary/?search=dot), [refract()](/glossary/?search=refract)
---
### Glossary/Reflect/README Ua (glossary/reflect/README-ua.md)
## reflect
Обчислює напрямок відбиття для падаючого вектора
### Оголошення
```glsl
float reflect(float I, float N)
vec2 reflect(vec2 I, vec2 N)
vec3 reflect(vec3 I, vec3 N)
vec4 reflect(vec4 I, vec4 N)
```
### Параметри
**```I```** — вектор інциденту (падаючий вектор).
**```N```** — вектор нормалі.
### Опис
Для вектора падіння **`I`** і нормалі до поверхні **`N`**, **`reflect`** повертає напрямок відбиття, обчислений як "**```I - 2.0 * dot(N, I) * N```**".
**```N```** має бути нормалізованим, щоб досягти бажаного результату.
### Дивіться також
[dot()](/glossary/?lan=ua&search=dot), [refract()](/glossary/?lan=ua&search=refract)
---
### Glossary/Reflect/README Vi (glossary/reflect/README-vi.md)
## Reflect
Tính vector phản xạ khi tia tới va chạm với một bề mặt.
### Các phiên bản
```glsl
float reflect(float I, float N)
vec2 reflect(vec2 I, vec2 N)
vec3 reflect(vec3 I, vec3 N)
vec4 reflect(vec4 I, vec4 N)
```
### Các tham số
```I``` Vector tới (incident vector), là vector chỉ hướng tia va chạm với bề mặt.
```N``` Vector pháp tuyến của bề mặt tại điểm va chạm, là vector vuông góc với bề mặt.
### Mô tả
Cho vector tới ```I``` và vector pháp tuyến của bề mặt va chạm ```N```, vector phản xạ chỉ hướng phản xạ được tính theo công thức ```I - 2.0 * dot(N, I) * N```.
```N``` nên được chuẩn hóa (normalize) để có kết quả chính xác nhất.
### Tham khảo thêm
[dot()](/glossary/?lan=vi&search=dot), [refract()](/glossary/?lan=vi&search=refract)
---
### Glossary/Refract/README (glossary/refract/README.md)
## Refract
Calculate the refraction direction for an incident vector
### Declaration
```glsl
float refract(float I, float N, float eta)
vec2 refract(vec2 I, vec2 N, float eta)
vec3 refract(vec3 I, vec3 N, float eta)
vec4 refract(vec4 I, vec4 N, float eta)
```
### Parameters
```I``` specifies the incident vector.
```N``` specifies the normal vector.
```eta``` specifies the ratio of indices of refraction.
### Description
For a given incident vector ```I```, surface normal ```N``` and ratio of indices of refraction, ```eta```, refract returns the refraction vector, ```R```.
```R``` is calculated as:
```glsl
k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I));
if (k < 0.0)
R = genType(0.0); // or genDType(0.0)
else
R = eta * I - (eta * dot(N, I) + sqrt(k)) * N;
```
The input parameters ```I``` and ```N``` should be normalized in order to achieve the desired result.
### See Also
[dot()](/glossary/?search=dot), [reflect()](/glossary/?search=reflect)
---
### Glossary/Refract/README Ua (glossary/refract/README-ua.md)
## refract
Обчислює напрямок заломлення для падаючого вектора
### Оголошення
```glsl
float refract(float I, float N, float eta)
vec2 refract(vec2 I, vec2 N, float eta)
vec3 refract(vec3 I, vec3 N, float eta)
vec4 refract(vec4 I, vec4 N, float eta)
```
### Параметри
**```I```** — вектор інциденту (падаючий вектор).
**```N```** — вектор нормалі.
**```eta```** — співвідношення показників заломлення.
### Опис
Для вектора падіння **`I`**, нормалі до поверхні **`N`** та співвідношення показників заломлення **`eta`**, **`refract`** повертає вектор заломлення **`R`**.
**```R```** обчислюється як:
```glsl
k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I));
if (k < 0.0)
R = genType(0.0); // or genDType(0.0)
else
R = eta * I - (eta * dot(N, I) + sqrt(k)) * N;
```
Вхідні параметри **`I`** та **`N`** повинні бути нормалізовані для досягнення бажаного результату.
### Дивіться також
[dot()](/glossary/?lan=ua&search=dot), [reflect()](/glossary/?lan=ua&search=reflect)
---
### Glossary/Refract/README Vi (glossary/refract/README-vi.md)
## Refract
Tính vector khúc xạ khi tia tới va chạm với một bề mặt.
### Các phiên bản
```glsl
float refract(float I, float N, float eta)
vec2 refract(vec2 I, vec2 N, float eta)
vec3 refract(vec3 I, vec3 N, float eta)
vec4 refract(vec4 I, vec4 N, float eta)
```
### Các tham số
```I``` Vector tới (incident vector), là vector chỉ hướng tia va chạm với bề mặt.
```N``` Vector pháp tuyến của bề mặt tại điểm va chạm, là vector vuông góc với bề mặt.
```eta``` Tỉ lệ chiết suất giữa hai môi trường.
### Mô tả
Cho vector tới ```I```, vector pháp tuyến của bề mặt va chạm ```N``` và , vector khúc xạ chỉ hướng khúc xạ sẽ được tính theo công thức dưới đây và trả về:
```glsl
k = 1.0 - eta * eta * (1.0 - dot(N, I) * dot(N, I));
if (k < 0.0)
R = genType(0.0); // hoặc genDType(0.0)
else
R = eta * I - (eta * dot(N, I) + sqrt(k)) * N;
```
```I``` và ```N``` nên được chuẩn hóa (normalize) để có kết quả chính xác nhất.
### Tham khảo thêm
[dot()](/glossary/?lan=vi&search=dot), [reflect()](/glossary/?lan=vi&search=reflect)
---
### Glossary/Return/README (glossary/return/README.md)
## Return
### Declaration / Example
### Parameters
### Description
### See Also
---
### Glossary/Return/README Ua (glossary/return/README-ua.md)
## return
Оператор зупиняє роботу функції та повертає вказане після нього значення
### Приклад
```glsl
float getSum(float a, float b) {
return a + b;
}
```
### Опис
Оператор **`return`** зупиняє роботу функції та повертає вказане після нього обов'язкове значення того типу, який має повертати функція
---
### Glossary/Return/README Vi (glossary/return/README-vi.md)
## Return
### Các phiên bản / Example
### Các tham số
### Mô tả
### Tham khảo thêm
---
### Glossary/Sampler2D/README (glossary/sampler2D/README.md)
## Sampler2D
### Declaration / Example
### Parameters
### Description
### See Also
---
### Glossary/Sampler2D/README Ua (glossary/sampler2D/README-ua.md)
## sampler2D
### Оголошення / Приклад
### Параметри
### Опис
### Дивіться також
---
### Glossary/Sampler2D/README Vi (glossary/sampler2D/README-vi.md)
## Sampler2D
### Các phiên bản / Example
### Các tham số
### Mô tả
### Tham khảo thêm
---
### Glossary/SamplerCube/README (glossary/samplerCube/README.md)
## SamplerCube
### Declaration / Example
### Parameters
### Description
### See Also
---
### Glossary/SamplerCube/README Ua (glossary/samplerCube/README-ua.md)
## samplerCube
### Оголошення / Приклад
### Параметри
### Опис
### Дивіться також
---
### Glossary/SamplerCube/README Vi (glossary/samplerCube/README-vi.md)
## SamplerCube
### Các phiên bản / Example
### Các tham số
### Mô tả
### Tham khảo thêm
---
### Glossary/Sign/README (glossary/sign/README.md)
## Sign
Extract the sign of the parameter
### Declaration
```glsl
float sign(float x)
vec2 sign(vec2 x)
vec3 sign(vec3 x)
vec4 sign(vec4 x)
```
### Parameters
```x``` specifies the value from which to extract the sign.
### Description
```sign()``` returns -1.0 if x is less than 0.0, 0.0 if x is equal to 0.0, and +1.0 if x is greater than 0.0.
### See Also
[abs](/glossary/?search=abs), [Chapter 05: Shaping Functions](/05/)
---
### Glossary/Sign/README Ua (glossary/sign/README-ua.md)
## sign
Виділяє знак параметра
### Оголошення
```glsl
float sign(float x)
vec2 sign(vec2 x)
vec3 sign(vec3 x)
vec4 sign(vec4 x)
```
### Параметри
**```x```** — значення, з якого слід витягти знак.
### Опис
**```sign()```** повертає: -1.0, якщо x менше 0.0; 0.0, якщо x дорівнює 0.0; +1.0, якщо x більше 0.0.
### Дивіться також
[abs](/glossary/?lan=ua&search=abs), [Розділ 05: Формотворчі функції](/05/?lan=ua)
---
### Glossary/Sign/README Vi (glossary/sign/README-vi.md)
## Sign
Trả về dấu của một số.
### Các phiên bản
```glsl
float sign(float x)
vec2 sign(vec2 x)
vec3 sign(vec3 x)
vec4 sign(vec4 x)
```
### Các tham số
```x``` số cần kiểm tra dấu âm dương.
### Mô tả
```sign()``` trả về -1.0 nếu x < 0.0, 0.0 nếu x = 0.0, và +1.0 nếu x > 0.0.
### Tham khảo thêm
[abs](/glossary/?lan=vi&search=abs), [Các hàm số cơ bản (Hàm hình dạng - Shape function)](/05/?lan=vi)
---
### Glossary/Sin/README (glossary/sin/README.md)
## Sin
Return the sine of the parameter
### Declaration
```glsl
float sin(float angle)
vec2 sin(vec2 angle)
vec3 sin(vec3 angle)
vec4 sin(vec4 angle)
```
### Parameters
```angle``` specifies the quantity, in radians, of which to return the sine.
### Description
```sin()``` returns the trigonometric sine of angle.
### See Also
[acos](/glossary/?search=acos), [cos](/glossary/?search=cos), [asin](/glossary/?search=asin), [tan](/glossary/?search=tan), [atan](/glossary/?search=atan), [Chapter 05: Shaping Functions](/05/)
---
### Glossary/Sin/README Pl (glossary/sin/README-pl.md)
## Sin
Zwraca sinus podanego argumentu
### Deklaracja
```glsl
float sin(float angle)
vec2 sin(vec2 angle)
vec3 sin(vec3 angle)
vec4 sin(vec4 angle)
```
### Parametry
```angle``` określa wartość kąta (w radianach), dla którego ma zostać obliczony sinus.
### Opis
```sin()``` zwraca trygonometryczny sinus podanego kąta.
### Zobacz także
[acos](/glossary/?lan=pl&search=acos), [cos](/glossary/?lan=pl&search=cos), [asin](/glossary/?lan=pl&search=asin), [tan](/glossary/?lan=pl&search=tan), [atan](/glossary/?lan=pl&search=atan), [Rozdział 05: Shaping Functions](/05/?lan=pl)
---
### Glossary/Sin/README Ua (glossary/sin/README-ua.md)
## sin
Повертає синус параметра
### Оголошення
```glsl
float sin(float angle)
vec2 sin(vec2 angle)
vec3 sin(vec3 angle)
vec4 sin(vec4 angle)
```
### Параметри
**```angle```** — величина в радіанах, синус якої потрібно повернути.
### Опис
**```sin()```** — повертає тригонометричний синус кута.
### Дивіться також
[acos](/glossary/?lan=ua&search=acos), [cos](/glossary/?lan=ua&search=cos), [asin](/glossary/?lan=ua&search=asin), [tan](/glossary/?lan=ua&search=tan), [atan](/glossary/?lan=ua&search=atan), [Розділ 05: Формотворчі функції](/05/?lan=ua)
---
### Glossary/Sin/README Vi (glossary/sin/README-vi.md)
## Sin
Hàm sin
### Các phiên bản
```glsl
float sin(float angle)
vec2 sin(vec2 angle)
vec3 sin(vec3 angle)
vec4 sin(vec4 angle)
```
### Các tham số
```angle``` góc cần tính sin (theo đơn vị radian)
### Mô tả
```sin()``` trả về kết quả của biểu thức ```sin( angle )```
### Tham khảo thêm
[acos](/glossary/?lan=vi&search=acos), [cos](/glossary/?lan=vi&search=cos), [asin](/glossary/?lan=vi&search=asin), [tan](/glossary/?lan=vi&search=tan), [atan](/glossary/?lan=vi&search=atan), [Các hàm số cơ bản (Hàm hình dạng - Shape function)](/05/?lan=vi)
---
### Glossary/Smoothstep/README (glossary/smoothstep/README.md)
## Smoothstep
Perform Hermite interpolation between two values
### Declaration
```glsl
float smoothstep(float edge0, float edge1, float x)
vec2 smoothstep(vec2 edge0, vec2 edge1, vec2 x)
vec3 smoothstep(vec3 edge0, vec3 edge1, vec3 x)
vec4 smoothstep(vec4 edge0, vec4 edge1, vec4 x)
vec2 smoothstep(float edge0, float edge1, vec2 x)
vec3 smoothstep(float edge0, float edge1, vec3 x)
vec4 smoothstep(float edge0, float edge1, vec4 x)
```
### Parameters
```edge0``` specifies the value of the lower edge of the Hermite function.
```edge1``` specifies the value of the upper edge of the Hermite function.
```x``` specifies the source value for interpolation.
### Description
```smoothstep()``` performs smooth Hermite interpolation between ```0``` and ```1``` when ```edge0 < x < edge1```. This is useful in cases where a threshold function with a smooth transition is desired. ```smoothstep()``` is equivalent to:
```glsl
genType t; /* Or genDType t; */
t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
return t * t * (3.0 - 2.0 * t);
```
Results are undefined ```if edge0 ≥ edge1```.
### See Also
[mix](/glossary/?search=mix), [step](/glossary/?search=step), [Chapter 05: Shaping Functions](/05/)
---
### Glossary/Smoothstep/README Vi (glossary/smoothstep/README-vi.md)
## Smoothstep
Thực hiện phép nội suy Hermitte giữa 0 và 1 theo tỉ lệ.
### Các phiên bản
```glsl
float smoothstep(float edge0, float edge1, float x)
vec2 smoothstep(vec2 edge0, vec2 edge1, vec2 x)
vec3 smoothstep(vec3 edge0, vec3 edge1, vec3 x)
vec4 smoothstep(vec4 edge0, vec4 edge1, vec4 x)
vec2 smoothstep(float edge0, float edge1, vec2 x)
vec3 smoothstep(float edge0, float edge1, vec3 x)
vec4 smoothstep(float edge0, float edge1, vec4 x)
```
### Các tham số
```edge0``` cận dưới trên trục hoành của hàm Hermitte
```edge1``` cận trên trên trục hoành của hàm Hermitte
```x``` giá trị trên trục hoành
### Mô tả
```smoothstep()``` thực hiện phép nội suy giữa ```0``` và ```1``` nếu ```edge0 < x < edge1```. Nếu ```x < edge0``` thì trả về ```0```, còn nếu ```x > edge1``` thì trả về ```1```. Hàm này hay dùng khi cần chuyển tiếp giữa 2 vùng mà không muốn đột ngột thay đổi giá trị. Hàm ```smoothstep()``` tương đương với:
```glsl
genType t; /* Hoặc genDType t; */
t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
return t * t * (3.0 - 2.0 * t);
```
Nếu ```edge0 ≥ edge1``` thì kết quả không xác định được.
### Tham khảo thêm
[mix](/glossary/?lan=vi&search=mix), [step](/glossary/?lan=vi&search=step), [Các hàm số cơ bản (Hàm hình dạng - Shape function)](/05/?lan=vi)
---
### Glossary/Sqrt/README (glossary/sqrt/README.md)
## Sqrt
Return the square root of the parameter
### Declaration
```glsl
float sqrt(float x)
vec2 sqrt(vec2 x)
vec3 sqrt(vec3 x)
vec4 sqrt(vec4 x)
```
### Parameters
```x``` specifies the value of which to take the square root.
### Description
```sqrt()``` returns the square root of ```x```.
### See Also
[inversesqrt](/glossary/?search=inversesqrt), [pow](/glossary/?search=pow), [Chapter 05: Shaping Functions](/05/)
---
### Glossary/Sqrt/README Ua (glossary/sqrt/README-ua.md)
## sqrt
Повертає значення квадратного кореня
### Оголошення
```glsl
float sqrt(float x)
vec2 sqrt(vec2 x)
vec3 sqrt(vec3 x)
vec4 sqrt(vec4 x)
```
### Параметри
**```x```** — значення, з якого потрібно взяти квадратний корінь.
### Опис
**```sqrt()```** повертає квадратний корінь з **`x`**.
### Дивіться також
[inversesqrt](/glossary/?lan=ua&search=inversesqrt), [pow](/glossary/?lan=ua&search=pow), [Розділ 05: Формотворчі функції](/05/?lan=ua)
---
### Glossary/Sqrt/README Vi (glossary/sqrt/README-vi.md)
## Sqrt
Tính căn bậc hai của một số.
### Các phiên bản
```glsl
float sqrt(float x)
vec2 sqrt(vec2 x)
vec3 sqrt(vec3 x)
vec4 sqrt(vec4 x)
```
### Các tham số
```x``` Số cần tính căn bậc 2.
### Mô tả
```sqrt()``` trả về căn bậc 2 của ```x```.
### Tham khảo thêm
[inversesqrt](/glossary/?lan=vi&search=inversesqrt), [pow](/glossary/?lan=vi&search=pow), [Các hàm số cơ bản (Hàm hình dạng - Shape function)](/05/?lan=vi)
---
### Glossary/Step/README (glossary/step/README.md)
## Step
Generate a step function by comparing two values
### Declaration
```glsl
float step(float edge, float x)
vec2 step(vec2 edge, vec2 x)
vec3 step(vec3 edge, vec3 x)
vec4 step(vec4 edge, vec4 x)
vec2 step(float edge, vec2 x)
vec3 step(float edge, vec3 x)
vec4 step(float edge, vec4 x)
```
### Parameters
```edge``` specifies the location of the edge of the step function.
```x``` specifies the value to be used to generate the step function.
### Description
```step()``` generates a step function by comparing ```x``` to ```edge```.
For element ```i``` of the return value, ```0.0``` is returned ```if x[i] < edge[i]```, and ```1.0``` is returned otherwise.
### See Also
[mix](/glossary/?search=mix), [smoothstep](/glossary/?search=smoothstep), [Chapter 05: Shaping Functions](/05/)
---
### Glossary/Step/README Ua (glossary/step/README-ua.md)
## step
Генерує східчасту функцію, порівнюючи два значення
### Оголошення
```glsl
float step(float edge, float x)
vec2 step(vec2 edge, vec2 x)
vec3 step(vec3 edge, vec3 x)
vec4 step(vec4 edge, vec4 x)
vec2 step(float edge, vec2 x)
vec3 step(float edge, vec3 x)
vec4 step(float edge, vec4 x)
```
### Параметри
**```edge```** — порогове значення.
**```x```** — значення для генерації східчастої функції.
### Опис
**```step()```** генерує східчасту функцію шляхом порівняння **`x`** із **`edge`**.
Якщо передане значення **`x`** менше за **`edge`**, то функція повертає **`0.0`**, інакше повертається **`1.0`**.
### Дивіться також
[mix](/glossary/?lan=ua&search=mix), [smoothstep](/glossary/?lan=ua&search=smoothstep), [Розділ 05: Формотворчі функції](/05/?lan=ua)
---
### Glossary/Step/README Vi (glossary/step/README-vi.md)
## Step
Kiểm tra một biến có nhỏ hơn ngưỡng nhất định không.
### Các phiên bản
```glsl
float step(float edge, float x)
vec2 step(vec2 edge, vec2 x)
vec3 step(vec3 edge, vec3 x)
vec4 step(vec4 edge, vec4 x)
vec2 step(float edge, vec2 x)
vec3 step(float edge, vec3 x)
vec4 step(float edge, vec4 x)
```
### Các tham số
```edge``` ngưỡng cận biên.
```x``` giá trị cần kiểm tra xem có nằm trong ngưỡng cận biên không.
### Mô tả
```step()``` so sánh ```x``` với ```edge```.
Với mỗi thành phần thứ ```i``` trong vector kết quả, nó sẽ nhận giá trị ```0.0``` nếu ```x[i] < edge[i]```, và ngược lại nhận giá trị ```1.0```.
### Tham khảo thêm
[mix](/glossary/?lan=vi&search=mix), [smoothstep](/glossary/?lan=vi&search=smoothstep), [Các hàm số cơ bản (Hàm hình dạng - Shape function)](/05/?lan=vi)
---
### Glossary/Struct/README (glossary/struct/README.md)
## Struct
Structure variable type
### Example
```glsl
struct matStruct {
vec4 ambientColor;
vec4 diffuseColor;
vec4 specularColor;
float specularExponent;
} newMaterial;
newMaterial = matStruct(vec4(0.1, 0.1, 0.1, 1.0),
vec4(1.0, 0.0, 0.0, 1.0),
vec4(0.7, 0.7, 0.7, 1.0),
50.0);
```
### Description
```struct``` declares a custom data structure based on standard types. A constructor for the structure with the same name is created automatically. The declaration of a variable (in this case "newMaterial") is optional.
---
### Glossary/Struct/README Vi (glossary/struct/README-vi.md)
## Struct
Kiểu dữ liệu cấu trúc - struct.
### Ví dụ
```glsl
struct matStruct {
vec4 ambientColor;
vec4 diffuseColor;
vec4 specularColor;
float specularExponent;
} newMaterial;
newMaterial = matStruct(vec4(0.1, 0.1, 0.1, 1.0),
vec4(1.0, 0.0, 0.0, 1.0),
vec4(0.7, 0.7, 0.7, 1.0),
50.0);
```
### Mô tả
```struct``` là một kiểu dữ liệu tự do được tạo nên từ các biến dữ liệu có kiểu cơ bản. Với mỗi struct, một hàm tạo cùng tên sẽ được tạo tự động. Không nhất thiết phải khởi tạo các giá trị khi dùng hàm tạo.
---
### Glossary/Tan/README (glossary/tan/README.md)
## Tan
Return the tangent of the parameter
### Declaration
```glsl
float tan(float angle)
vec2 tan(vec2 angle)
vec3 tan(vec3 angle)
vec4 tan(vec4 angle)
```
### Parameters
```angle``` specifies the quantity, in radians, of which to return the tangent.
### Description
```tan()``` returns the trigonometric tangent of angle.
### See Also
[cos](/glossary/?search=cos), [acos](/glossary/?search=acos), [sin](/glossary/?search=sin), [asin](/glossary/?search=asin), [atan](/glossary/?search=atan), [Chapter 05: Shaping Functions](/05/)
---
### Glossary/Tan/README Ua (glossary/tan/README-ua.md)
## tan
Повертає тангенс переданого кута
### Оголошення
```glsl
float tan(float angle)
vec2 tan(vec2 angle)
vec3 tan(vec3 angle)
vec4 tan(vec4 angle)
```
### Параметри
**```angle```** — величина кута в радіанах, тангенс якого потрібно повернути.
### Опис
**```tan()```** повертає тригонометричний тангенс кута.
### Дивіться також
[cos](/glossary/?lan=ua&search=cos), [acos](/glossary/?lan=ua&search=acos), [sin](/glossary/?lan=ua&search=sin), [asin](/glossary/?lan=ua&search=asin), [atan](/glossary/?lan=ua&search=atan), [Розділ 05: Формотворчі функції](/05/?lan=ua)
---
### Glossary/Tan/README Vi (glossary/tan/README-vi.md)
## Tan
Tính tan của một góc lượng giác (đơn vị radian)
### Các phiên bản
```glsl
float tan(float angle)
vec2 tan(vec2 angle)
vec3 tan(vec3 angle)
vec4 tan(vec4 angle)
```
### Các tham số
```angle``` góc cần tính tan (đơn vị radian)
### Mô tả
```tan()``` tính tan của góc ```angle```
### Tham khảo thêm
[cos](/glossary/?lan=vi&search=cos), [acos](/glossary/?lan=vi&search=acos), [sin](/glossary/?lan=vi&search=sin), [asin](/glossary/?lan=vi&search=asin), [atan](/glossary/?lan=vi&search=atan), [Các hàm số cơ bản (Hàm hình dạng - Shape function)](/05/?lan=vi)
---
### Glossary/Texture2D/README (glossary/texture2D/README.md)
## Texture2D
Retrieves texels from a texture
### Declaration
```glsl
vec4 texture2D(sampler2D sampler, vec2 coord)
vec4 texture2D(sampler2D sampler, vec2 coord, float bias)
```
### Parameters
```sampler``` specifies the sampler to which the texture from which texels will be retrieved is bound.
```coord``` specifies the texture coordinates at which texture will be sampled.
```bias``` specifies an optional bias to be applied during level-of-detail computation.
### Description
The texture2D function returns a texel, i.e. the (color) value of the texture for the given coordinates. The function has one input parameter of the type sampler2D and one input parameter of the type ```vec2``` : sampler, the uniform the texture is bound to, and coord, the 2-dimensional coordinates of the texel to look up.
There is an optional third input parameter of the type float: bias. After calculating the appropriate level of detail for a texture with mipmaps the bias is added before the actual texture lookup operation is executed.
Side note: On iOS devices texture lookup functionality is only available in the fragment shader.
### See Also
[textureCube](/glossary/?search=textureCube)
---
### Glossary/Texture2D/README Ua (glossary/texture2D/README-ua.md)
## texture2D
Отримує текселі (texels) з текстури
### Оголошення
```glsl
vec4 texture2D(sampler2D sampler, vec2 coord)
vec4 texture2D(sampler2D sampler, vec2 coord, float bias)
```
### Параметри
**```sampler```** — семплер, до якого прив'язана текстура, з якої будуть отримані текселі.
**```coord```** — координати текстури, за якими буде взята текстура.
**```bias```** — необов'язкове зміщення, яке буде застосовано під час обчислення рівня деталізації.
### Опис
Функція **`texture2D`** повертає тексель, тобто значення (кольору) текстури для заданих координат. Функція має перший вхідний параметр типу **`sampler2D`** і другий вхідний параметр типу **`vec2`**: семплер, до якої прив'язана текстура, і двовимірні координати текселя.
Існує додатковий третій вхідний параметр типу **`float`**. Після обчислення відповідного рівня деталізації для текстури з MIP-картами зміщення додається перед виконанням фактичної операції пошуку текстури.
Додаткова примітка: на пристроях iOS функція пошуку текстури доступна лише у фрагментному шейдері.
### Дивіться також
[textureCube](/glossary/?lan=ua&search=textureCube)
---
### Glossary/Texture2D/README Vi (glossary/texture2D/README-vi.md)
## Texture2D
Lấy màu của một vị trí bất kỳ trên texture có định dạng cube (6 mặt của khối lập phương).
### Các phiên bản
```glsl
vec4 texture2D(sampler2D sampler, vec2 coord)
vec4 texture2D(sampler2D sampler, vec2 coord, float bias)
```
### Các tham số
```sampler``` là sampler đã khởi tạo với texture, sẽ giúp ta lấy được màu tại tọa độ mong muốn.
```coord``` tọa độ vị trí cần lấy màu trên texture.
```bias``` sai số cho phép nếu áp dụng cơ chế Level-Of-Detail.
### Mô tả
Kết quả của hàm là 1 texel, tức màu tại vị trí chỉ định trên texture.
Tham số thứ ba không bắt buộc. Sau khi tính toán xong Level-Of-Detail phù hợp dựa trên các cấp mipmap, ```bias``` sẽ được dùng để tìm tọa độ trên texture.
Chú ý: Trên các thiết bị iOS, hàm này chỉ có thể dùng trong fragment shader.
### Tham khảo thêm
[textureCube](/glossary/?lan=vi&search=textureCube)
---
### Glossary/TextureCube/README (glossary/textureCube/README.md)
## TextureCube
Retrieves texels from a texture
### Declaration
```glsl
vec4 textureCube(samplerCube sampler, vec3 coord)
vec4 textureCube(samplerCube sampler, vec3 coord, float bias)
```
### Parameters
```sampler``` specifies the sampler to which the texture from which texels will be retrieved is bound.
```coord``` specifies the texture coordinates at which texture will be sampled.
```bias``` specifies an optional bias to be applied during level-of-detail computation.
### Description
The textureCube function returns a texel, i.e. the (color) value of the texture for the given coordinates. The function has one input parameter of the type samplerCube and one input parameter of the type vec3 : sampler, the uniform the texture is bound to, and coord, the 3-dimensional coordinates of the texel to look up.
There is an optional third input parameter of the type float: bias. After calculating the appropriate level of detail for a texture with mipmaps the bias is added before the actual texture lookup operation is executed.
Side note: On iOS devices texture lookup functionality is only available in the fragment shader.
### See Also
[texture2D](/glossary/?search=texture2D)
---
### Glossary/TextureCube/README Ua (glossary/textureCube/README-ua.md)
## textureCube
Отримує текселі (texels) з текстури
### Оголошення
```glsl
vec4 textureCube(samplerCube sampler, vec3 coord)
vec4 textureCube(samplerCube sampler, vec3 coord, float bias)
```
### Параметри
**```sampler```** — семплер, до якого прив'язана текстура, з якої будуть отримані текселі.
**```coord```** — координати текстури, за якими буде взята текстура.
**```bias```** — необов'язкове зміщення, яке буде застосовано під час обчислення рівня деталізації.
### Опис
Функція **`textureCube`** повертає тексель, тобто значення (кольору) текстури для заданих координат. Функція має перший вхідний параметр типу **`samplerCube`** і другий вхідний параметр типу **`vec3`**: семплер, до якої прив'язана текстура, і тривимірні координати текселя.
Існує додатковий третій вхідний параметр типу **`float`**. Після обчислення відповідного рівня деталізації для текстури з MIP-картами зміщення додається перед виконанням фактичної операції пошуку текстури.
Додаткова примітка: на пристроях iOS функція пошуку текстури доступна лише у фрагментному шейдері.
### Дивіться також
[texture2D](/glossary/?lan=ua&search=texture2D)
---
### Glossary/TextureCube/README Vi (glossary/textureCube/README-vi.md)
## TextureCube
Lấy màu của một vị trí bất kỳ trên texture có định dạng cube (6 mặt của khối lập phương).
### Các phiên bản
```glsl
vec4 textureCube(samplerCube sampler, vec3 coord)
vec4 textureCube(samplerCube sampler, vec3 coord, float bias)
```
### Các tham số
```sampler``` là sampler đã khởi tạo với texture, sẽ giúp ta lấy được màu tại tọa độ mong muốn.
```coord``` tọa độ vị trí cần lấy màu trên texture.
```bias``` sai số cho phép nếu áp dụng cơ chế Level-Of-Detail.
### Mô tả
Kết quả của hàm là 1 texel, tức màu tại vị trí chỉ định trên texture.
Tham số thứ ba không bắt buộc. Sau khi tính toán xong Level-Of-Detail phù hợp dựa trên các cấp mipmap, ```bias``` sẽ được dùng để tìm tọa độ trên texture.
Chú ý: Trên các thiết bị iOS, hàm này chỉ có thể dùng trong fragment shader.
### Tham khảo thêm
[texture2D](/glossary/?lan=vi&search=texture2D)
---
### Glossary/Uniform/README (glossary/uniform/README.md)
## Uniform
Uniform variable qualifier.
### Example
```glsl
uniform vec4 direction;
```
### Description
```uniform``` variables contain read-only data shared from WebGL/OpenGL environment to a vertex or fragment shader.
The value is per primitive, so is useful for variables which remain constant along a primitive, frame or scene.
### See Also
[attribute](/glossary/?search=attribute), [const](/glossary/?search=const), [varying](/glossary/?search=varying), [Chapter 03: Uniforms](/03/)
---
### Glossary/Uniform/README Ua (glossary/uniform/README-ua.md)
## uniform
Кваліфікатор уніфікованої змінної.
### Приклад
```glsl
uniform vec4 direction;
```
### Опис
**```uniform```**-змінні містять дані лише для читання, які передаються із середовища WebGL/OpenGL у вершинний або фрагментний шейдер.
Значення на рівні примітивів, тому вони корисні для змінних, які залишаються постійними вздовж примітива, кадру або сцени.
### Дивіться також
[attribute](/glossary/?lan=ua&search=attribute), [const](/glossary/?lan=ua&search=const), [varying](/glossary/?lan=ua&search=varying), [Розділ 03: Uniforms](/03/?lan=ua)
---
### Glossary/Uniform/README Vi (glossary/uniform/README-vi.md)
## Uniform
Qualifier đánh dấu biến chứa dữ liệu được gửi từ CPU sang GPU.
### Ví dụ
```glsl
uniform vec4 direction;
```
### Mô tả
Các biến ```uniform``` được gửi từ CPU sang cả 2 chương trình vertex shader và fragment shader chạy trên GPU. Giá trị của các biến này không thể thay đổi.
_The value is per primitive, so is useful for variables which remain constant along a primitive, frame or scene._
### Tham khảo thêm
[attribute](/glossary/?lan=vi&search=attribute), [const](/glossary/?lan=vi&search=const), [varying](/glossary/?lan=vi&search=varying), [Chương 03: Uniform](/03/?lan=vi)
---
### Glossary/Varying/README (glossary/varying/README.md)
## Varying
Varying variable qualifier.
### Example
```glsl
varying vec3 position;
```
### Description
```varying``` variables contain data shared from a vertex shader to a fragment shader.
The variable must be written in the vertex shader and the read-only value in the fragment shader is then interpolated from the vertices which make up the fragment.
### See Also
[attribute](/glossary/?search=attribute), [const](/glossary/?search=const), [uniform](/glossary/?search=uniform), [Chapter 03: Uniforms](/03/)
---
### Glossary/Varying/README Ua (glossary/varying/README-ua.md)
## varying
Кваліфікатор varying змінної.
### Приклад
```glsl
varying vec3 position;
```
### Опис
**```varying```**-змінні містять дані, які передаються від вершинного шейдера у фрагментний.
Змінна має бути спочатку оголошена у вершинному шейдері. У фрагментному шейдері її дані доступні лише для читання і є інтерполяцією з вершин, які складають фрагмент.
### Дивіться також
[attribute](/glossary/?lan=ua&search=attribute), [const](/glossary/?lan=ua&search=const), [uniform](/glossary/?lan=ua&search=uniform), [Розділ 03: Uniforms](/03/?lan=ua)
---
### Glossary/Varying/README Vi (glossary/varying/README-vi.md)
## Varying
Qualifier đánh dấu biến chứa dữ liệu đã được vertex shader xử lý và chuyển tiếp sang cho fragment shader xử lý tiếp.
### Ví dụ
```glsl
varying vec3 position;
```
### Mô tả
```varying``` đánh dấu biến chứa dữ liệu đã được vertex shader xử lý và chuyển tiếp sang cho fragment shader xử lý tiếp.
Biến này có thể được chỉnh sửa bởi vertex shader, nhưng phải là biến read-only đối với fragment shader.
### Tham khảo thêm
[attribute](/glossary/?lan=vi&search=attribute), [const](/glossary/?lan=vi&search=const), [uniform](/glossary/?lan=vi&search=uniform), [Chương 03: Uniform](/03/?lan=vi)
---
### Glossary/Vec2/README (glossary/vec2/README.md)
## Vec2
2 dimensional floating point vector
### Declaration
```glsl
vec2 aVec2 = vec2(1.0, 1.0);
vec2 bVec2 = vec2(1.0);
vec2 cVec2 = vec2(aVec3);
vec2 dVec2 = vec2(aVec3.x, aVec3.y);
```
### Description
```vec2``` is a floating point vector with two components. It can be initialized by:
- Providing a scalar value for each component.
- Providing one scalar value. This value is used for all components.
- Providing a vector of higher dimension. The respective values are used to initialize the components.
### See Also
[bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [bvec2](/glossary/?search=bvec2), [bvec3](/glossary/?search=bvec3), [bvec4](/glossary/?search=bvec4), [ivec2](/glossary/?search=ivec2), [ivec3](/glossary/?search=ivec3), [ivec4](/glossary/?search=ivec4), [vec2](/glossary/?search=vec2), [vec3](/glossary/?search=vec3), [vec4](/glossary/?search=vec4), [mat2](/glossary/?search=mat2), [mat3](/glossary/?search=mat3), [mat4](/glossary/?search=mat4)
---
### Glossary/Vec2/README Ua (glossary/vec2/README-ua.md)
## vec2
2-вимірний вектор із float-компонентами
### Оголошення
```glsl
vec2 aVec2 = vec2(1.0, 1.0);
vec2 bVec2 = vec2(1.0);
vec2 cVec2 = vec2(aVec3);
vec2 dVec2 = vec2(aVec3.x, aVec3.y);
```
### Опис
**```vec2```** — вектор з двома float-компонентами. Способи ініціалізації:
- надання скалярного значення для кожного компонента;
- надання одного скалярного значення, що буде використано для обох компонентів;
- надання вектора вищої розмірності, де відповідні значення будуть використані для ініціалізації компонентів;
### Дивіться також
[bool](/glossary/?lan=ua&search=bool), [int](/glossary/?lan=ua&search=int), [float](/glossary/?lan=ua&search=float), [bvec2](/glossary/?lan=ua&search=bvec2), [bvec3](/glossary/?lan=ua&search=bvec3), [bvec4](/glossary/?lan=ua&search=bvec4), [ivec2](/glossary/?lan=ua&search=ivec2), [ivec3](/glossary/?lan=ua&search=ivec3), [ivec4](/glossary/?lan=ua&search=ivec4), [vec2](/glossary/?lan=ua&search=vec2), [vec3](/glossary/?lan=ua&search=vec3), [vec4](/glossary/?lan=ua&search=vec4), [mat2](/glossary/?lan=ua&search=mat2), [mat3](/glossary/?lan=ua&search=mat3), [mat4](/glossary/?lan=ua&search=mat4)
---
### Glossary/Vec2/README Vi (glossary/vec2/README-vi.md)
## Vec2
Vector số nguyên 2 chiều.
### Các phiên bản
```glsl
vec2 aVec2 = vec2(1.0, 1.0);
vec2 bVec2 = vec2(1.0);
vec2 cVec2 = vec2(aVec3);
vec2 dVec2 = vec2(aVec3.x, aVec3.y);
```
### Mô tả
```vec2``` vector số nguyên gồm 2 thành phần. Nó có thể được khởi tạo bằng các cách:
- Chỉ định giá trị của từng thành phần
- Chỉ định 1 giá trị chung cho cả 2 thành phần
- Lấy giá trị từ 1 vector nhiều chiều hơn. Các thành phần sẽ được khởi tạo theo thứ tự.
### Tham khảo thêm
[bool](/glossary/?lan=vi&search=bool), [int](/glossary/?lan=vi&search=int), [float](/glossary/?lan=vi&search=float), [bvec2](/glossary/?lan=vi&search=bvec2), [bvec3](/glossary/?lan=vi&search=bvec3), [bvec4](/glossary/?lan=vi&search=bvec4), [ivec2](/glossary/?lan=vi&search=ivec2), [ivec3](/glossary/?lan=vi&search=ivec3), [ivec4](/glossary/?lan=vi&search=ivec4), [vec2](/glossary/?lan=vi&search=vec2), [vec3](/glossary/?lan=vi&search=vec3), [vec4](/glossary/?lan=vi&search=vec4), [mat2](/glossary/?lan=vi&search=mat2), [mat3](/glossary/?lan=vi&search=mat3), [mat4](/glossary/?lan=vi&search=mat4)
---
### Glossary/Vec3/README (glossary/vec3/README.md)
## Vec3
3 dimensional floating point vector
### Declaration
```glsl
vec3 aVec3 = vec3(1.0, 1.0, 1.0);
vec3 bVec3 = vec3(1.0);
vec3 cVec3 = vec3(aVec4);
vec3 dVec3 = vec3(aVec4.x, aVec4.y, aVec4.z);
vec3 eVec3 = vec3(aVec2, aFloat);
vec3 fVec3 = vec3(aVec2.x, aVec2.y, aFloat);
```
### Description
```vec3``` is a floating point vector with three components. It can be initialized by:
- Providing a scalar value for each component.
- Providing one scalar value. This value is used for all components.
- Providing a vector of higher dimension. The respective values are used to initialize the components.
- Providing a combination of vectors and/or scalars. The respective values are used to initialize the vector. The arguments of the constructor must have at least as many components as the vector that is initialized.
### See Also
[bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [bvec2](/glossary/?search=bvec2), [bvec3](/glossary/?search=bvec3), [bvec4](/glossary/?search=bvec4), [ivec2](/glossary/?search=ivec2), [ivec3](/glossary/?search=ivec3), [ivec4](/glossary/?search=ivec4), [vec2](/glossary/?search=vec2), [vec3](/glossary/?search=vec3), [vec4](/glossary/?search=vec4), [mat2](/glossary/?search=mat2), [mat3](/glossary/?search=mat3), [mat4](/glossary/?search=mat4)
---
### Glossary/Vec3/README Ua (glossary/vec3/README-ua.md)
## vec3
3-вимірний вектор із float-компонентами
### Оголошення
```glsl
vec3 aVec3 = vec3(1.0, 1.0, 1.0);
vec3 bVec3 = vec3(1.0);
vec3 cVec3 = vec3(aVec4);
vec3 dVec3 = vec3(aVec4.x, aVec4.y, aVec4.z);
vec3 eVec3 = vec3(aVec2, aFloat);
vec3 fVec3 = vec3(aVec2.x, aVec2.y, aFloat);
```
### Опис
**```vec3```** — вектор з трьома float-компонентами. Способи ініціалізації:
- надання скалярного значення для кожного компонента;
- надання одного скалярного значення, що буде використано для всіх компонентів;
- надання вектора вищої розмірності, де відповідні значення будуть використані для ініціалізації компонентів;
- надання комбінації векторів та/або скалярів. Для ініціалізації вектора використовуються відповідні значення. Аргументи конструктора повинні містити принаймні стільки ж компонентів, скільки ініціалізований вектор.
### Дивіться також
[bool](/glossary/?lan=ua&search=bool), [int](/glossary/?lan=ua&search=int), [float](/glossary/?lan=ua&search=float), [bvec2](/glossary/?lan=ua&search=bvec2), [bvec3](/glossary/?lan=ua&search=bvec3), [bvec4](/glossary/?lan=ua&search=bvec4), [ivec2](/glossary/?lan=ua&search=ivec2), [ivec3](/glossary/?lan=ua&search=ivec3), [ivec4](/glossary/?lan=ua&search=ivec4), [vec2](/glossary/?lan=ua&search=vec2), [vec3](/glossary/?lan=ua&search=vec3), [vec4](/glossary/?lan=ua&search=vec4), [mat2](/glossary/?lan=ua&search=mat2), [mat3](/glossary/?lan=ua&search=mat3), [mat4](/glossary/?lan=ua&search=mat4)
---
### Glossary/Vec3/README Vi (glossary/vec3/README-vi.md)
## Vec3
Vector số thực 3 chiều.
### Các phiên bản
```glsl
vec3 aVec3 = vec3(1.0, 1.0, 1.0);
vec3 bVec3 = vec3(1.0);
vec3 cVec3 = vec3(aVec4);
vec3 dVec3 = vec3(aVec4.x, aVec4.y, aVec4.z);
vec3 eVec3 = vec3(aVec2, aFloat);
vec3 fVec3 = vec3(aVec2.x, aVec2.y, aFloat);
```
### Mô tả
```vec3``` vector số thực gồm 3 thành phần. Nó có thể được khởi tạo bằng các cách:
- Chỉ định giá trị của từng thành phần
- Chỉ định 1 giá trị chung cho cả 3 thành phần
- Lấy giá trị từ 1 vector nhiều chiều hơn. Các thành phần sẽ được khởi tạo theo thứ tự.
- Lấy giá trị theo thứ tự lần lượt từ nhiều vector, miễn là đủ 3 thành phần.
### Tham khảo thêm
[bool](/glossary/?lan=vi&search=bool), [int](/glossary/?lan=vi&search=int), [float](/glossary/?lan=vi&search=float), [bvec2](/glossary/?lan=vi&search=bvec2), [bvec3](/glossary/?lan=vi&search=bvec3), [bvec4](/glossary/?lan=vi&search=bvec4), [ivec2](/glossary/?lan=vi&search=ivec2), [ivec3](/glossary/?lan=vi&search=ivec3), [ivec4](/glossary/?lan=vi&search=ivec4), [vec2](/glossary/?lan=vi&search=vec2), [vec3](/glossary/?lan=vi&search=vec3), [vec4](/glossary/?lan=vi&search=vec4), [mat2](/glossary/?lan=vi&search=mat2), [mat3](/glossary/?lan=vi&search=mat3), [mat4](/glossary/?lan=vi&search=mat4)
---
### Glossary/Vec4/README (glossary/vec4/README.md)
## Vec4
4 dimensional floating point vector
### Declaration
```glsl
vec4 aVec4 = vec4(1.0, 1.0, 1.0, 1.0);
vec4 bVec4 = vec4(1.0);
vec4 cVec4 = vec4(aVec2, aFloat, aVec3);
vec4 dVec4 = vec4(aBvec2.x, aBvec2.y, aFloat, aBvec3.x);
```
### Description
```vec4``` is a floating point vector with four components. It can be initialized by:
- Providing a scalar value for each component.
- Providing one scalar value. This value is used for all components.
- Providing a combination of vectors and scalars. The respective values are used to initialize the components. The arguments of the constructor must have at least as many components as the vector that is initialized.
### See Also
[bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float), [bvec2](/glossary/?search=bvec2), [bvec3](/glossary/?search=bvec3), [bvec4](/glossary/?search=bvec4), [ivec2](/glossary/?search=ivec2), [ivec3](/glossary/?search=ivec3), [ivec4](/glossary/?search=ivec4), [vec2](/glossary/?search=vec2), [vec3](/glossary/?search=vec3), [vec4](/glossary/?search=vec4), [mat2](/glossary/?search=mat2), [mat3](/glossary/?search=mat3), [mat4](/glossary/?search=mat4)
---
### Glossary/Vec4/README Vi (glossary/vec4/README-vi.md)
## Vec4
Vector số thực 4 chiều
### Các phiên bản
```glsl
vec4 aVec4 = vec4(1.0, 1.0, 1.0, 1.0);
vec4 bVec4 = vec4(1.0);
vec4 cVec4 = vec4(aVec2, aFloat, aVec3);
vec4 dVec4 = vec4(aBvec2.x, aBvec2.y, aFloat, aBvec3.x);
```
### Mô tả
```vec4``` là vector số thực gồm 4 thành phần. Nó có thể được khởi tạo bằng các cách:
- Chỉ định giá trị của từng thành phần
- Chỉ định 1 giá trị chung cho cả 4 thành phần
- Lấy giá trị theo thứ tự lần lượt từ nhiều vector, miễn là đủ 4 thành phần.
### Tham khảo thêm
[bool](/glossary/?lan=vi&search=bool), [int](/glossary/?lan=vi&search=int), [float](/glossary/?lan=vi&search=float), [bvec2](/glossary/?lan=vi&search=bvec2), [bvec3](/glossary/?lan=vi&search=bvec3), [bvec4](/glossary/?lan=vi&search=bvec4), [ivec2](/glossary/?lan=vi&search=ivec2), [ivec3](/glossary/?lan=vi&search=ivec3), [ivec4](/glossary/?lan=vi&search=ivec4), [vec2](/glossary/?lan=vi&search=vec2), [vec3](/glossary/?lan=vi&search=vec3), [vec4](/glossary/?lan=vi&search=vec4), [mat2](/glossary/?lan=vi&search=mat2), [mat3](/glossary/?lan=vi&search=mat3), [mat4](/glossary/?lan=vi&search=mat4)
---
### Glossary/Void/README (glossary/void/README.md)
## Void
### Declaration
```glsl
void main(void);
int aFunction(void);
void bFunction(float);
```
### Description
```void``` is used when a function has no parameters or when a function does not return a value.
### See Also
[void](/glossary/?search=void), [bool](/glossary/?search=bool), [int](/glossary/?search=int), [float](/glossary/?search=float)
---
### Glossary/Void/README Ua (glossary/void/README-ua.md)
## void
### Приклад
```glsl
void main(void);
int aFunction(void);
void bFunction(float);
```
### Опис
**```void```** — використовується для позначення функції без параметрів або коли вона не повертає значення.
### Дивіться також
[void](/glossary/?lan=ua&search=void), [bool](/glossary/?lan=ua&search=bool), [int](/glossary/?lan=ua&search=int), [float](/glossary/?lan=ua&search=float)
---
### Glossary/Void/README Vi (glossary/void/README-vi.md)
## Void
### Các phiên bản
```glsl
void main(void);
int aFunction(void);
void bFunction(float);
```
### Mô tả
```void``` is used when a function has no parameters or when a function does not return a value.
### Tham khảo thêm
[void](/glossary/?lan=vi&search=void), [bool](/glossary/?lan=vi&search=bool), [int](/glossary/?lan=vi&search=int), [float](/glossary/?lan=vi&search=float)
---
### MotionToolKit/SHORT SUMMARY (motionToolKit/SHORT_SUMMARY.md)
*[kynd](http://www.kynd.info) Sep 9, 2016*
Designing motion in a fragment shader is not straight forward and can be a bit tedious since it is not an animation tool after all. Here are some convenient tools and examples for controlling easing and timing, drawing shapes, and combining all these to create a nice sequence of motion. The first five examples introduce many useful functions that you can use as building blocks for your design. Following examples demonstrate how you can combine these tool to design complex animations.
---
### MotionToolKit/SUMMARY (motionToolKit/SUMMARY.md)
*[kynd](http://www.kynd.info) Sep 9, 2016*
Designing motion in a fragment shader is not straight forward and can be a bit tedious since it is not an animation tool after all. Here are some convenient tools and examples for controlling easing and timing, drawing shapes, and combining all these to create a nice sequence of motion. The first five examples introduce many useful functions that you can use as building blocks for your design. Following examples demonstrate how you can combine these tool to design complex animations.
Exercises:
* Can you draw different waves using different easing functions, then animate circles following the waves?
* Animate two circles. Can you express difference between different materials through motion? How a metal ball and a plastic ball behave differently?
* Design your character (an animal, monster, spaceship, etc.) by combining shapes and animate it.
* Speed up or down your character animation. Can you make it five times faster or slower than the original?
* Add a new scene to the "wipes" example. How can you make it easy so that you don't have to adjust the timing of all subsequent parts manually?
* The examples here are not necessarily optimized, especially the last one. Try reducing the number of calculation as much as possible. Many functions are running even when the elements they draw are not on-screen. How can you avoid this?
---
### ProceduralTexture/SUMMARY (proceduralTexture/SUMMARY.md)
*[kynd](http://www.kynd.info) Nov 20, 2016*
Shaders are often used to create realistic surfaces of natural or artificial material such as wood, marble, granite, metal, stone, etc. without using photographs or pre-rendered images. Here are demonstrations of some basic techniques. All the examples are based on a number of random and noise functions from [Random](http://thebookofshaders.com/10/), [Noise](http://thebookofshaders.com/11/), [Cellular Noise](http://thebookofshaders.com/12/) and [Fractal Brownian Motion](http://thebookofshaders.com/13/) chapters. Once you get the basic ideas, try tweaking and adding more details to make them more realistic, coming up with new textures and optimizing the performance.
Note that the terrain examples at the bottom use normal map and lighting which are techniques not yet introduced in this book. In short, what they do is to generate a map of the directions of the surface and shade the pixels accordingly. We will cover these ideas in future chapters. Stay tuned.
---
### .Github/FUNDING.Yml (.github/FUNDING.yml)
# These are supported funding model platforms
github: [patriciogonzalezvivo]
---
### .Github/Workflows/Publish.Yml (.github/workflows/publish.yml)
name: Build Book
on:
push:
tags:
- v*
jobs:
build:
runs-on: ubuntu-20.04
env:
DISPLAY: ':99.0'
steps:
- uses: actions/checkout@v2
- name: Set tag release as environment variable
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
- name: Step 1 - Install required APT packages
run: |
sudo add-apt-repository ppa:patriciogv/glslviewer-ppa
sudo apt-get update
# Setup the X11
sudo apt-get install libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xfixes0 x11-utils
/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -screen 0 1920x1200x24 -ac +extension GLX
sudo apt-get install glslviewer texlive-xetex pandoc python2.7
- name: Step 2 - Build books
run: make all
- name: Step 3 - Append version to book files
run: |
mkdir release
mv book.pdf release/book-$RELEASE_VERSION.pdf
mv book.epub release/book-$RELEASE_VERSION.epub
mv book.tex release/book-$RELEASE_VERSION.tex
- name: Step 4 - Release books
uses: fnkr/github-action-ghr@v1
if: startsWith(github.ref, 'refs/tags/')
env:
GHR_PATH: release/
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GHR_REPLACE: true
---