0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Rust在虚幻引擎5中的使用

jf_wN0SrCdH 来源:Rust语言中文社区 作者:Rust语言中文社区 2022-12-21 11:05 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

前言

前段时间,研究了一套 Rust 接入 Maya Plugin 的玩法,主要原理还是使用 C ABI 去交互。那我想着 UE 是使用 C++ 写的,肯定也可以使用 C ABI 去交互,如果可以的话在 UE 中就可以使用 Rust 代码去跑,甚至还可以使用 Rust Crates,免得使用 C++ 去写关于数据库操作、加密操作等容易引发安全漏洞的代码。所以我在昨天开始了这个计划,使用了 Rust 的 html2md 的库在 UE 中使用,效果图如下。

开工

这个案例就是在 UE 中实现 html2md,虽然实际效果可能没卵用,主要目的还是带大家跑下这套流程。

我们要实现的功能就是在 Level 放置一个 Text Render
游戏开始阶段,这个
Text Render 就会拉取 Rust 官网页面,并将它转为 Markdown 格式展示在游戏中。

创建 UE 项目

我这里使用的版本是 5.0.1,大家使用 4.x 也是可以的。
我们创建一个
第三人称游戏 C++项目,命名为Html2mdExample
45f90370-807e-11ed-8abf-dac502259ad0.png

创建 UE 插件

我们将 Html2md 的功能封装成一个插件,这样就可以在各个项目中去使用它。

我们创建一个空白插件,插件名随意,我这边就叫 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,并修改它的颜色、旋转、缩放等属性。

#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);

}

创建 Rust 项目

我们 Rust 项目要创建在 UE 插件项目目录下。找到插件源码目录,与 C++ 源码同级运行以下命令创建项目。

cargo new --lib html2md-dylib

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

Cargo.toml

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

# 将库打包成动态链接库
[lib]
crate-type = ["dylib"]
name = "html2md_dylib"

[dependencies]
# 用于 HTML 转为 Markdown
html2md = "0.2.14"
# 用于进行 HTTP 请求
reqwest = { version = "0.11.13", features = ["blocking"] }

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

src/md_loader.rs

在这里我们实现一个从 HTTP 请求拉取 HTML 并转为 Markdown 的实现。

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

将函数导出,这样在动态链接库中就可以调用这个函数了。

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

我们需要使用到构建脚本来帮我们生成 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 认到我们的动态链接库。相关文档

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");
}
}
}

构建 Rust 项目

我们先运行构建命令

cargo build --release

然后将 html2md_dylib.dll 复制一份到 插件目录/Binaries/Win64/html2md_dylib.dll

这一步可以使用脚本去完成,我这边就不写了。

连接 Rust & UE

因为我们 Rust 项目目录名不符合 UE 的规范,所以我们要将 html2md-dylib 目录更改为 Html2mdDyLibhtml2md-dylib.build.cs 也需要更为 Html2mdDyLib.build.cs

将动态链接库添加到依赖

我们编辑 html2md.build.cs,也就是插件的构建脚本。在 PublicDependencyModuleNames 添加 Html2mdDyLibProjects

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

插件加载动态链接库

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

插件加载动态链接库

如果与本案例命名不同,记得替换代码中的路径

// 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 调用 Rust

终于来到了最后要实现的目标,我们将调用 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();

// 在这里调用 Rust 接口
const char* text = "https://www.rust-lang.org/";
FString result = FString(load_md_from_url_ffi(text));
Text->SetText(FText::FromString(result)); // 设置 Text 内容

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

运行游戏!我们会发现 Text Render 展示了 Rust 官网的内容。

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

总结

通过这次案例,我发现 Rust 可以在 UE 中做很多事情,我只是使用了 html2md 库作为案例来演示,大家感兴趣的话也可以去使用 wsmysql 等,关于网络通讯、数据库、甚至可以在 Rust 中实现游戏功能的算法、状态机等接入到虚幻引擎中使用。
能用少量并安全的代码去编写这些复杂的功能,何乐而不为呢?

用洛佳大佬的话来说:“如果996了一整天,每个开发者都无法避免疲惫的自己忘记释放指针或者释放了两次,很有可能一个漏洞就埋下来了。

能用编程语言理论检查出来漏洞还是好事情。这也不意味着我可以做一个强行检查 C++ 的编译器来达到一样的效果,因为这种理论要求整个语言要重新设计,Rust 就是重新设计的结果”


审核编辑 :李倩


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 数据库
    +关注

    关注

    7

    文章

    3993

    浏览量

    67715
  • 编程语言
    +关注

    关注

    10

    文章

    1959

    浏览量

    38888
  • Rust
    +关注

    关注

    1

    文章

    240

    浏览量

    7472

原文标题:Rust 在虚幻引擎 5 中的使用

文章出处:【微信号:Rust语言中文社区,微信公众号:Rust语言中文社区】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    2025开放原子开发者大会旋武开源社区Rust分论坛成功举办

    11月22日,2025开放原子开发者大会——旋武开源社区Rust分论坛北京顺利召开。论坛以“共建中国Rust生态”为核心主题,汇聚京东、华为、vivo、阿里、毛豆教育、DORA社区及南京大学等企业与学术机构技术专家,及众多
    的头像 发表于 11-27 14:55 304次阅读

    硬件加密引擎保障数据安全方面有哪些优势呢?

    )。 算法可配置性:部分型号支持算法动态切换,例如在跨境物联网场景,设备可根据接入网络的区域要求,通过硬件指令切换至当地合规算法(如在国内用 SM4,欧美用 AES),无需修改软件架构。 5. 简化上层
    发表于 11-17 06:47

    2025开放原子开发者大会旋武社区Rust分论坛即将启幕

    在数字化转型持续深化、系统安全与性能需求愈发迫切的当下,Rust凭借强大的内存安全、高并发性能和卓越的开发者体验,正成为重塑软件开发疆界的关键力量,更是构建下一代可靠高效基础设施的核心选择。11月
    的头像 发表于 11-13 10:00 333次阅读

    RusT-Thread:基于Rust面向资源受限嵌入式设备的操作系统的实践 | 技术集结

    RT-Thread为基础,使用Rust语言重构其内核,形成了全新的RusT-Thread系统。系统采用模块化架构,涵盖内核服务、进程调度、内存管理、线程通信与时钟控制等核心
    的头像 发表于 11-07 17:37 6460次阅读
    <b class='flag-5'>RusT</b>-Thread:基于<b class='flag-5'>Rust</b>面向资源受限嵌入式设备的操作系统的实践 | 技术集结

    光庭信息亮相2025上海虚幻引擎技术开放日

    专家与前沿科技企业,共同解锁虚幻引擎(UE)技术的未来边界。光庭信息智能座舱事业部技术总监陈治汽车峰会专场发表《虚幻引擎助力3D智能座舱从
    的头像 发表于 08-28 15:30 984次阅读

    光庭信息邀您相约2025上海虚幻引擎技术开放日

    8月22日至23日,备受瞩目的2025上海虚幻引擎技术开放日(Unreal Fest Shanghai 2025)将在上海宝华万豪酒店隆重举行。Epic Games创始人兼CEO Tim
    的头像 发表于 08-21 16:10 993次阅读

    RT-Thread 遇上 Rust:安全内核 RusT-Thread 的诞生

    大家好,我们是中国科学技术大学操作系统原理与设计(H)课oooooS小组。这个项目是我们的课程大作业:参考RT-Thread架构,使用Rust搭建一个原生的嵌入式操作系统内核。初识Rust是因为xk
    的头像 发表于 08-02 11:03 3193次阅读
    RT-Thread 遇上 <b class='flag-5'>Rust</b>:安全内核 <b class='flag-5'>RusT</b>-Thread 的诞生

    信而泰×DeepSeek:AI推理引擎驱动网络智能诊断迈向 “自愈”时代

    定位到出口路由器端口存在大量物理层错误计数,更换光模块后,故障立即排除,业务完全恢复正常。此案例充分验证了AI推理引擎复杂网络故障诊断精准定位根因、大幅提升排障效率的核心价值。
    发表于 07-16 15:29

    请问OpenVINO™ 是否支持 Rust 绑定?

    无法确定OpenVINO™是否支持 Rust 绑定。
    发表于 06-25 07:45

    基于SEGGER的Ozone调试器和J-Trace工具跟踪Ferrocene的Rust应用

    2025年3月,SEGGER和Ferrous Systems合作,确保使用Ferrous Systems的Ferrocene工具链编译的Rust应用程序可以通过SEGGER的J-Trace工具实时下载分析。
    的头像 发表于 03-14 11:27 1262次阅读

    vivo打造最具影响力Rust赛事,点亮基础软件事业的“蓝河时代”

    蓝河操作系统创新赛,看见中国Rust生态的汇聚与发展
    的头像 发表于 02-27 15:08 2157次阅读
    vivo打造最具影响力<b class='flag-5'>Rust</b>赛事,点亮基础软件事业的“蓝河时代”

    二维影像扫描引擎可以应用于哪些行业?

    二维影像扫描引擎,作为自动识别技术的重要组成部分,以其高效、精准的扫描能力,多个行业领域内展现出广泛的应用前景。这些引擎不仅提升了数据采集的效率和准确性,还推动了各行业的数字化转型进程。零售业:
    的头像 发表于 02-14 14:59 860次阅读
    二维影像扫描<b class='flag-5'>引擎</b>可以应用于哪些行业?

    JavaScript与Rust和WebAssembly集成

    偶然一次机会,接触了Rust的代码。当时想给团队小伙伴做演示,发现自己并不能在移动端按照文档生成演示demo。我就想,要是Rust代码能转化成JavaScript就好了。结果一搜,还真有。
    的头像 发表于 01-24 15:43 795次阅读
    JavaScript与<b class='flag-5'>Rust</b>和WebAssembly集成

    容器引擎是什么意思

    容器引擎是一种虚拟化技术,它利用操作系统的内核来实现对应用程序的隔离和打包,使得应用程序可以不同的环境运行而无需修改代码。主机推荐小编为您整理发布容器引擎是什么意思,以下是关于容器
    的头像 发表于 01-09 09:49 710次阅读

    常见的容器云服务引擎有哪些?

    常见的容器云服务引擎有哪些?云服务引擎涵盖数据库、数据存储、数据处理、数据分析、容器云、机器学习及数据集成等多个领域,提供一站式解决方案。云服务引擎是云计算领域的重要组成部分,它们提供了各种服务来帮助用户构建、部署和管理应用程序
    的头像 发表于 01-07 09:49 674次阅读