fixes and work on ao, shading, tinting and lighting

This commit is contained in:
mcrcortex
2025-12-14 18:05:17 +10:00
parent edd0ce33ef
commit 2458a4a3f6
7 changed files with 90 additions and 43 deletions

View File

@@ -23,13 +23,14 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.Identifier;
import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.ColorResolver; import net.minecraft.world.level.ColorResolver;
import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.biome.Biomes;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.LeavesBlock; import net.minecraft.world.level.block.LeavesBlock;
import net.minecraft.world.level.block.LiquidBlock; import net.minecraft.world.level.block.LiquidBlock;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
@@ -65,9 +66,9 @@ public class ModelFactory {
//TODO: replace the fluid BlockState with a client model id integer of the fluidState, requires looking up //TODO: replace the fluid BlockState with a client model id integer of the fluidState, requires looking up
// the fluid state in the mipper // the fluid state in the mipper
private record ModelEntry(ColourDepthTextureData down, ColourDepthTextureData up, ColourDepthTextureData north, ColourDepthTextureData south, ColourDepthTextureData west, ColourDepthTextureData east, int fluidBlockStateId) { private record ModelEntry(ColourDepthTextureData down, ColourDepthTextureData up, ColourDepthTextureData north, ColourDepthTextureData south, ColourDepthTextureData west, ColourDepthTextureData east, int fluidBlockStateId, int tintingColour) {
public ModelEntry(ColourDepthTextureData[] textures, int fluidBlockStateId) { public ModelEntry(ColourDepthTextureData[] textures, int fluidBlockStateId, int tintingColour) {
this(textures[0], textures[1], textures[2], textures[3], textures[4], textures[5], fluidBlockStateId); this(textures[0], textures[1], textures[2], textures[3], textures[4], textures[5], fluidBlockStateId, tintingColour);
} }
} }
@@ -151,7 +152,19 @@ public class ModelFactory {
this.customBlockStateIdMapping = mapping; this.customBlockStateIdMapping = mapping;
} }
private record RawBakeResult(int blockId, BlockState blockState, MemoryBuffer rawData) { private static final class RawBakeResult {
private final int blockId;
private final BlockState blockState;
private final MemoryBuffer rawData;
public boolean isShaded;
public RawBakeResult(int blockId, BlockState blockState, MemoryBuffer rawData) {
this.blockId = blockId;
this.blockState = blockState;
this.rawData = rawData;
}
public RawBakeResult(int blockId, BlockState blockState) { public RawBakeResult(int blockId, BlockState blockState) {
this(blockId, blockState, new MemoryBuffer(MODEL_TEXTURE_SIZE*MODEL_TEXTURE_SIZE*2*4*6)); this(blockId, blockState, new MemoryBuffer(MODEL_TEXTURE_SIZE*MODEL_TEXTURE_SIZE*2*4*6));
} }
@@ -206,7 +219,7 @@ public class ModelFactory {
RawBakeResult result = new RawBakeResult(blockId, blockState); RawBakeResult result = new RawBakeResult(blockId, blockState);
int allocation = this.downstream.download(MODEL_TEXTURE_SIZE*MODEL_TEXTURE_SIZE*2*4*6, ptr -> this.rawBakeResults.add(result.cpyBuf(ptr))); int allocation = this.downstream.download(MODEL_TEXTURE_SIZE*MODEL_TEXTURE_SIZE*2*4*6, ptr -> this.rawBakeResults.add(result.cpyBuf(ptr)));
this.bakery.renderToStream(blockState, this.downstream.getBufferId(), allocation); result.isShaded = this.bakery.renderToStream(blockState, this.downstream.getBufferId(), allocation);
return true; return true;
} }
@@ -232,7 +245,7 @@ public class ModelFactory {
} }
} }
result.rawData.free(); result.rawData.free();
var bakeResult = this.processTextureBakeResult(result.blockId, result.blockState, textureData); var bakeResult = this.processTextureBakeResult(result.blockId, result.blockState, textureData, result.isShaded);
if (bakeResult!=null) { if (bakeResult!=null) {
this.uploadResults.add(bakeResult); this.uploadResults.add(bakeResult);
} }
@@ -248,7 +261,7 @@ public class ModelFactory {
var biomeEntry = this.biomeQueue.poll(); var biomeEntry = this.biomeQueue.poll();
while (biomeEntry != null) { while (biomeEntry != null) {
var biomeRegistry = Minecraft.getInstance().level.registryAccess().lookupOrThrow(Registries.BIOME); var biomeRegistry = Minecraft.getInstance().level.registryAccess().lookupOrThrow(Registries.BIOME);
var res = this.addBiome0(biomeEntry.id, biomeRegistry.getValue(ResourceLocation.parse(biomeEntry.biome))); var res = this.addBiome0(biomeEntry.id, biomeRegistry.getValue(Identifier.parse(biomeEntry.biome)));
if (res != null) { if (res != null) {
this.uploadResults.add(res); this.uploadResults.add(res);
} }
@@ -324,7 +337,7 @@ public class ModelFactory {
} }
} }
private ModelBakeResultUpload processTextureBakeResult(int blockId, BlockState blockState, ColourDepthTextureData[] textureData) { private ModelBakeResultUpload processTextureBakeResult(int blockId, BlockState blockState, ColourDepthTextureData[] textureData, boolean isShaded) {
if (this.idMappings[blockId] != -1) { if (this.idMappings[blockId] != -1) {
//This should be impossible to reach as it means that multiple bakes for the same blockId happened and where inflight at the same time! //This should be impossible to reach as it means that multiple bakes for the same blockId happened and where inflight at the same time!
throw new IllegalStateException("Block id already added: " + blockId + " for state: " + blockState); throw new IllegalStateException("Block id already added: " + blockId + " for state: " + blockState);
@@ -357,8 +370,16 @@ public class ModelFactory {
} }
} }
var colourProvider = getColourProvider(blockState.getBlock());
boolean isBiomeColourDependent = false;
if (colourProvider != null) {
isBiomeColourDependent = isBiomeDependentColour(colourProvider, blockState);
}
ModelEntry entry;
{//Deduplicate same entries {//Deduplicate same entries
var entry = new ModelEntry(textureData, clientFluidStateId); entry = new ModelEntry(textureData, clientFluidStateId, isBiomeColourDependent||colourProvider==null?-1:captureColourConstant(colourProvider, blockState, DEFAULT_BIOME)|0xFF000000);
int possibleDuplicate = this.modelTexture2id.getInt(entry); int possibleDuplicate = this.modelTexture2id.getInt(entry);
if (possibleDuplicate != -1) {//Duplicate found if (possibleDuplicate != -1) {//Duplicate found
this.idMappings[blockId] = possibleDuplicate; this.idMappings[blockId] = possibleDuplicate;
@@ -400,7 +421,6 @@ public class ModelFactory {
int checkMode = blockRenderLayer==ChunkSectionLayer.SOLID?TextureUtils.WRITE_CHECK_STENCIL:TextureUtils.WRITE_CHECK_ALPHA; int checkMode = blockRenderLayer==ChunkSectionLayer.SOLID?TextureUtils.WRITE_CHECK_STENCIL:TextureUtils.WRITE_CHECK_ALPHA;
var colourProvider = getColourProvider(blockState.getBlock());
ModelBakeResultUpload uploadResult = new ModelBakeResultUpload(); ModelBakeResultUpload uploadResult = new ModelBakeResultUpload();
@@ -409,10 +429,7 @@ public class ModelFactory {
//TODO: implement; //TODO: implement;
// TODO: if it has a constant colour instead... idk why (apparently for things like spruce leaves)?? but premultiply the texture data by the constant colour // TODO: if it has a constant colour instead... idk why (apparently for things like spruce leaves)?? but premultiply the texture data by the constant colour
boolean isBiomeColourDependent = false;
if (colourProvider != null) {
isBiomeColourDependent = isBiomeDependentColour(colourProvider, blockState);
}
//If it contains fluid but isnt a fluid //If it contains fluid but isnt a fluid
if ((!isFluid) && (!blockState.getFluidState().isEmpty()) && clientFluidStateId != -1) { if ((!isFluid) && (!blockState.getFluidState().isEmpty()) && clientFluidStateId != -1) {
@@ -535,7 +552,7 @@ public class ModelFactory {
//Change the scale from 0->1 (ends inclusive) //Change the scale from 0->1 (ends inclusive)
// this is cursed also warning stuff at 63 (i.e half a pixel from the end will be clamped to the end) // this is cursed also warning stuff at 63 (i.e half a pixel from the end will be clamped to the end)
int enc = Math.round(offset*64); int enc = Math.round(offset*64);
faceModelData |= Math.min(enc,63)<<16; faceModelData |= Math.min(enc,62)<<16;
//Still have 11 bits free //Still have 11 bits free
//Stuff like fences are solid, however they have extra side piece that mean it needs to have discard on //Stuff like fences are solid, however they have extra side piece that mean it needs to have discard on
@@ -575,7 +592,10 @@ public class ModelFactory {
modelFlags |= colourProvider != null?1:0; modelFlags |= colourProvider != null?1:0;
modelFlags |= isBiomeColourDependent?2:0;//Basicly whether to use the next int as a colour or as a base index/id into a colour buffer for biome dependent colours modelFlags |= isBiomeColourDependent?2:0;//Basicly whether to use the next int as a colour or as a base index/id into a colour buffer for biome dependent colours
modelFlags |= blockRenderLayer == ChunkSectionLayer.TRANSLUCENT?4:0;//Is translucent modelFlags |= blockRenderLayer == ChunkSectionLayer.TRANSLUCENT?4:0;//Is translucent
modelFlags |= blockRenderLayer == ChunkSectionLayer.CUTOUT?0:8;//Dont use mipmaps (AND ALSO FKING SPECIFIES IF IT HAS AO, WHY??? GREAT QUESTION, TODO FIXE THIS)
//TODO: THIS
modelFlags |= isShaded?8:0;//model has AO and shade
//modelFlags |= blockRenderLayer == RenderLayer.getSolid()?0:1;// should discard alpha //modelFlags |= blockRenderLayer == RenderLayer.getSolid()?0:1;// should discard alpha
MemoryUtil.memPutInt(uploadPtr, modelFlags); uploadPtr += 4; MemoryUtil.memPutInt(uploadPtr, modelFlags); uploadPtr += 4;
@@ -585,7 +605,7 @@ public class ModelFactory {
if (colourProvider == null) { if (colourProvider == null) {
MemoryUtil.memPutInt(uploadPtr, -1);//Set the default to nothing so that its faster on the gpu MemoryUtil.memPutInt(uploadPtr, -1);//Set the default to nothing so that its faster on the gpu
} else if (!isBiomeColourDependent) { } else if (!isBiomeColourDependent) {
MemoryUtil.memPutInt(uploadPtr, captureColourConstant(colourProvider, blockState, DEFAULT_BIOME)|0xFF000000); MemoryUtil.memPutInt(uploadPtr, entry.tintingColour);
} else if (!this.biomes.isEmpty()) { } else if (!this.biomes.isEmpty()) {
//Populate the list of biomes for the model state //Populate the list of biomes for the model state
int biomeIndex = this.modelsRequiringBiomeColours.size() * this.biomes.size(); int biomeIndex = this.modelsRequiringBiomeColours.size() * this.biomes.size();

View File

@@ -2,6 +2,7 @@ package me.cortex.voxy.client.core.model.bakery;
import me.cortex.voxy.common.util.MemoryBuffer; import me.cortex.voxy.common.util.MemoryBuffer;
import net.minecraft.client.model.geom.builders.UVPair;
import net.minecraft.client.renderer.block.model.BakedQuad; import net.minecraft.client.renderer.block.model.BakedQuad;
import org.lwjgl.system.MemoryUtil; import org.lwjgl.system.MemoryUtil;
@@ -15,6 +16,8 @@ public final class ReuseVertexConsumer implements VertexConsumer {
private int count; private int count;
private int defaultMeta; private int defaultMeta;
public boolean anyShaded;
public ReuseVertexConsumer() { public ReuseVertexConsumer() {
this.reset(); this.reset();
} }
@@ -45,6 +48,11 @@ public final class ReuseVertexConsumer implements VertexConsumer {
return this; return this;
} }
@Override
public VertexConsumer setColor(int i) {
return this;
}
@Override @Override
public ReuseVertexConsumer setUv(float u, float v) { public ReuseVertexConsumer setUv(float u, float v) {
MemoryUtil.memPutFloat(this.ptr + 16, u); MemoryUtil.memPutFloat(this.ptr + 16, u);
@@ -67,17 +75,19 @@ public final class ReuseVertexConsumer implements VertexConsumer {
return this; return this;
} }
@Override
public VertexConsumer setLineWidth(float f) {
return null;
}
public ReuseVertexConsumer quad(BakedQuad quad, int metadata) { public ReuseVertexConsumer quad(BakedQuad quad, int metadata) {
this.anyShaded |= quad.shade();
this.ensureCanPut(); this.ensureCanPut();
int[] data = quad.vertices();
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
float x = Float.intBitsToFloat(data[i * 8]); var pos = quad.position(i);
float y = Float.intBitsToFloat(data[i * 8 + 1]); this.addVertex(pos.x(), pos.y(), pos.z());
float z = Float.intBitsToFloat(data[i * 8 + 2]); long puv = quad.packedUV(i);
this.addVertex(x,y,z); this.setUv(UVPair.unpackU(puv),UVPair.unpackV(puv));
float u = Float.intBitsToFloat(data[i * 8 + 4]);
float v = Float.intBitsToFloat(data[i * 8 + 5]);
this.setUv(u,v);
this.meta(metadata); this.meta(metadata);
} }
@@ -98,6 +108,7 @@ public final class ReuseVertexConsumer implements VertexConsumer {
} }
public ReuseVertexConsumer reset() { public ReuseVertexConsumer reset() {
this.anyShaded = false;
this.defaultMeta = 0;//RESET THE DEFAULT META this.defaultMeta = 0;//RESET THE DEFAULT META
this.count = 0; this.count = 0;
this.ptr = this.buffer.address - VERTEX_FORMAT_SIZE;//the thing is first time this gets incremented by FORMAT_STRIDE this.ptr = this.buffer.address - VERTEX_FORMAT_SIZE;//the thing is first time this gets incremented by FORMAT_STRIDE

View File

@@ -191,8 +191,9 @@ public class RenderDataFactory {
boolean a = ModelQueries.isTranslucent(metadata); boolean a = ModelQueries.isTranslucent(metadata);
boolean b = ModelQueries.isDoubleSided(metadata); boolean b = ModelQueries.isDoubleSided(metadata);
//Pre shift by 1 //Pre shift by 1
type = a|b?0:4; //type = a|b?0:4;
type |= b?2:0; //type |= b&!a?2:0;
type = a?0:(b?2:4);
} }
return type; return type;
} }

View File

@@ -39,6 +39,6 @@ bool modelIsTranslucent(BlockModel model) {
return ((model.flagsA)&4u) != 0; return ((model.flagsA)&4u) != 0;
} }
bool modelHasMipmaps(BlockModel model) { bool modelIsShaded(BlockModel model) {
return ((model.flagsA)&8u) != 0; return ((model.flagsA)&8u) != 0;
} }

View File

@@ -98,7 +98,7 @@ layout(binding = LIGHTING_SAMPLER_BINDING) uniform sampler2D lightSampler;
vec4 getLighting(uint index) { vec4 getLighting(uint index) {
int i2 = int(index); int i2 = int(index);
return texture(lightSampler, clamp((vec2((i2>>4)&0xF, i2&0xF))/16, vec2(8.0f/256), vec2(248.0f/256))); return texture(lightSampler, clamp((vec2((i2>>4)&0xF, i2&0xF))/15, vec2(8.0f/256), vec2(248.0f/256)));
} }
#endif #endif

View File

@@ -43,15 +43,15 @@ vec4 uint2vec4RGBA(uint colour) {
return vec4((uvec4(colour)>>uvec4(24,16,8,0))&uvec4(0xFF))/255.0; return vec4((uvec4(colour)>>uvec4(24,16,8,0))&uvec4(0xFF))/255.0;
} }
bool useMipmaps() { //bool useMipmaps() {
return (interData.x&2u)==0u; // return (interData.x&2u)==0u;
} //}
uint tintingState() { uint tintingState() {
return (interData.x>>2)&3u; return (interData.x>>2)&3u;
} }
bool useCutout() { bool useDiscard() {
return (interData.x&1u)==1u; return (interData.x&1u)==1u;
} }
@@ -129,14 +129,16 @@ void main() {
vec2 uv2 = modf(uv, tile)*(1.0/(vec2(3.0,2.0)*256.0)); vec2 uv2 = modf(uv, tile)*(1.0/(vec2(3.0,2.0)*256.0));
vec4 colour; vec4 colour;
vec2 texPos = uv2 + getBaseUV(); vec2 texPos = uv2 + getBaseUV();
if (useMipmaps()) { //This is deprecated, TODO: remove the non mip code path
//if (useMipmaps())
{
vec2 uvSmol = uv*(1.0/(vec2(3.0,2.0)*256.0)); vec2 uvSmol = uv*(1.0/(vec2(3.0,2.0)*256.0));
vec2 dx = dFdx(uvSmol);//vec2(lDx, dDx); vec2 dx = dFdx(uvSmol);//vec2(lDx, dDx);
vec2 dy = dFdy(uvSmol);//vec2(lDy, dDy); vec2 dy = dFdy(uvSmol);//vec2(lDy, dDy);
colour = textureGrad(blockModelAtlas, texPos, dx, dy); colour = textureGrad(blockModelAtlas, texPos, dx, dy);
} else { }// else {
colour = textureLod(blockModelAtlas, texPos, 0); // colour = textureLod(blockModelAtlas, texPos, 0);
} //}
//If we are in shaders and are a helper invocation, just exit, as it enables extra performance gains for small sized //If we are in shaders and are a helper invocation, just exit, as it enables extra performance gains for small sized
// fragments, we do this here after derivative computation // fragments, we do this here after derivative computation
@@ -162,7 +164,11 @@ void main() {
//Also, small quad is really fking over the mipping level somehow //Also, small quad is really fking over the mipping level somehow
if (useCutout() && (textureLod(blockModelAtlas, texPos, 0).a <= 0.1f)) { #ifndef TRANSLUCENT
if (useDiscard() && (textureLod(blockModelAtlas, texPos, 0).a <= 0.1f)) {
#else
if (textureLod(blockModelAtlas, texPos, 0).a == 0.0f) {
#endif
//This is stupidly stupidly bad for divergence //This is stupidly stupidly bad for divergence
//TODO: FIXME, basicly what this do is sample the exact pixel (no lod) for discarding, this stops mipmapping fucking it over //TODO: FIXME, basicly what this do is sample the exact pixel (no lod) for discarding, this stops mipmapping fucking it over
#ifndef DEBUG_RENDER #ifndef DEBUG_RENDER

View File

@@ -58,7 +58,8 @@ uint makeQuadFlags(uint faceData, uint modelId, ivec2 quadSize, const in BlockMo
flags |= uint(any(greaterThan(quadSize, ivec2(1)))) & faceHasAlphaCuttoutOverride(faceData); flags |= uint(any(greaterThan(quadSize, ivec2(1)))) & faceHasAlphaCuttoutOverride(faceData);
} }
flags |= uint(!modelHasMipmaps(model))<<1;//Not mipmaps //TODO: remove, there is no non mip code path anymore
//flags |= uint(!modelHasMipmaps(model))<<1;//Not mipmaps
flags |= faceTintState(faceData)<<2; flags |= faceTintState(faceData)<<2;
flags |= face<<4;//Face flags |= face<<4;//Face
@@ -71,6 +72,11 @@ uint packVec4(vec4 vec) {
return vec_.x|vec_.y|vec_.z|vec_.w; return vec_.x|vec_.y|vec_.z|vec_.w;
} }
#ifndef PATCHED_SHADER
float computeDirectionalFaceTint(bool isShaded, uint face);
#endif
uvec3 makeRemainingAttributes(const in BlockModel model, const in Quad quad, uint lodLevel, uint face) { uvec3 makeRemainingAttributes(const in BlockModel model, const in Quad quad, uint lodLevel, uint face) {
uvec3 attributes = uvec3(0); uvec3 attributes = uvec3(0);
@@ -88,8 +94,10 @@ uvec3 makeRemainingAttributes(const in BlockModel model, const in Quad quad, uin
attributes.y = tintColour; attributes.y = tintColour;
#else #else
bool isTranslucent = modelIsTranslucent(model); bool isTranslucent = modelIsTranslucent(model);
bool hasAO = modelHasMipmaps(model);//TODO: replace with per face AO flag
bool isShaded = hasAO;//TODO: make this a per face flag //afak, these are the same variable in vanilla, (i.e. shaded == ao)
bool isShaded = modelIsShaded(model);
bool hasAO = isShaded;
vec4 tinting = getLighting(lighting); vec4 tinting = getLighting(lighting);
@@ -203,3 +211,4 @@ float computeDirectionalFaceTint(bool isShaded, uint face) {
#endif #endif
return 1.0f; return 1.0f;
} }
#endif