Refactor geometry generation to standardize Blender object coordinates
- Unified the canonical local frame for generated geometries (Plane, Depth Plane, Relief Plane, Cutout, Depth Cutout) to align with Blender's object coordinate system, setting X as horizontal, Z as up, and +Y as depth. - Removed the `Depth Axis` parameter from `O Image Cutout` and `O Image Depth Cutout`, simplifying the geometry generation process. - Updated the depth direction defaults to use +Y instead of -Z for `O Image Relief Plane` and Depth Symmetry. - Adjusted the geometry nodes to ensure thickness, projection, and shell displacements operate along the Y-axis. - Implemented new capabilities for handling object space normals to align with the new canonical frame. - Enhanced the Depth Symmetry functionality to mirror across the canonical Y-axis and perform a final rotation to maintain the correct orientation. - Added tests to validate the new coordinate system and ensure compatibility with existing assets.
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-09-14
|
||||
@@ -0,0 +1,111 @@
|
||||
## Context
|
||||
|
||||
当前 Plane、Depth Plane、Relief Plane、Cutout 与 Depth Cutout 的生成网格沿 Image Empty 局部坐标:图片平面为 XY,图片向上为 +Y,深度向纸内为 -Z。Cutout 的 BaseShape 位于 `Z=0`,Geometry Nodes 沿 Z 做厚度、投影和对称。这个约定与 Blender 常规对象坐标不一致:Blender 对象通常 up=Z、front=-Y。
|
||||
|
||||
为了把侧视对象最终摆成“左右对称轴为 X、up 为 Z”,现有实现给 Cutout 节点加入 `Depth Axis`,把输出整体转到 +X。该参数把最终摆放轴与对称轴耦合,还要求 Object Space Normal 额外补偿,使用户在四个 Cutout 入口间看到不一致的最终方向。
|
||||
|
||||
本次变更把生成几何的 canonical local frame 统一到 Blender 对象坐标,并删除 `Depth Axis`。
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
|
||||
- 为所有生成几何定义并实现同一套 Blender canonical local frame。
|
||||
- 让 Cutout BaseShape、Plane、Depth Plane、Relief Plane 的未修改网格都位于 XZ 平面,`Y=0`。
|
||||
- 让 Depth Symmetry 在 canonical 坐标中沿 Y 镜像,最后绕 Z 转到 X,保持 up=Z。
|
||||
- 让 Object Space Normal 随 canonical frame 和 Depth Symmetry 最终朝向一致。
|
||||
- 删除 `O Image Cutout` 与 `O Image Depth Cutout` 的 `Depth Axis` 接口和实现。
|
||||
|
||||
**Non-Goals:**
|
||||
|
||||
- 不改变 Image Empty 自身坐标或 Blender 相机/Server 模型输出坐标。
|
||||
- 不为用户新增轴向选择项。
|
||||
- 不自动迁移用户工程中已保存的旧节点组或已生成对象。
|
||||
|
||||
## Decisions
|
||||
|
||||
### 1. 新 canonical frame 由创建阶段直接生成
|
||||
|
||||
不添加“全局坐标变换”节点,而是在 Python 建网和节点构建阶段直接按新坐标生成。
|
||||
|
||||
```text
|
||||
旧 Image Empty local → 新 canonical object local
|
||||
|
||||
X → X
|
||||
Y → Z
|
||||
-Z → +Y
|
||||
+Z → -Y
|
||||
```
|
||||
|
||||
结果:
|
||||
|
||||
```text
|
||||
X = 图片右
|
||||
Z = 图片 up
|
||||
+Y = 图片纸内 / depth
|
||||
front = -Y
|
||||
BaseShape / Plane 未修改网格位于 XZ 平面,Y=0
|
||||
```
|
||||
|
||||
备选方案是在所有 modifier 前统一旋转,但会让 BaseShape、UV、metric 和节点内部轴反复转换,且不能消除 `Depth Axis` 类补偿。直接生成更直接,符合“少就是多”。
|
||||
|
||||
### 2. 所有节点深度轴从 Z 改为 Y
|
||||
|
||||
厚度、投影、Shell、Balloon、Relief 位移和 Depth Symmetry 镜像均改为 Y 轴语义:
|
||||
|
||||
- Image Plane 的网格/立方体尺寸使用 X/Z,厚度沿 Y。
|
||||
- Depth Plane 与 Relief Plane 的投影位移沿 Y。
|
||||
- Cutout 与 Depth Cutout 的 front/back 方向由 -Y/+Y 表达。
|
||||
- `Depth Direction` 默认值从 `(0, 0, 1)` 改为 `(0, 1, 0)`。
|
||||
|
||||
### 3. Depth Symmetry 作为两阶段坐标语义
|
||||
|
||||
`O Image Cutout Symmetry` 保持“先 canonical 对称、后最终摆放”:
|
||||
|
||||
```text
|
||||
canonical step:
|
||||
mirror plane = XZ, mirror axis = +Y
|
||||
keep one Y sign, mirror to the other side
|
||||
|
||||
final step:
|
||||
rotate around Z so +Y → +X
|
||||
keep +Z as up
|
||||
```
|
||||
|
||||
该 yaw 旋转同时会把 canonical front `-Y` 变成 `-X`。这是本变更明确接受的最终朝向。
|
||||
|
||||
删除 `O Image Cutout` 与 `O Image Depth Cutout` 的 `Depth Axis`。Depth Symmetry 的最终朝向只存在于 `O Image Cutout Symmetry`。
|
||||
|
||||
### 4. Object Space Normal 使用明确的几何属性契约
|
||||
|
||||
材质仍通过 Geometry 属性把 Object Space Normal 从生成坐标转换到最终渲染坐标:
|
||||
|
||||
- canonical frame 转换进入 Object Normal 的解释路径。
|
||||
- Depth Symmetry 的 front/back 反射改为 canonical Y 反射。
|
||||
- 最终 yaw 旋转由 `O Image Cutout Symmetry` 写入最终朝向属性,材质读取同一属性。
|
||||
- 删除旧 `Depth Axis` 对应的 `CUTOUT_Z_TO_X` 补偿路径。
|
||||
|
||||
普通 Plane / Depth Plane / Relief Plane 的 Object Normal 也按新 canonical frame 验证,不再依赖 Cutout 的旧轴补偿。
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- 影响面很大,几乎覆盖所有生成几何和节点资产 → 使用既有 `uv run node-group build` 与全量测试闭环;不保留兼容层。
|
||||
- BaseShape 和 Plane 世界位置可能出现符号/方向回归 → 对每个入口比较源 Image Empty 的世界 bounds 和生成网格 world-space 包围盒。
|
||||
- Object Space Normal 在渲染中的表现可能不易从网格位置直接推断 → 保留/扩展材质渲染测试,覆盖 front、back、wall 和最终朝向。
|
||||
- Depth Symmetry 最终 front 从 -Y 变为 -X,可能影响后续用户操作 → 在 spec 中明确该行为,不提供旧行为。
|
||||
- 旧 `.blend` 内嵌节点和已生成对象无法自动迁移 → 运行时继续从 `O_AnyImage.blend` 资产加载,不扫描用户工程。
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. 先在 Python 建网层实现新 canonical frame,并同步 Cutout BaseShape、Plane、Depth Plane、Relief Plane 的顶点/UV/法线。
|
||||
2. 重写 Geometry Nodes 的轴语义并删除 `Depth Axis`。
|
||||
3. 调整 Depth Symmetry 与 Object Normal 属性契约。
|
||||
4. 更新测试、`tools/nodes/check.py` 和资产构建;运行 `uv run node-group build`。
|
||||
5. 运行全量测试并检查旧 `Depth Axis`、旧轴常量与旧 world-space 方向引用。
|
||||
|
||||
回滚策略为从版本控制恢复本次变更前的源码与 `O_AnyImage.blend`,不涉及数据迁移。
|
||||
|
||||
## Open Questions
|
||||
|
||||
- 最终 yaw 旋转选择 `+Y → +X` 还是 `+Y → -X`:在实现时用一个小型 orientation test 固定,保持 front 变化方向可预测。
|
||||
- 普通 Plane / Depth Plane 的 Object Normal 转换放在材质节点内还是图片加载阶段:设计倾向保留材质属性契约,实现时按节点复杂度和测试成本选择。
|
||||
@@ -0,0 +1,28 @@
|
||||
## Why
|
||||
|
||||
AnyImage 生成对象的局部坐标系仍沿用 Image Empty 的 `XY + depth -Z`,与 Blender 常规对象坐标 `up=Z`、`front=-Y` 不一致。Cutout 因此需要额外的 `Depth Axis` 来把结果转到左右轴,但没有真正解决对称轴、深度方向和 Object Space Normal 的耦合问题。
|
||||
|
||||
## What Changes
|
||||
|
||||
- 统一所有生成几何的 canonical local frame:X 为图片水平、Z 为图片 up、+Y 为图片纸内深度、front 为 -Y。
|
||||
- BaseShape 与 Plane、Depth Plane、Relief Plane、Cutout、Depth Cutout 的未修改网格统一位于 XZ 平面,`Y=0`。
|
||||
- **BREAKING**:删除 `O Image Cutout` 与 `O Image Depth Cutout` 的 `Depth Axis` 输入及最终轴向旋转逻辑。
|
||||
- `O Image Cutout Symmetry` 在 canonical 坐标中沿 Y 轴镜像,最后绕 Z 旋转使对称轴指向 +X,并保持 up=+Z。
|
||||
- Depth Symmetry 最终对象允许 front 从 -Y 改变为 -X,以换取左右对称轴为 X。
|
||||
- Object Space Normal 的生成与着色转换随新 canonical frame 和最终对称朝向同步调整。
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `canonical-object-frame`: 定义所有生成几何共用的 Blender 对象局部坐标系、BaseShape 平面、UV 映射与深度方向。
|
||||
- `depth-symmetry-orientation`: 定义 Depth Symmetry 的 canonical 镜像轴、最终对称轴和 up 轴约束,以及允许 front 改变的最终朝向。
|
||||
- `object-space-normal-alignment`: 定义 Object Space Normal 如何随 canonical frame、Depth Symmetry 镜像与最终朝向保持对齐。
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
无。当前 `openspec/specs/` 中没有既有 capability 规格。
|
||||
|
||||
## Impact
|
||||
|
||||
影响 `src/anyimage/operators/cutout_tool/geometry.py`、`object.py`、`depth_calibration.py`,`src/anyimage/operators/convert_to_plane/`,`tools/nodes/groups/` 下的 Plane、Depth Plane、Relief Plane、Cutout、Depth Cutout、Symmetry 与材质节点,`tools/nodes/common/` 的深度表面、Cutout 和法线映射辅助,以及相关测试与 `src/anyimage/assets/O_AnyImage.blend`。不新增依赖。
|
||||
@@ -0,0 +1,63 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Generated meshes use the Blender object frame
|
||||
|
||||
系统 SHALL 让 Plane、Depth Plane、Relief Plane、Cutout BaseShape 与 Depth Cutout 的输入网格使用统一的 Blender 对象局部坐标:X 为图片水平方向,Z 为图片 up,+Y 为图片纸内深度方向。所有未应用 modifier 的输入网格 MUST 位于 `Y=0` 的 XZ 平面。
|
||||
|
||||
#### Scenario: Create a Plane or Cutout BaseShape
|
||||
|
||||
- **WHEN** 用户创建 Plane 或 Cutout BaseShape
|
||||
- **THEN** 未应用 modifier 的本地顶点 Y 坐标均为 0
|
||||
- **AND** 顶点 X 范围对应源 Image Empty 的水平 bounds
|
||||
- **AND** 顶点 Z 范围对应源 Image Empty 的 up bounds
|
||||
|
||||
### Requirement: Image UV maps to the XZ plane
|
||||
|
||||
系统 SHALL 将源图片的左右方向映射到本地 X,将源图片的上下方向映射到本地 Z,并保持 UV 采样在生成网格上的方向一致。
|
||||
|
||||
#### Scenario: Cutout UV corners follow image corners
|
||||
|
||||
- **WHEN** Cutout 从完整图片 bounds 生成 BaseShape
|
||||
- **THEN** 图片左下角对应的本地顶点位于最小 X 和最小 Z
|
||||
- **AND** 图片右上角对应的本地顶点位于最大 X 和最大 Z
|
||||
- **AND** UV 读取的颜色纹理方向与源图片一致
|
||||
|
||||
### Requirement: Depth and thickness operate along Y
|
||||
|
||||
系统 SHALL 让 Depth Plane、Relief Plane、Cutout 与 Depth Cutout 的投影、厚度和 Shell 位移沿本地 Y 方向表达,并 SHALL 让 front 方向为 -Y、depth/纸内方向为 +Y。
|
||||
|
||||
#### Scenario: Depth Plane displaces toward positive Y
|
||||
|
||||
- **WHEN** Depth Plane 使用有效深度图且 Reference Depth 大于采样深度
|
||||
- **THEN** 生成表面的 Y 坐标向 +Y 方向偏离输入平面
|
||||
- **AND** 输入平面保持在 `Y=0`
|
||||
|
||||
#### Scenario: Cutout thickness grows along Y
|
||||
|
||||
- **WHEN** Cutout 设置非零 Thickness
|
||||
- **THEN** 生成 Shell 的前后范围沿 Y 轴分布
|
||||
- **AND** 没有几何沿 Z 轴被当作厚度方向
|
||||
|
||||
### Requirement: Depth Direction defaults to positive Y
|
||||
|
||||
`O Image Relief Plane` 与 Depth Symmetry 的 canonical 深度方向 SHALL 使用本地 +Y 作为默认方向,而不是 -Z。
|
||||
|
||||
#### Scenario: Relief Plane direction default
|
||||
|
||||
- **WHEN** 用户从资产加载 `O Image Relief Plane`
|
||||
- **THEN** `Depth Direction` 默认值为 `(0, 1, 0)`
|
||||
|
||||
#### Scenario: Depth Symmetry canonical direction
|
||||
|
||||
- **WHEN** Depth Symmetry 使用默认方向校准
|
||||
- **THEN** 对称前的 canonical 镜像轴 SHALL 为 Y
|
||||
|
||||
### Requirement: Cutout node assets no longer expose Depth Axis
|
||||
|
||||
`O Image Cutout` 与 `O Image Depth Cutout` MUST 不再公开 `Depth Axis` 输入,并且 MUST 不包含把最终几何从 -Z 转到 +X 的旧轴向旋转。
|
||||
|
||||
#### Scenario: Inspect Cutout interfaces
|
||||
|
||||
- **WHEN** 检查 `O Image Cutout` 和 `O Image Depth Cutout` 的输入接口
|
||||
- **THEN** 不存在名为 `Depth Axis` 的 socket
|
||||
- **AND** 节点组内不存在旧 `CUTOUT_Z_TO_X` 最终旋转
|
||||
@@ -0,0 +1,43 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Depth Symmetry mirrors across the canonical Y axis
|
||||
|
||||
`O Image Cutout Symmetry` SHALL 在 canonical Blender 对象坐标中沿 Y 轴镜像,即镜像面为 `Y=0` 的 XZ 平面。镜像前后的几何 MUST 在最终旋转前保持 `(x, y, z)` 与 `(x, -y, z)` 的对应关系。
|
||||
|
||||
#### Scenario: Canonical mirroring
|
||||
|
||||
- **WHEN** 上游 Depth Cutout 输出 canonical 几何并连接 `O Image Cutout Symmetry`
|
||||
- **THEN** 对称节点先按 Y 轴删除越界半侧并镜像到另一侧
|
||||
- **AND** Fill Sides 开启时沿 Y 方向连接对应边界
|
||||
|
||||
### Requirement: Final symmetry axis is X with Z up
|
||||
|
||||
`O Image Cutout Symmetry` SHALL 在 canonical Y 镜像完成后执行绕 Z 的固定旋转,使对称轴从 +Y 变为 +X,并保持 +Z 为 up。最终结果 MUST 在本地坐标中关于 `X=0` 对称。
|
||||
|
||||
#### Scenario: Default Depth Symmetry result
|
||||
|
||||
- **WHEN** 用户通过 Depth Symmetry 入口生成对象
|
||||
- **THEN** 最终 evaluated local geometry 关于 `X=0` 对称
|
||||
- **AND** 最终 Z 范围反映图片 up 范围
|
||||
- **AND** 对象保持 up=Z
|
||||
|
||||
### Requirement: Depth Symmetry final front direction may change
|
||||
|
||||
Depth Symmetry 的最终朝向 SHALL 允许 canonical front `-Y` 随最终 yaw 旋转变为 `-X`。系统 MUST 不要求 Depth Symmetry 最终继续满足 front=-Y。
|
||||
|
||||
#### Scenario: Final front direction
|
||||
|
||||
- **WHEN** 使用把 +Y 映射到 +X 的最终 yaw 旋转
|
||||
- **THEN** canonical front 方向 -Y 映射为 -X
|
||||
- **AND** up 方向 +Z 保持不变
|
||||
|
||||
### Requirement: Depth Symmetry path has no Cutout Depth Axis
|
||||
|
||||
Depth Symmetry 创建流程 SHALL 不设置或依赖 `O Image Depth Cutout` 的 `Depth Axis`。所有最终轴向语义 MUST 只由 `O Image Cutout Symmetry` 承担。
|
||||
|
||||
#### Scenario: Create Depth Symmetry modifiers
|
||||
|
||||
- **WHEN** 用户通过 Depth Symmetry 入口创建对象
|
||||
- **THEN** 上游 `O Image Depth Cutout` 不包含 `Depth Axis` 输入
|
||||
- **AND** 上游 Cutout 输出 canonical +Y 深度结果
|
||||
- **AND** `O Image Cutout Symmetry` 决定最终 X 朝向
|
||||
@@ -0,0 +1,35 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Object Space Normal follows the canonical object frame
|
||||
|
||||
系统 SHALL 让 Plane、Depth Plane、Relief Plane、Cutout 与 Depth Cutout 的 Object Space Normal 贴图按新的 canonical Blender 对象坐标解释:X 为图片水平、Z 为 up、Y 为深度方向。Object Space Normal 渲染结果 MUST 与最终 evaluated geometry 的几何法线方向一致。
|
||||
|
||||
#### Scenario: Depth object uses Object Space Normal
|
||||
|
||||
- **WHEN** Depth Plane 或 Depth Solid 使用 Object Space Normal 贴图渲染
|
||||
- **THEN** 平面法线朝向 -Y
|
||||
- **AND** 深度表面产生的 normal 变化围绕 -Y 基准
|
||||
- **AND** 渲染 normal 不再按旧 `-Z` 基准解释
|
||||
|
||||
### Requirement: Depth Symmetry normal maps follow mirror and final orientation
|
||||
|
||||
`O Image Cutout Symmetry` SHALL 为 Object Space Normal 提供最终朝向所需的面属性。材质 SHALL 对 canonical front 保持 normal,对 canonical back 反射 Y 分量,并应用最终 yaw 旋转;侧壁 SHALL 关闭 normal map 影响。
|
||||
|
||||
#### Scenario: Front, back, and wall normals
|
||||
|
||||
- **WHEN** Depth Symmetry 对象启用 Object Space Normal 并分别渲染 front、back 和 side wall
|
||||
- **THEN** front normal 按 canonical 方向解释
|
||||
- **AND** back normal 的 Y 分量相对 front 发生反射
|
||||
- **AND** 最终 X 朝向旋转被应用
|
||||
- **AND** side wall 不显示 Object Space Normal 细节
|
||||
|
||||
### Requirement: Old Depth Axis normal compensation is removed
|
||||
|
||||
材质和 normal-map 辅助代码 MUST 不再为 `O Image Cutout` 或 `O Image Depth Cutout` 的旧 `Depth Axis=+X` 提供 `CUTOUT_Z_TO_X` 补偿。Object Normal 的最终轴向转换 SHALL 只来自 Depth Symmetry 的新朝向属性。
|
||||
|
||||
#### Scenario: Inspect normal transform attributes
|
||||
|
||||
- **WHEN** 检查 `O Image Layer` 使用的 Object Normal 转换逻辑
|
||||
- **THEN** 不存在以旧 `Depth Axis` 为输入的轴向补偿
|
||||
- **AND** Depth Symmetry 的最终朝向属性由 `O Image Cutout Symmetry` 写入
|
||||
- **AND** 材质按该属性执行最终 normal 旋转
|
||||
@@ -0,0 +1,31 @@
|
||||
## 1. Python 建网与校准
|
||||
|
||||
- [x] 1.1 在生成几何的 Python 层统一 canonical frame:X=图片右、Z=图片 up、Y=图片纸内,BaseShape/Plane 未修改网格位于 `Y=0` 的 XZ 平面。
|
||||
- [x] 1.2 更新 `cutout_tool/geometry.py` 的 BaseShape 顶点、UV、`world_plane_metric()`、`crop_plane_bounds()` 与 balloon profile 坐标到 XZ/Y 深度语义。
|
||||
- [x] 1.3 更新 `convert_to_plane/image_plane.py` 的普通 Plane 网格与对象矩阵到 XZ 平面、front=-Y。
|
||||
- [x] 1.4 更新 Depth Plane、Relief Plane 创建时的 `Depth Direction` 默认值和 `fit_image_depth_direction()`/`fit_depth_direction()` 到新坐标。
|
||||
- [x] 1.5 更新 `cutout_tool/object.py` 删除 Depth Axis 相关初始化,并将 Depth Symmetry 最终朝向交给 `O Image Cutout Symmetry`。
|
||||
|
||||
## 2. Geometry Nodes 轴语义
|
||||
|
||||
- [x] 2.1 更新 `O Image Plane` 的 Grid/Cube 尺寸与 Thickness 为 X/Z 平面、Y 厚度。
|
||||
- [x] 2.2 更新 `O Image Depth Plane` 的 UV、深度采样、投影和 Shell 厚度为 XZ 平面、+Y 深度。
|
||||
- [x] 2.3 更新 `O Image Relief Plane` 的 Depth Direction 默认 `(0,1,0)`、基座平移和位移方向为 Y。
|
||||
- [x] 2.4 更新 `O Image Cutout` 删除 `Depth Axis`,Balloon/Shell 厚度方向改为 Y。
|
||||
- [x] 2.5 更新 `O Image Depth Cutout` 删除 `Depth Axis`,深度投影、Split、Shell 与 Balloon 字段改为 Y 轴语义。
|
||||
- [x] 2.6 更新 `tools/nodes/common/` 中 depth surface、cutout、boundary smoothing、validity 等共享节点辅助,消除旧 Z 轴假设。
|
||||
|
||||
## 3. Depth Symmetry 与 Object Normal
|
||||
|
||||
- [x] 3.1 重写 `O Image Cutout Symmetry` 为 canonical Y 镜像,并在最后执行固定 yaw 旋转 `+Y → +X`,保持 up=Z,写入最终朝向属性。
|
||||
- [x] 3.2 更新 `tools/nodes/common/normal_map.py`:移除旧 `Depth Axis`/`CUTOUT_Z_TO_X` 补偿,按 canonical frame、Y 背面反射和最终 yaw 旋转解释 Object Normal。
|
||||
- [x] 3.3 更新 `O Image Layer` 与材质创建流程,使 Object Space Normal 读取新朝向属性并在渲染中匹配最终几何。
|
||||
- [x] 3.4 验证 Depth Symmetry 最终 front 从 -Y 变为 -X,且 up=Z、对称轴=X 的行为可测试。
|
||||
|
||||
## 4. 测试与资产
|
||||
|
||||
- [x] 4.1 更新或新增 canonical frame、BaseShape、UV、Depth Direction、厚度方向和 Depth Axis 移除的测试。
|
||||
- [x] 4.2 更新 Depth Symmetry 镜像、最终朝向和 Object Space Normal 的 front/back/wall 渲染测试。
|
||||
- [x] 4.3 更新 `tools/nodes/check.py`、节点 inventory 测试和 `tests/tools/test_pack.py` 中受影响的名称与接口断言。
|
||||
- [x] 4.4 运行 `uv run node-group build` 构建并校验 `O_AnyImage.blend`,检查无旧 Depth Axis、旧轴常量和 Capture Attribute。
|
||||
- [x] 4.5 运行全量测试并确认正常退出,检查旧引用与最终差异;不构建文档或打包扩展。
|
||||
Reference in New Issue
Block a user