[{"content":" 这是我在 2026 年春季于中科大学习丁虎老师的《大数据算法》课程时整理的期末考试复习笔记。非常喜欢的好课。只是可惜讲义编写得比较潦草。这里的笔记尽可能指出讲义中各种概念的几何意义与机器学习意义，并尝试找出各种定义、定理的动机。\n6 VC 维 VC 维及其几何概念 VC 维和核心集（coreset）是描述模型表达能力的数学工具。\n直观来看，VC 维描述的是一个分类器在任意的正负类指定下，能够区分（称为“打散”）的最大数据点数目。如：\n在二维平面上，二维直线可以打散（不共线的）3 个点，但不能打散（任何分布下的）4 个点，因此二维直线的 VC 维为 3； X 是二维平面 ， 是二维平面里的一个圆，那么 X 是三维平面 ， 是三维平面里的一个球，那么 X 是二维平面 ， 是二维平面里的一个多边形，那么 严格的数学的定义见讲义。以下是这些几何概念和机器学习中概念的对应，提供一些直观的理解。\n几何术语 机器学习标准术语 形象化解释 基集 输入空间 所有可能的数据样本的特征集合（如 ）。 范围族 假设空间 全参数下的模型集合。其中的每一个“范围” 都对应模型在某组特定参数下，判定为正类的决策区域。 有限子集 样本集 / 训练集 实际观测或用于训练的 个无标签数据点。 投影 二分集 (Dichotomies) 分类的行为集合。\n即当模型参数在整个参数空间内变化时，我们的模型在当前这 个特定样本上，所有可能输出的“正负标签向量”的集合。 打散 (Shattering) 完美拟合 / 记忆能力 如果当前训练集 被打散，意味着：无论这些数据点的真实标签是什么，模型总能找到正确分类这些数据的参数。 范围空间由基集和范围族共同确定。\nVC 维的定义是“存在”性的，如果存在大小为 的点集能被打散，则 . 反过来，如果对于任意大小为 的点集都不能被打散，则 .\nVC 维并不是越高越好。能完全打散样本集的模型容易产生过拟合，VC 维适当（较低）的模型能够有更强的泛化潜力。当 VC 维低于样本集大小时，泛化误差界开始起作用，训练集上的表现具有了代表性，这由 VC 不等式保证。\n定理 6.1：如果有一个 Range Space ，它的 VC 维 ，那么定义两个集合：\n令 ，，则这两个 Range Space 的 VC 维在 和 之间，即：\n这个定理描述了多个模型用并、交操作组合出来的新模型表达能力的上下界，提供了一个模型组合的“安全边界”。\n对于给定的范围空间 ，数据集合 ，误差参数 . 可在空间上定义一些“网状”结构：\n：对于 ，若 中任意大小足够的范围 均一定包含 中的点，则称 是 关于 的一个 。\n要求采样范围“不能漏掉”显著的区域。 ：对于 ，如果对于任意范围 ，，即采样集合 计算出来的密度与真实密度的误差都不超过 ，则称 是 的一个 。\n要求采样范围“能正确估计”显著的区域。 显然 的定义是更强的条件。\n定理 6.2 \u0026amp; 6.3： ， 是 的均匀采样子集。\n是 的概率 的条件为 是 的概率 的条件为 可以观察到这些概率和 无关。\n实际意义：经验观察可以推广到实际真理。无论多大的数据，学习一个能良好分类这些数据的模型只需要一个（良好采样的）小样本，这个小样本的大小仅和模型的复杂程度与对误差的容忍度有关，而与数据集的大小无关。\n假如说有一个巨大的包含正负样本的数据集，数据集的数据维度为 ，在该数据集上存在一个良好的分类超平面能很好的分开正样本和负样本，那么我们根据这两个定理，可以得出，当我们的SVM分类器的训练数据集的大小大概为 时，我们可以保证，对任何一个新来的数据点，分类出错的概率小于 。\nVC 维与 PAC Learning 可高效 PAC 学习的实际意义是：高概率的采样条件下（失败概率 ），对任意分布的训练\u0026amp;测试集，算法可学习到误差足够小（小于 ）的模型，且算法时间复杂度是 的多项式级别。（能大概率学到足够好的模型的多项式算法）\n定理6.4（奥卡姆剃刀）：如果一个算法能够高效地找到一个一致的假设（consistent hypothesis），那么对于任何有限概念类 ，只要提供至少 个样本，该算法就能实现 PAC 学习。其中样本数 满足：\n一致的假设是指能精确区分训练数据集上所有正负样本的假设，于是这样的假设训练误差为0. 实际意义：“若无必要，勿增实体”，假设越小，泛化能力越强。对于两个能通过训练数据集的分类的模型，选择更简单的那个（即 VC 维更小的那个），能得到更好的泛化能力。\n7 核心集 定义：对于数据集 上特定的问题 ，对于解空间 中任意解，满足以下误差约束的带权数据集 （足够具有代表性的数据集）\n带权是核心集必要的属性，这里的权重类似于将一个数据点复制多份来代表它在原始数据集中的重要程度。\n核心集的使用通常遵循”构建 -\u003e 求解 -\u003e 映射”的三步范式：\n数据缩减（构建核心集）： 给定一个包含数亿条记录的海量数据集 ，使用一种快速算法（通常是线性的，甚至是亚线性的时间复杂度）从中提取出一个极小的核心集 。核心集中的每个数据点通常会被赋予一个权重（Weight），用来代表它”代表”了原始数据集中的多少个点。 在核心集上运行算法（求解）： 将原来计算复杂度极高（例如 或 ）的机器学习或数据挖掘算法应用到核心集 上。因为 的规模远小于 （例如 有 10 亿个点， 只有 1 万个点），计算时间被成千上万倍地缩短。 结果映射（应用结果）： 将在核心集 上训练出的模型或得到的参数，直接作为原始数据集 的近似最优解。 对每个问题通常都有特定的核心集构建方式，包括分治、几何划分/聚类、贪心、重要性采样等。有一些直观的例子：\n点云最小包围球问题的核心集是临近边界的点（凸性）； k-means 聚类问题的核心集是靠近数据密集区的点；k-means++ 可以作为一个核心集初始化算法，其思想也是很多核心集构建算法的基础。 讲义及作业、考试中有介绍一些核心集的构建方法。(TODO)\n深度学习中核心集的主要应用有：\n持续学习：在历史样本中选择核心集作为记忆。\nYoon 等人提出的准则：小批量相似性、样本多样性、Coreset 亲和性。 池式主动学习：模型主动以 coreset 原则选取重要样本。 生成模型：优化数据子集选取、自适应动态选择数据点等。(Small-GAN) LLM：CoLM 技术。传统 coreset 方法用于语言数据存在 (1) 小数据源样本容易被忽略; (2) Adam 优化器的梯度缩放影响未被考虑; (3) 语言模型维度极高、距离度量容易退化。\nCoLM 提出的三步策略：小数据源样本保留、梯度归一化、梯度维度压缩。 8 最优传输 问题形式：有两个离散归一化分布向量 ，成本矩阵（“距离”），目标是找到一个传输计划（“耦合”）矩阵 满足 （记这类矩阵集合为 ），最小化总运输成本 .\n即：找到一个从分布 到分布 的最优传输计划 ，使得运输成本（由成本矩阵 定义）最小。\n熵正则化：TODO\n应用：\n生成式模型：Flow Matching, Diffusion Model. 领域自适应：在源领域上训练一个模型，利用最优传输将源领域的分布映射到目标领域，从而实现模型在目标领域的迁移。怎么感觉和我们在做的需求有点像，有空认真研究一下。 Wasserstein 鲁棒分布优化：TODO 9 分布式算法 10 Beyond worst case analysis 11 SGD 随机梯度下降 随机梯度下降系列算法目前研究的方向可以分为这四大类：\nVariance Reduction 技术：尽可能缩减随机采样梯度的方差；SAG, SVRG, SAGA 等。 动量法：解决梯度方向来回震荡的问题；Nesterov 加速等。 自适应算法：对不同参数自适应调整学习率；AdaGrad, RMSProp（均方根传播）。 二阶优化方法：基本上没什么人用，只在学术界出现；Hessian 矩阵求逆太慢了（计算量大）；近似又会引入误差，抵消了二阶微分引入的修正；claim 的优势是不受鞍点影响，但实际上动量法、自适应法也能解决。 目前影响力最广泛的算法是结合 2 和 3 的思想提出的 Adam 优化器 (2015)。2024 年 Keller Jordan 在博客中提出了 MUON 算法，\n回顾一下问题背景。我们先形式化一下机器学习想解决的问题：\n其中有误差情形 . 误差分为三部分\n其中 是模型的近似误差（函数空间 自身的缺陷）， 是泛化误差（模型对训练集 外数据分布估计的误差，也取决于函数空间的 VC 维）， 是训练误差（训练方法造成的误差）。SGD 主要关注的是训练误差的优化。\n由于随着函数空间变得复杂时，函数空间会变大从而近似误差会增加，但是 VC 维也会增加，使得泛化误差增大，因此近似误差和泛化误差之间（在 VC 维理论上）存在 trade-off。但是这一 trade-off 在当前的深度学习理论中并不清晰，存在许多实际应用中的反例。\n例子有线性回归、逻辑回归、神经网络等。\n为了保证梯度下降符合预期，人们提出了各种正则化策略，如 Ridge Regression（L2 正则化，=Weight Decay，解决多重共线性问题），Lasso 正则化（L1 正则化）。这些正则化策略能惩罚大的系数，让模型不仅尽可能拟合数据，还要尽量简单（“奥卡姆剃刀”），以减少过拟合风险。可以用偏差-方差分解理论解释（将一部分方差转化为偏差），也可以用贝叶斯先验（认为系数不应过大）解释。\n一般的梯度下降方法形式为：，终止条件为 （注意该终止条件在一些鞍点上也被满足，这是非预期的情形）。其收敛依赖于 Lipschitz 假设和强凸性。\nTable of Contents\n6 VC 维\nVC 维及其几何概念\nVC 维与 PAC Learning\n7 核心集\n8 最优传输\n9 分布式算法\n10 Beyond worst case analysis\n11 SGD 随机梯度下降\nReferences\nReferences [1] 丁虎, “大数据算法讲义.” [Online]. Available: https://hu-ding.github.io/data_pdf/2026/Big_Data_Alg_Draft.pdf ","permalink":"https://rubatotree.github.io/blog/posts/big-data-alg-notes-1/","summary":"\u003cp\u003e这是我在 2026 年春季于中科大学习\u003ca href=\"https://hu-ding.github.io/index.html\" target=\"_blank\" rel=\"noopener noreferrer\"\u003e\u003cspan style=\"color: #59a4ff;\"\u003e\u003cspan style=\"text-decoration: underline\"\u003e丁虎\u003c/span\u003e\u003c/span\u003e\u003c/a\u003e老师的\u003ca href=\"https://hu-ding.github.io/data%20course_2026.html\" target=\"_blank\" rel=\"noopener noreferrer\"\u003e\u003cspan style=\"color: #59a4ff;\"\u003e\u003cspan style=\"text-decoration: underline\"\u003e《大数据算法》\u003c/span\u003e\u003c/span\u003e\u003c/a\u003e课程时整理的期末考试复习笔记。非常喜欢的好课。只是可惜讲义编写得比较潦草。这里的笔记尽可能指出讲义中各种概念的几何意义与机器学习意义，并尝试找出各种定义、定理的动机。\u003c/p\u003e\n    \u003ch2 id=\"loc-1\"\u003e6 VC 维\u003c/h2\u003e\n    \u003ch3 id=\"loc-2\"\u003eVC 维及其几何概念\u003c/h3\u003e\n    \u003cp\u003eVC 维和核心集（coreset）是描述模型表达能力的数学工具。\u003c/p\u003e\n    \u003cp\u003e直观来看，VC 维描述的是一个分类器在任意的正负类指定下，能够区分（称为“打散”）的最大数据点数目。如：\u003c/p\u003e\n    \u003cp\u003e\u003c/p\u003e\n    \u003cul\u003e\n      \u003cli\u003e在二维平面上，二维直线可以打散（不共线的）3 个点，但不能打散（任何分布下的）4 个点，因此二维直线的 VC 维为 3；\u003c/li\u003e\n      \u003cli\u003eX 是二维平面 \u003cspan role=\"math\"\u003e\u003csvg class=\"typst-frame\" style=\"overflow: visible; width: 1.2372999999999998em; height: 0.683em;\" viewBox=\"0 0 16.70355 9.2205\" width=\"16.70355pt\" height=\"9.2205pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:h5=\"http://www.w3.org/1999/xhtml\"\u003e\u003cg\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 0 9.2205)\"\u003e\u003cuse xlink:href=\"#gB56EE940A3E6922E94D0196ED1F53569\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 10.570500000000001 4.320000000000001)\"\u003e\u003cuse xlink:href=\"#g65F6F2B57D840F34A42B9F03EDDAF329\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003c/g\u003e\u003cdefs id=\"glyph\"\u003e\u003csymbol id=\"gB56EE940A3E6922E94D0196ED1F53569\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 8.721001 7.4655004 c 0 -0.4590001 -0.21600056 -1.3905001 -0.7425003 -1.9170003 c -0.3510003 -0.35099983 -1.0665002 -0.783 -2.2815003 -0.783 h -1.5120001 l 0.87750006 3.5235004 c 0.08100033 0.3239994 0.121500015 0.45899963 0.37800026 0.49949932 c 0.121500015 0.013500214 0.5534997 0.013500214 0.8234997 0.013500214 c 0.9585004 0 2.4570007 0 2.4570007 -1.3364997 Z m 1.4714994 -6.21 c 0 0.16199994 -0.1619997 0.16199994 -0.1619997 0.16199994 c -0.121500015 0 -0.14850044 -0.094499946 -0.17549992 -0.18900001 c -0.33750057 -0.999 -0.9180002 -1.2285 -1.2285004 -1.2285 c -0.44550037 0 -0.53999996 0.29700002 -0.53999996 0.82350004 c 0 0.41849995 0.08100033 1.107 0.13500023 1.5389999 c 0.026999474 0.18900013 0.0539999 0.44550014 0.0539999 0.6345 c 0 1.0395 -0.9045 1.458 -1.269 1.5930002 c 1.3634996 0.29699993 2.9700003 1.2420001 2.9700003 2.6055002 c 0 1.1610003 -1.2150002 2.0249996 -2.9835005 2.0249996 h -3.8474998 c -0.27000022 0 -0.3915 0 -0.3915 -0.2699995 c 0 -0.14850044 0.12149978 -0.14850044 0.37799978 -0.14850044 c 0 0 0.2835002 0 0.513 -0.026999474 c 0.24300003 -0.027000427 0.36450005 -0.04050064 0.36450005 -0.21600056 c 0 -0.0539999 -0.013499975 -0.09449959 -0.0539999 -0.25650024 l -1.809 -7.2495 c -0.13499999 -0.5265 -0.16200006 -0.63449997 -1.2285001 -0.63449997 c -0.24300003 0 -0.36450005 0 -0.36450005 -0.26999998 c 0 -0.14850001 0.18900001 -0.14850001 0.18900001 -0.14850001 l 1.701 0.0405 l 1.7145 -0.0405 c 0.10800028 0 0.26999998 0 0.26999998 0.27 c 0 0.1485 -0.121500015 0.1485 -0.37799978 0.1485 c -0.49950004 0 -0.87750006 0 -0.87750006 0.24300003 c 0 0.08099997 0.02699995 0.14849997 0.040499926 0.2295 l 0.89100003 3.5775 h 1.6065001 c 1.2284999 0 1.4714999 -0.75600004 1.4714999 -1.2285001 c 0 -0.20249987 -0.1079998 -0.62100005 -0.18900013 -0.93149996 c -0.094500065 -0.37800002 -0.21600008 -0.87750006 -0.21600008 -1.1475 c 0 -1.4580001 1.6200004 -1.4580001 1.7955003 -1.4580001 c 1.1475 0 1.6199999 1.3635001 1.6199999 1.5525001 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"g65F6F2B57D840F34A42B9F03EDDAF329\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 4.7722497 1.7199 h -0.32130003 c -0.028349876 -0.20790005 -0.12284994 -0.76545006 -0.24569988 -0.85995 c -0.07559967 -0.05670005 -0.80324984 -0.05670005 -0.93555 -0.05670005 h -1.7387998 c 0.99224997 0.87885 1.323 1.14345 1.8899999 1.5875999 c 0.6992998 0.5575502 1.3513498 1.14345 1.3513498 2.0412 c 0 1.1434503 -1.0016997 1.8427501 -2.2112997 1.8427501 c -1.1718 0 -1.9656 -0.82214975 -1.9656 -1.6915498 c 0 -0.48195028 0.40634996 -0.5292001 0.50085 -0.5292001 c 0.22679996 0 0.50084996 0.16064978 0.50084996 0.5008497 c 0 0.17010021 -0.06614995 0.5008502 -0.55754995 0.5008502 c 0.29294991 0.67094994 0.93555 0.87885 1.3797 0.87885 c 0.94499993 0 1.4363999 -0.7371001 1.4363999 -1.5025501 c 0 -0.82214975 -0.58590007 -1.4741998 -0.88829994 -1.8143997 l -2.27745 -2.2491 c -0.094500005 -0.08505002 -0.094500005 -0.10395002 -0.094500005 -0.36855 h 3.8934 Z \"/\u003e\u003c/symbol\u003e\u003c/defs\u003e\u003c/svg\u003e\u003c/span\u003e，\u003cspan role=\"math\"\u003e\u003csvg class=\"typst-frame\" style=\"overflow: visible; width: 0.464em; height: 0.683em;\" viewBox=\"0 0 6.264 9.2205\" width=\"6.264pt\" height=\"9.2205pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:h5=\"http://www.w3.org/1999/xhtml\"\u003e\u003cg\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 0 9.2205)\"\u003e\u003cuse xlink:href=\"#g17CCB208AFBDD552FDFF541EA6E6D9E1\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003c/g\u003e\u003cdefs id=\"glyph\"\u003e\u003csymbol id=\"g17CCB208AFBDD552FDFF541EA6E6D9E1\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 5.886 5.0895 c 0 0.47250032 -0.43200016 0.87750006 -1.1205001 0.87750006 c -0.87750006 0 -1.4714999 -0.6615 -1.7279999 -1.0394998 c -0.10800004 0.6075001 -0.5940001 1.0394998 -1.2285001 1.0394998 c -0.62099993 0 -0.8775 -0.52649975 -0.999 -0.7694998 c -0.24299997 -0.4590001 -0.4185 -1.269 -0.4185 -1.3095002 c 0 -0.13499999 0.162 -0.13499999 0.162 -0.13499999 c 0.13500005 0 0.14850003 0.013499975 0.2295 0.3104999 c 0.22950006 0.9585004 0.49950004 1.6065001 0.9855001 1.6065001 c 0.22949994 0 0.41849995 -0.1079998 0.41849995 -0.6209998 c 0 -0.2835002 -0.040499926 -0.43200016 -0.21599996 -1.1340001 l -0.783 -3.1185002 c -0.040500045 -0.20249999 -0.121500015 -0.513 -0.121500015 -0.5805 c 0 -0.243 0.18900001 -0.36450002 0.3915 -0.36450002 c 0.16199994 0 0.40499997 0.10800001 0.49950004 0.37800002 c 0.02699995 0.054000005 0.48599994 1.8900001 0.5400001 2.133 l 0.43199992 1.7550004 c 0.0539999 0.17549992 0.43199992 0.80999994 0.75600004 1.1069999 c 0.10800004 0.094500065 0.4994998 0.4454999 1.0799999 0.4454999 c 0.35099983 0 0.5669999 -0.1619997 0.5669999 -0.1619997 c -0.40499973 -0.067500114 -0.70199966 -0.39150047 -0.70199966 -0.7425003 c 0 -0.21600008 0.14849997 -0.47249985 0.513 -0.47249985 c 0.36450005 0 0.7424998 0.31049967 0.7424998 0.7964997 Z \"/\u003e\u003c/symbol\u003e\u003c/defs\u003e\u003c/svg\u003e\u003c/span\u003e 是二维平面里的一个圆，那么 \u003cspan role=\"math\"\u003e\u003csvg class=\"typst-frame\" style=\"overflow: visible; width: 4.805555555555555em; height: 0.683em;\" viewBox=\"0 0 64.875 9.2205\" width=\"64.875pt\" height=\"9.2205pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:h5=\"http://www.w3.org/1999/xhtml\"\u003e\u003cg\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 0 9.2205)\"\u003e\u003cuse xlink:href=\"#gC216693D542D21E8E95CCCBC7495D99D\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003cuse xlink:href=\"#g6A56BD9E561F51C1AB29E4EAF58998F8\" x=\"10.125\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 19.871999999999996 9.2205)\"\u003e\u003cuse xlink:href=\"#gD54FB5694EC3FB5580CAE2E45CF230CB\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 25.1235 9.2205)\"\u003e\u003cuse xlink:href=\"#gC66649BF7054B405FEFD6EC249209D4C\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 34.8705 9.2205)\"\u003e\u003cuse xlink:href=\"#g8F0E7B478F08A2A3FD91F1F9F636BFE0\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 43.872 9.2205)\"\u003e\u003cuse xlink:href=\"#g78FD1D260678866025A88F528D8C9299\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 58.125 9.2205)\"\u003e\u003cuse xlink:href=\"#gE4A210D8FB7C5316135AEE56DDD63584\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003c/g\u003e\u003cdefs id=\"glyph\"\u003e\u003csymbol id=\"gC216693D542D21E8E95CCCBC7495D99D\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 9.8550005 8.802 v 0.41849995 c -0.41849995 -0.026999474 -0.9584999 -0.040499687 -1.3095007 -0.040499687 l -1.5389996 0.040499687 v -0.41849995 c 0.70200014 -0.013500214 0.98549986 -0.36450005 0.98549986 -0.6750002 c 0 -0.1079998 -0.040499687 -0.18899965 -0.067500114 -0.2699995 l -2.4705 -6.5070004 l -2.5785 6.8175006 c -0.08099985 0.18900013 -0.08099985 0.24300003 -0.08099985 0.24300003 c 0 0.39149952 0.7695 0.39149952 1.1069999 0.39149952 v 0.41849995 c -0.48599982 -0.040499687 -1.4175 -0.040499687 -1.9304999 -0.040499687 l -1.7145001 0.040499687 v -0.41849995 c 0.87750006 0 1.1340001 0 1.3230001 -0.51299953 l 3.132 -8.2890005 c 0.094500065 -0.2565 0.16200018 -0.29700002 0.3375001 -0.29700002 c 0.22949982 0 0.25649977 0.06750001 0.32399988 0.2565 l 3.0105 7.938 c 0.18900013 0.49950027 0.5535002 0.8909998 1.4715004 0.9045 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"g6A56BD9E561F51C1AB29E4EAF58998F8\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 8.9775 3.1455002 c 0 0.13499999 0 0.22949982 -0.17549992 0.22949982 c -0.14849949 0 -0.14849949 -0.08099985 -0.1619997 -0.21599984 c -0.1079998 -1.9305001 -1.5525002 -3.0375001 -3.0240002 -3.0375001 c -0.82350016 0 -3.4695 0.459 -3.4695 4.482 c 0 4.0365005 2.6325002 4.4955 3.4559999 4.4955 c 1.4715004 0 2.6730003 -1.2284999 2.9429998 -3.1994996 c 0.027000427 -0.18900013 0.027000427 -0.2295003 0.21600056 -0.2295003 c 0.2159996 0 0.2159996 0.040500164 0.2159996 0.32399988 v 3.1995006 c 0 0.22949982 0 0.3239994 -0.14849949 0.3239994 c -0.0539999 0 -0.1079998 0 -0.21600056 -0.1619997 l -0.6749997 -0.9989996 c -0.4994998 0.48600006 -1.1880002 1.1609993 -2.4840002 1.1609993 c -2.5245 0 -4.698 -2.1464996 -4.698 -4.9005 c 0 -2.7945 2.187 -4.914 4.698 -4.914 c 2.2005 0 3.5235 1.8765001 3.5235 3.4425 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"gD54FB5694EC3FB5580CAE2E45CF230CB\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 4.4820004 -3.213 c 0 0.040499926 -0.027000427 0.08100009 -0.054000378 0.10800004 c -1.4039998 1.053 -2.3355 3.753 -2.3355 5.913 v 1.1340001 c 0 2.16 0.9315002 4.8599997 2.3355 5.913 c 0.02699995 0.026999474 0.054000378 0.067500114 0.054000378 0.1079998 c 0 0.067500114 -0.067500114 0.13500023 -0.13500023 0.13500023 c -0.02699995 0 -0.0539999 -0.013500214 -0.08099985 -0.027000427 c -1.4850001 -1.1204996 -2.9025002 -3.8205 -2.9025002 -6.1289997 v -1.1340001 c 0 -2.3085 1.4175001 -5.0085 2.9025002 -6.129 c 0.02699995 -0.013499975 0.0539999 -0.02699995 0.08099985 -0.02699995 c 0.067500114 0 0.13500023 0.067499876 0.13500023 0.13499999 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"gC66649BF7054B405FEFD6EC249209D4C\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 8.9775 3.186 h -0.33749962 c -0.24300003 -2.2545002 -1.1610003 -2.619 -3.2805004 -2.619 h -3.7259998 l 3.3885002 3.834 c 0.121500015 0.13500023 0.121500015 0.21600008 0.121500015 0.21600008 c 0 0.067500114 -0.054000378 0.13500023 -0.094500065 0.18900013 l -2.7675002 3.9959998 h 3.1185 c 2.2815003 0 2.9565005 -0.48600006 3.2400002 -2.619 h 0.33749962 l -0.3779993 3.0375 h -7.492501 c -0.324 0 -0.35099995 0 -0.35099995 -0.31050014 l 3.3615003 -4.8869996 l -3.2130003 -3.6585002 c -0.13499999 -0.14850001 -0.13499999 -0.1755 -0.13499999 -0.216 c 0 -0.14850001 0.13499999 -0.14850001 0.33749998 -0.14850001 h 7.492501 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"g8F0E7B478F08A2A3FD91F1F9F636BFE0\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 3.888 2.808 v 1.1340001 c 0 2.3085 -1.4175 5.0085 -2.9025 6.1289997 c -0.02700001 0.013500214 -0.05400002 0.027000427 -0.08100003 0.027000427 c -0.067499995 0 -0.13499999 -0.067500114 -0.13499999 -0.13500023 c 0 -0.040499687 0.02700001 -0.08100033 0.05400002 -0.1079998 c 1.4039999 -1.0530005 2.3355002 -3.7530003 2.3355002 -5.913 v -1.1340001 c 0 -2.16 -0.9315002 -4.86 -2.3355002 -5.913 c -0.02700001 -0.02699995 -0.05400002 -0.067500114 -0.05400002 -0.10800004 c 0 -0.067500114 0.067499995 -0.13499999 0.13499999 -0.13499999 c 0.02700001 0 0.05400002 0.013499975 0.08100003 0.02699995 c 1.4849999 1.1205001 2.9025 3.8205001 2.9025 6.129 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"g78FD1D260678866025A88F528D8C9299\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 9.747001 4.6845 c 0 0.14849997 -0.121500015 0.26999998 -0.27000046 0.26999998 h -8.451 c -0.14850003 0 -0.26999998 -0.121500015 -0.26999998 -0.26999998 c 0 -0.14849997 0.121499956 -0.26999998 0.26999998 -0.26999998 h 8.451 c 0.14850044 0 0.27000046 0.121500015 0.27000046 0.26999998 Z m 0 -2.6190002 c 0 0.14849997 -0.121500015 0.26999998 -0.27000046 0.26999998 h -8.451 c -0.14850003 0 -0.26999998 -0.121500015 -0.26999998 -0.26999998 c 0 -0.14849997 0.121499956 -0.26999998 0.26999998 -0.26999998 h 8.451 c 0.14850044 0 0.27000046 0.121500015 0.27000046 0.26999998 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"gE4A210D8FB7C5316135AEE56DDD63584\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 6.1695004 2.3085 c 0 1.1070001 -0.8505001 2.16 -2.2545002 2.4435003 c 1.1070001 0.36449957 1.8900001 1.3094997 1.8900001 2.376 c 0 1.1070004 -1.1880002 1.8629999 -2.4840002 1.8629999 c -1.3635 0 -2.3895001 -0.8100004 -2.3895001 -1.836 c 0 -0.4454999 0.297 -0.70200014 0.6885 -0.70200014 c 0.41850007 0 0.68850005 0.29699993 0.68850005 0.6884999 c 0 0.6750002 -0.6345 0.6750002 -0.837 0.6750002 c 0.41850007 0.66150045 1.3095001 0.83700037 1.7955002 0.83700037 c 0.55349994 0 1.296 -0.29699993 1.296 -1.5120006 c 0 -0.1619997 -0.02699995 -0.9449997 -0.37800026 -1.539 c -0.40499973 -0.64799976 -0.86399984 -0.6884999 -1.2014999 -0.70199966 c -0.10800004 -0.013500214 -0.43199992 -0.040500164 -0.5265 -0.040500164 c -0.10800004 -0.013500214 -0.20249987 -0.02699995 -0.20249987 -0.16200018 c 0 -0.14849997 0.09449983 -0.14849997 0.32399988 -0.14849997 h 0.5940001 c 1.1069999 0 1.6065001 -0.918 1.6065001 -2.241 c 0 -1.836 -0.9315002 -2.2275 -1.5255003 -2.2275 c -0.5804999 0 -1.5929999 0.2295 -2.0654998 1.026 c 0.47249997 -0.067499995 0.8909999 0.22950006 0.8909999 0.74250007 c 0 0.48599994 -0.36449993 0.7559999 -0.7559999 0.7559999 c -0.32400006 0 -0.75600004 -0.18899989 -0.75600004 -0.783 c 0 -1.2284999 1.2555 -2.1195 2.7270002 -2.1195 c 1.6469998 0 2.8755002 1.2285 2.8755002 2.6055 Z \"/\u003e\u003c/symbol\u003e\u003c/defs\u003e\u003c/svg\u003e\u003c/span\u003e\u003c/li\u003e\n      \u003cli\u003eX 是三维平面 \u003cspan role=\"math\"\u003e\u003csvg class=\"typst-frame\" style=\"overflow: visible; width: 1.2372999999999998em; height: 0.683em;\" viewBox=\"0 0 16.70355 9.2205\" width=\"16.70355pt\" height=\"9.2205pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:h5=\"http://www.w3.org/1999/xhtml\"\u003e\u003cg\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 0 9.2205)\"\u003e\u003cuse xlink:href=\"#gB56EE940A3E6922E94D0196ED1F53569\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 10.570500000000001 4.320000000000001)\"\u003e\u003cuse xlink:href=\"#g5A4E2D0D0C30B609F94551681EE26848\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003c/g\u003e\u003cdefs id=\"glyph\"\u003e\u003csymbol id=\"gB56EE940A3E6922E94D0196ED1F53569\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 8.721001 7.4655004 c 0 -0.4590001 -0.21600056 -1.3905001 -0.7425003 -1.9170003 c -0.3510003 -0.35099983 -1.0665002 -0.783 -2.2815003 -0.783 h -1.5120001 l 0.87750006 3.5235004 c 0.08100033 0.3239994 0.121500015 0.45899963 0.37800026 0.49949932 c 0.121500015 0.013500214 0.5534997 0.013500214 0.8234997 0.013500214 c 0.9585004 0 2.4570007 0 2.4570007 -1.3364997 Z m 1.4714994 -6.21 c 0 0.16199994 -0.1619997 0.16199994 -0.1619997 0.16199994 c -0.121500015 0 -0.14850044 -0.094499946 -0.17549992 -0.18900001 c -0.33750057 -0.999 -0.9180002 -1.2285 -1.2285004 -1.2285 c -0.44550037 0 -0.53999996 0.29700002 -0.53999996 0.82350004 c 0 0.41849995 0.08100033 1.107 0.13500023 1.5389999 c 0.026999474 0.18900013 0.0539999 0.44550014 0.0539999 0.6345 c 0 1.0395 -0.9045 1.458 -1.269 1.5930002 c 1.3634996 0.29699993 2.9700003 1.2420001 2.9700003 2.6055002 c 0 1.1610003 -1.2150002 2.0249996 -2.9835005 2.0249996 h -3.8474998 c -0.27000022 0 -0.3915 0 -0.3915 -0.2699995 c 0 -0.14850044 0.12149978 -0.14850044 0.37799978 -0.14850044 c 0 0 0.2835002 0 0.513 -0.026999474 c 0.24300003 -0.027000427 0.36450005 -0.04050064 0.36450005 -0.21600056 c 0 -0.0539999 -0.013499975 -0.09449959 -0.0539999 -0.25650024 l -1.809 -7.2495 c -0.13499999 -0.5265 -0.16200006 -0.63449997 -1.2285001 -0.63449997 c -0.24300003 0 -0.36450005 0 -0.36450005 -0.26999998 c 0 -0.14850001 0.18900001 -0.14850001 0.18900001 -0.14850001 l 1.701 0.0405 l 1.7145 -0.0405 c 0.10800028 0 0.26999998 0 0.26999998 0.27 c 0 0.1485 -0.121500015 0.1485 -0.37799978 0.1485 c -0.49950004 0 -0.87750006 0 -0.87750006 0.24300003 c 0 0.08099997 0.02699995 0.14849997 0.040499926 0.2295 l 0.89100003 3.5775 h 1.6065001 c 1.2284999 0 1.4714999 -0.75600004 1.4714999 -1.2285001 c 0 -0.20249987 -0.1079998 -0.62100005 -0.18900013 -0.93149996 c -0.094500065 -0.37800002 -0.21600008 -0.87750006 -0.21600008 -1.1475 c 0 -1.4580001 1.6200004 -1.4580001 1.7955003 -1.4580001 c 1.1475 0 1.6199999 1.3635001 1.6199999 1.5525001 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"g5A4E2D0D0C30B609F94551681EE26848\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 4.8573 1.6348499 c 0 0.7371 -0.60479975 1.4742001 -1.6443 1.6915499 c 0.99224997 0.3591001 1.3513503 1.0678501 1.3513503 1.6443 c 0 0.7465501 -0.8599503 1.3041 -1.9089003 1.3041 c -1.04895 0 -1.8521999 -0.51030016 -1.8521999 -1.2662997 c 0 -0.32130003 0.20790005 -0.5008502 0.4914 -0.5008502 c 0.29295003 0 0.48195004 0.21735 0.48195004 0.4819498 c 0 0.27405024 -0.18900001 0.47250032 -0.48195004 0.49140024 c 0.33075 0.4158001 0.9827999 0.5197501 1.33245 0.5197501 c 0.42525005 0 1.0205998 -0.20790005 1.0205998 -1.0300503 c 0 -0.3968997 -0.1322999 -0.8315997 -0.37800002 -1.1245499 c -0.31184983 -0.3591001 -0.5764499 -0.37800002 -1.04895 -0.4063499 c -0.23624992 -0.018900156 -0.25514984 -0.018900156 -0.30239987 -0.028350115 c 0 0 -0.094500065 -0.018899918 -0.094500065 -0.12284994 c 0 -0.13230014 0.08504999 -0.13230014 0.24570012 -0.13230014 h 0.5102999 c 0.7370999 0 1.2663 -0.5102999 1.2663 -1.5214499 c 0 -1.1717999 -0.6803999 -1.5214499 -1.2284999 -1.5214499 c -0.37800002 0 -1.2096001 0.103949994 -1.6065 0.6615 c 0.44414997 0.018900037 0.5481 0.33075 0.5481 0.52919996 c 0 0.3024 -0.22680008 0.51975 -0.51975 0.51975 c -0.26460004 0 -0.5292 -0.16065001 -0.5292 -0.5481 c 0 -0.88829994 0.98279995 -1.4647499 2.12625 -1.4647499 c 1.31355 0 2.2207499 0.87885 2.2207499 1.8238499 Z \"/\u003e\u003c/symbol\u003e\u003c/defs\u003e\u003c/svg\u003e\u003c/span\u003e，\u003cspan role=\"math\"\u003e\u003csvg class=\"typst-frame\" style=\"overflow: visible; width: 0.464em; height: 0.683em;\" viewBox=\"0 0 6.264 9.2205\" width=\"6.264pt\" height=\"9.2205pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:h5=\"http://www.w3.org/1999/xhtml\"\u003e\u003cg\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 0 9.2205)\"\u003e\u003cuse xlink:href=\"#g17CCB208AFBDD552FDFF541EA6E6D9E1\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003c/g\u003e\u003cdefs id=\"glyph\"\u003e\u003csymbol id=\"g17CCB208AFBDD552FDFF541EA6E6D9E1\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 5.886 5.0895 c 0 0.47250032 -0.43200016 0.87750006 -1.1205001 0.87750006 c -0.87750006 0 -1.4714999 -0.6615 -1.7279999 -1.0394998 c -0.10800004 0.6075001 -0.5940001 1.0394998 -1.2285001 1.0394998 c -0.62099993 0 -0.8775 -0.52649975 -0.999 -0.7694998 c -0.24299997 -0.4590001 -0.4185 -1.269 -0.4185 -1.3095002 c 0 -0.13499999 0.162 -0.13499999 0.162 -0.13499999 c 0.13500005 0 0.14850003 0.013499975 0.2295 0.3104999 c 0.22950006 0.9585004 0.49950004 1.6065001 0.9855001 1.6065001 c 0.22949994 0 0.41849995 -0.1079998 0.41849995 -0.6209998 c 0 -0.2835002 -0.040499926 -0.43200016 -0.21599996 -1.1340001 l -0.783 -3.1185002 c -0.040500045 -0.20249999 -0.121500015 -0.513 -0.121500015 -0.5805 c 0 -0.243 0.18900001 -0.36450002 0.3915 -0.36450002 c 0.16199994 0 0.40499997 0.10800001 0.49950004 0.37800002 c 0.02699995 0.054000005 0.48599994 1.8900001 0.5400001 2.133 l 0.43199992 1.7550004 c 0.0539999 0.17549992 0.43199992 0.80999994 0.75600004 1.1069999 c 0.10800004 0.094500065 0.4994998 0.4454999 1.0799999 0.4454999 c 0.35099983 0 0.5669999 -0.1619997 0.5669999 -0.1619997 c -0.40499973 -0.067500114 -0.70199966 -0.39150047 -0.70199966 -0.7425003 c 0 -0.21600008 0.14849997 -0.47249985 0.513 -0.47249985 c 0.36450005 0 0.7424998 0.31049967 0.7424998 0.7964997 Z \"/\u003e\u003c/symbol\u003e\u003c/defs\u003e\u003c/svg\u003e\u003c/span\u003e 是三维平面里的一个球，那么 \u003cspan role=\"math\"\u003e\u003csvg class=\"typst-frame\" style=\"overflow: visible; width: 4.805555555555555em; height: 0.683em;\" viewBox=\"0 0 64.875 9.2205\" width=\"64.875pt\" height=\"9.2205pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:h5=\"http://www.w3.org/1999/xhtml\"\u003e\u003cg\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 0 9.2205)\"\u003e\u003cuse xlink:href=\"#gC216693D542D21E8E95CCCBC7495D99D\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003cuse xlink:href=\"#g6A56BD9E561F51C1AB29E4EAF58998F8\" x=\"10.125\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 19.871999999999996 9.2205)\"\u003e\u003cuse xlink:href=\"#gD54FB5694EC3FB5580CAE2E45CF230CB\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 25.1235 9.2205)\"\u003e\u003cuse xlink:href=\"#gC66649BF7054B405FEFD6EC249209D4C\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 34.8705 9.2205)\"\u003e\u003cuse xlink:href=\"#g8F0E7B478F08A2A3FD91F1F9F636BFE0\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 43.872 9.2205)\"\u003e\u003cuse xlink:href=\"#g78FD1D260678866025A88F528D8C9299\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 58.125 9.2205)\"\u003e\u003cuse xlink:href=\"#g7349D0C44BFB012D5A2A1F8B0A0C3F45\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003c/g\u003e\u003cdefs id=\"glyph\"\u003e\u003csymbol id=\"gC216693D542D21E8E95CCCBC7495D99D\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 9.8550005 8.802 v 0.41849995 c -0.41849995 -0.026999474 -0.9584999 -0.040499687 -1.3095007 -0.040499687 l -1.5389996 0.040499687 v -0.41849995 c 0.70200014 -0.013500214 0.98549986 -0.36450005 0.98549986 -0.6750002 c 0 -0.1079998 -0.040499687 -0.18899965 -0.067500114 -0.2699995 l -2.4705 -6.5070004 l -2.5785 6.8175006 c -0.08099985 0.18900013 -0.08099985 0.24300003 -0.08099985 0.24300003 c 0 0.39149952 0.7695 0.39149952 1.1069999 0.39149952 v 0.41849995 c -0.48599982 -0.040499687 -1.4175 -0.040499687 -1.9304999 -0.040499687 l -1.7145001 0.040499687 v -0.41849995 c 0.87750006 0 1.1340001 0 1.3230001 -0.51299953 l 3.132 -8.2890005 c 0.094500065 -0.2565 0.16200018 -0.29700002 0.3375001 -0.29700002 c 0.22949982 0 0.25649977 0.06750001 0.32399988 0.2565 l 3.0105 7.938 c 0.18900013 0.49950027 0.5535002 0.8909998 1.4715004 0.9045 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"g6A56BD9E561F51C1AB29E4EAF58998F8\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 8.9775 3.1455002 c 0 0.13499999 0 0.22949982 -0.17549992 0.22949982 c -0.14849949 0 -0.14849949 -0.08099985 -0.1619997 -0.21599984 c -0.1079998 -1.9305001 -1.5525002 -3.0375001 -3.0240002 -3.0375001 c -0.82350016 0 -3.4695 0.459 -3.4695 4.482 c 0 4.0365005 2.6325002 4.4955 3.4559999 4.4955 c 1.4715004 0 2.6730003 -1.2284999 2.9429998 -3.1994996 c 0.027000427 -0.18900013 0.027000427 -0.2295003 0.21600056 -0.2295003 c 0.2159996 0 0.2159996 0.040500164 0.2159996 0.32399988 v 3.1995006 c 0 0.22949982 0 0.3239994 -0.14849949 0.3239994 c -0.0539999 0 -0.1079998 0 -0.21600056 -0.1619997 l -0.6749997 -0.9989996 c -0.4994998 0.48600006 -1.1880002 1.1609993 -2.4840002 1.1609993 c -2.5245 0 -4.698 -2.1464996 -4.698 -4.9005 c 0 -2.7945 2.187 -4.914 4.698 -4.914 c 2.2005 0 3.5235 1.8765001 3.5235 3.4425 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"gD54FB5694EC3FB5580CAE2E45CF230CB\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 4.4820004 -3.213 c 0 0.040499926 -0.027000427 0.08100009 -0.054000378 0.10800004 c -1.4039998 1.053 -2.3355 3.753 -2.3355 5.913 v 1.1340001 c 0 2.16 0.9315002 4.8599997 2.3355 5.913 c 0.02699995 0.026999474 0.054000378 0.067500114 0.054000378 0.1079998 c 0 0.067500114 -0.067500114 0.13500023 -0.13500023 0.13500023 c -0.02699995 0 -0.0539999 -0.013500214 -0.08099985 -0.027000427 c -1.4850001 -1.1204996 -2.9025002 -3.8205 -2.9025002 -6.1289997 v -1.1340001 c 0 -2.3085 1.4175001 -5.0085 2.9025002 -6.129 c 0.02699995 -0.013499975 0.0539999 -0.02699995 0.08099985 -0.02699995 c 0.067500114 0 0.13500023 0.067499876 0.13500023 0.13499999 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"gC66649BF7054B405FEFD6EC249209D4C\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 8.9775 3.186 h -0.33749962 c -0.24300003 -2.2545002 -1.1610003 -2.619 -3.2805004 -2.619 h -3.7259998 l 3.3885002 3.834 c 0.121500015 0.13500023 0.121500015 0.21600008 0.121500015 0.21600008 c 0 0.067500114 -0.054000378 0.13500023 -0.094500065 0.18900013 l -2.7675002 3.9959998 h 3.1185 c 2.2815003 0 2.9565005 -0.48600006 3.2400002 -2.619 h 0.33749962 l -0.3779993 3.0375 h -7.492501 c -0.324 0 -0.35099995 0 -0.35099995 -0.31050014 l 3.3615003 -4.8869996 l -3.2130003 -3.6585002 c -0.13499999 -0.14850001 -0.13499999 -0.1755 -0.13499999 -0.216 c 0 -0.14850001 0.13499999 -0.14850001 0.33749998 -0.14850001 h 7.492501 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"g8F0E7B478F08A2A3FD91F1F9F636BFE0\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 3.888 2.808 v 1.1340001 c 0 2.3085 -1.4175 5.0085 -2.9025 6.1289997 c -0.02700001 0.013500214 -0.05400002 0.027000427 -0.08100003 0.027000427 c -0.067499995 0 -0.13499999 -0.067500114 -0.13499999 -0.13500023 c 0 -0.040499687 0.02700001 -0.08100033 0.05400002 -0.1079998 c 1.4039999 -1.0530005 2.3355002 -3.7530003 2.3355002 -5.913 v -1.1340001 c 0 -2.16 -0.9315002 -4.86 -2.3355002 -5.913 c -0.02700001 -0.02699995 -0.05400002 -0.067500114 -0.05400002 -0.10800004 c 0 -0.067500114 0.067499995 -0.13499999 0.13499999 -0.13499999 c 0.02700001 0 0.05400002 0.013499975 0.08100003 0.02699995 c 1.4849999 1.1205001 2.9025 3.8205001 2.9025 6.129 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"g78FD1D260678866025A88F528D8C9299\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 9.747001 4.6845 c 0 0.14849997 -0.121500015 0.26999998 -0.27000046 0.26999998 h -8.451 c -0.14850003 0 -0.26999998 -0.121500015 -0.26999998 -0.26999998 c 0 -0.14849997 0.121499956 -0.26999998 0.26999998 -0.26999998 h 8.451 c 0.14850044 0 0.27000046 0.121500015 0.27000046 0.26999998 Z m 0 -2.6190002 c 0 0.14849997 -0.121500015 0.26999998 -0.27000046 0.26999998 h -8.451 c -0.14850003 0 -0.26999998 -0.121500015 -0.26999998 -0.26999998 c 0 -0.14849997 0.121499956 -0.26999998 0.26999998 -0.26999998 h 8.451 c 0.14850044 0 0.27000046 0.121500015 0.27000046 0.26999998 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"g7349D0C44BFB012D5A2A1F8B0A0C3F45\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 6.3585 2.2275 v 0.41850019 h -1.3499999 v 6.1425 c 0 0.27000046 0 0.3510008 -0.21600008 0.3510008 c -0.121500015 0 -0.1619997 0 -0.26999998 -0.16200066 l -4.1445 -6.3315 v -0.41850019 h 3.591 v -1.1745 c 0 -0.48599994 -0.02699995 -0.63449997 -1.026 -0.63449997 h -0.28349996 v -0.4185 c 0.55349994 0.0405 1.2555001 0.0405 1.8225002 0.0405 c 0.5669999 0 1.2824998 0 1.836 -0.0405 v 0.4185 h -0.2835002 c -0.9990001 0 -1.026 0.14850003 -1.026 0.63449997 v 1.1745 Z m -2.3084998 0.41850019 h -3.2940001 l 3.2940001 5.0355005 Z \"/\u003e\u003c/symbol\u003e\u003c/defs\u003e\u003c/svg\u003e\u003c/span\u003e\u003c/li\u003e\n      \u003cli\u003eX 是二维平面 \u003cspan role=\"math\"\u003e\u003csvg class=\"typst-frame\" style=\"overflow: visible; width: 1.2372999999999998em; height: 0.683em;\" viewBox=\"0 0 16.70355 9.2205\" width=\"16.70355pt\" height=\"9.2205pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:h5=\"http://www.w3.org/1999/xhtml\"\u003e\u003cg\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 0 9.2205)\"\u003e\u003cuse xlink:href=\"#gB56EE940A3E6922E94D0196ED1F53569\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 10.570500000000001 4.320000000000001)\"\u003e\u003cuse xlink:href=\"#g65F6F2B57D840F34A42B9F03EDDAF329\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003c/g\u003e\u003cdefs id=\"glyph\"\u003e\u003csymbol id=\"gB56EE940A3E6922E94D0196ED1F53569\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 8.721001 7.4655004 c 0 -0.4590001 -0.21600056 -1.3905001 -0.7425003 -1.9170003 c -0.3510003 -0.35099983 -1.0665002 -0.783 -2.2815003 -0.783 h -1.5120001 l 0.87750006 3.5235004 c 0.08100033 0.3239994 0.121500015 0.45899963 0.37800026 0.49949932 c 0.121500015 0.013500214 0.5534997 0.013500214 0.8234997 0.013500214 c 0.9585004 0 2.4570007 0 2.4570007 -1.3364997 Z m 1.4714994 -6.21 c 0 0.16199994 -0.1619997 0.16199994 -0.1619997 0.16199994 c -0.121500015 0 -0.14850044 -0.094499946 -0.17549992 -0.18900001 c -0.33750057 -0.999 -0.9180002 -1.2285 -1.2285004 -1.2285 c -0.44550037 0 -0.53999996 0.29700002 -0.53999996 0.82350004 c 0 0.41849995 0.08100033 1.107 0.13500023 1.5389999 c 0.026999474 0.18900013 0.0539999 0.44550014 0.0539999 0.6345 c 0 1.0395 -0.9045 1.458 -1.269 1.5930002 c 1.3634996 0.29699993 2.9700003 1.2420001 2.9700003 2.6055002 c 0 1.1610003 -1.2150002 2.0249996 -2.9835005 2.0249996 h -3.8474998 c -0.27000022 0 -0.3915 0 -0.3915 -0.2699995 c 0 -0.14850044 0.12149978 -0.14850044 0.37799978 -0.14850044 c 0 0 0.2835002 0 0.513 -0.026999474 c 0.24300003 -0.027000427 0.36450005 -0.04050064 0.36450005 -0.21600056 c 0 -0.0539999 -0.013499975 -0.09449959 -0.0539999 -0.25650024 l -1.809 -7.2495 c -0.13499999 -0.5265 -0.16200006 -0.63449997 -1.2285001 -0.63449997 c -0.24300003 0 -0.36450005 0 -0.36450005 -0.26999998 c 0 -0.14850001 0.18900001 -0.14850001 0.18900001 -0.14850001 l 1.701 0.0405 l 1.7145 -0.0405 c 0.10800028 0 0.26999998 0 0.26999998 0.27 c 0 0.1485 -0.121500015 0.1485 -0.37799978 0.1485 c -0.49950004 0 -0.87750006 0 -0.87750006 0.24300003 c 0 0.08099997 0.02699995 0.14849997 0.040499926 0.2295 l 0.89100003 3.5775 h 1.6065001 c 1.2284999 0 1.4714999 -0.75600004 1.4714999 -1.2285001 c 0 -0.20249987 -0.1079998 -0.62100005 -0.18900013 -0.93149996 c -0.094500065 -0.37800002 -0.21600008 -0.87750006 -0.21600008 -1.1475 c 0 -1.4580001 1.6200004 -1.4580001 1.7955003 -1.4580001 c 1.1475 0 1.6199999 1.3635001 1.6199999 1.5525001 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"g65F6F2B57D840F34A42B9F03EDDAF329\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 4.7722497 1.7199 h -0.32130003 c -0.028349876 -0.20790005 -0.12284994 -0.76545006 -0.24569988 -0.85995 c -0.07559967 -0.05670005 -0.80324984 -0.05670005 -0.93555 -0.05670005 h -1.7387998 c 0.99224997 0.87885 1.323 1.14345 1.8899999 1.5875999 c 0.6992998 0.5575502 1.3513498 1.14345 1.3513498 2.0412 c 0 1.1434503 -1.0016997 1.8427501 -2.2112997 1.8427501 c -1.1718 0 -1.9656 -0.82214975 -1.9656 -1.6915498 c 0 -0.48195028 0.40634996 -0.5292001 0.50085 -0.5292001 c 0.22679996 0 0.50084996 0.16064978 0.50084996 0.5008497 c 0 0.17010021 -0.06614995 0.5008502 -0.55754995 0.5008502 c 0.29294991 0.67094994 0.93555 0.87885 1.3797 0.87885 c 0.94499993 0 1.4363999 -0.7371001 1.4363999 -1.5025501 c 0 -0.82214975 -0.58590007 -1.4741998 -0.88829994 -1.8143997 l -2.27745 -2.2491 c -0.094500005 -0.08505002 -0.094500005 -0.10395002 -0.094500005 -0.36855 h 3.8934 Z \"/\u003e\u003c/symbol\u003e\u003c/defs\u003e\u003c/svg\u003e\u003c/span\u003e，\u003cspan role=\"math\"\u003e\u003csvg class=\"typst-frame\" style=\"overflow: visible; width: 0.464em; height: 0.683em;\" viewBox=\"0 0 6.264 9.2205\" width=\"6.264pt\" height=\"9.2205pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:h5=\"http://www.w3.org/1999/xhtml\"\u003e\u003cg\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 0 9.2205)\"\u003e\u003cuse xlink:href=\"#g17CCB208AFBDD552FDFF541EA6E6D9E1\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003c/g\u003e\u003cdefs id=\"glyph\"\u003e\u003csymbol id=\"g17CCB208AFBDD552FDFF541EA6E6D9E1\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 5.886 5.0895 c 0 0.47250032 -0.43200016 0.87750006 -1.1205001 0.87750006 c -0.87750006 0 -1.4714999 -0.6615 -1.7279999 -1.0394998 c -0.10800004 0.6075001 -0.5940001 1.0394998 -1.2285001 1.0394998 c -0.62099993 0 -0.8775 -0.52649975 -0.999 -0.7694998 c -0.24299997 -0.4590001 -0.4185 -1.269 -0.4185 -1.3095002 c 0 -0.13499999 0.162 -0.13499999 0.162 -0.13499999 c 0.13500005 0 0.14850003 0.013499975 0.2295 0.3104999 c 0.22950006 0.9585004 0.49950004 1.6065001 0.9855001 1.6065001 c 0.22949994 0 0.41849995 -0.1079998 0.41849995 -0.6209998 c 0 -0.2835002 -0.040499926 -0.43200016 -0.21599996 -1.1340001 l -0.783 -3.1185002 c -0.040500045 -0.20249999 -0.121500015 -0.513 -0.121500015 -0.5805 c 0 -0.243 0.18900001 -0.36450002 0.3915 -0.36450002 c 0.16199994 0 0.40499997 0.10800001 0.49950004 0.37800002 c 0.02699995 0.054000005 0.48599994 1.8900001 0.5400001 2.133 l 0.43199992 1.7550004 c 0.0539999 0.17549992 0.43199992 0.80999994 0.75600004 1.1069999 c 0.10800004 0.094500065 0.4994998 0.4454999 1.0799999 0.4454999 c 0.35099983 0 0.5669999 -0.1619997 0.5669999 -0.1619997 c -0.40499973 -0.067500114 -0.70199966 -0.39150047 -0.70199966 -0.7425003 c 0 -0.21600008 0.14849997 -0.47249985 0.513 -0.47249985 c 0.36450005 0 0.7424998 0.31049967 0.7424998 0.7964997 Z \"/\u003e\u003c/symbol\u003e\u003c/defs\u003e\u003c/svg\u003e\u003c/span\u003e 是二维平面里的一个多边形，那么 \u003cspan role=\"math\"\u003e\u003csvg class=\"typst-frame\" style=\"overflow: visible; width: 6.083555555555556em; height: 0.683em;\" viewBox=\"0 0 82.12800000000001 9.2205\" width=\"82.12800000000001pt\" height=\"9.2205pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:h5=\"http://www.w3.org/1999/xhtml\"\u003e\u003cg\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 0 9.2205)\"\u003e\u003cuse xlink:href=\"#gC216693D542D21E8E95CCCBC7495D99D\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003cuse xlink:href=\"#g6A56BD9E561F51C1AB29E4EAF58998F8\" x=\"10.125\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 19.871999999999996 9.2205)\"\u003e\u003cuse xlink:href=\"#gD54FB5694EC3FB5580CAE2E45CF230CB\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 25.1235 9.2205)\"\u003e\u003cuse xlink:href=\"#gC66649BF7054B405FEFD6EC249209D4C\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 34.8705 9.2205)\"\u003e\u003cuse xlink:href=\"#g8F0E7B478F08A2A3FD91F1F9F636BFE0\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 43.872 9.2205)\"\u003e\u003cuse xlink:href=\"#g78FD1D260678866025A88F528D8C9299\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 58.125 9.2205)\"\u003e\u003cuse xlink:href=\"#g286B22BE3D21817B279DAF417D7BB771\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 68.628 9.2205)\"\u003e\u003cuse xlink:href=\"#g3A8636A6CACB0634704D50028701AD17\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003c/g\u003e\u003cdefs id=\"glyph\"\u003e\u003csymbol id=\"gC216693D542D21E8E95CCCBC7495D99D\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 9.8550005 8.802 v 0.41849995 c -0.41849995 -0.026999474 -0.9584999 -0.040499687 -1.3095007 -0.040499687 l -1.5389996 0.040499687 v -0.41849995 c 0.70200014 -0.013500214 0.98549986 -0.36450005 0.98549986 -0.6750002 c 0 -0.1079998 -0.040499687 -0.18899965 -0.067500114 -0.2699995 l -2.4705 -6.5070004 l -2.5785 6.8175006 c -0.08099985 0.18900013 -0.08099985 0.24300003 -0.08099985 0.24300003 c 0 0.39149952 0.7695 0.39149952 1.1069999 0.39149952 v 0.41849995 c -0.48599982 -0.040499687 -1.4175 -0.040499687 -1.9304999 -0.040499687 l -1.7145001 0.040499687 v -0.41849995 c 0.87750006 0 1.1340001 0 1.3230001 -0.51299953 l 3.132 -8.2890005 c 0.094500065 -0.2565 0.16200018 -0.29700002 0.3375001 -0.29700002 c 0.22949982 0 0.25649977 0.06750001 0.32399988 0.2565 l 3.0105 7.938 c 0.18900013 0.49950027 0.5535002 0.8909998 1.4715004 0.9045 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"g6A56BD9E561F51C1AB29E4EAF58998F8\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 8.9775 3.1455002 c 0 0.13499999 0 0.22949982 -0.17549992 0.22949982 c -0.14849949 0 -0.14849949 -0.08099985 -0.1619997 -0.21599984 c -0.1079998 -1.9305001 -1.5525002 -3.0375001 -3.0240002 -3.0375001 c -0.82350016 0 -3.4695 0.459 -3.4695 4.482 c 0 4.0365005 2.6325002 4.4955 3.4559999 4.4955 c 1.4715004 0 2.6730003 -1.2284999 2.9429998 -3.1994996 c 0.027000427 -0.18900013 0.027000427 -0.2295003 0.21600056 -0.2295003 c 0.2159996 0 0.2159996 0.040500164 0.2159996 0.32399988 v 3.1995006 c 0 0.22949982 0 0.3239994 -0.14849949 0.3239994 c -0.0539999 0 -0.1079998 0 -0.21600056 -0.1619997 l -0.6749997 -0.9989996 c -0.4994998 0.48600006 -1.1880002 1.1609993 -2.4840002 1.1609993 c -2.5245 0 -4.698 -2.1464996 -4.698 -4.9005 c 0 -2.7945 2.187 -4.914 4.698 -4.914 c 2.2005 0 3.5235 1.8765001 3.5235 3.4425 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"gD54FB5694EC3FB5580CAE2E45CF230CB\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 4.4820004 -3.213 c 0 0.040499926 -0.027000427 0.08100009 -0.054000378 0.10800004 c -1.4039998 1.053 -2.3355 3.753 -2.3355 5.913 v 1.1340001 c 0 2.16 0.9315002 4.8599997 2.3355 5.913 c 0.02699995 0.026999474 0.054000378 0.067500114 0.054000378 0.1079998 c 0 0.067500114 -0.067500114 0.13500023 -0.13500023 0.13500023 c -0.02699995 0 -0.0539999 -0.013500214 -0.08099985 -0.027000427 c -1.4850001 -1.1204996 -2.9025002 -3.8205 -2.9025002 -6.1289997 v -1.1340001 c 0 -2.3085 1.4175001 -5.0085 2.9025002 -6.129 c 0.02699995 -0.013499975 0.0539999 -0.02699995 0.08099985 -0.02699995 c 0.067500114 0 0.13500023 0.067499876 0.13500023 0.13499999 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"gC66649BF7054B405FEFD6EC249209D4C\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 8.9775 3.186 h -0.33749962 c -0.24300003 -2.2545002 -1.1610003 -2.619 -3.2805004 -2.619 h -3.7259998 l 3.3885002 3.834 c 0.121500015 0.13500023 0.121500015 0.21600008 0.121500015 0.21600008 c 0 0.067500114 -0.054000378 0.13500023 -0.094500065 0.18900013 l -2.7675002 3.9959998 h 3.1185 c 2.2815003 0 2.9565005 -0.48600006 3.2400002 -2.619 h 0.33749962 l -0.3779993 3.0375 h -7.492501 c -0.324 0 -0.35099995 0 -0.35099995 -0.31050014 l 3.3615003 -4.8869996 l -3.2130003 -3.6585002 c -0.13499999 -0.14850001 -0.13499999 -0.1755 -0.13499999 -0.216 c 0 -0.14850001 0.13499999 -0.14850001 0.33749998 -0.14850001 h 7.492501 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"g8F0E7B478F08A2A3FD91F1F9F636BFE0\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 3.888 2.808 v 1.1340001 c 0 2.3085 -1.4175 5.0085 -2.9025 6.1289997 c -0.02700001 0.013500214 -0.05400002 0.027000427 -0.08100003 0.027000427 c -0.067499995 0 -0.13499999 -0.067500114 -0.13499999 -0.13500023 c 0 -0.040499687 0.02700001 -0.08100033 0.05400002 -0.1079998 c 1.4039999 -1.0530005 2.3355002 -3.7530003 2.3355002 -5.913 v -1.1340001 c 0 -2.16 -0.9315002 -4.86 -2.3355002 -5.913 c -0.02700001 -0.02699995 -0.05400002 -0.067500114 -0.05400002 -0.10800004 c 0 -0.067500114 0.067499995 -0.13499999 0.13499999 -0.13499999 c 0.02700001 0 0.05400002 0.013499975 0.08100003 0.02699995 c 1.4849999 1.1205001 2.9025 3.8205001 2.9025 6.129 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"g78FD1D260678866025A88F528D8C9299\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 9.747001 4.6845 c 0 0.14849997 -0.121500015 0.26999998 -0.27000046 0.26999998 h -8.451 c -0.14850003 0 -0.26999998 -0.121500015 -0.26999998 -0.26999998 c 0 -0.14849997 0.121499956 -0.26999998 0.26999998 -0.26999998 h 8.451 c 0.14850044 0 0.27000046 0.121500015 0.27000046 0.26999998 Z m 0 -2.6190002 c 0 0.14849997 -0.121500015 0.26999998 -0.27000046 0.26999998 h -8.451 c -0.14850003 0 -0.26999998 -0.121500015 -0.26999998 -0.26999998 c 0 -0.14849997 0.121499956 -0.26999998 0.26999998 -0.26999998 h 8.451 c 0.14850044 0 0.27000046 0.121500015 0.27000046 0.26999998 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"g286B22BE3D21817B279DAF417D7BB771\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 9.747001 3.375 c 0 0.1485002 -0.121500015 0.26999998 -0.27000046 0.26999998 h -3.9555001 v 3.9555001 c 0 0.14849997 -0.121500015 0.26999998 -0.26999998 0.26999998 c -0.14849997 0 -0.26999998 -0.121500015 -0.26999998 -0.26999998 v -3.9555001 h -3.9555001 c -0.14850003 0 -0.26999998 -0.12149978 -0.26999998 -0.26999998 c 0 -0.14849997 0.121499956 -0.26999998 0.26999998 -0.26999998 h 3.9555001 v -3.9555001 c 0 -0.14849997 0.121500015 -0.27000004 0.26999998 -0.27000004 c 0.14849997 0 0.26999998 0.121500075 0.26999998 0.27000004 v 3.9555001 h 3.9555001 c 0.14850044 0 0.27000046 0.121500015 0.27000046 0.26999998 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"g3A8636A6CACB0634704D50028701AD17\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 12.7305 2.9160001 c 0 1.4985001 -0.9449997 3.0509999 -2.5515003 3.0509999 c -1.9439993 0 -3.1454997 -1.9979999 -3.3209996 -2.2949998 c -0.9045 1.0934999 -0.9180002 1.1070001 -1.2150002 1.3634999 c -0.43200016 0.36450005 -1.2284999 0.93149996 -2.295 0.93149996 c -1.566 0 -2.592 -1.4714999 -2.592 -3.0644999 c 0 -1.4985001 0.94500005 -3.051 2.5515 -3.051 c 1.944 0 3.1455 1.998 3.3209999 2.295 c 0.9045 -1.0935001 0.9180002 -1.1070001 1.2150002 -1.3635001 c 0.43200016 -0.3645 1.2285004 -0.9315 2.295 -0.9315 c 1.566 0 2.592 1.4715 2.592 3.0645 Z m -0.29699993 0 c 0 -1.3500001 -0.9449997 -2.4165 -2.0790005 -2.4165 c -0.62099934 0 -1.1744995 0.3105 -1.7819996 0.972 c -0.37800026 0.41850007 -0.98549986 1.2689999 -1.3635001 1.728 c 0.513 0.9180002 1.539 2.3355002 3.0645003 2.3355002 c 1.4309998 0 2.1599998 -1.4040003 2.1599998 -2.6190002 Z m -6.156 -0.29700017 c -0.513 -0.91799986 -1.539 -2.3355 -3.0645 -2.3355 c -1.431 0 -2.16 1.404 -2.16 2.6190002 c 0 1.3499999 0.94500005 2.4165 2.079 2.4165 c 0.62100005 0 1.1745 -0.31050014 1.7820001 -0.9720001 c 0.37800026 -0.41849995 0.98550034 -1.269 1.3635001 -1.7280002 Z \"/\u003e\u003c/symbol\u003e\u003c/defs\u003e\u003c/svg\u003e\u003c/span\u003e\u003c/li\u003e\n    \u003c/ul\u003e\n    \u003cp\u003e\u003c/p\u003e","title":"大数据算法 课程总结笔记 I（期末部分）"},{"content":" 图 1 玩音乐的最终归宿是转行具身智能。[1] TODO\nTable of Contents\nReferences\nReferences [1] 山下清悟, “超かぐや姫！.” [Online]. Available: https://www.netflix.com/title/81756595 [2] J. Park and H. Kang, “RenderMem: Rendering as Spatial Memory Retrieval.” [Online]. Available: https://arxiv.org/abs/2603.14669 [3] R. I. C. Muchacho and F. T. Pokorny, “Walk on Spheres for PDE-based Path Planning.” [Online]. Available: https://arxiv.org/abs/2406.01713 [4] C. Jambon, M. S. Nabizadeh, and M. Konaković Luković, “Walk on Decomposed Subdomains: A Hybrid Monte Carlo–Deterministic Solver for Elliptic PDEs,” ACM Trans. Graph., vol. 45, no. 4, July 2026, doi: 10.1145/3811340. [5] Heskey0, “具身智能 - 9 个方向讲透 2025-2026 灵巧手智能.” [Online]. Available: https://zhuanlan.zhihu.com/p/2046746760459171551 ","permalink":"https://rubatotree.github.io/blog/posts/embodied-notes-2/","summary":"\u003cp class=\"typst-parbreak\"\u003e\u003c/p\u003e\n    \u003cdiv style=\"display: grid; place-items: start center;\"\u003e\n      \u003cfigure\u003e\n        \u003cdiv style=\"display: grid; place-items: start center;\"\u003e\u003cimg src=\"/blog/images/embodied-notes-2/teaser.png\" alt loading=\"lazy\"\u003e\u003c/div\u003e\n        \u003cdiv style=\"display: grid; place-items: start center;\"\u003e\n          \u003cfigcaption\u003e图 1 玩音乐的最终归宿是转行具身智能。\u003ca id=\"loc-1\" href=\"#loc-3\" role=\"doc-biblioref\"\u003e[1]\u003c/a\u003e\u003c/figcaption\u003e\n        \u003c/div\u003e\n      \u003c/figure\u003e\n    \u003c/div\u003e\n    \u003cp class=\"typst-parbreak\"\u003e\u003c/p\u003e\n    \u003cp\u003eTODO\u003c/p\u003e\n    \u003cdiv class=\"toc\" style=\"display: none\"\u003e\u003cdetails\u003e\u003csummary\u003eTable of Contents\u003c/summary\u003e\u003cdiv\u003e\u003cnav role=\"doc-toc\"\u003e\u003col style=\"list-style-type: none\"\u003e\u003cli\u003e\u003cp\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ca href=\"#loc-2\"\u003eReferences\u003c/a\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003c/p\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/nav\u003e\u003c/div\u003e\u003c/details\u003e\u003c/div\u003e\n    \u003csection role=\"doc-bibliography\"\u003e\n      \u003ch2 id=\"loc-2\"\u003eReferences\u003c/h2\u003e\n      \u003cul style=\"list-style-type: none\"\u003e\n        \u003cli id=\"loc-3\"\u003e\u003cspan class=\"prefix\"\u003e\u003ca href=\"#loc-1\" role=\"doc-backlink\"\u003e[1]\u003c/a\u003e\u003c/span\u003e 山下清悟, “超かぐや姫！.” [Online]. Available: \u003ca href=\"https://www.netflix.com/title/81756595\" target=\"_blank\" rel=\"noopener noreferrer\"\u003e\u003cspan style=\"color: #59a4ff;\"\u003e\u003cspan style=\"text-decoration: underline\"\u003ehttps://www.netflix.com/title/81756595\u003c/span\u003e\u003c/span\u003e\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003cspan class=\"prefix\"\u003e[2]\u003c/span\u003e J. Park and H. Kang, “RenderMem: Rendering as Spatial Memory Retrieval.” [Online]. Available: \u003ca href=\"https://arxiv.org/abs/2603.14669\" target=\"_blank\" rel=\"noopener noreferrer\"\u003e\u003cspan style=\"color: #59a4ff;\"\u003e\u003cspan style=\"text-decoration: underline\"\u003ehttps://arxiv.org/abs/2603.14669\u003c/span\u003e\u003c/span\u003e\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003cspan class=\"prefix\"\u003e[3]\u003c/span\u003e R. I. C. Muchacho and F. T. Pokorny, “Walk on Spheres for PDE-based Path Planning.” [Online]. Available: \u003ca href=\"https://arxiv.org/abs/2406.01713\" target=\"_blank\" rel=\"noopener noreferrer\"\u003e\u003cspan style=\"color: #59a4ff;\"\u003e\u003cspan style=\"text-decoration: underline\"\u003ehttps://arxiv.org/abs/2406.01713\u003c/span\u003e\u003c/span\u003e\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003cspan class=\"prefix\"\u003e[4]\u003c/span\u003e C. Jambon, M. S. Nabizadeh, and M. Konaković Luković, “Walk on Decomposed Subdomains: A Hybrid Monte Carlo–Deterministic Solver for Elliptic PDEs,” \u003cem\u003eACM Trans. Graph.\u003c/em\u003e, vol. 45, no. 4, July 2026, doi: \u003ca href=\"https://doi.org/10.1145/3811340\" target=\"_blank\" rel=\"noopener noreferrer\"\u003e\u003cspan style=\"color: #59a4ff;\"\u003e\u003cspan style=\"text-decoration: underline\"\u003e10.1145/3811340\u003c/span\u003e\u003c/span\u003e\u003c/a\u003e.\u003c/li\u003e\n        \u003cli\u003e\u003cspan class=\"prefix\"\u003e[5]\u003c/span\u003e Heskey0, “具身智能 - 9 个方向讲透 2025-2026 灵巧手智能.” [Online]. Available: \u003ca href=\"https://zhuanlan.zhihu.com/p/2046746760459171551\" target=\"_blank\" rel=\"noopener noreferrer\"\u003e\u003cspan style=\"color: #59a4ff;\"\u003e\u003cspan style=\"text-decoration: underline\"\u003ehttps://zhuanlan.zhihu.com/p/2046746760459171551\u003c/span\u003e\u003c/span\u003e\u003c/a\u003e\u003c/li\u003e\n      \u003c/ul\u003e\n    \u003c/section\u003e","title":"图形已死，all in AI具身 II: 机器人会梦到怎样的现实呢"},{"content":" 这周组会上导师提到现在做 Rendering 已经很难有价值和影响力了，也很难找到好的课题，应该 all in 具身智能。感觉自己从一个转型阵痛期的组跳进了另一个转型阵痛期的组。不过转型是正确的，具身方向的确好发有影响力的论文，就业前景也比传统图形学好。虽然私心比较喜欢简洁优雅但没用的图形学，但确实应该现实一点。我们该思考一下怎样把已有的图形学、渲染经验搬到具身智能的应用上。\n组里同学分享的 RoboSplat [1] 一文确实相当契合 CG for embodied 的愿景，因此我们从这篇论文开始了解我们能够做什么。\n论文概要 本文的目标是通过输入场景的多视角 RGB 图片和单次示教样本（Expert Demonstration，人工操作机械臂完成一次任务，得到每帧的机械臂状态数据和单监督视角 RGB 图像序列）训练 VLA 模型泛化完成不同干扰场景下的同一任务。本文试图解决的干扰场景分为物体位姿移动(Object Pose)、监督相机移动(Camera View)、光照条件改变(Lighting)、物体种类改变(Object Type)、周边环境改变(Appearance)、机械臂外观改变(Cross Embodiment)六种。\n图 1 论文 teaser，展示了 RoboSplat 的训练过程。 本文做到泛化的具体方法则是做数据增强，从单次示教样本中根据这几种干扰情况生成上千条增强样本 (augmented demonstrations)。以往生成增强样本的思路是直接在 2D 图像空间做生成式编辑，而本文考虑将多视角图片训练成 3DGS 场景（并在语义上分离场景、物体、机械臂，给机械臂绑骨），去在 3DGS 场景中做编辑模拟这些干扰，再合成回样本图像序列。这样做的好处是保证了图像之间场景的一致性，且不会有抖动等情况出现，因此能准确指导 VLA 模型学习到正确的操作策略。\n本文对这几种任务做了测试：\nPick Object（抓取物体）：机械臂需要抓起放置在 30cm*40cm 范围桌面上的目标物体。\n难点： 测试基本的空间 3D 定位与抓取能力。 Close Drawer（关闭抽屉）：机械臂需要推关一个抽屉。抽屉的位置在 15cm*40cm 范围内随机变化，且抽屉在 Z 轴方向的旋转角度在 [-pi/8, pi/8] 之间随机偏转。\n难点： 涉及与关节体（Articulated Object）的物理交互，且需要适应抽屉角度的偏转。 Pick-Place-Close（抓、放、关抽屉）：这是一个多步骤的长程任务。机械臂需要：(1) 抓起桌上的物体 - (2) 将其放入抽屉 - (3) 最后将抽屉推关上。\n难点： 步骤多，任何一步失败都会导致整个任务失败，累积误差大。 Dual Pick-Place（双目标连续抓放）：机械臂需要连续抓起放置在不同位置的两个目标物体，并依次将它们放入固定的抽屉中。\n难点： 测试策略在连续操作和多目标调度下的稳定性。 Sweep（扫地/清理）：这是一个工具使用（Tool Use）任务。机器人需要：(1) 首先精准抓起一把刷子（扫帚）- (2) 然后使用刷子将砧板上的巧克力豆扫进簸箕（尘推）中。\n难点： 涉及复杂的接触力和精细的工具操作轨迹。 图 2 测试这些任务的具体图片场景。 本文没有做模拟测试，只做了实机测试。得到的结果均在干扰样本下能有 90% 级别的成功率，远远超出过去 2D 图像空间增强的方法。虽然本文需要生成更多增强样本达到和手动收集样本一样的成功率，但相比于手动收集样本的时间成本来说，本文的贡献是显而易见的。\n图 3 与手动操作收集样本的对比实验结果。 图 4 关于更改光照和外观的消融实验。下方的图例分别是：少量人工示教样本、RoboSplat 方法只增强位姿不增强光照/外观训练的模型、2D 图像空间增强方法、RoboSplat 完整的增强数据。 应用与愿景 具身智能的训练路线大致可以分为“大数据大模型”和“小数据高效率”两条，前者依赖大量的人工操作样本去试图泛化解决大量任务，后者试图根据少量的示范快速学习精确的任务。本文可以归类为后者。\n一篇 2018 的单样本具身智能学习论文 [2] 提到，理想的家庭机器人体验是：当你买了一个机器人回家，你希望对它说:“看好了，我演示一次怎么开这个抽屉，你以后就会了。” 这就是单样本模仿学习(One-Shot Imitation Learning)的终极愿景。\n本文的目的当然也是实现这个愿景，且采用的方式是数据增强：人类只需要做一次演示，剩下的数千次数据由 3DGS 生成，来达到和人类做数千次演示一样的训练结果。\n虽然很难不怀疑未来力大砖飞的大模型总能通过微调快速泛化到具体的任务场景，但现实世界的确太复杂了，用高几何先验的手段先去增强数据喂给模型想必效果还是比让模型自己想象“增强”要更行之有效的（对吗）。\n关于增强数据的物理正确性 本文在 3DGS 场景做干扰这一步做了刚体假设，即将物体、机械臂的骨骼视作刚体进行编辑，直接改变它们的位姿来模拟干扰。Appearance、Object Type、Cross Embodiment 这三种干扰是直接在 3DGS 场景中替换物体或机械臂的模型来模拟的。Lighting 则是给全局的 Gaussians 加一层色彩映射类的“滤镜”。换言之，本文完全没有考虑光照的物理正确性，也没有考虑具体运动中的物理交互。\n图 5 论文 Method Overview。先将测试数据训练成 3DGS 场景并用语义模型做分割、机械臂绑骨，用示教数据引导生成逐帧的数据。然后展示了几种数据增强的方式。 很难说是不是对任务做了 cherry-pick，专门挑了对光照和物理不敏感的任务。从 图 2 可以看出这些任务的场景都很简单，没有复杂的物理交互或光照，也没有对光照较敏感的任何材质（如金属表面、光滑小球、玻璃材质）。\n本文的实验没有对“3D滤镜”增强的数据和单用“2D滤镜”原始方法的数据增强做对比，考虑到它们实际表现都只会改变颜色的分布而没有做重光照，这里的“Lighting”增强可能相比原始 2D 增强的提升并不大（把这种增强叫做 Lighting 实在会惹恼图形学人）。可以认为本文根本没有在“光照条件”这一点上做增强。\n3DGS 带来提升的主要是 Object Pose、Camera View、Appearance、Cross Embodiment 这些对 3D 空间的外观做修改、从而高度依赖帧间一致性和多视角一致性的增强（保证几何是正确的，事实上这些任务对几何的依赖也确实高于对光照的依赖）。\n本文的 Limitation 也只提到了目前的刚体假设会在物理交互上不正确，完全没有提到光照增强的物理不正确性是否可能造成影响。\n然而目前并没有证据表明物理正确的光照能带来更好的训练效果。甚至可能出现这样的现象：大量不正确的光照会引导模型学到更鲁棒的特征，如更关注几何，而不是过拟合于特定的光照条件。也就是说，物理不正确的增强可能反而更有利于模型的泛化能力（“域随机化”）。这对图形学人来说的打击还是很大的。\n如果我们要做物理更正确的材质/光照增强，我们需要思考 RoboSplat 的 failure case，在怎样的场景中这种暴力的增强方法的确会干扰模型的判断。一个好想的例子是，一个纯金属的物体，若直接移动 Gaussians，随着物体的移动其外观不会发生改变，但现实中物体移动后表面的光照分布就完全变化了，模型可能不会认为这在前后是同一个物体了，从而造成任务的失败。另一个例子是在环境光分布较复杂的场景中，物体在不同位置的外观不同，模型也可能无法正确识别了。\n但一方面这种金属场景/复杂光照分布对物理正确重光照本来就是非常困难的事情，另一方面，我们也可以设计物理不正确但简单、覆盖面广的增强方案（如让物体颜色随时间随机变化）去引导模型只学物体的几何等光照/材质无关特征以提高鲁棒性、自然适应现实中的复杂光照和材质。目前来看“不那么图形学”的后者方案反而更有价值、更能体现“泛化”的力量。\n不管怎样，买条机械臂去手动试出来 RoboSplat 及其它 SOTA 方法的 failure case 是现在需要做的实在的事情。\n图形已死，all in AI具身 看了今年 SIGGRAPH 的许多文章，感觉图形学的确是有一点似了。基本上不是优雅但无用的工作，就是有用但不优雅的工作。Best Paper 及提名文章里也没有看到什么基于新方法的创新工作，做的基本上还是传统的图形学。今年更是没有一篇标题和具身智能相关的工作。虽然自己理想很想做那些优雅但无用的工作，但毕竟是要吃饭的。\n目前 GCL 组里有许多老师正在转行具身智能。PKU 和 NJU 过去做渲染的老师也都在往具身的方向靠。但目前这些转型中的组都还在摸索阶段。也许需要多和做具身的人联系，整理一下经验。\n从某个图形学转行群 [3] 潜水吃了一下图形学转行具身的新进展。今年暑期的启明星夏令营都已经变成以具身智能为主题了。还在群里摸到了一个具身智能资源收集仓库 [4]，感觉会很有用。（虽然看到 RoboSplat 这篇文章似乎还没收录进去？许多收录文章和图形学都没关系。\n不管从上文的论文阅读还是最新的论文来看，Rendering 和具身智能的结合还是不太容易的，并且想要把图形学的问题解耦出来而不参与具身的训练感觉不太可能。Monte Carlo PDE 方向在今天 VLA 方法主导下更难蹭上具身智能。物理仿真和动画可能更加贴近具身智能，但我们都不熟悉这个方向。希望我们的转型能早点熬出头。\n今后有必要熟悉一下具身智能的整套实验到测试的管线，在买到机械臂之前熟悉一下各种模拟器。没有背景的方向就是很难做哇。\nTable of Contents\n论文概要\n应用与愿景\n关于增强数据的物理正确性\n图形已死，all in AI具身\nReferences\nReferences [1] S. Yang et al., “Novel Demonstration Generation with Gaussian Splatting Enables Robust One-Shot Manipulation,” arXiv preprint arXiv:2504.13175, 2025. [2] T. Yu et al., “One-Shot Imitation from Observing Humans via Domain-Adaptive Meta-Learning.” [Online]. Available: https://arxiv.org/abs/1802.01557 [3] Heskey0, “具身智能 - 学术界的10年。从物理仿真到世界模型.” [Online]. Available: https://zhuanlan.zhihu.com/p/1925196445184656677 [4] O. E.-A. Community, “具身智能知识索引与产业地图.” [Online]. Available: https://github.com/Octoday-Hub/Embodied-AI ","permalink":"https://rubatotree.github.io/blog/posts/embodied-notes-1-robosplat/","summary":"\u003cp\u003e这周组会上导师提到现在做 Rendering 已经很难有价值和影响力了，也很难找到好的课题，应该 all in 具身智能。感觉自己从一个转型阵痛期的组跳进了另一个转型阵痛期的组。不过转型是正确的，具身方向的确好发有影响力的论文，就业前景也比传统图形学好。虽然私心比较喜欢简洁优雅但没用的图形学，但确实应该现实一点。我们该思考一下怎样把已有的图形学、渲染经验搬到具身智能的应用上。\u003c/p\u003e\n    \u003cp\u003e组里同学分享的 RoboSplat \u003ca id=\"loc-1\" href=\"#loc-10\" role=\"doc-biblioref\"\u003e[1]\u003c/a\u003e 一文确实相当契合 CG for embodied 的愿景，因此我们从这篇论文开始了解我们能够做什么。\u003c/p\u003e\n    \u003ch2 id=\"loc-2\"\u003e论文概要\u003c/h2\u003e\n    \u003cp\u003e本文的目标是通过输入场景的多视角 RGB 图片和\u003cstrong\u003e单次\u003c/strong\u003e示教样本（Expert Demonstration，人工操作机械臂完成一次任务，得到每帧的机械臂状态数据和单监督视角 RGB 图像序列）训练 VLA 模型泛化完成不同干扰场景下的同一任务。本文试图解决的干扰场景分为物体位姿移动(Object Pose)、监督相机移动(Camera View)、光照条件改变(Lighting)、物体种类改变(Object Type)、周边环境改变(Appearance)、机械臂外观改变(Cross Embodiment)六种。\u003c/p\u003e\n    \u003cp class=\"typst-parbreak\"\u003e\u003c/p\u003e\n    \u003cdiv style=\"display: grid; place-items: start center;\"\u003e\n      \u003cfigure\u003e\n        \u003cdiv style=\"display: grid; place-items: start center;\"\u003e\u003cimg src=\"/blog/images/embodied-notes-1-robosplat/robosplat-teaser.png\" alt loading=\"lazy\"\u003e\u003c/div\u003e\n        \u003cdiv style=\"display: grid; place-items: start center;\"\u003e\n          \u003cfigcaption\u003e图 1 论文 teaser，展示了 RoboSplat 的训练过程。\u003c/figcaption\u003e\n        \u003c/div\u003e\n      \u003c/figure\u003e\n    \u003c/div\u003e\n    \u003cp class=\"typst-parbreak\"\u003e\u003c/p\u003e\n    \u003cp\u003e本文做到泛化的具体方法则是做\u003cstrong\u003e数据增强\u003c/strong\u003e，从单次示教样本中根据这几种干扰情况生成上千条增强样本 (augmented demonstrations)。以往生成增强样本的思路是直接在 2D 图像空间做生成式编辑，而本文考虑将多视角图片训练成 3DGS 场景（并在语义上分离场景、物体、机械臂，给机械臂绑骨），去在 3DGS 场景中做编辑模拟这些干扰，再合成回样本图像序列。这样做的好处是保证了图像之间场景的一致性，且不会有抖动等情况出现，因此能准确指导 VLA 模型学习到正确的操作策略。\u003c/p\u003e\n    \u003cp\u003e本文对这几种任务做了测试：\u003c/p\u003e\n    \u003cp\u003e\u003c/p\u003e\n    \u003cul\u003e\n      \u003cli\u003e\n        \u003cp\u003ePick Object（抓取物体）：机械臂需要抓起放置在 30cm*40cm 范围桌面上的目标物体。\u003c/p\u003e\n        \u003cp\u003e\u003c/p\u003e\n        \u003cul\u003e\n          \u003cli\u003e难点： 测试基本的空间 3D 定位与抓取能力。\u003c/li\u003e\n        \u003c/ul\u003e\n        \u003cp\u003e\u003c/p\u003e\n      \u003c/li\u003e\n      \u003cli\u003e\n        \u003cp\u003eClose Drawer（关闭抽屉）：机械臂需要推关一个抽屉。抽屉的位置在 15cm*40cm 范围内随机变化，且抽屉在 Z 轴方向的旋转角度在 [-pi/8, pi/8] 之间随机偏转。\u003c/p\u003e","title":"图形已死，all in AI具身 I: RoboSplat 论文阅读与杂谈"},{"content":" 1. Monte Carlo PDE Probe-based Walk on Spheres for Efficient Path Reusing [Project] 我自己的文章。\n利用路径信息重用高效优化 Walk on Spheres 系列算法。\n考虑到 Walk on Spheres 的采样过程，每一步都要在球面上均匀采样一个点作为该点解值的一个无偏估计。由 Off-center 形式的平均值公式可以得到实际上在球内的偏心点按 Poisson Kernel 分布在球面上采样一个点得到的结果也是解值的无偏估计。因此 WoS 均匀采样得到的解值可以为球内每个点所重用，在算法上就是得到一条完整路径后将求解值 Splat 回路径上的每个球内。这个算法被我们称为 Naive Path Reuse，不清楚现在 sig 上那篇 Talking to Neighbors 有没有扩展成这样的形式。\n图 1 我们的 Naive Path Reuse 算法 然后考虑到这样 Splat 的开销过于大（球内每个点都需要查询并访存一次），正好 25 年 11 月又出来了 Harmonic Caching 的文章，发现后者正好可以将 Splat 的任务转化为求解几个 Fourier 系数的任务。因此和 HC 类似地在求解域预放置一些探针球，游走时取一个探针球做 Poisson Kernel 采样找到边界，若不存在探针球就 Fallback 到传统的 WoSt 算法，可以验证这个行为仍然是满足布朗运动的。找到 Dirichlet 边界后就将求解到的结果送回探针球中贡献 Fourier 系数。然后就非常快了。\n图 2 我们的 Walk on Probes 算法 当时这篇文章的 idea 成形已经是 11 月底了，只有两个月的时间做，临近交稿的时候还有各种 ddl 和期末考试，压力巨大。还好做完了，如果再晚半年就要和这些新的方差缩减算法比了，甚至要和 Best Paper 比，好可怕。今后还会继续做 Monte Carlo PDE 吗，不知道，既然能有想法就去做吧。\nWalk on Decomposed Subdomains: A Hybrid Monte Carlo–Deterministic Solver for Elliptic PDEs [1] [Project] 今年 Best Paper，太猛了\n通过空间划分解决 WoSt 路径过长的问题，从而高效提升速度。\n为了避免常规 Walk on Stars 路径过长的问题，该方法把求解域分为了网格状子域，用虚拟的 Dirichlet 边界分开，逐个求解再合并，这样每个子区域都是 Dirichlet 为主的区域，就易于求解了。\n论文内容量好大，做了超级多的实验和探索。总觉得自己也想到过类似的方法，但没能落地到这么实在的程度。\nTODO\nGradient Domain Reconstruction for Monte Carlo PDE Solvers [2] [Project] 今年 Best Paper Honorable Mentioned，大家都好厉害\nTODO\nMonte Carlo PDE Solvers for Nonlinear Radiative Boundary Conditions [3] [ArXiv] TODO\n2. Geometry Points as Tori: Fast Pointwise Signed Distance for Point Clouds [4] [Project] 甜甜圈统治世界！这篇真好玩。目前为止最喜欢的一篇。\n本文通过预计算对带法线的点云高效求 SDF。\n对每个点预计算出一个局部的环面 (Tori) 表示其邻域的 Geometry，从而就能把点云修补成完备且有解析 SDF 的曲面。求 SDF 时先筛出一些最近邻点，加权取 SDF 值。本文还提出了一些自归一化权重来避免特殊情况产生的误差。\n选取环面的原因是，在有解析 SDF 表达式的图元中，环面上曲率的分布非常丰富，因此能很好地表示各类二阶微分的邻域。这个思路太神奇好玩了。\n预计算环面参数的方法居然是直接把邻域所有点丢进 Transformer 中吐出来，这一步也很惊人，直觉上一般都会用低鲁棒性的最小二乘法的。这才是变压器的正确使用方法吗。\n本文的主页上还有很多很有趣的讨论，诸如为什么选用环面、为什么要用基于学习的方法、为什么不用端到端的学习方法、和其它方法相比有什么优势，几乎都是一些设计哲学问题。感觉这才是所谓理性地使用 AI-based 方法，看这篇的时候完全不会有“AI 来了图形学要完蛋了”的焦虑，反而是一种，“噢，这个设计真有趣，我相信它”的畅快感。\nManifold k-NN: Accelerated k-NN Queries for Manifold Point Clouds [5] [ArXiv] TODO\n3. 这段时间读到的一些非 SIG26 文章补充 LazyBrush: Flexible Painting Tool for Hand-drawn Cartoons [6] (EG 2008) 老文章。启发式解决非封闭线稿填色的问题，现在该方法被用在了 Krita 中。\n该文章想处理的交互逻辑如上图中间，用一笔选择想要填色的区域内部，即可得到右图这样，线稿内部完美填色，而线稿外部漏出的区域自动被修正掉。该文章将不完美填色问题建模成一个能量优化问题。能量函数由定义在两像素之间连边上的平滑项 和像素点上的数据项 组成。填色区域的边界会贡献平滑项，而一部分内部像素点会贡献数据项。\n平滑项 用于找到一条合适的边界，定义为和 点的亮度正相关，使得在较亮的区域（线稿内部）切换颜色会有较高的代价，而鼓励在较暗的区域（单根线的“中心”区域）切换颜色。这样的能量会鼓励填色区域不断“膨胀”直到被其所在的线稿区域的线条中心约束住，同时也会约束填色区域在线稿不封闭的小缝隙不漏出来。（边界跨过较窄的缝隙，贡献的能量会低于跨过外部更宽的缝隙）算法会像水流寻找地势最低处一样，寻找一条总光度值最低（最黑）的路径来强行连接断开的线条。\n数据项 用于修正填色时溢出边界的部分，定义为如果一个像素被用户指定需要填色但实际算法决定不填色时，贡献一个常数能量。这意味着如果填满一个溢出区域边界贡献的能量比删掉这一块区域的能量还高（小区域填满了大边界），不如直接删去这一块。\n具体的求解算法为图论的算法，就不在这里讨论了。老一辈图形学人的启发式方法还是漂亮，可惜目前除了 Krita 好像就没在别的软件里看到过了（Procreate 什么时候才能有！）不知道现代图形学的问题里会不会有类似这样“填色”的需求。\nTable of Contents\n1. Monte Carlo PDE\nProbe-based Walk on Spheres for Efficient Path Reusing [Project]\nWalk on Decomposed Subdomains: A Hybrid Monte Carlo–Deterministic Solver for Elliptic PDEs [1] [Project]\nGradient Domain Reconstruction for Monte Carlo PDE Solvers [2] [Project]\nMonte Carlo PDE Solvers for Nonlinear Radiative Boundary Conditions [3] [ArXiv]\n2. Geometry\nPoints as Tori: Fast Pointwise Signed Distance for Point Clouds [4] [Project]\nManifold k-NN: Accelerated k-NN Queries for Manifold Point Clouds [5] [ArXiv]\n3. 这段时间读到的一些非 SIG26 文章补充\nLazyBrush: Flexible Painting Tool for Hand-drawn Cartoons [6] (EG 2008)\nReferences\nReferences [1] C. Jambon, M. S. Nabizadeh, and M. Konaković Luković, “Walk on Decomposed Subdomains: A Hybrid Monte Carlo–Deterministic Solver for Elliptic PDEs,” ACM Trans. Graph., vol. 45, no. 4, July 2026, doi: 10.1145/3811340. [2] J. Wu, X. Hu, S. Zhao, and K. Xu, “Gradient Domain Reconstruction for Monte Carlo PDE Solvers,” ACM Transactions on Graphics, vol. 45, no. 4, July 2026, doi: 10.1145/3811295. [3] A. Bao, E. Shen, and J. Wang, “Monte Carlo PDE Solvers for Nonlinear Radiative Boundary Conditions.” [Online]. Available: https://arxiv.org/abs/2604.21717 [4] N. Feng, I. Gkioulekas, and K. Crane, “Points as Tori: Fast Pointwise Signed Distance for Point Clouds,” ACM Trans. Graph., vol. 45, no. 4, July 2026, doi: 10.1145/3811385. [5] P. Wang et al., “Manifold k-NN: Accelerated k-NN Queries for Manifold Point Clouds.” [Online]. Available: https://arxiv.org/abs/2605.02224 [6] D. Sýkora, J. Dingliana, and S. Collins, “LazyBrush: Flexible Painting Tool for Hand-drawn Cartoons,” Computer Graphics Forum, vol. 28, no. 2, pp. 599–608, 2009, doi: https://doi.org/10.1111/j.1467-8659.2009.01400.x. ","permalink":"https://rubatotree.github.io/blog/posts/sig26-paper-notes-3/","summary":"\u003ch2 id=\"loc-1\"\u003e1. Monte Carlo PDE\u003c/h2\u003e\n    \u003ch3 id=\"loc-2\"\u003eProbe-based Walk on Spheres for Efficient Path Reusing [\u003ca href=\"https://t7imal.github.io/projects/2026wop/\" target=\"_blank\" rel=\"noopener noreferrer\"\u003e\u003cspan style=\"color: #59a4ff;\"\u003e\u003cspan style=\"text-decoration: underline\"\u003eProject\u003c/span\u003e\u003c/span\u003e\u003c/a\u003e]\u003c/h3\u003e\n    \u003cimg src=\"/blog/images/sig26-paper-notes/WoP-teaser.png\" alt loading=\"lazy\"\u003e\n    \u003cp\u003e\u003cem\u003e我自己的文章。\u003c/em\u003e\u003c/p\u003e\n    \u003cp\u003e利用路径信息重用高效优化 Walk on Spheres 系列算法。\u003c/p\u003e\n    \u003cp\u003e考虑到 Walk on Spheres 的采样过程，每一步都要在球面上均匀采样一个点作为该点解值的一个无偏估计。由 Off-center 形式的平均值公式可以得到实际上在球内的偏心点按 Poisson Kernel 分布在球面上采样一个点得到的结果也是解值的无偏估计。因此 WoS 均匀采样得到的解值可以为球内每个点所重用，在算法上就是得到一条完整路径后将求解值 Splat 回路径上的每个球内。这个算法被我们称为 Naive Path Reuse，不清楚现在 sig 上那篇 Talking to Neighbors 有没有扩展成这样的形式。\u003c/p\u003e\n    \u003cp class=\"typst-parbreak\"\u003e\u003c/p\u003e\n    \u003cdiv style=\"display: grid; place-items: start center;\"\u003e\n      \u003cfigure\u003e\n        \u003cdiv style=\"display: grid; place-items: start center;\"\u003e\u003cimg src=\"/blog/images/sig26-paper-notes/wop_path_reuse.png\" alt loading=\"lazy\"\u003e\u003c/div\u003e\n        \u003cdiv style=\"display: grid; place-items: start center;\"\u003e\n          \u003cfigcaption\u003e图 1 我们的 Naive Path Reuse 算法\u003c/figcaption\u003e\n        \u003c/div\u003e\n      \u003c/figure\u003e\n    \u003c/div\u003e\n    \u003cp class=\"typst-parbreak\"\u003e\u003c/p\u003e\n    \u003cp\u003e然后考虑到这样 Splat 的开销过于大（球内每个点都需要查询并访存一次），正好 25 年 11 月又出来了 Harmonic Caching 的文章，发现后者正好可以将 Splat 的任务转化为求解几个 Fourier 系数的任务。因此和 HC 类似地在求解域预放置一些探针球，游走时取一个探针球做 Poisson Kernel 采样找到边界，若不存在探针球就 Fallback 到传统的 WoSt 算法，可以验证这个行为仍然是满足布朗运动的。找到 Dirichlet 边界后就将求解到的结果送回探针球中贡献 Fourier 系数。然后就非常快了。\u003c/p\u003e","title":"SIGGRAPH 2026 论文笔记 III: Monte Carlo PDE \u0026 几何"},{"content":" 1. 材质，外观，可微渲染 Fiber-level Woven Fabric Capture from a Single Microscopic Image [1] 另一位助教 @JerryShen 的文章之一。这篇没有上 Sig26，只是录进了 ToG，但也放在这里。\n从单张显微图像通过可微渲染重建织物的纤维级几何和材质。\n对于几何建模了基本可微的五层结构：\n编织模式 Pattern：平纹、斜纹等纹理模式，直接预设好，用预训练的 CNN 分类； 中心线层 Yarn Centerline：每根纤维从侧面看高度关于路径长度的函数，用抛物线和圆混合； 纤维截面层 Cross-sectional Fiber Distribution：在中心线周围生成 根纤维，纤维的螺旋扭转 、偏移 、周期性挤压变形等都是可微参数； 随机噪声层 Randomized Variation：用柏林噪声和白噪声让纤维的半径和纵向产生变化、噪声种子本身不可微但强度可微。 飘散纤维层 Flyaway Model：额外手动添加飘散出来的断线等纤维（定义有毛发 Hair 和环路 Loop 两种），模拟现实材质情况。这一层没法可微优化出来。 材质模型采用了 Chiang 的材质模型，特点是建模了光照的多次散射，可以精确模拟纤维的行为。\n训练采用三个阶段：\n初始化：用预训练的 CNN 先预测出这些参数的初值，其中编织模式、截面纤维数目等不可微参数在这一步就固定了。因为 CNN 擅长识别类型、数目等模式，所以这些初值就能非常可靠。对于材质在预测 Chiang 模型参数的同时还预测一组简化材质模型参数。 基于光栅化做粗优化：这一步用简化的材质模型（单散+Lambert）进行逆渲染，主要优化几何、颜色等。用 NVDiffRast 的“软边界光栅化”做高速逆渲染。优化 CNN 输出的 Gram 矩阵特征（结构）和 RGB（颜色）两个 Loss。这一步后几何参数被固定。 基于路径追踪做精细优化：将材质参数映射回 Chiang 模型，用 mitsuba 做可微路径追踪优化纤维材质参数。因为此时参数已经很少且基本准确，这一步可以做到很稳定的精细优化。 这篇提到的主要 Limitation 有：编制模式是预设的因此覆盖范围有限；不支持空间变化的颜色等、而实际情况是一些织物纤维本身存在渐变或布面印染等，难以 trivial 地支持；飘散纤维没有很好地被建模、无法可微优化；经纬纱颜色相似时边界会变模糊、模式会变得不明显、对初始化和粗优化阶段都不友好；几何模型目前只支持单股纱线、不支持复杂的合股纱；路径追踪阶段仍然耗时。作者说逆向的部分目前其实不那么 work，效果虽然很漂亮但和原图还是对不上。\n这篇审美真好，感觉每一步都很合理优雅哇。感觉这个需求是沈学长以往做的划痕艺术 [2] 的超级加强版。太厉害了。\nPureSample: Neural Materials Learned by Sampling Microgeometry [ArXiv] [GAMES] 用神经网络表达并学习由微几何定义的复杂材质 BRDF。\n现代渲染可以借助 Neural BRDF 来表达过去材质模型无法表达的复杂材质。该文章注意到实际物体的材质基本上由表面的微结构决定，microfacet 模型等都只是对微结构的简化，而直接对微结构做 Path Tracing 开销则过大，因此提出用神经网络去从给出的微结构几何中学出一个可采样的 BRDF。\n神经网络的输入来自对微表面的小区域做数次 Path Tracing 模拟（考虑到微结构实际上是 Sampling 易、Eval 难的），得到的数个 的样本，用 Flow Matching 的方法得到一个由简单分布到目标分布的可逆的“速度场”，从而使得 BRDF 可以被高效地采样和估值。具体求解的算法是 MeanFlow [3] ，感觉值得一看。注意到重分布只能表示散射行为而不能表示吸收行为，因此还需要对模拟的结果训练一个 Albedo 网络作为整体的吸收系数。由于从速度场中估值 pdf 比较耗，本文还蒸馏了一个轻量的 pdf 用于 MIS 权重和 BRDF 值计算，只在必要时才用无偏的 pdf。\n和去年的 Neural BRDF 重参数化采样 [4] 的区别主要在本文的目标微结构 BRDF 是可采样的，且要求得到的 Neural BRDF 可估值，从而采用的是 Flow Matching 算法，而 Wu 的工作则是针对一个难采样的 Neural BRDF 设计可采样的重要性分布，且不要求可估值。\n之前没做过材质，几乎都想不到这个问题。果然还是得和做 Rendering 的人多交流。\n2. 体积渲染 Multi-feature Radiance Baking Neural Networks for Instant Volumetric Rendering 好感动，MRPNN 的优化也被做出来了。同样是靠内部关系拿到的文章。\n用预烘焙的神经辐射场加速参与介质的“MRPNN [5] 式”体渲染，目标是烘焙一个只和密度场相关的预计算特征场，使得可以在各种光照条件下高速渲染体积，且解决 MRPNN 的欠采样情形 failure case。\n过去工作提到，体积中的辐射传输可以用一个算子 定义，对于体积中每一个位置，将局部的入射辐射函数映射为该点的出射辐射函数。易知这个算子只和相位函数有关，而和光照无关，而局部入射函数和位置、远场入射辐射、密度/相位函数分布有关。算子 可以形式化表述为一个卷积算子：\n本文的主要观察是，这个算子在球谐函数基下是对角化的，从而算子的作用可以转化为各阶球谐系数和算子系数的逐点乘法，以高效存储和求解。这个思想非常类似于算法中用 FFT 求解多项式乘法，同样是通过做一个傅里叶变换去将卷积算子对角化，非常优雅。\n然而局部入射辐射函数仍然是难求的，需要在体积内部模拟多次散射才能得到。并且，这是一个五维函数，本身难以烘焙。因此本文考虑对算子 做低秩分解，分别计算和位置与角度有关的特征，最后组合出辐射值。低秩分解的思路是只求出和光源方向相同方向上的散射值（称为隐空间特征，这样就只需要烘焙和位置相关的特征 ），然后再用 view modifier 微调到实际角度的情形。\n为了保证渲染的效果和效率，最后喂给网络的特征除了有隐空间特征、view modifier 外，还有沿光源采样的基础网格特征 （烘焙进网格中，用于替代沿路多次估计 ）和透射率分布特征 ，以及在邻域局部采样的相函数特征 和 Albedo 特征 . 从各个 Mipmap 层 采样到的特征最后拼接成送进网络的特征 . 因为这些特征已经很能概括散射了，所以网络只需要用一个简单的残差连接轻量 MLP。\n和 MRPNN 相同，把这个特征送进和场景无关的预训练 MLP 即可得到每个点的散射。\n比较维度 MRPNN MRBNN 性能提升原因 网络参数量 49.7 K 28.5 K 网络规模缩小近一倍，且使用了全融合架构。 采样元素量 480 个 432 个 减少了高维 SH 系数的重复访问。 输入维数 480+ 64 烘焙了物理先验，且逐层补充信息。 推理耗时 ~19.0 ms ~0.753 ms 参数量减小、维度降低、计算对角化。 并且 MRBNN 的采样步骤更快，因为只需要采样一次球谐系数，其它采样均是在 Mipmap 网格中采样标量，不需要反复访问纹理。MRBNN 输入的特征维数也更小（因为在预计算过程中已经融入了很多物理计算过的内容）。MRBNN 采用的残差连接 MLP 比 MRPNN 用的 SE 架构更轻量。综上能达到 20 倍以上的实时渲染性能提升。\n这篇文章的许多细节和设计动机我还没有完全看懂，有时间找原作者聊聊。\n参与介质渲染和 MRPNN 是我在图形学科研上痛苦受挫的开始。回忆过去还是比较想哭。这几年的自己不可能想出这样的优化，尽管不该是因为我不够努力。\n3. 风格化 Lifting Lines and Tone: Image-space Stylization in Path-space [6] [Project] 该工作是 NPR 描线 (Feature Lines) 和半调 (Tones) 在全局光照下的渲染系列最新的工作。\nWest 的往期工作提到用一个风格化渲染方程 来建模 NPR 的行为，其中 是一个定义上与屏幕空间坐标相关的风格化函数。该工作优化了对世界空间（路径空间）中的点找到其屏幕空间特征的算法（论文中将该操作称为“Lifting”）。\n该文章的设计目标基于以下原则：\nImage-space consistency：线条的宽度和半调图案间距在屏幕坐标系下应该稳定可控，需要在间接光、反射/折射（尤其是带曲率表面）、景深等影响下保持一致； Geometric correctness：从图像空间到路径空间的映射要保持局部几何特征，应该避免曲率造成的失真。 Distribution support：不仅需要支持镜面反射，还要支持任意分布定义的散射。 Estimator compatibility：积分结果需要无偏，且效率上要和传统路径追踪相当。 图 1 Failure modes（第二排，从左至右）：半调阴影间距沿表面测地线分布而不是在屏幕空间均匀分布；半调图案受表面曲率影响产生偏差；线宽在经过右侧球面反射后发生变化。我其实不太清楚过去工作产生这些 Failure mode 的原因。 对于描线，本文设计的方案（Conditional Lifting）是对于一条光路，做一次“Levi-Civita 平行移动”（就是微分几何的那个平行移动）。实际上就是去求屏幕空间中射线方向的微扰会在路径点上产生怎样的微扰、这种微扰是否会让该路径点有特征线的特征（如微扰后可见性发生了变化，或屏幕空间的微扰会造成路径空间的剧烈变化）。这个思路有种可微渲染感，但论文中实际实现方式是有限差分，用“冻结随机变量”的方法重用每步的采样方向保证差分路径间的强耦合性。\n对于半调，本文设计的方案（Canonical Lifting）则是先假设所有表面都是理想镜面、做一遍路径追踪在世界空间打下一系列记有对应屏幕空间坐标的锚点；在实际路径追踪时，对每个路径点去找邻域的锚点，并用移动最小二乘法插值出该路径点的屏幕空间坐标。感觉好 Tricky 啊，这个思路还是得参考艺术家是怎样决定经过光学变换后的半调的。\n图 2 这张图还是很形象地展示了平行移动描线是 make sense 的，这篇工作中带曲率的曲面会影响微扰在下一跳的微分，而以往工作做不到。我和我自己比 这篇颇有一种二十年前图形学“看起来对就是对”的 tricky 美感，不像是这个年代能出现在 ToG 的文章（？），不知道还有没有什么别的领域能体验一把这种拿到艺术家对 NPR 的需求并在数学上很好地建模的科研体验。这个系列工作要做的话感觉做不过 West 他们，说实话之前看他们工作的时候都想不出这些问题，就算自己提了新的渲染目标也不一定能把故事讲通，果然这篇只有他们自己能做出来。\n这个系列的工作目前基本没有做路径追踪基础上的加速，感觉有机会提炼出一些可 Caching 的东西，能凹到实时就更好了。\nNPR 与现代渲染方法结合的话，Neural 方法是难以建模一个相机相关的辐射场的（真的可以力大砖飞加一个相机参数维度吗，说不定呢）；Gaussian Primitives 由于 SH 的低频性质加上描边的特殊性，感觉很难表示描边和半调这种特征。现在做 NeRF/Gaussians 光场的 NPR/ 风格化基本都是用前馈网络做类似后处理的操作实现的，感觉这样做多视角一致性还是个问题，ai 幻觉可能还会有些不适感。\n4. 这段时间读到的一些非 SIG26 文章补充 Parameter-space ReSTIR for Differentiable and Inverse Rendering [7] (SIGGRAPH 2023) 用 ReSTIR 提速可微渲染。\n因为在思考在可微渲染任务里用 ReSTIR 所以看了。这篇主要提到可微渲染需要对梯度做积分，因此考虑用 ReSTIR 加速对梯度的采样。然后因为梯度向量的维数和参数相关，存屏幕空间会过大，因此需要在参数空间给每个参数单独存。并且因为梯度向量在实数域上，所以要对正值和负值分别设置储层，是一个经典 trick 了。这篇在当年也是 Conference Track。看完觉得自己的 idea 不可行了（x\nTable of Contents\n1. 材质，外观，可微渲染\nFiber-level Woven Fabric Capture from a Single Microscopic Image [1]\nPureSample: Neural Materials Learned by Sampling Microgeometry [ArXiv] [GAMES]\n2. 体积渲染\nMulti-feature Radiance Baking Neural Networks for Instant Volumetric Rendering\n3. 风格化\nLifting Lines and Tone: Image-space Stylization in Path-space [6] [Project]\n4. 这段时间读到的一些非 SIG26 文章补充\nParameter-space ReSTIR for Differentiable and Inverse Rendering [7] (SIGGRAPH 2023)\nReferences\nReferences [1] Z. Li et al., “Fiber-level Woven Fabric Capture from a Single Microscopic Image,” ACM Trans. Graph., May 2026, doi: 10.1145/3816036. [2] P. Shen, R. Li, B. Wang, and L. Liu, “Scratch-based Reflection Art via Differentiable Rendering,” ACM Trans. Graph., vol. 42, no. 4, July 2023, doi: 10.1145/3592142. [3] Z. Geng, M. Deng, X. Bai, J. Z. Kolter, and K. He, “Mean Flows for One-step Generative Modeling.” [Online]. Available: https://arxiv.org/abs/2505.13447 [4] L. Wu et al., “Neural BRDF Importance Sampling by Reparameterization.” [Online]. Available: https://arxiv.org/abs/2505.08998 [5] J. Hu, C. Yu, H. Liu, L.-q. Yan, Y. Wu, and X. Jin, “Deep Real-time Volumetric Rendering Using Multi-feature Fusion,” in SIGGRAPH '23: Special Interest Group on Computer Graphics and Interactive Techniques Conference, Los Angeles CA, United States, August 6 - 10, 2023, ACM,\u0026#x20;\u0026#x20;2023. [6] R. West, S. Mukherjee, and Y. Yue, “Lifting Lines and Tone: Image-space Stylization in Path-space,” ACM Transactions on Graphics, vol. 45, no. 4 (Proc. of SIGGRAPH 2026), 2026, doi: 10.1145/3811359. [7] W. Chang, V. Sivaram, D. Nowrouzezahrai, T. Hachisuka, R. Ramamoorthi, and T.-M. Li, “Parameter-space ReSTIR for Differentiable and Inverse Rendering,” in ACM SIGGRAPH 2023 Conference Proceedings, in SIGGRAPH '23. Los Angeles, CA, USA: Association for Computing Machinery,\u0026#x20;\u0026#x20;2023. doi: 10.1145/3588432.3591512. ","permalink":"https://rubatotree.github.io/blog/posts/sig26-paper-notes-2/","summary":"\u003ch2 id=\"loc-1\"\u003e1. 材质，外观，可微渲染\u003c/h2\u003e\n    \u003ch3 id=\"loc-2\"\u003eFiber-level Woven Fabric Capture from a Single Microscopic Image \u003ca id=\"loc-3\" href=\"#loc-18\" role=\"doc-biblioref\"\u003e[1]\u003c/a\u003e\u003c/h3\u003e\n    \u003cimg src=\"/blog/images/sig26-paper-notes/FiberLevel.png\" alt loading=\"lazy\"\u003e\n    \u003cp\u003e\u003cem\u003e另一位助教 \u003ca href=\"https://jerry-shen0527.github.io/\" target=\"_blank\" rel=\"noopener noreferrer\"\u003e\u003cspan style=\"color: #59a4ff;\"\u003e\u003cspan style=\"text-decoration: underline\"\u003e@JerryShen\u003c/span\u003e\u003c/span\u003e\u003c/a\u003e 的文章之一。这篇没有上 Sig26，只是录进了 ToG，但也放在这里。\u003c/em\u003e\u003c/p\u003e\n    \u003cp\u003e从单张显微图像通过可微渲染重建织物的纤维级几何和材质。\u003c/p\u003e\n    \u003cp\u003e对于几何建模了基本可微的五层结构：\u003c/p\u003e\n    \u003cp\u003e\u003c/p\u003e\n    \u003cul\u003e\n      \u003cli\u003e编织模式 Pattern：平纹、斜纹等纹理模式，直接预设好，用预训练的 CNN 分类；\u003c/li\u003e\n      \u003cli\u003e中心线层 Yarn Centerline：每根纤维从侧面看高度关于路径长度的函数，用抛物线和圆混合；\u003c/li\u003e\n      \u003cli\u003e纤维截面层 Cross-sectional Fiber Distribution：在中心线周围生成 \u003cspan role=\"math\"\u003e\u003csvg class=\"typst-frame\" style=\"overflow: visible; width: 0.8779999999999999em; height: 0.683em;\" viewBox=\"0 0 11.853 9.2205\" width=\"11.853pt\" height=\"9.2205pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:h5=\"http://www.w3.org/1999/xhtml\"\u003e\u003cg\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 0 9.2205)\"\u003e\u003cuse xlink:href=\"#g39F65B41E3D7ECE906702A35E9669C25\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003c/g\u003e\u003cdefs id=\"glyph\"\u003e\u003csymbol id=\"g39F65B41E3D7ECE906702A35E9669C25\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 11.448 1.9305 c 0 0.13499999 -0.121500015 0.13499999 -0.1619997 0.13499999 c -0.13500023 0 -0.13500023 -0.040499926 -0.20250034 -0.24300003 c -0.20249939 -0.7155 -0.63449955 -1.674 -1.3769999 -1.674 c -0.22949982 0 -0.3239994 0.135 -0.3239994 0.44550002 c 0 0.33749998 0.121500015 0.66150004 0.24300003 0.95849997 c 0.2564993 0.70200014 0.8234997 2.2005 0.8234997 2.97 c 0 0.87750006 -0.53999996 1.4445 -1.5524998 1.4445 c -1.0125003 0 -1.7010002 -0.59399986 -2.2005005 -1.3094997 c -0.013499737 0.17549992 -0.0539999 0.6345 -0.43200016 0.9584999 c -0.33749962 0.2835002 -0.7694998 0.35099983 -1.1069999 0.35099983 c -1.2149999 0 -1.8764999 -0.86399984 -2.106 -1.1745 c -0.067500114 0.76950026 -0.6345 1.1745 -1.2420001 1.1745 c -0.62099993 0 -0.8775 -0.52649975 -0.999 -0.7694998 c -0.24299997 -0.47250032 -0.4185 -1.269 -0.4185 -1.3095002 c 0 -0.13499999 0.162 -0.13499999 0.162 -0.13499999 c 0.13500005 0 0.14850003 0.013499975 0.2295 0.3104999 c 0.22950006 0.9585004 0.49950004 1.6065001 0.9855001 1.6065001 c 0.21599996 0 0.41849995 -0.1079998 0.41849995 -0.6209998 c 0 -0.2835002 -0.040499926 -0.43200016 -0.21599996 -1.1340001 l -0.783 -3.1185002 c -0.040500045 -0.20249999 -0.121500015 -0.513 -0.121500015 -0.5805 c 0 -0.243 0.18900001 -0.36450002 0.3915 -0.36450002 c 0.16199994 0 0.40499997 0.10800001 0.49950004 0.37800002 c 0.013499975 0.026999995 0.17550004 0.66150004 0.2564999 0.999 l 0.29700017 1.215 c 0.08099985 0.29699993 0.16199994 0.5940001 0.22949982 0.9045 l 0.17550015 0.6750002 c 0.20249987 0.41849995 0.918 1.6469998 2.2004998 1.6469998 c 0.6075001 0 0.7290001 -0.4994998 0.7290001 -0.9450002 c 0 -0.33749962 -0.094500065 -0.7154999 -0.20249987 -1.1204998 l -0.37799978 -1.566 c -0.13500023 -0.49950004 -0.14850044 -0.5805 -0.26999998 -1.026 c -0.054000378 -0.27000004 -0.1755004 -0.72900003 -0.1755004 -0.7965 c 0 -0.243 0.18900013 -0.36450002 0.3915 -0.36450002 c 0.41849995 0 0.49950027 0.33750004 0.6075001 0.7695 l 0.80999994 3.2535 c 0.040500164 0.17550015 0.75600004 1.7955 2.2275 1.7955 c 0.5805006 0 0.7290001 -0.4590001 0.7290001 -0.9450002 c 0 -0.7694998 -0.56699944 -2.3084998 -0.8369999 -3.0239997 c -0.121500015 -0.324 -0.17549992 -0.4725001 -0.17549992 -0.74250007 c 0 -0.6345 0.47249985 -1.107 1.1070004 -1.107 c 1.269 0 1.7684994 1.971 1.7684994 2.079 Z \"/\u003e\u003c/symbol\u003e\u003c/defs\u003e\u003c/svg\u003e\u003c/span\u003e 根纤维，纤维的螺旋扭转 \u003cspan role=\"math\"\u003e\u003csvg class=\"typst-frame\" style=\"overflow: visible; width: 0.64em; height: 0.683em;\" viewBox=\"0 0 8.64 9.2205\" width=\"8.64pt\" height=\"9.2205pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:h5=\"http://www.w3.org/1999/xhtml\"\u003e\u003cg\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 0 9.2205)\"\u003e\u003cuse xlink:href=\"#g6D487EE5ECC06F630D6411F35200858D\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003c/g\u003e\u003cdefs id=\"glyph\"\u003e\u003csymbol id=\"g6D487EE5ECC06F630D6411F35200858D\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 8.127 5.1705003 c 0 0 -0.01349926 0.13499975 -0.1619997 0.13499975 c -0.13499975 0 -0.13499975 -0.040499687 -0.20249987 -0.28349972 c -0.24300003 -0.8505001 -0.6884999 -1.8765001 -1.323 -2.6730003 v 0.83700013 c 0 2.1195 -1.2555003 2.781 -2.2545004 2.781 c -1.8495 0 -3.6315 -1.9305 -3.6315 -3.8339999 c 0 -1.2555001 0.81 -2.2815 2.187 -2.2815 c 0.8505001 0 1.8225002 0.31050003 2.8485003 1.1340001 c 0.17549992 -0.7155 0.6209998 -1.1340001 1.2284999 -1.1340001 c 0.7154999 0 1.1340003 0.74250007 1.1340003 0.9585 c 0 0.094500005 -0.08100033 0.13500005 -0.16200018 0.13500005 c -0.094500065 0 -0.13500023 -0.040500045 -0.17549992 -0.13500005 c -0.24300003 -0.6615 -0.75600004 -0.6615 -0.75600004 -0.6615 c -0.41849995 0 -0.41849995 1.0530001 -0.41849995 1.3770001 c 0 0.28349996 0 0.31050003 0.13499975 0.47249997 c 1.269 1.593 1.5524998 3.1725001 1.5524998 3.1725001 Z m -2.5919995 -3.834 c -1.1880002 -1.0395 -2.2275002 -1.1880001 -2.7675002 -1.1880001 c -0.81000006 0 -1.2150002 0.6075 -1.2150002 1.4715 c 0 0.6615001 0.35100007 2.1195002 0.783 2.808 c 0.6345 0.98550034 1.3635001 1.2420001 1.8360002 1.2420001 c 1.3365002 0 1.3365002 -1.7685001 1.3365002 -2.8215 c 0 -0.49950004 0 -1.2825 0.02699995 -1.512 Z \"/\u003e\u003c/symbol\u003e\u003c/defs\u003e\u003c/svg\u003e\u003c/span\u003e、偏移 \u003cspan role=\"math\"\u003e\u003csvg class=\"typst-frame\" style=\"overflow: visible; width: 1.0978em; height: 0.683em;\" viewBox=\"0 0 14.820300000000001 9.2205\" width=\"14.820300000000001pt\" height=\"9.2205pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:h5=\"http://www.w3.org/1999/xhtml\"\u003e\u003cg\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 0 9.2205)\"\u003e\u003cuse xlink:href=\"#gB56EE940A3E6922E94D0196ED1F53569\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 10.246500000000001 12.555000000000001)\"\u003e\u003cuse xlink:href=\"#g3A69B5BA14C4FC0AE0508775E710B241\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003c/g\u003e\u003cdefs id=\"glyph\"\u003e\u003csymbol id=\"gB56EE940A3E6922E94D0196ED1F53569\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 8.721001 7.4655004 c 0 -0.4590001 -0.21600056 -1.3905001 -0.7425003 -1.9170003 c -0.3510003 -0.35099983 -1.0665002 -0.783 -2.2815003 -0.783 h -1.5120001 l 0.87750006 3.5235004 c 0.08100033 0.3239994 0.121500015 0.45899963 0.37800026 0.49949932 c 0.121500015 0.013500214 0.5534997 0.013500214 0.8234997 0.013500214 c 0.9585004 0 2.4570007 0 2.4570007 -1.3364997 Z m 1.4714994 -6.21 c 0 0.16199994 -0.1619997 0.16199994 -0.1619997 0.16199994 c -0.121500015 0 -0.14850044 -0.094499946 -0.17549992 -0.18900001 c -0.33750057 -0.999 -0.9180002 -1.2285 -1.2285004 -1.2285 c -0.44550037 0 -0.53999996 0.29700002 -0.53999996 0.82350004 c 0 0.41849995 0.08100033 1.107 0.13500023 1.5389999 c 0.026999474 0.18900013 0.0539999 0.44550014 0.0539999 0.6345 c 0 1.0395 -0.9045 1.458 -1.269 1.5930002 c 1.3634996 0.29699993 2.9700003 1.2420001 2.9700003 2.6055002 c 0 1.1610003 -1.2150002 2.0249996 -2.9835005 2.0249996 h -3.8474998 c -0.27000022 0 -0.3915 0 -0.3915 -0.2699995 c 0 -0.14850044 0.12149978 -0.14850044 0.37799978 -0.14850044 c 0 0 0.2835002 0 0.513 -0.026999474 c 0.24300003 -0.027000427 0.36450005 -0.04050064 0.36450005 -0.21600056 c 0 -0.0539999 -0.013499975 -0.09449959 -0.0539999 -0.25650024 l -1.809 -7.2495 c -0.13499999 -0.5265 -0.16200006 -0.63449997 -1.2285001 -0.63449997 c -0.24300003 0 -0.36450005 0 -0.36450005 -0.26999998 c 0 -0.14850001 0.18900001 -0.14850001 0.18900001 -0.14850001 l 1.701 0.0405 l 1.7145 -0.0405 c 0.10800028 0 0.26999998 0 0.26999998 0.27 c 0 0.1485 -0.121500015 0.1485 -0.37799978 0.1485 c -0.49950004 0 -0.87750006 0 -0.87750006 0.24300003 c 0 0.08099997 0.02699995 0.14849997 0.040499926 0.2295 l 0.89100003 3.5775 h 1.6065001 c 1.2284999 0 1.4714999 -0.75600004 1.4714999 -1.2285001 c 0 -0.20249987 -0.1079998 -0.62100005 -0.18900013 -0.93149996 c -0.094500065 -0.37800002 -0.21600008 -0.87750006 -0.21600008 -1.1475 c 0 -1.4580001 1.6200004 -1.4580001 1.7955003 -1.4580001 c 1.1475 0 1.6199999 1.3635001 1.6199999 1.5525001 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"g3A69B5BA14C4FC0AE0508775E710B241\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 3.0618 5.90625 c 0 0.15119982 -0.11339998 0.35909986 -0.37800002 0.35909986 c -0.25515008 0 -0.5292001 -0.24569988 -0.5292001 -0.5197501 c 0 -0.16064978 0.12284994 -0.35909986 0.37800002 -0.35909986 c 0.27405 0 0.5292001 0.2645998 0.5292001 0.5197501 Z m 0.24569988 -4.5549 c 0 0.12285006 -0.12284994 0.12285006 -0.15120006 0.12285006 c -0.1322999 0 -0.14174986 -0.05669999 -0.17954993 -0.16065001 c -0.21735 -0.756 -0.63314986 -1.14345 -1.0016999 -1.14345 c -0.18900001 0 -0.23625004 0.12285 -0.23625004 0.33074996 c 0 0.21735 0.06615007 0.3969 0.15120006 0.6048 l 0.3024 0.75600004 l 0.4630499 1.20015 c 0.028350115 0.09449983 0.05669999 0.20789981 0.05669999 0.30239987 c 0 0.44414997 -0.37800002 0.8032501 -0.8977499 0.8032501 c -0.93555 0 -1.37025 -1.2852001 -1.37025 -1.4458499 c 0 -0.12285018 0.13229999 -0.12285018 0.16064999 -0.12285018 c 0.13230002 0 0.14174998 0.047250032 0.17009997 0.15120006 c 0.2457 0.81270003 0.6615 1.1529 1.01115 1.1529 c 0.15119994 0 0.23625004 -0.07559991 0.23625004 -0.33075 c 0 -0.21735 -0.05669999 -0.3591001 -0.29295003 -0.94499993 l -0.59535 -1.52145 c -0.037799954 -0.12284994 -0.08504999 -0.23624998 -0.08504999 -0.39689994 c 0 -0.44415003 0.37800002 -0.80325 0.89775 -0.80325 c 0.94500005 0 1.3607999 1.3040999 1.3607999 1.4458499 Z \"/\u003e\u003c/symbol\u003e\u003c/defs\u003e\u003c/svg\u003e\u003c/span\u003e、周期性挤压变形等都是可微参数；\u003c/li\u003e\n      \u003cli\u003e随机噪声层 Randomized Variation：用柏林噪声和白噪声让纤维的半径和纵向产生变化、噪声种子本身不可微但强度可微。\u003c/li\u003e\n      \u003cli\u003e飘散纤维层 Flyaway Model：额外手动添加飘散出来的断线等纤维（定义有毛发 Hair 和环路 Loop 两种），模拟现实材质情况。这一层没法可微优化出来。\u003c/li\u003e\n    \u003c/ul\u003e\n    \u003cp\u003e\u003c/p\u003e","title":"SIGGRAPH 2026 论文笔记 II: Rendering"},{"content":" 写一些笔记记录一下领域的最新进展。会持续更新，主页的 blog 发表日期仅供参考~\n1. 正向渲染加速 Gaussian Point Splatting [1] [Project] 本文用蒙特卡洛方法代替深度排序，加速了超大 3DGS 场景在 GPU 上的正向渲染过程。目前仅支持正向渲染。\n本文注意到单个 Gaussian Splat 到屏幕空间的行为可以等价于在屏幕空间上按一个 Gaussian 分布放回采样 个点的结果的期望（ 和 Gaussian 的参数相关）。而一系列 Gaussians 做 Alpha Blending 的行为可以等价于，对每个 Gaussian 采样 个点，然后对每个像素取深度上最靠前的点 作为 Splat 结果的无偏估计值。\n一方面该方法优化掉了每个 Tile 都要 GPU 排序的瓶颈，优化到了关于 Gaussian 数量的线性复杂度，还可以通过遮挡剔除等方式进一步剪枝。另一方面这个过程还可以高度并行化，取 的操作也只需要在屏幕空间缓冲区做一个很高效的原子查询+覆盖，因此跑起来就很快。并且对于超大场景，由于存在大量小于 1 像素的极小 Gaussians，这些 Gaussians 在传统管线中会占用大量的排序计算，造成性能瓶颈，而在该管线中可能只对应非常小的采样点数，因此效率提升会更大。\n由于其将深度排序行为替换成了蒙特卡洛方法，它还天然支持渲染出 3DGRT 特有的 “Gaussian 穿插”行为，避免了相机移动时的 Popping 现象。这种 Splatting 方法似乎是可以做到和 3DGRT 管线一致的。（3DGRT 管线可能被迫在射线相交的高斯球过多时放弃靠后的高斯球，但这一方面影响不大，另一方面也可以用随机终止 [2] 代替 Alpha Blending 做到一致无偏）\n图 1 Popping 行为和穿插行为 论文提到可微渲染的困难主要有： 是整数，关于 Gaussian 的位姿和密度不可微； 操作不可微；可微难以做到 空间复杂度。\n这篇的效率瓶颈主要在原子操作互斥锁、采样 Gaussians 时的显存吞吐、分布本身缺陷造成大 Gaussians 生成过多采样点拖慢效率等。对于这些问题本文都用了一些策略去应对。对于采样过程论文提到计算 CDF 并二分的方法比用别名法要快，每次相机移动都会改变所有 Gaussian 的 分布的确是个麻烦事。\n感觉这篇 Monte Carlo 方法的主要缺陷是，对屏幕空间颜色贡献较大的 Gaussian Point 主要是靠近相机的 Gaussian Point，被挡住的 Gaussian Point 实际上的贡献密度很小。感觉缺一点重要性采样，也许可做哇。这个问题在传统 3DGS 管线中也存在。本文的方法主要是靠遮挡剔除解决这个问题的。\n本文和 Stochastic Ray Tracing for the Reconstruction of 3D Gaussian Splatting [2] 同属于用 Monte Carlo 概率方法优化 3D Gaussian Primitive 渲染的方法。区别在于后一篇是基于 3DGRT 管线直接用 Monte Carlo 方法代替了 排序 + Alpha Blending 的过程，保持可微，效率瓶颈仍在求交；而该论文提出了一种比较新的 Splatting 方式，不需要求交、排序等操作，但仅支持正向渲染。二者每 spp 的像素颜色分布也有所不同。这篇的思路中被挡住的 Gaussians 基本就不会被采样到，从而不会影响效率。\n在 NeRF 上的类似工作则在 2023 年就有人做过 [3]，大致思路就是考虑到密度估计比颜色估计更快（只用查哈希表），因此先求路径上颜色贡献关于路径的 CDF，然后按该累计分布密度随机采样几个点得到无偏估计，最后做图像空间降噪。这篇的效率提升是传统方法的 7 倍，要低于 Gaussian Point Splatting 的提升倍数，可能深度排序在 3DGS 中还是太耗了。这篇在当年是 Conference Paper。不知道这样改进后密度估计的开销占比有多大。如果要设计基于和 Gaussian Point Splatting 一样的采样-覆写的方法，主要困难是对视锥内的密度场采样。不知道能不能靠预计算做一下。这篇由于是用贡献 CDF 采样颜色，所以天然不易采样到被挡住的点，比较类似 Stochastic 3DGRT。\n由于这篇和 Stochastic 3DGRT 一起将随机深度采样的方法变成了最高效的 3D Gaussian Primitives 正向渲染方法，基于低 spp 渲染结果先验的降噪工作可能会变得更加重要。\n这个项目没有什么依赖，工程非常好编译，感觉对进一步优化很友好。在我的 4060 笔记本电脑上试着跑了一下， 30M Gaussians 的场景可以跑到实时，但是帧间的噪声还是很明显。感觉网络降噪需求很迫切哇，想想每个像素能不能拿到更多信息，比如其对应的 Gaussian 的元信息，然后在相邻像素之间做一点概率统计重用什么的，感觉很有搞头啊。\n图 2 St. Sebastian church (30 M Gaussians) 场景在我的电脑上运行的结果。帧率在 30 帧左右，帧间噪声还是很明显的。 Mobile3DGS³: Accelerate Mobile 3DGS Rendering via Gradient-Aware Super-Sampling and Frame Interpolation 曾经助教、现好朋友 @SyouSanGin 的第一篇 SIGGRAPH，靠内部关系拿到了文章。\n本文做的是 3DGS 的超分。\n主要是观察到 3DGS 的屏幕空间梯度可以提前计算并缓存，在 0.25x 分辨率渲染时 Splat 颜色的同时也 Splat 每个像素的梯度信息，进一步做像素间多项式样条插值，即可在更快的速度内得到高质量的正向渲染结果。\n由于 3DGS 在图像空间的渲染结果本来就是比较光滑的（受到 3DGS 基元大小的限制，还受到训练集分辨率的限制），因此样条插值效果就很好。\n据原作者所说，后期的神经网络图像调优和帧间插值在本文的方法中贡献并不大。作者也测试过用二阶微分信息进一步优化插值的信息量，但并没有明显提升。\n过去的渲染超分方法（不限于 GS）普遍需要 GBuffer 作为网络的补充信息，而本文面对 3DGS 的任务当然是没有 GBuffer 的，合理利用已有信息量（像素点的微分信息）对邻域进行插值是相当漂亮的思路。在 25 年 11 月该文作者发现有一篇 ArXiv 论文 [4] 和他的思路撞了。但这篇提出了切空间梯度缓存的方法并且在工程上实现在了 GPU+NPU 上，在效率上做到了 make sense。\n很喜欢这种充分挖掘并高效利用信息量，而不是靠神经网络去暴力发现信息的规律的工作。\n2. 表达能力优化 Ref-DGS: Reflective Dual Gaussian Splatting [5] [Project] 靠构建“虚像”实现 2DGS 近场镜面反射的工作。靠神经网络去暴力发现信息的规律的工作\n过去的工作在重建镜面/Specular 场景时经常存在强行拟合镜面反射导致几何塌陷的问题，在几何出问题的同时光照也没能很好地拟合。因此本文希望解耦仅与几何相关的视角无关光照和 Specular 光照，从而在可微渲染过程中同时得到可信的几何和可信的 Specular 光照。\n考虑将光照分为视角无关和视角相关两部分相加，视角无关的部分可以很好地由传统的、几何紧贴表面的 2DGS（Geo-GS）表示。因为有了可信的几何所以也可以在上面得到 Normal 并优化 Diffuse 和 Roughness 材质参数。注意这里的 Diffuse 是加性的光照“直流分量”，而不是乘性的 Albedo，在定义上和材质模型有一些区别。\n视角相关部分进一步分为相机位姿无关（远场）和相机位姿相关（近场）部分，前者可以用可学习的环境贴图表示，后者则是本文主要的创新点，用另一组存储特征向量的 2DGS（Local-GS）表示，表示镜面内部的“虚像”。将 Local-GS Splat 到屏幕上、对每个像素将 Roughness 信息、相机与法线夹角信息和环境光贴图一起送进一个轻量的可学习 MLP 得到 Specular，直接加到 Diffuse 图上。\n图 3 Ref-DGS 的渲染管线展示。Geo-GS 为视角无关的 GS，Sph-Mip 为远场光照（环境贴图 MipMap），Local-GS 为渲染近场视角相关光照使用的虚拟“虚像”高斯。 Geo-GS 的训练是有深度先验做引导的。在合适的超参数下，Geo-GS 会忠实地贴在几何表面，Local-GS 则会进入物体内部拟合 Specular，从而得到优秀的几何。同时论文也确实能很好地表现将 Diffuse 部分和 Specular 部分解耦开（虽然这不是我们想要的解耦“烘焙式光照”）。\n很难信任用“虚像”的方法来做 Specular 的视差现象。在有曲率的曲面内部仍然做透视投影感觉根本说不通，不知道神经网络学到什么东西就拟合出来了。很难想象物体内部多个视角生成的 Local-GS 和轻量 MLP 是怎么耦合的。MLP 训练的参数是针对全局的，不知道为什么不做预训练。这个方法看起来也做不了薄物体，不知道怎样才能避免干扰。对 3DGS 不擅长处理的视角相关光照分开处理当然是合理的，但这样做实在让人不安。实验展示了指标上升，但看不出指标上升是因为渲染管线好了还是单纯因为几何好了（考虑到这里几何还用了先验）。\n但有启发性的一点是，把特征放在物体内部确实是合乎 Specular 信息的规律的：当绕着金属物体旋转时，高曲率边界的光照会高频快速地改变，这一部分较大的信息量可以由贴近边界的小高斯去拟合得到；内部的光照会相对较慢地流动，这一部分视角间共用的信息可以由靠近物体内部的大特征高斯拟合。总觉得反射信息共用应当有更好的方式去做。\nLearning View-Dependent Splatting Kernels [6] [Project] [GAMES] 尝试通过学习 Splatting Kernel 提高表达能力。看实验感觉主要优化的是输入视角不充分的区域。 靠神经网络去暴力发现信息的规律的工作之二\n本文的渲染管线是先将 Gaussian 椭球作为代理几何 Splat 到屏幕空间以得到 Splat 区域每个点到重心的标准化距离；而得到颜色的方法是对每个 Gaussian 将 Gaussian 存储的隐向量（通常为 5 维）、相机空间变换（坐标、缩放因子、旋转矩阵）送进一个全局的“神经投影”MLP 中“投影”得到一个 2D 空间的隐向量，再对每个像素点用另一个全局“解码器” MLP 接受每个 Gaussian 的隐向量以及标准化距离、输出该 Gaussian 对该像素的贡献，最后做 Alpha Blending 得到最终颜色。训练过程中，Gaussian 的隐向量和相机空间变换都是可学习的参数。\n图 4 本文的渲染与训练管线展示。 投影过程换成了“神经投影”，输出值自然可以根据视角不同发生变化，比原先用球谐函数的表达能力要强很多。正向渲染过程中由于 的推理开销较大，因此直接对每个 Gaussian 预计算标准化后径向每个采样点的颜色值并线性插值。\n一个有趣的现象是，学习到的 Kernel 参数在相似的场景、物体下会有相似的分布，如可以为树叶、头发等材质生成相似的“最适合”的 Kernel 形状，说明 Kernel 确实学到了一些物体本身的光照特征。\n作者提到这篇解决的问题是让 3DGS 的视角一致性更好了，如一个“长条形”的高斯从短边积分和从长边积分的密度应该不同，一篇 EG2025 的文章《Does 3D Gaussian Splatting Need Accurate Volumetric Rendering?》[7] 也论述了这种视角依赖性的现象，虽然没太看懂，感觉怪怪的。\n我觉得这篇之所以效果比较好是因为它把高斯的不同视角变得独立了，如优化正面能只优化正面，而不会在侧面产生一些伪影（所以输入不充分的区域效果好）。同时它的神经 Kernel 也保证了比较光滑，不会优化出一些比较明显的伪影（和 GabSplat 相比）。总之感觉更多是降低了“出错”的概率，而不是去让好的地方更好了。比较期待能用一个足够好的 Kernel 把细节变得更漂亮，消掉那种“3DGS 痕迹”。实验上的提升比起传统的 3DGS 在 2dB PSNR 左右，和 SOTA 方法相比基本上不到 1dB。\n3. 辐射场的新应用 Radiance Fields from Photons [8] [ArXiv] 针对“单光子相机”提出的 NeRF 辐射场训练方法。\n“单光子相机”（Single Photon Camera）指每个像素仅有 和 状态表示是否有光子，但帧率极高，可以理解为曝光时间极短、曝光次数极多的相机。“传统相机”（Conventional Camera）则指像素值在 之间、帧率正常、曝光时间长的相机。可以用前者的图像通过累计多次曝光得到后者的图像。前者能提供更多的信息量，特别地，可以避免长时间曝光产生的过曝、拖影等瑕疵，也能解决低亮度下传统相机信息量不足导致重建效果差的问题。现在越来越多的设备开始支持这种单光子相机，因此该论文提出的方法具有很大的实际应用价值。\n单光子相机的输入数量极大、每张输入的噪声也很高，且由于高噪无法通过几张相邻输入的关系得到相机位姿。本论文针对这种输入解决了三个问题：\n辐射场训练：根据泊松分布，一个像素被打进一个光子的概率 和像素内辐射强度 、曝光时间 的关系为\n单光子相机得到的结果服从以上概率的二项分布，训练一个可做体积分的概率场而非辐射场，由最大似然估计的原理知优化 即可，形式上和传统 NeRF 是相同的，只是积分后从概率转换到辐射强度需要经过一个含曝光时间 参数的映射。\n相机位姿：先根据相邻帧模拟曝光一次重建一个相对不可靠的“虚拟”位姿，然后在辐射场训练的同时把相机位姿也作为可训练参数进行优化。考虑到曝光极频繁的相机运动一定是非常光滑的，本文用低通滤波后的位姿和当前位姿的 Loss 作为一个正则项引导位姿的平滑优化。 大输入量：bit 压缩、实时磁盘读取等 common trick。 本文 claim 的针对运动相机、低光照场景、过曝场景的优化是显然的，因为单光子相机提供了足够多的信息量。技术上感觉也没什么难想到的地方，感觉像是纯粹应用比较小众且有前景就上了。这篇论文的 writing 也很神奇，每一段都有小标题，大标题的用词也很不同寻常，第一次见这种风格的文章。\n本文第 7 节论述了对迁移到 3DGS 的尝试，作者认为 3DGS 对输入的噪声过于敏感，以至于在该应用时优化会非常不稳定，造成大量的过拟合噪声，剪枝策略甚至会因为场景中大部分像素的方差都过大而把高斯球删光。论文提出先在预曝光的结果上训练一段时间再逐渐减小曝光时间精细调整（Sheduled Temporal Smoothing 策略）可以得到不错的结果，但可以观察到这仍然引入了运动模糊的问题。这也是一个未来改进方向（抗输入噪声的 3DGS）。\n图 5 迁移至 3DGS 的尝试结果。直接暴力训练会得到一个全黑的画面（Single Photon），预曝光策略能得到不错的结果，但仔细看运动模糊还是很严重。 到底是从哪里知道这种新应用的哇，我也想找一点冷门的应用场景写论文……不知道这篇的应用能不能继续往后水几篇。\n4. 这段时间读到的一些非 SIG26 文章补充 MVInverse: Feed-forward Multiview Inverse Rendering in Seconds [9] [Project] (CVPR2026) 输入多视角图片，输出多视角 G-Buffer，效率优化到实时级别。\n本文提出了交替注意力网络结构，在以往单图注意力网络的基础上交替叠加全局、多图之间的注意力网络，从而能在不同视角的注意力之间“对账”保证多视角一致性。\n对于编码器，在使用 DINOv2 提供语义先验的基础上还用了 ResNeXt 编码器提取高频特征，保证输出图片是锐利的。\n训练阶段采用两阶段训练，第一阶段在标注正确的 3D 数据集上学习物理规律，第二阶段自监督、用真实视频的光流约束，保证两帧之间对同一点的预测输出一致，以提高训练数据量。用锚点损失防止模型微调时产生漂移。\n因为以往的预测都是单图的，这里多图提供了更大的信息量，因此指标提升是可以预见的。并且因为多图逆渲染的需求是存在的（可微渲染这边基本都在做这种），故事也说得通。\n我没有怎么看过生成方面的文章，每学一个新东西都觉得好神奇。总感觉材质重建这种任务还是得靠生成式方法。\nHDR-NeRF: High Dynamic Range Neural Radiance Fields [10] Project (CVPR 2022) 用多个曝光条件不同的图片训练 HDR 的 NeRF 场。\n在体积分得到辐射量的后端再接一个根据相机曝光原理设计的可学习含参函数，就能顺便把该视角图片的曝光曲线也学了，因为信息量充分，所以能学到准确的 HDR NeRF 场。\n更早的一篇类似的 NeRF in the Wild [11] 也能达到类似训练 HDR 场的目的，但这一篇主要的卖点是在拍摄条件较差的输入下重建可信的 NeRF 场。\n因为当时想着材质重建做不好可能是光场 LDR 的原因，就看了这篇，结果做了实验发现 HDR 的光场并不能得到什么提升，遂放弃。这篇感觉也是一篇从应用切入的文章，好羡慕这种发现小众应用场景的科研能力。\nTable of Contents\n1. 正向渲染加速\nGaussian Point Splatting [1] [Project]\nMobile3DGS³: Accelerate Mobile 3DGS Rendering via Gradient-Aware Super-Sampling and Frame Interpolation\n2. 表达能力优化\nRef-DGS: Reflective Dual Gaussian Splatting [5] [Project]\nLearning View-Dependent Splatting Kernels [6] [Project] [GAMES]\n3. 辐射场的新应用\nRadiance Fields from Photons [8] [ArXiv]\n4. 这段时间读到的一些非 SIG26 文章补充\nMVInverse: Feed-forward Multiview Inverse Rendering in Seconds [9] [Project] (CVPR2026)\nHDR-NeRF: High Dynamic Range Neural Radiance Fields [10] Project (CVPR 2022)\nReferences\nReferences [1] J. Rijsdijk, C. Peters, M. Weinnman, and R. Marroquim, “Gaussian Point Splatting,” ACM Trans. Graph., vol. 45, no. 4, 2026, doi: 10.1145/3811272. [2] P. Xu, X. Sun, K. Mullia, R. Fei, I. Georgiev, and S. Zhao, “Stochastic Ray Tracing for the Reconstruction of 3D Gaussian Splatting.” [Online]. Available: https://arxiv.org/abs/2603.23637 [3] K. Gupta et al., “MCNeRF: Monte Carlo Rendering and Denoising for Real-Time NeRFs,” in SIGGRAPH Asia 2023 Conference Papers, in SA '23. Sydney, NSW, Australia: Association for Computing Machinery,\u0026#x20;\u0026#x20;2023. doi: 10.1145/3610548.3618221. [4] S. Niedermayr and C. N. R. Westermann, “Lightweight Gradient-Aware Upscaling of 3D Gaussian Splatting Images.” [Online]. Available: https://arxiv.org/abs/2503.14171 [5] N. Fan, Y. Wang, D. Yan, and P. Wonka, “Ref-DGS: Reflective Dual Gaussian Splatting.” [Online]. Available: https://arxiv.org/abs/2603.07664 [6] H. Ding, Z. Liu, F. Pei, K. Zhou, and H. Wu, “Learning View-Dependent Splatting Kernels.” [Online]. Available: https://arxiv.org/abs/2605.25426 [7] A. Celarek, G. Kopanas, G. Drettakis, M. Wimmer, and B. Kerbl, “Does 3D Gaussian Splatting Need Accurate Volumetric Rendering?,” Computer Graphics Forum, vol. 44, no. 2, p. e70032, 2025, doi: https://doi.org/10.1111/cgf.70032. [8] S. Jungerman, A. Garg, and M. Gupta, “Radiance Fields from Photons.” [Online]. Available: https://arxiv.org/abs/2407.09386 [9] X. Wu, C. Ren, J. Zhou, X. Li, and Y. Liu, “MVInverse: Feed-forward Multi-view Inverse Rendering in Seconds.” [Online]. Available: https://arxiv.org/abs/2512.21003 [10] X. Huang, Q. Zhang, Y. Feng, H. Li, X. Wang, and Q. Wang, “Hdr-nerf: High dynamic range neural radiance fields,” in Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition,\u0026#x20;\u0026#x20;2022, pp. 18398–18408. [11] R. Martin-Brualla, N. Radwan, M. S. M. Sajjadi, J. T. Barron, A. Dosovitskiy, and D. Duckworth, “NeRF in the Wild: Neural Radiance Fields for Unconstrained Photo Collections.” [Online]. Available: https://arxiv.org/abs/2008.02268 ","permalink":"https://rubatotree.github.io/blog/posts/sig26-paper-notes-1/","summary":"\u003cimg src=\"/blog/images/sig26-paper-notes/teaser-1.png\" alt loading=\"lazy\"\u003e\n    \u003cp\u003e写一些笔记记录一下领域的最新进展。会持续更新，主页的 blog 发表日期仅供参考~\u003c/p\u003e\n    \u003ch2 id=\"loc-1\"\u003e1. 正向渲染加速\u003c/h2\u003e\n    \u003ch3 id=\"loc-2\"\u003eGaussian Point Splatting \u003ca id=\"loc-3\" href=\"#loc-24\" role=\"doc-biblioref\"\u003e[1]\u003c/a\u003e [\u003ca href=\"https://jorisar.nl/gaussian_point_splatting/\" target=\"_blank\" rel=\"noopener noreferrer\"\u003e\u003cspan style=\"color: #59a4ff;\"\u003e\u003cspan style=\"text-decoration: underline\"\u003eProject\u003c/span\u003e\u003c/span\u003e\u003c/a\u003e]\u003c/h3\u003e\n    \u003cimg src=\"/blog/images/sig26-paper-notes/Rijsdijk2026GaussianPointSplatting.png\" alt loading=\"lazy\"\u003e\n    \u003cp\u003e本文用蒙特卡洛方法代替深度排序，加速了超大 3DGS 场景在 GPU 上的正向渲染过程。目前仅支持正向渲染。\u003c/p\u003e\n    \u003cp\u003e本文注意到单个 Gaussian Splat 到屏幕空间的行为可以等价于在屏幕空间上按一个 Gaussian 分布放回采样 \u003cspan role=\"math\"\u003e\u003csvg class=\"typst-frame\" style=\"overflow: visible; width: 0.909em; height: 0.683em;\" viewBox=\"0 0 12.271500000000001 9.2205\" width=\"12.271500000000001pt\" height=\"9.2205pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:h5=\"http://www.w3.org/1999/xhtml\"\u003e\u003cg\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 0 9.2205)\"\u003e\u003cuse xlink:href=\"#g97EE8E40EE0EEE4FD2AF6896DC5BA0D7\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003c/g\u003e\u003cdefs id=\"glyph\"\u003e\u003csymbol id=\"g97EE8E40EE0EEE4FD2AF6896DC5BA0D7\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 11.8935 9.0720005 c 0 0 0 0.14849949 -0.17549992 0.14849949 c -0.44550037 0 -0.9180002 -0.040499687 -1.3635006 -0.040499687 c -0.45899963 0 -0.9314995 0.040499687 -1.3769999 0.040499687 c -0.080999374 0 -0.24300003 0 -0.24300003 -0.2699995 c 0 -0.14850044 0.13500023 -0.14850044 0.24300003 -0.14850044 c 0.76950073 -0.013500214 0.9180002 -0.29699993 0.9180002 -0.59399986 c 0 -0.040499687 -0.026999474 -0.24300003 -0.040499687 -0.2835002 l -1.5120001 -6.0074997 l -2.9835005 7.047001 c -0.1079998 0.24299908 -0.121500015 0.2564993 -0.43199968 0.2564993 h -1.8090003 c -0.26999998 0 -0.3915 0 -0.3915 -0.2699995 c 0 -0.14850044 0.121500015 -0.14850044 0.37800002 -0.14850044 c 0.067500114 0 0.9180002 0 0.9180002 -0.121500015 l -1.8090003 -7.2495003 c -0.13499999 -0.53999996 -0.36449993 -0.972 -1.458 -1.0125 c -0.08100003 0 -0.22950006 -0.013500005 -0.22950006 -0.26999998 c 0 -0.094500005 0.067500055 -0.14850001 0.17550004 -0.14850001 c 0.43200004 0 0.9045 0.0405 1.35 0.0405 c 0.4590001 0 0.94499993 -0.0405 1.3905001 -0.0405 c 0.067499876 0 0.24300003 0 0.24300003 0.27 c 0 0.13499999 -0.121500015 0.1485 -0.26999998 0.1485 c -0.783 0.02700001 -0.89100003 0.324 -0.89100003 0.59400004 c 0 0.094499946 0.013499975 0.16199994 0.0539999 0.31050003 l 1.7820003 7.1280003 c 0.0539999 -0.08100033 0.0539999 -0.1079998 0.121500015 -0.24300003 l 3.3614998 -7.9515 c 0.094500065 -0.22950001 0.13500023 -0.2565 0.25650024 -0.2565 c 0.14849949 0 0.14849949 0.0405 0.2159996 0.28350002 l 1.8900003 7.5195 c 0.13500023 0.54000044 0.37800026 0.9585004 1.4580002 0.9990001 c 0.067500114 0 0.22949982 0.013500214 0.22949982 0.27000046 Z \"/\u003e\u003c/symbol\u003e\u003c/defs\u003e\u003c/svg\u003e\u003c/span\u003e 个点的结果的期望（\u003cspan role=\"math\"\u003e\u003csvg class=\"typst-frame\" style=\"overflow: visible; width: 0.909em; height: 0.683em;\" viewBox=\"0 0 12.271500000000001 9.2205\" width=\"12.271500000000001pt\" height=\"9.2205pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:h5=\"http://www.w3.org/1999/xhtml\"\u003e\u003cg\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 0 9.2205)\"\u003e\u003cuse xlink:href=\"#g97EE8E40EE0EEE4FD2AF6896DC5BA0D7\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003c/g\u003e\u003cdefs id=\"glyph\"\u003e\u003csymbol id=\"g97EE8E40EE0EEE4FD2AF6896DC5BA0D7\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 11.8935 9.0720005 c 0 0 0 0.14849949 -0.17549992 0.14849949 c -0.44550037 0 -0.9180002 -0.040499687 -1.3635006 -0.040499687 c -0.45899963 0 -0.9314995 0.040499687 -1.3769999 0.040499687 c -0.080999374 0 -0.24300003 0 -0.24300003 -0.2699995 c 0 -0.14850044 0.13500023 -0.14850044 0.24300003 -0.14850044 c 0.76950073 -0.013500214 0.9180002 -0.29699993 0.9180002 -0.59399986 c 0 -0.040499687 -0.026999474 -0.24300003 -0.040499687 -0.2835002 l -1.5120001 -6.0074997 l -2.9835005 7.047001 c -0.1079998 0.24299908 -0.121500015 0.2564993 -0.43199968 0.2564993 h -1.8090003 c -0.26999998 0 -0.3915 0 -0.3915 -0.2699995 c 0 -0.14850044 0.121500015 -0.14850044 0.37800002 -0.14850044 c 0.067500114 0 0.9180002 0 0.9180002 -0.121500015 l -1.8090003 -7.2495003 c -0.13499999 -0.53999996 -0.36449993 -0.972 -1.458 -1.0125 c -0.08100003 0 -0.22950006 -0.013500005 -0.22950006 -0.26999998 c 0 -0.094500005 0.067500055 -0.14850001 0.17550004 -0.14850001 c 0.43200004 0 0.9045 0.0405 1.35 0.0405 c 0.4590001 0 0.94499993 -0.0405 1.3905001 -0.0405 c 0.067499876 0 0.24300003 0 0.24300003 0.27 c 0 0.13499999 -0.121500015 0.1485 -0.26999998 0.1485 c -0.783 0.02700001 -0.89100003 0.324 -0.89100003 0.59400004 c 0 0.094499946 0.013499975 0.16199994 0.0539999 0.31050003 l 1.7820003 7.1280003 c 0.0539999 -0.08100033 0.0539999 -0.1079998 0.121500015 -0.24300003 l 3.3614998 -7.9515 c 0.094500065 -0.22950001 0.13500023 -0.2565 0.25650024 -0.2565 c 0.14849949 0 0.14849949 0.0405 0.2159996 0.28350002 l 1.8900003 7.5195 c 0.13500023 0.54000044 0.37800026 0.9585004 1.4580002 0.9990001 c 0.067500114 0 0.22949982 0.013500214 0.22949982 0.27000046 Z \"/\u003e\u003c/symbol\u003e\u003c/defs\u003e\u003c/svg\u003e\u003c/span\u003e 和 Gaussian 的参数相关）。而一系列 Gaussians 做 Alpha Blending 的行为可以等价于，对每个 Gaussian \u003cspan role=\"math\"\u003e\u003csvg class=\"typst-frame\" style=\"overflow: visible; width: 1.0248em; height: 0.683em;\" viewBox=\"0 0 13.8348 9.2205\" width=\"13.8348pt\" height=\"9.2205pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:h5=\"http://www.w3.org/1999/xhtml\"\u003e\u003cg\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 0 9.2205)\"\u003e\u003cuse xlink:href=\"#g16FCB66E7EC3CC47C0739BCD672A0DEE\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 9.261 12.555)\"\u003e\u003cuse xlink:href=\"#g3A69B5BA14C4FC0AE0508775E710B241\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003c/g\u003e\u003cdefs id=\"glyph\"\u003e\u003csymbol id=\"g16FCB66E7EC3CC47C0739BCD672A0DEE\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 10.26 9.382501 c 0 0.040499687 -0.027000427 0.13499928 -0.14850044 0.13499928 c -0.040499687 0 -0.0539999 -0.01349926 -0.20249939 -0.1619997 l -0.9449997 -1.0395002 c -0.121500015 0.18900013 -0.7425003 1.2014999 -2.2410007 1.2014999 c -3.0105 0 -6.048 -2.9834995 -6.048 -6.1154995 c 0 -2.1465 1.4985001 -3.6990001 3.6855004 -3.6990001 c 0.59399986 0 1.2014999 0.121500015 1.6875 0.32400003 c 0.6749997 0.27 0.93149996 0.5535 1.1745 0.82350004 c 0.121500015 -0.33750004 0.47249985 -0.8370001 0.6075001 -0.8370001 c 0.06749964 0 0.09449959 0.054 0.09449959 0.054 c 0.027000427 0.027000003 0.16200018 0.54 0.2295003 0.82350004 l 0.25650024 1.0395 c 0.0539999 0.22950006 0.121500015 0.4590001 0.17549992 0.6884999 c 0.14849949 0.6075001 0.1619997 0.6345 0.9314995 0.64800024 c 0.067500114 0 0.21600056 0.013499975 0.21600056 0.26999998 c 0 0.09449983 -0.067500114 0.14849997 -0.17549992 0.14849997 c -0.31050014 0 -1.1070004 -0.040500164 -1.4175005 -0.040500164 l -1.8899999 0.040500164 c -0.121500015 0 -0.2835002 0 -0.2835002 -0.26999998 c 0 -0.14849997 0.10800028 -0.14849997 0.4050002 -0.14849997 c 0 0 0.40499973 0 0.7154999 -0.027000189 c 0.3510003 -0.040499926 0.41849995 -0.08099985 0.41849995 -0.2565 c 0 -0.121500015 -0.14849997 -0.72899985 -0.28349972 -1.2285 c -0.37800026 -1.485 -2.1330004 -1.6335 -2.6055002 -1.6335 c -1.296 0 -2.7135 0.7695 -2.7135 2.835 c 0 0.41849995 0.13499999 2.646 1.5525 4.401 c 0.72899985 0.9180002 2.0385 1.7414999 3.3750002 1.7414999 c 1.3769999 0 2.1735 -1.0395002 2.1735 -2.6054997 c 0 -0.53999996 -0.040499687 -0.5535002 -0.040499687 -0.6884999 c 0 -0.13500023 0.14849949 -0.13500023 0.20249939 -0.13500023 c 0.17549992 0 0.17549992 0.02699995 0.24300003 0.26999998 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"g3A69B5BA14C4FC0AE0508775E710B241\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 3.0618 5.90625 c 0 0.15119982 -0.11339998 0.35909986 -0.37800002 0.35909986 c -0.25515008 0 -0.5292001 -0.24569988 -0.5292001 -0.5197501 c 0 -0.16064978 0.12284994 -0.35909986 0.37800002 -0.35909986 c 0.27405 0 0.5292001 0.2645998 0.5292001 0.5197501 Z m 0.24569988 -4.5549 c 0 0.12285006 -0.12284994 0.12285006 -0.15120006 0.12285006 c -0.1322999 0 -0.14174986 -0.05669999 -0.17954993 -0.16065001 c -0.21735 -0.756 -0.63314986 -1.14345 -1.0016999 -1.14345 c -0.18900001 0 -0.23625004 0.12285 -0.23625004 0.33074996 c 0 0.21735 0.06615007 0.3969 0.15120006 0.6048 l 0.3024 0.75600004 l 0.4630499 1.20015 c 0.028350115 0.09449983 0.05669999 0.20789981 0.05669999 0.30239987 c 0 0.44414997 -0.37800002 0.8032501 -0.8977499 0.8032501 c -0.93555 0 -1.37025 -1.2852001 -1.37025 -1.4458499 c 0 -0.12285018 0.13229999 -0.12285018 0.16064999 -0.12285018 c 0.13230002 0 0.14174998 0.047250032 0.17009997 0.15120006 c 0.2457 0.81270003 0.6615 1.1529 1.01115 1.1529 c 0.15119994 0 0.23625004 -0.07559991 0.23625004 -0.33075 c 0 -0.21735 -0.05669999 -0.3591001 -0.29295003 -0.94499993 l -0.59535 -1.52145 c -0.037799954 -0.12284994 -0.08504999 -0.23624998 -0.08504999 -0.39689994 c 0 -0.44415003 0.37800002 -0.80325 0.89775 -0.80325 c 0.94500005 0 1.3607999 1.3040999 1.3607999 1.4458499 Z \"/\u003e\u003c/symbol\u003e\u003c/defs\u003e\u003c/svg\u003e\u003c/span\u003e 采样 \u003cspan role=\"math\"\u003e\u003csvg class=\"typst-frame\" style=\"overflow: visible; width: 1.1018000000000001em; height: 0.683em;\" viewBox=\"0 0 14.8743 9.2205\" width=\"14.8743pt\" height=\"9.2205pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:h5=\"http://www.w3.org/1999/xhtml\"\u003e\u003cg\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 0 9.2205)\"\u003e\u003cuse xlink:href=\"#g97EE8E40EE0EEE4FD2AF6896DC5BA0D7\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 10.300500000000001 12.555000000000001)\"\u003e\u003cuse xlink:href=\"#g3A69B5BA14C4FC0AE0508775E710B241\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003c/g\u003e\u003cdefs id=\"glyph\"\u003e\u003csymbol id=\"g97EE8E40EE0EEE4FD2AF6896DC5BA0D7\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 11.8935 9.0720005 c 0 0 0 0.14849949 -0.17549992 0.14849949 c -0.44550037 0 -0.9180002 -0.040499687 -1.3635006 -0.040499687 c -0.45899963 0 -0.9314995 0.040499687 -1.3769999 0.040499687 c -0.080999374 0 -0.24300003 0 -0.24300003 -0.2699995 c 0 -0.14850044 0.13500023 -0.14850044 0.24300003 -0.14850044 c 0.76950073 -0.013500214 0.9180002 -0.29699993 0.9180002 -0.59399986 c 0 -0.040499687 -0.026999474 -0.24300003 -0.040499687 -0.2835002 l -1.5120001 -6.0074997 l -2.9835005 7.047001 c -0.1079998 0.24299908 -0.121500015 0.2564993 -0.43199968 0.2564993 h -1.8090003 c -0.26999998 0 -0.3915 0 -0.3915 -0.2699995 c 0 -0.14850044 0.121500015 -0.14850044 0.37800002 -0.14850044 c 0.067500114 0 0.9180002 0 0.9180002 -0.121500015 l -1.8090003 -7.2495003 c -0.13499999 -0.53999996 -0.36449993 -0.972 -1.458 -1.0125 c -0.08100003 0 -0.22950006 -0.013500005 -0.22950006 -0.26999998 c 0 -0.094500005 0.067500055 -0.14850001 0.17550004 -0.14850001 c 0.43200004 0 0.9045 0.0405 1.35 0.0405 c 0.4590001 0 0.94499993 -0.0405 1.3905001 -0.0405 c 0.067499876 0 0.24300003 0 0.24300003 0.27 c 0 0.13499999 -0.121500015 0.1485 -0.26999998 0.1485 c -0.783 0.02700001 -0.89100003 0.324 -0.89100003 0.59400004 c 0 0.094499946 0.013499975 0.16199994 0.0539999 0.31050003 l 1.7820003 7.1280003 c 0.0539999 -0.08100033 0.0539999 -0.1079998 0.121500015 -0.24300003 l 3.3614998 -7.9515 c 0.094500065 -0.22950001 0.13500023 -0.2565 0.25650024 -0.2565 c 0.14849949 0 0.14849949 0.0405 0.2159996 0.28350002 l 1.8900003 7.5195 c 0.13500023 0.54000044 0.37800026 0.9585004 1.4580002 0.9990001 c 0.067500114 0 0.22949982 0.013500214 0.22949982 0.27000046 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"g3A69B5BA14C4FC0AE0508775E710B241\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 3.0618 5.90625 c 0 0.15119982 -0.11339998 0.35909986 -0.37800002 0.35909986 c -0.25515008 0 -0.5292001 -0.24569988 -0.5292001 -0.5197501 c 0 -0.16064978 0.12284994 -0.35909986 0.37800002 -0.35909986 c 0.27405 0 0.5292001 0.2645998 0.5292001 0.5197501 Z m 0.24569988 -4.5549 c 0 0.12285006 -0.12284994 0.12285006 -0.15120006 0.12285006 c -0.1322999 0 -0.14174986 -0.05669999 -0.17954993 -0.16065001 c -0.21735 -0.756 -0.63314986 -1.14345 -1.0016999 -1.14345 c -0.18900001 0 -0.23625004 0.12285 -0.23625004 0.33074996 c 0 0.21735 0.06615007 0.3969 0.15120006 0.6048 l 0.3024 0.75600004 l 0.4630499 1.20015 c 0.028350115 0.09449983 0.05669999 0.20789981 0.05669999 0.30239987 c 0 0.44414997 -0.37800002 0.8032501 -0.8977499 0.8032501 c -0.93555 0 -1.37025 -1.2852001 -1.37025 -1.4458499 c 0 -0.12285018 0.13229999 -0.12285018 0.16064999 -0.12285018 c 0.13230002 0 0.14174998 0.047250032 0.17009997 0.15120006 c 0.2457 0.81270003 0.6615 1.1529 1.01115 1.1529 c 0.15119994 0 0.23625004 -0.07559991 0.23625004 -0.33075 c 0 -0.21735 -0.05669999 -0.3591001 -0.29295003 -0.94499993 l -0.59535 -1.52145 c -0.037799954 -0.12284994 -0.08504999 -0.23624998 -0.08504999 -0.39689994 c 0 -0.44415003 0.37800002 -0.80325 0.89775 -0.80325 c 0.94500005 0 1.3607999 1.3040999 1.3607999 1.4458499 Z \"/\u003e\u003c/symbol\u003e\u003c/defs\u003e\u003c/svg\u003e\u003c/span\u003e 个点，然后对每个像素取深度上最靠前的点 \u003cspan role=\"math\"\u003e\u003csvg class=\"typst-frame\" style=\"overflow: visible; width: 3.587566666666667em; height: 0.683em;\" viewBox=\"0 0 48.43215 9.2205\" width=\"48.43215pt\" height=\"9.2205pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:h5=\"http://www.w3.org/1999/xhtml\"\u003e\u003cg\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 0 9.2205)\"\u003e\u003cuse xlink:href=\"#g50DA4B7BDD6A87E9D1327A0524772811\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003cuse xlink:href=\"#gEFB0D4954C8ADA240A829471597EA46F\" x=\"11.2455\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003cuse xlink:href=\"#gE2E2D5A1CCC8ABB00A2F0ABA3493DF80\" x=\"14.9985\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 22.5045 12.555)\"\u003e\u003cuse xlink:href=\"#g4E22239E6353EBCF122352F4110B374\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 28.20285 9.82395)\"\u003e\u003cuse xlink:href=\"#g56ED44F5FD755E6F0095147CEA18179\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 35.70705 9.2205)\"\u003e\u003cuse xlink:href=\"#g30BD3B82B09CBDBBB2BC34793CC2B83E\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 41.89005 4.299750000000002)\"\u003e\u003cuse xlink:href=\"#gE25CF5D10793F9A0D0B42E2818F6348F\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 41.552550000000004 12.555)\"\u003e\u003cuse xlink:href=\"#g706D9051A358F9E2DAA9FFCC388B99A8\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003c/g\u003e\u003cdefs id=\"glyph\"\u003e\u003csymbol id=\"g50DA4B7BDD6A87E9D1327A0524772811\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 10.9755 0 v 0.4185 c -0.70199966 0 -1.0395002 0 -1.0529995 0.40500003 v 2.5785003 c 0 1.161 0 1.5795 -0.41849995 2.0655 c -0.18900013 0.22949982 -0.6345005 0.4994998 -1.4175005 0.4994998 c -1.1339998 0 -1.7280002 -0.80999994 -1.9575 -1.323 c -0.18900013 1.1745 -1.1880002 1.323 -1.7955003 1.323 c -0.98549986 0 -1.6199999 -0.58049965 -1.9979999 -1.4175 v 1.4175 l -1.9035 -0.14849997 v -0.41849995 c 0.94500005 0 1.053 -0.094500065 1.053 -0.75600004 v -3.618 c 0 -0.6075 -0.14849997 -0.6075 -1.053 -0.6075 v -0.4185 l 1.5255 0.0405 l 1.512 -0.0405 v 0.4185 c -0.9045 0 -1.053 0 -1.053 0.6075 v 2.484 c 0 1.404 0.9584999 2.16 1.8225002 2.16 c 0.85049963 0 0.9989996 -0.7290001 0.9989996 -1.4984999 v -3.1455002 c 0 -0.6075 -0.14849997 -0.6075 -1.053 -0.6075 v -0.4185 l 1.5255003 0.0405 l 1.5120001 -0.0405 v 0.4185 c -0.9045 0 -1.053 0 -1.053 0.6075 v 2.484 c 0 1.404 0.9584999 2.16 1.8224998 2.16 c 0.8505006 0 0.9990001 -0.7290001 0.9990001 -1.4984999 v -3.1455002 c 0 -0.6075 -0.14849949 -0.6075 -1.053 -0.6075 v -0.4185 l 1.5254998 0.0405 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"gEFB0D4954C8ADA240A829471597EA46F\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 3.3345 0 v 0.4185 c -0.89100003 0 -0.94499993 0.067499995 -0.94499993 0.59400004 v 4.9545 l -1.8900001 -0.14849997 v -0.41849995 c 0.87750006 0 0.99899995 -0.08099985 0.99899995 -0.7424998 v -3.6315002 c 0 -0.6075 -0.14849997 -0.6075 -1.053 -0.6075 v -0.4185 l 1.485 0.0405 c 0.4725001 0 0.94499993 -0.026999999 1.404 -0.0405 Z m -0.74250007 8.154 c 0 0.36450005 -0.3104999 0.7154999 -0.7155 0.7154999 c -0.459 0 -0.729 -0.37800026 -0.729 -0.7154999 c 0 -0.36450005 0.31050003 -0.7154999 0.7155 -0.7154999 c 0.459 0 0.729 0.37799978 0.729 0.7154999 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"gE2E2D5A1CCC8ABB00A2F0ABA3493DF80\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 7.2225003 0 v 0.4185 c -0.70200014 0 -1.0395002 0 -1.053 0.40500003 v 2.5785003 c 0 1.161 0 1.5795 -0.41850042 2.0655 c -0.18899965 0.22949982 -0.6345 0.4994998 -1.4175 0.4994998 c -0.98549986 0 -1.6199999 -0.58049965 -1.9979999 -1.4175 v 1.4175 l -1.9035 -0.14849997 v -0.41849995 c 0.94500005 0 1.053 -0.094500065 1.053 -0.75600004 v -3.618 c 0 -0.6075 -0.14849997 -0.6075 -1.053 -0.6075 v -0.4185 l 1.5255 0.0405 l 1.512 -0.0405 v 0.4185 c -0.9045 0 -1.053 0 -1.053 0.6075 v 2.484 c 0 1.404 0.9584999 2.16 1.8225002 2.16 c 0.85049963 0 0.9989996 -0.7290001 0.9989996 -1.4984999 v -3.1455002 c 0 -0.6075 -0.14849997 -0.6075 -1.053 -0.6075 v -0.4185 l 1.5255003 0.0405 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"g4E22239E6353EBCF122352F4110B374\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 5.4337497 6.4259996 c 0 0.04725027 -0.037799835 0.13230038 -0.15119982 0.13230038 c -0.18900013 0 -0.97335005 -0.07560015 -1.2096 -0.094500065 c -0.07559991 -0.009449959 -0.20790005 -0.018899918 -0.20790005 -0.21735 c 0 -0.1322999 0.13230014 -0.1322999 0.24569988 -0.1322999 c 0.4536004 0 0.4536004 -0.06615019 0.4536004 -0.14175034 c 0 -0.06614971 -0.018900394 -0.12284994 -0.037800312 -0.20790005 l -0.5386498 -2.1545997 c -0.19845009 0.31184983 -0.5197501 0.55754995 -0.97335005 0.55754995 c -1.2096 0 -2.4380999 -1.3324499 -2.4380999 -2.69325 c 0 -0.91665 0.61424994 -1.5687 1.4269499 -1.5687 c 0.51030016 0 0.9639001 0.29295 1.3419001 0.6615 c 0.17954993 -0.567 0.7276499 -0.6615 0.9733498 -0.6615 c 0.34019995 0 0.57645035 0.20789999 0.7465501 0.50084996 c 0.20790005 0.36854997 0.33075 0.9072 0.33075 0.94499993 c 0 0.12285006 -0.12284994 0.12285006 -0.15119982 0.12285006 c -0.13230038 0 -0.14175034 -0.037800074 -0.20790005 -0.29295003 c -0.11339998 -0.4536 -0.29295015 -1.01115 -0.68984985 -1.01115 c -0.24570036 0 -0.31185007 0.20789999 -0.31185007 0.46304998 c 0 0.17954999 0.018899918 0.26459998 0.047249794 0.38744998 l 1.31355 5.2542 c 0.009449959 0.018899918 0.037799835 0.15119982 0.037799835 0.15119982 Z m -1.5781498 -3.3452997 c 0 -0.037800074 -0.018899918 -0.10395002 -0.028349876 -0.1322999 l -0.44414997 -1.76715 c -0.06615019 -0.26459998 -0.27405 -0.4536 -0.48195004 -0.63315 c -0.085050106 -0.0756 -0.46305013 -0.378 -0.8694 -0.378 c -0.34965003 0 -0.68985 0.24569997 -0.68985 0.91665006 c 0 0.50084996 0.27405 1.54035 0.4914 1.91835 c 0.4346999 0.7559998 0.91664994 0.8977499 1.18125 0.8977499 c 0.6615 0 0.8410499 -0.71819997 0.8410499 -0.82215 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"g56ED44F5FD755E6F0095147CEA18179\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 3.4425 4.212 c 0 0.15525007 -0.11475015 0.2902503 -0.29699993 0.2902503 c -0.20925021 0 -0.41850019 -0.20249987 -0.41850019 -0.4050002 c 0 -0.16199994 0.12825012 -0.29024982 0.29700017 -0.29024982 c 0.22949982 0 0.41849995 0.21600008 0.41849995 0.40499973 Z m -0.24300003 -1.8832498 c 0 0.3847499 -0.35774994 0.6547499 -0.83025 0.6547499 c -0.81675005 0 -1.3162501 -0.9112499 -1.3162501 -1.04625 c 0 -0.094499946 0.10800004 -0.094499946 0.1417501 -0.094499946 c 0.10124993 0 0.11474991 0.02699995 0.14849997 0.094499946 c 0.31050003 0.6615001 0.7695 0.81675017 0.9990001 0.81675017 c 0.26999998 0 0.28349996 -0.24300003 0.28349996 -0.35775018 c 0 -0.094500065 -0.006750107 -0.121500015 -0.020250082 -0.17549992 l -0.6344999 -2.5245001 c -0.12825 -0.513 -0.55350006 -0.8505 -0.96525 -0.8505 c -0.11475003 0 -0.18900001 0.020249963 -0.24300003 0.033749938 c 0.162 0.094500065 0.20924997 0.27000004 0.20924997 0.35775006 c 0 0.11475003 -0.08099997 0.27675003 -0.30374998 0.27675003 c -0.22950003 0 -0.4185 -0.20925003 -0.4185 -0.43200004 c 0 -0.29025 0.30374998 -0.46575004 0.76275 -0.46575004 c 0.459 0 1.3364999 0.23625004 1.5457499 1.07325 l 0.6075001 2.4164999 c 0.013499975 0.067500114 0.033750057 0.12825012 0.033750057 0.22275019 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"g30BD3B82B09CBDBBB2BC34793CC2B83E\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 5.8050003 1.4445001 c 0 0.08099997 -0.08100033 0.17549992 -0.16200018 0.17549992 c -0.067500114 0 -0.094500065 -0.02699995 -0.17549992 -0.13499999 c -1.0665002 -1.3365 -2.538 -1.3365 -2.7 -1.3365 c -0.8505001 0 -1.2150002 0.6615 -1.2150002 1.4715 c 0 0.55350006 0.26999998 1.863 0.7290001 2.7000003 c 0.41849995 0.7694998 1.161 1.3499999 1.9034998 1.3499999 c 0.4590001 0 0.9720001 -0.17549992 1.1610003 -0.53999996 c -0.21600008 0 -0.4050002 0 -0.59399986 -0.18900013 c -0.21600008 -0.20249987 -0.24300003 -0.43199968 -0.24300003 -0.52649975 c 0 -0.32400036 0.24300003 -0.4725001 0.4994998 -0.4725001 c 0.3915 0 0.75600004 0.32400012 0.75600004 0.8640001 c 0 0.6615 -0.6345 1.1609998 -1.5929999 1.1609998 c -1.8225002 0 -3.6180003 -1.9305 -3.6180003 -3.8339999 c 0 -1.2150002 0.78300005 -2.2815 2.187 -2.2815 c 1.9305 0 3.0645003 1.431 3.0645003 1.593 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"gE25CF5D10793F9A0D0B42E2818F6348F\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 4.14855 5.90625 c 0 0.16064978 -0.12284994 0.35909986 -0.37800002 0.35909986 c -0.27405 0 -0.5292001 -0.2645998 -0.5292001 -0.5197501 c 0 -0.15119982 0.11339998 -0.35909986 0.37800002 -0.35909986 c 0.25514984 0 0.5292001 0.24569988 0.5292001 0.5197501 Z m -0.34965014 -2.6271 c 0 0.5197499 -0.44414997 0.88829994 -1.0111499 0.88829994 c -1.0489501 0 -1.6537501 -1.31355 -1.6537501 -1.4458499 c 0 -0.12285018 0.13230002 -0.12285018 0.16065001 -0.12285018 c 0.11339998 0 0.12285006 0.028350115 0.18900001 0.17009997 c 0.23625004 0.5481 0.7276499 1.1340001 1.2757499 1.1340001 c 0.23624992 0 0.32130003 -0.16065001 0.32130003 -0.4630499 c 0 -0.10395002 -0.018899918 -0.23625016 -0.028349876 -0.2835002 l -0.9072001 -3.6193497 c -0.16065001 -0.65205 -0.6615 -1.2001499 -1.2190499 -1.2001499 c -0.12285 0 -0.23624998 0.018899918 -0.34019995 0.05669999 c 0.24569994 0.11339998 0.32129997 0.34019995 0.32129997 0.48194993 c 0 0.22680002 -0.17954999 0.34965003 -0.36855 0.34965003 c -0.29294997 0 -0.53865 -0.25514996 -0.53865 -0.55754995 c 0 -0.3591001 0.36855 -0.59535 0.93555 -0.59535 c 0.56700003 0 1.6726499 0.34019995 1.9656 1.4930999 l 0.85049987 3.3831 c 0.028350115 0.10395002 0.047250032 0.18899989 0.047250032 0.33075 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"g706D9051A358F9E2DAA9FFCC388B99A8\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 5.50935 3.4775999 c 0 0.52919984 -0.60479975 0.6898501 -0.9828 0.6898501 c -0.47249985 0 -0.85049987 -0.31185007 -1.0583999 -0.67094994 c -0.17009997 0.38744998 -0.6048 0.67094994 -1.1340001 0.67094994 c -1.0583999 0 -1.6631999 -1.1623499 -1.6631999 -1.4458499 c 0 -0.12285018 0.13229996 -0.12285018 0.16064996 -0.12285018 c 0.12285 0 0.13230002 0.037800074 0.17955005 0.16065001 c 0.23624992 0.7371001 0.83159995 1.14345 1.29465 1.14345 c 0.31185007 0 0.5669999 -0.17009997 0.5669999 -0.6236999 c 0 -0.18900013 -0.11339998 -0.6615 -0.19844985 -0.9828 l -0.32130003 -1.2946501 c -0.094500065 -0.3212999 -0.40635002 -0.83159995 -0.88830006 -0.83159995 c -0.028349996 0 -0.31184995 0 -0.5103 0.13229999 c 0.38745004 0.12285 0.41580003 0.46305 0.41580003 0.51975 c 0 0.20789993 -0.16065001 0.34965003 -0.37800002 0.34965003 c -0.26459998 0 -0.53865 -0.22680002 -0.53865 -0.57645005 c 0 -0.47249997 0.5292 -0.68985 0.99225 -0.68985 c 0.4346999 0 0.8221499 0.27405 1.0584 0.67095 c 0.22679996 -0.50084996 0.74654984 -0.67095 1.1245499 -0.67095 c 1.08675 0 1.6631999 1.18125 1.6631999 1.4458499 c 0 0.12285006 -0.12284994 0.12285006 -0.15119982 0.12285006 c -0.1322999 0 -0.14175034 -0.047250032 -0.17955017 -0.16065001 c -0.19845009 -0.65205 -0.76545 -1.14345 -1.2946498 -1.14345 c -0.37800002 0 -0.5764501 0.25515 -0.5764501 0.61424994 c 0 0.24569994 0.22679996 1.10565 0.4914 2.1546 c 0.18900013 0.72765017 0.61424994 0.9639001 0.9261 0.9639001 c 0 0 0.31185007 0 0.51030016 -0.1322999 c -0.3024001 -0.085050106 -0.4158001 -0.34965014 -0.4158001 -0.5197501 c 0 -0.20790005 0.16064978 -0.3496499 0.37799978 -0.3496499 c 0.21735 0 0.5292001 0.17954993 0.5292001 0.5764499 Z \"/\u003e\u003c/symbol\u003e\u003c/defs\u003e\u003c/svg\u003e\u003c/span\u003e 作为 Splat 结果的无偏估计值。\u003c/p\u003e","title":"SIGGRAPH 2026 论文笔记 I: 3D Gaussians"},{"content":" 这是我在 2025 年春季于中科大学习于树澄老师的《实分析》[1] 课程时整理的期末考试复习笔记。课程录像已有同学上传到 Bilibili.\n实分析复习笔记 期中部分 Lebesgue 测度的建立 1. 集合论基础：规定一类集合的代数性质，使得简单生成元上的性质可被推广 集合的运算，集合列的极限，点集拓扑 作业 1a.3：上下极限的等价表述\n：事件无穷多次发生 ：事件从某时刻开始一直在发生 相关的定理：Borel-Cantelli 引理，Fatou 引理\n-代数：含有空集（单位元）、对补封闭、对可数并封闭（如果只对有限并封闭则称为代数）\nBorel -代数：包含 中所有开集的最小 -代数。\n要证明性质在 Borel -代数上成立，只需要证明性质对开集成立、对补封闭、对可数并封闭即可。而证明对开集成立只需要证明对开区间（ 上）或对方体（ 上）成立。\n而因为 Borel -代数和 Lebesgue 可测集只相差一个零测集，所以可以顺着把性质推广到可测集上。\n集：可数个闭集的交集； 集：可数个开集的交集。 有理数集是 集，但不是 集。\n证明：借助开集结构定理和稠密性说明。\n无理数集是 集，但不是 集。 2. 开集结构定理：把集合的结构简化成可研究的简单小单元（代数生成元） 上： 中开集均可唯一写成可数个开区间的不交并。\n上： 中开集均可写成可数方体的几乎不交并。2 进方体之类的概念。\n从而可以用方体几乎不交并的结构去逼近任何开集。后面推出可以逼近任何 Lebesgue 可测集（Littlewood 1）。\n所以 上可测集的结构是：可数个开区间的并、补操作加一个零测集。\n上可测集的结构是：可数个开集的并、补操作加一个零测集，或可数个方体的并、补操作加一个测度小于 的集合。\n3. 外测度：规定一个对任何集合都存在的，可计算的，性质稍差的测度 定义：方体覆盖测度下界\n基础性质：空集、单点集、可数点集为零测集。\n性质：单调性，次可数可加性，外正则性，特殊集合下的有限可加性（距离大于0的集合、两两不交紧集）。\n推论：线性变换下保持测度（作业 1c.3,4）。限制在 Lebesgue 测度下仍然成立。（作业2a.4）\n技巧：比较 与 的大小：\n：证明 小于任何方体覆盖的体积和。 ：证明对 存在方体覆盖体积满足 。 4. Lebesgue 测度：保留 Borel -代数性质，逼近性质，可数可加性，连续性的好性质 可测性：\n等价条件：Caratheodory 条件 （作业2a.3）在抽象测度下也能很好地表述。可测集将任何两个集合切成两部分，保持两部分的和仍为原测度。\n基础性质：, Borel -代数是 Lebesgue 可测集的真子集（作业 3a.2）。零测集可测；对可数并、补封闭（对可数交封闭）开集均可测（闭集均可测)。\n“好+小”：任何可测集只和 Borel 集相差一个零测集。（讲义定理 1.38，对于 集，一侧是由 Lebesgue 可测的定义动机直接得来，另一侧则由零测集可测性质保证。）\n任何可测集只和方体覆盖、外部开集、内部闭（紧！）集相差一个测度小于 的集合。\n重要性质：可数可加性。从而推出可以减。\n证明：有界情形取相差 的紧子集求并即可。无界情形加个极限，把全空间划分成可数个有界集合，再用有界集合的可数可加性加起来。\n测度连续性：单调集列极限的测度是测度的极限。递减集额外要求测度从某时刻起有限。\n单调递增情形把单调集列变成增量并的形式再用可数可加性，研究从集合并到级数的对应即可。\n单调递减情形取第一个有限集和后面集合的差集（就是想办法取补），就和递增情形相同了。\n可测集只和内部紧集，有限方体几乎不交并相差一个测度小于 的集合。（Littlewood 1）\n紧集：取 与内部闭集相交，得到一列递增集列，由测度连续性逼近。\n有限方体几乎不交并：把外部开集写成方体几乎不交并，再套一层测度连续性。\n不可测集：补充在后面。\n“插值”：（作业2b.1）紧集的测度有介值性。启发是有包含关系的有界集合间可以连续“插值”。现在看来用 插值更加漂亮。\nBorel-Cantelli 引理：.\n用概率论的语言表述，就是如果事件概率和是有限的，那么存在事件发生无穷次的概率为 0（？）\n用类似柯西列的想法去反证。\n逐项积分证明（作业5a.3）：\n5. 可测函数：对极限、四则运算、minmax、几乎处处相等、几乎处处收敛 封闭 定义：广义实值函数\n原始定义：（即 的逆像）可测。\n（等价定义）换成 都行。退一步 去逼近、取补即可。\n（作业 3a.3）只要任意开区间/任意开集/任意闭集/任意Borel集的逆像可测即可推出函数可测。只要用开集结构定理推广到开集上，然后说明对可数并和补封闭即可。\n示性函数可测（简单函数可测）， 上连续函数可测。\n可测函数对复合不封闭。连续(可测()) 可测（因为开集在连续映射下的逆像仍为开集），可测(连续())不一定可测。（讲义命题 1.57，作业 3a.2）\n可测函数对极限（上下极限）封闭。因为极限函数值域的开子集逆像就是函数列值域对应开子集逆像（上下极限意义下是单调集列）的极限。\n可测函数对 max, min, 四则运算封闭。对取绝对值封闭。\n定义：可测函数的正部和负部。\n可测函数在几乎处处相等意义下封闭。(作业 3b.1）连续性在几乎处处相等意义下不封闭。（作业 3b.2，塞一个 Dirichlet 函数即可。）\n可测函数在几乎处处收敛意义下封闭。\n单调递增函数可测。（作业 3b.2）\n6. 简单函数逼近 简单函数：有限个可测集的示性函数的线性组合。存在唯一标准表示：两两不交，系数不等。\n阶梯函数：有限个矩体的示性函数的线性组合。\n简单函数逼近系列定理\n非负可测函数可以用一列（有紧支集的）非负简单函数单调递增、逐点收敛逼近。\n逼近的形态是： 取 为最高点；底下按照 为步长去“切”函数。\n如果要求紧支集，那就用 再限制一下。\n如果函数有界，就可以一致收敛。\n因为不用限定最高点了。\n任意可测函数可以用一列（有紧支集的）简单函数在绝对值意义下单调递增、逐点收敛逼近。同理可要求有紧支集，可在有界条件下一致收敛。\n可测函数可被阶梯函数几乎处处收敛逼近。\n因为可测集（在这里是简单函数示性的集合）和方体的有限并只差一个测度为 的集合，所以先用简单函数逐点收敛逼近可测函数，再用阶梯函数按 逼近简单函数，最后取“不能逼近的集合”的上极限用 Borel-Cantelli 定理说明不能逼近的函数值的集合是零测集即可（我没看懂那个证明）。\nLusin 定理：设集合 可测， 为 上的可测函数，且 几乎处处有限. 则对任意 ，存在闭集 满足 且 连续.\n微积分中的一个引理：连续函数列在一致收敛意义下的极限函数也连续。\n证明：\n先说明简单函数的情形：对每块可测集都能用闭集按 逼近。 再证明有界可测函数（比几乎处处有限更严）的情形：用简单函数列可以一致收敛逼近它，从而能够说明在限制集下的连续性。限制集可以通过对简单函数连续的闭子集取交得到（闭集可数交仍然为闭集），用 限制即可。 最后用一个连续双射推广到几乎处处有限的可测函数上：. 取 Sigmoid, 之类的函数也都可以。 应用：\n任何几乎处处有限的可测函数都离一个连续函数只差测度为 的集合。先用 Lusin 定理得到连续部分的闭集，再用连续函数延拓定理连接这些闭集即可。 Egorov 定理：设 , 为可测集 上的可测函数，且 . 若 ，则对任意 ，存在闭子集 满足 且 在 上一致收敛到 .\n想法：令 . 那么存在下标列 使得 ，即满足一致收敛的集合（在测度意义下）足够大。\n证明：\n对于固定的 ， 关于 单调递增且收敛到 . 由测度连续性推出 . 为每个 取 满足 . 令 . 那么它与原来的 只相差 （它的形态是什么样的？）； 说明 上的一致收敛性；(想法:给定 ，则函数在 上和极限函数只差 ) 再给 取一个相差 的闭子集 即可。 理解： 增大会让 变小； 增大会让 增大（且收敛到 ）；所以对于每个 都取合适的 再并起来即可得到一致收敛的集合。但得到的其实还是和测度里 相关的类似“内闭一致收敛”的东西。\nLebesgue 积分 1. 积分理论的建立过程 1.1 非负简单函数 定义：各个集合测度按系数加权求和。另遵循 的规定。\n性质：正线性，可加性，单调性，连续性\n1.2 非负可测函数 定义：不大于 的简单函数的的积分的上确界\n可积性：仅要求这个上确界是有限值。\n性质：正线性，可加性，单调性，连续性；几乎处处意义下相等。\n定理（MCT，单调收敛定理）：设 可测， 是 上的非负可测函数. 若 单调递增并收敛到 （可弱化为几乎处处），那么\n证明：单调性可以得到 ；另一侧通过“退一小步”的想法得到 . 用法：\n简单函数可以单调递增、逐点收敛逼近非负可测函数，从而可以继承性质（正线性证明）； 可以用于把用 限制区域的函数列 的性质推到 上（连续性证明）。 可以证明几乎处处相等的函数有相同积分值。取一个比二者都大的几乎处处相等函数即可。（作业 5a.4） 要求单调，否则有 escape of mass 的反例，与 Fatou 引理情形相同。（作业 5a.3） 定理（逐项积分定理）：设 在可测集 上非负可测，则\n证明：对 RHS 操作，先写成部分和的极限形式，有限求和积分可换，交换后部分和函数单调递增，收敛到 ，因此用 MCT 即可。 可积性的一些命题：设 在可测集 上非负可测。\n被可积函数控制则可积：. 特别地，有界集合上的有界函数可积。这里的“控制”就是给了一个积分的上界。\n可积则 a.e. 有限：.\n定理（Fatou 引理）：设 为可测集 上的非负可测函数列. 则\n严格不等号的情形：escape of mass. 证明：讨论一列“下界函数列” 的极限的积分。一方面，其单调收敛到下极限函数，由 MCT，极限的积分为左式；另一方面， 总成立，因此每项积分小于右式，极限的积分也小于右式。（有更好的概括方式吗？） 用法：判断极限函数的可积性。 反 Fatou 引理（作业5b.4）：设 为可测集 上的非负可测函数列，且要求被可积函数 控制. 则\n从而可以两边夹一下，证明非负可测函数的控制收敛定理。\n证明方法是对 函数列用 Fatou 引理。\n1.3 可测函数 定义： 正部积分减负部积分\n性质：线性性，可数可加性，单调性，三角不等式，绝对连续性，平移不变性，几乎处处意义下相等，可积推出几乎处处有限。\n定理（DCT，控制收敛定理）：设 可测， 是 上的可测函数列且几乎逐点收敛到 上某个函数 . 若存在 使得对任意 ，则\n证明：研究 ，用 Fatou 引理说明 , 对非负可测函数 的积分无贡献，从而 的积分收敛到 0.\n可以反过来用于证明 MCT. 主要是讨论收敛目标函数不可积的情形。\n推论（BCT，有界收敛定理）：设 可测， 是 上的一列可测函数且 几乎逐点收敛到 上某个函数 . 若 且 在 上一致有界，即存在 使得对任意 对任意 有 ，则\n定理（“质量”落在紧集内）：存在紧集 使得 .\n证明：构造越来越大的紧集，用积分的连续性推出紧集内积分的极限是 上的积分，从而可以取得符合要求的紧集。 可积性并不代表 在无限远处趋于 0，不过如果要求一致连续则没问题（作业 5b.1）。 定理（绝对连续性）： 使得对任意可测集 ，.\n证明：对有界函数该定理显然；利用单调收敛定理将有界函数逼近研究的函数。 推论：变上限积分函数 关于 一致连续。 1.4 与 Riemann 积分的联系 “兼容”性证明：Riemann 可积要求在闭区间上有界。（从 Riemann 积分的定义出发）用阶梯函数去从上、下两个方向逼近，由定义 Riemann 积分意义下积分值即阶梯函数积分的极限；另一方面有界收敛定理说明 Lebesgue 积分意义下的积分值也是阶梯函数积分的极限。所以 Riemann 可积条件下两种积分方式得到的积分值是相同的。\n用法：把积分用 Lebesgue 积分相关的定理转化成一系列 Riemann 积分来计算。\n定理（Lebesgue）：黎曼可积 几乎处处连续（作业 6a.4）\n2. -空间 2.1. 范数的建立与证明 定义略\n性质：完备赋范线性空间。以几乎处处相等作为等价类。其中范数要求正定性、齐次性、三角不等式。\n定理（Holder 不等式）：\n引理（Young 不等式）： 证明：将 代入不等式，积分即得. 定理（Minkowski 不等式）：三角不等式，\n证明：写回积分定义，拆成两部，对每一部用 Holder 不等式放缩。 2.2. 完备性 性质：设 ， 在度量 下完备. 2.3. 几种收敛方式 逐点收敛\n一致收敛\n几乎处处收敛：\n依测度收敛：\n依范数收敛：\n定理：依范数收敛推出依测度收敛。\n定理：几乎一致收敛推出几乎处处收敛。\n定理：几乎一致收敛推出依测度收敛。\n定理（Egorov)：有限集条件下，几乎处处收敛推出几乎一致收敛。\n定理（Lebesgue）：有限集、几乎处处有限条件下，几乎处处收敛推出依测度收敛。\n证明：类似 Egorov 定理的想法。\n观察：.\n定理（Riesz）：几乎处处有限条件下，依测度收敛推出存在几乎处处收敛子列。\n证明：证明存在子列使得对于任意 ， 是零测集。这只需要利用依测度收敛条件取出一系列集合 使得不收敛部分越来越少，求和起来有限，再用Borel-Cantelli 定理说明上极限是零测集即可。取出集合还要求随着下标增大，收敛要求 逐渐收敛到 0，以满足定理对任意 的需求。\n反例（逐点收敛但不依测度收敛）：无限集上的函数。\n反例（依测度收敛但处处不收敛）：“扫描”。\n（作业 7a.1）“ 收敛推出几乎处处收敛”仅在 可行。\n反例：用一个逐渐缩小的区间不断扫描逐渐扩大的区间，使得每个位置都不收敛，但积分因区间缩小而减小。\n2.4. 稠密性定理 定义：任意邻域均与另一集合有交。\n定理：则：\n引理（稠密的传递性）：.\n证明：好长……\n定理：则： （具有紧支集的连续函数稠密）\n证明：把阶梯函数“连接”起来。 应用：Lebesgue 积分的变量替换法则（换元）：\n应用：平移变换的连续性： 则 .\n2.5. 性质 有限测度集上 （作业 6b.4）\n证明： 减小，有限集上小于 1 的部分至多增大为 1（无法贡献无穷大），大于 1 的部分一定减小。\n上 不同的空间互不包含。具体反例由作业 5a.2，作业 6b.4 给出，用 的形式构造。\n方法 1. “好”+“小” 将简单集合的性质推广到可测集主要有两种证明思路：\n任何 Lebesgue 可测集只和 Borel 集相差一个零测集。证明性质在简单集合上成立，在可数并、补下保持，并证明零测集不影响性质（或是几乎处处意义下的性质）即可。\n任何 Lebesgue 可测集只和外部开集、内部闭（甚至紧）集、方体覆盖相差一个测度小于 的集合。证明性质在开集上成立，并证明 取极限后性质也能保持即可。\n2. 用好的逼近坏的 “退 步海阔天空” 作业 1b.1：用开集列逼近闭集、用闭集列逼近开集\nMCT 的证明\n切比雪夫不等式（，作业 5a.1）的应用：\n可以把 逐步收敛到任意一个想要的数，如 0.（作业 4b.3，作业 5b.2）.\n方体覆盖 集合的外测度为方体覆盖测度的下极限。\n用紧集逼近无限集合 性质在 上成立 性质在 上成立。\n性质在 上成立 性质在 上成立。 可以用 MCT 一类的定理推过去。\n单调递增集列可以写成增量集合的不交并 从而用 Lebesgue 测度的可数可加性。\nLittlewood 三原则 可测集几乎是区间的有限并：“开集结构定理”\nLusin: 可测函数几乎是连续函数\nEgorov: 函数列几乎是一致收敛\n特殊的结构 Cantor 集，类 Cantor 集 “某进制下小数部分不含某个数的点集合”。\n性质：零测集\n（作业 2b.3）类 Cantor 集：给定一列正实数 满足 （收敛条件），令 为 每个区间中挖去长度为 的开子区间得到的新集合， 称为类 Cantor 集。\n则 . 由此可以构造出测度大于 0 的类 Cantor 集。\n（作业2a.1）性质：不连通、无内点、是完全集（极限完备）、\n（作业2a.2）类 Cantor 集之间的映射。\nCantor-Lebesgue 函数：将 Cantor 集映射到 上的单调函数。是连续双射。（连续统基数） 不可测集 构造（Vitali）：按有理数划分等价类，每个等价类找一个代表元。\n不可测性证明：有理数集可数， 上所有有理数平移后的并有限且充满整个 区间，但是由可数可加性，无限并只能取值 0 或无穷，从而矛盾。\n分球悖论\n（作业 3a.1）Vitali 集的可测子集必为零测集。\n（作业 3a.1）测度大于 0 的集合必有不可测子集。（用 Vitali 集取并构造）\n（作业 3a.2）零测集的子集必可测（是零测集）。\n（作业 3a.2）可测但非 Borel 集：类 Cantor 集给出了测度大于 0 的集合到零测集的连续双射；测度大于 0 的集合必有不可测子集；不可测子集映射到零测集的子集后是可测的（零测集的子集必可测）；Borel 集在连续双射下保持；但是 Borel 集必可测，矛盾。\n（作业 3a.2）可测(连续()) 映射不保可测性：想法是零测集上的映射一定可测，且可以把不可测集连续映射到零测集上。，合并后的映射即 。\n期末部分 1 Fubini 定理 Fubini 定理 设 ，则\n(F1) ；\n(F2) 函数 可积；\n(F3) .\nTonelli 定理 设 是 上非负可测函数，则\n(T1) 可测 ；\n(T2) 函数 可测；\n(T3) . 其中等式两端允许取 .\n证明：可积情形由 Fubini 推出；不可积情形用包围盒限制-MCT 的技术推出。\nFubini 定理证明：\n证明满足定理的集族对线性组合、单调极限封闭。\n证明可积简单函数（“生成元”）都在集族中。\n证明顺序：方体-符合条件的零测集的子集-有限个闭方体的几乎不交并-有限测度开集-有限测度 集-任意零测集-一般有限测度集合.\n说明可积函数可以由可积简单函数线性组合及取单调极限得到。\n推论：换元积分法。对三个初等矩阵证明测度不变性即可。\n推论：乘积集合的可测性\n由 Tonelli 定理可以直接得到可测集 的切片集合可测：\n(i) 可测 .\n(ii) 函数 可测.\n(iii) .\n记 称为 与 的乘积集合. 则有\n两个正测集的乘积集合可测，那么两个集合都可测。\n（设 可测，且 ，则 可测.）\n（引理），其中右端满足 .\n两个可测集的乘积集合一定可测，且测度为集合测度之积。\n推论：零测集 零测集 零测集（可测）.\n推论：，则 可测 均可测.\nLebesgue 积分的几何意义：面积\n卷积： 可测 可测.\n2 积分的微分理论 2.1 Lebesgue 微分定理（LDT） 表述：闭区间上可积函数有原函数，且原函数的导数几乎处处等于函数本身。\n在 上可微且对任意 有 .\n思想：研究局部可积性。如果 ，那么将左右式在区间上累积起来即可得到一个“原函数”。\n局部可积： 开球 . 记作 .\n空间性质：(1). 线性空间；(2). .\nHardy-Littlewood 极大函数：\n可测 可测； 证明：研究 ，借助 定义说明 ， 有开邻域（定义中开球所有点都有 ）. 可以借助这个证明理解用开球定义的动机。\n（H-L 极大不等式）：设 ，则对任意 ，. 证明：\n推论：. 只需说明 .\n推论：，则 . 这是因为 LDT 给出了局部可积函数在小局部上的平均值就是它本身，而这个均值在定义上就小于 H-L 极大函数. Vitali 覆盖引理：令 . 为 中 个开球，则存在一系列开球 两两不交且 .\n定理证明：用稠密的连续函数（自动满足微分定理）近似，误差部分用 HL 极大函数控制住。\n密度点： 可测. 密度点定义为满足 的 .\n例子：集合的内点；零测集无密度点（分子恒为0）；满测集上所有点.\n推论：可测集中的点几乎处处是密度点，补集上的点几乎处处不是密度点.\nLebesgue 点：. 满足 的点. 点集记作 . 该条件比 Lebesgue 微分定理中极限等式更强。 连续点一定是 Lebesgue 点，Lebesgue 点一定满足微分定理的等式.\n推论： 满测. （所以满足微分定理等式但是不是 Lebesgue 点的点集是零测的，从而能专注研究 这些性质更好的点？）\n正则收缩：用更一般的集合平均。 定义：集合“差不多是开球”\n(i) （外部可用开球包裹）\n(ii) .（和外部开球差不多大）\n引理：\n证明： 在 上的积分是不大于在外部开球上的积分的.\n推论：相对于中心球的 Lebesgue 微分定理等.\n2.2 Newton-Leibnez 公式 表述： 存在且 .\n反过来，.\n2.2.1 有界变差 定义：\n变差 全变差：（几何含义： 在 的取值变化量） 有界变差： 意义: 可微，且 的充分条件。\n例子：单调函数，有界 Lipschitz 连续函数 ……\n引理\n线性空间； 精细划分 性质\n. 在 单调递增. .\n可求长曲线： 连续.\n曲线可求长 证明方法就是利用范数关系。.\n弧长 Jordan 分解定理： 单调递增 . 证明：“”：闭区间上单调函数是有界的。\n“”：. 只需证明 单调递增；用定义证明即可。\n推论： 可微 且 .\n2.2.2 单调函数微分定理 闭区间上单调递增函数 满足：\na.e. 可微； ； . 证明：\nDini 导数：\n引理：注意逻辑关系！ 单增 存在 单增 零测.\n证明：“”显然. 下文证明“”.\n定义 零测\n则由假设及对称性， 单增 .\n从而四个 Dini 导数相等，从而 存在.\n证明：只需证 零测. Vitali 覆盖：满足每个点都有充分小邻域的无穷覆盖\n，则称 是 的一个 Vitali 覆盖.\n等价定义：\n定理： 两两不交，使得 .\n即，存在任意大的有限不交子覆盖.\n证明：\n2.2.3 绝对连续性 定义： 有限个两两不交的开区间 ，只要 ，就有 .\n关系：Lipschitz 连续 绝对连续 一致连续 逐点连续\n绝对连续但不 Lipschitz 连续的例子：\n一致连续但不绝对连续的例子：Cantor-Lebesgue 函数.\n定理：用积分定义的函数 绝对连续。（NL 定理的必要性）\n证明：用 Lebesgue 积分的绝对连续性转化一下。\n性质：线性空间；对乘法封闭； 证明：只证明最后一个.\n. 这是因为 在定义上就大于所有区间划分的区间两侧之和。把 切成 份使得每一份长度都小于 ，则函数差的绝对值加起来就小于 了.\n（从H班偷的）连续且 BV，且将零测集映射为零测集 AC\n复合（从 H 班偷来的）\n反例： 上，\n当 (i) 单增 或 (ii) Lipschitz 连续时，.\n. 证明： 且将零测集映射为零测集.\n定理： 存在 且若 ，则 为 上常值函数.\n证明： 的集合是满测集，里面每一点都可以在右侧取到满足差商小于 的闭邻域（因为导数用极限定义），它们构成 Vitali 覆盖。用 Vitali 覆盖定理取到有限个不交闭邻域，这些邻域对积分贡献小于 ；剩下的区间足够小，可以用绝对连续性将积分贡献控制下来。最后极限收紧。\n微积分基本定理的证明： 原函数存在性：直接用变上限积分定义，Lebesgue 微分定理保证了原函数的微分是函数.\nNL 公式：，则 . 由上面的定理， 常值函数，从而推出 NL 公式.\n2.2.4 其他课题 复值函数的绝对连续性保持所有我们想要的性质.\n可求长曲线弧长公式：\n公式成立的充要条件：\n3 抽象测度 代数：空集全集；可数并封闭；补封闭。代数：“可数”变成了“有限”. 例子：\n可测空间 ；测度空间 . 其中 要求满足可数可加性. 特殊性质的测度：有限测度、概率测度\n例子：“子空间”；“加权”Lebesgue 测度；Dirac 测度；计数测度.\n性质：单调性、次可数可加性、单调集列测度连续性.\n完备测度：任意 零测集的子集都属于 .\n延拓定理：任意测度可在 -代数中添加所有零测集的子集以唯一地延拓成完备测度.\n证明：主要部分是证明补集封闭，作 Venn 图之后就能得到要用的集合恒等式 trick.\n外测度：要求满足空集零测、单调性、次可数可加性。\nCaratheodory 定理\n满足条件 的集合称为 -可测集；\n上所有 -可测集组成的集合 是一个 -代数，且 是 上完备测度。\n由此可以由外测度引导出测度。\n外测度的构造 预测度：在 上代数 上满足空集零测性、可数可加性。\n预测度诱导出外测度：.\n满足： 是 上外测度；； 中元素均 -可测（Caratheodory条件）.\n测度空间的一种构造方式： 满足： ；若 -有限，则 是 上唯一的 延拓测度。\n-有限：存在 .\n一些刷到的有用的话的整理 “这个题大家做的真有点离谱了，一直在让我反思是不是学期内没有好好强调这些我认为简单的东西。首先，Fubini的条件是积分2维可积，一些学的比较好的同学也认为累次积分可积便可以了，但还差了一个 Tonelli（累次等于另一个累次等于二重积分），这也是Tonelli这个定理存在的一大意义。绝大部分同学（可以说几乎所有）都没提这个步骤。里面的大部分同学甚至是，上来就用Fubini换序，换完以后声称第一问可积和第三问换序的结论都做出来了。这种我都大概给了 12 分，我感觉如果按其他题一样定一个得分点严格改，最多 2 分，因为你完全没有表现出你学过实分析这门课的样子。所以希望大家以后学习的时候见到一个积分交换了次序，还是要下意识的去验证一下是不是多重绝对可积，就像看到极限和积分交换次序要去check控制收敛定理一样。这应该是实分析应该刻进DNA里的样子。” [2]\n作业题整理 [3]\n“为什么要引进积分收敛定理？很简单，因为构造一般可测函数的萝卜干积分时就要用到！\n怎么应用积分收敛定理？优先考虑单调收敛定理和控制收敛定理，其次考虑Fatou引理/广义控制收敛定理，如果以上方法全都不灵，则考虑Egorov定理。如果以上方法仍有问题，则85%概率以上是这道题目自己有问题。\n为什么是这个顺序？因为Egorov定理结论最强：可以做到一致收敛，从而无条件交换lim和积分号。其次，DCT, 广义DCT都是Fatou引理的直接推论，当然是先上儿子再上老子。\n如何选取合适的定理？有控制函数的，用DCT；无控制函数但有范数收敛的（例如fn的Lp范数收敛到f的Lp范数），用Fatou；仅有积分上界无收敛性的，考虑Egorov定理。什么都没有的，这题85%以上概率是错题。” [4]\nTable of Contents\n实分析复习笔记 期中部分\nLebesgue 测度的建立\n1. 集合论基础：规定一类集合的代数性质，使得简单生成元上的性质可被推广\n2. 开集结构定理：把集合的结构简化成可研究的简单小单元（代数生成元）\n3. 外测度：规定一个对任何集合都存在的，可计算的，性质稍差的测度\n4. Lebesgue 测度：保留 Borel -代数性质，逼近性质，可数可加性，连续性的好性质\n5. 可测函数：对极限、四则运算、minmax、几乎处处相等、几乎处处收敛 封闭\n6. 简单函数逼近\nLebesgue 积分\n1. 积分理论的建立过程\n1.1 非负简单函数\n1.2 非负可测函数\n1.3 可测函数\n1.4 与 Riemann 积分的联系\n2. -空间\n2.1. 范数的建立与证明\n2.2. 完备性\n2.3. 几种收敛方式\n2.4. 稠密性定理\n2.5. 性质\n方法\n1. “好”+“小”\n2. 用好的逼近坏的\n“退 步海阔天空”\n方体覆盖\n用紧集逼近无限集合\n单调递增集列可以写成增量集合的不交并\nLittlewood 三原则\n特殊的结构\nCantor 集，类 Cantor 集\n不可测集\n期末部分\n1 Fubini 定理\n2 积分的微分理论\n2.1 Lebesgue 微分定理（LDT）\n2.2 Newton-Leibnez 公式\n2.2.1 有界变差\n2.2.2 单调函数微分定理\n2.2.3 绝对连续性\n2.2.4 其他课题\n3 抽象测度\n一些刷到的有用的话的整理\nReferences\nReferences [1] 于树澄, “实分析讲义.” Accessed: Mar. 2024. [Online]. Available: https://icourse.club/uploads/files/729afc03c905ad7a94546c7cecfdd24f8a3dcaae.pdf [2] 所以你还是你吗？, “实分析（刘聪文）2023春课程评价.” Accessed: July 10, 2023. [Online]. Available: https://icourse.club/course/12373/#review-67036 [3] b. VADupleix, “Constructing a Borel set that intersects every interval with positive but non-full measure.” Accessed: Oct. 07, 2014. [Online]. Available: https://math.stackexchange.com/questions/961745/constructing-a-borel-set-that-intersects-every-interval-with-positive-but-non-fu [4] 章俊彦, “实分析（赵立丰）2015春课程评价.” Accessed: July 15, 2015. [Online]. Available: https://icourse.club/course/2058/#review-153 ","permalink":"https://rubatotree.github.io/blog/posts/ra-note/","summary":"\u003cp\u003e这是我在 2025 年春季于中科大学习\u003ca href=\"https://faculty.ustc.edu.cn/yushucheng/zh_CN/index.htm\" target=\"_blank\" rel=\"noopener noreferrer\"\u003e\u003cspan style=\"color: #59a4ff;\"\u003e\u003cspan style=\"text-decoration: underline\"\u003e于树澄\u003c/span\u003e\u003c/span\u003e\u003c/a\u003e老师的《实分析》\u003ca id=\"loc-1\" href=\"#loc-48\" role=\"doc-biblioref\"\u003e[1]\u003c/a\u003e 课程时整理的期末考试复习笔记。课程录像已有同学上传到 \u003ca href=\"https://www.bilibili.com/video/BV1LRJHz9Eub\" target=\"_blank\" rel=\"noopener noreferrer\"\u003e\u003cspan style=\"color: #59a4ff;\"\u003e\u003cspan style=\"text-decoration: underline\"\u003eBilibili\u003c/span\u003e\u003c/span\u003e\u003c/a\u003e.\u003c/p\u003e\n    \u003ch2 id=\"loc-2\"\u003e实分析复习笔记 期中部分\u003c/h2\u003e\n    \u003ch3 id=\"loc-3\"\u003eLebesgue 测度的建立\u003c/h3\u003e\n    \u003ch4 id=\"loc-4\"\u003e1. 集合论基础：规定一类集合的代数性质，使得简单生成元上的性质可被推广\u003c/h4\u003e\n    \u003cp\u003e\u003c/p\u003e\n    \u003col\u003e\n      \u003cli value=\"1\"\u003e集合的运算，集合列的极限，点集拓扑\u003c/li\u003e\n    \u003c/ol\u003e\n    \u003cp\u003e\u003c/p\u003e\n    \u003cp\u003e\u003c/p\u003e\n    \u003cul\u003e\n      \u003cli\u003e\n        \u003cp\u003e\u003cstrong\u003e作业 1a.3\u003c/strong\u003e：上下极限的等价表述\u003c/p\u003e\n        \u003cp\u003e\u003c/p\u003e\n        \u003cul\u003e\n          \u003cli\u003e\u003cspan role=\"math\"\u003e\u003csvg class=\"typst-frame\" style=\"overflow: visible; width: 3.0949999999999998em; height: 0.683em;\" viewBox=\"0 0 41.7825 9.2205\" width=\"41.7825pt\" height=\"9.2205pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:h5=\"http://www.w3.org/1999/xhtml\"\u003e\u003cg\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 0 9.2205)\"\u003e\u003cuse xlink:href=\"#g7FA5977BD6AF286C6FF8EDE62B3E9C33\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003cuse xlink:href=\"#gEFB0D4954C8ADA240A829471597EA46F\" x=\"3.753\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003cuse xlink:href=\"#g50DA4B7BDD6A87E9D1327A0524772811\" x=\"7.506\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003cuse xlink:href=\"#gF1E3D149091ABEF4B289FED13C61F321\" x=\"21.4515\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003cuse xlink:href=\"#gFD09D5EFCFE2E29428C744B1220D7FD4\" x=\"26.7705\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003cuse xlink:href=\"#g2F2BFEBC67313ECFF6C08A4643824EC5\" x=\"34.2765\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003c/g\u003e\u003cdefs id=\"glyph\"\u003e\u003csymbol id=\"g7FA5977BD6AF286C6FF8EDE62B3E9C33\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 3.4425 0 v 0.4185 c -0.9045 0 -1.053 0 -1.053 0.6075 v 8.343 l -1.9440001 -0.14850044 v -0.41849995 c 0.94500005 0 1.053 -0.09449959 1.053 -0.75599957 v -7.0200005 c 0 -0.6075 -0.14849997 -0.6075 -1.053 -0.6075 v -0.4185 l 1.4985 0.0405 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"gEFB0D4954C8ADA240A829471597EA46F\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 3.3345 0 v 0.4185 c -0.89100003 0 -0.94499993 0.067499995 -0.94499993 0.59400004 v 4.9545 l -1.8900001 -0.14849997 v -0.41849995 c 0.87750006 0 0.99899995 -0.08099985 0.99899995 -0.7424998 v -3.6315002 c 0 -0.6075 -0.14849997 -0.6075 -1.053 -0.6075 v -0.4185 l 1.485 0.0405 c 0.4725001 0 0.94499993 -0.026999999 1.404 -0.0405 Z m -0.74250007 8.154 c 0 0.36450005 -0.3104999 0.7154999 -0.7155 0.7154999 c -0.459 0 -0.729 -0.37800026 -0.729 -0.7154999 c 0 -0.36450005 0.31050003 -0.7154999 0.7155 -0.7154999 c 0.459 0 0.729 0.37799978 0.729 0.7154999 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"g50DA4B7BDD6A87E9D1327A0524772811\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 10.9755 0 v 0.4185 c -0.70199966 0 -1.0395002 0 -1.0529995 0.40500003 v 2.5785003 c 0 1.161 0 1.5795 -0.41849995 2.0655 c -0.18900013 0.22949982 -0.6345005 0.4994998 -1.4175005 0.4994998 c -1.1339998 0 -1.7280002 -0.80999994 -1.9575 -1.323 c -0.18900013 1.1745 -1.1880002 1.323 -1.7955003 1.323 c -0.98549986 0 -1.6199999 -0.58049965 -1.9979999 -1.4175 v 1.4175 l -1.9035 -0.14849997 v -0.41849995 c 0.94500005 0 1.053 -0.094500065 1.053 -0.75600004 v -3.618 c 0 -0.6075 -0.14849997 -0.6075 -1.053 -0.6075 v -0.4185 l 1.5255 0.0405 l 1.512 -0.0405 v 0.4185 c -0.9045 0 -1.053 0 -1.053 0.6075 v 2.484 c 0 1.404 0.9584999 2.16 1.8225002 2.16 c 0.85049963 0 0.9989996 -0.7290001 0.9989996 -1.4984999 v -3.1455002 c 0 -0.6075 -0.14849997 -0.6075 -1.053 -0.6075 v -0.4185 l 1.5255003 0.0405 l 1.5120001 -0.0405 v 0.4185 c -0.9045 0 -1.053 0 -1.053 0.6075 v 2.484 c 0 1.404 0.9584999 2.16 1.8224998 2.16 c 0.8505006 0 0.9990001 -0.7290001 0.9990001 -1.4984999 v -3.1455002 c 0 -0.6075 -0.14849949 -0.6075 -1.053 -0.6075 v -0.4185 l 1.5254998 0.0405 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"gF1E3D149091ABEF4B289FED13C61F321\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 4.86 1.728 c 0 0.7155 -0.4050002 1.1205 -0.5669999 1.2825001 c -0.44550014 0.43199992 -0.9720001 0.53999996 -1.539 0.648 c -0.75600016 0.14849997 -1.6605002 0.32399988 -1.6605002 1.1069999 c 0 0.47249985 0.35100007 1.026 1.512 1.026 c 1.4849999 0 1.5525 -1.2150002 1.5795 -1.6335001 c 0.013500214 -0.121500015 0.16200018 -0.121500015 0.16200018 -0.121500015 c 0.17549992 0 0.17549992 0.067500114 0.17549992 0.32400036 v 1.3634996 c 0 0.2295003 0 0.32400036 -0.14849997 0.32400036 c -0.067500114 0 -0.094500065 0 -0.26999998 -0.16200018 c -0.040500164 -0.0539999 -0.17549992 -0.17549992 -0.22950006 -0.21600008 c -0.513 0.37800026 -1.0665 0.37800026 -1.269 0.37800026 c -1.647 0 -2.1599998 -0.9045 -2.1599998 -1.6605 c 0 -0.4725001 0.21600002 -0.8505001 0.5805 -1.1475003 c 0.43200004 -0.35099983 0.81000006 -0.43199992 1.7820001 -0.62100005 c 0.29699993 -0.0539999 1.4039998 -0.26999998 1.4039998 -1.2419999 c 0 -0.68850005 -0.47249985 -1.2285001 -1.5254998 -1.2285001 c -1.1340001 0 -1.62 0.7695 -1.8765001 1.917 c -0.040499985 0.17550015 -0.05399996 0.22950006 -0.18900001 0.22950006 c -0.17549998 0 -0.17549998 -0.094500065 -0.17549998 -0.33749998 v -1.7820001 c 0 -0.22950001 0 -0.324 0.14850003 -0.324 c 0.067499995 0 0.08099997 0.013500005 0.33749998 0.27 c 0.02700001 0.02700001 0.02700001 0.054000005 0.27000004 0.31050003 c 0.594 -0.56700003 1.2015 -0.5805 1.485 -0.5805 c 1.5525002 0 2.1735 0.90450007 2.1735 1.8765 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"gFD09D5EFCFE2E29428C744B1220D7FD4\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 7.2225003 0 v 0.4185 c -0.9450002 0 -1.053 0.094500005 -1.053 0.756 v 4.7925 l -1.9845004 -0.14849997 v -0.41849995 c 0.9450002 0 1.053 -0.094500065 1.053 -0.75600004 v -2.4029999 c 0 -1.1745001 -0.64799976 -2.0925002 -1.6334999 -2.0925002 c -1.1340001 0 -1.188 0.63449997 -1.188 1.3365 v 4.482 l -1.9845 -0.14849997 v -0.41849995 c 1.053 0 1.053 -0.040500164 1.053 -1.2420001 v -2.0249999 c 0 -1.0530001 0 -2.2815 2.052 -2.2815 c 0.75600004 0 1.3499999 0.37800002 1.7414999 1.215 v -1.215 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"g2F2BFEBC67313ECFF6C08A4643824EC5\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 7.0335 2.9160001 c 0 1.7145002 -1.3095002 3.0509999 -2.8215003 3.0509999 c -1.0529997 0 -1.6199999 -0.59399986 -1.8899999 -0.8909998 v 0.8909998 l -1.944 -0.14849997 v -0.41849995 c 0.9585 0 1.053 -0.08099985 1.053 -0.6750002 v -6.318 c 0 -0.60749996 -0.14849997 -0.60749996 -1.053 -0.60749996 v -0.41849995 l 1.5120001 0.040499926 l 1.5255 -0.040499926 v 0.41849995 c -0.9045 0 -1.0530002 0 -1.0530002 0.60749996 v 2.2680001 v 0.121500015 c 0.067500114 -0.21600002 0.6345 -0.94500005 1.6605003 -0.94500005 c 1.6064997 0 3.0105 1.323 3.0105 3.0645 Z m -1.1205001 0 c 0 -1.6335001 -0.9450002 -2.7675002 -1.944 -2.7675002 c -0.53999996 0 -1.053 0.26999998 -1.4175 0.8235 c -0.18900013 0.28350008 -0.18900013 0.29700005 -0.18900013 0.56700003 v 3.0105 c 0.39150023 0.6884999 1.0530002 1.0799999 1.7415001 1.0799999 c 0.98549986 0 1.809 -1.1879997 1.809 -2.7134998 Z \"/\u003e\u003c/symbol\u003e\u003c/defs\u003e\u003c/svg\u003e\u003c/span\u003e：事件无穷多次发生\u003c/li\u003e\n          \u003cli\u003e\u003cspan role=\"math\"\u003e\u003csvg class=\"typst-frame\" style=\"overflow: visible; width: 2.729em; height: 0.683em;\" viewBox=\"0 0 36.8415 9.2205\" width=\"36.8415pt\" height=\"9.2205pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:h5=\"http://www.w3.org/1999/xhtml\"\u003e\u003cg\u003e\u003cg class=\"typst-text\" transform=\"matrix(1 0 0 -1 0 9.2205)\"\u003e\u003cuse xlink:href=\"#g7FA5977BD6AF286C6FF8EDE62B3E9C33\" x=\"0\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003cuse xlink:href=\"#gEFB0D4954C8ADA240A829471597EA46F\" x=\"3.753\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003cuse xlink:href=\"#g50DA4B7BDD6A87E9D1327A0524772811\" x=\"7.506\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003cuse xlink:href=\"#gEFB0D4954C8ADA240A829471597EA46F\" x=\"21.4515\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003cuse xlink:href=\"#gE2E2D5A1CCC8ABB00A2F0ABA3493DF80\" x=\"25.2045\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003cuse xlink:href=\"#gA19D6A5E7B9530AF4814F9B5C2E2C24B\" x=\"32.710499999999996\" y=\"0\" fill=\"#000000\" fill-rule=\"nonzero\"/\u003e\u003c/g\u003e\u003c/g\u003e\u003cdefs id=\"glyph\"\u003e\u003csymbol id=\"g7FA5977BD6AF286C6FF8EDE62B3E9C33\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 3.4425 0 v 0.4185 c -0.9045 0 -1.053 0 -1.053 0.6075 v 8.343 l -1.9440001 -0.14850044 v -0.41849995 c 0.94500005 0 1.053 -0.09449959 1.053 -0.75599957 v -7.0200005 c 0 -0.6075 -0.14849997 -0.6075 -1.053 -0.6075 v -0.4185 l 1.4985 0.0405 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"gEFB0D4954C8ADA240A829471597EA46F\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 3.3345 0 v 0.4185 c -0.89100003 0 -0.94499993 0.067499995 -0.94499993 0.59400004 v 4.9545 l -1.8900001 -0.14849997 v -0.41849995 c 0.87750006 0 0.99899995 -0.08099985 0.99899995 -0.7424998 v -3.6315002 c 0 -0.6075 -0.14849997 -0.6075 -1.053 -0.6075 v -0.4185 l 1.485 0.0405 c 0.4725001 0 0.94499993 -0.026999999 1.404 -0.0405 Z m -0.74250007 8.154 c 0 0.36450005 -0.3104999 0.7154999 -0.7155 0.7154999 c -0.459 0 -0.729 -0.37800026 -0.729 -0.7154999 c 0 -0.36450005 0.31050003 -0.7154999 0.7155 -0.7154999 c 0.459 0 0.729 0.37799978 0.729 0.7154999 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"g50DA4B7BDD6A87E9D1327A0524772811\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 10.9755 0 v 0.4185 c -0.70199966 0 -1.0395002 0 -1.0529995 0.40500003 v 2.5785003 c 0 1.161 0 1.5795 -0.41849995 2.0655 c -0.18900013 0.22949982 -0.6345005 0.4994998 -1.4175005 0.4994998 c -1.1339998 0 -1.7280002 -0.80999994 -1.9575 -1.323 c -0.18900013 1.1745 -1.1880002 1.323 -1.7955003 1.323 c -0.98549986 0 -1.6199999 -0.58049965 -1.9979999 -1.4175 v 1.4175 l -1.9035 -0.14849997 v -0.41849995 c 0.94500005 0 1.053 -0.094500065 1.053 -0.75600004 v -3.618 c 0 -0.6075 -0.14849997 -0.6075 -1.053 -0.6075 v -0.4185 l 1.5255 0.0405 l 1.512 -0.0405 v 0.4185 c -0.9045 0 -1.053 0 -1.053 0.6075 v 2.484 c 0 1.404 0.9584999 2.16 1.8225002 2.16 c 0.85049963 0 0.9989996 -0.7290001 0.9989996 -1.4984999 v -3.1455002 c 0 -0.6075 -0.14849997 -0.6075 -1.053 -0.6075 v -0.4185 l 1.5255003 0.0405 l 1.5120001 -0.0405 v 0.4185 c -0.9045 0 -1.053 0 -1.053 0.6075 v 2.484 c 0 1.404 0.9584999 2.16 1.8224998 2.16 c 0.8505006 0 0.9990001 -0.7290001 0.9990001 -1.4984999 v -3.1455002 c 0 -0.6075 -0.14849949 -0.6075 -1.053 -0.6075 v -0.4185 l 1.5254998 0.0405 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"gE2E2D5A1CCC8ABB00A2F0ABA3493DF80\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 7.2225003 0 v 0.4185 c -0.70200014 0 -1.0395002 0 -1.053 0.40500003 v 2.5785003 c 0 1.161 0 1.5795 -0.41850042 2.0655 c -0.18899965 0.22949982 -0.6345 0.4994998 -1.4175 0.4994998 c -0.98549986 0 -1.6199999 -0.58049965 -1.9979999 -1.4175 v 1.4175 l -1.9035 -0.14849997 v -0.41849995 c 0.94500005 0 1.053 -0.094500065 1.053 -0.75600004 v -3.618 c 0 -0.6075 -0.14849997 -0.6075 -1.053 -0.6075 v -0.4185 l 1.5255 0.0405 l 1.512 -0.0405 v 0.4185 c -0.9045 0 -1.053 0 -1.053 0.6075 v 2.484 c 0 1.404 0.9584999 2.16 1.8225002 2.16 c 0.85049963 0 0.9989996 -0.7290001 0.9989996 -1.4984999 v -3.1455002 c 0 -0.6075 -0.14849997 -0.6075 -1.053 -0.6075 v -0.4185 l 1.5255003 0.0405 Z \"/\u003e\u003c/symbol\u003e\u003csymbol id=\"gA19D6A5E7B9530AF4814F9B5C2E2C24B\" overflow=\"visible\"\u003e\u003cpath d=\"M 0 0m 4.8195 8.5725 c 0 0.49950027 -0.4994998 0.9449997 -1.2149999 0.9449997 c -0.94499993 0 -2.0925 -0.7154999 -2.0925 -2.1464996 v -1.5525002 h -1.0665001 v -0.41849995 h 1.0665001 v -4.374 c 0 -0.6075 -0.14850008 -0.6075 -1.0530001 -0.6075 v -0.4185 l 1.539 0.0405 c 0.5400001 0 1.1745001 0 1.7145001 -0.0405 v 0.4185 h -0.28349996 c -0.9990001 0 -1.026 0.14850003 -1.026 0.63449997 v 4.347 h 1.539 v 0.41849995 h -1.5795002 v 1.566 c 0 1.1880002 0.64800024 1.836 1.2420001 1.836 c 0.040499926 0 0.24300003 0 0.44550014 -0.09449959 c -0.16200018 -0.0539999 -0.4050002 -0.22949982 -0.4050002 -0.5670004 c 0 -0.31050014 0.21600008 -0.58049965 0.5805001 -0.58049965 c 0.3915 0 0.59399986 0.2699995 0.59399986 0.59399986 Z \"/\u003e\u003c/symbol\u003e\u003c/defs\u003e\u003c/svg\u003e\u003c/span\u003e：事件从某时刻开始一直在发生\u003c/li\u003e\n        \u003c/ul\u003e\n        \u003cp\u003e\u003c/p\u003e","title":"实分析 课程总结笔记"},{"content":"同步一下之前（2024冬）写过的文章~\n不知不觉快到期末了，也做完了本学期数字电路实验课程的最后一个实验。我选择了实验中分值最高的，组队用 FPGA 完成一个能在 VGA 屏幕上显示的小游戏。正好，在多年前我用 Gamemaker 复刻过一个 Flappy Bird，于是决定把它搬到 FPGA 上。\n在写完开发文档后才想到去搜网上的实现，结果发现已经有超多人做过了\u0026hellip;\u0026hellip;好在我们应该是完成度最高的（好耶！）。虽然我们的完成度很大一部分贡献来自找到了原版的素材（呜呜），而且还因为没有经验写下了一些超时的组合逻辑（Critical Waring，但是上板不会出问题？），不过还是有一些值得一提的小设计的。\n其实有看到华科也做过一个完成度相当高的FlappyBird，但他们的实现是写了CPU的，和我们的思路完全不同\n源代码 → tinatanhy/Flappybird: A project implementing Flappy Bird using Verilog\n我发的展示视频 → https://www.youtube.com/shorts/InrxOJ-FaT0\n队友发的展示视频 → https://www.bilibili.com/video/BV1w6CNYPEak\n本文在经过微调后会作为实验报告提交。\n1 | FPGA 与常规游戏开发的不同之处 硬件编程思维 在 FPGA 上，我们需要编写的是硬件模块，而不是串行执行的 CPU 逻辑。这使得我们面向过程或面向对象的思维都不太好用了，除非自己手搓一个 CPU，否则一切都要用状态机实现。因此，我们需要在设计时就完全地考虑游戏中需要的内容，并有层次地设计出状态的更新逻辑。\n“函数调用”的思维也不再好用——如果需要把数据交给一个时序逻辑元件计算，就得在本地维护一个状态机，在计算时不断轮询直到计算完毕，再进入下一个状态。与其把游戏逻辑设计成函数的形式，不如思考有没有更“硬件”的实现\u0026hellip;\u0026hellip;？\n数据的依赖关系、时序的先后关系也要妥善处理。硬件上的数据都是“并行”处理的，如果有数据依赖另一些数据，就得设计调度器让它们按顺序被计算出来。还有一些元件，如 BROM，有两个 clk 的延时，这种延时引起的问题也常常会引发各种难以修改的 bug。\n硬件的一切资源都是静态的，如果要做出“动态生成”的效果，与其设计对象池，不如想想有没有什么更好的替代方案。\n浮点数与图像插值 现代游戏中会有大量浮点数的运算，而对 FPGA 而言，浮点数运算是相当奢侈的。我们希望完全避免浮点数的运算，所以我们选择了 Flappy Bird，并且通过各种设计绕过了游戏中的各种浮点数。\n游戏中常见的图像的插值缩放、旋转等操作也会涉及大量浮点数的运算。因此要在游戏开始设计时，就想清楚有哪些不可避免的图像插值，尽可能地将它们预计算好。我们涉及图像插值的操作只有鸟的旋转，而这是在外部算好旋转的帧动画后再导入进来的。\n浮点数的困难也让 3D 游戏开发变得比想象中更加困难\u0026hellip;\u0026hellip;就算有计算机图形学基础，在 FPGA 上搓数学库怎么想都会有点噩梦。所以还是稳稳地复刻小游戏吧。\n我们的解决方案 我们解决浮点数问题的思路是：\n将需要用到除法、三角函数等复杂浮点数运算的地方隔离出来，用预计算处理：只有鸟的旋转。 用「定点数」处理相对简单浮点数的加减乘运算。 浮点数难处理是因为“浮”，所以把点定住不就好了（！）所以我们定义了一种新的数据类型，定点小数。它实际上就是在二进制的数位中打了一个“小数点”。若一共有 N 位，其中低 m 位前打了小数点，则可以得到以下的运算关系：\n数学运算 代码 $a+b$ a[N-1:0] + b[N-1:0] $a-b$ a[N-1:0] - b[N-1:0] $\\text{Int} (a)$（取整） a[N-1:m] $a\\times b$ (a[N-1:0] * b[N-1:0]) \u0026gt;\u0026gt; m 我们的游戏中主要用了两种定点小数：\nN=32, m=16，用于处理鸟的运动。\nN=8, m=4，用于处理图像的透明度混合：$C_\\text{new}=(1-\\alpha)C_\\text{src}+\\alpha C_\\text{dest}$。\n这是经典的的透明度混合公式，用于将抗锯齿的鸟和透明渐入的 Game Over 绘制在屏幕上。颜色的取值范围为$[0,1)$（ 4'h0到4'hF），透明度 $\\alpha$ 的取值范围为$[0,1]$（ 5'b0 到 5’b10000），因此 N=8 就能保证运算不溢出。\n空间资源的不足 FPGA 上可用于存储图像的 ROM 资源并不富裕。其实觉得 Lab 8 Part 1 放视频的小作业就是为了让我们意识到这一点（？）所以需要在游戏开发前估算好需要的 ROM 资源，尽可能地减少不必要的图像资源，或尽可能压缩现有的图像资源。\n综合、实现要等很久\u0026hellip;\u0026hellip; 每次从修改完成到上板都需要等至少十分钟时间，这没办法。所以要利用好板上的 LED、数码管等资源，将尽可能多的状态信息、Debug 信息输出到板上，在一次更新迭代中观察到更多的信息，以避免反复迭代寻找一个 bug 的来源。\n就算如此，一个 bug 修一下午的情况也不会少见。\n2 | 游戏的框架结构 和一般的游戏引擎一样，我们的框架以帧（tick）为基本单位更新游戏状态。因为我们使用的 VGA 屏幕刷新率为 72Hz，所以帧率也设置为了 72FPS。在一帧内，游戏逻辑和游戏绘制分配在两个大模块中运行，此外还有帧时钟、处理按钮输入的模块和根据游戏状态更新的板上 LED、数码管等处理模块。\n游戏逻辑（CalcCore）模块是一个「大状态机」，它每帧更新一次，读入外部的输入和上一帧的状态信息，在计算完成后再更新状态机的输出。游戏状态、分数、游戏对象（鸟、管道等）的更新和碰撞检测等均在这个大模块里执行。考虑到这些数据的更新存在依赖关系，如应该先更新管道和鸟的位置，再进行碰撞检测、更新游戏状态和分数，所以大模块的内部设计了一个调度各种小模块的状态机，保证各个数据更新的时序。\n而游戏绘制（ViewCore）模块负责读入游戏的各种状态，根据这些状态输出屏幕上各个像素的颜色。它本身不会改变游戏状态。这个大模块中主要有三部分。一部分负责在显示器每轮刷新时锁存游戏状态（因为和游戏逻辑模块不一定是同步更新的，不锁存会导致画面撕裂）；一部分负责和 VGA 显示器对接，输出当前被刷新像素的位置；还有一部分（PixelRenderer）根据像素位置读入各种图像资源 ROM，计算、渲染当前像素的颜色。\n3 | 每轮游戏的状态设计 我们根据原游戏的设计，将每轮游戏的周期设置为了四个状态：Reset（00）-Ready（01）-Ingame（10）-Gameover（11）。状态的控制由逻辑模块中的 StatusUpdate 模块控制，在下一节中会具体介绍。\n00. Reset 状态 板子启动、从 Gameover 界面重试、按 BTNU 键强制重试时，都会转移至这一状态。这一状态只会持续一帧，在一帧内将重置工作做完后，下一帧就会转入 Ready 状态，开始游戏。\n这一状态下会做这些事情：\n重置 CalcCore 中所有元件的数据，将所有元件重置到开始游戏前应有的状态。 生成一个世界种子（WorldData.v）。世界种子 world_seed[15:0] 一共 16 位，其中第 15 位表示当前的场景是白天还是黑夜；第 [14:13] 位表示鸟的颜色（因为空间不足只做了黄色鸟，这一特性只在鸟无法旋转的旧版中有所表现）；第 [12:0] 位用于生成整个世界的管道，每个世界种子唯一对应一种管道高度分布。在后文会讲到世界种子是怎样参与管道生成的。 世界种子由一个 RNG16 元件生成。我们本来打算做成真随机数，不过队友用一个简单计数器带上小变换实现的效果也不错（？）所以就这样了。毕竟每局游戏的时长是很难控制的，加上世界种子的大部分是用于再随机一次生成管道的，所以以上一局游戏时长为标准生成世界种子也是不错的选择。\n01. Ready 状态 这一状态是开始界面，播放鸟上下浮动、地板向前行进的动画，并显示 Ready 的字样和简单的教程。直到按下 BTNC 时，鸟就会向上跳跃，并进入游戏。\n原版的教程图片是手指戳戳，因为上了板子，所以我重绘了一下，做成了提示按 BTNC 按钮的小动图。效果还不错。\n10. Ingame 状态 这是游戏运行中的状态，屏幕上显示分数和管道，玩家正常游玩，直到撞击管道时再进入 Gameover 状态。\n11. Gameover 状态 屏幕震动几帧，半透明渐入地显示 Game Over 字样；鸟下坠落地，地板停止运动，在屏幕上方显示玩家最终的分数。提示玩家游戏已经失败，再按 BTNC 就可以重置游戏，回到 Reset 状态。\n4 | 一帧中的游戏状态更新 每帧需要更新的数据 经过我们的归纳总结，绘制模块总共需要以下状态信息参与。这也说明，这些状态信息唯一地决定了当前会显示的画面内容：\n// Top-WorldData模块：世界背景、鸟的颜色； input [15:0] world_seed_in, // GlobalDataUpdate板块：帧随机数，屏幕震动的信息 input [7:0] shake_x_in, input [7:0] shake_y_in, // TubeUpdate板块：四根被绘制管道的状态信息 input [11:0] score_decimal_in, input [31:0] tube_pos0_in, input [15:0] tube_height0_in, input [7:0] tube_spacing0_in, input [31:0] tube_pos1_in, input [15:0] tube_height1_in, input [7:0] tube_spacing1_in, input [31:0] tube_pos2_in, input [15:0] tube_height2_in, input [7:0] tube_spacing2_in, input [31:0] tube_pos3_in, input [15:0] tube_height3_in, input [7:0] tube_spacing3_in, // BirdUpdate板块：鸟相关的位置、动画状态信息 // 还有相机的横坐标，用于计算屏幕坐标和游戏坐标的关系； // 不过游戏里的相机是始终跟随鸟的，所以也在这里更新。 input [31:0] bird_x_in, input [31:0] p1_bird_y_in, input [31:0] p1_bird_velocity_in, input [1:0] bird_animation_in, input [7:0] bird_rotation_in, input [31:0] camera_x_in, // StatusUpdate模块：主状态、计数器、时间戳、分数等游戏进行状态信息。 input [1:0] game_status_in, input [31:0] timer_in, input [31:0] gameover_timestamp_in, input [15:0] score_in, 这些信息会传回 Top 模块，被 Top 送进绘制总模块 ViewCore，再被送进像素渲染器 PixelRenderer，被拆分成各个画面元素所需的信息，最终得到每个像素点显示的颜色。一部分信息还会通过 Top 模块显示在板子上。\n逻辑总模块 CalcCore 的工作就是负责调度各个子模块，以计算出这些能够决定屏幕显示内容的信息。\n时序元件的统一标准 为了便于时序的控制，我们规定逻辑模块中所有的时序元件需要遵守这样的运行规则：\n输入接口中的 clk 和 rstn 是全局的时钟信号和低电平复位信号； 每当需要开始计算时，外部会向元件发送一时钟周期的 upd 脉冲信号，表示应该以该时钟周期时的输入信号为操作数开始运算； 输出接口中的 finish 表示是否运算完毕。在接收到 upd 信号后，若在当前周期无法计算出结果，就将 finish 设置为 0，直到计算完毕再将 finish 设置为高电平；需保证 finish 处于高电平的时钟周期的输出结果一定是正确的结果。 不管是 CalcCore 这样的大模块，还是其中计算中间数据的小模块，都需要按照这样的规则进行设计，这样就能用统一的方法控制时序。\n时序元件内部遵守规则的模式可以体现为状态机；若功能实际上是以组合逻辑模式实现的，即第一周期就能计算出结果，也可以将 finish 始终置为 1。\n一帧的具体组成 作为一个大状态机，负责调度数据计算模块的 CalcCore 分为 8 个状态，标号为偶数的状态为等待状态，而标号为奇数的状态会向对应的计算模块发送一个时钟周期的 upd 信号后，立即转移到下一个状态，以按上述规则启动计算模块。\n下文将按照每帧的执行顺序，具体讲解逻辑模块涉及的各种元件设计。\n\u0026gt; 状态 0：等待帧时钟信号 负责等待外部的 upd 信号输入。\n在 Top 元件中有一个 FrameClock 模块，每 $72\\text{Hz}$ 向 CalcCore 发送一个 upd 信号，以启动每帧的数据更新。FrameClock 模块是一个简单实现的计数器。原则上 FrameClock 应该还需要等待 CalcCore 模块的 finish 信号，在计数器记录到一帧且 CalcCore 计算完毕后再发送一次 upd 信号，以避免中间数据的混乱；不过我们大致估算了计算量，认为这里不会超时，所以没有实现这一功能。\n\u0026gt; 状态 1→2：更新帧计数器，处理并等待按钮输入和帧随机数 A. 帧计数器 CalcCore 主模块中维护了一个 timer[31:0] 变量，在游戏开始（Ready 界面）时设置为 0，并在每一帧的开头自增 1。这一计数器在后文会有各种用途，如生成帧随机数、打时间戳等。\nB. 按钮输入 鸟的运动会依赖按钮输入。我们规定按钮输入也按帧更新，以保证同一帧内各个元件接收到的按钮输入状态均是相同的。输入模块在 Calc/KeyInput.v 中实现。\n按钮输入状态设计成了一个 3bits 的信号，分别表示：按钮是否刚好在这一帧被按下（Pressed, “上升沿”），按钮在这一帧是否被按住（Check, “高电平”），按钮是否刚好在这一帧被松开（Released, “下降沿”）。\n这样设计是为了考虑不同的按钮行为，如鸟只应在按钮刚好按下的一帧设置一次向上的速度；若在按钮按住时一直设置向上速度，鸟就会一直向上飞了，这不符合我们的预期。实际上我们整个游戏中也只用到了 Pressed 信号。Checked 和 Released 为以后可能的应用做准备，但到做出成品也并没有用上。\n输入状态的内部实现即边沿检测，且因为是以帧为单位，已经可以忽略抖动，所以用二级寄存器简单实现即可。\nC. 帧随机数 游戏中可能有一些依赖随机数的情景。在硬件编程中，与其动态地调用生成随机数的模块，不如在每帧开始时就生成一些每帧不同的随机数，来供给帧内的使用。帧随机数（实际上已经变成了专门负责屏幕抖动）的模块在 Calc/GlobalDataUpdate.v 中实现。\n我们用到帧随机数的场景只有一个：鸟撞到柱子后的几帧触发屏幕抖动。我们尚且不清楚 FPGA 能不能生成真随机数，不过用哈希实现伪随机数对这一项目更加有用。我们实现了一个接收 32 位信号，输出 16 位信号的时序哈希元件，保证输入信号发生微小变化都会使得输出信号发生较大的变化。这样，只要每帧都将 timer 输入哈希元件，就可以得到一个每帧都不同的随机数了。\n如果要使得每轮游戏的帧随机数都不同，还可以将 timer 的一部分异或上世界种子；不过因为这对屏幕抖动的功能并不重要，所以我们没有这样实现。\n哈希元件位于 Utils/Hash32to16.v。元件内部会对输入信号做多次运算，为了避免组合逻辑超时，我在运算过程中打了几拍。\n// Tick 0 internel_seed \u0026lt;- seed\t// 锁存输入种子，避免下一个时序发生更改 // Tick 1 hash_buffer_next \u0026lt;- ((internal_seed[15:0] ^ (internal_seed[31:16] \u0026lt;\u0026lt; 8)) + ((internal_seed[31:16] \u0026gt;\u0026gt; 8) ^ internal_seed[15:0])) * 1209846; // Tick 2 hash_buffer_next = (hash_buffer ^ (hash_buffer \u0026gt;\u0026gt; 4)) * 169150151; // Tick 3 hash_buffer_next = hash_buffer ^ (hash_buffer \u0026gt;\u0026gt; 8); 将 Tick 3 后的结果作为最终输出的结果。\n\u0026gt; 状态 3→4：更新管道，更新鸟的运动和动画帧 A. 管道的具体设计 游戏中，我们的主角（鸟）需要越过一根根管道。管道的硬件实现在 Calc/TubeUpdate.v 中。\n每根管道被抽象成了三个基本信息：tube_pos[31:0] 管道的世界坐标；tube_height[15:0] 管道的高度；tube_spacing[7:0] 上下管道之间的间距。通过这些信息可以完全地进行管道的碰撞检测与绘制。\n管道高度应该是完全随机的；管道的世界坐标和间距应当随着分数增长越来越密，以让游戏越来越难，但我们最终没有实现这一效果。管道的世界坐标间隔和上下管道间距在最终的版本中仍然是常数。\n在传统的程序设计中，我们的第一想法可能是用一个队列维护管道：当管道进入视野时，就将管道入队；离开视野时，就将管道出队；每帧更新队列中管道的位置，并对这些管道做碰撞检测。这种「实例化」的思想在软件编程中是很实用的，但在硬件编程中确实显得麻烦了。\n因此，我做了这样的硬件设计：用 4 组寄存器存储可能被绘制在屏幕上的 4 根管道的基本信息；每一帧都根据当前的分数，计算一次这些管道的基本信息。\n注意到如果给每根管道标号，游戏开始时的第一根管道标注为 0 号，那么玩家只会和标号与玩家分数相同的管道发生碰撞（分数的增加发生在越过管道后，此时可能与玩家发生碰撞的管道也会相应更新）；屏幕中会显示的管道也是标号与玩家分数临近的几根管道。所以我们可以根据分数确定 4 组寄存器中的管道标号：\n寄存器编号 0 1 2 3 管道标号 score - 1 score score + 1 score + 2 确定了标号后就能确定帧间同一根管道的同一性：我们只要根据标号用同样的算法计算世界坐标、管道间距和高度，得到的同一标号管道的基本信息就是相同的。世界坐标关于标号是简单的线性函数（-1 号除外，它会被放在屏幕外的远处，可以特殊讨论），管道间距是常数（如果要做出难度变化也可以加一个曲线映射），而随机高度的计算方法也呼之欲出了：将世界种子和分数打包在一起，送进哈希里得到结果。\n// ... Hash32to16 hash32to16_2( .clk(clk), .rstn(rstn), .start(upd), .seed({score + 16\u0026#39;d1, 3\u0026#39;b000, seed}), .finish(finish2), .hash(hash2) ); // ... wire [31:0] score_expand = {16\u0026#39;d0, score}; wire [31:0] score_shift = (score_expand \u0026lt;\u0026lt; 7) + (score_expand \u0026lt;\u0026lt; 6); // ... assign tube_pos2_calc = bird_start_x + 32\u0026#39;d576 + score_shift; assign tube_spacing2_calc = 120; assign tube_height2_calc = hash2[10:4] + hash2[15:11] + 44; // ... assign finish = finish0 \u0026amp; finish1 \u0026amp; finish2 \u0026amp; finish3; 其中的数据有经过一些 Tricky 的微调，目的都是为了平衡游戏体验。\n管道的设计是整个工程里我最喜欢的地方（捂脸）\nB. 鸟的运动更新 游戏中，鸟的运动符合重力的规律。而每按下一次按键，就会把鸟的竖直速度重置为一个向上的速度，这样就能让鸟“跳起来”。因此只要维护鸟的位置和速度，就能确定鸟的运动。鸟的模块实现在 Calc/BirdUpdate.v。动画更新也在这个模块中。\n鸟的运动是队友写的。其实实现逻辑并不难。枚举游戏状态，若在 Ready 状态，就让鸟上下平移；若在 Ingame 状态，就让鸟随着重力和输入运动；若在 Gameover 状态，就让鸟自由下坠。\n在确定鸟运动的同时判断是否越过上边界或者下边界，如果越界就将鸟的位置设置为边界前的位置，这样就能让边界“拦住”鸟了。\n不过，由于非阻塞赋值的逻辑，我们不太应该让赋值之间存在依赖关系；注意到这些赋值条件是可以设计成分支结构的，所以我们可以用 if 设计好分支，在每个分支中唯一确定下一个速度和位置。按下键盘的初始速度和重力都可以写成 32 位定点小数的形式，如 32'h00004400。下文是 Ingame 状态的更新逻辑：\nif(p1_input[0])begin if($signed(p1_bird_y[31:16]) \u0026lt; $signed(BIRD_MINIMUM_Y))begin p1_bird_y[31:16] \u0026lt;= BIRD_MINIMUM_Y; p1_bird_y[15:0] \u0026lt;= 0; end p1_bird_velocity \u0026lt;= BIRD_MAX_VELOCITY; end else begin if($signed(p1_bird_y[31:16] + p1_bird_velocity[31:16]) \u0026lt; $signed(BIRD_MINIMUM_Y)) begin p1_bird_y[31:16] \u0026lt;= BIRD_MINIMUM_Y; p1_bird_y[15:0] \u0026lt;= 0; p1_bird_velocity \u0026lt;= 0; end else if($signed(p1_bird_y[31:16] + p1_bird_velocity[31:16]) \u0026gt; $signed(BIRD_MAXIMUM_Y)) begin p1_bird_y[31:16] \u0026lt;= BIRD_MAXIMUM_Y; p1_bird_y[15:0] \u0026lt;= 0; p1_bird_velocity \u0026lt;= 0; end else begin p1_bird_y \u0026lt;= p1_bird_y + p1_bird_velocity; p1_bird_velocity \u0026lt;= p1_bird_velocity - 32\u0026#39;h00004400; end end 有许多细节需要注意：数值比较需要加 $signed；赋值都要对整数部分和小数部分分别处理。\n除此之外，每帧还需要将鸟的水平位置平移一下。\nC. 鸟的动画更新 鸟的动画分为两个维度：翅膀扇动动画和旋转动画。\n翅膀扇动动画只需要在帧计时器中每过一个固定的帧数就将动画自增 1 即可；这里的实现方式是也将动画当成了一个“定点小数”，内部用一个 5bit 计数器实现，而输出时只输出 [4:3] 位。这样就能得到每 8 帧更新一次动画，4 次更新一循环的效果。\n而旋转动画做起来就很麻烦了。我们需要根据鸟的速度做一个曲线，来确定旋转中的帧。鸟的旋转一共有 30 帧，从 $-90^\\circ$ 变化到 $+60^\\circ$；第 18 帧是 $0^\\circ$。\n按下按键时，鸟的速度是瞬间变化的，而鸟不应该瞬间旋转；我们用游戏开发中常见的“帧线性插值缓动”技巧来让鸟平滑地旋转到目标位置。此时，线性插值的系数和鸟的竖直速度与目标帧之间的映射都成为了可控制的因素。\nFPGA 一次编译需要十分钟以上，这样微调当然是不太现实的。所以我在曾经的复刻版本里实现了一个帧动画控制的鸟旋转，并将系数抄进了 FPGA 版。\n不过似乎因为组合逻辑太长，Implement 时这里会报组合超时\u0026hellip;\u0026hellip;但没有出什么大问题，我猜是因为等待管道和后面的碰撞检测的时间里，输入没有变化，足够让这些组合逻辑计算出正确的结果了。\n下面是超级 Tricky 的代码\u0026hellip;\u0026hellip;\n// 第一次映射：给速度映射到一个线性函数上，主要确定缩放和保证速度为 0 时处于 0° 的帧上。 p1_velparam_temp \u0026lt;= ($signed(-p1_bird_velocity) \u0026gt;\u0026gt;\u0026gt; 3) * PARAM_MULT + {16\u0026#39;d15, 16\u0026#39;b0}; // 第二次映射：根据映射给目标帧做一个 Clamp，将目标帧限制在 [1, 36] 之间。 // 注意到上下界还留了空位（区间超过了 30 帧），这是为了让动画更加符合直觉的小 Trick。 if($signed(p1_velparam_temp) \u0026lt; $signed(1)) begin p1_bird_velparam \u0026lt;= 32\u0026#39;d1; end else if($signed(p1_velparam_temp[31:16]) \u0026gt; $signed(36)) begin p1_bird_velparam[31:16] \u0026lt;= 16\u0026#39;d36; p1_bird_velparam[16:0] \u0026lt;= 0; end else begin p1_bird_velparam \u0026lt;= p1_velparam_temp; end // 第三次映射：将实际帧向目标帧做一个线性插值。 p1_bird_velparam_delayed \u0026lt;= (p1_bird_velparam_delayed \u0026gt;\u0026gt;\u0026gt; 7) * (128 - PARAM_LERP) + (p1_bird_velparam \u0026gt;\u0026gt;\u0026gt; 7) * PARAM_LERP; // 第四次映射：再做一个 Clamp + 平移，将空位切掉，并将区间平移到精灵帧对应的下标。 if($signed(p1_bird_velparam_delayed[31:16] + 1) \u0026lt; $signed(4)) begin bird_rotation \u0026lt;= 8\u0026#39;d29; end else if ($signed(p1_bird_velparam_delayed[31:16] + 1) \u0026gt; $signed(33)) begin bird_rotation \u0026lt;= 8\u0026#39;d0; end else begin bird_rotation \u0026lt;= 8\u0026#39;d32 - p1_bird_velparam_delayed[23:16]; end 也许在中间打几拍可以规避组合逻辑超时的问题。\n\u0026gt; 状态 5→6：做碰撞检测，更新分数和游戏状态 CalcCore/StatusUpdate.v 负责这一部分的工作。\n这一模块内部例化了一个负责碰撞检测的组合逻辑模块（CalcCore/CollisionCheck.v），将鸟的世界坐标和 1 号管道寄存器的信息输入碰撞检测模块，输出 collide 和 passed ，前者为 1 则说明该帧发生了碰撞，而后者为 1 则说明该帧玩家通过了 1 号寄存器中的管道，该加分了。\n因为管道和玩家的碰撞箱都很简单，所以这里用不等式做判断就好。\nmodule CollisionCheck( input [31:0] tube_pos, input [15:0] tube_height, input [7:0] tube_spacing, input [31:0] bird_x, input [15:0] p1_bird_y, output collide, output passed ); parameter TUBE_HITBOX_L = 2; parameter TUBE_HITBOX_R = 50; assign passed = bird_x \u0026gt;= tube_pos + TUBE_HITBOX_R; assign collide = ($signed(p1_bird_y) \u0026lt;= $signed(14)) || ( ($signed(bird_x) \u0026lt;= $signed(tube_pos + TUBE_HITBOX_R + 12)) \u0026amp;\u0026amp; ($signed(bird_x) \u0026gt;= $signed(tube_pos + TUBE_HITBOX_L - 12)) \u0026amp;\u0026amp; ( ($signed(p1_bird_y) \u0026lt;= $signed(tube_height + 8) || $signed(p1_bird_y) \u0026gt;= $signed(tube_height + tube_spacing - 8)))); endmodule 而 StatusUpdate 模块的其他部分负责维护游戏状态 game_status[1:0]、分数 score、十进制分数 score_decimal（避免在数码管和屏幕上显示时取模）和游戏结束时间戳 gameover_timestamp[31:0]（用于控制屏幕震动和 Gameover 标志渐入）。\n这一部分会按照以下规则维护游戏状态 game_status[1:0]：\n状态 00（Reset）：将分数、十进制分数、游戏结束时间戳都置为 0，并在下一个状态即转入 01（Ready）； 状态 01 （Ready）：等待，直到按钮按下（Pressed），就将下一个状态设置为 10（Ingame）。 状态 10（Ingame）：先检查是否发生碰撞，若发生碰撞，则打上游戏结束时间戳，并将下一个状态设置为 11（Gameover）；否则检查是否 Passed，如果 Pass 就将分数和十进制分数都自增 1。 状态 11（Gameover）：等待，直到按钮按下（Pressed），就将下一个状态设置为 00（Reset）以重置游戏。 此外，该模块还会接收一个 reset 输入（由 BTNU 控制，新开一轮游戏），若 reset 输入高电平，则将下一状态设置为 00 以强制重置游戏。\n\u0026gt; 状态 7→0：完成运算 在最后一个状态，向 Top 模块输出一个 Finish 信号，表示完成了所有逻辑运算。\n5 | 游戏的绘制逻辑 “Shader Approach” 我们并没有采用游戏开发常见的“画布逻辑”，维护一张屏幕大小的画布、由每个对象负责将自己绘制在画布上，而是选择了和 Shader 类似的逻辑，每个像素都读入游戏状态，并根据这些状态和像素位置自行思考自己应该是什么颜色。\n我们改造了提供的 DDP 代码，DDP 不再输出地址，而是输出具体的像素坐标；将像素坐标和游戏状态信息送进 PixelRenderer 里，就能通过一套组合逻辑计算出像素自身的颜色。\n显示部分的主模块 ViewCore 负责锁存信息、调度显示器相关模块，将像素坐标和状态信息送进 PixelRenderer里一起渲染得到显示在屏幕上的颜色。\nViewCore 会在第一帧锁存所有的状态信息。因为绘制帧和逻辑帧不保证同步，状态信息可能在绘制过程中发生更改，因此这一步锁存有助于避免画面撕裂。\n每访问到一个新的像素时，PixelRenderer 负责做以下事情：\n先根据像素在 VGA 的坐标计算出像素在游戏显示区域的屏幕坐标（screen_x, screen_y）和在游戏内的世界坐标（game_x, game_y）。 然后会将这些坐标和各个对象需要的状态数据送给各个对象对应的“子渲染器”，得到须在 ROM 中读取的地址和遮罩（如果当前像素上该对象不应被绘制，无法保证地址的正确性，则遮罩为 0，否则遮罩为 1）； 在读取出颜色后再送回子渲染器做后处理，得到每个对象的颜色贡献； 最后对它们分层，做透明度混合，以确定像素最终的颜色。 这样一套做下来肯定组合逻辑超时了\u0026hellip;\u0026hellip;毕竟一个像素（pclk）仅有两个 clk 的时间。不过居然意外的能跑，很惊喜。\nBROM 访问的延时引起了不少难修的 bug。比较违背预期的是遮罩的横坐标需要提前两个 pclk，以提前把地址送进 BROM 访问模块里。\nPixelRenderer 的渲染过程 1. 像素坐标的预处理 PixelRenderer 会先将像素坐标转换为屏幕坐标和世界坐标。屏幕震动的效果在这一阶段通过偏移（经过有符号扩展的）屏幕坐标实现：\nwire [15:0] screen_x = $signed(pixel_x + 2 - 256 + $signed({{8{shake_x[7]}}, shake_x})); wire [15:0] screen_y = $signed(pixel_y - 44 + $signed({{8{shake_y[7]}}, shake_y})); wire [31:0] game_x = $signed(camera_x + {31\u0026#39;b0, screen_x} - 31\u0026#39;d80); wire [31:0] game_y = 400 - screen_y; 这一阶段还会顺便把背景棋盘格的颜色计算出来。\nwire [10:0] grid_x = pixel_x \u0026gt;\u0026gt; 5, grid_y = pixel_y \u0026gt;\u0026gt; 5; wire [11:0] col_outside = (grid_x[0] ^ grid_y[0]) ? 12\u0026#39;h333 : 12\u0026#39;h222; 接下来，PixelRenderer 里会例化一系列子渲染器和 BROMAccess 模块，以对各个画面元素的颜色进行确定。\n2. BROMAccess：管理 BROM 数据的访问 这一模块（View/BROMAccess.v）负责例化所有的 BROM 模块，输入对各个 BROM 想要访问的地址，输出 BROM 中的颜色信息。\ninput [16:0] addr_bg, input [9:0] addr_land, input [9:0] addr_tube, input [15:0] addr_bird, input [13:0] addr_ui, input [11:0] addr_score, output reg [11:0] col_bg, output reg [11:0] col_land0, output reg [15:0] col_tube_0, output reg [15:0] col_bird00, output reg [15:0] col_bird01, output reg [15:0] col_bird02, output reg [15:0] col_ui, output reg [15:0] col_score 该模块还会在每个 pclk 开始锁存所有输入信息，以避免在两个 pclk 之间、数据访存之间改变输入的地址。这样的操作会使得一些 BROM 直接坏掉，导致存储的颜色信息出错、显示出一些杂点杂线，只有重新烧写 bitstream 才能解决。当时我们完全无法找到逻辑出错的问题，也不知道该怎样解决这个 bug，所以叫它「宇宙射线 bug」。最终修好的方式也是连蒙带猜修好的，感谢玄学。\n下图框出来的区域是那些「宇宙射线」：\n3. 子渲染器 子渲染器负责生成蒙版、访存地址和最终的颜色。需要通过子渲染器渲染的元素有：游戏背景、游戏地板、管道、鸟、UI、分数。因为硬件无法选择将要显示的是哪几个元素的内容，所以不如把它们的颜色全部访问出来，再最终根据蒙版选择混合。\n游戏中的素材全部是由像素图放大两倍显示的，因此会有明显的像素感。这也需要在渲染器实现。\n最简单的：背景渲染器 // View/Renderers/BGRenderer.v module BGRenderer#( parameter LATENCY = 0 ) ( input [15:0] screen_x, screen_y, input [15:0] game_x, game_y, input [15:0] world_seed, input [11:0] col_in, output [16:0] addr, output mask, output [11:0] col_out ); assign mask = ($signed(screen_x - LATENCY) \u0026gt;= $signed(1) \u0026amp;\u0026amp; $signed(screen_y) \u0026gt;= $signed(0) \u0026amp;\u0026amp; $signed(screen_x - LATENCY) \u0026lt; $signed(288) \u0026amp;\u0026amp; $signed(screen_y) \u0026lt; $signed(512)); assign addr = ((screen_x + 1) \u0026gt;\u0026gt; 1) + ((screen_y \u0026gt;\u0026gt; 1) \u0026lt;\u0026lt; 4) + ((screen_y \u0026gt;\u0026gt; 1) \u0026lt;\u0026lt; 7) + ({16\u0026#39;b0, world_seed[15]} \u0026lt;\u0026lt; 12) + ({16\u0026#39;b0, world_seed[15]} \u0026lt;\u0026lt; 15); assign col_out = col_in; endmodule 这里通过不等式确定了有无背景的蒙版；通过代数运算将屏幕坐标映射到了背景的访存地址；再将背景颜色不加修改地直接输出。\n复杂的：管道渲染器 虽然计算了四根管道的数据，我们最终只绘制了三根。代码看上去虽然很复杂，但重复的内容其实很多。\n// View/Renderers/TubeRenderer.v localparam TUBE_WIDTH = 52; // 并行 Pass 1 // 计算管道的屏幕坐标 wire [31:0] tube_0_x = game_x - tube_pos0; wire [31:0] tube_1_x = game_x - tube_pos1; wire [31:0] tube_2_x = game_x - tube_pos2; wire [15:0] tube_0_down_y = tube_height0 - game_y; wire [15:0] tube_1_down_y = tube_height1 - game_y; wire [15:0] tube_2_down_y = tube_height2 - game_y; wire [15:0] tube_0_up_y = game_y - (tube_height0 + tube_spacing0 + 1); wire [15:0] tube_1_up_y = game_y - (tube_height1 + tube_spacing1 + 1); wire [15:0] tube_2_up_y = game_y - (tube_height2 + tube_spacing2 + 1); // Mask 由横向和纵向分开计算。二者之并为最终的 Mask。 // 计算横向的 Mask wire tube_mask_0_x = $signed(game_x) \u0026gt;= $signed(tube_pos0) \u0026amp;\u0026amp; $signed(game_x - LATENCY) \u0026lt; $signed(tube_pos0 + TUBE_WIDTH + 1); wire tube_mask_1_x = $signed(game_x) \u0026gt;= $signed(tube_pos1) \u0026amp;\u0026amp; $signed(game_x - LATENCY) \u0026lt; $signed(tube_pos1 + TUBE_WIDTH + 1); wire tube_mask_2_x = $signed(game_x) \u0026gt;= $signed(tube_pos2) \u0026amp;\u0026amp; $signed(game_x - LATENCY) \u0026lt; $signed(tube_pos2 + TUBE_WIDTH + 1); // 计算下方管道的纵向 Mask wire tube_mask_0_down = ($signed(game_y) \u0026lt;= $signed(tube_height0)) \u0026amp;\u0026amp; tube_mask_0_x; wire tube_mask_1_down = ($signed(game_y) \u0026lt;= $signed(tube_height1)) \u0026amp;\u0026amp; tube_mask_1_x; wire tube_mask_2_down = ($signed(game_y) \u0026lt;= $signed(tube_height2)) \u0026amp;\u0026amp; tube_mask_2_x; // 计算上方管道的纵向 Mask wire tube_mask_0_up = ($signed(game_y) \u0026gt; $signed(tube_height0 + tube_spacing0)) \u0026amp;\u0026amp; tube_mask_0_x; wire tube_mask_1_up = ($signed(game_y) \u0026gt; $signed(tube_height1 + tube_spacing1)) \u0026amp;\u0026amp; tube_mask_1_x; wire tube_mask_2_up = ($signed(game_y) \u0026gt; $signed(tube_height2 + tube_spacing2)) \u0026amp;\u0026amp; tube_mask_2_x; // 求并 wire tube_place_mask = (tube_mask_0_up || tube_mask_0_down || tube_mask_1_up || tube_mask_1_down || tube_mask_2_up || tube_mask_2_down); // 并行 Pass 2 // 将屏幕坐标标准化成管道在未压缩的图上的坐标 wire [9:0] tube_x = (({10{tube_mask_0_x}} \u0026amp; tube_0_x[9:0] | {10{tube_mask_1_x}} \u0026amp; tube_1_x[9:0] | {10{tube_mask_2_x}} \u0026amp; tube_2_x[9:0])) \u0026gt;\u0026gt; 1; wire [9:0] tube_y = ({10{tube_mask_0_down}} \u0026amp; tube_0_down_y[9:0] | {10{tube_mask_1_down}} \u0026amp; tube_1_down_y[9:0] | {10{tube_mask_2_down}} \u0026amp; tube_2_down_y[9:0] | {10{tube_mask_0_up}} \u0026amp; tube_0_up_y[9:0] | {10{tube_mask_1_up}} \u0026amp; tube_1_up_y[9:0] | {10{tube_mask_2_up}} \u0026amp; tube_2_up_y[9:0]) \u0026gt;\u0026gt; 1; // Pass 3 // 根据未压缩图上的 y 坐标计算压缩后图上的 y 坐标 wire [3:0] tube_img_y = {3{($signed(tube_y) == 0)}} \u0026amp; 4\u0026#39;d0 | {3{($signed(tube_y) == 1)}} \u0026amp; 4\u0026#39;d1 | {3{($signed(tube_y) \u0026gt;= 2 \u0026amp;\u0026amp; $signed(tube_y) \u0026lt;= 9)}} \u0026amp; 4\u0026#39;d2 | {3{($signed(tube_y) == 10)}} \u0026amp; 4\u0026#39;d3 | {3{($signed(tube_y) == 11)}} \u0026amp; 4\u0026#39;d0 | {3{($signed(tube_y) == 12)}} \u0026amp; 4\u0026#39;d5 | {3{(tube_y \u0026gt; 12)}} \u0026amp; 4\u0026#39;d6; // 与透明度结合决定 Mask assign mask = col_in[3] \u0026amp; tube_place_mask; // 根据压缩图上的 x，y 坐标决定访问地址 assign addr = tube_place_mask ? (tube_img_y * 26 + tube_x) : 10\u0026#39;d256; // 不做后处理，直接输出颜色 assign col_out = col_in; 管道的图像在压缩后如下，是一张 26*7 的图片：\n管道的纵向坐标将会经过一个分段函数映射后得到正确的颜色。\n显示数字：分数渲染器 十进制分数最高只能增加到 999。这为我们的偷懒提供了帮助：我们只要对一位数、两位数、三位数分别写好分数的绘制方式，根据位数做一次选择，就能得到最终绘制的蒙版和颜色。\n而分数字体用一个 120 * 18 的精灵存储：\n// View/Renderers/ScoreRenderer.v localparam num_w = 12, num_h = 18, img_w = 120, score_y = 54, score_x11 = 144 - 12, score_x21 = 144 - 24, score_x22 = 144 - 0, score_x31 = 144 - 12 - 24, score_x32 = 144 - 12, score_x33 = 144 - 12 + 24; // Pass 1 // 这是一个选择器，决定当前显示的位数； wire score_view_1 = ~(|score_decimal[11:8]) \u0026amp; ~(|score_decimal[7:4]), score_view_2 = ~(|score_decimal[11:8]) \u0026amp; (|score_decimal[7:4]), score_view_3 = (|score_decimal[11:8]); // 计算分数的访存坐标 wire [11:0] score_posx_11 = (screen_x - score_x11) \u0026gt;\u0026gt; 1; wire [11:0] score_posx_21 = (screen_x - score_x21) \u0026gt;\u0026gt; 1; wire [11:0] score_posx_22 = (screen_x - score_x22) \u0026gt;\u0026gt; 1; wire [11:0] score_posx_31 = (screen_x - score_x31) \u0026gt;\u0026gt; 1; wire [11:0] score_posx_32 = (screen_x - score_x32) \u0026gt;\u0026gt; 1; wire [11:0] score_posx_33 = (screen_x - score_x33) \u0026gt;\u0026gt; 1; wire [11:0] score_posy = (screen_y - score_y) \u0026gt;\u0026gt; 1; // 计算每一位数的访存地址 wire [11:0] score_addr_11 = score_posx_11 + img_w * score_posy + score_decimal[3:0] * num_w; wire [11:0] score_addr_21 = score_posx_21 + img_w * score_posy + score_decimal[7:4] * num_w; wire [11:0] score_addr_22 = score_posx_22 + img_w * score_posy + score_decimal[3:0] * num_w; wire [11:0] score_addr_31 = score_posx_31 + img_w * score_posy + score_decimal[11:8] * num_w; wire [11:0] score_addr_32 = score_posx_32 + img_w * score_posy + score_decimal[7:4] * num_w; wire [11:0] score_addr_33 = score_posx_33 + img_w * score_posy + score_decimal[3:0] * num_w; // Pass 2 // 根据显示位数、游戏状态，对 x 和 y 分量分别计算 Mask； wire score_mask_y = ($signed(screen_y) \u0026gt;= score_y) \u0026amp;\u0026amp; ($signed(screen_y) \u0026lt; score_y + 36); wire score_mask_x11 = game_status[1] \u0026amp;\u0026amp; score_view_1 \u0026amp;\u0026amp; ($signed(screen_x) \u0026gt;= $signed(score_x11)) \u0026amp;\u0026amp; ($signed(screen_x - LATENCY) \u0026lt; $signed(score_x11 + 24)); wire score_mask_x21 = game_status[1] \u0026amp;\u0026amp; score_view_2 \u0026amp;\u0026amp; ($signed(screen_x) \u0026gt;= $signed(score_x21)) \u0026amp;\u0026amp; ($signed(screen_x) \u0026lt; $signed(score_x21 + 24)); wire score_mask_x22 = game_status[1] \u0026amp;\u0026amp; score_view_2 \u0026amp;\u0026amp; ($signed(screen_x) \u0026gt;= $signed(score_x22)) \u0026amp;\u0026amp; ($signed(screen_x - LATENCY) \u0026lt; $signed(score_x22 + 24)); wire score_mask_x31 = game_status[1] \u0026amp;\u0026amp; score_view_3 \u0026amp;\u0026amp; ($signed(screen_x) \u0026gt;= $signed(score_x31)) \u0026amp;\u0026amp; ($signed(screen_x) \u0026lt; $signed(score_x31 + 24)); wire score_mask_x32 = game_status[1] \u0026amp;\u0026amp; score_view_3 \u0026amp;\u0026amp; ($signed(screen_x) \u0026gt;= $signed(score_x32)) \u0026amp;\u0026amp; ($signed(screen_x) \u0026lt; $signed(score_x32 + 24)); wire score_mask_x33 = game_status[1] \u0026amp;\u0026amp; score_view_3 \u0026amp;\u0026amp; ($signed(screen_x) \u0026gt;= $signed(score_x33)) \u0026amp;\u0026amp; ($signed(screen_x - LATENCY) \u0026lt; $signed(score_x33 + 24)); // 求并，得到位置 Mask。 wire score_place_mask = score_mask_y \u0026amp; (score_mask_x11 || score_mask_x21 || score_mask_x22 || score_mask_x31 || score_mask_x32 || score_mask_x33); // 结合透明度信息得到最终的 Mask。 assign mask = score_place_mask \u0026amp; col_in[3]; // 将不同位数字对应的 Mask 信息通过一个选择器决定访存的地址；而 12\u0026#39;d2161 是一个透明像素的地址。 assign addr = score_place_mask ? ({12{score_mask_y}} \u0026amp; ( {12{score_mask_x11}} \u0026amp; score_addr_11 | {12{score_mask_x21}} \u0026amp; score_addr_21 | {12{score_mask_x22}} \u0026amp; score_addr_22 | {12{score_mask_x31}} \u0026amp; score_addr_31 | {12{score_mask_x32}} \u0026amp; score_addr_32 | {12{score_mask_x33}} \u0026amp; score_addr_33 )) : 12\u0026#39;d2161; // 不加后处理地输出颜色 assign col_out = col_in; UI 渲染器 这里只展示根据时间戳计算 Gameover 渐入的透明度的部分。\nwire [31:0] gameover_delta_time = timer - gameover_timestamp; wire [31:0] alpha_time = $signed(gameover_delta_time) \u0026lt; 0 ? 0 : $signed(gameover_delta_time) \u0026gt; 31 ? 31 : $signed(gameover_delta_time); assign col_out = {col_in[15:4], (col_in[3:0] \u0026amp; {4{mask}} \u0026amp; ({4{game_status != 2\u0026#39;b11}} | alpha_time[4:1]))}; 先将时间和时间戳相减，得到经过的时间；再做一个 Clamp，将透明度限制在 $[0,1)$ 上；再和颜色一起输出透明度。\n其余的子渲染器与这些渲染器类似，都是一些很麻烦的代码（呜呜）可以参见源代码。\n4. Alpha 混合 我们将游戏的图层分为了三层：UI层（最上层）、鸟层（中间层）和其他元素层（最下层）。最上层有 Gameover 的透明度需要加以混合；鸟层有边缘抗锯齿的半透明像素需要混合；而其他元素层不含任何透明度混合。\nPixelRenderer 会先用选择器综合得到每一层对应的像素颜色和透明度，再用线性插值方法将它们混合起来。\n// Layer 0 wire [11:0] rgb_layer0 = (~screen_mask) ? col_outside : (score_mask) ? col_score[15:4] : (land_mask) ? col_land : (tube_mask) ? col_tube[15:4] : col_bg; // Layer 1 wire [11:0] rgb_layer1 = col_bird[15:4]; wire [4:0] a_layer1 = ({1\u0026#39;b0, col_bird[3:0]} + |col_bird[3:0]) \u0026amp; {5{screen_mask}}; // Layer 2 wire [11:0] rgb_layer2 = col_ui[15:4]; wire [4:0] a_layer2 = {1\u0026#39;b0, col_ui[3:0]} + |col_ui[3:0]; // Blending Layer 0\u0026amp;1 wire [7:0] r_blend_1 = rgb_layer0[11:8] * (8\u0026#39;b00010000 - a_layer1) + rgb_layer1[11:8] * a_layer1; wire [7:0] g_blend_1 = rgb_layer0[ 7:4] * (8\u0026#39;b00010000 - a_layer1) + rgb_layer1[ 7:4] * a_layer1; wire [7:0] b_blend_1 = rgb_layer0[ 3:0] * (8\u0026#39;b00010000 - a_layer1) + rgb_layer1[ 3:0] * a_layer1; // Blending Blend1 \u0026amp; Layer2 wire [7:0] r_blend_2 = r_blend_1[7:4] * (8\u0026#39;b00010000 - a_layer2) + rgb_layer2[11:8] * a_layer2; wire [7:0] g_blend_2 = g_blend_1[7:4] * (8\u0026#39;b00010000 - a_layer2) + rgb_layer2[ 7:4] * a_layer2; wire [7:0] b_blend_2 = b_blend_1[7:4] * (8\u0026#39;b00010000 - a_layer2) + rgb_layer2[ 3:0] * a_layer2; // Final Result assign rgb = {r_blend_2[7:4], g_blend_2[7:4], b_blend_2[7:4]}; 其中，透明度值都加上了一个 |col_bird[3:0] 或者 |col_ui[3:0]。这相当于一个分段函数，将大于 0 的值都加 1，而 0 保持为 0 不变。这个小 Trick 是为了将透明度的范围从 [0,15]（$[0,1)$）映射到 [0,16] （$[0,1]$），以在后面的混合中得到完全不透明时的结果。因为玩家不易注意到低透明度时的透明度变化，所以挖掉 1 比挖掉其他的透明度更加合算。\n而混合部分就是对每个分量做平凡的线性插值混合，在计算机图像处理或者计算机图形学一类的课会经常见到： $$ C_\\text{new}=(1-\\alpha)C_\\text{src}+\\alpha C_\\text{dest} $$ 这一部分大概吃了不少组合延时。能算出来真的相当神奇了，再次感谢玄学（什么）\n6 | 板上的控制 按钮与拉杆 板上的 BTNC 负责游戏的主要控制，BTNU 负责重置游戏，在上文已经介绍过了。\nSW[15] 控制无敌模式，当拉杆拉下时不会再受到伤害。\nSW[14] 控制超速模式，使鸟的水平速度增加到原来的 20 倍，可以快速飞到分数比较远的地方检查有没有 Bug 发生。\n通过拉杆输出 Debug 信息 为了 Debug 的方便，我们在 Top 模块中对不同的 SW 输入情况输出了不同的 LED 灯值和数码管。具体如下，也欢迎自行探索：\nSW[15:0]=??00_0000_0000_0000 如果没有开启无敌模式，就会根据游戏状态输出不同视效信息：\nReady 状态：数码管闪烁输出「FLAPPY」字样；LED 闪烁。 Ingame 状态：数码管输出十进制分数；LED 播放流动动画。 Gameover 状态：数码管输出十进制分数；LED 闪烁。 如果开启了无敌模式，LED 就会加速闪烁，数码管闪烁输出「god bird」字样。\nSW[15:0]=0000_0000_0000_0001 输出 CalcCore 的各个状态信息。\nLED[7:0]：哪个灯亮，就表示 CalcCore 目前处于哪个状态，用于在状态卡住时进行 Debug；也能起 Profile 作用，灯的亮度会显示状态的耗时；但实际的测试结果是状态 0 常亮，说明每帧的时间是充裕的。 LED[8]：由 timer 控制闪烁，表示游戏在正常进行。如果不闪了就说明 CalcCore 卡住了。 LED[11:9]：输出 BTNC 的按键信息，检查按键是否被正确处理（似乎有时会有玄学 bug 导致按键不被处理）。从 9 到 11 分别对应 Pressed，Check，Released 状态。Pressed 和 Released 只会闪烁一瞬间，相机很难捕捉到。 LED[12]：输出 BTNU 的按下信号，表示触发重试。 LED[13]：常暗。亮了就说明板子的其他地方出了玄学问题。 LED[15:14]：输出游戏主状态 game_status，用于检查。 左侧四组数码管：输出鸟的 y 坐标（十进制）。 右侧四组数码管：前三位输出十进制的分数信息 score_decimal；第四位输出 score % 10，用于检查。 SW[15:0]=0000_0000_0000_0010 LED 和右侧四组数码管都显示世界种子 world_seed[15:0]。 SW[15:0]=0000_0000_0000_0100 数码管和 LED 都显示计时器 timer 的值（16 进制/二进制）。 SW[15:0]=0000_0000_0000_1000 LED 显示二进制的分数值； 左侧四组数码管显示鸟的游戏坐标的后四位（十进制）； 右侧四组数码管显示屏幕上 1 号寄存器的管道右边缘横坐标的后四位（十进制），即唯一与玩家可能碰撞的管道位置。 SW[15:0]=0000_0000_0001_0000 LED 显示二进制的分数值； 右侧四组数码管显示屏幕上 1 号寄存器的管道左边缘横坐标的后四位（十进制），即唯一与玩家可能碰撞的管道位置。 左侧四组数码管显示管道的高度（十进制）。 SW[15:0]=0000_0000_0010_0000 LED 同 SW=0000_0000_0000_0001 的情形。不会显示 BTNU 的信号，是因为忘记了。 右侧四组数码管显示玩家的速度整数部分，但是是按照无符号十进制显示的。 左侧四组数码管显示玩家的高度（十进制）。 SW[15:0]=0000_0000_0100_0000 显示专为 CalcCore 预留的 Debug 输出接口信息。测试用。 SW[15:0]=0000_0000_1000_0000 显示专为 ViewCore 预留的 Debug 输出接口信息。测试用。 数码管的实现 实际开发板的数码管信号和 FPGA Online 不一样。实际开发管中每根管的亮灭都是可以控制的，须通过一个 7 bit 、低电平有效的信号向每组数码管输出每根管是否点亮。\n// ---6--- // | | // 1 5 // | | // ---0--- // | | // 2 4 // | | // ---3--- 我们实现了两种数码管的显示模式，一种是输入每根数码管的 16 进制数字，在数码管上显示出来，和平时作业中的 SegWithMask 的行为是相同的；这种模式能够方便地输出各种 Debug 信息。\n// Hardware/SegWithMask.v module SegWithMask( input clk, // 100MHz 时钟 input rst, // 复位信号 (高电平有效) input [31:0] output_data,// 输出数据 input [ 7:0] output_valid, // 每个数码管的有效信号 output reg [ 6:0] seg_data, // 7段显示器数据输出 output reg [ 7:0] seg_an // 8位数码管阳极控制 ); reg [31:0] counter; reg [2:0] seg_id; // 管 Id, 用于选择哪个数码管 reg [3:0] seg_data1; // 存储当前要显示的4位数据 // 生成400Hz的信号 always @(posedge clk) begin if (rst) begin counter \u0026lt;= 0; seg_id \u0026lt;= 0; end else begin if (counter \u0026gt;= 24999) begin counter \u0026lt;= 0; seg_id \u0026lt;= seg_id + 1; if (seg_id \u0026gt;= 3\u0026#39;b111) begin // 0-7的循环 seg_id \u0026lt;= 0; // Reset seg_id when it exceeds the last index (7) end end else begin counter \u0026lt;= counter + 1; end end end // 控制数码管 always @(*) begin if (output_valid[seg_id]) begin // 检查当前管是否有效 case (seg_id) 3\u0026#39;b000: begin seg_data1 = output_data[3:0]; seg_an = 8\u0026#39;b11111110; // 选择第一个数码管 end 3\u0026#39;b001: begin seg_data1 = output_data[7:4]; seg_an = 8\u0026#39;b11111101; // 选择第二个数码管 end 3\u0026#39;b010: begin seg_data1 = output_data[11:8]; seg_an = 8\u0026#39;b11111011; // 选择第三个数码管 end 3\u0026#39;b011: begin seg_data1 = output_data[15:12]; seg_an = 8\u0026#39;b11110111; // 选择第四个数码管 end 3\u0026#39;b100: begin seg_data1 = output_data[19:16]; seg_an = 8\u0026#39;b11101111; // 选择第五个数码管 end 3\u0026#39;b101: begin seg_data1 = output_data[23:20]; seg_an = 8\u0026#39;b11011111; // 选择第六个数码管 end 3\u0026#39;b110: begin seg_data1 = output_data[27:24]; seg_an = 8\u0026#39;b10111111; // 选择第七个数码管 end 3\u0026#39;b111: begin seg_data1 = output_data[31:28]; seg_an = 8\u0026#39;b01111111; // 选择第八个数码管 end default: begin seg_data1 = 4\u0026#39;b0000; // 如果没有选择，默认输出为0 seg_an = 8\u0026#39;b11111111; // 关闭所有数码管 end endcase end else begin seg_data1 = 4\u0026#39;b0000; // 如果无效，输出为0 seg_an = 8\u0026#39;b11111111; // 关闭所有数码管 end // 根据4位数字选择7段显示 case(seg_data1) 4\u0026#39;b0000: seg_data = ~7\u0026#39;b0111111; // 0 -\u0026gt; inverse 4\u0026#39;b0001: seg_data = ~7\u0026#39;b0000110; // 1 -\u0026gt; inverse 4\u0026#39;b0010: seg_data = ~7\u0026#39;b1011011; // 2 -\u0026gt; inverse 4\u0026#39;b0011: seg_data = ~7\u0026#39;b1001111; // 3 -\u0026gt; inverse 4\u0026#39;b0100: seg_data = ~7\u0026#39;b1100110; // 4 -\u0026gt; inverse 4\u0026#39;b0101: seg_data = ~7\u0026#39;b1101101; // 5 -\u0026gt; inverse 4\u0026#39;b0110: seg_data = ~7\u0026#39;b1111101; // 6 -\u0026gt; inverse 4\u0026#39;b0111: seg_data = ~7\u0026#39;b0000111; // 7 -\u0026gt; inverse 4\u0026#39;b1000: seg_data = ~7\u0026#39;b1111111; // 8 -\u0026gt; inverse 4\u0026#39;b1001: seg_data = ~7\u0026#39;b1101111; // 9 -\u0026gt; inverse 4\u0026#39;b1010: seg_data = ~7\u0026#39;b1110111; // A -\u0026gt; inverse 4\u0026#39;b1011: seg_data = ~7\u0026#39;b1111111; // B -\u0026gt; inverse 4\u0026#39;b1100: seg_data = ~7\u0026#39;b0111001; // C -\u0026gt; inverse 4\u0026#39;b1101: seg_data = ~7\u0026#39;b1011110; // D -\u0026gt; inverse 4\u0026#39;b1110: seg_data = ~7\u0026#39;b1111001; // E -\u0026gt; inverse 4\u0026#39;b1111: seg_data = ~7\u0026#39;b1110001; // F -\u0026gt; inverse default: seg_data = 7\u0026#39;b1111111; // Close all segments (i.e., turned on) endcase end endmodule 另一种输入模式则是通过一个 56 位信号直接输入每根管的点亮与否，可以用来显示各种非数字的字符或者图案。具体实现就是上述代码除去了查表的部分。例如，下面的 56 位信号表示了 “FLAPPY” 字样：\nSegData2 = 56\u0026#39;b1111111_0001110_1000111_0001000_0001100_0001100_0010001_1111111; 7 | 显示屏输出 这一部分是最早实现的，却放在了文章的后面（？）\n只要跟着文档一步步做，就能显示出视频啦。因为没什么设计，这里就简单放一下实现的方法，作为实验报告了。\nDST 用于控制显示屏是否接收串口的颜色信息。只要输出理想的波形就好。其中的 Latency 参数用于控制图片的访存延迟。\nmodule DST#( parameter LATENCY = 2 ) ( input [ 0 : 0] rstn, input [ 0 : 0] pclk, output reg [ 0 : 0] hen, //水平显示有效 output reg [ 0 : 0] ven, //垂直显示有效 output reg [ 0 : 0] hs, //行同步 output reg [ 0 : 0] vs //场同步 ); localparam HSW_t = 119; localparam HBP_t = 63 - LATENCY; localparam HEN_t = 799; localparam HFP_t = 55 + LATENCY; localparam VSW_t = 5; localparam VBP_t = 22; localparam VEN_t = 599; localparam VFP_t = 36; localparam SW = 2\u0026#39;b00; localparam BP = 2\u0026#39;b01; localparam EN = 2\u0026#39;b10; localparam FP = 2\u0026#39;b11; reg [ 0 : 0] ce_v; reg [ 1 : 0] h_state; reg [ 1 : 0] v_state; reg [15 : 0] d_h; reg [15 : 0] d_v; wire [15 : 0] q_h; wire [15 : 0] q_v; CntS #(16,HSW_t) hcnt( //每个时钟周期计数器增加1，表示扫描一个像素 .clk (pclk), .rstn (rstn), .d (d_h), .ce (1\u0026#39;b1), .q (q_h) ); CntS #(16, VSW_t) vcnt( .clk (pclk), .rstn (rstn), .d (d_v), .ce (ce_v), .q (q_v) ); always @(*) begin case (h_state) SW: begin d_h = HBP_t; hs = 1; hen = 0; end BP: begin d_h = HEN_t; hs = 0; hen = 0; end EN: begin d_h = HFP_t; hs = 0; hen = 1; end FP: begin d_h = HSW_t; hs = 0; hen = 0; end endcase case (v_state) SW: begin d_v = VBP_t; vs = 1; ven = 0; end BP: begin d_v = VEN_t; vs = 0; ven = 0; end EN: begin d_v = VFP_t; vs = 0; ven = 1; end FP: begin d_v = VSW_t; vs = 0; ven = 0; end default: begin d_v = 0; vs = 0; ven = 0; end endcase end always @(posedge pclk) begin if (!rstn) begin h_state \u0026lt;= SW; v_state \u0026lt;= SW; ce_v \u0026lt;= 1\u0026#39;b0; end else begin if(q_h == 0) begin h_state \u0026lt;= h_state + 2\u0026#39;b01; if (h_state == FP) begin ce_v \u0026lt;= 0; if (q_v == 0) v_state \u0026lt;= v_state + 2\u0026#39;b01; end else ce_v \u0026lt;= 0; end else if (q_h == 1) begin if(h_state == FP) ce_v \u0026lt;= 1; else ce_v \u0026lt;= 0; end else ce_v \u0026lt;= 0; end end endmodule PS 上边沿检测模块，也可以用来检测下边沿。考虑到 DST 输出的信号应该没有明显抖动，且需要及时响应，这里只用了二级寄存器。\nmodule PS#( parameter WIDTH = 1 ) ( input s, input clk, input rstn, output p ); reg sig_r1, sig_r2; always @(posedge clk) begin if(~rstn) begin sig_r1 \u0026lt;= 1\u0026#39;b0; sig_r2 \u0026lt;= 1\u0026#39;b0; end else begin sig_r1 \u0026lt;= s; sig_r2 \u0026lt;= sig_r1; end end assign p = sig_r1 \u0026amp; ~sig_r2; endmodule 在我的理解里，去抖动应该是为了按钮、拉杆等输入信号服务，而不是为了这些内部信号服务的？我们其实全程都没有涉及到“去抖动”的设计。\nDDPGame DDP 像一个“像素计数器”（？）对显示在屏幕上的像素作计数，将计数器的值映射到颜色。对助教的 DDP 做了大幅度的修改，从输出访存地址改为了输出像素位置。只要放开用乘法器（？）用像素位置做访存似乎更自然。\nmodule DDPGame#( parameter H_LEN = 800, parameter V_LEN = 600 )( input hen, input ven, input rstn, input pclk, input [11:0] rdata, output reg [11:0] rgb, output reg [10:0] pixel_x, pixel_y ); wire p; PS #(1) ps( .s (~(hen\u0026amp;ven)), .clk (pclk), .rstn(rstn), .p (p) ); always @(posedge pclk) begin //可能慢一个周期，改hen,ven即可 if(!rstn) begin rgb \u0026lt;= 12\u0026#39;b0; pixel_x \u0026lt;= 0; pixel_y \u0026lt;= 0; end else if(hen \u0026amp;\u0026amp; ven) begin rgb \u0026lt;= rdata; pixel_x \u0026lt;= pixel_x + 1; end else if(p) begin rgb \u0026lt;= 0; pixel_x \u0026lt;= 0; if(pixel_y == V_LEN - 1) begin pixel_y = 0; end else begin pixel_y \u0026lt;= pixel_y + 1; end end else rgb \u0026lt;= 0; end endmodule 8 | 碎碎念 Blog 怎么写了这么长！（呜呜）\n设计的部分思考了好几天。写代码的时间一共是 5 个下午 + 4 个晚上（？）感觉还是很充实快乐的。\n与其把它当成 Verilog 的大作业，我更愿意把它当成一个限制性编程的小挑战。打破传统思维，用一种新的硬件编程思维去做游戏，意外地很新鲜很好玩。对下个学期的组原课程也许也充满动力了。\n终于做完了！耶\n","permalink":"https://rubatotree.github.io/blog/posts/fpga-flappy/","summary":"\u003cp\u003e同步一下之前（2024冬）写过的文章~\u003c/p\u003e\n\u003cp\u003e不知不觉快到期末了，也做完了本学期数字电路实验课程的最后一个实验。我选择了实验中分值最高的，组队用 FPGA 完成一个能在 VGA 屏幕上显示的小游戏。正好，在多年前我用 Gamemaker 复刻过一个 Flappy Bird，于是决定把它搬到 FPGA 上。\u003c/p\u003e","title":"用 FPGA 写 Flappy Bird"},{"content":" 同步一下之前（2024春）写过的文章，这是我当时在 计算机图形学 课上完成的作业报告，作为最难的一次作业，当时写了非常长的报告。\n本次作业要求实现 ARAP，ASAP 与 Hybrid 三种非固定边界的曲面参数化算法。我在理解并实现了这些参数化算法的基础上，对 ASAP 做了迭代方法和单一方程组方法的两种实现，并对这些算法做了进一步研究。\n这次作业在数学方面的知识对我来说还有许多我个人不太能独立理解的部分。感谢 @suchiwz 助教的耐心解答，让我能够对论文的各种细节做出能让我满意的理解。在本次作业报告中，我也会试着用刚做完 Homework 4 的大一学生也能理解的语言讲解我对这篇论文的理解。\n0. 准备工作 本次作业新增了四个模型。它们的共同特点都是有比较好的切割（没有像 Bunny Head 那样过细的瓶颈了），并且都有各自的难点，如下表所示：\n模型 特点 Cow 面数较多；网格较复杂，难以避免重叠；切割后仍保留了较多模型本身的几何特征（头部、眼睛、肢体），易于观察展开算法对形状的处理，确认算法的保形效果。 Beetle 高亏格曲面（即存在多条边界的曲面） Isis 有较多“细长”的三角形 Gargoyle 网格顶点数、面数非常多 Beetle 模型打破了 “模型只有一个边界” 的假设，因此我们需要对 Homework4 的边界映射算法做出调整，对每个边界都进行一次遍历，并取长度最长的边界作为映射的边界。相应地，对 Tutte 参数化中用到边界相关的代码进行调整，不再视不为主要边界的点位边界。这样，Tutte 参数化的结果就能够较好地处理 Beetle 模型，并将其作为 ARAP 的 Initial Guess 了。下图是 Floater 参数化处理后的 Beetle 模型。\n图 1 纹理映射结果 图 2 参数化结果（Floater） 对于本次作业的类型设计，因为每种算法都要考虑每个三角面的映射、 矩阵与能量，因此我单独为每个算法中的三角面设计了结构体，负责存储纹理坐标、映射结果、变换矩阵，并更新变换矩阵、计算能量，每次 Local 步骤中只需要遍历三角面并依次执行更新变换矩阵函数即可。我对每个算法本身也设计了类型结构。\n但是本次作业的类型设计有较多偷懒的地方，有较多为了编程便利而浪费的内存（如纹理坐标在每个三角面中又存了一遍（其实可以考虑用引用？）；三个顶点的映射结果必有一个是原点，其实不必存储）。我也并没有设计类的继承结构，而是将相似的结构对每个类型都复制了一遍。如果以后有机会重构代码，这些问题是有必要的解决的。\n1. ARAP 思路解析 本次论文中的几个算法都采用了相似的设计思路：先从参数化的理想结果出发，定义一个参数化能量；再通过解方程或者 Local-Global 迭代方法求这个能量的最小值。ARAP 定义的能量如下：\n它衡量的是网格中每个三角面“变形程度”的和。最外部的求和是对所有三角面能量的求和。每个三角面中，\n是将曲面上的点参数化映射后的实际结果； 描述了三角面中线段理想的变形结果——全等映射，即 As Rigid as Possible。 是将三维网格中的单个三角面全等映射到平面后的结果，以便用二维矩阵进行全等变换； 则是一个描述全等变换的矩阵。 描述的是原三角网格中，与该线段相对的角的余切值。 算法将全等变换作为参数化的理想结果，用对三角形每条线段映射后的实际结果与理想结果的向量作差并取距离平方，并用 值加权， 从而定义了每个三角形与其理想变换结果的差距。非可展曲面不可能将所有三角面全等地参数化映射到一个平面上，因此这一能量不可能取到 值。但是，这一能量存在最小值，我们可以将其作为我们的目标。\n从以上能量描述中，我们提取出自由的量：每个顶点均有一个参数坐标 待求解，每个三角面均有一个全等变换矩阵 待定。这些量必有一个取值组合能使得总能量最小。求出这个取值组合，也就求出了所有点的参数坐标，完成了曲面的参数化。因此，我们将几何上的参数化问题转换成了一个最优化问题。\n数学分析课程中介绍的极值问题解法是对待求极值函数（假设有 个自由变量）中的每个自由变量求偏导，令它们全部等于 ，列出 个含有 个变量的方程；解出该方程组成立的所有自由变量组合，并代入进行进一步验证。\n这一方法对于 ASAP 是可行的，但对于 ARAP 存在一些困难。全等变换的矩阵只有一个自由度，即 2D 旋转变换的角度（关于平移的问题会在后面解释）；无论如何用这个自由度表示 ，将得到的能量对这一自由度求导，总是无法让这一自由度在方程组中以线性形式出现（如 虽然只有一个自由度，但却并不是一个线性的方程组，对于计算机来说很难找到合适的机械算法进行求解）。\n因此，我们不考虑一口气解出所有的自由变量。我们注意到当 固定的时候， 存在一个最优值：将 全等变换到离 “最接近”的三角形时对应的矩阵。论文将这一“最接近”描述成了严谨的数学概念，这在后文中会讲解。论文给出了对每个三角形，在 作为已知量的情况下，求解 的方法，即 Local 步骤。\n而当 固定的时候，能量中 的每个分量都是以二次、一次的形式出现的。因此，我们对该能量以 的每个分量求偏导，就能得到一个关于 的线性方程组，使用 Eigen 求解即可，即 Global 步骤。\n将这两个步骤相互迭代，每次固定一组量，求出能让当前能量最小的另一组量，就能让能量值不断降低。这一能量最终会收敛于全局最小值。这样，经过多次迭代，我们也能在数值上求解能使能量最小的参数组合。\n论文给出了一种形象的描述，如下：\nLocal 步骤：先将三角网格的每个三角形拆卸下来，参考已有的参数化结果，把每个三角形分散放在平面上； Global 步骤：参考分散放置的三角形，对它们原本共有的顶点粘在一起，得到一个参数化结果以给 Local 步骤参考。 图 3 Local/Global 步骤示意图 具体操作 (1) 映射三角面 如果想要描述一个 2D 到 2D 的全等变换，我们需要描述平移、旋转的量。如果不使用齐次坐标，我们很难用矩阵描述这样的变换。但是，我们观察定义能量的定义式，可以发现，能量只关心三角形的边向量，无论怎样平移三角形都不会改变能量的值。全等变换对能量的自由度实际上只有旋转一个。因此，我们不妨在将三角形映射到平面时，采取最简单的规则，即将其中一个顶点 映射到原点上，一个顶点 映射到 轴上，通过三角形的不翻转的全等变换唯一确定顶点 的位置。这样，我们就能大大简化问题。\n先考虑从平面三角形到参数化后三角形的映射 ：\n这一组方程实际上可以去掉一个，写成如下的矩阵形式：\n从而得到\n这个矩阵在论文中也被称为离散三角网格的 Jacobi 矩阵。ARAP 算法还给出了另一种矩阵 ，在算法迭代过后能得到与 Jacobi 矩阵相同的结果（在迭代 ASAP 算法中不等价）：\n这样，我们用数学描述了三角面从三维网格全等映射到平面，再用 Jacobi 矩阵映射到与参数平面中对应三角形全等的目标三角形的过程。\n(2) Local 步骤 在 Local 步骤中，我们视已有的参数化结果（在第一次迭代时，将 Tutte 参数化的结果作为 ）为固定量，寻找能让能量最小的 组合。论文给出了寻找这种 的方法，并证明了其正确性。\n先将 （或者 ）作 SVD 分解 ； 将其中的 分量替换为单位矩阵； 将替换后的结果作为 ，即 。 SVD 分解中的 与 是行列式为正的正交阵，对应两次旋转变换； 是对角阵，其两个对角元记为 ，称为奇异值，对应两个方向上的伸缩变换（奇异值可以为负，对应翻转）。将 分量替换为单位阵，即取消了变换中的伸缩部分，只保留旋转部分。Eigen 提供了二阶矩阵奇异值分解的类。\n论文在附录中证明了 ARAP 能量等于下式，从而证明了以上方法的正确性：\n(3) Global 步骤 在 Global 步骤中，我们固定 ，寻找能使总能量最小的 的组合。这一组合能通过对所有顶点的 的每个分量分别求偏导后解线性方程组得到。论文已经给出了对顶点 的 求偏导，并使其等于 ，列出的方程：\n这是我们擅长求解的线性方程组。但在求解之前，还要注意方程组的一些特点：\n该方程左侧的系数对于同一个顶点的 分量都是相等的，从而我们可以把矩阵从 简化成 的形式，并通过对右侧的 分量分别求解得到 的 分量。\n观察该方程，它只关心 分量之间的差值。如果对每个 都做相等的平移，该方程组仍然成立！因此，该方程组的增广矩阵并非行满秩。为了让方程组只有唯一解，我们需要固定其中一个 点，来防止参数化结果的平移。\n最朴素的固定方法是将该顶点对应的单个方程改成 ，右侧为固定住的位置。但是这样的改写破坏了系数矩阵的对称性。我们可以进一步将 对应列的系数也全部设置为 ，在方程右侧减去用 代入得到的量，从而列出对称正定的方程组，用 Cholesky 分解求解，优化求解效率。\n该方程的系数矩阵仅仅与原网格的性质与被固定的量有关，因此我们可以在最开始就列出该矩阵并进行预分解，在迭代过程中用已有的求解器进行 Global 步骤，从而优化效率。\n在求解之后，我们还需要注意：\n参数化结果的任意旋转也不会改变整体的能量。对于部分数据，可能会出现这样的情况：随着 Local / Global 步骤的进行，参数化结果会不断旋转，而得不到一组收敛的 值。为了解决这个问题，我们除了固定一个位置锚点外，在算法开始时还需确定一个方向锚点，在 Global 步骤完成后，对整体以位置锚点为轴旋转，将方向锚点转回最初位置锚点-方向锚点确定的射线上。这个旋转可以通过复数比较漂亮地完成。 综上，我们分别需要确定两个锚点：一个位置锚点和一个方向锚点，分别是为了保证方程有唯一解，和保证参数化坐标最终收敛到一组确定的值。因为这是保持刚性的参数化方法，因此我们不能固定两个位置锚点，否则参数化结果会被“折断”。\n小心地实现了以上注意点后，我们就能得到一个稳定高效的 Global Phase 了。\n(4) 将步骤连接起来 在参数化算法开始前，我们可以预先确定要迭代的次数；反复进行 Local/Global 步骤后，我们就能得到一个理想的参数化结果。\n在得到结果后还有事情要干！因为 ARAP 是尽可能全等的变形，因此最后得到的参数平面中的三角形大小应与原三角网格中的三角形相近。但是，为了将纹理贴上参数平面，我们需要将参数平面进一步放缩，将其归一化到 的范围内。这样，我们就完成了 ARAP 算法的全部内容。\n效果展示 以下展示了 Cow 模型在不同迭代次数下的 ARAP 结果（正方形边界的 Floater 参数化作初值）：\n1 2 6 10 以下展示了其他模型在 ARAP 收敛（ 次迭代）后的参数化结果：\nBeetle Isis Gargoyle 因为 ARAP 是一种尽可能刚性的变换，所以会难以处理有较细瓶颈的、切割的不太好的曲面。以下是 Bunny_Head 与 David 的参数化结果，可以看到明显的三角形反转：\nBunny Head David 事实上，在 Cow 模型的边界与 Gargoyle 模型的局部也存在三角形翻转的问题。这也说明了这一算法并不完美，需要更优秀的 UV 展开才能得到好的参数曲面。\n2. ASAP ASAP 方法是尽可能相似的参数化算法，其中的相似即是相似三角形中的相似。与 ARAP 的全等变换相比，ASAP 的变换矩阵新增了一个缩放自由度，使得我们能用一个方程组直接求出所有的 。\nASAP 定义的能量与 ARAP 相同，只是对 的要求从全等变换（旋转变换）变成了相似变换。这样，我们可以将 写成 的形式，并对每个顶点的 每个三角形的 求偏导（这个时候求偏导后的 也是线性的，不再受 ARAP 那种限制了），得到一个自由度为 的线性方程组。直接对其求解即可。\n单一方程组方法 论文并没有直接给出对 求偏导的结果，但我们可以从对附录给出的 Hybrid 求导的结果里抄作业。\n对于顶点对应的行，我们直接在 ARAP 的方程组基础上，将方程右侧的 展开为关于 的线性式，求出方程右侧关于 , 的系数，并取负填入系数矩阵中 对应列即可。注意这里顶点坐标 分量对应的 系数不再相等了，因此不能再将系数矩阵缩小一倍，对分量分别求解了。\n对于三角面对应的行，我们参考 Hybrid 中对能量的 分量求偏导的结果：\n考虑 ASAP 的能量，方程组可以简化成如下形式，这是关于 的线性方程组：\n其中 中的 中含有未知量，将其展开成 的形式，整理出其系数，并分别填入系数矩阵中即可。\n在将方程组填入代码前，我们同样需要检查自由度的问题。我们首先注意到， 时，能量取最低值 ，对应了方程的退化情形。进一步思考，当参数化结果平移、旋转时，能量大小不变；当参数化结果缩小时，能量也会减小。为了防止参数化结果的平移、旋转、缩放、退化，我们可以固定两个位置锚点——因为参数化结果不再刚性，因此可以固定其尺寸。与 ARAP 相同，直接朴素地将两个顶点对应行设置为形如 的等式即可。这个矩阵也可以进一步化为对称正定的形式，但因为我目前的代码结构这样做会很麻烦，所以我还没有这样做。也许有重构机会的话我会试着把它化为对称阵。因为不传入 Initial Guess，所以我分别将三维模型中 方向的两个最远点固定在了 和 （所有点的 坐标都相同时特判）。因为最后会归一化，所以固定点位置的设置影响并不大。\n但是当我选取其他的固定点组合时，参数化的结果似乎也会发生变化…感觉不太应该发生这样的现象，但已经来不及检查了。\n值得一提的是，单一方程组方法不需要传入一个 Initial Guess，也不需要设置迭代次数；该方法可以天然地处理高亏格曲面（Beetle 模型自动地从最大边界展开了），因此可以作为其他方法的 Initial Guess 以加快收敛。\n迭代方法 除了单一方程组方法之外，论文还给出了求 ASAP 参数化的另一种思路，即 Local/Global 方法。这种方法只需要对 ARAP 的代码做很小的更改。\n论文将 ASAP 的能量最小值也化成了奇异值表示，形式如下：\n因此，在 Local 步骤中，只需要将 变为 即可使能量收敛于 ASAP 的最小能量。\n需要注意的是，在 ASAP 算法中， 矩阵的作用结果不再等于 矩阵的作用结果。我们需要求出原始的 矩阵进行奇异值分解。\n固定锚点的代码不需要修改，方程组求解过程中仍然只需要一个位置锚点。这是因为参考的参数化结果给定了一个三角形的大小，使得三角形不再能在 Global 步骤中自由地缩放。事实上两个位置锚点会造成参数化结果的扭曲。\n但是，和 ARAP 中的旋转类似，ASAP 的参数化结果有可能在迭代过程中产生缩放，使得最终结果无法收敛（并且这非常容易触发。能量减小的速度异常之快，实际上发生的是参数化结果不仅在趋于相似目标结果，还在不断缩小）。因此，在求解方程组之后，除了将图形转回锚点确定的方向之外，还需要将图形整体缩放，将“方向锚点”拉回其所在的位置。（事实上也算是固定了两个位置锚点，只是其中一个锚点的固定是在求解方程组过后才进行的）。\n虽然 ASAP 的迭代方法非常容易实现，但是其相比求解方程组方法，效率实在低下。其原因在于迭代收敛的速度实在太慢——Cow 模型需要迭代 次左右才能收敛至与单一方程组求解相近的形状。（而 ARAP 迭代 次左右就能得到相当令人满意的结果，尽管还没有完全收敛）\n效果展示 以下展示了不同模型在单一方程组求解 ASAP 后的参数化结果：\nCow Beetle Isis Gargoyle BunnyHead 可以看出相似变换的 ASAP 能正确处理 BunnyHead 模型。David 的参数化结果有明显问题，感觉是我哪里没写对。\n以下展示了 Cow 模型在不同迭代次数下的迭代方法 ASAP 结果：\n1 2 10 100 500 3. Hybrid 思路与操作 论文还发现，可以定义一种能量，通过控制能量中的参数 来混合 ARAP 和 ASAP 两种参数化方法。Hybrid 能量定义如下：\n其中 时，该能量的最优化与 ASAP 等价； 时，该能量的最优化与 ARAP 等价。\n可以这样理解：当 时，该式在形式上与 ASAP 等价；当 时，该能量强制要求 ，也就是要求变换矩阵为全等变换；当满足全等变换后，能量在形式上与 ARAP 等价。（我其实理解了很久才看出“强制要求全等变换”的含义）\n论文附录中指出，这里对 求偏导会得到三次的形式，如下：\n因此，和 ARAP 一样，我们无法通过解线性方程组求解该问题，从而转向 Local/Global 求解。Hybrid 的 Global 步骤和 ARAP 相同，因为求偏导后多出来的能量项全部消去了。下面研究 Local 步骤，即固定参数化坐标，求解 。\n关于 的三次方程组可以继续整理成如下形式：\n当 时有特解 。事实上我们在单一方程组求解的 ASAP 算法中就得到过该形式，但在该算法中 并不是常数。\n当 时有特解 。\n当 不为特殊值时，我们要用牛顿迭代法解该三次方程。初值的选取相当关键，因为如果初值选取不当，选取的结果可能无法得到全局极小值点，导致能量的发散。事实上， 是一个相当不错的初值。\n对 ARAP 算法的 Local 部分作出如上更改后，我们就实现了 Hybrid 算法。其实 Hybrid 算法的实现反而是最简单的？\n但由于 Hybrid 只能固定一个位置锚点和一个方向锚点，不能在每次 Global 后放缩参数化结果，因此在含有 ASAP 成分的参数化中，能量一定会有不断减小的趋势。同样地，Hybrid 实现的 ASAP 参数化的收敛也非常慢。\n效果展示 以下是 Isis 模型分别取 ，迭代 次的参数化结果：\n心得体会 在一周目的时候，我就确定了这个作业是所有作业里最难的一项。最优化，SVD 分解，Jacobi 矩阵，Local/Global 迭代方法…众多全新的数学概念给我幼小的心灵带来了极大的震撼。当时带着 ChatGPT 啃了好几天这篇论文，始终看不懂怎么去实现，也找不到看懂的方法，在网上搜索这些数学概念后也不觉得自己学会了，只能对“把三角形拆开再拼起来”的流程作感性的理解。最后作业的完成也非常 Cheat：在网上参考了一位学长的代码，把不知道该怎么实现的地方都看了一遍，再糊出一个 ARAP 的效果，不看 optional，直接跑路。当时“做完了”作业我也不觉得我学到了什么。\n后来做完弹簧质点模型加速算法后，我觉得我开始理解 Local/Global 迭代方法了。但因为寒假还在忙别的，所以没有回去重看 ARAP 的论文。现在二刷 Homework 5 后，我虽然还有一些数学概念没能完全理解，但我知道我该怎样去找方法理解了——边画图、查资料边和助教确认自己的理解，把没搞懂的东西各个击破，现在我觉得我已经能独立地实现 ARAP，ASAP，Hybrid 参数化算法，对论文的内容有了足够的理解了。寒假时丢掉的成就感在这里找回来了。\n这次作业绝对是这学期以来耗时最长的作业，不管是代码还是报告。从周二晚上肝到周六晚上，一些烂摊子（类结构设计的不好，ASAP 矩阵没来得及化成对称，ASAP 的固定点似乎还有问题，David 模型 ASAP 参数化出错等等）实在没精力收拾了（其他课还有好多作业！）。一些很普通的原因导致的 bug 耗了我很长时间，比如三角面初始化的时候所有三角形都翻转了，引起的 bug 花了我至少三个小时去各种地方查找；求 Jacobi 矩阵的时候 直接写成了 ，又花了我两个小时差错，等等。不过在查错的过程中我又反复翻了几遍论文，对论文看得更仔细了，是好事。\n在实现单方程组求解 ASAP 的时候还有过突发奇想，绕过辅助矩阵，直接以奇异值差的平方作为能量求解参数化坐标。在研究这个方法的过程中我手动求出了每个面用 表示的能量（其中有一个行列式的绝对值，我武断地去掉了绝对值，怀疑是这里出错了），用 Sympy 求偏导，再将求出的偏导式的 Latex 作为注释写进代码中，让 Github Copilot 帮我写构造线性方程组的代码，人工检查正确性（效果意外地不错，只填错了一项）。最后得到的结果是：局部还能看，但有大量很明显的三角形翻转。虽然我现在也不敢肯定这个错误是去掉绝对值导致的，但起码体验了一遍尝试发明算法的感觉。还是很惊叹于最新的科技，2008 年的时候可还没这么多减少试错成本的工具呢。\n对我而言最难的作业已经完成了，继续带着 optional 全收集的目标做完整个计算机图形学的作业吧。\n心得体会（2026） 两年过去了，这两年里既有一些快乐也有不少心酸。数字几何这门学科还是很优雅的。希望公开这个作业报告给接下来会复现这篇论文的大家参考一下吧。\nTable of Contents\n0. 准备工作\n1. ARAP\n思路解析\n具体操作\n(1) 映射三角面\n(2) Local 步骤\n(3) Global 步骤\n(4) 将步骤连接起来\n效果展示\n2. ASAP\n单一方程组方法\n迭代方法\n效果展示\n3. Hybrid\n思路与操作\n效果展示\n心得体会\n心得体会（2026）\n","permalink":"https://rubatotree.github.io/blog/posts/arap-note/","summary":"\u003cp\u003e同步一下之前（2024春）写过的文章，这是我当时在 \u003ca href=\"http://staff.ustc.edu.cn/~lgliu/Courses/ComputerGraphics_2024_spring-summer/default.htm\" target=\"_blank\" rel=\"noopener noreferrer\"\u003e\u003cspan style=\"color: #59a4ff;\"\u003e\u003cspan style=\"text-decoration: underline\"\u003e计算机图形学\u003c/span\u003e\u003c/span\u003e\u003c/a\u003e 课上完成的作业报告，作为最难的一次作业，当时写了非常长的报告。\u003c/p\u003e\n    \u003cp\u003e本次作业要求实现 ARAP，ASAP 与 Hybrid 三种非固定边界的曲面参数化算法。我在理解并实现了这些参数化算法的基础上，对 ASAP 做了迭代方法和单一方程组方法的两种实现，并对这些算法做了进一步研究。\u003c/p\u003e\n    \u003cp\u003e这次作业在数学方面的知识对我来说还有许多我个人不太能独立理解的部分。感谢 \u003ca href=\"https://github.com/suchiwz\" target=\"_blank\" rel=\"noopener noreferrer\"\u003e\u003cspan style=\"color: #59a4ff;\"\u003e\u003cspan style=\"text-decoration: underline\"\u003e@suchiwz\u003c/span\u003e\u003c/span\u003e\u003c/a\u003e 助教的耐心解答，让我能够对论文的各种细节做出能让我满意的理解。在本次作业报告中，我也会试着用刚做完 Homework 4 的大一学生也能理解的语言讲解我对这篇论文的理解。\u003c/p\u003e\n    \u003ch2 id=\"loc-1\"\u003e0. 准备工作\u003c/h2\u003e\n    \u003cp\u003e本次作业新增了四个模型。它们的共同特点都是有比较好的切割（没有像 Bunny Head 那样过细的瓶颈了），并且都有各自的难点，如下表所示：\u003c/p\u003e\n    \u003ctable\u003e\n      \u003ctr\u003e\n        \u003cth style=\"text-align: start; vertical-align: start;\"\u003e\u003cstrong\u003e模型\u003c/strong\u003e\u003c/th\u003e\n        \u003cth style=\"text-align: start; vertical-align: start;\"\u003e\u003cstrong\u003e特点\u003c/strong\u003e\u003c/th\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd style=\"text-align: start; vertical-align: start;\"\u003eCow\u003c/td\u003e\n        \u003ctd style=\"text-align: start; vertical-align: start;\"\u003e面数较多；网格较复杂，难以避免重叠；切割后仍保留了较多模型本身的几何特征（头部、眼睛、肢体），易于观察展开算法对形状的处理，确认算法的保形效果。\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd style=\"text-align: start; vertical-align: start;\"\u003eBeetle\u003c/td\u003e\n        \u003ctd style=\"text-align: start; vertical-align: start;\"\u003e高亏格曲面（即存在多条边界的曲面）\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd style=\"text-align: start; vertical-align: start;\"\u003eIsis\u003c/td\u003e\n        \u003ctd style=\"text-align: start; vertical-align: start;\"\u003e有较多“细长”的三角形\u003c/td\u003e\n      \u003c/tr\u003e\n      \u003ctr\u003e\n        \u003ctd style=\"text-align: start; vertical-align: start;\"\u003eGargoyle\u003c/td\u003e\n        \u003ctd style=\"text-align: start; vertical-align: start;\"\u003e网格顶点数、面数非常多\u003c/td\u003e\n      \u003c/tr\u003e\n    \u003c/table\u003e\n    \u003cp\u003eBeetle 模型打破了 “模型只有一个边界” 的假设，因此我们需要对 Homework4 的边界映射算法做出调整，对每个边界都进行一次遍历，并取长度最长的边界作为映射的边界。相应地，对 Tutte 参数化中用到边界相关的代码进行调整，不再视不为主要边界的点位边界。这样，Tutte 参数化的结果就能够较好地处理 Beetle 模型，并将其作为 ARAP 的 Initial Guess 了。下图是 Floater 参数化处理后的 Beetle 模型。\u003c/p\u003e","title":"ARAP 曲面参数化算法实现笔记"},{"content":" 前言 你好！我正在尝试使用 Typst 构建博客！\n感谢 George Honeywood [1] 的分享和室友 @Vertsineu 的帮助~\n图 1 你好，世界！ 本页面实际构建日期为 2026 年 5 月 11 日，为了同步一些早期的文章同时保持次序，将本文章的发布日期设置在了一个有意义的日子。\nTable of Contents\n前言\nReferences\nReferences [1] George Honeywood, “Typst and Hugo.” [Online]. Available: https://george.honeywood.org.uk/blog/typst-and-hugo/ ","permalink":"https://rubatotree.github.io/blog/posts/hello-hugo/","summary":"\u003ch2 id=\"loc-1\"\u003e前言\u003c/h2\u003e\n    \u003cp\u003e你好！我正在尝试使用 Typst 构建博客！\u003c/p\u003e\n    \u003cp\u003e感谢 George Honeywood \u003ca id=\"loc-2\" href=\"#loc-4\" role=\"doc-biblioref\"\u003e[1]\u003c/a\u003e 的分享和室友 \u003ca href=\"https://github.com/Vertsineu\" target=\"_blank\" rel=\"noopener noreferrer\"\u003e\u003cspan style=\"color: #59a4ff;\"\u003e\u003cspan style=\"text-decoration: underline\"\u003e@Vertsineu\u003c/span\u003e\u003c/span\u003e\u003c/a\u003e 的帮助~\u003c/p\u003e\n    \u003cp class=\"typst-parbreak\"\u003e\u003c/p\u003e\n    \u003cdiv style=\"display: grid; place-items: start center;\"\u003e\n      \u003cfigure\u003e\n        \u003cdiv style=\"display: grid; place-items: start center;\"\u003e\u003cimg src=\"/blog/images/hello-hugo/helloworld.jpg\" alt loading=\"lazy\"\u003e\u003c/div\u003e\n        \u003cdiv style=\"display: grid; place-items: start center;\"\u003e\n          \u003cfigcaption\u003e图 1 你好，世界！\u003c/figcaption\u003e\n        \u003c/div\u003e\n      \u003c/figure\u003e\n    \u003c/div\u003e\n    \u003cp class=\"typst-parbreak\"\u003e\u003c/p\u003e\n    \u003cp\u003e本页面实际构建日期为 2026 年 5 月 11 日，为了同步一些早期的文章同时保持次序，将本文章的发布日期设置在了一个有意义的日子。\u003c/p\u003e\n    \u003cdiv class=\"toc\" style=\"display: none\"\u003e\u003cdetails\u003e\u003csummary\u003eTable of Contents\u003c/summary\u003e\u003cdiv\u003e\u003cnav role=\"doc-toc\"\u003e\u003col style=\"list-style-type: none\"\u003e\u003cli\u003e\u003cp\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ca href=\"#loc-1\"\u003e前言\u003c/a\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u003ca href=\"#loc-3\"\u003eReferences\u003c/a\u003e\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u003c/p\u003e\u003c/li\u003e\u003c/ol\u003e\u003c/nav\u003e\u003c/div\u003e\u003c/details\u003e\u003c/div\u003e\n    \u003csection role=\"doc-bibliography\"\u003e\n      \u003ch2 id=\"loc-3\"\u003eReferences\u003c/h2\u003e\n      \u003cul style=\"list-style-type: none\"\u003e\n        \u003cli id=\"loc-4\"\u003e\u003cspan class=\"prefix\"\u003e\u003ca href=\"#loc-2\" role=\"doc-backlink\"\u003e[1]\u003c/a\u003e\u003c/span\u003e George Honeywood, “Typst and Hugo.” [Online]. Available: \u003ca href=\"https://george.honeywood.org.uk/blog/typst-and-hugo/\" target=\"_blank\" rel=\"noopener noreferrer\"\u003e\u003cspan style=\"color: #59a4ff;\"\u003e\u003cspan style=\"text-decoration: underline\"\u003ehttps://george.honeywood.org.uk/blog/typst-and-hugo/\u003c/span\u003e\u003c/span\u003e\u003c/a\u003e\u003c/li\u003e\n      \u003c/ul\u003e\n    \u003c/section\u003e","title":"Hello, World!"},{"content":"这里是我所珍视的好朋友们的博客链接——\n","permalink":"https://rubatotree.github.io/blog/friends/","summary":"Friends","title":"好朋友们！"}]