Unity プレーヤーオブジェクトが他のオブジェクトに隠れた時でも見えるようにする


記事のタイトルがやたらと長いですが…

プレーヤーオブジェクトをカメラで追っている時、他のオブジェクトがカメラとプレーヤーの間に入ってしまうとプレーヤーが見えなくなってしまって、このせいでなんだかモヤモヤするのを解消する方法です。

ゲームなどではよく、背面に隠れていてもZ深度テストを合格させて、ステンシルバッファに書き込んで前面に表示さる方法がとられていますが、これよりもっとシンプルな方法で試してみました。

で、どうやったかというと…

まず、カメラからプレーヤーオブジェクトに Ray を飛ばします。
カメラとプレーヤーの間に障害になるオブジェクトがないときは Rey はプレーヤーオブジェクトに当たっています。
ところが、他のオブジェクトがカメラとプレーヤーの間に入った場合、Ray はプレーヤーではなく間にあるオブジェクトに当たることになるので…
この RayHit 対象のオブジェクトを半透明にしてしまうという方法でやってみました。

// Ray
protected Ray _ray;
protected RaycastHit _rayhit;

// エディタで通常時のシェーダと透明用のシェーダを指定する
public Shader defaultShader; // 通常時
public Shader alphaShader; // 透明時

void Update()
{
	_ray = new Ray (mainCamera.transform.position, -(mainCamera.transform.position - playerObject.transform.position));
	if (Physics.Raycast (_ray, out _rayhit)) {
		if (_rayhit.collider.tag == "RayTarget") {
			// Ray が当たっている間は対象オブジェクトのシェーダを alphaShader にする
			Shader targetShader = _rayhit.collider.gameObject.GetComponent<Renderer> ().material.shader;
			if(targetShader != alphaShader)
			{
				targetShader = alphaShader;
			}
		} else {
			// Ray が当たっていない時は defaultShader に戻す
		}
	}
}

上記コードでは細かいところは省略していますが、基本的な処理はこんな感じで行なっています。
これで、プレーヤーオブジェクトが他のオブジェクトの向こう側に隠れても見えるようになりました。

サンプルの動作はこんな感じ。

ちなみにこのサンプルでは透明用のシェーダとして、先日記事を書いた半透明リムライトシェーダにノーマル(バンプ)マップを追加したものを使用しています。