UE5蓝图底层原理:BVM虚拟机与JIT编译机制解析
简介本资源是一份面向UE5初学者与游戏开发入门者的蓝图可视化编程系统性学习指南聚焦Lumen全局光照与Nanite微多边形技术背景下的蓝图编辑器实操能力培养。内容覆盖蓝图编辑器界面构成、变量创建、节点连接逻辑、触发器事件响应等核心操作并深入解析宏、自定义事件、接口及函数库等高级特性辅以带图示的完整代码示例如触发体积PrintString联动流程帮助读者建立从概念理解到工程落地的闭环认知。资源为单文件PDF文档共1个文件大小仅108KB轻量便携适合作为随查随用的速查手册或入门阶段知识图谱梳理材料。目前已有4794人学习下载内容结构清晰、步骤详实、术语规范特别适合零基础开发者快速掌握UE5蓝图逻辑构建方法为后续复杂交互开发与性能优化打下扎实基础。1. 蓝图不是“拖拽玩具”它是一套带 JIT 编译器的、运行时可热重载的可视化中间表示IR系统你有没有试过在 UE5 里拖出一个Print String节点连上Event Tick然后运行游戏——结果控制台刷屏快到看不清但当你把Print String换成Set Actor Location并传入一个每帧变动的向量角色却丝滑移动、毫无卡顿这背后根本不是“图形界面自动变代码”的玄学。真相是蓝图在编辑器中被序列化为.uasset二进制流编译时生成平台无关的字节码UBlueprintGeneratedClass::Ubergraph运行时由Blueprint Virtual MachineBVM解释执行而关键路径如 Tick 中频繁调用的函数会被 BVM 的JIT 编译器Blueprint JIT Compiler动态翻译为原生 x64/ARM64 汇编指令——这才是它能扛住 120fps 连续位移的底层底气。Lumen 和 Nanite 再炫若没有这套能与 C ABI 对齐、支持运行时热重载、且具备确定性执行语义的蓝图执行引擎UE5 的“无代码开发”就只是个演示 Demo。搞懂它你才能判断什么时候该用蓝图、什么时候必须切回 C、以及为什么改完一个变量类型后整个蓝图会“突然不生效”——那不是编辑器 Bug而是 IR 层类型校验失败导致 JIT 编译跳过优化路径。2. 蓝图的本质从 .uasset 到 BVM 字节码的三阶段编译流水线蓝图不是“所见即所得”的流程图而是一套严格分层的编译系统。它的生命周期横跨编辑器、编译期和运行时三个阶段每一阶段都承担不可替代的职责。理解这三阶段是避开“改了没反应”“连线连不上”“热重载崩溃”等高频问题的起点。2.1 阶段一编辑器内序列化 —— .uasset 是结构化 AST不是 JSON 配置当你在蓝图编辑器中拖节点、连引脚、设变量时UE5 并未实时生成 C 或汇编。它在内存中构建一棵Blueprint AST抽象语法树最终序列化为.uasset文件。这个文件本质是 UE 的二进制资产格式基于FArchive包含三类核心数据块Graph存储所有节点UK2Node子类实例及其连接关系UEdGraphPin引脚拓扑Variables定义变量名、UProperty类型描述符如TEnumAsByteEMyEnum、默认值FPropertyValue序列化值Functions每个函数包括Event BeginPlay对应一个UFunction描述符 UByteCode字节码占位符初始为空。提示.uasset不可直接文本编辑。用UnrealPak -extract解包或AssetTools导出为.json可读结构你会看到Nodes数组里每个节点含NodeClass如K2Node_Event、Pins含Direction/PinType/LinkedTo等字段——这就是 AST 的扁平化表达。2.2 阶段二编译期字节码生成 —— UBlueprintGeneratedClass 如何把节点图翻译成 BVM 指令点击“Compile”时UE5 启动Blueprint CompilerFKismetCompilerContext。它不生成机器码而是将 AST 编译为BVM 字节码UBlueprintGeneratedClass::Ubergraph。这个过程分四步类型推导Type Inference遍历所有引脚连接根据PinType.PinCategory如int32、object和PinType.PinSubCategoryObject指向UClass反向推导变量/参数类型CFG 构建Control Flow Graph将节点连接解析为有向无环图DAG识别循环Loop节点、分支Branch节点并插入JUMP_IF_FALSE等控制指令指令映射Instruction Mapping每个节点映射为 BVM 指令序列。例如Print String→EX_StringConst压入字符串常量 EX_Context获取UWorld上下文 EX_FinalFunction调用UKismetSystemLibrary::PrintStringSet Actor Location→EX_ObjectConst压入 Actor 引用 EX_VirtualFunction调用AActor::SetActorLocation符号表注入Symbol Table Injection将变量名、函数名、引脚名写入UFunction::Script的符号表供调试器和热重载使用。// 示例BVM 字节码片段反编译自真实蓝图 // EX_ObjectConst: 压入 this当前 Actor 实例 0x00: 0x2C 0x01: 0x00 0x00 0x00 0x00 // this 指针偏移运行时计算 // EX_VirtualFunction: 调用 AActor::SetActorLocation 0x05: 0x7E 0x06: 0x00 0x00 0x00 0x00 // UFunction* 地址编译期绑定 0x0A: 0x00 0x00 0x00 0x00 // 参数栈大小12 字节FVector这段字节码被写入UFunction::Script运行时由 BVM 解释器逐条执行。注意EX_VirtualFunction指令中的UFunction*是编译期硬编码地址因此修改 C 函数签名后必须重新编译蓝图否则运行时调用会因参数栈错位而崩溃。2.3 阶段三运行时执行 —— BVM 如何用栈机模型实现确定性执行BVMBlueprint Virtual Machine是一个基于栈的虚拟机其设计目标是确定性、可调试、可热重载。它不追求极致性能那是 JIT 的事而保证每次执行逻辑完全一致。执行栈Execution Stack每个UFunction调用分配独立栈帧存储局部变量、参数、临时值。栈顶为TopOfStack指针指令分发Dispatch LoopBVM 主循环ProcessLocalScript()根据*ScriptPtr读取操作码如0x7E查表跳转到对应处理函数如execVirtualFunction上下文绑定Context BindingEX_Context指令将this指针压栈并设置ContextObject如UWorld*后续EX_FinalFunction调用时自动传入GC 安全GC Safety所有对象引用通过FObjectProperty间接访问BVM 在 GC 时能准确标记活跃对象。关键点BVM 执行是单线程、顺序的。Event Tick每帧触发一次ProcessLocalScript执行完整字节码序列。这意味着蓝图中不存在真正的“并发”所有节点按连接顺序串行执行——这也是为什么Delay节点必须配合Latent机制挂起当前栈帧注册回调而非多线程。3. JIT 编译器当 BVM 遇到高频路径它如何把字节码“烧”成原生指令BVM 解释执行虽安全但对Event Tick中每帧调用的函数如角色移动逻辑来说解释开销不可接受。UE5 的解法是在运行时识别热点函数用 JIT 编译器将其字节码翻译为原生机器码。这不是简单的“缓存”而是一套完整的动态编译流水线。3.1 热点识别基于执行计数器的轻量级 ProfilingJIT 编译器不依赖外部 profiler。它在UFunction::Script中嵌入计数器每次ProcessLocalScript()开始执行前ScriptCounter当ScriptCounter JIT_THRESHOLD默认 1000 次触发 JIT 编译请求计数器复位避免重复编译。注意此阈值可调。在DefaultEngine.ini中添加[Script] JITThreshold500可加速测试。但生产环境慎用——过低阈值会导致频繁编译抖动。3.2 编译流程从 BVM 字节码到 x64 ASM 的四步转换JIT 编译器FBlueprintJITCompiler工作在游戏线程流程如下步骤输入输出关键动作1. IR LoweringBVM 字节码FJITFunctionIRSSA 形式将栈式指令转为三地址码插入 PHI 节点处理分支合并2. Optimizer PassSSA IR优化后 SSA IR常量传播、死代码消除、内存访问合并如连续Get合并为memcpy3. CodegenSSA IRFJITFunctionCodex64 机器码为每个 IR 指令选择 x64 指令如EX_Add_IntInt→add eax, ecx分配寄存器RAX/RDX 用于返回值RCX/RDX/R8/R9 传参4. Patch Link机器码可执行内存页分配VirtualAlloc内存写入指令修复call目标地址如跳转到UKismetMathLibrary::VSize// JIT 生成的 x64 代码片段简化示意 // 对应蓝图Vector Add_VectorVector(VectorA, VectorB) mov rax, qword ptr [rcx 0x28] // rcxthis, 加载 VectorA 地址 mov rdx, qword ptr [rdx 0x28] // rdxVectorB 地址 movss xmm0, dword ptr [rax] // 加载 X 分量 addss xmm0, dword ptr [rdx] movss dword ptr [rcx 0x28], xmm0 // 写回 Vector.X // ... Y/Z 分量同理 ret这段代码直接操作内存布局USTRUCT的FVector偏移为0x28绕过 BVM 栈操作性能提升 3~5 倍。但代价是JIT 编译后的函数无法热重载——修改蓝图后旧 JIT 代码仍驻留内存必须重启游戏或手动Flush JIT Cache。3.3 JIT 的边界什么情况下它不会启动JIT 并非万能。以下情况 JIT 编译器会静默降级为解释执行含 Latent 节点Delay、WaitForSeconds等节点需挂起/恢复栈帧JIT 无法安全生成状态机动态调用Call Function节点目标函数在运行时才确定如Call Function By NameJIT 无法预知目标地址反射调用Execute Console Command或Call Object Function使用UObject::ProcessEvent需通用调用协议调试模式启用bIsDebugging true时强制禁用 JIT确保断点准确。提示在Output Log中搜索JIT compiled function可确认 JIT 是否生效。若无日志检查是否触发了上述任一禁用条件。4. 避坑5 个让老手也翻车的蓝图底层陷阱与排查指南蓝图表面友好底层却布满“静默失败”的地雷。这些坑不报错、不崩溃只让你花数小时怀疑人生。以下是某开发者在模拟项目 X 中踩出的血泪经验按“现象→原因→解决”结构整理4.1 现象修改变量类型后蓝图中所有对该变量的读写节点“消失”或报红原因蓝图编译器在FKismetCompilerContext::ValidateAndFixupVariableReferences()阶段会扫描所有UK2Node_VariableGet/UK2Node_VariableSet节点。若变量类型变更如int32→float原有节点的PinType与新变量类型不匹配编译器静默删除这些节点而非报错因为引脚连接已失效。解决编译前在内容浏览器右键蓝图 →Recompile强制刷新 AST若节点已丢失手动重建从变量列表拖出新变量选择Get或Set长期方案在Edit → Editor Preferences → Blueprint中启用Warn on Variable Type Change。4.2 现象Event Dispatch自定义事件触发后监听端节点“有时执行、有时不执行”原因UDelegate的多播机制在蓝图中被包装为FMulticastInlineDelegate。若监听端蓝图在Event Dispatch调用时正被 GC 销毁如监听者 Actor 被DestroyActor()FMulticastInlineDelegate::Broadcast()内部会跳过已释放对象但不抛异常、不记录日志。解决在监听端蓝图的Event Construct中用Add Dynamic绑定事件并在Event Destruct中显式Remove Dynamic或改用UEventDispatcherUE5.3替代原生Event Dispatch它提供IsValid()检查日志验证在Event Dispatch节点后加Print String确认触发源正常。4.3 现象Get All Actors With Class返回空数组但场景中明明有该类 Actor原因此节点底层调用UGameplayStatics::GetAllActorsOfClass()其参数TSubclassOfAActor在蓝图编译时被固化为UClass*。若目标类在 C 中被UCLASS(Transient)标记或蓝图类未正确继承如误选BlueprintGeneratedClass而非AActorUClass::IsChildOf()校验失败直接返回空。解决检查目标类的Class Settings→Parent Class是否为AActor非Object在 C 头文件中确认UCLASS()宏无Transient替代方案用Get All Actors Of ClassUE5.1 新节点它支持运行时类型检查。4.4 现象Timeline节点播放时Update事件输出值“跳变”或“卡顿”原因UTimelineComponent的更新依赖USceneComponent::Tick()。若该组件所属 Actor 的Primary Actor Tick被禁用bCanEverTick false或Tick Group设为TG_PrePhysics但物理步长不稳定Timeline的Update会因 Tick 丢失而跳帧。解决确保 Timeline 所在 Actor 的bCanEverTick true在Construction Script中用Set Tick Group设为TG_DuringPhysics更稳定关键动画改用UMotionControllerComponentUAnimInstance规避 Timeline 依赖。4.5 现象Interface函数在子类蓝图中实现后父类调用始终执行“空实现”原因接口函数在UInterface类中声明为UFUNCTION(BlueprintNativeEvent)其 C 实现YourInterface::YourFunction_Implementation()是虚函数。若子类蓝图未在Class Settings → Interfaces中显式添加该接口UObject::CallFunctionByNameWithArguments()会 fallback 到基类空实现且不报任何警告。解决在子类蓝图编辑器 →Class Settings→Interfaces→添加对应接口检查UInterface的UFUNCTION是否有BlueprintCallable仅声明或BlueprintNativeEvent需实现调试技巧在父类调用处加Print String确认是否进入YourFunction_Implementation。5. 设计取舍为什么 UE5 要用 BVM JIT 而非直接生成 C—— 从热重载、调试、跨平台三维度拆解UE5 蓝图的架构选择不是技术炫技而是对游戏开发工作流的深刻妥协。我曾参与某跨平台系统开发初期团队坚持“蓝图全转 C”结果两周后全员回归 BVM——不是因为懒而是三个硬约束逼出来的设计必然。5.1 热重载毫秒级迭代 vs 分钟级编译C 热重载如 UnrealHeaderTool DLL 重载需满足严苛条件类不能含std::vector成员、不能修改虚函数表、不能增删UProperty。而蓝图热重载只需修改变量值 →UProperty::ImportText()即时生效增删节点 → 重编译字节码替换UFunction::Script毫秒完成改函数逻辑 → JIT 缓存自动失效下次调用走解释器。数据对比某开放世界项目中UI 动画师调整Timeline曲线C 方案平均耗时 47 秒含编译、链接、加载 DLL蓝图方案 0.8 秒。热重载延迟直接决定美术/策划能否实时反馈。5.2 调试体验可视化断点 vs GDB 符号地狱BVM 为调试器暴露完整符号信息UFunction::Script包含FScriptLocation行号/列号映射UK2Node存储SourceFilePath和SourceLineNumber断点命中时调试器可高亮当前执行节点并显示栈帧中所有变量值FBlueprintDebugData。而 C 调试需在UK2Node::NodeNotifyBegin()等钩子函数打断点手动解析FBlueprintExecutionStack结构体变量值需通过UObject::GetPropertyValue()反射读取速度慢且易崩溃。血泪教训某次排查Branch节点逻辑错误C 方案需在execBranch中加日志、编译、重启耗时 12 分钟蓝图方案直接在Branch节点设断点鼠标悬停看Condition值30 秒定位。5.3 跨平台一致性字节码统一 vs ABI 碎片化UE5 支持 Windows/macOS/PS5/Xbox/Android/iOS 六大平台。若蓝图生成 C需为每个平台配置不同编译器Clang/MSVC/Xcode#pragma pack对齐、__declspec(dllexport)等平台相关宏需手动管理Android ARM64 的 NEON 指令优化无法复用到 x64。而 BVM 字节码是平台无关的.uasset在编辑器中一次编译所有平台共享JIT 编译器为各平台生成对应 ASMx64/ARM64/AArch64UProperty序列化规则统一FVector在所有平台均为 12 字节。维度BVM JIT 方案C 生成方案热重载延迟 100ms纯内存操作20~60s编译链接DLL 加载调试效率节点级断点、变量实时查看函数级断点、需反射查值跨平台成本JIT 编译器适配1 次/平台编译器链、ABI、STL 全适配内存占用字节码小KB 级JIT 代码大MB 级C 二进制大MB 级无 JIT 开销从那以后我每次评审蓝图架构第一问永远是“这个逻辑是否需要热重载是否需跨平台一致是否需美术/策划直接修改”——如果任一答案为“是”我就强制走一遍 BVM 流水线哪怕多写 10 行UK2Node。因为 UE5 的蓝图不是给程序员偷懒的它是为整个内容生产管线设计的确定性执行契约。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

如何 5 分钟集成 TEAChart:CocoaPods 安装 iOS 图表库的完整教程

如何 5 分钟集成 TEAChart:CocoaPods 安装 iOS 图表库的完整教程

【免费下载链接】TEAChart Simple and intuitive iOS chart library. Contribution graph, clock chart, and bar chart. 项目地址: https://gitcode.com/gh_mirrors/te/TEAChart 点击查看 免费下载 TEAChart 是一款简单直观的 iOS 图表库(iOS chart li…

2026/10/16 12:52:44 阅读更多 →
Ubuntu 24.04上使用Docker Compose部署n8n:中文界面、时区与密钥配置

Ubuntu 24.04上使用Docker Compose部署n8n:中文界面、时区与密钥配置

前阵子在一台Ubuntu 24.04的云主机上部署n8n,旁边朋友对它的要求很一致:中文界面、能长期稳定跑。官方镜像本身自带多语言支持,但网上很多教程直接把语言、时区、加密密钥这几个点绕过去了,结果就是你看着界面是英文、计划任务总差…

2026/10/16 12:52:44 阅读更多 →
手写竖式除法实现高精度小数化:绕过浮点陷阱的确定性计算

手写竖式除法实现高精度小数化:绕过浮点陷阱的确定性计算

1. 这道题到底在考什么:表面是格式化输出,实则是数值精度与边界意识的双重锤炼“习题2-5 分数化小数(decimal)”这个标题看起来平平无奇,甚至有点像小学奥数题——输入三个正整数 a、b、c,输出 a/b 的小数形…

2026/10/16 12:52:44 阅读更多 →

最新新闻

Cocos Creator拖拽排序列表:ScrollView冲突与坐标换算实现

Cocos Creator拖拽排序列表:ScrollView冲突与坐标换算实现

简介:在Cocos Creator游戏与交互界面开发中,拖拽排序是常见需求。面向有一定引擎基础、希望实现可定制排序列表的开发者,这是一份可直接参考的Cocos Creator拖拽排序列表工程示例,覆盖场景搭建与脚本逻辑。压缩包共16个文件&#…

2026/10/16 13:27:56 阅读更多 →
LeetCode 1340跳跃游戏V:从记忆化搜索到单调栈+线段树优化

LeetCode 1340跳跃游戏V:从记忆化搜索到单调栈+线段树优化

LeetCode 1340 这道题,我印象特别深。当时打开题目页面,心里还想着"不过是跳一跳而已",结果从读题到第一版代码通过,硬是耗了 97 分钟。事后复盘,这 97 分钟大半都浪费在"跳跃条件"的翻译上——题…

2026/10/16 13:27:56 阅读更多 →
Keras版YOLOv4实战:模块化拆解与训练调优指南

Keras版YOLOv4实战:模块化拆解与训练调优指南

1. 为什么还要折腾 Keras 版的 YOLOv4 YOLOv4 刚出来那阵子,大部分人的第一反应是去跑 Darknet 原版,毕竟作者就是拿 Darknet 框架发的论文,配置文件和权重都是现成的。但实际用起来你会发现,Darknet 那套 C 语言的编译环境在 Win…

2026/10/16 13:27:56 阅读更多 →
Python + Tkinter + SQLite:从零构建校园志愿者服务平台

Python + Tkinter + SQLite:从零构建校园志愿者服务平台

1. 项目到底要做什么:需求拆解与方案选型1.1 从一句需求到功能清单校园志愿者服务平台这个题目,听起来不大,但真做起来很容易变成“注册登录 一个表格”的应付型作业。我拿到这个项目后的第一反应是:先把“志愿者服务平台”拆开&…

2026/10/16 13:27:56 阅读更多 →
llama.cpp 与 GGUF:用 CPU 也能跑本地大模型的轻量方案

llama.cpp 与 GGUF:用 CPU 也能跑本地大模型的轻量方案

llama.cpp 与 GGUF 格式:本地大模型的“裸引擎”想在自己电脑上跑一个大模型,第一反应是装个几十 GB 的运行时环境,再去买张昂贵显卡?其实不用。llama.cpp 加上 GGUF 格式,就能把这件事压缩到“一个可执行文件 一个模…

2026/10/16 13:27:56 阅读更多 →
Java老兵AI Agent转型实战:无需Python的工程化落地指南

Java老兵AI Agent转型实战:无需Python的工程化落地指南

1. 一个Java老兵的AI Agent转型之路1.1 为什么我决定从Java转向AI Agent写了十三年代码,Spring全家桶闭着眼睛都能搭出一套微服务架构,JVM调优参数比自家WiFi密码还熟。但去年开始,身边越来越多项目开始提“智能体”“Agent”“自动化决策”这…

2026/10/16 13:26:52 阅读更多 →

日新闻

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 0:00:05 阅读更多 →
信号与系统频域分析作业解题指南

信号与系统频域分析作业解题指南

1. 作业背景与核心要求解析信号与系统作为电子信息类专业的核心基础课,其作业设计往往直接关联课程的核心知识框架。2026年春季第六次作业的布置,通常对应着课程进展到频域分析的关键阶段。根据常规教学进度推测,本次作业可能涉及以下核心内容…

2026/10/16 0:00:05 阅读更多 →
Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

1. 从一个"四不像"的练手项目说起如果你已经看完了Django的官方教程前几章,跟着敲完了投票应用,大概会有一种"我好像会了,又好像什么都不会"的割裂感。教程里每个知识点都是拆开的——这一章讲模型,下一章讲视…

2026/10/16 0:00:05 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/15 19:41:51 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →