お米 is ライス

C#やらUnityやらを勉強していて、これはメモっといたほうがええやろ、ということを書くつもりです

【Cg Programming/Unity】テクスチャ基礎 ~ テクスチャを描画する【順番にやっていく】

f:id:spi_8823:20200519000504p:plain

お~~~~っほっほっほっほっ!!!
庶民のみなさま!今回はこちらをやっていきますのよ!
en.wikibooks.org
en.wikibooks.org
この節では3Dオブジェクト上にテクスチャを描画する方法を学ぶそうですのよ?
テクスチャって何ですかですって!?テクスチャはテクスチャですのよ!!

テクスチャの描画

真っ白な球体を眺めているのはもう飽きてきたんじゃありませんこと?え、飽きてない?物好きなのねあなた……。
どうせまん丸球体を転がすなら、ど~んとでっかく地球ぐらいは転がしてあげようじゃないですの!そう、わたくしの手のひらの上で滑稽に回り続けるあなたたちのように転がしてあげるわ!

テクスチャの用意

まずすることはと言えば、そうですの。地球の画像をどこかから持ってくるのですわ!
めんどくさい?もう、相変わらずしょうのない人ね……。そんなこともあろうかと、うちの執事に用意させたからココからダウンロードしてきなさい。
忘れないうちにわたくしに感謝しておくこと。いいわね?
f:id:spi_8823:20200518220859j:plain

テクスチャの登録

用意したテクスチャをシェーダから使うには、シェーダ(を使用するマテリアル)にテクスチャを登録しないといけませんわね。
シェーダに外部から値を渡してあげるにはどうすればいいか覚えてらして?あら、ダチョウ頭のあなたにしては珍しくちゃんと覚えているじゃない。えらいわ。
そう、シェーダのPropertiesにパラメータを用意して、CGコードの中で同名のuniform変数を宣言するんでしたわね!
今回は_TestTexという名前にいたしますわ!

Properties

この名前でPropertiesにテクスチャのパラメータを定義するには次のように書くといいんですの!

Properties
{
    _TestTex ("Test", 2D) = "white" {}
}

2Dというのがテクスチャを表していますわ!
"white"としたことでデフォルトでは真っ白な画像が使用されますわ!
最後の波かっこは昔の記法の名残のようで、今のバージョンではもう意味が無いそうですわ。

uniform変数の宣言

Propertiesで定義したパラメータをCGコードから使うにはuniform変数を宣言しなければならないんでしたわね!
CGコードではテクスチャはsampler2Dという型になっていますのよ!
ですから、宣言は次のようになりますわね!

uniform sampler2D _TestTex;
uniform float4 _TestTex_ST;
Tiling, Offset

あら、気づいたみたいね。_TestTex_STとはなんだ、でしょう?
この変数にはテクスチャのTilingOffsetの値が入っているのですわ!
Propertiesでテクスチャを定義すると、テクスチャと一緒にTilingOffsetという2次元ベクトルを一緒に設定できるようになるのですわ!
テクスチャの変数名の後ろに_STと付けたuniform変数にはこれらのベクトルの値が入るようになっているんですの。
Tilingはテクスチャの繰り返し描画、Offsetはテクスチャの初期位置をずらすために用いられることが多いのですわよ!

テクスチャ座標

さて、これでシェーダからテクスチャを参照することができるようになりましたわ!
あとは、テクスチャ上の色を取得して、ピクセルの色として出力すればいいだけですわね!
それにはもう一つ、色を取得すべきテクスチャ上の座標の情報が必要なんですわよ。
そんなのどうやって計算すればいいのか、と困惑しなくてもよろしくってよ!
うちの執事に計算させたテクスチャ座標をTEXCOORD0というセマンティクスを使って頂点シェーダのインプットとして渡すようにしておいたわ!
テクスチャ座標の値は頂点シェーダからフラグメントシェーダへそのまま受け渡すことが多いんですの。
このとき、これまたTEXCOORD0というセマンティクスを使って受け渡すことが多いんですけれど、頂点シェーダのインプットとしてのTEXCOORD0と、頂点シェーダからフラグメントシェーダへ受け渡す際のTEXCOORD0は別のものだということは気を付けておきなさい。

テクスチャの色の取得

テクスチャ座標が取得できればあとはテクスチャ座標を使ってテクスチャ上の色を取得するだけですわね!
テクスチャ座標がtexcoordという変数名だったなら、その座標の色は次のように取得できるわ!

float4 color = tex2D(_TestTex, texcoord);

驚くほど容易いですわね!

描画結果

実際に球に地球を描画いたしましたわ!
f:id:spi_8823:20200519000504p:plain
これの半分くらいはうちの土地ですの!

え?のっぺりしてる、ですって?そりゃそうなのですわ。だってライティングをしてないんですもの。
んもう、そう言うかと思って拡散反射で描画するテクスチャの色を変える方法もやってあげたのですわ!
f:id:spi_8823:20200519001744p:plain
日本の夜明け、ですわね!

コード

今回使ったコードですわ。
ありがたく拝見することね!

Shader "Custom/TexturedSpheres"
{
    Properties
    {
        _TestTex ("Test", 2D) = "white" {}  //テクスチャのパラメータ定義ですわ!
    }

    SubShader
    {
        pass
        {
            CGPROGRAM
            #pragma vertex v
            #pragma fragment f

            #include "UnityCG.cginc"

            uniform sampler2D _TestTex;
            uniform float4 _TestTex_ST;

            struct vertexInput
            {
                float4 vertexPos : POSITION;
                float4 texcoord : TEXCOORD0;    //頂点シェーダにインプットとして渡されるテクスチャ座標ですわ!
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 sv_position : SV_POSITION;
                float2 uv_position : TEXCOORD0; //テクスチャ座標ですわ!vertexInputのtexcoordとは違うから注意するのですわよ!
                float diffuseRatio : TEXCOORD1; //拡散反射の度合いですわ!
            };

            v2f v(vertexInput input)
            {
                v2f output;
                output.sv_position = UnityObjectToClipPos(input.vertexPos);
                output.uv_position = input.texcoord;    //フラグメントシェーダにそのまま受け渡しますわ!
                output.diffuseRatio = dot(UnityObjectToWorldNormal(input.normal), normalize(_WorldSpaceLightPos0.xyz)); //拡散反射の計算をしますわ!

                return output;
            }

            float4 f(v2f input) : COLOR
            {
                //テクスチャの色を取得しますわ!
                //Tilingの値は_TestTex_ST.xy、Offsetの値は_TestTex_ST.zwに入っているんですの!
                float4 texColor = tex2D(_TestTex, input.uv_position.xy * _TestTex_ST.xy + _TestTex_ST.zw);
                return texColor * pow(max(0, input.diffuseRatio), 2);   //テクスチャの色に拡散反射の値をかけて出力しますわ!
            }
            ENDCG
        }
    }
}