Skip to content

Port Structure Projection Rendering to 26.1 移植结构投影渲染到26.1 - #134

Merged
PigeonNian merged 1 commit into
dev/26.1from
fff/26.1-port
Sep 30, 2026
Merged

PigeonNian merged 1 commit into
dev/26.1from
fff/26.1-port

Conversation

@WhereisFff

Copy link
Copy Markdown
Contributor
  • 提供保留模型数据与流体邻接关系的投影场景和原生网格缓存
  • 统一方块、流体、方块实体及实体的透明渲染与相机变换
  • 支持资源重载失效、独立实例清理及预览方块光照管线

- 提供保留模型数据与流体邻接关系的投影场景和原生网格缓存
- 统一方块、流体、方块实体及实体的透明渲染与相机变换
- 支持资源重载失效、独立实例清理及预览方块光照管线
@PigeonNian
PigeonNian merged commit 8a65bea into dev/26.1 Sep 30, 2026
44 checks passed
@Gugle2308

Copy link
Copy Markdown

已合并关闭的 PR(state=closed, merged_at=2026-09-30T10:29:06Z),按约束 1(action 为 closed 时停止)跳过审查,未发布任何评论,也未修改 PR 标题。

@Gugle2308

Copy link
Copy Markdown

代码审查摘要 — AnvilLib PR #134

操作: opened → 正常审查
范围: 9 个文件(8 新增 / 0 删除,+657 / -1 行),全部位于 module.rendering/(projection 包 6 个 Java + PROJECTION.md + 1 个 .fsh + AT 文件)
对照源: dev/1.21.1 分支的 module.renderer/src/main/java/dev/anvilcraft/lib/v2/renderer/projection/(GhostConsumer / ProjectionRenderTypes / ProjectionRenderer / ProjectionScene / ProjectionShaders)+ assets/anvillib_renderer/shaders/core/projection.fsh|json + 187 行 clientTest/ProjectionTest.java

说明:本机无 26.1 mappings / gradle 缓存,未复现编译。所有 API 面结论均用仓库内既有 26.1 代码交叉验证(AnvilCraft api/rendering/BlockStateModelRenderer 的 new ModelBlockRenderer(boolean, boolean, BlockColors)、ALRPipelines / AnvilCraft ModRenderPipelines 的 RegisterRenderPipelinesEvent 注册写法、AnvilCraft ModelEvent.* 监听写法)。

🔍 移植对账(1.21.1 → 26.1)

1.21.1 实体 26.1 对应 结论
ProjectionScene(blocks/BE/entity/tint/Shifted/满亮) 同名 ✅ 逐行等价,含 Shifted 局部坐标映射(Ageratum 用例 shifted(-1,0,0).getFluidState(1,0,0).isSource() 直接依赖它)
GhostConsumer 内嵌进 ProjectionRenderer ✅ 超集(新增 setColor(int) / setLineWidth),setUv2(240,240) 满亮语义保留
ProjectionRenderer(VertexBuffer 缓存) ProjectionMesh(GpuBuffer) ✅ 等价,26.1 无 VertexBuffer 的合理替换;相机变换公式 ModelView × pose 与旧实现一致
RenderType.create + 自定义 shader RenderPipeline + structure_projection.fsh ✅ 着色器路径与 AnvilLibRendering.location("core/…") 约定吻合;fsh 的 discard 顺序、linear_fog→apply_fog(spherical/cylindrical) 为 26.1 必需改写
ProjectionShaders.generation() ProjectionRenderer.generation + ModelEvent.BakingCompleted ✅ 语义等价(reload→失效),监听写法与 AnvilCraft NegativeShapeModelEventListener 一致
直接 renderItem / EntityRenderDispatcher.render ProjectionFeatures(extract + submit + FeatureRenderDispatcher) ✅ 26.1 必需的路径重写,states 按 BE 身份缓存 render state
AT:RenderType.state、RenderSetup.layeringTransform/outputTarget/textureTransform 基线已有 ✅ 本 PR 只补了真正缺的 RenderSetup textures + RenderSetup$TextureBinding(并修掉 mode 行缺失的 EOF 换行)

🔴 关键问题

未发现阻塞性问题(alpha 越界先校验再 close(),不会破坏已有 mesh;close() 可重入;rebuild 异常路径 close()+rethrow 正确)。

⚠️ 警告(建议合并前处理)

  1. ProjectionFeatures.render — extractRenderState(entity, state, 0, Vec3.ZERO, null) 传 null ModelData
    原版 BlockEntityRenderDispatcher 走的是 level.getModelData(pos)(非空)。5.0 的 @Nullable 形参虽允许 null,但第三方 BER 一旦 modelData.get(属性) 就会 NPE——而「渲染第三方方块实体」正是这个库的目标场景。建议传 entity.getModelData()(与 ProjectionScene.getModelData 保持同一数据源);若有意不传,请在 Javadoc 写明。附带一提:Vec3.ZERO 作为 cameraPos 会让 renderer 的相机距离判定以世界原点为参照,建议用 CameraRenderState 里的相机位置或明确注释。

  2. ProjectionRenderer.rebuild — AO 被硬编码为 new ModelBlockRenderer(true, true, mc.getBlockColors())
    1.21.1 版走共享的 mc.getBlockRenderer(),其 AO 取自玩家的「平滑光照」选项(Minecraft.useAmbientOcclusion())。硬编码 true 后,关闭平滑光照的玩家会看到投影的明暗结构与自己身边的真实方块不一致。建议改回 Minecraft.useAmbientOcclusion();若「恒定 AO」是有意的预览风格,请在 PROJECTION.md / Javadoc 里说明。(同生态 AnvilCraft BlockStateModelRenderer 用的是 false,可见此处并无既定约定。)

  3. assertOnRenderThread() 被删除(rebuild / render 各一处)
    1.21.1 版两处都有 RenderSystem.assertOnRenderThread()。新代码在 rebuild 里调用 RenderSystem.getDevice().createBuffer(...)、render 里创建 render pass,都只能在渲染线程执行;去掉守卫后误用会静默损坏 GPU 状态而不是快速失败。建议恢复(成本极低),尤其是 ProjectionRenderer 现在是公开 API。

💡 建议(非阻塞)

  • ProjectionRenderTypes.ghost() 的动态管线成本与 serial 无上限:26.1 中每个 RenderType 需要自己的 RenderPipeline(需要编译),而 1.21.1 只是复用单个已注册 ShaderInstance,所以「未知 RenderType 逐个建管线」是新引入的开销模型;TYPES 满 128 或每次资源重载都会 clear(),重建时又用 projection_entity_<serial++> 的新 location,一个会话内 location 单调增长。建议按 (vertexFormat, 原 pipeline, sampler 集合) 归一化缓存(或退化成 1.21.1 那套「固定几条 + entityTranslucentCull 兜底」),并确认未走 RegisterRenderPipelinesEvent 的管线在 26.1 是按需编译且缓存以管线对象为键(Ageratum 用例已证明功能可用,这里关心的是卡顿/增长)。
  • GhostBuffers 复用了全局 renderBuffers().bufferSource(),endBatch() 会把全局待画几何一并冲出:1.21.1 的 render(pose, proj, buffers) 由调用方提供 BufferSource 以控制顺序。建议在文档中明确「必须在全局 source 已排空的 stage 边界调用」(Ageratum 用的是 RenderLevelStageEvent.AfterTranslucentBlocks,符合该约束),否则可能提前刷新别的阶段挂起的几何体(半透明排序风险)。
  • close() 中 this.buffers.memory.close() 可能被二次关闭:GhostBuffers 继承 MultiBufferSource.BufferSource 且未覆写 close(),若 FeatureRenderDispatcher.close() 会级联到传入的 buffer source,则同一个 ByteBufferBuilder 会被关两次。请确认 close() 幂等,或去掉显式那行(构建 GhostBuffers 的初衷正是把全局 source 藏起来,这点作者显然已考虑,只差一处收尾)。
  • ProjectionScene.minY 初值 0(沿用 1.21.1):全正 Y 场景下 getMinY()/getHeight() 失真(y=64..80 → minY=0、height=81)。当前被 getBrightness/getRawBrightness=15 与 isOutsideBuildHeight=false 短路,无实际影响,顺手可修。
  • rebuild 去掉了 1.21.1 的 if (state.isAir()) continue;,且每次 rebuild 都新建 ModelBlockRenderer / FluidRenderer。空气经 tesselateBlock 产出空网格、行为等价,但丢掉了一个廉价早退;两个 renderer 可缓存为字段。
  • 测试落点:1.21.1 线在本模块内有 clientTest/ProjectionTest.java,26.1 侧(本 PR)没有带任何测试,验证全部依赖 Ageratum 仓库。26.1 已有 module.test 及渲染类测试范式,建议在 AnvilLib 侧补一份冒烟测试(rebuild 越界 alpha、isValid() 失效/恢复、close() 释放),避免下游仓库成为唯一回归保护。

🟢 看起来不错

  • ProjectionScene 移植保真度很高(含 Shifted 流体邻接、tint 世界坐标偏移、BE modelData),shifted() 有意提升为 public 以支持仓外校验。
  • ALPHA 越界先校验后 close(),非法 opacity 不会摧毁已有 mesh(Ageratum 的 rebuild(scene, 256) 用例正依赖此行为)。
  • close() 幂等、rebuild 的 catch (RuntimeException | Error) 清理后重抛、ProjectionMesh 用 try (mesh) 及时归还 builder。
  • AT 增量最小化且顺手修掉了 accesstransformer.cfg 缺失的 EOF 换行;BLOCK_GHOST 的 texture/lightmap/overlay 复制逻辑对 pipeline sampler 做了存在性过滤,避免绑定不存在的采样器。
  • PROJECTION.md 明确写出了未验证范围(自定义资源包/光影/其他平台),透明度值得肯定。

📋 声称验证表

PR 声称 状态 证据
保留模型数据与流体邻接关系的投影场景 + 原生网格缓存 ✅ ProjectionScene.getModelData/Shifted/put;ProjectionMesh(GpuBuffer + RenderSystem.getSequentialBuffer)
统一方块/流体/BE/实体的透明渲染与相机变换 ✅ GhostConsumer 包住方块+流体网格;ProjectionFeatures 承接 BE/实体提交;两者的 pose 都按 ModelView × pose / 世界坐标平移处理
支持资源重载失效 ✅ ModelEvent.BakingCompleted → invalidateResources()(generation++、TYPES.clear());isValid() 由 built && bakedGeneration == generation 判定
独立实例清理 + 预览方块光照管线 ✅ close()/clear() 生命周期;BLOCK_PIPELINE(BLOCK_SNIPPET + TRANSLUCENT target)+ structure_projection.fsh;光照恒满亮(setUv2(240,240),fsh 不采样 Sampler2,与 1.21.1 一致)
「Ageratum runStructureTest 33 项真实客户端校验(缓存/层/流体邻接/实体/移动/资源重载/替换/清理)」 ✅ 已验证 Ageratum dev/26.1.2 src/clientTest/.../test/StructureTest.java:check( 出现 34 次(减定义行 = 33 项),import 的正是 dev.anvilcraft.lib.v2.rendering.projection.ProjectionRenderer/ProjectionScene,覆盖流体邻接、实体、reload、replacement、cleanup、layer 变化;build.gradle 以 structureTest 属性作为任务开关
未验证项(自定义资源包/光影/其他平台) ✅ 如实声明 PROJECTION.md 末段

结论: COMMENT — 这是一次保真度很高、证据链完整的移植,无阻塞问题;建议先处理 ⚠️1(null ModelData)、⚠️2(AO 硬编码)、⚠️3(恢复线程断言),其余为可选优化。若这三项均为有意设计,本 PR 可直接合并(等价 APPROVE)。

标题 Port Structure Projection Rendering to 26.1 移植结构投影渲染到26.1 已符合 <英文> <中文> 格式且描述准确,无需修改。

🧪 测试建议(若在 AnvilLib 侧补测试)

被测目标 推荐场景 优先级
ProjectionRenderer.rebuild/isValid/close alpha=0/255/256(越界抛 IllegalArgumentException 且不破坏旧 mesh)、close 幂等、reload 后 isValid() 变 false 且 rebuild 恢复 🔴
ProjectionScene.shifted() 跨边界流体邻居映射(正/负坐标、非零 origin) 🔴
ProjectionFeatures.render 含 modelData 的自定义 BER(验证不再 NPE)、alpha=255 与原 RenderType 直通 🟡
ProjectionRenderTypes.ghost() 未知非 BLOCK/非拌合 RenderType 缓存命中、128 条上限与重载清空后的重建 🟡
ProjectionMesh 空场景(build() 返回 null)不建 mesh、drawIndexed 索引数正确 🟢

由 Hermes Agent 审查

@Gugle2308

Copy link
Copy Markdown

💾 Self-improvement review: Patched SKILL.md in skill 'pr-fix-claim-verification' (1 replacement).

@WhereisFff
WhereisFff deleted the fff/26.1-port branch October 1, 2026 13:59
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