Guest User

Untitled

a guest
Feb 23rd, 2025
26
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.87 KB | None | 0 0
  1. #include <cmath>
  2. #include <vector>
  3.  
  4. // Basic 3D vector structure
  5. struct Vector3 {
  6.     float x, y, z;
  7.     Vector3() : x(0), y(0), z(0) {}
  8.     Vector3(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}
  9. };
  10.  
  11. // Overloaded operators for vector arithmetic
  12. inline Vector3 operator+(const Vector3& a, const Vector3& b) {
  13.     return Vector3(a.x + b.x, a.y + b.y, a.z + b.z);
  14. }
  15. inline Vector3 operator-(const Vector3& a, const Vector3& b) {
  16.     return Vector3(a.x - b.x, a.y - b.y, a.z - b.z);
  17. }
  18. inline Vector3 operator*(const Vector3& v, float s) {
  19.     return Vector3(v.x * s, v.y * s, v.z * s);
  20. }
  21. inline Vector3 operator*(float s, const Vector3& v) {
  22.     return v * s;
  23. }
  24. inline Vector3 operator/(const Vector3& v, float s) {
  25.     return Vector3(v.x / s, v.y / s, v.z / s);
  26. }
  27.  
  28. inline float dot(const Vector3& a, const Vector3& b) {
  29.     return a.x * b.x + a.y * b.y + a.z * b.z;
  30. }
  31. inline Vector3 cross(const Vector3& a, const Vector3& b) {
  32.     return Vector3(a.y * b.z - a.z * b.y,
  33.                    a.z * b.x - a.x * b.z,
  34.                    a.x * b.y - a.y * b.x);
  35. }
  36. inline float length(const Vector3& v) {
  37.     return sqrt(dot(v, v));
  38. }
  39. inline Vector3 normalize(const Vector3& v) {
  40.     float len = length(v);
  41.     return (len > 0.f) ? v / len : Vector3(0, 0, 0);
  42. }
  43.  
  44. // Triangle structure defined by three vertices.
  45. struct Triangle {
  46.     Vector3 p0, p1, p2;
  47. };
  48.  
  49. // Helper function: Computes the closest point on a triangle to a given point 'p'.
  50. // This function uses barycentric coordinate tests to determine whether the point
  51. // lies in one of the vertex regions, edge regions, or the interior face region.
  52. Vector3 ClosestPointOnTriangle(const Vector3& p, const Triangle& tri) {
  53.     // Rename triangle vertices for clarity.
  54.     const Vector3& A = tri.p0;
  55.     const Vector3& B = tri.p1;
  56.     const Vector3& C = tri.p2;
  57.  
  58.     // Compute vectors for two edges sharing vertex A.
  59.     Vector3 AB = B - A;
  60.     Vector3 AC = C - A;
  61.     // Vector from vertex A to point p.
  62.     Vector3 AP = p - A;
  63.  
  64.     // Compute dot products to measure how far p projects onto the triangle edges.
  65.     float d1 = dot(AB, AP); // p's projection on AB
  66.     float d2 = dot(AC, AP); // p's projection on AC
  67.  
  68.     // Check if p is in the vertex region outside A.
  69.     if (d1 <= 0.f && d2 <= 0.f)
  70.         return A;
  71.  
  72.     // Check if p is in the vertex region outside B.
  73.     Vector3 BP = p - B;
  74.     float d3 = dot(AB, BP); // p's projection on AB from B's perspective
  75.     float d4 = dot(AC, BP); // p's projection on AC (relative to A)
  76.     if (d3 >= 0.f && d4 <= d3)
  77.         return B;
  78.  
  79.     // Check if p is in the edge region of AB.
  80.     float vc = d1 * d4 - d3 * d2;
  81.     if (vc <= 0.f && d1 >= 0.f && d3 <= 0.f)
  82.         return A + AB * (d1 / (d1 - d3));
  83.  
  84.     // Check if p is in the vertex region outside C.
  85.     Vector3 CP = p - C;
  86.     float d5 = dot(AB, CP); // p's projection on AB (relative to C)
  87.     float d6 = dot(AC, CP); // p's projection on AC from C's perspective
  88.     if (d6 >= 0.f && d5 <= d6)
  89.         return C;
  90.  
  91.     // Check if p is in the edge region of AC.
  92.     float vb = d5 * d2 - d1 * d6;
  93.     if (vb <= 0.f && d2 >= 0.f && d6 <= 0.f)
  94.         return A + AC * (d2 / (d2 - d6));
  95.  
  96.     // Check if p is in the edge region of BC.
  97.     float va = d3 * d6 - d5 * d4;
  98.     if (va <= 0.f && (d4 - d3) >= 0.f && (d5 - d6) >= 0.f)
  99.         return B + (C - B) * ((d4 - d3) / ((d4 - d3) + (d5 - d6)));
  100.  
  101.     // p is inside the face region. Compute barycentric coordinates (v, w)
  102.     // so that p can be expressed as: A + AB*v + AC*w.
  103.     float denom = 1.f / (va + vb + vc);
  104.     float v = vb * denom;
  105.     float w = vc * denom;
  106.     return A + AB * v + AC * w;
  107. }
  108.  
  109. // Resolves collision between a sphere (center 'pos', radius 'radius')
  110. // and a set of triangles. Moves 'pos' out of any collisions by computing
  111. // the minimal displacement needed to separate the sphere from the intersecting triangles.
  112. Vector3 ResolveCollision(Vector3 pos, float radius, std::vector<Triangle>& triangles) {
  113.     bool collisionFound = true;
  114.     const int maxIterations = 10;
  115.     int iterations = 0;
  116.  
  117.     // Loop until no collisions are found or the maximum number of iterations is reached.
  118.     while (collisionFound && iterations < maxIterations) {
  119.         collisionFound = false;
  120.         // Iterate over each triangle in the scene.
  121.         for (const auto& tri : triangles) {
  122.             // Find the closest point on the triangle to the sphere center.
  123.             Vector3 closestPoint = ClosestPointOnTriangle(pos, tri);
  124.             // Compute the vector from this closest point to the sphere center.
  125.             Vector3 difference = pos - closestPoint;
  126.             float distanceSquared = dot(difference, difference);
  127.             // If the squared distance is less than the squared radius, a collision occurs.
  128.             if (distanceSquared < radius * radius) {
  129.                 float distance = sqrt(distanceSquared);
  130.                 float penetrationDepth = radius - distance;
  131.                 Vector3 pushDirection;
  132.                 // If the sphere center is not exactly at the collision point, normalize the difference vector.
  133.                 if (distance > 0.0001f)
  134.                     pushDirection = difference / distance;
  135.                 else {
  136.                     // If the sphere center is exactly on the triangle, use the triangle's normal.
  137.                     Vector3 triangleNormal = normalize(cross(tri.p1 - tri.p0, tri.p2 - tri.p0));
  138.                     // Use world up (0,0,1) if the triangle normal is degenerate.
  139.                     pushDirection = (length(triangleNormal) > 0.0001f) ? triangleNormal : Vector3(0, 0, 1);
  140.                 }
  141.                 // Move the sphere center by the penetration depth along the push direction.
  142.                 pos = pos + pushDirection * penetrationDepth;
  143.                 collisionFound = true;
  144.             }
  145.         }
  146.         iterations++;
  147.     }
  148.     return pos;
  149. }
Advertisement
Add Comment
Please, Sign In to add comment