Separate LightVolume and GPULightVolume

- LightVolumes now can act as a light cache with configurable size
 - More GridAlignedBB changes
 - Remove ILightUpdateListeners
 - Simplify pulley rendering using LightVolume
This commit is contained in:
Jozufozu 2021-09-08 15:48:49 -07:00
parent d13bf42c22
commit 6fcc960189
9 changed files with 100 additions and 143 deletions

View file

@ -27,7 +27,7 @@ import org.apache.commons.lang3.tuple.Pair;
import com.jozufozu.flywheel.backend.IFlywheelWorld;
import com.jozufozu.flywheel.light.GridAlignedBB;
import com.jozufozu.flywheel.light.ReadOnlyBox;
import com.jozufozu.flywheel.light.ImmutableBox;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllMovementBehaviours;
import com.simibubi.create.content.contraptions.base.IRotate;
@ -1143,7 +1143,7 @@ public abstract class Contraption {
GridAlignedBB betterBounds = GridAlignedBB.ofRadius(radius);
ReadOnlyBox contraptionBounds = GridAlignedBB.from(bounds);
ImmutableBox contraptionBounds = GridAlignedBB.from(bounds);
if (axis == Direction.Axis.X) {
betterBounds.setMaxX(contraptionBounds.getMaxX());
betterBounds.setMinX(contraptionBounds.getMinX());

View file

@ -6,10 +6,10 @@ import net.minecraft.world.LightType;
public abstract class ContraptionLighter<C extends Contraption> implements ILightUpdateListener {
protected final C contraption;
public final LightVolume lightVolume;
public final GPULightVolume lightVolume;
protected final LightUpdater lightUpdater;
protected GridAlignedBB bounds;
protected final GridAlignedBB bounds;
protected boolean scheduleRebuild;
@ -18,15 +18,14 @@ public abstract class ContraptionLighter<C extends Contraption> implements ILigh
lightUpdater = LightUpdater.get(contraption.entity.level);
bounds = getContraptionBounds();
growBoundsForEdgeData();
lightVolume = new LightVolume(contraptionBoundsToVolume(bounds));
lightVolume = new GPULightVolume(bounds);
lightVolume.initialize(contraption.entity.level);
lightVolume.initialize(lightUpdater.getProvider());
scheduleRebuild = true;
lightUpdater.addListener(this);
lightVolume.initialize(this.contraption.entity.level);
}
public abstract GridAlignedBB getContraptionBounds();
@ -37,26 +36,28 @@ public abstract class ContraptionLighter<C extends Contraption> implements ILigh
}
@Override
public void onLightUpdate(LightProvider world, LightType type, ReadOnlyBox changed) {
lightVolume.notifyLightUpdate(world, type, changed);
public void onLightUpdate(LightProvider world, LightType type, ImmutableBox changed) {
lightVolume.onLightUpdate(world, type, changed);
}
@Override
public void onLightPacket(LightProvider world, int chunkX, int chunkZ) {
lightVolume.notifyLightPacket(world, chunkX, chunkZ);
lightVolume.onLightPacket(world, chunkX, chunkZ);
}
protected GridAlignedBB contraptionBoundsToVolume(ReadOnlyBox box) {
GridAlignedBB bounds = box.copy();
protected void growBoundsForEdgeData() {
bounds.grow(2); // so we have at least enough data on the edges to avoid artifacts and have smooth lighting
bounds.setMinY(Math.max(bounds.getMinY(), 0));
bounds.setMaxY(Math.min(bounds.getMaxY(), 255));
return bounds;
}
}
@Override
public ReadOnlyBox getVolume() {
public ImmutableBox getVolume() {
return bounds;
}
public void delete() {
lightUpdater.removeListener(this);
lightVolume.delete();
}
}

View file

@ -3,7 +3,7 @@ package com.simibubi.create.content.contraptions.components.structureMovement;
import com.jozufozu.flywheel.light.GridAlignedBB;
import com.jozufozu.flywheel.light.IMovingListener;
import com.jozufozu.flywheel.light.LightProvider;
import com.jozufozu.flywheel.light.ReadOnlyBox;
import com.jozufozu.flywheel.light.ImmutableBox;
import com.simibubi.create.foundation.config.AllConfigs;
public class NonStationaryLighter<C extends Contraption> extends ContraptionLighter<C> implements IMovingListener {
@ -16,14 +16,15 @@ public class NonStationaryLighter<C extends Contraption> extends ContraptionLigh
if (getVolume().volume() > AllConfigs.CLIENT.maxContraptionLightVolume.get())
return false;
ReadOnlyBox contraptionBounds = getContraptionBounds();
ImmutableBox contraptionBounds = getContraptionBounds();
if (bounds.sameAs(contraptionBounds)) {
return false;
}
bounds.assign(contraptionBounds);
lightVolume.move(contraption.entity.level, contraptionBoundsToVolume(bounds));
growBoundsForEdgeData();
lightVolume.move(provider, bounds);
return true;
}

View file

@ -1,7 +1,5 @@
package com.simibubi.create.content.contraptions.components.structureMovement.pulley;
import java.util.Arrays;
import com.jozufozu.flywheel.backend.instancing.IDynamicInstance;
import com.jozufozu.flywheel.backend.instancing.Instancer;
import com.jozufozu.flywheel.backend.material.MaterialManager;
@ -9,23 +7,21 @@ import com.jozufozu.flywheel.core.instancing.ConditionalInstance;
import com.jozufozu.flywheel.core.instancing.GroupInstance;
import com.jozufozu.flywheel.core.instancing.SelectInstance;
import com.jozufozu.flywheel.core.materials.OrientedData;
import com.jozufozu.flywheel.light.BasicProvider;
import com.jozufozu.flywheel.light.GridAlignedBB;
import com.jozufozu.flywheel.light.IMovingListener;
import com.jozufozu.flywheel.light.LightProvider;
import com.jozufozu.flywheel.light.ListenerStatus;
import com.jozufozu.flywheel.light.ReadOnlyBox;
import com.jozufozu.flywheel.light.ImmutableBox;
import com.jozufozu.flywheel.light.LightUpdater;
import com.jozufozu.flywheel.light.LightVolume;
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.contraptions.relays.encased.ShaftInstance;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.vector.Vector3f;
import net.minecraft.world.IBlockDisplayReader;
import net.minecraft.world.LightType;
public abstract class AbstractPulleyInstance extends ShaftInstance implements IDynamicInstance {
public abstract class AbstractPulleyInstance extends ShaftInstance implements IDynamicInstance, IMovingListener {
final OrientedData coil;
final SelectInstance<OrientedData> magnet;
@ -36,9 +32,8 @@ public abstract class AbstractPulleyInstance extends ShaftInstance implements ID
protected final Direction rotatingAbout;
protected final Vector3f rotationAxis;
private byte[] bLight = new byte[1];
private byte[] sLight = new byte[1];
private GridAlignedBB volume;
private final GridAlignedBB volume = new GridAlignedBB();
private final LightVolume light;
public AbstractPulleyInstance(MaterialManager dispatcher, KineticTileEntity tile) {
super(dispatcher, tile);
@ -46,8 +41,7 @@ public abstract class AbstractPulleyInstance extends ShaftInstance implements ID
rotatingAbout = Direction.get(Direction.AxisDirection.POSITIVE, axis);
rotationAxis = rotatingAbout.step();
coil = getCoilModel()
.createInstance()
coil = getCoilModel().createInstance()
.setPosition(getInstancePosition());
magnet = new SelectInstance<>(this::getMagnetModelIndex);
@ -55,49 +49,60 @@ public abstract class AbstractPulleyInstance extends ShaftInstance implements ID
.addModel(getHalfMagnetModel());
rope = new GroupInstance<>(getRopeModel());
halfRope = new ConditionalInstance<>(getHalfRopeModel())
.withCondition(this::shouldRenderHalfRope);
halfRope = new ConditionalInstance<>(getHalfRopeModel()).withCondition(this::shouldRenderHalfRope);
updateOffset();
updateVolume();
light = new LightVolume(volume);
light.initialize(LightUpdater.get(world).getProvider());
beginFrame();
}
@Override
public void beginFrame() {
updateOffset();
transformModels();
}
private void transformModels() {
resizeRope();
coil.setRotation(rotationAxis.rotationDegrees(offset * 180));
magnet.update().get().ifPresent(data ->
{
int index = Math.max(0, MathHelper.floor(offset));
int neededRopeCount = getNeededRopeCount();
rope.resize(neededRopeCount);
magnet.update()
.get()
.ifPresent(data -> {
int i = Math.max(0, MathHelper.floor(offset));
short packed = light.getPackedLight(pos.getX(), pos.getY() - i, pos.getZ());
data.setPosition(getInstancePosition())
.nudge(0, -offset, 0)
.setBlockLight(bLight[index])
.setSkyLight(sLight[index]);
}
);
.setBlockLight(LightVolume.unpackBlock(packed))
.setSkyLight(LightVolume.unpackSky(packed));
});
halfRope.update().get().ifPresent(rope -> {
float f = offset % 1;
float halfRopeNudge = f > .75f ? f - 1 : f;
halfRope.update()
.get()
.ifPresent(rope1 -> {
float f = offset % 1;
float halfRopeNudge = f > .75f ? f - 1 : f;
rope.setPosition(getInstancePosition())
.nudge(0, -halfRopeNudge, 0)
.setBlockLight(bLight[0])
.setSkyLight(sLight[0]);
});
short packed = light.getPackedLight(pos.getX(), pos.getY(), pos.getZ());
rope1.setPosition(getInstancePosition())
.nudge(0, -halfRopeNudge, 0)
.setBlockLight(LightVolume.unpackBlock(packed))
.setSkyLight(LightVolume.unpackSky(packed));
});
if (isRunning()) {
int size = rope.size();
int bottomY = pos.getY() - size;
for (int i = 0; i < size; i++) {
short packed = light.getPackedLight(pos.getX(), bottomY + i, pos.getZ());
rope.get(i)
.setPosition(getInstancePosition())
.nudge(0, -offset + i + 1, 0)
.setBlockLight(bLight[size - i])
.setSkyLight(sLight[size - i]);
.setBlockLight(LightVolume.unpackBlock(packed))
.setSkyLight(LightVolume.unpackSky(packed));
}
} else {
rope.clear();
@ -117,6 +122,7 @@ public abstract class AbstractPulleyInstance extends ShaftInstance implements ID
magnet.delete();
rope.clear();
halfRope.delete();
light.delete();
}
protected abstract Instancer<OrientedData> getRopeModel();
@ -133,23 +139,24 @@ public abstract class AbstractPulleyInstance extends ShaftInstance implements ID
protected abstract boolean isRunning();
protected void resizeRope() {
int neededRopeCount = getNeededRopeCount();
rope.resize(neededRopeCount);
int length = MathHelper.ceil(offset);
if (volume == null || bLight.length < length + 1) {
volume = GridAlignedBB.from(pos.below(length), pos);
volume.fixMinMax();
bLight = Arrays.copyOf(bLight, length + 1);
sLight = Arrays.copyOf(sLight, length + 1);
initLight(BasicProvider.get(world), volume);
needsUpdate = true;
@Override
public boolean update(LightProvider provider) {
if (updateVolume()) {
light.move(provider, volume);
return true;
}
return false;
}
private boolean updateVolume() {
int length = MathHelper.ceil(offset) + 2;
if (volume.sizeY() < length) {
volume.assign(pos.below(length), pos)
.fixMinMax();
return true;
}
return false;
}
private void updateOffset() {
@ -167,7 +174,7 @@ public abstract class AbstractPulleyInstance extends ShaftInstance implements ID
private int getMagnetModelIndex() {
if (isRunning() || offset == 0) {
return offset > .25f ? 0 : 1;
return offset > .25f ? 0 : 1;
} else {
return -1;
}
@ -178,25 +185,14 @@ public abstract class AbstractPulleyInstance extends ShaftInstance implements ID
return false;
}
boolean needsUpdate;
@Override
public ImmutableBox getVolume() {
return volume;
}
@Override
public void onLightUpdate(LightProvider world, LightType type, ReadOnlyBox changed) {
initLight(world, changed.intersect(volume));
}
private void initLight(LightProvider world, ReadOnlyBox changed) {
int top = this.pos.getY();
BlockPos.Mutable pos = new BlockPos.Mutable();
changed.forEachContained((x, y, z) -> {
pos.set(x, y, z);
byte block = (byte) world.getLight(LightType.BLOCK, x, y, z);
byte sky = (byte) world.getLight(LightType.SKY, x, y, z);
int i = top - y;
bLight[i] = block;
sLight[i] = sky;
});
public void onLightUpdate(LightProvider world, LightType type, ImmutableBox changed) {
super.onLightUpdate(world, type, changed);
light.onLightUpdate(world, type, changed);
}
}

View file

@ -9,11 +9,9 @@ import com.simibubi.create.content.contraptions.fluids.actors.HosePulleyTileEnti
import com.simibubi.create.foundation.utility.AnimationTickHolder;
public class HosePulleyInstance extends AbstractPulleyInstance {
final HosePulleyTileEntity tile = (HosePulleyTileEntity) super.tile;
public HosePulleyInstance(MaterialManager dispatcher, HosePulleyTileEntity tile) {
super(dispatcher, tile);
beginFrame();
}
protected Instancer<OrientedData> getRopeModel() {
@ -41,7 +39,7 @@ public class HosePulleyInstance extends AbstractPulleyInstance {
}
protected float getOffset() {
return tile.getInterpolatedOffset(AnimationTickHolder.getPartialTicks());
return ((HosePulleyTileEntity) tile).getInterpolatedOffset(AnimationTickHolder.getPartialTicks());
}
protected boolean isRunning() {

View file

@ -9,11 +9,8 @@ import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
public class RopePulleyInstance extends AbstractPulleyInstance {
final PulleyTileEntity tile = (PulleyTileEntity) super.tile;
public RopePulleyInstance(MaterialManager dispatcher, PulleyTileEntity tile) {
super(dispatcher, tile);
beginFrame();
}
protected Instancer<OrientedData> getRopeModel() {
@ -38,10 +35,10 @@ public class RopePulleyInstance extends AbstractPulleyInstance {
protected float getOffset() {
float partialTicks = AnimationTickHolder.getPartialTicks();
return PulleyRenderer.getTileOffset(partialTicks, tile);
return PulleyRenderer.getTileOffset(partialTicks, (PulleyTileEntity) tile);
}
protected boolean isRunning() {
return tile.running || tile.isVirtual();
return ((PulleyTileEntity) tile).running || tile.isVirtual();
}
}

View file

@ -1,35 +0,0 @@
package com.simibubi.create.content.contraptions.components.structureMovement.render;
import java.util.ArrayList;
import com.jozufozu.flywheel.light.GridAlignedBB;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.Pair;
import com.simibubi.create.foundation.utility.outliner.AABBOutline;
public class LightVolumeDebugger {
public static void render(MatrixStack ms, SuperRenderTypeBuffer buffer) {
// ContraptionRenderDispatcher.RENDERERS.values()
// .stream()
// .flatMap(r -> {
// GridAlignedBB texture = r.getLighter().lightVolume.getTextureVolume();
// GridAlignedBB sample = r.getLighter().lightVolume.getSampleVolume();
//
// ArrayList<Pair<GridAlignedBB, Integer>> pairs = new ArrayList<>(2);
//
// pairs.add(Pair.of(texture, 0xFFFFFF));
// pairs.add(Pair.of(sample, 0xFFFF00));
//
// return pairs.stream();
// })
// .map(pair -> {
// AABBOutline outline = new AABBOutline(GridAlignedBB.toAABB(pair.getFirst()));
//
// outline.getParams().colored(pair.getSecond());
// return outline;
// })
// .forEach(outline -> outline.render(ms, buffer, AnimationTickHolder.getPartialTicks()));
}
}

View file

@ -14,7 +14,6 @@ import com.jozufozu.flywheel.backend.model.ModelRenderer;
import com.jozufozu.flywheel.core.model.IModel;
import com.jozufozu.flywheel.core.model.WorldModel;
import com.jozufozu.flywheel.event.BeginFrameEvent;
import com.jozufozu.flywheel.light.GridAlignedBB;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
@ -85,7 +84,7 @@ public class RenderedContraption extends ContraptionRenderInfo {
Vector3d cameraPos = event.getCameraPos();
lightBox = lighter.lightVolume.getTextureVolume().toAABB()
lightBox = lighter.lightVolume.toAABB()
.move(-cameraPos.x, -cameraPos.y, -cameraPos.z);
}
@ -111,7 +110,7 @@ public class RenderedContraption extends ContraptionRenderInfo {
}
renderLayers.clear();
lighter.lightVolume.delete();
lighter.delete();
materialManager.delete();
kinetics.invalidate();

View file

@ -18,7 +18,7 @@ import com.jozufozu.flywheel.light.ILightUpdateListener;
import com.jozufozu.flywheel.light.LightProvider;
import com.jozufozu.flywheel.light.LightUpdater;
import com.jozufozu.flywheel.light.ListenerStatus;
import com.jozufozu.flywheel.light.ReadOnlyBox;
import com.jozufozu.flywheel.light.ImmutableBox;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.base.IRotate;
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
@ -553,7 +553,7 @@ public class BeltTileEntity extends KineticTileEntity implements ILightUpdateLis
}
@Override
public void onLightUpdate(LightProvider world, LightType type, ReadOnlyBox changed) {
public void onLightUpdate(LightProvider world, LightType type, ImmutableBox changed) {
GridAlignedBB beltVolume = getVolume();
if (beltVolume.intersects(changed)) {