UNITY ScriptableRenderLoop アウトラインのミス
前回調べた時に ポストエフェクトのアウトラインが入っていた・・・
EdgeDetectionというやつだ なので、Unity-chanシェーダーのアウトラインではなく ポストエフェクトのアウトラインが入っていた たしかこれはDepthや法線でアウトラインを出すタイプだったと思う
ということで、EdgeDetectionを切ったものを出力
これえで 正しいアウトラインが出た
しかし ScriptableRenderLoopを使ったものは、上記のチェックを外しても 変わらずだった
UNITY EdgeDetection
ふと気になった 先ほど出力した画像のSphereに アウトラインが付いている・・・・・ なぜだ??
カメラに EdgeDetectionってやつがいた! こいつ怪しい!
ってことで こいつをOFFしたら、Sphereのアウトラインが消え Unity-Chanのアウトラインが、カラー反映したいいものになった
元々作っていたアウトラインの上に 黒で上書きされていたようだ・・
アウトラインを付けるポストプロセスのようだ。
ってことで、アウトライン調査やり直しである
ScriptableRenderLoopでUNITY Chan表示
環境
ベータ版の機能なので EditorをUNITY2017のβを使います。今回は b10です
サンプル
GitHub - Unity-Technologies/ScriptableRenderLoop: Scriptable Render Loop 個々のサンプルを落とす 多分コンパイルエラー出るので、エラー出る所をつぶせばなんとかなるはず
UnityちゃんPluginをいれる
Unityちゃんと、Unity-Chan Toon2.0を入れてみましょう GUIが邪魔なので IdleChangeとFaceのスクリプトを無効にし
通常のレンダリングパイプライン
デフォルトの状態。 Edit->ProjectSettings->Graphicsの ScriptableRenderLoopを Noneにする カメラもForwardになっている事を確認
正しく表示されてます
BasicRenderPipeline
上記の設定を BasicRenderPipelineに変更すると
何も表示されなくなりました これは、Shaderパス名が違うからです。
今までのシェーダーではForwardの場合は ForwardBase というパスが実行されますが このRenderLoopでは BasicPass というパスを実行しているので その部分を修正してみる
BasicRenderPipeline.cs#Render が、実際のパイプライン
public static void Render(ScriptableRenderContext context, IEnumerable<Camera> cameras) { foreach (var camera in cameras) { // Culling CullingParameters cullingParams; if (!CullResults.GetCullingParameters(camera, out cullingParams)) continue; CullResults cull = CullResults.Cull(ref cullingParams, context); // Setup camera for rendering (sets render target, view/projection matrices and other // per-camera built-in shader variables). context.SetupCameraProperties(camera); // clear depth buffer var cmd = new CommandBuffer(); cmd.ClearRenderTarget(true, false, Color.black); context.ExecuteCommandBuffer(cmd); cmd.Release(); // Setup global lighting shader variables SetupLightShaderVariables(cull.visibleLights, context); // Draw opaque objects using BasicPass shader pass // var settings = new DrawRendererSettings(cull, camera, new ShaderPassName("BasicPass")); // パス名を変更する var settings = new DrawRendererSettings(cull, camera, new ShaderPassName("ForwardBase")); settings.sorting.flags = SortFlags.CommonOpaque; settings.inputFilter.SetQueuesOpaque(); context.DrawRenderers(ref settings); // Draw skybox context.DrawSkybox(camera); // Draw transparent objects using BasicPass shader pass settings.sorting.flags = SortFlags.CommonTransparent; settings.inputFilter.SetQueuesTransparent(); context.DrawRenderers(ref settings); context.Submit(); } }
なんとなく表示された。
ライティングが元と違う。原因調査中だけどライティングの計算式が違うのかな?
アウトラインが無くなった。 これに関しては デフォルトでは2パスでアウトラインを表示しています(オブジェクト拡大法で) 通常のレンダリングとは別に アウトラインのパスを暗黙的に実行します ところが ScriptableRenderLoopでは パスは明示的にしか指定できないため Outlineパスが呼ばれない ので、スクリプトと 先ほどのRenderを修正しなければならない
ScriptableRenderLoop概要
今までは情報がある程度まとまってから書いてたけど 試しに気にせずに毎日でも書くことにしたよ すぐ飽きるけど
ScriptableRenderLoopとは
UNITY2017から入る機能の1つで、現在はベータ版でお試しが可能 今までブラックボックスだった UNITYのレンダリングパイプラインをスクリプトでカスタマイズできる機能 具体的に何ができるかといわれると 難しいけど、G-Bufferとかライト計算とかいろいろと自由にできる
今までのRenderingPipeline
今までは レンダリングモードが Forwardの時は ForwardBase、Deferredは Deferred が実行されていた Unity - マニュアル: Unity のレンダリングパイプライン マルチパスは シェーダーにて 複数パスを書いて 暗黙的に実行させる ライトモードにより、実行するシェーダーパスは固定であり レンダリングパイプラインは変更する事が不可能
グラフィックスコマンドバッファ
Unity - マニュアル: グラフィックスコマンドバッファ
拡張され、指定されたタイミングで任意のGPU命令を実行させることが可能になった 上記の図の緑色の地点に コールバック関数を差し込むことが出来る 例えば ポストプロセスを行う時によく使われる
ただし、レンダリングパイプライン自体は変更する事が出来ない
ScriptableRenderLoop
まず シェーダーのパスを任意に実行可能。マテリアル事、ライト毎にパスを変える事も可能 また レンダリングパイプライン自体も自由に書くことが出来る そのため G-Bufferも自由に設計可能だし、ライトの計算なども自分で行う必要がある カリングやオブジェクトのソート等の一部の機能は 変更する事は出来ない
UNITYことはじめ~ShaderLab あたり
UNITY歴
実はあまり触ってない。プラグイン書く仕事はしたけど C++をバインディングしたり、そんなのだし 一応簡単に画面を触るけど 正直表面すら理解してないので はじめてUNITYをちゃんと勉強する
幸いなことに、仕事でUNITYを使う機会があり、今回は深い部分を調査する R&D案件だ
ShaderLab
なぜ最初にShaderか? 一般的に一番難しそうではないか? だからこそ、ここを理解する間には UNITYの全部が理解できるはずである なんせ 心臓部であるので
ShaderLabって?
基本的に HLSLである。一部セマンティクスや型が違ったりするけど そのHLSLをラップして、 DirectX9の FXファイルのような感じで、パスを制御したり色々できる
意外と機能がおおいので ゆっくり勉強する
基礎構文とかはヘルプみて
シェーダーの種類
サーフェースシェーダ、頂点シェーダとフラグメントシェーダ、固定関数シェーダ の3個がある 固定関数シェーダーは ご存知DirectX9以前にあったやつで、今の時代は使う事はないだろう
頂点シェーダとフラグメントシェーダは 一般的なシェーダーで ご存知のもので、 想像通りのものである ドメインシェーダ、ハルシェーダ、ジオメトリシェーダ、コンピュートシェーダも記述できる
問題のサーフェースシェーダだが、結論からいうと 頂点シェーダとフラグメントシェーダを簡単に書くものである pragmaで Lambertとか指定すると、自動的に 頂点シェーダとフラグメントシェーダを生成してくれているようだ もちろん、細かい制御は出来ないので その時は自力で書こう
Aboutシェーダ
細かいのはヘルプ見てもらうとして 頂点&フラグメントシェーダのサンプルを
Shader "Unlit/SimpleUnlitTexturedShader" { Properties { // we have removed support for texture tiling/offset, // so make them not be displayed in material inspector [NoScaleOffset] _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } Pass { Name "FORWARD" Tags { "LightMode"="ForwardBase" } Cull Back CGPROGRAM // use "vert" function as the vertex shader #pragma vertex vert // use "frag" function as the pixel (fragment) shader #pragma fragment frag // vertex shader inputs struct appdata { float4 vertex : POSITION; // vertex position float2 uv : TEXCOORD0; // texture coordinate }; // vertex shader outputs ("vertex to fragment") struct v2f { float2 uv : TEXCOORD0; // texture coordinate float4 vertex : SV_POSITION; // clip space position }; // vertex shader v2f vert (appdata v) { v2f o; // transform position to clip space // (multiply with model*view*projection matrix) o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); // just pass the texture coordinate o.uv = v.uv; return o; } // texture we will sample sampler2D _MainTex; // pixel shader; returns low precision ("fixed4" type) // color ("SV_Target" semantic) fixed4 frag (v2f i) : SV_Target { // sample texture and return it fixed4 col = tex2D(_MainTex, i.uv); return col; } ENDCG } } }
Shader “Unlit/SimpleUnlitTexturedShader” シェーダー名を設定。UNITY Editorから参照するときの名前
Properties マテリアルで設定するパラメータ テクスチャとか色々
SubShader シェーダーの始まり
SubShader/Tags 不透明オブジェクト、半透明オブジェクト等 シェーダーの設定をKeyValue方式で設定
SubShader/Pass レンダリングパス カリングやZTestなども設定できる
SubShader/Pass/Name 他のシェーダーから呼ぶ時に指定する名前
SubShader/Pass/Tags シェーダーの設定をKeyValue方式で。 例えば “LightMode”=“ForwardBase" であれば、Forwardレンダリングの時に使われるパスである Deferred等複数のパスを作れば、その時のレンダリングモードに応じたパスを実行する
CGPROGRAM~ENDCG シェーダーの具体的な中身。だいたいHLSL
pragma vertex vert pragma fragment frag 頂点シェーダ、フラグメントシェーダを使う&関数名を設定。 サーフェースシェーダだとここが surfaceになる。 その他 pragmaは色々あるのでヘルプ参照
などなど
とりあえず ヘルプに詳しく書いている
【UNITY】PostProcess
イメージエフェクト
ってUNITYでは 言うらしいよ ポストプロセスの事
概要
ポストプロセスに関しては ご存知と思うが UNITYは基本的に オブジェクトにスクリプトをくっつけていくタイプだ
UNITYではポストプロセスはカメラにつけるっぽい
MonoBehaviour.OnRenderImage(RenderTexture,RenderTexture) を実装したスクリプトを、カメラと同じ階層のGameObjectに入れれば ポストプロセスとして成立する
スクリプト作成
using UnityEngine; [RequireComponent(typeof(Camera))] //public abstract class Compose : MonoBehaviour public class Compose : MonoBehaviour { private Material _material; public string ShaderName; protected Material Material { get { return _material; } } protected virtual void Awake() { Shader shader = Shader.Find(ShaderName); _material = new Material(shader); } protected virtual void OnRenderImage(RenderTexture source, RenderTexture destination) { Graphics.Blit(source, destination, _material); } }
上記でかいたように OnRenderImageを実装する
sourceがエフェクト前の画像であり destinationにポストエフェクト適応させた出力を行う
ShaderNameプロパティで指定したシェーダーを読み込み それを実行している
Shaderは割愛。好きに書けばいい
スクリプト配置
GameObjectを作りそこにスクリプトをアタッチ そして 同じレイヤーにカメラを置けば完成