Stacks of Cache

- Instancing support for bezier girders
- Transformation matrices for bezier segments are only calculated once
This commit is contained in:
simibubi 2022-02-08 18:18:16 +01:00
parent 051e7ffc1f
commit 26d6a7b3e4
5 changed files with 390 additions and 234 deletions

View file

@ -3,7 +3,11 @@ package com.simibubi.create.content.logistics.trains;
import java.util.Iterator; import java.util.Iterator;
import com.jozufozu.flywheel.repack.joml.Math; import com.jozufozu.flywheel.repack.joml.Math;
import com.jozufozu.flywheel.util.transform.MatrixTransformStack;
import com.mojang.math.Matrix4f;
import com.simibubi.create.content.logistics.trains.track.TrackRenderer;
import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@ -14,6 +18,8 @@ import net.minecraft.nbt.Tag;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
public class BezierConnection implements Iterable<BezierConnection.Segment> { public class BezierConnection implements Iterable<BezierConnection.Segment> {
@ -264,17 +270,19 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
public Iterator<Segment> iterator() { public Iterator<Segment> iterator() {
resolve(); resolve();
var offset = Vec3.atLowerCornerOf(tePositions.getFirst()) var offset = Vec3.atLowerCornerOf(tePositions.getFirst())
.scale(-1) .scale(-1)
.add(0, 3 / 16f, 0); .add(0, 3 / 16f, 0);
return new Bezierator(this, offset); return new Bezierator(this, offset);
} }
public static class Segment { public static class Segment {
public int index; public int index;
public Vec3 position; public Vec3 position;
public Vec3 derivative; public Vec3 derivative;
public Vec3 faceNormal; public Vec3 faceNormal;
public Vec3 normal; public Vec3 normal;
} }
private static class Bezierator implements Iterator<Segment> { private static class Bezierator implements Iterator<Segment> {
@ -293,16 +301,16 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
this.bc = bc; this.bc = bc;
end1 = bc.starts.getFirst() end1 = bc.starts.getFirst()
.add(offset); .add(offset);
end2 = bc.starts.getSecond() end2 = bc.starts.getSecond()
.add(offset); .add(offset);
finish1 = bc.axes.getFirst() finish1 = bc.axes.getFirst()
.scale(bc.handleLength) .scale(bc.handleLength)
.add(end1); .add(end1);
finish2 = bc.axes.getSecond() finish2 = bc.axes.getSecond()
.scale(bc.handleLength) .scale(bc.handleLength)
.add(end2); .add(end2);
faceNormal1 = bc.normals.getFirst(); faceNormal1 = bc.normals.getFirst();
faceNormal2 = bc.normals.getSecond(); faceNormal2 = bc.normals.getSecond();
@ -321,12 +329,203 @@ public class BezierConnection implements Iterable<BezierConnection.Segment> {
float t = this.bc.getSegmentT(segment.index); float t = this.bc.getSegmentT(segment.index);
segment.position = VecHelper.bezier(end1, end2, finish1, finish2, t); segment.position = VecHelper.bezier(end1, end2, finish1, finish2, t);
segment.derivative = VecHelper.bezierDerivative(end1, end2, finish1, finish2, t) segment.derivative = VecHelper.bezierDerivative(end1, end2, finish1, finish2, t)
.normalize(); .normalize();
segment.faceNormal = faceNormal1.equals(faceNormal2) ? faceNormal1 : VecHelper.slerp(t, faceNormal1, faceNormal2); segment.faceNormal =
faceNormal1.equals(faceNormal2) ? faceNormal1 : VecHelper.slerp(t, faceNormal1, faceNormal2);
segment.normal = segment.faceNormal.cross(segment.derivative) segment.normal = segment.faceNormal.cross(segment.derivative)
.normalize(); .normalize();
return segment; return segment;
} }
} }
private SegmentAngles[] bakedSegments;
private GirderAngles[] bakedGirders;
@OnlyIn(Dist.CLIENT)
public static class SegmentAngles {
public Matrix4f tieTransform;
public Couple<Matrix4f> railTransforms;
public BlockPos lightPosition;
}
@OnlyIn(Dist.CLIENT)
public static class GirderAngles {
public Couple<Matrix4f> beams;
public Couple<Couple<Matrix4f>> beamCaps;
public BlockPos lightPosition;
}
@OnlyIn(Dist.CLIENT)
public SegmentAngles[] getBakedSegments() {
if (bakedSegments != null)
return bakedSegments;
int segmentCount = getSegmentCount();
bakedSegments = new SegmentAngles[segmentCount + 1];
Couple<Vec3> previousOffsets = null;
for (BezierConnection.Segment segment : this) {
int i = segment.index;
boolean end = i == 0 || i == segmentCount;
SegmentAngles angles = bakedSegments[i] = new SegmentAngles();
Couple<Vec3> railOffsets = Couple.create(segment.position.add(segment.normal.scale(.965f)),
segment.position.subtract(segment.normal.scale(.965f)));
Vec3 railMiddle = railOffsets.getFirst()
.add(railOffsets.getSecond())
.scale(.5);
if (previousOffsets == null) {
previousOffsets = railOffsets;
continue;
}
// Tie
Vec3 prevMiddle = previousOffsets.getFirst()
.add(previousOffsets.getSecond())
.scale(.5);
Vec3 tieAngles = TrackRenderer.getModelAngles(segment.normal, railMiddle.subtract(prevMiddle));
angles.lightPosition = new BlockPos(railMiddle);
MatrixTransformStack mts = new MatrixTransformStack();
mts.translate(prevMiddle)
.rotateYRadians(tieAngles.y)
.rotateXRadians(tieAngles.x)
.rotateZRadians(tieAngles.z)
.translate(-1 / 2f, -2 / 16f - 1 / 256f, 0);
angles.tieTransform = mts.unwrap()
.last()
.pose();
angles.railTransforms = Couple.create(null, null);
// Rails
float scale = end ? 2.2f : 2.1f;
for (boolean first : Iterate.trueAndFalse) {
Vec3 railI = railOffsets.get(first);
Vec3 prevI = previousOffsets.get(first);
Vec3 diff = railI.subtract(prevI);
Vec3 anglesI = TrackRenderer.getModelAngles(segment.normal, diff);
mts = new MatrixTransformStack();
mts.translate(prevI)
.rotateYRadians(anglesI.y)
.rotateXRadians(anglesI.x)
.rotateZRadians(anglesI.z)
.translate(0, -2 / 16f + (i % 2 == 0 ? 1 : -1) / 2048f - 1 / 256f, -1 / 32f)
.scale(1, 1, (float) diff.length() * scale);
angles.railTransforms.set(first, mts.unwrap()
.last()
.pose());
}
previousOffsets = railOffsets;
}
return bakedSegments;
}
@OnlyIn(Dist.CLIENT)
public GirderAngles[] getBakedGirders() {
if (bakedGirders != null)
return bakedGirders;
int segmentCount = getSegmentCount();
bakedGirders = new GirderAngles[segmentCount + 1];
Couple<Couple<Vec3>> previousOffsets = null;
for (BezierConnection.Segment segment : this) {
int i = segment.index;
boolean end = i == 0 || i == segmentCount;
GirderAngles angles = bakedGirders[i] = new GirderAngles();
Vec3 leftGirder = segment.position.add(segment.normal.scale(.965f));
Vec3 rightGirder = segment.position.subtract(segment.normal.scale(.965f));
Vec3 upNormal = segment.derivative.normalize()
.cross(segment.normal);
Vec3 firstGirderOffset = upNormal.scale(-8 / 16f);
Vec3 secondGirderOffset = upNormal.scale(-10 / 16f);
Vec3 leftTop = segment.position.add(segment.normal.scale(1))
.add(firstGirderOffset);
Vec3 rightTop = segment.position.subtract(segment.normal.scale(1))
.add(firstGirderOffset);
Vec3 leftBottom = leftTop.add(secondGirderOffset);
Vec3 rightBottom = rightTop.add(secondGirderOffset);
angles.lightPosition = new BlockPos(leftGirder.add(rightGirder)
.scale(.5));
Couple<Couple<Vec3>> offsets =
Couple.create(Couple.create(leftTop, rightTop), Couple.create(leftBottom, rightBottom));
if (previousOffsets == null) {
previousOffsets = offsets;
continue;
}
angles.beams = Couple.create(null, null);
angles.beamCaps = Couple.create(Couple.create(null, null), Couple.create(null, null));
float scale = end ? 2.3f : 2.2f;
for (boolean first : Iterate.trueAndFalse) {
// Middle
Vec3 currentBeam = offsets.getFirst()
.get(first)
.add(offsets.getSecond()
.get(first))
.scale(.5);
Vec3 previousBeam = previousOffsets.getFirst()
.get(first)
.add(previousOffsets.getSecond()
.get(first))
.scale(.5);
Vec3 beamDiff = currentBeam.subtract(previousBeam);
Vec3 beamAngles = TrackRenderer.getModelAngles(segment.normal, beamDiff);
MatrixTransformStack mts = new MatrixTransformStack();
mts.translate(previousBeam)
.rotateYRadians(beamAngles.y)
.rotateXRadians(beamAngles.x)
.rotateZRadians(beamAngles.z)
.translate(0, 2 / 16f + (segment.index % 2 == 0 ? 1 : -1) / 2048f - 1 / 1024f, -1 / 32f)
.scale(1, 1, (float) beamDiff.length() * scale);
angles.beams.set(first, mts.unwrap()
.last()
.pose());
// Caps
for (boolean top : Iterate.trueAndFalse) {
Vec3 current = offsets.get(top)
.get(first);
Vec3 previous = previousOffsets.get(top)
.get(first);
Vec3 diff = current.subtract(previous);
Vec3 capAngles = TrackRenderer.getModelAngles(segment.normal, diff);
mts = new MatrixTransformStack();
mts.translate(previous)
.rotateYRadians(capAngles.y)
.rotateXRadians(capAngles.x)
.rotateZRadians(capAngles.z)
.translate(0, 2 / 16f + (segment.index % 2 == 0 ? 1 : -1) / 2048f - 1 / 1024f, -1 / 32f)
.rotateZ(top ? 0 : 0)
.scale(1, 1, (float) diff.length() * scale);
angles.beamCaps.get(top)
.set(first, mts.unwrap()
.last()
.pose());
}
}
previousOffsets = offsets;
}
return bakedGirders;
}
} }

View file

@ -19,15 +19,17 @@ import com.jozufozu.flywheel.util.transform.TransformStack;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.content.logistics.trains.BezierConnection; import com.simibubi.create.content.logistics.trains.BezierConnection;
import com.simibubi.create.content.logistics.trains.BezierConnection.GirderAngles;
import com.simibubi.create.content.logistics.trains.BezierConnection.SegmentAngles;
import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.world.phys.Vec3;
public class TrackInstance extends BlockEntityInstance<TrackTileEntity> { public class TrackInstance extends BlockEntityInstance<TrackTileEntity> {
private List<BezierInstance> instances; private List<BezierTrackInstance> instances;
public TrackInstance(MaterialManager materialManager, TrackTileEntity track) { public TrackInstance(MaterialManager materialManager, TrackTileEntity track) {
super(materialManager, track); super(materialManager, track);
@ -37,47 +39,52 @@ public class TrackInstance extends BlockEntityInstance<TrackTileEntity> {
@Override @Override
public void update() { public void update() {
if (blockEntity.connections.stream().allMatch(Map::isEmpty)) { if (blockEntity.connections.stream()
.allMatch(Map::isEmpty)) {
return; return;
} }
instances = blockEntity.connections.stream() instances = blockEntity.connections.stream()
.flatMap(FlwUtil::mapValues) .flatMap(FlwUtil::mapValues)
.map(this::createInstance) .map(this::createInstance)
.filter(Objects::nonNull) .filter(Objects::nonNull)
.toList(); .toList();
LightUpdater.get(world).addListener(this); LightUpdater.get(world)
.addListener(this);
} }
@Override @Override
public ImmutableBox getVolume() { public ImmutableBox getVolume() {
List<BlockPos> out = new ArrayList<>(); List<BlockPos> out = new ArrayList<>();
out.addAll(blockEntity.connections.getFirst() out.addAll(blockEntity.connections.getFirst()
.keySet()); .keySet());
out.addAll(blockEntity.connections.getSecond() out.addAll(blockEntity.connections.getSecond()
.keySet()); .keySet());
return GridAlignedBB.containingAll(out); return GridAlignedBB.containingAll(out);
} }
@Override @Override
public void updateLight() { public void updateLight() {
if (instances == null) return; if (instances == null)
instances.forEach(BezierInstance::updateLight); return;
instances.forEach(BezierTrackInstance::updateLight);
} }
@Nullable @Nullable
private BezierInstance createInstance(BezierConnection bc) { private BezierTrackInstance createInstance(BezierConnection bc) {
if (!bc.isPrimary()) return null; if (!bc.isPrimary())
return new BezierInstance(bc); return null;
return new BezierTrackInstance(bc);
} }
@Override @Override
public void remove() { public void remove() {
if (instances == null) return; if (instances == null)
instances.forEach(BezierInstance::delete); return;
instances.forEach(BezierTrackInstance::delete);
} }
private class BezierInstance { private class BezierTrackInstance {
private final ModelData[] ties; private final ModelData[] ties;
private final ModelData[] left; private final ModelData[] left;
@ -86,17 +93,20 @@ public class TrackInstance extends BlockEntityInstance<TrackTileEntity> {
private final BlockPos[] leftLightPos; private final BlockPos[] leftLightPos;
private final BlockPos[] rightLightPos; private final BlockPos[] rightLightPos;
private BezierInstance(BezierConnection bc) { private @Nullable GirderInstance girder;
private BezierTrackInstance(BezierConnection bc) {
BlockPos tePosition = bc.tePositions.getFirst(); BlockPos tePosition = bc.tePositions.getFirst();
girder = bc.hasGirder ? new GirderInstance(bc) : null;
PoseStack pose = new PoseStack(); PoseStack pose = new PoseStack();
TransformStack.cast(pose) TransformStack.cast(pose)
.translate(getInstancePosition()) .translate(getInstancePosition())
.nudge((int) bc.tePositions.getFirst() .nudge((int) bc.tePositions.getFirst()
.asLong()); .asLong());
var mat = materialManager.cutout(RenderType.cutoutMipped()) var mat = materialManager.cutout(RenderType.cutoutMipped())
.material(Materials.TRANSFORMED); .material(Materials.TRANSFORMED);
int segCount = bc.getSegmentCount(); int segCount = bc.getSegmentCount();
ties = new ModelData[segCount]; ties = new ModelData[segCount];
@ -107,82 +117,120 @@ public class TrackInstance extends BlockEntityInstance<TrackTileEntity> {
rightLightPos = new BlockPos[segCount]; rightLightPos = new BlockPos[segCount];
mat.getModel(AllBlockPartials.TRACK_TIE) mat.getModel(AllBlockPartials.TRACK_TIE)
.createInstances(ties); .createInstances(ties);
mat.getModel(AllBlockPartials.TRACK_SEGMENT_LEFT) mat.getModel(AllBlockPartials.TRACK_SEGMENT_LEFT)
.createInstances(left); .createInstances(left);
mat.getModel(AllBlockPartials.TRACK_SEGMENT_RIGHT) mat.getModel(AllBlockPartials.TRACK_SEGMENT_RIGHT)
.createInstances(right); .createInstances(right);
Vec3 leftPrevious = null; SegmentAngles[] segments = bc.getBakedSegments();
Vec3 rightPrevious = null; for (int i = 1; i < segments.length; i++) {
SegmentAngles segment = segments[i];
var modelIndex = i - 1;
for (BezierConnection.Segment segment : bc) { ties[modelIndex].setTransform(pose)
Vec3 left = segment.position.add(segment.normal.scale(.965f)); .mulPose(segment.tieTransform);
Vec3 right = segment.position.subtract(segment.normal.scale(.965f)); tiesLightPos[modelIndex] = segment.lightPosition.offset(tePosition);
if (leftPrevious != null) { for (boolean first : Iterate.trueAndFalse) {
var modelIndex = segment.index - 1; (first ? this.left : this.right)[modelIndex].setTransform(pose)
{ .mulPose(segment.railTransforms.get(first));
// Tie (first ? leftLightPos : rightLightPos)[modelIndex] = segment.lightPosition.offset(tePosition);
Vec3 railMiddle = left.add(right)
.scale(.5);
Vec3 prevMiddle = leftPrevious.add(rightPrevious)
.scale(.5);
var tie = ties[modelIndex].setTransform(pose);
Vec3 diff = railMiddle.subtract(prevMiddle);
Vec3 angles = TrackRenderer.getModelAngles(segment.normal, diff);
tie.translate(prevMiddle)
.rotateYRadians(angles.y)
.rotateXRadians(angles.x)
.rotateZRadians(angles.z)
.translate(-1 / 2f, -2 / 16f - 1 / 256f, 0);
tiesLightPos[modelIndex] = new BlockPos(railMiddle).offset(tePosition);
}
// Rails
for (boolean first : Iterate.trueAndFalse) {
Vec3 railI = first ? left : right;
Vec3 prevI = first ? leftPrevious : rightPrevious;
var rail = (first ? this.left : this.right)[modelIndex].setTransform(pose);
Vec3 diff = railI.subtract(prevI);
Vec3 angles = TrackRenderer.getModelAngles(segment.normal, diff);
rail.translate(prevI)
.rotateYRadians(angles.y)
.rotateXRadians(angles.x)
.rotateZRadians(angles.z)
.translate(0, -2 / 16f + (segment.index % 2 == 0 ? 1 : -1) / 2048f - 1 / 256f, 0)
.scale(1, 1, (float) diff.length() * 2.1f);
(first ? leftLightPos : rightLightPos)[modelIndex] = new BlockPos(prevI).offset(tePosition);
}
} }
leftPrevious = left;
rightPrevious = right;
} }
updateLight(); updateLight();
} }
void delete() { void delete() {
for (ModelData d : ties) d.delete(); for (ModelData d : ties)
for (ModelData d : left) d.delete(); d.delete();
for (ModelData d : right) d.delete(); for (ModelData d : left)
d.delete();
for (ModelData d : right)
d.delete();
if (girder != null)
girder.delete();
} }
void updateLight() { void updateLight() {
for (int i = 0; i < ties.length; i++) { for (int i = 0; i < ties.length; i++)
ties[i].updateLight(world, tiesLightPos[i]); ties[i].updateLight(world, tiesLightPos[i]);
} for (int i = 0; i < left.length; i++)
for (int i = 0; i < left.length; i++) {
left[i].updateLight(world, leftLightPos[i]); left[i].updateLight(world, leftLightPos[i]);
} for (int i = 0; i < right.length; i++)
for (int i = 0; i < right.length; i++) {
right[i].updateLight(world, rightLightPos[i]); right[i].updateLight(world, rightLightPos[i]);
} if (girder != null)
girder.updateLight();
} }
private class GirderInstance {
private final Couple<ModelData[]> beams;
private final Couple<Couple<ModelData[]>> beamCaps;
private final BlockPos[] lightPos;
private GirderInstance(BezierConnection bc) {
BlockPos tePosition = bc.tePositions.getFirst();
PoseStack pose = new PoseStack();
TransformStack.cast(pose)
.translate(getInstancePosition())
.nudge((int) bc.tePositions.getFirst()
.asLong());
var mat = materialManager.cutout(RenderType.cutoutMipped())
.material(Materials.TRANSFORMED);
int segCount = bc.getSegmentCount();
beams = Couple.create(() -> new ModelData[segCount]);
beamCaps = Couple.create(() -> Couple.create(() -> new ModelData[segCount]));
lightPos = new BlockPos[segCount];
beams.forEach(mat.getModel(AllBlockPartials.GIRDER_SEGMENT_2)::createInstances);
beamCaps.forEach(c -> c.forEach(mat.getModel(AllBlockPartials.GIRDER_SEGMENT)::createInstances));
GirderAngles[] bakedGirders = bc.getBakedGirders();
for (int i = 1; i < bakedGirders.length; i++) {
GirderAngles segment = bakedGirders[i];
var modelIndex = i - 1;
lightPos[modelIndex] = segment.lightPosition.offset(tePosition);
for (boolean first : Iterate.trueAndFalse) {
beams.get(first)[modelIndex].setTransform(pose)
.mulPose(segment.beams.get(first));
for (boolean top : Iterate.trueAndFalse)
beamCaps.get(top)
.get(first)[modelIndex].setTransform(pose)
.mulPose(segment.beamCaps.get(top)
.get(first));
}
}
updateLight();
}
void delete() {
beams.forEach(arr -> {
for (ModelData d : arr)
d.delete();
});
beamCaps.forEach(c -> c.forEach(arr -> {
for (ModelData d : arr)
d.delete();
}));
}
void updateLight() {
beams.forEach(arr -> {
for (int i = 0; i < arr.length; i++)
arr[i].updateLight(world, lightPos[i]);
});
beamCaps.forEach(c -> c.forEach(arr -> {
for (int i = 0; i < arr.length; i++)
arr[i].updateLight(world, lightPos[i]);
}));
}
}
} }
} }

View file

@ -1,20 +1,27 @@
package com.simibubi.create.content.logistics.trains.track; package com.simibubi.create.content.logistics.trains.track;
import static com.simibubi.create.AllBlockPartials.GIRDER_SEGMENT;
import static com.simibubi.create.AllBlockPartials.GIRDER_SEGMENT_2;
import static com.simibubi.create.AllBlockPartials.TRACK_SEGMENT_LEFT;
import static com.simibubi.create.AllBlockPartials.TRACK_SEGMENT_RIGHT;
import static com.simibubi.create.AllBlockPartials.TRACK_TIE;
import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.backend.Backend;
import com.jozufozu.flywheel.repack.joml.Math; import com.jozufozu.flywheel.repack.joml.Math;
import com.jozufozu.flywheel.util.transform.TransformStack; import com.jozufozu.flywheel.util.transform.TransformStack;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.blaze3d.vertex.VertexConsumer;
import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.content.logistics.trains.BezierConnection; import com.simibubi.create.content.logistics.trains.BezierConnection;
import com.simibubi.create.content.logistics.trains.BezierConnection.GirderAngles;
import com.simibubi.create.content.logistics.trains.BezierConnection.SegmentAngles;
import com.simibubi.create.foundation.render.CachedBufferer; import com.simibubi.create.foundation.render.CachedBufferer;
import com.simibubi.create.foundation.render.SuperByteBuffer;
import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer; import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer;
import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.renderer.LevelRenderer; import net.minecraft.client.renderer.LevelRenderer;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.RenderType;
@ -23,6 +30,7 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction.Axis; import net.minecraft.core.Direction.Axis;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
public class TrackRenderer extends SafeTileEntityRenderer<TrackTileEntity> { public class TrackRenderer extends SafeTileEntityRenderer<TrackTileEntity> {
@ -46,162 +54,63 @@ public class TrackRenderer extends SafeTileEntityRenderer<TrackTileEntity> {
ms.pushPose(); ms.pushPose();
BlockPos tePosition = bc.tePositions.getFirst(); BlockPos tePosition = bc.tePositions.getFirst();
BlockState air = Blocks.AIR.defaultBlockState();
ClientLevel level = Minecraft.getInstance().level;
SegmentAngles[] segments = bc.getBakedSegments();
TransformStack.cast(ms) TransformStack.cast(ms)
.nudge((int) tePosition.asLong()); .nudge((int) tePosition.asLong());
if (bc.hasGirder) renderGirder(bc, ms, vb, tePosition);
renderGirder(bc, ms, vb, tePosition);
Vec3 previous1 = null; for (int i = 1; i < segments.length; i++) {
Vec3 previous2 = null; SegmentAngles segment = segments[i];
int light = LevelRenderer.getLightColor(level, segment.lightPosition.offset(tePosition));
for (BezierConnection.Segment segment : bc) { CachedBufferer.partial(TRACK_TIE, air)
Vec3 rail1 = segment.position.add(segment.normal.scale(.965f)); .mulPose(segment.tieTransform)
Vec3 rail2 = segment.position.subtract(segment.normal.scale(.965f)); .disableDiffuseMult()
.light(light)
.renderInto(ms, vb);
if (previous1 != null) { for (boolean first : Iterate.trueAndFalse)
int centralLight = 0; CachedBufferer.partial(first ? TRACK_SEGMENT_LEFT : TRACK_SEGMENT_RIGHT, air)
.mulPose(segment.railTransforms.get(first))
{ .disableDiffuseMult()
// Tie .light(light)
Vec3 railMiddle = rail1.add(rail2) .renderInto(ms, vb);
.scale(.5);
Vec3 prevMiddle = previous1.add(previous2)
.scale(.5);
Vec3 diff = railMiddle.subtract(prevMiddle);
Vec3 angles = getModelAngles(segment.normal, diff);
centralLight = LevelRenderer.getLightColor(Minecraft.getInstance().level,
new BlockPos(railMiddle).offset(tePosition));
SuperByteBuffer sbb =
CachedBufferer.partial(AllBlockPartials.TRACK_TIE, Blocks.AIR.defaultBlockState());
sbb.translate(prevMiddle)
.rotateYRadians(angles.y)
.rotateXRadians(angles.x)
.rotateZRadians(angles.z)
.translate(-1 / 2f, -2 / 16f - 1 / 256f, 0);
sbb.disableDiffuseMult()
.light(centralLight);
sbb.renderInto(ms, vb);
}
// Rails
for (boolean first : Iterate.trueAndFalse) {
Vec3 railI = first ? rail1 : rail2;
Vec3 prevI = first ? previous1 : previous2;
Vec3 diff = railI.subtract(prevI);
Vec3 angles = getModelAngles(segment.normal, diff);
SuperByteBuffer sbb = CachedBufferer.partial(
first ? AllBlockPartials.TRACK_SEGMENT_LEFT : AllBlockPartials.TRACK_SEGMENT_RIGHT,
Blocks.AIR.defaultBlockState());
sbb.translate(prevI)
.rotateYRadians(angles.y)
.rotateXRadians(angles.x)
.rotateZRadians(angles.z)
.translate(0, -2 / 16f + (segment.index % 2 == 0 ? 1 : -1) / 2048f - 1 / 256f, 0)
.scale(1, 1, (float) diff.length() * 2.1f);
sbb.disableDiffuseMult()
.light(LevelRenderer.getLightColor(Minecraft.getInstance().level,
new BlockPos(prevI).offset(tePosition)));
sbb.renderInto(ms, vb);
}
}
previous1 = rail1;
previous2 = rail2;
} }
ms.popPose(); ms.popPose();
} }
private static void renderGirder(BezierConnection bc, PoseStack ms, VertexConsumer vb, BlockPos tePosition) { private static void renderGirder(BezierConnection bc, PoseStack ms, VertexConsumer vb, BlockPos tePosition) {
Vec3 previousG11 = null; if (!bc.hasGirder)
Vec3 previousG21 = null; return;
Vec3 previousG12 = null;
Vec3 previousG22 = null;
for (BezierConnection.Segment segment : bc) { BlockState air = Blocks.AIR.defaultBlockState();
Vec3 rail1 = segment.position.add(segment.normal.scale(.965f)); ClientLevel level = Minecraft.getInstance().level;
Vec3 rail2 = segment.position.subtract(segment.normal.scale(.965f)); GirderAngles[] girders = bc.getBakedGirders();
Vec3 upNormal = segment.derivative.normalize() for (int i = 1; i < girders.length; i++) {
.cross(segment.normal); GirderAngles segment = girders[i];
Vec3 firstGirderOffset = upNormal.scale(-8 / 16f); int light = LevelRenderer.getLightColor(level, segment.lightPosition.offset(tePosition));
Vec3 secondGirderOffset = upNormal.scale(-10 / 16f);
Vec3 g11 = segment.position.add(segment.normal.scale(1))
.add(firstGirderOffset);
Vec3 g12 = segment.position.subtract(segment.normal.scale(1))
.add(firstGirderOffset);
Vec3 g21 = g11.add(secondGirderOffset);
Vec3 g22 = g12.add(secondGirderOffset);
if (previousG11 != null) { for (boolean first : Iterate.trueAndFalse) {
Vec3 railMiddle = rail1.add(rail2) CachedBufferer.partial(GIRDER_SEGMENT_2, air)
.scale(.5); .mulPose(segment.beams.get(first))
int centralLight = LevelRenderer.getLightColor(Minecraft.getInstance().level, .disableDiffuseMult()
new BlockPos(railMiddle).offset(tePosition)); .light(light)
Vec3 normal = segment.normal; .renderInto(ms, vb);
float l = 2.2f;
for (boolean first : Iterate.trueAndFalse) { for (boolean top : Iterate.trueAndFalse)
for (boolean top : Iterate.trueAndFalse) { CachedBufferer.partial(GIRDER_SEGMENT, air)
Vec3 railI = top ? first ? g11 : g12 : first ? g21 : g22; .mulPose(segment.beamCaps.get(top)
Vec3 prevI = top ? first ? previousG11 : previousG12 : first ? previousG21 : previousG22; .get(first))
Vec3 diff = railI.subtract(prevI); .disableDiffuseMult()
Vec3 angles = getModelAngles(normal, diff); .light(light)
.renderInto(ms, vb);
SuperByteBuffer sbb2 =
CachedBufferer.partial(AllBlockPartials.GIRDER_SEGMENT, Blocks.AIR.defaultBlockState());
sbb2.translate(prevI)
.rotateYRadians(angles.y)
.rotateXRadians(angles.x)
.rotateZRadians(angles.z)
.translate(0, 2 / 16f + (segment.index % 2 == 0 ? 1 : -1) / 2048f - 1 / 1024f, 0)
.rotateZ(top ? 0 : 0)
.scale(1, 1, (float) diff.length() * l);
sbb2.disableDiffuseMult()
.light(centralLight);
sbb2.renderInto(ms, vb);
}
{
Vec3 railI = (first ? g11 : g12).add(first ? g21 : g22)
.scale(.5);
Vec3 prevI = (first ? previousG11 : previousG12).add(first ? previousG21 : previousG22)
.scale(.5);
Vec3 diff = railI.subtract(prevI);
Vec3 angles = getModelAngles(normal, diff);
SuperByteBuffer sbb2 =
CachedBufferer.partial(AllBlockPartials.GIRDER_SEGMENT_2, Blocks.AIR.defaultBlockState());
sbb2.translate(prevI)
.rotateYRadians(angles.y)
.rotateXRadians(angles.x)
.rotateZRadians(angles.z)
.translate(0, 2 / 16f + (segment.index % 2 == 0 ? 1 : -1) / 2048f - 1 / 1024f, 0)
.scale(1, 1, (float) diff.length() * l);
sbb2.disableDiffuseMult()
.light(centralLight);
sbb2.renderInto(ms, vb);
}
}
} }
previousG11 = g11;
previousG12 = g12;
previousG21 = g21;
previousG22 = g22;
} }
} }

View file

@ -10,9 +10,9 @@
"to": [2, 4, 8], "to": [2, 4, 8],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 8]}, "rotation": {"angle": 0, "axis": "y", "origin": [8, 8, 8]},
"faces": { "faces": {
"north": {"uv": [8, 1, 12, 3], "rotation": 270, "texture": "#0"}, "north": {"uv": [2, 5, 4, 9], "texture": "#0"},
"east": {"uv": [0, 5, 4, 9], "texture": "#0"}, "east": {"uv": [0, 5, 4, 9], "texture": "#0"},
"south": {"uv": [8, 1, 12, 3], "rotation": 270, "texture": "#0"}, "south": {"uv": [2, 5, 4, 9], "texture": "#0"},
"west": {"uv": [0, 5, 4, 9], "texture": "#0"} "west": {"uv": [0, 5, 4, 9], "texture": "#0"}
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 297 B

After

Width:  |  Height:  |  Size: 404 B