LoginSignup
50
43

More than 5 years have passed since last update.

[Unity] ShaderTutorial2D

Last updated at Posted at 2016-07-26

対象

Shaderやってみたいけど,どう勉強すればよいか分からない人

導入

とりあえず動かしてみる

  1. Create -> Shader -> ImageEffectShader選択
  2. ダブルクリックで開き,一行目をShader "ShaderTutorial/Tutorial1"にする.
  3. Materialを作成し,ShaderをShaderTutorial -> Tutorial1にする.
  4. C#スクリプトを作成,後述するスクリプトを記入
  5. スクリプトをMainCameraにアタッチ
  6. Materialがない!ってエラーが出るので,materialをアタッチ
  7. 終了

手順2
Create.png

手順3
MaterialShader.png

手順4

Tutorial1.cs
using UnityEngine;
using System.Collections;

[ExecuteInEditMode]
public class Tutorial1 : MonoBehaviour {

    public Material mat;

    void OnRenderImage(RenderTexture src, RenderTexture dest){
        Graphics.Blit (src, dest, mat);
    }
}

結果

色が反転します.

ネガ.png

以下のチュートリアルはShaderToyの
https://www.shadertoy.com/view/Md23DV

この投稿をUnityで実装したものになります.

数値に関しては,float, half, fixedの3種類がありますが,
このチュートリアルではfixedとfloatのみを使用しています.

Github

Tutorial1

Tutorial1.png

Tutorial1.shader
Shader "ShaderTutorial/Tutorial1"
{
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                o.uv = v.uv;
                return o;
            }


            fixed4 frag (v2f i) : SV_Target
            {
                return fixed4(1.0, 1.0, 0.0, 1.0);
            }
            ENDCG
        }
    }
}

fragの中身に注目してください.

fixed4(1.0, 1.0, 0.0, 1.0)が黄色を示しています.
パラメータはそれぞれ(Red, Green, Blue, Alpha(透明度))を示しています.

値は0~1.0です.

Point

fragの中で色をreturnすることで絵が出る

Tutorial2

result_tutorial2.png

ここからはフラグメントシェーダのみスクリプトを示します.

Tutorial2.shader
fixed4 frag (v2f i) : SV_Target
{
    fixed3 color = fixed3(0.0, 1.0, 1.0);
    fixed alpha = 1.0;

    fixed4 pixel = fixed4(color, alpha);
    return pixel;
}

Point

fixed3型のcolorとfixed型のalphaを合体してfixed4型にできる.

Tutorial3

result_tutorial3.png

Tutorial3.shader
fixed4 frag (v2f i) : SV_Target
{
    fixed redAmount = 0.6;
    fixed greenAmount = 0.2;
    fixed blueAmount = 0.9;

    fixed3 color = fixed3(0.0, 0.0, 0.0);
    color.x = redAmount;
    color.y = greenAmount;
    color.z = blueAmount;

    fixed alpha = 1.0;
    fixed4 pixel = fixed4(color, alpha);
    return pixel;
}

Point

fixed3の3要素には,color.xのように,xyzでアクセスできる.

Tutorial4

result_tutorial4.png

Tutorial4.shader
fixed4 frag (v2f i) : SV_Target
{
    fixed3 color1 = fixed3(0.886, 0.576, 0.898);
    fixed3 color2 = fixed3(0.537, 0.741, 0.408);
    fixed3 pixel;

    if(i.uv.x > 0.5){
        pixel = color2;
    } else {
        pixel = color1;
    }

    return fixed4(pixel, 1.0);
}

Point

引数であるiを使うことにより,現在処理しているピクセルのuv座標をi.uvで取得することができる.
今回はi.uv.x > 0.5すなわち,画面を横に分断するように色を分けた.
uv座標のx軸は画面の左から一番右端へ0~1.0である.

Tutorial5

result_Tutorial5.png

Tutorial5.shader
fixed4 frag (v2f i) : SV_Target
{
    fixed3 color1 = fixed3(0.886, 0.576, 0.898);
    fixed3 color2 = fixed3(0.537, 0.741, 0.408);
    fixed3 pixel;

    float dis = 50;

    if(i.uv.x * _ScreenParams.x > dis){
        pixel = color2;
    } else {
        pixel = color1;
    }

    return fixed4(pixel, 1.0);
}

Point

uv座標に,スクリーンの解像度(_ScreenParams)を掛け算することで,現在処理しているピクセルの位置を取得できる.

Tutorial6 線の引き方

result_tutorial6.png

Tutorial6.shader
// HORIZONTAL AND VERTICAL LINES
fixed4 frag (v2f i) : SV_Target
{
    fixed3 backgroundColor = fixed3(1.0, 1.0, 1.0);
    fixed3 color1 = fixed3(0.216, 0.471, 0.698); // blue
    fixed3 color2 = fixed3(1.00, 0.329, 0.298); // red
    fixed3 color3 = fixed3(0.867, 0.910, 0.247); // yellow

    fixed3 pixel = backgroundColor;

    // line1
    float leftCoord = 0.54;
    float rightCoord = 0.55;
    if(i.uv.x < rightCoord && i.uv.x > leftCoord) pixel = color1;

    // line2
    float lineCoordinate = 0.4;
    float lineThickness = 0.003;
    if(abs(i.uv.x - lineCoordinate) < lineThickness ) pixel = color2;

    // line3
    if(abs(i.uv.y - 0.6) < 0.01) pixel = color3;

    return fixed4(pixel, 1.0);
}

Point

線の引き方には2種類あり,一つ目は線の端の座標を示す方法(line1).二つ目は線の中心の座標と厚さを示す方法である(line2,3)
後者の場合にはif(abs(i.uv.x - lineCoordinate) < lineThickness )で表せる.

もし上下が反転していたら

v2f vert(appdata v)
{
    v2f o;
    o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
    o.uv = v.uv;
    o.uv.y = 1-o.uv.y; //この行を加える.
    return o;
}

Tutorial7 座標の視覚化

result_tutorial7.png

Tutorial7.shader
// VISUALISING THE COORDINATE SYSTEM
fixed4 frag (v2f i) : SV_Target
{
    fixed3 backgroundColor = fixed3(1.0, 1.0, 1.0);
    fixed3 axesColor = fixed3(0.0, 0.0, 1.0);
    fixed3 gridColor = fixed3(0.5, 0.5, 0.5);

    fixed3 pixel = backgroundColor;

    const float tickWidth = 0.1;
    for(float lc=0.0; lc< 1.0; lc+=tickWidth){
        if(abs(i.uv.x - lc) < 0.002) pixel = gridColor;
        if(abs(i.uv.y - lc) < 0.002) pixel = gridColor;
    }

    // Draw the axes
    if(abs(i.uv.x)<0.005) pixel = axesColor;
    if(abs(i.uv.y)<0.006) pixel = axesColor;

    return fixed4(pixel, 1.0);
}

Point

for文で線を引く座標を変えることで,等間隔に線を引くことができる.

Tutorial8 座標 軸中心

result_tutorial8.png

fragの外にも記入したため,全文

Tutorial8.shader
Shader "ShaderTutorial/Tutorial8"
{
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        // 追加
        CGINCLUDE
        float mod(float  a, float  b) { return a-b*floor(a/b); } 
        ENDCG


        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                o.uv = v.uv;
                return o;
            }

            // MOVING THE COORDINATE CENTER TO THE CENTER OF THE FRAME
            fixed4 frag (v2f i) : SV_Target
            {
                fixed2 r = 2.0 * fixed2(i.uv.x - 0.5, i.uv.y - 0.5);
                fixed3 backgroundColor = fixed3(1.0, 1.0, 1.0);
                fixed3 axesColor = fixed3(0.0, 0.0, 1.0);
                fixed3 gridColor = fixed3(0.5, 0.5, 0.5);

                fixed3 pixel = backgroundColor;

                const float tickWidth = 0.1;
                if( mod(r.x, tickWidth) < 0.008 ) pixel = gridColor;
                if( mod(r.y, tickWidth) < 0.008 ) pixel = gridColor;

                // Draw the axes
                if(abs(r.x)<0.006) pixel = axesColor;
                if(abs(r.y)<0.007) pixel = axesColor;

                return fixed4(pixel, 1.0);
            }


            ENDCG
        }
    }
}

Point

自前の関数をPassの外側に,CGINCLUDE ~ ENDCG の間に記述している.
このmod関数はaをbで割った余りを返す関数である.
これを使うことで,
if(r.xをtickWidthで割った余り < 0.008) グリッドの色にする.
とすることができている.

また,i.uv.xが0~1の値をとるのに対し,-0.5したものを2倍することによって
r,画面の領域を-1 ~ 1で表すことができる.

Tutorial9 縦横比にあわせる

result_tutorial9.png

Tutorial9.shader
// MAKING THE ASPECT RATIO OF THE COORDINATE SYSTEM 1.0
fixed4 frag (v2f i) : SV_Target
{
    float2 r = 2.0 * (i.uv - 0.5);
    float aspectRatio = _ScreenParams.x / _ScreenParams.y;
    r.x *= aspectRatio;

    fixed3 backgroundColor = fixed3(1.0, 1.0, 1.0);
    fixed3 axesColor = fixed3(0.0, 0.0, 1.0);
    fixed3 gridColor = fixed3(0.5, 0.5, 0.5);

    fixed3 pixel = backgroundColor;

    const float tickWidth = 0.2;
    if( mod(r.x, tickWidth) < 0.008 ) pixel = gridColor;
    if( mod(r.y, tickWidth) < 0.008 ) pixel = gridColor;

    // Draw the axes
    if(abs(r.x)<0.006) pixel = axesColor;
    if(abs(r.y)<0.007) pixel = axesColor;

    return fixed4(pixel, 1.0);
}

Point

r.xに_ScreenParamsから求めたaspectRatioを掛け算することで,縦横の目盛りが同じ長さになる.

Tutorial10 DISK

result_tutorial10.PNG

Tutorial10.shader
// Draw Disks
fixed4 frag (v2f i) : SV_Target
{
    float2 r = 2.0 * (i.uv - 0.5);
    float aspectRatio = _ScreenParams.x / _ScreenParams.y;
    r.x *= aspectRatio;

    fixed3 backgroundColor = fixed3(1.0, 1.0, 1.0);
    fixed3 col1 = fixed3(0.216, 0.471, 0.698); // blue
    fixed3 col2 = fixed3(1.00, 0.329, 0.298); // red
    fixed3 col3 = fixed3(0.867, 0.910, 0.247); // yellow

    fixed3 pixel = backgroundColor;

    //Disk1 blue
    float radius = 0.8;
    if(r.x*r.x + r.y*r.y < radius*radius){
        pixel = col1;
    }

    //Disk2 red
    if(length(r) < 0.3){
        pixel = col3;
    }

    //Disk3 yellow
    float2 center = fixed2(0.9, -0.4);
    float2 d = r - center;
    if( length(d) < 0.6){
        pixel = col2;
    }

    return fixed4(pixel, 1.0);
}

Point

Disk1では,2点間の距離求める公式を2乗することで,半径0.8以内を塗るという処理を行っている.
Disk2では,ベクトルの距離を求めるlength関数を用いることで,短く書いている.
Disk3では,移動させたい分だけ引き算することによって円の中心位置を移動している.
例: 
math
y = (x-3)^2

だと,線がx軸正の方向に3移動する.

Tutorial11 Functionを作る

result_tutorial11.PNG

Tutorial11.shader
Shader "ShaderTutorial/Tutorial11"
{
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        // 追加
        CGINCLUDE
        fixed3 disk(fixed2 r, fixed2 center, fixed radius, fixed3 color, fixed3 pixel){
            fixed3 col = pixel;
            if(length(r - center) < radius){
                col = color;
            }
            return col;
        }
        ENDCG


        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                o.uv = v.uv;
                o.uv.y = 1-o.uv.y;
                return o;
            }

            // Functions
            fixed4 frag (v2f i) : SV_Target
            {
                float2 r = 2.0 * (i.uv - 0.5);
                float aspectRatio = _ScreenParams.x / _ScreenParams.y;
                r.x *= aspectRatio;

                fixed3 backgroundColor = fixed3(0.3, 0.3, 0.3);
                fixed3 col1 = fixed3(0.216, 0.471, 0.698); // blue
                fixed3 col2 = fixed3(1.00, 0.329, 0.298); // red
                fixed3 col3 = fixed3(0.867, 0.910, 0.247); // yellow

                fixed3 pixel = backgroundColor;

                pixel = disk(r, fixed2(0.1, 0.3), 0.5, col3, pixel);
                pixel = disk(r, fixed2(-0.8, -0.6), 1.5, col1, pixel);
                pixel = disk(r, fixed2(0.8, 0.0), 0.15, col2, pixel);


                return fixed4(pixel, 1.0);
            }


            ENDCG
        }
    }
}

Point

関数はCGINCLUDE ~ ENDCG内に記述.
return文が使える.

Tutorial12 STEP

result_tutorial12.PNG

Tutorial12.shader
// BUILT-IN FUNCTION: STEP
fixed4 frag (v2f i) : SV_Target
{
    float2 r = 2.0 * (i.uv - 0.5);
    float aspectRatio = _ScreenParams.x / _ScreenParams.y;
    r.x *= aspectRatio;

    fixed3 backgroundColor = fixed3(0.0, 0.0, 0.0); // black
    fixed3 col1 = fixed3(0.216, 0.471, 0.698); // blue
    fixed3 col2 = fixed3(1.00, 0.329, 0.298); // red
    fixed3 col3 = fixed3(0.867, 0.910, 0.247); // yellow

    fixed3 pixel = backgroundColor;

    float edge, variable, ret;

    // divide the screen into five parts horizontally
    // for different examples
    if(r.x < -0.6 * aspectRatio){ // part1
        variable = r.y;
        edge = 0.2;
        if( variable > edge ){
            ret = 1.0;
        }else{
            ret = 0.0;
        }
    }
    else if(r.x < -0.2 * aspectRatio){ //part2
        variable = r.y;
        edge = -0.2;
        // part1と同じこと
        ret = step(edge, variable); 
    }
    else if(r.x < 0.2 * aspectRatio){
        // 1.0 - step(a,b) で反転
        ret = 1.0 - step(0.5, r.y); 
    }
    else if(r.x < 0.6 * aspectRatio){
        // r.yが-0.4以上でretは0.3 + 0.5 = 0.8
        ret = 0.3 + 0.5 * step(-0.4, r.y);  
    }
    else{
        // stepを二つ使うことでgapを生み出すことができる
        ret = step(-0.3, r.y) * (1.0 - step(0.2, r.y)); 
    }

    pixel = fixed3 (ret, ret, ret);
    return fixed4(pixel, 1.0);
}

Point

名前 説明
step(a,b) bがaをより大きければ1, そうでなければ0

Tutorial13

result_tutorial13.png

Tutorial13.shader
Shader "ShaderTutorial/Tutorial13"
{
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        // 追加
        CGINCLUDE
        #define PI 3.14159
        ENDCG


        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                o.uv = v.uv;
                o.uv.y = 1-o.uv.y;
                return o;
            }

            // BUILT-IN FUNCTION: CLAMP
            fixed4 frag (v2f i) : SV_Target
            {
                float2 r = 2.0 * (i.uv - 0.5);
                float aspectRatio = _ScreenParams.x / _ScreenParams.y;
                r.x *= aspectRatio;

                fixed3 backgroundColor = fixed3(0.0, 0.0, 0.0); // black
                fixed3 col1 = fixed3(0.216, 0.471, 0.698); // blue
                fixed3 col2 = fixed3(1.00, 0.329, 0.298); // red
                fixed3 col3 = fixed3(0.867, 0.910, 0.247); // yellow

                fixed3 pixel = backgroundColor;

                float edge, variable, ret;

                // divide the screen into four parts horizontally
                // for different examples
                if(i.uv.x < 0.25){ // part1
                    ret = i.uv.y;
                }
                else if(i.uv.x < 0.5){ // part2
                    float minVal = 0.3;
                    float maxVal = 0.6;
                    variable = i.uv.y;
                    if (variable < minVal){
                        ret = minVal;
                    }
                    if( variable > minVal && variable < maxVal){
                        ret = variable;
                    }
                    if( variable > maxVal ){
                        ret = maxVal;
                    }
                }
                else if(i.uv.x < 0.75){ // part3
                    float minVal = 0.6;
                    float maxVal = 0.8;
                    variable = i.uv.y;
                    ret = clamp(variable, minVal, maxVal);
                }
                else { // part4
                    float y = cos(5.0 * 2.0 * PI *i.uv.y);
                    y = (y+1.0)*0.5; // map [-1,1] to [0,1]
                    ret = clamp(y, 0.2, 0.8);
                }

                pixel = fixed3 (ret, ret, ret);
                return fixed4(pixel, 1.0);
            }


            ENDCG
        }
    }
}

Point

名前 説明
float Clamp(float a,float min,float max) aがminよりも小さければmin, aがmaxよりも大きければmax, それ以外であればaを返す

Tutorial14 smoothstep

result_tutorial14.png

Tutorial14.shader
// BUILT-IN FUNCTION: SMOOTHSTEP
fixed4 frag (v2f i) : SV_Target
{
    fixed3 backgroundColor = fixed3(0.0, 0.0, 0.0); // black
    fixed3 col1 = fixed3(0.216, 0.471, 0.698); // blue
    fixed3 col2 = fixed3(1.00, 0.329, 0.298); // red
    fixed3 col3 = fixed3(0.867, 0.910, 0.247); // yellow

    fixed3 pixel = backgroundColor;

    float edge, variable, ret;

    // divide the screen into five parts horizontally
    // for different examples
    if(i.uv.x < 1.0/5.0){ // part1
        edge = 0.5;
        ret = step(edge, i.uv.y);
    }
    else if(i.uv.x < 2.0/5.0){ // part2
        float edge0 = 0.45;
        float edge1 = 0.55;
        float t = (i.uv.y - edge0) / (edge1 - edge0);
        //when i.uv.y == edge0 => t = 0.0
        //when i.uv.y == edge1 => t = 1.0
        //0から1に線形に遷移する
        float t1 = clamp(t, 0.0, 1.0);
        //edge0 未満の時は マイナスの値をとり,
        //edge1 より大きい時は1.0より大きい値をとる.
        //しかし,0~1の値がほしいのでclampを使います
        ret = t1;
    }
    else if(i.uv.x < 3.0/ 5.0){ // part3
        float edge0 = 0.45;
        float edge1 = 0.55;
        float t = clamp((i.uv.y - edge0)/(edge1 - edge0), 0.0, 1.0);
        float t1 = 3.0*t*t - 2.0*t*t*t;
        //線形でなくなめらかにする.
        ret = t1;
    }
    else if(i.uv.x < 4.0/5.0){ // part4
        ret = smoothstep(0.45, 0.55, i.uv.y);
    }
    else if(i.uv.x < 5.0/5.0){
        float edge0 = 0.45;
        float edge1 = 0.55;
        float t = clamp((i.uv.y - edge0)/(edge1 - edge0), 0.0, 1.0);
        float t1 = t*t*t*(t*(t*6.0 - 15.0) + 10.0);
        ret = t1;
    }


    pixel = fixed3 (ret, ret, ret);
    return fixed4(pixel, 1.0);
}

Point

名前 説明
float smoothstep(float min, float max, float a) aがminとmaxの間の時に,線形でなく,なめらかに補完するような値を返す.min以下であれば0,max以上で1

Tutorial15 lerp

result_tutorial15.png

Tutorial15.shader
// BUILT-IN FUNCTION: LERP
fixed4 frag (v2f i) : SV_Target
{

    fixed3 backgroundColor = fixed3(0.0, 0.0, 0.0); // black
    fixed3 col1 = fixed3(0.216, 0.471, 0.698); // blue
    fixed3 col2 = fixed3(1.00, 0.329, 0.298); // red
    fixed3 col3 = fixed3(0.867, 0.910, 0.247); // yellow

    fixed3 pixel = backgroundColor;

    fixed3 ret;

    // divide the screen into five parts horizontally
    // for different examples
    if(i.uv.x < 1.0/5.0){ // part1
        float x0 = 0.2;
        float x1 = 0.7;
        float m = 0.1;
        float val = x0 * (1.0-m) + x1*m;
        ret = fixed3(val, val, val);
    }
    else if(i.uv.x < 2.0/5.0){ // part2
        float x0 = 0.2;
        float x1 = 0.7;
        float m = i.uv.y;
        float val = x0*(1.0-m) + x1*m;
        ret = fixed3(val, val, val);
    }
    else if(i.uv.x < 3.0/ 5.0){ // part3
        float x0 = 0.2;
        float x1 = 0.7;
        float m = i.uv.y;
        float val = lerp(x0, x1, m);
        ret = fixed3(val, val, val);

    }
    else if(i.uv.x < 4.0/5.0){ // part4
        float m = i.uv.y;
        ret = lerp(col1, col2, m);
    }
    else if(i.uv.x < 5.0/5.0){
        //smoothstepとlerpを使った色の遷移
        float m = smoothstep(0.5, 0.6, i.uv.y);
        ret = lerp(col1, col2, m);
    }


    pixel = ret;
    return fixed4(pixel, 1.0);
}

Point

名前 説明
float lerp(a,b,s) a+s(b-a)を返す.aからbへの線形補完 sは基本0~1で使う

Tutorial16 COLOR ADDITION AND SUBSTRCTION

result_tutorial16.png

Tutorial16.shader
Shader "ShaderTutorial/Tutorial18"
{
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        // 追加
        CGINCLUDE
        // なめらかなDISK
        float disk(float2 r, float2 center, float radius){
            float distanceFromCenter = length(r - center);
            float outsideOfDisk = smoothstep(radius - 0.005, radius + 0.005, distanceFromCenter);
            float insideOfDisk = 1.0 - outsideOfDisk;
            return insideOfDisk;

        }
        ENDCG


        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                o.uv = v.uv;
                o.uv.y = 1-o.uv.y;
                return o;
            }

            // ANTI-ALIASING WITH SMOOTHSTEP
            fixed4 frag (v2f i) : SV_Target
            {
                float2 r = 2.0 * (i.uv - 0.5);
                float aspectRatio = _ScreenParams.x / _ScreenParams.y;
                r.x *= aspectRatio;

                fixed3 black = float3(0.0, 0.0, 0.0); // black
                fixed3 white = float3(1.0, 1.0, 1.0);
                fixed3 gray = float3(0.3, 0.3, 0.3);
                fixed3 col1 = float3(0.216, 0.471, 0.698); // blue
                fixed3 col2 = float3(1.00, 0.329, 0.298); // red
                fixed3 col3 = float3(0.867, 0.910, 0.247); // yellow

                fixed3 ret;
                fixed3 pixel;
                float d;


                if(i.uv.x < 1.0/3.0){ // part1
                    ret = gray;
                    d = disk(r, float2(-1.1, 0.3), 0.4);
                    ret = lerp(ret, col1, d);
                    d = disk(r, float2(-1.3, 0.0), 0.4);
                    ret = lerp(ret, col2, d);
                    d = disk(r, float2(-1.05, -0.3), 0.4);
                    ret = lerp(ret, col3, d);
                }
                else if(i.uv.x < 2.0/3.0){ // part2
                    // Color addition
                    ret = black;
                    ret += disk(r, float2(0.1, 0.3), 0.4) * col1;
                    ret += disk(r, float2(-0.1, 0.0), 0.4) * col2;
                    ret += disk(r, float2(0.15, -0.3), 0.4) * col3;
                }
                else if(i.uv.x < 3.0/ 3.0){ // part3
                    // Color substraction
                    ret = white;
                    ret -= disk(r, float2(1.1, 0.3), 0.4) * col1;
                    ret -= disk(r, float2(1.05, 0.0), 0.4) * col2;
                    ret -= disk(r, float2(1.35, -0.25), 0.4) * col3;

                }



                pixel = ret;
                return fixed4(pixel, 1.0);
            }


            ENDCG
        }
    }
}

Point

円の境界をなめらかにしている.
ret に加算減算することで色を変化させている.

Tutorial17 回転

result_tutorial17.PNG

Tutorial17.shader
Shader "ShaderTutorial/Tutorial17"
{
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        // 追加
        CGINCLUDE

        #define PI 3.14159

        // (anti-aliased)Gridを作る関数
        float coordinateGrid(float2 r){
            float3 axisCol = float3(0.0, 0.0, 1.0);
            float3 gridCol = float3(0.5, 0.5, 0.5);
            float ret = 0.0;

            // Draw grid lines
            const float tickWidth = 0.1;
            for(float i= -2.0;i<2.0; i+= tickWidth){
                ret += 1.0 - smoothstep(0.0, 0.008, abs (r.x - i));
                ret += 1.0 - smoothstep(0.0, 0.008, abs (r.y - i));
            }

            // Draw the axis
            ret += 1.0-smoothstep(0.001, 0.015, abs(r.x));
            ret += 1.0-smoothstep(0.001, 0.015, abs(r.y));
            return ret;
        }

        // returns 1.0 if inside circle
        float disk(float2 r, float2 center, float radius){
            return 1.0 - smoothstep( radius - 0.005, radius + 0.005, length(r - center));
        }

        // returns 1.0 if inside the disk
        float rectangle(float2 r, float2 bottomLeft, float2 topRight){
            float ret;
            float d = 0.005;
            ret = smoothstep(bottomLeft.x - d, bottomLeft.x + d, r.x);
            ret *= smoothstep(bottomLeft.y - d, bottomLeft.y + d, r.y);
            ret *= 1.0 - smoothstep(topRight.y - d, topRight.y + d, r.y);
            ret *= 1.0 - smoothstep(topRight.x - d, topRight.x + d, r.x);
            return ret;
        }
        ENDCG


        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                o.uv = v.uv;
                o.uv.y = 1-o.uv.y;
                return o;
            }

            //COORDINATE TRANSFORMATIONS: ROTATION
            fixed4 frag (v2f i) : SV_Target
            {
                float2 r = 2.0 * (i.uv - 0.5);
                float aspectRatio = _ScreenParams.x / _ScreenParams.y;
                r.x *= aspectRatio;

                fixed3 bgCol = float3(1.0, 1.0, 1.0); // white

                fixed3 col1 = float3(0.216, 0.471, 0.698); // blue
                fixed3 col2 = float3(1.00, 0.329, 0.298); // red
                fixed3 col3 = float3(0.867, 0.910, 0.247); // yellow

                fixed3 ret;
                float2 q;
                float angle;
                angle = 0.2*PI; // 単位はラジアン
                // 2次元の回転
                q.x = cos(angle)*r.x + sin(angle)*r.y;
                q.y = -sin(angle)*r.x + cos(angle)*r.y;

                ret = bgCol;
                // draw the old and new coordinate systems
                ret = lerp(ret, col1, coordinateGrid(r)*0.4);
                ret = lerp(ret, col2, coordinateGrid(q));

                // draw shapes
                ret = lerp(ret, col1, disk(r, float2(1.0, 0.0), 0.2));
                ret = lerp(ret, col2, disk(q, float2(1.0, 0.0), 0.2));
                ret = lerp(ret, col1, rectangle(r, float2(-0.8, 0.2),float2(-0.5, 0.4)));
                ret = lerp(ret, col2, rectangle(q, float2(-0.8, 0.2),float2(-0.5, 0.4)));



                fixed3 pixel = ret;
                return fixed4(pixel, 1.0);
            }


            ENDCG
        }
    }
}

Point

回転行列をrに掛け算することで,座標を回転させ,その座標上の図形も回転させている.

Tutorial18 スケーリング

result_tutorial18.PNG

Tutorial18.shader
Shader "ShaderTutorial/Tutorial18"
{
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        // 追加
        CGINCLUDE

        #define PI 3.14159

        // (anti-aliased)Gridを作る関数
        float coordinateGrid(float2 r){
            float3 axisCol = float3(0.0, 0.0, 1.0);
            float3 gridCol = float3(0.5, 0.5, 0.5);
            float ret = 0.0;

            // Draw grid lines
            const float tickWidth = 0.1;
            for(float i= -2.0;i<2.0; i+= tickWidth){
                ret += 1.0 - smoothstep(0.0, 0.008, abs (r.x - i));
                ret += 1.0 - smoothstep(0.0, 0.008, abs (r.y - i));
            }

            // Draw the axis
            ret += 1.0-smoothstep(0.001, 0.015, abs(r.x));
            ret += 1.0-smoothstep(0.001, 0.015, abs(r.y));
            return ret;
        }

        // returns 1.0 if inside circle
        float disk(float2 r, float2 center, float radius){
            return 1.0 - smoothstep( radius - 0.005, radius + 0.005, length(r - center));
        }

        // returns 1.0 if inside the disk
        float rectangle(float2 r, float2 bottomLeft, float2 topRight){
            float ret;
            float d = 0.005;
            ret = smoothstep(bottomLeft.x - d, bottomLeft.x + d, r.x);
            ret *= smoothstep(bottomLeft.y - d, bottomLeft.y + d, r.y);
            ret *= 1.0 - smoothstep(topRight.y - d, topRight.y + d, r.y);
            ret *= 1.0 - smoothstep(topRight.x - d, topRight.x + d, r.x);
            return ret;
        }
        ENDCG


        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                o.uv = v.uv;
                o.uv.y = 1-o.uv.y;
                return o;
            }

            //COORDINATE TRANSFORMATIONS: SCALING
            fixed4 frag (v2f i) : SV_Target
            {
                float2 r = 2.0 * (i.uv - 0.5);
                float aspectRatio = _ScreenParams.x / _ScreenParams.y;
                r.x *= aspectRatio;

                fixed3 bgCol = float3(1.0, 1.0, 1.0); // white

                fixed3 col1 = float3(0.216, 0.471, 0.698); // blue
                fixed3 col2 = float3(1.00, 0.329, 0.298); // red
                fixed3 col3 = float3(0.867, 0.910, 0.247); // yellow

                fixed3 ret;
                ret = bgCol;

                // original
                ret = lerp(ret, col1, coordinateGrid(r)/2.0);

                // scaled
                float2 q = 0.3*r;
                ret = lerp(ret, col2, coordinateGrid(q));

                // draw shapes
                ret = lerp(ret, col2, disk(q, float2(0.0, 0.0), 0.1)); //大
                ret = lerp(ret, col1, disk(r, float2(0.0, 0.0), 0.1));

                ret = lerp(ret, col1, rectangle(r, float2(-0.5, 0.0),float2(-0.2, 0.2)));
                ret = lerp(ret, col2, rectangle(q, float2(-0.5, 0.0),float2(-0.2, 0.2))); //大



                fixed3 pixel = ret;
                return fixed4(pixel, 1.0);
            }


            ENDCG
        }
    }
}

Point

rに係数をかけることで,拡大・縮小できる.(0.3をかけることで,大きくなっている.)

Tutorial19 Transform

result_tutorial19.PNG

Tutorial19.shader
Shader "ShaderTutorial/Tutorial19"
{
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        // 追加
        CGINCLUDE

        #define PI 3.14159

        // (anti-aliased)Gridを作る関数
        float coordinateGrid(float2 r){
            float3 axisCol = float3(0.0, 0.0, 1.0);
            float3 gridCol = float3(0.5, 0.5, 0.5);
            float ret = 0.0;

            // Draw grid lines
            const float tickWidth = 0.1;
            for(float i= -2.0;i<2.0; i+= tickWidth){
                ret += 1.0 - smoothstep(0.0, 0.008, abs (r.x - i));
                ret += 1.0 - smoothstep(0.0, 0.008, abs (r.y - i));
            }

            // Draw the axis
            ret += 1.0-smoothstep(0.001, 0.015, abs(r.x));
            ret += 1.0-smoothstep(0.001, 0.015, abs(r.y));
            return ret;
        }

        // returns 1.0 if inside circle
        float disk(float2 r, float2 center, float radius){
            return 1.0 - smoothstep( radius - 0.005, radius + 0.005, length(r - center));
        }

        // returns 1.0 if inside the disk
        float rectangle(float2 r, float2 bottomLeft, float2 topRight){
            float ret;
            float d = 0.005;
            ret = smoothstep(bottomLeft.x - d, bottomLeft.x + d, r.x);
            ret *= smoothstep(bottomLeft.y - d, bottomLeft.y + d, r.y);
            ret *= 1.0 - smoothstep(topRight.y - d, topRight.y + d, r.y);
            ret *= 1.0 - smoothstep(topRight.x - d, topRight.x + d, r.x);
            return ret;
        }
        ENDCG


        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                o.uv = v.uv;
                o.uv.y = 1-o.uv.y;
                return o;
            }

            //COORDINATE TRANSFORMATIONS
            fixed4 frag (v2f i) : SV_Target
            {
                float2 r = 2.0 * (i.uv - 0.5);
                float aspectRatio = _ScreenParams.x / _ScreenParams.y;
                r.x *= aspectRatio;

                fixed3 bgCol = float3(1.0, 1.0, 1.0); // white

                fixed3 col1 = float3(0.216, 0.471, 0.698); // blue
                fixed3 col2 = float3(1.00, 0.329, 0.298); // red
                fixed3 col3 = float3(0.867, 0.910, 0.247); // yellow

                fixed3 ret;
                ret = bgCol;

                float angle = -0.6;
                float2x2 rotationMatrix = float2x2(cos(angle), -sin(angle),
                                                sin(angle), cos(angle));


                if(i.uv.x < 1.0/2.0) //part1
                {
                    //座標の中心をuv.x: 1/4の位置にする。
                    r = r - float2(-aspectRatio/2.0, 0);
                    float2 rotated = mul(rotationMatrix, r);
                    float2 rotatedTranslated = rotated - float2(0.4, 0.5);
                    ret = lerp(ret, col1, coordinateGrid(r) * 0.3);
                    ret = lerp(ret, col2, coordinateGrid(rotated)*0.3);
                    ret = lerp(ret, col3, coordinateGrid(rotatedTranslated)*0.3);

                    ret = lerp(ret, col1, rectangle(r, float2(-0.1, -0.2), float2(0.1, 0.2)));
                    ret = lerp(ret, col2, rectangle(rotated, float2(-0.1, -0.2), float2(0.1, 0.2)));
                    ret = lerp(ret, col3, rectangle(rotatedTranslated, float2(-0.1, -0.2), float2(0.1, 0.2)));
                }
                else if(i.uv.x < 2.0/2.0){ //part2
                    //座標の中心をuv.x: 1/4の位置にする。
                    r = r - float2(aspectRatio/2.0, 0);
                    float2 translated = r - float2(0.4, 0.5);
                    float2 translatedRotated = mul(rotationMatrix, translated);

                    ret = lerp(ret, col1, coordinateGrid(r) * 0.3);
                    ret = lerp(ret, col2, coordinateGrid(translated)*0.3);
                    ret = lerp(ret, col3, coordinateGrid(translatedRotated)*0.3);

                    ret = lerp(ret, col1, rectangle(r, float2(-0.1, -0.2), float2(0.1, 0.2)));
                    ret = lerp(ret, col2, rectangle(translated, float2(-0.1, -0.2), float2(0.1, 0.2)));
                    ret = lerp(ret, col3, rectangle(translatedRotated, float2(-0.1, -0.2), float2(0.1, 0.2)));
                }




                fixed3 pixel = ret;
                return fixed4(pixel, 1.0);
            }


            ENDCG
        }
    }
}

Point

float2x2で,2かける2の正方行列を示す.これによって回転行列を表現し,mul関数によって行列の掛け算を行っている.

Tutorial20 Animations

result_tutorial21.gif

Tutorial20.shader
Shader "ShaderTutorial/Tutorial20"
{
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        // 追加
        CGINCLUDE

        #define PI 3.14159

        // (anti-aliased)Gridを作る関数
        float coordinateGrid(float2 r){
            float3 axisCol = float3(0.0, 0.0, 1.0);
            float3 gridCol = float3(0.5, 0.5, 0.5);
            float ret = 0.0;

            // Draw grid lines
            const float tickWidth = 0.1;
            for(float i= -2.0;i<2.0; i+= tickWidth){
                ret += 1.0 - smoothstep(0.0, 0.008, abs (r.x - i));
                ret += 1.0 - smoothstep(0.0, 0.008, abs (r.y - i));
            }

            // Draw the axis
            ret += 1.0-smoothstep(0.001, 0.015, abs(r.x));
            ret += 1.0-smoothstep(0.001, 0.015, abs(r.y));
            return ret;
        }

        // returns 1.0 if inside circle
        float disk(float2 r, float2 center, float radius){
            return 1.0 - smoothstep( radius - 0.005, radius + 0.005, length(r - center));
        }

        // returns 1.0 if inside the rect
        float rectangle(float2 r, float2 bottomLeft, float2 topRight){
            float ret;
            float d = 0.005;
            ret = smoothstep(bottomLeft.x - d, bottomLeft.x + d, r.x);
            ret *= smoothstep(bottomLeft.y - d, bottomLeft.y + d, r.y);
            ret *= 1.0 - smoothstep(topRight.y - d, topRight.y + d, r.y);
            ret *= 1.0 - smoothstep(topRight.x - d, topRight.x + d, r.x);
            return ret;
        }

        float mod(float  a, float  b) { return a-b*floor(a/b); } 
        ENDCG


        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
                o.uv = v.uv;
                o.uv.y = 1-o.uv.y;
                return o;
            }

            //ANIMATION
            fixed4 frag (v2f i) : SV_Target
            {
                float2 r = 2.0 * (i.uv - 0.5);
                float aspectRatio = _ScreenParams.x / _ScreenParams.y;
                r.x *= aspectRatio;

                fixed3 bgCol = float3(1.0, 1.0, 1.0); // white

                fixed3 col1 = float3(0.216, 0.471, 0.698); // blue
                fixed3 col2 = float3(1.00, 0.329, 0.298); // red
                fixed3 col3 = float3(0.867, 0.910, 0.247); // yellow

                fixed3 ret;
                ret = bgCol;

                float angle = -0.6;
                float2x2 rotationMatrix = float2x2(cos(angle), -sin(angle),
                                                sin(angle), cos(angle));


                if(i.uv.x < 1.0/5.0) // part1
                {
                    float2 q = r + float2(aspectRatio*4.0/5.0, 0);

                    ret = fixed3(0.3, 0.3, 0.3);
                    //時間は_Time.yで取得できる
                    float y = _Time.y;

                    //yを-1 ~ 1の値にする
                    y = mod(y,2.0) -1.0;
                    ret = lerp(ret, col1, disk(q, float2(0.0, y), 0.1));
                }
                else if(i.uv.x < 2.0/5.0) //part2
                {
                    float2 q = r + float2(aspectRatio*2.0/5.0, 0);
                    ret = fixed3(0.4, 0.4, 0.4);
                    //振幅
                    float amplitude = 0.8;
                    float y = 0.8 * sin(0.5*_Time.y* 2.0 * PI);
                    float radius = 0.15 + 0.05 * sin(_Time.y * 8.0);
                    ret = lerp(ret, col1, disk(q, float2(0.0, y), radius));
                }
                else if(i.uv.x < 3.0/5.0) //part3
                {
                    float2 q = r + float2(aspectRatio*0/5.0, 0);
                    ret = float3(0.5, 0.5, 0.5);

                    float x = 0.2*cos(_Time.y*5.0);
                    float y = 0.3*sin(_Time.y*5.0);
                    float radius = 0.2 + 0.1*sin(_Time.y*2.0);
                    fixed3 color = lerp(col1, col2, sin(_Time.y)*0.5 + 0.5);
                    ret = lerp(ret, color, rectangle(q, float2(x-0.1, y-0.1), float2(x+0.1, y+0.1)));
                }
                else if(i.uv.x < 4.0/5.0) //part4
                {
                    float2 q = r + float2(-aspectRatio*2.0/5.0, 0);
                    ret = float3(0.4, 0.4, 0.4);

                    for(float i=-1.0; i<1.0; i+= 0.2)
                    {
                        float x = 0.2 * cos(_Time.y*5.0 + i*PI);
                        float y = i;

                        float2 s = q - float2(x, y);
                        float angle = _Time.y * 3.0 + i;
                        float2x2 rot = float2x2(cos(angle), -sin(angle),
                                                sin(angle),  cos(angle));
                        s = mul(rot, s);
                        ret = lerp(ret, col1, rectangle(s, float2(-0.06, -0.06), float2(0.06, 0.06)));
                    }
                }
                else if(i.uv.x < 5.0/5.0) //part5
                {
                    float2 q = r + float2(-aspectRatio*4.0/5.0, 0);
                    ret = float3(0.3, 0.3, 0.3);

                    float speed = 2.0;
                    float t = _Time.y * speed;
                    float stopEveryAngle = PI / 2.0;
                    float stopRatio = 0.5;
                    //0.5<frac(t)<1の時,t1は一定となる。そこで止まっている。
                    float t1 = (floor(t) + smoothstep(0.0, 1.0 - stopRatio, frac(t)))*stopEveryAngle;

                    float x = -0.2*cos(t1);
                    float y = 0.3 * sin(t1);
                    float dx = 0.1 + 0.03 * sin(t*10.0);
                    float dy = 0.1 + 0.03 * sin(t*10.0+PI);
                    ret = lerp(ret, col1, rectangle(q, float2(x-dx, y-dy), float2(x+dx, y+dy)));


                }


                fixed3 pixel = ret;
                return fixed4(pixel, 1.0);
            }


            ENDCG
        }
    }
}

Point

_Time.yで時間を取得できる.

Tutorial21 Plasma

result_tutorial21.PNG

Tutorial21.shader
//Plasma
fixed4 frag (v2f i) : SV_Target
{
    float2 r = 2.0 * (i.uv - 0.5);
    float aspectRatio = _ScreenParams.x / _ScreenParams.y;
    r.x *= aspectRatio;
    float t = _Time.y;
    r = r*8.0;

    float v1 = sin(r.x + t);
    float v2 = sin(r.y + t);
    float v3 = sin(r.x + r.y + t);
    float v4 = sin(sqrt(r.x*r.x + r.y*r.y) + 1.7*t);
    float v = v1 + v2 + v3 + v4;
    fixed3 ret;

    if(i.uv.x < 1.0 / 10.0) // part1
    {
        //vertical waves
        ret = float3(v1, v1, v1);
    }
    else if(i.uv.x < 2.0/10.0) // part2
    {
        // horizontal waves;
        ret = float3(v2, v2, v2);
    }
    else if(i.uv.x < 3.0/10.0) // part3
    {
        // diagonal waves
        ret = float3(v3, v3, v3);
    }
    else if(i.uv.x < 4.0/10.0) // part4
    {
        // circular waves
        ret = float3(v4, v4, v4);
    }
    else if(i.uv.x < 5.0/10.0) // part5
    {
        // the sum of all waves
        ret = float3(v, v, v);
    }
    else if(i.uv.x < 6.0/10.0) // part6
    {
        // Add periodicity to the gradients
        ret = float3(sin(2.0 * v), sin(2.0 * v), sin(2.0 * v));
    }
    else if(i.uv.x < 10.0/10.0) // part7
    {
        // mix colors
        v *= 1.0;
        ret = float3(sin(v), sin(v+0.5*PI), sin(v+1.0*PI));
    }

    ret = 0.5 + 0.5 * ret;

    fixed3 pixel = ret;
    return fixed4(pixel, 1.0);
}

Point

sin,cosと_Time.yを組み合わせると周期的な模様ができる.

50
43
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
50
43