fix blueprint lighting
This commit is contained in:
@@ -6,7 +6,7 @@ minecraft_version=1.20.1
|
||||
yarn_mappings=1.20.1+build.10
|
||||
loader_version=0.18.3
|
||||
# Mod Properties
|
||||
mod_version=26.3.25.1
|
||||
mod_version=26.3.25.2
|
||||
maven_group=dev.tggamesyt
|
||||
archives_base_name=szar
|
||||
# Dependencies
|
||||
|
||||
@@ -4,10 +4,13 @@ import dev.tggamesyt.szar.BlueprintBlockEntity;
|
||||
import net.minecraft.block.BlockRenderType;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.render.LightmapTextureManager;
|
||||
import net.minecraft.client.render.VertexConsumerProvider;
|
||||
import net.minecraft.client.render.WorldRenderer;
|
||||
import net.minecraft.client.render.block.BlockRenderManager;
|
||||
import net.minecraft.client.render.block.entity.BlockEntityRenderer;
|
||||
import net.minecraft.client.render.block.entity.BlockEntityRendererFactory;
|
||||
import net.minecraft.client.render.model.BakedQuad;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.registry.Registries;
|
||||
import net.minecraft.util.Identifier;
|
||||
@@ -21,6 +24,7 @@ public class BlueprintBlockEntityRenderer implements BlockEntityRenderer<Bluepri
|
||||
@Override
|
||||
public void render(BlueprintBlockEntity entity, float tickDelta, MatrixStack matrices,
|
||||
VertexConsumerProvider vertexConsumers, int light, int overlay) {
|
||||
|
||||
if (!entity.hasStoredBlock()) return;
|
||||
|
||||
String storedId = entity.getStoredBlockId();
|
||||
@@ -33,93 +37,37 @@ public class BlueprintBlockEntityRenderer implements BlockEntityRenderer<Bluepri
|
||||
if (storedState.getRenderType() == BlockRenderType.INVISIBLE) return;
|
||||
|
||||
BlockState blueprintState = entity.getCachedState();
|
||||
BlockRenderManager renderer = MinecraftClient.getInstance().getBlockRenderManager();
|
||||
|
||||
var renderer = MinecraftClient.getInstance().getBlockRenderManager();
|
||||
|
||||
var storedModel = renderer.getModel(storedState);
|
||||
var blueprintModel = renderer.getModel(blueprintState);
|
||||
var particleSprite = storedModel.getParticleSprite();
|
||||
|
||||
var random = Random.create();
|
||||
var wrappedModel = new BlueprintWrappedModel(
|
||||
blueprintModel,
|
||||
storedModel,
|
||||
blueprintState,
|
||||
storedState, entity
|
||||
);
|
||||
|
||||
var layer = net.minecraft.client.render.RenderLayers.getBlockLayer(storedState);
|
||||
var consumer = vertexConsumers.getBuffer(layer);
|
||||
|
||||
matrices.push();
|
||||
// No scaling here anymore
|
||||
|
||||
for (var direction : new net.minecraft.util.math.Direction[]{
|
||||
null,
|
||||
net.minecraft.util.math.Direction.UP,
|
||||
net.minecraft.util.math.Direction.DOWN,
|
||||
net.minecraft.util.math.Direction.NORTH,
|
||||
net.minecraft.util.math.Direction.SOUTH,
|
||||
net.minecraft.util.math.Direction.EAST,
|
||||
net.minecraft.util.math.Direction.WEST
|
||||
}) {
|
||||
random.setSeed(42L);
|
||||
var quads = blueprintModel.getQuads(blueprintState, direction, random);
|
||||
for (var quad : quads) {
|
||||
int[] vertexData = quad.getVertexData().clone();
|
||||
remapUVs(vertexData, quad.getSprite(), particleSprite);
|
||||
offsetVertsAlongNormal(vertexData, quad.getFace(), 0.001f);
|
||||
|
||||
consumer.quad(
|
||||
matrices.peek(),
|
||||
new net.minecraft.client.render.model.BakedQuad(
|
||||
vertexData,
|
||||
quad.getColorIndex(),
|
||||
quad.getFace(),
|
||||
particleSprite,
|
||||
quad.hasShade()
|
||||
),
|
||||
1f, 1f, 1f, light, overlay
|
||||
);
|
||||
}
|
||||
}
|
||||
renderer.getModelRenderer().render(
|
||||
entity.getWorld(),
|
||||
wrappedModel,
|
||||
storedState,
|
||||
entity.getPos(),
|
||||
matrices,
|
||||
consumer,
|
||||
false,
|
||||
net.minecraft.util.math.random.Random.create(),
|
||||
42L,
|
||||
overlay
|
||||
);
|
||||
|
||||
matrices.pop();
|
||||
|
||||
}
|
||||
|
||||
private void remapUVs(int[] vertexData,
|
||||
net.minecraft.client.texture.Sprite fromSprite,
|
||||
net.minecraft.client.texture.Sprite toSprite) {
|
||||
// Vertex format: X, Y, Z, COLOR, U, V, UV2, NORMAL — each vertex is 8 ints
|
||||
int vertexSize = 8;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int uvOffset = i * vertexSize + 4;
|
||||
// Unpack UV floats from int bits
|
||||
float u = Float.intBitsToFloat(vertexData[uvOffset]);
|
||||
float v = Float.intBitsToFloat(vertexData[uvOffset + 1]);
|
||||
|
||||
// Normalize UV from the source sprite's atlas space to 0-1
|
||||
float normalizedU = (u - fromSprite.getMinU()) / (fromSprite.getMaxU() - fromSprite.getMinU());
|
||||
float normalizedV = (v - fromSprite.getMinV()) / (fromSprite.getMaxV() - fromSprite.getMinV());
|
||||
|
||||
// Remap to target sprite's atlas space
|
||||
float newU = toSprite.getMinU() + normalizedU * (toSprite.getMaxU() - toSprite.getMinU());
|
||||
float newV = toSprite.getMinV() + normalizedV * (toSprite.getMaxV() - toSprite.getMinV());
|
||||
|
||||
vertexData[uvOffset] = Float.floatToRawIntBits(newU);
|
||||
vertexData[uvOffset + 1] = Float.floatToRawIntBits(newV);
|
||||
}
|
||||
}
|
||||
|
||||
private void offsetVertsAlongNormal(int[] vertexData, net.minecraft.util.math.Direction face, float amount) {
|
||||
float dx = face.getOffsetX() * amount;
|
||||
float dy = face.getOffsetY() * amount;
|
||||
float dz = face.getOffsetZ() * amount;
|
||||
|
||||
int vertexSize = 8;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int base = i * vertexSize;
|
||||
float x = Float.intBitsToFloat(vertexData[base]);
|
||||
float y = Float.intBitsToFloat(vertexData[base + 1]);
|
||||
float z = Float.intBitsToFloat(vertexData[base + 2]);
|
||||
|
||||
vertexData[base] = Float.floatToRawIntBits(x + dx);
|
||||
vertexData[base + 1] = Float.floatToRawIntBits(y + dy);
|
||||
vertexData[base + 2] = Float.floatToRawIntBits(z + dz);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
package dev.tggamesyt.szar.client;
|
||||
|
||||
import dev.tggamesyt.szar.BlueprintBlockEntity;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.render.Camera;
|
||||
import net.minecraft.client.render.model.BakedModel;
|
||||
import net.minecraft.client.render.model.BakedQuad;
|
||||
import net.minecraft.client.render.model.json.ModelOverrideList;
|
||||
import net.minecraft.client.render.model.json.ModelTransformation;
|
||||
import net.minecraft.client.texture.Sprite;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Direction;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.math.random.Random;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class BlueprintWrappedModel implements BakedModel {
|
||||
|
||||
private final BakedModel blueprint;
|
||||
private final BakedModel stored;
|
||||
private final BlockState blueprintState;
|
||||
private final BlockState storedState;
|
||||
private final BlueprintBlockEntity entity;
|
||||
|
||||
public BlueprintWrappedModel(BakedModel blueprint, BakedModel stored,
|
||||
BlockState blueprintState, BlockState storedState, BlueprintBlockEntity entity) {
|
||||
this.blueprint = blueprint;
|
||||
this.stored = stored;
|
||||
this.blueprintState = blueprintState;
|
||||
this.storedState = storedState;
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads(BlockState state, Direction face, Random random) {
|
||||
List<BakedQuad> original = blueprint.getQuads(blueprintState, face, random);
|
||||
List<BakedQuad> result = new ArrayList<>(original.size());
|
||||
|
||||
for (BakedQuad quad : original) {
|
||||
int[] data = quad.getVertexData().clone();
|
||||
|
||||
Direction quadFace = quad.getFace();
|
||||
Sprite target = getSpriteForFace(stored, storedState, quadFace);
|
||||
|
||||
remapUVs(data, quad.getSprite(), target);
|
||||
|
||||
BlockPos pos = entity.getPos();
|
||||
Camera camera = MinecraftClient.getInstance().gameRenderer.getCamera();
|
||||
Vec3d camPos = camera.getPos();
|
||||
double dx = pos.getX() + 0.5 - camPos.x;
|
||||
double dy = pos.getY() + 0.5 - camPos.y;
|
||||
double dz = pos.getZ() + 0.5 - camPos.z;
|
||||
double distance = Math.sqrt(dx*dx + dy*dy + dz*dz);
|
||||
float offsetAmount = 0.0001f + (float)distance * 1e-5f;
|
||||
offsetAmount = Math.min(offsetAmount, 0.001f); // clamp max
|
||||
offsetVertsAlongNormal(data, quad.getFace(), offsetAmount);
|
||||
|
||||
result.add(new BakedQuad(
|
||||
data,
|
||||
quad.getColorIndex(),
|
||||
quadFace,
|
||||
target,
|
||||
quad.hasShade()
|
||||
));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// --- IMPORTANT: delegate everything else properly ---
|
||||
|
||||
@Override
|
||||
public boolean useAmbientOcclusion() {
|
||||
return stored.useAmbientOcclusion(); // important for lighting
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDepth() {
|
||||
return stored.hasDepth();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSideLit() {
|
||||
return stored.isSideLit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBuiltin() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Sprite getParticleSprite() {
|
||||
return stored.getParticleSprite();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelTransformation getTransformation() {
|
||||
return stored.getTransformation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelOverrideList getOverrides() {
|
||||
return stored.getOverrides();
|
||||
}
|
||||
|
||||
// --- helpers ---
|
||||
|
||||
private Sprite getSpriteForFace(BakedModel model, BlockState state, Direction face) {
|
||||
Random rand = Random.create(42L);
|
||||
|
||||
List<BakedQuad> quads = model.getQuads(state, face, rand);
|
||||
if (!quads.isEmpty()) return quads.get(0).getSprite();
|
||||
|
||||
quads = model.getQuads(state, null, rand);
|
||||
for (BakedQuad q : quads) {
|
||||
if (q.getFace() == face) return q.getSprite();
|
||||
}
|
||||
|
||||
return model.getParticleSprite();
|
||||
}
|
||||
|
||||
private void remapUVs(int[] vertexData, Sprite from, Sprite to) {
|
||||
int stride = 8;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int uvIndex = i * stride + 4;
|
||||
|
||||
float u = Float.intBitsToFloat(vertexData[uvIndex]);
|
||||
float v = Float.intBitsToFloat(vertexData[uvIndex + 1]);
|
||||
|
||||
float nu = (u - from.getMinU()) / (from.getMaxU() - from.getMinU());
|
||||
float nv = (v - from.getMinV()) / (from.getMaxV() - from.getMinV());
|
||||
|
||||
float newU = to.getMinU() + nu * (to.getMaxU() - to.getMinU());
|
||||
float newV = to.getMinV() + nv * (to.getMaxV() - to.getMinV());
|
||||
|
||||
vertexData[uvIndex] = Float.floatToRawIntBits(newU);
|
||||
vertexData[uvIndex + 1] = Float.floatToRawIntBits(newV);
|
||||
}
|
||||
}
|
||||
|
||||
private void offsetVertsAlongNormal(int[] vertexData, Direction face, float amount) {
|
||||
if (face == null) return; // skip general quads
|
||||
|
||||
float dx = face.getOffsetX() * amount;
|
||||
float dy = face.getOffsetY() * amount;
|
||||
float dz = face.getOffsetZ() * amount;
|
||||
|
||||
int vertexSize = 8; // X,Y,Z,COLOR,U,V,UV2,NORMAL
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int base = i * vertexSize;
|
||||
float x = Float.intBitsToFloat(vertexData[base]);
|
||||
float y = Float.intBitsToFloat(vertexData[base + 1]);
|
||||
float z = Float.intBitsToFloat(vertexData[base + 2]);
|
||||
|
||||
vertexData[base] = Float.floatToRawIntBits(x + dx);
|
||||
vertexData[base + 1] = Float.floatToRawIntBits(y + dy);
|
||||
vertexData[base + 2] = Float.floatToRawIntBits(z + dz);
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 873 B After Width: | Height: | Size: 880 B |
@@ -7,3 +7,4 @@ accessible field net/minecraft/server/network/ServerPlayerInteractionManager pla
|
||||
accessible method net/minecraft/client/render/entity/LivingEntityRenderer addFeature (Lnet/minecraft/client/render/entity/feature/FeatureRenderer;)Z
|
||||
accessible field net/minecraft/client/render/entity/EntityRenderDispatcher renderers Ljava/util/Map;
|
||||
accessible method net/minecraft/world/GameRules$BooleanRule create (ZLjava/util/function/BiConsumer;)Lnet/minecraft/world/GameRules$Type;
|
||||
accessible method net/minecraft/client/render/block/BlockModelRenderer renderQuad (Lnet/minecraft/world/BlockRenderView;Lnet/minecraft/block/BlockState;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/client/render/VertexConsumer;Lnet/minecraft/client/util/math/MatrixStack$Entry;Lnet/minecraft/client/render/model/BakedQuad;FFFFIIIII)V
|
||||
Reference in New Issue
Block a user