Repository navigation
Fix scaled cube outline seams (26.2) 修复缩放几何的轮廓接缝 - #267
Conversation
- 为选择几何增加每格坐标单位参数,保留默认方块坐标调用方式 - 按尺度换算接缝距离与投影容差,保留薄层几何和部分可见线段 - 覆盖缩放、严格阈值、模型浮点边界与相机变换回归
🌿 Roseau API Breaking Change Report
|
Gugle2308
left a comment
There was a problem hiding this comment.
结论:审查通过。三份文件与 #264/#265/#266 在 head 上逐字节相同,容差换算的划分正确;26.2 的 geometry 包与 26.1 全等,CubeHighlightEvents 多出的运行期构造点已核实无害。
本次审查对应 head 072ff07b(dev/26.2 @ f9d320ad),3 文件 +91/−17,与 API 的 changed_files=3 / additions=91 / deletions=17 及 grep -c "^diff --git"=3 一致;三个文件的 index <old>..<new> 与实际 blob 对得上(461c450e8..b9838477b / 720e24d3c..ee6be8e8f / 2a9b5efb0..d546072d3)。state=open、draft=false、merged=false;CI build / build ✅;除 Roseau 报告(cube ✅ 0 breaking)外无人工评论。
✅ 一、与姊妹 PR 及 26.1 的关系
head 层面对比:
OutlineVisibility.java vs266=SAME vs265=SAME
SelectionGeometry.java vs266=SAME vs265=SAME
OutlineVisibilityTest.java vs266=SAME vs265=SAME
跨版本结构对账:
module.cube/文件集 26.2 ↔ 26.1 仅多一个regressionTest/.../client/model/ModelCaptureTest.java(26.2 分支既有的测试文件,与本 PR 无关);module.cube/.../geometry/包 七个文件 md5 全部相同(ConvexShape/OutlineBuilder/OutlineCache/OutlineVisibility/PackedOutline/SelectionGeometry/package-info);- 267 与 266 的 cube 模块差异仅 4 个文件(
CubeHighlightEvents/OutlineRenderer/ModelCapture/ModelCaptureTest),全是 26.2 分支的模型捕获与渲染签名演进,与本 PR 不相交。
七线分组维持既有结论:
#262 (1.21.1) / #263 (1.21.4) base=ee3f6d12e→a3ddb8ab9 (jetbrains @Nullable)
#264~#268 720e24d3c→ee6be8e8f (jspecify @Nullable)
✅ 二、容差换算的划分逐行核对正确
| 位置 | 语义 | 应缩放 | 实测 |
|---|---|---|---|
OutlineVisibility.java:28-29 |
OFFSET/EPSILON × unitsPerBlock |
几何单位 | 已乘 ✓ |
:92、:109 abs(a) <= distanceEpsilon |
plane·(point−camera) |
几何单位 | 已换算 ✓ |
low/high = min∓epsilon、clipShape 的 allowance |
与 normal·segment.start() 同量纲 |
几何单位 | 用 epsilon ✓ |
Interval.valid() = max−min > EPSILON |
线段参数 t ∈ [0,1] | 不缩放 | 原值 ✓ |
merge 的 next.min ≤ cur.max + EPSILON |
参数域 | 不缩放 | 原值 ✓ |
append 的 high−low ≤ EPSILON |
参数域 | 不缩放 | 原值 ✓ |
direction > EPSILON |
归一化向量点积(无量纲) | 不缩放 | 原值 ✓ |
side.lengthSqr() > 0.5 |
归一化成功与否 | 无量纲 | 原值 ✓ |
若把参数域或余弦容差一并乘缩放,scale=128 时会把有效区间判无效、把近平共面误判为左右覆盖。阈值语义从绝对 0.1/16 提升为「0.1/16 × 每格单位数」,在方块坐标系下保持不变。
测试 :142-159(6 档偏移 × 0.5/1/128 三倍率 + 相机逆变换)、:162-173(128 倍部分线段保留)、:176-181(0/-1/NaN/+∞)与描述四项声称逐条对应。
✅ 三、26.2 特有条件:CubeHighlightEvents 运行期构造点无害
// CubeHighlightEvents.java:38-39
PackedOutline fallback = segments > SelectionGeometry.MAX_OUTLINE_SEGMENTS
? new SelectionGeometry(List.of(ConvexShape.box(target.bounds()))).fallbackOutline() : null;三点核实后确认不需要补 unitsPerBlock:
- 只取
fallbackOutline()(SelectionGeometry:57返回PackedOutline.of(edges),不带 visibility),PackedOutline.forView遇visibility == null直接返回自身 ⇒ 接缝逻辑不参与; - 即便走
OutlineBuilder.build,单 shape 时i<j配对循环无组合 ⇒any=false⇒shapes传List.of(),forView首行早退; - 该几何恒 scale=1,与
target.bounds()的方块坐标尺度一致。
⚠️ 四、库内无生产调用方传入缩放
267 head 全树构造点:
ModelSelections.java:120 new SelectionGeometry(shapes) // 1 参 → scale=1(唯一主路径)
CubeHighlightEvents.java:39 new SelectionGeometry(List.of(box(...))) // 1 参 → scale=1(超限降级)
module.test/PortVerification.java:77,79 new SelectionGeometry(List.of(...)) // 1 参 → scale=1
OutlineVisibilityTest.java:147,167,179 2 参(新增测试,唯二传 scale 处)
全树 scaling( 只在新增测试(:146、:166)与无关的 FlexibleTestScreen:155;SelectionGeometry 仅被 module.cube 与 module.test 引用;ModelSelections(:32 的 shared 键、:114-123 的 intern)仍是 1 参。⇒ 实际几何一律 unitsPerBlock == 1,本 PR 对现网渲染/拾取零差异。
真实交付是「让下游接入方能把缩放烘焙进几何并保持相对阈值」。建议描述点名接入方,或标注「为后续接入做准备」。
⚠️ 五、ModelSelections.shared 的 intern 键不含缩放
// ModelSelections.java:32
private final Map<List<ConvexShape>, SelectionGeometry> shared = new HashMap<>();
// :114-123
SelectionGeometry existing = this.shared.get(shapes); // 键只有 shapes 列表
SelectionGeometry geometry = new SelectionGeometry(shapes); // 恒 scale=1
this.shared.put(geometry.shapes(), geometry);List<ConvexShape> 走值相等(ConvexShape.equals),键按内容匹配。今天无影响;但新公开构造器把「带缩放几何」变成可达输入 —— 若将来有人把缩放几何送进 intern(最自然的接入方式),第二个不同 scale 的请求会静默复用 scale=1 实例,接缝阈值退回绝对值且无告警。
建议 intern(List<ConvexShape>, double unitsPerBlock) 并入键(如 record GeometryKey(List<ConvexShape>, double)),或在 intern 上方注明「只接受 block 坐标几何」。正面确认:OutlineCache.ready 是 LinkedHashMap<SelectionGeometry, …>(:20)、pending 是 IdentityHashMap(:21),SelectionGeometry 未覆写 equals/hashCode(grep 计数 0)⇒ 缓存按身份做键,同 shapes 不同 scale 的实例不会串味。
💡 六、其余(非阻塞)
OutlineBuilder四个常量未随之缩放(GEOMETRY_EPSILON/LINE_EPSILON/SAMPLE_DISTANCE/MERGE_EPSILON;该文件unitsPerBlock引用数 = 0)。属「棱线生成/合并」侧的绝对几何单位阈值,scale=128 时换算回方块空间变紧 128 倍(1e-7 → 7.8e-10block)。新增测试在 128 倍下实测通过,当前是经验安全而非不变量保证。建议加注释说明「本类容差为绝对几何单位、不随unitsPerBlock缩放」。- 拾取侧容差不随缩放变化:
SelectionGeometry.clip的1.0E-9/1.0E-12/1.0E-10(:82、:84-85、:92、:105-111)保持原值,经SelectionPart逆变换后世界空间等效容差随缩放放大。属既有行为、本 PR 未改,建议在unitsPerBlock的 javadoc(:27-31)补后半句「不影响射线拾取精度」——作者已写了「只影响轮廓接缝容差」的前半句。 - 参数校验顺序变化:2 参构造器把
unitsPerBlock校验(:33)放在shapes校验(:37)之前,两参数同时非法时抛缩放错误。无害,仅记录。 unitsPerBlock()为包私有(:51-52,无修饰符)而类是public:外部(AnvilCraft)能传值但读不回,SelectionPart也无承载字段,无法自检「几何缩放与变换矩阵是否匹配」。若预期外部接入,考虑公开或提供SelectionPart侧校验入口。- 测试可补两处:①「同 shapes、不同
unitsPerBlock不共享实例」锁住 §五;②Double.MIN_VALUE/1e300下inflate(offset)的边界行为(当前只校验finite && > 0)。
✅ 七、测试执行链路确认
26.2 与 26.1/1.21.8/1.21.11 同属「16 行 module.cube/build.gradle」形态(1.21.1/1.21.4 是 293 行),接线完整:
:15sourceSets.test.java.setSrcDirs(['src/regressionTest/java'])、:11-13test { useJUnitPlatform() }、:1-5JUnit 5 (junit-bom:5.10.2);:8neoForge { addModdingDependenciesTo(sourceSets.test) };- 根
build.gradle的subprojects统一应用java+module.gradle,module.gradle未禁用test,默认build → check → test成立; gradle/scripts/ci.gradle:21ciBuild依赖:${target.path}:build⇒ 新增 3 个测试确实在 CI 中执行,与build / build✅ 相互印证。
estimatedBytes 从 160 增至 168(SelectionGeometry:47)、从 64 增至 72(OutlineVisibility:83),与新增一个 double 字段一致(+8 字节)。这两个数值同时被 OutlineCache 与 MAX_GEOMETRY_BYTES(ModelSelections)的预算判定消费,因此 +8 是必要的精度修正。
验证边界
未编译、未运行 Gradle(Cube 模块依赖 MC/JOML 运行时)。结论基于 head 源码逐行核对 + 26.2/26.1 两条 base 的 blob 与全包内容对账 + 七线 patch-diff 归一化比对 + 匿名 API 状态/check-runs。§四「无生产消费者」由本仓库全树 new SelectionGeometry( 与 scaling( grep 得出;若接入点在 AnvilCraft(另一仓库),该判断需相应调整——请作者确认预期接入方。
为 cube 选择几何增加每格坐标单位参数,使放大后的薄层几何按实际尺寸隐藏微小接缝。保留原有默认调用方式,并同步换算投影距离容差。
已通过本版本 cube 模块测试和 JAR 构建,覆盖严格阈值、模型浮点边界、相机变换与部分线段保留。