Windows下Dll在Unity中使用的一般方式
Unity中虽然已经有广泛的库和插件,但是相较于C++的库生态而言,还是有一定的差距;因此本篇博文记录Windows下将C++函数打包成动态链接库在Unity中使用的一般方法。
环境
Visual Studio 2019 , Unity2022 , Windows11,OpenCV
说明
- Unity中有针对Windows 下DLL文件的自动加载机制,所以只要把打包好的动态链接库拷贝到
Assets/Plugins
,然后在Unity脚本中进行注册便可以使用。 - 由于动态链接库本质上可以理解成一个插件,所以本次记录侧重 Unity和C++动态链接库函数的传参一致性问题。
步骤
Visual Studio 2019
- 新建一个项目,在源文件中按照如下格式编写函数
缩略版:
extern "C" {// 变量static bool isModelInitialized = false;__declspec(dllexport) int add( int width, int height) {return width + height;}}
Demo:
#include "opencv2/highgui.hpp"
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
//#include"opencv2/xfeatures2d.hpp"
#include "SFace.h"
#include "opencv2/dnn.hpp"
#include "opencv2/calib3d.hpp"
#include "opencv2/video.hpp"
#include "face_detector.hpp"
#include <iostream>using namespace cv;
using namespace declass;extern "C" {// static bool isModelInitialized = false;static YOLOv8_face* fdModel = nullptr;static SFace* face_recognizer = nullptr;static Mat targetFeature;__declspec(dllexport) bool reGetStartFaceBox(unsigned char* pixelData, int width, int height, int* box) {return false;}__declspec(dllexport) bool getStartFaceFeature(unsigned char* pixelData, int width, int height) {return true;}// 释放资源的函数__declspec(dllexport) void Cleanup() {{delete fdModel;delete face_recognizer;fdModel = nullptr;face_recognizer = nullptr;isModelInitialized = false;}
extern "C"
是一种 C++ 中的语言链接约定,用于指示编译器以 C 的方式处理函数的名称修饰(name mangling)规则。
__declspec(dllexport)
是 Microsoft 编译器特有的一个声明符,用于声明某个函数、变量或类在 DLL(动态链接库)中导出,使得它可以被其他程序或库调用。
之后进行编译,便可以得到一个dll文件。
Unity
接下来需要将动态链接库拷贝到Unity的Assets/Plugins
目录:
接下来我们新建一个脚本,在Unity中注册我们编写好的函数
public class FaceRecongnize
{// faceRecong是dll文件名字,函数名和上面的demo是一致的。[DllImport("faceRecong", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]public static extern bool reGetStartFaceBox(IntPtr pixelData, int width, int height, int[] box);[DllImport("faceRecong", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]public static extern bool getStartFaceFeature(IntPtr pixelData, int width, int height);[DllImport("faceRecong", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]public static extern void Cleanup();}
至于参数,比如我想把一个纹理,或者一个数组传入到动态链接库中进行赋值,一般是用指针进行传送,比如上面的纹理数据和box,都是指针。
调用示例。
PS:一个比较值得关注的点是,如果使用了第三方库,OpenCV,我们还需要把OpenCV相关的dll文件也拷贝到Assets/Plugins下,这是因为动态链接库之间也有一些依赖关系,我们需要把他们都导入进去。同时我建议如果要打包的话,因为可能跨设备运行,所以建议采用相对目录的方式,配置Visual Studio中的第三方库的依赖关系。
Refer
-
Mac下在Unity中调用C++库
-
演练:创建和使用自己的动态链接库 (C++)