LoginSignup
2
3

More than 1 year has passed since last update.

unityアプリ(standalone, androidスマホ, OculusQuest2)でc++ライブラリを使う

Posted at

Linux standalone、Android、Oculus Quest 2用のUnityアプリで、c++ライブラリを使う方法を説明します。
standaloneとAndroidについては、unity公式に解説がありますが、わかりづらかったので使い方をまとめました。
アプリの内容は「c++ライブラリを使って計算した結果を表示する」という簡単なものです。

環境

  • 開発環境 + standaloneアプリ環境
    • ubuntu 16.04
    • c++ライブラリ
      • c++ 11
      • cmake
    • unity
      • 2019.4.17f1
  • Androidスマホ
    • xperia 5
  • Oculus Quest 2

C++ライブラリの開発

初めにC++ライブラリを開発します。

ライブラリ

今回はテスト目的なので、引数で渡された2つの整数を加算する、という簡単なライブラリを開発しました。
クラス内のでのインスタンス生成と、その関数呼び出しを試したかったので、2つのクラスを用意し、1つのクラスからもう1つのクラスを使うようにしました。

calculator.cpp
#include "calculator.h"

int Calculator::calc(const int a, const int b) {
  return calculator2_.calc2(a, b);
}
calculator.h
#ifndef __CALCULATOR_H__
#define __CALCULATOR_H__

#include "calculator2.h"

class Calculator {
 public:
  Calculator() {}
  int calc(const int a, const int b);

 private:
  Calculator2 calculator2_;
};

#endif  // __CALCULATOR_H__
calculator2.cpp
#include "calculator2.h"

int Calculator2::calc2(const int a, const int b) {
  return a * b;
}
calculator2.h
#ifndef CALCULATOR2_H_
#define CALCULATOR2_H_

class Calculator2 {
 public:
  Calculator2() {}
  int calc2(const int a, const int b);
};

#endif  // CALCULATOR2_H_

wrapperの実装

ネームマングリングの問題を回避するため、c言語でwrapperを実装します。
c#からc++の関数を直接呼び出すことができないためc言語でwrapperを用意し、このwrapperからc++の関数を呼び出すようにします。
c#からはこのwrapperを呼び出します。

ネームマングリングについては、分かりやすく解説している記事やサイトが多くあるのでここでは説明しません。

wrapper.cpp
#include "wrapper.h"
#include "calculator.h"

extern "C" {

Calculator* pCalc;
void Test_constructor() { pCalc = new Calculator(); }
int Test_calc(int a, int b) { return pCalc->calc(a, b); }
void Test_destructor() { delete pCalc; }

}
wrapper.h
#ifndef WRAPPER_H_
#define WRAPPER_H_

#ifdef __cplusplus
extern "C" {
#endif

void Test_constructor();
int Test_calc(int a, int b);
void Test_destructor();

#ifdef __cplusplus
}
#endif

#endif  // WRAPPER_H_

動作確認

standaloneアプリ、androidアプリのぞれぞれで異なる方法でビルドする必要があるため後ほど詳しくは後ほど説明しますが、
事前にコンパイルチェックと動作確認はしておいたほうが、後ほど手戻りが少なくてすみます。
動作確認は以下のファイルを用意して行いました。

main.c
#include "wrapper.h"
#include <stdio.h>

int main(int argc, char *argv) {
    int a;
    int b;
    int c;

    a = 2;
    b = 3;

    Test_constructor();
    c = Test_calc(a, b);
    Test_destructor();

    printf("%d\n", c);

    return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 2.8)

project(calc)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")

include_directories(lib)
add_library(calc SHARED wrapper.cpp lib/calculator.cpp lib/calculator2.cpp)

add_executable(a.out main.c)
target_link_libraries(a.out calc)
# Build
$ cmake .
$ make

# 実行
./a.out
6

unityアプリの開発

standaloneアプリとandroidアプリでは、unityアプリの実装方法は同じです。
異なるのはアプリのビルド設定と、ライブラリのビルド方法になります。

unity(C#)側から整数をライブラリの関数に渡しその結果をテキストとして表示する、というアプリを実装します。

standaloneアプリとandroidアプリ共通部の実装

unityアプリの実装

unityアプリ実装では、特に特別な手順はありません。

  1. アプリの種類で3Dを選択し、新規プロジェクトを作成します。
  2. Hierarchy上で右クリックし、UI->Textと選択し、textオブジェクトを作成します。
  3. Hierarchy上で右クリックし、Create Emplyを選択しオブジェクトを作成します。作成したオブジェクトの名前を変更します。自分はCalcObjectとしました。

c++ライブラリ呼び出しスクリプトの実装

c++ライブラリを呼び出し、その計算結果をテキストオブジェクトに表示するC#スクリプトを実装します。
まず、Assetsフォルダ下にScriptsというフォルダを作成し、Scriptsフォルダの下にCalc.csというファイルを作成します。
このファイルの内容は以下の通りです。

Calc.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Runtime.InteropServices;

public class Calc : MonoBehaviour
{

    [DllImport("libcalc.dll")] public static extern void Test_constructor();
    [DllImport("libcalc.dll")] public static extern int Test_calc(int a, int b);


    public GameObject test_obj = null;
    private int a = 0;
    private int ret;

    void Start()
    {
        Test_constructor();
    }

    void Update()
    {
        ret = Test_calc(a, 2);
        a++;

        Text text = test_obj.GetComponent<Text> ();
        text.text = ret.ToString();
    }
}

c++ライブラリを使うために必要な実装は以下になります。
以下を行うことで、C#スクリプト内でc++ライブラリ(厳密にはwrapperの関数)を呼び出せるようになります。

  • using System.Runtime.InteropServices; : DllImportを使うために必要になります
  • DllImport : c++ライブラリの関数をインポートし、使えるようにします。()内はインポートするファイル名です。これは関数ごとに必要になります。呼び出すことができる関数はwrapperで実装された関数です。

このCalc.csCalcObjectに追加します。
すると、textというパラメータが表示されるので、Canvas下のTextをドラッグ&ドロップします。

image.png

standaloneアプリの実装

c++ライブラリのビルド

開発環境(自分の場合はubuntu 16.04)上で動作するライブラリをビルドします。開発環境上でそのままライブラリをビルドすればよいです。
自分は以下のCMakeファイルを作成し、ビルドしました。
なお、C#から使うためには動的ライブラリである必要があります(macを除く)。そのためadd_libraryのオプションでSHAREDとしています。

CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(calc)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
add_library(calc SHARED wrapper.cpp calculator.cpp calculator2.cpp)

ビルドが成功すれば、libcalc.soというファイルが生成されます。
Assetsフォルダ化にAssets-> Plugins -> x86_64 -> ubuntuという階層でフォルダを作成し、このフォルダに生成されたlibcalc.soを置きます。

pluginのロード設定

この後、Android用のライブラリもビルドしてPluginsフォルダ下に置くことになります。そうすると、同名のファイルがあるよ、というエラー

「unity That means one or more plugins are set to be compatible with Editor. Only one plugin at the time can be used by Editor.」

がでます。
これを防ぐため、プラグインごとに使用する環境を設定します。

Projectウィンドウでプラグイン(今回はAssets/Plugins/x86_64/ubuntu/libcalc.so)を選択します。
右のインスペクタウィンドウで以下のように選択し、Applyボタンを押下します。
- Include Platforms : Editor, Standalone
- Platform Settings : Linux x86_64

image.png

unityアプリのビルド設定

standaloneアプリを実装する場合は、プロジェクト生成時のデフォルトの設定のままでよいです。

ビルド&実行

通常のunityアプリの開発と同じように、build and runからビルドします。
アプリ実行後、画面上に数値が表示され、それが増加していけば正しく動作しています。

image.png

スマホ用Androidアプリの実装

Androidアプリ用のc++ライブラリをビルドするにはAndroidStudioを使う必要があります。
そのため最初にAndroid Studioのインストール方法と、次にAndroidプロジェクトを作成してビルドする方法を説明します。

AndroidStudioのインストール

  • 公式よりAndroid Studioをダウンロードします。自分は4.2.1 for Linux 64-bitをダウンロードしました。
  • ダウンロードしたフォルダを解凍し、Android Studioを実行します。
$ tar -xzvf android-studio-ide-202.7351085-linux.tar.gz
$ cd android-studio/bin/
$ ./studio.sh

初めてインストールする場合はセットアップウィザードが表示されるので画面に従って進めます。設定はデフォルトのままで問題ありません。
自分は、特定のバージョンのAndroid SDKをインストールしたかったので、Android 11.0とAndroid 7.1.1をインストールしました。

プロジェクト作成

  • Android Studio起動後、Create Projectからプロジェクトを作成します。プロジェクトのテンプレートにはC++ Nativeを選択します。
  • プロジェクトを作成したら、c++ライブラリのビルドに必要なAndroid NDKをインストールします。
    • メニューのTool -> SDK Managerを開く
    • SDK Tools タブ -> NDK (side by side)CMakeを選択し、Applyを押下

c++ライブラリのビルド

  • 上で作成した、c++のソースコードを、app/src/main/cppフォルダ下に置きます。自分はwrapperと他のソースコードを分けたかったため、libというフォルダも作りました。
    image.png

  • app/src/main/cppフォルダ化にCMakeLists.txtというファイルを作成し以下の内容にします。(コメントは省略)

CMakeLists.txt
project("cpplib") # プロジェクト名は、Androidプロジェクト名となっているので、環境ごとに異なります。

set(TARGET_LIB "calc") 

include_directories(lib)

add_library(${TARGET_LIB}
            SHARED
#            native-lib.cpp
            wrapper.cpp
            lib/calculator.cpp
            lib/calculator2.cpp
)

find_library(LOG_LIB log)

target_link_libraries(${TARGET_LIB} ${LOG_LIB})

1つ注意点としてはnative-lib.cppを使わないことです。これはJavaからcのライブラリを呼び出すためのコードが含まれていますが、今回はJavaを使用しないのでライブラリには含めません。

  • プロジェクトのビルド設定をします。app/srcフォルダ下のbuild.gradleを開きます。(build.gradleは2つファイルがあるので注意してください)
    • SDKのバージョンを確認し、異なっていたら修正します。自分は、Android 11(version 30)とAndroid 7.1.1(version 25)をインストトールしたので、以下のようにしました。
build.gradle
android {
    compileSdkVersion 30
    buildToolsVersion "30.0.3"

    defaultConfig {
        applicationId "com.xxx.xxx" # 環境ごとに異なります
        minSdkVersion 25
        targetSdkVersion 30
  • メニューのBuild -> Make Projectからビルドします。なお、デフォルトではdebugビルドとなっています。releaseビルドをしたい場合は、Build VariantsActive Build VariansReleaseを選択します。
    ビルドに成功したらapp/build/intermediates/cmake/release(もしくはdebug)/objフォルダ化にライブラリが出力されます。ライブラリはcpuアーキテクチャごとに生成されるため、arm64-v8a, armeabi-v7a, x86, x86_64の4つのフォルダの下に、それぞれライブラリが出力されています。

pluginのロード設定

上記で出力されたライブラリをunityのAssets/Pluginsフォルダ下にコピーします。そして先ほどと同様に、プラグインごとに環境を設定します。
- arm64-v8a
- Include Platforms : Android
- Platform Settings : CPU ARM64
- armeabi-v7a
- Include Platforms : Android
- Platform Settings : CPU ARMv7

unityアプリのビルド設定

通常のAndroidアプリのビルド方法と同じです。

  • メニューのFile -> Build Settingsを選択します
  • PlatformAndroidを選択しSwitch Platformを押下します
  • Player Settingsを押下します
  • Player -> Other Settingsを選択します
    • Package Name -> Defaultとなっている箇所に、任意の名前を設定します
    • `Minimum API Level` -> Android versionを指定します。これは対象とするデバイスに合わせて設定してください

なお、自分はstandaloneアプリと別sceanとして保存したかったので、最初にメニューのSave asから別名のsceanとして保存しました。

ビルド&実行

AndroidスマホをPCに接続し、Build & Runを押下します。
なお、事前にAndroidスマホ側でUSBデバッグを有効にしておいてください。

Oculus Quest2用Androidアプリの実装

unityのビルド設定と、Canvasの位置調整以外は上記のスマホ用Androidアプリと同じです。

unityアプリのビルド設定

Oculus Quest 2のビルド設定は、多くの記事で説明されているのでここでは詳しく説明しません。

  • Build Settingの変更
    • File -> Build Settingを選択
    • PlatformでAndroidを選択し、Switch Platformボタンを押す
  • Oculus Integrationをインポート
    • Asset StoreからOculus Integration for Unityをインポートする
  • XR Plug-in Managementのインストール
    • Window -> Package Managerを選択
    • XR Plug-in Managementを選択し、インストール
  • Player Settingの変更
    • Edit -> Project Settingsを選択
    • Player -> Other Settingsを選択
    • Package Nameに任意の名前を入力
    • Minimum API LevelをAndroid 7.1 'Nougat' (API level 25)にする
    • Api Compatibility Levelを.NET 4.xにする
    • XR Plug-in Managementを選択
    • Android と Standalone の “Oculus” にチェック 入れる

unityアプリの変更

  • カメラの変更
    • HierarchyからMain Cameraを削除
    • ProjectからAssets/Oculus/VR/Prefabsを選択し、OVRCameraRigをHierarchyドラッグ&ドロップ
    • OVRCameraRigのOVR Managerスクリプトで、Target Devicesで、Quest2にチェック
  • Canvasの設定変更
    • HierarchyでCanvasを選択
      • Render ModeをWorld Spaceに変更
      • Event Cameraに、CenterEyeAnchor (Camera) を設定
    • positionを(0, 0, 40)に設定
    • width, heightを(100, 50)に設定
  • Textの設定変更
    • positionを(0, 0, 0)に設定
    • width, heightを(100, 50)に設定

今回はTextが画面に表示されればよかっただけなので、Canvas, Textの位置、大きさは適当に設定しました。

ビルド&実行

Oculus Quest 2をPCに接続し、Build & Runを押下します。

参考

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3