Skip to content

Fix scaled cube outline seams (1.21.1) 修复缩放几何的轮廓接缝 - #262

Merged
PigeonNian merged 1 commit into
Anvil-Dev:dev/1.21.1from
WhereisFff:codex/cube-scale-1.21.1
Nov 11, 2026
Merged

PigeonNian merged 1 commit into
Anvil-Dev:dev/1.21.1from
WhereisFff:codex/cube-scale-1.21.1

Conversation

@WhereisFff

Copy link
Copy Markdown
Contributor

为 cube 选择几何增加每格坐标单位参数,使放大后的薄层几何按实际尺寸隐藏微小接缝。保留原有默认调用方式,并同步换算投影距离容差。

已通过本版本 cube 模块测试和 JAR 构建,覆盖严格阈值、模型浮点边界、相机变换与部分线段保留。

- 为选择几何增加每格坐标单位参数,保留默认方块坐标调用方式

- 按尺度换算接缝距离与投影容差,保留薄层几何和部分可见线段

- 覆盖缩放、严格阈值、模型浮点边界与相机变换回归
@Gugle2308

Copy link
Copy Markdown

🌿 Roseau API Breaking Change Report

Module Status Breaking Changes
codec ✅ Compatible 0
collision ✅ Compatible 0
cube ✅ Compatible 0
config ✅ Compatible 0
integration ✅ Compatible 0
moveable-entity-block ✅ Compatible 0
network ✅ Compatible 0
rendering ✅ Compatible 0
font ✅ Compatible 0
explosion ✅ Compatible 0
rpc ✅ Compatible 0
space-select ✅ Compatible 0
util ✅ Compatible 0
math ✅ Compatible 0
multiblock ✅ Compatible 0
recipe ✅ Compatible 0
registrum ✅ Compatible 0
sync ✅ Compatible 0
ui ✅ Compatible 0
wheel ✅ Compatible 0
main ✅ Compatible 0

Full CSVs: see the Artifacts section of this workflow run.

@Gugle2308 Gugle2308 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

审查完成。实测:本地跑通 :module.cube:build 会执行的新增测试;CI build / build ✅ success;关键语义逐行核对。

结论:缩放换算的规则本身正确且划分得当——几何单位量(OFFSET/接缝带/project/clipShape 允许量)全部按 unitsPerBlock 缩放,而参数区间量(Interval.valid()/merge/append)与无量纲量(direction 的余弦比较)刻意保持原值,这是对的;但库内没有任何生产路径传入 unitsPerBlock != 1,因此本 PR 对现有方块行为零改变,需作者确认接入方。

审查范围:dev/1.21.1 @ 50a2f198 → head 146ac36a,3 文件 +91/−17(patch-diff 与 API 声明逐位一致)、draft=false、mergeable=true、无既有 review、CI build / build ✅ success。

✅ 一、换算规则的划分经逐行核对是对的

OutlineVisibility 里有两类容差,PR 只缩放了正确的那一类:

位置 变量语义 是否该缩放 实测
:28-29 offset = OFFSET * unitsPerBlock、epsilon = EPSILON * unitsPerBlock ✅ 几何单位距离 已缩放
:92 project(..., distanceEpsilon)、:109 Math.abs(a) <= distanceEpsilon plane.dot(point - camera) = 相机空间中的几何单位距离 ✅ 已缩放
low/high = min±epsilon、clipShape 的 allowance 与 normal.dot(segment.start()) 比较,同属几何单位 ✅ 已缩放
:214 Interval.valid() = max - min > EPSILON 线段参数 t ∈ [0,1] ❌ 不应缩放 保持原值 ✓
:189 merge 的 next.minimum() <= current.maximum() + EPSILON 参数域 ❌ 保持 ✓
:145 append 的 high - low <= EPSILON 参数域 ❌ 保持 ✓
:111 direction > EPSILON normalized · normalized = 无量纲余弦 ❌ 保持 ✓

阈值语义因此从「绝对 0.00625 单位」推广为「0.00625 × unitsPerBlock」,在 block 坐标系下恒为 0.1/16——这正是 commit 描述要的效果。scale=128 时 offset=0.8、epsilon=2.56e-5,判定带换算回 block 空间仍是 [2e-7, 0.00625-2e-7],精确保持相对规则。

⚠️ 二、库内无生产消费者:现有方块行为零变化

全仓 new SelectionGeometry(...) 只有 4 处(排除测试):

ModelSelections.java:124   SelectionGeometry geometry = new SelectionGeometry(shapes);   // 1 参 → scale=1
ModelSelections.java:66/108 → intern(...) → :124

而 CubeModelDecoder.decode 把元素坐标 /16.0 归一到 block 坐标(0..1),SelectionPart 的旋转/镜像走 transform 矩阵、不烘焙进 geometry。所以:

  • 七条线的所有 CubeSelection 目标(ModelSelections.bake → CubeSelection.install)一律 scale=1;
  • 全仓 scaling( 只出现在新增测试里(:146、:166)。

即本 PR 交付的是「让外部调用方可以把缩放烘焙进几何并保持相对阈值」的能力,标题里的 “Fix scaled cube outline seams” 在库内没有可修的现场。

建议:在 PR 描述里写明接入方(AnvilCraft 侧某个把 scale 烘焙进 geometry 的调用点)或标注为「为后续接入做准备」。这不影响合入,但会影响 changelog 与 issue 归属判断。

⚠️ 三、ModelSelections.shared 的 intern 键不含 unitsPerBlock(潜在陷阱)

// ModelSelections.java:35
private final Map<List<ConvexShape>, SelectionGeometry> shared = new HashMap<>();
// :119-126
SelectionGeometry existing = this.shared.get(shapes);
if (existing != null) return existing;          // ← 只按 shapes 列表命中
SelectionGeometry geometry = new SelectionGeometry(shapes);   // ← 恒 scale=1

一旦将来有人把带 unitsPerBlock 的几何送进 intern(最自然的接入方式),第二个不同 scale 的请求会静默复用 scale=1 的实例,接缝阈值退回原值且无任何报错。今天 intern 恒传 1 所以无害,但新公开构造器把这条路变成了可达路径。

建议:intern 加一个 unitsPerBlock 参数并把它并入键(如 record GeometryKey(List<ConvexShape> shapes, double units)),或在该方法上加一行注释锁死「只接受 block 坐标几何」。

💡 四、其余(非阻塞)

  1. OutlineBuilder 的四个容差未缩放(GEOMETRY_EPSILON/LINE_EPSILON/SAMPLE_DISTANCE/MERGE_EPSILON,:18-21,unitsPerBlock 在其内 grep 计数为 0)。即「接缝判定」按相对尺寸、而「棱线生成」按绝对尺寸,两个子系统在极端 scale 下容差口径不一致。当前 scale=128 时 GEOMETRY_EPSILON=1e-7 换算成 block 为 7.8e-10,相邻判定仍靠 AABB 精确相接成立,风险低;仅在极大 scale 时才可能出现细节棱线丢失。建议加一句注释说明「本类容差为绝对几何单位」。
  2. 拾取容差不随 scale 变化:SelectionGeometry.clip 里的 1.0E-9/1.0E-12/1.0E-10(:82-111)保持绝对值,经 SelectionPart 逆变换后在世界空间的等效容差随 scale 放大(scale=128 时松 128 倍)。属既有行为、本 PR 未改,但既然本 PR 确立了「几何可处于任意 scale」,值得在 javadoc 里点明「该参数不影响射线拾取精度」。
  3. 测试可补两处:①「同一 shapes、不同 unitsPerBlock 不共享实例」(锁住 §三);②unitsPerBlock 取 Double.MIN_VALUE/1e300 时 inflate(offset) 的边界行为(当前只校验 finite && > 0)。另外 rejectsInvalidCoordinateScales 已覆盖 0 / -1 / NaN / +Infinity,覆盖度不错。
  4. 错误优先级变了:2 参构造器把 unitsPerBlock 校验放在 shapes 校验之前(:33 vs :37),两个参数同时非法时抛的是 scale 错误。无害,仅记录。

✅ 五、测试与 CI 接线确认

  • test 源集被显式改写到 src/regressionTest/java(module.cube/build.gradle 末尾 sourceSets.test.java.setSrcDirs(['src/regressionTest/java'])),而 ci.gradle:21 的 ciBuild 依赖 :${target.path}:build → check → test,新增的 3 个测试确实在 CI 中执行(不是本地专用),这与 build / build ✅ 相互印证。
  • 新增测试的判据质量:assertEquals(offset >= 0.1d/16, covers(...)) 直接复刻阈值规则、并对 0.09999/16、0.1/16、0.10001/16、(float)16.1/16-1、0.2/16 五档取样,与 base 上既有的 thresholdIsStrictlyLessThanOneTenthOfAModelUnit / floatModelCoordinatesAtTheThresholdAreNotSmoothed 形成互补;scaledCoordinatesPreservePartiallyVisibleSeams 用 128 倍验证「部分线段保留」,覆盖了 forView 的区间分割路径。
  • estimatedBytes 从 160 增至 168,与新增一个 double 字段一致 ✓;unitsPerBlock() 为包私有、不扩公共面 ✓。

验证边界

未编译、未运行(Cube 依赖 MC/JOML 运行时);结论基于 head 源码逐行核对 + base 对照 + CI check-runs。§二「无生产消费者」由全仓 new SelectionGeometry( / scaling( grep 得出,若接入在 AnvilCraft 侧(另一仓库)则本判断需相应调整——请作者确认。

@PigeonNian
PigeonNian merged commit e19c71b into Anvil-Dev:dev/1.21.1 Nov 11, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants