03 - added
This commit is contained in:
parent
08b4735e08
commit
6b87f8d44a
|
|
@ -0,0 +1,55 @@
|
|||
## Hello World
|
||||
|
||||
新しいプログラミング言語を学ぶときはたいてい最初に「Hello World」を表示します。一行のシンプルなプログラムで新しい世界に高らかにご挨拶というわけです。
|
||||
|
||||
しかしGPUの世界で文字を書くのは第一歩にしてはかなりの大仕事です。代わりに鮮やかな色でこの熱意を表現することにしましょう。
|
||||
|
||||
<div class="codeAndCanvas" data="hello_world.frag"></div>
|
||||
|
||||
もしこの本をブラウザーで読んでいるのであれば、上のサンプルコードをクリックして好きなところを編集することができます。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```型の値が割り当てられることになっています。コードの一貫性を保ち、真っ白な画面で何時間もデバッグするのを避けるために、浮動小数点型の値には小数点(```.```)を使うことを習慣にしましょう。下記のようなコードはうまく動くとは限りません。
|
||||
|
||||
```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種類の入力、空間(画面上のピクセルの位置)と時間(ページがロードされてから経過した秒数)を使って変化させる方法を学びます。
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<?php
|
||||
<?php
|
||||
|
||||
$path = "..";
|
||||
$subtitle = ": Hello world!";
|
||||
|
|
@ -23,5 +23,5 @@
|
|||
<li class="navigationBar" onclick="nextPage()">Next > ></li>
|
||||
</ul>';
|
||||
|
||||
include($path."/footer.php");
|
||||
include($path."/footer.php");
|
||||
?>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
## 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 graphic 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.
|
||||
|
||||
前章ではGPUがたくさんのスレッドを並列に扱い、それぞれのスレッドが画像の部分部分に色を割り当てていく様子を学びました。シェーダーではそれぞれのスレッド間でやりとりを行うことはできませんが、CPUからそれぞれのスレッドに入力を送ることができる必要があります。グラフィックカードは、全てのスレッドにのまったく同じ入力を送るように設計されています(訳注: 英語の”uniform”には均一な、一様な、という意味があります)。それぞれのスレッドは同じデータを受け取り、それを書き換えることはできません。
|
||||
|
||||
These inputs are call ```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.
|
||||
|
||||
これらの入力は ```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
|
||||
```
|
||||
|
||||
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 iGlobalTime; // 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.
|
||||
|
||||
<div class="codeAndCanvas" data="time.frag"></div>
|
||||
|
||||
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*.
|
||||
|
||||
<div class="codeAndCanvas" data="space.frag"></div>
|
||||
|
||||
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. 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.
|
||||
Loading…
Reference in New Issue