Iris / 着色器兼容桥(iris/ + shadercompat/)
基本信息
| 属性 | 值 |
|---|---|
| 包 | com.gtnewhorizons.angelica.iris(3 个)+ com.gtnewhorizons.angelica.shadercompat(1 个) |
| 本条目覆盖 | 4 个文件 |
| 总行数 | 335 + 324 + 317 + 201 = 1177 |
| 上游依赖 | net.coderbot.iris(内嵌 Iris)9 个类 + net.irisshaders.iris.api.v0.IrisApi + GLSM 7 个类 |
| 性质 | 全部是 Angelica 原创的「桥接适配层」 —— 把 1.7.10 的 GL 状态模型翻译成 Iris 着色器包期待的模型 |
⚠️ 这 4 个文件不是 Iris 的代码。 它们是 Angelica 自己写的,用来在内嵌 Iris 与 1.7.10/GLSM 之间搭桥。但它们的 import 大量指向 net.coderbot.iris,读代码时要分清「哪部分是 Iris 的、哪部分是 Angelica 的」。
| # | 文件 | 行数 | 可见性 |
|---|---|---|---|
| 1 | IrisDisplayListState.java |
335 | public final |
| 2 | IrisGLSMBridge.java |
324 | public(非 final) |
| 3 | ImmediateExtendedAttribs.java |
317 | public final |
| 4 | ShaderGlint.java |
201 | public final |
IrisGLSMBridge:Iris ↔ GLSM 的注册面(324 行)
iris/IrisGLSMBridge.java 是这一组里唯一在主代码里被直接调用的类,两个静态入口都在 ClientProxy:
| 入口 | 行 | 调用点 | 时机 |
|---|---|---|---|
installImmediateExtendedHandler() |
:67 |
ClientProxy.java:144 |
preInit,enableIris 为真时 |
installPostTransformHook() |
:71 |
AngelicaClientTweaker 路径 |
挂钩着色器源码转换 |
register() |
:104 |
ClientProxy.java:169 |
init,enableIris 为真时 |
register() 构造一个匿名 GLStateManager 回调对象,实现三组「锁 / 延迟改写」接口:
- 混合状态:
isBlendLocked()(:116)、isOverrideHeld()(:121)、deferBlendModeToggle()(:126)、deferBlendFunc()(:131)、flushDeferredBlend()(:136) - alpha 测试:
isAlphaTestLocked()(:145)、deferAlphaTestToggle()(:150)、deferAlphaFunc()(:155) - 深度与颜色写掩码:
isDepthColorLocked()(:162)、isOverrideHeld()(:167)、deferDepthEnable()(:172)、deferColorMask()(:177)
即:着色器包要求在「render pass 边界」切换 GL 状态时,Angelica 不能让 GLSM 缓存的状态机提前生效,于是把这些切换延迟到 pass 真正开始时再 flush。
ShaderGlint:把「现代闪光贴图」压进 1.7.10
类注释是本仓最长最坦诚的一段之一(:24-30)
Maybe overcomplicated, but it’s required to bridge the gap between the modern glint texture and white texture 1.7.10 has. Some shaders are able to render the glint just fine as they seem to have some amount of support for older Minecraft, but others like AstraLex do not render correctly. It expects the color to be within the texture. This might introduce some oddities that I’m not seeing, but for now this appears to fix the issue.
四个要点:
| 要点 | 原文依据 |
|---|---|
| 1.7.10 没有闪光贴图 | the modern glint texture vs white texture 1.7.10 has |
| 部分着色器包本来能处理 | Some shaders ... as they seem to have some amount of support for older Minecraft |
| AstraLex 不行 | others like AstraLex do *not* render correctly |
| 作者不确定这是完美解 | This might introduce some oddities that I'm not seeing, but for now this appears to fix the issue |
⚠️ AstraLex 被点名 —— 这是一个具体的第三方着色器包兼容目标。改这个类的行为应先确认 AstraLex 是否仍需此绕行。
4 个核心常量(:32-34)
| 常量 | 值 | 行 | 可见性 |
|---|---|---|---|
GLINT_MASK |
new ResourceLocation("textures/misc/enchanted_item_glint.png") |
:32 |
private |
TINT_SLOTS |
64 |
:33 |
public |
NO_TINT |
-1 |
:34 |
public |
⚠️ GLINT_MASK 是 1.7.10 原版资源路径 textures/misc/enchanted_item_glint.png —— 该资源在 1.7.10 中不存在(这正是类注释说「1.7.10 只有白色纹理」的原因)。⚠️ ensureMaskLoaded(:176-)用 try-with-resources 读它并有 maskFailed 标志(:37)—— 资源缺失是预期情况,走 maskFailed 降级。但这意味着玩家若安装了提供该贴图的资源包,行为会改变。
5 个状态标志(:36-56)
| 字段 | 行 | 类型 | 语义 |
|---|---|---|---|
maskLoaded / maskFailed |
:36-37 |
boolean |
mask 加载结果 |
maskW / maskH |
:38-39 |
int |
mask 尺寸 |
maskLum |
:40 |
int[] |
亮度查找表(预乘后的每 texel 值) |
injecting |
:50 |
boolean |
防重入 |
swapped |
:51 |
boolean |
纹理是否已替换 |
depth |
:52 |
int |
嵌套深度 |
prevTexture |
:54 |
int |
替换前的纹理 id |
⚠️ 5 个 boolean/int 静态字段全部非 volatile —— 见下方问题。
⚠️ colorToSlot 是 Int2IntLinkedOpenHashMap(:42)—— 有序的(Linked 而非普通)。顺序有意义(LIFO 复用槽位),与 ItemPropCache 的 Object2ObjectLinkedOpenHashMap 同款(见 掉落物品实例化)。
⚠️ slotTextures 是 int[TINT_SLOTS] = 64 个 GL 纹理 id(:46)—— 预先上传 64 个「不同颜色版本的闪光纹理」。⚠️ 这个 64 元素数组是 static final 且无上限保护 —— 若 tint 种类超过 64,tintSlot(:129)需回收槽位。回收策略本条目未读。
⚠️ tintBuffer 是 static ByteBuffer(:56) —— 用 org.lwjgl.BufferUtils 分配(:16 import),一次性分配、永久复用。
颜色变化的回调(:48、:93)
private static final GlintColorHandler COLOR_HANDLER = ShaderGlint::onColorChanged; // :48
⚠️ 方法引用赋给 GLSM 的 GlintColorHandler 接口(com.gtnewhorizons.angelica.glsm.hooks.GlintColorHandler,:5 import)—— 与 TextureTracker 写 StateUpdateNotifiers.bindTextureNotifier 是同款「注册全局回调」手法(见 客户端渲染服务)。但这里没有静态块自动注册,COLOR_HANDLER 只是定义了引用, 注册点本条目未找到。
两个上传路径
| 方法 | 行 | 语义 |
|---|---|---|
tintSlot(r, g, b) |
:129 |
在 64 个槽里找/分配一个,返回槽位 |
uploadTinted(r, g, b) |
:153 |
找到后把染好色的 mask 上传到该槽的纹理 |
⚠️ 两条路径的存在说明槽位分配与纹理上传是分离的 —— tintSlot 只管索引,uploadTinted 管 GL。⚠️ 本条目未读这两个方法的实现(:129-175),槽位耗尽时的行为不可判定(复用最旧?分配新槽?返回 NO_TINT?)。
ImmediateExtendedAttribs:立即模式绘制的扩展顶点属性
类注释说明了目标(:26-28)
Supplies per-quad {@code mc_midTexCoord} + {@code at_tangent} for immediate-mode draws so parallax/POM shader packs reconstruct sprite bounds correctly.
即:为立即模式绘制逐 quad 提供 mc_midTexCoord(精灵中心 UV)与 at_tangent(切线),让视差 / POM(Parallax Occlusion Mapping)着色器包能正确重建精灵边界。
⚠️ mc_midTexCoord 与 at_tangent 是 Iris 的顶点属性名(net.coderbot.iris.vertices,:13-15 import IrisQuadView / NormI8 / NormalHelper)。1.7.10 的顶点格式没有这两个属性 —— 这是 Angelica 加的扩展。
6 个常量与 2 个位标志(:30-41)
| 常量 | 值 | 行 | 语义 |
|---|---|---|---|
VERTEX_SIZE |
8 |
:30 |
每顶点 int 数量 |
X / Y / Z / U / V |
0 / 1 / 2 / 3 / 4 |
:31 |
5 个索引挤在一行 |
UV_EPS |
1.0e-5f |
:33 |
|
POM_SUPPRESS_EPS |
1.0e-4f |
:34 |
|
POM_MAX_TILE_EXTENT |
0.125f |
:36 |
= 1/8 |
WANTS_MID |
1 |
:38 |
program 需要的属性位 |
WANTS_TANGENT |
2 |
:39 |
同上 |
NEUTRAL_TANGENT |
NormI8.pack(1.0f, 0.0f, 0.0f, 1.0f) |
:41 |
中性切线(+X) |
⚠️ X / Y / Z / U / V 五个索引在一行内逗号分隔(:31)—— 与 ShadowQuadMath 的 RECORD_SIZE 索引同类写法。编译器不检查,笔误会静默改变索引。
⚠️ POM_MAX_TILE_EXTENT = 0.125f = 1/8 —— 用于 :142、:181 的判定:
&& (!limitTileExtent || ((umax - umin) <= POM_MAX_TILE_EXTENT && (vmax - vmin) <= POM_MAX_TILE_EXTENT));
即「POM 模式下只处理 UV 跨度 ≤ 1/8 的 tile」,更大的 tile(整张纹理)跳过特殊处理。这个阈值是硬编码的经验值,无注释。
⚠️ 两个 eps 常量相差 10 倍(UV_EPS = 1e-5 vs POM_SUPPRESS_EPS = 1e-4)—— 用途不同(前者比 UV,后者抑制 POM),无注释说明各自判据。
⚠️ 5 个索引只覆盖 0-4,但 VERTEX_SIZE = 8 —— 索引 5/6/7 是颜色/法线/光照(在 :31 未定义常量,本条目未读到它们的访问代码)。⚠️ VERTEX_SIZE = 8 与 VertexTransform 用的 gtnhlib VERTEX_SIZE 可能不是同一个(后者是 gtnhlib 定义的,本条目不可判定其值)。两处都是 8 的概率高,但不可假定相同。
program 需求缓存(:43-45)
private static volatile int currentProgramWants = 0; // :43
private static final Int2IntOpenHashMap programWantsExtCache = new Int2IntOpenHashMap(); // :45
| 方法 | 行 |
|---|---|
onProgramBound(int program) |
:47 |
onProgramDeleted(int program) |
:64 |
onShaderPackChanged() |
:68 |
⚠️ currentProgramWants 是 volatile 的(:43)—— 本类里唯一正确处理跨线程可见性的静态字段。与 ShaderGlint 的 5 个非 volatile 标志形成对比。
⚠️ programWantsExtCache 是非并发的 Int2IntOpenHashMap(:45)—— program id → 需求位 的缓存。⚠️ onProgramBound / onProgramDeleted / onShaderPackChanged 三个方法会写/清它,无同步。若 program 绑定发生在渲染线程而 onShaderPackChanged 在其它线程,会损坏 map 内部状态。本条目未读这三个方法体,不下结论。
⚠️ onProgramDeleted(:64)的存在说明作者想到了 program 泄漏 —— 会从缓存里移除。但 onShaderPackChanged(:68)是全清还是部分清,本条目未读。
唯一的 GLSM 接口实现
implements ImmediateExtendedAttribHandler(com.gtnewhorizons.angelica.glsm.hooks.ImmediateExtendedAttribHandler,:4 import)—— GLSM 的钩子接口(与 BatchStateGuard 同包,见 TESR 管线)。
⚠️ GLSM 通过这个接口回调本类 —— 意味着本类的 onProgramBound 等方法由 GLSM 在特定时机调用,不是自己调。调用时机本条目不可判定。
4 个静态内存操作 import(:19-22)
memGetFloat / memGetInt / memPutFloat / memPutInt(gtnhlib MemoryUtilities)—— 直接读写直接内存。与 PlayerReflectionCapture(memAlloc / memFree)同款。⚠️ 无 memFree 的 import —— 本类只做读写不做分配(内存由 GLSM 侧提供)。
formsRectAxis(:236)
一个 private static boolean 辅助(float a, float b, float c)—— 判定三个浮点是否构成轴对齐矩形。⚠️ 本条目未读其实现。
IrisDisplayListState:display list 的 Java 侧作用域记录
335 行,public final。类注释(:26-27):
Records Java-side rendering scopes alongside cached geometry.
即:在缓存几何(display list)之外,把 Java 侧的渲染作用域也一并记录下来。
⚠️ 这是三者中最难理解的。display list 只缓存 GL 命令,而 Iris 的着色器需要知道「这段几何是用哪个 program / 什么 gbuffer / 什么 special condition 画的」—— 这些是Java 侧的状态,不是 GL 命令,display list 无法重放。本类(public final + 私有构造器 + 全静态方法,:29)就是解决这个的。
⚠️ 335 行中本条目只读到第 30 行(import 区 + 类注释 + 第一个方法 runProgramTransition 的签名 :31)。这是本条目最大的缺口。
import 揭示的依赖面(21 个 import)
GLSM(3 个):
| 类 | 用途 |
|---|---|
DisplayListManager |
display list 管理 |
BatchStateGuard |
GLSM hook(与 BatchStateFallback、DeferredDrawBatcher 共用同一单槽回调,见 TESR 管线) |
CommandRecorder |
命令录制 |
DisplayListCommand |
命令类型 |
Angelica 自有(2 个):
| 类 | 位置 |
|---|---|
ShaderGlint |
com.gtnewhorizons.angelica.shadercompat(同本条目的另一个类) |
FallingBlockRendering |
com.gtnewhorizons.angelica.rendering(见 Tessellator 条目) |
内嵌 Iris(11 个):
| 类 | 用途 |
|---|---|
net.coderbot.iris.gbuffer_overrides.matching.SpecialCondition |
gbuffer 覆盖的特殊条件 |
net.coderbot.iris.layer.GbufferPrograms |
gbuffer program 选择(见 渲染崩溃恢复) |
net.coderbot.iris.pipeline.WorldRenderingPhase |
渲染阶段 |
net.coderbot.iris.shaderpack.materialmap.NamespacedId |
材质映射 |
net.coderbot.iris.uniforms.CapturedRenderingState |
捕获的渲染状态 |
net.coderbot.iris.uniforms.EntityIdHelper |
实体 id |
net.coderbot.iris.uniforms.ItemIdManager |
物品 id |
net.minecraft.block.Block |
原版 |
net.minecraft.entity.Entity |
原版 |
net.minecraft.item.Item / ItemStack |
原版 |
⚠️ net.coderbot.iris.pipeline.WorldRenderingPhase 与 net.minecraft.item.Item 被 import —— Item 是 net.minecraft.item.Item(原版)不是 Iris 的。这正是幻觉模式 6「跨 mod 物品混入」需要警惕的地方:import 列表里 net.coderbot.iris.* 与 net.minecraft.* 混排,必须逐个看清包名。
⚠️ ItemIdManager 是 Iris 的物品 id 分配器 —— 与 EntityIdHelper(RenderRecovery 步骤 2 用到)配套。这两个都是 Iris 的「给渲染对象分配稳定 id」的机制,1.7.10 原版没有。ItemIdManager 的 id 分配策略本条目不可判定。
⚠️ SpecialCondition + WorldRenderingPhase + NamespacedId 说明本类要处理「按方块/物品 id 走不同 gbuffer program」的逻辑 —— 这是 Iris 的 SpecialCondition 机制(某些方块走特殊 pass)。⚠️ 1.7.10 没有这套机制,本类在补。
fastutil 的两个集合(:5-6)
| import | 用途 |
|---|---|
BooleanArrayList |
布尔数组列表 —— 记录「作用域内是否有 program 切换」 |
ObjectArrayList |
对象数组列表 —— 记录作用域对象 |
⚠️ ObjectArrayList 无泛型参数写在 import 上,实际类型在字段声明里(本条目未读到)。⚠️ 两者是 fastutil 的非并发实现 —— 静态方法里读写,单线程假设。
runProgramTransition(:31)
public static void runProgramTransition(Runnable transition) { ... }
⚠️ 唯一读到的方法。语义从名字推断是「在 program 切换前后包裹一段代码」(transition 是个 Runnable)。⚠️ 实现本条目未读(:31-)。
RenderingState:被内嵌 Iris 消费的相机/投影快照
com.gtnewhorizons.angelica.rendering.RenderingState(42 行,public class,非 final)只有一个成员是 3 行的桥——它把 1.7.10 的 ActiveRenderInfo 里的投影/模型视图矩阵与相机位置,同步给内嵌 Iris 拿去用。
| 成员 | 行 | 注解 | 类型 |
|---|---|---|---|
INSTANCE |
:12 |
public static final |
eager 初始化的单例 |
cameraPosition |
:13-14 |
@Getter |
final Vector3d |
projectionBuffer |
:15-16 |
@Getter |
final FloatBuffer(16 float) |
modelViewBuffer |
:17-18 |
@Getter |
同上 |
projectionMatrix |
:19-20 |
@Getter |
final Matrix4f,初值 identity() |
modelViewMatrix |
:21-22 |
@Getter |
同上 |
fov |
:23-25 |
@Getter + @Setter |
float |
5 个方法全是「写」,没有「读」(除 Lombok 生成的 getter):
| 方法 | 行 | 做什么 |
|---|---|---|
setCameraPosition(x, y, z) |
:28-30 |
cameraPosition.set(x, y, z) |
setProjectionMatrix(FloatBuffer) |
:32-36 |
projectionMatrix.set(projection) + projectionMatrix.get(0, projectionBuffer) |
setModelViewMatrix(FloatBuffer) |
:38-41 |
同上(modelView*) |
⚠️ 这是「矩阵 + 直接内存 buffer」双表示:每个 setter 一次写两处(:33-34、:39-40)。Lombok 依赖(:3-4 import Getter / Setter)—— 与 ItemPropCache.ItemProp 的 @Data 同款编译期依赖。
⚠️ BufferUtils 是 org.lwjgl.BufferUtils(:7)—— LWJGL 2.x 的 createFloatBuffer(createDirectFloatBuffer 在 LWJGL 2 里已改名)。与 utils/BufferUtil.java 是不同东西(见 utils 纹理工具层)。
三个注入点(全部在 src/mixin/java,属 mixin/ 维度)
| 注入点 | 位置 | 调什么 |
|---|---|---|
MixinActiveRenderInfo |
:19-20 |
setProjectionMatrix + setModelViewMatrix |
MixinEntityRenderer |
:44 |
setCameraPosition(...) |
MixinEntityRenderer |
:53 |
setFov(fov) |
MixinRenderGlobal(celeritas) |
:211 |
getFov() |
⚠️ 写入方全在 mixin 侧,src/main 下零调用(除自身的 setter)—— 与 WitherArmorState、TesrAttribution 同一模式:src/main 的类只被 mixin 驱动。
三个消费方全在内嵌 Iris(net/coderbot/iris/)
| 消费方 | 行 | 用什么 |
|---|---|---|
pipeline/HandRenderer.java |
:235 |
getProjectionBuffer() → glMultMatrix |
pipeline/DeferredWorldRenderingPipeline.java |
:2130 |
getModelViewBuffer() → horizonRenderer.renderHorizon(...) |
pipeline/ShadowRenderer.java |
:465 |
getProjectionMatrix()(三元里与 DHCompat.getProjection() 二选一) |
⚠️ ⚠️ 这是本条目里「内嵌上游 ≠ 本 mod 代码」的最清晰例证:RenderingState 是 Angelica 自己的类(在 com.gtnewhorizons.angelica.rendering),但它存在的唯一理由是给内嵌 Iris 提供 1.7.10 缺失的相机/投影状态——Iris 侧的 HandRenderer、DeferredWorldRenderingPipeline、ShadowRenderer 都假定这些状态存在(现代版由 Iris 自己的管线管理)。这三个 Iris 类不是 Angelica 的代码,且它们是「被服务方」。
⚠️ ShadowRenderer.java:465 的三元表达式(源码行内):
final Matrix4fc projView = ((shouldRenderDH && DHCompat.hasRenderingEnabled()) ? DHCompat.getProjection() : RenderingState.INSTANCE.getProjectionMatrix());
即 有 DH(Distortion Horizon)且启用时用 DH 的矩阵,否则用 RenderingState 的。两条路径的矩阵语义必须一致,否则切 DH 时阴影会跳变。DHCompat 不在本仓库,本条目不可判定。
⚠️ ⚠️ 两个 FloatBuffer 是一次性分配的 16 float(:16、:18)—— **只读不写。**Iris 侧 glMultMatrix(FloatBuffer)(HandRenderer.java:235)读它;renderHorizon(FloatBuffer) 同理。没有并发写(只有 setter 写,而 setter 在渲染线程)。
⚠️ projectionMatrix.set(projection) 从 FloatBuffer 读(:33)—— 若传入的 buffer 位置/容量不对(如 position() != 0),JOML 的 set(FloatBuffer) 从当前位置读,读到错数据。⚠️ setModelViewMatrix 同理(:39)。无位置重置。
⚠️ cameraPosition 是 Vector3d(双精度)而矩阵是 float(:14 vs :20)—— 两种精度并存。setCameraPosition 接 double(:28),Iris 侧读到的 getCameraPosition() 是 Vector3d。1.7.10 的实体位置是 double 精度,所以这是正确的(现代 MC 同样是 double)。
⚠️ 全部 5 个字段非 volatile 的单例(:12-25)—— 跨线程无 happens-before。MixinRenderGlobal.java:211 读 getFov()(celeritas 侧,可能在渲染线程),写入在 MixinEntityRenderer(主线程)。同线程假设。
⚠️ fov 是唯一有 @Setter 的字段(:23-25)—— 因为 1.7.10 的 fov 会被 mod 动态改变(FOV 动画 mod),需要 Iris 侧跟随。这是唯一「可被外部 mod 修改」的状态。
已知问题 / 风险
IrisDisplayListState.java335 行中本条目只读到第 31 行 —— 本条目最大的缺口。它是三者中最核心的(display list 与 Iris 状态的桥接),却读得最少。ShaderGlint的 5 个静态状态标志非 volatile(:36-40、:50-52、:54、:56),而ImmediateExtendedAttribs.currentProgramWants是 volatile(:43)—— 同一子系统的线程安全标准不一致。ShaderGlint.COLOR_HANDLER只定义了方法引用(:48),注册点未找到 —— 若未注册,颜色变化回调永不触发。ShaderGlint.slotTextures固定 64 个纹理槽(:33、:46),槽位耗尽时的行为未读(tintSlot实现未读)。ShaderGlint.ensureMaskLoaded读的textures/misc/enchanted_item_glint.png在 1.7.10 不存在(:32、:176)—— 玩家资源包提供该文件会改变行为。ShaderGlint的作者自述解法可能有副作用(类注释:29-30:> This might introduce some oddities that I’m not seeing)。ShaderGlint点名 AstraLex 为兼容目标(:26)—— 该着色器包若不再需要此绕行,此类的复杂度就是纯负担。ImmediateExtendedAttribs的 5 个顶点索引挤在一行(:31),编译器不检查。ImmediateExtendedAttribs.programWantsExtCache是非并发 map(:45),由三个 public static 方法(:47、:64、:68)读写,无同步。ImmediateExtendedAttribs.VERTEX_SIZE = 8与 gtnhlib 的VERTEX_SIZE是两个独立定义(:30vsVertexTransform),值是否相同未验证。POM_MAX_TILE_EXTENT = 0.125f(1/8)是硬编码经验阈值无注释(:36、:142、:181)。X/Y/Z/U/V只覆盖 0-4 而VERTEX_SIZE = 8(:30-31),索引 5/6/7 无命名常量。IrisDisplayListState与BatchStateFallback/DeferredDrawBatcher三者都 import GLSM 的BatchStateGuard—— 单槽回调的争抢关系未确认。IrisDisplayListState的 import 列表里net.coderbot.iris.*与net.minecraft.item.Item混排(:9-19)—— 必须逐个看包名,Item是原版不是 Iris 的。ShaderGlint201 行、ImmediateExtendedAttribs317 行中各约 100–200 行未读 —— 常量与方法清单已列,实现细节不可判定。RenderingState的 5 个字段非 volatile 的单例(:12-25),写入在 mixin 侧主线程、读取在渲染线程,同线程假设无保障。RenderingState.setProjectionMatrix/setModelViewMatrix不重置传入FloatBuffer的 position(:33、:39)—— 位置不对会静默读到错矩阵。ShadowRenderer.java:465的DHCompat.getProjection()与RenderingState.getProjectionMatrix()二选一(内嵌 Iris 侧)—— 两条路径的矩阵语义一致性本仓库不可判定。RenderingState在src/main下零调用(全靠 mixin 驱动)—— 移除任一 mixin 注入点会让它静默失效。
相关条目
- 渲染崩溃恢复 -
GbufferPrograms/CapturedRenderingState的复位点 - Tessellator / 线程世界访问 / 渲染队列 -
FallingBlockRendering(IrisDisplayListState的依赖) - 护甲 / 闪光 / 玩家反射 -
GlintClock(与ShaderGlint是两套闪光机制) - 客户端渲染服务 -
TextureTracker的同款「注册全局回调」手法 - TESR 实例化管线 -
BatchStateGuard的另一个使用者 - Iris(内嵌) - 本条目 3 个文件的依赖来源
- Subprojects(内嵌子项目) - GLSM 的
GlintColorHandler/ImmediateExtendedAttribHandler/DisplayListManager - 掉落物品实例化 -
GlintCapture/ItemPropCache的归属 - Angelica mixin 分组 -
RenderingState的 3 个写入注入点 - utils 纹理工具层 -
BufferUtil与本条目的org.lwjgl.BufferUtils是不同的东西