parent
86eb812e7d
commit
83485dc276
@ -1,8 +1,145 @@
|
||||
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.
|
||||
|
||||
### matrix
|
||||
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
|
||||
|
||||
Vectors are fun, they're the meat of your shader and soon enough you'll to have transform them.
|
||||
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) );
|
||||
|
||||
[to be continued]
|
||||
//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 genearal, 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``` **attributes** 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 sometihng like:
|
||||
```glsl
|
||||
uniform vec2 u_resolution;
|
||||
```
|
||||
See what we did here? we stuck a ```unifrom``` 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 argumnts qualifiers, you can specify the behaviour of the 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).
|
||||
|
||||
|
||||
### 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 BUG 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?]("https://thebookofshaders.com/")
|
||||
|
||||
|
||||
|
@ -0,0 +1,53 @@
|
||||
## An introduction for those coming from JS
|
||||
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.
|
||||
|
||||
Last note, a **shader** is made of 2 programs, the **vertex shaderr** and the **fragment shader**.
|
||||
In a nutshell, the **vertex shader**, the first programm, recieves a *geometry* as an input and turns it into series of **pixels** (or *fragments*) then hands it 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!
|
||||
|
||||
* [types](./01/)
|
||||
* [vectors](./02/)
|
||||
* [unicorns](./03/)
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 60 KiB |
Binary file not shown.
After Width: | Height: | Size: 23 KiB |
Loading…
Reference in New Issue