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.registries.BuiltInRegistries;
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.ColorResolver;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.Biomes;
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.LiquidBlock;
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
// the fluid state in the mipper
private record ModelEntry(ColourDepthTextureData down, ColourDepthTextureData up, ColourDepthTextureData north, ColourDepthTextureData south, ColourDepthTextureData west, ColourDepthTextureData east, int fluidBlockStateId) {
public ModelEntry(ColourDepthTextureData[] textures, int fluidBlockStateId) {
this(textures[0], textures[1], textures[2], textures[3], textures[4], textures[5], 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, int tintingColour) {
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;
}
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) {
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);
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;
}
@@ -232,7 +245,7 @@ public class ModelFactory {
}
}
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) {
this.uploadResults.add(bakeResult);
}
@@ -248,7 +261,7 @@ public class ModelFactory {
var biomeEntry = this.biomeQueue.poll();
while (biomeEntry != null) {
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) {
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) {
//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);
@@ -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
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);
if (possibleDuplicate != -1) {//Duplicate found
this.idMappings[blockId] = possibleDuplicate;
@@ -400,7 +421,6 @@ public class ModelFactory {
int checkMode = blockRenderLayer==ChunkSectionLayer.SOLID?TextureUtils.WRITE_CHECK_STENCIL:TextureUtils.WRITE_CHECK_ALPHA;
var colourProvider = getColourProvider(blockState.getBlock());
ModelBakeResultUpload uploadResult = new ModelBakeResultUpload();
@@ -409,10 +429,7 @@ public class ModelFactory {
//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
boolean isBiomeColourDependent = false;
if (colourProvider != null) {
isBiomeColourDependent = isBiomeDependentColour(colourProvider, blockState);
}
//If it contains fluid but isnt a fluid
if ((!isFluid) && (!blockState.getFluidState().isEmpty()) && clientFluidStateId != -1) {
@@ -535,7 +552,7 @@ public class ModelFactory {
//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)
int enc = Math.round(offset*64);
faceModelData |= Math.min(enc,63)<<16;
faceModelData |= Math.min(enc,62)<<16;
//Still have 11 bits free
//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 |= 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.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
MemoryUtil.memPutInt(uploadPtr, modelFlags); uploadPtr += 4;
@@ -585,7 +605,7 @@ public class ModelFactory {
if (colourProvider == null) {
MemoryUtil.memPutInt(uploadPtr, -1);//Set the default to nothing so that its faster on the gpu
} else if (!isBiomeColourDependent) {
MemoryUtil.memPutInt(uploadPtr, captureColourConstant(colourProvider, blockState, DEFAULT_BIOME)|0xFF000000);
MemoryUtil.memPutInt(uploadPtr, entry.tintingColour);
} else if (!this.biomes.isEmpty()) {
//Populate the list of biomes for the model state
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 net.minecraft.client.model.geom.builders.UVPair;
import net.minecraft.client.renderer.block.model.BakedQuad;
import org.lwjgl.system.MemoryUtil;
@@ -15,6 +16,8 @@ public final class ReuseVertexConsumer implements VertexConsumer {
private int count;
private int defaultMeta;
public boolean anyShaded;
public ReuseVertexConsumer() {
this.reset();
}
@@ -45,6 +48,11 @@ public final class ReuseVertexConsumer implements VertexConsumer {
return this;
}
@Override
public VertexConsumer setColor(int i) {
return this;
}
@Override
public ReuseVertexConsumer setUv(float u, float v) {
MemoryUtil.memPutFloat(this.ptr + 16, u);
@@ -67,17 +75,19 @@ public final class ReuseVertexConsumer implements VertexConsumer {
return this;
}
@Override
public VertexConsumer setLineWidth(float f) {
return null;
}
public ReuseVertexConsumer quad(BakedQuad quad, int metadata) {
this.anyShaded |= quad.shade();
this.ensureCanPut();
int[] data = quad.vertices();
for (int i = 0; i < 4; i++) {
float x = Float.intBitsToFloat(data[i * 8]);
float y = Float.intBitsToFloat(data[i * 8 + 1]);
float z = Float.intBitsToFloat(data[i * 8 + 2]);
this.addVertex(x,y,z);
float u = Float.intBitsToFloat(data[i * 8 + 4]);
float v = Float.intBitsToFloat(data[i * 8 + 5]);
this.setUv(u,v);
var pos = quad.position(i);
this.addVertex(pos.x(), pos.y(), pos.z());
long puv = quad.packedUV(i);
this.setUv(UVPair.unpackU(puv),UVPair.unpackV(puv));
this.meta(metadata);
}
@@ -98,6 +108,7 @@ public final class ReuseVertexConsumer implements VertexConsumer {
}
public ReuseVertexConsumer reset() {
this.anyShaded = false;
this.defaultMeta = 0;//RESET THE DEFAULT META
this.count = 0;
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 b = ModelQueries.isDoubleSided(metadata);
//Pre shift by 1
type = a|b?0:4;
type |= b?2:0;
//type = a|b?0:4;
//type |= b&!a?2:0;
type = a?0:(b?2:4);
}
return type;
}

View File

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

View File

@@ -98,7 +98,7 @@ layout(binding = LIGHTING_SAMPLER_BINDING) uniform sampler2D lightSampler;
vec4 getLighting(uint 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

View File

@@ -43,15 +43,15 @@ vec4 uint2vec4RGBA(uint colour) {
return vec4((uvec4(colour)>>uvec4(24,16,8,0))&uvec4(0xFF))/255.0;
}
bool useMipmaps() {
return (interData.x&2u)==0u;
}
//bool useMipmaps() {
// return (interData.x&2u)==0u;
//}
uint tintingState() {
return (interData.x>>2)&3u;
}
bool useCutout() {
bool useDiscard() {
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));
vec4 colour;
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 dx = dFdx(uvSmol);//vec2(lDx, dDx);
vec2 dy = dFdy(uvSmol);//vec2(lDy, dDy);
colour = textureGrad(blockModelAtlas, texPos, dx, dy);
} else {
colour = textureLod(blockModelAtlas, texPos, 0);
}
}// else {
// 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
// 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
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
//TODO: FIXME, basicly what this do is sample the exact pixel (no lod) for discarding, this stops mipmapping fucking it over
#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(!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 |= face<<4;//Face
@@ -71,6 +72,11 @@ uint packVec4(vec4 vec) {
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 attributes = uvec3(0);
@@ -88,8 +94,10 @@ uvec3 makeRemainingAttributes(const in BlockModel model, const in Quad quad, uin
attributes.y = tintColour;
#else
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);
@@ -203,3 +211,4 @@ float computeDirectionalFaceTint(bool isShaded, uint face) {
#endif
return 1.0f;
}
#endif