Accretion

- Combine rotating/actor instance types
- Preference towards actor, but the arbitrary pivot was never used
- Inline KineticInstance
- Remove magic 3/10 constant in rotating shader, instead use
  renderSeconds and multiply by 6 ahead of time
- Now the rotational speed is in degrees per second
This commit is contained in:
Jozufozu 2025-01-11 23:04:01 -08:00
parent 1fbfeb6f00
commit b2891263d6
12 changed files with 109 additions and 166 deletions

View file

@ -6,9 +6,9 @@ import com.simibubi.create.content.kinetics.simpleRelays.ShaftBlock;
import dev.engine_room.flywheel.api.visualization.VisualizationContext;
import dev.engine_room.flywheel.lib.visual.AbstractBlockEntityVisual;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.core.Vec3i;
import net.minecraft.world.level.block.state.BlockState;
public abstract class KineticBlockEntityVisual<T extends KineticBlockEntity> extends AbstractBlockEntityVisual<T> {
@ -32,7 +32,7 @@ public abstract class KineticBlockEntityVisual<T extends KineticBlockEntity> ext
protected final void updateRotation(RotatingInstance instance, Direction.Axis axis, float speed) {
instance.setRotationAxis(axis)
.setRotationOffset(getRotationOffset(axis))
.setRotationalSpeed(speed)
.setRotationalSpeed(speed * RotatingInstance.SPEED_MULTIPLIER)
.setColor(blockEntity)
.setChanged();
}
@ -51,7 +51,7 @@ public abstract class KineticBlockEntityVisual<T extends KineticBlockEntity> ext
protected final RotatingInstance setup(RotatingInstance key, Direction.Axis axis, float speed) {
key.setRotationAxis(axis)
.setRotationalSpeed(speed)
.setRotationalSpeed(speed * RotatingInstance.SPEED_MULTIPLIER)
.setRotationOffset(getRotationOffset(axis))
.setColor(blockEntity)
.setPosition(getVisualPosition())
@ -76,7 +76,7 @@ public abstract class KineticBlockEntityVisual<T extends KineticBlockEntity> ext
return shaft(rotationAxis());
}
public static float rotationOffset(BlockState state, Axis axis, BlockPos pos) {
public static float rotationOffset(BlockState state, Axis axis, Vec3i pos) {
if (shouldOffset(axis, pos)) {
return 22.5f;
} else {
@ -84,7 +84,7 @@ public abstract class KineticBlockEntityVisual<T extends KineticBlockEntity> ext
}
}
public static boolean shouldOffset(Axis axis, BlockPos pos) {
public static boolean shouldOffset(Axis axis, Vec3i pos) {
// Sum the components of the other 2 axes.
int x = (axis == Axis.X) ? 0 : pos.getX();
int y = (axis == Axis.Y) ? 0 : pos.getY();

View file

@ -1,69 +0,0 @@
package com.simibubi.create.content.kinetics.base;
import org.joml.Vector3f;
import dev.engine_room.flywheel.api.instance.InstanceHandle;
import dev.engine_room.flywheel.api.instance.InstanceType;
import dev.engine_room.flywheel.lib.instance.ColoredLitInstance;
import net.createmod.catnip.utility.theme.Color;
import net.minecraft.core.BlockPos;
public class KineticInstance extends ColoredLitInstance {
public float x;
public float y;
public float z;
public float rotationalSpeed;
public float rotationOffset;
protected KineticInstance(InstanceType<? extends KineticInstance> type, InstanceHandle handle) {
super(type, handle);
}
public KineticInstance setPosition(BlockPos pos) {
return setPosition(pos.getX(), pos.getY(), pos.getZ());
}
public KineticInstance setPosition(Vector3f pos) {
return setPosition(pos.x(), pos.y(), pos.z());
}
public KineticInstance setPosition(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
return this;
}
public KineticInstance nudge(float x, float y, float z) {
this.x += x;
this.y += y;
this.z += z;
return this;
}
public KineticInstance setColor(KineticBlockEntity blockEntity) {
colorRgb(colorFromBE(blockEntity));
return this;
}
public KineticInstance setColor(Color c) {
color(c.getRed(), c.getGreen(), c.getBlue());
return this;
}
public KineticInstance setRotationalSpeed(float rotationalSpeed) {
this.rotationalSpeed = rotationalSpeed;
return this;
}
public KineticInstance setRotationOffset(float rotationOffset) {
this.rotationOffset = rotationOffset;
return this;
}
public static int colorFromBE(KineticBlockEntity be) {
if (be.hasNetwork())
return Color.generateFromLong(be.network).getRGB();
return 0xFFFFFF;
}
}

View file

@ -1,20 +1,48 @@
package com.simibubi.create.content.kinetics.base;
import org.joml.Quaternionf;
import org.joml.Vector3f;
import dev.engine_room.flywheel.api.instance.InstanceHandle;
import dev.engine_room.flywheel.api.instance.InstanceType;
import dev.engine_room.flywheel.lib.instance.ColoredLitInstance;
import net.createmod.catnip.utility.theme.Color;
import net.minecraft.core.Direction;
import net.minecraft.core.Vec3i;
public class RotatingInstance extends ColoredLitInstance {
public static final float SPEED_MULTIPLIER = 6;
public class RotatingInstance extends KineticInstance {
public byte rotationAxisX;
public byte rotationAxisY;
public byte rotationAxisZ;
public float x;
public float y;
public float z;
/**
* Speed in degrees per second
*/
public float rotationalSpeed;
/**
* Offset in degrees
*/
public float rotationOffset;
public RotatingInstance(InstanceType<? extends KineticInstance> type, InstanceHandle handle) {
/**
* Base rotation of the instance, applied before kinetic rotation
*/
public final Quaternionf rotation = new Quaternionf();
public RotatingInstance(InstanceType<? extends RotatingInstance> type, InstanceHandle handle) {
super(type, handle);
}
public static int colorFromBE(KineticBlockEntity be) {
if (be.hasNetwork())
return Color.generateFromLong(be.network).getRGB();
return 0xFFFFFF;
}
public RotatingInstance setRotationAxis(Direction.Axis axis) {
Direction orientation = Direction.get(Direction.AxisDirection.POSITIVE, axis);
return setRotationAxis(orientation.step());
@ -31,4 +59,45 @@ public class RotatingInstance extends KineticInstance {
return this;
}
public RotatingInstance setPosition(Vec3i pos) {
return setPosition(pos.getX(), pos.getY(), pos.getZ());
}
public RotatingInstance setPosition(Vector3f pos) {
return setPosition(pos.x(), pos.y(), pos.z());
}
public RotatingInstance setPosition(float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
return this;
}
public RotatingInstance nudge(float x, float y, float z) {
this.x += x;
this.y += y;
this.z += z;
return this;
}
public RotatingInstance setColor(KineticBlockEntity blockEntity) {
colorRgb(colorFromBE(blockEntity));
return this;
}
public RotatingInstance setColor(Color c) {
color(c.getRed(), c.getGreen(), c.getBlue());
return this;
}
public RotatingInstance setRotationalSpeed(float rotationalSpeed) {
this.rotationalSpeed = rotationalSpeed;
return this;
}
public RotatingInstance setRotationOffset(float rotationOffset) {
this.rotationOffset = rotationOffset;
return this;
}
}

View file

@ -7,7 +7,6 @@ import org.joml.Quaternionf;
import com.simibubi.create.AllPartialModels;
import com.simibubi.create.content.kinetics.base.KineticBlockEntityVisual;
import com.simibubi.create.content.kinetics.base.KineticInstance;
import com.simibubi.create.content.kinetics.base.RotatingInstance;
import com.simibubi.create.content.processing.burner.ScrollInstance;
import com.simibubi.create.foundation.render.AllInstanceTypes;
@ -158,7 +157,7 @@ public class BeltVisual extends KineticBlockEntityVisual<BeltBlockEntity> {
.rotation(q)
.speed(0, speed * MAGIC_SCROLL_MULTIPLIER)
.offset(0, bottom ? SCROLL_OFFSET_BOTTOM : SCROLL_OFFSET_OTHERWISE)
.colorRgb(KineticInstance.colorFromBE(blockEntity))
.colorRgb(RotatingInstance.colorFromBE(blockEntity))
.setChanged();
return key;

View file

@ -1,11 +1,9 @@
package com.simibubi.create.content.kinetics.drill;
import org.joml.Quaternionf;
import com.simibubi.create.AllPartialModels;
import com.simibubi.create.content.contraptions.actors.ActorInstance;
import com.simibubi.create.content.contraptions.behaviour.MovementContext;
import com.simibubi.create.content.contraptions.render.ActorVisual;
import com.simibubi.create.content.kinetics.base.RotatingInstance;
import com.simibubi.create.foundation.render.AllInstanceTypes;
import com.simibubi.create.foundation.virtualWorld.VirtualRenderWorld;
@ -19,7 +17,7 @@ import net.minecraft.world.level.block.state.BlockState;
public class DrillActorVisual extends ActorVisual {
ActorInstance drillHead;
RotatingInstance drillHead;
private final Direction facing;
public DrillActorVisual(VisualizationContext visualizationContext, VirtualRenderWorld contraption, MovementContext context) {
@ -38,21 +36,22 @@ public class DrillActorVisual extends ActorVisual {
else
eulerY = facing.toYRot() + ((axis == Direction.Axis.X) ? 180 : 0);
drillHead = instancerProvider.instancer(AllInstanceTypes.ACTOR, Models.partial(AllPartialModels.DRILL_HEAD))
drillHead = instancerProvider.instancer(AllInstanceTypes.ROTATING, Models.partial(AllPartialModels.DRILL_HEAD))
.createInstance();
drillHead.rotation.rotationXYZ(eulerX * Mth.DEG_TO_RAD, eulerY * Mth.DEG_TO_RAD, 0);
drillHead.setPosition(context.localPos)
.setBlockLight(localBlockLight())
.setRotationOffset(0)
.setRotationAxis(0, 0, 1)
.setLocalRotation(new Quaternionf().rotationXYZ(eulerX * Mth.DEG_TO_RAD, eulerY * Mth.DEG_TO_RAD, 0))
.setSpeed(getSpeed(facing))
.setChanged();
.setRotationOffset(0)
.setRotationAxis(0, 0, 1)
.setRotationalSpeed(getSpeed(facing))
.light(localBlockLight(), 0)
.setChanged();
}
@Override
public void beginFrame() {
drillHead.setSpeed(getSpeed(facing))
drillHead.setRotationalSpeed(getSpeed(facing))
.setChanged();
}

View file

@ -45,7 +45,7 @@ public class GearboxVisual extends KineticBlockEntityVisual<GearboxBlockEntity>
.createInstance();
key.setRotationAxis(axis)
.setRotationalSpeed(getSpeed(direction))
.setRotationalSpeed(getSpeed(direction) * RotatingInstance.SPEED_MULTIPLIER)
.setRotationOffset(getRotationOffset(axis)).setColor(blockEntity)
.setPosition(getVisualPosition())
.light(blockLight, skyLight)

View file

@ -60,7 +60,7 @@ public class MixerVisual extends EncasedCogVisual implements SimpleDynamicVisual
mixerHead.setPosition(getVisualPosition())
.nudge(0, -renderedHeadOffset, 0)
.setRotationalSpeed(speed * 2)
.setRotationalSpeed(speed * 2 * RotatingInstance.SPEED_MULTIPLIER)
.setChanged();
}

View file

@ -4,7 +4,6 @@ import static com.simibubi.create.Create.asResource;
import org.lwjgl.system.MemoryUtil;
import com.simibubi.create.content.contraptions.actors.ActorInstance;
import com.simibubi.create.content.kinetics.base.RotatingInstance;
import com.simibubi.create.content.processing.burner.ScrollInstance;
@ -14,6 +13,7 @@ import dev.engine_room.flywheel.api.layout.IntegerRepr;
import dev.engine_room.flywheel.api.layout.LayoutBuilder;
import dev.engine_room.flywheel.lib.instance.SimpleInstanceType;
import dev.engine_room.flywheel.lib.util.ExtraMemoryOps;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@ -26,6 +26,7 @@ public class AllInstanceTypes {
.vector("color", FloatRepr.NORMALIZED_UNSIGNED_BYTE, 4)
.vector("light", IntegerRepr.SHORT, 2)
.vector("overlay", IntegerRepr.SHORT, 2)
.vector("rotation", FloatRepr.FLOAT, 4)
.vector("pos", FloatRepr.FLOAT, 3)
.scalar("speed", FloatRepr.FLOAT)
.scalar("offset", FloatRepr.FLOAT)
@ -38,14 +39,15 @@ public class AllInstanceTypes {
MemoryUtil.memPutByte(ptr + 3, instance.alpha);
ExtraMemoryOps.put2x16(ptr + 4, instance.light);
ExtraMemoryOps.put2x16(ptr + 8, instance.overlay);
MemoryUtil.memPutFloat(ptr + 12, instance.x);
MemoryUtil.memPutFloat(ptr + 16, instance.y);
MemoryUtil.memPutFloat(ptr + 20, instance.z);
MemoryUtil.memPutFloat(ptr + 24, instance.rotationalSpeed);
MemoryUtil.memPutFloat(ptr + 28, instance.rotationOffset);
MemoryUtil.memPutByte(ptr + 32, instance.rotationAxisX);
MemoryUtil.memPutByte(ptr + 33, instance.rotationAxisY);
MemoryUtil.memPutByte(ptr + 34, instance.rotationAxisZ);
ExtraMemoryOps.putQuaternionf(ptr + 12, instance.rotation);
MemoryUtil.memPutFloat(ptr + 28, instance.x);
MemoryUtil.memPutFloat(ptr + 32, instance.y);
MemoryUtil.memPutFloat(ptr + 36, instance.z);
MemoryUtil.memPutFloat(ptr + 40, instance.rotationalSpeed);
MemoryUtil.memPutFloat(ptr + 44, instance.rotationOffset);
MemoryUtil.memPutByte(ptr + 48, instance.rotationAxisX);
MemoryUtil.memPutByte(ptr + 49, instance.rotationAxisY);
MemoryUtil.memPutByte(ptr + 50, instance.rotationAxisZ);
})
.build();
@ -85,36 +87,6 @@ public class AllInstanceTypes {
})
.build();
public static final InstanceType<ActorInstance> ACTOR = SimpleInstanceType.builder(ActorInstance::new)
.cullShader(asResource("instance/cull/actor.glsl"))
.vertexShader(asResource("instance/actor.vert"))
.layout(LayoutBuilder.create()
.vector("pos", FloatRepr.FLOAT, 3)
.vector("light", IntegerRepr.SHORT, 2)
.scalar("offset", FloatRepr.FLOAT)
.vector("axis", FloatRepr.NORMALIZED_BYTE, 3)
.vector("rotation", FloatRepr.FLOAT, 4)
.vector("rotationCenter", FloatRepr.NORMALIZED_BYTE, 3)
.scalar("speed", FloatRepr.FLOAT)
.build())
.writer((ptr, instance) -> {
MemoryUtil.memPutFloat(ptr, instance.x);
MemoryUtil.memPutFloat(ptr + 4, instance.y);
MemoryUtil.memPutFloat(ptr + 8, instance.z);
MemoryUtil.memPutShort(ptr + 12, instance.blockLight);
MemoryUtil.memPutShort(ptr + 14, instance.skyLight);
MemoryUtil.memPutFloat(ptr + 16, instance.rotationOffset);
MemoryUtil.memPutByte(ptr + 20, instance.rotationAxisX);
MemoryUtil.memPutByte(ptr + 21, instance.rotationAxisY);
MemoryUtil.memPutByte(ptr + 22, instance.rotationAxisZ);
ExtraMemoryOps.putQuaternionf(ptr + 24, instance.rotation);
MemoryUtil.memPutByte(ptr + 40, instance.rotationCenterX);
MemoryUtil.memPutByte(ptr + 41, instance.rotationCenterY);
MemoryUtil.memPutByte(ptr + 42, instance.rotationCenterZ);
MemoryUtil.memPutFloat(ptr + 44, instance.speed);
})
.build();
public static void init() {
// noop
}

View file

@ -1,13 +0,0 @@
#include "flywheel:util/matrix.glsl"
#include "flywheel:util/quaternion.glsl"
void flw_instanceVertex(in FlwInstance instance) {
float degrees = instance.offset + flw_renderSeconds * instance.speed;
vec4 kineticRot = quaternionDegrees(instance.axis, degrees);
vec3 rotated = rotateByQuaternion(flw_vertexPos.xyz - instance.rotationCenter, kineticRot) + instance.rotationCenter;
flw_vertexPos.xyz = rotateByQuaternion(rotated - .5, instance.rotation) + instance.pos + .5;
flw_vertexNormal = rotateByQuaternion(rotateByQuaternion(flw_vertexNormal, kineticRot), instance.rotation);
flw_vertexLight = max(vec2(instance.light) / 256., flw_vertexLight);
}

View file

@ -1,8 +0,0 @@
void flw_transformBoundingSphere(in FlwInstance instance, inout vec3 center, inout float radius) {
// The instance will spin about the rotation center, so we need to expand the radius to account for that
float extraForKinetic = length(center - instance.rotationCenter);
float extraForModel = length(center - 0.5);
radius += extraForKinetic + extraForModel;
center += instance.pos;
}

View file

@ -1,5 +1,5 @@
void flw_transformBoundingSphere(in FlwInstance instance, inout vec3 center, inout float radius) {
// The instance will spin about (0.5, 0.5, 0.5), so we need to expand the radius to account for that
// The instance will spin about the rotation center, so we need to expand the radius to account for that
radius += length(center - 0.5);
center += instance.pos;
}

View file

@ -1,21 +1,15 @@
#include "flywheel:util/matrix.glsl"
const float uTime = 0.;
mat3 kineticRotation(float offset, float speed, vec3 axis) {
float degrees = offset + flw_renderTicks * speed * 3./10.;
return rotationDegrees(axis, degrees);
}
#include "flywheel:util/quaternion.glsl"
void flw_instanceVertex(in FlwInstance instance) {
mat3 spin = kineticRotation(instance.offset, instance.speed, instance.axis);
float degrees = instance.offset + flw_renderSeconds * instance.speed;
vec3 worldPos = spin * (flw_vertexPos.xyz - .5);
flw_vertexPos.xyz = worldPos.xyz + instance.pos + .5;
vec4 kineticRot = quaternionDegrees(instance.axis, degrees);
vec3 rotated = rotateByQuaternion(flw_vertexPos.xyz - .5, instance.rotation);
flw_vertexNormal = spin * flw_vertexNormal;
flw_vertexOverlay = instance.overlay;
flw_vertexPos.xyz = rotateByQuaternion(rotated, kineticRot) + instance.pos + .5;
flw_vertexNormal = rotateByQuaternion(rotateByQuaternion(flw_vertexNormal, instance.rotation), kineticRot);
flw_vertexLight = max(vec2(instance.light) / 256., flw_vertexLight);
flw_vertexOverlay = instance.overlay;
#if defined(DEBUG_RAINBOW)
flw_vertexColor = instance.color;