Point in a 3D plane - nearly working... but not quite!
in
Programming Questions
•
8 months ago
Hi
I'm working on some basic 3D physics and I'm trying to get a point to bounce off an inclined plane. After scouring the web I think I've got a reliable way of detecting when the point's velocity vector intersects the plane defined by the three vertices of the triangle. I also think I've got a working way of detecting if that velocity/plane intersection point lies within the triangle defined by the three vertices. I think I've also got a working way of calculating the reflection vector of the velocity against the plane. So far so good. What I don't have working reliably is when the point has reliably collided with the plane. As you can see from the code below I'm doing a comparison on the y axis values and confirming that the velocity vector points downward. While this test largely works it triggers a false positive at the apex of the bounce forcing an unnatural return trajectory.
So, the question is, what is the best way to test for the point/plane intersection conditions being true? And I guess secondly, have I made a stupid mistake somewhere else that's leading to this behaviour? I'd like to allow for perfectly elastic collisions in the first instance with the opportunity to apply a coefficient of restitution ultimately.
Happy to take hints rather than outright solutions as I'd prefer to solve myself if possible...but this has been bugging me for a few days now!
Thanks in advance for any assistance
Cheers
Matt
PS I know this can all be done with toxilibs but I'd like to try and roll my own solution out of curiosity's sake in the first instance.
I'm working on some basic 3D physics and I'm trying to get a point to bounce off an inclined plane. After scouring the web I think I've got a reliable way of detecting when the point's velocity vector intersects the plane defined by the three vertices of the triangle. I also think I've got a working way of detecting if that velocity/plane intersection point lies within the triangle defined by the three vertices. I think I've also got a working way of calculating the reflection vector of the velocity against the plane. So far so good. What I don't have working reliably is when the point has reliably collided with the plane. As you can see from the code below I'm doing a comparison on the y axis values and confirming that the velocity vector points downward. While this test largely works it triggers a false positive at the apex of the bounce forcing an unnatural return trajectory.
So, the question is, what is the best way to test for the point/plane intersection conditions being true? And I guess secondly, have I made a stupid mistake somewhere else that's leading to this behaviour? I'd like to allow for perfectly elastic collisions in the first instance with the opportunity to apply a coefficient of restitution ultimately.
Happy to take hints rather than outright solutions as I'd prefer to solve myself if possible...but this has been bugging me for a few days now!
Thanks in advance for any assistance
Cheers
Matt
PS I know this can all be done with toxilibs but I'd like to try and roll my own solution out of curiosity's sake in the first instance.
- PVector gravity;
InclinedPlane inclinedPlane;
int moverCount;
Mover[] moverList;
void setup() {
size(1000, 600, P3D);
colorMode(RGB, 255, 255, 255, 255);
noStroke();
smooth(5);
gravity = new PVector(0, -0.01, 0);
inclinedPlane = new InclinedPlane();
moverCount = 1;
moverList = new Mover[moverCount];
for (int i=0; i< moverCount; i++) {
moverList[i] = new Mover();
}
}
void draw() {
background(100);
translate(width/2, (height/4)*3, 0);
rotateY(mouseX/200.0);
lights();
inclinedPlane.render();
for (int i=0; i< moverCount; i++) {
moverList[i].applyForce(gravity);
moverList[i].update();
moverList[i].render();
}
}
class Mover {
PVector location;
PVector velocity;
PVector acceleration;
Mover() {
location = new PVector(random(100), 400, random(-100));
velocity = new PVector(0, 0, 0);
acceleration = new PVector(0, 0, 0);
}
void applyForce(PVector inputForce) {
acceleration.add(inputForce);
}
void update() {
velocity.add(acceleration);
location.add(velocity);
acceleration.mult(0);
PVector intersectionPoint = inclinedPlane.getRayIntersection(location, velocity);
if (velocity.y<0&&location.y < intersectionPoint.y) {//is this the best test?
if (inclinedPlane.isPointInTriangle(intersectionPoint)) {
velocity = inclinedPlane.getReflectionVector(velocity);
}
}
}
void render() {
pushStyle();
pushMatrix();
translate(location.x, -location.y, location.z);
ambient(128, 0, 0);
fill(255, 0, 0);
sphere(5);
popMatrix();
popStyle();
}
}
class InclinedPlane {
PVector vertex1;
PVector vertex2;
PVector vertex3;
PVector centroid;
PVector planeNormal;
float normalDisplayLength;
PVector displayNormal;
PVector pointInPlane;
InclinedPlane() {
vertex1 = new PVector(0, 0, 0);
vertex2 = new PVector(200, 100, 0);
vertex3 = new PVector(0, 50, -200);
PVector planeVector1_2 = PVector.sub(vertex2, vertex1);
PVector planeVector1_3 = PVector.sub(vertex3, vertex1);
PVector midPlaneVector1_2 = PVector.div(planeVector1_2, 2);
PVector bisection = PVector.sub(midPlaneVector1_2, vertex3);
bisection.mult(2/3.0);
centroid = PVector.add(vertex3, bisection);
planeNormal = planeVector1_2.cross(planeVector1_3);
planeNormal.normalize();
normalDisplayLength = 20;
displayNormal = PVector.mult(planeNormal, normalDisplayLength);
pointInPlane = new PVector(0, 0, 0);
}
PVector getRayIntersection(PVector inputOrigin, PVector inputVector) {
PVector normalisedInput = inputVector.get();
normalisedInput.normalize();
PVector pointOffset = PVector.sub(vertex1, inputOrigin);
float dot1 = PVector.dot(planeNormal, pointOffset);
float dot2 = PVector.dot(planeNormal, normalisedInput);
float t = dot1/dot2;
PVector scaledVector = PVector.mult(normalisedInput, t);
pointInPlane = PVector.add(inputOrigin, scaledVector);
return pointInPlane;
}
PVector getReflectionVector(PVector inputVector) {
PVector normalisedInput = inputVector.get();
normalisedInput.normalize();
float doubleDotProduct = 2 * PVector.dot(normalisedInput, planeNormal);
PVector scaledNormal = PVector.mult(planeNormal, doubleDotProduct);
PVector reflectionVector = PVector.sub(normalisedInput, scaledNormal);
return reflectionVector;
}
boolean isPointInTriangle(PVector inputPoint) {
// Compute vectors
PVector v0 = PVector.sub(vertex3, vertex1);
PVector v1 = PVector.sub(vertex2, vertex1);
PVector v2 = PVector.sub(inputPoint, vertex1);
// Compute dot products
float dot00 = PVector.dot(v0, v0);
float dot01 = PVector.dot(v0, v1);
float dot02 = PVector.dot(v0, v2);
float dot11 = PVector.dot(v1, v1);
float dot12 = PVector.dot(v1, v2);
// Compute barycentric coordinates
float invDenom = 1 / ((dot00 * dot11) - (dot01 * dot01));
float u = ((dot11 * dot02) - (dot01 * dot12)) * invDenom;
float v = ((dot00 * dot12) - (dot01 * dot02)) * invDenom;
// Check if point is in triangle
if ((u >= 0) && (v >= 0) && (u + v < 1)) {
return true;
}
else {
return false;
}
}
void render() {
pushStyle();
stroke(0, 0, 255);
line(centroid.x, -centroid.y, centroid.z, centroid.x+displayNormal.x, -(centroid.y+displayNormal.y), centroid.z+displayNormal.z);
popStyle();
pushStyle();
pushMatrix();
translate(pointInPlane.x, -pointInPlane.y, pointInPlane.z);
fill(0, 255, 0);
ambient(0, 128, 0);
sphere(2);
popMatrix();
popStyle();
fill(130);
beginShape();
vertex(vertex1.x, -vertex1.y, vertex1.z);
vertex(vertex2.x, -vertex2.y, vertex2.z);
vertex(vertex3.x, -vertex3.y, vertex3.z);
endShape();
}
}
1