跳到主要内容

接入第三方SDK

前言

IdeaXR 不能直接调用外部第三方库的接口函数,需要经过一层中转的方式接入。

Docusaurus Plushie

本教程主要介绍如何用 c++ 创建IVRNative动态库 并且接入第三方库的内容。

编译IVRNative动态库

下文 使用 VS2019 编译动态dll 库文件。

编译前准备

  • 你需要准备 开发C++ 的环境,本教程以 VS2019 为开发工具
  • ivr 头文件和ivr静态库lib文件 点此下载

创建项目

使用 VS 2019 添加 动态链接库 项目:

Docusaurus Plushie

Docusaurus Plushie

点击创建后,如下所示:

Docusaurus Plushie

添加 ivr头文件和lib静态库

将下载好的 ivr 文件和lib库 放入项目文件夹下:

Docusaurus Plushie

配置 ivr头文件和lib静态库

选择项目 -> 鼠标右键 -> 属性,按照如下流程配置头文件和静态库:

Docusaurus Plushie

Docusaurus Plushie

Docusaurus Plushie

Docusaurus Plushie

静态库有2个文件 一个是debug 版本 ,另一个是release 版本,按自己所需选择对应库文件。

功能开发

创建头文件

首先,我们基于IVRNative节点创建头文件, 我们将它命名为MyScriptClass.h :

MyScriptClass.h
#include<IVR.hpp>
#include <Spatial.hpp>

namespace ivr {

class MyScriptClass : public Spatial
{
IVR_CLASS(MyScriptClass, Spatial)

private:
int some_data;

public:

static void _register_methods();

MyScriptClass();
~MyScriptClass();

void _init(); // 必须要有

void do_something(int index);//自定义方法

int get_some_data();//自定义方法
};

}

以上有一些注意事项,
IVR.hpp,包含我们所有的基本定义。
Spatial.hpp, 包含对 Spatial 类的绑定。我们将在我们的模块中继承这个类。

我们使用命名空间 ivr , 因为IVRNative中的所有内容都在此命名空间中定义。

然后我们有了我们的类定义, 它通过继承3D节点 Spatial(也可以继承其他节点)。 IVR_CLASS 宏 为我们设置了一些内部事物。

之后, 我们声明一个名为 some_data 的成员变量。

我们定义了我们的方法,包括构造函数和析构函数,但是还有其他两个函数可能看起来很熟悉。

第一个是我们的 _register_methods , 这是一个静态函数, IdeaXR 内部将调用它来为我们找出 IVRNativeScript 上 可以调用哪些方法 以及 它暴露的属性。
第二个是我们的 _init 函数, 它是在 IdeaXR 中正确设置我们的对象之后调用的。 即使您没有在其中放置任何代码, 它也必须存在。 第三个是我们的 do_something 函数, 自定义的方法,名字自己命名

实现接口函数

接下来,我们创建 MyScriptClass.cpp 文件来实现我们的接口函数:

MyScriptClass.cpp
#include "pch.h"
#include "MyScriptClass.h"

#pragma comment(lib, "第三方SDK.lib")

using namespace ivr;

void MyScriptClass::_register_methods()
{
register_method("do_something", &MyScriptClass::do_something);
register_method("get_some_data", &MyScriptClass::get_some_data);
}

MyScriptClass::MyScriptClass()
{

}

MyScriptClass::~MyScriptClass()
{
// 添加需要清除的代码
}

void MyScriptClass::_init()
{
some_data = 1;
}

void MyScriptClass::do_something(int index)
{
// 可在此处调用第三方库的接口函数
}

int MyScriptClass::get_some_data()
{
// 可在此处调用第三方库的接口函数

return 0;
}

上述代码应该很清晰, 我们正在实现我们在头文件中定义的每个类的方法。
注意 register_method 调用 必须是 public 修饰的方法, 否则在 IVRScript脚本 中将无法使用它。不需要在 IVRScript 脚本中调用的方法无需绑定注册,如上的_init方法。

导出接口类

还有一个我们需要的 C++ 文件;
我们将它命名为 MyPlugin.cpp 。 我们现在需要的是一小段代码, 告诉 IdeaXR 我们的 IVRNative 插件中的所有 IVRNativeScripts。

MyPlugin.cpp
#include "pch.h"
#include "IVR.hpp"
#include "MyScriptClass.h"

extern "C" void IVR_EXPORT ivr_native_init(ivr_native_init_options * o) {
ivr::IVR::native_init(o);
}

extern "C" void IVR_EXPORT ivr_native_terminate(ivr_native_terminate_options * o) {
ivr::IVR::native_terminate(o);
}

extern "C" void IVR_EXPORT ivr_nativescript_init(void* handle) {
ivr::IVR::nativescript_init(handle);

ivr::register_class<ivr::MyScriptClass>();
}

请注意, 我们这里没有使用 ivr 命名空间, 因为这里实现的三个函数需要在没有命名空间的情况下定义。

IdeaXR 加载我们的插件并卸载它时, 分别调用 ivr_native_initivr_native_terminate 函数。
我们在这里所做的只是解析我们的绑定模块中的函数来初始化它们, 但你可能需要根据需求来设置更多内容。

重要的功能是第三个函数叫做 ivr_nativescript_init ,我们为动态库中的每个类调用函数 register_class 来注册该类。

编译完成

经过上述步骤,已经可以编译动态库文件了。使用 VS2019 编译后会生成MyScript.dll
如果编译出错,请注意,需要把 pch.h 中的 framework.h 移动到dllmain.cpp中。 Docusaurus Plushie

Docusaurus Plushie

到此,编译已完成。

创建一个IVRNative插件

在IdeaXR中创建插件

经过上述教程后,相信你已经上手了。现在开始创建插件,需要接入IdeaXR 中进行脚本开发。

Docusaurus Plushie

按照上述图片所示,单击 创建自定义插件 后,填写必要内容,选择我们编译好的MyPlugin.dll文件和 第三方依赖的文件:

Docusaurus Plushie

如果开发第三方插件有依赖项,请务必选择编译的dll中所依赖的库。
创建成功后,在编辑器下方 文件 中会显示如下,除native文件夹,其余文件为系统必备的文件,详情请查看自定义节点插件

Docusaurus Plushie

plugin.is 是脚本的配置文件。
MyPlugin.is 为功能脚本,主要的开发内容都在其内。
native 文件夹 如下所示:

Docusaurus Plushie

bin 文件夹存放的内容是 选择的插件dll 和 选择的依赖dll

在插件脚本中调用

所有的环境都已经准备好了,现在开始获取我们动态库中编写的实例,在脚本中添加如下代码,

res:://addons/my_plugin/MyPlugin.is
extends Spatial

func get_my_plugin(): // 获取动态库实例
var my_plugin = load("res://addons/my_plugin/native/MyPlugin.idns")
if my_plugin != null:
return my_plugin.new()
else :
print_debug("加载plugin出错")
return null

func _ready():
var my_plugin = get_my_plugin()
if my_plugin:
my_plugin.do_something(2) //调用动态库中的方法
var data = my_plugin.get_some_data() //调用动态库中的方法

func _physics_process(delta):
pass

之后,你就可以通过 my_plugin 操作我们在构建dll库中 创建的方法, 方法必须是在函数_register_methods 中绑定注册过的。

MyScriptClass.cpp
void MyScriptClass::_register_methods()
{
register_method("do_something", &MyScriptClass::do_something);
register_method("get_some_data", &MyScriptClass::get_some_data);
}

本教程到此就结束了,开始你的插件创作内容吧!