Reuse contraption matrices

- Optimize memory usage by reusing ContraptionMatrices instances
This commit is contained in:
PepperBell 2021-08-05 17:48:35 -07:00
parent 26fbe97ae6
commit 333ef9ecbb
4 changed files with 80 additions and 67 deletions

View file

@ -7,47 +7,55 @@ import com.simibubi.create.foundation.utility.AnimationTickHolder;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.vector.Matrix4f; import net.minecraft.util.math.vector.Matrix4f;
import net.minecraft.util.math.vector.Vector3d;
/** /**
* LIFETIME: one frame
*
* <p> * <p>
* ContraptionMatrices must be re-created per-contraption per-frame * ContraptionMatrices must be cleared and setup per-contraption per-frame
* </p> * </p>
*/ */
public class ContraptionMatrices { public class ContraptionMatrices {
/** private final MatrixStack modelViewProjection = new MatrixStack();
* The results from using this are undefined. private final MatrixStack viewProjection = new MatrixStack();
*/ private final MatrixStack model = new MatrixStack();
public static final ContraptionMatrices EMPTY = new ContraptionMatrices(); private final Matrix4f world = new Matrix4f();
private final Matrix4f light = new Matrix4f();
private final MatrixStack modelViewProjection; private boolean ready;
private final MatrixStack viewProjection;
private final MatrixStack model;
private final Matrix4f world;
private final Matrix4f light;
private ContraptionMatrices() { public ContraptionMatrices() {
this.viewProjection = this.model = this.modelViewProjection = new MatrixStack(); world.setIdentity();
this.world = new Matrix4f(); light.setIdentity();
this.light = new Matrix4f();
} }
public ContraptionMatrices(MatrixStack viewProjection, AbstractContraptionEntity entity) { public void setup(MatrixStack viewProjection, AbstractContraptionEntity entity) {
this.viewProjection = copyStack(viewProjection);
float partialTicks = AnimationTickHolder.getPartialTicks(); float partialTicks = AnimationTickHolder.getPartialTicks();
this.model = creatModelMatrix(entity, partialTicks);
world = translateTo(entity, partialTicks); this.viewProjection.pushPose();
transform(this.viewProjection, viewProjection);
model.pushPose();
entity.doLocalTransforms(partialTicks, new MatrixStack[] { model });
light = getWorld().copy(); modelViewProjection.pushPose();
getLight().multiply(this.getModel() transform(modelViewProjection, viewProjection);
transform(modelViewProjection, model);
translateToEntity(world, entity, partialTicks);
light.set(world);
light.multiply(model
.last().pose()); .last().pose());
modelViewProjection = copyStack(viewProjection); ready = true;
transform(getModelViewProjection(), this.getModel()); }
public void clear() {
clearStack(modelViewProjection);
clearStack(viewProjection);
clearStack(model);
world.setIdentity();
light.setIdentity();
ready = false;
} }
public MatrixStack getModelViewProjection() { public MatrixStack getModelViewProjection() {
@ -70,28 +78,8 @@ public class ContraptionMatrices {
return light; return light;
} }
public static Matrix4f createModelViewPartial(AbstractContraptionEntity entity, float pt, Vector3d cameraPos) { public boolean isReady() {
float x = (float) (MathHelper.lerp(pt, entity.xOld, entity.getX()) - cameraPos.x); return ready;
float y = (float) (MathHelper.lerp(pt, entity.yOld, entity.getY()) - cameraPos.y);
float z = (float) (MathHelper.lerp(pt, entity.zOld, entity.getZ()) - cameraPos.z);
Matrix4f mat = Matrix4f.createTranslateMatrix(x, y, z);
Matrix4f modelMatrix = creatModelMatrix(entity, pt).last().pose();
mat.multiply(modelMatrix);
return mat;
}
public static MatrixStack creatModelMatrix(AbstractContraptionEntity entity, float partialTicks) {
MatrixStack model = new MatrixStack();
entity.doLocalTransforms(partialTicks, new MatrixStack[] { model});
return model;
}
public static Matrix4f translateTo(Entity entity, float partialTicks) {
double x = MathHelper.lerp(partialTicks, entity.xOld, entity.getX());
double y = MathHelper.lerp(partialTicks, entity.yOld, entity.getY());
double z = MathHelper.lerp(partialTicks, entity.zOld, entity.getZ());
return Matrix4f.createTranslateMatrix((float) x, (float) y, (float) z);
} }
public static void transform(MatrixStack ms, MatrixStack transform) { public static void transform(MatrixStack ms, MatrixStack transform) {
@ -103,11 +91,17 @@ public class ContraptionMatrices {
.normal()); .normal());
} }
public static MatrixStack copyStack(MatrixStack ms) { public static void translateToEntity(Matrix4f matrix, Entity entity, float partialTicks) {
MatrixStack cms = new MatrixStack(); double x = MathHelper.lerp(partialTicks, entity.xOld, entity.getX());
double y = MathHelper.lerp(partialTicks, entity.yOld, entity.getY());
transform(cms, ms); double z = MathHelper.lerp(partialTicks, entity.zOld, entity.getZ());
matrix.setTranslation((float) x, (float) y, (float) z);
return cms;
} }
public static void clearStack(MatrixStack ms) {
while (!ms.clear()) {
ms.popPose();
}
}
} }

View file

@ -79,7 +79,7 @@ public class ContraptionRenderDispatcher {
ContraptionMatrices matrices = renderInfo.getMatrices(); ContraptionMatrices matrices = renderInfo.getMatrices();
// something went wrong with the other rendering // something went wrong with the other rendering
if (matrices == null) return; if (!matrices.isReady()) return;
PlacementSimulationWorld renderWorld = renderInfo.renderWorld; PlacementSimulationWorld renderWorld = renderInfo.renderWorld;

View file

@ -1,9 +1,6 @@
package com.simibubi.create.content.contraptions.components.structureMovement.render; package com.simibubi.create.content.contraptions.components.structureMovement.render;
import javax.annotation.Nullable;
import com.jozufozu.flywheel.event.BeginFrameEvent; import com.jozufozu.flywheel.event.BeginFrameEvent;
import com.jozufozu.flywheel.event.RenderLayerEvent;
import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
@ -11,13 +8,12 @@ import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.worldWrappers.PlacementSimulationWorld; import com.simibubi.create.foundation.utility.worldWrappers.PlacementSimulationWorld;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.vector.Vector3d;
public class ContraptionRenderInfo { public class ContraptionRenderInfo {
public final Contraption contraption; public final Contraption contraption;
public final PlacementSimulationWorld renderWorld; public final PlacementSimulationWorld renderWorld;
private ContraptionMatrices matrices = ContraptionMatrices.EMPTY; private ContraptionMatrices matrices = new ContraptionMatrices();
private boolean visible; private boolean visible;
public ContraptionRenderInfo(Contraption contraption, PlacementSimulationWorld renderWorld) { public ContraptionRenderInfo(Contraption contraption, PlacementSimulationWorld renderWorld) {
@ -34,7 +30,7 @@ public class ContraptionRenderInfo {
} }
public void beginFrame(BeginFrameEvent event) { public void beginFrame(BeginFrameEvent event) {
matrices = null; matrices.clear();
AbstractContraptionEntity entity = contraption.entity; AbstractContraptionEntity entity = contraption.entity;
@ -49,7 +45,7 @@ public class ContraptionRenderInfo {
* Need to call this during RenderLayerEvent. * Need to call this during RenderLayerEvent.
*/ */
public void setupMatrices(MatrixStack viewProjection, double camX, double camY, double camZ) { public void setupMatrices(MatrixStack viewProjection, double camX, double camY, double camZ) {
if (matrices == null) { if (!matrices.isReady()) {
AbstractContraptionEntity entity = contraption.entity; AbstractContraptionEntity entity = contraption.entity;
viewProjection.pushPose(); viewProjection.pushPose();
@ -60,14 +56,14 @@ public class ContraptionRenderInfo {
viewProjection.translate(x, y, z); viewProjection.translate(x, y, z);
matrices = new ContraptionMatrices(viewProjection, entity); matrices.setup(viewProjection, entity);
viewProjection.popPose(); viewProjection.popPose();
} }
} }
/** /**
* If #setupMatrices is called correctly, this will not return null * If #setupMatrices is called correctly, the returned matrices will be ready
*/ */
public ContraptionMatrices getMatrices() { public ContraptionMatrices getMatrices() {
return matrices; return matrices;

View file

@ -15,6 +15,7 @@ import com.jozufozu.flywheel.core.model.IModel;
import com.jozufozu.flywheel.core.model.WorldModel; import com.jozufozu.flywheel.core.model.WorldModel;
import com.jozufozu.flywheel.event.BeginFrameEvent; import com.jozufozu.flywheel.event.BeginFrameEvent;
import com.jozufozu.flywheel.light.GridAlignedBB; 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.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionLighter; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionLighter;
@ -26,6 +27,7 @@ import net.minecraft.client.renderer.RenderType;
import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntity;
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.MathHelper;
import net.minecraft.util.math.vector.Matrix4f; import net.minecraft.util.math.vector.Matrix4f;
import net.minecraft.util.math.vector.Vector3d; import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.world.World; import net.minecraft.world.World;
@ -39,7 +41,8 @@ public class RenderedContraption extends ContraptionRenderInfo {
private final Map<RenderType, ModelRenderer> renderLayers = new HashMap<>(); private final Map<RenderType, ModelRenderer> renderLayers = new HashMap<>();
private Matrix4f modelViewPartial; private final Matrix4f modelViewPartial = new Matrix4f();
private boolean modelViewPartialReady;
private AxisAlignedBB lightBox; private AxisAlignedBB lightBox;
public RenderedContraption(Contraption contraption, PlacementSimulationWorld renderWorld) { public RenderedContraption(Contraption contraption, PlacementSimulationWorld renderWorld) {
@ -73,20 +76,31 @@ public class RenderedContraption extends ContraptionRenderInfo {
public void beginFrame(BeginFrameEvent event) { public void beginFrame(BeginFrameEvent event) {
super.beginFrame(event); super.beginFrame(event);
modelViewPartial.setIdentity();
modelViewPartialReady = false;
if (!isVisible()) return; if (!isVisible()) return;
kinetics.beginFrame(event.getInfo()); kinetics.beginFrame(event.getInfo());
Vector3d cameraPos = event.getCameraPos(); Vector3d cameraPos = event.getCameraPos();
modelViewPartial = ContraptionMatrices.createModelViewPartial(contraption.entity, AnimationTickHolder.getPartialTicks(), cameraPos);
lightBox = GridAlignedBB.toAABB(lighter.lightVolume.getTextureVolume()) lightBox = GridAlignedBB.toAABB(lighter.lightVolume.getTextureVolume())
.move(-cameraPos.x, -cameraPos.y, -cameraPos.z); .move(-cameraPos.x, -cameraPos.y, -cameraPos.z);
} }
@Override
public void setupMatrices(MatrixStack viewProjection, double camX, double camY, double camZ) {
super.setupMatrices(viewProjection, camX, camY, camZ);
if (!modelViewPartialReady) {
setupModelViewPartial(modelViewPartial, getMatrices().getModel().last().pose(), contraption.entity, camX, camY, camZ, AnimationTickHolder.getPartialTicks());
modelViewPartialReady = true;
}
}
void setup(ContraptionProgram shader) { void setup(ContraptionProgram shader) {
if (modelViewPartial == null || lightBox == null) return; if (!modelViewPartialReady || lightBox == null) return;
shader.bind(modelViewPartial, lightBox); shader.bind(modelViewPartial, lightBox);
lighter.lightVolume.bind(); lighter.lightVolume.bind();
} }
@ -144,4 +158,13 @@ public class RenderedContraption extends ContraptionRenderInfo {
private void buildActors() { private void buildActors() {
contraption.getActors().forEach(kinetics::createActor); contraption.getActors().forEach(kinetics::createActor);
} }
public static void setupModelViewPartial(Matrix4f matrix, Matrix4f modelMatrix, AbstractContraptionEntity entity, double camX, double camY, double camZ, float pt) {
float x = (float) (MathHelper.lerp(pt, entity.xOld, entity.getX()) - camX);
float y = (float) (MathHelper.lerp(pt, entity.yOld, entity.getY()) - camY);
float z = (float) (MathHelper.lerp(pt, entity.zOld, entity.getZ()) - camZ);
matrix.setTranslation(x, y, z);
matrix.multiply(modelMatrix);
}
} }