2014年9月7日日曜日

Windowsコンソールアプリケーションの終了時にポーズする方法

Windowsでコンソールアプリケーションを作る際,特に入力を受け付けないプログラムを作った場合,Visual StudioでF5を押すと結果を確認してしまう前に終了してしまうことがある.C++ Multithreading Cookbookを読んでいたら,system("pause")をmain()のreturnに使う方法が載っていて,なるほどなぁ,と思ったのでメモ.

#include <cstdlib>

int main()
{
    return system("pause");
}

2014年9月5日金曜日

CEDEC 2014に参加してきた

CEDEC 2014に参加してきて,次のようなセッションを聞いたり体験したりしてきました.

9/2 (火)

  • 物語の力 冲方 丁
  • プロシージャルな音ゲーつくろうぜ。
    -BPM解析と格闘した10年、そしてこれからの10年 -
  • 子どもたちのプログラミング学習の現状
  • GameJamでクリエイターに「何が起きたのか?」
    〜バンダイナムコスタジオが挑んだ人材育成の舞台裏〜
  • Houdini EngineとHoudini Indieによるプロシージャルコンテンツ作成
  • TalesOfシリーズにおける自動リギングとワークフロー
9/3 (水)
  • ウェアラブルコンピューティングの動向とウェアラブルゲームへの展開
  • ディジタルゲームにおけるマルチストリーミング再生の理論的な制御方法
  • Intel RealSenceテクノロジーが実現するインターフェース
  • ファイナルファンタジーXIVのファイルシステムとバッチシステム
  • CGにおける運度や変形の記述とその数理
9/4 (木)
  • これからのゲームとゲームクリエイター
  • 「祭り」のゲームデザイン
    〜フリーダムウォーズのゲームデザイン・コンセプト〜
  • Character Transfer
    キャラクタ固有の表情特徴を考慮した顔アニメーション生成手法
  • 実測に基づいた曲率依存反射関数による半透明物体のリアルタイムレンダリング
  • 30〜40人規模の開発チームでマルチプラットフォームタイトルを
    ゲームエンジンから作った理由とその効果
  • ライブラリを作ってはいけない
    〜それでも作りたいあなたへのアドバイス〜
  • 執筆のススメ〜会社勤めをしながら著述賞をとる方法〜
インタラクティブセッション
  • リアルタイムに初音ミクを歌わせるタイプソングシステム「HANAUTA」と
    そのアジャイル型開発
  • バーチャルロープスライダー
  • Oculus VRを用いたテレイグジスタンス(Telexistence)体験
  • HTML5を活用したインタラクティブ物理シミュレーション
    〜タブレット端末による柔軟体・流体の力学計算〜
  • Stick'n Roll
    曲面ディスプレイと棒状インターフェースを用いたアミューズメントシステム
2日目の懇親会(?)では色々な人と話をすることもでき,まだまだ学ばなければならないことが多いなぁ,と刺激を受けました.できればそれぞれの感想も書きたいところですが,今日は疲れたので,明日というか今日,出社して退社して帰ってから書こうかな,と思います.

2014年8月26日火曜日

OpenGLでの頂点データの扱いの変化

History of OpenGLを参考に,OpenGLで頂点をGPUに渡す方法がどう変わってきたか調べてみた.

OpenGL 1.0 (1992)

一番最初は,Begin()からEnd()の間に,1頂点ずつ送るコマンドを使っていた.

glBegin(GL_TRIANGLE_STRIP);
    glVertex2f( 0.0f,  0.5f);
    glVertex2f( 0.5f,  0.5f);
    glVertex2f(-0.5f, -0.5f);
glEnd();

OpenGL 1.1 (1997)

glVertexPointer()により,頂点をまとめて送れるようになる.

// 直接描画
GLfloat vertices[] = {
     0.0f,  0.5f,
     0.5f, -0.5f,
    -0.5f, -0.5f,
};
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(
    2,          // 要素数
    GL_FLOAT,   // 型
    0,          // stride (0なので詰めてある想定になる)
    vertices
);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);

更に,インデックス指定による頂点の共有が可能に.この場合は,glDrawElements()で描画を行う.
// インデックス指定による描画
GLfloat vertices[] = {
    -0.5f,  0.5f,
     0.5f,  0.5f,
     0.5f, -0.5f,
    -0.5f, -0.5f,
};
GLushort indices[] = {
    0, 1, 2,
    0, 2, 3
};
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vertices);
glDrawElements(GL_TRIANGLE_STRIP, 6, GL_UNSIGNED_SHORT, indices);

四角形を書くのに三角形2つを使う場合,6個の頂点が必要だったのが,これで4つで済むように.

OpenGL 1.5 (2003)

glEnableClientState()という名前からも分かるように,今までは頂点情報をCPU側に置いていたが,GPU側に頂点バッファオブジェクト(Vertex Buffer Object, VBO)を用意し,データを格納できる機能が追加される.

// 直接描画

// バッファの生成
GLuint buffer;
glGenBuffers(1, &buffer);

// バッファの種類を設定
glBindBuffer(GL_ARRAY_BUFFER, buffer);

// バッファにデータを設定
GLfloat vertices[] = {
 0.0f,  0.5f,
 0.5f, -0.5f,
-0.5f, -0.5f,
};
glBufferData(
    GL_ARRAY_BUFFER,
    sizeof vertices,
    vertices,
    GL_STATIC_DRAW
);

// バッファのデータと関連づけ
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, 0);

// 描画
glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);

// バッファの削除
glDeleteBuffers(1, &buffer);
// インデックス指定による描画

// 頂点用バッファの生成
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);

// インデックス用バッファの生成
GLuint indexBuffer;
glGenBuffers(1, &indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);

GLfloat vertices[] = {
    -0.5f,  0.5f,
     0.5f,  0.5f,
     0.5f, -0.5f,
    -0.5f, -0.5f,
};
glBufferData(
    GL_ARRAY_BUFFER,
    sizeof vertices,
    vertices,
    GL_STATIC_DRAW
);

GLushort indices[] = {
    0, 1, 2,
    0, 2, 3
};
glBufferData(
    GL_ELEMENT_ARRAY_BUFFER,
    sizeof indices,
    indices,
    GL_STATIC_DRAW
);

glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, 0);

glDrawElements(GL_TRIANGLE_STRIP, 6, GL_UNSIGNED_SHORT, 0);

glDeleteBuffers(1, &vertexBuffer);
glDeleteBuffers(1, &indexBuffer);

OpenGL 2.0 (2004)

プログラマブルシェーダの登場により,頂点シェーダとバッファを関連づける機能が追加される.

とりあえず頂点位置を指定するだけの簡単な頂点シェーダ.
#version 110

attribute vec4 position;

void main(void)
{
  gl_Position = position;
}

頂点シェーダに関連付けて三角形を書く.
// バッファの生成
GLuint buffer;
glGenBuffers(1, &buffer);

// バッファの種類を設定
glBindBuffer(GL_ARRAY_BUFFER, buffer);

// バッファにデータを設定
GLfloat vertices[] = {
 0.0f,  0.5f,
 0.5f, -0.5f,
-0.5f, -0.5f,
};
glBufferData(
    GL_ARRAY_BUFFER,
    sizeof vertices,
    vertices,
    GL_STATIC_DRAW
);

// アトリビュート変数のインデックスを取得
GLuint position = glGetAttribLocation(program, "position");

// アトリビュート変数を有効化
glEnableVertexAttribArray(position);
// アトリビュート変数の設定
glVertexAttribPointer(position, 2, GL_FLOAT, 0, 0);

glDrawArrays(GL_TRIANGLES, 0, 3);

OpenGL 3.0 (2008)

バッファをバインドして,glEnableVertexAttribArray()で有効化して,glVertexAttribPointer()で位置を指定して,というのを切り替える度に実行しないといけないのは面倒だよね,ということで,それらをまとめるための頂点配列オブジェクト(Vertex Array Object, VAO)が導入される.

とりあえず,頂点位置以外に頂点色も指定できる単純な頂点シェーダ.
#version 130
in vec4 position;
in vec4 color;

out vec4 oColor;

void main(void)
{
    gl_Position = position;
    oColor = color;
}

良い感じにVAOを活用した短いコードを思いつかなかったので,適当に赤,緑,青を切り替えられるプログラム.
// 現在のプログラムの取得
GLuint program;
glGetIntegerv(GL_CURRENT_PROGRAM, reinterpret_cast<GLint*>(&program));

// 頂点配列オブジェクトの生成
GLuint VAOs[3];
glGenVertexArrays(3, VAOs);

// 最初の頂点配列オブジェクトのバインド
glBindVertexArray(VAOs[0]);

GLfloat const vertices[] = {
     0.0f,  0.5f,
     0.5f, -0.5f,
    -0.5f, -0.5f,
};

// 頂点バッファの生成,バインド,データ設定
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(
    GL_ARRAY_BUFFER,
    sizeof vertices,
    vertices,
    GL_STATIC_DRAW
);

// 頂点シェーダのin変数positionの設定
GLint position = glGetAttribLocation(program, "position");
glEnableVertexAttribArray(position);
glVertexAttribPointer(
    position,
    2,
    GL_FLOAT,
    GL_FALSE,
    sizeof(GLfloat) * 2,
    0
);

// カラーバッファの生成,バインド,データ設定
GLuint colorBuffers[3];
glGenBuffers(3, colorBuffers);

GLfloat const r[] = {
    1.f, 0.f, 0.f, 1.f,
    1.f, 0.f, 0.f, 1.f,
    1.f, 0.f, 0.f, 1.f,
};
glBindBuffer(GL_ARRAY_BUFFER, colorBuffers[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof r, r, GL_STATIC_DRAW);

// 頂点シェーダのin変数colorの設定
GLint color    = glGetAttribLocation(program, "color");
glEnableVertexAttribArray(color);
glVertexAttribPointer(
    color,
    4,
    GL_FLOAT,
    GL_FALSE,
    sizeof(GLfloat) * 4,
    0
);

// 2つ目の頂点配列オブジェクトのバインド
glBindVertexArray(VAOs[1]);
{
    // 頂点バッファのバインドやin変数の設定など
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glEnableVertexAttribArray(position);
    glVertexAttribPointer(
        position,
        2,
        GL_FLOAT,
        GL_FALSE,
        sizeof(GLfloat) * 2,
        0
    );

    GLfloat const g[] = {
        0.f, 1.f, 0.f,
        0.f, 1.f, 0.f,
        0.f, 1.f, 0.f,
    };
    glBindBuffer(GL_ARRAY_BUFFER, colorBuffers[1]);
    glBufferData(GL_ARRAY_BUFFER, sizeof g, g, GL_STATIC_DRAW);
    glEnableVertexAttribArray(color);
    glVertexAttribPointer(
        color,
        3,
        GL_FLOAT,
        GL_FALSE,
        sizeof(GLfloat) * 3,
        0
    );
}

// 3つ目の頂点配列オブジェクトのバインド
glBindVertexArray(VAOs[2]);
{
    // 頂点バッファのバインドやin変数の設定など
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glEnableVertexAttribArray(position);
    glVertexAttribPointer(
        position,
        2,
        GL_FLOAT,
        GL_FALSE,
        sizeof(GLfloat) * 2,
        0
    );

    GLfloat const b[] = {
        0.f, 0.f, 1.f,
        0.f, 0.f, 1.f,
        0.f, 0.f, 1.f,
    };
    glBindBuffer(GL_ARRAY_BUFFER, colorBuffers[2]);
    glBufferData(GL_ARRAY_BUFFER, sizeof b, b, GL_STATIC_DRAW);
    glEnableVertexAttribArray(color);
    glVertexAttribPointer(
        color,
        3,
        GL_FLOAT,
        GL_FALSE,
        sizeof(GLfloat) * 3,
        0
    );

}
glBindVertexArray(0);

glClearColor(0.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);

// 描画前にバインドする頂点配列オブジェクトを切り替えると,
// 色が変わる.
glBindVertexArray(VAOs[0]);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);

glFlush();

glDeleteBuffers(3, colorBuffers);
glDeleteBuffers(1, &vertexBuffer);
glDeleteVertexArrays(3, VAOs);

最近のOpenGLの入門書だと最初からシェーダを用意して,VAO用意して,VBO用意して,ようやく描画,という感じのコードが載ってたりして,初心者からすると非常に難しそうに思える気がする.でも,こうやって歴史を辿ってみると,何となく必要性が分かったような気がしないでもない.

3.0以降の変化は気が向いたら調べよう.VAOの例を考えてたら疲れた.

2014年7月31日木曜日

参照カウントはmutableかimmutableか

C++で参照カウントを実装する場合に,参照カウントを変更するincrement,decrementはconstなメンバ関数にすべきか,非constにすべきか,constにする場合,カウンタをmutableにするか,という話題が出た.感覚的にはconstにしてカウンタはimmutableかな,と思ったのだけれど,とりあえずいくつかのライブラリを調べてみた.


  • const派 (カウンタはmutable)
    • LLVM
    • Unreal Engine 4
  • 非const派
    • boost
    • libcxx
    • Loki
参照カウンタは,オブジェクトの状態の一部ではないので変更しても問題ない,参照カウンタを
変更しても,外から見える振る舞いは変わらない,という理由でconstにしても良いのでは,といった説明を見たりしていると,constでも良いのでは,という気がしてきた.

2014年6月14日土曜日

[Unreal Engine 4] TextRenderComponentで徐々に文字を表示するBlueprint

まず,UE4のTextRenderComponentで日本語を表示するまで,の手順でTextRenderComponentで日本語表示ができる状態になっているとします.

コンテンツブラウザで,Blueprintを追加します.


クラスはアクタを選択します.


追加したBlueprintには,BP_ScriptRenderという名前をつけました.



追加したBlueprintをダブルクリックし,コンポーネントの追加からTextRenderを選びます.


TextRenderの名前をTargetにし,フォントの設定で作成した日本語用のフォントとマテリアルを使うように変更します.日本語が出ることを確認するため,Textを日本語のメッセージに変えておきましょう.


保存してから,通常の画面に戻り,Blueprintをドラッグアンドドロップし,配置しましょう.
裏面からは見えなかったりするので,画面に映る状態に調整しましょう.


調整が終わったら,Blueprintに戻り,イベントグラフの編集に移ります.
まずは,float型の変数を追加し,Counterという名前にします.


Begin Playイベントを追加し,ゲーム起動時に色々初期化するようにします.
まず,マイブループリントからTargetを選び,ドラッグアンドドロップでイベントグラフに配置します.


ピンから線を引っ張って話すと,コンポーネントの追加ができるので,Set Textを入力して検索し,追加しましょう.


デフォルトでは空文字列を設定するようになっているので,Begin PlayイベントをSet TextにつないでやればOKです.同時に,Counterにも0をセットするように追加しておきましょう.次の図のようになります.


次に,Tickイベントを使って,Counterを更新するようにします.TickイベントからDelta secondsを取得し,Counterの値に追加し,それをCounterにセットする,という流れです.


次に,表示する文字列を入れておくための変数を追加します.変数の種類はTextにします.


Get Substringというコンポーネントを使うと,文字列の一部を取り出すことができるので,これを使ってテキストの開始からCounter番目の文字までを取り出します.Source StringにScriptをつなぎます.(Textからstringに変換するコンポーネントが自動的に追加されます).更に,Length(取り出す文字列の長さ)にCounterをつなぎます.(floatからintegerに変換するコンポーネントが自動的に追加されます).Start indexは,文字列をどこから取り出すか(0が最初の文字),なので0にしておきます.できたものが次の図のようになります.


最後に,Counterの更新からTickイベントを受け取って,TargetのSet Textコンポーネントに取り出した文字列を設定するようにします.


これで,再生すると1秒に1文字ずつ表示されます.

2014年6月10日火曜日

UE4のTextRenderComponentで日本語を表示するまで

どうにかTextRenderComponentで日本語が表示できたので,メモ.

まず,日本語を含むフォントテクスチャを作る.これについては,こちらを参照.
次に,フォント表示用のマテリアルを作成する.コンテンツブラウザの新規からマテリアルを選択する.


マテリアルには,とりあえずMSGothicMaterialと名前をつけた.このマテリアルをダブルクリックし,マテリアルエディタを開く.


最初からある最終結果を表すノードを選び,左下のプロパティからBlend modeの設定をMaskedに変更する.


次に,右クリックメニューからFont Samplerを追加する.


Font Samplerの一番下の丸(アルファ成分?)をオパシティマスクにつなぎ,マテリアルを保存する.


最後に,適当なところにTextRenderComponentのアクタを配置したら,右側のプロパティから表示したい文章をTextに設定し,マテリアルとフォントに作成したフォントとマテリアルを設定すれば,日本語が表示される.

ただ,日本語のように漢字も含めると文字数が多い場合、テクスチャが複数枚になるのだけれど、まだそこの扱い方が分かっていない.
さっさと日本語出せるようにして,アドベンチャーゲームのように1文字ずつ表示されるような機能作ってみたい.

2014年6月7日土曜日

Unreal Engine 4で日本語フォントを作る方法

まず,コンテンツブラウザで「新規」,「マテリアル & テクスチャ」、「Font」の順に選び,
フォントを追加します.

日本語で使えるフォントを選びます.ここでは,とりあえずMSゴシックを選んでみました.

コンテンツブラウザにできた新しいフォントをダブルクリックし,フォントエディタ(正式名称が見つけられませんでした.)を開きます.

右側にあるプロパティから,「Import Options」の中の「Unicode Range」に「3040-309F,30A0-30FF,4E00-9FFF」を入力します.
それぞれ,平仮名、片仮名,漢字に対応しています.そして,アセットメニューから「再インポート」を選びます.

これで,日本語を含むフォントができます.

ただ,日本語フォントを作っても,TextRenderComponentには日本語表示が崩れるというバグがあるようです.
(AnswerHubへ)

プレビューではちゃんと日本語が表示できるので,TextRenderComponent以外に何かしらフォントを表示する方法では表示できるかも?

その後の経緯が見つけられないのと,4.2でも表示がおかしくなることから,まだ直っていないのかも.