NinaLabo

個人ゲーム開発者の技術メモ

【memo6】フラグメントシェーダーで四角形を描く(Unity)

【今日のまとめ】

・足しても掛けても四角形は描ける模様

 

------------------------------------

Unity でゲームは作っていますが、Shader も 画像処理も初心者です。

アウトプットばかりだと腐っていくので、毎日1時間程度は自分の知らないことを少しずつインプットしていこうかと思ってます。

タイトルに【memo】とあるものはほぼ自分用の備忘録なので他の記事よりも殴り書きなのはご容赦ください。

------------------------------------

 

 

前回は黒い円を描きました。

f:id:ninagreen:20180919192749p:plain

「まる」の次は「さんかく」を描きたい!と思ったのですが、どう書いたら良いかよくわらかなかったのでまずは簡単そうな四角にしたいと思います。

 

前回のstep関数を使えばできそう。 

            float4 frag_test (v2f_img i) : SV_Target
            {
                float d = step(i.uv.x, 0.2) + step (0.8, i.uv.x) + step(i.uv.y, 0.2) + step (0.8, i.uv.y);
                return d;
            }

 

四角形の周囲の領域 (x <= 0.2 || x >= 0.8|| y <= 0.2 || y >= 8) が 1以上(白)になるように足してみました。一応うまくいってるっぽい。

f:id:ninagreen:20180920193857p:plain

 

あ、いやよく見ると、隅の部分がなんかはみ出してて汚い。clamp しないとダメですかね。

float4 frag_test (v2f_img i) : SV_Target
{
    float d = clamp(step(i.uv.x, 0.2) + step (0.8, i.uv.x) + step(i.uv.y, 0.2) + step (0.8, i.uv.y), 01);
    return d;
}

綺麗になった!

f:id:ninagreen:20180920195227p:plain

 

もう少し簡潔に書けそうです。

 step関数にはfloatNのvector型を渡すこともできて、それぞれのpropertyごとに計算してくれるっぽいです。

            float4 frag_test (v2f_img i) : SV_Target
            {
                float2 d = step(i.uv, float2(0.20.2)) + step (float2(0.80.8), i.uv);
                return clamp(d.x + d.y, 01);
            } 

 というか、xもyも同じ値であればこうするほうがもっと簡潔かも。

            float4 frag_test (v2f_img i) : SV_Target
            {
                float2 d = step(i.uv, 0.2) + step (0.8, i.uv);
                return clamp(d.x + d.y, 01);
            }

 

黒い四角じゃなくて青い四角もできますね

            float4 frag_test (v2f_img i) : SV_Target
            {
                float2 d = step(i.uv, 0.2) + step (0.8, i.uv);
                return d.x + d.y >= 1 ? 1 : float4(0011);
            }

f:id:ninagreen:20180921184223p:plain

 

 調べてたら、四角形を書いているコードを他にも発見

nn-hokuson.hatenablog.com

 

まったく別のアプローチですね。まず、こういう画像を作って、

            float4 frag_test (v2f_img i) : SV_Target
            {
                fixed2 size = fixed2(0.3,0.1); // 中心の四角形のサイズ(横、縦の長さ)を定義

 

                 // 四角形の左下の座標を取得(中心座標からサイズの半分をマイナスした箇所)
                fixed2 leftbottom = fixed2(0.5,0.5) - size * 0.5;

 

                // leftbottom <= i.uv ならば1 (四角形の左下座標より右上にいる場合は白にする)
                fixed2 uv = step(leftbottom, i.uv); 

 

                return uv.x*uv.y; // x=1&&y=1の場合のみ塗りつぶす
            }

f:id:ninagreen:20180921185437p:plain

 

こういうコードで上下左右した画像ができるから、

           float4 frag_test (v2f_img i) : SV_Target
            {
                fixed2 size = fixed2(0.3,0.1);
                fixed2 leftbottom = fixed2(0.5,0.5) - size * 0.5;
                fixed2 uv = step(leftbottom, 1 - i.uv); // 1 - i.uv にすると上下左右反転できる
                return uv.x*uv.y;
            } 

f:id:ninagreen:20180921185626p:plain

 

それを掛け算で掛け合わせると四角ができますってことだと思う

            float4 frag_test (v2f_img i) : SV_Target
            {
                fixed2 size = fixed2(0.3,0.1);
                fixed2 leftbottom = fixed2(0.5,0.5) - size * 0.5;
                fixed2 uv = step(leftbottom, i.uv);
                uv *= step(leftbottom, 1 - i.uv);
                return uv.x*uv.y;
            }

f:id:ninagreen:20180921185834p:plain

 

最後反転すれば白い背景の黒い四角になりますね

            float4 frag_test (v2f_img i) : SV_Target
            {
                fixed2 size = fixed2(0.3,0.1);
                fixed2 leftbottom = fixed2(0.5,0.5) - size * 0.5;
                fixed2 uv = step(leftbottom, i.uv);
                uv *= step(leftbottom, 1 - i.uv);
                return 1 - uv.x*uv.y;
            }

f:id:ninagreen:20180921190017p:plain

 

 他にも色々なアプローチがありそうですが、四角形はひとまずここまで。

【memo5】シェーダーで step 関数を使ってみる(Unity)

【今日のまとめ】

・フラグメントシェーダーで if 文 は遅いらしい

・if 文 の代わりに step関数が使える。ただし、順序や不等号は要注意。

x >= edge x <= edge x > edge x < edge
step(edge,x) step(x,edge) 1.0 - step(edge,x) 1.0 - step(x,edge)

 

------------------------------------

Unity でゲームは作っていますが、Shader も 画像処理も初心者です。

アウトプットばかりだと腐っていくので、毎日1時間程度は自分の知らないことを少しずつインプットしていこうかと思ってます。

タイトルに【memo】とあるものはほぼ自分用の備忘録なので他の記事よりも殴り書きなのはご容赦ください。

------------------------------------

 

 

前回は下記資料を参考にdistance関数を使ってみました。

docs.google.com

 

今日のお題は黒い円です。写経だけだと頭を使わないので、そろそろ資料のコードをあまり見ずに作ってみようかと思います

 

*ドリル1: 黒い円 (Shader3Scene)

f:id:ninagreen:20180919192749p:plain

前回は下記の画像の状態ができたわけだけから、それを応用して距離が一定の閾値内は黒、それ以上は白にすればできそう

f:id:ninagreen:20180919193001p:plain

 

ってことでこれでいいんじゃない?

と思ったら、数字のfloatを表すfはいらないらしい

            float4 frag_test (v2f_img i) : SV_Target
            {
                float d = distance(float2(0.50.5), i.uv);
                return d > 0.5 ? 1f : 0f;
            }

 

こんな感じで、

            float4 frag_test (v2f_img i) : SV_Target
            {
                float d = distance(float2(0.50.5), i.uv);
                return d > 0.5 ? 1 : 0;
            }

こうなりました。簡単。シェーダーも三項演算子使えるんですね。

f:id:ninagreen:20180919193527p:plain

 

別にif文でもいいけどね、と思っていたら、どうもシェーダーだとif分は遅いとか?え・・・C#の世界では想像もつかない・・・

light11.hatenadiary.com

qiita.com

 

if文の代わりにstep関数を使うほうがいいらしい。

step (DirectX HLSL)

 

step(edge, value)

value が edge 以上の場合は1、それ以外は0

 

なので、先ほどのを書き換えるとこうですかね。

            float4 frag_test (v2f_img i) : SV_Target
            {
                float valuedistance(float2(0.50.5), i.uv);
                return 1 - step(value0.5);
            }

 

わかりにくい・・・

x < edge が step (x,edge) であるほうが個人的にはわかりやすいですが、逆なんですよね・・この対応表がわかりやすいですが、覚えられる自信がなく・・何回も調べてしまいそうです・・

 

x >= edge x <= edge x > edge x < edge
step(edge,x) step(x,edge) 1.0 - step(edge,x) 1.0 - step(x,edge)

 

 

短いですが、今日はここまで。 

【memo4】float4 って何?(Unity)

【今日のまとめ】Shader2Scene

・float4 は ベクトル型

(Unity の シェーダー言語 のベースとなる HLSL 言語では、基本的な文法はC/C++に準ずるが、グラフィックスプログラムを記述するのに適した専用のベクトル・行列型や関数を備えている)

 

------------------------------------

Unity でゲームは作っていますが、Shader も 画像処理も初心者です。

アウトプットばかりだと腐っていくので、毎日1時間程度は自分の知らないことを少しずつインプットしていこうかと思ってます。

タイトルに【memo】とあるものはほぼ自分用の備忘録なので他の記事よりも殴り書きなのはご容赦ください。

------------------------------------

 

今日は昨日の解決してない疑問を調べるところから

関数の戻り値はfloat4なのにfloatで返していいの?

ninagreen.hatenablog.com

 

まずは、C#だと見慣れない float4 ってどういうこと?

 

調べてみると float4 はベクトル型らしいです

ベクトル型 (DirectX HLSL)

2 つの部分で構成される単一の名前。1 つめの部分では、スカラー型のいずれかを指定します。2 つ目の部分では、成分の数を指定します。その値は 1 ~ 4 の範囲内である必要があります。

つまり、float4は、floatというスカラー型に成分の数(4)を付加したベクトル型ってことみたい。

 

宣言は

float4 fVector = { 0.2f0.3f0.4f1.0f };

でも

vector <float4> fVector = { 1.0f0.3f0.4f1.0f };

でもいいらしい(後者は書かないだろうけど)

 

あと、初期化は

float4 fVector = { 0.2f0.3f0.4f1.0f };

でもいいし、

float4 fVector = float4(1.0f0.5f1.0f1.0f);

とも書けるらしい。ちなみに、C#の勢いで new float4 って書くとエラーでした。

 

あと、ベクトル型へのアクセスは、xyzwだけじゃなく、rgbaでもアクセスできるらしい。独特ですねー

float4 data = float4(1.0f0.5f0.0f1.0f);

 

// result1 と result2 は同じ結果になる
float4 result1 = float4(data.x, data.y, data.z, data.w);
float4 result2 = float4(data.r, data.g, data.b, data.a);

 

あとは抜き出したい成分だけを連続で順序も自由に記述できる。これは便利。C#にもあればいいのに。

float4 pos = float4(1,2,3,4);

float2 f_2D;

f_2D = pos.xy; // float2(1, 2)と同じ

f_2D = pos.xz; // float2(1, 3)と同じ

f_2D = pos.zx; // float2(3, 1)と同じ

f_2D = pos.xx; // float2(1, 1)と同じ

あとはこんなのも書けるらしい。

float2 p;
p.xy = 0;

こう書くと 変数 p の x と y の両方に同時に 0 を入れることができるっぽい。C#的には xy という変数に 0 を代入してるようにしか見えないですね・・・

 

こんなこともできるみたい

float4 pos = float4(1,2,3,4);

float4 f_4D;

f_4D = pos; // float4(1,2,3,4)と同じ

f_4D.xz = pos.xz; // float4(1,0,3,0)と同じ

f_4D.zx = pos.xz; // float4(3,0,1,0)と同じ

 

あ、こんなのもある

f_4D.xyzw = pos.w; // float4(3,3,3,3)と同じ

 

ここからは推測だけど、↑がありなら

f_4D.xyzw = 3;

と書くこともできて、

f_4D = 3;

とxyzwを省略して書くこともできるってことじゃないだろうか・・?

 

つまり、

関数の戻り値はfloat4なのにfloatで返していいの?

は良いってことになり、

float値がxyzwに代入されたfloat4を返してるの同義であると、一旦自分の中で理解することにします。

 

【memo3】フラグメントシェーダーで distance を使ってみる(Unity)

【今日のまとめ】Shader2Scene

・SV_TARGET は フラグメントシェーダーのセマンティクスの1つで、戻り値に色を返すことを意味している

・シェーダーでは距離を取得するのに distance という組み込み関数が使える

 

 

------------------------------------

Unity でゲームは作っていますが、Shader も 画像処理も初心者です。

アウトプットばかりだと腐っていくので、毎日1時間程度は自分の知らないことを少しずつインプットしていこうかと思ってます。

タイトルに【memo】とあるものはほぼ自分用の備忘録なので他の記事よりも殴り書きなのはご容赦ください。

------------------------------------

 

今日はDistanceを使ったお絵描き!

docs.google.com

 

前回のfrag_testの中身をこういう感じに書き換えると

            float4 frag_test (v2f_img i) : SV_Target
            {
                float d = distance(float2(0.50.5), i.uv);
                return d;
            }

こうなるらしい。

f:id:ninagreen:20180912190223p:plain

 

ここで疑問が・・・

中心座標(0.5, 0.5)と引数で渡されたuv座標の距離を取得してると思われるが、

dには何が入ってくるの?関数の戻り値はfloat4なのにfloatで返していいの?前回忘れてたけど、SV_Targetって何?

 

dには何が入ってくるの?

dの値を直接見たいんだけど、シェーダーでコンソールでログ出力ってどうするの?

 

Unity フォーラムで質問してる人発見

https://forum.unity.com/threads/how-to-print-shaders-var-please.26052/

 

I guess that sfkdkjjj want to print value of variable inside vertex/pixel shader.

Usually in shaders You use colours or similar tricks to debbug your variables. It is not possible to see value directly.

You can use Pix to see exact values. But it will not be what you expect. This is not even close to usual debbuging.

え、待って、値を直接見ることは not possible !?まじかー

色とかを表示して、擬似的にデバッグするって、まじかー

 

色から推測すると、dは中心は黒(0)で、遠くなるほど値が大きくなって白(1)に近づいているってことだと思う。たぶん。各頂点は、a x a + b x b = c x c に当てはめると c = √(0.5x0.5 + 0.5x0.5) = 0.7ぐらい。たぶん。

 

関数の戻り値はfloat4なのにfloatで返していいの?

調べて見たけどよくわからず。もう時間なので明日に持ち越し。

 

SV_Targetって何?

セマンティクスなるものらしい

qiita.com

セマンティクスとは、シェーダープログラムの入力や出力の値が、何を意味するかを表すためのもの。型が、値の表現の幅(最大値は何か、実数か小数か、スカラーかベクトルか、…)を表すのに対して、セマンティクスは、値の用途(位置か、法線か、色か…)を表すイメージ

ちなみに、SV_TARGET は ピクセルの色 だそう。わかりやすい記事でした。

 

Passブロックって何?

前回、Passがいまいちわからなかったのですが、わかりやすい説明を見つけました。

Passは、オブジェクトのレンダリング処理を記述する部分です。

複数パスを定義することも可能で、その場合には複数回のレンダリング処理が走ることとなります。 

blog.applibot.co.jp

 

【memo2】はじめてのフラグメントシェーダー(Unity)

【今日のまとめ】Shader1Scene

フラグメントシェーダーには Passブロック が必要

 vert_img は Unityが標準で用意した頂点シェーダーの関数で、フラグメントシェーダーに対して、uv座標が入ったv2f_img型の変数を渡す

 

 

------------------------------------

Unity でゲームは作っていますが、Shader も 画像処理も初心者です。

アウトプットばかりだとそのうち技術についていけなくなるので、毎日1時間程度は自分の知らないことを少しずつインプットしていこうかと思ってます。

タイトルに【memo】とあるものはほぼ自分用の備忘録なので他の記事よりも殴り書きなのはご容赦ください。

------------------------------------

 

今日は昨日の続きからですね。

ninagreen.hatenablog.com

 

板ポリの上に絵を書こうとしている途中でした。

 

ある地点の座標を受け取って、その色を決める関数を作ると、GPUで全ピクセル分実行されて絵になるということらしいです

 

Shader "Custom/Shader1" {

    CGINCLUDE
    #include "UnityCG.cginc"
}

 

ってことでここまでサンプル通りに打ち込んでたら、エラーが・・

 

No ENDCG tag found after CGINCLUDE tag

 

あ、CGINCLUDE は最後に ENDCG がいるんですね。CGINCLUDEって何?とかVisual StudioでCGINCLUDEの部分に色が付かないのは何故?とか気になりますが、さすがに一旦置いておきます。

 

とりあえず写経して、

 

Shader "Custom/Shader1" {

    CGINCLUDE
    #include "UnityCG.cginc"

    float4 frag_test (v2f_img i) : SV_Target
    {
        return float4 (i.uv.x, i.uv.y, 01);
    }
    ENDCG

    SubShader {
        Pass
        {
        CGPROGRAM
        #pragma vertex vert_img
        #pragma fragment frag_test
        ENDCG
        }
    }
}

 昨日作ったMaterial のShaderの箇所から選択(Shader "Custom/Shader1がそのまま反映されるっぽい

f:id:ninagreen:20180911181212p:plain

 

そうするとなんか色が変わってる。

実行時間なくリアルタイムで反映されるのはいいですね。

f:id:ninagreen:20180911181256p:plain

 

調べていくと、どうやらCGINCLUDEは必須ではなさそう。もっと簡潔にこう書ける

Shader "Custom/Shader1" {
    SubShader {
        Pass
        {
        CGPROGRAM
        #include "UnityCG.cginc"
        #pragma vertex vert_img
        #pragma fragment frag_test

            float4 frag_test (v2f_img i) : SV_Target
            {
                return float4 (i.uv.x, i.uv.y, 01);
            }
        ENDCG
        }
    }
}

 ちなみにこれはフラグメントシェーダーなるものらしい。Surfaceシェーダーのほうが入門としてはよかったっぽいけど、と思ったらそうでもない?

Unityにおける Surface Shader と Vertex/Fragment Shader の大まかな使い分けは、ライトの影響を受けるモノには Surface Shader で、受けないモノには Vertex/Fragment Shader です。

が、勘違いしてはいけません。「Surface Shader > Vertex/Fragment Shader」ではなく、むしろシェーダーの基本は Vertex/Fragment の方です。(以降 V/F Shader と書きます)

 

tsumikiseisaku.com

 

とりあえず先に進もう。ちょいちょい出てくるよくわからないコードはおまじないで覚えればいいのかもしれないけど、一応調べてみた。

 

Shader "Custom/Shader1" {   

// シェーダーの名前を定義かな

 

 

    SubShader {

// SubShader シェーダーの1単位っぽい。Unity 公式ページ、意味不明・・

「Unity の各シェーダーはサブシェーダーの一覧から構成されます。Unity がメッシュを描画するとき、使用するシェーダーを見つけ、ユーザーのグラフィックカードで実行する最初のサブシェーダーを選択します。」

// 同一ファイルに複数のシェーダーを書きたい時はこのSubShaderを並列で並べればいいってことかな

 

        Pass
        {

// フラグメントシェーダーだと必ずPassを書かないといけないらしい。Passって何?

// Unity公式は相変わらずよくわからない、もうちょっと初心者にわかりやすく書いてくれればなあ

Pass ブロックはゲームオブジェクトのジオメトリを 1 回レンダリングします。」 

// 取るとエラーになるし、もうここはフラグメントシェーダーのおまじないってことで・・・

 

        CGPROGRAM

// おそらくCGプログラムをこれから書きますよってこと。今まではCGプログラムじゃなかったのか?

 

        #include "UnityCG.cginc"

// Unityが標準で用意しているシェーダープログラムを読み込む、だと思う
 

        #pragma vertex vert_img
        #pragma fragment frag_test 

// 頂点(Vertex)シェーダー に vert_img関数を、Fragmentシェーダー にfrag_test関数を使うと指定しているっぽい

// frag_test は自分でこのあと定義しているけど、vert_img はどっから出てきたかというと、どうやらUnityCG.cginc で定義されている関数っぽい

// ちなみに #pragma (プラグマ)はコンパイラに指示を与えるもので、コンパイルディレクティブっていうらしい

 // vert_img はこの記事の説明がわかりやすい

www.shibuya24.info

 

            float4 frag_test (v2f_img i) : SV_Target
            {
                return float4 (i.uv.x, i.uv.y, 01);
            }

// ここがメインの処理。uvは0〜1の座標が渡されるので、

// 左上が (0, 0, 0, 1)、左下が(0, 1, 0, 1)、右上が(1, 0, 0, 1)、右下が(1, 1, 0, 1)ってことでしょ?あれ?

f:id:ninagreen:20180911190657p:plain

// UVの座標系は原点が左下なのか、つまり左が0、上が1・・だと

// 左上が (0, 1, 0, 1): 緑、左下が(0, 0, 0, 1): 黒、右上が(1, 1, 0, 1): 黄、右下が(1, 0, 0, 1): 赤

// あってる!

        ENDCG
        }
    }
}

// CGPROGRAM の終わりってことだと思われる

 

なんかシェーダーって前提となる知識が多い印象。内輪で盛り上がっているコミュニティに外からよそ者がやってきたけど、会話に入れなくて困ってる、みたいな気分になります(あくまで個人的な感想です・・・)

 

【memo1】Unity の Quad と Plane の違い

【今日のまとめ】

Plane (プレイン)は 1辺10単位で  三角形 200 個!

Quad (クワッド)は 1辺1単位で 三角形 2個!

処理負荷はQuadのほうが軽いので、単純に画像や動画を1枚貼るだけならQuadのほうが良さげ。

docs.unity3d.com

 

------------------------------------

Unity でゲームは作っていますが、Shader も 画像処理も初心者です。

アウトプットばかりだとそのうち技術についていけなくなるので、毎日1時間程度は自分の知らないことを少しずつインプットしていこうかと思ってます。

タイトルに【memo】とあるものはほぼ自分用の備忘録なので他の記事よりも殴り書きなのはご容赦ください。

------------------------------------

 

今日は楽しいというワードに魅かれて、これをやってみようかと思います。

docs.google.com

 

適当な板ポリを置いてその上に絵を描く」というのにチャレンジしようかと。まずは板ポリを作成して・・・

f:id:ninagreen:20180910185738p:plain

 

ん?え、待って、板ポリって Plane じゃなくて Quad なの?(3Dも初心者)

 

気になることがあるとすぐ脱線。

まずは Unityマニュアル で調べてみました。

docs.unity3d.com

 

Plane (プレイン)は 1辺10単位とのことなので、

1辺10 x 1辺10 x 2(四角形は三角形を2個分) = 三角形 200 個!

Quad (クワッド)は 1辺1単位なので、

1辺1 x 2 = 三角形 2個!

 

処理の負荷はQuadのほうが軽いので、単純に画像や動画を1枚貼るだけならQuadのほうが良さげという理解。

 

こっちの記事のほうが詳しい。

tsuwabuki.hatenablog.com

 

では本題に戻って。

 

Quadを作った

f:id:ninagreen:20180910192727p:plain

 

Mesh Renderer が Default-Material になっているので、

f:id:ninagreen:20180910192749p:plain

 

右クリック -> Create -> Material でこんな感じの設定のマテリアルを作って

f:id:ninagreen:20180910192859p:plain

 

アタッチすれば、水色になった

f:id:ninagreen:20180910192953p:plain

 

とかやってたら1時間たってしまったので、今日はここまで。

(肝心のShaderまでいってないという・・・)

git の 取り消しコマンドまとめ

いつも忘れてしまうので、git の取り消し系の操作をまとめました。

コマンドの書き方はいくつかあるかと思いますが、たくさんあっても覚えられないので、よく使っているものだけを記述しています。

 

《CASE1》git add の 取り消し

指定したファイルのaddを取り消す

git reset HEAD [ファイルパス]

 

《CASE2》git commit の 取り消し

直前のコミットを取り消す

git reset --soft HEAD^

 

《CASE3》git push の 取り消し

git reset --soft HEAD^

でコミットを取り消して

git push -f origin [ブランチ名]

で強制的にブランチを上書き

 *個人用のブランチならいいが、共有ブランチではやらないほうが無難。

 

《CASE4》マージ の 取り消し

github 上から、マージされたプルリクエストの「Revert」ボタンを押す

*共有ブランチには直接pushせずに、プルリクエストを送る前提。

 

《番外編1》新規ファイルの削除

作業ディレクトリから追跡対象外のファイル(Untracked files)をまとめて削除

git add 前の新規ファイルを一括で削除できるので、追加した覚えのないゴミファイルを削除するには便利だが、うっかり大切なファイルまで消さないように注意

 git clean -df

 

《番外編2》チェリーピック

指定したコミットを別のブランチに持ってくるには、コミットを取り込みたいブランチに移動して

git cherry-pick [コミットハッシュ]

で出来る。

 

マージに含まれる複数のコミットを全て持ってくる場合には、

git cherry-pick -m 1 [マージコミットのコミットハッシュ]

で出来る。