卯月と作業報告の候
もうちょっとレンダリングフローの見直し中
前月に引き続き。
2D/3Dシーンと UI モジュールの関係がかなり変わってきています。
前はシーンのほうが偉くて、それの後描画的な立ち位置で UI の描画が入り込んでました。 今は UI のほうが偉くて、UIFrameWindow クラスをルートとした、ちょうど WPF や HTML のような UI要素の階層構造の一部(Canvas とか)としてシーンが描画されるようになりました。
なんでこんなふうになったの?
ウリというかコンセプトもちょっと変わってくると思います。 今までは「ゲームエンジン」だったけど、それプラス、「リアルタイムグラフィックスアプリケーション」。 なんかかっこいい。字面が。
あと、描画はコールバックの外側でもできるようになりました。 コードはこんなイメージ。
void Main() { // コードをコンパイルして Shader オブジェクトを作る auto shader = Shader::Create("test.fx"); while (Engine::UpdateFrame()) { // Lumino 自体の描画処理 Engine::RenderFrame(); // 画面全体への、シェーダを用いた直接描画 auto* r = Engine::GetSceneGraph3D()->GetRenderer(); r->SetShader(shader); r->DrawScreenRectangle(); // 描画結果をウィンドウに表示する Engine::PresentFrame(); } }
ピクセルシェーダをゴリゴリ書くとこんなのが出たりします。
ドキュメントとホームページ
ドキュメント書きたい。でもデザインめんどい。
こんなことがしたい。
サイトジェネレータとか今時は星の数ほどあるけど、 がっつりとしたマニュアルやAPIドキュメント作りたいときはイマイチ力不足を感じます。
で、自作とかしてた最中に DocFX を見つけました。 この子はねぇ・・・つよいよ。
自作とかするまえにかなりたくさん調べたつもりだったけど、なんでヒットしなかったのか・・・。無能なだけか。
日本語情報もまだ少ないみたいだからそのうち使い方まとめとこう。
お試し版
ごめんね
弥生と作業報告の候
忙しい仕事が、今日、ようやく終わった。予定。
レンダリングフローの見直し中
今は OnRender コールバックの中とか、決められた範囲でしか描画できないけど それだとデバッグ描画するときにやり辛いので、制限無くどこでも描画できるように調整してます。
ハードウェアでアウトラインフォント書きたい
今の Lumino の文字描画は全部ビットマップベースです。一度テクスチャに書いてからスプライトとして描画しています。 シェーダをサポートしようと決めたときから気になってたのが、シェーダで文字を装飾するときに 普通のメッシュと同じシェーダを再利用しづらいことでした。
もう何年も前からやりたいやりたいで後回しになってましたが、レンダリングのアーキテクチャとかパイプラインとかを整理する中で 「やっぱり実現性の検討くらいはやっておいた方がいいよね」と思いました。まる。
そこそこキレイに書けてるんじゃないかな?
テッセレーションは glues を使いました。 後で poly2tri も試してみたいけど、多分 gluTess のほうが FreeType とは相性良さそう?
あと、それだけだとアンチエイリアス無くてとても見れたものじゃなくなるので、 辺の押し出しでアンチエイリアスを表現してます。nanovg と同じやりかた。
で、とりあえず何とか使い物になる品質まで持っていけたと思うんだけど、やっぱり最終的な描画結果はグラボ依存です。 「このピクセル、GeForce よりも Radeon の方が濃く見えます」とかすごく細かいところで微妙に差があります。 多分もうこの辺が限界だと思うので、安定して描けるビットマップとは互いに長所短所を補いながら両立していく方向で調整。
最後に
Mac の文字キレイ(羨望)
睦月と作業報告の候
今月は黙々と作ってました。
ティーポット作れるようにしました
姿勢制御系のテストに使いたかったので。
Gizmo 作ってます
3Dゲームの設計始めた途端シーンエディタが欲しくなったので、その取っ掛かりです。
リポジトリ構成を大きく変えました
いままでサブモジュールとしてたものをすべて Lumino リポジトリに取り込みました。 最近 Issues を絡めたフローを意識して開発進めてますが、各リポジトリに頻繁に変更が入るのでかえって管理が面倒。 安定してきたらまた分けるかも。(何年先になるだろうか・・・)
C++ から言語バインダの自動生成できるようにしてます
UE4 の UCLASS マクロみたいに、
LN_CLASS() class Sprite : public Object { ... };
と書いてコマンドラインツールに突っ込むと、ほかのプログラム言語用のラッパーを自動生成します。
今までは C 言語用の公開インターフェイスから変換してたけど、Lumino の機能が増えるにつれて限界になってきたので直接 C++ から変換できるようにしてます。
今は C# のみ。
SWIG 使わないの?
- プロパティシステムやリフレクション、なんちゃってGC、イベントのブロードキャストなど、Lumino の機能が大きくなってきたので SWIG じゃカバーしきれない。
- HSP その他、いずれは対応したいと思っているプログラム言語に SWIG が対応していない。将来的にも和製のマイナー言語なんて対応される見込みも無く。
今後の予定
これから毎月報告していく予定ですが、そのたびにお試し版をリリースできるようにしたいです。
ゲームエンジン「Lumino」の紹介
この記事は「ゲームエンジン・ライブラリ・ツールの開発 Advent Calendar 2016(http://qiita.com/advent-calendar/2016/gameengine)」の21日目です。 それなりのゲームエンジンを目指しつつも未だぴよぴよですが、せっかくなので公開したい。ということで、こんなことやっています、という紹介です。
Lumino とは
Lumino はゲームやグラフィックスソフトウェア を簡単に開発できるよう支援するための C++ ライブラリです。 ゲーム開発をメインのユースケースとしていますが、グラフィックスを中心とした様々な機能を、既存のアプリケーションに組み込んで使用することもできます。
特徴
さて、紹介、という体で改めて特徴に向き合うのもなかなか難しいです。
というのも、今の Lumino は単なるリアルタイムレンダリングエンジンにちょっとゲーム寄りの機能が付いた、という感じです。 それがどんなに効率よく綺麗な絵を描くことができるとしても、今できることはレガシーなマテリアルシステムで簡単な絵を描くだけです。 これまで作りこんできたシステムでどこまで行けるかは、今後の課題です。
そんな感じでまだまだ開発中ですが、今は以下のような方向を向いて進んでいます。
広く使われている API デザイン
Lumino はできるだけ Lumino らしさを求めないようにしています。 もしかしたら「ライブラリの色が薄い」と言うとピンと来る人もいるかもしれません。 Lumino で得た知識は他の開発ツールで利用できますし、逆に他の開発ツールで得た知識も Lumino で利用しやすい、ということを常に意識しています。
高パフォーマンス
Lumino はマルチコア環境に最適化されています。 昨今はPCに限らずモバイルでもマルチコアは当たり前になってきました。 そういったデバイスの性能を活かしきれるような設計にしています。
組み込みやすさ
Lumino に研究開発やプロトタイピングでも使いやすいように、という要求を持たせたのは、 私がエンジニアの仕事に就いてしばらく経ってからでした。 以来、既にある別のツールキットに組み込んで使うようなケースも考えています。
使い方
チュートリアルを書き始めています。よろしければ参考にしてみてください。
ゲームエンジン Lumino のチュートリアル https://github.com/lriki/LuminoTutorial
開発環境の準備 https://github.com/lriki/LuminoTutorial/blob/master/Common/1.md
以下、いくつかの例を紹介します。 Lumino の雰囲気を見ていただければと思います。
Lumino で Hello world
#include <Lumino.h> using namespace ln; void Main() { // Lumino の初期化処理 Engine::Initialize(); // 2D テキストを作成する auto text = TextBlock2D::Create("Hello, world!"); // Lumino の更新処理 (ウィンドウへの描画などを行い、ウィンドウが閉じられていれば false を返す) while (Engine::Update()) {} }
スプライトを表示する
#include <Lumino.h> using namespace ln; void Main() { Engine::Initialize(); // 画像を読み込み、2Dスプライトを作成する auto sprite = Sprite2D::Create("Assets/icon256.png"); // 2Dスプライトの位置を設定する sprite->SetPosition(200, 100); while (Engine::Update()) { } }
ユーザー入力を受け取る
void Main() { Engine::Initialize(); // アクションマッピング (キーコンフィグ) // "left" と "right" に キーボードの左右キーと、ゲームパッドの1軸を割り当てる Input::AddButtonBinding("left", KeyboardBinding::Create(Keys::Left)); Input::AddButtonBinding("left", GamepadBinding::Create(GamepadElement::Axis1Minus)); Input::AddButtonBinding("right", KeyboardBinding::Create(Keys::Right)); Input::AddButtonBinding("right", GamepadBinding::Create(GamepadElement::Axis1Plus)); auto text = TextBlock2D::Create("A"); while (Engine::Update()) { Vector3 pos = text->GetPosition(); if (Input.IsPressed("left")) // "left" が押されているか? pos.x -= 5; if (Input.IsPressed("right")) // "right" が押されているか? pos.x += 5; text->SetPosition(pos); } }
音を鳴らす
void Main() { Engine::Initialize(); // BGM を再生する GameAudio::PlayBGM("bgm.ogg"); int count = 0; while (Engine::Update()) { // およそ2秒ごとに効果音を鳴らす if (count % 120 == 0) { GameAudio::PlaySE("se.wav"); } count++; } }
活用事例
開発中であったり、身内公開のままプロジェクトが終わったものが多いので、いくつかスクリーンショットでのご紹介です。
今後のロードマップ
一応、2D/3Dゲームを作る力はあります。が、それは私自身が開発に携わっていてヘルプが出せるからであって、第三者に Lumino だけ渡しても多分無理です。
なので、まずはなによりもドキュメントの整備と、開発中のゲームで必要な機能を優先的に実装したため生まれてしまった 滅茶苦茶汚いコード 負債の返済です。
そんなことと、開発中のゲームの完成を経て ver1.0 でしょうか。 そのあとはマルチプラットフォームとか、IDE とか、物理ベースレンダリングとかやりたいですね。
もし何かご意見などありましたら、GitHub の Issues に投げていただけると幸いです。
Welcome to Lumino blog
ゲームエンジン Lumino の開発ブログを立てました。
開発情報をアウトプットする、とは言ったものの、書き出しで悶々とするのはいつものことで。 さて、何を書きましょうか。
時はゲームエンジン戦国時代。ちょっと検索すれば玉石混交、ものすごい数のゲームエンジンが見つかります。 そんな中で、なぜ新しいゲームエンジンを作っているのでしょうか?
といって学習容易性とか再利用性とか、アレコレもっともらしい理由を考えてみましたが、 開発を7年以上続けている手前そんなのは愚問で、結局は「好きだから」に帰ってくるのでした。
そう、7年も前です。 Unity のような今となってはメジャーなゲームエンジンの名前も、それほど大きく聞こえなかったころです。 ゲームプログラマになるための勉強をし、それをノート代わりにコードに落としてライブラリを作り、 友人らとのゲーム開発プロジェクトで使っていた、というのが Lumino の始まりでした。
そんな背景があるので、新しく作っているというよりは、これまで使っていたものを もっといろいろなプロジェクトで使えるようにブラッシュアップしている、といったほうがいいかもしれません。
そんなことをしつつ、今もゲーム開発や、さらに社内アプリ、後輩教育の補助などで使っています。
さて、これだけ長いことひとつのシステムをかまい続けているので、なかなかどうして かわいい子のように思えてくるのですが、まぁ、そんな他愛もない話はまた今度。
それでは、よろしくお願いします。