diff --git a/.gitignore b/.gitignore index 5e044a0..d96c2e8 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,5 @@ log/* .idea/ idea/ /07/test.html +/appendix/04/index.html /09/test.html diff --git a/appendix/04/01/README.md b/appendix/04/01/README.md new file mode 100644 index 0000000..3b319be --- /dev/null +++ b/appendix/04/01/README.md @@ -0,0 +1,78 @@ +![first search result for 'strong type' on Google Image, on the 2016/05/20](strong_type.jpg) +### 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 cooresponds 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 [Aragorn](https://en.wikipedia.org/wiki/Aragorn) 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; +``` +and this 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 adressing 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. + + diff --git a/appendix/04/01/index.php b/appendix/04/01/index.php new file mode 100644 index 0000000..bc98d1f --- /dev/null +++ b/appendix/04/01/index.php @@ -0,0 +1,28 @@ +

The Book of Shaders by Patricio Gonzalez Vivo

+
+
+ '; + + $Parsedown = new Parsedown(); + echo $Parsedown->text(file_get_contents ('README.md')); + + echo ' +
+
+ '; + + include($path."/footer.php"); +?> diff --git a/appendix/04/01/strong_type.jpg b/appendix/04/01/strong_type.jpg new file mode 100644 index 0000000..07fa95d Binary files /dev/null and b/appendix/04/01/strong_type.jpg differ diff --git a/appendix/04/02/README.md b/appendix/04/02/README.md new file mode 100644 index 0000000..30fe3d1 --- /dev/null +++ b/appendix/04/02/README.md @@ -0,0 +1,167 @@ +![first search result for 'vector villain' on Google Image, on the 2016/05/20](vector.jpg) +### 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 horendous **`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, `ivec4`: 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? (actually a 4 diemnsional space 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 wether 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 htere is no restriction on how to use the vectors. +For instance, if you want to store only one boolean value in a `bvce4`, 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 = v4.abgr; // backawrds = 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 = v4.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](../01/), 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 **vesrions** 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 equel 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). diff --git a/appendix/04/02/index.php b/appendix/04/02/index.php new file mode 100644 index 0000000..bc98d1f --- /dev/null +++ b/appendix/04/02/index.php @@ -0,0 +1,28 @@ +

The Book of Shaders by Patricio Gonzalez Vivo

+
+
+ '; + + $Parsedown = new Parsedown(); + echo $Parsedown->text(file_get_contents ('README.md')); + + echo ' +
+
+ '; + + include($path."/footer.php"); +?> diff --git a/appendix/04/02/vector.jpg b/appendix/04/02/vector.jpg new file mode 100644 index 0000000..4852d70 Binary files /dev/null and b/appendix/04/02/vector.jpg differ diff --git a/appendix/04/03/README.md b/appendix/04/03/README.md new file mode 100644 index 0000000..9fcecbb --- /dev/null +++ b/appendix/04/03/README.md @@ -0,0 +1,8 @@ + +### matrix + +Vectors are fun, they're the meat of your shader and soon enough you'll to have transform them. + +[to be continued] + + diff --git a/appendix/04/03/index.php b/appendix/04/03/index.php new file mode 100644 index 0000000..bc98d1f --- /dev/null +++ b/appendix/04/03/index.php @@ -0,0 +1,28 @@ +

The Book of Shaders by Patricio Gonzalez Vivo

+
+
+ '; + + $Parsedown = new Parsedown(); + echo $Parsedown->text(file_get_contents ('README.md')); + + echo ' +
+
+ '; + + include($path."/footer.php"); +?> diff --git a/appendix/04/04/README.md b/appendix/04/04/README.md new file mode 100644 index 0000000..8b6968d --- /dev/null +++ b/appendix/04/04/README.md @@ -0,0 +1,13 @@ + + +### textures and space + +Let's start with a gentle one ; the Y axis is flipped. +Y points 'up', to the sky, while in the DOM & Canvas worlds, we're used to having the Y pointing 'down'. +This makes sense in the context of a DOM as it follows the way a web page would unroll(the navbar at the top, content at the bottom), +but if you were to tell where is the 'up' direction of a piece of paper, I'm sure you'd point 'up''. + +This implies that the point 0,0, which is located in the top left corner of a canvas element will be located in the bottom right corner of a WebGL context. +The textures coordinates also will follow this rule which might be counter-intuitive but soon you'll get used to it. + +[to be continued] diff --git a/appendix/04/04/index.php b/appendix/04/04/index.php new file mode 100644 index 0000000..bc98d1f --- /dev/null +++ b/appendix/04/04/index.php @@ -0,0 +1,28 @@ +

The Book of Shaders by Patricio Gonzalez Vivo

+
+
+ '; + + $Parsedown = new Parsedown(); + echo $Parsedown->text(file_get_contents ('README.md')); + + echo ' +
+
+ '; + + include($path."/footer.php"); +?> diff --git a/appendix/04/05/README.md b/appendix/04/05/README.md new file mode 100644 index 0000000..960fc21 --- /dev/null +++ b/appendix/04/05/README.md @@ -0,0 +1,5 @@ + + +### uniforms & unicorns + +[to be started] diff --git a/appendix/04/05/index.php b/appendix/04/05/index.php new file mode 100644 index 0000000..bc98d1f --- /dev/null +++ b/appendix/04/05/index.php @@ -0,0 +1,28 @@ +

The Book of Shaders by Patricio Gonzalez Vivo

+
+
+ '; + + $Parsedown = new Parsedown(); + echo $Parsedown->text(file_get_contents ('README.md')); + + echo ' +
+
+ '; + + include($path."/footer.php"); +?> diff --git a/appendix/04/README.md b/appendix/04/README.md index 83053f1..bc377a7 100644 --- a/appendix/04/README.md +++ b/appendix/04/README.md @@ -1,2 +1,49 @@ ## An introduction for those coming from JS -by .... +by Nicolas Barradeau + + +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. + +SO, ready? +off we go, jump to one of the sections below! + +* [types](./01/) +* [vectors](./02/) +* [matrices](./03/) +* [textures](./04/) +* [uniforms & unicorns](./05/) diff --git a/appendix/04/index.php b/appendix/04/index.php index 041cc63..9ab9c01 100644 --- a/appendix/04/index.php +++ b/appendix/04/index.php @@ -1,5 +1,10 @@ -text(file_get_contents ('README.md')); - + /* echo '
'; + //*/ - include($path."/footer.php"); + include($path."/footer.php"); ?>