デフォルトのマテリアルでは頂点カラーがうまく表示されなかったので、シェーダー側で対応させてみる…
※このページの内容の動作確認にはUnity5.3を使用しています。
メッシュの各頂点に動的に色をつけたい場合、最も手っ取り早くて実用的な方法は専用のシェーダーを作ることですが、一応他にも方法はあります。パフォーマンスはかなり悪くなりますが、たとえばテクスチャを作成してメッシュに貼り付けるという方法。それから、頂点カラーをスクリプトから変更するやり方もあります。こんな感じ↓Color32[] colors = { new Color32(255, 0, 0, 255), new Color32( 0, 255, 0, 255), new Color32( 0, 0, 255, 255) };
Mesh mesh = GetComponent<MeshFilter>().mesh; mesh.colors32 = colors;
上記はメッシュの頂点が3つだけ(つまり三角形)の場合の例ですが、テクスチャを用意する方法よりは手軽に設定できて便利ですね。
ただ、このコードを実行しても結果はこんな感じになります。
頂点カラーが適用されずマテリアルで設定した色のまま |
これはなぜかというと、シェーダー側で頂点カラーに対応してないからです。Mesh.colorsのドキュメントをよく読んでみると
// (Note that most built-in Shaders don't display vertex colors. Use one that does, such as a Particle Shader, to see vertex colors)
「ほとんどの組み込みシェーダーでは頂点カラーが表示されないことに注意。頂点カラーを見るには、Particle Shaderなど頂点カラーが表示できるものを使うこと」
と書かれています。この記述のとおり、Standard Shaderは頂点カラー非対応で、頂点カラーにはParticles関連のシェーダーくらいしか対応していません。
というわけで、とりあえずStandard Shaderを頂点カラーに対応させてみます。Create > Shader > Standard Surface Shaderで新規のシェーダーを作成し、次のように変更しました。
Shader "Custom/VertexColorStandard" { Properties { _Color ("Color", Color) = (1,1,1,1) _MainTex ("Albedo (RGB)", 2D) = "white" {} _Glossiness ("Smoothness", Range(0,1)) = 0.5 _Metallic ("Metallic", Range(0,1)) = 0.0 } SubShader { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM // Physically based Standard lighting model, and enable shadows on all light types #pragma surface surf Standard fullforwardshadows vertex:vert // Use shader model 3.0 target, to get nicer looking lighting #pragma target 3.0 struct Input { float2 uv_MainTex; fixed4 vertexColor; }; void vert(inout appdata_full v, out Input o) { UNITY_INITIALIZE_OUTPUT(Input, o); o.vertexColor = v.color; } sampler2D _MainTex; half _Glossiness; half _Metallic; fixed4 _Color; void surf (Input IN, inout SurfaceOutputStandard o) { // Albedo comes from a texture tinted by color fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; o.Albedo = c.rgb * IN.vertexColor; // Metallic and smoothness come from slider variables o.Metallic = _Metallic; o.Smoothness = _Glossiness; o.Alpha = c.a; } ENDCG } FallBack "Diffuse" }
なげえ!…でも変更点はそんなに多くありません。
#pragma surface surf Standard fullforwardshadows vertex:vert
まずは#pragmaの行にvertex:vertを追加し「頂点に関する処理はvert関数内でやるよ!」ということを指定しています。関数名さえ一致していれば別にvertex:getvinfoでもvertex:chotenでも何でも大丈夫だと思います。おそらくvertが一般的なのかな。
struct Input { float2 uv_MainTex; fixed4 vertexColor; }; void vert(inout appdata_full v, out Input o) { UNITY_INITIALIZE_OUTPUT(Input, o); o.vertexColor = v.color; }
次にInput構造体に頂点カラーの値を保管しておくためのvertexColorを追加。さらにvert関数も追加。この関数内で頂点の色を取得しInputに一旦保存(o.vertexColor = v.color)、あとのsurf関数内でその値を使用するという流れです。ちなみにappdata_fullという構造体の中には頂点の位置、接線、法線、テクスチャ座標(×4)、そして色といった頂点データがてんこもりに入っています。今回はその中のcolorの値を取得したわけです。
o.Albedo = c.rgb * IN.vertexColor;
実際にsurf関数内で変更したのはこの行だけ。直前で計算したこの座標の色(c.rgb)に、さっきvert関数で受け取った頂点カラー(IN.vertexColor)を掛け合わせてブレンドしています。
あとはこのシェーダーでマテリアルを作成しゲームオブジェクトに追加すると、冒頭のコードがきちんと反映されるようになります。マテリアルで設定した色やテクスチャと混ざるようになるので、使い方次第では面白いことができそう。
それと、ググったらコミュニティで頂点カラーの強さやアルファ(透明)にも対応したシェーダーが公開されていました。いや~こりゃ便利ですな!
…でもそうなると今回の作業の意味は… ま、まあ何事も勉強ということで…
0 件のコメント:
コメントを投稿