pistons are lit and bearings are better lit in the corners

stop sampling light in places that don't matter
This commit is contained in:
JozsefA 2021-01-18 00:31:33 -08:00
parent 22a90c8e5d
commit 398a848791
13 changed files with 150 additions and 221 deletions

View file

@ -190,7 +190,7 @@ public abstract class Contraption {
// Create subcontraptions // Create subcontraptions
for (BlockFace blockFace : pendingSubContraptions) { for (BlockFace blockFace : pendingSubContraptions) {
Direction face = blockFace.getFace(); Direction face = blockFace.getFace();
StabilizedContraption subContraption = new StabilizedContraption(face); StabilizedContraption subContraption = new StabilizedContraption(this, face);
World world = entity.world; World world = entity.world;
BlockPos pos = blockFace.getPos(); BlockPos pos = blockFace.getPos();
if (!subContraption.assemble(world, pos)) if (!subContraption.assemble(world, pos))

View file

@ -13,6 +13,7 @@ public class BearingLighter extends ContraptionLighter<BearingContraption> {
@Override @Override
public GridAlignedBB getContraptionBounds() { public GridAlignedBB getContraptionBounds() {
GridAlignedBB localBounds = GridAlignedBB.fromAABB(contraption.bounds); GridAlignedBB localBounds = GridAlignedBB.fromAABB(contraption.bounds);
localBounds.rotate45(contraption.getFacing().getAxis());
localBounds.translate(contraption.anchor); localBounds.translate(contraption.anchor);
return localBounds; return localBounds;
} }

View file

@ -11,11 +11,14 @@ import net.minecraft.world.World;
public class StabilizedContraption extends Contraption { public class StabilizedContraption extends Contraption {
public Contraption parent;
private Direction facing; private Direction facing;
public StabilizedContraption() {} public StabilizedContraption() {}
public StabilizedContraption(Direction facing) { public StabilizedContraption(Contraption parent, Direction facing) {
this.parent = parent;
this.facing = facing; this.facing = facing;
} }

View file

@ -5,6 +5,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.Blo
import com.simibubi.create.content.contraptions.components.structureMovement.TranslatingContraption; import com.simibubi.create.content.contraptions.components.structureMovement.TranslatingContraption;
import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.*; import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.*;
import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.render.light.ContraptionLighter;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.CarpetBlock; import net.minecraft.block.CarpetBlock;
@ -18,6 +19,8 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorld; import net.minecraft.world.IWorld;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.world.gen.feature.template.Template.BlockInfo; import net.minecraft.world.gen.feature.template.Template.BlockInfo;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Pair;
import java.util.ArrayList; import java.util.ArrayList;
@ -226,4 +229,9 @@ public class PistonContraption extends TranslatingContraption {
return tag; return tag;
} }
@OnlyIn(Dist.CLIENT)
@Override
public ContraptionLighter<?> makeLighter() {
return new PistonLighter(this);
}
} }

View file

@ -0,0 +1,35 @@
package com.simibubi.create.content.contraptions.components.structureMovement.piston;
import com.simibubi.create.foundation.render.light.ContraptionLighter;
import com.simibubi.create.foundation.render.light.GridAlignedBB;
import net.minecraft.util.Direction;
import net.minecraft.util.math.Vec3i;
public class PistonLighter extends ContraptionLighter<PistonContraption> {
public PistonLighter(PistonContraption contraption) {
super(contraption);
}
@Override
public GridAlignedBB getContraptionBounds() {
GridAlignedBB bounds = GridAlignedBB.fromAABB(contraption.bounds);
bounds.translate(contraption.anchor);
int length = contraption.extensionLength;
Vec3i direction = contraption.orientation.getDirectionVec();
int shift = length / 2;
int shiftX = direction.getX() * shift;
int shiftY = direction.getY() * shift;
int shiftZ = direction.getZ() * shift;
bounds.translate(shiftX, shiftY, shiftZ);
int grow = (length + 1) / 2;
int extendX = Math.abs(direction.getX() * grow);
int extendY = Math.abs(direction.getY() * grow);
int extendZ = Math.abs(direction.getZ() * grow);
bounds.grow(extendX, extendY, extendZ);
return bounds;
}
}

View file

@ -126,7 +126,7 @@ public class ClientEvents {
CouplingRenderer.renderAll(ms, buffer); CouplingRenderer.renderAll(ms, buffer);
CreateClient.schematicHandler.render(ms, buffer); CreateClient.schematicHandler.render(ms, buffer);
CreateClient.outliner.renderOutlines(ms, buffer); CreateClient.outliner.renderOutlines(ms, buffer);
LightVolumeDebugger.render(ms, buffer); // LightVolumeDebugger.render(ms, buffer);
// CollisionDebugger.render(ms, buffer); // CollisionDebugger.render(ms, buffer);
buffer.draw(); buffer.draw();

View file

@ -1,6 +1,12 @@
package com.simibubi.create.foundation.render; package com.simibubi.create.foundation.render;
public class RenderMath { public class RenderMath {
public static final float SQRT2 = 1.41421356237f;
public static int timesSqrt2(int i) {
return (int) Math.floor((float) i * SQRT2 / 4f);
}
public static int nextPowerOf2(int a) { public static int nextPowerOf2(int a) {
int h = Integer.highestOneBit(a); int h = Integer.highestOneBit(a);
return (h == a) ? h : (h << 1); return (h == a) ? h : (h << 1);

View file

@ -1,165 +0,0 @@
package com.simibubi.create.foundation.render;
import net.minecraft.client.renderer.GLAllocation;
import sun.nio.ch.DirectBuffer;
import java.nio.*;
public class SafeDirectBuffer implements AutoCloseable {
private ByteBuffer wrapped;
public SafeDirectBuffer(int capacity) {
this.wrapped = GLAllocation.createDirectByteBuffer(capacity);
}
public void close() throws Exception {
if (wrapped instanceof DirectBuffer) {
((DirectBuffer) wrapped).cleaner().clean();
}
}
/**
* Only use this function to pass information to OpenGL.
*/
@Deprecated
public ByteBuffer getBacking() {
return wrapped;
}
public void order(ByteOrder bo) {
wrapped.order(bo);
}
public void limit(int limit) {
wrapped.limit(limit);
}
public void rewind() {
wrapped.rewind();
}
public byte get() {
return wrapped.get();
}
public ByteBuffer put(byte b) {
return wrapped.put(b);
}
public byte get(int index) {
return wrapped.get();
}
public ByteBuffer put(int index, byte b) {
return wrapped.put(index, b);
}
public ByteBuffer compact() {
return wrapped.compact();
}
public boolean isReadOnly() {
return wrapped.isReadOnly();
}
public boolean isDirect() {
return wrapped.isDirect();
}
public char getChar() {
return wrapped.getChar();
}
public ByteBuffer putChar(char value) {
return wrapped.putChar(value);
}
public char getChar(int index) {
return wrapped.getChar(index);
}
public ByteBuffer putChar(int index, char value) {
return wrapped.putChar(index, value);
}
public short getShort() {
return wrapped.getShort();
}
public ByteBuffer putShort(short value) {
return wrapped.putShort(value);
}
public short getShort(int index) {
return wrapped.getShort(index);
}
public ByteBuffer putShort(int index, short value) {
return wrapped.putShort(index, value);
}
public int getInt() {
return wrapped.getInt();
}
public ByteBuffer putInt(int value) {
return wrapped.putInt(value);
}
public int getInt(int index) {
return wrapped.getInt(index);
}
public ByteBuffer putInt(int index, int value) {
return wrapped.putInt(index, value);
}
public long getLong() {
return wrapped.getLong();
}
public ByteBuffer putLong(long value) {
return wrapped.putLong(value);
}
public long getLong(int index) {
return wrapped.getLong(index);
}
public ByteBuffer putLong(int index, long value) {
return wrapped.putLong(index, value);
}
public float getFloat() {
return wrapped.getFloat();
}
public ByteBuffer putFloat(float value) {
return wrapped.putFloat(value);
}
public float getFloat(int index) {
return wrapped.getFloat(index);
}
public ByteBuffer putFloat(int index, float value) {
return wrapped.putFloat(index, value);
}
public double getDouble() {
return wrapped.getDouble();
}
public ByteBuffer putDouble(double value) {
return wrapped.putDouble(value);
}
public double getDouble(int index) {
return wrapped.getDouble(index);
}
public ByteBuffer putDouble(int index, double value) {
return wrapped.putDouble(index, value);
}
}

View file

@ -4,7 +4,6 @@ package com.simibubi.create.foundation.render.instancing;
import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.platform.GlStateManager;
import com.simibubi.create.foundation.render.RenderMath; import com.simibubi.create.foundation.render.RenderMath;
import com.simibubi.create.foundation.render.RenderWork; import com.simibubi.create.foundation.render.RenderWork;
import com.simibubi.create.foundation.render.SafeDirectBuffer;
import com.simibubi.create.foundation.render.TemplateBuffer; import com.simibubi.create.foundation.render.TemplateBuffer;
import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.BufferBuilder;
import org.lwjgl.opengl.*; import org.lwjgl.opengl.*;

View file

@ -16,9 +16,10 @@ public abstract class ContraptionLighter<C extends Contraption> {
GridAlignedBB bounds = getContraptionBounds(); GridAlignedBB bounds = getContraptionBounds();
bounds.grow(1); // so we have at least enough data on the edges to avoid artifacts bounds.grow(1); // so we have at least enough data on the edges to avoid artifacts
GridAlignedBB importantArea = GridAlignedBB.copy(bounds);
bounds.nextPowerOf2Centered(); bounds.nextPowerOf2Centered();
lightVolume = new LightVolume(bounds); lightVolume = new LightVolume(bounds, importantArea);
lightVolume.initialize(contraption.entity.world); lightVolume.initialize(contraption.entity.world);
} }

View file

@ -1,6 +1,7 @@
package com.simibubi.create.foundation.render.light; package com.simibubi.create.foundation.render.light;
import com.simibubi.create.foundation.render.RenderMath; import com.simibubi.create.foundation.render.RenderMath;
import net.minecraft.util.Direction;
import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.SectionPos; import net.minecraft.util.math.SectionPos;
@ -79,12 +80,26 @@ public class GridAlignedBB {
} }
public void translate(Vec3i by) { public void translate(Vec3i by) {
this.minX += by.getX(); translate(by.getX(), by.getY(), by.getZ());
this.minY += by.getY(); }
this.minZ += by.getZ();
this.maxX += by.getX(); public void translate(int x, int y, int z) {
this.maxY += by.getY(); minX += x;
this.maxZ += by.getZ(); maxX += x;
minY += y;
maxY += y;
minZ += z;
maxZ += z;
}
public void rotate45(Direction.Axis axis) {
if (axis == Direction.Axis.X) {
this.grow(0, RenderMath.timesSqrt2(sizeY()), RenderMath.timesSqrt2(sizeZ()));
} else if (axis == Direction.Axis.Y) {
this.grow(RenderMath.timesSqrt2(sizeX()), 0, RenderMath.timesSqrt2(sizeZ()));
} else if (axis == Direction.Axis.Z) {
this.grow(RenderMath.timesSqrt2(sizeX()), RenderMath.timesSqrt2(sizeY()), 0);
}
} }
/** /**
@ -103,12 +118,12 @@ public class GridAlignedBB {
int diffY = newSizeY - sizeY; int diffY = newSizeY - sizeY;
int diffZ = newSizeZ - sizeZ; int diffZ = newSizeZ - sizeZ;
this.minX -= diffX / 2; // floor division for the minimums minX -= diffX / 2; // floor division for the minimums
this.minY -= diffY / 2; minY -= diffY / 2;
this.minZ -= diffZ / 2; minZ -= diffZ / 2;
this.maxX += (diffX + 1) / 2; // ceiling divison for the maximums maxX += (diffX + 1) / 2; // ceiling divison for the maximums
this.maxY += (diffY + 1) / 2; maxY += (diffY + 1) / 2;
this.maxZ += (diffZ + 1) / 2; maxZ += (diffZ + 1) / 2;
} }
/** /**
@ -134,12 +149,12 @@ public class GridAlignedBB {
} }
public void grow(int x, int y, int z) { public void grow(int x, int y, int z) {
this.minX -= x; minX -= x;
this.minY -= y; minY -= y;
this.minZ -= z; minZ -= z;
this.maxX += x; maxX += x;
this.maxY += y; maxY += y;
this.maxZ += z; maxZ += z;
} }
public GridAlignedBB intersect(GridAlignedBB other) { public GridAlignedBB intersect(GridAlignedBB other) {

View file

@ -10,70 +10,80 @@ import org.lwjgl.system.MemoryUtil;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
// TODO: Don't immediately destroy light volumes.
// There's a high chance that a contraption will stop and soon after start again.
// By caching lightvolumes based on their volumes/locations, we can save having
// to reread all the lighting data in those cases.
public class LightVolume { public class LightVolume {
private final GridAlignedBB volume; private final GridAlignedBB sampleVolume;
private final GridAlignedBB textureVolume;
private ByteBuffer lightData; private ByteBuffer lightData;
private boolean bufferDirty; private boolean bufferDirty;
private int glTexture; private int glTexture;
public LightVolume(GridAlignedBB volume) { public LightVolume(GridAlignedBB textureVolume, GridAlignedBB sampleVolume) {
// the gpu requires that all textures have power of 2 side lengths // the gpu requires that all textures have power of 2 side lengths
if (!volume.hasPowerOf2Sides()) if (!textureVolume.hasPowerOf2Sides())
throw new IllegalArgumentException("LightVolume must have power of 2 side lengths"); throw new IllegalArgumentException("LightVolume must have power of 2 side lengths");
this.volume = volume; this.textureVolume = textureVolume;
this.sampleVolume = sampleVolume;
this.glTexture = GL11.glGenTextures(); this.glTexture = GL11.glGenTextures();
this.lightData = MemoryUtil.memAlloc(this.volume.volume() * 2); // TODO: maybe figure out how to pack light coords into a single byte this.lightData = MemoryUtil.memAlloc(this.textureVolume.volume() * 2); // TODO: maybe figure out how to pack light coords into a single byte
} }
public GridAlignedBB getBox() { public GridAlignedBB getTextureVolume() {
return GridAlignedBB.copy(volume); return GridAlignedBB.copy(textureVolume);
}
public GridAlignedBB getSampleVolume() {
return GridAlignedBB.copy(sampleVolume);
} }
public int getMinX() { public int getMinX() {
return volume.minX; return textureVolume.minX;
} }
public int getMinY() { public int getMinY() {
return volume.minY; return textureVolume.minY;
} }
public int getMinZ() { public int getMinZ() {
return volume.minZ; return textureVolume.minZ;
} }
public int getMaxX() { public int getMaxX() {
return volume.maxX; return textureVolume.maxX;
} }
public int getMaxY() { public int getMaxY() {
return volume.maxY; return textureVolume.maxY;
} }
public int getMaxZ() { public int getMaxZ() {
return volume.maxZ; return textureVolume.maxZ;
} }
public int getSizeX() { public int getSizeX() {
return volume.sizeX(); return textureVolume.sizeX();
} }
public int getSizeY() { public int getSizeY() {
return volume.sizeY(); return textureVolume.sizeY();
} }
public int getSizeZ() { public int getSizeZ() {
return volume.sizeZ(); return textureVolume.sizeZ();
} }
public void notifyLightUpdate(ILightReader world, LightType type, SectionPos location) { public void notifyLightUpdate(ILightReader world, LightType type, SectionPos location) {
GridAlignedBB changedVolume = GridAlignedBB.fromSection(location); GridAlignedBB changedVolume = GridAlignedBB.fromSection(location);
changedVolume.intersectAssign(volume); // compute the region contained by us that has dirty lighting data. changedVolume.intersectAssign(sampleVolume); // compute the region contained by us that has dirty lighting data.
if (!changedVolume.empty()) { if (!changedVolume.empty()) {
if (type == LightType.BLOCK) copyBlock(world, changedVolume); if (type == LightType.BLOCK) copyBlock(world, changedVolume);
@ -88,11 +98,11 @@ public class LightVolume {
public void initialize(ILightReader world) { public void initialize(ILightReader world) {
BlockPos.Mutable pos = new BlockPos.Mutable(); BlockPos.Mutable pos = new BlockPos.Mutable();
int shiftX = volume.minX; int shiftX = textureVolume.minX;
int shiftY = volume.minY; int shiftY = textureVolume.minY;
int shiftZ = volume.minZ; int shiftZ = textureVolume.minZ;
volume.forEachContained((x, y, z) -> { textureVolume.forEachContained((x, y, z) -> {
pos.setPos(x, y, z); pos.setPos(x, y, z);
int blockLight = world.getLightLevel(LightType.BLOCK, pos); int blockLight = world.getLightLevel(LightType.BLOCK, pos);
@ -111,9 +121,9 @@ public class LightVolume {
public void copyBlock(ILightReader world, GridAlignedBB worldVolume) { public void copyBlock(ILightReader world, GridAlignedBB worldVolume) {
BlockPos.Mutable pos = new BlockPos.Mutable(); BlockPos.Mutable pos = new BlockPos.Mutable();
int xShift = volume.minX; int xShift = textureVolume.minX;
int yShift = volume.minY; int yShift = textureVolume.minY;
int zShift = volume.minZ; int zShift = textureVolume.minZ;
worldVolume.forEachContained((x, y, z) -> { worldVolume.forEachContained((x, y, z) -> {
pos.setPos(x, y, z); pos.setPos(x, y, z);
@ -133,9 +143,9 @@ public class LightVolume {
public void copySky(ILightReader world, GridAlignedBB worldVolume) { public void copySky(ILightReader world, GridAlignedBB worldVolume) {
BlockPos.Mutable pos = new BlockPos.Mutable(); BlockPos.Mutable pos = new BlockPos.Mutable();
int xShift = volume.minX; int xShift = textureVolume.minX;
int yShift = volume.minY; int yShift = textureVolume.minY;
int zShift = volume.minZ; int zShift = textureVolume.minZ;
worldVolume.forEachContained((x, y, z) -> { worldVolume.forEachContained((x, y, z) -> {
pos.setPos(x, y, z); pos.setPos(x, y, z);
@ -159,7 +169,7 @@ public class LightVolume {
GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_R, GL20.GL_MIRRORED_REPEAT); GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_R, GL20.GL_MIRRORED_REPEAT);
GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_T, GL20.GL_MIRRORED_REPEAT); GL11.glTexParameteri(GL13.GL_TEXTURE_3D, GL13.GL_TEXTURE_WRAP_T, GL20.GL_MIRRORED_REPEAT);
if (bufferDirty) { if (bufferDirty) {
GL12.glTexImage3D(GL12.GL_TEXTURE_3D, 0, GL40.GL_RG8, volume.sizeX(), volume.sizeY(), volume.sizeZ(), 0, GL40.GL_RG, GL40.GL_UNSIGNED_BYTE, lightData); GL12.glTexImage3D(GL12.GL_TEXTURE_3D, 0, GL40.GL_RG8, textureVolume.sizeX(), textureVolume.sizeY(), textureVolume.sizeZ(), 0, GL40.GL_RG, GL40.GL_UNSIGNED_BYTE, lightData);
bufferDirty = false; bufferDirty = false;
} }
} }
@ -199,6 +209,6 @@ public class LightVolume {
} }
private int index(int x, int y, int z) { private int index(int x, int y, int z) {
return (x + volume.sizeX() * (y + z * volume.sizeY())) * 2; return (x + textureVolume.sizeX() * (y + z * textureVolume.sizeY())) * 2;
} }
} }

View file

@ -2,17 +2,33 @@ package com.simibubi.create.foundation.render.light;
import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.foundation.render.ContraptionRenderDispatcher; import com.simibubi.create.foundation.render.ContraptionRenderDispatcher;
import com.simibubi.create.foundation.render.RenderedContraption;
import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer;
import com.simibubi.create.foundation.utility.Pair;
import com.simibubi.create.foundation.utility.outliner.AABBOutline; import com.simibubi.create.foundation.utility.outliner.AABBOutline;
import com.simibubi.create.foundation.utility.outliner.Outline;
import java.util.ArrayList;
public class LightVolumeDebugger { public class LightVolumeDebugger {
public static void render(MatrixStack ms, SuperRenderTypeBuffer buffer) { public static void render(MatrixStack ms, SuperRenderTypeBuffer buffer) {
ContraptionRenderDispatcher.renderers.values() ContraptionRenderDispatcher.renderers.values()
.stream() .stream()
.map(r -> r.getLighter().lightVolume.getBox()) .flatMap(r -> {
.map(volume -> new AABBOutline(GridAlignedBB.toAABB(volume))) 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)); .forEach(outline -> outline.render(ms, buffer));
} }
} }