Open3D 0.17.0 を Visual Studio 2022 でソースからコンパイル (CUDA対応)


この記事では Windows で Open3D ([http://www.open3d.org/](http://www.open3d.org/)) を使ったアプリケーションを C++ で作成できるように環境を構築します。C++ のプロジェクトを CMake で作成し、コマンドラインもしくは Visual Studio の IDE を用いて Open3D 0.17.0 をリンクしたプロジェクトを開発できるようにします。Open3D から CUDA が使えるようにライブラリをソースからビルドします。 

# 環境
* 開発環境として、Visual Studio 2022（Community）の「C++デスクトップ環境」がインストールされていること。
* Git for Windows（[https://gitforwindows.org/](https://gitforwindows.org/) ）もしくは互換ソフトがインストールされ、コマンドラインから git が使用できること。（Git from the command line and also from 3rd-party software にチェックを入れてインストールする。）
* CMake(3.20 以上）がインストールされ、コマンドラインから cmake が実行できること。（[https://cmake.org/](https://cmake.org/)  にある Latest Release の Windows x64 Installer を実行して 「Add CMake to the system PATH for all users」にチェックを入れてインストールする。）
* 環境変数（パスを含む）の設定が必要になります。環境変数は、設定の「システム」＞「バージョン情報」＞「システムの詳細設定」から変更できます。
* コマンドラインでの作業には「Developer Command Prompt for VS 2022」を使います。スタートメニューの「Visual Studio 2022」フォルダ内にショートカットがあります。「ターミナル」の設定を変更し、「既定のプロファイル」に「Developer Command Prompt for VS 2022」を登録しておくと、エクスプローラーで作業するディレクトリを開き、コンテキストメニューから「ターミナルで開く」ことができて便利です。

# CUDA のインストール
* コンピュータに搭載されたグラフィックボードに合わせて、nVidia のグラフィックドライバをインストールします。公式のページ [https://www.nvidia.co.jp/Download/index.aspx?lang=jp](https://www.nvidia.co.jp/Download/index.aspx?lang=jp) から最適なものをダウンロードしてインストールしておきます。
* CUDA Toolkit を公式のページからダウンロードしてインストールしておきます。筆者は CUDA 11.8 を使いました。Open3D 0.17 から CUDA 12.0 に対応したようですが、最新の CUDA 12.1 を含めて未検証です。CUDA Toolkit の旧バージョンは [https://developer.nvidia.com/cuda-toolkit-archive](https://developer.nvidia.com/cuda-toolkit-archive) から取得できます。

# ディレクトリ構成
* この記事では、ダウンロードしたソース、コンパイルされたライブラリなどは c:\dev にいれることにします。これは任意の場所に変更することができます。この記事に沿って作業すると最終的なディレクトリ構成は次のようになります。
```
dev/
├── bin
├── open3d
    ├── bin
    ├── CMake
    ├── include
    ├── lib
├── make
    ├── open3d-0.17.0
        ├── build 
```
* ソースコードは c:\dev\make\open3d-0.17.0 にダウンロードされ、c:\dev\make\open3d-0.17.0\build でビルドが行われます。
* c:\dev\open3d にビルドしたライブラリがインストールされます。
* 環境変数 `CMAKE_PREFIX_PATH` に c:\dev を設定することで、CMake の find_package(Open3D) でライブラリを参照できるようにします。
* 出来上がった c:\open3d\bin 内の dll を c:\dev\bin にコピーします。環境変数 `Path` の末尾に c:\dev\bin を追加して、アプリケーション実行時に動的ライブラリが参照できるようにします。
* Open3D 以外のライブラリも同じように扱います。

（追記：`Path` の追記によって `CMAKE_PREFIX_PATH` は無くても動作します。→ https://qiita.com/kkoba775/private/9e938006fdc53c707d82 ）

# 準備１ zlib のインストール
以下の作業で Open3D ライブラリ構築で必要となる zlib をインストールします。
## ビルド
ディレクトリ c:\dev と c:\dev\make を作成し、[http://zlib.net/](http://zlib.net/) から zlib source code, version 1.2.13, zipfile format (zlib1213.zip) をダウンロードし、内容を c:\dev\make に展開する。これらは Windows の GUI で作業してください。
```
dev/
├── make
    ├── zlib-1.2.13
``` 

Developer Command Prompt for VS 2022 で
```DOS
> cd \dev\make\zlib-1.2.13
> md build
> cd build
> cmake -DCMAKE_INSTALL_PREFIX="c:\dev\zlib" ..
> cmake --build . --config Release --target INSTALL
> cmake --build . --config Debug --target INSTALL
> cd \dev
> md bin
> copy zlib\bin\*.dll bin\
```
として c:\dev\zlib （CMAKE_INSTALL_PREFIX で指定）にインストールを行う。
ディレクトリ c:\dev\bin を作成し、C:\dev\zlib\bin 内の zlib.dll と zlibd.dll を  c:\dev\bin に移動（またはコピー）する。作業が完了すると、ディレクトリ構成は下のようになる。
```
dev/
├── bin
├── zlib
    ├── bin
    ├── include
    ├── lib
    ├── share
├── make
    ├── zlib-1.2.13
        ├── build 
```
作業後、c:\dev\make\zlib-1.2.13 以下は不要なので削除してよい。build 以下だけでも削除すれば容量の節約になる。
## 環境変数の設定
環境変数 Path の最後の行に c:\dev\bin を追加する。
環境変数 ZLIB_ROOT を作成し、c:\dev\zlib を設定する。
`` > set`` で環境変数の一覧が見れるので、設定が反映されていない場合には一旦 Windows からサインアウトしてサインインし直す。 

なお、CMAKE で xxx_ROOT が有効になるのは CMake 3.12 以降であるが、Open3D 内のバージョン指定ではこれより古いものがある。ZLIB_ROOT を有効にするためには、CMP0074 に NEW を指定する必要がある。 

# 準備２ fmt のインストール
Open3D では書式付出力のライブラリとして {fmt} [https://github.com/fmtlib/fmt](https://github.com/fmtlib/fmt) を使っている。デフォルトでは fmt 9.0.0 をダウンロードしてライブラリに取り込むが、これが CUDA のコンパイラ nvcc で警告を生じ、ライブラリ構築に失敗する。この問題は open3d-0.17.0\cmake\Open3DShowAndAbortOnWarning.cmake の 32 行目以降を編集して 
```diff_CMake
    set(DISABLE_NVCC_WARNINGS
        2809           # ignoring return value from routine declared with "nodiscard" attribute (cub)
+       186            # ignoring pointless comparison of unsigned integer with zero (fmt 9.0.0)
    )
```
とすることで解決できるが、今回は Open3D 本体を書き換えるのは避け、対策がなされた fmt 9.1.0 をシステムに登録して利用することにする。 ([Fix warnings #1288](https://github.com/fmtlib/fmt/commit/9a56a608ee6f357825c65789bd4f28e73070d70a)) 

Developer Command Prompt で以下を実行する。
```DOS
> cd \dev\make
> git clone https://github.com/fmtlib/fmt.git -b 9.1.0 fmt-9.1.0 --depth 1
> cd fmt-9.1.0
> md build
> cd build
> cmake -DCMAKE_CXX_FLAGS_INIT="/utf-8" -DCMAKE_INSTALL_PREFIX="c:\dev\fmt" ..
> cmake --build . --config Release --target INSTALL
> cmake --build . --config Debug --target INSTALL
```
環境変数 `CMAKE_PREFIX_PATH` を作成し c:\dev を設定する。
`` > set`` で環境変数の一覧が見れるので、設定が反映がされていない場合には一旦 Windows からサインアウトしてサインインし直す。 

# Open3D のインストール
準備ができたので、Developer Command Prompt で以下を実行する。
```DOS
> cd \dev\make
> git clone https://github.com/isl-org/Open3D open3d-0.17.0 -b v0.17.0 --depth 1
> cd open3d-0.17.0
> md build
> cd build
> cmake -DCMAKE_POLICY_DEFAULT_CMP0074=NEW -DUSE_SYSTEM_FMT=ON -DBUILD_SHARED_LIBS=ON -DBUILD_CUDA_MODULE=ON -DBUILD_EXAMPLES=ON -DBUILD_PYTHON_MODULE=OFF -DBUILD_WEBRTC=OFF -DCMAKE_DEBUG_POSTFIX=d -DCMAKE_INSTALL_PREFIX="c:/dev/open3d" .. 
> cmake --build . --config Release --target ALL_BUILD
> cmake --build . --config Release --target INSTALL
```
```cmake ..``` で指定したオプションの意味を以下に示す。
* ```CMAKE_POLICY_DEFAULT_CMP0074=NEW``` で ZLIB_ROOT が有効になる。
* ```USE_SYSTEM_FMT=ON``` はインストール済みの fmt 9.1.0 を利用する指定である。
* ```BUILD_SHARED_LIBS=ON``` で動的ライブラリ(.dll)を作成する。3rd party packages を内部に取り込めるのでライブラリがシンプルになる。
* ```BUILD_CUDA_MODULE=ON``` CUDA の利用を指定。今回のメイン。
* ```BUILD_EXAMPLES=ON``` でサンプルプログラムがコンパイルされる。動作テストが主目的だが、有用なプログラムも得られる。
* ```BUILD_PYTHON_MODULE=OFF```, ```BUILD_WEBRTC=OFF``` 今回は対象外。
* ```CMAKE_DEBUG_POSTFIX=d``` デバックライブラリの末尾に d をつける。

コンパイルに時間がかかるので、BUILD と INSTALL の工程に分けて、まずは Release ライブラリを作成する。途中、警告が多数出力されるが、エラー（赤字）ではないので無視する。続けて
```DOS
> cmake --build . --config Debug --target ALL_BUILD
```
として、デバックライブラリの作成を試みる。これは ```入力ファイル '..\..\lib\Debug\glfw3.lib' を開けません。```というエラーとともに停止してしまうが、続けて
```DOS
> copy lib\Debug\glfw3d.lib lib\Debug\glfw3.lib
> cmake --build . --config Debug --target ALL_BUILD
> cmake --build . --config Debug --target INSTALL
```
とすることで処理を完了できる。

C:\dev\open3d\bin 内の Open3D.dll と Open3Dd.dll を  c:\dev\bin に移動（またはコピー）する。Windows の GUI を使うか、コマンドラインから以下を実行する。
```
> cd \dev
> copy open3d\bin\*.dll bin\
```

# ライブラリの使用方法
## 簡単な例
最も簡単な例で使い方を説明する。作業用の適当なディレクトリを用意して、以下の内容で ```sphere.cpp``` と ```CMakeLists.txt``` を作成する。
```sphere.cpp
#include <open3d/Open3D.h>

int main(int argc, char *argv[]) {
    auto sphere = open3d::geometry::TriangleMesh::CreateSphere(1.0);
    sphere->ComputeVertexNormals();
    sphere->PaintUniformColor({0.0, 1.0, 1.0});
    open3d::visualization::DrawGeometries({sphere});
    return 0;
}
```
```CMakeLists.txt
cmake_minimum_required(VERSION 3.20)

project(test_open3d CXX)

set(CMAKE_CXX_STANDARD 17) 
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")

find_package(Open3D REQUIRED)

add_executable(sphere sphere.cpp)
target_link_libraries(sphere Open3D::Open3D)
```
Developer Command Prompt から
```
> md build
> cd build
> cmake ..
> cmake --build . --config Release
> Release\sphere.exe
```
とすれば、水色の球を表示するウィンドウが生成される。

## GPU の使用例
Open3D のサンプルプログラムをコンパイルする例を示す。適当な作業用ディレクトリを用意し、```C:\dev\make\open3d-0.17.0\examples\cpp``` 内にある ```OnlineSLAMRGBD.cpp``` と ```OnlineSLAMUtil.h``` のコピーを置く。同じディレクトリ内に
```CMakeLists.txt
cmake_minimum_required(VERSION 3.20)

project(test_slam CXX)

set(CMAKE_CXX_STANDARD 17) 
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")

find_package(Open3D REQUIRED)

add_executable(slam OnlineSLAMRGBD.cpp OnlineSLAMUtil.h)
target_link_libraries(slam Open3D::Open3D)
```
を作り、Developer Command Prompt から
```
> md build
> cd build
> cmake ..
```
とすると、```build``` ディレクトリ内に ```test_slam.sln``` が作成される。これを Windows の GUI からダブルクリックして、Visual Studio を起動する。ソリューションエクスプローラーから、```slam``` を展開し、```Source Files``` の下の ```OnlineSLAMRGBD.cpp``` をダブルクリックして編集を開始する。188 行目を下の 189 行目で置き換える。
```OnlineSLAMRGBD.cpp
187:    auto& app = gui::Application::GetInstance();
188: //    app.Initialize(argc, const_cast<const char**>(argv));
189:    app.Initialize("c:/dev/open3d/bin/Open3D/resources");
190:    auto mono =
191:            app.AddFont(gui::FontDescription(gui::FontDescription::MONOSPACE));
192:    app.AddWindow(std::make_shared<examples::online_slam::ReconstructionWindow>(
193:            get_rgbd_image_input, intrinsic_t, default_params, device, mono));
194:    app.Run();

```
ソリューションエクスプローラーから、```slam``` を右クリックし、「スタートアッププロジェクトに設定」する。ツールバーで ```Release▼``` を選択してからビルドを行う。(```Debug▼```にしてデバッグ実行も可能。)

初めて ```slam.exe``` を実行すると RGBD 画像データセット（1.7 GB）のダウンロードが始まる。ダウンロードが完了していれば、ウィンドウが表示される。その中の ```Resume/Pause``` スイッチを切り替えると、途中経過を表示しながら SLAM が実行される。

コマンドラインから 
```
> cd Release
> slam --device CPU:0
```
とすれば GPU を使わずに CPU で実行することもできる。  ```> slam --help``` で他のデータセットを利用する方法が表示される。