このセクションでは、最適化のレンダリングを技術的に紹介します。パフォーマンス向上のためのライティング結果を焼く方法と Shadowgun の開発者が彼らのゲームを素晴らしいものに見えるようにするライティングをベイクして高コントラストのテクスチャをレバレッジする方法を示します。モバイルに最適化されたゲームがどのように見えるか、一般的な情報を探している場合は、グラフィックスメソッドページをチェックしてください。
時には、あなたのゲーム内のレンダリングを最適化することは、いくつかの割に合わない仕事を必要とします。Unity が提供するストラクチャーのすべては何かを速く動作させるのが容易になりますが、限られたハードウェア上で忠実に動作する必要がある場合、あなたが、自分自身でもっとより速くする鍵となるストラクチャーの変化を導入することができ、ストラクチャーを回避して行く方法でより高速になものになります。選択するあなたのツールは、エディターのスクリプト、シンプルなシェーダーと昔ながらのアート制作です。
まず最初に、この マテリアルとシェーダーとテクスチャをチェックしてください。
#pragma debug
)
#pragma DEBUG
を追加した場合は、インスペクター経由でコンパイルされたシェーダーを開くと、中間 CG コードを見ることができます。これは、シェーダーの特定の部分が実際にはどのように計算されるか、検査するのに便利で、また、あなたがサーフェスシェーダーから欲しい特定の側面をつかむためや CG シェーダーに適用するのに使えます。Shadowgun は、それを実行するハードウェアを考慮した素晴らしいグラフィカルな成果です。アートの質はパズルの鍵であると言われますが、そのような品質を達成するために、プログラマは彼らのアーティストの可能性を最大限引き出させるカップルのトリックがあります。
グラフィックスメソッドページでは、すばらしい最適化の例として Shadowgun の黄金の彫像を使用してます:それらの彫像に通常のマップを使用していくつかの固体を定義を与える代わりに彼らはテクスチャにライティングのディテールをベイクしました。ここに、あなたがあなた自身のゲームで同様のテクニックをどのように、なぜ、使用するのか表示しています。
// This is the pixel shader code for drawing normal-mapped
// specular highlights on static lightmapped geometry
// 5 texture reads, lots of instructions
SurfaceOutput o;
fixed4 tex = tex2D(_MainTex, IN.uv_MainTex);
fixed4 c = tex * _Color;
o.Albedo = c.rgb;
o.Gloss = tex.a;
o.Specular = _Shininess;
o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));
float3 worldRefl = WorldReflectionVector (IN, o.Normal);
fixed4 reflcol = texCUBE (_Cube, worldRefl);
reflcol *= tex.a;
o.Emission = reflcol.rgb * _ReflectColor.rgb;
o.Alpha = reflcol.a * _ReflectColor.a;
fixed atten = LIGHT_ATTENUATION(IN);
fixed4 c = 0;
half3 specColor;
fixed4 lmtex = tex2D(unity_Lightmap, IN.lmap.xy);
fixed4 lmIndTex = tex2D(unity_LightmapInd, IN.lmap.xy);
const float3x3 unity_DirBasis = float3x3(
float3( 0.81649658, 0.0, 0.57735028),
float3(-0.40824830, 0.70710679, 0.57735027),
float3(-0.40824829, -0.70710678, 0.57735026) );
half3 lm = DecodeLightmap (lmtex);
half3 scalePerBasisVector = DecodeLightmap (lmIndTex);
half3 normalInRnmBasis = saturate (mul (unity_DirBasis, o.Normal));
lm *= dot (normalInRnmBasis, scalePerBasisVector);
return half4(lm, 1);
// This is the pixel shader code for lighting which is
// baked into the texture
// 2 texture reads, very few instructions
fixed4 c = tex2D (_MainTex, i.uv.xy);
c.xyz += texCUBE(_EnvTex,i.refl) * _ReflectionColor * c.a;
return c;
リアルタイムのライティングは間違いなく高品質ですが、ベイクした方が、パフォーマンスはかなり向上します。では、どうやってベイクするのでしょう? Render to Texel というエディターツールが、この目的のために作成されました。このツールは、以下の工程を経てテクスチャにライティングを焼き付けます:
これが最高のグラフィックの最適化がどのように機能するかです。これらはエディターでそれらを予備成形し、ゲームを実行する前に計算の爆発を回避します。一般的に、これがあなたがしたい何かです:
ちょうど、オーディオトラックの低音と高音のように、画像はまた、高周波と低周波成分を有し、レンダリングするとき、さまざまな方法で処理するのが最善で、完全なステレオサウンドを作成するためにサブウーファーとツイーターを使用する方法に似ています。画像の異なる周波数を可視化する 1 つの方法は、Photoshop で“ハイパス”フィルターを使用することです。Filters->Other->High Pass . あなたが以前にオーディオの作業を行っている場合は、あなたはハイパスの意味がわかるでしょう。本質的に、すべての周波数のうち、X よりも低いと遮断され、通過させるパラメーターをフィルターに渡します。画像の場合、ガウスぼかし、低域を通過するのと同じです。
周波数は物事を分離することと、何か処理方法を決定するよい方法であるため、リアルタイムグラフィックスに適用されます。例えば、基本的なライトマップ環境では、最終画像は低い周波数であるライトマップと高周波であるテクスチャの合成によって得られます。Shadowgun では、低周波数の光は、迅速に光プローブを用いて文字に適用され、高周波光は、任意の光の方向を持つ単純なバンプマップシェーダーを使用することによって疑似されています。
一般に、光の異なる周波数をレンダリングするために異なる方法を使用することで、例えば、ベイクか動的か、オブジェクト毎かレベル毎か、ピクセル毎かの頂点毎か、など、あなたは限られたハードウェア上でフルボディのイメージを作成することができます。要約すると、一般的に高周波と低周波の両方で強力なバリエーションの色または値を持つようにすることをお勧めします。
注意: 通常、これらの分解は、繰延レンダラーでのステップを参照しますが、ここではそうではありません。このすべては一回のパスで行われます。これらこの合成に基づいた 2 つの関連シェーダーです。:
Shader "MADFINGER/Environment/Virtual Gloss Per-Vertex Additive (Supports Lightmap)" {
Properties {
_MainTex ("Base (RGB) Gloss (A)", 2D) = "white" {}
//_MainTexMipBias ("Base Sharpness", Range (-10, 10)) = 0.0
_SpecOffset ("Specular Offset from Camera", Vector) = (1, 10, 2, 0)
_SpecRange ("Specular Range", Float) = 20
_SpecColor ("Specular Color", Color) = (0.5, 0.5, 0.5, 1)
_Shininess ("Shininess", Range (0.01, 1)) = 0.078125
_ScrollingSpeed("Scrolling speed", Vector) = (0,0,0,0)
}
SubShader {
Tags { "RenderType"="Opaque" "LightMode"="ForwardBase"}
LOD 100
CGINCLUDE
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
samplerCUBE _ReflTex;
#ifndef LIGHTMAP_OFF
float4 unity_LightmapST;
sampler2D unity_Lightmap;
#endif
//float _MainTexMipBias;
float3 _SpecOffset;
float _SpecRange;
float3 _SpecColor;
float _Shininess;
float4 _ScrollingSpeed;
struct v2f {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
#ifndef LIGHTMAP_OFF
float2 lmap : TEXCOORD1;
#endif
fixed3 spec : TEXCOORD2;
};
v2f vert (appdata_full v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.texcoord + frac(_ScrollingSpeed * _Time.y);
float3 viewNormal = mul((float3x3)UNITY_MATRIX_MV, v.normal);
float4 viewPos = mul(UNITY_MATRIX_MV, v.vertex);
float3 viewDir = float3(0,0,1);
float3 viewLightPos = _SpecOffset * float3(1,1,-1);
float3 dirToLight = viewPos.xyz - viewLightPos;
float3 h = (viewDir + normalize(-dirToLight)) * 0.5;
float atten = 1.0 - saturate(length(dirToLight) / _SpecRange);
o.spec = _SpecColor * pow(saturate(dot(viewNormal, normalize(h))), _Shininess * 128) * 2 * atten;
#ifndef LIGHTMAP_OFF
o.lmap = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
#endif
return o;
}
ENDCG
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
fixed4 frag (v2f i) : SV_Target
{
fixed4 c = tex2D (_MainTex, i.uv);
fixed3 spec = i.spec.rgb * c.a;
#if 1
c.rgb += spec;
#else
c.rgb = c.rgb + spec - c.rgb * spec;
#endif
#ifndef LIGHTMAP_OFF
fixed3 lm = DecodeLightmap (tex2D(unity_Lightmap, i.lmap));
c.rgb *= lm;
#endif
return c;
}
ENDCG
}
}
}
Shader "MADFINGER/Environment/Lightprobes with VirtualGloss Per-Vertex Additive" {
Properties {
_MainTex ("Base (RGB) Gloss (A)", 2D) = "white" {}
_SpecOffset ("Specular Offset from Camera", Vector) = (1, 10, 2, 0)
_SpecRange ("Specular Range", Float) = 20
_SpecColor ("Specular Color", Color) = (1, 1, 1, 1)
_Shininess ("Shininess", Range (0.01, 1)) = 0.078125
_SHLightingScale("LightProbe influence scale",float) = 1
}
SubShader {
Tags { "RenderType"="Opaque" "LightMode"="ForwardBase"}
LOD 100
CGINCLUDE
#pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _MainTex_ST;
float3 _SpecOffset;
float _SpecRange;
float3 _SpecColor;
float _Shininess;
float _SHLightingScale;
struct v2f {
float4 pos : SV_POSITION;
float2 uv : TEXCOORD0;
float3 refl : TEXCOORD1;
fixed3 spec : TEXCOORD3;
fixed3 SHLighting: TEXCOORD4;
};
v2f vert (appdata_full v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.uv = v.texcoord;
float3 worldNormal = mul((float3x3)_Object2World, v.normal);
float3 viewNormal = mul((float3x3)UNITY_MATRIX_MV, v.normal);
float4 viewPos = mul(UNITY_MATRIX_MV, v.vertex);
float3 viewDir = float3(0,0,1);
float3 viewLightPos = _SpecOffset * float3(1,1,-1);
float3 dirToLight = viewPos.xyz - viewLightPos;
float3 h = (viewDir + normalize(-dirToLight)) * 0.5;
float atten = 1.0 - saturate(length(dirToLight) / _SpecRange);
o.spec = _SpecColor * pow(saturate(dot(viewNormal, normalize(h))), _Shininess * 128) * 2 * atten;
o.SHLighting = ShadeSH9(float4(worldNormal,1)) * _SHLightingScale;
return o;
}
ENDCG
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
fixed4 frag (v2f i) : SV_Target
{
fixed4 c = tex2D (_MainTex, i.uv);
c.rgb *= i.SHLighting;
c.rgb += i.spec.rgb * c.a;
return c;
}
ENDCG
}
}
}
いくつかの GPU、特にモバイルデバイスで、アルファテストのため高いパフォーマンスのオーバーヘッドの発生を見つけます。( discard and clip ピクセルシェーダーでの操作または使用で)。あなたは可能であればアルファブレンドと一緒にアルファテストシェーダーを交換する必要があります。アルファテストを避けることができない場合、最小限のアルファテストされた画素の総数を維持する必要があります。
いくつかの画像、特に iOS/Android の PVR テクスチャ圧縮を使用する場合、アルファチャンネルに視覚的な不都合が出る傾向があります。このような場合には、イメージングソフトウェアで直接 PVRT の圧縮パラメーターを調整する必要があるかもしれません。PVR export plugin をインストールしたり、イマジネーションテックから、PVRTC 形式のクリエイター PVRTexToolを使用して、それらの調整を行うことができます。圧縮の結果できる .pvr 拡張子を持つ画像ファイルを、Unity のエディターへ直接インポートしても、指定した圧縮パラメーターは保持されます。PVRT-圧縮テクスチャでは十分によい画質にならないか、特に鮮明な画像が必要な場合( GUI 用のテクスチャなど)、32 ビットのテクスチャの代わりに、16 ビットの使用も検討できます。そうすることで、メモリ帯域幅および必要なストレージは半分に低減します。
OpenGL ES 2.0 をサポートしているすべての Android デバイスは ETC1 圧縮フォーマットをサポート。したがって、可能な限り好ましいテクスチャフォーマットとして ETC1 の使用を奨励します。
NVIDIA Tegra や Qualcomm の Snapdragon など、特定のグラフィックス·アーキテクチャをターゲットにする場合、それらのアーキテクチャで利用可能な独自の圧縮形式の使用を検討する価値はあるかもしれません。Android マーケットはまた、サポートされるテクスチャ圧縮フォーマットに基づいてフィルタリングでき、サポートしていないデバイス上でダウンロードを防止することができる例えば 3D テクスチャと一緒に配布アーカイブ( .apk )を意味します。
ダウンロード テクセルへのレンダリング. あなたのモデルにライティングをベイクする。 Photoshop で結果にハイパスフィルターを実行します。 “モバイル/キューブマップ”シェーダーを編集し、テクセルパッケージへのレンダリングに含まれ、欠落した低周波の光の詳細は、頂点光によって置換されます。