- 投稿日:2019-09-09T23:49:33+09:00
ASP.NET Core でSPAではなくVue.jsを利用してみる(4)
クライアント側にVue.jsをSPA(シングルページアプリケーション)ではない方法で利用することについて記述していきます。
全体
・Vue.jsとblumaの設定
・cssをblumaに変更
・バリデーションの変更
・Vue.jsでのコンポーネントの利用(本稿)-Vue.jsでのコンポーネントの利用-
環境
「ASp.Net Core でPostgreSQLを利用してIdentityで認証を使えるようにする」で作成した環境にVue.jsを組み込み、cssフレームワークをblumaに変更します。
- VisualStudio2019 Ver.16.2.3
- ASP.NET Core 2.2
- PostgreSQL 9.6 インストール済み、接続用のアカウント作成済み
- EntityFramework
- Vue.js 2.6.10
- bluma 0.7.5Vue.jsを使う理由
すいません、タイトルに偽りありでした。ようやくVue.jsの記述にたどり着きました。本当はRazorPageでクライアントコンポーネントにVue.jsが使いたかっただけなのですが。
事の発端はJQuery使いにくい、クライアント動作の為のHTMLはサーバーサイドで作っているのでソースが分かれてしまうのがいや、RazorPageの利点を生かしたままクライアント側のコンポーネントを再利用可能な状態で整理して作りたいという思いから、どうせやるなら.Net Core、それならLinuxで動かそう、それならDBもMySQLかPostgresだよねー、JQueryやめるならBootstrapも変えちゃえと思ってたらこんなことに...。作るもの
そんなに大きなものは作れないので、ボタンを押すとページをロックしてページが変わるか一定時間ロック状態にするボタンを作ります。
下ごしらえ
とりあえず、画面ロックのJavaScriptとして、「wwwroot/js/utilities.js」を作り「_Layout.cshtml」のどこかで作ったスクリプトを読み込ませておきます。
utilities.js// スクリーンロック function lockScreen(message, timeout) { // ロック用のdivを生成 var lockElement = document.createElement('div'); lockElement.id = "screenLock"; var textElement = document.createElement('div'); textElement.innerText = message; lockElement.appendChild(textElement); // ロック用のスタイル lockElement.style.display = 'table'; lockElement.style.height = '100%'; lockElement.style.left = '0px'; lockElement.style.position = 'fixed'; lockElement.style.top = '0px'; lockElement.style.width = '100%'; lockElement.style.zIndex = '9999'; lockElement.style.opacity = '0.9'; lockElement.style.background = "white"; textElement.style.display = 'table-cell'; textElement.style.textAlign = 'center'; textElement.style.verticalAlign = 'middle'; textElement.style.margin = 'auto'; textElement.style.fontSize = 'x-large'; // ロックの追加 var objBody = document.getElementsByTagName("body").item(0); objBody.appendChild(lockElement); if (timeout) { // タイムアウトが設定されていれば、そのmsec後にロック解除 setTimeout(function () { // ロック画面の削除 unlockScreen(); }, timeout); } else { // タイムアウトが設定されていなければ、30秒後に解除 setTimeout(function () { unlockScreen(); }, 30000); } } // スクリーンロック解除 function unlockScreen() { var lockElement = document.getElementById('screenLock'); var dom_obj_parent = lockElement.parentNode; dom_obj_parent.removeChild(lockElement); }見ての通り、画面全体を覆う「div」を作っているだけです。画面が切り替わる場合は解除不要ですがページを更新しない場合は「unlockScreen」を呼び出してロックを解除した方がいいです。(タイムアウトするはずですが、それはちっと...)
コンポーネントの作成
「wwwroot/vue/compornents」フォルダを作成し、その下に「button-with-lock.js」を以下のように作成します。
button-with-lock.jsVue.component('button-with-lock', { props: { label: String, lockmessage: String }, template: '<button type="submit" class="button is-primary is-outlined" v-on:click="lockOnClick">{{label}}</button>', methods: { lockOnClick: function () { lockScreen(this.lockmessage); } } });最初の「button-with-lock」はコンポーネント名で、使う場合にはタグ名となります。
「props」はタグ内の属性として外部から設定できるものです。
「template」は、挿入されるHTMLにvue独自の味付けをしたものです。ここでは「v-on:click」でonclickイベントで後述の「methods」の「lockOnClick」を実行させます。また、propで設定した「label」に入っている文字列をボタンのテキストとなるように「{{label}}」(二つの中かっこでくくる)と、その内容に置き換わります。
最後の「methosds」はスクリプトを記述しています。ここでは下ごしらえで作成した「lockScreen」に引数として「prop」に設定されている「lockmessage」を渡しています。なお、ES6のみを対象とする場合、「template」ではテンプレート文字列(「`」でくくり、改行も利用できる文字列)のほうが書きやすいです。IE11もサポートしたいので文字列にしていますので、改行を使いたい場合は行末に「\」を入れる必要があります。
コンポーネントンの利用
作成したコンポーネントをログイン画面で利用してみます。
「Areas/identity/Pages/Account/Login.schtml」の記述を以下のようにします。Login.schtml@page @model LoginModel @{ ViewData["Title"] = "Log in"; } <script src="~/vue/compornents/button-with-lock.js" asp-append-version="true"></script> @*vueのターゲットになるようにidを設定する*@ <div class="section" id="vueTarget"> (フォームの前半は省略...) <div class="field has-text-centered"> @*ボタンをコンポーネントに置き換える*@ @*<button type="submit" class="button is-primary is-outlined">ログイン</button>*@ <button-with-lock label="ログイン" lockmessage="ログイン中..."></button-with-lock> </div> </div> </div> </form> </div> <script> //vueを利用する var vm = new Vue({ el: '#vueTarget', }); </script>最初に作ったコンポーネントを読み込んでいます。(多分後のvueインスタンス作成)直前でも大丈夫)
全体の「div」の「id」を「vueTarget」としました。これはvueを使う目印になります。(名前は何でもいいです)
最後のほうのログインボタンを作ったコンポーネントで置き換えています。このように「props」に設定している値を属性として指定できます。
最後にvueインスタンスを作成すると、コンポーネントが実装されます。この時「el」で対象となる「div」の「id」を「vueTarget」指定したことで、この「div」内が対象となります。(つまり作ったコンポーネント「button-with-lock」が設定した「div」の範囲外なら何もしないということです。)
これでデバッグを実行すると、ボタンをクリックするとロックされます。(見やすいように、サーバーの「login」の実装に数秒の待ち時間を入れたほうがわかりやすいです)RazorPageのモデルと関連付ける
上記のボタンはそれなりに使えると思います。
ただ、実際には作ったコンポーネントにRazorPageのモデルから値を連携させたい場面があるので、ここではとりあえずロックメッセージをモデルから取得するように変更します。(実際にはすることはないと思う)まずはビューモデルである「Areas/identity/Pages/Account/Login.cshtml.cs」にロックメッセージのプロパティを追加します。
Login.schtml.cs前の方は省略... [BindProperty] public InputModel Input { get; set; } public IList<AuthenticationScheme> ExternalLogins { get; set; } public string ReturnUrl { get; set; } // ログイン中のメッセージを追加 public string TestLockMessage { get; set; } = "ろぐいんちゅうでっせー"; この後ろも省略ログイン中のメッセージとして「TestLockMessage」を追加しています。
次にモデルをvueインスタンスの作成時に「data」で与えるのですが、この時ひと工夫が必要でした。(結構調べるのに手間取った)。
ビューモデルを@Json.Serialize(Model)でシリアライズして渡そうとしたのですが、単純なビューモデルではなく「PageModel」を継承しているためにこのクラスのメンバが大きいうえに循環参照していたりしてエラーになってしまいます。循環参照は無視させると、時間がかかりすぎて帰ってきませんでした。何をしようとしているのやら...。
調べていくと「Json.Serialize」の第2引数で与える「JsonSerializerSettings」の「ContractResolver」のメソッド「GetSerializableMembers」をオーバーライドしてシリアライズする対象を選別すればいいことがわかりました。「Utility」フォルダを作って「JsonConverterExceptPageModel.cs」を以下のように作成しました。JsonConverterExceptPageModel.csusing Newtonsoft.Json; using Newtonsoft.Json.Serialization; using System; using System.Collections.Generic; using Microsoft.AspNetCore.Mvc.Rendering; using System.Reflection; using Microsoft.AspNetCore.Mvc.RazorPages; namespace WebApplication1.Utility { public static class JsonConverterExceptPageModel { static DefaultContractResolver resolver = new DefaultContractResolver(); static public Microsoft.AspNetCore.Html.IHtmlContent Serialize(IJsonHelper jsonHelper, object value) { JsonSerializerSettings settings = new JsonSerializerSettings(); NotInhelitContractResolver resolver = new NotInhelitContractResolver(); settings.ContractResolver = resolver; return jsonHelper.Serialize(value, settings); } } public class NotInhelitContractResolver : DefaultContractResolver { protected override List<MemberInfo> GetSerializableMembers(Type objectType) { Type pageModel = typeof(PageModel); List<MemberInfo> list = new List<MemberInfo>(); foreach (var member in base.GetSerializableMembers(objectType)) { if (member.DeclaringType != pageModel) list.Add(member); } return list; } } }「GetSerializableMembers」のところで「PageModel」のメンバを除外するようにしています。使う環境によってはもう少し工夫がいるかもしれません。
で、「Areas/identity/Pages/Account/Login.schtml」」を以下のように変更します。
Login.schtml@page @model LoginModel @using WebApplication1.Utility @*これを追加した*@ 中略... <div class="field has-text-centered"> @*ボタンをコンポーネントに置き換える*@ @*<button type="submit" class="button is-primary is-outlined">ログイン</button>*@ <button-with-lock label="ログイン" v-bind:lockmessage="items.TestLockMessage"></button-with-lock> </div> </div> </div> </form> </div> <script> //vuew利用する var vm = new Vue({ el: '#vueTarget', data: { @*これを追加した*@ items: @JsonConverterExceptPageModel.Serialize(Json, Model) } }); </script>作成したシリアライズ用のクラスを利用する為に、最初に「@using WebApplication1.Utility」を追加。
ログインボタン「lockmessage」プロパティーは「vue」の「data」の「item.TestLockMessage」を参照させています。参照させる場合はこのように、「v-bind:prop名」の形になります。これで実行すればロックメッセージが関西弁に変わります。
これで当初の目的であったRazorPageの利点も生かしながらクライアントサイドのコンポーネントをvue.jsで記述することができるようになったので、ひとまずこのシリーズは終わりかな。
まあ、これを使って使えそうなコンポーネントができればどこかで公開するかもしません。C#.Net coreもvueも本格的には使っていないので、つたない部分があるかと思います。
もっとすっきり記述する方法もあるかと思いますので、こうした方がいいのではとかありましたらご指摘ください。
- 投稿日:2019-09-09T17:52:08+09:00
【Unity(C#)】自作VIVEコンテンツでスタート位置を気にしなくて済む実装
VIVEのリセンター機能
Standing Mode
やSeated Mode
にはSteamVRが用意している機能で
リセンター(再トラッキングしてポジションを中央に戻す)が可能ですが、Room-Scale
でのプレイには対応していません。なので、VIVEを担いで営業デモに行った際にはスタート位置をバミるという手法を使っていました。
バミらないと、いきなりポリゴンにめり込んだ状態から始まったり、
明後日の方向を向いてしまって、後ろからしゃべりかけられてストーリーが展開する...なんてことが起きます。位置と向きを補正
しかし、バミリは複数のコンテンツを体験していただく際には厄介です。(あれがこっち、これはあっちと余計なことに気を使います)
さらに、コンテンツの内容、作り方によってはスタート位置がまちまちになってしまうので、
部屋の大きさによっては、
・コンテンツAでは前方のスペースに十分なエリアが必要
・コンテンツBでは後方のスペースに十分なエリアが必要
といった具合に、それぞれのコンテンツで必要なエリアの幅が異なることで正しく体験できないという現象が起きかねません。また、私は製作者側なのでデモ時に上記のような状況でも何をどう対処すればいいか瞬時に判断できますが、
コンテンツを使うユーザーからしたら意味不明で、ストレスでしかありません。なので、コンテンツにリセンター機能を実装して組み込むことで、開始位置の固定を取り払いました。
コード
やっていることはシンプルで、
スタートと同時にコルーチン内でCameraRigの角度を回転させてCamera(プレイヤー)の向きを補正し、
その後にCameraRigの位置にCamera(プレイヤー)のトラッキング位置を考慮した補正をかけています。using UnityEngine; using System.Collections; using UnityEngine.Events; /// <summary> /// Recenter your camera when you start VR. Attach to CameraRig. /// </summary> public class ReCenterCamera : MonoBehaviour { [SerializeField, Tooltip("Set this child camera")] GameObject eyeCamera; [SerializeField,Tooltip("This event is skiped one frame")] UnityEvent startEvent; void Start() { StartCoroutine(ReCenterCoroutine()); } IEnumerator ReCenterCoroutine() { Vector3 cameraRig_Angles = this.gameObject.transform.eulerAngles; Vector3 eyeCamera_Angles = eyeCamera.transform.eulerAngles; this.gameObject.transform.eulerAngles += new Vector3(0, cameraRig_Angles.y - eyeCamera_Angles.y, 0); Vector3 cameraRig_StartPos = this.gameObject.transform.position; Vector3 eyeCamera_Pos = eyeCamera.transform.position; this.gameObject.transform.position += new Vector3(cameraRig_StartPos.x - eyeCamera_Pos.x, 0, cameraRig_StartPos.z - eyeCamera_Pos.z); yield return null; startEvent.Invoke(); } }位置の補正に関しては前回の記事の内容をそのまま転用しています。
今回苦労したのは角度に関してです。
角度の調整
図解します。
黒い四角がカメラ(プレーヤー)、青い四角がCameraRigだとします。
それぞれのY軸回りのローテーションはy₁
,y₂
です。
カメラ(プレーヤー)をVR起動時に、必ずA地点の方に向けた状態でスタートしたいという想定です。シンプルな計算で、実装できます。
カメラ(プレーヤー)とCameraRigのY軸回りのローテーションの差を計算して、CameraRigのY軸回りのローテーションに足すだけです。今回のプログラムでは加算代入によって
y₂+y₂-y₁
の部分を実装しています。this.gameObject.transform.eulerAngles += new Vector3(0, cameraRig_Angles.y - eyeCamera_Angles.y, 0);なぜコルーチンなのか
なぜ、コルーチンにしているのかにも、きちんとした理由があり、今回苦労した原因です。
その原因とはトラッキングが完了してから補正する必要があるということです。
自分の今いる座標、回転座標が定まっていない(トラッキングが完了していない)状態で補正をかけても
意味がありませんよね。なので、
①Updateでトラッキングの処理が終わる
②Updateより後に実行されるコルーチン内で位置、角度の補正
という流れになっているということです。※コルーチンのUnityの実行順についてはこちらで図解してあります。
この実装の欠点
この実装にはいくつか不具合の元がありまして、既存のコンテンツに後入れで導入した場合、バグを生む可能性があります。
例えば、カメラの座標がワールド座標の○○を超えたらイベント発生、などの実装があった場合、
最初の1フレームでそのイベントが発生してしまう恐れがあります。なぜそんなことが起きる可能性があるかというと、最初の1フレームをトラッキングに使用するので、
実際に目に見えて始まる位置(補正後の位置)とは異なる座標を1フレーム分通過してしまうからです。なので、最初の1フレームの間、そのイベントのトリガーはオフにしておいて、
位置補正終了と同時にオンにするなどの工夫が必要です。
今回のコードにもイベントを登録できる形で組み込んでいます。yield return null; startEvent.Invoke(); //ここにトリガーをオンにするイベントを登録また、トラッキングがMissingになった状態でUpdateの最初の1フレームを通過してしまうと
補正が正しくかからない等の問題点も残しており、まだまだ改善の余地はありそうです。あと今回の内容はOculusコンテンツに導入しても正しく動きます。
むしろ、最初はOculus向けに作ってた機能で、VIVEにつっこんだらなんか動いたからヨシ!って感じです。
- 投稿日:2019-09-09T16:07:17+09:00
【.NetCore】Html.Rawで<br>だけそのままにする。
改行文字を<br >に変換するだけでは改行されない。
安直に改行文字の\rや\nを<br >に置換すればいいと思うが、実はRazorではバインドした段階で値がHTMLエンコードされる。
よって表示時には& lt;br & gt;に変換されてしまう。強制エンコードされてしまう以上、タグを埋め込むのは不可能なのでエンコードせずに出力してみる。
View@Html.Raw(sample.text)@Html.Rowメソッドを使うと、Htmlエンコードされずにそのままの値をHTMLに出力してくれる。
出力される値が固定の場合はこの方法で問題ないが、任意に変更できる場合はクロスサイトスクリプティングの危険がある。
よってこの方法は用途によっては使えない。なんか楽しかったので2種類のパターンを考えた
その1、エンコードして改行だけデコードする。
1度エンコードして、改行文字のとこだけデコードを行う。
その値をHtml.Raw()で出力すれば<br >だけそのまま出力されるので改行される。View@Html.Raw(Html.Encode(tmp.Detail).Replace("
", "<br>"))その2、ゴリ押し
Viewvar detail = tmp.Detail.Split("\r\n"); @foreach (string tmp in detail) { @tmp<br /> }これで改行ごとに<br >が挿入されるので改行できる。
HTMLエンコードなにそれ?って人はこっちでいいと思います。その1をStaticメソッドにしとくといいかも!?
- 投稿日:2019-09-09T16:07:17+09:00
【C#】Html.Rawで<br>だけそのままにする。【Razor】
改行文字を<br >に変換するだけでは改行されない。
安直に改行文字の\rや\nを<br >に置換すればいいと思うが、実はRazorではバインドした段階で値がHTMLエンコードされる。
よって表示時には& lt;br & gt;に変換されてしまう。強制エンコードされてしまう以上、タグを埋め込むのは不可能なのでエンコードせずに出力してみる。
View@Html.Raw(sample.text)@Html.Rowメソッドを使うと、Htmlエンコードされずにそのままの値をHTMLに出力してくれる。
出力される値が固定の場合はこの方法で問題ないが、任意に変更できる場合はクロスサイトスクリプティングの危険がある。
よってこの方法は用途によっては使えない。なんか楽しかったので2種類のパターンを考えた
その1、エンコードして改行だけデコードする。
1度エンコードして、改行文字のとこだけデコードを行う。
その値をHtml.Raw()で出力すれば<br >だけそのまま出力されるので改行される。View@Html.Raw(Html.Encode(tmp.Detail).Replace("
", "<br>"))その2、ゴリ押し
Viewvar detail = tmp.Detail.Split("\r\n"); @foreach (string tmp in detail) { @tmp<br /> }これで改行ごとに<br >が挿入されるので改行できる。
HTMLエンコードなにそれ?って人はこっちでいいと思います。その1をStaticメソッドにしとくといいかも!?
- 投稿日:2019-09-09T09:15:10+09:00
【ReSharper】ReSharper の使い方に関する記事まとめ(75個)
備考
この投稿は自分のブログの記事の転載になります
http://baba-s.hatenablog.com/entry/2019/06/07/090000はじめに
自分のブログで公開した ReSharper の使い方に関する記事を75個まとめました
おすすめ
- 後置テンプレートを使う
- Visual Studio を軽量化する
- Jenkins と ReSharper を使用して静的解析を行う方法
- よく記述するコードをライブテンプレートに登録してコーディングを楽にする方法
Unity
- Unity との連携を有効にする方法
- Unity におけるコードの問題点を見つける
- Unity においてパフォーマンスがあまり良くないコードを削除したり書き換えたりする
- Unity においてパフォーマンスがあまり良くないコードをハイライト表示する
- Unity の SerializeField 属性が適用された変数の命名規則を設定する
- Unity で暗黙的に使用されるキーワードの太字を解除する方法
コードクリーンナップ
- 型指定を var に置換する
- クラスや構造体にアクセス修飾子を自動で付与する
- クラスや構造体のメンバーにアクセス修飾子を自動で付与する
- メンバの修飾子の順番を自動で並べ替える
- 名前付き引数を使用するかどうかを自動で適用する
- 不要な括弧を自動で削除する
- 実行順がわかりづらい処理に自動で括弧を付けて実行順をわかりやすくする
- 一行のステートメントに自動で波括弧を付けたり、
一行にまとめられるステートメントから自動で波括弧を削除したりする- 複数の属性の指定を自動で1つにまとめたり、自動で分割したりする
- 単純なプロパティとバッキングフィールドを自動プロパティに置き換える
- 変数に自動で readonly を適用する
- 自動実装プロパティから不要な setter を自動で削除する
- 関数呼び出しの型指定を自動で削除したり基底クラスに変更したりする
- 組み込み型の記述を自動で C# 型に変更する
- 未使用の using を自動で削除する
- using を自動で region で囲む
- 名前空間付きの呼び出しを自動で using に置き換える
- Formatting Style に従ってコードを自動で整形する
- コードフォーマットする時に名前付き引数を使うかどうかは変更しないようにする
- ReSharper の Code Cleanup をコマンドラインから実行する方法
自動生成
Inspect
- 変数がどこに渡されていくのか追跡する
- 関数がどこから呼び出されてくるのか追跡する
- 関数の引数がどこから渡されてくるのか追跡する
- 関数がどのように関数を呼び出していくのか追跡する
- ソリューションやプロジェクトの問題を一覧で確認する
ファイルレイアウト
ショートカットキー
- bool を反転する
- タイプミスを修正する
- 関数を式形式に変更する
- 行や選択範囲を複製する
- 完全修飾名をコピーする
- 行コメントを切り替える
- 引数の順番を変更する方法
- コードの位置合わせを行う方法
- クリップボードの履歴から貼り付ける
- Ctrl+E, F で Full Cleanup を実行する方法
- オブジェクト初期化子を自動で記述する
- クラスや構造体を新しいファイルに移動する
- Ctrl + Alt + / で選択範囲を一行コメントに切り替えられる
- Ctrl + Shift + / で選択範囲を複数行コメントに切り替えられる
オプション
トラブルシューティング
- 命名規則が適用されない場合
- ReSharper を一時的に無効化する方法
- パラメータヒントを非表示にする方法
- 宣言へ移動する時の挙動を変更する方法
- 名前空間をフォルダ構成に合わせないようにする
- タブキーを押した時の挙動をタブの挿入に戻す方法
- 関数をオーバーライドしたい時のコード補完の方法
- ReSharper をインストールしても正常に動作しなかった時に、
キャッシュを削除したら正常に動作するようになった拡張機能
- 関数を複製できる拡張機能
- 関数の複雑度が簡単に閲覧できるようになる拡張機能
- ツールチップやパラメータ情報に色付けできる拡張機能
- コーディングを楽にするテンプレートを使用できる拡張機能
- ヒープ割り当てが発生しているコードを可視化できる拡張機能
- 関数の引数を改行できる、一行にまとめることができる拡張機能
その他
- 投稿日:2019-09-09T00:29:30+09:00
【Unity】謎のアサーション'IsNormalized(dir)'&'IsNormalized(ray.GetDirection())'
バージョン
Unity 2019.1.9f1
はじめに
こんなアサーションに遭遇しました。
Assertion failed on expression: 'IsNormalized(dir)' Assertion failed on expression: 'IsNormalized(ray.GetDirection())'クリックしてもそれ以上の情報はなく、どこに問題があるのかどころか、誰がこのアサーションを吐いているのかさえ分からず。
とりあえず調べてみると公式フォーラムでFlare Layerを切ると消えたという情報が出てきます。
切ってみると確かに出なくなりましたが、このままではレンズフレアが使えない、ということで色々試して回避できそうな方法が分かったので共有します。再現手順
- 空のシーンを作成します。
- Directional LightにLens Flareを追加します。
- Main CameraにFlare Layerを追加します。
ここまではレンズフレアを使うときにやる普通の作業かと思います。
このあと下記の2パターンで確認できました。パターン1(Orthographicカメラ)
- Main CameraのProjectionをOrthographicにします。
- 再生します。
- Main CameraとDirectional LightのPositionを一致させます。
パターン2(Perspectiveカメラ)
- Main CameraのProjectionをPerspectiveにします。
- 再生します。
- Main CameraとDirectional LightのTransformを一致させつつ、PositionとRotationを適当に動かします。 (例えばPosition: -2, -13, -10、Rotation: 77.2, 112.32, 0とか)
原因ははっきりとは分からないのですが、カメラとLens Flareの位置関係によってはレンズフレアの計算ができない状況になるのでしょう。
対処法
このアサーションに遭遇する原因として一番ありそうなのがカメラにLens Flareが付いてしまっているパターン。
この場合、Lens Flareの使い方が間違っていると思われますので、まずは使い方が合っているか確認するのがいいかと思います。
こちらやこちらを参考にさせて頂くと、空のオブジェクトやLightに付けるのが正しいかと思いますので、そのようにしましょう。それでも、再現手順でやったように、カメラとLens Flareの位置が一致する状況があれば発生してしまうことでしょう。
その場合は両者の位置関係を意識したうえで、スクリプトやオブジェクト配置を見直してみるのがいいかと思います。おわりに
すぐに原因箇所が分からないアサーションなので、解決に時間を取られてしまわないよう、一助になれば幸いです。