• unityでボーンコンストレインするC#スプリクトを書いたものの……

    2019-06-30 20:58
    書いたものの結局必要なかったというか、そもそもの原因を勘違いしていたという結論



    事の始まりとして自作ゆかりさんを一度テスト的にunityに持ち込んでモーション当ててみて大丈夫かを確認するところが始まり

    unity標準のhumanoid という人体構造用のボーンを踏襲することでアセットストアなどで売られているモーションを適用できるようになるのだけども
    これは当然MMDのときとは構造が違う

    それでまぁ多少はすり合わせればいいのだけど、腕のねじりを分散緩和するようなボーンがどうやら組み込まれていないっぽい
    (ただ肩だとかの?さらに親や子のほうにねじれ具合を分散するなどの対策はされているらしい、いま見直してもうちょっと正確な理解になったがこの時点ではあまり把握していなかった)
    参考:UnityでHumanoidリグを利用する際の肘関節の捩れを調べる


    そもそも最新のunityには回転コンストレインのスプリクトがある
    参考:Unityにおけるボーン回転コンストレイント
    じゃぁhumanoidボーンから部分的に並列的な親子関係にして、
    自前のボーンのほうにコンストレインで値を移してあげてねじりだけMMDと同一構造のところに同じように分散したらいいのでは?
    と思いblenderでのボーン構造見直しもそれを見込んで行って
    unity上で設定して動かしてみるとなんかずれる

    ここで勘違いしたのが「unityの回転コンストレインってワールド空間判定でやっているのでは?だからずれるのでは?」
    やったことないスプリクトに挑戦する前に、もうちょっと試して確認するべきだったよね
    まーそのうちやろうとか詳しくなりたいと思ってたことであるので知識、学習的に無駄なことはなかったんだけども

    さんざん勘違いしてたと書いているから今更なのだけども
    unityの回転コンストレインはちゃんとローカル軸を見てやってくれてたっぽい
    ということを自前のスプリクト完成してから
    「あれ?こっちもずれる上にずれ方に見覚えしかないぞ!?」
    という

    自前のスプリクトもunityのコンストレインもunity上でキューブとか出して
    簡易的に対象のボーン回りと同じ親子構造作って試したらどっちも一応正常動作してて
    完全に別の原因ですよ……

    

    そうなると何が原因かが謎で頭抱えるのだけど
    先ほど上に「もうちょっと正確な理解になった」と書いたhumanoidボーンについて
    上腕のねじりを肩とかにも分散してるっぽいというのが
    今ちょうど上腕で試しているのでそれが原因か?とかちょっと思っているところなんだけども
    (でもねじりを分散したとき(根本はxz回転のみコンストレイン、子供のほうでY回転を0.25づつ請け負う)に思いっきりずれるのであって、根元でxyz全部請け負ってコンストレインする分にはずれない(少なくとも見た目上は)なのでやっぱり違うかな……)
    それはそれとしてせっかく参考書とか買って読みふけって書いてみて
    正常に動いてはいるからスプリクト晒しとけ!!
    という奴ですはい(結論)

    ただまぁ返す返すunity標準のコンストレインで用は足りるというかそっちのほうが優秀というかなので
    自分と同じくスプリクトやり始めた人がみたらなんか参考になるところあるかもぐらいの感じ
    (例によって自分がすぐ忘れるからコメント入れまくったつもりなので)


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


    [ExecuteInEditMode] //これをつけることでゲームすたーとしていないエディター上でも動作するようになる
    public class LocalRotationConstraints : MonoBehaviour //通常はMonoBehaviourを継承することでunity用の各種メソッド?を使用できる
    {
    //public……どこからでもアクセスできる変数ですよという宣言
    //private……このクラス内からしかアクセスできないですよ(このクラスの外では使用しませんよ)という宣言
    //後程スプリクトを書き換える時などに、このクラス自体が不要じゃね?となったとき、publicが使われていたら
    //いやどっかでこの変数使ってるはずだぞアブねー確認!となる為のものらしい

    //各型で変数を宣言(といってもVector3は正確にはクラスだったらしい……)
    //これで登録欄も同時にできるっぽいがボタンなどは無理なので下のカスタムインスペクター用の記述で改めて書く
    //(するとそちらが優先される?)
    public GameObject ConstraintBone;
    public Vector3 ThisBoneRotation;
    public Vector3 ConstraintBoneRotation;
    public float ConstraintWeight;
    public bool ConstraintX;
    public bool ConstraintY;
    public bool ConstraintZ;
    public bool ConstraintActive;




    // 初期化に使用 最初に一回だけ実行される処理ということ、繰り返さなくていいならここに記述してしまう
    private void Start()
    {
    //リアルタイムで動いてほしい処理なので個々の記述はとくになし
    }


    // Update はフレームごとに1 回 毎フレーム繰り返す、常時処理されるということ
    // FixedUpdateは一定間隔(フレーム落ちしても本来のフレームタイミングでということ?)
    // FixedUpdateであるべきな気がするけどExecuteInEditModeで反応しなかったのでいったん通常のUpdate
    private void Update()
    {
    if (ConstraintActive == true)
    {

    //vectore3の入れ物を用意しておく ゼロで初期化済みにしておく
    Vector3 Temporary_Value = Vector3.zero;


    //Mathf.DeltaAngleは角度の差を-180~180の間の最小で返してくれる350と20みたいな時でも330ではなく-30となって実際安心
    //それぞれの軸の有効無効判定もして有効なものだけ処理
    if (ConstraintX == true)
    {
    Temporary_Value.x = Mathf.DeltaAngle(ConstraintBoneRotation.x, ConstraintBone.transform.localEulerAngles.x);
    }
    if (ConstraintY == true)
    {
    Temporary_Value.y = Mathf.DeltaAngle(ConstraintBoneRotation.y, ConstraintBone.transform.localEulerAngles.y);
    }
    if (ConstraintZ == true)
    {
    Temporary_Value.z = Mathf.DeltaAngle(ConstraintBoneRotation.z, ConstraintBone.transform.localEulerAngles.z);
    }

    //その差分をこちらのベースと足してあげてからクォータニオンに変換して入れる
    this.transform.localRotation = Quaternion.Euler(ThisBoneRotation + (Temporary_Value * ConstraintWeight) );

    }
    }




    //以下はボタンが押されたとき用の処理

    //通常時のコンストレインされる側ボーン角度を取得
    //角度はlocalRotationだとQuaternion(xyzw)で取得する必要があることに注意
    //Vector3でほしいときはlocalEulerAngles
    public Vector3 GTBR()
    {
    Vector3 Temporary_Value = this.transform.localEulerAngles;
    return Temporary_Value;
    }

    //通常時のコンストレインする側ボーン角度を取得
    public Vector3 GCBR(GameObject NowBone)
    {
    Vector3 Temporary_Value = NowBone.transform.localEulerAngles;
    return Temporary_Value;
    }

    /*
    //間違えた時のためにボーン角度リセット
    //必要かと思ったがRevert的なリセット方法というかデフォルト時の値取得方法なさそうなのでいったんオミット
    public void ResetBone(GameObject NowBone)

    {
    this.transform.localRotation = Quaternion.identity;
    NowBone.transform.localRotation = Quaternion.identity;
    }
    */

    }







    //ここから下はスプリクトのUI(カスタムインスペクターというらしい)の描画に関する記述-----------------------------------------------------------------------------------------------------------

    [CustomEditor(typeof(LocalRotationConstraints))] //属性を与えて(?)どのスプリクトをカスタマイズするのかを指定
    public class LRCEditor : Editor //カスタムインスペクターの場合はEditorを継承しないとダメらしい(ので別クラスで記述することになる)
    {



    public override void OnInspectorGUI()
    {
    // 「target は処理コードのインスタンスで 処理コードの型でキャストする」
    //クラスを宣言しなおしてそれをインスタンスで取得しているということでよいかな??
    LocalRotationConstraints LRC = target as LocalRotationConstraints;


    //シリアライズオブジェクト?関係あるかもしれないのでコメント扱いで残している
    //serializedObject.Update();
    //ボーンを登録するフィールドを改めて設定と取得
    LRC.ConstraintBone = EditorGUILayout.ObjectField("On the constraining side", LRC.ConstraintBone, typeof(GameObject), true) as GameObject;
    //こちらもシリアライズオブジェクト
    //serializedObject.ApplyModifiedProperties();

    //間にスペース作る
    EditorGUILayout.Space(); EditorGUILayout.Space();

    //このボーンの基本角度入力欄
    LRC.ThisBoneRotation = EditorGUILayout.Vector3Field("ThisBoneRotation", LRC.ThisBoneRotation);

    //ボタンを表示するのと同時に、押されたときにTrueを返すので一緒にif文に含めてしまうことで押された時の処理も書けるようにということらしい
    if (GUILayout.Button("GetThisBoneRotation"))
    {
    // 以下はボタンが押されたときに実行される処理
    //上で記述した角度取得メソッドを呼び出してこのボーンの角度を取得
    LRC.ThisBoneRotation = LRC.GTBR();
    ;

    }


    //上と同じ内容の拘束側ボーン版
    LRC.ConstraintBoneRotation = EditorGUILayout.Vector3Field("ConstraintBoneRotation", LRC.ConstraintBoneRotation);
    if (GUILayout.Button("GetConstraintBoneRotation"))
    {
    //このボーンの角度ではないので対象ボーンをゲームオブジェクトとして渡すところだけ上と違う
    LRC.ConstraintBoneRotation = LRC.GCBR(LRC.ConstraintBone);



    }



    /*
    //スプリクトが変に動作したときに各ボーンの角度おかしくなった時用の角度リセットボタン
    //いったんオミット
    EditorGUILayout.Space(); EditorGUILayout.Space();
    if (GUILayout.Button("RotationRest"))
    {
    LRC.ResetBone(LRC.ConstraintBone);

    }
    */


    EditorGUILayout.Space(); EditorGUILayout.Space();

    //コンストレインの影響度
    LRC.ConstraintWeight = EditorGUILayout.FloatField("Weight", LRC.ConstraintWeight);

    //コンストレインのXYZそれぞれのONOFF用チェックボックス
    LRC.ConstraintX = EditorGUILayout.Toggle("X", LRC.ConstraintX);
    LRC.ConstraintY = EditorGUILayout.Toggle("Y", LRC.ConstraintY);
    LRC.ConstraintZ = EditorGUILayout.Toggle("Z", LRC.ConstraintZ);

    //コンストレインをアクティブ状態にするかどうかのチェックボックス
    LRC.ConstraintActive = EditorGUILayout.Toggle("ConstraintActive", LRC.ConstraintActive);
    }


    }

    数年前のblender用pythonと違ってC#だから
    スペース修正しなおしとかしなくてもコピペで動くかも、動かんかも






    そしてどうでもいいけどマリオメーカー2かってコース作ったのでついでで晒しておく!
    (本当に関係ない)

    QSP-0YY-LNG
    森をコイン集めながら登っていくコース
    現在クリア率30%ぐらいなので平均して三回チャレンジしたらクリアできてる感じの難易度のコース
    普通にマリオにありそうな感じのを作りたいと思ってやったので難易度的にもあっている気はする……?


    RXH-831-L6G
    前作でも作ったパズル系ステージがいま見直すとごちゃごちゃして
    パズル以前のところが把握しずらいのではと思っていろいろ整理しなおしたり簡略化したりしてみたコース
    壁を壊さないと進めないけどどうやって壊せる形にもっていくかみたいな感じ



    前作があっての今作だからかネットで作られているコースも落ち着いた難易度のものが前作より多い印象でヌルゲーマーには大分ありがたい……

    あとコース作ってもどっかで晒してみて、誰かの評価なり足跡なりつけてもらわないと
    野良の人というかマリオメーカーでコースをランダムに遊ぶとかには限りなく引っ掛かりにくいようなので
    コース作った人はどこかでガンガンコースIDさらしたほうがいいと思う
    (自分のコースも某所で晒してみる前は足跡一個もつかなかったし、
     ぎゃくにいいね!してくれた人のまだ遊ばれてないコース遊んだらそのコースのタイムが更新された=ほかの人も遊んだみたいなお知らせが割と早めに来たりとか)





    しばらく時間あったのでのんびりながら期間的には集中していろいろ手を出せていたのだけど
    また普通に戻ってしまうので
    次のゆかりさんをunityに持ち込む進展報告の更新はいつになるやら……
  • 広告
  • PC新調したのでMMDVR動画作ってた(unityシェーダーはどうした)

    2019-06-15 03:01
    いやーセルシェーダーおよびそれ用にゆかりさんをunityにもっていく作業をすすめようとはおもってたんだけども
    前からつくってみたかったとういうか実際いくつかは作ってたんだけど
    その時はPCのスペック低くて低解像めなのをMMD標準のシェーディングでだすのが手一杯だったりとか
    当時は360度動画しか投稿できなかった(記憶違いじゃなければ)で
    後方特に何も用意してないからその分解像度的に無駄がとかあって
    せっかくMMDのゆかりさんも更新したんだからさーと一個出してみたら興が乗ってという奴ですはい







    で、一番上のは以前出したのと同じでほぼ固定カメラなのだけども
    二つ目以降はカメラの視点切り替えとかもやってみたりとか
    下のになるほどカメラがエロく動くようになっていっちゃってる

    VRでカメラワークってどうすんだ?みたいなこと思いつつだったんだけども
    大きく位置移動したり激しく動くものがあるタイミングで
    それなら視聴者はここに視点を移動させるだろう、というタイミングでカット切り替えて
    次のカットでも同じ画面位置に見てほしいものを配置しておくとわりとすんなりいけたかもしんないと勝手に思ってる
    そういうところは普通のカメラワークと同じでよさそうというか

    あと自分はたまにVR映像みるかー程度の使用頻度だったのだけど
    昔に比べるとわりとVR酔いに耐性ができてきたっぽく昔なら速攻不快感かんじていただろうなというカメラ動きも割と普通に見れるようになっていた
    ただそれは逆に自分で作成するときにVR慣れてない方が見て大丈夫かこれの感覚的判断ができなくなってしまったということでもあるので
    上の三本、後半に行くほどグリングリンとはやらないもののすこし動かしたりしちゃってるので
    大丈夫なもんかなーコレというのが謎なところ



    あとは出力するのにEquirectangularXというエフェクトとお芋という方が作られた出力~合成の自動化マクロ(とそれで使うフリーソフト)など使ったのだけど
    ちょっと問題が起こったのでメモ
    というのも自分のゆかりさんリムライト表現にスフィアマップを使っているんだけども
    上記の方法だと出力時間短縮のためにカメラ角度を45、-45度という感じで正面からは撮ってなくて
    結果としてスフィアマップの表示が意図しない形になってしまっていた

    ただ幸いにして「エミッシブで問題が起こる場合がある」とのことでの対策のために
    さらに真正面からもう一度追加で取り直して重ねるというオプションがあったので
    それを使用して(合成用マスクもふちにちょっとグラデを入れてあげて)とかで改善できた



    そのほかはMMDのエフェクト初めてまともに使ってみたとかなので
    わからんながらわりと雑に割り当てちゃったかなーとか思いつつ

    よく見かけるray-mmdとかは自分のゆかりさんには完全に使えないなーというのを発見したりとかして頭抱えたり
    (背景にだけ使いたかったんだけど、シーン全体に影響してしまう、その結果ゆかりさんのリムライト表現に用に用意している薄皮&スフィアマップの表示がこれまたおかしくなるという)
    あとVRはカメラの角度何度も変えて取り直して合成するからカメラの角度で反射だとかの感じが変わっちゃうのは使用できないらしいみたいな情報とかもみかけたり
    フォグに関してもそういうのあるらしかったんだけど自分の使用したhkFog_Postに関しては大丈夫そうだったかな

    HgDOFの被写体深度のぼかしもやっちゃうと低解像度に見えちゃうとかで避けたほうがいいらしいとかみかけたのでかなり弱めに使用してみたりとか
    (シーンの途中で思いっきり強くするとかやってみてもよかったかもなと今更ちょっと思った)

    AutoLuminasも初めてつかってみたのでこういう設定をモデル側でしとけばいいのかーとか
    ゆかりさんも対応させたほうがよかったかなとか今更ちょっと思ったり
    それだけのために更新するのもうーんとおもうのでやんないけども


    という感じの思ったこと垂れ流しメモ
    明日からはまたunity関連に戻るかなー
    ゆかりさんをunityにもっていくにあたってボーン構造をunity標準の名称、親子関係に修正し始めてるのだけど
    ウェイトの割り当て直しとかも発生してしまうっぽくてなかなかめんどい(ので現実逃避してた面は否めない)

    最後にMMDのエフェクト使った通常の映像もニコニコに投稿したりしてたので
    ついでにペタッとしておく

  • セルシェーディングのシェーダー作るにあたってライト周りのことメモ殴り書き(またもうちょっとわかったり整理できたら追記していくやつ)

    2019-05-23 22:55
    ちょっとセルシェーディングやるにあたって複数のライトがあった場合の処理をちゃんとやろうとして
    その結果調べたりしたことやブックマークがそこそこの量になってごちゃごちゃしてきたので
    一旦メモ的に書いてみることで脳内整理&今後自分でも見返せるようにする
    (とはいえふわふわ認識のままごちゃごちゃ書くやつなので他人が見ても意味なさそう)


    まず通常のシェーディングとして陰影を形成して
    それを明るい領域、暗い領域になるように絞った後それをマスク化してという流れになるんだけど
    それをやるためには一つのPass内で全部の明暗を処理しないといけない(と思う)
    (Passをまたぐと前のpassの情報を取得、調整、再利用というのは基本的に無理っぽい重ね書きレベルのことしかできない感じ?)

    ここでDeferredとForwardBase&ForwardAddとVertex Litの三種類があるので
    セルシェーディングをやるにあたりどれが一番いいのかというのに今さら行き当たった感じの話


    ・Deferred(まだあやふやだがセルシェーディングには向かないっぽい?)
    g-bufferといういくつかの材料(ワールド座標ノーマル情報だとかデプス情報だとか、メタリックだのベースカラーだの)を全オブジェクト描写してしまって最後に一括処理するような感じっぽい?
    でこのg-bufferに陰影があればよかったのだけどそれは最後に一括処理されるときにはじめて生成されるっぽい?
    (と思っていたのだけどこの記事を書くために調べなおしていると陰影情報のみ描写したものもあるっぽい情報があるので後々ちらべ直す……
     今から調べると話がそれるのでいったん保留)
    のでセルシェーディングの材料としての単純な陰影情報としては利用できないっぽい(?)

    あと全オブジェクトを一括処理する都合上プロジェクト全体に影響が出る感じで処理の切り替えが必要っぽいとか
    (例えばVRChatだと(やったことないけども……)forwardbase設定らしいので多分駄目)
    半透明は基本使えないとかもあったりするらしいけどまだあやふやなのと陰影情報の取得には関係なくなってくると思うので割愛


    ・ForwardBase&ForwardAdd(セルシェーディングに最も向いてる?)
    従来通りオブジェクト事に描写していく方式(であってる?)
    ただunityの仕様だと(ほかのソフトでも同じ?)一つ目のPass内でとれるライトの情報には限界があるっぽい?

    主な参考先
    VRChatの皆に手軽に綺麗になってほしくて作ったシェーダーの話

    ・_WorldSpaceLightPos0
    unityが一番重要だと判断したライト(基本的にDirectional Light)が一つだけ情報が取れる

    ・unity_4LightPosX0
    あまり重要でない(重要度二番目以降ということ?)ライトが四つまで情報をとれる

    ・ShadeSH9
    それ以降のライト及びライトプローブにベイクされた情報を取得できる

    ということのようなんだけど(それぞれさらに精度とかあるようだけどそこはいったん省く)
    unity_4LightPosX0でとれるライトの情報がいまいちしっくりこない……
    ビルトインのシェーダー変数だと「重要でない最初の 4つのポイントライト」という説明だけども
    ・ポイントライトのみ
    シンプルなシェーダー記述で試しなおしてみたもののスポットライトも反応しているっぽくて

    ・重要度
    二番目以降という解釈でいいのかもっと後ろのほうなのか……?というのが謎
    というのも以前シンプルな構成で試した時に一番近くて強いポイントライトが反応してなかったからなんだけども
    これはまた試しなおしたらちゃんと反応してたっぽい……
    前の時は自前の記述部分がおかしくてそういう風に見える動作になっちゃってただけとかなのか?というところが確信が得られないので不安

    さらにForwardAddというのがあって
    こっちを使用すればすべてのライトを順番に処理してくれるようなのだけど
    これがもう2Pass目以降になってしまい、1Pass目で描写したものに加算(おそらく)で上乗せする形なので
    セルシェーディングの領域分けに利用するのは不可能なんじゃないのかなと思う
    (1pass目でセルシェーディングしたものに重ねることはできるけどそれはもう普通のシェーディングが重なったどっちつかずのものになっちゃうのではというか……)
    なおかつ先ほどunity_4LightPosX0で処理したライトとの重要度的な比較でどっちが重要だと判定されているわけ?というのもまだわかってないのも痛い……
    (仮に_WorldSpaceLightPos0系、ForwardAdd系、unity_4LightPosX0系の順で重要だとされるならば、ForwardAdd無理にでもしないと二番目に重要なライトは処理されていないということになってしまう……)

    とかいろいろ知識不足なところもありつつでベストとはいいがたい感じがしてしまう

    ・Vertex Lit
    unity_LightPosition[]を使用することで一つのPASS内で重要なライトを8個まで処理できる!
    主な参考先
    [Unity] ひとつのPass内で複数のライトを使う
    Unityでハマッたこと一覧メモ
    ライトにもいろいろ種類があるからややこしい処理をさらに自前でしなきゃいけないものの
    情報取得という点では申し分ないしこれ使えばいいじゃん!
    とおもったらどうも落ち影を受けるということができないらしい……
    (自分でいろいろ書こうという感じで超頑張れば別なのかもしれないけども……)
    あがー……

    ・減衰の取得に関して
    unity_4LightAtten0[0~3]
    unity_LightAtten[0~7].z
    でそれぞれ取得できるっぽいもののそのままで使用できるわけではないというか
    これをそのままフラグメントシェーダーの最終出力に突っ込んだとしても
    ポイントライトから離れるにつれ暗くなるという本来イメージしている状態にはならないっぽい?
    これまた上のほうで出した参考サイトからパクり&改変なんだけども

    float4 worldPos = mul(unity_ObjectToWorld, v.vertex);
    //ライトの位置を取得
    float4 lightPosition = float4(unity_4LightPosX0[i], unity_4LightPosY0[i], unity_4LightPosZ0[i], 1.0);
    //ライトの位置と頂点位置を減算して方向を取得(長さをとりたいので正規化はしない)
    float3 lightDirection = lightPosition.xyz - worldPos.xyz;
    //内積でベクトルの長さをとる
    fixed lengthSq = dot(lightDirection, lightDirection);
    //ライトの減衰を取得?
    float attenuation = 1.0 / (1.0 + unity_4LightAtten0[i] * lengthSq);

    という感じでいくつか材料的な値をとってきて最後に計算してやることでやっとイメージ通りの減衰の出力になる
    (上の図の場合はattenuationがその出力内容
    ただ最後の行の計算の意味がさっぱり理解できてないけどなー!!!

    ただポイントライトはこれでいいんだけど
    スポットライトの場合が全然わからん……という段階

    ・ライトのIntensityの取得に関して
    _LightColor0だとかで色を取得する際に
    ライトの色のrgb x Intensity
    という形で混ぜ込まれて渡されるらしい?
    なのでIntensityが欲しい場合は
    _LightColor0同士で内積を出せばベクトルの長さとしてライトの強さを取得できるっぽい
    (これまた上記サイトの内容)
    色にライトの強さ混ぜ込まれているというのも知らなかったし
    内積は方向が一致してるかしてないかを-1~1で取得できるという解釈だったのだけど
    それは正規化されたベクトルの場合で、そうでない場合は同じもの同士をやることで長さ(強さ?)を取得できるというのを知らなかったのでメモしておく



    ということまでわかった段階が今

    これまでForwardBase(addは使わない)でセルシェーディング書いてきたものの
    複数ライトを処理しなきゃという段階になってライトの重要度の判定がいまいちわからんとかもあり
    じゃぁちゃんと複数ライト処理できる方法あるらしいからそっちに変更するかとしたものの
    それがVertex Litで落ち影もらえないのはダメよな……となり
    じゃぁやはりForwardBaseでできる範囲内で頑張るしかないのか??


    で、そうなってくると取捨選択の話になってくる気もするけどもForwardBaseだけだと不安な部分について
    ・二つ目のDirectional LightってShadeSH9とかで考慮してくれてるのか?(してくれてない気がする)
    ・上でも書いたけどForwardAddで処理される内容と判断されたライトが抜け落ちるとかない?(これは試しなおしたところだと大丈夫そう?以前のシェーダー記述が駄目だっただけ?)
    ・スポットライトはShadeSH9でしか処理されてないとかっぽいけど大丈夫なもんなのか?
    (そもそも浅く広く調べる感じになってしまっているのもあってまだDirectional Lightとpint lightしかシーンにおいてなかったとかもある……)

    という点をつぶしていかないとどうにも……

    ただ今のところForwardBase以外に選択肢はないように感じるなぁ結局
    正直シェーダー自分で頑張って書くというレベルまでやるなら
    複数ライトの情報ぐらい制限なく取れるイメージだったけどエンジンごと(もしくはもうここはそういうものでどのエンジンでも同じ?)の制約というかできることできないことあるのね……



    というあたりのことをやってたら脳内ごちゃごちゃしてきたので書き出してすっきりしたいという話だった
    (前の記事に追記してもよかったんだけどこれだけで長くなりそうだったから別記事としてメモすることにした……)
    ただこれ書き始めたところでDeferredでも陰影情報とれるっぽい感じのを見かけたので(勘違いかもだが)まずそれもちょっと調べたいかな(優先度は低めで)

    あまりに内容が難しい、もしくはForwardBaseのみでは無理っぽいライト情報は切り捨てる方向で行くしかないのかなーとかも考えないと
    わかんないのでぼーっとしてしまうみたいな時間が長くなるばかりかもしれない……