今時のモバイル環境のための
リッチコンテンツ制作ノウハウ
ユニティ・テクノロジーズ・ジャパン合同会社
        大前 広樹


     Unity名古屋セミナー
Rewind 2011/App of 2011
「リッチコンテンツ」の
ベンチマーク的ゲーム
http://beta.unity3d.com/assetstore/
    ShadowgunSampleLevel.zip
無料でダウンロード可能
同梱のシェーダーは商用利用可能
1.ハードを知ろう

2. ライティングをうまくやろう

3. 余ってるパワーをうまく使おう
ハードを知ろう
• ShadowGunのターゲット

   • iPhone4
   • iPad, iPad2
   • Tegra2以上のAndroid

   • Tegra3積んでたら色々おまけ処理
• http://www.youtube.com/watch?
   v=QmvJxbHWZSU&feature=player_embedded
• だいたいGPUネック、ときどきCPUネック
 (ShadowGunではiPad2のみCPU、ほかはGPU)

• 大体フラグメントシェーダ

• 頂点処理、頂点数が問題になることはほとんどない

• メモリは沢山あるけど、バスは遅い

• Power-VR系はソート順ほとんど意味なし

• Aderno, Tegraはソート順はパフォーマンスにかな
 り影響(手前から描こう)
あと、よくある間違い




うっかりPC用のシェーダを使ってしまっている
• まずは、モバイル向けのシェーダに限定
 しよう
Basic GPU optimizations
• Use simplest possible fragment shaders (vertex shaders are usually
not problem)


• Shader variables precision is very important (smaller precision ->
faster shaders) – beware of artifacts however


• Rendering order is important (especially on non-PowerVR GPUs) :
try render back -> front


• You can utilize shader tag ‘queue’ to enforce rendering order
globally : ie. skybox goes last, weapon in 1st person view first


• Sometimes, rearranging math expressions in shaders can have
significant effect – so don’t be afraid to experiment 


                                            Bootcamp Asia 2012   06/26/12   Page 9
• Fragment Shaderを出来る限りシンプルにする

• 頂点シェーダは大体において余っている(ので、エキ
 ストラでアレコレやりたいときに使える)

• 描画順は意外と重要(特にPower-VR以外のGPUでは)

• Queueを使って描画の順番を整理しよう
• シェーダ内で計算順序を入れ替えてみると、結構イン
 パクトがある場合があるので、恐れず実験しよう!
• フラグメントシェーダを軽くするには?

• Precision超重要

• 計算順もたまに変えてみよう
Precisionとは

浮動小数点の精度のこと
float                     より精確



      half



     fixed                      より速い

http://http.developer.nvidia.com/Cg/fp20.html
結論:
可能な限りfixedを使う
ライティングを上手くやろう
ShadowGunが綺麗なのは
ライティングを頑張った結果
使えるもの


  静的なライト(ライトマップ)

動的なライト効果を軽く済ませる方法
 ライトプローブ、疑似スペキュラ

  ちょっといい影のつけかた
Lighting in Shadowgun

• Lighting has major impact for overall game look. GI makes
almost any graphics assets look nice 

• We use lightmaps for static world geometry

• For dynamic objects ‘light probes’ are utilized : result is
consistent lighting for all surfaces (we have about ~500 light
probes per level, 3.5m spacing)

• There is usually one 1024x1024 lightmap per level

• Lightmaps are NOT compressed because of artifacts




                                       Bootcamp Asia 2012   06/26/12   Page 10
• グローバルイルミネーションさえ当てれば、大
 抵のモデルは綺麗に見える:)

• 静的なものはコスト安く、ライトマップで対応
• 動的に動くものはライトプローブを使う
• ライトマップは綺麗に見せたいので非圧縮
GI lightmaps + probes




               Bootcamp Asia 2012   06/26/12   Page 11
• ライトマップの問題点

 • ディフューズカラーはいいが、スペ
  キュラがないのでメタル感が出ない
Specular lighting
• Precomputed lighting is perfect for diffuse lighting component


• Specular (view dependent) component however poses a problem
(solutions exists but not viable on current mobile platforms)


• This is where we start to cheat:

   • We precompute ‘specular lighting cubemap’ (this is just set of artists
   defined directional light projected to low-res cubemap)
   • In runtime, we use this cubemap as standard environment map (additive)
   • Artists create different specular cubemaps for different parts of level

• To make this fake specular lighting consistent with lightmapped geometry
we just modulate it with lightmap (yes, this has no physical basis, but looks
OK)




                                                  Bootcamp Asia 2012   06/26/12   Page 12
• スペキュラライティング自体はあるが、
 ダイナミックライトの計算は重すぎる

• Cubemapを使って、フェイクなスペキュ
 ラをつける
• フェイク・キューブマップの作り方
 • アーティストに頼んで、適当なライティングで場所・
  場所に合ったキューブマップをいくつか作ってもらう

 • 特定のエリアに入ったら、そのキューブマップを使っ
  て環境マップ処理をする

 • スペキュラがライトマップとあまり矛盾しないように
  イイ感じに調整(人力)
Cubemap based specular lighting

  Cubemap used for fake specular lighting




                           Bootcamp Asia 2012   06/26/12   Page 13
Cubemap based specular lighting


                   No specular lighting




                    Bootcamp Asia 2012   06/26/12   Page 14
Cubemap based specular lighting

              Cubemap based specular
              lighting




                      Bootcamp Asia 2012   06/26/12   Page 15
• ハイライト

 • スペキュラがどういう感じに素材に当
  たるかの計算
• 普通のやり方だと、アルファ成分に入れ
 る
Glossiness mask “trick”

• For glossy surfaces we usually use some kind of mask, which defines actual
glossiness

• Common approach is to use alpha channel of diffuse texture to store
glossiness




            Diffuse tex RGB              Diffuse tex A (glossiness)

                                             Bootcamp Asia 2012   06/26/12   Page 16
• PVRTC4bitで、アルファあり・なしの違
 いで、大分クオリティが変わってしまう
Glossiness mask “trick”
• Using additional texture channel for glossiness however has drawbacks:
   • Increased memory requirements (4 bpp vs 8 bpp for DXT1 / DX5)
   • Significant quality degradation on some platforms (PVRTC)




 4 BPP PVRTC with alpha                    4 BPP PVRTC without
                                           alpha




                                               Bootcamp Asia 2012   06/26/12   Page 17
• ディフューズカラーからハイライト率を
 はじき出すための計算をする

• どのカラーを強く出すかのためのバイア
 スをかけるベクターを用意
Glossiness mask “trick”
• So what we do is following. Instead of just taking:
   •glossinesMask = tex2D(DiffuseTex,uv).a

• We calculate:
   •glossinesMask = dot(tex2D(DiffuseTex,uv),CustomGlossExtractionWeights)

   • We have introduced four component vector
   CustomGlossExtractionWeights which basically defines how diffuse
   texture channels get combined to create glossiness mask.

   • This way we can have textures which defines glossiness purely by alpha
   channel (weights = (0,0,0,1)) or for example luminance of RGB channels
   (weights = (0.3,0.6,0.1,0))

   • Those weights don’t have to be normalized, so they control ‘specular
   strength’ also




                                                 Bootcamp Asia 2012   06/26/12   Page 18
Diffuse texture




        Red       Green            Blue
                Green * WeightG
Red * WeightR
                                          Blue * WeightB




                                  Glossiness mask
                                                           Page 19
とはいうモノの・・・
サンプルでやってないじゃん・・・orz
ただ、有効なテクニックであることは
     まちがいない
ライトプローブ
GI lightmaps + probes




               Bootcamp Asia 2012   06/26/12   Page 11
• Unity 3.5から使える機能

• ライトマップを焼くときに、動的なオ
 ブジェクトのためにGIライトを当てら
 れる仕掛け

• 沢山置けばおk
・・・・・
• とにかく、恥ずかしげもなくGIつきライ
 トマップ+ライトプローブから始める

• アンビエントオクルージョンもライト
 マップ作成時に焼く
• 無料版でも、ライトマップは使える(G
 Iの焼き付けは有料版のみ)

• 無料版でも、アンビエントオクルージョ
 ンの焼き付けは出来る=存在感のある絵
 作りが可能!

       やってみて!
影
• ShadowGunでは、影はいわゆる「丸
 影」

• でもそれだと味気ないので、「丸影
 2.0」を実装
Character shadows
• In most cases, we should be fillrate bound


• So we should have some spare vertex processing available, which can be
used to make blob shadows better


• Basic idea is to approximate character using spheres and calculate
analytically expressed ambient occlusion (AO) between spheres and
ground plane in vertex shader (for Shadowgun, we use 3 spheres : left
foot, right foot, pelvis)

• Even if derivation of sphere vs plane AO closed form expression is not
trivial, result is surprisingly simple and efficient. For further information
see Iñigo Quilez (Iq / RGBA demogroup) website as he is the author of
formulas we use.




                                               Bootcamp Asia 2012   06/26/12   Page 21
• シェーダは大体フィルが遅い(ということ
 は・・)

• 3つの球からAOを計算して、頂点シェー
 ダで動的にテッセレートしたメッシュで
 描画
影AOの計算




 地面
動的にテッセ
     レートされた
     丸影メッシュ




Bootcamp Asia 2012   06/26/12   23
Bootcamp Asia 2012   06/26/12   24
サンプルないじゃん・・・
ゴッドレイ
Volumetric FX




           Bootcamp Asia 2012   06/26/12   Page 27
ボリュームライトやゴッドレイのようなもの
Volumetric FX – optimizing fillrate (1)
• First step is to use the simplest possible fragment
shader

• In many cases, we don’t even need to sample
texture

  • Just procedurally calculate intensity per vertex (it is some kind of
  gradient in most cases anyway)

  • If it doesn’t look smooth enough …

  • … just use more vertices




                                              Bootcamp Asia 2012   06/26/12   Page 28
• ポリゴンとテクスチャ、加算合成で表現
 (昔ながらのテクニック)

• とにかくここでも、出来るだけシンプルなフラ
 グメントシェーダを使う

• そのうえで、どうやったら画面に描画されるピ
 クセル数が少なくなるかを考える
Volumetric FX – optimizing fillrate (2)
• Second step is to limit number of pixels we throw to
screen

• Decrease transparency as viewer is moving closer to
surface

• Once transparency is close to zero …

• Start to shrink surface
  • shrink direction is controlled via normals
  • takes place in vertex shader

• Eventually surface tris degenerate to lines and thus don’t
generate any pixels to rasterize



                                            Bootcamp Asia 2012   06/26/12   Page 29
• 一般的に、描画されるサイズはカメラが
 対象に近づいたら大きくなる

• 描画サイズが大きくなると負荷が高くな
 る
法線方向


         エッジの片方を
カメラが近づいたときにぐーっと動かす
         (頂点シェーダ)
MADFINGER-god-rays.shader
結論

頂点シェーダは余りがちなので

いろいろ遊べる余地があるよ!
Q&A
おわり

Unity名古屋セミナー [Shadowgun]