Gaming Life

一日24時間、ゲームは10時間

VS 16.7以前では一時オブジェクトのアドレスを&演算子で取得してもエラーが出なかったらしい

Visual Studio 2019のバージョンを16.8に上げてから、DirectX12のコードをビルドしてみたら、これまでコンパイルできていたものができなくなっていた。そのコードがこれ。

hr = m_device->CreateCommittedResource(
            &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), // ここでC2102エラー
            D3D12_HEAP_FLAG_NONE,
            &depthBufferDesc,
            D3D12_RESOURCE_STATE_DEPTH_WRITE,
            &depthClearValue,
            IID_PPV_ARGS(&m_depthBuffer)
        );

docs.microsoft.com

C2102: '&'に左辺値がありません。

エラーの原因は、一時オブジェクト(右辺値)である CD3DX12_HEAP_PROPERTY のアドレスを、&演算子で取得しようとしたこと。よく考えれば、一時オブジェクトのアドレスを取得なんてしてはいけないことだと思う。なので、試しに他のコンパイラで似たようなコードを書いてみた。

#include <iostream>

struct A { int a, b, c, d; };

A make_A() { return A{}; }

void func(A*) {}

int main() {
    func(&(A{}));
    func(&make_A());
}

wandbox.org

gccでもclangでも、このコードはコンパイル出来なかった。右辺値のアドレスを取ろうとするのは駄目みたい。

で、MSVCのオンラインコンパイルも可能な、Compiler Explorerでも同じコードをコンパイルしてみた。すると、MSVCだけコンパイルが通ることが確認できた。

godbolt.org

どうもVisual Studioが間違っていて、バージョン16.8からコンパイルが通るようになったみたい。

ちなみに手元で試した限り、Visual Studio 2017では、このコードのコンパイルが通った。

UE4でNVIDIA NSight Graphicsを使ったGPUプロファイリングをしてみる

本記事は、「Online Game-Tech LT 2020」のLT発表の補足資料として用意しました。登壇一日前で時間がない中で本記事を執筆しているため、必要最低限の説明だけにとどまっていることをご容赦ください。時間があればそのうち修正します。

connpass.com

NVIDIA NSight Graphicsとは

NVIDIAが開発したグラフィックアプリケーション用のプロファイラ。RenderDocと比べて、GPUの低レイヤの調査に向いている。

セットアップ

今回は、UE4で作成したゲームパッケージでプロファイルするのではなく、エディタ上でプロファイルする。製品版に近い状態でプロファイルしたい場合は、Developmentパッケージを作成し、それをプロファイルするのがよい。

公式サイトからNVIDIA NSight Graphicsをダウンロードする(以下NSightと表記)。 developer.nvidia.com

プロファイルする時は、必ず管理者権限で実行すること。そうしないと警告メッセージが出て、詳細な調査ができない。

起動するとこのようなウィンドウが表示される。「Create New Project」を選択し、プロファイルのための新しいプロジェクトを作成する。 f:id:ai_gaminglife:20201031210430j:plain

プロセス立ち上げのための設定ウィンドウが立ち上がったら、「Application Executable」にUE4Editor.exeのパスを、「Commnad Line Arguments」にプロファイルしたいuprojectのパスと-game引数を記述する。なお、私の環境ではなぜか「-dx12」引数をつけないとプロファイルできなかった。そんなことをしなくても普通は出来るはずなんだけど……もし「-game」だけで起動しない方がいれば試してみてください。

UE4Editor.exeはデフォルトで、「C:\Program Files\Epic Games\UE_4.「バージョン番号」\Engine\Binaries\Win64\UE4Editor.exe」のパスにある。

f:id:ai_gaminglife:20201031211100p:plain

「Launch Frame Debugger」を押すとUE4Editorが起動する。プロファイルしたいシーンに移動したら、NSightウィンドウで「Capture for Live Analysis」ボタンをクリックする。すると、下図のような画面が立ち上がる。これを使ってフレーム単位の詳細なプロファイリングを行っていく。

f:id:ai_gaminglife:20201031211938j:plain

実際のNSightを使ってのプロファイリング手順は「Unreal Fest 2019」講演が詳しいので、そちらを参考のこと。

www.slideshare.net

【C++20】constメンバ関数の実装を要求するconcept

C++20から導入されるコンセプトは、requires節を使用して、型に対してあるメンバ関数の実装を要求することが出来る。 そのメンバ関数に対して、const関数であることを要求できないかと考え、実装してみた。

#include <type_traits>

template <typename T>
concept Drawable = requires(T x) {
    // 型がdraw() const:関数を持つことを要求する
    std::declval<std::add_const_t<T>>().draw();
};

template <Drawable T>
void f(T& x) {
    x.draw();
}

struct A {
    void draw() const {}
};
struct B {
    void draw() {}
};
struct C {
    void func() {}
};

int main() {
    A a;
    B b;
    C c;
    f(a);
    f(b); // draw()関数が非constなのでコンパイルエラー
    f(c); // draw()関数をもたないのでコンパイルエラー
}

wandbox.org

※追記

他の書き方もあるみたい。

// conceptの引数型をconst型にする
template <typename T>
concept Drawable = requires(const T& x) {
    { x.draw() };
};

// 非constメンバ関数の実装も同時に制約条件に加えたい場合
// 1.
template <typename T>
concept ActorClass = requires(const T& x, T& y) {
    { x.draw() };
    { y.update() };
};

// 2.
template <typename T>
concept ActorClass = requires(const T& x) {
    { x.draw() };
} and
requires(T& x) {
   { x.update() };
};

// 3.
template <typename T>
concept ActorClass = requires(const T& x) {
    { x.draw() };
    { const_cast<T&>(x).update() };
};

個人的には、2の書き方が記述量こそ多いが一番直感的かなと思う。が、どれも特に挙動に違いはないと思われるので、好きなのを使えばいい。

Visual Studioのコードスニペットのshortcut名にはハイフンは使えない

Visual Studioコードスニペットを自作していたら、表題の件にハマったのでメモがてら共有。

qiita.com

上記の記事で紹介されている Visual Studio Snippet Generatorで、スニペットを作ったのだが、Shortcutにハイフン(-)を入れると、コードスニペットが正しく機能しなくなった。

tools.unitycoder.com

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <Title>commentblock-test</Title>
      <Shortcut>commentblock-test</Shortcut>
      <Description>create basic style comment block</Description>
      <Author>ai</Author>
    </Header>
    <Snippet>
      <Declarations>
        <Literal Editable="false"></Literal>
      </Declarations>
      <Code Language="cpp"><![CDATA[// ---------------------------------------------------------------- //
//  $end$
// ---------------------------------------------------------------- //]]></Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

このXMLVisual Studioにインポートして commentblock-test を入力してTabキーを押すと、正しく動かない。

f:id:ai_gaminglife:20200813201649j:plain f:id:ai_gaminglife:20200813201651j:plain

色々試した結果、Shortcutからハイフンを取り除くと、正しく動作するようになった。

↓改良後のXML

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <Title>commentblockTest</Title>
      <Shortcut>commentblockTest</Shortcut>
      <Description>create basic style comment block</Description>
      <Author>ai</Author>
    </Header>
    <Snippet>
      <Declarations>
        <Literal Editable="false"></Literal>
      </Declarations>
      <Code Language="cpp"><![CDATA[// ---------------------------------------------------------------- //
//  $end$
// ---------------------------------------------------------------- //]]></Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

f:id:ai_gaminglife:20200813201707j:plain f:id:ai_gaminglife:20200813201712j:plain

ちなみに

Visual Studio Snippet Generatorは、デフォルトでC#用のスニペットファイルを出力する。C++などでそのスニペットを使用したいときは、 <Code Language> をcppなどに変更する必要がある。

参考

docs.microsoft.com

WPF勉強中(1)最初に参考にした資料とか疑問点とか

前回の記事以来、時間を見つけてはWPFの学習を進めている。しかし、ただ黙々と一人学習していてもモチベが続かないので、定期的にブログで進捗や参考にしている資料、疑問点を文章化していこうと思う。

参考にしている資料

» WPF 学習用ドキュメント作りました

最初の学習に利用した資料。「WPF 入門」「WPF 実践」「WPF 逆引き集」の内、「WPF 実践」しか読んでないが、非常に良かった。私はあるフレームワークを最初に学ぶ時、参考コードの設計をやたら気にしてしまうタイプなのだが、この資料のサンプルコードはMVVMのスタイルを守っているので、かなり肌にあっていた。

  • WPF 4.5入門

www.slideshare.net

日本語でWPFについて調べると、必ずヒットする「かずきのBlog@hatena」の著者が執筆した、WPFの入門資料。全部は読んでないが、ざっと流し見した感じ、WPFの機能について順を追って丁寧に説明されており良さげ。何より現役マイクロソフト社員が作成した資料ということもあり、信頼ができる。

特に参考になったのは「6.2 データバインディングを前提としたプログラミングモデル」の章。MVVMライブラリであるPrismの簡単な使い方が学べた。

  • XAML Controls Gallery

www.microsoft.com

マイクロソフト謹製、XAMLのサンプルをまとめたアプリ。このコントロールでどんな表現ができるのだろう、と確認したい時によく使う。ただ問題点が一つありまして(後述)……

github.com

マイクロソフト謹製のWPFのサンプル集。大量のサンプルコードが公開されている。MVVMデザインは(見た限り)無視して、初学者に理解しやすい形でコーディングされてるっぽい。

作ったもの

f:id:ai_gaminglife:20200721011956g:plain 実用性は皆無の習作。一応MVVMを意識してコーディングした。

疑問点

どうもXAML Controls Galleryは、UWP(WPFの後継的扱いのライブラリ)で作られているっぽい。一応下記の手順で、UWPのコントロールWPFで扱うことはできるらしいのだが、うまくいかなかった。その内リベンジしたい。

docs.microsoft.com

  • Prism(もしくはLivet)の使い方

「WPF4.5入門」で、BindableBaseとDelegateCommandの使い方は大体把握したが、それ以外はまだからっきし。WPFでそこそこの規模のアプリケーションを作るなら、PrismやLivetといったMVVMフレームワークを使うのが普通らしいので、使えるようにしたい。どこかにサンプル無いかなあ。

  • データの永続化

SQ Liteとかでデータを永続化できるらしいけど……外に公開するようなツールを作る、という段階まで来たらこれも意識しなきゃ駄目っぽい。まだそこまで出来そうにないので優先度は低め。

まとめ

というわけで、現時点での進捗をまとめてみた。思い描くようなツールを実装できるまでには、まだまだ時間がかかりそう。

DirectX12の魔導書を読んだ

『DirectX12の魔導書』を大体読み終わったので感想。

自分はDirectXOpenGLなどのグラフィックスAPIをほぼ触ったことがなかったので(昔DX11で三角ポリゴン出したくらい?)、勉強として買った。

本の構成は以下の通り。

  • Chapter1 前提となる知識とDirectX12の概略
  • Chapter2 グラフィックスパイプラインと様々なシェーダー
  • Chapter3 初期化から画面クリアまで
  • Chapter4 ポリゴンの表示
  • Chapter5 ポリゴンにテクスチャを貼り付ける
  • Chapter6 行列による座標変換
  • Chapter7 PMDの読み込みとモデルの表示
  • Chapter8 マテリアル
  • Chapter9 リファクタリング
  • Chapter10 スキニングとアニメーション
  • Chapter11 インバースキネマティック(IK)
  • Chapter12 マルチパスレンダリング
  • Chapter13 影行列とシャドウマップ
  • Chapter14 マルチレンダーターゲットとその応用
  • Chapter15 スクリーンスペースアンビエントオクルージョン(SSAO)
  • Chapter16 imguiの利用
  • Chapter17 Effecseerライブラリの利用
  • Chapter18 DirectXTKの利用(文字列表示)

自分はChapter13以降、実装がしんどそうだったので軽く流し読みした程度。その代わり、Chapter12まではかなり時間をかけて実際にコーディングして実装した。(ただしChapter11のIKは難しくて断念した)

以下その頃の作業記録ツイート。

本書は高校数学とC++の最低限の知識がある読者を想定して描かれている。ただ、自分が読んだ限りそこまでの知識でこの本を完走するのは厳しく、追加でグラフィックスパイプライン(頂点シェーダとかピクセルシェーダとか……)など、現代のコンピュータグラフィックスに求められる基礎知識を持っておいたほうが良いと感じた。(副読書としてCGエンジニア検定の参考書あたりを持っておくのがよさそう)

2020年7月現在、DirectX12に関する日本語の参考資料は公式のリファレンスぐらいしかない(追記: すらりんラボさんの本があった)。そのため本書の発売前は、3Dモデルの描画まで実装したら、後は影を描画して終わりくらいの分量かなーと思っていた。

ところが実際には、DirectX12の初期化から始まり、ポリゴンを描画し、3Dモデルの描画にアニメーション、果てはポストプロセスの実装とかなり奥深くまで解説している。ここまでの分量の実装を一冊で解説する本は、DirectX11の解説書も含めて心当たりがない(OpenGLならあるかも)。この分量をこなすのには時間はかかったが、ポストプロセスを使ってアウトラインもどきのシェーダーが実装できた時は感動した。

誤植がやたら多かったのはマイナスポイント。また、Github経由で動作確認が取れているサンプルコードが公開されているのだが、それもある章を境にほぼ別モノに書き換わっていて、対応を取るのに苦労した。

しかしながら、誤植などの対応を取る作業がむしろDirectX12の理解を深める一助となったところがある。誤植がほぼ無い書籍だったら、サンプルコードを写経するばかりで、ほぼ理解できずに終わっていたと思う。なのでヨシ(?)。

総じて、DirectX12の入門書として充分人に勧められるクオリティだった。どうしてもDirectX12を習得しなければならない人や、DirectX12そのものの難解さや書籍中の誤植も笑って許せる、マゾ気質の人は是非買って挑戦してみることをおすすめします。

……これ推薦文になってるのか?

GUIフレームワーク探しの旅の果てにWPFにチャレンジしている

GUIフレームワークを探して三千里

数年前から使い勝手の良いGUIツール作成用のフレームワークを探している。

今自分は、ゲームを作るならUE4かOpenSiv3D(それとUnity)を使い、CLIツールや少し込み入ったスクリプトの実装にはPythonを使っている。たまにProcessingやシェルスクリプトを使うこともある。プログラムを真面目に書くようになってもうすぐ4年、こんな具合に「これを作るならこれを使う」といった流れが確立しつつあるのだが、GUIツールの実装に使える、自分の肌にあったフレームワーク・ライブラリには出会えていない。

最初に試したのはQt。クロスプラットフォームGUIツールで最もよく使われているフレームワークの一つだと思う。映像・ゲーム業界的にも広く使われているフレームワークで、就職活動中、中途のツールエンジニアの採用要項に「Qtの使用経験○年以上」と書かれているのを頻繁に見かけた。

www.qt.io

挑戦の結果、Qtを極めるのは断念した。理由としては独自のQMakeというビルドシステムが理解できなかったこと、専用IDEであるQt Designerにどうしても馴染めなかったこと、そして何より必要なストレージ容量が多すぎた(おおよそ20GBから40GB)ことが挙げられる。特に最後の必要な容量の多さは致命的で、ただでさえ莫大な容量が必要になるUE4を使っているのに、それに加えてQtを入れておく余裕は自分のPCにはなかった。

次に試したのがOpenSiv3D。本来はゲーム開発に使うのが主なフレームワークだが、モダンなC++で書ける上、開発者が日本人でサポートも充実してることからこれでGUIツールが作れないかなーと考えた。

これも結果は断念。最低限のUIパーツは揃っているが、まだまだGUIアプリケーション開発に投入するには機能不足だった。何よりデザイナーを使ってウィジェットを配置出来ないのが不便だった。(なおOpenSiv3Dはオープンソースで開発されているので自分で実装する、という手もあったが、そんな技術力ななかった)

他にPyQt(QtのPythonバインディング)も試したが、動的型付け言語でGUIを作るというのがどうも気持ち悪くなって諦めている。

そんなこんなで色々と迷走した挙げ句、今はWPF(Windows Presentation Foundation)に挑戦している。WPFとは、Microsoftが開発したGUI開発用のフレームワークで、主にC#VB、そしてXAMLというUI配置を簡単に表現できるマークアップ言語で実装できる。WPFの歴史は意外と古く、2006年頃から使えたらしい。

WPFというと自分は「Windowwsでしか動かない」「Windowsフォームに取って代わる程の人気が出なかった(UWPと並ぶ)残念な子」「よく知らないけど.NET一族のひとつらしい」ぐらいの認識を持っていた。特にWindowsでしか動かないというのが、せっかく開発したツールもMac使いが多い(と勝手に思っている)デザイナーに使ってもらえず終いになってしまうのでは、という考えにさせてしまい、これまでチャレンジしてこなかった。

だが2019年に、クロスプラットフォームフレームワークである.NET CoreがWPFをサポートすることが発表され、WPFでWin / Linux / macOSに対応したGUIツールが開発できるようになっていた

(追記)と思ったら、.NET Coreに対応しただけでWPFWindowsでしか動かないらしい。びえん。

codezine.jp

これはやるしかないだろう、とWPFに挑戦することにした。

(ちなみに.NET Fremeworkと.NET Coreは今後統合され、.NET 5として新生。新たにUIクロスプラットフォームフレームワークが公開されるらしい。UWPと同じ運命を辿らなければ良いなあ)

触ってみての所感

まだWPFを触り始めて数日程度しか立っていないが、とにかくC#が難しい。多少なりUnityの経験があるのでなんとかなるだろうと思っていたが、C++Pythonには無い構文、当然のように使うことが求められる大量のインターフェース、参照型と値型の違いなどなど予想以上に苦しめられている。C++より難しいんじゃねえのこの言語。

ただ、WPFそのものは想像以上に使い勝手が良い。日本語ドキュメントが充実していないのは玉に瑕だが、直感的に使えて、かつVisual Studioとの相性が抜群に良いので、今後もWPFの学習を続けたいと思えた。C++書くときもコレくらいVisual Studioが仕事してくれたらなあ……

参考にしている資料

チュートリアルとして、こちらのサイトの資料を使っている。プログラミング自体の経験が浅い人には難しすぎるが、ある程度の経験がある人なら非常に参考になる資料だと思う。

http://kisuke0303.sakura.ne.jp/blog/?p=340

また、WPFが推奨している開発スタイル(デザインパターン?)であるMVVMについては、下記のページで紹介されているリンクを主に見て勉強している。まだ全部は見切れていないが……

https://qiita.com/usada-kumi/items/046c9a43b15b9e376198

結び

以上、WPFに挑戦しているよという話でした。ブログに記事として上げた以上は、これまでの挑戦のように途中で断念することなく、何かしらツールを完成させて、ここで公開できるといいなぁ。