UE5.1 から使える透過 OverlayMaterial、便利ですよね
今日はその OverlayMaterial のちょっとひねくれた使い方について紹介します
OverlayMaterial とは? #
Mesh に Material を重ねて描画できる仕組みです
SkeletalMesh、StaticMesh のどちらにも適用でき、1 パスで描画できます
以前は Mesh を複製してレンダリングする際、ProceduralMesh、PosableMesh などの別コンポーネントが必要で、かつ 2 倍のパスが必要でしたが、 コレが登場したことで、お手軽かつ軽量に追加のエフェクトを付けられるようになりました
基本的な使い方はヒストリアさんの記事をどうぞ
観測範囲では専ら背面法アウトラインのために採用されている気がします 僕も今のところその使い方が主ですね
OverlayMaterial でできること #
OverlayMaterial で使用される Mesh は、対象の Mesh を 1 つに統合したものです
なので、元の Mesh に設定している情報はほぼ使えると思って良いです
- VertexColor
- VertexNormal
- UV …
Texture も自由に使用できます かなり自由が効くので、色々チャレンジしてみると良いでしょう
利用例:SkeletalMesh に適用するエフェクト #
SkeletalMesh に適用することで、いろんなエフェクトがつけられます
利用例:アウトライン #
背面法を使ったアウトラインが簡単に実現できます
横道1:部分的に適用したい #
OverlayMaterial は 1 パスで描画するため、元の Mesh に複数の MaterialSlot があった場合、1 つに統合されてしまいます なので、特定の Material 部分だけに適用したい…となると、少し工夫が必要です
OverlayMaterial は元の Mesh の情報を取得できるので、VertexColor を IDMap 代わりにしてみましょう
VertexColor で区別することで、指定した部分にだけ適用することが可能になります
この方法は、OverlayMaterial で Mask を使うときにも役立ちます 下記は実用例をボカしたものですが、アウトラインの太さを調整する Mask を適用する際に、VertexColor で振り分けすることで、領域ごとの MaskTexture を使えるようにしています
横道2:欲張った VertexNormal の使い方 #
OverlayMaterial で背面法アウトラインを作る際、気をつけておかなければいけないのが、 OverlayMaterial は元の Mesh の情報を引き継ぐ、というところです
アニメキャラの場合、顔の VertexNormal を書き換えて、影の落ち方を調整する手法がありますが、 通常の背面法とは違い、同じ Mesh を使うことになるため、VertexNormal の方向へ拡張すると、アウトラインが乱れる場合があります
画像はその例です 左側にある方は VertexNormal を調整していますが、そのせいでアウトラインがうまく入らなくなっています
VertexNormal が駄目な場合は元の Normal 情報を VertexColor に入れておけば良いのですが、前の横道1でやったように、VertexColor を IDMap として使いたい場合はそれもできません
ではどうするか…
となったときが腕の見せ所
UVMap に埋め込むことにします
UE5 では Mesh の UVMap は 4 枚まで使えます
UVMap 1つで 2 チャンネル分…Normal(WorldNormal)は 3 チャンネルなので、2 枚あれば足りますね
というわけで Material はこんな感じにします
結果はこのとおり
手前側が UVMap に埋め込んだ Normal を使ったもの、奥側が転写した VertexNormal をそのまま使ったほうです
きちんとアウトラインが入っています
VertexNormal を転写してない方(画像左)と比べても遜色ない状態です
おまけとして、Blender で UV に埋め込んだ際のスクリプトを載せておきます
あくまで参考です…
import bpy
uv1_name = 'uv_normal1'
uv2_name = 'uv_normal2'
def pack_normals_to_uv(mesh):
uv1 = mesh.data.uv_layers.get(uv1_name)
if uv1 is None:
uv1 = mesh.data.uv_layers.new(name=uv1_name)
uv2 = mesh.data.uv_layers.get(uv2_name)
if uv2 is None:
uv2 = mesh.data.uv_layers.new(name=uv2_name)
mesh_normals = mesh.data.vertex_normals
for loop in mesh.data.loops:
x, y, z = mesh_normals[loop.vertex_index].vector
print(loop.index, x, y, z)
uv1.data[loop.index].uv = ((x + 1) * 0.5, (y + 1) * 0.5)
uv2.data[loop.index].uv = ((z + 1) * 0.5 , 0.0)
if __name__ == '__main__':
selected_mesh = bpy.context.active_object
print(selected_mesh)
pack_normals_to_uv(selected_mesh)
UVMap に情報を埋め込む、という事例は結構あるので、困ったときのアイデアの一つとして覚えておくと良いかもですね