2015年1月1日木曜日

【Unity】Shaderはじめました。その3.5

あけましておめでとうございます。2015年になってしまいました。

前回のその3にて頂点色を表示するシェーダというものがありました。

オブジェクトが真っ白であまりにも味気ないのと、結局頂点色ってなんなの?という思いがありましたので追記ということで少しやっていくことにします。


【Vertex color】


Shader !Debug/Vertex color {
    SubShader {
        Pass {
            Fog { Mode Off }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            // vertex input: position, color
            struct appdata {
                float4 vertex : POSITION;
                fixed4 color : COLOR;
            };

            struct v2f {
                float4 pos : SV_POSITION;
                fixed4 color : COLOR;
            };

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

            fixed4 frag (v2f i) : COLOR0 { return i.color; }
            ENDCG
        }
    }
}

シェーダそのものは前回と同じものを使用します。相変わらず真っ白ですね。
中央のキューブはそのまま、左右のキューブはエディタでスケールを変えたものになります。
今回はオブジェクトに以下のスクリプトをアタッチします。

using UnityEngine;
using System.Collections;

public class vcolor : MonoBehaviour {

    void Start()
    {
        Mesh mesh = GetComponent<MeshFilter>().mesh;
        Vector3[] vertices = mesh.vertices;
        int[] triangles = mesh.triangles;
        Color[] colors = new Color[vertices.Length];
        int i = 0;

        while (i < vertices.Length)
        {
            colors[i] = Color.Lerp(Color.red, Color.green, vertices[i].y);
            i++;
        }
        mesh.colors = colors;

        //頂点位置の確認
        for(int j = 0; j < vertices.Length; j++)
        {
            Debug.Log ("vertices " + j + " : "+ vertices[j]);
        }

        //triangles確認
        for(int j = 0; j < vertices.Length; j++)
        {
            Debug.Log ("triangles " + j + " : "+ triangles[j]);
        }
    }
}

頂点位置とtrianglesの確認は消していただいてかまいません。
while文とその周りが重要です。再生するとこのようになります。


大したことはしていません。順を追ってやっていきましょう。

■Mesh mesh = GetComponent<MeshFilter>().mesh;
MeshFilterコンポーネントの参照をします。
まずここで参照しないと続く .vertices や .colors などのMeshクラスの持つ変数が利用できないので必ずしてください。

■Color[] colors = new Color[vertices.Length];
頂点の数だけ色を用意したいので配列を作り、領域を確保します。
vertices.Length が頂点の数になります。Vector3[] vertices の配列の長さを返しているわけです。

■colors[i] = Color.Lerp(Color.red, Color.green, vertices[i].y);
while文を使って全頂点に適用しています。
頂点のy座標が0なら赤、1以上なら緑になるように色を設定しています。
Lerp()を使うことでグラデーションを表現しています。

この3つのオブジェクト、色の変化が似ていると思いませんか?
明らかにy座標違うじゃん!もっと色に違いがあるべきなんじゃないの?!と思うのが自然です。

キューブの頂点らは以下のようになっています。


黒文字で書かれているのが頂点座標です。Vector3 vertices[n] にあたるものです。
その絶対値は全て0.5です。エディタ上でオブジェクトのスケールをどんなに変えてもこの値が変わることはありませんでした。
なので大きさが違ったり形が違ったりしても色が同じように付くのです。

もう少し実験してみましょう。先ほどまでアタッチしていたスクリプトをはずし、新たに次のスクリプトをアタッチします。

using UnityEngine;
using System.Collections;

public class vcolor2 : MonoBehaviour 
{

    // Use this for initialization
    void Start () 
    {
        Mesh mesh = GetComponent<MeshFilter>().mesh;
        Vector3[] vertices = mesh.vertices;
        Color[] colors = new Color[vertices.Length];

        //個別に設定
        colors[5] = Color.red;
        colors[6] = Color.blue;
        colors[12] = Color.green;
        colors[20] = Color.yellow;

        mesh.colors = colors;
    }
}

再生するとこのように色が付きます。

greenはどこにあるのかというと下の面にあります。


色を指定した頂点の周りには色がついています。また指定していない部分は黒くなっています。
色のつく範囲ですが、色指定された頂点のある triangle上のみに限られています。
これはこのキューブが12枚の triangle で構成されているからです。
黄色に染まっている面と青に染まっている面は見かけ上つながっていますが実際にはつながっていないということです。
見かけ上このキューブは8個の頂点を持っています。しかし実際は24個の頂点を持っているのです。
そして同じ座標にある vertices[6], vertices[12], vertices[20] はそれぞれ独立していて連動しません。vertices[6] を動かしても他の2つは微動だにしません。

もう少し実験しましょう。
次はコイツです。色指定する頂点以外の頂点をすべて透明にします。

using UnityEngine;
using System.Collections;

public class vcolor2 : MonoBehaviour 
{
// Use this for initialization
    void Start () 
    {
        Mesh mesh = GetComponent<MeshFilter>().mesh;
        Vector3[] vertices = mesh.vertices;
        Color[] colors = new Color[vertices.Length];

        for(int i = 0; i < vertices.Length; i++)
        {
            colors[i] = Color.clear;
        }

        //個別に設定
        colors[5] = Color.red;
        colors[6] = Color.blue;
        colors[12] = Color.green;
        colors[20] = Color.yellow;
        mesh.colors = colors;
    }
}

これで透明に…ならない?!

あれ?おかしいな…と思って色々いじってみたんですが状況は

・頂点色無指定の状態だと真っ白
・何か一つでも指定すれば指定していないものはRGBA全て 0.0 となり黒く表示される
・Alpha 0.0 でも透明にならない

というところから動かず。
各頂点の alpha はしっかり 0.0 になっているのでこれはもうシェーダの問題だ。
Vertex color はそういうシェーダなんだ。

そんなことで片づけてしまうのは非常に悔しいのですがシェーダの中身をいじっても透明にならないので打ち切ります。


ざんねん わたしの ぼうけんは これで おわってしまった




<追記>




すばらしい。すばらしいぞ。
やったことはシェーダのPassの頭の部分(Fogの真上)に
    ZWrite Off
    Blend SrcAlpha OneMinusSrcAlph
の2行を追加しただけ。
標準的なアルファブレンディングだそうです。
ブレンディングについてはここ

0 件のコメント:

コメントを投稿