fix blueprint lighting
This commit is contained in:
@@ -6,7 +6,7 @@ minecraft_version=1.20.1
|
|||||||
yarn_mappings=1.20.1+build.10
|
yarn_mappings=1.20.1+build.10
|
||||||
loader_version=0.18.3
|
loader_version=0.18.3
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
mod_version=26.3.25.1
|
mod_version=26.3.25.2
|
||||||
maven_group=dev.tggamesyt
|
maven_group=dev.tggamesyt
|
||||||
archives_base_name=szar
|
archives_base_name=szar
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
|||||||
@@ -4,10 +4,13 @@ import dev.tggamesyt.szar.BlueprintBlockEntity;
|
|||||||
import net.minecraft.block.BlockRenderType;
|
import net.minecraft.block.BlockRenderType;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.client.MinecraftClient;
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.render.LightmapTextureManager;
|
||||||
import net.minecraft.client.render.VertexConsumerProvider;
|
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.BlockRenderManager;
|
||||||
import net.minecraft.client.render.block.entity.BlockEntityRenderer;
|
import net.minecraft.client.render.block.entity.BlockEntityRenderer;
|
||||||
import net.minecraft.client.render.block.entity.BlockEntityRendererFactory;
|
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.client.util.math.MatrixStack;
|
||||||
import net.minecraft.registry.Registries;
|
import net.minecraft.registry.Registries;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
@@ -21,6 +24,7 @@ public class BlueprintBlockEntityRenderer implements BlockEntityRenderer<Bluepri
|
|||||||
@Override
|
@Override
|
||||||
public void render(BlueprintBlockEntity entity, float tickDelta, MatrixStack matrices,
|
public void render(BlueprintBlockEntity entity, float tickDelta, MatrixStack matrices,
|
||||||
VertexConsumerProvider vertexConsumers, int light, int overlay) {
|
VertexConsumerProvider vertexConsumers, int light, int overlay) {
|
||||||
|
|
||||||
if (!entity.hasStoredBlock()) return;
|
if (!entity.hasStoredBlock()) return;
|
||||||
|
|
||||||
String storedId = entity.getStoredBlockId();
|
String storedId = entity.getStoredBlockId();
|
||||||
@@ -33,93 +37,37 @@ public class BlueprintBlockEntityRenderer implements BlockEntityRenderer<Bluepri
|
|||||||
if (storedState.getRenderType() == BlockRenderType.INVISIBLE) return;
|
if (storedState.getRenderType() == BlockRenderType.INVISIBLE) return;
|
||||||
|
|
||||||
BlockState blueprintState = entity.getCachedState();
|
BlockState blueprintState = entity.getCachedState();
|
||||||
BlockRenderManager renderer = MinecraftClient.getInstance().getBlockRenderManager();
|
|
||||||
|
var renderer = MinecraftClient.getInstance().getBlockRenderManager();
|
||||||
|
|
||||||
var storedModel = renderer.getModel(storedState);
|
var storedModel = renderer.getModel(storedState);
|
||||||
var blueprintModel = renderer.getModel(blueprintState);
|
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 layer = net.minecraft.client.render.RenderLayers.getBlockLayer(storedState);
|
||||||
var consumer = vertexConsumers.getBuffer(layer);
|
var consumer = vertexConsumers.getBuffer(layer);
|
||||||
|
|
||||||
matrices.push();
|
matrices.push();
|
||||||
// No scaling here anymore
|
|
||||||
|
|
||||||
for (var direction : new net.minecraft.util.math.Direction[]{
|
renderer.getModelRenderer().render(
|
||||||
null,
|
entity.getWorld(),
|
||||||
net.minecraft.util.math.Direction.UP,
|
wrappedModel,
|
||||||
net.minecraft.util.math.Direction.DOWN,
|
storedState,
|
||||||
net.minecraft.util.math.Direction.NORTH,
|
entity.getPos(),
|
||||||
net.minecraft.util.math.Direction.SOUTH,
|
matrices,
|
||||||
net.minecraft.util.math.Direction.EAST,
|
consumer,
|
||||||
net.minecraft.util.math.Direction.WEST
|
false,
|
||||||
}) {
|
net.minecraft.util.math.random.Random.create(),
|
||||||
random.setSeed(42L);
|
42L,
|
||||||
var quads = blueprintModel.getQuads(blueprintState, direction, random);
|
overlay
|
||||||
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
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
matrices.pop();
|
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 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 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/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