Shader : "GLSL 2D Tutorials"を理解する その1 (step1~7)

f:id:zonu_a0:20210614053810p:plain

Shadertoyの入門によさそうな作品を見つけたので、それを解読して理解を深めていこうと思います

GLSL 2D Tutorials

www.shadertoy.com

  • 全部で28のステップがある
  • 13行目の #define TUTORIAL 0 の"0"の部分を変更して実行することで、対応するステップの画面を確認できる
  • 各ステップの内容は L16-43 に記載
  • 0はタイトル画面的なもの

1 VOID. BLANK SCREEN.

f:id:zonu_a0:20210614055848p:plain

ソースコード

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
}

解読

  • コメント訳↓

無効。 空白の画面。

"main" 関数は、シェーダー効果を生成するために1秒間に数回呼び出されます。
このシステムは、60フレーム/秒(FPS)の速度を生成することを目的としています。
ただし、GLSLスクリプトの計算が難しい場合は、フレームレートが低下します。 (画面下の情報バーでフレームレートを読み取ることができます。
この関数では何もしていないため、このシェーダーは黒い画面を生成します。

  • メイン関数についての説明
  • パフォーマンスチューニングも手軽にできるのいいね

2 SOLID COLOR

f:id:zonu_a0:20210614060738p:plain

ソースコード

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    fragColor = vec4(1.0, 1.0, 0.0 ,1.0);
}

解読

  • コメント訳↓

ソリッドカラー

"fragColor" は、シェーダーの出力変数です。
その値によって、画面上の画像が決まります。
このシェーダーは、その値を黄色に設定します。

3 GLSL VECTORS

f:id:zonu_a0:20210614062244p:plain

ソースコード

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Here we are seperating the color and transparency parts
    // of the vec4 that represents the pixels.
    vec3 color = vec3(0.0, 1.0, 1.0);
    float alpha = 1.0;
    
    vec4 pixel = vec4(color, alpha);
    fragColor = pixel;
}

解読

  • コメント訳↓

GLSLベクトル

"fragColor" には、0から1までの4つの数字で構成されるvec4オブジェクトを割り当てる必要があります。
最初の3つの数字は色を決定し、4番目の数字は不透明度を決定します。
(今のところ、透明度の値を変更しても効果はありません)
"vec4" データオブジェクトは、4つの "float" 引数、または1つの "vec3" と1つの "float" 引数を指定することで構築できます。

  • vec4は vec4( float, float, float, float )vec4( vec3, float ) で生成できる

4 RGB COLOR MODEL AND COMPONENTS OF VECTORS

f:id:zonu_a0:20210614070758p:plain

ソースコード

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // play with these numbers:
    float redAmount = 0.6; // amount of redness
    float greenAmount = 0.2; // amount of greenness
    float blueAmount = 0.9; // amount of blueness
    
    vec3 color = vec3(0.0); 
    // Here we only input a single argument. It is a third way of
    // contructing vectors.
    // "vec3(x)" is equivalent to vec3(x, x, x);
    // This vector is initialized as
    // color.x = 0.0, color.y = 0.0; color.z = 0.0;
    color.x = redAmount;
    color.y = greenAmount;
    color.z = blueAmount;
    
    float alpha = 1.0;
    vec4 pixel = vec4(color, alpha);    
    fragColor = pixel;
}

解読

  • コメント訳

RGBカラーモデルとベクトルの成分

初期化後、ドット"."表記を使用してベクトルの成分に到達できます。

RGB:http://en.wikipedia.org/wiki/RGB_color_model
色は3つの数字で表されます(ここでは[0.0、1.0]の範囲)
モデルは、与えられた強度の純粋な赤、緑、青のライトの追加を想定しています。

私のようなデザインスキルがなく、見栄えの良い一貫性のある色のセットを選択するのに苦労している場合は、これらのWebサイトのいずれかを使用して、さまざまな色のセットを参照できるカラーパレットを選択できます。
https://kuler.adobe.com/create/color-wheel/
http://www.colourlovers.com/palettes
http://www.colourlovers.com/colors

  • 色はrgb(0.0~1.0)で表現するよ、という話
  • vec3(x,x,x)vec3(x) と省略して書ける (知らんかった)
  • adobeのカラーホイール の色の関係式きになる

5 THE COORDINATE SYSTEM

f:id:zonu_a0:20210614071918p:plain

ソースコード

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // choose two colors
    vec3 color1 = vec3(0.886, 0.576, 0.898);
    vec3 color2 = vec3(0.537, 0.741, 0.408);
    vec3 pixel;
    
    // if the x coordinate is greater than 100 then plot color1
    // else plot color2
    float widthOfStrip = 100.0;
    if( fragCoord.x > widthOfStrip ) {
        pixel = color2;
    } else {
        pixel = color1;
    }
    
    fragColor = vec4(pixel, 1.0);
}

解読

  • コメント訳↓
座標系

"fragCoord" (fragment coordinate) は入力変数です。  
  
画面上のどのピクセルにいるかがわかります。  
座標の中心は左下隅であり、座標値は右と上に向かって増加します。  
  
main関数は、画面上のすべてのピクセルに対して実行されます。  
各呼び出しで、 "gl_FracCoord" は対応するピクセルの座標を持ちます。  
  
GPUには多くのコアがあるため、異なるピクセルの関数呼び出しを同時に並行して計算できます。  
これにより、CPU上で1つずつ直列にピクセルカラーを計算するよりも高速になります。  
しかし、それも重要な制約を課します。  
ピクセルの値は、別のピクセルの値に依存することはできません。  
(計算は並行して行われ、どちらがもう一方の前に終了するかを知ることは不可能です)  
ピクセルの結果は、ピクセル座標(およびその他の入力変数)にのみ依存します。  
これは、シェーダープログラミングの最も重要な違いです。  
私たちは何度も何度もこの点に到達します

単色ではないものを描きましょう。
  • 左端から100pixel以内のピクセルなら color1、それ以外は color2で描画する処理
  • fragCoord からピクセル座標を取得できる
  • mainImage関数(=フラグメントシェーダ)は全ピクセルに対して行われる
  • フラグメントシェーダは並列実行されるため、他のピクセルの値に依存することができない

6 RESOLUTION, THE FRAME SIZE

f:id:zonu_a0:20210614081950p:plain

ソースコード

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec3 color1 = vec3(0.741, 0.635, 0.471);
    vec3 color2 = vec3(0.192, 0.329, 0.439);
    vec3 pixel;
    
    // sugar syntax for "if" conditional. It says
    // "if the x coordinate of a pixel is greater than the half of
    // the width of the screen, then use color1, otherwise use
    // color2."
    pixel = ( fragCoord.x > iResolution.x / 2.0 ) ? color1 : color2;
    
    fragColor = vec4(pixel, 1.0);
}

解読

  • コメント訳
解像度、フレームサイズ  
ブラウザのサイズを変更するか、フルスクリーンモードにして元に戻すと、最初の色と2番目の色の幅の比率が画面サイズによって変化することがわかります。  
これは、ストリップの幅を、画面の幅と高さの比率ではなく、絶対ピクセル数で設定しているためです。  
  
左半分と右半分を異なる色でペイントしたいとします。  
水平方向のピクセル数がわからないと、すべてのフレームサイズで機能するシェーダーを準備することはできません。  
   
ピクセル数の観点から画面サイズ(幅と高さ)をどのように知ることができますか。 それは変数 "iResolution" で与えられます。  
"iResolution.x" はフレームの幅であり、  
"iResolution.y" はフレームの高さです
  • 画面の右半分をcolor1、左半分をcolor2で描画する処理
  • 画面サイズ(ピクセル数)は変化するので注意
  • iResolution で現在の画面サイズを取得可能
  • 三項演算子も使える

7 COORDINATE TRANSFORMATION

f:id:zonu_a0:20210614082134p:plain

ソースコード

{
    vec2 r = vec2(fragCoord.x / iResolution.x,
                  fragCoord.y / iResolution.y);
    // r is a vec2. Its first component is pixel x-coordinate divided by
    // the frame width. And second component is the pixel y-coordinate
    // divided by the frame height.
    //
    // For example, on my laptop, the full screen frame size is
    // 1440 x 900. Therefore iResolution is (1440.0, 900.0).
    // The main function should be run 1440*900=1296000 times to
    // generate a frame.
    // fragCoord.x will have values between 0 and 1439, and
    // fragCoord.y will have values between 0 and 899, whereas
    // r.x and r.y will have values between [0,1].
    
    vec3 color1 = vec3(0.841, 0.582, 0.594);
    vec3 color2 = vec3(0.884, 0.850, 0.648);
    vec3 color3 = vec3(0.348, 0.555, 0.641);
    vec3 pixel;
    
    // sugar syntax for "if" conditional. It says
    // "if the x coordinate of a pixel is greater than the half of
    // the width of the screen, then use color1, otherwise use
    // color2."
    if( r.x < 1.0/3.0) {
        pixel = color1;
    } else if( r.x < 2.0/3.0 ) {
        pixel = color2;
    } else {
        pixel = color3;
    }
            
    // pixel = ( r.x < 1.0/3.0 ) ? color1 : (r.x<2.0/3.0) ? color2: color3;
    // same code, single line.
    
    fragColor = vec4(pixel, 1.0);
}

解読

  • コメント訳↓
座標変換

ほとんどの場合、画面の座標で作業する代わりに、独自の座標系を使用する方が便利です。

ここでは、絶対画面座標 "fragCoord" の代わりに、新しい座標系 "r" を作成して使用します。
"r" では、x座標とy座標が0から1になります。
xの場合、0は左側、1は右側です。
yの場合、0は下側、1は上側です。

"r" を使用して、画面を3つの部分に分割しましょう。
"r"はvec2です。
その第一成分は、ピクセルのx座標をフレーム幅で割ったものです。
そして第二成分は、ピクセルのy座標をフレームの高さで割ったものです。

たとえば、私のラップトップでは、フルスクリーンのフレームサイズは1440 x900です。
したがって、iResolutionは(1440.0、900.0)です。
フレームを生成するには、main関数を1440 * 900 = 1296000回実行する必要があります。
fragCoord.xの値は0〜1439で、
fragCoord.yの値は0〜899ですが、
r.xとr.yの値は0~1の間です。
  • 画面を横に3分割して、左から color1, color2, color3 をで描画する処理
  • ピクセル座標を画面全体を0~1とする座標rに置換することで、処理をシンプルに

今回はここまで


zonu.hatenablog.com