mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-15 15:43:42 +01:00
Frame rate and tick rate limiting with distance.
- Significant performance improvement when dealing with massive amounts of dynamic instances, otherwise marginal.
This commit is contained in:
parent
e91a15cf5f
commit
0b25f662dc
12 changed files with 141 additions and 43 deletions
|
@ -51,6 +51,8 @@ public class DeployerInstance extends ShaftInstance implements IDynamicInstance,
|
|||
relight(pos, pole.getInstance());
|
||||
|
||||
updateRotation(pole, hand, yRot, zRot, zRotPole);
|
||||
|
||||
beginFrame();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -15,6 +15,8 @@ import com.simibubi.create.foundation.render.backend.instancing.*;
|
|||
|
||||
import com.simibubi.create.foundation.render.backend.instancing.impl.OrientedModel;
|
||||
import com.simibubi.create.foundation.render.backend.instancing.impl.TransformedModel;
|
||||
|
||||
import net.minecraft.client.renderer.ActiveRenderInfo;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.gen.feature.template.Template;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
@ -44,14 +46,13 @@ public class ContraptionKineticRenderer extends InstancedTileRenderer<Contraptio
|
|||
materials.put(KineticRenderMaterials.ACTORS, new RenderMaterial<>(this, AllProgramSpecs.C_ACTOR, ActorModel::new));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
actors.forEach(ActorInstance::tick);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beginFrame(double cameraX, double cameraY, double cameraZ) {
|
||||
super.beginFrame(cameraX, cameraY, cameraZ);
|
||||
public void beginFrame(ActiveRenderInfo info, double cameraX, double cameraY, double cameraZ) {
|
||||
super.beginFrame(info, cameraX, cameraY, cameraZ);
|
||||
|
||||
actors.forEach(ActorInstance::beginFrame);
|
||||
}
|
||||
|
|
|
@ -28,20 +28,11 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
|||
import net.minecraft.block.BlockRenderType;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BlockModelRenderer;
|
||||
import net.minecraft.client.renderer.BlockRendererDispatcher;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.IRenderTypeBuffer;
|
||||
import net.minecraft.client.renderer.LightTexture;
|
||||
import net.minecraft.client.renderer.Matrix4f;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.RenderTypeLookup;
|
||||
import net.minecraft.client.renderer.WorldRenderer;
|
||||
import net.minecraft.client.renderer.*;
|
||||
import net.minecraft.client.renderer.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.SectionPos;
|
||||
import net.minecraft.world.ILightReader;
|
||||
import net.minecraft.world.LightType;
|
||||
import net.minecraft.world.World;
|
||||
|
@ -94,9 +85,9 @@ public class ContraptionRenderDispatcher {
|
|||
return contraption;
|
||||
}
|
||||
|
||||
public static void beginFrame(double camX, double camY, double camZ) {
|
||||
public static void beginFrame(ActiveRenderInfo info, double camX, double camY, double camZ) {
|
||||
for (RenderedContraption renderer : renderers.values()) {
|
||||
renderer.beginFrame(camX, camY, camZ);
|
||||
renderer.beginFrame(info, camX, camY, camZ);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,12 +20,7 @@ import com.simibubi.create.foundation.utility.worldWrappers.PlacementSimulationW
|
|||
import net.minecraft.block.BlockRenderType;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.BlockModelRenderer;
|
||||
import net.minecraft.client.renderer.BlockRendererDispatcher;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.Matrix4f;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.RenderTypeLookup;
|
||||
import net.minecraft.client.renderer.*;
|
||||
import net.minecraft.client.renderer.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.texture.OverlayTexture;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
|
@ -87,8 +82,8 @@ public class RenderedContraption {
|
|||
}
|
||||
}
|
||||
|
||||
public void beginFrame(double camX, double camY, double camZ) {
|
||||
kinetics.beginFrame(camX, camY, camZ);
|
||||
public void beginFrame(ActiveRenderInfo info, double camX, double camY, double camZ) {
|
||||
kinetics.beginFrame(info, camX, camY, camZ);
|
||||
|
||||
AbstractContraptionEntity entity = contraption.entity;
|
||||
float pt = AnimationTickHolder.getPartialTicks();
|
||||
|
|
|
@ -4,7 +4,6 @@ import com.simibubi.create.foundation.render.KineticRenderer;
|
|||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.client.renderer.*;
|
||||
import net.minecraft.client.renderer.texture.AtlasTexture;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import org.lwjgl.opengl.GL20;
|
||||
|
@ -57,8 +56,8 @@ public class RenderHooksMixin {
|
|||
double camY = cameraPos.getY();
|
||||
double camZ = cameraPos.getZ();
|
||||
|
||||
CreateClient.kineticRenderer.get(world).beginFrame(camX, camY, camZ);
|
||||
ContraptionRenderDispatcher.beginFrame(camX, camY, camZ);
|
||||
CreateClient.kineticRenderer.get(world).beginFrame(info, camX, camY, camZ);
|
||||
ContraptionRenderDispatcher.beginFrame(info, camX, camY, camZ);
|
||||
}
|
||||
|
||||
@Inject(at = @At("TAIL"), method = "checkBlockRerender")
|
||||
|
|
|
@ -15,6 +15,7 @@ import com.simibubi.create.foundation.render.backend.instancing.RenderMaterial;
|
|||
import com.simibubi.create.foundation.render.backend.instancing.impl.OrientedModel;
|
||||
import com.simibubi.create.foundation.render.backend.instancing.impl.TransformedModel;
|
||||
|
||||
import net.minecraft.client.renderer.ActiveRenderInfo;
|
||||
import net.minecraft.client.renderer.Matrix4f;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
|
@ -42,7 +43,7 @@ public class KineticRenderer extends InstancedTileRenderer<BasicProgram> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void beginFrame(double cameraX, double cameraY, double cameraZ) {
|
||||
public void beginFrame(ActiveRenderInfo info, double cameraX, double cameraY, double cameraZ) {
|
||||
int cX = MathHelper.floor(cameraX);
|
||||
int cY = MathHelper.floor(cameraY);
|
||||
int cZ = MathHelper.floor(cameraZ);
|
||||
|
@ -62,7 +63,7 @@ public class KineticRenderer extends InstancedTileRenderer<BasicProgram> {
|
|||
instancedTiles.forEach(this::add);
|
||||
}
|
||||
|
||||
super.beginFrame(cameraX, cameraY, cameraZ);
|
||||
super.beginFrame(info, cameraX, cameraY, cameraZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -17,6 +17,7 @@ import net.minecraft.client.renderer.Matrix4f;
|
|||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.Vector3f;
|
||||
import net.minecraft.client.world.ClientWorld;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.potion.Effects;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
@ -37,10 +38,13 @@ public class FastRenderDispatcher {
|
|||
}
|
||||
|
||||
public static void tick() {
|
||||
ClientWorld world = Minecraft.getInstance().world;
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
ClientWorld world = mc.world;
|
||||
|
||||
KineticRenderer kineticRenderer = CreateClient.kineticRenderer.get(world);
|
||||
kineticRenderer.tick();
|
||||
|
||||
Entity renderViewEntity = mc.renderViewEntity;
|
||||
kineticRenderer.tick(renderViewEntity.getX(), renderViewEntity.getY(), renderViewEntity.getZ());
|
||||
|
||||
ConcurrentHashMap.KeySetView<TileEntity, Boolean> map = queuedUpdates.get(world);
|
||||
map
|
||||
|
|
|
@ -9,9 +9,22 @@ package com.simibubi.create.foundation.render.backend.instancing;
|
|||
* <br><br> If your goal is offloading work to shaders, but you're unsure exactly how you need
|
||||
* to parameterize the instances, you're encouraged to implement this for prototyping.
|
||||
*/
|
||||
public interface IDynamicInstance {
|
||||
public interface IDynamicInstance extends IInstance {
|
||||
/**
|
||||
* Called every frame.
|
||||
*/
|
||||
void beginFrame();
|
||||
|
||||
/**
|
||||
* As a further optimization, dynamic instances that are far away are ticked less often.
|
||||
* This behavior can be disabled by returning false.
|
||||
*
|
||||
* <br> You might want to opt out of this if you want your animations to remain smooth
|
||||
* even when far away from the camera. It is recommended to keep this as is, however.
|
||||
*
|
||||
* @return <code>true</code> if your instance should be slow ticked.
|
||||
*/
|
||||
default boolean decreaseFramerateWithDistance() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package com.simibubi.create.foundation.render.backend.instancing;
|
||||
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
/**
|
||||
* A general interface providing information about any type of thing that could use
|
||||
* Flywheel's instanced rendering. Right now, that's only {@link InstancedTileRenderer},
|
||||
* but there could be an entity equivalent in the future.
|
||||
*/
|
||||
public interface IInstance {
|
||||
|
||||
BlockPos getWorldPosition();
|
||||
}
|
|
@ -16,10 +16,23 @@ package com.simibubi.create.foundation.render.backend.instancing;
|
|||
* </li>
|
||||
* </ul>
|
||||
*/
|
||||
public interface ITickableInstance {
|
||||
public interface ITickableInstance extends IInstance {
|
||||
|
||||
/**
|
||||
* Called every tick.
|
||||
*/
|
||||
void tick();
|
||||
|
||||
/**
|
||||
* As a further optimization, tickable instances that are far away are ticked less often.
|
||||
* This behavior can be disabled by returning false.
|
||||
*
|
||||
* <br> You might want to opt out of this if you want your animations to remain smooth
|
||||
* even when far away from the camera. It is recommended to keep this as is, however.
|
||||
*
|
||||
* @return <code>true</code> if your instance should be slow ticked.
|
||||
*/
|
||||
default boolean decreaseTickRateWithDistance() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,11 +10,9 @@ import com.simibubi.create.foundation.render.backend.gl.BasicProgram;
|
|||
import com.simibubi.create.foundation.render.backend.gl.shader.ShaderCallback;
|
||||
import com.simibubi.create.foundation.render.backend.instancing.impl.ModelData;
|
||||
import com.simibubi.create.foundation.render.backend.instancing.impl.OrientedData;
|
||||
import com.simibubi.create.foundation.utility.AnimationTickHolder;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.Matrix4f;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.*;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IBlockReader;
|
||||
|
@ -30,6 +28,8 @@ public abstract class InstancedTileRenderer<P extends BasicProgram> {
|
|||
|
||||
protected Map<MaterialType<?>, RenderMaterial<P, ?>> materials = new HashMap<>();
|
||||
|
||||
protected int frame;
|
||||
|
||||
protected InstancedTileRenderer() {
|
||||
registerMaterials();
|
||||
}
|
||||
|
@ -38,15 +38,74 @@ public abstract class InstancedTileRenderer<P extends BasicProgram> {
|
|||
|
||||
public abstract void registerMaterials();
|
||||
|
||||
public void tick() {
|
||||
if (tickableInstances.size() > 0)
|
||||
tickableInstances.values().forEach(ITickableInstance::tick);
|
||||
public void tick(double cameraX, double cameraY, double cameraZ) {
|
||||
// integer camera pos
|
||||
int cX = (int) cameraX;
|
||||
int cY = (int) cameraY;
|
||||
int cZ = (int) cameraZ;
|
||||
|
||||
if (tickableInstances.size() > 0) {
|
||||
for (ITickableInstance instance : tickableInstances.values()) {
|
||||
if (!instance.decreaseTickRateWithDistance()) {
|
||||
instance.tick();
|
||||
continue;
|
||||
}
|
||||
|
||||
public void beginFrame(double cameraX, double cameraY, double cameraZ) {
|
||||
BlockPos pos = instance.getWorldPosition();
|
||||
|
||||
int dX = pos.getX() - cX;
|
||||
int dY = pos.getY() - cY;
|
||||
int dZ = pos.getZ() - cZ;
|
||||
|
||||
int dSq = dX * dX + dY * dY + dZ * dZ;
|
||||
|
||||
int divisor = (dSq / 1024) + 1;
|
||||
|
||||
if (frame % divisor == 0)
|
||||
instance.tick();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void beginFrame(ActiveRenderInfo info, double cameraX, double cameraY, double cameraZ) {
|
||||
frame++;
|
||||
processQueuedAdditions();
|
||||
if (dynamicInstances.size() > 0)
|
||||
dynamicInstances.values().forEach(IDynamicInstance::beginFrame);
|
||||
|
||||
Vector3f look = info.getHorizontalPlane();
|
||||
float lookX = look.getX();
|
||||
float lookY = look.getY();
|
||||
float lookZ = look.getZ();
|
||||
|
||||
// integer camera pos
|
||||
int cX = (int) cameraX;
|
||||
int cY = (int) cameraY;
|
||||
int cZ = (int) cameraZ;
|
||||
|
||||
if (dynamicInstances.size() > 0) {
|
||||
for (IDynamicInstance dyn : dynamicInstances.values()) {
|
||||
if (!dyn.decreaseFramerateWithDistance()) {
|
||||
dyn.beginFrame();
|
||||
continue;
|
||||
}
|
||||
|
||||
BlockPos pos = dyn.getWorldPosition();
|
||||
|
||||
int dX = pos.getX() - cX;
|
||||
int dY = pos.getY() - cY;
|
||||
int dZ = pos.getZ() - cZ;
|
||||
|
||||
float dot = dX * lookX + dY * lookY + dZ * lookZ;
|
||||
|
||||
if (dot < 0) continue; // is it behind the camera?
|
||||
|
||||
int dSq = dX * dX + dY * dY + dZ * dZ;
|
||||
|
||||
int divisor = (dSq / 1024) + 1; // https://www.desmos.com/calculator/aaycpludsy
|
||||
|
||||
if (frame % divisor == 0)
|
||||
dyn.beginFrame();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void render(RenderType layer, Matrix4f viewProjection, double camX, double camY, double camZ) {
|
||||
|
|
|
@ -30,12 +30,13 @@ import java.util.stream.Stream;
|
|||
*
|
||||
* @param <T> The type of {@link TileEntity} your class is an instance of.
|
||||
*/
|
||||
public abstract class TileEntityInstance<T extends TileEntity> {
|
||||
public abstract class TileEntityInstance<T extends TileEntity> implements IInstance {
|
||||
|
||||
protected final InstancedTileRenderer<?> renderer;
|
||||
protected final T tile;
|
||||
protected final World world;
|
||||
protected final BlockPos pos;
|
||||
protected final BlockPos instancePos;
|
||||
protected final BlockState blockState;
|
||||
|
||||
public TileEntityInstance(InstancedTileRenderer<?> renderer, T tile) {
|
||||
|
@ -44,6 +45,7 @@ public abstract class TileEntityInstance<T extends TileEntity> {
|
|||
this.world = tile.getWorld();
|
||||
this.pos = tile.getPos();
|
||||
this.blockState = tile.getBlockState();
|
||||
this.instancePos = pos.subtract(renderer.getOriginCoordinate());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -89,7 +91,12 @@ public abstract class TileEntityInstance<T extends TileEntity> {
|
|||
* represents should be rendered at to appear in the correct location.
|
||||
*/
|
||||
public BlockPos getInstancePosition() {
|
||||
return pos.subtract(renderer.getOriginCoordinate());
|
||||
return instancePos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPos getWorldPosition() {
|
||||
return pos;
|
||||
}
|
||||
|
||||
protected void relight(BlockPos pos, IFlatLight<?>... models) {
|
||||
|
|
Loading…
Reference in a new issue