🌋

VulkanSceneGraphで簡単Vulkan?

2021/09/20に公開

ハードウェアレイトレーシングに興味を持ち、Vulkanのレイトレーシング拡張を学ぶためにまずはVulkan自体を学ぼうとするも、あまりの複雑さに心が折れてしまいました。
そんなときに出会ったのがVulkanSceneGraph(以下VSG)というライブラリです。
しかしVSGは登場してからまだ日が浅いようで、日本語はおろか英語で調べてもほとんど解説記事が見つかりませんでした。
そこで本記事ではVSGの使い方について調査・試行錯誤しながら書いていきます。

VSGとは

VulkanSceneGraph(VSG)は、OpenGL用のシーングラフライブラリとして昔から使われているOpenSceneGraph(OSG)の後継として同じ開発者の方が開発されているVulkan用のシーングラフライブラリです。
2021年9月現在はまだ開発途中のようで(もうすぐリリース?)、生のVulkanが顔を出すところも多少ありますが、ハードウェアレイトレーシング関連の機能も実装されているようです(サンプルコード参照)。

VSGのインストール

基本的にVSGのドキュメントのとおりですが、少し注意点があります。

  1. Vulkan SDKをインストールする。ダウンロードページからWindows用インストーラをダウンロードして、普通にインストールできます。VSGのドキュメントに書かれているVULKAN_SDK環境変数はインストーラが自動で設定してくれます。
    ただし、インストールする内容を選択する画面で、追加コンポーネント「Debuggable Shader API Libraries - 64-bit」も選択する必要があります。
    Shader APIという名前なのでシェーダ関係の何かだけかと思ってしまいますが、実際のところこれはデバッグビルド用のVulkanライブラリ(.libファイル)で、これがないとVSGを使ったプログラムをデバッグビルドする際にリンクエラーになります。このRedditポストのおかげで解決しました。
  2. Visual Studio(以下VS)に付属している「Developer PowerShell for VS 2019」を起動し、下記のようにしてリポジトリをクローンし、CMakeでVS用のソリューション(.sln)を生成します。
git clone https://github.com/vsg-dev/VulkanSceneGraph.git
cd .\VulkanSceneGraph\
cmake . -G "Visual Studio 16 2019" -A x64  # CMakeではVS2019からアーキテクチャを別オプションで指定するように変わった。参考:https://cmake.org/cmake/help/git-stage/generator/Visual%20Studio%2016%202019.html
  1. 出力されたソリューションを管理者権限で起動したVSで開きCMakePredefinedTargetsの中のALL_BUILDINSTALLをビルドします。
  2. CMakeがVSGを発見できるように環境変数CMAKE_PREFIX_PATHC:\Program Files\VSGを追加します。

vsgXchangeのインストール

3Dプログラムを作る際は画像ファイルや3Dモデルの読み書きが必要になることが多いですが、これはVSG本体ではなく、vsgXchange(https://github.com/vsg-dev/vsgXchange)という拡張ライブラリに含まれています。
今回は後でテクスチャの読み込みなどを行うので、vsgXchangeも導入しておきます。
例によって導入方法はvsgXchangeのREADMEに従いますが、今回はWindows環境なので改めて書いておきます。

  1. Developer PowerShell for VS 2019で次のコマンドを実行し、リポジトリのクローンとソリューションの生成を行います。
git clone https://github.com/vsg-dev/vsgXchange.git
cd .\vsgXchange\
cmake . -G "Visual Studio 16 2019" -A x64
  1. 生成されたソリューション(.sln)を管理者権限のVSで開き、ALL_BUILDINSTALLをビルドします。
  2. 環境変数CMAKE_PREFIX_PATHC:\Program Files\vsgXchangeを追加する(セミコロン区切り)。

プログラムを作ってみる

VSGを使って単純な物体を描画するプログラムを作ってみます。
今回は、

  • 基本的な形状の描画(vsg::Builderクラス)
  • テクスチャ画像の読み込み(vsgXchange)

といった機能を試してみます。

CMakeプロジェクトの作成

VSGのドキュメントによれば、ビルドツールはCMakeが推奨されています。
最近のVSはCMakeプロジェクトを直接扱えるようになっていますが、VSからプロジェクトを作った際はうまくVSGを組み込めなかったため、今回はLinuxで開発する時のように手作業でプロジェクトを作り、CMakeでVS用のソリューションを生成して開くという手順をとります。

プロジェクトのフォルダ構造は次のようにします。

  • VSGTest\
    • src\
      • main.cpp:ソースコード本体
    • data\
      • texture.png:テクスチャ画像(512x512のPNG画像、下記)
    • CMakeLists.txt:CMakeプロジェクトファイル(後述)

CMakeLists.txtの内容は次のようにします(VSGのドキュメントおよびvsgXchangeのドキュメントを参考にしています)。

cmake_minimum_required(VERSION 3.7)

project(VSGTest)

set(CMAKE_CXX_STANDARD 17)

find_package(vsg REQUIRED)
find_package(vsgXchange REQUIRED)

add_executable(VSGTest src/main.cpp)
target_link_libraries(VSGTest vsg::vsg vsgXchange::vsgXchange)

プログラムを書く

今のところAPIドキュメントなどはないようなのですが、下記のサンプルコードを参考にしてプログラムを書いてみました。

ソースコード(main.cpp)の内容は下記の通りです。

main.cpp
#include <vsg/all.h>
#include <vsgXchange/all.h>

int main()
{
  // サイズやタイトルを設定してウィンドウを作成
  auto windowTraits = vsg::WindowTraits::create(640, 480, "VSG test");
  auto window = vsg::Window::create(windowTraits);

  // シーンのルートとなるノード(Groupには様々な子ノードを追加できる)
  auto scene = vsg::Group::create();

  // vsgXchangeで画像をテクスチャとして読み込む
  // 参考: https://github.com/vsg-dev/vsgXchange#how-to-use-vsgxchange-in-your-own-applications
  // (ただし最近変わったのか、今はReaderWriter_allの代わりにallと書く)
  auto options = vsg::Options::create(vsgXchange::all::create());
  auto texture = vsg::read_cast<vsg::Data>("data/texture.png", options);

  // Builderクラスでプリミティブ形状を生成する
  // 参考: https://github.com/vsg-dev/vsgExamples/blob/master/examples/utils/vsgbuilder/vsgbuilder.cpp
  auto builder = vsg::Builder::create();
  // 位置、形状、色の設定
  vsg::GeometryInfo geomInfo;
  geomInfo.position.set(0.0f, 0.0f, 0.0f);
  geomInfo.dx.set(1.0f, 0.0f, 0.0f);
  geomInfo.dy.set(0.0f, 1.0f, 0.0f);
  geomInfo.dz.set(0.0f, 0.0f, 1.0f);
  geomInfo.color.set(1.0f, 1.0f, 1.0f, 1.0f);
  // 描画設定
  vsg::StateInfo stateInfo;
  stateInfo.image = texture;  // テクスチャを設定

  // 立方体を生成しシーンに追加
  auto box = builder->createBox(geomInfo, stateInfo);
  scene->addChild(box);

  // Viewerは描画関係を担当している?
  auto viewer = vsg::Viewer::create();

  // 投影や視点を設定しカメラを作成
  auto perspective = vsg::Perspective::create(60.0, (double)window->extent2D().width / (double)window->extent2D().height, 1.0, 10000.0);
  auto lookAt = vsg::LookAt::create(vsg::dvec3(2, 2, 3), vsg::dvec3(0, 0, 0), vsg::dvec3(0, 1, 0));
  auto camera = vsg::Camera::create(perspective, lookAt, vsg::ViewportState::create(window->extent2D()));

  // ウィンドウを描画用に登録?
  viewer->addWindow(window);

  // イベントハンドラの登録
  viewer->addEventHandler(vsg::CloseHandler::create(viewer)); // 画面を閉じたときに終了するようにする
  viewer->addEventHandler(vsg::Trackball::create(camera));  // マウスで視点を移動できるようにする

  // Vulkan関係の何か?要調査
  auto commandGraph = vsg::createCommandGraphForView(window, camera, scene);
  viewer->assignRecordAndSubmitTaskAndPresentation({ commandGraph });

  viewer->compile();

  // メインループ
  while (viewer->advanceToNextFrame()) {
    viewer->handleEvents();
    viewer->update();
    viewer->recordAndSubmit();
    viewer->present();
  }

  return 0;
}

これを実行すると、画像のようにテクスチャの貼られた立方体が表示されます。ライティングもされているようです。
マウスで視点移動も可能です。
screenshot

まとめ

この記事では、VulkanSceneGraphライブラリを使用して簡単にVulkanを用いた3D表示を行う方法を解説しました。
今はまだ簡単なシーンを表示しただけですが、今後は3Dモデルの読み込みやシェーダの変更といったより高度な機能についても調査予定です。

付録

テクスチャ画像 texture.png

MSペイントで適当に描いた画像です。
texture.png

Discussion