Skybox IV

sodium support, nether functions
This commit is contained in:
techno-sam
2026-04-25 16:35:41 +02:00
parent acb6e0bb30
commit 4bd557f846
13 changed files with 290 additions and 5 deletions
+1 -1
View File
@@ -4,7 +4,7 @@ indent_style = tab
tab_width = 4 tab_width = 4
insert_final_newline = true insert_final_newline = true
[{*.py,*.ipynb}] [{*.py,*.ipynb,*.fsh,*.vsh}]
indent_size = 4 indent_size = 4
indent_style = space indent_style = space
@@ -41,7 +41,7 @@ public class SkyShaderInterface implements ChunkShaderInterface {
this.uniformColorModulator = context.bindUniform("u_ColorModulator", GlUniformFloat4v::new); this.uniformColorModulator = context.bindUniform("u_ColorModulator", GlUniformFloat4v::new);
this.uniformTextures = new EnumMap<>(ChunkShaderTextureSlot.class); this.uniformTextures = new EnumMap<>(ChunkShaderTextureSlot.class);
this.uniformTextures.put(ChunkShaderTextureSlot.BLOCK, context.bindUniform("u_BlockTex", GlUniformInt::new)); this.uniformTextures.put(ChunkShaderTextureSlot.BLOCK, context.bindUniformOptional("u_BlockTex", GlUniformInt::new));
this.fogShader = options.fog().getFactory().apply(context); this.fogShader = options.fog().getFactory().apply(context);
} }
@@ -83,6 +83,7 @@ public class SkyShaderInterface implements ChunkShaderInterface {
GlStateManager._activeTexture(GL32C.GL_TEXTURE0 + slot.ordinal()); GlStateManager._activeTexture(GL32C.GL_TEXTURE0 + slot.ordinal());
GlStateManager._bindTexture(textureId); GlStateManager._bindTexture(textureId);
GlUniformInt uniform = this.uniformTextures.get(slot); GlUniformInt uniform = this.uniformTextures.get(slot);
if (uniform != null)
uniform.setInt(slot.ordinal()); uniform.setInt(slot.ordinal());
} }
@@ -0,0 +1,37 @@
package io.github.slimeistdev.crystalline_sky.compat.sodium;
import io.github.slimeistdev.crystalline_sky.registry.client.CrystallineAtlases;
import io.github.slimeistdev.crystalline_sky.util.SharedRenderVariables;
import net.caffeinemc.mods.sodium.client.gl.device.GLRenderDevice;
import net.caffeinemc.mods.sodium.client.gl.shader.uniform.GlUniformFloat2v;
import net.caffeinemc.mods.sodium.client.gl.shader.uniform.GlUniformMatrix4f;
import net.caffeinemc.mods.sodium.client.render.chunk.shader.ChunkShaderOptions;
import net.caffeinemc.mods.sodium.client.render.chunk.shader.ShaderBindingContext;
import net.caffeinemc.mods.sodium.mixin.core.render.texture.TextureAtlasAccessor;
import net.minecraft.client.Minecraft;
public class SkyboxShaderInterface extends SkyShaderInterface {
private final GlUniformMatrix4f uniformInvViewProjMatrix;
private final GlUniformFloat2v uniformTexCoordShrink;
public SkyboxShaderInterface(ShaderBindingContext context, ChunkShaderOptions options) {
super(context, options);
this.uniformInvViewProjMatrix = context.bindUniform("u_InvViewProjMatrix", GlUniformMatrix4f::new);
this.uniformTexCoordShrink = context.bindUniformOptional("u_TexCoordShrink", GlUniformFloat2v::new);
}
@Override
public void setupState() {
super.setupState();
this.uniformInvViewProjMatrix.set(SharedRenderVariables.invSkyboxMat);
if (this.uniformTexCoordShrink != null) {
TextureAtlasAccessor textureAtlas = (TextureAtlasAccessor) Minecraft.getInstance().getTextureManager().getTexture(CrystallineAtlases.SKYBOXES.texture);
double subTexelPrecision = 1 << GLRenderDevice.INSTANCE.getSubTexelPrecisionBits();
double subTexelOffset = 3.0517578E-5F;
this.uniformTexCoordShrink.set(
(float) (subTexelOffset - (double) 1.0F / (double) textureAtlas.getField_43113() / subTexelPrecision),
(float) (subTexelOffset - (double) 1.0F / (double) textureAtlas.getField_43114() / subTexelPrecision)
);
}
}
}
@@ -1,15 +1,19 @@
package io.github.slimeistdev.crystalline_sky.mixin.client; package io.github.slimeistdev.crystalline_sky.mixin.client;
import io.github.slimeistdev.crystalline_sky.registry.CrystallineItems; import io.github.slimeistdev.crystalline_sky.registry.CrystallineItems;
import io.github.slimeistdev.crystalline_sky.util.SharedRenderVariables;
import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.Direction;
import net.minecraft.world.item.Item; import net.minecraft.world.item.Item;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable; import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
@@ -21,6 +25,9 @@ public class ClientLevelMixin {
@Mutable @Mutable
private static Set<Item> MARKER_PARTICLE_ITEMS; private static Set<Item> MARKER_PARTICLE_ITEMS;
@Unique
private static final Float crystalline_sky$fullBright = 1.0f;
@Inject(method = "<clinit>", at = @At("RETURN")) @Inject(method = "<clinit>", at = @At("RETURN"))
private static void modifyBlockMarkerItems(CallbackInfo ci) { private static void modifyBlockMarkerItems(CallbackInfo ci) {
MARKER_PARTICLE_ITEMS = new HashSet<>(MARKER_PARTICLE_ITEMS); MARKER_PARTICLE_ITEMS = new HashSet<>(MARKER_PARTICLE_ITEMS);
@@ -29,4 +36,10 @@ public class ClientLevelMixin {
MARKER_PARTICLE_ITEMS.add(CrystallineItems.SKY.value()); MARKER_PARTICLE_ITEMS.add(CrystallineItems.SKY.value());
MARKER_PARTICLE_ITEMS.add(CrystallineItems.WEEPING_SKY.value()); MARKER_PARTICLE_ITEMS.add(CrystallineItems.WEEPING_SKY.value());
} }
@Inject(method = "getShade", at = @At("HEAD"), cancellable = true)
private void fullBrightSkyBox(Direction direction, boolean shade, CallbackInfoReturnable<Float> cir) {
if (SharedRenderVariables.shouldShadeFullBright())
cir.setReturnValue(crystalline_sky$fullBright);
}
} }
@@ -0,0 +1,23 @@
package io.github.slimeistdev.crystalline_sky.mixin.client;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import io.github.slimeistdev.crystalline_sky.registry.client.CrystallineAtlases;
import net.minecraft.client.renderer.block.ModelBlockRenderer;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.core.Direction;
import net.minecraft.world.level.BlockAndTintGetter;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@Mixin(ModelBlockRenderer.class)
public class ModelBlockRendererMixin {
@WrapOperation(method = "renderModelFaceFlat", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/BlockAndTintGetter;getShade(Lnet/minecraft/core/Direction;Z)F"))
private float fullBrightSkybox(BlockAndTintGetter instance, Direction direction, boolean shade,
Operation<Float> original, @Local(name = "bakedQuad") BakedQuad bakedQuad) {
if (bakedQuad.getSprite().atlasLocation().equals(CrystallineAtlases.SKYBOXES.texture))
return 1.0f;
return original.call(instance, direction, shade);
}
}
@@ -0,0 +1,23 @@
package io.github.slimeistdev.crystalline_sky.mixin.client.compat.sodium;
import com.llamalad7.mixinextras.expression.Definition;
import com.llamalad7.mixinextras.expression.Expression;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import com.llamalad7.mixinextras.sugar.Local;
import io.github.slimeistdev.crystalline_sky.annotation.mixin.ConditionalMixin;
import io.github.slimeistdev.crystalline_sky.compat.Mods;
import net.caffeinemc.mods.sodium.client.render.chunk.vertex.format.impl.CompactChunkVertex;
import net.minecraft.util.Mth;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@ConditionalMixin(mods = Mods.SODIUM)
@Mixin(CompactChunkVertex.class)
public class CompactChunkVertexMixin {
@Definition(id = "quantized", local = @Local(type = int.class, name = "quantized"))
@Expression("quantized = @(?)")
@ModifyExpressionValue(method = "encodeTexture", at = @At("MIXINEXTRAS:EXPRESSION"))
private static int clamp(int original) {
return Mth.clamp(original, 0, 32767);
}
}
@@ -5,6 +5,7 @@ import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import io.github.slimeistdev.crystalline_sky.annotation.mixin.ConditionalMixin; import io.github.slimeistdev.crystalline_sky.annotation.mixin.ConditionalMixin;
import io.github.slimeistdev.crystalline_sky.compat.Mods; import io.github.slimeistdev.crystalline_sky.compat.Mods;
import io.github.slimeistdev.crystalline_sky.compat.sodium.SkyShaderInterface; import io.github.slimeistdev.crystalline_sky.compat.sodium.SkyShaderInterface;
import io.github.slimeistdev.crystalline_sky.compat.sodium.SkyboxShaderInterface;
import io.github.slimeistdev.crystalline_sky.registry.client.CrystallineRenderTypes; import io.github.slimeistdev.crystalline_sky.registry.client.CrystallineRenderTypes;
import net.caffeinemc.mods.sodium.client.gl.shader.GlProgram; import net.caffeinemc.mods.sodium.client.gl.shader.GlProgram;
import net.caffeinemc.mods.sodium.client.render.chunk.ShaderChunkRenderer; import net.caffeinemc.mods.sodium.client.render.chunk.ShaderChunkRenderer;
@@ -43,8 +44,10 @@ public class ShaderChunkRendererMixin {
@WrapOperation(method = "createShader", at = @At(value = "INVOKE", target = "Lnet/caffeinemc/mods/sodium/client/gl/shader/GlProgram$Builder;link(Ljava/util/function/Function;)Lnet/caffeinemc/mods/sodium/client/gl/shader/GlProgram;"), remap = false) @WrapOperation(method = "createShader", at = @At(value = "INVOKE", target = "Lnet/caffeinemc/mods/sodium/client/gl/shader/GlProgram$Builder;link(Ljava/util/function/Function;)Lnet/caffeinemc/mods/sodium/client/gl/shader/GlProgram;"), remap = false)
private static GlProgram<ChunkShaderInterface> useSkyShaderInterface(GlProgram.Builder instance, Function<ShaderBindingContext, ChunkShaderInterface> factory, Operation<GlProgram<ChunkShaderInterface>> original, String argPath, ChunkShaderOptions argOptions) { private static GlProgram<ChunkShaderInterface> useSkyShaderInterface(GlProgram.Builder instance, Function<ShaderBindingContext, ChunkShaderInterface> factory, Operation<GlProgram<ChunkShaderInterface>> original, String argPath, ChunkShaderOptions argOptions) {
if (argPath.equals("sodium_compat/block_layer_sky") || argPath.equals("sodium_compat/block_layer_skybox")) { if (argPath.equals("sodium_compat/block_layer_sky")) {
factory = (shader) -> new SkyShaderInterface(shader, argOptions); factory = (shader) -> new SkyShaderInterface(shader, argOptions);
} else if (argPath.equals("sodium_compat/block_layer_skybox")) {
factory = (shader) -> new SkyboxShaderInterface(shader, argOptions);
} }
return original.call(instance, factory); return original.call(instance, factory);
@@ -1,7 +1,22 @@
package io.github.slimeistdev.crystalline_sky.util; package io.github.slimeistdev.crystalline_sky.util;
import org.apache.commons.lang3.mutable.MutableInt;
import org.joml.Matrix4f; import org.joml.Matrix4f;
public class SharedRenderVariables { public class SharedRenderVariables {
public static final Matrix4f invSkyboxMat = new Matrix4f(); public static final Matrix4f invSkyboxMat = new Matrix4f();
// because chunk meshing is multithreaded :(
public static final ThreadLocal<MutableInt> shadeFullBright = ThreadLocal.withInitial(() -> new MutableInt(0));
public static boolean shouldShadeFullBright() {
return shadeFullBright.get().intValue() > 0;
}
public static void pushShadeFullBright() {
shadeFullBright.get().increment();
}
public static void popShadeFullBright() {
shadeFullBright.get().decrement();
}
} }
@@ -0,0 +1,99 @@
#version 330 core
#import <sodium:include/fog.glsl>
in vec2 v_uv0; // The top-left texture coordinates
in vec2 v_uv1; // The bottom-right texture coordinates
in vec3 v_Pos; // The interpolated view-relative coordinates
in float v_FragDistance; // The fragment's distance from the camera
in float v_MaterialMipBias;
in float v_MaterialAlphaCutoff;
uniform sampler2D u_BlockTex; // The block (skybox) texture
uniform vec4 u_FogColor; // The color of the shader fog
uniform float u_FogStart; // The starting position of the shader fog
uniform float u_FogEnd; // The ending position of the shader fog
uniform vec4 u_ColorModulator;
out vec4 fragColor; // The output fragment for the color framebuffer
#define SCALE 1
#define BAYER_BIAS 0.03125
#define FACE_DBG 0
const mat4x4 bayerMatrix4x4 = mat4x4(
0.0, 8.0, 2.0, 10.0,
12.0, 4.0, 14.0, 6.0,
3.0, 11.0, 1.0, 9.0,
15.0, 7.0, 13.0, 5.0
) / 16.0;
void main() {
vec3 dir = normalize(v_Pos);
vec3 dabs = abs(dir);
float dmax = max(dabs.x, max(dabs.y, dabs.z));
bool positive;
#if FACE_DBG
vec3 col;
#else
vec2 uv;
vec2 section;
#endif
if (dabs.x == dmax) {
positive = dir.x > 0;
#if FACE_DBG
col = vec3(1.0, 0.0, 0.0);
#else
uv = positive ? -dir.zy : vec2(dir.z, -dir.y);
section = vec2(positive ? 2.0 : 0.0, 1.0);
#endif
} else if (dabs.y == dmax) {
positive = dir.y > 0;
#if FACE_DBG
col = vec3(0.0, 1.0, 0.0);
#else
uv = positive ? dir.xz : vec2(dir.x, -dir.z);
section = vec2(positive ? 1.0 : 2.0, 0.0);
#endif
} else {
positive = dir.z > 0;
#if FACE_DBG
col = vec3(0.0, 0.0, 1.0);
#else
uv = positive ? vec2(dir.x, -dir.y) : -dir.xy;
section = vec2(positive ? 1.0 : 3.0, 1.0);
#endif
}
#if FACE_DBG
col *= positive ? 1.0 : 0.5;
vec4 diffuseColor = vec4(col, 1.0);
#else
uv = (uv / dmax + 1.0) / 2.0;
uv = clamp(uv, vec2(0.0), vec2(1.0));
uv = (uv + section) / vec2(4.0, 2.0);
vec2 uvR = v_uv0 + uv * (v_uv1 - v_uv0);
vec4 diffuseColor = texture(u_BlockTex, uvR, v_MaterialMipBias);
//vec4 diffuseColor = vec4(v_uv0, uv.x*0.00000000001, 1.0);
#endif
diffuseColor *= vec4(u_ColorModulator.rgb, 1.0);
#ifdef USE_FRAGMENT_DISCARD
int x = int(gl_FragCoord.x / SCALE) % 4;
int y = int(gl_FragCoord.y / SCALE) % 4;
float bayer = bayerMatrix4x4[y][x];
if (u_ColorModulator.a <= bayer + BAYER_BIAS) {
discard;
}
#endif
fragColor = _linearFog(diffuseColor, v_FragDistance, u_FogColor, u_FogStart, u_FogEnd);
}
@@ -0,0 +1,66 @@
#version 330 core
#import <sodium:include/fog.glsl>
#import <sodium:include/chunk_vertex.glsl>
#import <sodium:include/chunk_matrices.glsl>
#import <sodium:include/chunk_material.glsl>
// The inverse(model-view) * inverse(projection) matrix
uniform mat4 u_InvViewProjMatrix;
out vec2 v_uv0;
out vec2 v_uv1;
out vec3 v_Pos;
out float v_MaterialMipBias;
#ifdef USE_FRAGMENT_DISCARD
out float v_MaterialAlphaCutoff;
#endif
#ifdef USE_FOG
out float v_FragDistance;
#endif
uniform int u_FogShape;
uniform vec3 u_RegionOffset;
uniform vec2 u_TexCoordShrink;
uvec3 _get_relative_chunk_coord(uint pos) {
// Packing scheme is defined by LocalSectionIndex
return uvec3(pos) >> uvec3(5u, 0u, 2u) & uvec3(7u, 3u, 7u);
}
vec3 _get_draw_translation(uint pos) {
return _get_relative_chunk_coord(pos) * vec3(16.0);
}
void main() {
_vert_init();
// Transform the chunk-local vertex position into world model space
vec3 translation = u_RegionOffset + _get_draw_translation(_draw_id);
vec3 position = _vert_position + translation;
#ifdef USE_FOG
v_FragDistance = getFragDistance(u_FogShape, position);
#endif
// Transform the vertex position into model-view-projection space
gl_Position = u_ProjectionMatrix * u_ModelViewMatrix * vec4(position, 1.0);
// somehow this unbreaks view bobbing. No clue *how*, but it does.
vec3 screenPos = gl_Position.xyz / gl_Position.w;
vec4 projected4 = u_InvViewProjMatrix * vec4(screenPos, 1.0);
vec3 projected = projected4.xyz / projected4.w;
vec4 projectedO4 = u_InvViewProjMatrix * vec4(0.0, 0.0, 1.0, 0.0);
vec3 projectedO = projectedO4.xyz / projectedO4.w;
v_Pos = projected - projectedO;
v_uv0 = (vec2(1.0) * u_TexCoordShrink) + _vert_tex_diffuse_coord; // FMA for precision
v_uv1 = (vec2(-1.0) * u_TexCoordShrink) + ((_vert_color.ag * 255.0 / 256.0) + (_vert_color.rb / 256.0));
v_MaterialMipBias = _material_mip_bias(_material_params);
#ifdef USE_FRAGMENT_DISCARD
v_MaterialAlphaCutoff = _material_alpha_cutoff(_material_params);
#endif
}
@@ -23,8 +23,10 @@
"client.GameRendererMixin", "client.GameRendererMixin",
"client.LevelRenderer_NoSodium_Mixin", "client.LevelRenderer_NoSodium_Mixin",
"client.LevelRendererMixin", "client.LevelRendererMixin",
"client.ModelBlockRendererMixin",
"client.RenderTargetMixin", "client.RenderTargetMixin",
"client.SimpleBakedModelMixin", "client.SimpleBakedModelMixin",
"client.compat.sodium.CompactChunkVertexMixin",
"client.compat.sodium.DefaultMaterialsMixin", "client.compat.sodium.DefaultMaterialsMixin",
"client.compat.sodium.DefaultTerrainRenderPassesMixin", "client.compat.sodium.DefaultTerrainRenderPassesMixin",
"client.compat.sodium.ShaderChunkRendererMixin", "client.compat.sodium.ShaderChunkRendererMixin",
@@ -1,5 +1,6 @@
package io.github.slimeistdev.crystalline_sky.fabric.skybox_model; package io.github.slimeistdev.crystalline_sky.fabric.skybox_model;
import io.github.slimeistdev.crystalline_sky.util.SharedRenderVariables;
import net.fabricmc.fabric.api.renderer.v1.Renderer; import net.fabricmc.fabric.api.renderer.v1.Renderer;
import net.fabricmc.fabric.api.renderer.v1.RendererAccess; import net.fabricmc.fabric.api.renderer.v1.RendererAccess;
import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial; import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial;
@@ -61,6 +62,7 @@ public class SkyboxBakedModel extends ForwardingBakedModel {
// copied from net.fabricmc.fabric.impl.renderer.VanillaModelEncoder.emitBlockQuads // copied from net.fabricmc.fabric.impl.renderer.VanillaModelEncoder.emitBlockQuads
@Override @Override
public void emitBlockQuads(BlockAndTintGetter blockView, BlockState state, BlockPos pos, Supplier<RandomSource> randomSupplier, RenderContext context) { public void emitBlockQuads(BlockAndTintGetter blockView, BlockState state, BlockPos pos, Supplier<RandomSource> randomSupplier, RenderContext context) {
SharedRenderVariables.pushShadeFullBright();
QuadEmitter emitter = context.getEmitter(); QuadEmitter emitter = context.getEmitter();
for (int i = 0; i <= ModelHelper.NULL_FACE_ID; i++) { for (int i = 0; i <= ModelHelper.NULL_FACE_ID; i++) {
@@ -88,6 +90,7 @@ public class SkyboxBakedModel extends ForwardingBakedModel {
emitter.emit(); emitter.emit();
} }
} }
SharedRenderVariables.popShadeFullBright();
} }
@Override @Override
+1 -1
View File
@@ -26,5 +26,5 @@ modVersion=0.1.2
compatibleVersions=1.21.1 compatibleVersions=1.21.1
# mod compat # mod compat
enable_sodium=false enable_sodium=true
enable_axiom=false enable_axiom=false