lumino trail

ゲームエンジン作ってます。Github:https://github.com/lriki/Lumino Twitter:https://twitter.com/lriki8

開発状況 2018 #3

ずっといじってる Chainer のほうですが、Model とか Updater とかの学習の土台ができてきたので、少しずつ集めていた 500 体くらいの 3D モデルをデータセットにして学習させています。 (今までは数体だったので過学習状態でした)

・・・が、これがまたとんでもなく時間かかっていて、ちょっと足踏み中。学習中は暇なのでジャヴァスクリプターしてます。

Lumino 本体はそんなに変更ないですが、ジャヴァスクリプターついでに Emscripten について調べてたりします。C++ コードを JavaScript に変換するアレ。

Core モジュールはほぼ変更無しでブラウザで動かせました。

ファイルIO 以外はね!!!

ずーっとネイティブアプリを相手にしてたのでこの辺戸惑いが多かったですが、まぁなんとかなるでしょう。

開発状況 2018 #2

相変わらず Chainer いじってます。 なので Lumino 自体の進み具合は微妙です。

SkinnedMesh 周りを作っています

SkinnedMesh は当面公開予定のないモジュールでしたが、今回のツールでポーズ付けたりする必要があるので作りこんでいます。

2月中はほぼずっとこれ。

f:id:lriki:20180228223118p:plain

言語バインダ自動生成を clang で置き換えています

SkinnedMesh 実装中の息抜きに、Lumino とほかの言語 (C,C#,Ruby など) をつなぐグルーコードの自動生成にお直し入れたりしています。

これまで自前のパーサ組んでましたがメンテするの限界なので clang に置き換えています。

開発状況 2018 #1

年末からずっと Chainer をいじっています。そのため Lumino の開発は停滞・・・するかと思いましたが、 3D な学習データの作成やボクセルマップのビューアを作るのにそこそこ都合が良かったので、その途中で必要になった機能や不具合の修正がいくつか入っています。

MeshResource クラスがインデックスバッファのフォーマットを自動検出できるようにしました

メッシュを扱うとき、メッシュコンテナや LOD など、効率的な描画のためには考えなければならないことがたくさんありますが、MeshResource クラスはそういったメッシュ構造の最小単位です。 この人は addBox() や addSquare() といった、形状を動的に追加できるメソッドを持っていますが、これまでは 16bit インデックスバッファの限界までしか追加できませんでした。

Box 2000 個も使えないんじゃボクセルマップで使うのはキツイです。ということで拡張しました。

ファイルをウィンドウへドラッグ&ドロップできるようにしました

ビューアならこれくらいできて当然だよね?ということで。 インターフェイスWPF と Qt をまぜまぜしたような感じです。

UIMainWindow* window = Engine::getMainWindow();

// D&D 許可
window->setAllowDragDrop(true);

window->connectOnDragEnter([](UIDragDropEventArgs* e)
{
    if (e->data()->hasDropFiles())
    {
        // ファイルなら受け入れる
        e->setEffect(DragDropEffects::Copy);
    }
});

window->connectOnDragDrop([](UIDragDropEventArgs* e)
{
    for (auto& file : e->data()->dropFiles())
    {
        // Drop されたファイルパスを表示
        Console::writeLine(file);
    }
});

connectOn~ は少し冗長を感じるので += 演算子をサポートするかもしれません。

時計回りの頂点並びをポリゴン正面方向にしました

Lumino は左手座標系です。

方向 向き
X方向 右が正
Y方向 上が正
Z方向 奥が正

回転方向などなど全部「左」に統一するため、面方向も左ねじにしました。

内部文字コードの統一と Mac 対応中

UTF16 に統一しようとしています。char でも wchar_t でもなく、char16_t です。Qt や Cocoa に倣う、という感じで。

個人開発レベルのゲームエンジンでこんなことやるのは正気を疑われそうですが、和製のライブラリということでエンコーディング周りは元からかなり気を使って作っていました。 Core モジュールのユニットテスト通せた今のところ、特に大きな問題は出てないです。

このまま上手くいければいいなぁ・・・。

今後の予定

Lumino はゲームエンジンだけではなく一般的なグラフィックス系アプリのフレームワークとしての利用も想定しています。 とはいえソレをメインで開発しているわけではないので、細かい TODO が山ほど溜まってしまいました。

これの消化ばかりに時間を使うわけにもいかないので、Mac 対応の途中でお亡くなりになってるユニットテストを通したら次のお試し版を出したいです。

師走と作業報告の候

一年の振り返りとかやろうとしたけど、意外と予定が詰まってしまいました。 あとでちゃんとやろう。・・・とか言いつつ積んでる記事が4つくらいあった気がします。

ひとまず、いつもの報告です。

イチからシーンを構築してレンダリングし、png に保存できるようにしました

ゲームじゃなくてツール開発向けの機能です。

ゲーム用のレンダリングは Engine クラスにいろいろ隠蔽されていますが、それを使わないでレンダリングできるようにしています。

コードはこんなイメージ。

auto world = newObject<World3D>();

// スキンメッシュのコンポーネントを作る。
auto skinnedMeshComponent = SkinnedMeshComponent::create("3Dモデルファイル");

// スキンメッシュを表示するためのオブジェクトを作り、コンポーネントを追加した後ワールドに追加する。これでレンダリングされるようになる。
auto skinnedMeshObj = newObject<WorldObject>();
skinnedMeshObj->addComponent(skinnedMeshComponent);
world->add(skinnedMeshObj);

// メッシュの境界ボックスを取得しておく。
Box aabb = skinnedMeshComponent->getSkinnedMeshModel()->getBoundingBox();

// 平行投影カメラを作る。境界ボックス全体を視界とする。
auto camera = OrthographicCamera::create();
camera->setOrthographicSize(aabb.height);
camera->setNearClip(0);
camera->setFarClip(aabb.depth);
camera->setPosition(Vector3(aabb.center.x, aabb.center.y, aabb.center.z - (aabb.depth / 2)));
camera->lookAt(aabb.center);
world->add(camera);

// 描画先レンダーターゲットを作る。
auto renderTarget = RenderTargetTexture::create(512, 512, TextureFormat::R8G8B8A8);

// OffscreenWorldRenderView を作り、レンダーターゲットと、そこへ描画するワールド、視点(カメラ) をひとつにまとめる。
auto ofs = newObject<OffscreenWorldRenderView>(world, camera->getCameraComponent());
ofs->setRenderTarget(renderTarget);
ofs->setBackgroundColor(Color::White);

// レンダリングして画像に保存
ofs->render();
ofs->getRenderTarget()->readSurface()->save("img.png");

f:id:lriki:20171231233710p:plain

シェーダがスフィアマップ対応してないとか、ちょっとまだレンダリングおかしい。

2Dイラストからドット絵アニメを自動生成したい

企画中のゲームで、パターン多めのドット絵アニメを作ろうとしています。

そんなところで、前々からディープラーニング勉強してみたかったのでこんなプランを考えました。

  1. 2Dイラストをディープラーニングで3Dボクセルマップに変換
  2. 3Dボクセルマップからメッシュモデル作成
  3. メッシュモデルにボーン入れ
  4. 必要に応じてSD化
  5. 普通にスキンメッシュアニメーション
  6. フレームをキャプチャ
  7. 手動で仕上げ(あるいは画風変換)

フォトスキャンのイラスト版みたいなイメージ。 あらゆる形状のモデルを、ってのは多分ものすごく難しいから、まずは人型で行ってみます。

んで第1版。

f:id:lriki:20171231233731p:plain

前途多難。

霜月と作業報告の候

光かわいい。

物理ベースレンダリングを標準サポートします

f:id:lriki:20171201005215p:plain

動機:マテリアルとライトがシンプルに作れるから

こんなのこんなの はめんどくさいよ!とっつきにくくなるだけだよ!

とか言いつつ光学をかじっています。

ライトのインターフェイスを仕上げました

インターフェイスAPI とはすなわち、ユーザーとの約束である。 これを決定し、将来にわたってメンテナンスを続けることはつまり鎖であり、それは信頼である。

  • AmbientLight
  • HemisphereLight
  • DirectionalLight
  • PointLight
  • SpotLight

どこか で見たことあるようなクラスたちだね!

物理ベースレンダリング用なので、プロパティもほとんど同じようなのがいます。

ソフトシャドウ作ってます

今のところ DirectionalLight に限り、影を落とすことができます。

FXAA 作ってます

MSAA よりちょっと高速かも。ただ、なんか汚い気がする。

まとめ

Lumino っていう名前らしい機能やっと作ってあげられそう。

ていうか早くブランチ閉じて記事書く詐欺を解決して次のテスト版準備しないと・・・。

神無月と作業報告の候

よくない。とっても良くない。

主に進捗が。

またブランチ1ヶ月以上のばしてるよ。

よくない。

SSAO

ほい

f:id:lriki:20171031213352p:plain

後で記事書く。複雑だから。

Clustered Shading

ほい

f:id:lriki:20171031213338p:plain

後で記事書く。複雑だから。

CornellBox

ほい

f:id:lriki:20171031213420p:plain

これは複雑じゃないかな。

レンダリングパイプライン

先月「Deferred Shading はやらない」とか言ってたけど、SSAO 作る途中で似たような仕組みをやっていました。

その結果、クラシックなライティングでも Clustered でも Deferred でも、その子たちの差し替えとかハイブリッドとかついでにカスタムシェーダもやっちゃうよとか なんかもうなんでもできそうなパイプラインが見えた気がするので、いいかげんこいつの fix にかかるよ。 (と言っても書きなぐりゴミコードが多いから時間かかりそうだけど・・・)

これ以上求めるならコンシューマなつよいゲームエンジンとか使ってねの限界が見えた気がします。 だから進捗悪くなったのだろうか。燃え尽き症候群的な。ラスボスの前でセーブして積んでる的な。

よくない。よくないよ。

長月と作業報告の候

文字列周りの内部的な変更

先月、

  • 内部文字コードを統一にする
  • 例外を積極的に使わないようにする

とか言ってましたが、まだ全体として仕上げるには至ってないです・・・。

String クラスは内部構造を大きく変えました。できるだけ標準ライブラリに依存しないようになっています。 ちなみに SSO(Short String Optimization) も付くようになりました。

編集用のメッシュデータ構造

LOD 作るためのポリ削減とか、法線のより自然な自動計算とか、ちょっと凝ったメッシュ編集にはただのトライアングルリストじゃつらいので、編集用のデータ構造を持ったメッシュクラスを作っています。

実行速度はごめんな。

RenderView

試験的に「RenderView」という機能を作ってみています。

RenderView はこんな人↓

  • ペイントソフトでいうところのレイヤーのようなもの
  • シーンのぞき窓 (オフスクリーンレンダリングでもなんでも)
  • UIウィジェットを配置できる
  • 親子関係を持つことができる
  • ポストエフェクトを適用できる

Unity 知ってる人には、Camera からレンダーターゲット関係の情報を全部独立させたものというと何となくわかるかも。

特にアプリ全体を通して共通な、画面の構成やエフェクトに関係する情報を直感的な感じでまとめたい、というところから作り出しています。 (最近の3Dゲームエンジンは Camera がたくさんの情報を持ちすぎる気がする・・・)

Clustered Shading

作成中のゲームで、大きな1つのメッシュモデル(主に地形)の上にたくさんのライトを置きたくなりました。

というところで、Forward Rendering でもライトをたくさん使えるライティング技法であるところの Clustered Shading を実装中です。 うまく動いたらこれを Lumino 標準のライティングにしたいかな。

ちなみに、Lumino は今のところ Deferred Shading をやるつもりはありません。 そういうことができるレンダリングフレームワークは用意してますが、標準機能としては実装しないです。

(メモ) なぜ Deferred Shading をサポートしないのか?

半透明オブジェクトの描画には Deferred Shading は使えないです。 昨今のゲームエンジンは、不透明には Deferred、半透明には Forward のハイブリッドが一般的です。 Deferred は他にも G-Buffer の肥大化とか MSAA と相性悪いとかいろいろありますが、半透明の問題が一番大変。

きらびやかなエフェクトとか、かっこよく、あるいは切なく、Cool に決めたいんです。 日本とか、アジア圏のゲームはそういう半透明オブジェクトを多用することが多いそうです。 自分の作るゲームもそうだし。

あと、Lumino はシェーダを積極的にサポートしてます。(和製のフリーなゲームエンジン・ライブラリとしては珍しいかも?) ハイブリッドでいく場合、ユーザーはそれぞれの特徴に気を付けてコーディングしなければならないです。 学習の負担とか、実行効率とか、レンダリングのクォリティとか、Luminoがターゲットとする小・中規模ゲームデザインとして必要な範囲は何だとか、 いろいろ考えた結果、そんな方向を向いています。 (ライト1000個使えるよ!とか言われても実際にそんなに使わないよね?)

ただ、それよりもつまらない現実的な問題として、業界の外から技術を追うことに対して時間がとりにくくなりそうだってことがあったりします。