Imaginantia

思ったことを書きます

記録 Synを見ました

www.tokyonode.jp

これです。28日に行ってきました。

写真これしか撮ってなかった。

結論から言うと私はすごく好きでした。というか「私好み」でした。

以下、記録として視たものについて記しておきます。知りたくない方は観てから読んでください。

 

私はだいたいどんな作品も「構造」(骨組み、みたいな意味合い) で読もうとするところがあります。ゲームを観察してた影響だと思いますが。

だから「時系列順に出来事が起きるモノ」は、その時点で"そう"読み終えてしまって、まぁ、いつものか、っていう感じがする。

だけど Syn はそうじゃなかったので良かったのです。つまり、あの場所で展示をする意味があり、あのような展示方式にする意味があり、そうなった理由を私達に説明しているのです。

それだけで私はとても満足でした。そういう外側の発想をちゃんと作品化する、というのはなかなか見られないものですから。

 

私は次のように解釈しました:

  • 人々がたくさん入る、動的な・時系列に沿った展示空間を作りたい、という話になる。
  • 同じ場所に居るだけでは面白くないので、人を動かしたい。
  • しかし1グループで構成するとthroughputが低い。
  • よって、複数グループを同時並行で回せる構造を作る必要がある。
  • そうなった場合、次グループ・前グループがうっかり見えてしまう可能性があり、そうすると没入感が損なわれる。
  • しかし、これを逆手に取り、「次/前グループが見えること」そのものを演出に組み込むことで世界の境界を広げ、閉じることができる。
  • その為に、私達は「過去の私達」を認識する必要があった。これによって次グループの存在がスムーズに認識できるようになる。
  • それを合理化する為に、逆再生が必要だった。

つまり、まず Syn の没入感 (Immersion) とは、「あの空間」に対する没入ではなく「このメタ構造を識っている」という没入を狙っているのだと思ったのです。

過去に何が起きているかわかる。未来で何が起きるかわかる、という、世界そのものに自己がascendするような感覚。

もちろんこれが正しい演出意図かどうかは知りませんが、それはまぁどうでもよくて、私はこう認識し、それが私には嬉しかったというだけの話です。

 

この芯 (Syn?) だけでは作品にはならないので、実現するための肉付けがとてもたくさん入っています。それが「演出」。

始まりの部屋と終わりの部屋はタイミング同期の為に必要です。特に始まりの部屋はチュートリアル (ダンサーがこれくらいの行動を行うことを予め知らせておく) でもあるので大事です。あとモニタに展示空間全体の3Dモデルが映してあって「これからここに行きますよー」っていう提示もやっていましたね。デカ映像が色々映ってはいましたが、これは次の部屋の始まりと接続するための最後のぐにょぐにょちゃんを引っ張ってくるのが目的だったのかな?

終わりの部屋はクールダウンが主な目的だと思っています。CUE で体感したんですが、前の演出がなんであれ、その後に大人しくなると「前の演出が激しかった」という相対的認識が発生して「良かった」という感情が起きやすい気がします。

メイン部屋は大きく3パートの構成になっているのかな?最初に縦長キューブをモチーフとして記憶させ、道具と人で演出するパートが入り、最後に全ての種明かしみたいな展開が入る。

種明かしっぽいことをするのはなんか Rhizomatiks っぽくて良かったです。まぁ元の意図としてもその必要があるということにはなるはずですが。

だからメインパートの前半には「観客に演出を記憶させる」為に動いているように見えるところがちょこちょこあって。1つ気になったのは照明がめちゃくちゃゲーミング色になってたところ。あともう1つ、「パンパン」音が鳴ったときの壁が海モチーフっぽくて妙に具体的だったところ。

ゲーミングにするんだ~へ~って思っていたところ、この部分が逆再生の結果そこそこ見返すことになっていたので、「見た覚えある!」っていうのを強調する意図があったのかなって思いました。

あとパンパン音が鳴るときの壁は、こっち側でもあっち側でも多分同じ映像が流れていた気がします。具体性を上げることで記憶しやすくさせて、さらに音と映像をつなげることで強制的に既視感を与える。

そうなってくるとだんだん「私は何を見たのか?」が気になってきて、意識がメタレベルへ昇華していく、という構造です。そういえば途中で3D効果が消失するところも、「あ、これが本当の世界か」と一瞬冷めさせて、戻して「じゃあこっちは何の世界 ?」っていう意識の切り替えを促していたようにも思います。

中間あたりで扉が開いたとき、奥に「前のグループ」の観客が居たのが観えました。アレは未来の私達を見せる意図だったのかなと。最後にその伏線回収をやって、見えなかったあの続きが視えて、終わり。

まぁ、納得できる意味づけです。私にとっては。

 

あと最後の部屋は「観えなくても視える」をやりたかった感じはします。丁寧な観察をさせるには盛り上がっちゃうパートだと難しいので (特に人が居るとそっちに目が行くので難しい)、人を抜き、さらに肉眼では観えないけれど認識を与えることで視えるようになるモノを置き、穏やかに観察してもらう時間。

クールダウンとしても適切で。ここは素直な部屋だったと思います。

 

じゃあこの「私達はパズルをこう解きました発表会」が展示の目的だったかというと当然そんなことはないと思います。結局はこれは作品を成り立たせる為の構造を作品自体に埋め込んだというだけの話で、見方はまぁなんでもいいのでしょう。各々が面白いと感じればそれで。

中途半端に解釈がありそうで無い物語性をつけちゃったりすると私はめちゃくちゃ冷めちゃうタイプなので、そういうところには諦めが最初からあったように観えて (最初の部屋、色々表示されては居ますが本当に何かあるわけではないじゃないですか、アレ) よかったなあって思います。

正確には、まぁそういうのがあったとしても、そこが本意ではないと私が認識できる程度の芯がちゃんとあったので、私はそれを満足とした、という意味ですね。

まとめると、とてもおもしろかったです。

日記 231028

10月は全然ブログ書いてないですね。まぁ、まぁ。

ワールドのことはあんまり書くことがないかなと。なんというか、ありがちなやつでもあるし、何故か無かったやつでもある感じです。とりあえず実在させておこうと思ったので作りました。

概ね想定通りな感じで良かったです。色々話したりできたのもよかった。

 

後は最近なんとなく思ったことについて書きます。日記です。

語彙の話。

人間の思考が語彙によって制限されるというのはよく言う話ですが、それはつまり語彙が増えると思考しやすくなるということです。

そしてこのコンピュータ科学の分野っていうのは、当然ながら「これまでになかったもの」を扱う必要がある以上、語彙を増やさなきゃいけない分野だということになります。

この文章を書こうとしたきっかけは Graphics.Blit です。Blit って何?

で、調べてみるとこれは "Block Transfer" の略であることがわかります。正確には、Block Transfer の略 Blt の慣用読みを綴って "Blit" ですね。

「ブロック転送」を一語で表す英単語が生まれているわけです。すごいことだと思いました。

他にもまぁ Pixel (picture element) も結構キモいし、Raycast でほぼ1語として使われている (Physics.Raycast は "c" が小文字です) のもそういう方向性かなってちょっと思います。

そういう風にちゃんと「新しい語」として認識できると「概念」を認識できるようになる。っていう…のは一般的にあるとは思います。

とは言ってもそういうケースは稀で。大体は既存の語を借用していることがほとんど。

"render" は元々「やる」くらいの意味しかない語だと思います。"execute" も「行う」だし。でもそれらは "perform" とは違うという認識を私はしている。

いや、どうせ言語認識なんて曖昧なものではありますが。多少概念の認識…特に認識速度には影響してるなあとちょっと思いました。

 

www.youtube.com

この動画、マジでいい内容なんですけど、それに関連する話題として「vector と covector が性質として異なるのに、まとめてみんな vector と呼んでしまっていた」という話があります。

「3つのスカラー値で構成される値」といえば "vector" です。だけど、所謂「向き」を表すベクトルの扱い方と、法線ベクトルの扱い方は違う、っていうことがよく知られています。

それは法線ベクトルは所謂 vector ではなく covector だから、なんですけど、この違いは語彙が無いときっとわからないのです。

この語彙を生み出すためには線形代数的にベクトルをどう扱うべきかを丁寧につっついていく必要があって。それをやってるのがこの動画なんですが。

それまでは…というかまぁ現代の多くの人は、多分まとめて vector として認識しています。(ベクトル空間の元であることは間違いないですよ、もちろん)

同じように見えるものを区別するというのもまた抽象化の一つで。ちゃんとできていると「言葉が違う」すなわち「自然に違う扱い方ができるようになる」のです。そうありたいものですね。

 

語彙は多ければ多いほど良い…っていうのは確かにそうでしょうけど、私はあんまり語彙を増やさないタイプの人間です。細かい意味に展開可能であるべきだと思っているところがある。論理を丁寧に追えることが前提ですが…。

少ない言葉でもその組み合わせで十分な展開ができるなら、関係ないと思ったものたちもうまく繋げられたりするかなとか思ったりする。

…でもまぁ限界はある。いや、まぁ、細かく展開可能じゃないものはちゃんと大事な語彙として覚えているので大丈夫。"monad" とか。

なんの話だっけ。

 

ちょっと思ったのは、VR空間での諸々にはきっと語彙が全然足りないので、もしかしたらもっと私達は言葉を発明しなきゃいけないのかもしれない。

でも、逆に言えば、まだ新しい語彙が必要としていない領域なのかもしれない。

新概念が明確に出てきたら、そういうところできっと明らかになるんかなあってちょっと思ったりしました。

でてくるのかは、しらない。

 

おわり。

VRChatでGPGPUする (2023年版)

とりあえず私のやりかたについて情報を書いておこうかなと思います。

簡潔に言うと:

  • RenderTextureをUdonで用意して
  • VRCGraphics.Blit で計算を回して
  • CPUで情報取りたければ VRCAsyncGPUReadback.Request から OnAsyncGpuReadbackComplete で拾います。

サンプル作ってみたのでそっちを見る方が早いかもしれません。ご自由にどうぞ: particles0925.unitypackage (Rawからダウンロードできます)

あとリポジトリにフォルダごとアップロードしたのでGitHub上でも見やすくなりました: Particles/

ちなみに何かに部分的に流用した場合でも特に私のことは書かないで大丈夫です (書かないでください)。いい感じによろしくおねがいします。

基本的な仕組み

要はGPU側のバッファを作って、用意したシェーダで中身を更新していきたいわけです。

今はUdonnew RenderTexture すればGPUバッファを作れるのでめちゃ簡単ですね。

中身の更新は素直に VRCGraphics.Blit を使います。source をちゃんと指定してもまぁいいんだと思いますが、なんか怖いので、自前で渡すようにしてます。

状態の更新を行うには「前フレームの自分自身のバッファ」を拾う必要がありますが、多分 Double Buffering の機能は無いので (いつ使えるのか微妙によくわからないので)、バッファは必ず2個セットで作るようにしています。

こんなかんじ:

public Material update;

private RenderTexture rt0;
private RenderTexture rt1;
private bool outputIs0 = true;

void Start()
{
    int W = 256;
    int H = 256;
    rt0 = new RenderTexture(W, H, 0, RenderTextureFormat.ARGBFloat);
    rt0.filterMode = FilterMode.Point;
    rt0.Create();
    rt1 = new RenderTexture(W, H, 0, RenderTextureFormat.ARGBFloat);
    rt1.filterMode = FilterMode.Point;
    rt1.Create();
    update.SetFloat("_Init", 1);
}

void FixedUpdate()
{
    if(outputIs0) {
        update.SetTexture("_Store", rt0);
        VRCGraphics.Blit(null, rt1, update);
    } else {
        update.SetTexture("_Store", rt1);
        VRCGraphics.Blit(null, rt0, update);
    }
    update.SetFloat("_Init", 0);
    outputIs0 = !outputIs0;
}

初期化は毎回 _Init 変数を使ってやってます。なんかもったいない気もするけどしょうがない気もする。バッファは何故か _Store という名前をずっと使い続けていますが、好みで大丈夫です。

ちなみに何度 Blit を呼んでももちろん大丈夫なので、複数パスのシミュレーションとかも気軽に書けるかなって思います。

Double Buffering を配列でやるかどうかは好みだと思います。

計算シェーダ

ここからはもう個人のやり方なので、参考にしたりしなかったりしてください

基本的に .shader ファイルにはほぼ何も書かず、.cginc に処理を記述するようにしています。理由は:

  • どうせ描画するときにも使う関数が結構多い
  • インデントが深くて邪魔
  • 複数パスを1ファイルにまとめて書ける

という感じです。

なのでこれはほぼ固定です。

Shader "Im/Test/Update"
{
    Properties
    {
        _Store ("Store", 2D) = "black" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "Core.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
#if UNITY_UV_STARTS_AT_TOP
                o.vertex = float4(v.uv.x*2-1,1-v.uv.y*2,1,1);
#else
                o.vertex = float4(v.uv.x*2-1,v.uv.y*2-1,1,1);
#endif
                o.uv = v.uv;
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
                uint2 iuv = i.uv * float2(W,H);
                return update(iuv);
            }
            ENDCG
        }
    }
}

念のため UV_STARTS_AT_TOP を気にしたりしつつ座標 (uint2) を update 関数に投げます。メイン処理は Core.cginc にあるという想定。

ちなみに i.uv * float2(W, H) は基本的には「整数 + 0.5」になっているはずです。なので uint2 に突っ込んだらちゃんと floor になって正しい値がとれるはず。

バッファをサンプルする関数はだいたいコレです:

#define W 256
#define H 256

sampler2D _Store;

float4 pick(uint2 iuv) {
    return tex2Dlod(_Store, float4((iuv+0.5)/float2(W,H), 0, 0));
}

言うことは特にないですね。これを表示側のシェーダでも使えばまぁいい感じになると思います。更新部分を少し書き換えるのを忘れずに。

if(outputIs0) {
    update.SetTexture("_Store", rt0);
    VRCGraphics.Blit(null, rt1, update);
    visual.SetTexture("_Store", rt1);
} else {
    update.SetTexture("_Store", rt1);
    VRCGraphics.Blit(null, rt0, update);
    visual.SetTexture("_Store", rt0);
}

その他

複数ピクセル

1pxだと情報が足りないので複数ピクセル使って1要素を構成したいことがあります。その場合は適当に縦横に並べています。2x2pxで同じリソースを参照するほうが多分効率が良いのでこれがいいはず。

ちなみに9pxで足りるときでも16px使います。きれいに揃えたほうが多分速い…というよりもGPU的に気持ちが良いと思います。

あと、このときは pick の引数を増やしたほうがわかりやすい感じになります。多分。

#define EW 4
#define EH 2
float4 pick(uint2 particleIndex, uint2 elementIndex) {
    return tex2Dlod(_Store, float4((particleIndex*float2(EW, EH)+elementIndex+0.5)/float2(W*EW, H*EH), 0, 0));
}
float4 d0 = pick(pi, uint2(0,0));
float4 d1 = pick(pi, uint2(1,0));
float4 d4 = pick(pi, uint2(0,1));
float4 d5 = pick(pi, uint2(1,1));

こうやって使う。

逆に書き込みのときは「選ぶ」関数を使って return することになります。

float4 select(uint2 elementIndex, float4 d0, float4 d1, float4 d2, float4 d3, float4 d4, float4 d5, float4 d6, float4 d7) {
    return elementIndex.y == 0
        ? elementIndex.x < 2 ? elementIndex.x == 0 ? d0 : d1: elementIndex.x == 2 ? d2 : d3
        : elementIndex.x < 2 ? elementIndex.x == 0 ? d4 : d5: elementIndex.x == 2 ? d6 : d7;
}

Mipmap

変なこと をするときにMipmapがほしいときがあります。

RenderTexture を作るときに設定すればいいです。

rt.useMipMap = true;
rt.autoGenerateMips = true;

こうすると Blit 後に自動的にMipmapが更新されるようになるっぽいです。

Udonに読み戻す

これをまず読むのが一番いいと思います。

creators.vrchat.com

VRCAsyncGPUReadback.RequestTexture 型を引数に取ります。なのでもちろん RenderTexture を渡せます。

引数がいっぱいありますが要は「一部分だけ読み出せる」っぽいので、必要最低限のところを切り出すのが効率良いんじゃないかなと思います。

Callbackとして指定する IUdonEventReceiver インタフェースは VRC.Udon.Common.Interfaces にあるので using しておきましょう。

完了すると OnAsyncGpuReadbackComplete メソッドを呼んでくれますが、この間に1フレーム経つことには注意が必要です。

ちょうど1フレームとは仕様には明言されていませんが、実験的には1フレームのようです。でもそれに依存したコードはあんまり良くないかも。まぁ「そのうち帰ってくる」わけです。だからいい感じにロジック側で遅延を吸収してあげる必要があります。非同期処理あるあるですね。

ちなみにデータは byte[] Color[] Color32[] float[] のどの形式でも受け取ることができます。これは例えば AudioClip.SetData に直接渡したりもできるということです。たのしそう。

あと、現在は Quest 上だと VRCAsyncGPUReadback が動きません (hasError = true になります) が、Unity 2022 になると直ります (Quest の open-beta で直っています)。わくわく。

おわりに

phi16.hatenablog.com

懐かしいですね。良い環境になりました。いっぱい計算しましょう。

 

サンプルの解説は特にありませんが、まぁわからないところがあったら気軽に呼んでください。

GameObjectとUObjectの違いを考える

折角なので (?) UnityとUEの設計思想について、各エンジンにおける「オブジェクト」概念を調べてみることで垣間見る、ということをやろうと思います。

純粋に「設計思想」について考えるだけであって、それぞれの完成度がどうとか、会社がどうとかという話は関係ありません。

できるだけニュートラルに書いてみようと思いますが、多少偏りはあると思います。

参照するドキュメントページはコレです:

どれも現在最新バージョンのドキュメントです。

Unity

世界 (Scene) に存在する全ての物体の基礎となるクラスがGameObjectです。各GameObjectは座標変換を表すtransformを持っていて、つまり「全てのオブジェクトは、空間内に位置する」という設計です。つまり例えばネットワーク管理オブジェクトなども、恐らく位置概念は不要であるにも関わらず、必ず位置の情報を持たなければなりません

transformは位置だけではなく階層構造を保持するものでもあり、各GameObjectは子GameObjectを複数持つことが出来ます。「オブジェクトは階層構造を成す」もので、これによって Scene 内のオブジェクト一覧は hierarchy と呼ばれています。

各GameObjectは複数のComponentを持ちます。GameObjectの挙動を指定するのは全てComponentなので、「オブジェクトはコンポーネントによって意味が規定される」わけです。つまり「GameObject自体は、とてもまっさらな存在」です。

 

Componentを作成するときに継承されるのがMonoBehaviourクラスです。名前の通り挙動 (Behaviour) を表すものです。Unity本体の動作と協調する為にたくさんのイベントハンドラを持っています。持っている変数には特筆すべきものはないですね。

イベントハンドラ群を見てみると、Start/Updateの他、Applicationの状態・可視性の変化・マウス操作・レンダリング時・Animator/AudioFilter/Collision/Joint/Particle などのイベントを受け取ることができるようになっています。「どんな挙動も、これらの外部イベントを受け取りたくなるだろう」という想定になっていると言えるわけです。加えて OnConnectedToServer OnFailedToConnect などもあり、「誰だって通信したくなる」気持ちも持っているのかもしれません。

…とは言え、多分過去の名残でこうなってしまっているだけで、最近のAPIだとインタフェースを追加実装するのが一般的かと思います。

Unreal Engine 5

UObjectは世界 (Level) に存在する物体、というよりももう少し広く、レベル間を跨ぐことも出来る感じがします。実際位置の情報などは持っておらず、"物体"というよりも"対象"という訳がふさわしいかもしれません。とは言え「子オブジェクト」の概念はあって、入れ子構造を表現できます。

UObjectは基本的にはそれだけで使うよりは継承してカスタムな挙動を作る為に使われるクラスです。例えばレベルに存在するオブジェクトはActorと呼ばれ、UObjectを継承しています。「子オブジェクト」も、別にUObjectがそのままぶら下がっているわけではなく、基本的には派生クラスが付いているものです。つまりは「オブジェクト自体が挙動を持つ」仕組みです。

なのでUObjectには外部イベントを拾うハンドラがたくさん存在しています。正直関数名から何に使うのかを想定するのはかなり厳しいように見えますが、まぁ色んなユースケースに合わせて拡張していった結果であることがわかります。実際 4.27 から 5.3 にかけてメソッドは10個程度増えているようです:

  • AppendToClassSchema
  • ConformSparseClassDataStruct
  • DeclareConstructClasses
  • DeclareCustomVersions
  • GetExtendedAssetRegistryTagsForSave
  • IsCapturingAsRootObjectForTransaction
  • OverrideConfigSection
  • PostCDOCompiled
  • PostLoadAssetRegistryTags
  • ResolveSubobject
  • SetEditChangePropagationFlags
  • TryUpdateDefaultConfigFile

UObjectはGameObject/MonoBehaviourとは違い、「いろんな状況をまるごとこいつで解決する」という姿勢で作られているように見えますね。

ちなみに Unity 2017.1 から 2023.2 になって追加されたメソッドは GameObject.TryGetComponent GameObject.FindAnyObjectByType MonoBehaviour.OnParticleSystemStopped MonoBehaviour.OnParticleUpdateJobScheduled くらいでした。

 

レベルに存在する物体 (GameObjectに対応するもの)である Actor (AActorクラス) についても少し見てみます。これはUObjectの直接の子クラスで「レベルに置かれたモノ」を表すのですが、これ自体は位置の情報を持っていません。代わりにRootComponentと呼ばれるUSceneComponentのインスタンスが持っています。というわけでコンポーネントという概念自体はUEにもあります。オブジェクト自体に挙動を記述できる他、コンポーネントを使うことで挙動をつなぎ合わせることも出来るわけです。UEはそういう「なにかをやる、という目的だけで言うと手段がたくさんある」環境であると思います。

Unityは「位置を持つ」というのはもうオブジェクトに根底から必要な要件として設計されているわけですが、UEは逆にコンポーネントとして取り外し可能な程度のものだと認識しているわけですね (Actorから取り外すことはできませんけども)。

さて、AActorのメソッドもたくさんあるので紹介できる気がしません。ただ、とりあえず「何でも出来るものを作って、その機能を切り出して使ってもらう」という姿勢である、ということは言えると思います。 例えば TakeDamage メソッドがあり、SetReplicates メソッドがあります。つまり「万物はダメージを受けるし、通信によってサーバと同期される」という想定なのです。

まとめ

以上のことを大雑把に言うと、「Unityは (できるだけ) 最小限の機能を基盤に置いて、後からつなぎ合わせる設計」「UEは、最大限の機能を基盤に置いて、好みに合わせて抜いてもらう設計」と言えるのではないかと思います。

追記: 「位置」に関しては違うのでは?という意見をもらいました。その通りだと思います。 UEはC++ベースなので「位置」概念が希薄だったのかなと、ほとんどの概念系クラスには位置は要らないですよね。 Unityは代わりに「全て (概念を含めて) を物体化」させることで (概念を含めた) 管理をしやすくする意図があったのかなと思っています。概念と物体の区別は必要ない、という単純化。Unity"3D"って言ってますし。

これは結局選択なので、好みはあれど良し悪しは (観点が無ければ!) 言いにくいものです。逆に言えば、「ソフトウェア開発の基本ができている」という観点から見ればUnityは良く出来ていて、「ゲームに必要な機能がまず揃っている」という観点から見るとUEは良く出来ているわけです。

が、その観点が正しいのかどうかはまた別の話です。良い観点が見つかると良いですね。

 

というわけで、なんとなくドキュメントを眺める回をやってみました。

もっと色々書けることはあると思いますが、何にせよ「基本的なクラス設計からどういうゲームエンジンなのかは伺える」ということを主張したかったので、結果には満足です。

ちなみに GodotのObject/Node は面白いなあって思います。もっとモジュール化が徹底されている雰囲気で (個人的な) 好感度が高いです。

おわり。

 


Unityの回転表現がQuaternion (向きに依存しない標準的な回転表現) で、UEの回転表現がRotator (Euler角、地上方向基準だと使いやすい) なところから既に伺えることはかなり多いなあと個人的には思っています。

日記 230914

Twitterに書いてもしょうがない気がするのでだらだらと。

全て個人の感想です。

 


Unity について

  • 発表について
    • 少なくとも過剰反応している人は「居る」。
      • 読み取れないことを勝手に憶測する人・文章を読み取り間違えて嘘を撒く人
      • まぁいつものことである
    • 公式発表自体が揺れているっぽいのは事実。
      • つまりUnity自体がちょっと怪しいのも事実。
    • Fee 体系がやばいという話と Unity の信頼がやばいという話は別。
      • (この文章は「Fee 体系がやばい」「Unity の信頼がやばい」とは書いていません)
    • 10% は多い。
      • Unityが見えている10%と、私達が見えている ("夢見たい") 10% が一致しているのかはわからない。
      • でも感覚になんらかの齟齬があるのは事実だと思う。
  • Runtime Fee について
    • 結局最大の問題は「どうやって検知するか?」というところ。
      • これが不透明であるなら疑念はどうしても消えない
    • どうしてこうなったかの経緯や意図もわからないのでそういう点はなんとも言えない。
      • し、何も言うべきではないと思う。
  • 信頼について
    • まず、個人的には、プロダクトは他のエンジンよりもちゃんと良いもの、だと思う。
      • 不満があるということと矛盾はしないです。
    • で、信頼という言葉を使うのなら「他の企業は信頼ができるのか?」ということを考えなければならない。
    • そして、当然「自作エンジンは信頼ができるのか?」ということも考えなければならない。
      • この「信頼」という言葉が指しているのは違うものではあるけれど、繋がっているものではある。
    • その上で Unity を捨てるなら、まぁそれはそういう選択なんだと思う。おかしくはない。
      • 「抗議」をするなら、それはまだ信頼していたいっていう意味ですよね。

他環境について

  • 設計の筋がきちんと通っていて、納得があり、何が出来て何が出来ないのかがわかるのが良いモノ、だと私は思う。
  • その点において UE と C++ はどっちも無い。
    • UE は結局レガシーを積みまくった知見とやらの塊で、それに価値はあるけれど、私は使いたくない。
    • C++ も過去の遺物で、他言語環境からすればなんでこんな苦行してるの、ってなるものだと思う。
    • 両者に利点はあるが、その利点を享受できる人はかなり限られていると思う。
      • UE はプロトタイピングには良いんだと思う。でも丁寧な構造を考え始めるとどんどん余計なものがついてくる感じがする。
      • C++ の速度面での利点は正直今微妙な気がする。強いて言えば古のソフトウェアを直接叩けるとか。闇魔術が使えるとか。まぁ実際それが大きい。
  • Unity は少なくともやるべきことは明らかかなって思う。何故なら何も無いので。
  • Godot はぱっと見た感じ嫌いじゃなかった。いい子なんだと思う。

 

ソフトウェア開発の気持ちとしては「レガシーを捨てる」っていうのは成長のために必要な要素で、それが無い場所に成長はないと思っている。

Unity はレガシーを捨てようとして悪戦苦闘している。Epic はそんな雰囲気はない。その時点でエンジニアリングの観点からは Epic に信頼がない。私は。

頑張ろうとしていること自体が評価できるわけではないけど、UE ほどのしんどいレガシーを Unity は抱えてないと思う。私はずっと Rotator が気に食わない。あと Character とかも。

 

あと C++ を勉強する価値は…あるけど、あるけど、実用する価値はあんまりないと思う、本当に。それよりは C をやったほうがいいかもしれない。

module も concept も遅すぎたよ…。overload だけでもう何ページ文章が書けるんだかって感じじゃない。いや、名前解決だけで…。

C++ という言語が存在する価値は大きくあるんだけど、実用はまた別の話だと思う。じゃあ実用で何を使うか、っていうと選びにくいのが現状ではあるんですけどね…。

でもわざわざ必要の無い地獄に行かなくても良い。消極的に行くならわかるし、まぁ私も結局そうなっている。

 

まぁ好きじゃなくても使う、っていうのは全然わかる話。世の中は不幸で出来ている。

 

あと、独自エンジン派はまぁ勝手にやればいいと思うけど、その結果自分がどれほどのなにかの上に立っていたのかを知るんだろうなと思います。

エンジン移行もそんな簡単にできる話じゃないと思うよ。思ったより。

その他思うこと

とりあえずみんな煽りすぎだし煽られすぎだと思う。ちゃんと見てちゃんとおかしいならちゃんと抗議すれば良い。SNSで見栄えが良いような抗議をするのは違うだろ。

そういう社会的な追い込みをするのは好きではない。SNSは本当に「その辺の人」が強者になりすぎる。そういう暴力ではなく、明確な論理で対話してほしい。

まぁもちろんUnityが対話に出てこいというのが大前提ですが。それはそう。

出てこないからと言って「はい信頼失いましたー!」とか言うのは小学生か?みたいな話じゃん。

 

ところで。

まぁいろいろ難しいのはもちろんわかる。だって不思議フォーマット FBX を今の今まで引き摺っているんだぜ。やっとそろそろ解放されるかもしれないっていう段階。

でもこれは「難しいことをやらなければならないのでは」という話だ。単なるstaticなデータだけではなくbehaviourもデータ化しないと本当の可搬性を表現できない。

みんな万物が可搬であってほしいだろ?

…いや、まぁそうじゃないのは現状のエンジン依存を見ると明らかなんですけど。できるわけがない、というのもそうなんですけど。

全てが可搬である必要はないが、可搬なサブセットを作ることはできるはずだ。

そしてそのサブセット内で十分な表現力を達成することはできるはずだ。

この辺の考えに関しては Web 系がやっぱりいちばん強いと思う。標準化っていう意味でもそう。

ゲーム系の人間がそういうことを考えることに期待するべきではまぁないんだろうな。

 

プログラミング言語界隈で昔から DSL っていう概念は盛んだけれど、何故かあんまり一般に広まる感じがしない不思議。

これは機能ではなく概念で、即ちもっと広く適用できる話なのだけど、人類には意外と難しいものだったりするのかしら。

「物事を記述するには適切な言語を使おう」というだけの話なんだが。

まぁ自然言語1つしか知らない大多数の人間には酷なのかもしれない。

まーいいやこの話は。

 


ちょっと今回の話題はそこそこキレてます。説明しない Unity もアレだけど、主には過剰なネガキャンをする人間に。

というかなんでUnityが評価されてないのか本当によくわからん。いや正確に言うとUEが評価されている理由がわからん。

いやわかるけど、それで評価するのは「見た目で判断している」ようにしか見えなくて、まぁ本当にそうなんだと思うけど、それに納得がいかない。

もしも本当に世の中の開発者がみんな easy を選ぶというのなら、ソフトウェア開発という文化そのものが死んでるっていう話になると思う。

そしてそうじゃないと思うから。だからわからん。分母が開発者じゃないっていうのはわかるけどな。

ゲーム開発者はエンジニアじゃないのかもしれない。まぁそれもそうか…。

 

まぁはい。世の中がいい感じに発展してくれることを祈っています。

私はUnityが好きだけど、まぁ別にどこ行っても大丈夫なつもりではありますよ。

おわり。

日記 230818

ちょっとだけ。

今日は進捗は無いけどいろいろ良いことがある日でした。進捗がないのは大問題ですが。

VRの話をいろいろしましたが、その中でtwitterでしづらい、個人的な話を少し書いておきます。

 

VRの話…に限らずいろんなコンテキストで「人間」を前提にした議論を読むことがあります。頭があって。手があって。足がある。

私はその態度がどうしても苦手で。

元々私は人間という生物自体はそんなに好きではなくて。好きなのは人の知性…というか思考、反応、出力、その辺です。

だからそれを忘れることができるこのVRという媒体はとてもありがたくて。そのありがたさを考えるとそんな陳腐なものを前提に入れてしまうことにものすごく違和感があるのです。

その話で言うとVRで性別観念を持ち出してくるのもすごく苦手で。「特徴を持つこと」と「性別」は無関係なんですよ、根本的に。だから、好きにすればいいんですよ。ただそれだけなのに。

一応言うと苦手なのはそういう「観念の押し付け」であって、人の見た目という概念とか性的特徴とかそういうのではないです。私は銀髪でかわいい感じの子が好きです。

で。

真面目そうな議論で、まぁ、現実の身体があり、それとのシンクロ的な、みたいな話がよく行われると思うのですが、その時点でこの「仮想の身体」という概念に対して無礼だと思うんですよ。

私達は何らかの方法でアバターを動かしている、だけ。それで済む話じゃないんですか?その先はなんでもいいじゃないですか。

そう強く思うモチベーションの一つは、ゲームという媒体が与える「主観性」が十分強いから。三人称視点であっても、キャラクターがダメージを受けたら「痛い」のです。私達が。

この人間という生物は、自身のこの「生物的に神経が繋がっている手足」だけでなく、それを介して「制御できていると感じられているもの」も自己だと認識する傾向があります。

だから大事なのは観測可能性・制御可能性であって、「身体」ではない、と、強く願っているのです。私は。そうあってほしいのです。

私達はただ慣れているだけなんですよ、この体に。そして操作方法というのは慣れるものです。そんな話は実際いくらかあります (「視界を反転させても慣れる」話とか、「方位が認識できるようにもなれる」とか)。

結局脳内でニューラルネットが動いてるだけで。学習したらなんでも適合できる。わかりやすい話じゃないですか。

VRはこれまでの媒体よりも単に圧倒的に次元の高い入力と出力が行えているだけ。それを身体性と呼ぶ人もいるのかもしれませんが、その言葉自体にnegativeな気持ちがあってね…。

 

この、そうあってほしい、というのは確かに私の願いでしかないから、あんまり強く言えなくて。

でも抽象的にモノを考えるという意識としては、まぁ身体なんていう意味わからんものよりも可観測可制御のほうがモデル化しやすいわけで。

立場としては合理的だと自分で思うのだけど、その立場がちょっと自分の願いが入りすぎてて認めにくいなって思う、そんな話でした。


 

ずっと昔に考えたことですが、VRChatのアバターは「理想的な性」という概念を持っていると思っているんです。いわゆる現実のなんとやら、とは一切無関係に。

それは別にVRChatによって始まったことではなく、昔からイラスト系では自由だったかと思いますけれども。

でもね、VRChatで「自己」としてそれを獲得できるようになったことで、救われた人たちがたくさん居ると思うんですよね。

まぁそれは素直な「気づき」で済む話がほとんどでしょうけど、それ以上に強く救われている人も居ると思うんですよ。

だからこの「曖昧さ」を大切にしてほしいなって思うんです。私は。

 

なんでもいいのなら、その概念はなくなることができるんです。

日記 230805

日記を書こうと思いましたが書くことがありませんでした。

でも書くことがないことを残すのも日記なのかもしれません。

作業と仕事と生活で100%になっております。当分これが続く予定です。

きびしー。

もうこういうのはこれっきりにしたいですね。私はもっとのんびりしたいです。

そうも行かないことは既にわかっていますが、気持ちとして、私はとてものんびりしたいです。

 

最近は疲れるとふらっと1時間くらい寝てしまうことが増えた気がします。前からそうなような気もします。

だいたいそういうときってやることが抽象的で手の動かし方がわからないときです。横になりながら手を動かすシミュレーションをしたりするんですけどね。白昼夢の中で作業してもどうしようもないんやで。

まぁこんな時間まで起きてるからというアレはアレ。

 

そんなに伸ばすこともないしこの辺でおわっておきます。

また適当なときに日記書きますね。

おわり。