Collision refinements

- Fixed reversed matrices and swapped rotation axes passed into the collision resolver
- Temporarily reduced collision manifold generation to collisions that are NOT edge-to-edge collisions.
- Enabled collision response for clockwork bearings
This commit is contained in:
simibubi 2020-06-19 14:14:42 +02:00
parent 56fe0c9c8a
commit d9105b4e60
7 changed files with 203 additions and 51 deletions

View file

@ -73,6 +73,7 @@ public class ClientEvents {
SuperRenderTypeBuffer buffer = SuperRenderTypeBuffer.getInstance();
CreateClient.schematicHandler.render(ms, buffer);
CreateClient.outliner.renderOutlines(ms, buffer);
// CollisionDebugger.render(ms, buffer);
buffer.draw();
ms.pop();
@ -110,6 +111,7 @@ public class ClientEvents {
double delta = event.getScrollDelta();
// CollisionDebugger.onScroll(delta);
boolean cancelled = CreateClient.schematicHandler.mouseScrolled(delta)
|| CreateClient.schematicAndQuillHandler.mouseScrolled(delta) || FilteringHandler.onScroll(delta)
|| ScrollValueHandler.onScroll(delta);

View file

@ -109,6 +109,7 @@ public class CreateClient {
KineticDebugger.tick();
ZapperRenderHandler.tick();
ExtendoGripRenderHandler.tick();
// CollisionDebugger.tick();
outliner.tickOutlines();
}

View file

@ -65,32 +65,36 @@ public class ContraptionCollider {
if (entity instanceof PlayerEntity && !world.isRemote)
return;
Vec3d centerOf = VecHelper.getCenterOf(BlockPos.ZERO);
Vec3d centerOfBlock = VecHelper.getCenterOf(BlockPos.ZERO);
Vec3d entityPosition = entity.getPositionVec();
Vec3d centerY = new Vec3d(0, entity.getBoundingBox()
.getYSize() / 2, 0);
Vec3d position = entityPosition.subtract(contraptionPosition)
.subtract(centerOf);
.subtract(centerOfBlock)
.add(centerY);
position =
VecHelper.rotate(position, -contraptionRotation.x, -contraptionRotation.y, -contraptionRotation.z);
position = position.add(centerOf)
VecHelper.rotate(position, -contraptionRotation.z, -contraptionRotation.y, -contraptionRotation.x);
position = position.add(centerOfBlock)
.subtract(centerY)
.subtract(entityPosition);
AxisAlignedBB localBB = entity.getBoundingBox()
.offset(position)
.grow(1.0E-7D);
OrientedBB obb = new OrientedBB(localBB);
if (!contraptionRotation.equals(Vec3d.ZERO)) {
Matrix3d rotation = new Matrix3d().asIdentity();
rotation.multiply(new Matrix3d().asXRotation(AngleHelper.rad(contraptionRotation.x)));
rotation.multiply(new Matrix3d().asYRotation(AngleHelper.rad(contraptionRotation.y)));
rotation.multiply(new Matrix3d().asZRotation(AngleHelper.rad(contraptionRotation.z)));
obb.setRotation(rotation);
}
ReuseableStream<VoxelShape> potentialHits = getPotentiallyCollidedShapes(world, contraption, localBB);
if (potentialHits.createStream()
.count() == 0)
continue;
OrientedBB obb = new OrientedBB(localBB);
if (!contraptionRotation.equals(Vec3d.ZERO)) {
Matrix3d rotation = new Matrix3d().asIdentity();
rotation.multiply(new Matrix3d().asXRotation(AngleHelper.rad(contraptionRotation.z)));
rotation.multiply(new Matrix3d().asYRotation(AngleHelper.rad(contraptionRotation.y)));
rotation.multiply(new Matrix3d().asZRotation(AngleHelper.rad(contraptionRotation.x)));
obb.setRotation(rotation);
}
MutableBoolean onCollide = new MutableBoolean(true);
potentialHits.createStream()
.forEach(shape -> {
@ -98,12 +102,12 @@ public class ContraptionCollider {
Vec3d intersect = obb.intersect(bb);
if (intersect == null)
return;
intersect = VecHelper.rotate(intersect, contraptionRotation.x, contraptionRotation.y,
contraptionRotation.z);
intersect = VecHelper.rotate(intersect, contraptionRotation.z, contraptionRotation.y,
contraptionRotation.x);
obb.setCenter(obb.getCenter()
.add(intersect));
entity.move(MoverType.PISTON, intersect);
entity.move(MoverType.PLAYER, intersect);
Vec3d entityMotion = entity.getMotion();
if (entityMotion.getX() > 0 == intersect.getX() < 0)

View file

@ -47,6 +47,10 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe
if (running && Contraption.isFrozen())
disassemble();
if (hourHand != null)
hourHand.collisionTick();
if (minuteHand != null)
minuteHand.collisionTick();
if (!world.isRemote && assembleNextTick) {
assembleNextTick = false;

View file

@ -0,0 +1,82 @@
package com.simibubi.create.foundation.collision;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.AllSpecialTextures;
import com.simibubi.create.CreateClient;
import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.MatrixStacker;
import com.simibubi.create.foundation.utility.outliner.AABBOutline;
import net.minecraft.client.Minecraft;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.RayTraceResult.Type;
import net.minecraft.util.math.Vec3d;
public class CollisionDebugger {
static AxisAlignedBB staticBB = new AxisAlignedBB(BlockPos.ZERO.up(10));
static OrientedBB movingBB = new OrientedBB(new AxisAlignedBB(BlockPos.ZERO));
static Vec3d seperation;
static double angle = 0;
static AABBOutline outline;
public static void onScroll(double delta) {
angle += delta;
movingBB.setRotation(new Matrix3d().asZRotation(AngleHelper.rad(angle)));
}
public static void render(MatrixStack ms, SuperRenderTypeBuffer buffer) {
ms.push();
outline = new AABBOutline(movingBB.getAsAxisAlignedBB());
outline.getParams()
.withFaceTexture(seperation == null ? AllSpecialTextures.CHECKERED : null)
.colored(0xffffff);
if (seperation != null)
outline.getParams()
.lineWidth(1 / 64f)
.colored(0xff6544);
MatrixStacker.of(ms)
.translate(movingBB.center);
ms.peek()
.getModel()
.multiply(movingBB.rotation.getAsMatrix4f());
MatrixStacker.of(ms)
.translateBack(movingBB.center);
outline.render(ms, buffer);
ms.pop();
ms.push();
if (seperation != null) {
outline.getParams()
.colored(0x65ff44)
.lineWidth(1 / 32f);
MatrixStacker.of(ms)
.translate(seperation)
.translate(movingBB.center);
ms.peek()
.getModel()
.multiply(movingBB.rotation.getAsMatrix4f());
MatrixStacker.of(ms)
.translateBack(movingBB.center);
outline.render(ms, buffer);
}
ms.pop();
}
public static void tick() {
staticBB = new AxisAlignedBB(BlockPos.ZERO.up(60));
RayTraceResult mouse = Minecraft.getInstance().objectMouseOver;
if (mouse != null && mouse.getType() == Type.BLOCK) {
BlockRayTraceResult hit = (BlockRayTraceResult) mouse;
movingBB.setCenter(hit.getHitVec());
seperation = movingBB.intersect(staticBB);
}
CreateClient.outliner.showAABB(staticBB, staticBB)
.withFaceTexture(seperation == null ? AllSpecialTextures.CHECKERED : null);
}
}

View file

@ -1,7 +1,10 @@
package com.simibubi.create.foundation.collision;
import net.minecraft.client.renderer.Matrix4f;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
public class Matrix3d {
@ -113,5 +116,26 @@ public class Matrix3d {
public Matrix3d copy() {
return new Matrix3d().add(this);
}
float[] conversionBuffer = new float[16];
@OnlyIn(Dist.CLIENT)
public Matrix4f getAsMatrix4f() {
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
conversionBuffer[j * 4 + i] = i == j ? 1 : 0;
conversionBuffer[0] = (float) m00;
conversionBuffer[1] = (float) m01;
conversionBuffer[2] = (float) m02;
conversionBuffer[4] = (float) m10;
conversionBuffer[5] = (float) m11;
conversionBuffer[6] = (float) m12;
conversionBuffer[8] = (float) m20;
conversionBuffer[9] = (float) m21;
conversionBuffer[10] = (float) m22;
return new Matrix4f(conversionBuffer);
}
}

View file

@ -5,6 +5,8 @@ import static java.lang.Math.abs;
import org.apache.commons.lang3.mutable.MutableDouble;
import org.apache.commons.lang3.mutable.MutableObject;
import com.simibubi.create.CreateClient;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.Vec3d;
@ -30,10 +32,7 @@ public class OrientedBB {
public Vec3d intersect(AxisAlignedBB bb) {
Vec3d extentsA = extentsFromBB(bb);
// Inverse rotation, to bring our OBB to AA space
Vec3d intersects = separateBBs(bb.getCenter(), center, extentsA, extents, rotation.transpose());
// clean up
rotation.transpose();
Vec3d intersects = separateBBs(bb.getCenter(), center, extentsA, extents, rotation);
return intersects;
}
@ -60,9 +59,9 @@ public class OrientedBB {
Vec3d uA1 = new Vec3d(0, 1, 0);
Vec3d uA2 = new Vec3d(0, 0, 1);
Vec3d uB0 = new Vec3d(m.m00, m.m01, m.m02);
Vec3d uB1 = new Vec3d(m.m10, m.m11, m.m12);
Vec3d uB2 = new Vec3d(m.m20, m.m21, m.m22);
Vec3d uB0 = new Vec3d(m.m00, m.m10, m.m20);
Vec3d uB1 = new Vec3d(m.m01, m.m11, m.m21);
Vec3d uB2 = new Vec3d(m.m02, m.m12, m.m22);
checkCount = 0;
@ -74,34 +73,42 @@ public class OrientedBB {
|| isSeparatedAlong(bestAxis, bestSep, uA2, t.z, eA.z, a20 * eB.x + a21 * eB.y + a22 * eB.z)
// Separate along B's local axes
|| isSeparatedAlong(bestAxis, bestSep, uB0, t.x * m.m00 + t.y * m.m10 + t.z * m.m20,
|| isSeparatedAlong(bestAxis, bestSep, uB0, (t.x * m.m00 + t.y * m.m10 + t.z * m.m20),
eA.x * a00 + eA.y * a10 + eA.z * a20, eB.x)
|| isSeparatedAlong(bestAxis, bestSep, uB1, t.x * m.m01 + t.y * m.m11 + t.z * m.m21,
|| isSeparatedAlong(bestAxis, bestSep, uB1, (t.x * m.m01 + t.y * m.m11 + t.z * m.m21),
eA.x * a01 + eA.y * a11 + eA.z * a21, eB.y)
|| isSeparatedAlong(bestAxis, bestSep, uB2, t.x * m.m02 + t.y * m.m12 + t.z * m.m22,
|| isSeparatedAlong(bestAxis, bestSep, uB2, (t.x * m.m02 + t.y * m.m12 + t.z * m.m22),
eA.x * a02 + eA.y * a12 + eA.z * a22, eB.z)
// Separate along axes perpendicular to AxB
|| isSeparatedAlong(bestAxis, bestSep, uA0.crossProduct(uB0), t.z * m.m10 - t.y * m.m20,
eA.y * a20 + eA.z * a10, eB.y * a02 + eB.z * a01)
|| isSeparatedAlong(bestAxis, bestSep, uA0.crossProduct(uB1), t.z * m.m11 - t.y * m.m21,
eA.y * a21 + eA.z * a11, eB.x * a02 + eB.z * a00)
|| isSeparatedAlong(bestAxis, bestSep, uA0.crossProduct(uB2), t.z * m.m12 - t.y * m.m22,
eA.y * a22 + eA.z * a12, eB.x * a01 + eB.y * a00)
/*
* The following checks (edge-to-edge) need special separation logic. They are
* not necessary as long as the obb is only rotated around one axis at a time
* (Which is the case for contraptions at the moment)
*
*/
|| isSeparatedAlong(bestAxis, bestSep, uA1.crossProduct(uB0), t.x * m.m20 - t.z * m.m00,
eA.x * a20 + eA.z * a00, eB.y * a12 + eB.z * a11)
|| isSeparatedAlong(bestAxis, bestSep, uA1.crossProduct(uB1), t.x * m.m21 - t.z * m.m01,
eA.x * a21 + eA.z * a01, eB.x * a12 + eB.z * a10)
|| isSeparatedAlong(bestAxis, bestSep, uA1.crossProduct(uB2), t.x * m.m22 - t.z * m.m02,
eA.x * a22 + eA.z * a02, eB.x * a11 + eB.y * a10)
|| isSeparatedAlong(bestAxis, bestSep, uA2.crossProduct(uB0), t.y * m.m00 - t.x * m.m10,
eA.x * a10 + eA.y * a00, eB.y * a22 + eB.z * a21)
|| isSeparatedAlong(bestAxis, bestSep, uA2.crossProduct(uB1), t.y * m.m01 - t.x * m.m11,
eA.x * a11 + eA.y * a01, eB.x * a22 + eB.z * a20)
|| isSeparatedAlong(bestAxis, bestSep, uA2.crossProduct(uB2), t.y * m.m02 - t.x * m.m12,
eA.x * a12 + eA.y * a02, eB.x * a21 + eB.y * a20)))
// Separate along axes perpendicular to AxB
// || isSeparatedAlong(bestAxis, bestSep, uA0.crossProduct(uB0), t.z * m.m10 - t.y * m.m20,
// eA.y * a20 + eA.z * a10, eB.y * a02 + eB.z * a01)
// || isSeparatedAlong(bestAxis, bestSep, uA0.crossProduct(uB1), t.z * m.m11 - t.y * m.m21,
// eA.y * a21 + eA.z * a11, eB.x * a02 + eB.z * a00)
// || isSeparatedAlong(bestAxis, bestSep, uA0.crossProduct(uB2), t.z * m.m12 - t.y * m.m22,
// eA.y * a22 + eA.z * a12, eB.x * a01 + eB.y * a00)
//
// || isSeparatedAlong(bestAxis, bestSep, uA1.crossProduct(uB0), t.x * m.m20 - t.z * m.m00,
// eA.x * a20 + eA.z * a00, eB.y * a12 + eB.z * a11)
// || isSeparatedAlong(bestAxis, bestSep, uA1.crossProduct(uB1), t.x * m.m21 - t.z * m.m01,
// eA.x * a21 + eA.z * a01, eB.x * a12 + eB.z * a10)
// || isSeparatedAlong(bestAxis, bestSep, uA1.crossProduct(uB2), t.x * m.m22 - t.z * m.m02,
// eA.x * a22 + eA.z * a02, eB.x * a11 + eB.y * a10)
//
// || isSeparatedAlong(bestAxis, bestSep, uA2.crossProduct(uB0), t.y * m.m00 - t.x * m.m10,
// eA.x * a10 + eA.y * a00, eB.y * a22 + eB.z * a21)
// || isSeparatedAlong(bestAxis, bestSep, uA2.crossProduct(uB1), t.y * m.m01 - t.x * m.m11,
// eA.x * a11 + eA.y * a01, eB.x * a22 + eB.z * a20)
// || isSeparatedAlong(bestAxis, bestSep, uA2.crossProduct(uB2), t.y * m.m02 - t.x * m.m12,
// eA.x * a12 + eA.y * a02, eB.x * a21 + eB.y * a20)
))
return bestAxis.getValue()
.normalize()
@ -121,18 +128,41 @@ public class OrientedBB {
double diff = distance - (rA + rB);
if (diff > 0)
return true;
if (distance != 0 && -diff < abs(bestSeparation.getValue())) {
bestAxis.setValue(axis);
bestSeparation.setValue(Math.signum(TL) * abs(diff));
boolean isBestSeperation = distance != 0 && -(diff) <= abs(bestSeparation.getValue());
// boolean isBestSeperation = checkCount == 12; // Debug specific separations
if (isBestSeperation) {
bestAxis.setValue(axis.normalize());
double sTL = Math.signum(TL);
double value = sTL * abs(diff);
bestSeparation.setValue(value);
// Visualize values
// if (CollisionDebugger.staticBB != null) {
// Vec3d normalizedAxis = axis.normalize();
// showDebugLine(Vec3d.ZERO, normalizedAxis.scale(TL), 0xbb00bb, "tl", 4);
// showDebugLine(Vec3d.ZERO, normalizedAxis.scale(sTL * rA), 0xff4444, "ra", 3);
// showDebugLine(normalizedAxis.scale(sTL * (distance - rB)), normalizedAxis.scale(TL), 0x4444ff, "rb", 2);
// showDebugLine(normalizedAxis.scale(sTL * (distance - rB)),
// normalizedAxis.scale(sTL * (distance - rB) + value), 0xff9966, "separation", 1);
// System.out.println("TL:" + TL + ", rA: " + rA + ", rB: " + rB);
// }
}
return false;
}
static void showDebugLine(Vec3d relativeStart, Vec3d relativeEnd, int color, String id, int offset) {
Vec3d center = CollisionDebugger.staticBB.getCenter()
.add(0, 1 + offset / 16f, 0);
CreateClient.outliner.showLine(id + checkCount, center.add(relativeStart), center.add(relativeEnd))
.colored(color)
.lineWidth(1 / 32f);
}
public Matrix3d getRotation() {
return rotation;
}
public void setRotation(Matrix3d rotation) {
this.rotation = rotation;
}
@ -140,9 +170,14 @@ public class OrientedBB {
public Vec3d getCenter() {
return center;
}
public void setCenter(Vec3d center) {
this.center = center;
}
public AxisAlignedBB getAsAxisAlignedBB() {
return new AxisAlignedBB(0, 0, 0, 0, 0, 0).offset(center)
.grow(extents.x, extents.y, extents.z);
}
}