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.util.math.MathHelper;
import net.minecraft.util.math.vector.Matrix4f;
import net.minecraft.util.math.vector.Vector3d;
/**
* LIFETIME: one frame
*
* <p>
* ContraptionMatrices must be re-created per-contraption per-frame
* ContraptionMatrices must be cleared and setup per-contraption per-frame
* </p>
*/
public class ContraptionMatrices {
/**
* The results from using this are undefined.
*/
public static final ContraptionMatrices EMPTY = new ContraptionMatrices();
private final MatrixStack modelViewProjection = new MatrixStack();
private final MatrixStack viewProjection = new MatrixStack();
private final MatrixStack model = new MatrixStack();
private final Matrix4f world = new Matrix4f();
private final Matrix4f light = new Matrix4f();
private final MatrixStack modelViewProjection;
private final MatrixStack viewProjection;
private final MatrixStack model;
private final Matrix4f world;
private final Matrix4f light;
private boolean ready;
private ContraptionMatrices() {
this.viewProjection = this.model = this.modelViewProjection = new MatrixStack();
this.world = new Matrix4f();
this.light = new Matrix4f();
public ContraptionMatrices() {
world.setIdentity();
light.setIdentity();
}
public ContraptionMatrices(MatrixStack viewProjection, AbstractContraptionEntity entity) {
this.viewProjection = copyStack(viewProjection);
public void setup(MatrixStack viewProjection, AbstractContraptionEntity entity) {
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();
getLight().multiply(this.getModel()
modelViewProjection.pushPose();
transform(modelViewProjection, viewProjection);
transform(modelViewProjection, model);
translateToEntity(world, entity, partialTicks);
light.set(world);
light.multiply(model
.last().pose());
modelViewProjection = copyStack(viewProjection);
transform(getModelViewProjection(), this.getModel());
ready = true;
}
public void clear() {
clearStack(modelViewProjection);
clearStack(viewProjection);
clearStack(model);
world.setIdentity();
light.setIdentity();
ready = false;
}
public MatrixStack getModelViewProjection() {
@ -70,28 +78,8 @@ public class ContraptionMatrices {
return light;
}
public static Matrix4f createModelViewPartial(AbstractContraptionEntity entity, float pt, Vector3d cameraPos) {
float x = (float) (MathHelper.lerp(pt, entity.xOld, entity.getX()) - cameraPos.x);
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 boolean isReady() {
return ready;
}
public static void transform(MatrixStack ms, MatrixStack transform) {
@ -103,11 +91,17 @@ public class ContraptionMatrices {
.normal());
}
public static MatrixStack copyStack(MatrixStack ms) {
MatrixStack cms = new MatrixStack();
transform(cms, ms);
return cms;
public static void translateToEntity(Matrix4f matrix, 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());
matrix.setTranslation((float) x, (float) y, (float) z);
}
public static void clearStack(MatrixStack ms) {
while (!ms.clear()) {
ms.popPose();
}
}
}

View file

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

View file

@ -1,9 +1,6 @@
package com.simibubi.create.content.contraptions.components.structureMovement.render;
import javax.annotation.Nullable;
import com.jozufozu.flywheel.event.BeginFrameEvent;
import com.jozufozu.flywheel.event.RenderLayerEvent;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity;
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 net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.vector.Vector3d;
public class ContraptionRenderInfo {
public final Contraption contraption;
public final PlacementSimulationWorld renderWorld;
private ContraptionMatrices matrices = ContraptionMatrices.EMPTY;
private ContraptionMatrices matrices = new ContraptionMatrices();
private boolean visible;
public ContraptionRenderInfo(Contraption contraption, PlacementSimulationWorld renderWorld) {
@ -34,7 +30,7 @@ public class ContraptionRenderInfo {
}
public void beginFrame(BeginFrameEvent event) {
matrices = null;
matrices.clear();
AbstractContraptionEntity entity = contraption.entity;
@ -49,7 +45,7 @@ public class ContraptionRenderInfo {
* Need to call this during RenderLayerEvent.
*/
public void setupMatrices(MatrixStack viewProjection, double camX, double camY, double camZ) {
if (matrices == null) {
if (!matrices.isReady()) {
AbstractContraptionEntity entity = contraption.entity;
viewProjection.pushPose();
@ -60,14 +56,14 @@ public class ContraptionRenderInfo {
viewProjection.translate(x, y, z);
matrices = new ContraptionMatrices(viewProjection, entity);
matrices.setup(viewProjection, entity);
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() {
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.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;
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.util.math.AxisAlignedBB;
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.Vector3d;
import net.minecraft.world.World;
@ -39,7 +41,8 @@ public class RenderedContraption extends ContraptionRenderInfo {
private final Map<RenderType, ModelRenderer> renderLayers = new HashMap<>();
private Matrix4f modelViewPartial;
private final Matrix4f modelViewPartial = new Matrix4f();
private boolean modelViewPartialReady;
private AxisAlignedBB lightBox;
public RenderedContraption(Contraption contraption, PlacementSimulationWorld renderWorld) {
@ -73,20 +76,31 @@ public class RenderedContraption extends ContraptionRenderInfo {
public void beginFrame(BeginFrameEvent event) {
super.beginFrame(event);
modelViewPartial.setIdentity();
modelViewPartialReady = false;
if (!isVisible()) return;
kinetics.beginFrame(event.getInfo());
Vector3d cameraPos = event.getCameraPos();
modelViewPartial = ContraptionMatrices.createModelViewPartial(contraption.entity, AnimationTickHolder.getPartialTicks(), cameraPos);
lightBox = GridAlignedBB.toAABB(lighter.lightVolume.getTextureVolume())
.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) {
if (modelViewPartial == null || lightBox == null) return;
if (!modelViewPartialReady || lightBox == null) return;
shader.bind(modelViewPartial, lightBox);
lighter.lightVolume.bind();
}
@ -144,4 +158,13 @@ public class RenderedContraption extends ContraptionRenderInfo {
private void buildActors() {
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);
}
}