5 #ifndef ENGINE_PROJ_PHYSICS_HPP
6 #define ENGINE_PROJ_PHYSICS_HPP
8 #include "Components.hpp"
13 #include "PhysicsParam.hpp"
39 static std::vector<CollisionPoint>
Raycast(
const Scene& scene, glm::vec3 pos, glm::vec3 dir,
float maxDistance = FLT_MAX) {
41 std::vector<CollisionPoint> points;
69 std::vector<CollisionPoint> points =
Raycast(scene, pos, dir, maxDistance);
71 float penetration = 0;
72 for (
const auto& point : points) {
73 if (point.PenetrationDepth > penetration) {
74 collisionPoint = point;
78 return collisionPoint;
90 if (
GJK(colliderA, colliderB, simplex, type)) {
94 return EPA2(simplex, colliderA, colliderB);
115 Support l_edges[EPA_MAX_NUM_LOOSE_EDGES][2];
122 glm::vec3 search_dir;
129 faces[0] = {simplex[0], simplex[1], simplex[2]};
130 faces[0].normal = normalize(cross(simplex[1] - simplex[0], simplex[2] - simplex[0]));
131 faces[1] = {simplex[0], simplex[2], simplex[3]};
132 faces[1].normal = normalize(cross(simplex[2] - simplex[0], simplex[3] - simplex[0]));
133 faces[2] = {simplex[0], simplex[3], simplex[1]};
134 faces[2].normal = normalize(cross(simplex[3] - simplex[0], simplex[1] - simplex[0]));
135 faces[3] = {simplex[1], simplex[3], simplex[2]};
136 faces[3].normal = normalize(cross(simplex[3] - simplex[1], simplex[2] - simplex[1]));
139 for (
int iterations = 0; iterations < EPA_MAX_NUM_ITERATIONS; iterations++) {
141 min_dist = dot(faces[0][0], faces[0].normal);
145 for (
int i = 1; i < num_faces; i++) {
146 n_dist = dot(faces[i][0], faces[i].normal);
147 if (n_dist < min_dist) {
153 search_dir = faces[c_idx].normal;
155 n_dist = dot(current, search_dir);
158 if (n_dist - min_dist < EPA_TOLERANCE) {
160 Barycentric({0, 0, 0}, faces[c_idx][0], faces[c_idx][1], faces[c_idx][2], u, v, w);
161 glm::vec3 v1 = u * faces[c_idx][0].supportA + v * faces[c_idx][1].supportA + w * faces[c_idx][2].supportA;
162 glm::vec3 v2 = u * faces[c_idx][0].supportB + v * faces[c_idx][1].supportB + w * faces[c_idx][2].supportB;
164 return {search_dir, {v1, v2}, n_dist,
true};
170 for (
int i = 0; i < num_faces; i++) {
171 if (dot(faces[i].normal, current - faces[i][0]) > 0) {
176 for (
int j = 0; j < FACE_VERTS; j++) {
177 current_edge[0] = faces[i][j];
178 current_edge[1] = faces[i][(j + 1) % 3];
182 for (
int k = 0; k < num_loose_edges; k++) {
183 if (l_edges[k][1] == current_edge[0] && l_edges[k][0] == current_edge[1]) {
188 l_edges[k][0] = l_edges[num_loose_edges - 1][0];
189 l_edges[k][1] = l_edges[num_loose_edges - 1][1];
200 if (num_loose_edges >= EPA_MAX_NUM_LOOSE_EDGES)
break;
202 l_edges[num_loose_edges][0] = current_edge[0];
203 l_edges[num_loose_edges][1] = current_edge[1];
209 faces[i] = faces[num_faces - 1];
218 for (
int i = 0; i < num_loose_edges; i++) {
221 if (num_faces >= EPA_MAX_NUM_FACES)
break;
224 faces[num_faces][0] = l_edges[i][0];
225 faces[num_faces][1] = l_edges[i][1];
226 faces[num_faces][2] = current;
227 faces[num_faces].normal = normalize(cross(l_edges[i][0] - l_edges[i][1], l_edges[i][0] - current));
231 if (dot(faces[num_faces][0], faces[num_faces].normal) + EPA_BIAS < 0) {
232 temp = faces[num_faces][0];
233 faces[num_faces][0] = faces[num_faces][1];
234 faces[num_faces][1] = temp;
235 faces[num_faces].normal = -faces[num_faces].normal;
242 printf(
"EPA did not converge\n");
244 search_dir = faces[c_idx].normal;
245 n_dist = dot(faces[c_idx][0], search_dir);
247 Barycentric({0, 0, 0}, faces[c_idx][0], faces[c_idx][1], faces[c_idx][2], u, v, w);
248 glm::vec3 v1 = u * faces[c_idx][0].supportA + v * faces[c_idx][1].supportA + w * faces[c_idx][2].supportA;
249 glm::vec3 v2 = u * faces[c_idx][0].supportB + v * faces[c_idx][1].supportB + w * faces[c_idx][2].supportB;
251 return {search_dir, {v1, v2}, n_dist,
true};
266 glm::vec3 direction = -support;
269 for (
int iterations = 0; iterations < GJK_MAX_NUM_ITERATIONS; iterations++) {
274 if (dot(support, direction) <= 0) {
275 return type == D2 && simplex.
index == 3;
279 simplex.push(support);
282 if (NextSimplex(simplex, direction, type)) {
291 switch (simplex.
index) {
292 case 2:
return Line(simplex, direction);
293 case 3:
return Triangle(simplex, direction);
294 case 4:
return type == D2 || Tetrahedron(simplex, direction);
301 static bool Line(Simplex &simplex, glm::vec3 &direction) {
302 Support& a = simplex[0];
303 Support& b = simplex[1];
305 glm::vec3 ab = b - a;
310 if (dot(ab, ao) > 0) {
311 direction = cross(cross(ab, ao), ab);
321 static bool Triangle(Simplex &simplex, glm::vec3 &direction) {
322 Support& a = simplex[0];
323 Support& b = simplex[1];
324 Support& c = simplex[2];
326 glm::vec3 ab = b - a;
327 glm::vec3 ac = c - a;
330 glm::vec3 abc = cross(ab, ac);
333 if (dot(cross(abc, ac), ao) > 0) {
335 if (dot(ac, ao) > 0) {
338 direction = cross(cross(ac, ao), ac);
341 return Line(simplex = {a, b}, direction);
345 if (dot(cross(ab, abc), ao) > 0) {
347 return Line(simplex = {a, b}, direction);
350 if (dot(abc, ao) > 0) {
364 static bool Tetrahedron(Simplex &simplex, glm::vec3 &direction) {
365 Support& a = simplex[0];
366 Support& b = simplex[1];
367 Support& c = simplex[2];
368 Support& d = simplex[3];
370 glm::vec3 ab = b - a;
371 glm::vec3 ac = c - a;
372 glm::vec3 ad = d - a;
375 glm::vec3 abc = cross(ab, ac);
376 glm::vec3 acd = cross(ac, ad);
377 glm::vec3 adb = cross(ad, ab);
380 if (dot(abc, ao) > 0) {
381 return Triangle(simplex = {a, b, c}, direction);
384 if (dot(acd, ao) > 0) {
385 return Triangle(simplex = {a, c, d}, direction);
388 if (dot(adb, ao) > 0) {
389 return Triangle(simplex = {a, d, b}, direction);
423 int numPosIterations = 1;
424 int numSubsteps = 10;
426 float h = dt / (float) numSubsteps;
431 for (
auto &elem : elements) {
432 elem->x = elem->tf->position;
433 elem->q = elem->tf->rotation;
434 elem->v = elem->rb->velocity;
435 elem->w = elem->rb->w;
438 for (
int sStep = 0; sStep < numSubsteps; sStep++) {
439 for (
auto &elem : elements) {
441 if (!elem->rb->kinematic)
444 elem->xPrev = elem->x;
445 elem->qPrev = elem->q;
448 elem->v += h * elem->rb->force * elem->rb->iMass;
449 elem->x += h * elem->v;
451 glm::mat3 t1 = elem->rb->invMoment;
452 glm::mat3 t2 = elem->rb->moment;
455 elem->w += h * t1 * (elem->rb->t - glm::cross(elem->w, (t2 * elem->w)));
458 elem->q = elem->q + (h * 0.5f) * glm::qua<float>{0, elem->w.x, elem->w.y, elem->w.z} * elem->q;
459 elem->q = glm::normalize(elem->q);
464 for (
int _ = 0; _ < numPosIterations; _++) {
469 for (
auto &elem : elements) {
471 elem->v = (elem->x - elem->xPrev) / h;
473 elem->dQ = elem->q * glm::inverse(elem->qPrev);
475 elem->w = (2.0f / h) * glm::vec3(elem->dQ.x, elem->dQ.y, elem->dQ.z);
477 elem->w = elem->dQ.w >= 0 ? elem->w : -elem->w;
479 elem->v -= elem->v * glm::min(1.0f, h * elem->rb->airDrag);
480 elem->w -= elem->w * glm::min(1.0f, h * elem->rb->angularDrag);
484 for (
auto &elem : elements) {
486 elem->tf->position = elem->x;
487 elem->tf->rotation = elem->q;
488 if (!elem->rb->kinematic)
490 elem->rb->velocity = elem->v;
491 elem->rb->w = elem->w;
506 glm::vec3 p1 = pe1->x + pe1->q * joint->positionA;
508 if (pe2 ==
nullptr) {
509 p2 = joint->positionB;
511 p2 = pe2->x + pe2->q * joint->positionB;
515 glm::vec3 normal = p2 - p1;
516 float sqrDist = glm::length2(normal);
517 if (sqrDist > joint->maxLength * joint->maxLength) {
518 float invDepth = glm::inversesqrt(sqrDist);
519 return CollisionPoint{normal * invDepth, {p1, p2}, joint->maxLength - (1.0f/invDepth),
true};
520 }
else if (sqrDist < joint->minLength * joint->minLength) {
522 float invDepth = glm::inversesqrt(sqrDist);
523 return CollisionPoint{normal * -invDepth, {p1, p2}, (1.0f/invDepth) - joint->minLength,
true};
537 for (
const auto& joint : joints) {
558 for (
int i = 0; i < elements.size(); ++i) {
560 if (pe1->c ==
nullptr)
continue;
562 for (
int j = i + 1; j < elements.size(); ++j) {
564 if (pe2->c ==
nullptr)
continue;
567 pe1->c->processCollision(pe2);
568 pe2->c->processCollision(pe1);
569 if (!pe1->c->trigger && !pe2->c->trigger && type != D2) {
590 bool e1Static = (e1 ==
nullptr) || !e1->rb->kinematic;
591 bool e2Static = (e2 ==
nullptr) || !e2->rb->kinematic;
593 if (e1Static && e2Static) {
603 glm::vec3 prod1 = glm::cross(r1, cp.
Normal);
605 w1 = e1->rb->iMass + glm::dot(prod1, e1->rb->invMoment * prod1);
611 glm::vec3 prod2 = glm::cross(r2, cp.
Normal);
612 w2 = e2->rb->iMass + glm::dot(prod2, e2->rb->invMoment * prod2);
616 float aTilde = a / (h * h);
622 float dLambda = (-cp.
PenetrationDepth - (aTilde * lambda)) / (w1 + w2 + aTilde);
623 glm::vec3 p = dLambda * cp.
Normal;
630 e1->x += p * e1->rb->iMass;
631 e1->q += 0.5f * glm::qua<float>{0.f, e1->rb->invMoment * glm::cross(r1, p)} * e1->q;
635 e2->x -= p * e2->rb->iMass;
636 e2->q -= 0.5f * glm::qua<float>{0.f, e2->rb->invMoment * glm::cross(r2, p)} * e2->q;
650 ECS ecs = scene.GetECS();
651 auto out = std::vector<Ref<Joint>>();
653 auto s_rb = CreateRef<RigidBody>();
654 s_rb->setMomentCube(0, 0, 0, 0);
659 joint->rigidBody = rb;
661 if (joint->connectedRigidBody ==
nullptr) {
662 joint->connectedRigidBody = s_rb;
665 out.emplace_back(joint);
678 auto out = std::vector<Ref<PhysicsEntity>>();
679 auto s_rb = CreateRef<RigidBody>();
680 s_rb->setMomentCube(0, 0, 0, 0);
681 s_rb->kinematic =
false;
683 ECS ecs = scene.GetECS();
695 rb->physicsEntity = physicsEntity;
697 out.emplace_back(physicsEntity);
709 auto out = std::vector<Ref<PhysicsEntity>>();
710 auto s_rb = CreateRef<RigidBody>();
711 s_rb->setMomentCube(0, 0, 0, 0);
712 s_rb->kinematic =
false;
714 ECS ecs = scene.GetECS();
727 rb->physicsEntity = physicsEntity;
728 physicsEntity->x = physicsEntity->tf->position;
729 physicsEntity->q = physicsEntity->tf->rotation;
730 out.emplace_back(physicsEntity);
747 support.supportA = shapeA.furthestInDir(norm);
748 support.supportB = shapeB.furthestInDir(-norm);
749 return support = support.supportA - support.supportB;
768 static void Barycentric(
const glm::vec3 &p,
const glm::vec3 &a,
const glm::vec3 &b,
const glm::vec3 &c,
769 float &u,
float &v,
float &w) {
770 glm::vec3 v0 = b - a, v1 = c - a, v2 = p - a;
771 float d00 = dot(v0, v0);
772 float d01 = dot(v0, v1);
773 float d11 = dot(v1, v1);
774 float d20 = dot(v2, v0);
775 float d21 = dot(v2, v1);
776 float invDenom = 1.0f / (d00 * d11 - d01 * d01);
777 v = (d11 * d20 - d01 * d21) * invDenom;
778 w = (d00 * d21 - d01 * d20) * invDenom;
785 #endif //ENGINE_PROJ_PHYSICS_HPP