Skip to content

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

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

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

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
space-select ✅ Compatible 0
font ✅ Compatible 0
util ✅ Compatible 0
explosion ✅ Compatible 0
rpc ✅ 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.

结论:审查通过。三份文件与 #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:

  1. 只取 fallbackOutline()(SelectionGeometry:57 返回 PackedOutline.of(edges),不带 visibility),PackedOutline.forView 遇 visibility == null 直接返回自身 ⇒ 接缝逻辑不参与;
  2. 即便走 OutlineBuilder.build,单 shape 时 i<j 配对循环无组合 ⇒ any=false ⇒ shapes 传 List.of(),forView 首行早退;
  3. 该几何恒 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 的实例不会串味。

💡 六、其余(非阻塞)

  1. OutlineBuilder 四个常量未随之缩放(GEOMETRY_EPSILON / LINE_EPSILON / SAMPLE_DISTANCE / MERGE_EPSILON;该文件 unitsPerBlock 引用数 = 0)。属「棱线生成/合并」侧的绝对几何单位阈值,scale=128 时换算回方块空间变紧 128 倍(1e-7 → 7.8e-10 block)。新增测试在 128 倍下实测通过,当前是经验安全而非不变量保证。建议加注释说明「本类容差为绝对几何单位、不随 unitsPerBlock 缩放」。
  2. 拾取侧容差不随缩放变化:SelectionGeometry.clip 的 1.0E-9 / 1.0E-12 / 1.0E-10(:82、:84-85、:92、:105-111)保持原值,经 SelectionPart 逆变换后世界空间等效容差随缩放放大。属既有行为、本 PR 未改,建议在 unitsPerBlock 的 javadoc(:27-31)补后半句「不影响射线拾取精度」——作者已写了「只影响轮廓接缝容差」的前半句。
  3. 参数校验顺序变化:2 参构造器把 unitsPerBlock 校验(:33)放在 shapes 校验(:37)之前,两参数同时非法时抛缩放错误。无害,仅记录。
  4. unitsPerBlock() 为包私有(:51-52,无修饰符)而类是 public:外部(AnvilCraft)能传值但读不回,SelectionPart 也无承载字段,无法自检「几何缩放与变换矩阵是否匹配」。若预期外部接入,考虑公开或提供 SelectionPart 侧校验入口。
  5. 测试可补两处:①「同 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 行),接线完整:

  • :15 sourceSets.test.java.setSrcDirs(['src/regressionTest/java'])、:11-13 test { useJUnitPlatform() }、:1-5 JUnit 5 (junit-bom:5.10.2);
  • :8 neoForge { addModdingDependenciesTo(sourceSets.test) };
  • 根 build.gradle 的 subprojects 统一应用 java + module.gradle,module.gradle 未禁用 test,默认 build → check → test 成立;
  • gradle/scripts/ci.gradle:21 ciBuild 依赖 :${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(另一仓库),该判断需相应调整——请作者确认预期接入方。

@PigeonNian
PigeonNian merged commit 8694cab into Anvil-Dev:dev/26.2 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