自由学习记录(161)

image placeimage placeimage placeimage placeimage placeimage placexxx(xxxxx) 这种形式通常就是 函数式宏 ,也叫 带参数宏

对象式宏:#define true false

函数式宏:看括号
C++
#define MAX(a, b) ((a) > (b) ? (a) : (b))

Rider / Visual Studio / clangd 往往会在悬停时告诉你它是 macro。

Type Deduction (类型推导)

复制代码
MyStruct* pMS = malloc(sizeof(MyStruct));

这里用 malloc 申请了一块原始内存,大小够放一个 MyStruct

注意这里是 C 风格分配,应该配套 free,而不是 delete

关键点有两个:

  1. 你确实每次都新追加了 image place

    • 代码里 appendAnchorParagraph() 每次都会 body.appendChild(paragraph)
    • 所以截图里后面多个 image place 说明"追加文本"这一步是成功的。
  2. 但图片 paste 时,CSDN 并没有按"你刚选中的最新那一段"来替换

    • 你现在只是用原生 Range + Selection 去选中文本,然后直接对 body.dispatchEvent(pasteEvent) 派发 paste。
    • CSDN 这个编辑器本质上是 CKEditor,它内部通常维护一套自己的 selection/bookmark/focus 状态,不一定完全跟随你手工塞进去的浏览器原生选区
    • 所以会出现这种现象:页面上看起来新文本加到了后面,但编辑器内部真正"认定的插入点"还停留在第一次成功 paste 的那个位置,于是后续图片仍然插到第一次的区域。

F12 控制台默认控制的是当前页面的运行环境;单独元素只是这个环境里的一个对象,不是一个独立控制台。

复制代码
CKEDITOR exists: true:说明全局 CKEDITOR 存在
instances: ['editor']:说明当前至少有一个实例,名字是 editor
has focus: function:可以用 editor.focus()
has getSelection: function:可以用 CKEditor 自己的选区 API,而不必依赖原生 document.getSelection()
has createRange: function:可以用 CKEditor 自己的 range,而不必依赖原生 document.createRange()
has editable: function:可以拿到编辑器真正的可编辑区域
has insertHtml: function:可以用编辑器原生方式插入 image place

当前这段:

  • 追加文本:appendAnchorParagraph()
  • 选中文本:selectAnchorParagraphText()
  • 派发粘贴:body.dispatchEvent(pasteEvent)

这套流程只改了浏览器 DOM 和原生选区,但没有确保 CKEditor 内部选区同步切到最新的 image place

现在的逻辑是直接拿"刚 append 出来的那个段落节点引用"继续往下用,不是从 body 顶部往下扫,也不是从底部往上扫。

"粘贴完图片后,默认选中图片"的逻辑,不是你这段扩展代码直接规定的 ,而主要是 CSDN 编辑器 / CKEditor 的图片 widget 机制 在起作用。

Console 是在当前页面的 JS 执行环境里运行代码,而这个环境里可以访问 documentwindow 以及这份文档中的所有 DOM 节点。

div 是 HTML 里的一个非常通用的元素,全称通常理解为 division,就是"分区、区块"。

range.setStart(textNode, 0)

range.setEnd(textNode, textNode.textContent?.length || 0)

不 collapse:是"选中一段"

前者是在创建一个有长度的选区 ,后者是在创建一个没有长度、只有一个插入点的光标位置

range.setStart(textNode, 0)

range.setEnd(textNode, 11)

这表示从 0 到 11 的内容都被选中了。

如果这段文本是 "image place",那就等于整段被高亮选中

这时后续 paste / insert 行为通常会被浏览器或编辑器理解成:

  • 新内容替换这段选中的文本
  • 或在这段选区上执行某种插入逻辑

所以它不是"光标停在后面",而是"这一段内容正处于被选中状态"。

collapse() 的作用就是:

把原本有起点和终点的 range,收缩成同一个位置。

所以 collapse 后,这个 range 不再表示"一段被选中的文本",而表示:

一个插入点 / 光标位置

这就是你图里说的"光标闪在 place 后面"的那个意思。

粘贴图片之后,原 range 基本应该视为"失效"或"语义变了" ,然后你要基于插入后的实际 DOM / 编辑器选区重新定位。

for (const auto &x : data) {

model.update(x);

}

它的一个直接好处就是:

你不需要自己写这种东西:

for (size_t i = 0; i < data.size(); ++i) {

model.update(data[i]);

}

确实少了一类和"索引"有关的错误,例如:

  • i < data.size() 写成 i <= data.size()

  • ij 混用

  • data[i] 写成 data[k]

  • 下标偏移写错,比如 i + 1

因为 append text 这套逻辑根本不是"在当前光标位置插入",而是直接操作 DOM,把节点 append 到编辑区容器末尾 ,所以它天然稳定落在尾部。
在英语语境中, Sun 更多指那个巨大的发热天体;而 Sunshine 象征着"快乐、希望、温暖",形容人时听起来更亲切、更自然。

TUniquePtr 是虚幻引擎(Unreal Engine, UE)中的一个核心概念 。它是 UE 自行实现的智能指针库的一部分,专门用于独占式管理UObject 对象的生命周期。

自动释放 :当 TUniquePtr 超出作用域或被重新赋值时,它所包含的对象会被自动删除并释放内存。
为什么 UE 不直接用 std::unique_ptr
虽然 C++ 标准库中有 std::unique_ptr ,但 UE 开发了自己的版本,原因主要包括:

  • 跨平台兼容性:确保在所有目标平台(PC, 控制台, 移动端)上表现一致。
  • 深度集成 :更好地适配 UE 的内存分配器和容器库(如 TArray , TMap )。

TUniquePtr 与 UObject 的关系
这是最容易混淆的一点:

  • 非 UObject 专用TUniquePtr 主要用于管理原生 C++ 对象 (不带 UCLASS 宏的类)。
  • 不能管理 UObjectUObject 受到 UE 自身的垃圾回收(GC)机制 管理。如果你尝试用 TUniquePtr 包装一个 UObject ,会导致引擎崩溃或引用计数的逻辑冲突。

除了 TUniquePtr ,UE 的 智能指针系统 还包括:

  • TSharedPtr :共享指针,允许多个指针指向同一对象(带引用计数)。
  • TSharedRef :共享引用,类似于 TSharedPtr 但不能为空,安全性更高。
  • TWeakPtr :弱指针,不增加引用计数,用于解决循环引用问题。

UE 官方强烈建议"尽可能优先使用 TSharedRef" ,但这主要是为了提升代码安全性

TSharedRef 永远不能为空 :它在初始化时必须绑定一个有效对象,且没有 IsValid() 方法。如果你尝试给它传空值,程序会直接崩溃(断言失败)。

TSharedPtr 可以为空 :它支持 nullptr ,你可以用它来表示"可能有、也可能没有"的对象。

TWeakObjectPtr :如果你想引用一个 UObject 但不想影响它的回收时机,就必须用 TWeakObjectPtr 。它常用于观察关卡中的 Actor 状态。

It's a "Smart" Observer (Safety)

If you use a Raw Pointer (MyClass* ) to avoid a leak:

If B tries to use that pointer, the game crashes (Use-after-free).

  • TWeakPtr fix: It knows when the object is gone. You call Pin() , it returns nullptr , and your game keeps running.

"加一个空判断"并不能从根上拦住 use-after-free。

裸指针世界里,运行时根本不知道它是不是还合法

Parsing headers for ZMDRenderEditor

ZMDRenderEditor 这个 target 的头文件做解析。

UnrealBuildToolUnrealHeaderTool 这些工具本身是基于 .NET 跑的。

为了避免你电脑本地 .NET 版本不一致导致问题,UE 往往会直接带一套它自己认可的版本。

.NET Framework :这是 .NET 的早期版本,主要且仅能运行在 Windows 系统上。

.NET Core:这是为了实现跨平台而重新设计的开源版本,是现代 .NET 的前身。

.NET (5及以后版本):微软从 2020 年起删除了 "Core" 后缀,将两者合并,现在的 ".NET" 特指这个最新的跨平台通用平台。

C# 依赖 .NET 提供的 CLR(公共语言运行时)和类库来工作。

C# 编写代码,这些代码必须编译成中间语言 (IL)。程序在运行时,由 .NET 的 CLR 进行即时编译 (JIT) 转换成机器码并执行。

以前的 .NET Framework,还是现在的 .NET 5/6/7+,都包含垃圾回收、内存管理和异常处理等功能,C# 代码的这些运行管理全部依赖 CLR。

.NET 平台不只服务于 C#,它也支持 VB.NET、F# 等其他编程语言,但 C# 是其中最主流、最原生的一种。

裸指针本身只是一个地址值。

编译器只需要知道"这是个指向 FOpenCVState 的指针",不需要知道 FOpenCVState 里面到底有多少成员、占多少字节。

TUniquePtr<FOpenCVState>

隐含了所有权和析构责任。TUniquePtr<FOpenCVState> 自己析构时,delete Ptr;不是模板参数一出现就必须知道完整 layout,

而是 TUniquePtr<T> 的析构逻辑在这个点上要对 Tdelete,于是要求 T 是完整类型。

裸指针只需要知道"指向谁";

智能指针在析构点还需要知道"怎么把它正确销毁"。

能声明在头文件里,但常常要求析构函数写到 cpp 里"。

Python 自带的 list 不是为数值计算设计的。

比如你有一百万个点坐标、像素值、矩阵元素,list 当然也能装,但它的问题是:

  • 每个元素本质上是一个 Python 对象,开销大

  • 循环计算通常靠 Python 解释器一项一项跑,慢

  • 不天然适合线代、图像、张量这类"规则数组"

而 NumPy 的 ndarray 是"连续、同类型、面向数值"的内存块,更接近 C 数组。

所以它在做大规模数值运算时,速度和内存效率通常都比 list 好很多。

ONNX Runtime (ORT) is a high-performance, cross-platform engine for accelerating machine learning model inference and training .

ONNX 是一种模型交换格式,不是某个单独"推理库"。全称是 Open Neural Network Exchange。你可以把它理解成"神经网络的通用文件格式 / 中间表示",目的是把模型从 PyTorch、TensorFlow 等训练框架导出后,交给别的运行时去做推理

训练框架训练模型 → 导出成 .onnx → 用某个 runtime 跑推理。

真正执行推理的,常见是 ONNX Runtime,而不是 ONNX 本身。

Epic 的 NNE(Neural Network Engine)官方文档明确写了,UNNEModelData 在 cook 模型时就会处理诸如 .onnx 这样的文件格式;另外官方插件 NNERuntimeORT 也明确是一个基于 ONNX Runtime 的 runtime。也就是说,Unreal 不是把 ONNX 当野路子兼容,而是有官方插件和官方框架在接它。

在 Unreal 进程里,把一个训练好的神经网络当成一个可调用的计算模块来执行。

UE 不只是画画面、跑逻辑、播动画,

它还把一份模型文件喂给某个推理后端,然后每帧或按需输入数据,拿回结果,再把结果用于游戏逻辑或画面表现。

UE 自己不是"直接理解所有模型数学细节"的那个东西,真正执行时通常要靠一个 runtime / backend。

具体执行可能走某个 runtime

加载后,UE 会得到一个"可执行模型实例"。

模型一般不能直接吃 UE 原始数据,要先整理成模型要求的 tensor。

例如:

  • 把摄像头帧缩放到 224x224

  • BGR 转 RGB

  • uint8float

  • 做归一化

  • [N, C, H, W][N, H, W, C] 排列

这一步很关键。很多"模型跑不通"其实不是模型坏了,而是:

  • 输入 shape 不对

  • 通道顺序不对

  • 数据类型不对

  • 归一化不对

第一类,是"把 MetaHuman 角色放进工程"本身占的空间。

这个会占一些,而且往往不算特别小,因为 MetaHuman 不是一个简单模型,它通常带着:

材质与贴图

面部骨骼/控制相关资源

身体、头发、服装等资源

LOD、动画蓝图、控制 Rig 或相关依赖

实时流,不是 iPhone 那类偏离线深度捕获再后处理流程。实时链路更像是在传实时数据,重点是网络连通和 UE 端绑定,不是本地堆积大量录制文件。

手机上先把面部数据录下来,尤其是深度数据,

然后再把这份录制数据拿去驱动 MetaHuman / 做解算,

这叫 offline workflow。Epic 的文档里明确写的是:iOS 版 Live Link Face 支持"实时"或"基于深度数据的离线"工作流;而 Android 版页面写的是用于"实时生成动画",没有写 iOS 那种离线深度捕获能力。

而不是

先在手机里做一段高质量面捕录制,再把那段"深度面捕数据"拿回来后处理。

MetaHuman 在编辑器里跑起来,对显存、CPU、实时预览压力,通常比"磁盘再多占一点"更容易先成为问题。

MetaHuman Capture Source 官方 API 描述就是:它代表一个物理设备或档案,用来把素材导入编辑器,并在 MetaHuman Performance 里生成动画序列;这明显是偏 采集数据资产化/离线处理 的对象,不是你现在最短路径里必须先建的第一步。

这里不是 Content Browser 右键加资产,而是去 Live Link 面板 里加 source。Live Link 本身就是 UE 的实时流数据系统,Live Link Face Source 文档也明确说明它用于配置 source 和 subject 来做 realtime animation

"电脑摄像头不一定更好",很多时候反而更差 。大量笔记本 webcam 的典型问题是:

分辨率低、动态范围差、弱光噪点重、镜头太广或太软、固定在屏幕上导致拍摄角度偏高,而且用户离镜头太远。面捕最怕的就是这些,因为嘴角、眼睑、法令纹附近的细节会直接影响解算质量。Epic 在 MetaHuman Video Source 的文档里甚至专门提到 webcam 可能会掉帧,需要看 Live Link subject properties 里的 dropping 指标。

你以前看到的那套 Live Link Face ,确实主要是手机导向,尤其 iPhone。

但现在如果你用的是 MetaHuman 相关工作流,UE 5.6/5.7 已经存在 webcam 实时面捕路径,不再是"只能手机"。

**Live Link 面板里看到你的 Android 设备 / subject。**subject 绑定到 MetaHuman。Live Link 面板在跳,但 MetaHuman 不动。

Live Link Face Source

是"实时流入口"。把手机表情数据送进 UE。官方文档专门就是拿它做实时动画的。

Capture Source(离线)

是"采集数据来源资产"。更接近 Capture Manager / Animator 工作流里的输入源描述。

  • PyTorch 常见 .pt.pth

  • TensorFlow 常见 SavedModel、.pb

  • Keras 常见 .h5

  • scikit-learn、XGBoost 也有各自序列化方式

  • 还有很多厂商/推理引擎自己的专用格式

训练结果可以有很多种格式,ONNX 只是其中一种,而且是偏"通用交换格式"的一种。

原框架格式通常和原框架绑定得很深。

比如你在 PyTorch 里训练出一个模型,最自然的做法就是继续用 PyTorch 去推理。

但如果你的部署目标是:

  • Windows 桌面程序

  • Android/iOS

  • UE/Unity 插件

  • C++ 服务端

  • GPU/NPU/加速卡

  • 浏览器 / WebAssembly

  • 边缘设备

这时问题就来了:目标环境未必适合把整套训练框架搬过去。

  • 体积大

  • 依赖复杂

  • 启动慢

  • 对目标平台支持不一致

  • 对某些硬件优化不够

  • C++/游戏引擎里集成麻烦

所以很多时候,训练框架负责"产出模型",部署/runtime 负责"高效执行模型"。

ONNX 本质上是一个中间标准。

意思是:

"我不管你最早在 PyTorch、TensorFlow 还是别的框架里训练,我先把模型导出成一个统一规范,然后交给支持 ONNX 的推理引擎去跑。"

训练框架 → 导出成 ONNX → 用 ONNX Runtime / TensorRT / OpenVINO / 其他后端部署

所以 ONNX 的定位不是"最适合训练",而是"适合交换、部署、推理"。

游戏/UE/Unity 里也常提 ONNX

轻量集成

C++ 接口

容易接入 GPU/NPU 加速

UE 里做人脸、姿态、分类、分割、语音之类功能,很多时候并不想把 Python + PyTorch 整套塞进项目里。
这时 ONNX + ONNX Runtime 就很自然

MetaHuman Performance

是"把采集到的 footage / capture data 解算成动画序列"的资产,不是实时预览的第一步。官方 API 描述里就写了,它是从 Capture Source 的视频素材追踪出动画序列。

MetaHuman Identity

是"表演者数字身份/拟合身份"的资产,主要用于 Animator 的解算链路,不是你现在只想让手机实时驱动 MetaHuman 时必须先做的第一步。MetaHuman Performance 的官方描述里也明确提到它依赖 Identity。

;Fab 上也有越来越多的 MetaHuman collections。

UE 5.6 起最新版 MetaHuman Creator 直接在 Unreal Engine 内使用,不再以"新用户走旧网页应用"为主。

https://dev.epicgames.com/documentation/metahuman/metahumans-on-fab?

MetaHuman format (.mhpkg).

for DCC 的,本质上不是"现成可直接放进 UE 里玩的角色资产",而是给 外部数字内容制作软件 用的配套工具。DCC 就是 Digital Content Creation ,典型就是 Maya、Houdini、Blender 这类建模/绑定/毛发/动画软件。

一组 Maya 工具,用来编辑 MetaHuman 的某些部分,比如面部、身体次级形变、以及相关数据处理,不是一个"直接下载完整角色就能免 rig 使用"的角色包。通常它依赖从 UE 里的 MetaHuman 角色通过 DCC Export 导出的数据来继续编辑。

for Maya = 你已经有 MetaHuman 了,现在要进 Maya 做深加工 。常见用途是:

改表情/脸部数据、做身体的二级变形、调整某些绑定相关内容。官方也单独提供了 Maya 的 Pose Editor 这类工具来做身体次级变形。

for Houdini 更偏程序化流程、毛发流程、组装流程。如果你是想做发型、胡子、复杂 groom,Houdini 这条线更相关。官方还有专门的 Groom Starter Kit / Advanced Kit / Exporter 文档。

Assembly 在官方定义里就是"把你的角色构建成可在项目里使用的资产"的过程;而 UE 5.7 的 Blueprint API 里甚至直接有 Build MetaHuman 这样的装配入口,目标就是 MetaHuman Character Editor,这说明 assembly 现在本身就是 UE 内的一段资产构建流程,而不是单纯云端网页操作。

能不能把它当资源迁移到别的项目?

原则上可以 ,但要用 UE 的 Migrate ,不要只靠资源管理器手拷一个 .uasset。官方对 Migrate 的定义很明确:它会复制所选资产,连同它的 references 和 dependencies 一起复制 到另一个项目;Sources Panel 里对 Migrate 的说明也是"复制该资源及其依赖到另一个项目的 Content 文件夹"。这意味着,MetaHuman Character 作为一个 uasset 可以参与项目间迁移,但前提是把依赖一起带走

按目前官方文档看,不会被 uasset 取代,因为两者用途不同.uasset 是 UE 项目里的原生资产形态;.mhpkgMetaHuman Manager 用来验证并打包、上传到 Fab 的分发格式 。Epic 明确写了:MetaHuman Manager 会生成 .mhpkg;而在新的 MetaHuman 格式下,Fab 只接受来自 MetaHuman Manager 的 .mhpkg 文件来上架。

项目内编辑/迁移:看 uasset
对外发布/上架 Fab:看 .mhpkg

官方流程里,webcam 方法也属于 Live Link 体系 ,但不是传统意义上"手机 Live Link Face 那一条老路"的唯一入口了。MetaHuman 的实时驱动文档明确写了:实时动画可以来自 mono camera(包括 webcam) 、支持的移动设备,或者音频源;并且这些 MetaHuman Live Link sources 可以在 Unreal 的 Live Link 面板里创建,也可以在 Live Link Hub 里创建。

Live Link 里生成 SourceSubject。你要理解成:

  • Source = 数据从哪里来(webcam / 手机 / 音频)

  • Subject = Unreal 里可被角色消费的那路动画数据

    官方文档就是按 "create source and subject" 这个模型来描述 MetaHuman 实时驱动的。

不要把"webcam 面捕"简单理解成"电脑版 Live Link Face app"。更准确地说,它仍然是 Live Link 管线,但源类型不是同一个东西。

填手机 IP + Port,然后点 Connect,这一步叫"连接 Source(源)"。

把数据源接进 Live Link Client 。Live Link 官方定义里,Source 是数据来源/连接本身Subject 是这个 Source 提供出来的一条具体数据流

Source 连上后,Live Link 才会出现对应 Subject。

然后你在角色蓝图或动画蓝图里选这个 Subject,

ipconfig 里会看到:

  • Ethernet adapter

  • Wireless LAN adapter Wi-Fi

很多根本不是实体硬件卡,而是:

  • 驱动创建的虚拟接口

  • 软件层模拟出来的网络出口

  • 协议封装器

这时候叫"网卡"就不准确了。

叫"适配器"更合理,因为它强调的是:

它向系统提供了一个可用的网络接入接口,不管背后是硬件还是真虚拟。

"无线局域网 adapter"不等于"热点"。

无线局域网适配器(Wireless LAN adapter) 是你电脑或手机里的 Wi-Fi 网络接口

Default Gateway 的含义是:这张接口把"去别的网段/外网的流量"交给谁。

它描述的是路由出口,不是单独用来标记"发出端/接收端"。

  • 有 Default Gateway:通常说明这张网卡正在把某个设备当作上游路由器

  • 没有 Default Gateway:通常说明这张网卡不是当前默认出网口,或者它所在网络根本不需要再往上交

"电脑连接手机热点"这个场景里:

  • 默认网关 往往就是 手机在这个热点局域网里的地址

  • 也就是手机作为这个小局域网的"路由器"

所以你会常看到这种结构:

复制代码

手机热点: 192.168.82.11
电脑: 192.168.82.49
默认网关: 192.168.82.11

这里:

  • 电脑自己的局域网地址:192.168.82.49

  • 手机给自己的热点接口分配的地址:192.168.82.11

  • 电脑看到的默认网关:也是 192.168.82.11

手机既是热点提供者,也是这个局域网里的网关。

为什么会这样?

因为默认网关本来就是"本机要出这个局域网时,先把包交给谁"。

而在手机热点场景里,电脑要出网只能先交给手机,所以手机自然就是网关。

app 里的连接/目标地址设置页,把 电脑当前所在局域网 IP 填进去。

电脑连接手机热点时:

  • 手机会充当路由器 / 网关

  • 手机自己有一个热点局域网地址

  • 电脑会被手机分配另一个局域网 IPv4 地址

所以通常是:

  • 手机 IP :例如 192.168.43.1

  • 电脑 IP :例如 192.168.43.72

它们在同一个网段 ,但不是同一个地址

电脑上看 ipconfig 时,常见对应关系是:

  • IPv4 地址 = 电脑自己的地址

  • 默认网关 = 手机热点的地址

手机一边用蜂窝数据上网

一边自己开一个 Wi-Fi 热点给电脑接入

这两个不是一回事。

所以即使手机没有连任何外部 Wi-Fi,只用 SIM 卡流量,它仍然会给热点分配一个本地网段,比如:

192.168.82.11


192.168.43.1

这就是你要找的那个"手机 IP"。

你说的是"像镜子一样的屏幕里向右",这本质是监看需求。

如果你去反 Yaw 数据,那么:

你录到的角色动作也会真的变成反向,

不是"显示像镜子",而是"动画本身被改了"。

现在的热点分享无需同时打开WLAN,主要是因为手机硬件(芯片)能力提升,实现了双频Wi-Fi技术(Wi-Fi Bridge) ,热点创建与接入不再冲突。此外,蓝牙、蜂窝数据网络等多种连接方式的成熟,使得热点分享不再单一依赖WLAN芯片,提高了分享效率和便捷性。

早期的手机Wi-Fi芯片功能单一,只能"连接"或"发出"信号,因此开热点需先关闭Wi-Fi(即WLAN)。现代芯片支持同时进行无线信号的接收和发送,即把手机当作一个路由器使用,实现Wi-Fi信号桥接

蜂窝数据直接热点 :开启热点主要目的是分享蜂窝数据(4G/5G),而不是WiFi网络,现代系统已优化vivo官网HONOR 所示的移动网络共享流程,

Android的话连Wi-Fi的同时是开热点的情况下热点的网络流量会走热点机连上的Wi-Fi。类似于路由器无线中继的效果(多一层NAT转换)

虽然实时编译很强大,但它主要适用于修改 .cpp 文件中的函数体 。以下情况通常无法通过实时编译生效,建议关闭编辑器重新编译:

  • 修改头文件 :例如在 UCLASS 中新增 UPROPERTY UFUNCTION
  • 更改构造函数:修改构造函数中的初始化逻辑。

Live Coding :使用 Live++ 技术,通过打补丁的方式更新二进制文件,通常比旧版的热重载更稳定,不会产生 REHOTRELOADED 类名污染的问题。

UE 的构建工具 UnrealBuildTool 检测到你的项目是一个 Git 仓库,于是它去调用系统里的 git status,判断哪些文件改过,用来辅助 adaptive non-unity build 的工作集分析。也就是根据改动文件,决定更合理的编译范围。

  • A Source/ZMDRender/SimpleRotatingCube.cpp

    说明这个文件已经 git add

  • AM Source/ZMDRender/ZMDRender.Build.cs

    说明你 add 之后又继续改了

  • ?? Source/ZMDRender/MirrorCaptureDisplayActor.cpp

    说明这个文件还没被 Git 跟踪

它当时不是在严格读取这个类的真实接口,而是在拿 UE 里"常见 UMG / UserWidget 使用习惯"去套。

SetZOrderInViewport 不是所有 widget 类都能这么直接用

你的这个类里,实际 ZOrder 可能是通过 AddToViewport 传入,或者在你自定义逻辑里由 UUserWidget 外层控制

也就是说,它把"常见模式"误当成"当前类一定支持的模式"

写了 WidgetClassToUse 的 fallback,但用的是接近普通 C++ 的写法,而 Unreal 这里实际是 TSubclassOf<UUserWidget>,不是裸 UClass*

很多 AI 写 UE 代码时,表面上像 C++,但它脑子里其实还是"泛 C++ + 一点 UE 词汇",没有真正进入 Unreal 的类型规则。

draft 是从 Unreal UI patterns 的概念层写出来的,但没有针对你项目中的具体类型做严格验证。

TSubclassOfTObjectPtrTWeakObjectPtr 这些 UE 包装类型

UMG / Slate / Widget API,因为版本和类层级差异大

Actor / Component / Widget 的生命周期函数调用点

任何"看起来像 UE 里应该有"的函数名,比如 SetXXXInViewportRefreshBrushUpdateLayout 这种最容易被它脑补

viewport

指的是这个 Widget 怎么被放到屏幕显示层里,以及放进去之后的显示布局控制。通常包括:

  • 什么时候 AddToViewport()

  • 什么时候移除

  • 显示在屏幕哪个位置

  • 尺寸多大

  • 对齐方式是什么

  • 是否全屏、是否铺满、是否跟随某个规则更新

相关推荐
南境十里·墨染春水2 小时前
linux学习进展 主函数的参数
linux·运维·学习
淮北4942 小时前
obsidian管理自己的计划
linux·学习·kanban·obsidian
南無忘码至尊2 小时前
Unity学习90天-第1天-认识Transform + 坐标系
学习·unity·游戏引擎
my_daling2 小时前
DSMC通信协议理解,以及如何在FPGA上实现DSMC从设备(1)
学习·fpga开发
嵌入式×边缘AI:打怪升级日志2 小时前
Makefile 完全学习笔记:从入门到通用模板解析
笔记·学习
ACGkaka_3 小时前
ES 学习(九)从文本到词元:分词器如何“拆解“你的数据
大数据·学习·elasticsearch
南無忘码至尊3 小时前
Unity学习90天-第1天-认识Unity并书写我们的第一个脚本
学习·unity·游戏引擎
2301_792674863 小时前
java学习day27(算法)
java·学习·算法
zhangrelay3 小时前
蓝桥云课一分钟-星界战纪-Stellar Combat-make
笔记·学习