Merge pull request #79 from nicoptere/master

appendix: coming from JS +types +vectors
This commit is contained in:
Patricio Gonzalez Vivo 2016-05-22 12:25:35 -04:00
commit d8b2ff51d5
15 changed files with 470 additions and 5 deletions

1
.gitignore vendored
View File

@ -9,4 +9,5 @@ log/*
.idea/
idea/
/07/test.html
/appendix/04/index.html
/09/test.html

78
appendix/04/01/README.md Normal file
View File

@ -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.

28
appendix/04/01/index.php Normal file
View File

@ -0,0 +1,28 @@
<?php
$path = "../../../";
$subtitle = "learning to fly";
$language = isset( $_GET[ 'lan' ] ) ? $_GET[ 'lan' ] : "";
$README = "README";
include($path."/header.php");
include($path."/src/parsedown/Parsedown.php");
echo '
<div class="header"><p><a href="https://thebookofshaders.com/">The Book of Shaders</a> by <a href="http://patriciogonzalezvivo.com">Patricio Gonzalez Vivo</a></p></div>
<hr>
<div id="content">
';
$Parsedown = new Parsedown();
echo $Parsedown->text(file_get_contents ('README.md'));
echo '
</div>
<hr>
<ul class="navigationBar" >
<li class="navigationBar" onclick="previusPage()">&lt; &lt; Previous</li>
<li class="navigationBar" onclick="homePage()"> Home </li>
<li class="navigationBar" onclick="nextPage()">Next &gt; &gt;</li>
</ul>';
include($path."/footer.php");
?>

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

167
appendix/04/02/README.md Normal file
View File

@ -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).

28
appendix/04/02/index.php Normal file
View File

@ -0,0 +1,28 @@
<?php
$path = "../../../";
$subtitle = "learning to fly";
$language = isset( $_GET[ 'lan' ] ) ? $_GET[ 'lan' ] : "";
$README = "README";
include($path."/header.php");
include($path."/src/parsedown/Parsedown.php");
echo '
<div class="header"><p><a href="https://thebookofshaders.com/">The Book of Shaders</a> by <a href="http://patriciogonzalezvivo.com">Patricio Gonzalez Vivo</a></p></div>
<hr>
<div id="content">
';
$Parsedown = new Parsedown();
echo $Parsedown->text(file_get_contents ('README.md'));
echo '
</div>
<hr>
<ul class="navigationBar" >
<li class="navigationBar" onclick="previusPage()">&lt; &lt; Previous</li>
<li class="navigationBar" onclick="homePage()"> Home </li>
<li class="navigationBar" onclick="nextPage()">Next &gt; &gt;</li>
</ul>';
include($path."/footer.php");
?>

BIN
appendix/04/02/vector.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

8
appendix/04/03/README.md Normal file
View File

@ -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]

28
appendix/04/03/index.php Normal file
View File

@ -0,0 +1,28 @@
<?php
$path = "../../../";
$subtitle = "learning to fly";
$language = isset( $_GET[ 'lan' ] ) ? $_GET[ 'lan' ] : "";
$README = "README";
include($path."/header.php");
include($path."/src/parsedown/Parsedown.php");
echo '
<div class="header"><p><a href="https://thebookofshaders.com/">The Book of Shaders</a> by <a href="http://patriciogonzalezvivo.com">Patricio Gonzalez Vivo</a></p></div>
<hr>
<div id="content">
';
$Parsedown = new Parsedown();
echo $Parsedown->text(file_get_contents ('README.md'));
echo '
</div>
<hr>
<ul class="navigationBar" >
<li class="navigationBar" onclick="previusPage()">&lt; &lt; Previous</li>
<li class="navigationBar" onclick="homePage()"> Home </li>
<li class="navigationBar" onclick="nextPage()">Next &gt; &gt;</li>
</ul>';
include($path."/footer.php");
?>

13
appendix/04/04/README.md Normal file
View File

@ -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]

28
appendix/04/04/index.php Normal file
View File

@ -0,0 +1,28 @@
<?php
$path = "../../../";
$subtitle = "learning to fly";
$language = isset( $_GET[ 'lan' ] ) ? $_GET[ 'lan' ] : "";
$README = "README";
include($path."/header.php");
include($path."/src/parsedown/Parsedown.php");
echo '
<div class="header"><p><a href="https://thebookofshaders.com/">The Book of Shaders</a> by <a href="http://patriciogonzalezvivo.com">Patricio Gonzalez Vivo</a></p></div>
<hr>
<div id="content">
';
$Parsedown = new Parsedown();
echo $Parsedown->text(file_get_contents ('README.md'));
echo '
</div>
<hr>
<ul class="navigationBar" >
<li class="navigationBar" onclick="previusPage()">&lt; &lt; Previous</li>
<li class="navigationBar" onclick="homePage()"> Home </li>
<li class="navigationBar" onclick="nextPage()">Next &gt; &gt;</li>
</ul>';
include($path."/footer.php");
?>

5
appendix/04/05/README.md Normal file
View File

@ -0,0 +1,5 @@
### uniforms & unicorns
[to be started]

28
appendix/04/05/index.php Normal file
View File

@ -0,0 +1,28 @@
<?php
$path = "../../../";
$subtitle = "learning to fly";
$language = isset( $_GET[ 'lan' ] ) ? $_GET[ 'lan' ] : "";
$README = "README";
include($path."/header.php");
include($path."/src/parsedown/Parsedown.php");
echo '
<div class="header"><p><a href="https://thebookofshaders.com/">The Book of Shaders</a> by <a href="http://patriciogonzalezvivo.com">Patricio Gonzalez Vivo</a></p></div>
<hr>
<div id="content">
';
$Parsedown = new Parsedown();
echo $Parsedown->text(file_get_contents ('README.md'));
echo '
</div>
<hr>
<ul class="navigationBar" >
<li class="navigationBar" onclick="previusPage()">&lt; &lt; Previous</li>
<li class="navigationBar" onclick="homePage()"> Home </li>
<li class="navigationBar" onclick="nextPage()">Next &gt; &gt;</li>
</ul>';
include($path."/footer.php");
?>

View File

@ -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/)

View File

@ -1,5 +1,10 @@
<?php
<?php
$path = "../../";
$subtitle = "learning to fly";
$language = isset( $_GET[ 'lan' ] ) ? $_GET[ 'lan' ] : "";
$README = "README";
include($path."/header.php");
include($path."/src/parsedown/Parsedown.php");
@ -11,15 +16,16 @@
$Parsedown = new Parsedown();
echo $Parsedown->text(file_get_contents ('README.md'));
/*
echo '
</div>
<hr>
<ul class="navigationBar" >
<li class="navigationBar" onclick="previusPage()">&lt; &lt; Previous</li>
<!--li class="navigationBar" onclick="previusPage()">&lt; &lt; Previous</li /-->
<li class="navigationBar" onclick="homePage()"> Home </li>
<li class="navigationBar" onclick="nextPage()">Next &gt; &gt;</li>
</ul>';
//*/
include($path."/footer.php");
include($path."/footer.php");
?>