デフォルトのマテリアルでは頂点カラーがうまく表示されなかったので、シェーダー側で対応させてみる…
※このページの内容の動作確認には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 件のコメント:
コメントを投稿