はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【Unity】StandardShaderを置き換えて動作を軽量化する

はじめに

今回はStandardShaderを置き換えて軽量化しようという記事になります!

まずStandardShader様々な機能を持つ万能なシェーダです。

公式にあるお堅い言葉にするとこんな感じ。

Unity の Standard Shader は、包括的な機能を持つビルトインシェーダーです。
Standard Shader によって、すべてのマテリアルタイプで使用できるよう、様々なシェーダータイプ(Diffuse、Specular、Bumped Specular、Reflective など)が 1 つのシェーダーに結合されます。

Standard Shader - Unity マニュアル


普段シェーダーを触ったことがない方は基本的にはこちらを無意識に利用しているはずです。(デフォルトがこれのため)

f:id:hanaaaaaachiru:20200304130430p:plain


ただし万能が故に、使わない機能も多く無駄な処理がなされている可能性も大いにあります。

特にモバイルゲームではここを改善することでパフォーマンスが向上したりするかもしれません。


そこで今回は実際にStandardShaderを置き換えてみましょう。

自作シェーダー

まずはStandardShaderでいうAlbedo(テクスチャではなく色)のみを持つシェーダーを書いて、置き換えてみます。

f:id:hanaaaaaachiru:20200304131026p:plain

その前に、StandardShaderのプロパティがどのように実装されているかをみてみましょう。

Properties {
 _Color ("Color", Color) = (1.000000,1.000000,1.000000,1.000000)
 _MainTex ("Albedo", 2D) = "white" { }
 _Cutoff ("Alpha Cutoff", Range(0.000000,1.000000)) = 0.500000
 _Glossiness ("Smoothness", Range(0.000000,1.000000)) = 0.500000
 _GlossMapScale ("Smoothness Scale", Range(0.000000,1.000000)) = 1.000000
[Enum(Metallic Alpha,0,Albedo Alpha,1)]  _SmoothnessTextureChannel ("Smoothness texture channel", Float) = 0.000000
[Gamma]  _Metallic ("Metallic", Range(0.000000,1.000000)) = 0.000000
 _MetallicGlossMap ("Metallic", 2D) = "white" { }
[ToggleOff]  _SpecularHighlights ("Specular Highlights", Float) = 1.000000
[ToggleOff]  _GlossyReflections ("Glossy Reflections", Float) = 1.000000
 _BumpScale ("Scale", Float) = 1.000000
[Normal]  _BumpMap ("Normal Map", 2D) = "bump" { }
 _Parallax ("Height Scale", Range(0.005000,0.080000)) = 0.020000
 _ParallaxMap ("Height Map", 2D) = "black" { }
 _OcclusionStrength ("Strength", Range(0.000000,1.000000)) = 1.000000
 _OcclusionMap ("Occlusion", 2D) = "white" { }
 _EmissionColor ("Color", Color) = (0.000000,0.000000,0.000000,1.000000)
 _EmissionMap ("Emission", 2D) = "white" { }
 _DetailMask ("Detail Mask", 2D) = "white" { }
 _DetailAlbedoMap ("Detail Albedo x2", 2D) = "grey" { }
 _DetailNormalMapScale ("Scale", Float) = 1.000000
[Normal]  _DetailNormalMap ("Normal Map", 2D) = "bump" { }
[Enum(UV0,0,UV1,1)]  _UVSec ("UV Set for secondary textures", Float) = 0.000000
[HideInInspector]  _Mode ("__mode", Float) = 0.000000
[HideInInspector]  _SrcBlend ("__src", Float) = 1.000000
[HideInInspector]  _DstBlend ("__dst", Float) = 0.000000
[HideInInspector]  _ZWrite ("__zw", Float) = 1.000000
}

この一番上にある_Colorが今回の目的のAlbedoという文字の右にある色のことです。

f:id:hanaaaaaachiru:20200304131026p:plain

ちなみになんですが、StandartShader50871行もコードがあるみたいでした。

行が長いから重いとは限りませんが、想像以上にすごくてビックリです。

f:id:hanaaaaaachiru:20200304131519p:plain

追記)このようなご指摘をいただきました。


これをSurface Shaderで書いてみましょう。

Shader "Custom/Simple" {
    Properties{
        _Color ("Albedo", Color) = (1,1,1,1)
    }
	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200
		
		CGPROGRAM
		#pragma surface surf Standard fullforwardshadows
		#pragma target 3.0

		struct Input {
			float2 uv_MainTex;
		};

		fixed4 _Color;

		void surf (Input IN, inout SurfaceOutputStandard o) {
			o.Albedo = _Color.rgb;
		}
		ENDCG
	}
	FallBack "Diffuse"
}


あとはマテリアルのシェーダーをCustom -> Simpleに置き換えれば、自動的に色も引き継がれます。

f:id:hanaaaaaachiru:20200304132800p:plain

f:id:hanaaaaaachiru:20200304132809p:plain

モバイル用シェーダーに置き換える

実はUnityはモバイル用にシンプルなシェーダーを事前に用意してくれています。
docs.unity3d.com


場所はMobileカテゴリ以下にある奴です。

f:id:hanaaaaaachiru:20200304132941p:plain


これらはたとえモバイルでなくとも用いることができ、よりパフォーマンスを出すことができます。

しかし機能に制限がつくことだけは注意してください。

  • シェーダーに色合いを加えるマテリアルの色や主要な色はありません
  • シェーダーが法線マップを取得するために、ベーステクスチャからタイリングとオフセットが使用されます
  • パーティクルシェーダーは AlphaTest と ColorMask をサポートしません
  • 制限された特性とライティングのサポート - 例えば、シェーダーの中には 1 つのディレクショナルライトしかサポートしないものがある、など

Unity シェーダーのパフォーマンス - Unity マニュアル

さいごに

今回自作のシェーダーも作りましたが、実際にどれくらいのパフォーマンスの改善があったかは計測していないのでわかっていません。

ただしモバイルシェーダーは確実に効果があるはずなので、まずはそちらを利用してみると良いかもしれないですね。

ではまた。