<?xml version="1.0" encoding="utf-8" standalone="yes"?><?xml-stylesheet type="text/xsl" href="/rss.xsl"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>古月月仔的博客</title><link>https://tingdonghu.github.io/</link><description>Recent content on 古月月仔的博客</description><generator>Hugo</generator><language>zh-cn</language><managingEditor>古月月仔</managingEditor><webMaster>古月月仔</webMaster><lastBuildDate>Mon, 20 Apr 2026 00:00:00 +0800</lastBuildDate><atom:link href="https://tingdonghu.github.io/index.xml" rel="self" type="application/rss+xml"/><item><title>【课堂笔记】可计算理论导论：从零开始理解计算的边界</title><link>https://tingdonghu.github.io/posts/%E8%AF%BE%E5%A0%82%E7%AC%94%E8%AE%B0/%E5%8F%AF%E8%AE%A1%E7%AE%97%E7%90%86%E8%AE%BA%E5%AF%BC%E8%AE%BA-%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5%E4%B8%8E%E5%85%A5%E9%97%A8/</link><pubDate>Mon, 20 Apr 2026 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/%E8%AF%BE%E5%A0%82%E7%AC%94%E8%AE%B0/%E5%8F%AF%E8%AE%A1%E7%AE%97%E7%90%86%E8%AE%BA%E5%AF%BC%E8%AE%BA-%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5%E4%B8%8E%E5%85%A5%E9%97%A8/</guid><description>&lt;h1 id="可计算理论导论从零开始理解计算的边界"&gt;可计算理论导论：从零开始理解计算的边界&lt;/h1&gt;
&lt;h2 id="前言为什么我们需要可计算理论"&gt;前言：为什么我们需要可计算理论？&lt;/h2&gt;
&lt;p&gt;在开始接触可计算理论之前，你可能会问一个很自然的问题：&lt;strong&gt;我已经会写代码了，为什么还要学这些抽象的理论？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;让我们用一个简单的例子来回答这个问题。&lt;/p&gt;
&lt;p&gt;想象一下，你写了一个程序来处理数据：&lt;/p&gt;
&lt;div class="code-block" data-lang="python"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;python&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;process_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 做一些复杂的处理&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;some_computation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;should_stop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这个程序有一个 &lt;code&gt;while True&lt;/code&gt; 循环。如果 &lt;code&gt;should_stop&lt;/code&gt; 永远返回 &lt;code&gt;False&lt;/code&gt;，程序就会永远运行下去——我们称之为 &lt;strong&gt;死循环&lt;/strong&gt; 或 &lt;strong&gt;无限循环&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;现在，一个很自然的问题出现了：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;有没有一个万能工具，能够自动检测任何程序是否会陷入死循环？&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;你可能会想：&amp;ldquo;这不就是编译器或静态分析工具要做的事情吗？&amp;rdquo; 但可计算理论给出的答案是：&lt;/p&gt;
&lt;h2 id="不存在这样的万能工具"&gt;&lt;strong&gt;不存在这样的万能工具。&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;这就是可计算理论要告诉我们的第一个重要事实：&lt;strong&gt;计算机的能力是有根本边界的。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="什么是可计算理论"&gt;什么是可计算理论？&lt;/h2&gt;
&lt;p&gt;可计算理论（Computability Theory）是计算机科学的理论基石之一，它试图回答以下根本性问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;什么是 &amp;ldquo;可计算&amp;rdquo; 的？&lt;/strong&gt; —— 能够用计算机解决的问题有什么特征？&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;计算机能解决什么问题？&lt;/strong&gt; —— 哪些问题存在算法？&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;计算机解决不了什么问题？&lt;/strong&gt; —— 哪些问题永远不存在算法？&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这些问题听起来很抽象，但它们关系到：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;程序的可靠性&lt;/strong&gt;：我们能否证明程序正确？&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;密码学的安全性&lt;/strong&gt;：密码学的安全性依赖于某些问题的难解性&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;人工智能的边界&lt;/strong&gt;：AI 能否解决所有问题？&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;算法设计的方向&lt;/strong&gt;：哪些问题值得投入精力去优化&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="教材与学习方法"&gt;教材与学习方法&lt;/h2&gt;
&lt;p&gt;本文基于 MIT Michael Sipser 教授的经典教材《Introduction to the Theory of Computation》（《计算理论导引》第三版）。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;学习建议&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;不要被符号吓到&lt;/strong&gt;：数学符号只是表达方式的简化，理解背后的直观含义更重要&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;动手画图&lt;/strong&gt;：自动机的状态转移图、语法树等，动手画一画会帮助你理解&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;联系编程实践&lt;/strong&gt;：每个理论概念都可以对应到实际的编程场景&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;循序渐进&lt;/strong&gt;：从最简单的有限自动机开始，逐步过渡到图灵机&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="一可计算理论的三个分支"&gt;一、可计算理论的三个分支&lt;/h2&gt;
&lt;p&gt;计算理论通常分为三个主要领域，它们从不同角度研究计算：&lt;/p&gt;</description></item><item><title>【LLM应用开发实践】Agent 实战落地经验与技术思考</title><link>https://tingdonghu.github.io/posts/agent/agent%E5%AE%9E%E6%88%98%E8%90%BD%E5%9C%B0%E7%BB%8F%E9%AA%8C%E4%B8%8E%E6%8A%80%E6%9C%AF%E6%80%9D%E8%80%83/</link><pubDate>Sun, 19 Apr 2026 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/agent/agent%E5%AE%9E%E6%88%98%E8%90%BD%E5%9C%B0%E7%BB%8F%E9%AA%8C%E4%B8%8E%E6%8A%80%E6%9C%AF%E6%80%9D%E8%80%83/</guid><description>&lt;h1 id="agent-实战落地经验与技术思考"&gt;Agent 实战落地经验与技术思考&lt;/h1&gt;
&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;在当前 AI Agent 技术快速发展的背景下，很多开发者都在探索如何构建高效可靠的 Agent 应用。本文整理了一场来自一线开发者的技术分享，聚焦于 Agent 实践中的真实经验、技术思考与设计哲学，希望能为正在探索 Agent 开发的同学提供参考。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一重新思考-agent-框架的价值"&gt;一、重新思考 Agent 框架的价值&lt;/h2&gt;
&lt;h3 id="11-框架层的价值正在降低"&gt;1.1 框架层的价值正在降低&lt;/h3&gt;
&lt;p&gt;在大模型发展初期，各类 Agent 框架（如 LangChain、LangGraph）曾备受关注。这些框架试图在应用和大模型之间构建一层抽象层，主要价值是方便切换不同模型厂商。&lt;/p&gt;
&lt;p&gt;然而实践表明，这种抽象层的实际价值已经很低：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;模型切换成本并不低&lt;/strong&gt;：不同模型在相同 prompt 下表现差异显著，切换模型往往需要重新优化 prompt 和 tool 设计&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;兼容层已普及&lt;/strong&gt;：各大模型厂商基本都兼容 OpenAI 或其他标准 API 格式&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agent 本质简单&lt;/strong&gt;：Agent 就是一个大 while 循环——观察状态、思考下一步、执行工具或回答，循环往复&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="12-真正的价值在哪里"&gt;1.2 真正的价值在哪里？&lt;/h3&gt;
&lt;p&gt;Agent 开发真正的价值在于 &lt;strong&gt;一线交互过程中积累的 Know-how&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;模型在什么场景下表现更好？&lt;/li&gt;
&lt;li&gt;哪些 prompt 写法能获得更好的效果？&lt;/li&gt;
&lt;li&gt;上下文如何构建才能发挥模型最大潜力？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些经验是框架无法提供的，只能在真实场景中通过大量测试、观察、调优获得。像Manus这样的应用之所以能超越模型厂商的官方 Agent 实现，正是因为他们在一线积累了大量特定领域的 insights。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;关键洞察&lt;/strong&gt;：应用厂商并不一定会被模型厂商吞噬。垂类场景的深度理解是难以被替代的护城河。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/agent/agent%E5%AE%9E%E6%88%98%E8%90%BD%E5%9C%B0%E7%BB%8F%E9%AA%8C%E4%B8%8E%E6%8A%80%E6%9C%AF%E6%80%9D%E8%80%83/01-comparison-framework-knowhow.png"
alt="框架 vs 一线 Know-how 对比"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
框架 vs 一线 Know-how 对比
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;</description></item><item><title>【论文阅读】Reflective Context Learning: Studying the Optimization Primitives of Context Space</title><link>https://tingdonghu.github.io/posts/agent/%E8%AE%BA%E6%96%87%E9%98%85%E8%AF%BBrcl/</link><pubDate>Sun, 19 Apr 2026 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/agent/%E8%AE%BA%E6%96%87%E9%98%85%E8%AF%BBrcl/</guid><description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;摘要&lt;/strong&gt;：本文是对Contextual AI团队2026年4月最新预印本论文《Reflective Context Learning》的深度解读。该论文首次提出Context Learning与传统参数空间优化在数学本质上同构的核心论点，统一了prompt工程、上下文学习、工具设计等分散领域的研究视角，系统性分析了上下文空间优化面临的高方差、信用分配困难、灾难性遗忘等经典病理，并在此基础上提出了包含五大核心优化原语的RCL（Reflective Context Learning）框架，为Agent无需参数更新即可持续自演进提供了理论基础与实践指导。&lt;/p&gt;
&lt;/blockquote&gt;</description></item><item><title>【LLM应用开发原理】从提示词工程、上下文工程到Harness工程的设计哲学</title><link>https://tingdonghu.github.io/posts/agent/agent-engineering-evolution-from-prompt-to-harness-philosophy/</link><pubDate>Wed, 15 Apr 2026 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/agent/agent-engineering-evolution-from-prompt-to-harness-philosophy/</guid><description>&lt;hr&gt;
&lt;h2 id="引言"&gt;引言&lt;/h2&gt;
&lt;p&gt;大模型驱动的智能体（Agent）技术发展至今，已经走过了三个清晰的工程化阶段：从最初「怎么写好提示词」的单点技巧探索，到「怎么高效管理上下文」的模块体系构建，再到今天「怎么部署生产级Agent」的完整工程体系。这三个阶段的演进不是技术的随机迭代，而是遵循着清晰的设计哲学脉络，本质是软件工程理念在AI时代的自然延伸。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/agent/agent-engineering-evolution-from-prompt-to-harness-philosophy/01-timeline-agent-evolution.png"
alt="Agent工程化三阶段演进时间线"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
Agent工程化三阶段演进时间线
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="一提示词工程prompt-engineering人机交互接口的第一次对齐"&gt;一、提示词工程（Prompt Engineering）：人机交互接口的第一次对齐&lt;/h2&gt;
&lt;h3 id="设计哲学把自然语言变成新的编程语言"&gt;设计哲学：把自然语言变成新的编程语言&lt;/h3&gt;
&lt;p&gt;提示词工程是Agent技术的第一个工程化阶段，它要解决的核心问题是&lt;strong&gt;消除自然语言的歧义性，实现人类意图与大模型能力的精准对齐&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;在大模型刚出现的阶段，开发者很快发现：同样的问题用不同的表述方式问大模型，得到的结果可能天差地别。这背后的本质是大模型的能力是建立在海量文本数据的统计规律之上，它对自然语言的理解和人类的认知存在天然的偏差。提示词工程的出现，就是为了构建一套「翻译规则」，把人类的自然语言需求翻译成大模型能够精准理解的输入格式。&lt;/p&gt;
&lt;h3 id="核心方法论的演进"&gt;核心方法论的演进&lt;/h3&gt;
&lt;p&gt;从最基础的指令明确化，到角色设定、思维链（Chain-of-Thought）引导、Few-shot示例注入、输出格式约束，提示词工程的所有方法论本质上都是在做同一件事：&lt;strong&gt;给大模型足够的上下文约束，减少它的输出分布空间，让结果落在预期的范围内&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/agent/agent-engineering-evolution-from-prompt-to-harness-philosophy/02-framework-prompt-engineering.png"
alt="提示词工程核心方法论架构图"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
提示词工程核心方法论架构图
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;这一阶段的标志性成果包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OpenAI官方发布的&lt;a href="https://platform.openai.com/docs/guides/prompt-engineering" target="_blank"&gt;《Prompt Engineering Guide》&lt;/a&gt;
，系统化梳理了提示词设计的最佳实践&lt;/li&gt;
&lt;li&gt;Google DeepMind提出的&lt;a href="https://arxiv.org/abs/2201.11903" target="_blank"&gt;思维链（CoT）技术&lt;/a&gt;
，大幅提升了大模型的复杂推理能力&lt;/li&gt;
&lt;li&gt;各种提示词框架的出现，把零散的技巧变成可复用的模板&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;提示词工程的历史贡献在于它第一次证明了：不需要微调大模型参数，只通过优化输入就能显著提升大模型的输出质量，这为后续的工程化探索打开了全新的思路。&lt;/p&gt;
&lt;h2 id="二上下文工程context-engineering模型记忆能力的工程化突破"&gt;二、上下文工程（Context Engineering）：模型记忆能力的工程化突破&lt;/h2&gt;
&lt;h3 id="设计哲学让大模型从闭卷考试变成开卷考试"&gt;设计哲学：让大模型从「闭卷考试」变成「开卷考试」&lt;/h3&gt;
&lt;p&gt;提示词工程很快遇到了它的能力天花板：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;上下文窗口长度限制，无法注入大量的领域知识&lt;/li&gt;
&lt;li&gt;知识更新滞后，大模型的训练数据是静态的，无法获取实时信息&lt;/li&gt;
&lt;li&gt;幻觉问题难以避免，大模型会编造不存在的信息&lt;/li&gt;
&lt;li&gt;知识复用成本高，每次交互都需要重复注入相同的背景信息&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;上下文工程（核心是RAG技术体系）的出现就是为了系统性解决这些问题，它的设计哲学非常朴素：&lt;strong&gt;既然大模型的「内部记忆」有限且不可修改，那就给它外接一个「外部知识库」，让它可以动态检索需要的信息来回答问题&lt;/strong&gt;。&lt;/p&gt;</description></item><item><title>【Vibe-Coding】前后端基础知识扫盲-1</title><link>https://tingdonghu.github.io/posts/ai%E7%BC%96%E7%A8%8B/ai%E7%BC%96%E7%A8%8B%E5%89%8D%E5%90%8E%E7%AB%AF%E7%9F%A5%E8%AF%86%E6%89%AB%E7%9B%B21/</link><pubDate>Mon, 13 Apr 2026 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/ai%E7%BC%96%E7%A8%8B/ai%E7%BC%96%E7%A8%8B%E5%89%8D%E5%90%8E%E7%AB%AF%E7%9F%A5%E8%AF%86%E6%89%AB%E7%9B%B21/</guid><description>&lt;hr&gt;
&lt;blockquote class="dream-alert tip"&gt;
&lt;p class="heading"&gt;
&lt;ion-icon name="bulb-outline"&gt;&lt;/ion-icon&gt;Tip&lt;/p&gt;
&lt;p&gt;最近疯狂迷恋Vibe Coding, 一闲下来就在和AI交流，发现一个问题，就是虽然AI能基于需求快速构建一个产品，但是由于我没有体系的学过WEB产品的开发知识，导致我想要指定AI对某一具体细节内容进行修改，只能描述当前的问题是什么，想要达到效果是什么。&lt;/p&gt;
&lt;p&gt;这种模式一方面导致产品对我来说几乎是一个黑盒，快速开发到及格没问题，但是很难达到我理想的效果，而且这种编码方式有时候也不是很可控，出现问题只能靠AI，AI会为了改一个简单的问题而去动一些全局的架构文件，以至于牵一发而动全身。&lt;/p&gt;
&lt;p&gt;还有就是一些具体的前端问题，样式微调对AI来说还是有点困难，还需要手动定位调整，鉴于此我决定来一次WEB产品的地毯式快速入门，以帮助我能更好的定位问题和构建产品，由于我本身有一些编程基础，所以具体的语法可以不是很关注，主要学某个东西是什么、为什么这样做，现代WEB产品构建有没有更高级模块化的方案了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;想象一下，你正在用淘宝购物、在微信上聊天、或者在B站看视频。这些看似简单的操作，背后其实有一个庞大而精密的系统在运转。当你点击&amp;quot;购买&amp;quot;按钮时，数据就像快递包裹一样，在你的手机、服务器、数据库之间来回传递。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/ai%E7%BC%96%E7%A8%8B/ai%E7%BC%96%E7%A8%8B%E5%89%8D%E5%90%8E%E7%AB%AF%E7%9F%A5%E8%AF%86%E6%89%AB%E7%9B%B21/01-vibe-coding-workflow.png"
alt="Vibe-Coding工作流"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
Vibe-Coding工作流
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="第一章网页是如何工作的"&gt;第一章：网页是如何工作的？&lt;/h2&gt;
&lt;h3 id="11-从输入网址到看到页面发生了什么"&gt;1.1 从输入网址到看到页面，发生了什么？&lt;/h3&gt;
&lt;p&gt;让我们从一个最熟悉的场景开始：你在浏览器地址栏输入 &lt;code&gt;www.taobao.com&lt;/code&gt;，然后按下回车。接下来的几毫秒里，到底发生了什么？&lt;/p&gt;
&lt;p&gt;让我用一个&amp;quot;餐厅吃饭&amp;quot;的比喻来帮你理解：&lt;/p&gt;
&lt;div class="code-block" data-lang="text"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;text&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;你的操作：在浏览器输入 www.taobao.com
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;第一步：浏览器问&amp;#34;服务员&amp;#34;（DNS）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;www.taobao.com 这个餐厅的地址在哪？&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; DNS 回答：&amp;#34;哦，那家店啊，地址是 110.75.115.70&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;第二步：浏览器&amp;#34;开车&amp;#34;到那个地址
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;#34;你好，我想来份淘宝首页！&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;第三步：餐厅&amp;#34;后厨&amp;#34;（服务器）开始准备
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 看看你要什么菜（数据）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 去&amp;#34;仓库&amp;#34;（数据库）拿食材
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 把菜&amp;#34;炒&amp;#34;好（处理数据）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 装盘（组装成网页）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;第四步：服务员把菜端过来
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;第五步：你开始&amp;#34;吃&amp;#34;（浏览器渲染）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 先看菜的样子（HTML结构）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 再看摆盘好不好看（CSS样式）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; - 尝尝味道（JavaScript交互）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;你看到的：淘宝首页！&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这个比喻是不是好懂多了？接下来，让我们把这个比喻里的每个角色，翻译成程序员的语言。&lt;/p&gt;</description></item><item><title>【LLM应用开发原理】Agent记忆与检索</title><link>https://tingdonghu.github.io/posts/agent/llm%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E5%8E%9F%E7%90%86agent%E8%AE%B0%E5%BF%86%E4%B8%8E%E6%A3%80%E7%B4%A2/</link><pubDate>Tue, 10 Mar 2026 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/agent/llm%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E5%8E%9F%E7%90%86agent%E8%AE%B0%E5%BF%86%E4%B8%8E%E6%A3%80%E7%B4%A2/</guid><description>&lt;hr&gt;</description></item><item><title>【LLM应用开发原理】Function Calling底层原理与MCP</title><link>https://tingdonghu.github.io/posts/agent/llm%E6%8A%80%E6%9C%AFmcp%E6%98%AF%E4%BB%80%E4%B9%88%E5%AE%97%E8%BF%B0%E5%92%8C%E6%A6%82%E5%BF%B5%E6%A2%B3%E7%90%86/</link><pubDate>Mon, 09 Mar 2026 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/agent/llm%E6%8A%80%E6%9C%AFmcp%E6%98%AF%E4%BB%80%E4%B9%88%E5%AE%97%E8%BF%B0%E5%92%8C%E6%A6%82%E5%BF%B5%E6%A2%B3%E7%90%86/</guid><description>&lt;h1 id="从只能回答到能调用工具llm能力的演进"&gt;从&amp;quot;只能回答&amp;quot;到&amp;quot;能调用工具&amp;quot;：LLM能力的演进&lt;/h1&gt;
&lt;h2 id="背景与演进"&gt;背景与演进&lt;/h2&gt;
&lt;p&gt;在传统的 LLM 交互中，模型只能通过自然语言与用户对话。无论用户问什么问题，LLM 都只能基于其训练数据生成文本回答——它无法真正&amp;quot;做&amp;quot;任何事情，比如查询实时天气、读取数据库、发送邮件或执行代码。&lt;/p&gt;
&lt;p&gt;这就好比一个非常博学但行动力为零的学者：他知道一切知识，但当你让他&amp;quot;帮我查一下明天的航班&amp;quot;时，他只能告诉你&amp;quot;我很抱歉，我无法访问实时数据&amp;quot;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Function Calling 的出现，改变了这一局面&lt;/strong&gt;。它让 LLM 从&amp;quot;只能回答问题&amp;quot;的被动角色，变成了&amp;quot;能指挥工具干活&amp;quot;的主动指挥官。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;核心比喻&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;传统 LLM&lt;/strong&gt;：像一台只有屏幕的电视机——只能被动显示内容&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Function Calling&lt;/strong&gt;：给这台电视接上了遥控器——可以控制外部设备&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MCP&lt;/strong&gt;：为所有遥控器制定了统一的标准协议&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;延伸阅读&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://platform.openai.com/docs/guides/function-calling" target="_blank"&gt;OpenAI Function Calling Documentation&lt;/a&gt;
- Function Calling官方文档&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.anthropic.com/en/docs/build-with-claude/tool-use" target="_blank"&gt;Anthropic Tool Use Guide&lt;/a&gt;
- Claude工具调用指南&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2 id="function-calling底层原理"&gt;Function Calling底层原理&lt;/h2&gt;
&lt;p&gt;现代大模型（如 GPT-4、Claude、Qwen-7B-Chat 等）之所以能够精准调用工具，是因为在训练阶段进行了特殊的&lt;strong&gt;有监督微调&lt;/strong&gt;，使用精心构造的数据集让模型建立了&amp;quot;任务意图→工具选择→参数提取&amp;quot;的概率关联。&lt;/p&gt;
&lt;p&gt;这一过程让模型学会：当用户意图匹配某个工具时，不再输出自然语言，而是输出特定格式的结构化数据（通常是 JSON），方便代理层解析并执行相应的服务调用。&lt;/p&gt;
&lt;p&gt;从技术角度看，Function Calling 的实现涉及三个层面：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;层面&lt;/th&gt;
&lt;th&gt;核心机制&lt;/th&gt;
&lt;th&gt;解决的问题&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;训练层面&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;有监督微调（SFT）&lt;/td&gt;
&lt;td&gt;让模型&amp;quot;学会&amp;quot;识别何时需要调用工具&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;推理层面&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;约束解码（Constrained Decoding）&lt;/td&gt;
&lt;td&gt;保证输出 JSON 的语法正确性&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;协议层面&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;标准循环交互&lt;/td&gt;
&lt;td&gt;实现意图→执行→→结果的完整闭环&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/agent/llm%E6%8A%80%E6%9C%AFmcp%E6%98%AF%E4%BB%80%E4%B9%88%E5%AE%97%E8%BF%B0%E5%92%8C%E6%A6%82%E5%BF%B5%E6%A2%B3%E7%90%86/01-framework-function-calling-layers.png"
alt="Function Calling 三层技术架构"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
Function Calling 三层技术架构
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;</description></item><item><title>【LLM应用开发原理】Agent Skill原理与基础</title><link>https://tingdonghu.github.io/posts/agent/llm%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E5%8E%9F%E7%90%86agentskill%E5%8E%9F%E7%90%86%E4%B8%8E%E5%9F%BA%E7%A1%80/</link><pubDate>Mon, 09 Mar 2026 00:00:00 +1200</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/agent/llm%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E5%8E%9F%E7%90%86agentskill%E5%8E%9F%E7%90%86%E4%B8%8E%E5%9F%BA%E7%A1%80/</guid><description>&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/agent/llm%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E5%8E%9F%E7%90%86agentskill%E5%8E%9F%E7%90%86%E4%B8%8E%E5%9F%BA%E7%A1%80/00-framework-skill-concept-overview.png"
alt="Skill在Agent架构中的全景位置"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
Skill在Agent架构中的全景位置
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="从工具到技能agent能力的进化"&gt;从工具到技能：Agent能力的进化&lt;/h2&gt;
&lt;p&gt;在Agent开发的早期阶段，我们通过**工具调用（Tool Calling）**让模型具备了访问外部世界的能力。这一模式最早由OpenAI在2023年3月的GPT-4 API中正式引入，随后成为业界标准。但随着任务复杂度的提升，单纯的工具集合逐渐暴露出局限性。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;维度&lt;/th&gt;
&lt;th&gt;工具（Tool）&lt;/th&gt;
&lt;th&gt;技能（Skill）&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;粒度&lt;/td&gt;
&lt;td&gt;单一动作（如&amp;quot;搜索&amp;quot;）&lt;/td&gt;
&lt;td&gt;组合流程（如&amp;quot;撰写研报&amp;quot;）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;逻辑&lt;/td&gt;
&lt;td&gt;无状态，单次调用&lt;/td&gt;
&lt;td&gt;有状态，多步协调&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;复用&lt;/td&gt;
&lt;td&gt;通用性强，场景普适&lt;/td&gt;
&lt;td&gt;领域特定，针对性强&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;依赖&lt;/td&gt;
&lt;td&gt;独立执行&lt;/td&gt;
&lt;td&gt;可依赖其他技能/工具&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;抽象层级&lt;/td&gt;
&lt;td&gt;底层原语&lt;/td&gt;
&lt;td&gt;高层能力&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/agent/llm%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E5%8E%9F%E7%90%86agentskill%E5%8E%9F%E7%90%86%E4%B8%8E%E5%9F%BA%E7%A1%80/01-infographic-tool-to-skill-evolution.png"
alt="从工具到技能的进化"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
从工具到技能的进化
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="skill的设计起源"&gt;Skill的设计起源&lt;/h2&gt;
&lt;h3 id="1-软件工程的模块化思想"&gt;1. 软件工程的模块化思想&lt;/h3&gt;
&lt;p&gt;Skill的设计灵感源于软件工程中久经考验的**模块化编程（Modular Programming）**思想，这一思想可追溯到Dijkstra在1968年发表的经典论文《&lt;a href="https://archive.org/details/disciplineofprogr0000dijk" target="_blank"&gt;A Discipline of Programming&lt;/a&gt;
》&lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;。正如Parnas在1972年《&lt;a href="https://dl.acm.org/doi/10.1145/361094.361138" target="_blank"&gt;On the Criteria to Be Used in Decomposing Systems into Modules&lt;/a&gt;
》&lt;sup id="fnref:2"&gt;&lt;a href="#fn:2" class="footnote-ref" role="doc-noteref"&gt;2&lt;/a&gt;&lt;/sup&gt;中所阐述的，模块化的核心在于&amp;quot;信息隐藏&amp;quot;（Information Hiding）——将复杂的实现细节封装在模块内部，只暴露必要的接口。&lt;/p&gt;</description></item><item><title>【LLM应用开发原理】Agent经典开发范式</title><link>https://tingdonghu.github.io/posts/agent/llm%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E5%8E%9F%E7%90%86agent%E7%BB%8F%E5%85%B8%E5%BC%80%E5%8F%91%E8%8C%83%E5%BC%8F/</link><pubDate>Fri, 06 Mar 2026 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/agent/llm%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E5%8E%9F%E7%90%86agent%E7%BB%8F%E5%85%B8%E5%BC%80%E5%8F%91%E8%8C%83%E5%BC%8F/</guid><description>&lt;h3 id="动手学agent"&gt;动手学Agent&lt;/h3&gt;
&lt;p&gt;推荐一个Datawhale开源项目，体系学习，动手实现一个简单Agent架构：&lt;a href="https://github.com/datawhalechina/hello-agents" target="_blank"&gt;HelloAgent&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;具体的编码实现项目中非常详细，本博文中我只尝试做一个设计思想整理。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;延伸阅读&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://python.langchain.com/docs/tutorials/agents/" target="_blank"&gt;LangChain: Getting Started with Agents&lt;/a&gt;
- 主流Agent框架的实现细节&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Significant-Gravitas/AutoGPT" target="_blank"&gt;AutoGPT: Autonomous GPT-4 Agent&lt;/a&gt;
- 首个自主Agent的探索&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/yoheinakajima/babyagi" target="_blank"&gt;BabyAGI: Task-driven Autonomous Agent&lt;/a&gt;
- 任务驱动的自主Agent实现&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2 id="agent经典范式"&gt;Agent经典范式&lt;/h2&gt;
&lt;h3 id="1-react范式reasoning-and-acting"&gt;1. ReAct范式（Reasoning and Acting）&lt;/h3&gt;
&lt;p&gt;最基础、应用最广的范式，是目前绝大多数 Agent 的基石。&lt;/p&gt;
&lt;p&gt;它模仿人类解决问题的直觉：&lt;strong&gt;先思考（Thought），再行动（Action），最后观察结果（Observation）。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心思想解析&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;ReAct的精髓在于将&amp;quot;推理&amp;quot;（Reasoning）和&amp;quot;行动&amp;quot;（Acting）融合在同一循环中。这与传统程序设计的&amp;quot;分析-执行&amp;quot;分离模式截然不同。&lt;/p&gt;
&lt;p&gt;想象一下人类解决数学应用题的过程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;阅读题目（理解问题）&lt;/li&gt;
&lt;li&gt;思考需要什么条件（Thought）&lt;/li&gt;
&lt;li&gt;列出已知和未知的量（分析）&lt;/li&gt;
&lt;li&gt;应用公式计算（Action）&lt;/li&gt;
&lt;li&gt;验证结果是否合理（Observation）&lt;/li&gt;
&lt;li&gt;如果不合理，调整思路重新计算（循环）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;ReAct范式正是将这种人类自然的解决问题方式形式化，让LLM能够像人类一样&amp;quot;边想边做&amp;quot;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;逻辑链路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;传统LLM是一问一答。ReAct引入了一个&lt;strong&gt;循环&lt;/strong&gt;（Loop）&lt;/p&gt;
$$用户输入 \xrightarrow{思考} 行为 \xrightarrow{观察} 再次思考 \dots 直到得出答案$$&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/agent/llm%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E5%8E%9F%E7%90%86agent%E7%BB%8F%E5%85%B8%E5%BC%80%E5%8F%91%E8%8C%83%E5%BC%8F/01-flowchart-react-loop.png"
alt="ReAct循环流程"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
ReAct循环流程
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;</description></item><item><title>【LLM应用开发原理】我怎样理解Agent</title><link>https://tingdonghu.github.io/posts/agent/llm%E6%8A%80%E6%9C%AF%E6%88%91%E6%80%8E%E6%A0%B7%E7%90%86%E8%A7%A3agent/</link><pubDate>Thu, 05 Mar 2026 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/agent/llm%E6%8A%80%E6%9C%AF%E6%88%91%E6%80%8E%E6%A0%B7%E7%90%86%E8%A7%A3agent/</guid><description>&lt;p&gt;寒假开学以来，一直在学习一些Agent相关的技术文档和媒体视频，从概念设计思想到手搓了几个Demo，最近在尝试拆解一些热门框架的源码，这段时间的学习让我对Agent的看法大为改观，沉迷于每日头脑风暴，有些想法不吐不快，做此纪录。&lt;/p&gt;
&lt;h2 id="怎样理解agent"&gt;怎样理解Agent&lt;/h2&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/agent/llm%E6%8A%80%E6%9C%AF%E6%88%91%E6%80%8E%E6%A0%B7%E7%90%86%E8%A7%A3agent/image-20260307194504863.png"
alt="Chat类AI产品"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
Chat类AI产品
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;自 2023 年 ChatGPT 引爆全球以来，我几乎每天都在与各类 Chat 产品交互。在那段时期，我对大模型的认知还停留在一个极简的逻辑上——&lt;strong&gt;&amp;ldquo;模型即产品”&lt;/strong&gt;。我理所当然地认为，大模型就是一个能与我无障碍交流的聊天窗口。&lt;/p&gt;
&lt;p&gt;随后，前年开始，Agent(智能体)的概念被自媒体反复咀嚼与炒作：从早期的&amp;quot;工作流颠覆世界”，到后来层出不穷、月更不辍的新名词，每一波浪潮都宣称要重塑人类社会。这种浮躁的空气让我对 Agent 这个词产生了某种程度的&amp;rdquo;&lt;strong&gt;PTSD&lt;/strong&gt;(创伤后应激障碍)”，导致我迟迟没有沉下心去剖析它的底层机理。&lt;/p&gt;
&lt;p&gt;但在这一段时间系统性的学习后，我大致认清了Agent的产品形态。现在，我可以非常肯定地给出一个核心结论：&lt;strong&gt;Agent 绝非炒作概念，它是以大模型为核心驱动(类似CPU)的下一代操作系统。&lt;/strong&gt; 我们此前以及现在所使用的所有顶级 AI 产品，剥开它们的对话外壳，其本质都是一套复杂而精密的 Agent 系统。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/agent/llm%E6%8A%80%E6%9C%AF%E6%88%91%E6%80%8E%E6%A0%B7%E7%90%86%E8%A7%A3agent/image-20260307194545131.png"
alt="复杂Agent案例"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
复杂Agent案例
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;h3 id="transformer的无状态性"&gt;Transformer的无状态性&lt;/h3&gt;
&lt;p&gt;提到大模型与 Agent 的进化，绕不开 AI 时代真正的分水岭：Transformer 架构。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://tingdonghu.github.io/posts/llm%e6%8a%80%e6%9c%aftransformer%e6%9e%b6%e6%9e%84%e5%ae%97%e8%bf%b0/" target="_blank"&gt;【LLM技术】Transformer架构宗述 | 古月月仔的博客&lt;/a&gt;
&lt;/p&gt;</description></item><item><title>【年度总结】致我的2025：一些事实与感受</title><link>https://tingdonghu.github.io/posts/%E4%B8%AA%E4%BA%BA%E6%84%9F%E6%82%9F/%E5%B9%B4%E5%BA%A6%E6%80%BB%E7%BB%93%E8%87%B4%E6%88%91%E7%9A%842025%E4%B8%80%E4%BA%9B%E4%BA%8B%E5%AE%9E%E4%B8%8E%E6%84%9F%E5%8F%97/</link><pubDate>Mon, 26 Jan 2026 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/%E4%B8%AA%E4%BA%BA%E6%84%9F%E6%82%9F/%E5%B9%B4%E5%BA%A6%E6%80%BB%E7%BB%93%E8%87%B4%E6%88%91%E7%9A%842025%E4%B8%80%E4%BA%9B%E4%BA%8B%E5%AE%9E%E4%B8%8E%E6%84%9F%E5%8F%97/</guid><description>&lt;hr&gt;
&lt;h2 id="致我的2025一些事实与感受"&gt;&lt;strong&gt;致我的2025：一些事实与感受&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;听到Eason在《四季》里唱：“最后已事过境迁 长街风景已变” ，虽然语境情感不同，却突然增加好多情感流动和共鸣。&lt;/p&gt;
&lt;p&gt;又至一年腊八，感慨过去这一年，自己也历尽了四季轮回。如今回首，2025年的每一季风霜雨雪，都在有形与无形中塑造延续着我。自己对关于爱、失去、成长、身份与存在这些人生命题有了一些新的感受。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E4%B8%AA%E4%BA%BA%E6%84%9F%E6%82%9F/%E5%B9%B4%E5%BA%A6%E6%80%BB%E7%BB%93%E8%87%B4%E6%88%91%E7%9A%842025%E4%B8%80%E4%BA%9B%E4%BA%8B%E5%AE%9E%E4%B8%8E%E6%84%9F%E5%8F%97/mmexport1769402412113.jpg"
alt="蛇年打铁花留念"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
蛇年打铁花留念
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;h3 id="春"&gt;春&lt;/h3&gt;
&lt;p&gt;保研后的第一个长假，我同时在做好几件事：为之后的科研做点准备，保持学习习惯，还有一份实习。拿到第一笔自己赚的、不算少的钱时，感觉很好，计划着给奶奶买点什么。但她没等到。事情发生在寒假末尾，很突然。&lt;/p&gt;
&lt;p&gt;之后的一段时间都处于一种当时不知道如何描述的难过中。现在回想，在这种难过里，有一部分是因为想起高中时一位好友，同样的猝不及防，以至我时常怀疑只是一场梦。还有一部分，是清明回家，我发现关于她的痕迹比我想象中少很多，我之前疏于记录，更难以找到合照，家里人也在平常避免提起奶奶，好像这样就能避开伤心。我无法批评这种的行为的对错，因为发现自己也会无意识地避免去想高中的那位好友，避免去想奶奶。我害怕面对，也全然学不会如何面对死亡，只是忽地想到：在不经意间，我自己也变成了遗忘的同谋。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E4%B8%AA%E4%BA%BA%E6%84%9F%E6%82%9F/%E5%B9%B4%E5%BA%A6%E6%80%BB%E7%BB%93%E8%87%B4%E6%88%91%E7%9A%842025%E4%B8%80%E4%BA%9B%E4%BA%8B%E5%AE%9E%E4%B8%8E%E6%84%9F%E5%8F%97/1000114361-1769398789309edit.jpg"
alt="找到的一张合照"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
找到的一张合照
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;h3 id="夏"&gt;夏&lt;/h3&gt;
&lt;p&gt;毕业前最后的夏天，我刻意让自己慢下来，像一位收藏家一样细细感受每一份情感，时间突然多出来了，做了两件事：&lt;/p&gt;
&lt;p&gt;一是和朋友们好好告别。和宠爱我的老师、实验室同袍、舍友、开黑小团体吃了很多次饭，谈天说地，暑假也和几个朋友约着去了彼此的城市，或者又自己一人去了新的城市，作为一场城市生命的短暂访客。广州早茶的烟火气，苏州的园林曲径，这些画面和毕业的感伤混在一起，成了很复杂的记忆。&lt;/p&gt;
&lt;p&gt;二是我开始有意识地去“记录”感受。记住别人对我的好，也记住我对他人的不舍。我把自己的毕业季，当作一场盛大的、需要全身心投入的仪式来体验。好像又有突然明白：真正的告别，不是在那一天，而是在那之后无数个回想起“最后一次”的瞬间。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E4%B8%AA%E4%BA%BA%E6%84%9F%E6%82%9F/%E5%B9%B4%E5%BA%A6%E6%80%BB%E7%BB%93%E8%87%B4%E6%88%91%E7%9A%842025%E4%B8%80%E4%BA%9B%E4%BA%8B%E5%AE%9E%E4%B8%8E%E6%84%9F%E5%8F%97/1000114920.jpeg"
alt="红浪漫成员毕业留念"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
红浪漫成员毕业留念
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;</description></item><item><title>【C++】组合、继承和多态</title><link>https://tingdonghu.github.io/posts/%E4%BE%AF%E6%8D%B7%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/c++%E7%BB%84%E5%90%88%E7%BB%A7%E6%89%BF%E5%92%8C%E5%A4%9A%E6%80%81/</link><pubDate>Mon, 05 Jan 2026 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/%E4%BE%AF%E6%8D%B7%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/c++%E7%BB%84%E5%90%88%E7%BB%A7%E6%89%BF%E5%92%8C%E5%A4%9A%E6%80%81/</guid><description>&lt;hr&gt;
&lt;p&gt;组合（Composition）、继承（Inheritance）和多态（Polymorphism）是C++中面向对象编程（OOP）的三大支柱。&lt;/p&gt;
&lt;p&gt;之前只在大学课本上学到一点皮毛，在此做复习和深入挖掘。&lt;/p&gt;
&lt;h2 id="组合-composition物理嵌套与高效复用"&gt;组合 (Composition)物理嵌套与高效复用&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;组合&lt;/strong&gt;描述的是一种“有一个 (Has-a)”的关系。在 C++ 中，当我们将一个类的对象作为另一个类的数据成员时，就形成了组合。&lt;/p&gt;
&lt;p&gt;从内存布局的角度来看，组合体现为&lt;strong&gt;物理上的直接嵌套&lt;/strong&gt;：成员对象的所有数据成员被完整地包含在宿主对象的内存空间内。这意味着，如果你在栈上创建一个宿主对象，其组合的所有成员也都在栈上；同理，若宿主在堆上，成员也在堆上。&lt;/p&gt;
&lt;p&gt;这种布局方式带来了极高的执行效率，因为数据在内存中是连续存放的，极大提高了 CPU 的缓存命中率。&lt;/p&gt;
&lt;p&gt;在初始化逻辑上，C++ 遵循严格的顺序：&lt;strong&gt;成员对象先构造，宿主对象后构造&lt;/strong&gt;；析构时则完全相反。设计上，C++ 社区推崇“优先使用组合而非继承”，因为组合是一种“黑盒复用”，宿主类只需关心成员类的公共接口，而不需要了解其内部实现，这大大降低了代码间的耦合度。&lt;/p&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Engine&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* 引擎数据 */&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Car&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Engine&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Car 组合了 Engine
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;如果你在栈上创建一个 &lt;code&gt;Car&lt;/code&gt; 对象，那么 &lt;code&gt;Engine&lt;/code&gt; 的数据会&lt;strong&gt;直接包含&lt;/strong&gt;在 &lt;code&gt;Car&lt;/code&gt; 的内存块内部。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;设计原则&lt;/strong&gt;：&lt;strong&gt;优先使用组合，而不是继承&lt;/strong&gt;。组合耦合度低，灵活性高。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;生命周期&lt;/strong&gt;：成员对象（Engine）随宿主对象（Car）的创建而创建，随其销毁而销毁。&lt;/p&gt;
&lt;h2 id="继承-inheritance结构延伸与逻辑分类"&gt;继承 (Inheritance)：结构延伸与逻辑分类&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;继承&lt;/strong&gt;建立的是一种“是一个 (Is-a)”的关系，允许你基于已有的类创建新类，从而复用代码。它允许子类继承父类的属性和行为。&lt;/p&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Animal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;eat&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Eating...&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Animal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// Cat 继承自 Animal
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;meow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Meow!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;派生类（Cat）的内存结构是：&lt;strong&gt;父类的数据成员 + 派生类特有的数据成员&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;核心逻辑&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;可见性&lt;/strong&gt;：&lt;code&gt;public&lt;/code&gt; 继承表示父类的公有成员在子类中依然公有。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;构造顺序&lt;/strong&gt;：先调用父类构造函数，再调用子类构造函数。析构顺序则相反。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在内存层面，继承表现为&lt;strong&gt;结构的延伸&lt;/strong&gt;：子类对象的内存块头部通常包含了一个完整的父类对象副本，随后才是子类特有的数据成员。这种“头部对齐”的特性使得父类指针能够安全地指向子类对象的起始地址。&lt;/p&gt;
&lt;p&gt;继承被称为“白盒复用”，因为子类往往能够看到父类的 &lt;code&gt;protected&lt;/code&gt; 成员，这虽然增强了灵活性，但也导致了较高的耦合——父类的任何微小改动都可能波及整个继承链。&lt;/p&gt;</description></item><item><title>【C++】作用域与内存管理</title><link>https://tingdonghu.github.io/posts/%E4%BE%AF%E6%8D%B7%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/c++%E5%8F%98%E9%87%8F%E7%9A%84%E4%BD%9C%E7%94%A8%E5%9F%9F%E4%B8%8E%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/</link><pubDate>Fri, 02 Jan 2026 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/%E4%BE%AF%E6%8D%B7%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/c++%E5%8F%98%E9%87%8F%E7%9A%84%E4%BD%9C%E7%94%A8%E5%9F%9F%E4%B8%8E%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86/</guid><description>&lt;hr&gt;
&lt;h2 id="生命周期与作用域的区别"&gt;生命周期与作用域的区别&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;作用域（Scope）是空间/代码&lt;/strong&gt;维度的概念：指你的变量名在代码的哪个范围内“可见”（编译器能认出这个名字）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;生命周期（Lifetime）是时间/内存&lt;/strong&gt;维度的概念：指变量在程序运行过程中，从“分配内存”到“释放内存”的这段物理时间。&lt;/p&gt;
&lt;p&gt;对于&lt;strong&gt;栈对象&lt;/strong&gt;，两者几乎是绑定的，栈对象的作用域决定了其生命周期；作用域结束的地方，就是生命周期终结的地方。&lt;/p&gt;
&lt;p&gt;对于&lt;strong&gt;堆对象&lt;/strong&gt;，其作用域和生命周期则是分离的；一般来说堆对象的的名字（指针）有作用域，但对象本身没有。&lt;/p&gt;
&lt;h2 id="object的生命周期"&gt;Object的生命周期&lt;/h2&gt;
&lt;p&gt;在 C++ 中，对象的生命周期是指从对象被创建到被销毁的整个过程。&lt;/p&gt;
&lt;p&gt;CPP中的内存布局主要分为五个区域，其中最核心的是栈内存和堆内存。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;区域&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;存储内容&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;生命周期&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;栈 (Stack)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;局部变量、函数参数、返回地址。&lt;/td&gt;
&lt;td&gt;自动管理，进入作用域创建，离开销毁。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;堆 (Heap)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;通过 &lt;code&gt;new&lt;/code&gt; 分配的对象。&lt;/td&gt;
&lt;td&gt;手动管理，直到 &lt;code&gt;delete&lt;/code&gt; 或程序结束。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;全局/静态存储区&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;全局变量、&lt;code&gt;static&lt;/code&gt; 变量。&lt;/td&gt;
&lt;td&gt;程序启动时分配，程序结束时释放。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;常量存储区&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;字符串常量（如 &lt;code&gt;&amp;quot;Hello&amp;quot;&lt;/code&gt;）。&lt;/td&gt;
&lt;td&gt;整个程序运行期间。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;代码区 (Text)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;程序的机器指令（二进制代码）。&lt;/td&gt;
&lt;td&gt;只读，整个程序运行期间。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="栈-stack-与-栈对象"&gt;栈 (Stack) 与 栈对象&lt;/h2&gt;
&lt;h3 id="什么是栈"&gt;什么是栈？&lt;/h3&gt;
&lt;p&gt;栈是一块连续的内存区域。它的运作模式是 &lt;strong&gt;LIFO (Last In, First Out，后进先出)&lt;/strong&gt;。类似于你在往弹夹里压子弹，最后压进去的子弹，最先被打出来。&lt;/p&gt;
&lt;h3 id="什么是栈对象-stack-objects"&gt;什么是栈对象 (Stack Objects)？&lt;/h3&gt;
&lt;p&gt;通常指&lt;strong&gt;值类型 (Value Types)&lt;/strong&gt; 或 &lt;strong&gt;基本数据类型&lt;/strong&gt;。一般包含：局部变量（如 &lt;code&gt;int a = 10&lt;/code&gt;）、函数参数、函数返回地址等。&lt;/p&gt;
&lt;p&gt;栈对象的生命周期非常短。当一个函数（方法）开始执行时，系统会在栈上“压入”一个&lt;strong&gt;栈帧 (Stack Frame)&lt;/strong&gt;，里面装着这个函数需要的所有局部变量。当函数执行结束（&lt;code&gt;return&lt;/code&gt;），这个栈帧直接被“弹出”，所有数据瞬间销毁。&lt;/p&gt;
&lt;p&gt;栈对象不需要担心内存泄漏，速度极快，CPU 甚至有专门的指令来处理栈指针。&lt;/p&gt;
&lt;blockquote class="dream-alert note"&gt;
&lt;p class="heading"&gt;
&lt;ion-icon name="information-circle-outline"&gt;&lt;/ion-icon&gt;Note&lt;/p&gt;
&lt;p&gt;在 C++ 或 Swift (Struct) 中，复杂的对象也可以完全存在栈上。但在 Java 或 C# 中，通常只有基本类型（int, boolean）和对象的&lt;strong&gt;引用&lt;/strong&gt;在栈上。&lt;/p&gt;</description></item><item><title>【C++】LearnCppDate</title><link>https://tingdonghu.github.io/posts/c++/c++learncppdate/</link><pubDate>Thu, 01 Jan 2026 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/c++/c++learncppdate/</guid><description>&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;最近在学习的时候发现自己陷入了一个瓶颈，就是发现自己过去主要的学习方式&amp;ndash;看视频，大脑有点脱敏，且频频走神。看视频时常产生一种“我在进步”的错觉，但实际写代码时会大脑一片空白。&lt;/p&gt;
&lt;p&gt;之前看过的一本书&lt;a href="https://1000h.org/training-tasks/language.html" target="_blank"&gt;《1000hours》&lt;/a&gt;
里曾经提到一种理论，和我现在的情况很像，就是如果在学习一项技能，或者学习一个新事物时，如果仅仅是投入时间和金钱，但是没有投入最重要的&lt;strong&gt;注意力&lt;/strong&gt;，则其效率会变的非常低下。&lt;/p&gt;
&lt;p&gt;自己思考了一下发现自己现在日常生活中最专注的情况主要是：读书、和AI深度交流、完全沉浸式的娱乐；基于自己的专注能力，打算亲身实践一下新的学习方法，即啃高信息密度的书/文档、遇到不懂的问题问AI，遇到需要动图辅助理解的知识点再去找视频讲解，最后对每日啃过的内容进行一个思维整理输出，写为笔记方便复习，希望新的学习方法能改善我当前的学习困境。&lt;/p&gt;
&lt;p&gt;本篇笔记的内容也主要集中于我在啃这个网站&lt;a href="https://www.learncpp.com/" target="_blank"&gt;Learn C++ – Skill up with our free tutorials&lt;/a&gt;
文档内容的每日总结输出，和中间过程与AI探讨的一些小Tips和理解。&lt;/p&gt;
&lt;h2 id="day01"&gt;Day01&lt;/h2&gt;
&lt;h3 id="programs-and-programming-languages"&gt;Programs and programming languages&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;计算机硬件的局限性与“二进制”语言&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;计算机的核心由 &lt;strong&gt;CPU（中央处理器）&lt;/strong&gt; 和 &lt;strong&gt;内存（RAM）&lt;/strong&gt; 组成。尽管 CPU 拥有强大的计算能力，但它本质上是非常“笨”的，只能识别电信号的通（1）与断（0）。这意味着，计算机原生唯一能理解的语言就是&lt;strong&gt;机器语言（Machine Language）&lt;/strong&gt;。程序员在早期必须通过冗长的 0 和 1 序列来下达指令，这不仅极其违反人类直觉、容易出错，而且由于不同厂家的 CPU 指令集各异，一份代码无法在不同的电脑上通用，这种“不可移植性”严重限制了软件的发展。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;低级语言的改良：汇编语言的过渡&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;为了缓解机器语言带来的痛苦，&lt;strong&gt;汇编语言（Assembly Language）&lt;/strong&gt; 应运而生。它引入了“助记符”的概念，用简单的英文单词（如 &lt;code&gt;ADD&lt;/code&gt;、&lt;code&gt;MOV&lt;/code&gt;）代替了晦涩的二进制码。虽然这让代码变得稍微可读了一些，但它依然属于&lt;strong&gt;低级语言&lt;/strong&gt;。汇编语言与底层硬件是一一对应的，程序员仍需关注寄存器和内存地址等硬件细节。此外，它依然需要一个名为“汇编器”的工具将其翻译回机器码，且跨平台运行的问题依然没有得到根本解决。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;高级语言的革命：效率与跨平台的飞跃&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;为了让编程真正回归逻辑本身，&lt;strong&gt;高级语言（High-level Languages）&lt;/strong&gt;（如 C++、C、Python）成为了现代开发的主流。高级语言最大的突破在于它允许程序员使用接近自然语言和数学逻辑的方式编写代码。更重要的是，它通过**编译器（Compiler）**实现了代码的“可移植性”：程序员只需编写一套逻辑，编译器就能根据不同的目标机器，将其翻译成对应的机器码。这种抽象不仅让代码更易维护，还让复杂软件的协作开发成为了可能。&lt;/p&gt;
&lt;blockquote class="dream-alert note"&gt;
&lt;p class="heading"&gt;
&lt;ion-icon name="information-circle-outline"&gt;&lt;/ion-icon&gt;Note&lt;/p&gt;
&lt;p&gt;跨平台是高级语言与硬件脱钩后的必然产物。它将程序员从繁琐的硬件指令中解放出来，专注于逻辑表达。尽管 C++ 需要为不同平台重新编译（源码级跨平台），而 Java/Python 通过虚拟机实现（字节码级跨平台），但它们的本质逻辑是一致的：即通过一层“翻译中介”，屏蔽底层硬件差异。作为开发者，应当区分“语言特性”与“系统特性”，优先使用标准库以确保代码的可移植性。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;翻译的双轨制：编译器Compiler与 解释器Interpreter&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在高级语言进化的过程中，为了平衡“运行效率”与“开发便捷性”，分化出了两种核心的翻译策略。&lt;strong&gt;编译器&lt;/strong&gt;路线（以 C/C++ 为代表）采取的是“离线翻译”模式，在程序运行前将整篇代码一次性转化为机器码。这就像翻译一本完整的书，虽然编译过程耗时，但产出的程序执行速度极快，且能在运行前通过严格的语法体检排除隐患。而&lt;strong&gt;解释器&lt;/strong&gt;路线（以 Python/LISP 为代表）则采取“同声传译”模式，在程序运行时逐行翻译并执行。这种方式虽然牺牲了部分运行性能，但换来了极高的调试效率和灵活性，允许程序员即写即看结果。&lt;/p&gt;
&lt;p&gt;如下为两种代码翻译方法的示意图：&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/c&amp;#43;&amp;#43;/%E3%80%90c&amp;#43;&amp;#43;%E3%80%91learncppdate/image-20260106205329384.png"
alt="a simplified representation of the compiling process"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
a simplified representation of the compiling process
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;</description></item><item><title>【Games101】动画基础</title><link>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E5%8A%A8%E7%94%BB%E5%9F%BA%E7%A1%80/</link><pubDate>Fri, 19 Dec 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E5%8A%A8%E7%94%BB%E5%9F%BA%E7%A1%80/</guid><description>&lt;p&gt;动画通过连续图像产生运动感，其发展从手绘到数字时代。关键帧动画是基础技术，通过定义关键姿态并由计算机插值生成中间帧，数学本质是参数空间的插值过程。&lt;/p&gt;
&lt;h1 id="动画概念"&gt;动画概念&lt;/h1&gt;
&lt;h2 id="动画概述与历史"&gt;动画概述与历史&lt;/h2&gt;
&lt;p&gt;动画的本质是“赋予生命”，通俗来说就是通过随时间变化的场景模型，输出一系列连续图像，利用人眼的视觉暂留产生运动感 ，基于对人眼感知的能力，动画的帧数一般为以下的标准：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;帧率标准&lt;/strong&gt;：电影通常为 &lt;strong&gt;24 fps&lt;/strong&gt;，一般视频为 &lt;strong&gt;30 fps&lt;/strong&gt;，而虚拟现实（VR）则需要高达 &lt;strong&gt;90 fps&lt;/strong&gt; 来保证流畅度 。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E5%8A%A8%E7%94%BB%E5%9F%BA%E7%A1%80/image-20251219213410718.png"
alt="image-20251219213410718"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
image-20251219213410718
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;一些重要动画的发展史&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;早期尝试&lt;/strong&gt;：公元前 3200 年伊朗的陶器彩绘被认为是最早的动画原型 ；1831 年出现了诡盘（Phenakistoscope） 。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;电影诞生&lt;/strong&gt;：1878 年埃德沃德·迈布里奇拍摄的《萨莉·加德纳》是第一部电影，最初用于科学研究 。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;手绘巅峰&lt;/strong&gt;：1937 年迪士尼推出了首部长篇手绘动画《白雪公主与七个小矮人》 。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数字时代&lt;/strong&gt;：1963 年 Ivan Sutherland 的 &lt;strong&gt;Sketchpad&lt;/strong&gt; 开启了数字计算机生成动画的先河 ；1995 年《玩具总动员》成为首部全 CG 长篇电影 。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="关键帧动画-keyframe-animation"&gt;关键帧动画 (Keyframe Animation)&lt;/h2&gt;
&lt;p&gt;这是最传统也是最基础的动画技术 。关键帧动画的核心在于将动画序列分解为由核心动作组成的“关键点” 。
&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E5%8A%A8%E7%94%BB%E5%9F%BA%E7%A1%80/image-20251219213455017.png"
alt="image-20251219213455017"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
image-20251219213455017
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;</description></item><item><title>【Games101】颜色与感知(Color and Perception)</title><link>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E9%A2%9C%E8%89%B2%E4%B8%8E%E6%84%9F%E7%9F%A5color-and-perception/</link><pubDate>Thu, 18 Dec 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E9%A2%9C%E8%89%B2%E4%B8%8E%E6%84%9F%E7%9F%A5color-and-perception/</guid><description>&lt;p&gt;颜色是光线与感光系统互动的结果。人眼通过三种视锥细胞将连续光谱转换为三个神经信号，这解释了为何三原色能模拟色彩，并产生了同色异谱现象。&lt;/p&gt;
&lt;h2 id="光谱分布-spd"&gt;光谱分布 (SPD)&lt;/h2&gt;
&lt;p&gt;在理解计算机如何模拟颜色之前，必须澄清一个根本的物理事实：&lt;strong&gt;颜色并非物体固有的属性，而是光线与特定感光系统（如人眼、相机传感器）相互作用的产物&lt;/strong&gt;。一个物体之所以呈现红色，并非因为它“是”红色，而是因为它吸收了可见光中除红光波段外的其他光线，并将红光反射到了我们的眼睛中。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E9%A2%9C%E8%89%B2%E4%B8%8E%E6%84%9F%E7%9F%A5color-and-perception/image-20251218213216865.png"
alt="光谱"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
光谱
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;可见光谱 (Visible Spectrum)&lt;/strong&gt;：决定我们看到何种颜色的关键，是光的&lt;strong&gt;可见光谱&lt;/strong&gt;。这是电磁波谱中波长介于 &lt;strong&gt;400纳米（紫光）到 700纳米（红光）&lt;/strong&gt; 之间的一段。波长低于400nm的紫外线、高于700nm的红外线，人眼都无法直接感知。因此，在绝大多数游戏、影视渲染等视觉应用中，我们仅需模拟和计算这一狭小波长范围内的光线行为，这极大地简化了问题。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;光谱功率分布 (SPD)：&lt;strong&gt;为了精确描述一束光的颜色构成，我们使用&lt;/strong&gt;光谱功率分布（Spectral Power Distribution, SPD）&lt;/strong&gt; 这一核心物理量。SPD 描述了光在&lt;strong&gt;每个波长（λ）上携带的能量（或功率）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;它可以看作是一个函数：横坐标是波长 λ，纵坐标是该波长上的辐射能量。一束纯净的单色激光的 SPD 是一个尖锐的尖峰，而日常的太阳光或白炽灯光则是在整个可见光谱上都有广泛分布。SPD 是定义一种光最基础、最完整的物理方式。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E9%A2%9C%E8%89%B2%E4%B8%8E%E6%84%9F%E7%9F%A5color-and-perception/image-20251218213408973.png"
alt="不同光线的SPD"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
不同光线的SPD
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;blockquote class="dream-alert tip"&gt;
&lt;p class="heading"&gt;
&lt;ion-icon name="bulb-outline"&gt;&lt;/ion-icon&gt;Tip&lt;/p&gt;
&lt;p&gt;SPD 就像是光的“成分配方表”。日光的配方比较均匀，而白炽灯的配方里“长波（红色）”比例更高 。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;光线还具有线性性质&lt;/strong&gt;：不同光线的能量（其 SPD）是&lt;strong&gt;线性可叠加&lt;/strong&gt;的。&lt;/p&gt;</description></item><item><title>【Games101】相机与透镜</title><link>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E7%9B%B8%E6%9C%BA%E4%B8%8E%E9%80%8F%E9%95%9C/</link><pubDate>Tue, 16 Dec 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E7%9B%B8%E6%9C%BA%E4%B8%8E%E9%80%8F%E9%95%9C/</guid><description>&lt;p&gt;成像包含合成与捕捉两个环节。针孔相机虽能实现清晰成像，但进光量不足；引入透镜可提升亮度，却带来了景深与视场角等物理权衡，揭示了亮度与清晰度的内在矛盾。&lt;/p&gt;
&lt;p&gt;我们在之前的课程里（光栅化、光线追踪）一直在忙着计算“光线是怎么传播的”。但这只是故事的一半。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Synthesis (合成)&lt;/strong&gt;：我们在之前的课程里做的光栅化、光线追踪，是在计算场景中光线的传播。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Capture (捕捉)&lt;/strong&gt;：这节课讲的是，如何用一个虚拟的“设备”（相机）把这些光线记录下来变成图像。
&lt;/p&gt;
$$
\mathrm{Imaging} = \mathrm{Synthesis} + \mathrm{Capture}
$$&lt;h2 id="针孔与透镜"&gt;针孔与透镜&lt;/h2&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E7%9B%B8%E6%9C%BA%E4%B8%8E%E9%80%8F%E9%95%9C/image-20251216205130244.png"
alt="小孔成像示意"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
小孔成像示意
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;最原始的相机是&lt;strong&gt;针孔相机 (Pinhole Camera)&lt;/strong&gt;。它很简单，却道出了成像的本质。利用小孔成像原理，强制让光线“各行其道”。因为孔极小，物体上一点发出的光，只能通过这唯一的孔打在传感器的一个点上。其优点在于：无限景深。无论远近，所有物体都是清晰的（没有虚焦概念）。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E7%9B%B8%E6%9C%BA%E4%B8%8E%E9%80%8F%E9%95%9C/image-20251216205459106.png"
alt="小孔成像需要在暗室中曝光几个小时"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
小孔成像需要在暗室中曝光几个小时
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;致命缺陷&lt;/strong&gt;：&lt;strong&gt;太暗了&lt;/strong&gt;。因为孔太小，进光量微乎其微。要想拍出亮的照片，曝光时间得按小时算。&lt;/p&gt;
&lt;blockquote class="dream-alert tip"&gt;
&lt;p class="heading"&gt;
&lt;ion-icon name="bulb-outline"&gt;&lt;/ion-icon&gt;Tip&lt;/p&gt;
&lt;p&gt;**如果把孔弄大点呢？**结果是光线会乱。物体上一点发出的光会打在传感器的一片区域上，图像就糊了（Blur）。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;为了解决“暗”的问题，我们需要把孔弄大（光圈）。但为了解决孔大导致的“糊”的问题，我们引入了&lt;strong&gt;透镜&lt;/strong&gt;。透镜能把从物体上同一点发出、射向不同方向的光线，重新&lt;strong&gt;汇聚&lt;/strong&gt;到传感器上的同一个点。代价则是&lt;strong&gt;焦距 (Focus)&lt;/strong&gt; 的产生。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;透镜只能让特定距离的物体完美汇聚。&lt;/li&gt;
&lt;li&gt;比这个距离远或近的物体，汇聚点就不在传感器上了，结果就是&lt;strong&gt;模糊 (Defocus Blur)&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote class="dream-alert note"&gt;
&lt;p class="heading"&gt;
&lt;ion-icon name="information-circle-outline"&gt;&lt;/ion-icon&gt;Note&lt;/p&gt;</description></item><item><title>【C++】封装与常用关键字</title><link>https://tingdonghu.github.io/posts/%E4%BE%AF%E6%8D%B7%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/c++%E5%B0%81%E8%A3%85%E4%B8%8E%E5%B8%B8%E7%94%A8%E5%85%B3%E9%94%AE%E5%AD%97/</link><pubDate>Mon, 15 Dec 2025 12:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/%E4%BE%AF%E6%8D%B7%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/c++%E5%B0%81%E8%A3%85%E4%B8%8E%E5%B8%B8%E7%94%A8%E5%85%B3%E9%94%AE%E5%AD%97/</guid><description>&lt;hr&gt;
&lt;h2 id="基本概念"&gt;基本概念&lt;/h2&gt;
&lt;h3 id="封装的概念"&gt;封装的概念&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;封装（Encapsulation）&lt;/strong&gt; 是面向对象编程（OOP）的三大特性之一，简单来说，封装就是将**数据（属性）&lt;strong&gt;和&lt;/strong&gt;操作数据的函数（行为）**绑定在一起，形成一个名为“类（Class）”的单位，并对外部隐藏内部实现的细节。&lt;/p&gt;
&lt;p&gt;封装的核心思想是**“对外提供接口，对内隐藏实现”**。它的好处包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;安全性（数据隐藏）：&lt;/strong&gt; 防止外部代码随意修改对象内部的关键数据，避免程序进入非法状态。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;易维护性：&lt;/strong&gt; 如果内部逻辑需要修改，只要外部接口（函数名、参数）不变，调用者的代码就不需要改动。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;模块化：&lt;/strong&gt; 代码结构更清晰，每个类负责自己的逻辑。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="访问修饰符"&gt;访问修饰符&lt;/h3&gt;
&lt;p&gt;C++ 通过三个关键字来控制成员的访问权限。它们是实现封装的关键工具：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;关键字&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;访问权限说明&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;public&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;公有&lt;/strong&gt;：类内部和类外部都可以直接访问。通常用于存放成员函数。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;private&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;私有&lt;/strong&gt;：&lt;strong&gt;（默认）&lt;/strong&gt; 只有类内部的函数可以访问，外部无法直接访问。通常用于存放成员变量。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;protected&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;保护&lt;/strong&gt;：类内部及**派生类（子类）**可以访问，但类外部无法直接访问。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;this&lt;/code&gt; 指针&lt;/strong&gt;：是一个指向当前对象实例的指针。常用于在成员函数中区分“成员变量”和“同名参数”。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;class&lt;/code&gt; 的成员默认是 &lt;code&gt;private&lt;/code&gt;，而 &lt;code&gt;struct&lt;/code&gt; 的成员默认是 &lt;code&gt;public&lt;/code&gt;。通常建议用 &lt;code&gt;class&lt;/code&gt; 实现复杂的逻辑封装。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;friend&lt;/code&gt;（友元）&lt;/strong&gt;：如果你希望某个外部函数或类能访问当前类的 &lt;code&gt;private&lt;/code&gt; 成员，可以用 &lt;code&gt;friend&lt;/code&gt; 声明。它会打破封装，所以要谨慎使用。&lt;/p&gt;
&lt;blockquote class="dream-alert note"&gt;
&lt;p class="heading"&gt;
&lt;ion-icon name="information-circle-outline"&gt;&lt;/ion-icon&gt;Note&lt;/p&gt;
&lt;p&gt;&lt;code&gt;friend&lt;/code&gt;：破坏封装还是增强封装？&lt;/p&gt;
&lt;p&gt;&lt;code&gt;friend&lt;/code&gt; 允许特定的类或函数访问私有成员。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;视角一&lt;/strong&gt;：它破坏了封装，因为它打开了后门。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;视角二（更深层）&lt;/strong&gt;：它&lt;strong&gt;增强了封装&lt;/strong&gt;。通过将紧密耦合的工具类设为友元，可以避免为了让外部访问而被迫将成员声明为 &lt;code&gt;public&lt;/code&gt;，从而将权限精确控制在最小范围内。&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;const&lt;/code&gt;&lt;/strong&gt;：在封装中，常用于修饰不修改成员变量的函数（如 &lt;code&gt;getBalance() const&lt;/code&gt;），这被称为&lt;strong&gt;常成员函数&lt;/strong&gt;，能提高代码的安全性和可读性。&lt;/p&gt;
&lt;h3 id="example"&gt;Example&lt;/h3&gt;
&lt;p&gt;来一个银行账户的栗子：我们不希望别人直接修改我们的余额（&lt;code&gt;balance&lt;/code&gt;），而是必须通过存款或取款函数来操作。&lt;/p&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BankAccount&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 私有成员：外部无法直接访问
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;ownerName&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 构造函数：初始化数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;BankAccount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;initialBalance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ownerName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initialBalance&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;initialBalance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 公有成员函数：提供受控的访问接口（Getter）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;getBalance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 公有成员函数：存款（Setter/Action）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;deposit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;存入: &amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34; 元&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 公有成员函数：取款
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;withdraw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;取出: &amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34; 元&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;余额不足或金额非法！&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;BankAccount&lt;/span&gt; &lt;span class="n"&gt;myAccount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;张三&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1000.0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// myAccount.balance = 1000000; // 错误！编译会报错，因为 balance 是 private 的
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;myAccount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deposit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 正确：通过公有接口操作
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;myAccount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;withdraw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 正确：通过公有接口操作
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;当前余额: &amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;myAccount&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getBalance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34; 元&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="进阶部分"&gt;进阶部分&lt;/h2&gt;
&lt;h3 id="访问控制的边界与编译时检查"&gt;访问控制的边界与编译时检查&lt;/h3&gt;
&lt;p&gt;在 C++ 中，封装不仅仅是“隐藏变量”，它是&lt;strong&gt;一种编译器层面的协议&lt;/strong&gt;。&lt;/p&gt;</description></item><item><title>【Games101】高级光线传播与复杂外观建模</title><link>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E9%AB%98%E7%BA%A7%E5%85%89%E7%BA%BF%E4%BC%A0%E6%92%AD%E4%B8%8E%E5%A4%8D%E6%9D%82%E5%A4%96%E8%A7%82%E5%BB%BA%E6%A8%A1/</link><pubDate>Mon, 15 Dec 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E9%AB%98%E7%BA%A7%E5%85%89%E7%BA%BF%E4%BC%A0%E6%92%AD%E4%B8%8E%E5%A4%8D%E6%9D%82%E5%A4%96%E8%A7%82%E5%BB%BA%E6%A8%A1/</guid><description>&lt;p&gt;高级光线传播技术旨在提升复杂光照下的渲染效率与质量。文章对比了无偏与有偏方法，并详细分析了双向路径追踪和梅特罗波利斯光线传播两种策略的原理、适用场景及优缺点。&lt;/p&gt;
&lt;blockquote class="dream-alert tip"&gt;
&lt;p class="heading"&gt;
&lt;ion-icon name="bulb-outline"&gt;&lt;/ion-icon&gt;Tip&lt;/p&gt;
&lt;p&gt;这节课可以当作一个小综述，大致了解就好。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote class="dream-alert tip"&gt;
&lt;p class="heading"&gt;
&lt;ion-icon name="bulb-outline"&gt;&lt;/ion-icon&gt;Tip&lt;/p&gt;
&lt;p&gt;前的课程我们学习了路径追踪（Path Tracing），它是现代渲染的“黄金标准”。但是，它并非万能。在面对“光路特别复杂”或者“材质特别复杂”的情况时，标准路径追踪会产生巨大的噪点，或者效率极低。这节课就是为了解决这两个难题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;高级光线传播&lt;/strong&gt;：怎么在复杂光照下算得更准、更快？&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;高级外观建模&lt;/strong&gt;：怎么渲染那些不是简单平面的物体（如头发、雾气、皮肤）？&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h1 id="高级光线传播-advanced-light-transport"&gt;高级光线传播 (Advanced Light Transport)&lt;/h1&gt;
&lt;p&gt;这部分的核心在于解决标准 Path Tracing 收敛慢、噪点多的问题。&lt;/p&gt;
&lt;h3 id="无偏与有偏-unbiased-vs-biased"&gt;无偏与有偏 (Unbiased vs. Biased)&lt;/h3&gt;
&lt;p&gt;在深入算法之前，我们需要先建立一个评价标准：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;无偏 (Unbiased)&lt;strong&gt;定义为：蒙特卡洛估计的期望值&lt;/strong&gt;始终等于&lt;/strong&gt;真实值。其特点为：样本少时会有噪点（Noise），但只要样本够多，结果一定是对的。之前学过的Path Tracing就是一个无偏的方法。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;有偏 (Biased)&lt;strong&gt;定义为：估计值的期望与真实值有系统性偏差。其特点为：样本少时，结果通常是&lt;/strong&gt;模糊 (Blurry)&lt;/strong&gt; 的，而不是噪点。&lt;strong&gt;一致性 (Consistent)&lt;/strong&gt;：这是有偏方法中好的那一类。如果样本数趋向于无穷大时，误差能收敛到0，就叫“一致”。&lt;/p&gt;
&lt;blockquote class="dream-alert tip"&gt;
&lt;p class="heading"&gt;
&lt;ion-icon name="bulb-outline"&gt;&lt;/ion-icon&gt;Tip&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;通俗理解&lt;/strong&gt;：无偏 = 画面有噪点但准确；有偏 = 画面平滑但可能模糊（看起来像把噪点抹平了）。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="解决光路难找的几种高级策略"&gt;解决“光路难找”的几种高级策略&lt;/h2&gt;
&lt;p&gt;当光源被遮挡，或者光线需要经过多次反弹才能进入眼睛时（例如：光线打到墙上，墙漫反射到玻璃球，玻璃球折射聚焦到地板，我们看地板上的亮斑），标准 Path Tracing 很难随机“碰”到这种路径。&lt;/p&gt;
&lt;h3 id="双向路径追踪-bdpt---bidirectional-path-tracing"&gt;双向路径追踪 (BDPT - Bidirectional Path Tracing)&lt;/h3&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E9%AB%98%E7%BA%A7%E5%85%89%E7%BA%BF%E4%BC%A0%E6%92%AD%E4%B8%8E%E5%A4%8D%E6%9D%82%E5%A4%96%E8%A7%82%E5%BB%BA%E6%A8%A1/image-20251216173414432.png"
alt="双向路径追踪示意"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
双向路径追踪示意
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;</description></item><item><title>【Games101】材质与外观</title><link>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E6%9D%90%E8%B4%A8%E4%B8%8E%E5%A4%96%E8%A7%82/</link><pubDate>Thu, 11 Dec 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E6%9D%90%E8%B4%A8%E4%B8%8E%E5%A4%96%E8%A7%82/</guid><description>&lt;p&gt;在计算机图形学中，材料的视觉外观由其与光线的相互作用决定，这通过双向反射分布函数（BRDF）数学模型精确描述。BRDF必须遵循非负性、线性、可逆性和能量守恒等物理定律，以确保渲染的真实性。&lt;/p&gt;
&lt;p&gt;在计算机图形学中，我们如何定义和区分不同的材料？&lt;/p&gt;
&lt;p&gt;例如，一个3D咖啡杯模型，通过赋予不同的表面属性，它可以呈现出陶瓷、金属或塑料的质感。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E6%9D%90%E8%B4%A8%E4%B8%8E%E5%A4%96%E8%A7%82/image-20251215205054966.png"
alt="image-20251215205054966"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
image-20251215205054966
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;答案是：&lt;strong&gt;材料的视觉外观完全由其与光线的相互作用方式决定&lt;/strong&gt;。这种相互作用在图形学中通过一个称为&lt;strong&gt;BRDF（双向反射分布函数）&lt;/strong&gt; 的数学模型来精确描述。因此，一个核心等式被确立：&lt;strong&gt;Material == BRDF&lt;/strong&gt;。这意味着，改变一个物体的材质，本质上就是改变它的BRDF。&lt;/p&gt;
&lt;h3 id="brdf-的物理性质"&gt;BRDF 的物理性质&lt;/h3&gt;
&lt;p&gt;BRDF（双向反射分布函数）作为一个描述材质物理属性的函数，必须遵循以下几条核心的物理定律。这些性质保证了渲染结果在物理上的真实性和可信度。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;非负性 (Non-negativity)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这是最基本的性质。因为 BRDF 描述的是光能量的分布比例，而光能量不可能是负数，所以 BRDF 函数的值必须永远大于等于零 。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;公式：
$$
f_{r}(\omega_{i}\rightarrow\omega_{r})\ge0
$$&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;线性 (Linearity)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;材质对光照的反应是线性的。这意味着，如果你有两个光源照亮物体，物体反射的总光线等于这两个光源分别照射时反射光线的总和 。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E6%9D%90%E8%B4%A8%E4%B8%8E%E5%A4%96%E8%A7%82/image-20251215213822499.png"
alt="image-20251215213822499"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
image-20251215213822499
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;物理意义&lt;/strong&gt;：这一性质允许我们将场景中所有光源的影响（通过积分）累加起来，计算出最终的出射辐射亮度（Radiance）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;公式：
&lt;/p&gt;
$$
L_{r}(p,\omega_{r})=\int_{H^{2}}f_{r}(p,\omega_{i}\rightarrow\omega_{r})L_{i}(p,\omega_{i})\cos\theta_{i}d\omega_{i}
$$&lt;p&gt;
这个积分公式体现了所有入射光 $L_i$ 对出射光 $L_r$ 的线性贡献 。&lt;/p&gt;</description></item><item><title>【Games101】光线追踪与蒙特卡洛路径追踪</title><link>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E5%85%89%E7%BA%BF%E8%BF%BD%E8%B8%AA%E4%B8%8E%E8%92%99%E7%89%B9%E5%8D%A1%E6%B4%9B%E8%B7%AF%E5%BE%84%E8%BF%BD%E8%B8%AA/</link><pubDate>Tue, 09 Dec 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E5%85%89%E7%BA%BF%E8%BF%BD%E8%B8%AA%E4%B8%8E%E8%92%99%E7%89%B9%E5%8D%A1%E6%B4%9B%E8%B7%AF%E5%BE%84%E8%BF%BD%E8%B8%AA/</guid><description>&lt;p&gt;蒙特卡洛积分利用随机采样近似计算复杂积分，其理论基础是概率论。文章介绍了离散与连续随机变量、概率密度函数、期望值以及随机变量函数的概念，并阐述了这些知识在图形学渲染问题中的应用。&lt;/p&gt;
&lt;blockquote class="dream-alert tip"&gt;
&lt;p class="heading"&gt;
&lt;ion-icon name="bulb-outline"&gt;&lt;/ion-icon&gt;Tip&lt;/p&gt;
&lt;p&gt;在图形学中，我们经常遇到无法算出解析解的积分（比如上一节课的渲染方程，需要对半球面上所有光线积分）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决思路&lt;/strong&gt;：既然算不准，那我就随机取样。 比如我想知道一个广场上所有人的平均身高，我不需要真的去量几万个人的身高（求积分），我只需要随机抓 100 个人量一下（采样），算个平均值（期望），就能大概估算出结果。这就是概率论在渲染中的核心作用。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;蒙特卡洛积分是一种基于随机采样的方法，而概率论是它的理论基石。&lt;/p&gt;
&lt;h2 id="概率论基础"&gt;概率论基础&lt;/h2&gt;
&lt;h3 id="随机变量-random-variables"&gt;随机变量 (Random Variables)&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;定义&lt;/strong&gt;：随机变量 $X$ 是一个变量，它的值是不确定的，代表了一个随机过程的潜在结果 。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;例子&lt;/strong&gt;：掷骰子。$X$ 可能取的值是 $\{1, 2, 3, 4, 5, 6\}$ 。&lt;/p&gt;
&lt;h4 id="离散情况-discrete-case--以掷骰子为例"&gt;离散情况 (Discrete Case) —— 以“掷骰子”为例&lt;/h4&gt;
&lt;p&gt;如果 $X$ 是离散的，它取第 $i$ 个值 $x_i$ 的可能性记为 $p_i$ 。这里的$p_i$有两个硬性条件 ：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;非负性&lt;/strong&gt;：$p_i \ge 0$（概率不能是负数）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;归一化&lt;/strong&gt;：$\sum_{i=1}^{n} p_i = 1$（所有可能性的概率加起来必须等于 1，也就是必然会发生某件事）。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;则对于掷骰子来说，每个面朝上的概率是相等的，即 $p_i = 1/6$&lt;/p&gt;
&lt;h4 id="期望-expected-value"&gt;期望 (Expected Value)&lt;/h4&gt;
&lt;p&gt;期望可以理解为&lt;strong&gt;平均值&lt;/strong&gt;。如果你不断地从分布中抽取样本，最终得到的平均结果就是期望 。
&lt;/p&gt;
$$
E[X] = \sum_{i=1}^{n} x_i p_i
$$&lt;p&gt;
即：（结果1 $\times$ 概率1）+（结果2 $\times$ 概率2）&amp;hellip;&lt;/p&gt;
&lt;p&gt;则在例子掷骰子中会发生这种情况：虽然骰子只有整数点数，但其期望是：
&lt;/p&gt;
$$
E[X] = 1 \cdot \frac{1}{6} + 2 \cdot \frac{1}{6} + \dots + 6 \cdot \frac{1}{6} = 3.5
$$&lt;p&gt;
虽然你永远掷不出 3.5 这个点数，但“3.5”代表了掷很多次后的平均结果。&lt;/p&gt;</description></item><item><title>【Games101】辐射度量学与全局光照</title><link>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E8%BE%90%E5%B0%84%E5%BA%A6%E9%87%8F%E5%AD%A6%E4%B8%8E%E5%85%89%E7%BA%BF%E8%BF%BD%E8%B8%AA/</link><pubDate>Sun, 07 Dec 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E8%BE%90%E5%B0%84%E5%BA%A6%E9%87%8F%E5%AD%A6%E4%B8%8E%E5%85%89%E7%BA%BF%E8%BF%BD%E8%B8%AA/</guid><description>&lt;p&gt;辐射度量学为计算机图形学提供物理正确的光照计算基础，通过定义辐射能量、通量、立体角和辐射强度等物理量，使渲染结果从“看起来像”转变为“物理正确”，是通往路径追踪等高级渲染技术的基石。&lt;/p&gt;
&lt;h2 id="先导"&gt;先导&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;“光到底是什么？”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是为了回答一个你在写 Blinn-Phong 模型代码时可能产生的终极疑问：&lt;strong&gt;“我的光照强度设为 10，但这个 10 到底是什么单位？是 10 个灯泡？还是 10 个太阳？”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果没有这套物理系统，Whitted-style 光线追踪的结果永远只是“看起来像”，而不是“物理正确” 。&lt;/p&gt;
&lt;h3 id="为什么要学辐射度量学-radiometry"&gt;为什么要学辐射度量学 (Radiometry)？&lt;/h3&gt;
&lt;p&gt;辐射度量学是一套精确测量电磁辐射（包括光）空间属性的系统。它引入了一系列物理量（如辐射通量、强度、辐照度、辐射亮度），让我们能够以物理正确的方式进行光照计算 。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;在此之前的渲染器就像是在画画，颜色深浅全凭感觉调参数（比如 &lt;code&gt;float intensity = 10.0&lt;/code&gt;）。 学完这部分后，你的渲染器将变成一台&lt;strong&gt;照相机&lt;/strong&gt;。每一个像素的颜色值，都对应着真实物理世界中打到底片上的能量数值。这是通往&lt;strong&gt;路径追踪 (Path Tracing)&lt;/strong&gt; 的必经之路 。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="基础概念"&gt;基础概念&lt;/h2&gt;
&lt;h3 id="能量与通量"&gt;能量与通量&lt;/h3&gt;
&lt;p&gt;**辐射能量 (Radiant Energy, $Q$)**定义为：电磁辐射的能量。其单位是焦耳 (Joule, $J$) 。&lt;/p&gt;
&lt;blockquote class="dream-alert tip"&gt;
&lt;p class="heading"&gt;
&lt;ion-icon name="bulb-outline"&gt;&lt;/ion-icon&gt;Tip&lt;/p&gt;
&lt;p&gt;说人话：就像水池里蓄的总水量。但在图形学中我们很少直接用它，因为光通常是持续不断的。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;**辐射通量 / 功率 (Radiant Flux / Power, $\Phi$)**定义为：单位时间内发射、反射、传输或接收的能量 。其公式表达为：
&lt;/p&gt;
$$
\Phi \equiv \frac{dQ}{dt}
$$&lt;p&gt;
其单位为：瓦特 (Watt, $W$) 或 流明 (Lumen, $lm$)&lt;/p&gt;
&lt;blockquote class="dream-alert note"&gt;
&lt;p class="heading"&gt;
&lt;ion-icon name="information-circle-outline"&gt;&lt;/ion-icon&gt;Note&lt;/p&gt;
&lt;p&gt;上述两个概念可以通俗理解为：光子流。想象光是水流。能量 ($Q$) 是这一盆水有多少。通量 ($\Phi$) 是水龙头的流速。单位时间流出来的光子越多，这盏灯就越“亮”。比如一个 60W 的灯泡，这个“瓦数”描述的就是它的 Flux（虽然电功率和光功率有转换效率问题，但概念类似）。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="立体角-solid-angle"&gt;立体角 (Solid Angle，$\Omega$)&lt;/h3&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E8%BE%90%E5%B0%84%E5%BA%A6%E9%87%8F%E5%AD%A6%E4%B8%8E%E5%85%89%E7%BA%BF%E8%BF%BD%E8%B8%AA/image-20251209175146602-1765273927742-1.png"
alt="平面角与立体角"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
平面角与立体角
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;</description></item><item><title>【算法刷题】排序算法总结</title><link>https://tingdonghu.github.io/posts/%E7%AE%97%E6%B3%95%E5%88%B7%E9%A2%98/%E7%AE%97%E6%B3%95%E5%88%B7%E9%A2%98%E5%9F%BA%E7%A1%80%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/</link><pubDate>Sat, 06 Dec 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/%E7%AE%97%E6%B3%95%E5%88%B7%E9%A2%98/%E7%AE%97%E6%B3%95%E5%88%B7%E9%A2%98%E5%9F%BA%E7%A1%80%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/</guid><description>&lt;hr&gt;
&lt;p&gt;本文整理了冒泡排序和选择排序的算法笔记。冒泡排序通过相邻元素交换实现排序，时间复杂度O(n²)，稳定且原地排序。选择排序通过选择最小元素放置到已排序末尾完成排序。&lt;/p&gt;
&lt;blockquote class="dream-alert tip"&gt;
&lt;p class="heading"&gt;
&lt;ion-icon name="bulb-outline"&gt;&lt;/ion-icon&gt;Tip&lt;/p&gt;
&lt;p&gt;近来准备重拾刷题的习惯，为就业早做准备，刚好把之前学过的算法笔记顺带整理一下，理一遍思路，夯实基础。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="基础算法-basic-algorithms"&gt;基础算法 (Basic Algorithms)&lt;/h2&gt;
&lt;h3 id="冒泡排序-bubble-sort"&gt;冒泡排序 (Bubble Sort)&lt;/h3&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E7%AE%97%E6%B3%95%E5%88%B7%E9%A2%98/%E7%AE%97%E6%B3%95%E5%88%B7%E9%A2%98%E5%9F%BA%E7%A1%80%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/v2-43dc4f02286be372415bec478a227940_b.webp"
alt="动图"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
动图
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;核心思想&lt;/strong&gt;：重复交换相邻的逆序元素，使最大/小值如气泡般“浮”到顶端。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;时间复杂度&lt;/strong&gt;：O(n²) (平均 &amp;amp; 最坏)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;关键特性&lt;/strong&gt;：&lt;strong&gt;稳定&lt;/strong&gt;、原地排序、最简单但效率最低。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;来道例题&lt;/strong&gt;：&lt;a href="https://www.acwing.com/file_system/file/content/whole/index/content/10768559/" target="_blank"&gt;5334. 冒泡排序 - AcWing题库&lt;/a&gt;
&lt;/p&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;//示例代码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Bubble_Sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 每一轮将最大的元素“冒泡”到末尾
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;swap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote class="dream-alert note"&gt;
&lt;p class="heading"&gt;
&lt;ion-icon name="information-circle-outline"&gt;&lt;/ion-icon&gt;Note&lt;/p&gt;
&lt;p&gt;个人认为在冒泡排序中最重要的点是，要理解其核心操作是&lt;strong&gt;两两对比&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每次&lt;strong&gt;比较相邻的两个元素&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;如果顺序错误就交换，让较大的元素“冒泡”上浮&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每一次得到一个相对最大(小)值移动到队尾，然后在下一次循环时就不必考虑该值，从而&lt;strong&gt;逐步缩小范围&lt;/strong&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每轮结束后，&lt;strong&gt;当前最大元素一定“沉”到最后&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;下一轮只需比较前面 n-1 个元素，再下一轮比较 n-2 个&amp;hellip;&lt;/li&gt;
&lt;li&gt;这正是代码中 &lt;code&gt;j &amp;lt; n-1-i&lt;/code&gt;的原因&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h3 id="选择排序-selection-sort"&gt;选择排序 (Selection Sort)&lt;/h3&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E7%AE%97%E6%B3%95%E5%88%B7%E9%A2%98/%E7%AE%97%E6%B3%95%E5%88%B7%E9%A2%98%E5%9F%BA%E7%A1%80%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95/5d50f9a16c5bb410be12eee453d31ef2.gif"
alt="img"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
img
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;</description></item><item><title>【Games101】光线追踪基础Ray-Tracing</title><link>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E5%85%89%E7%BA%BF%E8%BF%BD%E8%B8%AAray-tracing/</link><pubDate>Thu, 04 Dec 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E5%85%89%E7%BA%BF%E8%BF%BD%E8%B8%AAray-tracing/</guid><description>&lt;p&gt;阴影贴图是光栅化渲染中生成阴影的主流技术。其核心思想是：一个点被照亮需同时被相机和光源可见。算法分为两步：首先从光源视角渲染生成记录最近距离的深度图；然后在相机视角渲染时，将每个点投影回光源视角，对比其实际距离与深度图记录值，以判断该点处于光照还是阴影中。&lt;/p&gt;
&lt;p&gt;要讲述光线追踪，首先需要先引入之前的光栅化中的一个内容&amp;ndash;阴影贴图&lt;/p&gt;
&lt;h1 id="先导"&gt;先导&lt;/h1&gt;
&lt;h2 id="阴影贴图-shadow-mapping"&gt;阴影贴图 (Shadow Mapping)&lt;/h2&gt;
&lt;h3 id="为什么需要-shadow-mapping"&gt;&lt;strong&gt;为什么需要 Shadow Mapping？&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;在光栅化渲染中，我们通常是一个三角形一个三角形地画，很难直接知道“谁挡住了谁”从而产生阴影 。为了解决这个问题，我们引入了 &lt;strong&gt;Shadow Mapping&lt;/strong&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;定位&lt;/strong&gt;：这是目前最主流的阴影生成技术，从早期的《玩具总动员》到《塞尔达传说：荒野之息》、《超级马里奥：奥德赛》等现代游戏都在使用 。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;本质&lt;/strong&gt;：它是一种&lt;strong&gt;图像空间 (Image-space)&lt;/strong&gt; 的算法 。这意味着它依赖生成的图像（深度图）来计算，而不需要一直纠缠于复杂的场景几何数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E5%85%89%E7%BA%BF%E8%BF%BD%E8%B8%AAray-tracing/image-20251204170440998.png"
alt="image-20251204170440998"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
image-20251204170440998
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Shadow Mapping 的核心思想非常朴素，只有一句话：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;如果一个点不在阴影里，那么它必须能同时被“摄像机”和“光源”看到。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果不被阴影覆盖（也就是被照亮），说明那个点既能被你的眼睛（相机）看见，也能被头顶的太阳（光源）直接照射到。如果那个点被太阳“看不见”（中间有障碍物挡住了），那它就在阴影里。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E5%85%89%E7%BA%BF%E8%BF%BD%E8%B8%AAray-tracing/%E5%9B%BE%E7%89%877-1764840093756-2.png"
alt="图片7"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
图片7
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;h3 id="算法流程经典的两步走-2-pass"&gt;&lt;strong&gt;算法流程：经典的“两步走” (2-Pass)&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Shadow Mapping 之所以叫 Mapping，就是因为它需要生成一张图（Map）。整个过程分为两次渲染：&lt;/p&gt;</description></item><item><title>【博客魔改】Butterfly 主题配置 Giscus 评论系统</title><link>https://tingdonghu.github.io/posts/hexo%E5%8D%9A%E5%AE%A2/%E5%8D%9A%E5%AE%A2%E9%AD%94%E6%94%B9butterfly-%E4%B8%BB%E9%A2%98%E9%85%8D%E7%BD%AE-giscus-%E8%AF%84%E8%AE%BA%E7%B3%BB%E7%BB%9F/</link><pubDate>Wed, 03 Dec 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/hexo%E5%8D%9A%E5%AE%A2/%E5%8D%9A%E5%AE%A2%E9%AD%94%E6%94%B9butterfly-%E4%B8%BB%E9%A2%98%E9%85%8D%E7%BD%AE-giscus-%E8%AF%84%E8%AE%BA%E7%B3%BB%E7%BB%9F/</guid><description>&lt;hr&gt;
&lt;p&gt;本文介绍了为Hexo博客的Butterfly主题配置Giscus评论系统的详细步骤。Giscus是一个基于GitHub Discussions的免费评论工具，无需自建服务器。配置过程主要包括：创建公开的GitHub仓库并启用Discussions功能，安装Giscus应用，最后在配置页面生成并获取必要的代码片段。&lt;/p&gt;
&lt;blockquote class="dream-alert tip"&gt;
&lt;p class="heading"&gt;
&lt;ion-icon name="bulb-outline"&gt;&lt;/ion-icon&gt;Tip&lt;/p&gt;
&lt;p&gt;最近把很多老博客整理搬运到hexo上面的时候，突然发现自己的博客还没有配置评论系统，刚好前两天刷到一个Giscus官方教程，个人用了也觉得确实是很好用，索性搬来配置到博客上去了，顺带水篇博客记录一下，方便后续主题修改后重新配置。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="giscus简介"&gt;Giscus简介&lt;/h2&gt;
&lt;p&gt;Giscus 是一个基于 GitHub Discussions 的评论系统，完全免费、无需服务器、数据存储在 GitHub 仓库中。本指南详细介绍如何为 Hexo Butterfly 主题配置 Giscus。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Giscus&lt;/code&gt; 使用 &lt;code&gt;GitHub Discussions&lt;/code&gt; 作为数据库存储博客下面的评论。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Giscus&lt;/code&gt; 插件加载时，会使用 &lt;code&gt;GitHub Discussions&lt;/code&gt; 搜索 API 根据选定的映射方式（如 URL、pathname、 等）来查找与当前页面关联的 discussion。如果找不到匹配的 &lt;code&gt;discussion&lt;/code&gt;，&lt;code&gt;giscus bot&lt;/code&gt; 就会在第一次有人留下评论或回应时自动创建一个 &lt;code&gt;discussion&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;如果要评论，访客必须按 &lt;code&gt;GitHub OAuth&lt;/code&gt; 流程授权 &lt;code&gt;giscus app&lt;/code&gt; 代表他发帖。或者访客也可以直接在 &lt;code&gt;GitHub Discussion&lt;/code&gt; 里评论，作者可以在 &lt;code&gt;GitHub&lt;/code&gt; 上管理评论。&lt;/p&gt;
&lt;h2 id="giscus配置"&gt;Giscus配置&lt;/h2&gt;
&lt;h3 id="第一步创建-github-仓库"&gt;第一步：创建 GitHub 仓库&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;登录 GitHub，点击右上角 &lt;code&gt;+&lt;/code&gt;→ &lt;code&gt;New repository&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;填写仓库信息：&lt;strong&gt;Repository name&lt;/strong&gt;: 例如 &lt;code&gt;blog-comments&lt;/code&gt;&lt;strong&gt;Visibility&lt;/strong&gt;: 必须选择 &lt;strong&gt;Public&lt;/strong&gt;（公开）&lt;/li&gt;
&lt;li&gt;点击 &lt;code&gt;Create repository&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="第二步启用-discussions-功能"&gt;第二步：启用 Discussions 功能&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;进入仓库页面 → 点击 &lt;code&gt;Settings&lt;/code&gt;选项卡&lt;/li&gt;
&lt;li&gt;左侧菜单选择 &lt;code&gt;General&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;向下滚动到 &lt;code&gt;Features&lt;/code&gt;区域&lt;/li&gt;
&lt;li&gt;勾选 &lt;strong&gt;Discussions&lt;/strong&gt; 复选框&lt;/li&gt;
&lt;li&gt;点击 &lt;code&gt;Save changes&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/hexo%E5%8D%9A%E5%AE%A2/%E5%8D%9A%E5%AE%A2%E9%AD%94%E6%94%B9butterfly-%E4%B8%BB%E9%A2%98%E9%85%8D%E7%BD%AE-giscus-%E8%AF%84%E8%AE%BA%E7%B3%BB%E7%BB%9F/image-20251203140248796.png"
alt="image-20251203140248796"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
image-20251203140248796
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;</description></item><item><title>【博客魔改】Hexo添加 Github alerts 支持</title><link>https://tingdonghu.github.io/posts/hexo%E5%8D%9A%E5%AE%A2/%E5%8D%9A%E5%AE%A2%E9%AD%94%E6%94%B9hexo%E6%B7%BB%E5%8A%A0-github-alerts-%E6%94%AF%E6%8C%81/</link><pubDate>Wed, 03 Dec 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/hexo%E5%8D%9A%E5%AE%A2/%E5%8D%9A%E5%AE%A2%E9%AD%94%E6%94%B9hexo%E6%B7%BB%E5%8A%A0-github-alerts-%E6%94%AF%E6%8C%81/</guid><description>&lt;hr&gt;
&lt;blockquote class="dream-alert tip"&gt;
&lt;p class="heading"&gt;
&lt;ion-icon name="bulb-outline"&gt;&lt;/ion-icon&gt;Tip&lt;/p&gt;
&lt;p&gt;一直很喜欢 Github 上的 &lt;a href="https://github.com/orgs/community/discussions/16925" target="_blank"&gt;Alerts&lt;/a&gt;
书写格式，非常简洁快捷，比hexo各类主题带的外挂标签方便很多，然后发现现在用的 hexo 主题并不支持解析该格式的语法。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;给个示例：&lt;/p&gt;
&lt;div class="code-block" data-lang="markdown"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;markdown&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;&amp;gt; &lt;/span&gt;&lt;span class="ge"&gt;[!NOTE]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;gt; 这是一个注意事项提示框。这种提示框通常用于展示一般性的提示信息。&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;通过简单的引用加调用预设语法既可以写出好看的外挂标签的效果：&lt;/p&gt;
&lt;blockquote class="dream-alert note"&gt;
&lt;p class="heading"&gt;
&lt;ion-icon name="information-circle-outline"&gt;&lt;/ion-icon&gt;Note&lt;/p&gt;
&lt;p&gt;这是一个注意事项提示框。这种提示框通常用于展示一般性的提示信息。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;参考&lt;a href="https://blog.dogxi.me/hexo-github-alerts/" target="_blank"&gt;Hexo 美化：添加 Github alerts 支持 | Dogxi 的狗窝&lt;/a&gt;
的博客做了一点魔改，在此记录一下，方便自己后续潜移修改。&lt;/p&gt;
&lt;h2 id="配置步骤"&gt;配置步骤&lt;/h2&gt;
&lt;h3 id="1-更换-markdown-渲染器"&gt;1. 更换 Markdown 渲染器&lt;/h3&gt;
&lt;p&gt;Hexo 默认的 &lt;code&gt;marked&lt;/code&gt;渲染器不支持此语法，需要更换为 &lt;code&gt;markdown-it&lt;/code&gt;：&lt;/p&gt;
&lt;div class="code-block" data-lang="bash"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 卸载默认渲染器&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;npm uninstall hexo-renderer-marked --save
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 安装 markdown-it 渲染器&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;npm install hexo-renderer-markdown-it --save&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="2-创建解析脚本"&gt;2. 创建解析脚本&lt;/h3&gt;
&lt;p&gt;在 Hexo 根目录创建脚本文件：&lt;code&gt;scripts/github-alerts.js&lt;/code&gt;&lt;/p&gt;
&lt;div class="code-block" data-lang="javascript"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;javascript&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// GitHub Alerts 解析脚本
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nx"&gt;hexo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;markdown-it:renderer&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;md&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;md&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ruler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;block&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;github-alert&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;blockquote_open&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 找到 blockquote 的内容
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 只处理第一个段落
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;paragraph_open&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;inline&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 兼容 [!NOTE]、[!NOTE]&amp;lt;br&amp;gt;、[!NOTE]\n
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="sr"&gt;/^\[!(NOTE|WARNING|TIP|IMPORTANT|CAUTION|INFO|SUCCESS|ERROR)\][\s:：-]*(.*)$/i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;alertType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;restContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 给 blockquote_open 加 class
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;attrGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;class&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;className&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39; &amp;#39;&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="sb"&gt;`alert alert-&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;alertType&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;attrSet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;class&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;restContent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// [!NOTE] 和内容在同一行
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;restContent&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// [!NOTE] 单独一行，移除该段
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="3-创建样式文件"&gt;3. 创建样式文件&lt;/h3&gt;
&lt;p&gt;在 &lt;code&gt;source/css/github-alerts.css&lt;/code&gt;创建样式文件：&lt;/p&gt;</description></item><item><title>【C++】复数类与字符串类</title><link>https://tingdonghu.github.io/posts/%E4%BE%AF%E6%8D%B7%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/c++%E5%A4%8D%E6%95%B0%E7%B1%BB%E4%B8%8E%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%B1%BB/</link><pubDate>Tue, 02 Dec 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/%E4%BE%AF%E6%8D%B7%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/c++%E5%A4%8D%E6%95%B0%E7%B1%BB%E4%B8%8E%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%B1%BB/</guid><description>&lt;hr&gt;
&lt;p&gt;本文以Complex类为例，介绍了C++程序的基本结构，包括头文件与实现文件的分离、防御性声明、命名空间的使用，以及inline函数的定义方式与注意事项。&lt;/p&gt;
&lt;h2 id="c-programs-代码的基本形式以complex-class为例"&gt;C++ programs 代码的基本形式(以Complex class为例)&lt;/h2&gt;
&lt;h3 id="头文件与类声明"&gt;头文件与类声明&lt;/h3&gt;
&lt;p&gt;在写C++项目时,一般将类声明和实现分为两部分存储,即&lt;code&gt;.h&lt;/code&gt;和&lt;code&gt;.cpp&lt;/code&gt;文件中.&lt;code&gt;.cpp&lt;/code&gt;文件中要包含&lt;code&gt;#inlcude&lt;/code&gt;他的声明头文件&lt;/p&gt;
&lt;blockquote class="dream-alert warning"&gt;
&lt;p class="heading"&gt;
&lt;ion-icon name="warning-outline"&gt;&lt;/ion-icon&gt;Warning&lt;/p&gt;
&lt;p&gt;在&lt;code&gt;.cpp&lt;/code&gt;文件中,自己的头文件一般用引号,而引用标准库文件则用尖括号:&lt;/p&gt;
&lt;div class="code-block" data-lang="c&amp;#43;&amp;#43;"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&amp;lt;iostream.h&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#inlcude&amp;#39;complex.h&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/blockquote&gt;
&lt;h4 id="头文件的防御性声明"&gt;头文件的防御性声明&lt;/h4&gt;
&lt;p&gt;在大型项目中,一个写好的类声明文件可能会被引用到程序的各个部分,而有一种规范安全的写法可以解决程序四处引用导致类重复声明的问题&lt;/p&gt;
&lt;p&gt;示例:&lt;/p&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#ifndef _COMPLEX_
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#define _COMPLEX_
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#endif&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h4 id="namespace命名空间"&gt;namespace命名空间&lt;/h4&gt;
&lt;p&gt;namesapce主要的用途是免去每个函数之前都加一个类名,举个栗子:&lt;/p&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;//使用命名空间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&amp;lt;iostram&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cin&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;...;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;...;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;//使用更加具体的命名空间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&amp;lt;iostram&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cin&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;...;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;...;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;//不使用命名空间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&amp;lt;iostram&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cin&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;...;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;...;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h4 id="inline方式书写类"&gt;inline方式书写类&lt;/h4&gt;
&lt;p&gt;对于某一个C++类,我们可以将其声明和定义直接写在一起(就是像C语音中一串写下来一样),示例:&lt;/p&gt;
&lt;div class="code-block" data-lang="c&amp;#43;&amp;#43;"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;c&amp;#43;&amp;#43;&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c++" data-lang="c++"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;complex&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;complex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;im&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;....&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;complex&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;operator&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;complex&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;real&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="nf"&gt;imag&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;retrun&lt;/span&gt; &lt;span class="n"&gt;im&lt;/span&gt;&lt;span class="p"&gt;;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;private&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;im&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;friend&lt;/span&gt; &lt;span class="n"&gt;complex&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;_doapl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;complex&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;complex&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;像如上内容中,在类定义中直接将函数具体实现写在&lt;code&gt;{...}&lt;/code&gt;中就是&lt;code&gt;inline&lt;/code&gt;写法&lt;/p&gt;</description></item><item><title>【ComfyUI】批量生成自动化</title><link>https://tingdonghu.github.io/posts/comfyui/comfyuii2i%E6%89%B9%E9%87%8F%E7%94%9F%E6%88%90%E8%87%AA%E5%8A%A8%E5%8C%96/</link><pubDate>Mon, 01 Dec 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/comfyui/comfyuii2i%E6%89%B9%E9%87%8F%E7%94%9F%E6%88%90%E8%87%AA%E5%8A%A8%E5%8C%96/</guid><description>&lt;p&gt;作者针对YOLO项目数据不足的问题，利用ComfyUI进行数据增强。由于官方批量功能不适用，他通过导出工作流API并编写Python脚本，实现了本地批量图片的自动化处理，高效生成训练所需的一对一对应图像数据。&lt;/p&gt;
&lt;p&gt;之前玩一个yolo项目的时候碰上了数据不足训练结果很差的问题，刚好现在AI生图这么发达，而自己之前有摸索过一点使用ComfyUI生图的工作流，索性开始用ComfyUI开始造数据。ComfyUI本身是支持多批次生成功能的。设置次数后可以反复运行该工作流，但是官方提供的这个更多是面向同一提示词、不同随机种子抽卡情况的。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/comfyui/comfyuii2i%E6%89%B9%E9%87%8F%E7%94%9F%E6%88%90%E8%87%AA%E5%8A%A8%E5%8C%96/image-20251201204323062.png"
alt="image-20251201204323062"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
image-20251201204323062
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;我造数据需要的工况则是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;N张图片经过工作流处理生成N张图片,每对图片一一对应&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;显然和官方提供的方法不太匹配，中间也找了几篇博客，有的是提供了批量加载图片节点，配合工作流的一个循环（LoopStart和LoopEnd）去实现的，个人尝试了一下发现其限制很大，每次限制加载100张，而且循环的逻辑很难用，还会出现重复加载的问题，只能算是面向非程序人员的解决方案了。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/comfyui/comfyuii2i%E6%89%B9%E9%87%8F%E7%94%9F%E6%88%90%E8%87%AA%E5%8A%A8%E5%8C%96/imageurl/img/plugins/comfyui-easy-use/compressed/lgqn8e9ixbgqmmp3dnqx5y.webp"
alt="Load Images For Loop文章图片"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
Load Images For Loop文章图片
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;还有些方法就是使用第三方的平台或者插件等调用API，该方法的解决问题是很不错的。这里留一个链接方便以后查找&lt;a href="https://doc.51easyai.com/getting-started/quickstart" target="_blank"&gt;快速开始 - EasyAI在线文档&lt;/a&gt;
。但是感觉我就很简单一个需求，完全没必要用这么复杂的东西，索性自己配合GPT整理了一个脚本，用于本地的Image2Image的工作流批量运行.&lt;/p&gt;
&lt;h3 id="comfyui导出工作流为api"&gt;ComfyUI导出工作流为API&lt;/h3&gt;
&lt;p&gt;要注意在保存导出为API之前，工作流中的预览图片节点要尽量去除，节省算力，同时要保证该工作流是确实可用的，可以运行出图的。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/comfyui/comfyuii2i%E6%89%B9%E9%87%8F%E7%94%9F%E6%88%90%E8%87%AA%E5%8A%A8%E5%8C%96/image-20251201210839690.png"
alt="image-20251201210839690"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
image-20251201210839690
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;</description></item><item><title>【论文阅读】ViewDiff：基于文生图模型的3D一致图像生成技术</title><link>https://tingdonghu.github.io/posts/comfyui/%E8%AE%BA%E6%96%87%E9%98%85%E8%AF%BBviewdiff%E5%9F%BA%E4%BA%8E%E6%96%87%E7%94%9F%E5%9B%BE%E6%A8%A1%E5%9E%8B%E7%9A%843d%E4%B8%80%E8%87%B4%E5%9B%BE%E5%83%8F%E7%94%9F%E6%88%90%E6%8A%80%E6%9C%AF/</link><pubDate>Tue, 04 Nov 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/comfyui/%E8%AE%BA%E6%96%87%E9%98%85%E8%AF%BBviewdiff%E5%9F%BA%E4%BA%8E%E6%96%87%E7%94%9F%E5%9B%BE%E6%A8%A1%E5%9E%8B%E7%9A%843d%E4%B8%80%E8%87%B4%E5%9B%BE%E5%83%8F%E7%94%9F%E6%88%90%E6%8A%80%E6%9C%AF/</guid><description>&lt;hr&gt;
&lt;p&gt;CVPR 2024论文ViewDiff提出了一种新方法，利用预训练的文生图扩散模型生成高质量且多视角一致的3D图像，旨在克服现有方法在真实感和视角一致性上的不足。&lt;/p&gt;
&lt;p&gt;大家好，我今天要分享的内容是ViewDiff 基于文生图模型的3D一致图像生成技术，是CVPR2024的一篇论文。&lt;/p&gt;
&lt;p&gt;论文原址：https://lukashoel.github.io/ViewDiff/&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/comfyui/%E8%AE%BA%E6%96%87%E9%98%85%E8%AF%BBviewdiff%E5%9F%BA%E4%BA%8E%E6%96%87%E7%94%9F%E5%9B%BE%E6%A8%A1%E5%9E%8B%E7%9A%843d%E4%B8%80%E8%87%B4%E5%9B%BE%E5%83%8F%E7%94%9F%E6%88%90%E6%8A%80%E6%9C%AF/image-20251104112946823-1762226997192-1.png"
alt="image-20251104112946823"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
image-20251104112946823
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;近年来 生成式人工智能(artificial intelligence generated content, AIGC)重新定义了视觉内容的生成、制作和编辑过程, 特别是自从扩散模型LDM（Latent Diffusion Model）和DiT (Diffusion Transformer)架构发布以来，由这两个架构所衍生的Stable Diffusion社区生态带来了AIGC领域的一片繁荣。&lt;/p&gt;
&lt;p&gt;最近国内常提起的豆包修图和Nannobanana也是基于上述的DIT框架。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/comfyui/%E8%AE%BA%E6%96%87%E9%98%85%E8%AF%BBviewdiff%E5%9F%BA%E4%BA%8E%E6%96%87%E7%94%9F%E5%9B%BE%E6%A8%A1%E5%9E%8B%E7%9A%843d%E4%B8%80%E8%87%B4%E5%9B%BE%E5%83%8F%E7%94%9F%E6%88%90%E6%8A%80%E6%9C%AF/image-20251104112253545.png"
alt="image-20251104112253545"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
image-20251104112253545
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="相关工作"&gt;相关工作&lt;/h2&gt;
&lt;h3 id="过往方法"&gt;过往方法&lt;/h3&gt;
&lt;p&gt;上述生成的内容主要局限在2D领域，扩散模型社区的繁荣吸引了很多研究人员探索扩散模型在3D内容生成领域的应用。&lt;/p&gt;
&lt;p&gt;现有方法普遍存在以下问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;优化类方法（如DreamFusion）生成结果非逼真、缺乏背景&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;相比起训练模型的2D数据,真实3D多视图数据的获取难度大，而通过2D数据合成的3D数据训练模型的模型普遍缺乏真实感。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;基于上述问题，本论文提出方法的核心目标是：&lt;/p&gt;
&lt;p&gt;利用预训练T2I模型先验，从真实数据中生成多视角一致的高质量图像&lt;/p&gt;
&lt;h3 id="前置知识"&gt;前置知识&lt;/h3&gt;
&lt;p&gt;在讲述本文方法的实现细节之前，先来讲述一下前置工作&lt;/p&gt;</description></item><item><title>【AIGC】生图模型概念&amp;模块宗述</title><link>https://tingdonghu.github.io/posts/comfyui/aigc%E7%94%9F%E5%9B%BE%E6%A8%A1%E5%9E%8B%E6%A6%82%E5%BF%B5%E6%A8%A1%E5%9D%97%E5%AE%97%E8%BF%B0/</link><pubDate>Wed, 22 Oct 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/comfyui/aigc%E7%94%9F%E5%9B%BE%E6%A8%A1%E5%9E%8B%E6%A6%82%E5%BF%B5%E6%A8%A1%E5%9D%97%E5%AE%97%E8%BF%B0/</guid><description>&lt;hr&gt;
&lt;p&gt;文章概述了生成式AI在视觉内容领域的演进，从早期算法到VAE和GAN，再到当前主流的扩散模型，分析了其核心思想与特点，并指出AIGC正向更高分辨率、更丰富内容和更可控的方向发展。&lt;/p&gt;
&lt;p&gt;随着人工智能以空前的速度不断发展, 生成式人工智能(artificial intelligence generated content, AIGC)重新定义了视觉内容的生成、制作和编辑过程, 彻底改变了我们感知和创造视觉内容的方式.&lt;/p&gt;
&lt;p&gt;早期算法通常使用图像匹配或人工设计的生成规则合成简单的纹理或结构; 随后, 深度学习时代提出变分自编码(variational auto-encoder, VAE)和生成对抗网络(generative adversarial net work, GAN), 它们能够学习如人像、室内场景等典型的图像分布; 当前,涌现出了大型的&lt;strong&gt;扩散模型&lt;/strong&gt;来 生成图像和更具挑战性的视频, 其生成的质量之高 甚至是人也难以区分真假. 从传统算法到 VAE 和 GAN, 再到扩散模型, AIGC 正在向更高分辨率、更丰富内容和更可控的生成方向演变.&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/comfyui/aigc%E7%94%9F%E5%9B%BE%E6%A8%A1%E5%9E%8B%E6%A6%82%E5%BF%B5%E6%A8%A1%E5%9D%97%E5%AE%97%E8%BF%B0/image-20251022230653074.png"
alt="图像生成模型架构和图像生成数据集的发展概览 "
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
图像生成模型架构和图像生成数据集的发展概览
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="图像生成模型"&gt;图像生成模型&lt;/h2&gt;
&lt;p&gt;目前主流的图像生成模型大致可以分为以下四类：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;模型类型&lt;/th&gt;
&lt;th&gt;代表模型&lt;/th&gt;
&lt;th&gt;核心思想&lt;/th&gt;
&lt;th&gt;特点&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GAN（生成对抗网络）&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;StyleGAN、BigGAN、CycleGAN&lt;/td&gt;
&lt;td&gt;生成器与判别器对抗训练&lt;/td&gt;
&lt;td&gt;图像质量高，但训练不稳定，控制性差&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;VAE（变分自编码器）&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;VQ-VAE、DALL-E 1&lt;/td&gt;
&lt;td&gt;编码为潜在变量再解码&lt;/td&gt;
&lt;td&gt;稳定性好，但图像模糊，细节差&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Diffusion（扩散模型）&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Stable Diffusion、DALL-E 2/3、Imagen&lt;/td&gt;
&lt;td&gt;去噪过程生成图像&lt;/td&gt;
&lt;td&gt;图像质量高，控制性强，训练成本高&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;自回归模型&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Parti、ImageGPT&lt;/td&gt;
&lt;td&gt;像语言模型一样逐像素/块生成&lt;/td&gt;
&lt;td&gt;可扩展性强，但生成速度慢&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/comfyui/aigc%E7%94%9F%E5%9B%BE%E6%A8%A1%E5%9E%8B%E6%A6%82%E5%BF%B5%E6%A8%A1%E5%9D%97%E5%AE%97%E8%BF%B0/image-20251022230951682.png"
alt="图像生成与编辑模型分类"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
图像生成与编辑模型分类
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;</description></item><item><title>【LLM应用开发】N8N搭建一个接入Notion的自动化工具</title><link>https://tingdonghu.github.io/posts/llm/llm%E6%8A%80%E6%9C%AFn8n%E6%90%AD%E5%BB%BA%E4%B8%80%E4%B8%AA%E6%8E%A5%E5%85%A5notion%E7%9A%84%E8%87%AA%E5%8A%A8%E5%8C%96%E5%B7%A5%E5%85%B7/</link><pubDate>Tue, 30 Sep 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/llm/llm%E6%8A%80%E6%9C%AFn8n%E6%90%AD%E5%BB%BA%E4%B8%80%E4%B8%AA%E6%8E%A5%E5%85%A5notion%E7%9A%84%E8%87%AA%E5%8A%A8%E5%8C%96%E5%B7%A5%E5%85%B7/</guid><description>&lt;p&gt;本文提供Notion API上传小文件的官方文档和视频教程链接，帮助开发者将文件附加到数据库页面。&lt;/p&gt;
&lt;h2 id="参考文献技术文档视频教程"&gt;参考文献||技术文档||视频教程&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=MwudPf0dz5k" target="_blank"&gt;https://www.youtube.com/watch?v=MwudPf0dz5k&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;&lt;a href="https://developers.notion.com/docs/uploading-small-files#example-attach-a-file-property-to-a-page-in-a-database" target="_blank"&gt;https://developers.notion.com/docs/uploading-small-files#example-attach-a-file-property-to-a-page-in-a-database&lt;/a&gt;
&lt;/p&gt;</description></item><item><title>【LLM应用开发原理】Transformer架构宗述</title><link>https://tingdonghu.github.io/posts/llm/llm%E6%8A%80%E6%9C%AFtransformer%E6%9E%B6%E6%9E%84%E5%AE%97%E8%BF%B0/</link><pubDate>Tue, 30 Sep 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/llm/llm%E6%8A%80%E6%9C%AFtransformer%E6%9E%B6%E6%9E%84%E5%AE%97%E8%BF%B0/</guid><description>&lt;p&gt;NLP 技术从传统统计方法演进至神经网络，Word Embeddings、RNN/LSTM 等模型逐步发展。Transformer 凭借自注意力机制实现突破，成为里程碑，并催生了 BERT、GPT 等变革性模型。&lt;/p&gt;
&lt;h3 id="博文背景"&gt;博文背景&lt;/h3&gt;
&lt;p&gt;之前在学习大模型相关技术的时候，看了很多篇对 Transfomer 解释的博客，但是感觉总是理解不透彻，不久之后就忘掉了，打算自己整理输出一下，以便更好的理解。&lt;/p&gt;
&lt;h3 id="transformer-的来源"&gt;Transformer 的来源&lt;/h3&gt;
&lt;p&gt;2017 年，Google 团队在论文《&lt;strong&gt;Attention Is All You Need&lt;/strong&gt;》中提出 Transformer，它完全摒弃递归结构，引入 &lt;strong&gt;自注意力机制&lt;/strong&gt;（Self-Attention），实现了全局上下文感知与并行计算的平衡，成为 NLP 乃至深度学习领域的里程碑。&lt;strong&gt;Transformer&lt;/strong&gt; 是 NLP 技术的一次革命性突破。与 RNN 和 LSTM 不同，Transformer 摒弃了序列数据的顺序处理方式，转而采用 &lt;strong&gt;自注意力机制&lt;/strong&gt;（Self-Attention），使得每个单词都能够直接与其它所有单词进行交互，从而提高了计算效率，并能捕捉更复杂的依赖关系。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/llm/llm%E6%8A%80%E6%9C%AFtransformer%E6%9E%B6%E6%9E%84%E5%AE%97%E8%BF%B0/1533981-20250718224012244-220282788.png"
alt="Trasnformer架构"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
Trasnformer架构
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;h4 id="bert"&gt;BERT&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;BERT&lt;/strong&gt;（Bidirectional Encoder Representations from Transformers）是基于 Transformer 的预训练模型，通过在大规模文本上进行双向预训练，BERT 能够更好地理解文本的上下文信息。BERT 的出现彻底改变了 NLP 模型的训练方法，许多 NLP 任务通过 &lt;strong&gt;迁移学习&lt;/strong&gt;，即先在大规模语料上预训练，再在具体任务上微调，取得了显著的效果提升。&lt;/p&gt;
&lt;h4 id="gpt"&gt;GPT&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;GPT&lt;/strong&gt;（Generative Pre-trained Transformer)系列是由 OpenAI 提出的基于 Transformer 架构的生成模型。与 BERT 的“编码器”结构不同，GPT 采用了“解码器”结构，专注于生成任务，如文本生成、翻译、问答等。&lt;/p&gt;</description></item><item><title>【LLM应用开发原理】RAG是什么详解</title><link>https://tingdonghu.github.io/posts/agent/llm%E6%8A%80%E6%9C%AFrag%E6%98%AF%E4%BB%80%E4%B9%88%E5%AE%97%E8%BF%B0%E4%B8%8E%E8%AF%A6%E8%A7%A3/</link><pubDate>Sat, 13 Sep 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/agent/llm%E6%8A%80%E6%9C%AFrag%E6%98%AF%E4%BB%80%E4%B9%88%E5%AE%97%E8%BF%B0%E4%B8%8E%E8%AF%A6%E8%A7%A3/</guid><description>&lt;p&gt;RAG（检索增强生成）通过构建知识库和智能检索机制，为AI模型精准提供外部信息，解决大模型知识过时和幻觉问题。它避免了昂贵的模型重训练，克服了直接输入长文本的低效性，是实现高效、准确AI应用的关键技术。&lt;/p&gt;
&lt;h1 id="rag基本概念"&gt;RAG基本概念&lt;/h1&gt;
&lt;h2 id="一个简单的rag案例"&gt;一个简单的RAG案例&lt;/h2&gt;
&lt;p&gt;许多纯小白对于大模型和RAG可能并没有一个具体的概念，现以下面的的简单案例介绍以下：&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/agent/llm%E6%8A%80%E6%9C%AFrag%E6%98%AF%E4%BB%80%E4%B9%88%E5%AE%97%E8%BF%B0%E4%B8%8E%E8%AF%A6%E8%A7%A3/image-20250914114138671.png"
alt="image-20250914114138671"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
image-20250914114138671
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;想象一下，你开了一家网店，生意越来越火，客服消息回不过来了。你听说现在AI很厉害，于是买了一个基于“Deepseek”大模型的AI客服机器人。&lt;/p&gt;
&lt;p&gt;第一天上线，你就发现了问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;顾客问：“你们最新款的iPhone 16什么时候预售？”&lt;/li&gt;
&lt;li&gt;AI客服答得头头是道，但内容却是基于去年的iPhone 14。因为它的大脑（Deepseek）训练数据只更新到2023年底，它根本不知道2024年发布的iPhone 16！&lt;/li&gt;
&lt;li&gt;顾客问：“你们店独家定制的那款‘星空杯’用什么材料？能进微波炉吗？”&lt;/li&gt;
&lt;li&gt;AI客服开始胡编乱造，因为它的大脑里完全没有你家私域产品的任何信息。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这时候，你该怎么办？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;方案一：给AI大脑“重新上学”？——成本太高！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;最直接的想法是：我把自家所有的产品手册、最新政策都整理成教材，让这个AI大脑（Deepseek）重新学习一遍，不就行了？&lt;/p&gt;
&lt;p&gt;但这相当于送它去读一次“考研冲刺班”，代价极其高昂：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;烧钱&lt;/strong&gt;：训练一次大模型，需要大量的顶级显卡和算力，费用可能是几十万甚至上百万。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;费时&lt;/strong&gt;：训练过程漫长，等你训练好了，可能最新的促销活动又变了。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不通用&lt;/strong&gt;：难道每个店家都要为了自己的产品，单独训练一个“专属大脑”吗？这太不现实了。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;结论：让模型重新学习，此路不通。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;方案二：把说明书当“小抄”递给AI——聪明但有限！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我们又想出一个巧妙的办法：我不改变AI的大脑，每次它回答问题的时候，我都把厚厚的产品说明书像“小抄”一样塞给它看，让它照着抄总行吧？&lt;/p&gt;
&lt;p&gt;这个方法叫 &lt;strong&gt;“提示词工程”&lt;/strong&gt; ，确实有用！但马上遇到了新麻烦：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;“小抄”太长了&lt;/strong&gt;：你的产品库有成百上千件商品，说明书加起来有几十万字。AI的“短期记忆”（上下文窗口）是有限的，一次看不完这么厚的“小抄”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“抄”得太慢&lt;/strong&gt;：每次都要处理海量文本，AI反应会变得非常慢，顾客等不及就走了。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;“抄”串行&lt;/strong&gt;：信息太多太杂，AI可能会看花眼，把A产品的功能安到B产品上，开始&lt;strong&gt;胡说八道（术语叫“幻觉”）&lt;/strong&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;结论：直接塞“小抄”，效率低，效果差。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;终极方案：给AI配一个“超级秘书”（RAG）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;既然“小抄”太长，那我们能不能做一个&lt;strong&gt;智能摘要&lt;/strong&gt;，每次只把“小抄”里&lt;strong&gt;最相关的那一页&lt;/strong&gt;精准地抽出来递给AI呢？&lt;/p&gt;
&lt;p&gt;当然可以！这套完美的解决方案，就叫做 &lt;strong&gt;RAG（检索增强生成）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;你可以把它想象成给AI配了一个无所不知的“超级秘书”。这个秘书有两大本领：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. 预处理：把厚书拆成单页（知识库切片）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;首先，秘书会把你们店厚厚的所有产品说明书、客服话术、最新活动文件（我们称之为 &lt;strong&gt;“知识库”&lt;/strong&gt;），全部拆解。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;她不会粗暴地一撕两半，而是&lt;strong&gt;有逻辑地拆&lt;/strong&gt;：按章节、按段落、按产品型号，拆成一个个大小适中、意思完整的小片段（Chunk）。&lt;/li&gt;
&lt;li&gt;比如，关于“iPhone 16”的配置、价格、预售政策，会被整理成不同的卡片页。&lt;/li&gt;
&lt;li&gt;这一步解决了“小抄太长”的基础问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;2. 智能检索：建立超级索引（向量化检索）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;接着，秘书会做一个谁也做不到的绝活：她给每一页“知识卡片”都生成一个&lt;strong&gt;独一无二的“数学指纹”（向量）&lt;/strong&gt;，并把这些指纹和卡片一起存进一个超级快的“智能档案柜”（向量数据库）里。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;这个“数学指纹”的神奇之处在于：&lt;strong&gt;意思相近的内容，指纹也相似。&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;当顾客提问：**“iPhone 16预售政策是什么？”**秘书会瞬间分析这个问题，生成一个问题的“指纹”。然后她转身在“智能档案柜”里进行指纹匹配，&lt;strong&gt;一秒内&lt;/strong&gt;就从几十万张卡片中，精准地找出那几张关于“iPhone 16预售政策”的卡片。&lt;strong&gt;这个过程，就相当于从一本厚厚的书中，瞬间精准地翻到了你最需要的那一页。&lt;/strong&gt; 这就是对海量知识的“智能压缩”和“精准切片”。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;3. 协同工作：秘书递纸条，AI来回答&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>【Games101】几何表达与绘制</title><link>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E5%87%A0%E4%BD%95%E8%A1%A8%E8%BE%BE%E4%B8%8E%E7%BB%98%E5%88%B6/</link><pubDate>Sat, 05 Jul 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E5%87%A0%E4%BD%95%E8%A1%A8%E8%BE%BE%E4%B8%8E%E7%BB%98%E5%88%B6/</guid><description>&lt;p&gt;几何是计算机图形学中三维建模与渲染的基础，应用于物体建模、几何变换和碰撞检测等领域。其表示方法主要分为隐式表示（如代数曲面、水平集和距离函数）和显式表示，用于描述不同复杂度的形状。&lt;/p&gt;
&lt;h1 id="几何概念"&gt;几何概念&lt;/h1&gt;
&lt;blockquote class="dream-alert tip"&gt;
&lt;p class="heading"&gt;
&lt;ion-icon name="bulb-outline"&gt;&lt;/ion-icon&gt;Tip&lt;/p&gt;
&lt;p&gt;个人感觉本章前面的内容有点空洞和理论，建议直接快速浏览，从几何处理部分看起。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="几何的应用applications-of-geometry"&gt;几何的应用（Applications of Geometry）&lt;/h2&gt;
&lt;p&gt;在图形学中，几何不仅仅关乎抽象的数学对象，它是三维建模和渲染的基础。以下是几何学的几个应用领域：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;物体建模&lt;/strong&gt;：通过几何学，计算机可以表示任何形状，例如从简单的几何体（如球体、立方体等）到复杂的自由形状（如汽车、人物模型等）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;几何变换&lt;/strong&gt;：在渲染和动画中，物体的形状需要根据不同的需要进行变换，例如平移、旋转、缩放等。这些变换都可以通过几何学的运算来实现。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;碰撞检测&lt;/strong&gt;：几何学还用于物理引擎中的碰撞检测，确保虚拟世界中的物体不会穿透或重叠。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E5%87%A0%E4%BD%95%E8%A1%A8%E8%BE%BE%E4%B8%8E%E7%BB%98%E5%88%B6/image-20251203140412366.png"
alt="一些几何学应用"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
一些几何学应用
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="几何表示representations-of-geometry"&gt;几何表示（Representations of Geometry)&lt;/h2&gt;
&lt;h3 id="隐式表示implicit-representations"&gt;隐式表示（Implicit Representations）&lt;/h3&gt;
&lt;p&gt;隐式表示并不是直接通过列举点或多边形来描述物体的表面，而是通过某个数学方程或函数来定义物体的几何形状。隐式表示方法通过一个方程或函数来表示物体表面上的所有点。这些函数通常被用来定义物体的边界或表面。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;代数曲面（Algebraic Surfaces）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E5%87%A0%E4%BD%95%E8%A1%A8%E8%BE%BE%E4%B8%8E%E7%BB%98%E5%88%B6/image-20251203140426016.png"
alt="代数曲面"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
代数曲面
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;代数曲面是通过代数方程来描述物体的形状。最简单的例子是球体，它可以通过方程 $x^2 + y^2 + z^2 = r^2$ 来表示。这种表示方法非常直观，适合表示对称性较好的几何形状，但对于复杂图形无能为力。&lt;/p&gt;</description></item><item><title>【Games101】纹理映射与着色</title><link>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E7%BA%B9%E7%90%86%E6%98%A0%E5%B0%84%E4%B8%8E%E7%9D%80%E8%89%B2/</link><pubDate>Thu, 03 Jul 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E7%BA%B9%E7%90%86%E6%98%A0%E5%B0%84%E4%B8%8E%E7%9D%80%E8%89%B2/</guid><description>&lt;p&gt;纹理是计算机图形学中用于增强模型表面细节的二维图像或数据贴图。通过纹理映射技术，结合UV坐标系和重心坐标插值，可将纹理贴合到三维模型表面，提供颜色、法线等丰富信息，提升视觉真实感。&lt;/p&gt;
&lt;h1 id="什么是-texture"&gt;什么是 Texture？&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;纹理（Texture）&lt;/strong&gt; 是计算机图形学中用于增强图像细节和真实感的图像或数据贴图。它本质上是一种二维（通常是图片）或多维数据，常用于为图形表面提供颜色、法线、反射、透明度等信息。结合我们上节课提到的 &lt;strong&gt;布林-冯反射模型（Blinn-Phong Reflectance Model）&lt;/strong&gt;，纹理可以在漫反射部分表现不同的模型颜色，通过将纹理映射到表面，提供更加丰富的视觉效果。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;纹理&lt;/strong&gt; 作为图形表面上的“贴图”，通常是二维图像，但在某些情况下，也可以是多维数据，用来提供表面的额外信息，增强其细节。&lt;/p&gt;
&lt;p&gt;在 &lt;strong&gt;布林-冯反射模型&lt;/strong&gt; 中，纹理主要用于模拟漫反射光照效果（即表面反射的光线分布），使得物体表面看起来更加自然和复杂。例如，在一个物体表面的漫反射部分，纹理可以通过控制不同区域的颜色和明暗，进一步模拟表面材料的特性。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E7%BA%B9%E7%90%86%E6%98%A0%E5%B0%84%E4%B8%8E%E7%9D%80%E8%89%B2/image-20251128185121557.png"
alt="包含了多种反射的示例"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
包含了多种反射的示例
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="纹理映射texture-mapping"&gt;纹理映射（Texture Mapping）&lt;/h2&gt;
&lt;p&gt;纹理映射是一种将二维纹理图像（通常为位图）“贴”到三维模型表面的方法，目的是在不增加几何体复杂度的前提下，为三维物体提供更细致的视觉效果。通过纹理映射，物体表面可以拥有丰富的颜色、图案、细节等信息，而不需要额外的多边形面片。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E7%BA%B9%E7%90%86%E6%98%A0%E5%B0%84%E4%B8%8E%E7%9D%80%E8%89%B2/image-20250722165716060.png"
alt="地球仪表面展开"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
地球仪表面展开
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;如上图所示：3D物体的表面其实都是2D的，比如地球仪，将地球仪上的图撕下来，可以平铺成一张2D的图物体的表面，通过这种方式可以和一张图有一一对应的关系，这张图就叫纹理， 将这张图平铺/裁剪/拉伸到任何物体表面，就叫纹理映射，纹理上的坐标系通常以UV来表示。&lt;/p&gt;
&lt;h2 id="uv坐标系"&gt;UV坐标系&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;UV 坐标系统&lt;/strong&gt;：这是一种标准的坐标系统，用来描述如何将纹理与物体表面的几何形状进行对应。纹理坐标的值通常在 [0, 1] 范围内：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;U&lt;/code&gt; 是纹理图像的水平方向坐标，类似于 x 轴；&lt;/li&gt;
&lt;li&gt;&lt;code&gt;V&lt;/code&gt; 是纹理图像的垂直方向坐标，类似于 y 轴。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每个顶点都被赋予一个 &lt;code&gt;(U, V)&lt;/code&gt; 坐标，当渲染时，图形管线会根据这些坐标从纹理图像中提取颜色信息。屏幕上的采样点（x,y）可以用重心坐标算出在纹理中采样的uv，得到对应纹理。&lt;/p&gt;</description></item><item><title>【Games101】着色基础</title><link>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E7%9D%80%E8%89%B2%E5%9F%BA%E7%A1%80/</link><pubDate>Tue, 01 Jul 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E7%9D%80%E8%89%B2%E5%9F%BA%E7%A1%80/</guid><description>&lt;p&gt;Shading是图形学中模拟光线与物体表面交互，计算颜色和明暗的技术。其核心包括局部着色模型，以及漫反射、镜面高光和环境光等基础光照现象的模拟，以实现逼真的视觉效果。&lt;/p&gt;
&lt;p&gt;Shading是图形学中决定物体表面外观的关键技术，它模拟光线与物体表面的交互过程。&lt;/p&gt;
&lt;h2 id="什么是shading"&gt;什么是Shading？&lt;/h2&gt;
&lt;p&gt;Shading是指计算物体表面颜色和明暗的过程，通过模拟光线与材质相互作用来产生逼真的视觉效果。&lt;/p&gt;
&lt;h2 id="局部着色shading-is-local"&gt;局部着色（Shading is Local）&lt;/h2&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E7%9D%80%E8%89%B2%E5%9F%BA%E7%A1%80/image-20250703000938953.png"
alt="光线与着色点"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
光线与着色点
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;局部着色定义为：计算特定着色点处反射到相机的光线&lt;/p&gt;
&lt;p&gt;其关键要素一般为：l 光线照射方向向量，n 着色点表面法向量，v 观察视角方向，以及一个关键的表面参数（比如颜色color，光泽度shininess）&lt;/p&gt;
&lt;h2 id="基础光照现象"&gt;基础光照现象&lt;/h2&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E7%9D%80%E8%89%B2%E5%9F%BA%E7%A1%80/image-20250703000605878.png"
alt="三种不同的Shading类型"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
三种不同的Shading类型
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;如上图所示，**镜面高光（Specular highlights）**在杯口和把手转折处形成明亮的聚焦光斑，体现了光滑表面对光源的直接反射；**漫反射（Diffuse reflection）**在杯身侧面形成均匀的色彩渐变，如淡绿色杯子柔和的明暗过渡，反映了朗伯体表面的均匀散射特性；**环境光（Ambient lighting）**则使背光面（如棕色杯子底部）保持基础可见性，代表间接光照的简化模拟。&lt;/p&gt;
&lt;h3 id="漫反射与兰伯特余弦定律lamberts-cosine-law"&gt;漫反射与兰伯特余弦定律（Lambert&amp;rsquo;s Cosine Law）&lt;/h3&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E7%9D%80%E8%89%B2%E5%9F%BA%E7%A1%80/image-20250703001945326.png"
alt="漫反射"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
漫反射
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;</description></item><item><title>【Games101】光栅化基础</title><link>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E5%85%89%E6%A0%85%E5%8C%96%E5%9F%BA%E7%A1%80/</link><pubDate>Sun, 29 Jun 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E5%85%89%E6%A0%85%E5%8C%96%E5%9F%BA%E7%A1%80/</guid><description>&lt;p&gt;光栅化是将几何图元（如三角形）转换为屏幕像素的核心渲染过程，涉及视口变换等步骤，并依托于CRT、LCD、OLED等显示设备最终成像。&lt;/p&gt;
&lt;h1 id="什么是光栅化"&gt;什么是光栅化？&lt;/h1&gt;
&lt;p&gt;光栅化是 &lt;strong&gt;将几何图元（如三角形、线段）转换为屏幕上的像素（或片元）的过程&lt;/strong&gt;，是实时3D渲染的核心步骤。它通过计算图元覆盖的像素区域，并插值顶点属性（颜色、深度等），最终生成可供显示的2D图像。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E5%85%89%E6%A0%85%E5%8C%96%E5%9F%BA%E7%A1%80/image-20250629184634259.png"
alt="光栅化转化为像素点"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
光栅化转化为像素点
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="显示器模型"&gt;显示器模型&lt;/h2&gt;
&lt;p&gt;图形学中，屏幕就认为是一个装了像素的二维数组。如数组大小1920*1080，每个数组为一个像素点，像素是最小单位，每个像素由RBG的四维矩阵构成。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E5%85%89%E6%A0%85%E5%8C%96%E5%9F%BA%E7%A1%80/image-20250629215327416.png"
alt="显示器简化模型"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
显示器简化模型
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;如上图所示像素的坐标以左下角为准，如图中蓝色像素坐标为（2，1）&lt;/p&gt;
&lt;p&gt;像素的中心为（x+0.5,y+0.5）&lt;/p&gt;
&lt;h2 id="视口变换"&gt;视口变换&lt;/h2&gt;
&lt;p&gt;在进行了上节课的&lt;strong&gt;透视投影变换&lt;/strong&gt;操作之后，所有物体都处在了[-1，1]³的立方体中，接下来就要把他画在屏幕上。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E5%85%89%E6%A0%85%E5%8C%96%E5%9F%BA%E7%A1%80/image-20250629212820029.png"
alt="透视投影变换"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
透视投影变换
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;</description></item><item><title>【Games101】变换基础概念</title><link>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E5%8F%98%E6%8D%A2%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5/</link><pubDate>Fri, 27 Jun 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E5%8F%98%E6%8D%A2%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5/</guid><description>&lt;p&gt;计算机图形学中的基本变换包括缩放、镜像、错切和旋转，每种变换都可通过特定的数学矩阵来描述物体在二维空间中的位置、大小和方向变化。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;变换Transformation&lt;/strong&gt;是计算机图形学中的基础概念，用于描述和操作物体在二维或三维空间中的位置、方向和大小。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E5%8F%98%E6%8D%A2%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5/image-20250626180918517.png"
alt="变换概念"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
变换概念
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="基本变换类型"&gt;基本变换类型&lt;/h2&gt;
&lt;h3 id="缩放变换scale"&gt;缩放变换（Scale）&lt;/h3&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E5%8F%98%E6%8D%A2%E5%9F%BA%E7%A1%80%E6%A6%82%E5%BF%B5/image-20250626181358791.png"
alt="对称缩放"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
对称缩放
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;h1 id="endbmatrix"&gt;如图所示的坐标轴内物体缩放，其数学变换公式为:
$$
\begin{aligned}
x' &amp;= s \cdot x \\
y' &amp;= s \cdot y
\end{aligned}
$$
矩阵格式表述为:
$$
\begin{bmatrix}
x&amp;rsquo; \
y'
\end{bmatrix}&lt;/h1&gt;
&lt;p&gt;\begin{bmatrix}
s &amp;amp; 0 \
0 &amp;amp; s
\end{bmatrix}
\begin{bmatrix}
x \
y
\end{bmatrix}
$$
而以此推广为非对称缩放变化:&lt;/p&gt;</description></item><item><title>【Games101】图形学概述与数学基础</title><link>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E5%9B%BE%E5%BD%A2%E5%AD%A6%E6%A6%82%E8%BF%B0%E4%B8%8E%E6%95%B0%E5%AD%A6%E5%9F%BA%E7%A1%80/</link><pubDate>Tue, 24 Jun 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E5%9B%BE%E5%BD%A2%E5%AD%A6%E6%A6%82%E8%BF%B0%E4%B8%8E%E6%95%B0%E5%AD%A6%E5%9F%BA%E7%A1%80/</guid><description>&lt;p&gt;计算机图形学是研究计算机中图形表示、生成、处理和显示的交叉学科，其核心内容包括图形表示、生成、处理与显示，并与计算机视觉、图像处理等学科紧密关联。学习图形学需要掌握线性代数基础，如向量的点乘、叉乘及矩阵运算。&lt;/p&gt;
&lt;h2 id="基本概念"&gt;基本概念&lt;/h2&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E5%9B%BE%E5%BD%A2%E5%AD%A6%E6%A6%82%E8%BF%B0%E4%B8%8E%E6%95%B0%E5%AD%A6%E5%9F%BA%E7%A1%80/image-20250624195425600.png"
alt="CG与真实拍摄"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
CG与真实拍摄
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;h3 id="计算机图形学是什么"&gt;&lt;strong&gt;计算机图形学是什么？&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;计算机图形学(Computer Graphics)是研究如何在计算机中表示、生成、处理和显示图形的学科。它结合了数学、物理学、计算机科学和艺术等多个领域的知识，致力于解决如何在计算机上创建和操作视觉内容的问题，其最直观的用途包括如下四个方面。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;图形表示&lt;/strong&gt;：研究如何在计算机中表示2D和3D图形对象&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;图形生成&lt;/strong&gt;：如何从模型数据生成可视图像&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;图形处理&lt;/strong&gt;：对已有图形进行变换、编辑和优化&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;图形显示&lt;/strong&gt;：如何将生成的图形高效地显示在输出设备上&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="图形学cg与其他学科的关系"&gt;&lt;strong&gt;图形学(CG)与其他学科的关系&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;计算机视觉(CV)&lt;/strong&gt;：图形学是&amp;quot;从模型到图像&amp;quot;，计算机视觉是&amp;quot;从图像到模型&amp;quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;图像处理&lt;/strong&gt;：图形学绘制（渲染）图像，图像处理修改已有图像&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;计算几何&lt;/strong&gt;：提供图形学所需的几何算法&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;人机交互&lt;/strong&gt;：图形学为HCI提供可视化界面&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;为什么要学图形学？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;因为图形学很酷！&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/games101%E7%AC%94%E8%AE%B0/games101%E5%9B%BE%E5%BD%A2%E5%AD%A6%E6%A6%82%E8%BF%B0%E4%B8%8E%E6%95%B0%E5%AD%A6%E5%9F%BA%E7%A1%80/image-20250624152226718.png"
alt="图形学很酷"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
图形学很酷
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="线性代数基础"&gt;线性代数基础&lt;/h2&gt;
&lt;h3 id="向量的点乘dot-product"&gt;向量的点乘（Dot Product）&lt;/h3&gt;
&lt;p&gt;两个向量的点乘结果是一个标量&lt;/p&gt;
$$
\vec{a} \cdot \vec{b} = \|\vec{a}\| \|\vec{b}\| \cos\theta
$$&lt;p&gt;
&lt;strong&gt;几何意义&lt;/strong&gt;：&lt;/p&gt;</description></item><item><title>【C++】C++中的设计模式</title><link>https://tingdonghu.github.io/posts/c++/c++c++%E4%B8%AD%E7%9A%84%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/</link><pubDate>Thu, 01 May 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/c++/c++c++%E4%B8%AD%E7%9A%84%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/</guid><description>&lt;hr&gt;
&lt;p&gt;设计模式是针对软件设计中反复出现问题的通用解决方案，其核心在于提升代码复用性，避免重复劳动。&lt;/p&gt;
&lt;h2 id="什么是设计模式"&gt;什么是设计模式&lt;/h2&gt;
&lt;p&gt;引用**克里斯托弗·亚历山大（Christopher Alexander）**在1977年的著作《&lt;strong&gt;A Pattern Language: Towns, Buildings, Construction&lt;/strong&gt;》中提出了关于设计模式的经典定义。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;英文原版&lt;/strong&gt;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&amp;ldquo;Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice.&amp;rdquo;&lt;/em&gt;
— Christopher Alexander, &lt;em&gt;A Pattern Language&lt;/em&gt;, 1977&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;中文翻译&lt;/strong&gt;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“每一个模式描述了一个在我们环境中反复出现的问题，并描述了该问题解决方案的核心。通过这种方式，你可以无数次地使用该解决方案，而无需以相同的方式重复两次。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;说人话就是:&lt;code&gt;不需要重复造轮子&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;推荐一本历史性著作《设计模式:可复用面相对象软件的基础》&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/c&amp;#43;&amp;#43;/c&amp;#43;&amp;#43;c&amp;#43;&amp;#43;%E4%B8%AD%E7%9A%84%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B8%AD%E6%96%87%E7%89%88%E5%B0%81%E9%9D%A2.jpg"
alt="设计模式:可复用面相对象软件的基础"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
设计模式:可复用面相对象软件的基础
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;</description></item><item><title>3D生成AI学习笔记（一）：范式革命与管线全景图</title><link>https://tingdonghu.github.io/posts/3dgenai/part1-paradigm-revolution-pipeline/</link><pubDate>Sun, 27 Apr 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/3dgenai/part1-paradigm-revolution-pipeline/</guid><description>&lt;h1 id="第一部分开篇明义3d生成ai的范式革命与管线全景图"&gt;第一部分：开篇明义——3D生成AI的范式革命与管线全景图&lt;/h1&gt;
&lt;h2 id="11-传统3d内容制作管线拆解一座精确到小时的工时金字塔"&gt;1.1 传统3D内容制作管线拆解：一座精确到小时的工时金字塔&lt;/h2&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/3dgenai/part1-paradigm-revolution-pipeline/01-comparison-pipeline-hours.png"
alt="传统3D管线工时 vs AI辅助压缩对比"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
传统3D管线工时 vs AI辅助压缩对比
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;要理解3D生成AI带来的冲击，必须先理解传统3D内容制作管线的深度与复杂度。下面以&lt;strong&gt;影视级/3A游戏角色&lt;/strong&gt;为基准，逐环节拆解。&lt;/p&gt;
&lt;h3 id="111-高模雕刻数字粘土的几何密度极限"&gt;1.1.1 高模雕刻：数字粘土的几何密度极限&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;定义层&lt;/strong&gt;：高模雕刻（High-Poly Sculpting）是在计算机中使用数字笔刷对虚拟几何体进行增减材料的操作，目标是创建包含极高表面细节的&lt;strong&gt;三维数字原型&lt;/strong&gt;，细节精度需达到毛孔、皱纹、织物纤维级别。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;原理层&lt;/strong&gt;：为什么需要数百万乃至数千万个多边形？因为真实世界的表面细节具有分形特征——当你不断放大，新的细节持续涌现。传统多边形建模无法高效表达这种不规则表面，而雕刻模式基于**细分曲面（Subdivision Surface）**技术，允许艺术家在低精度基网（Base Mesh）上操作，由算法实时细分生成光滑表面。法线烘焙（Normal Baking）的哲学前提是：人眼对表面朝向的变化极其敏感，但对 silhouette 边缘的 polygon 阶梯不敏感（在一定距离外）。因此，我们可以将高模的微观表面法线信息编码到一张法线贴图（Normal Map）中，施加到低模表面，在渲染时欺骗光照计算，获得接近高模的视觉效果。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;实例层&lt;/strong&gt;：在 &lt;strong&gt;ZBrush&lt;/strong&gt; 中的典型流程为：导入基础人形（约 5,000-10,000 面）→ 使用 &lt;strong&gt;Dynamesh&lt;/strong&gt; 动态重建均匀拓扑（解决拉伸问题）→ 逐级增加细分级别（Subdivision Levels，通常 4-7 级，最终可达 500万-2,000万 有效面）→ 使用 Standard/Clay Buildup/Trim Dynamic 笔刷塑造体积 → 使用 Dam Standard/Orb Cracks 笔刷雕刻皱纹与破损 → 使用 NoiseMaker 或 Surface Noise 添加微观皮肤毛孔。一个影视级角色高模的纯雕刻工时通常为 &lt;strong&gt;2-5 天&lt;/strong&gt;，复杂生物（如带鳞片的龙）可达 &lt;strong&gt;2 周&lt;/strong&gt;。关键概念是&lt;strong&gt;多边形流（Polygon Flow）&lt;/strong&gt;——即使在 Dynamesh 阶段不关注拓扑，艺术家仍需在心里规划肌肉走向，因为雕刻的细节分布必须遵循解剖学张力线。&lt;/p&gt;</description></item><item><title>3D生成AI学习笔记（三）：核心生成模型范式</title><link>https://tingdonghu.github.io/posts/3dgenai/part3-core-generative-models/</link><pubDate>Sun, 27 Apr 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/3dgenai/part3-core-generative-models/</guid><description>&lt;h1 id="第三部分核心篇上3d生成模型的核心范式"&gt;第三部分：核心篇（上）——3D生成模型的核心范式&lt;/h1&gt;
&lt;h2 id="31-基于体素与栅格的生成"&gt;3.1 基于体素与栅格的生成&lt;/h2&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/3dgenai/part3-core-generative-models/01-comparison-generation-paradigms.png"
alt="3D生成四大范式对比"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
3D生成四大范式对比
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;h3 id="311-3d-gan深度卷积在三维空间的首次成功"&gt;3.1.1 3D-GAN：深度卷积在三维空间的首次成功&lt;/h3&gt;
&lt;p&gt;三维生成对抗网络的早期探索中，&lt;strong&gt;3D Generative Adversarial Network (3D-GAN)&lt;/strong&gt; 由 Wu 等人于 CVPR 2016 提出，是首次将深度卷积架构成功扩展到三维体素空间的开创性工作。其前身可追溯至 Goodfellow 等人 2014 年的原始 GAN 框架以及 3DShapeNets (Wu et al., CVPR 2015) 对三维形状的卷积编码器探索；其后续影响则体现在后续大量基于体素的条件生成模型（如 3D-VAE-GAN、PrGAN）以及隐式场方法中对三维卷积特征的处理。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;完整架构&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;3D-GAN 的生成器 $G$ 采用 5 层三维转置卷积（3D Transposed Convolution），将低维潜码 $\mathbf{z} \in \mathbb{R}^{200}$（从标准正态分布采样）映射到 $64 \times 64 \times 64$ 的占据体素网格：&lt;/p&gt;
$$
\mathbf{z} \sim \mathcal{N}(0, I), \quad G(\mathbf{z}) = \mathbf{o} \in [0,1]^{64 \times 64 \times 64}
$$&lt;p&gt;生成器的逐层变换为：&lt;/p&gt;</description></item><item><title>3D生成AI学习笔记（二）：先修知识体系</title><link>https://tingdonghu.github.io/posts/3dgenai/part2-prerequisite-knowledge/</link><pubDate>Sun, 27 Apr 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/3dgenai/part2-prerequisite-knowledge/</guid><description>&lt;h1 id="第二部分筑基篇不可或缺的先修知识"&gt;第二部分：筑基篇——不可或缺的先修知识&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;如果你不知道数据是如何表示的，你就不知道模型在学什么；如果你不知道模型在优化什么，你就不知道它为什么会失败。&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;3D生成AI是一个极度跨学科的领域。它要求研究者同时具备3D计算机图形学的几何直觉和深度学习的优化理论。本章的目标不是泛泛而谈，而是为后续所有技术细节打下&lt;strong&gt;数学上严谨、工程上可落地&lt;/strong&gt;的基础。我们会从最底层的表示方法出发，逐步建立起连接图形学与深度学习的完整知识图谱。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="21-3d计算机图形学基础"&gt;2.1 3D计算机图形学基础&lt;/h2&gt;
&lt;h3 id="211-五种核心表示方法重点中的重点"&gt;2.1.1 五种核心表示方法（重点中的重点）&lt;/h3&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/3dgenai/part2-prerequisite-knowledge/01-infographic-3d-representations.png"
alt="3D核心表示方法总览"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
3D核心表示方法总览
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;在3D生成AI中，&lt;strong&gt;表示（Representation）就是一切&lt;/strong&gt;。神经网络最终输出的不可能是&amp;quot;一个物体&amp;quot;的抽象概念，它必须选择一种数学结构来编码几何与外观。不同的表示决定了：模型的架构设计、损失函数的构造、训练难度的量级，以及最终生成结果的用途。&lt;/p&gt;
&lt;h4 id="多边形网格polygon-mesh"&gt;多边形网格（Polygon Mesh）&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;精确数学定义&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;一个多边形网格是一个三元组 $\mathcal{M} = (V, E, F)$，其中：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;顶点集合 $V = \{v_1, v_2, \dots, v_N\} \subset \mathbb{R}^3$；&lt;/li&gt;
&lt;li&gt;边集合 $E \subset V \times V$，其中每条边 $e_{ij} = (v_i, v_j)$；&lt;/li&gt;
&lt;li&gt;面集合 $F$，每个面 $f \in F$ 是顶点的一个循环子集。在计算机图形学中，我们几乎总是使用&lt;strong&gt;三角网格&lt;/strong&gt;，即每个面恰好包含3个顶点：$f = (v_i, v_j, v_k)$。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一个网格是**流形（Manifold）**的，当且仅当每个点 $p \in \mathcal{M}$ 存在一个邻域 $U_p$，使得 $U_p$ 同胚于（homeomorphic to） either $\mathbb{R}^2$（内部点）或 $\mathbb{R}^2_{\geq 0}$（边界点）。直观地说，流形网格在局部看起来必须像一张纸或半张纸——不允许存在&amp;quot;三张纸在一个边上交汇&amp;quot;（非流形边）或&amp;quot;多张纸在一个点交汇&amp;quot;（非流形顶点）的情况。&lt;/p&gt;</description></item><item><title>3D生成AI学习笔记（五）：评估与验证</title><link>https://tingdonghu.github.io/posts/3dgenai/part5-evaluation-validation/</link><pubDate>Sun, 27 Apr 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/3dgenai/part5-evaluation-validation/</guid><description>&lt;h1 id="第五部分验证与评估篇如何衡量生成结果的好坏"&gt;第五部分：验证与评估篇——如何衡量生成结果的好坏？&lt;/h1&gt;
&lt;p&gt;在三维生成模型的研究与发展中，评估（Evaluation）绝非简单的&amp;quot;打分数&amp;quot;环节，而是整个科学方法论体系的基石。与二维图像生成领域存在 Fréchet Inception Distance（FID）这类虽不完美却已被广泛接受的&amp;quot;通用货币&amp;quot;不同，三维生成至今尚未形成单一的主导性指标。这种碎片化现状源于三维数据本身的异质性——同样的生成结果可以以体素、点云、网格、隐式场或神经辐射场（NeRF）的形式存在；也源于评估维度的多元性——几何精度、视觉保真度、拓扑正确性、物理合规性、语义对齐度与感知质量往往此消彼长，难以被压缩为一个标量。&lt;/p&gt;
&lt;p&gt;本部分将从主观实验设计、客观指标体系的数学本质、指标间的内在冲突，以及下游任务驱动的功能性验证四个维度，建立一套方法论层面严谨、可复现且难以被操纵的评估框架。我们的核心论点是：&lt;strong&gt;一个好的评估协议必须同时是多维的（覆盖几何、视觉、语义、物理）、多视角的（避免单一渲染视角的偏差）、统计上严谨的（报告显著性与效应量），并与下游任务锚定的（functional correctness）&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="51-主观评估"&gt;5.1 主观评估&lt;/h2&gt;
&lt;p&gt;主观评估是三维生成结果评价中不可被客观指标完全替代的核心环节。原因在于，三维内容的最终受众是人类，而人类视觉系统对几何瑕疵、光照不协调和语义违和的敏感度，往往无法被现有的逐点距离度量所捕捉。然而，主观评估若设计不当，极易引入巨大的系统偏差与噪声，导致结论不可信。&lt;/p&gt;
&lt;h3 id="511-用户研究设计方法"&gt;5.1.1 用户研究设计方法&lt;/h3&gt;
&lt;h4 id="ab测试pairwise-comparison"&gt;AB测试（Pairwise Comparison）&lt;/h4&gt;
&lt;p&gt;在三维生成评估中，AB测试（成对比较）是最可靠的主观评估范式之一。其基本实验设计为：被试在每次试验中观察由两个不同模型生成的三维结果（以旋转渲染视频或交互式视图呈现），并在强制选择（forced choice）或分级量表上做出判断。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;统计模型：Bradley-Terry 模型&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;设共有 $M$ 个待比较的模型（或方法），每个模型具有一个潜在的感知质量分数（latent score）$\theta_i \in \mathbb{R}$。Bradley-Terry 模型假设模型 $i$ 在成对比较中击败模型 $j$ 的概率为：&lt;/p&gt;
$$P(i \text{ beats } j) = \frac{e^{\theta_i}}{e^{\theta_i} + e^{\theta_j}}$$&lt;p&gt;该模型可视为 Logistic 模型在离散选择场景下的特例。给定 $N$ 次独立观测，其中 $w_{ij}$ 表示模型 $i$ 击败模型 $j$ 的次数，对数似然函数为：&lt;/p&gt;
$$\ell(\boldsymbol{\theta}) = \sum_{i&lt;j} \left[ w_{ij} (\theta_i - \theta_j) - (w_{ij} + w_{ji}) \log(1 + e^{\theta_i - \theta_j}) \right]$$&lt;p&gt;为避免尺度不可识别性，通常施加约束 $\sum_{i=1}^M \theta_i = 0$ 或固定 $\theta_1 = 0$。通过最大似然估计（MLE）求解 $\hat{\boldsymbol{\theta}}$，可获得各模型的全局排序。Fisher 信息矩阵 $\mathbf{I}(\boldsymbol{\theta})$ 可用于估计参数的标准误，进而构造置信区间。&lt;/p&gt;</description></item><item><title>3D生成AI学习笔记（六）：实战与前沿趋势</title><link>https://tingdonghu.github.io/posts/3dgenai/part6-practice-frontier-trends/</link><pubDate>Sun, 27 Apr 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/3dgenai/part6-practice-frontier-trends/</guid><description>&lt;h1 id="第六部分实战与趋势篇动手路径与未来展望"&gt;第六部分：实战与趋势篇——动手路径与未来展望&lt;/h1&gt;
&lt;h2 id="61-核心开源框架详解"&gt;6.1 核心开源框架详解&lt;/h2&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/3dgenai/part6-practice-frontier-trends/01-framework-ecosystem-map.png"
alt="3D生成AI生态系统全景"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
3D生成AI生态系统全景
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;在3D生成AI领域，框架的选择直接决定了实验的迭代速度和调试的便利程度。与2D视觉领域PyTorch和TensorFlow的二分天下不同，3D生成AI目前仍处在&amp;quot;工具链快速演化&amp;quot;的阶段。选择框架时，需要区分两个维度：一是&lt;strong&gt;神经渲染框架&lt;/strong&gt;（负责从3D表示生成2D图像并反向传播梯度），二是&lt;strong&gt;生成式3D框架&lt;/strong&gt;（负责调用2D先验或3D先验来优化3D表示）。nerfstudio属于前者，threestudio属于后者，而Kaolin和PyTorch3D则是更底层的几何操作基础设施。&lt;/p&gt;
&lt;h3 id="611-nerfstudio"&gt;6.1.1 nerfstudio&lt;/h3&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/3dgenai/part6-practice-frontier-trends/02-infographic-nerfstudio-architecture.png"
alt="nerfstudio架构"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
nerfstudio架构
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;nerfstudio是社区目前最成熟、工程化程度最高的NeRF训练与渲染框架。它并非单一算法的复现，而是一个&lt;strong&gt;模块化的NeRF研究平台&lt;/strong&gt;。其设计目标是将NeRFpipeline中的各个组件（数据加载、场表示、采样策略、体渲染、后处理）彻底解耦，使得研究者可以通过修改YAML配置文件或继承基类的方式快速组合出新方法。&lt;/p&gt;
&lt;h4 id="架构概览与源码导航"&gt;架构概览与源码导航&lt;/h4&gt;
&lt;p&gt;nerfstudio的目录结构反映了其严格的分层设计：&lt;/p&gt;
&lt;div class="code-block" data-lang="text"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;text&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;nerfstudio/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── models/ # 模型定义，继承自Model基类
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├── base_surface_model.py # 表面模型（NeuS, VolSDF风格）的抽象基类
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├── instant_ngp.py # Instant-NGP的完整复现
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├── nerfacto.py # 推荐的默认模型，集成多技术
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └── mipnerf.py # mip-NeRF 360实现
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── fields/ # 神经场表示，负责将空间坐标映射到密度/颜色/语义
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├── base_field.py
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├── instant_ngp_field.py # 哈希编码+小MLP
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └── nerfacto_field.py # 基于哈希编码的NeRF场
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── model_components/ # 可复用组件，避免重复造轮子
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├── renderers.py # 光线行进积分器
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├── loss.py # MSE, Charbonnier, distortion loss等
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └── ray_samplers.py # 均匀采样、重要性采样、PDF采样
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── data/ # 数据IO与预处理
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ ├── dataparsers/ # COLMAP, blender, polycam, nuscenes等
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └── datasets.py # 内存映射与缓存策略
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── pipelines/ # 训练管线
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └── base_pipeline.py # 定义train/val步骤和优化器配置
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└── engine/ # 训练引擎，基于PyTorch Lightning封装
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └── trainers.py&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;关键设计哲学&lt;/strong&gt;：&lt;code&gt;models&lt;/code&gt;与&lt;code&gt;fields&lt;/code&gt;的分离。&lt;code&gt;models&lt;/code&gt;负责&amp;quot;策略&amp;quot;（如proposal sampling、损失组合、参数调度），而&lt;code&gt;fields&lt;/code&gt;只负责&amp;quot;表示&amp;quot;（给定坐标，输出属性）。这种分离使得你可以将Instant-NGP的哈希编码场（&lt;code&gt;instant_ngp_field.py&lt;/code&gt;）与mip-NeRF的抗锯齿采样策略组合，而不需要重写整个训练循环。&lt;/p&gt;</description></item><item><title>3D生成AI学习笔记（四）：后处理与生产管线</title><link>https://tingdonghu.github.io/posts/3dgenai/part4-postprocessing-production/</link><pubDate>Sun, 27 Apr 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/3dgenai/part4-postprocessing-production/</guid><description>&lt;h1 id="第四部分核心篇下从生成到可用资产后处理优化与管线"&gt;第四部分：核心篇（下）——从生成到可用资产：后处理、优化与管线&lt;/h1&gt;
&lt;h2 id="工程级扩展版"&gt;工程级扩展版&lt;/h2&gt;
&lt;hr&gt;
&lt;h2 id="41-网格提取与优化"&gt;4.1 网格提取与优化&lt;/h2&gt;
&lt;p&gt;AI生成的三维表示（隐式场、点云、NeRF密度场）必须经过网格提取和优化才能转化为游戏引擎或影视管线中的可用资产。本节从算法原理出发，结合生产管线中的实际问题，给出可直接落地的技术方案。&lt;/p&gt;
&lt;h3 id="411-marching-cubes的完全算法详解"&gt;4.1.1 Marching Cubes的完全算法详解&lt;/h3&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/3dgenai/part4-postprocessing-production/01-infographic-marching-cubes.png"
alt="Marching Cubes原理"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
Marching Cubes原理
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Marching Cubes（MC）是隐式曲面网格提取的事实标准算法。在AI生成管线中，它通常作用于神经隐式场（如NeRF的密度场、NeuS的SDF或Instant NGP的占用网格）的离散采样结果，将其转化为可渲染的三角网格。&lt;/p&gt;
&lt;h4 id="问题设置与算法流程"&gt;问题设置与算法流程&lt;/h4&gt;
&lt;p&gt;给定隐式场 $f: \mathbb{R}^3 \rightarrow \mathbb{R}$，目标是提取零水平集 $S = \{ x \in \mathbb{R}^3 \mid f(x) = 0 \}$ 的三角网格近似。在实际工程中，$f$ 可能是神经网络的输出，也可能是经过后处理的符号距离场（SDF）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;完整算法步骤：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;体素化空间&lt;/strong&gt;：在感兴趣区域（AABB）内建立规则体素网格，分辨率通常为 $N \times N \times N$（如 $256^3$ 或 $512^3$）。分辨率的选择是面数与精度的直接权衡：$256^3$ 对人物角色可能足够，但机械硬表面细节需要 $512^3$ 甚至更高。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;角点采样&lt;/strong&gt;：对每个体素的8个角点计算场值 $v_i = f(p_i)$。若使用神经网络，此步骤需要 $O(N^3)$ 次前向传播，是主要瓶颈。工程上常使用稀疏采样或缓存策略（如Instant NGP的哈希网格直接解码）。&lt;/p&gt;</description></item><item><title>【深度学习】常见的激活函数</title><link>https://tingdonghu.github.io/posts/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%B8%B8%E8%A7%81%E7%9A%84%E6%BF%80%E6%B4%BB%E5%87%BD%E6%95%B0/</link><pubDate>Thu, 30 Jan 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%B8%B8%E8%A7%81%E7%9A%84%E6%BF%80%E6%B4%BB%E5%87%BD%E6%95%B0/</guid><description>&lt;hr&gt;
&lt;p&gt;激活函数为神经网络引入非线性，使其能够学习复杂模式。它分为饱和与非饱和两类，前者如Sigmoid和tanh，后者如ReLU。使用激活函数可避免网络退化为线性模型，并解决梯度消失等问题，从而增强模型的表达能力。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;激活函数（Activation Function）&lt;/strong&gt;&lt;/em&gt;,是一种添加到人工神经网络中的函数，旨在帮助网络学习数据中的复杂模式。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%B8%B8%E8%A7%81%E7%9A%84%E6%BF%80%E6%B4%BB%E5%87%BD%E6%95%B0/d9bc438935856aa36e7c169fb27dffbd.png"
alt="img"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
img
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;h3 id="什么是激活函数"&gt;什么是激活函数&lt;/h3&gt;
&lt;p&gt;在神经元中，输入的input经过一系列加权求和后作用于另一个函数，这个函数就是这里的激活函数。类似于人类大脑中基于神经元的模型，激活函数最终决定了是否传递信号以及要发射给下一个神经元的内容。
激活函数为神经网络引入了非线性元素，使得网络能够逼近复杂的非线性函数，从而解决更广泛的问题。&lt;/p&gt;
&lt;h3 id="为什么要使用激活函数"&gt;为什么要使用激活函数&lt;/h3&gt;
&lt;p&gt;如果不用激活函数，每一层输出都是上层输入的线性函数，无论神经网络有多少层，输出都是输入的线性组合，这种情况就是最原始的&lt;em&gt;&lt;strong&gt;感知机（Perceptron）&lt;/strong&gt;&lt;/em&gt;。
使用激活函数能够给神经元引入非线性因素，使得神经网络可以任意逼近任何非线性函数，使深层神经网络表达能力更加强大，这样神经网络就可以应用到众多的非线性模型中。&lt;/p&gt;
&lt;h3 id="激活函数的分类"&gt;激活函数的分类&lt;/h3&gt;
&lt;p&gt;基于激活函数的本质，可以将激活函数分为以下两大类：&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%B8%B8%E8%A7%81%E7%9A%84%E6%BF%80%E6%B4%BB%E5%87%BD%E6%95%B0/image-20250425155707483.png"
alt="image-20250425155707483"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
image-20250425155707483
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;饱和激活函数&lt;/strong&gt;&lt;/em&gt;：Sigmoid、tanh&amp;hellip;&amp;hellip;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;非饱和激活函数&lt;/strong&gt;&lt;/em&gt;：ReLU、LeakyRelu、ELU、PReLU、RReLU&amp;hellip;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="什么是饱和"&gt;什么是饱和？&lt;/h4&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%B8%B8%E8%A7%81%E7%9A%84%E6%BF%80%E6%B4%BB%E5%87%BD%E6%95%B0/image-20250425155722212.png"
alt="image-20250425155722212"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
image-20250425155722212
&lt;/figcaption&gt;
&lt;/figure&gt;
反之，不满足以上条件的函数则称为非饱和激活函数。
&lt;em&gt;&lt;strong&gt;Sigmoid&lt;/strong&gt;&lt;/em&gt;函数需要一个实值输入压缩至[0,1]的范围
&lt;em&gt;&lt;strong&gt;tanh函数&lt;/strong&gt;&lt;/em&gt;需要讲一个实值输入压缩至 [-1, 1]的范围
相对于饱和激活函数，使用非饱和激活函数的优势在于两点：&lt;/p&gt;</description></item><item><title>【机器学习】梯度下降与损失函数</title><link>https://tingdonghu.github.io/posts/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E6%A2%AF%E5%BA%A6%E4%B8%8B%E9%99%8D%E4%B8%8E%E6%8D%9F%E5%A4%B1%E5%87%BD%E6%95%B0/</link><pubDate>Mon, 20 Jan 2025 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E6%A2%AF%E5%BA%A6%E4%B8%8B%E9%99%8D%E4%B8%8E%E6%8D%9F%E5%A4%B1%E5%87%BD%E6%95%B0/</guid><description>&lt;hr&gt;
&lt;p&gt;梯度下降是一种通过计算目标函数梯度并沿其反方向迭代调整参数以寻找最小值的优化方法。它利用导数、偏导数和方向导数等概念，在机器学习中常用于最小化损失函数，但可能收敛于局部最优解而非全局最优。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;梯度下降（Gradient Descent GD）&lt;em&gt;&lt;strong&gt;简单来说就是一种寻找&lt;/strong&gt;&lt;/em&gt;目标函数&lt;/strong&gt;&lt;/em&gt;最小化的方法，它利用梯度信息，通过不断迭代调整参数来寻找合适的目标值。&lt;/p&gt;
&lt;h3 id="什么是梯度"&gt;什么是梯度？&lt;/h3&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E6%A2%AF%E5%BA%A6%E4%B8%8B%E9%99%8D%E4%B8%8E%E6%8D%9F%E5%A4%B1%E5%87%BD%E6%95%B0/v2-6d78a2ab1092a44151213358e805bace_1440w.png"
alt="Gradient-Descent（全世界最通俗易懂的梯度下降法详解-优化函数大法）"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
Gradient-Descent（全世界最通俗易懂的梯度下降法详解-优化函数大法）
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;关于梯度的引入，可以分为四个概念：导数-&amp;gt;偏导-&amp;gt;方向导数-&amp;gt;梯度
&lt;em&gt;&lt;strong&gt;导数&lt;/strong&gt;&lt;/em&gt;：当函数定义域和取值都在实数域中时，导数可以表示函数曲线上的切线斜率。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E6%A2%AF%E5%BA%A6%E4%B8%8B%E9%99%8D%E4%B8%8E%E6%8D%9F%E5%A4%B1%E5%87%BD%E6%95%B0/20160325131532476.png"
alt="经典的导数与微分示意图"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
经典的导数与微分示意图
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;偏导数&lt;/strong&gt;&lt;/em&gt;：偏导其实就是多元函数一个多变量的函数的偏导数是它关于其中一个变量的导数，而保持其他变量恒定。因为曲面上的每一点都有无穷多条切线，描述这种函数的导数相当困难。偏导数就是选择其中一条切线，并求出它的斜率 。几何意义是表示固定面上一点的切线斜率。
多元函数降维时候的变化，比如[二元函数]固定y，只让x单独变化，从而看成是关于x的[一元函数]的变化来研究。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E6%A2%AF%E5%BA%A6%E4%B8%8B%E9%99%8D%E4%B8%8E%E6%8D%9F%E5%A4%B1%E5%87%BD%E6%95%B0/70.jpeg"
alt="这里写图片描述"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
这里写图片描述
&lt;/figcaption&gt;
&lt;/figure&gt;
但是偏导数有一个缺点，就是只能表示多元函数沿[坐标轴]方向的变化率，但是很多时候要考虑多元函数沿任意方向的变化率，于是就有了方向导数。
&lt;em&gt;&lt;strong&gt;方向导数&lt;/strong&gt;&lt;/em&gt;：某个方向的导数，本质就是函数在A点上无数个切线的[斜率]的定义，每个切线都代表一个方向，每个方向都是有方向导数的。&lt;/p&gt;</description></item><item><title>【OpenPCDet】PointPillar算法思路</title><link>https://tingdonghu.github.io/posts/3dcomputervison/openpcdetpointpillar%E7%AE%97%E6%B3%95%E6%80%9D%E8%B7%AF/</link><pubDate>Tue, 31 Dec 2024 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/3dcomputervison/openpcdetpointpillar%E7%AE%97%E6%B3%95%E6%80%9D%E8%B7%AF/</guid><description>&lt;p&gt;PointPillar 是一种用于三维物体检测的深度学习模型，尤其适用于激光雷达点云数据的处理。它的设计思想相对简洁，并且在保持高效性的同时能获得较高的精度。
&lt;a href="https://arxiv.org/abs/1812.05784" target="_blank"&gt;论文地址&lt;/a&gt;
&lt;a href="https://link.zhihu.com/?target=https%3A//github.com/SmallMunich/nutonomy_pointpillars" target="_blank"&gt;代码地址&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="前言"&gt;前言&lt;/h2&gt;
&lt;p&gt;本文要解析的模型叫做&lt;a href="https://zhida.zhihu.com/search?content_id=167602095&amp;amp;content_type=Article&amp;amp;match_order=1&amp;amp;q=PointPillars&amp;amp;zhida_source=entity" target="_blank"&gt;PointPillars&lt;/a&gt;
，是2019年出自工业界的一篇Paper。
该模型最主要的特点是&lt;strong&gt;检测速度和精度的平衡&lt;/strong&gt;。该模型的平均检测速度达到了62Hz，最快速度达到了105Hz，确实遥遥领先了其他的模型。这里我们引入&lt;a href="https://zhida.zhihu.com/search?content_id=167602095&amp;amp;content_type=Article&amp;amp;match_order=1&amp;amp;q=CIA-SSD&amp;amp;zhida_source=entity" target="_blank"&gt;CIA-SSD&lt;/a&gt;
&lt;strong&gt;模型中的精度-速度图&lt;/strong&gt;，具体对比如下所示。
&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://github.com/user-attachments/assets/2b4acd80-8c42-4b92-a8ee-34f9be41f0b4"
alt="Image"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
Image
&lt;/figcaption&gt;
&lt;/figure&gt;
截止CIA-SSD论文发表前，PointPillars的检测速度都是遥遥领先的，而且精度也不低。
现有的一些研究喜欢将不规则、稀疏的点云数据按照以下两种方式进行处理，然后引入RPN层进行3D Bbox Proposal，这两种方法为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一种是将点云数据划纳入一个个&lt;strong&gt;体素（Voxel）&lt;strong&gt;中，构成规则的、密集分布的体素集。常见的有&lt;/strong&gt;VoxelNet&lt;/strong&gt;和&lt;strong&gt;SECOND&lt;/strong&gt;；&lt;/li&gt;
&lt;li&gt;另一种从&lt;strong&gt;俯视角度&lt;/strong&gt;将点云数据进行处理，获得一个个&lt;strong&gt;伪图片&lt;/strong&gt;的数据。常见的模型有&lt;strong&gt;MV3D和AVOD&lt;/strong&gt;。
PointPillar模型采用了一种不同于上述两种思路的点云建模方法。从模型的名称PointPillars可以看出，该方法将Point转化成一个个的&lt;strong&gt;Pillar（柱体）&lt;/strong&gt;，从而构成了&lt;strong&gt;伪图片&lt;/strong&gt;的数据。
然后对伪图片数据进行&lt;strong&gt;BBox Proposal&lt;/strong&gt;就很简单了，作者采用了&lt;strong&gt;SSD&lt;/strong&gt;的网络结构进行了Proposal。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="数据处理"&gt;数据处理&lt;/h2&gt;
&lt;p&gt;PointPillar的一大亮点是将点云划分为一个个的Pillar，从而构成了伪图片的数据。
如何构成这个伪图片呢？作者在论文中是给出了这样的图，如下。
&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://github.com/user-attachments/assets/24ae971c-0384-4019-897b-37a988259979"
alt="Image"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
Image
&lt;/figcaption&gt;
&lt;/figure&gt;
具体实现步骤如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;按照点云数据所在的X，Y轴（不考虑Z轴）将点云数据划分为&lt;strong&gt;一个个的网格&lt;/strong&gt;，凡是落入到一个网格的点云数据被视为其处在&lt;strong&gt;一个pillar&lt;/strong&gt;里，或者理解为它们构成了一个Pillar。&lt;/li&gt;
&lt;li&gt;每个点云用一个 $ D=9$ 维的向量表示，分别为 $(x,y,z,r,x_c,y_c,z_c,x_p,y_p)$。其中 $(x,y,z,r)$ 为该点云的真实坐标信息（三维）和反射强度（注在openpcdet的代码实现中是10维，多了一个zp，也就是该点在z轴上与该点所处pillar的z轴中心的偏移量）. $(x_c,y_c,z_c)$ 为该点云所处Pillar中所有点的几何中心; $x_p$ , $y_p$ 为 $x-x_c$ , $y-y_c$ ,反应了点与几何中心的&lt;strong&gt;相对位置&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;假设每个样本中有 $P$ 个非空的pillars，每个pillar中有 $N$ 个点云数据，那么这个样本就可以用一个 $(D,P,N)$ 张量表示。
那么可能就有人问了，怎么保证每个pillar中有 $N$ 个点云数据呢？
如果每个pillar中的点云数据数据超过 $N$ 个，那么我们就随机采样至 $N$ 个；如果每个pillar中的点云数据数据少于 $N$ 个，少于的部分我们就填充为0；这样就实现了点云数据的张量化，具体过程如下图所示&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://github.com/user-attachments/assets/d66b3bbb-0681-4947-b1a6-a997bd14ed40"
alt="Image"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
Image
&lt;/figcaption&gt;
&lt;/figure&gt;
实现张量化后，作者利用简化版本的PointNet对张量化的点云数据进行处理和特征提取。
特征提取可以理解为对点云的维度进行处理，原来的点云维度为 $D=9$ ,处理后的维度为 $C$ ,那么我们就获得了一个 $(C,P,N)$ 的张量。
接着，我们按照Pillar所在维度进行Max Pooling操作，即获得了 $(C,P)$ 维度的特征图。
为了获得伪图片特征，作者将 $ P$ 转换为 $(H,W)$ ,即 $P-&gt;H*W$ .那么我们就获得了形如 $(C,H,W)$ 的伪图片了。具体过程如下：
&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://github.com/user-attachments/assets/5d8d4957-d83a-43b1-8a67-7b45fd05fb12"
alt="Image"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
Image
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;</description></item><item><title>【OpenPCDet】关于spconv的一些问题解决方案</title><link>https://tingdonghu.github.io/posts/3dcomputervison/openpcdet%E5%85%B3%E4%BA%8Espconv%E7%9A%84%E4%B8%80%E4%BA%9B%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/</link><pubDate>Mon, 30 Dec 2024 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/3dcomputervison/openpcdet%E5%85%B3%E4%BA%8Espconv%E7%9A%84%E4%B8%80%E4%BA%9B%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/</guid><description>&lt;p&gt;最近在修改对OpenPCDet中一些算法做改进评估的时候碰到了一系列的和spconv模组相关的问题，找到了一些解决方法。
本人的服务器环境：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;操作系统版本：Ubuntu20.04
GPU：3090Ti
CUDA版本:11.3
Pytorch：1.8.1
Python:3.8&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;问题1：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;File &amp;ldquo;/home/OpenPCDet/pcdet/utils/spconv_utils.py&amp;rdquo;, line 4, in &lt;module&gt;
if float(spconv.&lt;strong&gt;version&lt;/strong&gt;[2:]) &amp;gt;= 2.2:
AttributeError: module &amp;lsquo;spconv&amp;rsquo; has no attribute &amp;lsquo;&lt;strong&gt;version&lt;/strong&gt;&amp;rsquo;
原本以为是版本过低的问题，查资料发现是安装了多个spconv版本&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="code-block" data-lang="python"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;python&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;uninstall&lt;/span&gt; &lt;span class="n"&gt;spconv&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;cu113&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;uninstall&lt;/span&gt; &lt;span class="n"&gt;spconv&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;pip&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;spconv&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;cu113&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;测试版本：&lt;/p&gt;
&lt;div class="code-block" data-lang="python"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;python&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;spconv&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__version__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;问题2：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;AttributeError: module &amp;lsquo;spconv&amp;rsquo; has no attribute &amp;lsquo;SparseModule&amp;rsquo;
研究后发现是spconv版本更新导致，在spconv2的使用中，mport spconv 要改写成 import spconv.pytorch as spconv&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;问题3：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ImportError: generic_type: cannot initialize type &amp;ldquo;ExternalAllocator&amp;rdquo;: an object with that name is already defined
解决方法：
降低版本&lt;/p&gt;</description></item><item><title>【OpenPCDet】模型的数据采样训练</title><link>https://tingdonghu.github.io/posts/3dcomputervison/openpcdet%E6%A8%A1%E5%9E%8B%E7%9A%84%E6%95%B0%E6%8D%AE%E9%87%87%E6%A0%B7%E8%AE%AD%E7%BB%83/</link><pubDate>Fri, 20 Dec 2024 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/3dcomputervison/openpcdet%E6%A8%A1%E5%9E%8B%E7%9A%84%E6%95%B0%E6%8D%AE%E9%87%87%E6%A0%B7%E8%AE%AD%E7%BB%83/</guid><description>&lt;p&gt;在&lt;strong&gt;OpenPCDet&lt;/strong&gt;中，KITTI 数据集的 ImageSet 中已经包含了训练和测试数据的索引信息，这使得可以不必直接扫描点云数据文件来获取某个特定的数据集。通过修改 ImageSet 中的索引，就可以直接选择不同的数据帧来进行训练、测试或推理。&lt;/p&gt;
&lt;h3 id="1-kitti-数据集中的-imageset"&gt;1. KITTI 数据集中的 ImageSet&lt;/h3&gt;
&lt;p&gt;imageset 文件夹包含了多个文本文件，其中每个文件列出了训练和测试数据的帧索引。这些文件通常以如下格式命名：&lt;/p&gt;
&lt;div class="code-block" data-lang="bash"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;bash&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;data/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── kitti/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ├── ImageSets/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ │ ├── train.txt &lt;span class="c1"&gt;# 训练集的帧索引&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ │ ├── val.txt &lt;span class="c1"&gt;# 验证集的帧索引&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ │ └── test.txt &lt;span class="c1"&gt;# 测试集的帧索引&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;每个 txt 文件中列出了一系列的帧编号，例如：&lt;/p&gt;
&lt;div class="code-block" data-lang="python"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;python&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="mi"&gt;000000&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="mi"&gt;000001&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="mi"&gt;000002&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这些帧编号对应的是 velodyne 文件夹中的 .bin 点云数据文件.&lt;/p&gt;
&lt;h3 id="2-修改索引文件"&gt;2. 修改索引文件&lt;/h3&gt;
&lt;p&gt;此处我想要基于Kitti数据集进行采样，生成十个不同的用于训练的数据集
可以直接原本的train.txt进行采样，将其保存为一个新的索引集
在kitti文件路径下新建一个脚本文件&lt;/p&gt;
&lt;div class="code-block" data-lang="python"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;python&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;random&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 读取原始的 train.txt 文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;kitti/training/imageset/train.txt&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;r&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readlines&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 随机采样 10 组数据&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;num_samples&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="c1"&gt;# 每组采样的帧数量&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;num_groups&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="c1"&gt;# 需要采样的组数&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 随机生成 10 组数据集&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_groups&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 随机选择 1000 个帧&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;sampled_lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sample&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_samples&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;# 保存到不同的 train_sampledX.txt 文件中&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;sampled_file_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;kitti/training/imageset/train_sampled&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;.txt&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sampled_file_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writelines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sampled_lines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Group &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; saved to &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;sampled_file_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;运行以上代码即可在原本的目录下生成一系列的采样数据集
&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://github.com/user-attachments/assets/ac52c130-cc24-4b59-b33c-db3ccc6649a5"
alt="image"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
image
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;</description></item><item><title>【OpenPCDet】Uncertainty Estimation学习笔记（一）</title><link>https://tingdonghu.github.io/posts/3dcomputervison/openpcdetuncertainty-estimation%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E4%B8%80/</link><pubDate>Sat, 30 Nov 2024 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/3dcomputervison/openpcdetuncertainty-estimation%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E4%B8%80/</guid><description>&lt;h2 id="为什么要研究uncertainty"&gt;为什么要研究uncertainty？&lt;/h2&gt;
&lt;p&gt;训练好的[神经网络模型本质是一个拥有大量确定参数的函数，不管你给什么输入，它都能给你一个输出。这会导致两种我们不愿意看到的意外情况：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对明明错误的预测结果，模型输出的[置信度]却很高&lt;/li&gt;
&lt;li&gt;对没有见过的输入(OoD，Out-of-ditribution)，比如给一个识别猫/狗的模型输入一张桌子图片，模型一定会输出：”这是猫“ or “这是狗”，而不是告诉我们 “它似乎不是猫，也不是狗”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以，我们希望模型能输出 uncertainty，辅助使用模型的人进行更好地决策。比如上面的例子中，我们希望对错误分类的样本、OoD样本，模型能够给出一个较高的uncertainty。&lt;/p&gt;
&lt;h2 id="uncertainy是什么"&gt;uncertainy是什么？&lt;/h2&gt;
&lt;p&gt;参考NIPS2017年的论文 &lt;a href="https://link.zhihu.com/?target=https%3A//papers.nips.cc/paper/7141-what-uncertainties-do-we-need-in-bayesian-deep-learning-for-computer-vision.pdf" target="_blank"&gt;What Uncertainties Do We Need in Bayesian Deep Learning for Computer Vision? &lt;/a&gt;
，Gal阐述了两种uncertainty：Aleatoric uncertainty(i.e. data uncertainty) 和 Epistemic uncertainty(i.e. model uncertainty)，即随机不确定度(也称数据不确定度)，和认知不确定度(也称模型不确定度)。&lt;/p&gt;
&lt;p&gt;Epistemic uncertainty可以通过增加数据解决，比如下图：只有一个data point的时候，符合要求的模型有很多种可能，uncertainty很高。当数据点增加，模型逐渐确定，uncertainty减小。
&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://github.com/user-attachments/assets/82e8de7c-1ac8-4cbe-82c1-417cf2299c3c"
alt="image"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
image
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="how怎么计算不确定度"&gt;How？怎么计算不确定度&lt;/h2&gt;
&lt;h3 id="1epistemic-uncertainty建模"&gt;1.Epistemic uncertainty建模&lt;/h3&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://github.com/user-attachments/assets/0a9ea3a7-f202-4c11-919d-b599aed777dd"
alt="image"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
image
&lt;/figcaption&gt;
&lt;/figure&gt;
Monte-Carlo 和 Ensemble
对一个随机分布，不确定性建模的方法有很多，标准差、方差、风险值（VaR）和熵都是合适的度量。在深度学习中，建模不确定度需要用到Bayesian DeepLearning。从Bayesian的角度，深度学习训练的本质是求一个posterior distribution $P(W|D)$ ，其中W是参数，D是数据。根据bayes theorem（贝叶斯定理），我们有 $P(W|D)=\frac{P(D|W)P(W)}{P(D)}$
但是这个公式没法用，因为 $P(D)$ 理论上代表的是真实的数据分布，无法获取; $P(W)$ 在神经网络中也是不存在的，因为模型训练好以后，所有参数都是确定的数，而不是distribution，没法计算 $P(W)$ 。于是我们想到bayes theorem的另一个公式: $P(D)=\sum_i{P(D|W_i)P(W_i)}$&lt;/p&gt;</description></item><item><title>卷积神经网络(CNN)的原理</title><link>https://tingdonghu.github.io/posts/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9Ccnn%E7%9A%84%E8%AF%A6%E7%BB%86%E5%8E%9F%E7%90%86/</link><pubDate>Sun, 10 Nov 2024 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9Ccnn%E7%9A%84%E8%AF%A6%E7%BB%86%E5%8E%9F%E7%90%86/</guid><description>&lt;hr&gt;
&lt;p&gt;卷积神经网络（CNN）的核心运算“卷积”是一种数学操作，通过翻转和滑动叠加来捕捉数据的局部与全局特征。这种机制使CNN在图像识别等计算机视觉任务中表现出色，能够有效处理图像中的平移不变性。&lt;/p&gt;
&lt;h2 id="引言"&gt;引言&lt;/h2&gt;
&lt;p&gt;卷积神经网络（Convolutional Neural Network，CNN）是一种在计算机视觉领域取得了巨大成功的深度学习模型。它们的设计灵感来自于生物学中的视觉系统，旨在模拟人类视觉处理的方式。在过去的几年中，CNN已经在图像识别、目标检测、图像生成和许多其他领域取得了显著的进展，成为了计算机视觉和深度学习研究的重要组成部分。&lt;/p&gt;
&lt;h2 id="卷积是什么"&gt;卷积是什么？&lt;/h2&gt;
&lt;p&gt;教科书上一般定义函数f,g的卷积f*g(n)如下：
连续形式：
&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9Ccnn%E7%9A%84%E8%AF%A6%E7%BB%86%E5%8E%9F%E7%90%86/9c2f215a5a4e799b471a83ecbc95044e.jpeg"
alt="在这里插入图片描述"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
在这里插入图片描述
&lt;/figcaption&gt;
&lt;/figure&gt;
离散形式：
&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%8D%B7%E7%A7%AF%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9Ccnn%E7%9A%84%E8%AF%A6%E7%BB%86%E5%8E%9F%E7%90%86/237b89f84f60bc0183a2cde78336a38f.jpeg"
alt="在这里插入图片描述"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
在这里插入图片描述
&lt;/figcaption&gt;
&lt;/figure&gt;
并且也解释了，先对g函数进行翻转，相当于在数轴上把g函数从右边褶到左边去，也就是卷积的“卷”的由来。
然后再把g函数平移到n，在这个位置对两个函数的对应点相乘，然后相加，这个过程是卷积的“积”的过程。&lt;/p&gt;
&lt;h4 id="对卷积的通俗理解"&gt;对卷积的通俗理解&lt;/h4&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;所谓两个函数的卷积，本质上就是先将一个函数翻转，然后进行滑动叠加&lt;/strong&gt;&lt;/em&gt;
在连续情况下，叠加指的是对两个函数的乘积求积分，在离散情况下就是加权求和，为简单起见就统一称为叠加。
整体看来是这么个过程：
翻转——&amp;gt;滑动——&amp;gt;叠加——&amp;gt;滑动——&amp;gt;叠加——&amp;gt;滑动——&amp;gt;叠加 &amp;hellip;.
多次滑动得到的一系列叠加值，构成了卷积函数。
&lt;em&gt;&lt;strong&gt;卷积的“卷”&lt;/strong&gt;&lt;/em&gt;，指的的函数的翻转，从 g(t) 变成 g(-t) 的这个过程；
&lt;em&gt;&lt;strong&gt;卷积的“积”&lt;/strong&gt;&lt;/em&gt;，指的是滑动积分/加权求和。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;对卷积的意义的理解：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;从“积”的过程可以看到，我们得到的叠加值，是个全局的概念。以信号分析为例，卷积的结果是不仅跟当前时刻输入信号的响应值有关，也跟过去所有时刻输入信号的响应都有关系，考虑了对过去的所有输入的效果的累积。在图像处理的中，卷积处理的结果，其实就是把每个像素周边的，甚至是整个图像的像素都考虑进来，对当前像素进行某种加权处理。所以说，“积”是全局概念，或者说是一种“混合”，把两个函数在时间或者空间上进行混合。&lt;/li&gt;
&lt;li&gt;那为什么要进行“卷”？直接相乘不好吗？我的理解，进行“卷”（翻转）的目的其实是施加一种约束，它指定了在“积”的时候以什么为参照。在信号分析的场景，它指定了在哪个特定时间点的前后进行“积”，在空间分析的场景，它指定了在哪个位置的周边进行累积处理。&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h2 id="卷积神经网络"&gt;卷积神经网络&lt;/h2&gt;
&lt;h3 id="图像原理"&gt;图像原理&lt;/h3&gt;
&lt;p&gt;在了解卷积神经网络前，我们先来看看图像的原理：
图像在计算机中是一堆按顺序排列的数字，数值为0到255。0表示最暗，255表示最亮。 如下图：&lt;/p&gt;</description></item><item><title>【OpenPCDet】详细部署与复现</title><link>https://tingdonghu.github.io/posts/3dcomputervison/openpcdet%E8%AF%A6%E7%BB%86%E9%83%A8%E7%BD%B2%E4%B8%8E%E5%A4%8D%E7%8E%B0/</link><pubDate>Fri, 25 Oct 2024 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/3dcomputervison/openpcdet%E8%AF%A6%E7%BB%86%E9%83%A8%E7%BD%B2%E4%B8%8E%E5%A4%8D%E7%8E%B0/</guid><description>&lt;p&gt;本文详细介绍了在Ubuntu 20.04系统上配置OpenPCDet 3D目标检测工具箱的完整流程，涵盖创建虚拟环境、安装PyTorch与spconv等关键依赖，并最终完成编译和数据导入。&lt;/p&gt;
&lt;h3 id="openpcdet简介"&gt;OpenPCDet简介&lt;/h3&gt;
&lt;p&gt;OpenPCDet是一个用于3D目标检测的开源工具箱，它提供了多种数据集的加载器，支持多种模型，并且易于扩展。&lt;/p&gt;
&lt;h3 id="本人使用硬件与环境"&gt;本人使用硬件与环境&lt;/h3&gt;
&lt;p&gt;Linux操作系统（Ubuntu20.04）
Python环境（Anaconda下独立创建）
CPU: 11th Gen Intel® Core™ i9-11900K @ 3.50GHz × 16
GPU: NVIDIA GeForce RTX 3090
cuda：11.3&lt;/p&gt;
&lt;h3 id="配置步骤"&gt;配置步骤&lt;/h3&gt;
&lt;h4 id="创建虚拟环境"&gt;创建虚拟环境&lt;/h4&gt;
&lt;div class="code-block" data-lang="shell"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;shell&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;conda create -n pcdet &lt;span class="nv"&gt;python&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3.8 &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h4 id="激活进入虚拟环境"&gt;激活进入虚拟环境&lt;/h4&gt;
&lt;div class="code-block" data-lang="shell"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;shell&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;conda activate pcdet&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h4 id="安装pytorch"&gt;安装pytorch&lt;/h4&gt;
&lt;p&gt;查看cuda版本&lt;/p&gt;
&lt;div class="code-block" data-lang="shell"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;shell&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; nvcc -V &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;查看运行结果
&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/3dcomputervison/openpcdet%E8%AF%A6%E7%BB%86%E9%83%A8%E7%BD%B2%E4%B8%8E%E5%A4%8D%E7%8E%B0/4b241aa925cb4de2a1df63d6d1271ec4.png"
alt="在这里插入图片描述"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
在这里插入图片描述
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;</description></item><item><title>【虚幻引擎】GameMode和GameSate</title><link>https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8Egamemode%E5%92%8Cgamesate/</link><pubDate>Sun, 21 Apr 2024 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8Egamemode%E5%92%8Cgamesate/</guid><description>&lt;hr&gt;
&lt;p&gt;GameMode是服务器端权威的游戏规则管理者，定义核心逻辑；GameState则负责在服务器与客户端间同步全局游戏状态，如比分和时间。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8Egamemode%E5%92%8Cgamesate/image-20250422211945454.png"
alt="image-20250422211945454"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
image-20250422211945454
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;在虚幻引擎（Unreal Engine）中，&lt;strong&gt;GameMode&lt;/strong&gt; 和 &lt;strong&gt;GameState&lt;/strong&gt; 都是多人游戏中的核心类，但它们的分工和用途有显著区别。以下是它们的对比和典型应用场景：&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="1-gamemode游戏规则管理者"&gt;&lt;strong&gt;1. GameMode（游戏规则管理者）&lt;/strong&gt;&lt;/h3&gt;
&lt;h4 id="职责"&gt;&lt;strong&gt;职责&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;仅存在于服务器端&lt;/strong&gt;（不会复制到客户端）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;定义游戏的核心规则&lt;/strong&gt;：胜利条件、玩家生成逻辑、回合制规则等。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;管理玩家登录/退出&lt;/strong&gt;（通过&lt;code&gt;Login&lt;/code&gt;/&lt;code&gt;Logout&lt;/code&gt;等事件）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;生成并持有PlayerController、PlayerState等&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="典型用途"&gt;&lt;strong&gt;典型用途&lt;/strong&gt;&lt;/h4&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 示例：在GameMode中设置玩家生成逻辑
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;AMyGameMode&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;PostLogin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;APlayerController&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;NewPlayer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Super&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;PostLogin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NewPlayer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 生成玩家角色
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NewPlayer&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;GetPawn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="k"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;SpawnPlayerAtTransform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NewPlayer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SpawnTransform&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h4 id="关键特性"&gt;&lt;strong&gt;关键特性&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;服务器权威&lt;/strong&gt;：客户端无法修改GameMode的逻辑。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不复制&lt;/strong&gt;：客户端无法直接访问GameMode。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="2-gamestate游戏状态同步者"&gt;&lt;strong&gt;2. GameState（游戏状态同步者）&lt;/strong&gt;&lt;/h3&gt;
&lt;h4 id="职责-1"&gt;&lt;strong&gt;职责&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;存在于服务器和客户端&lt;/strong&gt;（自动复制到所有客户端）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;存储并同步游戏全局状态&lt;/strong&gt;：比分、剩余时间、玩家列表等。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;提供客户端可见的数据&lt;/strong&gt;（如通过&lt;code&gt;PlayerArray&lt;/code&gt;访问所有玩家的&lt;code&gt;PlayerState&lt;/code&gt;）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="典型用途-1"&gt;&lt;strong&gt;典型用途&lt;/strong&gt;&lt;/h4&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 示例：在GameState中同步比分
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;AMyGameState&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;OnRep_TeamScores&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 客户端更新UI显示比分
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;UpdateScoreboardUI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TeamAScore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TeamBScore&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h4 id="关键特性-1"&gt;&lt;strong&gt;关键特性&lt;/strong&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;数据同步&lt;/strong&gt;：通过属性复制（&lt;code&gt;Replicated&lt;/code&gt;）或RPC同步到客户端。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;客户端可读&lt;/strong&gt;：UI可以直接绑定GameState的数据（如剩余时间）。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id="核心区别对比"&gt;&lt;strong&gt;核心区别对比&lt;/strong&gt;&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;特性&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;GameMode&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;GameState&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;存在位置&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;仅服务器&lt;/td&gt;
&lt;td&gt;服务器 + 客户端（复制）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;用途&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;定义规则、逻辑控制&lt;/td&gt;
&lt;td&gt;存储和同步全局状态&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;是否复制到客户端&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ 否&lt;/td&gt;
&lt;td&gt;✅ 是&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;客户端访问权限&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;无法直接访问&lt;/td&gt;
&lt;td&gt;可读取数据（如显示比分）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;生命周期&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;游戏开始时创建，结束时销毁&lt;/td&gt;
&lt;td&gt;随游戏运行持续存在&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h3 id="协作流程示例"&gt;&lt;strong&gt;协作流程示例&lt;/strong&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;服务器&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;GameMode决定玩家生成规则（如出生点选择）。&lt;/li&gt;
&lt;li&gt;GameState更新并同步比分到所有客户端。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;客户端&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;通过GameState获取实时比分，更新UI。&lt;/li&gt;
&lt;li&gt;无法修改规则（必须通过服务器GameMode）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h3 id="何时使用"&gt;&lt;strong&gt;何时使用？&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;用GameMode&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;需要权威控制游戏逻辑（如判断胜利条件）。&lt;/li&gt;
&lt;li&gt;处理玩家登录/退出等敏感操作。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用GameState&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;需要让所有客户端知道全局状态（如倒计时、玩家列表）。&lt;/li&gt;
&lt;li&gt;UI需要绑定的动态数据（如实时比分）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;通过这种分工，虚幻引擎实现了&lt;strong&gt;逻辑与状态的分离&lt;/strong&gt;，确保多人游戏的同步性和安全性。&lt;/p&gt;</description></item><item><title>【虚幻引擎】虚幻5.1UUserWidget不再包含OnLevelRemovedFromWorld的问题</title><link>https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E%E8%99%9A%E5%B9%BB5.1uuserwidget%E4%B8%8D%E5%86%8D%E5%8C%85%E5%90%ABonlevelremovedfromworld%E7%9A%84%E9%97%AE%E9%A2%98/</link><pubDate>Sat, 20 Apr 2024 00:00:00 +0000</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E%E8%99%9A%E5%B9%BB5.1uuserwidget%E4%B8%8D%E5%86%8D%E5%8C%85%E5%90%ABonlevelremovedfromworld%E7%9A%84%E9%97%AE%E9%A2%98/</guid><description>&lt;hr&gt;
&lt;p&gt;在虚幻引擎5.1中，&lt;code&gt;OnLevelRemovedFromWorld&lt;/code&gt;函数已被移除，导致编译错误。解决方案是重写&lt;code&gt;NativeDestruct&lt;/code&gt;函数来实现相同的资源清理逻辑，从而成功编译。&lt;/p&gt;
&lt;p&gt;在跟着Blaster课程项目写Menu插件的时候,在Menu.h中一直报以下错误无法编译,百思不得其解.&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E%E8%99%9A%E5%B9%BB5.1uuserwidget%E4%B8%8D%E5%86%8D%E5%8C%85%E5%90%ABonlevelremovedfromworld%E7%9A%84%E9%97%AE%E9%A2%98/image-20250421115907081.png"
alt="image-20250421115907081"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
image-20250421115907081
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;严重性代码说明项目文件33行禁止显示状态详细信息
错误C3668“UMenu::OnLevelRemovedFromWorld”: 包含重写说明符“override”的方法没有重写任何基类方法MenuSystem F:\UE\UEproject\MultiplayCourse\MenuSystem\Plugins\MultiplayerSessions\Source\MultiplayerSessions\Public\Menu.h23&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E%E8%99%9A%E5%B9%BB5.1uuserwidget%E4%B8%8D%E5%86%8D%E5%8C%85%E5%90%ABonlevelremovedfromworld%E7%9A%84%E9%97%AE%E9%A2%98/image-20250421120505541.png"
alt="image-20250421120505541"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
image-20250421120505541
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;查阅资料后发现是虚幻5.1和5.0的版本问题: 虚幻5.1 UUserWidget不再包含OnLevelRemovedFromWorld.我们可以重载一个类似的函数用于达到相同的效果:&lt;/p&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;virtual&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;NativeDestruct&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;.cpp&lt;/code&gt;文件中实现:&lt;/p&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;UMenu&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;NativeDestruct&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;MenuTearDown&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Super&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;NativeDestruct&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;NativeDestruct()&lt;/code&gt; 是 &lt;code&gt;UUserWidget&lt;/code&gt;（用户控件）提供的一个 &lt;strong&gt;关键生命周期虚函数&lt;/strong&gt;(析构函数)，用于 &lt;strong&gt;处理控件的销毁逻辑&lt;/strong&gt;。&lt;/p&gt;</description></item><item><title>【MultiplayerCourse】创建多人联机插件</title><link>https://tingdonghu.github.io/posts/multiplayercourse/multiplayercourse%E5%88%9B%E5%BB%BA%E5%A4%9A%E4%BA%BA%E8%81%94%E6%9C%BA%E6%8F%92%E4%BB%B6/</link><pubDate>Fri, 19 Apr 2024 00:00:00 +0000</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/multiplayercourse/multiplayercourse%E5%88%9B%E5%BB%BA%E5%A4%9A%E4%BA%BA%E8%81%94%E6%9C%BA%E6%8F%92%E4%BB%B6/</guid><description>&lt;p&gt;本文记录了在Unreal Engine 5中配置Steam在线子系统的具体步骤，包括启用插件、修改项目依赖项以及编辑配置文件，以实现多人游戏功能。&lt;/p&gt;
&lt;p&gt;此博客为学习油管DruidMech大佬的广域网多人射击游戏的笔记
附上项目GitHub源码地址https://github.com/DruidMech/MultiplayerCourseMenuSystem&lt;/p&gt;
&lt;h2 id="新建项目"&gt;新建项目&lt;/h2&gt;
&lt;p&gt;首先使用引擎（5.0及以上）创建一个基于第三人称模板的&lt;code&gt;.cpp&lt;/code&gt;项目，我这里将其命名为&lt;code&gt;MenuSystem&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="subsystem插件配置"&gt;Subsystem插件配置&lt;/h2&gt;
&lt;p&gt;一、在编辑器-插件中打开&lt;code&gt;Oline Subsystem Steam&lt;/code&gt;插件，然后重启项目。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/multiplayercourse/multiplayercourse%E5%88%9B%E5%BB%BA%E5%A4%9A%E4%BA%BA%E8%81%94%E6%9C%BA%E6%8F%92%E4%BB%B6/image-20250419144230516.png"
alt="image-20250419144230516"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
image-20250419144230516
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;二、在项目的&lt;code&gt;Build.cs&lt;/code&gt;下找到一个&lt;code&gt;PublicDependencyModuleNames&lt;/code&gt;,把插件的配置项&lt;code&gt;OnlineSubsystemSteam&lt;/code&gt;、&lt;code&gt;OnlineSubsystem&lt;/code&gt;添加到其中然后编译&lt;/p&gt;
&lt;div class="code-block" data-lang="c#"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;c#&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c#" data-lang="c#"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;PublicDependencyModuleNames&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Core&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;CoreUObject&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Engine&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;InputCore&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;HeadMountedDisplay&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;EnhancedInput&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;OnlineSubsystemSteam&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;OnlineSubsystem&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/multiplayercourse/multiplayercourse%E5%88%9B%E5%BB%BA%E5%A4%9A%E4%BA%BA%E8%81%94%E6%9C%BA%E6%8F%92%E4%BB%B6/image-20250419145217432.png"
alt="image-20250419145217432"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
image-20250419145217432
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;三、在&lt;code&gt;项目/config/DefaultEngine.ini&lt;/code&gt;中添加下面代码&lt;/p&gt;
&lt;div class="code-block" data-lang="text"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;text&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[/Script/Engine.GameEngine]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; +NetDriverDefinitions=(DefName=&amp;#34;GameNetDriver&amp;#34;,DriverClassName=&amp;#34;OnlineSubsystemSteam.SteamNetDriver&amp;#34;,DriverClassNameFallback=&amp;#34;OnlineSubsystemUtils.IpNetDriver&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [OnlineSubsystem]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; DefaultPlatformService=Steam
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [OnlineSubsystemSteam]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; bEnabled=true
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; SteamDevAppId=480
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ; If using Sessions
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ; bInitServerOnClient=true
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [/Script/OnlineSubsystemSteam.SteamNetDriver]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; NetConnectionClassName=&amp;#34;OnlineSubsystemSteam.SteamNetConnection&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;注意：&lt;/p&gt;</description></item><item><title>【虚幻引擎】委托(Delegates)与回调(Callbacks)</title><link>https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E%E5%A7%94%E6%89%98delegates%E4%B8%8E%E5%9B%9E%E8%B0%83callbacks/</link><pubDate>Mon, 15 Apr 2024 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E%E5%A7%94%E6%89%98delegates%E4%B8%8E%E5%9B%9E%E8%B0%83callbacks/</guid><description>&lt;hr&gt;
&lt;p&gt;虚幻引擎的委托机制是一种类型安全的事件通知系统，支持动态绑定和多播功能，适用于观察者模式和回调实现。主要包括单播、多播、动态委托及事件等类型，并提供基本使用示例。&lt;/p&gt;
&lt;h1 id="unreal-engine-中的-delegates委托详解"&gt;Unreal Engine 中的 Delegates（委托）详解&lt;/h1&gt;
&lt;p&gt;Delegates（委托）是 Unreal Engine 中一种强大的事件通知机制，它允许开发者在不直接引用类的情况下调用成员函数。本质上，委托是一种类型安全的函数指针，特别适合用于实现观察者模式、事件系统和回调机制。&lt;/p&gt;
&lt;h2 id="基本概念"&gt;基本概念&lt;/h2&gt;
&lt;h3 id="核心特点"&gt;核心特点&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;类型安全&lt;/strong&gt;：编译时会检查函数签名匹配&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;动态绑定&lt;/strong&gt;：可以在运行时绑定/解绑函数&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;多播能力&lt;/strong&gt;：可以同时通知多个接收者（Multicast Delegates）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;序列化支持&lt;/strong&gt;：部分委托类型支持蓝图序列化&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="委托类型"&gt;委托类型&lt;/h2&gt;
&lt;p&gt;Unreal Engine 提供了几种主要的委托类型：&lt;/p&gt;
&lt;h3 id="1-单播委托-singlecast-delegates"&gt;1. 单播委托 (Singlecast Delegates)&lt;/h3&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;DECLARE_DELEGATE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyDelegate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 无参数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;DECLARE_DELEGATE_OneParam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyParamDelegate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 单参数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;DECLARE_DELEGATE_TwoParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyTwoParamDelegate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;int32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 双参数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="2-多播委托-multicast-delegates"&gt;2. 多播委托 (Multicast Delegates)&lt;/h3&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;DECLARE_MULTICAST_DELEGATE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyMulticastDelegate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;DECLARE_MULTICAST_DELEGATE_OneParam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyMulticastParamDelegate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="3-动态委托-dynamic-delegates"&gt;3. 动态委托 (Dynamic Delegates)&lt;/h3&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;DECLARE_DYNAMIC_DELEGATE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FMyDynamicDelegate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;DECLARE_DYNAMIC_MULTICAST_DELEGATE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FMyDynamicMulticastDelegate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="4-事件-events"&gt;4. 事件 (Events)&lt;/h3&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;DECLARE_EVENT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyOwnerClass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MyEvent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="使用示例"&gt;使用示例&lt;/h2&gt;
&lt;h3 id="单播委托示例"&gt;单播委托示例&lt;/h3&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 声明一个带有一个参数(int32)的单播委托类型，命名为FScoreChangedDelegate
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 该委托用于在分数变化时通知订阅者
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;DECLARE_DELEGATE_OneParam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FScoreChangedDelegate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;int32&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 定义一个继承自AActor的类AMyActor
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AMyActor&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;AActor&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 声明一个FScoreChangedDelegate类型的委托实例OnScoreChanged
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 这个委托将用于在分数更新时通知所有绑定的函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;FScoreChangedDelegate&lt;/span&gt; &lt;span class="n"&gt;OnScoreChanged&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 更新分数的方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;UpdateScore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;int32&lt;/span&gt; &lt;span class="n"&gt;NewScore&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 执行委托，通知所有绑定的函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// ExecuteIfBound是安全执行方法，只有在有绑定时才会实际调用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 参数NewScore将传递给所有绑定的函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;OnScoreChanged&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteIfBound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;NewScore&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 定义一个监听分数变化的类AMyListener
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AMyListener&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 绑定到分数变化委托的方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;BindToScoreChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AMyActor&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;Actor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 使用BindUObject将当前对象(this)的HandleScoreChanged方法绑定到Actor的OnScoreChanged委托
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// BindUObject专门用于绑定UObject成员函数，会自动处理对象生命周期
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Actor&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;OnScoreChanged&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BindUObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;AMyListener&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;HandleScoreChanged&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 处理分数变化的回调函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;HandleScoreChanged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;int32&lt;/span&gt; &lt;span class="n"&gt;NewScore&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 当分数变化时，记录日志显示新分数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// %d将被NewScore的值替换
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;UE_LOG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LogTemp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Warning&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Score changed to %d&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;NewScore&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h4 id="执行流程"&gt;执行流程&lt;/h4&gt;
&lt;pre class="mermaid"&gt;
sequenceDiagram
participant 调用方 as 调用方(AMyActor)
participant 委托系统 as 委托系统(OnScoreChanged)
participant 监听方 as 监听方(AMyListener)
Note over 监听方: 初始化阶段
监听方-&amp;gt;&amp;gt;委托系统: BindUObject(this, &amp;amp;AMyListener::HandleScoreChanged)
Note right of 委托系统: 存储绑定信息：&amp;lt;br/&amp;gt;- 目标对象(this)&amp;lt;br/&amp;gt;- 函数指针(HandleScoreChanged)
Note over 调用方: 执行阶段
调用方-&amp;gt;&amp;gt;委托系统: ExecuteIfBound(NewScore)
委托系统-&amp;gt;&amp;gt;监听方: 检查目标对象有效性
alt 对象有效
监听方--&amp;gt;&amp;gt;委托系统: 确认可调用
委托系统-&amp;gt;&amp;gt;监听方: 调用HandleScoreChanged(NewScore)
监听方-&amp;gt;&amp;gt;监听方: 执行日志输出 UE_LOG(...)
else 对象无效
委托系统--x 监听方: 跳过执行（自动清理绑定）
end
&lt;/pre&gt;
&lt;p&gt;流程图有时候网页上无法基于代码绘制显示，再附一张截图&lt;/p&gt;</description></item><item><title>【虚幻引擎】UC++的宏定义语法</title><link>https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8Euc++%E7%9A%84%E5%AE%8F%E5%AE%9A%E4%B9%89%E8%AF%AD%E6%B3%95/</link><pubDate>Wed, 10 Apr 2024 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8Euc++%E7%9A%84%E5%AE%8F%E5%AE%9A%E4%B9%89%E8%AF%AD%E6%B3%95/</guid><description>&lt;hr&gt;
&lt;p&gt;Unreal Engine通过UCLASS、UPROPERTY和UFUNCTION等反射宏，将C++类、属性和函数暴露给引擎反射系统与蓝图编辑器，实现可视化编辑和脚本交互。GENERATED_BODY()宏必须置于类定义起始处。&lt;/p&gt;
&lt;h2 id="unreal-engine中宏定义语法的使用"&gt;Unreal Engine中宏定义语法的使用&lt;/h2&gt;
&lt;h3 id="示例代码"&gt;示例代码：&lt;/h3&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 类声明宏：使类被纳入Unreal反射系统
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// - Blueprintable：允许在蓝图中创建该类的子类
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// - meta=(DisplayName=&amp;#34;My Object&amp;#34;)：在编辑器中显示的自定义名称
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;UCLASS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Blueprintable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DisplayName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;My Object&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UMyObject&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;UObject&lt;/span&gt; &lt;span class="c1"&gt;// 必须继承UObject或其子类
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 代码生成宏：必须出现在类体内第一个位置
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// - 展开后会包含类型信息、反射数据等引擎所需的内容
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;GENERATED_BODY&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 属性声明宏：将成员变量暴露给反射系统
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// - EditAnywhere：可在编辑器的任意位置（如蓝图、细节面板）编辑此属性
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// - Category=&amp;#34;Stats&amp;#34;：在编辑器中归入&amp;#34;Stats&amp;#34;分类组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;UPROPERTY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EditAnywhere&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Category&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Stats&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;Health&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;100.0f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 带默认值的公开属性
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 函数声明宏：将函数暴露给反射系统
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// - BlueprintCallable：允许蓝图调用此方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// - 可添加其他说明符如：
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// - Category=&amp;#34;Gameplay&amp;#34;：函数分组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// - meta=(ToolTip=&amp;#34;Heal amount&amp;#34;)：悬停提示文本
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;UFUNCTION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BlueprintCallable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Heal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;Amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 可被蓝图调用的方法
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="关键宏参数详解"&gt;关键宏参数详解：&lt;/h3&gt;
&lt;h4 id="uclass-常用参数"&gt;UCLASS 常用参数：&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;参数&lt;/th&gt;
&lt;th&gt;作用&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Blueprintable&lt;/td&gt;
&lt;td&gt;允许基于此类创建蓝图&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BlueprintType&lt;/td&gt;
&lt;td&gt;允许在蓝图中作为变量类型使用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NotBlueprintable&lt;/td&gt;
&lt;td&gt;明确禁止蓝图继承（默认）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;meta=(DisplayName)&lt;/td&gt;
&lt;td&gt;编辑器显示名称&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id="uproperty-常用参数"&gt;UPROPERTY 常用参数：&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;参数&lt;/th&gt;
&lt;th&gt;作用&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;VisibleAnywhere&lt;/td&gt;
&lt;td&gt;属性可见但不可编辑&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EditAnywhere&lt;/td&gt;
&lt;td&gt;属性可任意编辑&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EditDefaultsOnly&lt;/td&gt;
&lt;td&gt;仅允许在类默认值中编辑&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BlueprintReadOnly&lt;/td&gt;
&lt;td&gt;蓝图只读访问&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Category&lt;/td&gt;
&lt;td&gt;属性分类（编辑器分组）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;meta=(ClampMin=0)&lt;/td&gt;
&lt;td&gt;元数据：限制最小值&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4 id="ufunction-常用参数"&gt;UFUNCTION 常用参数：&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;参数&lt;/th&gt;
&lt;th&gt;作用&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;BlueprintCallable&lt;/td&gt;
&lt;td&gt;可从蓝图调用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;BlueprintPure&lt;/td&gt;
&lt;td&gt;纯函数（无副作用）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Category&lt;/td&gt;
&lt;td&gt;函数分类&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;meta=(Deprecated)&lt;/td&gt;
&lt;td&gt;标记为已弃用&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="特殊说明"&gt;特殊说明：&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;GENERATED_BODY()&lt;/code&gt; 必须：&lt;/p&gt;</description></item><item><title>【游戏设计】游戏开发中AI</title><link>https://tingdonghu.github.io/posts/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/%E6%B8%B8%E6%88%8F%E8%AE%BE%E8%AE%A1%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91%E4%B8%ADai/</link><pubDate>Sat, 06 Apr 2024 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/%E6%B8%B8%E6%88%8F%E8%AE%BE%E8%AE%A1%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91%E4%B8%ADai/</guid><description>&lt;hr&gt;
&lt;p&gt;游戏AI旨在设计非玩家角色的智能行为，以增强体验、创造挑战和模拟世界。文章重点介绍了经典的状态机（FSM）方法，通过拆分行为为独立状态（如巡逻、攻击）并定义转换条件来实现简单AI，同时指出了状态增多时维护复杂的弊端。&lt;/p&gt;
&lt;p&gt;文章的思路来源于Voidmatrix大神视频总结，以及一些本人开发BossAI的感悟所写。&lt;/p&gt;
&lt;p&gt;附上大神原视频链接：&lt;a href="https://www.bilibili.com/video/BV13EdSYgEGR/?share_source=copy_web&amp;amp;vd_source=a06df7b174b0e55e45242729b8ce1758" target="_blank"&gt;【游戏开发秘籍】状态机？行为树？一个视频速通游戏开发中的AI！#06&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="游戏ai是什么"&gt;游戏AI是什么&lt;/h2&gt;
&lt;p&gt;​ **游戏开发领域中，AI通常指的是对非玩家角色行为的设计与研究，让他们能够感知周围的环境，并且做出相应的动作表现。**例如和玩家交互聊天的NPC、按照特定规则巡逻的怪物或是直接与玩家进行对抗的人机等等，一个能与我们的游戏玩法相匹配，逻辑自洽的角色，除去策划上的工作，在开发技术上也是大有研究的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;游戏AI的核心目标&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;增强体验&lt;/strong&gt;：通过智能的NPC行为、动态难度调整等提升游戏趣味性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;创造挑战&lt;/strong&gt;：让敌人或对手具备合理的策略，避免过于简单或作弊。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;模拟世界&lt;/strong&gt;：构建逼真的生态系统（如《荒野之息》中的动物行为）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="状态机fsm"&gt;状态机（FSM）&lt;/h2&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/%E6%B8%B8%E6%88%8F%E8%AE%BE%E8%AE%A1%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91%E4%B8%ADai/image-20250417110706673.png"
alt="状态机"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
状态机
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;​ 最经典最简单的AI实现技术便是&lt;strong&gt;状态机&lt;/strong&gt;，我们可以把NPC的每一个具体的行动都拆分成一个独立的状态。&lt;/p&gt;
&lt;p&gt;​ 接下来我们只需要设计好状态间的挑战条件就可以了，譬如 NPC拥有巡逻、攻击、逃跑和治疗4个状态，默认的入口状态为巡逻，也就是在这个NPC在程序中被实例化添加到游戏世界中时，它便会巡视自己的领地。按照固定的路线徘徊，当玩家等敌对角色进入到他的视野范围后，状态机便会跳转到攻击的状态，在攻击状态下，他会持续逼近玩家的位置，并且试图对其造成伤害。而当在这个战斗过程中自身生命值低于一定数值时，NPC就会进入到逃跑状态，在逃离玩家一定范围后，他们也会停下来治疗自己，恢复生命值，然后继续进入到巡逻或是战斗的状态循环，整套逻辑，这样一个栩栩如生的NPC角色就诞生在了我们创造的游戏世界中了。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/%E6%B8%B8%E6%88%8F%E8%AE%BE%E8%AE%A1%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91%E4%B8%ADai/image-20250417111013341.png"
alt="NPC状态机循环"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
NPC状态机循环
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;​ 而作为最经典的压实线状态机的实验代码，可以说是最简单的了。&lt;/p&gt;
&lt;p&gt;​ 以前面空洞武士项目教程中的代码为例，对于状态节点的设计，我们除去执行更新到 update接口外，通常还需要预留on inter和on X的接口，用来通知该状态的进入并进行初始化以及处理状态退出式的逻辑，譬如在攻击状态进入和退出时，我们需要设置NPC手持武器道具的可见性，并且更新其锁敌感知范围的逻辑，对于状态机本身等待提供 update的更新方法外，也还需要提供设置入口状态，切换状态和注册新状态的接口，为了更快捷的查找，在实际开发过程中，我们可以使用媒体书读或是哈希表来存储状态ID到具体状态对象的映射，那么在状态机更新的过程中，实际执行了当前选中的状态攻击方法，在设置入口状态或是切换不同的状态时，也只需要根据传入的ID，将当前状态指针指向不同的具体状态对象即可。&lt;/p&gt;
&lt;h3 id="状态机的弊端"&gt;状态机的弊端&lt;/h3&gt;
&lt;p&gt;​ 不过跟过空洞武士项目介绍的同学其实可能就已经意识到了这台机正如AI实现方法的弊端了，**不同的状态之间彼此穿插，如果我们要新增一个状态或是修改已有的状态跳转条件时，都需要考虑与现有状态的调整关系，当系统的状态数过多时，维护各个状态间的关系就会变得非常困难。**那么封装的思想这时就起作用了，我们能否把功能相似的具体状态封装成一个更大的抽象状态，我们只需要去关注不同抽象状态间的跳转，思路便会清晰很多。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/%E6%B8%B8%E6%88%8F%E8%AE%BE%E8%AE%A1%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91%E4%B8%ADai/image-20250417111541371.png"
alt="过于复杂的状态机"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
过于复杂的状态机
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;</description></item><item><title>【C++】特殊字符的意义和用法区分</title><link>https://tingdonghu.github.io/posts/%E4%BE%AF%E6%8D%B7%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/c++-.%E7%89%B9%E6%AE%8A%E5%AD%97%E7%AC%A6%E7%9A%84%E6%84%8F%E4%B9%89%E5%92%8C%E7%94%A8%E6%B3%95%E5%8C%BA%E5%88%86/</link><pubDate>Fri, 05 Apr 2024 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/%E4%BE%AF%E6%8D%B7%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/c++-.%E7%89%B9%E6%AE%8A%E5%AD%97%E7%AC%A6%E7%9A%84%E6%84%8F%E4%B9%89%E5%92%8C%E7%94%A8%E6%B3%95%E5%8C%BA%E5%88%86/</guid><description>&lt;p&gt;C++中四种运算符的核心区别：&lt;code&gt;::&lt;/code&gt;用于访问命名空间、类或静态成员；&lt;code&gt;-&amp;gt;&lt;/code&gt;通过指针访问对象成员；&lt;code&gt;.&lt;/code&gt;通过对象实例访问成员；&lt;code&gt;*&lt;/code&gt;用于指针解引用。&lt;/p&gt;
&lt;p&gt;在 C++ 中，&lt;code&gt;::&lt;/code&gt;、&lt;code&gt;-&amp;gt;&lt;/code&gt; 、&lt;code&gt;.&lt;/code&gt; 和&lt;code&gt;*&lt;/code&gt;是四种不同的运算符，分别用于不同的上下文场景。它们的详细解释和用法对比：&lt;/p&gt;
&lt;h2 id="1-作用域解析运算符"&gt;&lt;strong&gt;1. 作用域解析运算符 &lt;code&gt;::&lt;/code&gt;&lt;/strong&gt;&lt;/h2&gt;
&lt;h3 id="用途"&gt;&lt;strong&gt;用途&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问 &lt;strong&gt;命名空间、类、结构体或枚举&lt;/strong&gt; 的成员&lt;/li&gt;
&lt;li&gt;调用 &lt;strong&gt;静态成员&lt;/strong&gt;（变量或函数）&lt;/li&gt;
&lt;li&gt;区分同名的全局变量和局部变量&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="示例"&gt;&lt;strong&gt;示例&lt;/strong&gt;&lt;/h3&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="n"&gt;MyNamespace&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;staticValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;staticMethod&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Static method called!&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;MyClass&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;staticValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 静态成员变量定义
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 访问命名空间成员
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;MyNamespace&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 输出: 42
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 访问类的静态成员
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;MyClass&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;staticValue&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 输出: 100
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;MyClass&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;staticMethod&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 输出: Static method called!
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="关键点"&gt;&lt;strong&gt;关键点&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;::&lt;/code&gt; &lt;strong&gt;不依赖对象实例&lt;/strong&gt;，直接通过类名或命名空间访问成员。&lt;/li&gt;
&lt;li&gt;常用于 &lt;strong&gt;全局变量、静态成员、嵌套类&lt;/strong&gt; 等场景。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="2-成员访问运算符"&gt;&lt;strong&gt;2. 成员访问运算符 &lt;code&gt;-&amp;gt;&lt;/code&gt;&lt;/strong&gt;&lt;/h2&gt;
&lt;h3 id="用途-1"&gt;&lt;strong&gt;用途&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;通过 &lt;strong&gt;指针&lt;/strong&gt; 访问对象的成员（变量或函数）&lt;/li&gt;
&lt;li&gt;等价于 &lt;code&gt;(*ptr).member&lt;/code&gt;（先解引用，再用 &lt;code&gt;.&lt;/code&gt; 访问）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="示例-1"&gt;&lt;strong&gt;示例&lt;/strong&gt;&lt;/h3&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Value: &amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;MyClass&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;MyClass&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 指向对象的指针
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 通过指针访问成员
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 等价于 (*ptr).value = 20;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 输出: Value: 20
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="关键点-1"&gt;&lt;strong&gt;关键点&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-&amp;gt;&lt;/code&gt; &lt;strong&gt;只能用于指针&lt;/strong&gt;，不能用于普通对象。&lt;/li&gt;
&lt;li&gt;在 &lt;strong&gt;智能指针&lt;/strong&gt;（如 &lt;code&gt;std::shared_ptr&lt;/code&gt;）和 &lt;strong&gt;迭代器&lt;/strong&gt; 中也常用。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="3-成员访问运算符"&gt;&lt;strong&gt;3. 成员访问运算符 &lt;code&gt;.&lt;/code&gt;&lt;/strong&gt;&lt;/h2&gt;
&lt;h3 id="用途-2"&gt;&lt;strong&gt;用途&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;通过 &lt;strong&gt;对象实例&lt;/strong&gt;（非指针）访问成员（变量或函数）&lt;/li&gt;
&lt;li&gt;适用于 &lt;strong&gt;结构体、类、联合体&lt;/strong&gt; 等&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="示例-2"&gt;&lt;strong&gt;示例&lt;/strong&gt;&lt;/h3&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Value: &amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;MyClass&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 通过对象访问成员
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 输出: Value: 40
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="关键点-2"&gt;&lt;strong&gt;关键点&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.&lt;/code&gt; &lt;strong&gt;只能用于对象实例&lt;/strong&gt;，不能用于指针。&lt;/li&gt;
&lt;li&gt;在 &lt;strong&gt;结构体、类、联合体&lt;/strong&gt; 中通用。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="4-解引用指针运算符-"&gt;4. 解引用/指针运算符 &lt;code&gt;*&lt;/code&gt;&lt;/h2&gt;
&lt;h3 id="用途-3"&gt;&lt;strong&gt;用途&lt;/strong&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;指针声明&lt;/strong&gt;：表示变量是指针类型&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解引用&lt;/strong&gt;：获取指针指向的实际值&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;乘法运算&lt;/strong&gt;：算术乘法（本文不讨论，因与其他运算符无关）&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="示例与详解"&gt;&lt;strong&gt;示例与详解&lt;/strong&gt;&lt;/h3&gt;
&lt;h4 id="1-指针声明"&gt;&lt;strong&gt;(1) 指针声明&lt;/strong&gt;&lt;/h4&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// ptr 是一个指向 int 的指针
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;int* ptr&lt;/code&gt; 表示 &lt;code&gt;ptr&lt;/code&gt; 存储的是内存地址，而非直接的值。&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="2-解引用获取指针指向的值"&gt;&lt;strong&gt;(2) 解引用（获取指针指向的值）&lt;/strong&gt;&lt;/h4&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 输出: 42（通过 * 获取指针指向的实际值）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 修改指针指向的值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 输出: 100
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h4 id="3-与"&gt;&lt;strong&gt;(3) 与 &lt;code&gt;-&amp;gt;&lt;/code&gt; 的关系&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;ptr-&amp;gt;member&lt;/code&gt; 等价于 &lt;code&gt;(*ptr).member&lt;/code&gt;：&lt;/p&gt;</description></item><item><title>【虚幻引擎】UC++与标准C++的区别</title><link>https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8Euc++%E4%B8%8E%E6%A0%87%E5%87%86c++%E7%9A%84%E5%8C%BA%E5%88%AB/</link><pubDate>Tue, 19 Mar 2024 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8Euc++%E4%B8%8E%E6%A0%87%E5%87%86c++%E7%9A%84%E5%8C%BA%E5%88%AB/</guid><description>&lt;hr&gt;
&lt;h2 id="1-类声明与反射系统"&gt;1. 类声明与反射系统&lt;/h2&gt;
&lt;h3 id="11-类定义语法"&gt;1.1 类定义语法&lt;/h3&gt;
&lt;h4 id="unreal-c"&gt;Unreal C++&lt;/h4&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 必须继承UObject且使用反射宏
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;UCLASS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Blueprintable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DisplayName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;My Object&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UMyObject&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;UObject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;GENERATED_BODY&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// 必须包含
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;UPROPERTY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EditAnywhere&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Category&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Stats&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;Health&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;100.0f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;UFUNCTION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BlueprintCallable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Heal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;Amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h4 id="标准-c"&gt;标准 C++&lt;/h4&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyObject&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;Health&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;100.0f&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Heal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;Amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Health&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;Amount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="12-反射机制对比"&gt;1.2 反射机制对比&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;特性&lt;/th&gt;
&lt;th&gt;Unreal C++&lt;/th&gt;
&lt;th&gt;标准 C++&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;运行时类型信息&lt;/td&gt;
&lt;td&gt;通过UCLASS宏自动生成&lt;/td&gt;
&lt;td&gt;仅支持有限RTTI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;动态属性访问&lt;/td&gt;
&lt;td&gt;UPROPERTY字段可通过名字字符串访问&lt;/td&gt;
&lt;td&gt;需要手动实现反射系统&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;方法调用&lt;/td&gt;
&lt;td&gt;UFUNCTION支持蓝图调用和RPC&lt;/td&gt;
&lt;td&gt;只能静态调用&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="2-内存管理模型"&gt;2. 内存管理模型&lt;/h2&gt;
&lt;h3 id="21-对象生命周期"&gt;2.1 对象生命周期&lt;/h3&gt;
&lt;h4 id="unreal-c-1"&gt;Unreal C++&lt;/h4&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 自动垃圾回收
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;UMyObject&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;Obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NewObject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;UMyObject&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Obj&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;MarkPendingKill&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 标记销毁
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 手动控制引用
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Obj&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;AddToRoot&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// 防止被GC
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Obj&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;RemoveFromRoot&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h4 id="标准-c-1"&gt;标准 C++&lt;/h4&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 手动管理
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;MyObject&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;MyObject&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;delete&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 或使用智能指针
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;auto&lt;/span&gt; &lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_shared&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyObject&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="22-内存分配器对比"&gt;2.2 内存分配器对比&lt;/h3&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Unreal自定义分配器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;FMemory&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;FMemory&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Ptr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 标准库分配器
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="3-核心数据类型差异"&gt;3. 核心数据类型差异&lt;/h2&gt;
&lt;h3 id="31-字符串处理"&gt;3.1 字符串处理&lt;/h3&gt;
&lt;h4 id="unreal-c-2"&gt;Unreal C++&lt;/h4&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;FString&lt;/span&gt; &lt;span class="n"&gt;Str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Hello&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// UTF-16
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;FText&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;NSLOCTEXT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;NS&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Key&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Localized Text&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 格式化
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;FString&lt;/span&gt; &lt;span class="n"&gt;Format&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FString&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;%s:%d&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h4 id="标准-c-2"&gt;标准 C++&lt;/h4&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Hello&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 依赖编码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;format&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;{}:{}&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// C++20
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="32-容器类对比"&gt;3.2 容器类对比&lt;/h3&gt;
&lt;h4 id="数组操作"&gt;数组操作&lt;/h4&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Unreal
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;TArray&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;int32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Arr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 标准库
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;erase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h4 id="字典操作"&gt;字典操作&lt;/h4&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Unreal
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;TMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;FName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FString&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Key&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Value&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 标准库
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;unordered_map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;emplace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Key&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Value&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="4-多线程编程"&gt;4. 多线程编程&lt;/h2&gt;
&lt;h3 id="41-任务系统"&gt;4.1 任务系统&lt;/h3&gt;
&lt;h4 id="unreal-c-3"&gt;Unreal C++&lt;/h4&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// GameThread执行
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;AsyncTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ENamedThreads&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;GameThread&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[](){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;UE_LOG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LogTemp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Warning&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Main thread&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 并行任务
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ParallelFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[](&lt;/span&gt;&lt;span class="n"&gt;int32&lt;/span&gt; &lt;span class="n"&gt;Index&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 并行执行
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h4 id="标准-c-3"&gt;标准 C++&lt;/h4&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kr"&gt;thread&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;([](){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;New thread&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="5-编译系统差异"&gt;5. 编译系统差异&lt;/h2&gt;
&lt;h3 id="51-模块定义"&gt;5.1 模块定义&lt;/h3&gt;
&lt;h4 id="unreal模块"&gt;Unreal模块&lt;/h4&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// MyModule.Build.cs
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyModule&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ModuleRules&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;MyModule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ReadOnlyTargetRules&lt;/span&gt; &lt;span class="n"&gt;Target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;PublicDependencyModuleNames&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Core&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h4 id="cmake示例"&gt;CMake示例&lt;/h4&gt;
&lt;div class="code-block" data-lang="cmake"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cmake&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cmake" data-lang="cmake"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;add_library&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;MyModule&lt;/span&gt; &lt;span class="s"&gt;STATIC&lt;/span&gt; &lt;span class="s"&gt;src.cpp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;target_link_libraries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;MyModule&lt;/span&gt; &lt;span class="s"&gt;PUBLIC&lt;/span&gt; &lt;span class="s"&gt;Core&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="6-常用宏对比"&gt;6. 常用宏对比&lt;/h2&gt;
&lt;h3 id="61-常用unreal宏"&gt;6.1 常用Unreal宏&lt;/h3&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;UE_LOG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LogTemp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Warning&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Message&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 日志
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 断言
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ensureMsgf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bCondition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Message&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// 带消息断言
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h3 id="62-标准c等效"&gt;6.2 标准C++等效&lt;/h3&gt;
&lt;div class="code-block" data-lang="cpp"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;cpp&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Message&amp;#34;&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 日志
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 断言
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;bCondition&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;runtime_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Message&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 异常
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="7-最佳实践建议"&gt;7. 最佳实践建议&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;在Unreal项目中&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;始终使用&lt;code&gt;UCLASS()&lt;/code&gt;/&lt;code&gt;UFUNCTION()&lt;/code&gt;暴露需要反射的类&lt;/li&gt;
&lt;li&gt;对&lt;code&gt;UObject&lt;/code&gt;派生类不要使用智能指针&lt;/li&gt;
&lt;li&gt;使用&lt;code&gt;TArray&lt;/code&gt;代替&lt;code&gt;std::vector&lt;/code&gt;以获得更好性能&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;在独立模块中&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;可使用标准库容器和智能指针&lt;/li&gt;
&lt;li&gt;通过纯接口类与Unreal代码交互&lt;/li&gt;
&lt;li&gt;将标准C++代码封装在&lt;code&gt;Private&lt;/code&gt;目录&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;通用规则&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;避免在头文件中混合两种风格的代码&lt;/li&gt;
&lt;li&gt;对性能关键路径使用Unreal优化容器&lt;/li&gt;
&lt;li&gt;跨平台代码优先使用Unreal封装&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;</description></item><item><title>【游戏设计】游戏开发中的跳跃设计</title><link>https://tingdonghu.github.io/posts/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/%E6%B8%B8%E6%88%8F%E8%AE%BE%E8%AE%A1%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91%E4%B8%AD%E7%9A%84%E8%B7%B3%E8%B7%83%E8%AE%BE%E8%AE%A1/</link><pubDate>Fri, 15 Mar 2024 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/%E6%B8%B8%E6%88%8F%E8%AE%BE%E8%AE%A1%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91%E4%B8%AD%E7%9A%84%E8%B7%B3%E8%B7%83%E8%AE%BE%E8%AE%A1/</guid><description>&lt;hr&gt;
&lt;p&gt;游戏角色跳跃设计需平衡物理模拟与玩家体验，通过插值平滑跳跃高度、引入跳跃缓冲和跳跃宽限期来优化操作手感，并可根据游戏类型定制重力参数。&lt;/p&gt;
&lt;p&gt;文章的思路来源于&lt;code&gt;Voidmatrix&lt;/code&gt;UP的B站视频总结，以及一些本人游戏开发的感悟所写。&lt;/p&gt;
&lt;p&gt;附上原视频链接：&lt;a href="https://www.bilibili.com/video/BV1mDrzYiE5b/?share_source=copy_web&amp;amp;vd_source=a06df7b174b0e55e45242729b8ce1758" target="_blank"&gt;【游戏开发秘籍】二段跳？土狼跳？跳跃还有这么多骚操作！游戏角色跳跃功能实现 #01&lt;/a&gt;
&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;游戏的跳跃设计往往决定了这个游戏的上手手感,对于开发者来说,好的游戏跳跃的设计(以及优化)基本要遵循以下原则:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;物理模拟与心理预期的平衡&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;既需要遵循基础物理规律（如自由落体）满足玩家直觉，但也要适配游戏的合理放大能力（如2.5米跳跃高度）。
&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/%E6%B8%B8%E6%88%8F%E8%AE%BE%E8%AE%A1%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91%E4%B8%AD%E7%9A%84%E8%B7%B3%E8%B7%83%E8%AE%BE%E8%AE%A1/image-20250423170741832.png"
alt="黑神话悟空中的跳跃"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
黑神话悟空中的跳跃
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;跳跃高度控制的插值过度&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当角色达到预设高度限制时强制速度归零（直接下落或平滑减速）,但是直接将角色的速度取为0会导致手感上很生硬(就好像撞到了空气墙),所以现代游戏设计一般会在高度限制上做一个速度插值平滑过渡（如接近上限时渐衰减）.
&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/%E6%B8%B8%E6%88%8F%E8%AE%BE%E8%AE%A1%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91%E4%B8%AD%E7%9A%84%E8%B7%B3%E8%B7%83%E8%AE%BE%E8%AE%A1/image-20250423170913428.png"
alt="空气墙与插值"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
空气墙与插值
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;跳跃缓冲（Jump Buffering）&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;存储提前输入的跳跃指令（如连续跳跃落地前几帧按键），在满足条件时自动触发。这点比较类似于游戏连招系统中的按键缓存.
&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91/%E6%B8%B8%E6%88%8F%E8%AE%BE%E8%AE%A1%E6%B8%B8%E6%88%8F%E5%BC%80%E5%8F%91%E4%B8%AD%E7%9A%84%E8%B7%B3%E8%B7%83%E8%AE%BE%E8%AE%A1/image-20250423171011911.png"
alt="跳跃缓冲"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
跳跃缓冲
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;跳跃宽限期（Coyote Time）&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>【OpenPCDet】模型预测结果解读</title><link>https://tingdonghu.github.io/posts/3dcomputervison/openpcdet%E6%A8%A1%E5%9E%8B%E9%A2%84%E6%B5%8B%E7%BB%93%E6%9E%9C%E8%A7%A3%E8%AF%BB/</link><pubDate>Sat, 02 Mar 2024 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/3dcomputervison/openpcdet%E6%A8%A1%E5%9E%8B%E9%A2%84%E6%B5%8B%E7%BB%93%E6%9E%9C%E8%A7%A3%E8%AF%BB/</guid><description>&lt;p&gt;OpenPCDet模型的推理结果以字典形式输出，包含检测目标的类别、位置、尺寸等关键信息。不同模型输出结构类似，但具体字段可能略有差异。&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/3dcomputervison/openpcdet%E6%A8%A1%E5%9E%8B%E9%A2%84%E6%B5%8B%E7%BB%93%E6%9E%9C%E8%A7%A3%E8%AF%BB/aab43926a7fe400898d4bfc41f661d63.png"
alt="在这里插入图片描述"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
在这里插入图片描述
&lt;/figcaption&gt;
&lt;/figure&gt;
在 OpenPCDet 中，每个模型的推理结果通常是&lt;strong&gt;一个包含多个键值对的字典&lt;/strong&gt;，其中包含与 3D 检测任务相关的信息。不同模型的输出结构可能略有不同，但一般来说，模型输出通常包含以下几个关键字段：
以下给一段&lt;code&gt;output/kitti_models/pointrcnn/default/eval/eval_with_train/epoch_80/val/result.pkl&lt;/code&gt;中选取某一帧的结果示例,提取为json文件便于阅读：&lt;/p&gt;
&lt;div class="code-block" data-lang="json"&gt;
&lt;div class="code-block__bar"&gt;
&lt;span class="code-block__dots"&gt;&lt;i class="dot-red"&gt;&lt;/i&gt;&lt;i class="dot-yellow"&gt;&lt;/i&gt;&lt;i class="dot-green"&gt;&lt;/i&gt;&lt;/span&gt;
&lt;span class="code-block__lang"&gt;json&lt;/span&gt;
&lt;span class="code-block__actions"&gt;
&lt;button class="code-block__btn" data-act="wrap"&gt;软折行&lt;/button&gt;
&lt;button class="code-block__btn" data-act="copy"&gt;复制&lt;/button&gt;
&lt;button class="code-block__btn" data-act="fold"&gt;折叠&lt;/button&gt;
&lt;/span&gt;
&lt;/div&gt;
&lt;div class="code-block__body"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;&amp;#34;pointrcnn&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Car&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Pedestrian&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Pedestrian&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;truncated&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;occluded&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;alpha&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;-4.0102105140686035&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;-1.6028798818588257&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;-4.731999397277832&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;bbox&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;196.87057495117188&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;410.6382141113281&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;373.0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;688.0215454101562&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;172.8148193359375&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;709.7300415039062&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;224.52003479003906&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;667.0341186523438&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;172.51962280273438&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;687.4990844726562&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;223.23146057128906&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;dimensions&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;4.10535192489624&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;1.4689395427703857&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;1.6220554113388062&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;0.9827990531921387&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;1.7112400531768799&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;0.6871805191040039&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;0.5967018008232117&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;1.6898497343063354&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;0.67041015625&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;location&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;-2.7540218830108643&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;1.6045180559158325&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;4.157565593719482&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;3.2612111568450928&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;1.4242191314697266&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;24.295761108398438&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;2.5298221111297607&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;1.3910222053527832&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;24.260332107543945&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;rotation_y&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;-4.574054718017578&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;-1.476109504699707&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;-4.6344404220581055&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;score&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;0.9997606873512268&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;0.9978153705596924&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;0.9920910596847534&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;boxes_lidar&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;4.406521797180176&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;2.786322832107544&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;-0.915142297744751&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;4.10535192489624&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;1.6220554113388062&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;1.4689395427703857&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;3.003258228302002&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;24.574119567871094&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;-3.132066488265991&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;-0.7385169863700867&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;0.9827990531921387&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;0.6871805191040039&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;1.7112400531768799&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;-0.09468691051006317&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;24.53524398803711&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;-2.4012603759765625&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;-0.7080038189888&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;0.5967018008232117&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;0.67041015625&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;1.6898497343063354&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="mf"&gt;3.0636441707611084&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="内容解读"&gt;内容解读&lt;/h2&gt;
&lt;h3 id="name"&gt;name&lt;/h3&gt;
&lt;p&gt;含义：检测到的物体类别。
​示例：&lt;code&gt;[&amp;quot;Car&amp;quot;, &amp;quot;Pedestrian&amp;quot;, &amp;quot;Pedestrian&amp;quot;, ...]&lt;/code&gt;
​说明：&lt;/p&gt;</description></item><item><title>【虚幻引擎】设置UI自适应屏幕大小</title><link>https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E%E8%AE%BE%E7%BD%AEui%E8%87%AA%E9%80%82%E5%BA%94%E5%B1%8F%E5%B9%95%E5%A4%A7%E5%B0%8F/</link><pubDate>Thu, 30 Nov 2023 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E%E8%AE%BE%E7%BD%AEui%E8%87%AA%E9%80%82%E5%BA%94%E5%B1%8F%E5%B9%95%E5%A4%A7%E5%B0%8F/</guid><description>&lt;hr&gt;
&lt;p&gt;锚点是虚幻引擎UI布局的核心工具，通过将控件锚定在父物体或屏幕的特定点，确保界面在不同屏幕分辨率下能自适应缩放并保持稳定的相对位置关系。&lt;/p&gt;
&lt;p&gt;在游戏中，如果想实现不同分辨率下，都可以支持当前的UI界面布局，都需要用到锚点功能。
‌&lt;a href="https://www.baidu.com/s?sa=re_dqa_generate&amp;amp;wd=%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E&amp;amp;rsv_pq=ca8de6dd007d16af&amp;amp;oq=%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8Eui%E9%94%9A%E7%82%B9%E6%98%AF%E4%BB%80%E4%B9%88&amp;amp;rsv_t=51d7gQl1KDGIFZHot4xxk8eoDFmMyx2fKF46n5XUr4N9FLnLgEu0uIVIDyzrutkjPI9DBew&amp;amp;tn=15007414_12_dg&amp;amp;ie=utf-8" target="_blank"&gt;虚幻引擎&lt;/a&gt;
中的UI锚点（Anchor）是指控件在屏幕或父物体上的固定点，用于确定控件的位置和布局。‌ 锚点的作用是确保UI元素在屏幕缩放或形变时保持相对位置不变。&lt;/p&gt;
&lt;p&gt;在虚幻引擎中，锚点可以理解为将子物体“挂”在父物体上的点。当父物体的位置或大小发生变化时，子物体的位置会相应地调整，保持它们之间的相对关系不变。锚点的位置可以在屏幕的任意角落，通常用于自适应屏幕尺寸和保持布局的稳定性‌。
具体来说，锚点有以下几种情况：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当锚点与父物体的某个顶点重合时，子物体在该点的位置不会改变，只有当父物体该点位置改变时，子物体才会跟着移动。&lt;/li&gt;
&lt;li&gt;如果锚点不重合，子物体在父物体变形时会跟着缩放，保持与父物体各顶点的距离不变‌。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="具体实现"&gt;具体实现：&lt;/h3&gt;
&lt;p&gt;错误的UI锚点设置方法如下：&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E%E8%AE%BE%E7%BD%AEui%E8%87%AA%E9%80%82%E5%BA%94%E5%B1%8F%E5%B9%95%E5%A4%A7%E5%B0%8F/e6bab021dbbf44a2bbaae6670b646233.png"
alt="img"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
img
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;如上图为锚点设置不准确，导致缩放时出现屏幕空缺&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E%E8%AE%BE%E7%BD%AEui%E8%87%AA%E9%80%82%E5%BA%94%E5%B1%8F%E5%B9%95%E5%A4%A7%E5%B0%8F/2f3cb2f4e5604e1e857b11dfb50526b0.png"
alt="img"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
img
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;将锚点修改为下图所示：&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E%E8%AE%BE%E7%BD%AEui%E8%87%AA%E9%80%82%E5%BA%94%E5%B1%8F%E5%B9%95%E5%A4%A7%E5%B0%8F/30e978c4df3241b3a9a83f106c50451b.png"
alt="img"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
img
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;</description></item><item><title>【虚幻引擎】VRiod的二次元角色导入</title><link>https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8Evriod%E7%9A%84%E4%BA%8C%E6%AC%A1%E5%85%83%E8%A7%92%E8%89%B2%E5%AF%BC%E5%85%A5/</link><pubDate>Mon, 20 Nov 2023 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8Evriod%E7%9A%84%E4%BA%8C%E6%AC%A1%E5%85%83%E8%A7%92%E8%89%B2%E5%AF%BC%E5%85%A5/</guid><description>&lt;hr&gt;
&lt;p&gt;本文介绍了将VRoid Studio创建的二次元角色模型导入虚幻引擎的完整流程。首先在VRoid Studio中设计并导出VRM格式的角色文件，然后通过VRM4U插件将其导入虚幻引擎项目，并提供了插件安装、配置及常见问题的解决方法。&lt;/p&gt;
&lt;h1 id="vriod的二次元角色导入虚幻引擎"&gt;VRiod的二次元角色导入虚幻引擎&lt;/h1&gt;
&lt;p&gt;突然想在虚幻项目中用点二次元角色,找了些资料以及自己实践作如下博客,附一篇视频教程:&lt;a href="https://www.bilibili.com/video/BV1ox4y1v7dD/?share_source=copy_web&amp;amp;vd_source=a06df7b174b0e55e45242729b8ce1758" target="_blank"&gt;如何在UE5中快速导入VroidStudio的二次元萌妹&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id="vroid-studio使用"&gt;VRoid Studio使用&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;VRoid Studio&lt;/strong&gt;是由&lt;code&gt;pixiv&lt;/code&gt;开发的一款3D角色绘制软件,可以在Steam上免费下载使用.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;软件的主要功能就是通过类似绘画的方式进行人物的建模，让用户可以更加轻松地创造自己的虚拟人物（形象）。软件的操作界面也非常的简单直观，里面配备了许多预设项目和参数，让用户不需要从头开始建模，只需选择项目、组合它们并调整参数即可创建自己的角色，其中就包含了面部、发型、衣服、化妆等等可定制的参数。同时，用户能直接想画画一样直观的模拟发型，还能直接在3D模型上绘制特定的面部表情、眼睛或服装设计。此外，用户可以通过全尺寸钢笔工具绘制自己所需要的纹理，它支持数位板压力感应，用户可以直接在3D模型或UV开发上直接实时绘制纹理用来创建角色。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;对于我们这种只会写代码的人来说,使用&lt;code&gt;VRoid Studio&lt;/code&gt;只需要把他提供的资源组合一下,就能得到很好看的角色.&lt;/p&gt;
&lt;p&gt;比如我们选择软件提供的模板,这个蓝头发的美眉,进入微调界面:&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8Evriod%E7%9A%84%E4%BA%8C%E6%AC%A1%E5%85%83%E8%A7%92%E8%89%B2%E5%AF%BC%E5%85%A5/image-20250424222850712.png"
alt="VRoid捏二次元角色"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
VRoid捏二次元角色
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;调整为自己心仪的模样后点击右上角导出为&lt;code&gt;VRM&lt;/code&gt;文件.&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8Evriod%E7%9A%84%E4%BA%8C%E6%AC%A1%E5%85%83%E8%A7%92%E8%89%B2%E5%AF%BC%E5%85%A5/image-20250424223042603.png"
alt="捏猫娘脸"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
捏猫娘脸
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;不进行骨骼贴图调整,直接使用默认选项导出:&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8Evriod%E7%9A%84%E4%BA%8C%E6%AC%A1%E5%85%83%E8%A7%92%E8%89%B2%E5%AF%BC%E5%85%A5/image-20250424223201161.png"
alt="image-20250424223201161"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
image-20250424223201161
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;</description></item><item><title>【机器学习】基础知识总结</title><link>https://tingdonghu.github.io/posts/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86%E6%80%BB%E7%BB%93/</link><pubDate>Mon, 30 Oct 2023 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86%E6%80%BB%E7%BB%93/</guid><description>&lt;h1 id="机器学习基础知识全梳理从原理到实践"&gt;机器学习基础知识全梳理：从原理到实践&lt;/h1&gt;
&lt;h2 id="写在前面"&gt;写在前面&lt;/h2&gt;
&lt;p&gt;机器学习作为人工智能的核心分支，已经渗透到我们生活的方方面面：推荐系统推荐你喜欢的音乐、垃圾邮件自动识别、自动驾驶车辆感知环境、医疗辅助诊断等等。但你是否想过，这些系统是如何&amp;quot;学习&amp;quot;的？&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;本文适合对机器学习已有初步了解的学习者进行系统复习&lt;/strong&gt;，内容从基础概念到算法原理，由浅入深，注重理解而非死记硬背。如果你是机器学习新手，强烈推荐先系统学习吴恩达老师的经典课程。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;推荐入门课程&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.bilibili.com/video/BV1owrpYKEtP/" target="_blank"&gt;吴恩达机器学习 2025 重制版&lt;/a&gt;
- B站高清完整课程，附课件和实战项目&lt;/li&gt;
&lt;li&gt;&lt;a href="https://see.stanford.edu/Course/CS229" target="_blank"&gt;CS229: Machine Learning&lt;/a&gt;
- 斯坦福大学官方课程资料&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/playlist?list=PLZHQObOWTQDNU6R1_67000DiV4ZFndKSg" target="_blank"&gt;3Blue1Brown: Neural Networks&lt;/a&gt;
- 视觉化理解神经网络&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2 id="一什么是机器学习"&gt;一、什么是机器学习？&lt;/h2&gt;
&lt;h3 id="形式化定义"&gt;形式化定义&lt;/h3&gt;
&lt;p&gt;机器学习是人工智能的一个分支，它使计算机系统能够从数据中学习并做出决策或预测，而无需进行明确的编程。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;通俗理解&lt;/strong&gt;：假设你有一个数据集，需要通过这个数据集找出一个函数或方法来分析数据并对新数据进行预测。从这个角度看，&lt;strong&gt;机器学习本质上就是&amp;quot;找函数&amp;quot;的过程&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id="学习范式类比"&gt;学习范式类比&lt;/h3&gt;
&lt;p&gt;我们可以用一个形象的类比来理解机器学习的核心思想：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;传统编程&lt;/th&gt;
&lt;th&gt;机器学习&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;输入数据 + 明确规则 → 输出结果&lt;/td&gt;
&lt;td&gt;输入数据 + 期望输出 → 推导规则&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;规则由人类编写&lt;/td&gt;
&lt;td&gt;规则从数据中学习&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;适合规则明确的任务&lt;/td&gt;
&lt;td&gt;适合规则难以定义的任务&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;举例说明&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;传统编程&lt;/strong&gt;：编写一个程序判断数字是否能被 2 整除——规则明确（&lt;code&gt;x % 2 == 0&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;机器学习&lt;/strong&gt;：训练模型识别手写数字——规则难以用代码表达，需要从大量样本中学习&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="学习的三要素"&gt;学习的三要素&lt;/h3&gt;
&lt;p&gt;有效的机器学习需要三个核心要素：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;数据（Data）&lt;/strong&gt;：学习的素材，质量决定上限&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;模型（Model）&lt;/strong&gt;：函数的假设空间，决定表达能力&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;算法（Algorithm）&lt;/strong&gt;：从数据中优化模型参数的方法&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;延伸阅读&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.cs.cmu.edu/~tom/mlbook.html" target="_blank"&gt;Mitchell, T. (1997). Machine Learning&lt;/a&gt;
- 经典教材，学习形式化定义&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.nature.com/articles/323533a0" target="_blank"&gt;Learning representations by back-propagating errors&lt;/a&gt;
- 神经网络反向传播经典论文&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2 id="二机器学习四大范式"&gt;二、机器学习四大范式&lt;/h2&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86%E6%80%BB%E7%BB%93/01-comparison-learning-paradigms.png"
alt="机器学习范式"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
机器学习范式
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;</description></item><item><title>【虚幻引擎】设置双人分屏</title><link>https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E%E8%AE%BE%E7%BD%AE%E5%8F%8C%E4%BA%BA%E5%88%86%E5%B1%8F/</link><pubDate>Fri, 11 Aug 2023 00:00:00 +0800</pubDate><author>古月月仔</author><guid>https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E%E8%AE%BE%E7%BD%AE%E5%8F%8C%E4%BA%BA%E5%88%86%E5%B1%8F/</guid><description>&lt;hr&gt;
&lt;p&gt;本文记录了在项目中实现本地分屏联机功能的过程，包括在项目设置中启用分屏模式、配置游戏模式，并详细解析了用于动态生成玩家角色的蓝图核心逻辑与关键节点。&lt;/p&gt;
&lt;p&gt;在开发项目的时候想添加一个本地联机功能,使用分屏功能实现,查了一些资料做此记录博客.&lt;/p&gt;
&lt;h2 id="项目设置"&gt;项目设置&lt;/h2&gt;
&lt;p&gt;在项目设置中&lt;code&gt;Local Multiplayer&lt;/code&gt;目录下打开使用分屏功能,可以选择垂直/水平分屏,一般像双人成行那样选择垂直模式.&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E%E8%AE%BE%E7%BD%AE%E5%8F%8C%E4%BA%BA%E5%88%86%E5%B1%8F/image-20250425120633628.png"
alt="image-20250425120633628"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
image-20250425120633628
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠Warning !&lt;/p&gt;
&lt;p&gt;注意此处要跳过将手柄指定到玩家1选项.,因为我们想实现一个玩家1使用键鼠操作,后续玩家使用手柄操作的模式&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E%E8%AE%BE%E7%BD%AE%E5%8F%8C%E4%BA%BA%E5%88%86%E5%B1%8F/51d8c8a72e89a298328920c8855a6207.png"
alt="img"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
img
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;
&lt;h2 id="游戏模式设置"&gt;游戏模式设置&lt;/h2&gt;
&lt;p&gt;打开项目设置后就可以修改我们的游戏模式.&lt;/p&gt;
&lt;p&gt;&lt;figure style="text-align: center; margin: 1.5rem auto;"&gt;
&lt;img src="https://tingdonghu.github.io/posts/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E/%E8%99%9A%E5%B9%BB%E5%BC%95%E6%93%8E%E8%AE%BE%E7%BD%AE%E5%8F%8C%E4%BA%BA%E5%88%86%E5%B1%8F/0cd310daba03794899369a39b83d0450.png"
alt="img"
class="zoomable"
style="max-width: 100%; height: auto; border-radius: 8px; cursor: zoom-in;"
loading="lazy" /&gt;
&lt;figcaption style="margin-top: 8px; font-size: 0.85em; color: #888; font-style: italic;"&gt;
img
&lt;/figcaption&gt;
&lt;/figure&gt;&lt;/p&gt;</description></item></channel></rss>