tanaka's Programming Memo

プログラミングについてのメモ。

PBR Desert Landscapeを高速化する

汗人柱さんのこちらの記事 → 【作者セール】ファンタジー系のリアルな3Dモデルが66%OFF〜80%OFF / VRでめちゃくちゃ使えそうな綺麗なワンルームの3Dモデルがなんと無料!(9アセット紹介) - Unity AssetStoreまとめ で紹介されていたPBR Desert LandscapePost Processing Profilesがお値打ちだと感じたので買ってみました。ちょうど、正月休み中に1日ぐらいでゲームを作ろう課題を実施する予定だったので、活用の場所もあるしということで。

本記事は、Unity2017.1.1とUnity2017.2の両方で動作確認しました。

目次

PBR Desert Landscapeの概要

ざっと以下のようなものが雑多に入っているアセットです。

  • Terrain用の 2種類の地面のテクスチャー
  • 大きい岩プレハブ 2種類
  • 普通の岩 1種類
  • 小さい岩 8種類
  • 地面に転がっている石プレハブ 4種類
  • 崖プレハブ 3種類
  • 枯れ木プレハブ 1種類
  • 草プレハブ 1種類
  • サンプルシーン 1つ

サンプルのシーンは以下のような感じです。112x112のTerrainに、各種プレハブを配置して構成されています。

f:id:am1tanaka:20171218222959p:plain

各モデルがテクスチャー、ノーマルマップ、MetallicSmoothnessマップが用意されているので、そのままでも綺麗なモデルです。ポリゴン数は小さい岩で200ポリゴン程度から、大きい岩の2,500ポリゴン程度です。

f:id:am1tanaka:20171218222849p:plain

シーンにUtilityのFPSカウンターを追加しただけで、WebGL向けにビルドしたのが上の画像です。パッと見、見本と影の部分が違います。あと、20fps程度なので、ちょっとこのままだとWebGLでは使えません。この辺りを解決してみました。

明るさの調整

見本はこんな感じです。

https://d2ujflorbtfzji.cloudfront.net/package-screenshot/71f53867-3eaf-45ca-a4df-eb053aba03ce_scaled.jpg

明らかに明るさが違います。これはライトマップのデータがないのが原因でした。アセットにはライトマップのデータが含まれておらず、自動生成も無効なので、自動生成を有効にするか、手動でライトマップを生成する必要がありました。

WindowメニューからLighting -> Settingsを開いて、[Generate Lighting]をクリックすると、ライトマップの生成が始まります。

f:id:am1tanaka:20171218225713p:plain

最初のビルドは凄く時間がかかりますが、生成が完了したら以下のように見本のようになりました。

f:id:am1tanaka:20171219003322p:plain

高速化

次は高速化です。プレハブのポリゴン数は、最大でも2,500ポリゴン程度です。Terrainの方が遥かにポリゴン数が多いので、モデルのポリゴン数は遅い主因ではなさそうです。

となるとエフェクトだろうということで、カメラにアタッチされていたエフェクトを一つずつ解除しながら確認しました。すると、以下のものがうちのPCでは相当遅いことが確認できました。

  • Allow MSAA (ドットを滑らかにする設定)
  • Obscurance (遮蔽物との距離で光の影響を変化させる効果)
  • Ambient Occlusion(角などの狭いところが暗くなる効果)

他には、以下のような設定で速くなりました。

以上で、WebGLで50fpsぐらいになりました。

f:id:am1tanaka:20171218231929p:plain

非力なうちのPCでも30fpsは軽く上回れているので、ゲーム作りには問題なさそうです。

先にポリゴン数は主因ではないと書きましたが、ポリゴン数も勿論影響します。カメラが向いている方向に岩が多かったり、地面が続いていると、画面には表示されていなくても処理速度は落ちます。必要になれば、マップの作り方を工夫したり、描画範囲の制御をすればよいでしょう。

Post Processing Profileの利用

デフォルトのエフェクトは古いし、せっかくPost Processing Profileを購入したので、古いエフェクトを削除して入れ替えてみました。

Post Processing Profileとは、ポストプロセスの定番アセットPost Processing Stackの設定集です。

カメラに設定したコンポーネントに付属のプロファイルをドラッグ&ドロップするだけで、プロの人が調整した画面効果を利用できます。缶ジュース一本奢って、これだけの例をもらえるなら安いものでした。

設定の仕方ですが、今回はカメラに古い設定がされているので、まずはそれを外します。サンプルシーンでは、FPSControllerの子供のFirstPersonCharacterがカメラを持っているので選びます。

f:id:am1tanaka:20171218232922p:plain

Inspectorビューで枠で囲んだコンポーネントが旧式のPost Processing Stackのスクリプトなので、全てチェックを外すか、Remove Componentします。

f:id:am1tanaka:20171218233357p:plain

Nothing SelectedになっているのはAmbient Occlusionコンポーネントです。作業中に元のファイルを消しちゃってこうなっちゃいました。

次に、プロファイルを設定できるように、Add ComponentからEffects -> Post-Processing Behaviourを選択してアタッチします。

f:id:am1tanaka:20171218233712p:plain

これで、カメラに後処理効果を設定できるようになります。ProjectビューのPostProcessing Profilesフォルダー内に沢山設定があります。

f:id:am1tanaka:20171218233857p:plain

1種類のプロファイルごとに、????high, ????low, ????_mediumの3種類の設定が用意されています。highは効果を贅沢に使っている分、実行速度は遅くなります。lowは効果を簡略化して高速化したものです。mediumはその中間です。カメラオブジェクトを選択してから、使いたいプロファイルを、InspectorビューのPost Processing Behaviourにドラッグ&ドロップすれば、プロファイルが適用されて画面が変化します。

f:id:am1tanaka:20171218234259p:plain

プロファイル例

一通り、プロファイルの作例を示します。

Blood

f:id:am1tanaka:20171218235151p:plain

Camera1

f:id:am1tanaka:20171218235110p:plain

Camera_BW

f:id:am1tanaka:20171218235227p:plain

Cinematic

f:id:am1tanaka:20171218235304p:plain

Crazy

f:id:am1tanaka:20171218235344p:plain

Cry

f:id:am1tanaka:20171218235426p:plain

Lomo

f:id:am1tanaka:20171218235459p:plain

Narc

f:id:am1tanaka:20171218235537p:plain

Purple

f:id:am1tanaka:20171218235601p:plain

Realistic

f:id:am1tanaka:20171218235638p:plain

UE

f:id:am1tanaka:20171218235712p:plain

仕上げ

Narcなどの面白いエフェクトもありますが、今回は無難にRealisticを選択しました。うちのPCだと処理速度の都合でlow設定にしました。

最後に、そのままの設定でライトマップを生成すると以下のように明るくなりすぎてしまいました。

f:id:am1tanaka:20171218235924p:plain

流石に光りすぎだろうということで、Lighting設定(WindowメニューからLighting -> Settings)のEnvironment Lightingと、Environment ReflectionsのIntensity Multiplierをどちらも0.5に調整しました。

f:id:am1tanaka:20171219000058p:plain

あと、効果があったか分かりませんが、デフォルトのシーンだと、岩などにstaticが未設定だったので、プレハブにstaticを設定した方がよいかと思います。

以上で完成したのが以下の画面です。

f:id:am1tanaka:20171219000350p:plain

新しいエフェクトの方が効率化されているようで、処理速度は同じか、少し向上しました。反射マップを無効にしましたが、静止物だけならGIで反映してくれるので、影響は感じませんでした。

設定のまとめ

記事中に省略したことも含めて、今回やったことは以下の通りです。

  • 新しいプロジェクトを作成して、PBR Desert Landscapeアセットと、Post Processing Profileアセットをインポート
  • EditメニューからProject Settings -> Qualityを選択して、WebGLのクオリティをUltraに変更
  • WebGLの解像度を800x450ピクセルに設定。その他、ビルドに必要な項目を設定
  • ProjectビューからPBR Desert Landscapeフォルダーを開いて、岩や崖などの動かないオブジェクトを選択して、staticにチェックを入れて静止物に設定
  • WindowメニューからLighting -> Settinsを選択して、以下を設定
    • Environment LightingとEnvironment ReflectionsのIntensity Multiplierをどちらも0.5に変更
    • Lightmap Resolutionを20に変更(ライトマップの計算を速くするため)
    • Ambient Occlusionにチェック(マップに焼くなら実行時の速度には影響しないし)
    • 以上設定したら、[Generate Lighting]ボタンをクリック
  • HierarchyビューからFPSControllerを開いて、FirstPersonCharacterを選択して、Inspectorビューで以下を設定
    • Rendering PathをDeferredに変更
    • Allow MSAAのチェックを外す
    • Flare Layerより下の古いPost Processingエフェクト用のコンポーネントを削除
    • Add Componentボタンをクリックして、Effects -> Post Processing Behaviourを設定
  • ProjectビューのPost Processing Profileフォルダーから、適用したいプロファイルを、カメラのPost Processing BehaviourのProfile欄にドラッグ&ドロップ

まとめ

合計300円程度で、リアルな砂漠のマップと、画面効果を得ることができました。そのままの設定だと非力なPCでは重いですが、画面効果の調整で実用レベルにすることができました。

今回はPost Processing Profileを使いましたが、不要な効果を削除したり、Post Processing Stackを自力で設定すれば、このアセットは無くてもここでやったことはほぼできます。PBR Desert Landscapeだけならそれこそコンビニでジュースを買うレベルなので、使い道があればオススメなアセットだと思います。

参考URLと利用したアセット

assetsale.hateblo.jp

Ubuntu(Lubuntu)にTensorFlowをインストールしてHelloWorldを動かす

Ubuntu(Lubuntu)16.04にTensorFlowをインストールして、動作確認するまでの手順です。

インストール方法はいろいろありますが、仮想環境が安定している感じなので、Anacondaでのインストールを行います。

Installing TensorFlow on Ubuntu  |  TensorFlow

目次

Anacondaのインストール

f:id:am1tanaka:20171215164229p:plain

  • 64bit版の方がよさそうだったので、 64-Bit(x86) Installerをクリックしてダウンロードします
  • ダウンロードが完了したら、ダウンロードフォルダーを開きます
  • ダウンロードしたAnaconda3-x.x.x-Linux-x86_64.shファイルを右クリックして、[パスをコピーする]を選びます

f:id:am1tanaka:20171215164740p:plain

  • スタートメニューから実行を選択して、lxteと入力して、ターミナルを起動します
  • ターミナル画面を右クリックして、貼り付けをします
  • インストーラーが起動するので、指示に従ってインストールしていきます
  • [Enter]キーを押します
  • ライセンス規約が表示されるので、[Enter]キーを押して全て表示します
  • ライセンス規約に同意するか質問されるので、yes[Enter]キーで確認します

f:id:am1tanaka:20171215165007p:plain

  • インストール先が表示されます。特に問題がなければ[Enter]キーを押して進めます

以上でAnacondaのインストールは完了です。最後にパスを設定しておきます。

  • atom ~Atomでユーザーフォルダーを開きます
  • .profileを探してクリックして開きます
  • 最後に以下の行を追加します
PATH="$PATH:~/anaconda3/bin"
  • 上書き保存したら、Atomは閉じて構いません
  • ターミナルでsource ~/.profileを実行します

以上でパスの設定完了です。conda -Vと入力すると、バージョンが確認できます。

tensorflow用の仮想Pythonを作成

anacondaでTensorFlow用の環境を作成します。設定名をtensorflowにして、Pythonのバージョンは3.5にします。現時点でのPythonの最新版は3.6.3ですが、TensorFlowがまだ3.5までのサポートなので、それにあわせます。

ターミナルから以下を実行します。

conda create -n tensorflow python=3.5

インストールが開始して、確認が表示されたら[Enter]キーを押して作業を進めます。

インストールが完了したら以下を実行してTensorflow用の環境に切り替えます。

source activate tensorflow

f:id:am1tanaka:20171215170945p:plain

上記のように、行頭に(tensorflow)と表示されれば成功です。

TensorFlowパッケージのインストール

必要なパッケージをインストールします。インストールフォルダーを作成して移動したら、インストールコマンドを実行します。

pip install --ignore-installed --upgrade tensorflow

インストールが終わったら完了です。

動作確認

動作確認します。

  • pythonを実行して、Pythonを起動します
  • >>>に続けて、以下を入力していってください
import tensorflow as tf
hello = tf.constant('Hello, TensorFlow!')
sess = tf.Session()
  • 上記まで実行したところで、Your CPU supports...というようなメッセージが表示される場合があります。これは、このCPUの機能を全て使っていないので、ソースからビルドするとTensorFlowの動作を高速化できます、というメッセージです。そのままでもそこそこ速いので、必要性が出てくるまではこのままでいきます。今後も同様の警告が表示されるかもしれませんが、無視して構いません
  • 以下を実行します
print(sess.run(hello))

これでb'Hello, TensorFlow!'のように表示されれば、TensorFlowの動作確認完了です。

f:id:am1tanaka:20171215171932p:plain

終了する手順

TensorFlowの停止方法です。

  • [Ctrl]+[D]キーでPythonを終了します
  • source deactivateを実行して、tensorflowの仮想環境を終了します

以上で終わりです。コマンドラインを閉じて構いません。

作業を再開する手順

作業の再開方法です。

  • スタートメニューの実行からlxteなどを入力してターミナルを起動します
  • source activate tensorflowを実行して、TensorFlow用の仮想Pythonを起動します
  • 必要に応じて、cdコマンドで作業用フォルダーに移動します
  • pythonを実行して、インタープリターを起動するか、pythonを実行します

まとめ

以上で、TensorFlowの実行環境が整います。 Getting Started With TensorFlow  |  TensorFlowMNIST For ML Beginners  |  TensorFlow などに進んでください。手書き文字認識のチュートリアルなどで外部ファイルを利用する際は、作業用のフォルダーを作成して、その中で作業するとよいかと思います。

参考URL

TextMesh Proのデフォルトのスプライトの設定方法

TextMesh Proではフォント以外に、spriteタグを使えばスプライトを表示することができます。自分で作成したスプライトを表示しようとしたら、デフォルトのスプライトが表示されて、作成したものを表示するのに苦労したので、メモを残しておきます。

目次

TextMesh Pro用のスプライトアセットの作り方

Sprites, TextMesh Pro Documentationの通りです。ざっと手順は以下の通り。

  • スプライト用の画像をProjectビューにドロップ
  • Inspectorビューから以下を設定
    • Texture Typeは[Sprite (2D and UI)]
    • Sprite Modeは[Multiple]
    • Sprite Editorを開いて、文字をSliceして切り分ける

上記で分割したら、スプライトを選択して、右クリック -> Create -> TextMeshPro -> Sprite Asset を選択します。

f:id:am1tanaka:20171202004145p:plain

同じフォルダーに、作成したスプライトと同じ名前のアセットが作成されます。

Projectビューで、 Resources -> Sprites というフォルダーを作成して、作成したスプライトのアセットを作成したフォルダー内に移動させます。TextMesh Proは、このフォルダーからフォントを探します。

f:id:am1tanaka:20171202004346p:plain

デフォルトのスプライトを設定

これをやると楽です。Projectビューの検索ボックスにTMP Settingsと入力して検索します。すると、アセットが見つかりますので、それを選択します。

f:id:am1tanaka:20171202004524p:plain

InspectorビューでDefault Sprite Assetという項目を探して、そこに作成したスプライトアセットを設定します。

f:id:am1tanaka:20171202004606p:plain

以上で、デフォルトのスプライトが作成したスプライトになりますので、TextMesh Proでファイルを指定しなくてもよいので楽です。

表示方法

スプライトをTextMesh Proで表示するには、Textにspriteタグを指定します。スプライトはインデックスや名前で指定できます。以下のように書くと、インデックスの0と1と2に該当するスプライトが表示されます。

<sprite=0><sprite=1><sprite=2>

以上です。

参考URL

www.youtube.com

こちらでSettingの仕方を発見しました。それ以外は以下のサイトにて。

Amplify Shader Editorでロを描くシェーダーを作ってみた

目次

はじめに

Unity1週間ゲームジャムのSpaceの回で開発したで、シェーダーが使いたくなりました。当初公開版のロの発射は、以下のようなアニメーションをしています。

f:id:am1tanaka:20171201005113g:plain

この時はシェーダーが分からなかったので、テクスチャーを複製してアルファ値を書き換えて、以下のようなアニメーションパターンを生成してアニメさせました。

f:id:am1tanaka:20171122221058p:plain

しかし、手段として不細工だし、本来は以下のような感じで、書き順で出現させたかったのです。

f:id:am1tanaka:20171201000651g:plain

このようなシェーダーをAmplify Shader Editorで作ってみました。この記事で使ったバージョンは 1.3.9です。

準備

Amplify Shader Editorは、2017/11/29現在、Asset Storeでトップセールスを叩き出している人気アセットです。Unity1週間ゲームジャムのキャンペーンでいただいたバウチャーでゲットしました。

まず、どのようなことができるかを汗人柱様のこちら( 【Amplify Shader Editor】ノードベースでシェーダ作りのAmplifyを触ってみました。エディタの操作性、学習コスト、サンプルデモを大量に紹介! - Unity AssetStoreまとめ )でざっと確認。その上で、実際に自分でもアセットをインポートして、サンプルを動かしてみました。うちの数年前のしょぼいLen○vo E440でも問題なく動きます。凄い。

そして、上記のブログにリンクがありました以下の小林 信行様のスライドを見ながら、基本的な使い方をヨチヨチと学びました。時間的には3時間ぐらいやったと思います。

www.slideshare.net

バージョンが変わっていて、ちょくちょく違う部分がありました。大きく引っかかったのは以下の3つほど。

  • Node Propertiesの表記がなくなって、マスターノードの時はOutput Nodeなど、選択時のノードの名前に変わった(マスターノードではなく、アウトプットノードという名前かも。もしそうだったら読み替えてください)
  • マスターノードプロパティの項目が色々変わっている。Available Propertiesとかなくなってる(多分)
  • ノーマルマップのNormalという項目がUnpack Normal Mapに変わった

UVアニメーションを操作してみた辺りでシェーダーの凄さに感動しました。

作ってみる

雰囲気がつかめたので、なんとなく方針が思い浮かびました。やりたかったことは以下の2点です。

  • 半透明のオブジェクトに影が落ちるようにする
  • floatのパラメーターをMaterialに追加して、0~1を変化させて、ロが徐々に描きあがるようにする

書き順は、テクスチャーの赤の要素で表すことにしました。黒から真っ赤までで0~255の値を表せます。0が描画開始時で、255で完成です。

利用したテクスチャー

まずは、普通に描画するための四角のテクスチャーです。

f:id:am1tanaka:20171130001925p:plain

これに、書き順を表す赤色の以下のようなテクスチャーを用意しました。暗いところが早く描かれて、真っ赤な部分が最後に描かれるというように使います。

f:id:am1tanaka:20171130001821p:plain

背景と、ノーマルマップの作成に以下の画像を使いました。

f:id:am1tanaka:20171130174014p:plain

シーンの作成

作業用のシーンは以下のように作りました。

f:id:am1tanaka:20171130183837p:plain

Main Camera

以下の設定をしました。

  • Position 0, 0, -10
    • カメラのデフォルトはYが1で、配置しずらいので0
  • Projection [Orthographic]
    • 平行投影にしました
  • Size 2
    • 高さの半分を2、つまり、画面の高さは4にしました
  • Clipping PlanesのFarを50
    • 奥行きは不要なので、距離を縮めて少しでもデプスバッファの精度を上げようとしました。うちのAndroid端末ではあまり効果なしでしたが^^;

Directional Light

影が綺麗になっていなかったら、Shadow TypeのResolution欄を[Very High Resolution]にします。

背景

Quadを作成して、以下を設定しました。

  • Positoin 0, 0, 0
  • Scale 4, 4, 1

マテリアルを作成して、背景画像を設定しました。

ボール

影が落ちるかのテストのためのボールをSphereで作成しました。特に設定はないので、適当に配置します。

Quadを作成して、Positionを0, 0, -0.01に設定しました。Zを0より少し手前にしないと、背景と重なってしまうので、Zには-0.01を設定してあります。

このオブジェクトは他のオブジェクトに影を落とす必要は無いので、Mesh RendererのCast Shadow欄を[Off]にします。

カスタムシェーダーの作成

Asset StoreからAmplify Shader Editorをインポートしたら、シェーダーを作成します。

ProjectビューのCreateから、Amplify Shader -> Surface Shaderを選択します。

f:id:am1tanaka:20171130002337p:plain

新しいシェーダーが作成されて、Amplify Shader Editorが開きます。名前をつけて保存して、すぐにQuadに割り当てます。

ウィンドウ左上のShader Name欄をRo Draw Shaderなどに変更します。変更されたら自動的に保存されるように、灰色の丸いアイコンをクリックして緑にします。

f:id:am1tanaka:20171130192111p:plain

これで、UnityのProjectビューに新しいシェーダーが保存されます。シェーダーのファイル名もRo Draw Shaderなどに変更しておきましょう。

f:id:am1tanaka:20171130192314p:plain

これをQuadに割り当てます。まずはProjectビューのCreateボタンから、Materialを選択して、マテリアルを作成して、名前をRo Materialなどにします。

作成したマテリアルを選択したら、InspectorビューのシェーダーをRo Draw Shaderに切り替えます。

f:id:am1tanaka:20171130192533p:plain

作成したマテリアルを、Quadにドラッグ&ドロップすると、まだ何も設定していないシェーダーでQuadが描画されるようになります。

f:id:am1tanaka:20171130192717p:plain

実際に画面の変化を確認しながら、シェーダーを作成していきます。

Amplify Shader EditorのCanvasの操作

Amplify Surface Shaderを表示するウィンドウをCanvasといいます。表示するには、シェーダーのダブルクリック、あるいは、Windowメニューから Amplify Shader Editor -> Open Canvas メニューを選びます。

f:id:am1tanaka:20171130211014p:plain

Canvasウィンドウは以下のようになっています。

f:id:am1tanaka:20171130211758p:plain

編集エリアの操作方法は以下の通りです。

  • マウスのホイール回転で拡大縮小
  • マウスのホイールか右ドラッグ移動で、平行移動
  • マウスの左クリックで選択
  • 端子上で左ドラッグで、線を引く
  • マウスの左ドラッグで、複数のノード選択

Canvasに表示されている四角いものをノードと呼びます。最初に表示されているものをマスターノードといい、このノードの端子に様々な素材や計算結果を接続することで、シェーダーを作ります。マスターノードのプロパティーで、シェーダーの本質的な属性を設定します。

テクスチャーを描画する

では手始めに、テクスチャーを描画してみます。

Canvasのなにも無いところを右クリックして、Search欄にTextureと入力して候補を絞り、[Texture Sample [ T ]]を選択します。

f:id:am1tanaka:20171130212553p:plain

テクスチャーを設定するためのノードが作成されます。

f:id:am1tanaka:20171130212613p:plain

メニューに書いてあった[ T ]というのは、[T]キーを押しながら画面を左クリックすると、そのノードを作れる、という意味です。よく利用するノードにはこのようなショートカットキーが割り振られています。覚えられる人は覚えておくとよいでしょう(僕はあまり覚えられませんが)。

最初、名前が[Texture Sample 0]などになっているので、プロパティーウィンドウのName欄か、名前の部分をダブルクリックして選択して、Textureなどに変更しましょう。

f:id:am1tanaka:20171130212802p:plain

これをマスターノードに繋げます。ノードには端子と呼ばれる丸い要素が並んでいて、隣に文字が書いてあります。例えばTexture Sampleノードには[Tex][UV]というノードと、[RGBA][R][G][B][A]という合計7つの端子があります。このうち、左側にある[Text]と[UV]は入力端子で、データを入力するためのものです。右側に並んでいる残りの端子は出力端子で、このノードの出力結果を次のノードの入力端子に接続することで渡します。

TextureノードのRGBAノードをドラッグして、マスターノードのAlbedoノードにドロップしてください。

f:id:am1tanaka:20171130213300p:plain

これでTextureノードに設定したテクスチャーを描画する準備ができました。あとは、このノードにテクスチャーを渡します。これはUnityのMaterialでやりましょう。

Unityに切り替えて、先ほど作成したロ用のマテリアルを選択します。

f:id:am1tanaka:20171130213606p:plain

Projectビューからロ用のテクスチャーをドラッグして、InspectorビューのTexture欄にドロップします。

f:id:am1tanaka:20171130213712p:plain

これでテクスチャーが表示されるようになりました。

f:id:am1tanaka:20171130214134p:plain

テクスチャーの調整

良く見ると、真ん中が透過していません。また、不要なデータが生成されたりしているので、テクスチャーの読み込み方を変更します。テクスチャーを選択して、Inspectorビューを以下のように設定します.

  • Alpha Is Transparentにチェックを入れて、透過を有効にする
  • 今回は縮小して使うことはないので、Generate Mip Mapのチェックを外して、不要な縮小イメージの生成をやめる
  • ループして表示することはないので、Wrap Modeは[Clamp]に変更
  • 拡大縮小時の修正は不要なので、Filter Modeは[Point (no filter)に変更

以上設定したら、[Apply]ボタンを押して、変更を確定します。

f:id:am1tanaka:20171130214519p:plain

今度は謎の模様が表示されるようになりました。マスターノードの設定をして解決します。

f:id:am1tanaka:20171130213806p:plain

マスターノードの設定

Amplify Shader EditorのCanvasを開きます。マスターノードをクリックするか、右上の[+]をクリックすると、マスターノードが選ばれます。必要な属性を設定していきます。設定したら、少し待つと保存とシェーダーのビルドが実施されて、Unityの画面も変わります。色々と設定をいじって、動作を確認するとよいでしょう。

  • 影を落とす必要はないので、Cast Shadowsのチェックを外します
  • 半透明が使えて、かつ、影を受けるには独自の設定が必要なので、Blend Modeを[Custom]に変更します
  • Render Typeを[Transparent]に変更します
  • Render Queueは、ジオメトリ後に描画した方が半透明の結果がよくなりそうなので、[Alpha Test]に変更しておきます
    • ここをTransparentにすると、影のあとの描画になるため、影が落ちなくなります

f:id:am1tanaka:20171201000043p:plain

Render TypeをTransparentに変更したので、マスターノードのOpacity端子が使えるようになりました。テクスチャーのアルファ端子をマスターノードのOpacity端子に繋げば、期待の結果になります。

f:id:am1tanaka:20171130220516p:plain

f:id:am1tanaka:20171130220635p:plain

以上で、やりたいことの1つである半透明のオブジェクトに影を落とすことができました。次は描き順を実装します。

描き順の考え方

出力 -> 入力 -> 処理 の順番で検討するとまとめやすいです。

出力

線を描きたい部分はテクスチャーのアルファ値をそのまま出力して、まだ描画したくない場所のアルファ値を0にできればうまくいきそうです。

入力

  • どこまで描いているかを表すfloat値Stroke
  • 描き順のテクスチャーを設定するStroke Texture

以上の入力があればいけそうです。

処理

知識がないので、if的なものしか思い浮かびませんでした。とりあえず動かすということで、今回はこれでいきます。

必要なノードを揃える

floatパラメーターの作成

描き順のパラメーターを表すノードを作ります。Amplify Shader EditorのCanvasの何もないところを、[1]キーを押しながら左クリックします。そうすると、Floatノードが作成されます。名前を`Stroke‘にしておきます。

Materialのインスペクターに表示するために、Typeを[Property]に変更します。Materialが選択されていれば、これでマテリアルから値を設定することができます。

このパラメーターは0~1の範囲で値をとるので、Minを0、Maxを1にしておきましょう。

f:id:am1tanaka:20171130224657p:plain

テクスチャーノードの作成

シェーダーに描き順のテクスチャーを設定できるようにします。[T]キーを押しながら何もないところをクリックするなどして、Texture Sampleを追加します。NameをStroke Textureなど、分かるように変えておきましょう。

f:id:am1tanaka:20171130224959p:plain

Compareノードの作成

以下の判定ができるCompareノードを追加します。Canvasの右のウィンドウからLogical Operatorsの左の三角をクリックして開きます。その中に[Compare (A <= B)]を表すものがあるので、それをドラッグして、Canvasの編集エリアにドロップしてください。

f:id:am1tanaka:20171130225327p:plain

f:id:am1tanaka:20171130225452p:plain

接続する

ノードを接続していきます。

  • Stroke TextureノードのR端子を、CompareノードのA端子に接続します
    • 描き順テクスチャーの赤色が比較対象になります
  • Strokeノードの出力ノードを、CompareノードのB端子に接続します
    • これで、A端子に入力されるStroke Textureの赤要素の値が、Materialで設定したStrokeの値以下だった場合にTrue、大きい場合にFalseに入れた値が出力されるようになります
  • TextureノードのA端子を、CompareノードのTrue端子に接続します
    • 比較結果が成立している時に、Textureノードの元のアルファ値が設定されるようにします
  • Stroke TextureノードのG端子(B端子でも可)を、CompareノードのFalse端子に接続します
    • Stroke Textureは赤のみ使っているので、GとBは常に0です。比較結果が不成立の時、0を出力したいので、この値を設定しました
  • Compareノードの出力端子を、マスターノードのOpacity端子に接続します
    • 比較結果を、透明度として設定します

以上でシェーダーは完成です!

f:id:am1tanaka:20171130230951p:plain

Unityの設定

シェーダーは完成したので、Unityで必要なパラメーターを設定します。

テクスチャーファイルの形式を設定

描き順を赤色で示したテクスチャーをProjectビューに読み込ませて選択して、Inspectorで以下の設定をします。

  • Alpha Sourceは不要なので[None]に変更
  • MipMapは不要なので、Generate Mip Mapのチェックを外す
  • リピート描画はしないので、Wrap Modeを[Clamp]に変更
  • 拡大縮小時の補間は不要なので、Filter Modeを[Point (no filter)]に変更
  • [Apply]ボタンをクリック

f:id:am1tanaka:20171130222142p:plain

シェーダーにパラメーターを設定

Projectビューから、シェーダーを設定したマテリアルを選択します。Inspectorビューを確認すると、Stroke Texture欄と、Stroke欄が増えています。Stroke Texture欄に、赤色の描き順テクスチャーを設定してください。

f:id:am1tanaka:20171130231301p:plain

動作確認

これで準備完了です。InspectorビューのStrokeを操作して、値を変更させてみてください。0の時は左上に少し描くだけで、値を増やすに従って、ロが描かれていくようになります。

f:id:am1tanaka:20171201000651g:plain

複数のオブジェクトに対応させる

これで完成!と思ったのですが、実用段階で問題が出てしまいました。オブジェクトが1つなら問題ないのですが、複数のオブジェクトを別々にアニメーションさせようとするとうまくいきません。

原因は、StrokeプロパティーをMaterialで渡していることです。Materialは全てのオブジェクトが共通のものを見ますので、個別にアニメーションさせることができないのです。

対策は、StrokeプロパティーのTypeを、[Property]から[Instanced Property]に変更することです。Instanced Propertyは、GPU内で複製を生成して、個別に値を持たせる機能です。このプロパティーはスクリプトからしか値が渡せないので、開発時はMaterialで渡す方が楽そうです。あるいは、以下に汎用的に使えるスクリプトを掲載しましたので、最初からこれをテスト用のオブジェクトにアタッチする手もあります。

対応手順

Amplify Shader EditorのCanvasで、Strokeノードを選択して、パラメーターのTypeを[Instanced Property]に変更します。

f:id:am1tanaka:20171201215542p:plain

灰色でProperty Nameと書いてある欄の_Strokeが、このプロパティーにアクセスする時の名前です。

マテリアルが、Instanced Propertyを扱えるように設定します。Projectビューから、シェーダーを割り当てたマテリアルを選択します。InspectorビューのEnable GPU Instancingにチェックを入れます。

f:id:am1tanaka:20171201220733p:plain

シェーダーをアタッチしたオブジェクトに、新規でC#スクリプトを作成してアタッチして、RoAnimatorScriptなどの名前にします。スクリプトは、以下の通りです。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RoAnimatorScript : MonoBehaviour {

    [TooltipAttribute("描き順の進捗を0-1で表します。")]
    public float Stroke = 0f;
    // メッシュレンダラーのインスタンス
    private MeshRenderer meshRenderer;
    // 設定するプロパティー
    private MaterialPropertyBlock props;

    void Start () {
        meshRenderer = GetComponent<MeshRenderer>();
        Stroke= 0f;
        props = new MaterialPropertyBlock();
        Update();
    }

    // Update is called once per frame
    void Update () {
        props.SetFloat("_Stroke", Stroke);
        meshRenderer.SetPropertyBlock(props);
    }
}

オブジェクトにfloat型のStrokeプロパティーを持たせて、Update()時にMeshRendererにプロパティーを渡すスクリプトです。_Strokeが、先ほどシェーダーで確認した、シェーダー側のプロパティー名です。

これで今度こそ完成です。オブジェクトごとに別のStroke値を持つことができるようになったので、あとはスクリプトやアニメーションで、このオブジェクトのStrokeプロパティーの値を変更するようにしてください。

f:id:am1tanaka:20171201221418g:plain

Animationでのパラメーターの調整

RoAnimatorScriptのStrokeパラメーターをAnimationに追加すれば、赤色テクスチャーで調整をしなくても、Animationの方で描き方に緩急を付けることができます。

f:id:am1tanaka:20171201222042p:plain

まとめ

目的のシェーダーが完成しました。ノードのグラフを見ながら操作できるので、コードで組み立てるよりも遥かに分かりやすく、直感的でした。ぼんやりと作り方の方針が思い浮かんだ状態で、ぽちぽちと操作をしていったら、いつの間にか完成していて驚きです。シェーダー初心者で、これから学んでみようという方にはオススメです。

ビジュアルスクリプティングはマウス操作が面倒で好きではないのですが、これは認めざるを得ません。Amplify Shader Editorで作成したシェーダーを通常のコードで見ることもできるので、自分が作ったシェーダーがどのようなコードで動くのかを見ることができて、コードでの組み立て方の雰囲気も掴めました。

今回はCompareで分かりやすく比較しましたが、もっとエレガントな方法がある気がします。いずれそれが分かる時がきたら追記しようと思います。

参考URL

UI Builderでボタンを作ってみた

かっこいいUIが欲しい!ということで購入してみました。とりあえず簡単なボタンの作例を示したのち、添付のドキュメントをざっくり意訳したものを書きました。

目次

ボタンを作ってみる

UI Builderを使って、以下のようなランキングやツイートを呼び出すボタンを作ってみました。

f:id:am1tanaka:20171128232931p:plain

ボタンを作る

ボタンは普通にUnityのUIのButtonで作ります。

HierarchyビューのCreateをクリックして、UI -> Buttonを選択して、ボタンを作成します

f:id:am1tanaka:20171128221719p:plain

名前を適当に決めます。例えばTwitterButtonなど。

ボタンの形状を設定する

ボタンの形を画像から選びます。Projectビューから、UI - BUILDER -> Prefabs -> Source Files -> Panels ->Panels@1x-assets フォルダーを開きます。カテゴリーごとに、様々なパネルのスプライトが入っています。

今回は、ターゲットデバイスの高さを1136ピクセルにしたので、Panels@1x-assetsフォルダーのものを使います。Panels@1x-assetsフォルダーにはより高い解像度の画像がありますので、高解像度のスマホ向けなどの場合は、2xの方を選択するとよさそうです。

画像を確認するには、ProjectビューをTwo Column Layoutにすると便利です。One Column Layoutに設定していたら、Projectビューの右上のハンバーガーメニューから切り替えるとよいです。

f:id:am1tanaka:20171128221156p:plain

片側にくっつけるボタンということで、OneSidePanelsフォルダーを選択して、作りたいボタンに合う形のものを探します。今回は、OneSideCornerPanelRadius 50px Fill.pngにします。

f:id:am1tanaka:20171128222200p:plain

先ほど作成したボタンを選択します。選んだOneSideCornerPanelRadius 50px Fill.pngをドラッグして、InspectorビューのSource Image欄にドロップします。

f:id:am1tanaka:20171128222527p:plain

これでボタンの形状が設定できました。Rect Transformを調整して、配置や大きさを整えます。

f:id:am1tanaka:20171128222959p:plain

アイコンを設定

アイコンを設定します。ボタンの子供にTextが設定されていますが、これを削除してImageに変更して、そこにアイコン画像を設定しましょう。HierarchyビューからCanvas -> TwitterButtonを開いて、子供のTextを選択して、Deleteキーや右クリック -> Delete で削除します。

f:id:am1tanaka:20171128223302p:plain

TwitterButtonオブジェクトを右クリックして、UI ->Image でイメージを追加します。

f:id:am1tanaka:20171128223358p:plain

アイコンを探します。ProjectビューからUI - BUILDER -> Source Files -> Icons -> Icons@1x-assets フォルダーを開くと、アイコンがカテゴリー分けされています。Socialフォルダーを開くと、それらしい画像が見つかります。

f:id:am1tanaka:20171128223643p:plain

Hierarchyビューから、先ほどのTwitterButtonの子供として作成したImageオブジェクトを選択します。

f:id:am1tanaka:20171128223735p:plain

探したツイート的アイコンをドラッグして、InspectorビューのSource Image欄にドロップします。

f:id:am1tanaka:20171128223830p:plain

色が同じでよくわかりませんが、これでアイコンが設定できました。

f:id:am1tanaka:20171128223850p:plain

色を設定

ボタンの地とアイコンを着色します。UI Builderの色見本を確認します。ProjectビューからUI - BUILDER -> Prefabs -> 1. Fundamental UI Elements -> ColorSchemesフォルダーを開きます。

最初の__ColorsPalettePreviewプレハブに、全ての色見本が設定されています。これをSceneビューにドラッグ&ドロップして、表示します。

f:id:am1tanaka:20171128224622j:plain

UI Builder 1.2には18種類の色見本が用意されています。イメージに合いそうな色見本を採用して、その色を使います。

HierarchyビューからTwitterButtonオブジェクトを選択します。InspectorビューのImageコンポーネントのColor欄の右のスポイトをクリックして、色の選択モードにします。

f:id:am1tanaka:20171128225311p:plain

色見本から、使いたい色の上でクリックします。同様に、子供のImageオブジェクトも選択して、ツイートアイコンの色も設定します。

ついでに背景の色も、真っ黒ではなく、色見本の一番暗い色に変更してみました。背景の色は、Main Cameraで設定できます。InspectorビューのClear Flags欄をSolid Colorに変更して、Background欄の右のスポイトをクリックして、色見本から設定したい色を拾います。

f:id:am1tanaka:20171128230059p:plain

以下のようになりました。左が背景色が真っ黒。右が背景色を調整したものです。心なしか、お、いい感じ、という雰囲気になった気がします。

f:id:am1tanaka:20171128230450p:plain -> f:id:am1tanaka:20171128230211p:plain

ランキングボタンを作成する

ランキングボタンは、ツイートボタンを複製して作ります。

HierarchyビューでTwitterButtonを選択したら、[Ctrl]+[D]キーで複製して、名前をRankingButtonに変更します。

f:id:am1tanaka:20171128230802p:plain

画面の反対側に配置します。ボタンの形を左右反転させたいので、ScaleのXを-1にします。

f:id:am1tanaka:20171128231137p:plain

アイコンをトロフィーっぽいのに変更します。Projectビューから UI - Builder -> Source Files -> Icons -> Icons@1x-assets -> Standardフォルダーを開いておきます。

Hierarchyビューから、Canvas -> RankingButtonを開いて、Imageオブジェクトを選択します。

f:id:am1tanaka:20171128231512p:plain

Projectビューからトロフィーっぽいアイコンをドラッグして、InspectorビューのImageコンポーネントのSource Image欄にドロップします。

f:id:am1tanaka:20171128231554p:plain -> f:id:am1tanaka:20171128231645p:plain

色を黄色っぽいものに変更してみました。以下、完成イメージです。

f:id:am1tanaka:20171128231807p:plain

まとめ

使いたいデザインを探して、それをUnityのUIのImageに設定することで簡単に自由な大きさに調整することができました。また、色見本でバランスの良い配色にすることでとても画面が引き立つことが感じられました。

他にも、アニメーションやサンプル画面などがあり、配色やデザインの勉強にもなります。

センスのある人ならいいのですが、自分のような者だと、時間をかけて画面をデザインした挙句、残念なものになることが多かったです。このアセットを使えば、時短とクオリティーアップを両立できそうです。もっと早く使っておくべきでした。ソリッドな雰囲気のゲームを作るのには、この色見本や形状はとても役立ちそうです。

有料のアセットですが、Unity1週間ゲームジャムなどのゲームジャムに参加したり、ちょくちょく個人製作をするのであれば、このお値段は安いです。

こちらに、付属ドキュメントの意訳を書きました。併せてご利用いただければ幸いです。

UI Builder 1.2 ドキュメントの意訳

画面を少しでもセンス良くしたい・・・と思ってUI Builderを購入してみました。ドキュメントを読んだので、間引きしつつの意訳をまとめておきます。

目次

1. はじめに

UI Builderは、初心者が初めてUIを作る場合にも、プロが仕事を効率化するのにも使えます。

  • 200以上の切り分けられた要素
  • 130以上のピクセルアイコン
  • 1つのフォントと10通りのスタイル
  • 70以上のドラッグ&ドロップ要素
  • 30以上の古典的アプリケーションの画面例
  • 23以上の基本的なゲームの画面例
  • 3つのiWatchの例
  • 20以上の色の組み合わせ(Color Scheme)
  • 9つのHD写真イメージ

UI Builderが提供するこれらの要素を組み合わせたり、変更したりして、独自のユーザーインターフェースや、UnityのGUIシステム用のスキンやスプライトを作ることができます。

(追記:用意されている要素の一覧を手っ取り早く確認するには、Projectビューから UI - BUILDER -> Scenes - All Elements In One Place -> UI - Builder Scene を開きます)

f:id:am1tanaka:20171128133728p:plain

2. 基本的なUI要素

矩形や円、三角形といった基本的なスライスされた要素について、様々な大きさ、太さ、角の丸みのものが用意されています。これらの基本要素をカスタマイズすることで、多様な基本図形を作ることができます。色の組み合わせやアイコン、文字(フォント)も組み合わせます。

a) 切り分けられた形状(Sliced Panels - Circles - Knots - Tags]

f:id:am1tanaka:20171128124623p:plain

スプライトエディターは、9-slicing(9つに切り分けられた)画像をサポートします。このプレハブの要素を使うことで、選んだ要素のサイズを自由に調整できるようになります。

使い方

  • Projectビューから Source Files -> Panels -> Panels@1x-assets あるいは Panels@2x-assets -> 使いたい形状 を選択します
    • Panels@1x-assetsは標準のピクセル数、Panels@2x-assetsはその2倍のピクセル数の高解像度用の画像です
  • UI -> Image を作成するか、ゲームオブジェクトにImageコンポーネントを追加します
  • 作成したUIパネルやImageコンポーネントのSource Imageフィールドに、選択した形状をドラッグ&ドロップします
  • 色、画像タイプ(Simple, Sliced, Tiled あるいは Field)を選択します

f:id:am1tanaka:20171128215329p:plain

  • 選択した形状を使って、作りたい形状やストロークになるように調整します
  • UI Builderに用意された作成済みの要素を使うこともできます

b) Typography(文字表現)

モダンなフォントとして最適なOpen Sansの10種類のスタイルが用意されています。TextコンポーネントのFontとして設定して使うことができます。

f:id:am1tanaka:20171128133907p:plain

使い方

  • UI -> Text を作成するか、ゲームオブジェクトにTextコンポーネントを追加します
  • TextコンポーネントのFont欄のコンテンツ選択ボタンをクリックして、使いたいOpen Sansのスタイルを選択します
  • 色や大きさ、アライメントなどを調整して使います

c) アイコン

130を超えるアイコンが用意されています。これらは、以下の7種類のカテゴリーに分類されています。

  • ナビゲーションアイコン
  • メディアアイコン
  • 天気アイコン
  • スタンダードアイコン
  • テクノロジーアイコン
  • ロケーションアイコン
  • アプリアイコン

f:id:am1tanaka:20171128143409p:plain

使い方

  • UI -> Imageを作成して、Source Image欄に使いたいアイコンを設定します
    • Source Image欄のコンテキスト選択ボタンを押すか、Projectビューから UI - BUILDER -> Source Files -> Icons フォルダーに入っているので、その中から探します(等倍、2倍、4倍のものがカテゴリー別に入っています)
  • イメージのタイプをSimpleにします
  • Set Native Sizeボタンをクリックして、元画像のアスペクト比にします
  • 同じゲームオブジェクトにButtonコンポーネントを追加すれば、ボタンとして動くようになります

d)Color Schemes

Color Schemesで用意した色の組み合わせを使って、簡単にユーザーインターフェースの色を決められます。UI-Builderのゲームやアプリインターフェースの例でもこの色が使われています。美的に見えるような色の組み合わせを用意してあります。

使い方

  • Projectビューから UI-BUILDER -> Prefabs -> 1. Fundamental UI Elements -> ColorSchemesフォルダーを開きます
  • __ColorsPalettePreview をシーンに配置します
  • 色を設定したいコンポーネントのColor欄のスポイトアイコンをクリックします
  • 配置した__ColorsPalettePreviewから、使いたい色を選択します

以上です。__ColorsPalettePreviewは、使わない時はInspectorビューの上のチェックを外して、無効にしておくと良いでしょう。

3. 作成済みのUIコンポーネントエレメントの使い方

Panel, Scroll View, Chart, Input, Scroll Bar, Toggle/Switch, Slider, Label, Tag, Buttonそしてカスタムパネルといったドラッグ&ドロップ要素が用意されています。

f:id:am1tanaka:20171128161148p:plain

使い方

作成済みのUIエレメントを使う場合、いくつかのオプションが使えます。

  • a) Projectビューの UI - BUILDER -> Prefabs -> 2. Ready-Made Component Elements フォルダーに、カテゴリー分けされて要素のプレハブがあるので、それを使いたいシーンに配置します
  • b) 同フォルダーにある __Ready-Made Component Elements プレハブをシーンに配置すると、全ての要素が確認できるので、そこから必要なエレメントを使いたいシーンに配置します
  • b) Projectビューの UI - BUILDER -> Scenes - All Elements In One Place -> UI - Builder Scene シーンを開いて、必要なエレメントを使いたいシーンに配置します

4. UI Templates of Applications and Games

このアセットを利用して構築したアプリケーションやゲームの画面例です。

f:id:am1tanaka:20171128170730p:plain

もし、これらのゲームやアプリを実際に作成したい場合、用意されているテンプレート画面にプログラムを実装して、ストアにアップロードできます。

5. Animations

クリック時やホバー時、揺れて警告を知らせるダイナミックなもの、情報バナー、バブルといった10種類以上のアニメーションが用意されています。

全てのアニメーションは、親オブジェクトのScaleが1,1,1の時のみ、正しく動作します。親オブジェクトのScaleが1,1,1で、アニメーションオブジェクトがその親の子に設定しなければ正しく動作しません。親のオブジェクトにButtonコンポーネントを加えて、Animatorコンポーネントも必要に応じて設定します。子のオブジェクトからは全てのAnimationコンポーネントを削除します。

6. 容量の節約とスプライトのクオリティ

スプライトには事前にPacking Tagは設定されていません。そのため、スプライトが統合されず、無駄な容量を消費します。作成済みのプロジェクトを使う場合、2通りの考え方があります。

その1

利用するスプライトが少数だったり、1つのスライス済みのスプライトを複製して使い回すような場合は、それほど容量の無駄はありませんので、Packing Tagは空欄のままで構いません

その2

容量を節約したり、ドローコールが多くて処理落ちするような場合は、以下のような対策が考えられます。

  • 主要なUIのCanvasを選択して、プレハブを作成します
  • Projectビューで右クリックをして、Select all dependenciesメニューを選択します
  • 選択したCanvasで利用されているアセットが選ばれるので、どのスプライトが使われているかが確認できます
  • 上記で確認したスプライトのPacking Tagに、My Spritesなどのように同じキーワードを設定して、Applyボタンを押します

以上で、Unityが実行する時に利用するスプライトを1つのアトラス(画像)にまとめますので、容量やドローコールに関するパフォーマンスの向上が期待できます。

共通の設定

スプライトを使ったCanvasについて、いくつか設定を確認します。EditメニューからProject Settings -> Quality を選択して、Textures Quality欄がFull Resになっていることと、Anti Aliasing欄をより高いサンプリング設定にすると、スプライトのクオリティーがより良くなります。また、2DゲームやSpriteが縮小して表示されないのであれば、Sprite設定のGenerate Mip Mapsのチェックは外しましょう。

最後に(田中記)

開発者への連絡方法や、バージョンアップの履歴などは省きました。訳の精度は保証できませんので、怪しい部分は元のドキュメントをお読みください。

また、ボタンの作例をこちらに書きました。併せてご覧いただければ幸いです。

Mathf.Clamp()とMathf.Repeat()

いつも、上限値を含むのかとか、マイナスになるとどうなるっけとか、忘れてしまうので。

Mathf.Repeat()

  • 上限値は含まない
    • Mathf.Repeat(3,3);は、0
  • -1で最大値になる
    • Mathf.Repeat(-1,3);は、2

Mathf.Clamp()

  • 上限値を含む(Mathf.Clamp(3,0,3);は、3

テストプログラム

   void Start () {
        for (float i=-5f; i<6f; i+=1f)
        {
            Debug.Log("Repeat("+i+", 4)="+Mathf.Repeat(i, 4f));
        }
        for (float i = -2f; i < 6f; i += 1f)
        {
            Debug.Log("Clamp(" + i + ", 0, 4)=" + Mathf.Clamp(i, 0f, 4f));
        }
    }

結果

Repeat(-5, 4)=3
Repeat(-4, 4)=0
Repeat(-3, 4)=1
Repeat(-2, 4)=2
Repeat(-1, 4)=3
Repeat( 0, 4)=0
Repeat( 1, 4)=1
Repeat( 2, 4)=2
Repeat( 3, 4)=3
Repeat( 4, 4)=0
Repeat( 5, 4)=1

Clamp(-2, 0, 4)=0
Clamp(-1, 0, 4)=0
Clamp(0, 0, 4)=0
Clamp(1, 0, 4)=1
Clamp(2, 0, 4)=2
Clamp(3, 0, 4)=3
Clamp(4, 0, 4)=4
Clamp(5, 0, 4)=4