JKになりたい

何か書きたいことを書きます。主にWeb方面の技術系記事が多いかも。

Shaderやっていく〜床に丸を書くやつ〜

完成図

考え方

1) 床のマテリアルに円を書くようなShaderを実装します

2) キャラクターの位置にその円がくるようスクリプトからパラメータを変更します

あまり言及することはないのですが、強いて言うならShaderのプロパティをスクリプトから変更する、というのが新しい点で今回のポイントです。

実装

まず、Shaderから見ていきます。

Shader "Custom/RadiusShader"
{
    Properties
    {
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Center("Center", Vector) = (200,0,200,0) 
        _Radius("Radius", Float) = 1
        _RadiusColor("Radius Color", Color) = (1,0,0,1) 
        _RadiusWidth("Radius Width", Float) = 0.5
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        #pragma surface surf Standard fullforwardshadows
        #pragma target 3.0

        sampler2D _MainTex;
        float3 _Center; 
        float _Radius; 
        fixed4 _RadiusColor; 
        float _RadiusWidth;

        struct Input
        {
            float2 uv_MainTex;
            float3 worldPos;
        };

        void surf(Input IN, inout SurfaceOutputStandard o) 
        {
            float d = distance(_Center, IN.worldPos);
            if ((d > _Radius) && (d < (_Radius + _RadiusWidth)))
            {
                o.Albedo = _RadiusColor;
            }
            else
            {
                o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb;
            }
        }
        ENDCG
    }
    FallBack "Diffuse"
}

SurfaceFunctionの実装を見ていきます。非常にシンプルですね。 _Centerが円の中心としたい場所なので、その値と現在参照されている位置のワールド座標との距離によって、テクスチャを貼るか円の色を塗るかを決定しています。 条件もとてもシンプルなので特に解説するところはないですね。

次はスクリプトです。こちらも非常にシンプルです。

[ExecuteInEditMode]
public class SetRadiusProperties : MonoBehaviour
{
    public Material[] radiusMaterials; 
    public float radius = 1; 
    public Color color = Color.white; 
    void Update()
    {
        foreach(Material radiusMaterial in radiusMaterials)
        {
            radiusMaterial.SetVector("_Center", transform.position);
            radiusMaterial.SetFloat("_Radius", radius);
            radiusMaterial.SetColor("_RadiusColor", color);
        }
    }
}

円を書きたいマテリアルを入れておいて、それらのプロパティにtransform.positionを入れることで動かしているだけになります。

床のマテリアルにRadiusShaderを使用し、動かすキャラクターにSetRadiusPropertiesをアタッチすると動作確認ができるかと思います。

おわりに

シンプルに実用性の高そうなShaderが実装できました。 次からライティングモデルを勉強していきたいなーと思います。