LoginSignup
0
1

More than 5 years have passed since last update.

NGUIのPanelにSpineをクリップしてみた

Last updated at Posted at 2018-12-26

アプリで、NGUIを使っていて、困った話です。以外に、悩んだのでメモも兼ねて投稿します。

当時の状況

アプリのUIには、NGUIを使っていました。
また、演出には、Spineが使われており、UnityのRuntimeで再生させています。
2Dの演出やエフェクトにはSpineが使われているところが多く、NGUIのインスタンスにAddComponentして再生している箇所もあります。

起きた問題

NGUIでViewを重ねた時に、後ろで再生されているSpineのエフェクトが、前面にあるViewに隠れず表示されてしまっていました。具体的には、UIScrollViewに、UIGridでアイテムを並べてあって、そのアイテムの子供にSpineのComponentがあり、再生された時にNGUIのクリップが効かず、スクロールで本来隠れて見えない範囲のSpineの演出が表示されてしまっている状況でした。

原因

NGUIは、子供のオブジェクトをクリップして、描画を行っていますが、SpineのRuntimeでは行っていません。その為、Spineにクリップする処理を足します。

行った対応

今回は、シェーダーにクリップ領域を渡して、フラグメントシェーダーでクリップしています。

実際に書いたコード

UIPanelには、localCorners と worldCorners というメンバを持っています。
下の画像は、dumpしてみたログになります。画像から、どんな情報が入っているかは、想像が付くかと思います。
キャプチャ.PNG

今回は、Panelの頂点座標が、world座標系に変換されている worldCorners をそのまま使用する事ができました。
シェーダーに要素を渡しているコードです。

// MeshRendererは、MaterialにSetVectorする
meshRenderer = gameObject.GetComponent<MeshRenderer>();
// UIPanel は、GetComponentInParentしなくても、クリップする領域のpanelのインスタンスであれば、OK
worldCorners = gameObject.GetComponentInParent<UIPanel>().worldCorners;
mat = meshRenderer.material;

// _ClipArea
// x : UIPanel のxのworld座標系の左上のx座標
// y : UIPanel のyのworld座標系の左上のy座標
// z : UIPanel のxのworld座標系の右下のx座標
// w : UIPanel のyのworld座標系の右下のy座標
mat.SetVector("_ClipArea", new Vector4(worldCorners[0].x, worldCorners[0].y, worldCorners[2].x, worldCorners[2].y));

今回は、Skeleton-Fog.shaderを修正しています。

頂点シェーダーの内容です。
worldPosには、World座標に変換したvertexを入れています。2DのUV座標系になっている為、必要なのは、xとyの値になります。

Skeleton-Fog.shader
------------------------------------------------
struct v2f {
    float4 vertex : SV_POSITION;
    float4 color : COLOR;
    float2 texcoord : TEXCOORD0;
    float2 worldPos : TEXCOORD1;
};

v2f vert(appdata_t v)
{
    v2f o;
    o.vertex = UnityObjectToClipPos(v.vertex);
    o.color = v.color;
    o.texcoord = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
    // クリップ領域をWorld座標に変換
    o.worldPos = mul(unity_ObjectToWorld, v.vertex).xy;
    return o;
}

フラグメントシェーダーの内容です。
worldPosには、World座標に変換されたvertexが入っています。
また、_ClipAreaには、クリップ領域の情報が入っているはずなので、以下のような情報をセットしてありますので、xの座標の判定は、xとzでチェックし、yの座標の判定は、yとwでチェックしています。

Skeleton-Fog.shader
------------------------------------------------
fixed4 frag(v2f i) : COLOR
{
    float inArea = (step(_ClipArea.x, i.worldPos.x) *
                    step(i.worldPos.x, _ClipArea.z) *
                    step(_ClipArea.y, i.worldPos.y) *
                    step(i.worldPos.y, _ClipArea.w));
    // クリップ領域に入っていなければ、inAreaが 0.0 になる為、色が出ない。
    return inArea * i.color * tex2D(_MainTex, i.texcoord);
}

以上となります。

0
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1