おもちゃラボ

Unityで遊びを作ってます

【Unityシェーダ入門】綺麗に半透明のモデルが表示できるシェーダを作る

UnityのStandard Surface Shaderを使うと3Dモデルを半透明で表示することが出来ます。ただ、モデルの形状が複雑な場合には、裏面のポリゴンが見えて汚い表示になってしまうことがあります。

そこで、隠面は表示せず、手前側の面のみ半透明で表示するシェーダを作ってみました。左が綺麗な半透明シェーダを使ったドラゴン、右がStandard Surface Shaderを使って半透明にしたドラゴンです。

f:id:nn_hokuson:20180123193622j:plain

Standard Surface Shaderではドラゴン裏側の羽まで見えてしまっていますね。

f:id:nn_hokuson:20180123194352j:plain:w300

これを解決する方法を紹介していきます。目次は次のとおりです。

半透明でモデルをきれいに表示する方法

綺麗に表示する方法を考える前に、なぜモデルを半透明で表示すると汚く表示されるのかを考えてみましょう。

Unityのサイトによると・・・

Usually semitransparent shaders do not write into the depth buffer. However, this can create draw order problems, especially with complex non-convex meshes. If you want to fade in & out meshes like that, then using a shader that fills in the depth buffer before rendering transparency might be useful.

Unity - Manual: ShaderLab: Culling & Depth Testing

どうやらコレが原因のようです。半透明モデルを描画する際にデプスバッファ(Zバッファ)への書き込みを行わないため、後から裏面を描画すると上書きされてしまうのですね。

これを解決するため、先にデプスバッファにモデルのZ値(デプス値)のみを書き込みます。この時モデルは描画しません。

f:id:nn_hokuson:20180123202047j:plain:w600

これでモデルを表示する場所のZ値だけ正しく更新されます。続けて、そのZ値を参照しながらモデルを描画します。デプス値は正しく設定されているので、Zテストにより裏面は描画されないことになります。

f:id:nn_hokuson:20180123201728j:plain:w600

分かってしまえば、超簡単ですね!では早速シェーダを作ってみましょう。

半透明シェーダプログラム作る

プロジェクトウインドウで右クリックし、Create→Shader→Standard Surface Shaderを選択してください。名前はSemiTransparent.shaderにしました。

f:id:nn_hokuson:20180123194944p:plain:w100

いま作ったシェーダファイルを右クリックし、Create→Materialを選択してください。これでSemiTransparent用のマテリアルが作成できました。

f:id:nn_hokuson:20180123195132p:plain:w220

今回はSurface Shaderを使ってモデルを綺麗に半透明表示するシェーダを作ってみます。SemiTransparent.shaderを開いて次のプログラムを入力してください。

Shader "SemiTransparent" {
	Properties {
		_Color ("Color", Color) = (1,1,1,1)
		_MainTex ("Albedo (RGB)", 2D) = "white" {}
	}

	SubShader {
		Tags { "RenderType"="Transparent" "Queue"="Transparent"}
		LOD 200

		Pass{
  		  ZWrite ON
  		  ColorMask 0
		}

		CGPROGRAM
		#pragma surface surf Standard fullforwardshadows alpha:fade
		#pragma target 3.0

		sampler2D _MainTex;

		struct Input {
			float2 uv_MainTex;
		};

		fixed4 _Color;

		void surf (Input IN, inout SurfaceOutputStandard o) 
		{
			fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
			o.Albedo = c.rgb;
			o.Metallic = 0;
			o.Smoothness = 0;
			o.Alpha = c.a;
		}
		ENDCG
	}
	FallBack "Diffuse"
}

このシェーダでは2パスでモデルを描画しています。1パス目では「ColorMask 0」を指定することでモデルは描画せずZバッファ(デプスバッファ)にのみ書き込んでいます。

2パス目で通常通りモデルを描画しています。先にZバッファに値を書き込んでいるため、裏面のモデルはZテストに失敗し描画されません。

実行結果

シェーダが作成できたら、マテリアルをモデルにアタッチしてみましょう。プロジェクトウィンドウからマテリアルをドラッグ&ドロップします。

モデルのインスペクタからマテリアルのColorのアルファ値を操作することで、モデルの透明度を変化させることができます。

f:id:nn_hokuson:20180123195539p:plain:w350  f:id:nn_hokuson:20180123200120p:plain:w200

きれいに半透明のモデルが表示されたら成功です!

f:id:nn_hokuson:20180123195938g:plain:w450

GPU Gems 3 日本語版

GPU Gems 3 日本語版

Amazon