Projected stepheight

- The oriented collision response now accounts for an entities' step height to automatically climb blocks such as stairs or slabs
This commit is contained in:
simibubi 2020-07-19 20:54:29 +02:00
parent 53a58def49
commit 5ebb44f50b
4 changed files with 80 additions and 27 deletions

View file

@ -222,7 +222,7 @@ public class ContraptionCollider {
// params.colored(0x4499ff); // params.colored(0x4499ff);
continue; continue;
} }
Vec3d separation = intersect.asSeparationVec(); Vec3d separation = intersect.asSeparationVec(entity.stepHeight);
if (separation != null && !separation.equals(Vec3d.ZERO)) { if (separation != null && !separation.equals(Vec3d.ZERO)) {
collisionResponse.setValue(currentResponse.add(separation)); collisionResponse.setValue(currentResponse.add(separation));
// Debug.debugChat("Collision " + currentResponse.add(separation) // Debug.debugChat("Collision " + currentResponse.add(separation)

View file

@ -6,6 +6,7 @@ import com.simibubi.create.CreateClient;
import com.simibubi.create.foundation.collision.ContinuousOBBCollider.ContinuousSeparationManifold; import com.simibubi.create.foundation.collision.ContinuousOBBCollider.ContinuousSeparationManifold;
import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer;
import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.Debug;
import com.simibubi.create.foundation.utility.MatrixStacker; import com.simibubi.create.foundation.utility.MatrixStacker;
import com.simibubi.create.foundation.utility.outliner.AABBOutline; import com.simibubi.create.foundation.utility.outliner.AABBOutline;
@ -28,7 +29,9 @@ public class CollisionDebugger {
public static void onScroll(double delta) { public static void onScroll(double delta) {
angle += delta; angle += delta;
angle = (int) angle;
OBB.setRotation(new Matrix3d().asZRotation(AngleHelper.rad(angle))); OBB.setRotation(new Matrix3d().asZRotation(AngleHelper.rad(angle)));
Debug.debugMessage("Angle: " + angle);
} }
public static void render(MatrixStack ms, SuperRenderTypeBuffer buffer) { public static void render(MatrixStack ms, SuperRenderTypeBuffer buffer) {
@ -51,26 +54,26 @@ public class CollisionDebugger {
outline.render(ms, buffer); outline.render(ms, buffer);
ms.pop(); ms.pop();
ms.push(); // ms.push();
if (motion.length() != 0 && (seperation == null || seperation.getTimeOfImpact() != 1)) { // if (motion.length() != 0 && (seperation == null || seperation.getTimeOfImpact() != 1)) {
outline.getParams() // outline.getParams()
.colored(0x6544ff) // .colored(0x6544ff)
.lineWidth(1 / 32f); // .lineWidth(1 / 32f);
MatrixStacker.of(ms) // MatrixStacker.of(ms)
.translate(seperation != null ? seperation.getAllowedMotion(motion) : motion) // .translate(seperation != null ? seperation.getAllowedMotion(motion) : motion)
.translate(OBB.center); // .translate(OBB.center);
ms.peek() // ms.peek()
.getModel() // .getModel()
.multiply(OBB.rotation.getAsMatrix4f()); // .multiply(OBB.rotation.getAsMatrix4f());
MatrixStacker.of(ms) // MatrixStacker.of(ms)
.translateBack(OBB.center); // .translateBack(OBB.center);
outline.render(ms, buffer); // outline.render(ms, buffer);
} // }
ms.pop(); // ms.pop();
ms.push(); ms.push();
if (seperation != null) { if (seperation != null) {
Vec3d asSeparationVec = seperation.asSeparationVec(); Vec3d asSeparationVec = seperation.asSeparationVec(.5f);
if (asSeparationVec != null) { if (asSeparationVec != null) {
outline.getParams() outline.getParams()
.colored(0x65ff44) .colored(0x65ff44)
@ -91,7 +94,7 @@ public class CollisionDebugger {
public static void tick() { public static void tick() {
AABB = new AxisAlignedBB(BlockPos.ZERO.up(60)).offset(.5, 0, .5); AABB = new AxisAlignedBB(BlockPos.ZERO.up(60)).offset(.5, 0, .5);
motion = new Vec3d(0, -2, -.5f); motion = Vec3d.ZERO;
RayTraceResult mouse = Minecraft.getInstance().objectMouseOver; RayTraceResult mouse = Minecraft.getInstance().objectMouseOver;
if (mouse != null && mouse.getType() == Type.BLOCK) { if (mouse != null && mouse.getType() == Type.BLOCK) {
BlockRayTraceResult hit = (BlockRayTraceResult) mouse; BlockRayTraceResult hit = (BlockRayTraceResult) mouse;

View file

@ -33,6 +33,8 @@ public class ContinuousOBBCollider extends OBBCollider {
Vec3d uB2 = new Vec3d(m.m02, m.m12, m.m22); Vec3d uB2 = new Vec3d(m.m02, m.m12, m.m22);
checkCount = 0; checkCount = 0;
mf.stepSeparationAxis = uB1;
mf.stepSeparation = Double.MAX_VALUE;
if ( if (
// Separate along A's local axes (global XYZ) // Separate along A's local axes (global XYZ)
@ -60,29 +62,62 @@ public class ContinuousOBBCollider extends OBBCollider {
return true; return true;
double sTL = signum(TL); double sTL = signum(TL);
double value = sTL * abs(diff); double seperation = sTL * abs(diff);
double entryTime = 0; double entryTime = 0;
double exitTime = Double.MAX_VALUE; double exitTime = Double.MAX_VALUE;
if (!discreteCollision) { if (!discreteCollision) {
mf.isDiscreteCollision = false; mf.isDiscreteCollision = false;
if (abs(value) > abs(projectedMotion)) if (abs(seperation) > abs(projectedMotion))
return true; return true;
entryTime = abs(value) / abs(projectedMotion); entryTime = abs(seperation) / abs(projectedMotion);
exitTime = (diff + abs(rA) + abs(rB)) / abs(projectedMotion); exitTime = (diff + abs(rA) + abs(rB)) / abs(projectedMotion);
mf.latestCollisionEntryTime = Math.max(entryTime, mf.latestCollisionEntryTime); mf.latestCollisionEntryTime = Math.max(entryTime, mf.latestCollisionEntryTime);
mf.earliestCollisionExitTime = Math.min(exitTime, mf.earliestCollisionExitTime); mf.earliestCollisionExitTime = Math.min(exitTime, mf.earliestCollisionExitTime);
} }
Vec3d normalizedAxis = axis.normalize();
boolean isBestSeperation = distance != 0 && -(diff) <= abs(mf.separation); boolean isBestSeperation = distance != 0 && -(diff) <= abs(mf.separation);
// boolean isBestSeperation = discreteCollision && checkCount == 5; // Debug specific separations // boolean isBestSeperation = discreteCollision && checkCount == 5; // Debug specific separations
double dot = mf.stepSeparationAxis.dotProduct(axis);
if (dot != 0 && discreteCollision) {
Vec3d cross = axis.crossProduct(mf.stepSeparationAxis);
double dotSeparation = signum(dot) * TL - (rA + rB);
double stepSeparation = -dotSeparation;
Vec3d stepSeparationVec = axis;
if (!cross.equals(Vec3d.ZERO)) {
Vec3d sepVec = normalizedAxis.scale(dotSeparation);
Vec3d axisPlane = axis.crossProduct(cross);
Vec3d stepPlane = mf.stepSeparationAxis.crossProduct(cross);
stepSeparationVec =
sepVec.subtract(axisPlane.scale(sepVec.dotProduct(stepPlane) / axisPlane.dotProduct(stepPlane)));
stepSeparation = stepSeparationVec.length();
if (abs(mf.stepSeparation) > abs(stepSeparation) && stepSeparation != 0) {
// CollisionDebugger.showDebugLine(Vec3d.ZERO, sepVec, 0x111155, "stepsep", -16);
mf.stepSeparation = stepSeparation;
}
} else {
if (abs(mf.stepSeparation) > stepSeparation) {
mf.stepSeparation = stepSeparation;
// CollisionDebugger.showDebugLine(Vec3d.ZERO, stepSeparationVec, 0xff9999, "axis", -16);
}
}
// if (abs(mf.separation) < abs(stepSeparation) && stepSeparation != 0)
}
if (isBestSeperation) { if (isBestSeperation) {
mf.axis = axis.normalize(); mf.axis = normalizedAxis;
mf.separation = value; mf.separation = seperation;
// Visualize values // Visualize values
// if (CollisionDebugger.AABB != null) { // if (CollisionDebugger.AABB != null) {
@ -113,6 +148,9 @@ public class ContinuousOBBCollider extends OBBCollider {
double earliestCollisionExitTime = Double.MAX_VALUE; double earliestCollisionExitTime = Double.MAX_VALUE;
boolean isDiscreteCollision = true; boolean isDiscreteCollision = true;
Vec3d stepSeparationAxis;
double stepSeparation;
public double getTimeOfImpact() { public double getTimeOfImpact() {
if (latestCollisionEntryTime == UNDEFINED) if (latestCollisionEntryTime == UNDEFINED)
return UNDEFINED; return UNDEFINED;
@ -131,16 +169,23 @@ public class ContinuousOBBCollider extends OBBCollider {
.scale(getTimeOfImpact() * length); .scale(getTimeOfImpact() * length);
} }
@Override public Vec3d asSeparationVec(double obbStepHeight) {
public Vec3d asSeparationVec() { if (isDiscreteCollision) {
if (isDiscreteCollision) if (stepSeparation <= obbStepHeight)
return createSeparationVec(stepSeparation, stepSeparationAxis);
return super.asSeparationVec(); return super.asSeparationVec();
}
double t = getTimeOfImpact(); double t = getTimeOfImpact();
if (t == UNDEFINED) if (t == UNDEFINED)
return null; return null;
return Vec3d.ZERO; return Vec3d.ZERO;
} }
@Override
public Vec3d asSeparationVec() {
return asSeparationVec(0);
}
} }
} }

View file

@ -95,6 +95,11 @@ public class OBBCollider {
public Vec3d asSeparationVec() { public Vec3d asSeparationVec() {
double sep = separation; double sep = separation;
Vec3d axis = this.axis;
return createSeparationVec(sep, axis);
}
protected Vec3d createSeparationVec(double sep, Vec3d axis) {
return axis.normalize() return axis.normalize()
.scale(signum(sep) * (abs(sep) + 1E-4)); .scale(signum(sep) * (abs(sep) + 1E-4));
} }