0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Rust在虛幻引擎5中的使用

jf_wN0SrCdH ? 來源:Rust語言中文社區(qū) ? 作者:Rust語言中文社區(qū) ? 2022-12-21 11:05 ? 次閱讀

前言

前段時間,研究了一套 Rust 接入 Maya Plugin 的玩法,主要原理還是使用 C ABI 去交互。那我想著 UE 是使用 C++ 寫的,肯定也可以使用 C ABI 去交互,如果可以的話在 UE 中就可以使用 Rust 代碼去跑,甚至還可以使用 Rust Crates,免得使用 C++ 去寫關(guān)于數(shù)據(jù)庫操作、加密操作等容易引發(fā)安全漏洞的代碼。所以我在昨天開始了這個計劃,使用了 Rust 的 html2md 的庫在 UE 中使用,效果圖如下。

開工

這個案例就是在 UE 中實現(xiàn) html2md,雖然實際效果可能沒卵用,主要目的還是帶大家跑下這套流程。

我們要實現(xiàn)的功能就是在 Level 放置一個 Text Render。
游戲開始階段,這個
Text Render 就會拉取 Rust 官網(wǎng)頁面,并將它轉(zhuǎn)為 Markdown 格式展示在游戲中。

創(chuàng)建 UE 項目

我這里使用的版本是 5.0.1,大家使用 4.x 也是可以的。
我們創(chuàng)建一個
第三人稱游戲 C++項目,命名為Html2mdExample。
45f90370-807e-11ed-8abf-dac502259ad0.png

創(chuàng)建 UE 插件

我們將 Html2md 的功能封裝成一個插件,這樣就可以在各個項目中去使用它。

我們創(chuàng)建一個空白插件,插件名隨意,我這邊就叫 html2md。

4619586e-807e-11ed-8abf-dac502259ad0.png

在插件中添加 Text Render

我們要在插件中添加一個 Actor,作為處理 HTTP 請求,并渲染 MarkdownText Render

一定要選擇添加到插件中,而不是項目中。

4638d2fc-807e-11ed-8abf-dac502259ad0.png

TextRender.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Runtime/Engine/Classes/Components/TextRenderComponent.h"
#include "TextRender.generated.h"

UCLASS()
class HTML2MD_API ATextRender : public AActor
{
GENERATED_BODY()

UPROPERTY(VisibleAnywhere)
UTextRenderComponent* Text;

public:
ATextRender();

protected:
virtual void BeginPlay() override;

public:
virtual void Tick(float DeltaTime) override;

};

TextRender.cpp

簡單寫一寫代碼,添加一個 UTextRenderComponent,并修改它的顏色、旋轉(zhuǎn)、縮放等屬性。

#include "TextRender.h"

ATextRender::ATextRender()
{
PrimaryActorTick.bCanEverTick = true;

Text = CreateDefaultSubobject<UTextRenderComponent>(TEXT("Text"));
Text->SetupAttachment(RootComponent);
}

void ATextRender::BeginPlay()
{
Super::BeginPlay();

Text->SetRelativeRotation(FRotator(90.f, 180.f, 0.f));
Text->SetTextRenderColor(FColor(0, 255, 225));
Text->SetRelativeScale3D(FVector(2.f, 2.f, 2.f));
}

void ATextRender::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);

}

創(chuàng)建 Rust 項目

我們 Rust 項目要創(chuàng)建在 UE 插件項目目錄下。找到插件源碼目錄,與 C++ 源碼同級運行以下命令創(chuàng)建項目。

cargo new --lib html2md-dylib

464fe384-807e-11ed-8abf-dac502259ad0.png

Cargo.toml

[package]
name = "html2md-dylib"
version = "0.1.0"
edition = "2021"

# 將庫打包成動態(tài)鏈接庫
[lib]
crate-type = ["dylib"]
name = "html2md_dylib"

[dependencies]
# 用于 HTML 轉(zhuǎn)為 Markdown
html2md = "0.2.14"
# 用于進行 HTTP 請求
reqwest = { version = "0.11.13", features = ["blocking"] }

[build-dependencies]
# 用于生成 C 頭文件
cbindgen = "0.24.3"

src/md_loader.rs

在這里我們實現(xiàn)一個從 HTTP 請求拉取 HTML 并轉(zhuǎn)為 Markdown 的實現(xiàn)。

pub struct MDLoader;

impl MDLoader {
pub fn load_md_from_url(url: &str) -> String {
let body = if let Ok(res) = reqwest::get(url) {
if let Ok(text) = res.text() {
text
} else {
return format!("Failed get {} text", url);
}
} else {
return format!("Failed get {} body", url);
};

html2md::parse_html(&body)
}
}

src/lib.rs

將函數(shù)導出,這樣在動態(tài)鏈接庫中就可以調(diào)用這個函數(shù)了。

use std::{c_char, CStr, CString};

mod md_loader;

#[no_mangle]
pub extern "C" fn load_md_from_url_ffi(url: *const c_char) -> *const c_char {
let url = unsafe { CStr::from_ptr(url) };
let res = md_loader::load_md_from_url(&url.to_string_lossy());

CString::new(res).unwrap().into_raw()
}

build.rs

我們需要使用到構(gòu)建腳本來幫我們生成 C 頭文件,我們將在 C++ 代碼中使用它。

頭文件生成到 include/UEHtml2md.h

extern crate cbindgen;

use std::env;

fn main() {
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let mut config: cbindgen::Config = Default::default();
config.language = cbindgen::Cxx;

cbindgen::generate_with_config(&crate_dir, config)
.expect("Unable to generate bindings")
.write_to_file("include/UEHtml2md.h");
}

html2md-dylib.build.cs

我們要添加一個 Rust 項目名.build.cs,讓 UE 認到我們的動態(tài)鏈接庫。相關(guān)文檔

using System;
using System.IO;
using UnrealBuildTool;
public class Html2mdDyLib : ModuleRules
{
public Html2mdDyLib(ReadOnlyTargetRules Target) : base(Target)
{
Type = ModuleType.External;
if (Target.Platform == UnrealTargetPlatform.Win64)
{
// 添加頭文件目錄
PublicIncludePaths.Add(Path.Combine(ModuleDirectory, "include"));
// 添加 .lib
PublicAdditionalLibraries.Add(Path.Combine(ModuleDirectory, "target", "release", "html2md_dylib.dll.lib"));
// 添加 .dll
PublicDelayLoadDLLs.Add("html2md_dylib.dll");
// 我們需要將 .dll 文件復制到這邊
RuntimeDependencies.Add("$(PluginDir)/Binaries/Win64/html2md_dylib.dll");
}
}
}

構(gòu)建 Rust 項目

我們先運行構(gòu)建命令

cargo build --release

然后將 html2md_dylib.dll 復制一份到 插件目錄/Binaries/Win64/html2md_dylib.dll。

這一步可以使用腳本去完成,我這邊就不寫了。

連接 Rust & UE

因為我們 Rust 項目目錄名不符合 UE 的規(guī)范,所以我們要將 html2md-dylib 目錄更改為 Html2mdDyLib,html2md-dylib.build.cs 也需要更為 Html2mdDyLib.build.cs

將動態(tài)鏈接庫添加到依賴

我們編輯 html2md.build.cs,也就是插件的構(gòu)建腳本。在 PublicDependencyModuleNames 添加 Html2mdDyLibProjects

PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
"Html2mdDyLib",
"Projects",
// ... add other public dependencies that you statically link with here ...
}
);

插件加載動態(tài)鏈接庫

html2md.h

插件頭文件中聲明 DLL 句柄

// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"

class Fhtml2mdModule : public IModuleInterface
{
void* Html2mdLibraryHandle;

public:

/** IModuleInterface implementation */
virtual void StartupModule() override;
virtual void ShutdownModule() override;
};

html2md.cpp

插件加載動態(tài)鏈接庫

如果與本案例命名不同,記得替換代碼中的路徑

// Copyright Epic Games, Inc. All Rights Reserved.

#include "html2md.h"
#include "Core.h"
#include "Modules/ModuleManager.h"
#include "Interfaces/IPluginManager.h"

#define LOCTEXT_NAMESPACE "Fhtml2mdModule"

void Fhtml2mdModule::StartupModule()
{
FString BaseDir = IPluginManager::Get().FindPlugin("html2md")->GetBaseDir();
FString Html2mdLibraryPath = FPaths::Combine(*BaseDir, TEXT("Binaries/Win64/html2md_dylib.dll"));
Html2mdLibraryHandle = !Html2mdLibraryPath.IsEmpty() ? FPlatformProcess::GetDllHandle(*Html2mdLibraryPath) : nullptr;

if (Html2mdLibraryHandle == nullptr)
{
FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("ThirdPartyLibraryError", "Failed to load Html2mdLibrary"));
}
}

void Fhtml2mdModule::ShutdownModule()
{
FPlatformProcess::FreeDllHandle(Html2mdLibraryHandle);
Html2mdLibraryHandle = nullptr;
}

#undef LOCTEXT_NAMESPACE

IMPLEMENT_MODULE(Fhtml2mdModule, html2md)

Text Render 調(diào)用 Rust

終于來到了最后要實現(xiàn)的目標,我們將調(diào)用 Rust 接口,將返回值顯示在 Text Render 中。

TextRender.cpp

#include "TextRender.h"
#include "Html2mdDyLib/include/UEHtml2md.h"

ATextRender::ATextRender()
{
PrimaryActorTick.bCanEverTick = true;

Text = CreateDefaultSubobject<UTextRenderComponent>(TEXT("Text"));
Text->SetupAttachment(RootComponent);
}

void ATextRender::BeginPlay()
{
Super::BeginPlay();

// 在這里調(diào)用 Rust 接口
const char* text = "https://www.rust-lang.org/";
FString result = FString(load_md_from_url_ffi(text));
Text->SetText(FText::FromString(result)); // 設(shè)置 Text 內(nèi)容

Text->SetRelativeRotation(FRotator(90.f, 180.f, 0.f));
Text->SetTextRenderColor(FColor(0, 255, 225));
Text->SetRelativeScale3D(FVector(2.f, 2.f, 2.f));
}
void ATextRender::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);

}

編譯項目

Visual Studio虛幻引擎 中編譯都可以。

在 UE 中查看效果

我們將 TextRender 拖入場景。

465ca560-807e-11ed-8abf-dac502259ad0.png

運行游戲!我們會發(fā)現(xiàn) Text Render 展示了 Rust 官網(wǎng)的內(nèi)容。

46719b64-807e-11ed-8abf-dac502259ad0.png

總結(jié)

通過這次案例,我發(fā)現(xiàn) Rust 可以在 UE 中做很多事情,我只是使用了 html2md 庫作為案例來演示,大家感興趣的話也可以去使用 ws,mysql 等,關(guān)于網(wǎng)絡(luò)通訊、數(shù)據(jù)庫、甚至可以在 Rust 中實現(xiàn)游戲功能的算法、狀態(tài)機等接入到虛幻引擎中使用。
能用少量并安全的代碼去編寫這些復雜的功能,何樂而不為呢?

用洛佳大佬的話來說:“如果996了一整天,每個開發(fā)者都無法避免疲憊的自己忘記釋放指針或者釋放了兩次,很有可能一個漏洞就埋下來了。

能用編程語言理論檢查出來漏洞還是好事情。這也不意味著我可以做一個強行檢查 C++ 的編譯器來達到一樣的效果,因為這種理論要求整個語言要重新設(shè)計,Rust 就是重新設(shè)計的結(jié)果”


審核編輯 :李倩


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 數(shù)據(jù)庫
    +關(guān)注

    關(guān)注

    7

    文章

    3737

    瀏覽量

    64173
  • 編程語言
    +關(guān)注

    關(guān)注

    10

    文章

    1921

    瀏覽量

    34505
  • Rust
    +關(guān)注

    關(guān)注

    1

    文章

    228

    瀏覽量

    6526

原文標題:Rust 在虛幻引擎 5 中的使用

文章出處:【微信號:Rust語言中文社區(qū),微信公眾號:Rust語言中文社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦

    如何用Rust編寫一個ChatGPT桌面應用(保姆級教程)

    用IDEA開發(fā)的java仔) 安裝 Rust 語言工具鏈:首先,請確保你已安裝了 Rust 編程語言工具鏈,包括 Rust 編譯器 (rustc) 和包管理工具 (cargo)??梢酝ㄟ^訪問
    的頭像 發(fā)表于 09-25 11:19 ?227次閱讀
    如何用<b class='flag-5'>Rust</b>編寫一個ChatGPT桌面應用(保姆級教程)

    未來嵌入式系統(tǒng)的黃金搭檔 MCX N947遇上Rust

    基于 Rust 的安全性和性能引入了 Rust。 Rust 有很多優(yōu)勢,內(nèi)存安全、并發(fā)安全、生態(tài)系統(tǒng)、包管理與構(gòu)建管理,同時也有與 C/C++ 相同等級的性能。Rust 通過強化所有權(quán)
    的頭像 發(fā)表于 07-25 09:14 ?1201次閱讀
    未來嵌入式系統(tǒng)的黃金搭檔 MCX N947遇上<b class='flag-5'>Rust</b>

    Vector和HighTec推出基于Rust和AUTOSAR Classic實現(xiàn)安全應用的解決方案

    Vector和HighTec兩家公司成功展示了Rust應用程序與基于C語言的AUTOSAR Classic基礎(chǔ)軟件的集成,這在行業(yè)內(nèi)還屬首次。這樣一來,Rust及其優(yōu)勢可以被應用在有最高功能安全要求的汽車ECU
    的頭像 發(fā)表于 07-17 14:42 ?566次閱讀
    Vector和HighTec推出基于<b class='flag-5'>Rust</b>和AUTOSAR Classic實現(xiàn)安全應用的解決方案

    Aurix Tc375Lk上使用Rust編程語言可以嗎?

    您好,如果我想在 Aurix Tc375Lk 上使用 Rust 編程語言,可以嗎?如果是,鏈接 rust 編譯器 ADS 和 freetoolchain 的步驟是什么?你有 ADS 或 freetoolchian
    發(fā)表于 05-17 13:42

    [鴻蒙]OpenHarmony4.0的Rust開發(fā)

    背景 Rust 是一門靜態(tài)強類型語言,具有更安全的內(nèi)存管理、更好的運行性能、原生支持多線程開發(fā)等優(yōu)勢。Rust 官方也使用 Cargo 工具來專門為 Rust 代碼創(chuàng)建工程和構(gòu)建編譯
    的頭像 發(fā)表于 02-26 17:28 ?740次閱讀
    [鴻蒙]OpenHarmony4.0的<b class='flag-5'>Rust</b>開發(fā)

    谷歌捐款100萬美元給Rust基金會,以增強C++與Rust的交互性

    如今,谷歌多項核心業(yè)務仍以 C++為主要編程語言,雖然無法直接使用Rust替代現(xiàn)有的C++程序,但谷歌依然選擇支持Rust基金會的“Interop Initiative”計劃,幫助那些選用C++的機構(gòu)更為順暢地過渡至Rust上。
    的頭像 發(fā)表于 02-19 15:41 ?539次閱讀

    一次Rust重寫基礎(chǔ)軟件的實踐

    Rust 語言。本文的主要目的是通過記錄此次轉(zhuǎn)化過程遇到的比較常見且有意思的問題以及解決此問題的方法與大家一起做相關(guān)的技術(shù)交流和討論。
    的頭像 發(fā)表于 01-25 11:21 ?545次閱讀

    如何利用 S5PV210 的 G2D 引擎

    大佬們好! 小弟最近在學習 S5PV210 的時候遇見了一些關(guān)于 G2D 引擎的疑惑,有沒有大佬好心幫幫忙,小弟在這里先謝過了 ! 我嘗試裸機環(huán)境下面配置 S5PV210 的 G
    發(fā)表于 01-04 21:56

    從Rustup出發(fā)看Rust編譯生態(tài)

    從Rustup出發(fā)看Rust編譯生態(tài) 1. Rust和LLVM的關(guān)系是怎樣的? 2. Rustuptargets是什么,為什么可以安裝多個? 3. Rust
    的頭像 發(fā)表于 01-02 11:00 ?448次閱讀

    如何在同步的 Rust 方法調(diào)用異步代碼 | Tokio 使用的幾點教訓

    同步的 Rust 方法調(diào)用異步代碼經(jīng)常會導致一些問題,特別是對于不熟悉異步 Rust runtime 底層原理的初學者。
    的頭像 發(fā)表于 12-24 16:23 ?1182次閱讀

    索尼黑科技賦能虛擬制片 引領(lǐng)科技發(fā)展

    日前,2023虛幻引擎技術(shù)開放日在上海舉行。虛幻引擎開放日是行業(yè)難得的盛會,眾多精彩主旨演講與技術(shù)分享更是囊括了前沿的虛幻
    的頭像 發(fā)表于 12-08 13:42 ?496次閱讀

    【愛芯派 Pro 開發(fā)板試用體驗】用rust寫模型runner

    ,能夠完成模型加載到執(zhí)行的全部推理任務。這次主要以獲取版本為例,介紹一下如何用rust接入以及相關(guān)API,完整的runner待后期完善,本例僅僅涉及三個API,AX_ENGINE_Init
    發(fā)表于 12-02 22:00

    虛幻引擎技術(shù)的再開發(fā)助力更高質(zhì)的虛擬制片

    Unreal Fest Shanghai 2023 虛幻引擎技術(shù)開放日將于2023年11月30日(周四)- 12月1日(周五)在上海前灘香格里拉酒店舉辦!
    的頭像 發(fā)表于 11-29 10:15 ?657次閱讀

    如何編寫高性能的Rust代碼

    為了最大限度地提高Rust應用程序的性能,你需要了解支持代碼的底層硬件架構(gòu),如何優(yōu)化算法和數(shù)據(jù)結(jié)構(gòu),以及如何對代碼進行配置和基準測試。本文中,我們將簡要介紹這些主題,希望能更好地理解如何編寫高性能的Rust代碼。
    的頭像 發(fā)表于 11-03 14:28 ?749次閱讀
    如何編寫高性能的<b class='flag-5'>Rust</b>代碼

    使用Rust優(yōu)化Python性能

    在數(shù)據(jù)分析領(lǐng)域Python無疑是最流行的編程語言,但是Python有一個硬傷就是作為一個編譯語言性能上有些微的欠缺。而同樣最流行的語言Rust則在性能方面表現(xiàn)優(yōu)秀。本文我們一起學習一個優(yōu)化項目的實踐,對一個數(shù)據(jù)分析程序,改為Rust
    的頭像 發(fā)表于 11-01 15:59 ?797次閱讀
    使用<b class='flag-5'>Rust</b>優(yōu)化Python性能