• 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のみでは無理っぽいライト情報は切り捨てる方向で行くしかないのかなーとかも考えないと
    わかんないのでぼーっとしてしまうみたいな時間が長くなるばかりかもしれない……


  • unity shader用にほかのサイトからパクって調整した処理を残しておくコーナー

    2019-05-14 11:38
    1
    ライトの色を合成するのにRGVをHSVにして
    HとSを混ぜてあげれば色合いだけ変わるんじゃねーの?

    2
    でもHって1で一周するやつだから単純な足し算引き算じゃ混ぜれんよね……
    (0.9と0.1の間は0になってほしいところ0.5になるという)
    角度をベクトルに変換して混ぜることで間をとる方法があるらしいぞコレだな!?
    これパクって改変だな!?


    うまくいかないと思ったらCG言語でのatan2とかいうの-90度も90度も90度として返してくるとからしいぞ……
    なんか精度低くした代わりに処理速度早くしてなおかつちゃんと180~-180で値返してくれるのを公開してくれてるサイトがあったぞ!
    これパクって改変だな!?

    4
    なんとかうまくいったけど水色のオブジェクトに赤いライトあてると緑色になる
    色相の混ざり方的には完全に合ってるけど感覚的にはダメな奴だなコレ……?

    という流れでせっかくパクって何とか改変したのに使わなくなった処理をメモ的に張り付けておくことにするという流れですはい……

    上で書いたCG言語でのatan2では都合が悪かったので0~360で角度を返してくれるようにした奴
    パクり元サイトは以下
    近似式でatan2の処理を高速化してみる
    高速化されているという部分は処理負荷自体に詳しくないのでシェーダーでも早いものなのかなどはわかってない(キリッ)

    //------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    //CG言語でのatan2は90も-90も90で返してきてしまうらしい?
    //とにかく180度以上になった時にきついのでユニークで実装
    //処理自体も正確ではなくなる近似値をとるようにして高速化しているらしい
    //https://garchiving.com/approximation-atan2/
    //ここにあったものを微改変
    //------------------------------------------------------------------------------------------------------------------------------------------------------------------------


    float atan2_360(float yv, float xv) {
    float x = abs(xv);
    float y = abs(yv);
    float z;
    bool c;

    c = y < x;
    if (c)z = (float)y / x;
    else z = (float)x / y;

    float a;
    //0~45度までで変換しているらしい
    //ここで処理の正確さと速さをコメントアウトで選択するらしい
    //一旦一番早いものを使用
    a = z * (-1556 * z + 6072); //2次曲線近似
    //a = z * (z * (-448 * z - 954) + 5894); //3次曲線近似
    //a = z * (z * (z * (829 * z - 2011) - 58) + 5741); //4次曲線近似

    if (c) {
    if (xv > 0) {
    if (yv < 0)a = 36000 - a;
    }
    if (xv < 0) {
    if (yv > 0)a = 18000 - a;
    if (yv < 0)a = a + 18000;
    }
    }

    if (!c) {
    if (xv > 0) {
    if (yv > 0) a = 9000 - a;
    if (yv < 0) a = 27000 + a;
    }
    if (xv < 0) {
    if (yv > 0) a = a + 9000;
    if (yv < 0) a = 27000 - a;
    }
    }

    //0~3600になっているので補正
    a = a * 0.01;


    return a;
    }

    角度をベクトルに変換してから混ぜて平均をとるという方法で
    HSVのHを混ぜる処理
    パクり元サイトは以下
    角度の平均を求める方法
    注意
    ・上で作成したatan2_360を使っている箇所がある
    ・実際自分がシェーダー内で使っていた部分から
     このブログ上で改変省略してシンプルにした部分があるので
     その部分間違えてる可能性あるので動かんかったら修正の必要あり




    //------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    //HSVのHの平均を出すために角度として考えてベクトル変換してから平均値を出す関数
    //https://qiita.com/koyo-miyamura/items/37d555ae150047ebefde
    //計算内容自体の参考
    //------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    float H_average(float base_H, float light_H) {

    float angles_rad;

    //0~1に360をかけて角度に、そこからさらにラジアンというものに変換
    angles_rad = radians(360 * base_H);
    //サインとコサインでベクトルにする(できるらしい?)
    float2 base_vectors = float2 (cos(angles_rad), sin(angles_rad));

    //ほかの要素も同様に処理
    angles_rad = radians(360 * light_H);
    float2 light_vectors = float2 (cos(angles_rad), sin(angles_rad));

    //ベクトルを足して割る
    float2 last_vectors =(base_vectors + light_vectors)/ 2 ;

    //ベクトルからラジンアン、角度、Hに逆変換
    //CG言語のatan2は90も-90も区別せず90度と返してくるらしいのでいただいてきた独自処理で0~360でもらう
    float last_H = (atan2_360(last_vectors.y, last_vectors.x)) / 360;

    return last_H;
    }


    移植してみたけど使わなかったものを残しておくための記事だけども
    RGBとHSVの変換に関してもパクったサイトURLを貼っておく
    【Unity】RGBをHSVに変換して明るさとかを変えるシェーダー

    基本的にセルシェーダーの更新は一つ前の記事を追記で更新していこうと思ってるけども
    こういう風にパクってきたとはいえ色々調べたのに使わなかったみたいなのまたでたら
    こっちに追記するかも