是_BSL

是_BSL

修复了 BSL 光影在 Yes Steve Model 及其他自定义渲染管线模型上导致的半透明闪烁问题。

Bug修复

YES BSL —— BSL 光影 × Yes Steve Model 兼容修复

纯客户端模组 | Minecraft 1.21 | NeoForge | MIT

修复 BSL Shaders 在由原生 / 自定义渲染管线绘制的模型上导致的 半透明闪烁 —— 目前针对 Yes Steve Model (YSM) 验证,覆盖玩家模型与第一人称手模。

与 BSL Shaders、Iris 或 Yes Steve Model 均无隶属关系。


现象

开启 BSL Shaders 与 Advanced Materials 后,某些模型在镜头移动时出现 半透明并闪烁。YSM 的玩家模型与第一人称手模是已知案例。

模型本身没坏,YSM 也没坏。是光影包采样到了 贴图的错误区域。


原理

BSL 在 Advanced Materials 下启用视差遮挡贴图(POM)—— 而这一点才是关键 —— 它 使用视差校正后的坐标去采样模型自身的贴图:

若 未设置 "跳过视差" 标记:
    newCoord   = parallax(原始纹理坐标, ...)
    modelColor = texture(modelTexture, newCoord)     <- 不再是原始纹理坐标

newCoord 由 vTexCoord / vTexCoordAM 推导,二者又来自 OptiFine / Iris 围绕 mc_midTexCoord 与 at_tangent 的约定。

几何体来源 顶点由谁写入 扩展属性是否正确 结果
MC 标准模型(方块、原版生物、手持物品) BufferBuilder ✅ Iris 的 MixinBufferBuilder 每 4 个顶点填充一次 POM 映射成立 —— 正常
YSM 等模组 原生代码直接写入 IrisVertexFormats.ENTITY 内存 ❌ 取值不满足该映射前提 newCoord 偏离真实的 texCoord

于是 albedo 采样到贴图 错误的区域。这类模型贴图布局紧凑、充满空白像素 —— 而 空白像素的 alpha 会被 alpha test 丢弃:

  • 于是看起来 半透明(空白处被抠掉了);
  • 偏移量随视角每帧变化,于是 闪烁。

一个现成的对照实验。 BSL 为 地图 这个物品单独预留了一个类别(id 400),因为地图是平面贴图,同样经不起 POM。 手持地图时手臂渲染完全正常,而空手时闪烁 —— 两者显示的却是同一份 YSM 手模。 唯一差异就是这个 id。仅凭这一条就能锁定 POM 是元凶。


修复方式

在渲染目标几何体期间,让 Iris 对外报告光影包自己预留的 "跳过法线与视差" 类别值。

这里有 两条完全独立的路径 —— 同一个几何体,在不同 program 里使用不同的变量:

渲染对象 program 判据 光影包逃生舱
玩家模型 gbuffers_entities entityId == 10100 实体侧的"跳过法线与视差"类别
第一人称手模 gbuffers_hand heldItemId / 100 == 4 物品侧的"地图"类别(id 400)

为什么是"读取时覆盖"而不是"写入时改写"。 Iris 也在同一位置写 currentEntity。若本模组也去改写,谁先谁后取决于 Mixin 的应用顺序 —— 不可靠。改为在 读取 时覆盖则与顺序无关:读取发生在渲染过程中,此时上下文恰好指向被渲染的对象。

为什么不会误伤。

  • 实体侧:本模组 不 盲目信任 10100。它在运行时读取光影包 真实的 映射表,只有当它确实遵循 BSL 这套约定时修复才生效。换成别的光影包会自动不生效。
  • 手模侧:只在 空手 时伪造该 id;持有物品时保持真值。在 BSL 中,heldItemId 真正被读取的只有三处,而空手时伪造 400 与真值 0 完全等价(400 的彩色光数据位恰好是 00)。

性能

CapturedRenderingState.getCurrentRenderedEntity() 会 按顶点 被调用,因此热路径被压缩为一次 volatile int 读取:

final int overrideId = EntityIdOverride.activeOverrideId;
if (overrideId >= 0) { cir.setReturnValue(overrideId); }

不参与渲染时 —— 也就是绝大多数绘制:方块、生物、粒子、GUI —— 这次读取就是全部开销。无反射。实测与未安装时的差距约 1 FPS,属浮动误差范围。


安装

  1. Minecraft 1.21 + NeoForge;
  2. 把 YES_BSL-1.0.0.jar 放入 .minecraft/mods/(版本隔离时是 versions/<name>/mods/);
  3. 完成。

仅客户端。 服务器上不需要,装不装也没有区别。

依赖 —— 均为可选;缺失时对应部分自动失效,不会崩溃:

模组 版本 说明
Iris 1.8+ 实际必需 —— 没有光影加载器就没有要修的东西
Yes Steve Model 2.x 当前针对它验证

启动日志:

[YES-BSL] 已就绪:渲染目标模型时会把 iris 报告的 id 映射到光影包预留的 Skip 类别(entityId=10100 / heldItemId=400)。

配置

首次启动生成 config/yes_bsl.properties:

键 默认 作用
enabled true 总开关;false 时完全惰性(等价于卸载本模组)
affectsAllEntities false 是否也作用于非玩家实体 —— 为其它模组适配时可用
skipEntityId 10100 光影包为"不适合视差贴图"预留的类别 id

关于「注入失败」的两种不同严格程度

本模组有两个 mixin 配置,对失败的态度 刻意不同:

配置 目标 失败的后果
yes_bsl.mixins.json Minecraft 自己的 EntityRenderDispatcher 直接报错(required=true)
yes_bsl.iris.mixins.json Iris 内部类 静默失效(required=false)

前者是刻意的:本模组的唯一功能就挂在这一处,而靶点签名在大版本内非常稳定。一旦它不再匹配,明确报错 远比"悄悄什么都不做"更好排查。后者则相反 —— Iris 内部结构变动更频繁,且光影相关的失败不该拖垮游戏。

若你看到 EntityRenderDispatcher 相关的 Mixin 报错,说明本模组与该 Minecraft 版本不兼容。请先移除它,或等待适配版本。


为其它模组适配

骨架与 YSM 解耦,适配新目标通常只需要改 一处判定 —— 要么是 TargetDetector#isTargetEntity(实体路径),要么是 HandMaterialOverride#shouldReportHeldItemId(手持物路径)。更换光影包时,需确认它的 entity.properties / item.properties 里"跳过法线与视差"对应哪个编号,再填进 skipEntityId。

务必保留"实际映射校验"这一步 —— 它保证只有当光影包确实把该编号分配给该用途时修复才生效。完整指引见项目 README。


许可

MIT —— 可自由使用、修改、分发,仅需保留署名。

本项目 不包含 任何第三方的代码或资源,与下列项目 无隶属关系,也不代表它们的立场。

项目 协议 本项目的关系
BSL Shaders All Rights Reserved 不含、不修改、不再分发;本模组仅调整 Iris 对外报告的 id
Iris LGPL-3.0 仅通过 @Mixin(targets=...) 引用其类名 —— 未复制其代码
Yes Steve Model All Rights Reserved 不反编译、不修改、不内嵌;仅用于检测其是否加载

致谢 Capt Tatsu(BSL Shaders)—— 本模组完全依赖他在 entity.properties / item.properties 中预留的跳过类别,以及 400 这个精心设计的编号(彩色光数据位为 00,使伪造它不产生副作用);以及 Iris 团队 提供的规范 id 映射 API 与注入点。

代码由 DeepSeek 监修。