Keeps StoryModEngine's GPU instancing (InstancedShader/InstanceFlush/InstanceBatchCollector/
InstanceBatchBuffers) alive under an active Oculus/Iris shader pack, with the pack's own lighting applied to
instanced geometry, instead of falling back to slow immediate-mode rendering whenever a pack is active.
Full design/rationale: see the plan this was implemented from (starry-hopping-ullman.md) for the research this
is based on and why each design choice was made.
This addon works by mixin-injecting into Oculus's own internal, unstable classes (net.irisshaders.iris.*) -
not a public API. Every version below was individually confirmed by decompiling the real jar, not assumed from
general Iris/Oculus knowledge:
- Oculus
1.20.1-1.8.0(Modrinth). Resolved to commit5751a2f6b8ffb1293a4239b6717006ba97d8c8fbon the1.20.1-newbranch ofgithub.com/Asek3/Oculus(no git tag exists for this release - resolved by Modrinth publish-timestamp + changelog cross-reference). - Embeddium
0.3.14+mc1.20.1(Modrinth version string; Oculus's owngradle.propertiesat the matching commit pins the same release as0.3.14-git.8af1729+mc1.20.1via a different maven mirror - same jar content, different version-string convention between the two repositories).
Before bumping either version, re-verify these specific facts against the new jar (javap -p or a decompiler
like CFR is enough - no full IDE/dev-environment needed for this step):
net.irisshaders.iris.pipeline.IrisRenderingPipelinestill has a privatecreateShader(String, ProgramSource, ProgramId, AlphaTest, VertexFormat, FogMode, boolean, boolean, boolean, boolean)overload with this exact signature, and still takesProgramSetonly as a constructor parameter (never stored as a field) - both assumptionsmixin/IrisRenderingPipelineMixin.javadepends on directly.net.irisshaders.iris.shaderpack.programs.ProgramSourcestill has a private 8-arg constructor(String name, String vertexSource, String geometrySource, String tessControlSource, String tessEvalSource, String fragmentSource, ProgramDirectives directives, ProgramSet parent)- whatmixin/ProgramSourceAccessor.javainvokes.ProgramSetstill exposesgetGbuffersEntities()/getGbuffersBasic()/getGbuffersTextured()/getGbuffersTexturedLit()as publicOptional<ProgramSource>getters.- Oculus still shades
io.github.douira.glsl_transformer(the AST-transform libraryshader/ InstancedVertexMerger.javauses) directly into its own jar rather than requiring it as a separate Gradle dependency (confirmed by inspecting the jar's contents, not the Modrinth page) - and that itsSingleASTTransformer/Root.replaceReferenceExpressions/Root.rename/TranslationUnit.parseAndInjectNodesAPI shape (mirrored from Oculus's ownpipeline.transform.transformer.VanillaTransformer/EntityPatcherusage) hasn't changed. ProgramId.EntitiesandShaderKey.ENTITIES_CUTOUT's parameterization (AlphaTests.ONE_TENTH_ALPHA,FogMode.PER_VERTEX, not intensity/fullbright/glint/text) still match whatOculusInstancingIntegrationpasses tocreateShader.
If any of these have changed shape, the mixins will most likely fail to apply (a loud, visible startup error, not
a silent misrender - Mixin logs apply failures) or compileJava will fail outright, since none of this is
reflection-based. That's a deliberate trade-off: better a build failure pointing straight at what changed than a
mixin that half-applies and misrenders quietly.
Deliberately out of scope for this change (see the plan's "Future extension points" for how to pick these up):
- No shadow-map participation. Instanced NPCs render with correct pack lighting but don't appear in the pack's shadow map.
- No pack-authorable override shader. Always merges into the pack's own
gbuffers_entities(falling back throughgbuffers_basic/gbuffers_textured/gbuffers_textured_lit) - a pack can't ship a bespoke instancing shader the way it optionally can foriris-flw-compat's Flywheel integration. - Overlay tint doesn't carry through (entity hurt-flash/heal-flash tint). Iris's own entity-format patching
unconditionally injects a per-vertex overlay-texel attribute and reads it directly, and that injection happens
inside Iris's own patch pass - after this addon's own merge step has already handed off its output - so there
is no text-level hook available to redirect it to this engine's per-instance
InstanceOverlayattribute the way the lightmap coordinate is redirected. This is a status-effect indicator, not lighting, so it's out of scope for what this change is actually about. - Packs calling the legacy
ftransform()built-in directly (instead of referencinggl_Vertex/gl_ModelViewMatrixthemselves) won't pick up the per-instance transform, because Iris's own patcher injects its ownftransform()implementation (in terms ofgl_Vertex) after this addon's merge runs, using the genuine per-vertex position rather than this engine's per-instance transform of it. A legacy GLSL 1.10-era pattern most modern packs don't use.
See shader/InstancedVertexMerger.java's class doc for the exact substitution strategy and why each of the above
is out of reach for a vertex-only merge.
gradlew compileJava succeeds against the real Oculus/Embeddium jars (via Modrinth's maven, fg.deobf) and a
freshly-built StoryModEngine jar - confirms every signature above and the glsl-transformer API usage compile as
written. Not yet verified: actual visual behavior in-game (mixins applying at runtime, the merged shader
linking without GL errors, lighting actually matching the pack). Per the plan's build-tooling research, that needs
a built jar installed in a real Forge 1.20.1 launcher instance (Forge installer, not gradlew runClient) with
Oculus + Embeddium + StoryModEngine + this addon all present - a third-party Mixin dependency's refmap-remapping
behaves differently between ForgeGradle's dev environment and a real production launch, so a dev-only smoke test
would not be trustworthy for this part even if it ran without errors.
To do that verification pass:
./gradlew buildthis project and StoryModEngine (in that dependency order).- Install both mods' jars, plus Oculus
1.20.1-1.8.0and Embeddium0.3.14+mc1.20.1, into a real Forge1.20.1-47.4.22instance. - Load into a world with an Iris/Oculus-compatible shader pack active (e.g. Complementary or BSL), spawn
instanced NPCs, and confirm: instancing stays on the fast path (check the log for
[OculusSMECompat] Instancing now lit by the active pack's own '...' program.); lit NPCs visibly respond to the pack's sun angle/ambient occlusion/color grading; toggling the pack off cleanly reverts to vanilla-correct lighting; a pack with an unusual/minimalgbuffers_entities(or none at all) falls back to the existing immediate-draw path without crashing.