Unityな日々(Unity Geek)

Unityで可視化アプリを開発するための試行錯誤の覚書

オブジェクトの一部をマスクする

Unityで、GameObjectの一部にマスクをかけるには、DepthMaskを使う。
参考:Unity - Manual: ShaderLab syntax: SubShader Tags

1. Maskとなるオブジェクトの設定

1-1. 新規シェーダを作成。Maskシェーダのスクリプト(下記)を記述する。

Maskオブジェクトの順番を、レギュラー・ジオメトリとマスクをかけるジオメトリの間に設定している。

Shader "Masked/Mask" {
	
	SubShader {
		// Render the mask after regular geometry, but before masked geometry and
		// transparent things.
		
		Tags {"Queue" = "Geometry+10" }
		
		// Don't draw in the RGBA channels; just the depth buffer
		
		ColorMask 0
		ZWrite On
		
		// Do nothing specific in the pass:
		
		Pass {}
	}
}

肝は、SubShaderの中の、

Tags {"Queue" = "Geometry+10" }

の部分。Queueはレンダリングの順番を指定するタグ。デフォルトの設定値は次の通り。数字が小さいものから先にレンダリングされる。

Queue Value
Background 1000
Geometry 2000
AlphaTest 2450
Transparent 3000
Overlay 4000


Geometryは一般のオブジェクトを指す。上のスクリプトでは、Geometryのデフォルト値に10を加えた値、すなわち2010をQueueタグに設定していることになる。

1-2. 新しいMaterialを作り、Maskシェーダをアタッチする。

f:id:yasuda0404:20130401142827p:plain

1-3. このMaterialを、Maskとして使用したいオブジェクトにアタッチ。

2.Maskをかけるオブジェクトの設定

2-1. Maskをかけたいオブジェクトに、任意のMaterialを設定する。
2-2. 同オブジェクトに、次のスクリプトをアタッチ。

  

/*
	SetRenderQueue.cs
	
	Sets the RenderQueue of an object's materials on Awake. This will instance
	the materials, so the script won't interfere with other renderers that
	reference the same materials.
*/

using UnityEngine;

[AddComponentMenu("Rendering/SetRenderQueue")]

public class SetRenderQueue : MonoBehaviour {
	
	[SerializeField]
	protected int[] m_queues = new int[]{3000};
	
	protected void Awake() {
		Material[] materials = renderer.materials;
		for (int i = 0; i < materials.Length && i < m_queues.Length; ++i) {
			materials[i].renderQueue = m_queues[i];
		}
	}
}

[SerializeField]は、public変数ではないが、Inspectorウィンドウから値を設定できるようにする修飾子。
このスクリプトは、MaskをかけたいオブジェクトのRenderQueueを3000にしている。これによって、Regular Geometry(2000)→Mask(2010)→Maskをかけたいオブジェクト(3000)の順番にレンダリングされ、MaskをかけたいオブジェクトのみにMaskがかかることになる。


要は、RenderQueueの値を相対的に変えることで、レンダリングの順番を変更し、Maskをかけることになる。