国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Unity開(kāi)發(fā)進(jìn)行C、C++源碼交互,支持跨平臺(tái)

這篇具有很好參考價(jià)值的文章主要介紹了Unity開(kāi)發(fā)進(jìn)行C、C++源碼交互,支持跨平臺(tái)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

前言

公司新項(xiàng)目,要和做C++算法的人一起合作開(kāi)發(fā),起初項(xiàng)目定于Windows平臺(tái),就看了一些C++和DLL交互的一些資料,做了一套生成DLL交互的接口,后來(lái)項(xiàng)目寫(xiě)方案由于設(shè)備又定到安卓平臺(tái),嘗試過(guò)打包之后,DLL打包不到安卓平臺(tái),試過(guò)將dll改名打AB包然后用Assembly.Load的方式,但這種方式只適用于C#的DLL,后來(lái)經(jīng)過(guò)多方調(diào)研,在某q群拋出這個(gè)問(wèn)題才知道有和C++源碼交互的方式,但自己幾經(jīng)嘗試都調(diào)用失敗,差點(diǎn)放棄想在安卓平臺(tái)編譯成so來(lái)交互,元旦過(guò)后,某天夢(mèng)中想到這個(gè)問(wèn)題,應(yīng)該去q群繼續(xù)拋出這個(gè)問(wèn)題請(qǐng)教別人是怎么做的,最終經(jīng)過(guò)兩天的不懈努力,嘗試編寫(xiě)了C接口和解決打包過(guò)程中的各種問(wèn)題,最終總結(jié)了這幾天來(lái)的成果。


需求分析

先上個(gè)圖

unity c++,Unity,unity,c語(yǔ)言,c++,c#
這是一個(gè)基于Unity渲染的數(shù)智人項(xiàng)目,前端使用Unity來(lái)顯示和交互,一些輸入和數(shù)字人的表現(xiàn)都是C#層開(kāi)發(fā),比如動(dòng)畫(huà)系統(tǒng)、麥克風(fēng)輸入、語(yǔ)音數(shù)據(jù)同步嘴唇等等,后端算法主要采用C++開(kāi)發(fā),比如文本和語(yǔ)音互轉(zhuǎn)、AI、算法模型訓(xùn)練等,這就涉及到了C#和C++之間的交互,也就是相互調(diào)用的問(wèn)題。

所以我最終的流程就是

  1. Unity用麥克風(fēng)監(jiān)聽(tīng)玩家說(shuō)話,并把說(shuō)話內(nèi)容發(fā)給C++算法
  2. C++得到文本,進(jìn)行智能對(duì)話系統(tǒng)的訓(xùn)練
  3. 得到訓(xùn)練的對(duì)話文本后,文本轉(zhuǎn)語(yǔ)音,發(fā)送到Unity
  4. Unity根據(jù)語(yǔ)音數(shù)據(jù)驅(qū)動(dòng)說(shuō)話,包括嘴唇變化、肢體動(dòng)作的表現(xiàn)
  5. AI數(shù)智人回答完畢又開(kāi)始循環(huán)到步驟1

具體實(shí)現(xiàn)

1.C#層接口定義

C#層代碼:因?yàn)楹瘮?shù)與生成的 C++ 代碼鏈接在一起,所以沒(méi)有單獨(dú)的 DLL 可進(jìn)行 _P/Invoke 調(diào)用。因此,可使用"__Internal"關(guān)鍵字代替 DLL 名稱,從而使 C++ 鏈接器負(fù)責(zé)解析函數(shù),而不是在運(yùn)行時(shí)加載函數(shù),如下例所示:

  • 定義了初始化函數(shù),給C++傳遞C#層的接口,并緩存在C++來(lái)使用C#的回調(diào),比如Unity的日志輸出、Unity內(nèi)接收語(yǔ)音數(shù)據(jù)的方法,從而緩存后使得C++具有調(diào)用C#回調(diào)函數(shù)(委托)的能力。
[DllImport("__Internal")]
    static extern int Init(
        ULogCallback logCallback
        ,UReceivesAI_DialogueCallback diaogueCallback
   );
    • 兩個(gè)初始化作為回調(diào)的參數(shù),可以自行拓展,然后給C++緩存起來(lái),其中的ULogCallback 為Unity的日志回調(diào)的委托,diaogueCallback為接收AI對(duì)話的委托,ULogCallback 的原型為:
 /// <summary>
    /// Unity日志調(diào)用的回調(diào)委托
    /// </summary>
    /// <param name="level"></param>
    /// <param name="msg"></param>
    public delegate void ULogCallback(LogLevel level, string msg);

    public enum LogLevel
    {
        Info,
        Warn,
        Error
    };
    • 而diaogueCallback的原型為:
 /// <summary>
    /// Unity接收的AI對(duì)話語(yǔ)音的回調(diào)委托
    /// </summary>
    /// <param name="voiceDatas">語(yǔ)音數(shù)據(jù)</param>
    public delegate void UReceivesAI_DialogueCallback(byte[] voiceDatas);
    • 調(diào)用的時(shí)候我們默認(rèn)發(fā)送Unity的日志委托,我們封裝了InitDLL方法,然后回調(diào)參數(shù)可以自行拓展,但是要對(duì)應(yīng)C++接口一起修改。
[MonoPInvokeCallback(typeof(void))]
    /// <summary>
    /// 輸出日志
    /// </summary>
    /// <param name="level">等級(jí)</param>
    /// <param name="msg">消息</param>
    static void UnityLog(LogLevel level, string msg)
    {
        msg = $"Unity回調(diào)收到C++輸出日志:{msg}";
        if (level == LogLevel.Info)
        {
            Debug.Log(msg);
        }
        else if (level == LogLevel.Warn)
        {
            Debug.LogWarning(msg);
        }
        else
        {
            Debug.LogError(msg);
        }
    }

public static void InitDLL(UReceivesAI_DialogueCallback UDialogueCallback)
    {
        /*int init = Init(
            Marshal.GetFunctionPointerForDelegate((Delegate)(ULogCallback)UnityLog),
            Marshal.GetFunctionPointerForDelegate((Delegate)UDialogueCallback)
            );*/

        int init = Init(
            UnityLog//這個(gè)方法回調(diào)基本不變,不做參數(shù)
            ,UDialogueCallback
            );
    }

注意事項(xiàng):

這里要注意個(gè)問(wèn)題,在使用DLL交互時(shí)沒(méi)有問(wèn)題,但是用源碼交互時(shí)會(huì)出現(xiàn)報(bào)錯(cuò):NotSupportedException: To marshal a managed method, please add an attribute named ‘MonoPInvokeCallback’ to the method definition. The method we’re attempting to marshal is…,查了下資料發(fā)現(xiàn)需要在傳遞的委托函數(shù)上加上[MonoPInvokeCallback(typeof(…))],里面的類型我目前填void,或者只有一個(gè)函數(shù)參數(shù)的情況下填那個(gè)參數(shù)的類型。

參考:
unity c++,Unity,unity,c語(yǔ)言,c++,c#

  • 定義了給C++發(fā)送語(yǔ)音數(shù)據(jù)的接口,以下接口封裝都比較簡(jiǎn)單,不做過(guò)多介紹
 [DllImport("__Internal")]
    public static extern void ReceivingMicrophoneSpeech(byte[] voiceDatas);
  • 定義了給C++發(fā)送文本測(cè)試的接口
[DllImport("__Internal")]
    public static extern void TEST_Call(string msg);

2.創(chuàng)建C/C++的動(dòng)態(tài)鏈接庫(kù)工程

由于之前交互C++DLL,創(chuàng)建過(guò)動(dòng)態(tài)鏈接庫(kù)工程,所以接下來(lái)Unity中的C++代碼都從鏈接庫(kù)工程里拷貝過(guò)去(后來(lái)NativeCode我改名為CInterface),關(guān)于如何新建鏈接庫(kù)工程,可以參考文末鏈接:Unity 之 C#與C++/C交互指針函數(shù)指針結(jié)構(gòu)體交互
unity c++,Unity,unity,c語(yǔ)言,c++,c#

3.C++層對(duì)應(yīng)C#層定義接口

使用 IL2CPP 腳本后端時(shí),可將 C++ (.cpp) 代碼文件直接添加到 Unity 項(xiàng)目中。這些 C++ 文件將充當(dāng) Plugin Inspector 中的插件。如果將 C++ 文件配置為與 Windows 播放器兼容,則 Unity 會(huì)將這些文件與從托管程序集生成的 C++ 代碼一起編譯。單擊 .cpp 文件,然后在 Inspector 窗口的 Platform settings 部分中選擇平臺(tái)設(shè)置。
unity c++,Unity,unity,c語(yǔ)言,c++,c#

在C#層定義了交互接口后,同時(shí)也要定義C/C++端的對(duì)應(yīng)數(shù)據(jù)結(jié)構(gòu),要嚴(yán)格的和C#的定義一一對(duì)應(yīng),可以參考文末鏈接:C#與C++之間類型的對(duì)應(yīng)
CInterface.h

#ifndef __NativeCode_H__
#define __NativeCode_H__
//#ifndef EXPORT_DLL
//#define EXPORT_DLL  __declspec(dllexport) //導(dǎo)出dll聲明
//#endif

enum class LogLevel {
	Info,
	Warn,
	Error
};


//定義回調(diào)函數(shù)指針
typedef void(__stdcall* ULogCallback)(LogLevel level ,const char*);//Unity日志輸出函數(shù)
typedef void(__stdcall* UReceivesAI_DialogueCallback)(unsigned char voiceDatas[]);//Unity需要播放的AI對(duì)話函數(shù)


extern "C" {

	int Init(ULogCallback logCallback ,UReceivesAI_DialogueCallback diaogueCallback);//初始化注冊(cè)Unity回調(diào)函數(shù)

	void ReceivingMicrophoneSpeech(unsigned char voiceDatas[]);
	
	void TEST_Call(char* char_Str);//測(cè)試方法
}

#endif//__NativeCode_H__

CInterface.cpp

//#include "pch.h"
#include "CInterface.h"

ULogCallback ULog;
UReceivesAI_DialogueCallback UReceivesAI_Dialogue;

extern "C" {
	int Init(ULogCallback logCallback ,UReceivesAI_DialogueCallback diaogueCallback)
	{
		ULog = logCallback;
		UReceivesAI_Dialogue = diaogueCallback;

		//TODO:logCallback支持中文字符
		ULog(LogLevel::Info, "12345");
		ULog(LogLevel::Info, "abc");
		

		return 0;
	}

	void TEST_Call(char * char_Str) {
		ULog(LogLevel::Info, char_Str);
	}

	void ReceivingMicrophoneSpeech(unsigned char voiceDatas[]) {
		ULog(LogLevel::Info, "Call ReceivingMicrophoneSpeech");
	}
}

注意事項(xiàng):

打包的時(shí)候,編譯cpp時(shí)會(huì)出現(xiàn)以下報(bào)錯(cuò):

  • CInterface.h出現(xiàn)不支持__declspec,所以DLL交互時(shí)留下__declspec(dllexport) 關(guān)鍵字都去掉
  • CInterface.cpp中的DLL交互留下頭文件#include "pch.h"找不到,直接注釋掉即可
  • 所有的C++接口都需要extern “C”
  • 集成cpp源碼到Unity交互需要在ProjectSetting-Player-OtherSetting-Configuration-ScriptingBackend選擇IL2CPP

總結(jié)

使用CPP源碼可以在Unity引擎打包后編譯成對(duì)應(yīng)平臺(tái)的代碼,前提是腳本后端選擇IL2CPP,但是在編輯器模式這套方法是用不了的,所以我打算后期在編輯器模式下使用dll交互,加個(gè)平臺(tái)判斷,等后期流程上成熟后將繼續(xù)總結(jié)下。


參考資料

Windows 播放器:適用于 IL2CPP 的 C++ 源代碼插件

Unity 之 C#與C++/C交互指針函數(shù)指針結(jié)構(gòu)體交互

C#與C++之間類型的對(duì)應(yīng)文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-800993.html

到了這里,關(guān)于Unity開(kāi)發(fā)進(jìn)行C、C++源碼交互,支持跨平臺(tái)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包