クリックした場所にシェーダーグラフで円を描く #1

投稿者: | 2020-02-08


マウスクリックをした場所を中心とした円を表示させてみます。

シェーダーグラフで円を表示します。

空のゲームオブジェクトに付けたスクリプトで円を動かしています。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CircleScript : MonoBehaviour
{

    public List<MeshRenderer> meshRenderer;
   
    public Color lineColor = Color.white;
    public Color color = new Color(186f/255, 122f/255, 122f/255);
    public float lineWeight = 1f;
    public float speed = 0.5f;

    public Texture tex;
    public Texture lineTex;
    public float lifespan = 20f;
    public float planeDistance = 0f;
    public float tile = 0.05f;

    float n;

    Plane groundPlane;
    float rayDistance;
    Ray ray;

    // Start is called before the first frame update
    void Start()
    {

        n = -2;

        groundPlane = new Plane(Vector3.up, planeDistance); // デフォルトで原点を通る上向きの面を作る。

    }

    // Update is called once per frame
    void Update()
    {

        if (Input.GetMouseButtonDown(0)) // 左クリックを押した時
        {

            n = -2;
            StopCoroutine("Circle");

            foreach (MeshRenderer m in meshRenderer)
            {              
                m.material.SetVector("Vector3_AA163A00", GetCursorPosition3D());
                m.material.SetVector("Color_C6ECEE0D", lineColor);
                m.material.SetFloat("Vector1_D18FC8A0", lineWeight);
                m.material.SetVector("Color_663D4E35", color);               
                m.material.SetTexture("Texture2D_3CEFAFD0", lineTex);
                m.material.SetTexture("Texture2D_35C0B18", tex);
                m.material.SetFloat("Vector1_1023FC45", tile);

                
            }

            StartCoroutine("Circle");     

        }


    }

    IEnumerator Circle()
    {
        while (true)
        {
            Debug.Log(n);
            foreach (MeshRenderer m in meshRenderer)
            {
                m.material.SetFloat("Vector1_7EB580A3", n);

                
            }
            n -= speed;
            yield return new WaitForSeconds(0.01f);


            if (n < -lifespan)
            {
                foreach (MeshRenderer m in meshRenderer)
                {
                    m.material.SetFloat("Vector1_7EB580A3", 1 + lineWeight);


                }
                yield break;
            }
        }
    }

    Vector3 GetCursorPosition3D()
    {
        ray = Camera.main.ScreenPointToRay(Input.mousePosition); // マウスカーソルから、カメラが向く方へのレイ
        groundPlane.Raycast(ray, out rayDistance); // レイを飛ばす

        return ray.GetPoint(rayDistance); // Planeとレイがぶつかった点の座標を返す

    }

}

円を表示させたいオブジェクトをリストに入れておきます。

シェーダーグラフを作る

Projectで右クリックからPBR Graphを新規作成します。

今作ったシェーダーグラフを右クリックしてマテリアルを作ると、このシェーダーグラフが設定されたマテリアルが作られます。
このマテリアルをシーン上のPlaneオブジェクトにドラッグアンドドロップします。Planeオブジェクトはワールドの原点に置きます。

シェーダーグラフをダブルクリックするとタブが開いて、シェーダーグラフを編集できます。

シェーダーグラフの何も無いところで右クリックして、Create Nodeをクリックします。

すると、ウィンドウがでるのでPositionを検索して選択します。

このノードは、オブジェクトの表面の今処理している位置の座標を出力します。

SpaceがWorldになっているのでワールド座標です。

同じ様にもう一つVector3のノードを作ります。

ここに円の中心の座標を入れます。

円の座標を外部から得るために、Vector3のノードを右クリックして、Convert To Propertyをクリックします。

右上の「Blackboard」がオンになっていると左側にこのプロパティが表示されます。

マテリアルのインスペクタにも表示されます。

2つの座標の距離を計算するために新しくDistanceノードを作ります。PositionのOutの横の点からなにもない場所へドラッグアンドドロップします。

Distanceを検索すると、AとBが見つかります。

Aを選ぶと、Aの入力に接続された状態でDistanceが新規作成されます。

Vector3をもう一方につなぐと、2つの座標の距離がDistanceから出力されます。

この値を使って、円の中心までの距離がある値より小さい時は表面の色を変えるようにしてみます。値を比較するにはComparisonを使います。

Comparisonは、2つの入力値を比較して真偽値を出力します。プルダウンメニューから条件を選べます。Lessを選択して、Bについている入力欄に適当な値を入れておきます。

この真偽値をつかって処理を変えるにはBranchを使います。

Branchは、Predicateの入力の値が真の場合はTrueに設定した値を、偽の場合はFalseに設定した値を出力します。

TrueとFalseから何もないところにドラッグアンドドロップして、Colorのノードを2つ作ります。

カラーピッカーから2つのノードに別の色を設定します。

そして、BranchのOutとマスターのAlbedoを繋げると表面の色を設定できます。

Save Assetで保存するとシーンに反映されます。

Planeを原点に置いているので、中心から一定の範囲内にある場所だけ色が変わって円が見えます。

円の縁だけを表示する

条件を変えて円の縁だけを表示してみます。Distanceのノードからの出力を受け取るComparisonノードを1つ増やして下限の条件を作ります。

例えば、1より大きいとTrueを出力するものと、2より小さいとTrueを出力するものをAndノードに接続して、両方ともTrueのときだけBranchにTrueを渡すようにします。

すると、円の中心に近すぎる場所は白く塗られなくなって、リングが表示されます。

円を動かす

冒頭のgif画像のように円を外側へ動かすには、Distanceの値を時間とともに減少させます。

中心からの距離が1より大きく2より小さいときに色を変えるなら、上の画像の、中心から1.5の距離にある①の部分は色が変わり、距離が2.5の②はその外側にあるので色が変わりませんが、次の時間に距離から1を引くと、①は0.5、②は1.5になるので、①は中心に近すぎて色が変わらず、②は変わります。
その次の時間に距離から引く値を増やして2を引くと、今度は③の色が変わります。
このように、色が変わる部分が中心から遠ざかって行きます。

Distanceから引く値を入れるノードを新しく作って、Convert To Propertyで外部から入力できるようにします。そして、そのノードとDistanceの出力を足したものをComparisonに入力します。

スクリプトでコルーチンの中で引く値を減らしてセットする処理を繰り返します。

IEnumerator Circle()
{
    while (true)
    {
        foreach (MeshRenderer m in meshRenderer)
        {
           m.material.SetFloat("Vector1_7EB580A3", n); // 距離に足す値をセット
        }

        n -= 0.5f; // 距離に足す値を減らす

        yield return new WaitForSeconds(0.01f);

	if (n < -20f) // 十分に円が広がると終了
        {
            foreach (MeshRenderer m in meshRenderer)
            {
                m.material.SetFloat("Vector1_7EB580A3", 2); // 円の縁を中心へ戻す
            }

            yield break;
        }
    }
}

マテリアルのSetFloatメソッドを使ってマテリアルに値を教えます。第一引数のプロパティ名は、シェーダーグラフのBlackboardのReferenceをコピペしています。

メッシュレンダラーをリストに入れて、複数のオブジェクトに同時に円を表示させています。

マウスクリックした場所の座標を渡す

同じ様に、コルーチンをスタートする前に、マウスクリックした座標をマテリアルにセットします。

foreach (MeshRenderer m in meshRenderer)
{              
    m.material.SetVector("Vector3_AA163A00", GetCursorPosition3D()); // マウスクリックした座標
    m.material.SetVector("Color_C6ECEE0D", lineColor); // 線の色
    m.material.SetFloat("Vector1_D18FC8A0", lineWeight); // 線の太さ
    m.material.SetVector("Color_663D4E35", color); // 全体の色
    m.material.SetTexture("Texture2D_3CEFAFD0", lineTex); // 線のテクスチャ
    m.material.SetTexture("Texture2D_35C0B18", tex); // 全体のテクスチャ
    m.material.SetFloat("Vector1_1023FC45", tile); // 模様の大きさ
}

StartCoroutine("Circle"); 

他にもいろいろな値を渡しています。

マウスクリックした場所の座標は、以前の記事と同じ方法で、Plane.Raycastを使って取得しています。

Vector3 GetCursorPosition3D()
{
    ray = Camera.main.ScreenPointToRay(Input.mousePosition); // マウスカーソルから、カメラが向く方へのレイ
    groundPlane.Raycast(ray, out rayDistance); // レイを飛ばす

    return ray.GetPoint(rayDistance); // Planeとレイがぶつかった点の座標を返す
}

コメントを残す

メールアドレスが公開されることはありません。