【Unity】スカートの中を手軽に隠したい時の対処

こんにちは、Unityエンジニアのオオブチです。

 VTuberの3D配信とか含め3Dのキャラクタが動くライブ映像ではたまに意図せずスカートの中が映ってしまう事故が起きたりするじゃないですか。こういう時のモデル側の対処として事前にモデルのテクスチャを暗くグラデーションさせておく、という事がたまにあるかと思います。セットアップするエンジニア目線で言えば「見せたくないならテクスチャを予め黒塗りにしたモデルをくださいよ~~~」と思ったりするんですが、当然すべてのキャラクタがそういうテクスチャであるわけないし、自社でサポートしているキャラクタならまだしも他社のキャラクタをゲストにしている場合は基本的にテクスチャやマテリアルのプロパティは指示がない限り触りません。動かすために取り扱うアバターデータは大体こちらで受け取る前におよそクオリティチェックみたいなことをしているはずで、改造してしまうとゲストの事務所との確認で作業が数営業日止まったりすることも想像に難くありませんし。

 映像を出す直前になってテクスチャの編集を指示された日には「大きく動き回るならスパッツ穿きませんか????」とか思ってしまうのですが、パフォーマンスの直前にどうにかしたいと言われても対処法を考える余裕などなく、その時は結局その場の画像編集が早い人にテクスチャに黒でグラデーションを掛けてもらったりしました。
事後になってから、であればスパッツっぽいものを作って穿かせればいいのでは?と思ってこういうものを試しました。

Shader "Unlit/Custom/spats"
{
    Properties
    {
        _Normal("Normal", float) = 0.01
        _Area("Area", float) = 0.01
        _Axises("Axises", Vector) = (1,1,1,0)
        _Grad("Grad", float) = 1
        _Color("Color", Color)=(0,0,0,1)
        _Offset("Offset", Vector)=(0,0,0,0)
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" "Queue"="Transparent"}
        LOD 100
        Blend SrcAlpha OneMinusSrcAlpha
        //ZWrite On
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog
            
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float4 normal :NORMAL;
            };

            struct v2f
            {
                UNITY_FOG_COORDS(1)
                float4 vertex : SV_POSITION;
                float4 localPos:TEXCOORD2;
            };

            float4 _Color, _Offset, _Axises;
            float _Normal,_Area, _Grad;

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex + v.normal * _Normal);
                o.localPos = v.vertex+ _Offset;
                UNITY_TRANSFER_FOG(o,o.vertex);
                return o;
            }

            float Ellipsoid(float3 pos, float3 axises){
                return sqrt(pow(pos.x/axises.x,2)+pow(pos.y/axises.y,2)+pow(pos.z/axises.z,2));
            }

            fixed4 frag(v2f i) : SV_Target
            {
                return (1-clamp(Ellipsoid(i.localPos.xyz, _Axises.xyz)* _Grad + _Area,0,1))* _Color;
            }
            ENDCG
        }
    }
}

 何ということは無い頂点移動と半透明描画のシェーダです。このマテリアルでは描画するメッシュを法線方向に押し出して、メッシュのローカル座標で楕円体みたいなエリアを塗りつぶしています。カリングの方向が違うだけでトゥーン系のシェーダでアウトライン出すときの頂点移動と多分大体一緒ですね。元のメッシュに重ねて描画することでメッシュの特定のエリアだけをグラデーションで黒塗りにしたり出来ます。これを元のメッシュに上塗りしてみます。

 そういう訳で早速試してみようと思うので、ユニティちゃんにお越しいただきました。

こんにちは

左側が元のPrefab、右側が適応後です↓

テクスチャの黒塗りと同じ効果

該当のLeg、Skinという名の2つのメッシュのマテリアルのリストに作ったマテリアルを追加してPropertyとRenderQueueを整えました。ちゃんと隠れてほしい部分が暗くなっていて良さそうですね。

 この方法のいいところはメッシュの形状とかテクスチャに頼らず、元のアバターを触らなくていいところです。演出的に使う/使わないの判断だけしてもらえばOK(該当メッシュを複製しておいてenable/disableするのが便利かも)。
 逆に向かないケースで言えば、鋭角なエッジが多いモデルだと面が割けて見えたりすることがあります(髪の毛とか服の厚みみたいな)。
 一般的には鋭角なエッジが多いモデルでアウトラインを出すならエッジに小さなベベルを掛けるとか、スクリプトからかモデリング段階かで法線をメッシュに転写するとか、なんらか対処をするのでしょうが今回の方法はパパっと作って適応できるのが一個の良さなので深追いはしないことにします(体のラインに鋭角ってあんまりないし)。

短いですが今回はこの辺で。さようなら。


ユニティちゃんライセンス条項 2.01バージョン


この記事が気に入ったらサポートをしてみませんか?