bekovski

alalala

Jan 9th, 2018
121
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.85 KB | None | 0 0
  1. #pragma once
  2.  
  3. #include "pch.h"
  4. #include "MeshObject.h"
  5. #include "Quat.h"
  6.  
  7. using namespace Kore;
  8.  
  9. // A plane is defined as the plane's normal and the distance of the plane to the origin
  10. class PlaneCollider {
  11. public:
  12.  
  13.     // Distance
  14.     float d;
  15.  
  16.     // Normal
  17.     vec3 normal;
  18. };
  19.  
  20.  
  21. /************************************************************************/
  22. /* Task P9.2 Implement the box-sphere intersection test you derived for
  23. /* this task. You can use the collider in the main update function in Exercise.cpp
  24. /* to test it against the sphere (you can find it via phyics.physicsObject[0]).
  25. /* You can instantiate your collider in the Exercise.cpp init function.
  26. /************************************************************************/
  27. class BoxCollider {
  28. public:
  29.     const vec3 center;
  30.     const float length;
  31.     const float height;
  32.     const float depth;
  33.  
  34.     BoxCollider(vec3 center, float length, float height, float depth)
  35.         : center(center), length(length), height(height), depth(depth) {
  36.     }
  37. };
  38.  
  39.  
  40.  
  41. class TriangleCollider {
  42.     void LoadVector(vec3& v, int index, float* vb) {
  43.         v.set(vb[index*8 + 0], vb[index*8 + 1], vb[index*8 + 2]);
  44.     }
  45.  
  46. public:
  47.     vec3 A;
  48.     vec3 B;
  49.     vec3 C;
  50.  
  51.     float Area() {
  52.         return 0.5f * ((B-A).cross(C-A)).getLength();
  53.     }
  54.  
  55.     void LoadFromBuffers(int index, int* ib, float* vb) {
  56.         LoadVector(A, ib[index * 3], vb);
  57.         LoadVector(B, ib[index * 3 + 1], vb);
  58.         LoadVector(C, ib[index * 3 + 2], vb);
  59.     }
  60.  
  61.     vec3 GetNormal() {
  62.         vec3 n = (B-A).cross(C-A);
  63.         n.normalize();
  64.         return n;
  65.     }
  66.  
  67.     PlaneCollider GetPlane() {
  68.         vec3 n = GetNormal();
  69.         float d = n.dot(A);
  70.  
  71.         PlaneCollider p;
  72.         p.d = -d;
  73.         p.normal = n;
  74.         return p;
  75.     }
  76. };
  77.  
  78. class TriangleMeshCollider {
  79. public:
  80.     MeshObject* mesh;
  81.  
  82.     int lastCollision;
  83. };
  84.  
  85. // A sphere is defined by a radius and a center.
  86. class SphereCollider {
  87. public:
  88.  
  89.     vec3 center;
  90.     float radius;
  91.  
  92.     // Return true iff there is an intersection with the other sphere
  93.     bool IntersectsWith(const SphereCollider& other) {
  94.         float distance = (other.center - center).getLength();
  95.         return distance < other.radius + radius;
  96.     }
  97.  
  98.     // Collision normal is the normal vector pointing towards the other sphere
  99.     vec3 GetCollisionNormal(const SphereCollider& other) {
  100.         vec3 n = other.center - center;
  101.         n = n.normalize();
  102.         return n;
  103.     }
  104.  
  105.     // The penetration depth
  106.     float PenetrationDepth(const SphereCollider& other) {
  107.         return other.radius + radius - (other.center - center).getLength();
  108.     }
  109.  
  110.     vec3 GetCollisionNormal(const PlaneCollider& other) {
  111.         return other.normal;
  112.     }
  113.  
  114.     float PenetrationDepth(const PlaneCollider &other) {
  115.         return other.normal.dot(center) + other.d - radius;
  116.     }
  117.  
  118.     float Distance(const PlaneCollider& other) {
  119.         return other.normal.dot(center) + other.d;
  120.     }
  121.  
  122.     bool IntersectsWith(const PlaneCollider& other) {
  123.         return Kore::abs(Distance(other)) <= radius;
  124.     }
  125.  
  126.     bool IsInside(const PlaneCollider& other) {
  127.         return Distance(other) < radius;
  128.     }
  129.  
  130.     bool IsOutside(const PlaneCollider& other) {
  131.         return Distance(other) > radius;
  132.     }
  133.  
  134.     /************************************************************************/
  135.     /* Task P9.2 - Check for intersection with a box collider            */
  136.     /************************************************************************/
  137.     bool IntersectsWith(const BoxCollider& other) {
  138.         vec3 closestPoint = this->closestPoint(other);
  139.  
  140.         if (center.distance(closestPoint) <= radius)
  141.             return true;
  142.  
  143.         // else there is no intersection
  144.         return false;
  145.     }
  146.  
  147.     vec3 GetCollisionNormal(const TriangleCollider& other) {
  148.         // Use the normal of the triangle plane
  149.         vec3 n = (other.B - other.A).cross(other.C - other.A);
  150.         n.normalize();
  151.         return n;
  152.     }
  153.  
  154.     float PenetrationDepth(const TriangleCollider& other) {
  155.         // Use the triangle plane
  156.         // The assumption is that we have a mesh and will not collide only on a vertex or an edge
  157.  
  158.         return 0.0f;
  159.     }
  160.    
  161.     bool IntersectsWith(TriangleMeshCollider& other) {
  162.         TriangleCollider coll;
  163.         int* current = other.mesh->mesh->indices;
  164.         float* currentVertex = other.mesh->mesh->vertices;
  165.         for (int i = 0; i < other.mesh->mesh->numFaces; i++) {
  166.             coll.LoadFromBuffers(i, current, currentVertex);
  167.             if (coll.Area() < 0.1f) continue;
  168.             if (IntersectsWith(coll)) {
  169.                 other.lastCollision = i;
  170.                 vec3 normal;
  171.                 if (coll.GetNormal().x() < -0.8f)
  172.                     normal = coll.GetNormal();
  173.                 // Kore::log(Warning, "Intersected with triangle: %f, %f, %f", coll.GetNormal().x(), coll.GetNormal().y(), coll.GetNormal().z());
  174.                 return true;
  175.             }
  176.         }
  177.         return false;
  178.     }
  179.  
  180.     vec3 GetCollisionNormal(const TriangleMeshCollider& other) {
  181.         TriangleCollider coll;
  182.         coll.LoadFromBuffers(other.lastCollision, other.mesh->mesh->indices, other.mesh->mesh->vertices);
  183.         return coll.GetNormal();
  184.     }
  185.  
  186.     float PenetrationDepth(const TriangleMeshCollider& other) {
  187.         // Get a collider for the plane of the triangle
  188.         TriangleCollider coll;
  189.         coll.LoadFromBuffers(other.lastCollision, other.mesh->mesh->indices, other.mesh->mesh->vertices);
  190.         PlaneCollider plane = coll.GetPlane();
  191.  
  192.         return PenetrationDepth(plane);    
  193.     }
  194.  
  195.  
  196.     // Find the point where the sphere collided with the triangle mesh
  197.     vec3 GetCollisionPoint(const TriangleMeshCollider& other) {
  198.         // We take the point on the sphere that is closest to the triangle
  199.         vec3 result = center - GetCollisionNormal(other) * radius;
  200.         return result;
  201.     }
  202.  
  203.     // Find a set of basis vectors such that the provided collision normal x is the first column of the basis matrix,
  204.     // and the other two vectors are perpendicular to the collision normal
  205.     mat3 GetCollisonBasis(vec3 x) {
  206.         x.normalize();
  207.         mat3 basis;
  208.         basis.Set(0, 0, x.x());
  209.         basis.Set(1, 0, x.y());
  210.         basis.Set(2, 0, x.z());
  211.  
  212.         // Find a y-vector
  213.         // x will often be the global y-axis, so don't use this -> use global z instead
  214.         vec3 y(0, 0, 1);
  215.         y = x.cross(y);
  216.         y = y.normalize();
  217.  
  218.         basis.Set(0, 1, y.x());
  219.         basis.Set(1, 1, y.y());
  220.         basis.Set(2, 1, y.z());
  221.  
  222.         vec3 z = x.cross(y);
  223.         z.normalize();
  224.  
  225.         basis.Set(0, 2, z.x());
  226.         basis.Set(1, 2, z.y());
  227.         basis.Set(2, 2, z.z());
  228.         return basis;
  229.     }
  230.  
  231.     /************************************************************************/
  232.     /* Task P9.1: Implement these functions. They should return true only if the
  233.      * axis from the sphere center to the vertex of the triangle is a separating axis.
  234.     /************************************************************************/
  235.     bool IsSeparatedByVertexA(const TriangleCollider& other)
  236.     {
  237.         return isSeparatedByVertex(other, other.A);
  238.     }
  239.  
  240.     bool IsSeparatedByVertexB(const TriangleCollider& other)
  241.     {
  242.         return isSeparatedByVertex(other, other.B);
  243.     }
  244.  
  245.     bool IsSeparatedByVertexC(const TriangleCollider& other)
  246.     {
  247.         return isSeparatedByVertex(other, other.C);
  248.     }
  249.  
  250.     bool IntersectsWith(const TriangleCollider& other) {
  251.         // Separating Axes Test
  252.         // 1 Face
  253.         // 3 Vertices
  254.         // 3 Edges
  255.         // No overlap if all of the resulting axes are not touching
  256.  
  257.         vec3 A = other.A - center;
  258.         vec3 B = other.B - center;
  259.         vec3 C = other.C - center;
  260.         float rr = radius * radius;
  261.         vec3 V = (B - A).cross(C - A);
  262.         float d = A.dot(V);
  263.         float e = V.dot(V);
  264.         bool sepPlane = d * d > rr * e;
  265.         float aa = A.dot(A);
  266.         float ab = A.dot(B);
  267.         float ac = A.dot(C);
  268.         float bb = B.dot(B);
  269.         float bc = B.dot(C);
  270.         float cc = C.dot(C);
  271.         vec3 AB = B - A;
  272.         vec3 BC = C - B;
  273.         vec3 CA = A - C;
  274.         float d1 = ab - aa;
  275.         float d2 = bc - bb;
  276.         float d3 = ac - cc;
  277.         float e1 = AB.dot(AB);
  278.         float e2 = BC.dot(BC);
  279.         float e3 = CA.dot(CA);
  280.         vec3 Q1 = A * e1 - d1 * AB;
  281.         vec3 Q2 = B * e2 - d2 * BC;
  282.         vec3 Q3 = C * e3 - d3 * CA;
  283.         vec3 QC = C * e1 - Q1;
  284.         vec3 QA = A * e2 - Q2;
  285.         vec3 QB = B * e3 - Q3;
  286.         bool sepEdge1 = (Q1.dot(Q1) > rr * e1 * e1) & (Q1.dot(QC) > 0);
  287.         bool sepEdge2 = (Q2.dot(Q2) > rr * e2 * e2) & (Q2.dot(QA) > 0);
  288.         bool sepEdge3 = (Q3.dot(Q3) > rr * e3 * e3) & (Q3.dot(QB) > 0);
  289.  
  290.         bool sepVertexA = IsSeparatedByVertexA(other);
  291.         bool sepVertexB = IsSeparatedByVertexB(other);
  292.         bool sepVertexC = IsSeparatedByVertexC(other);
  293.  
  294.         bool separated = sepPlane | sepVertexA | sepVertexB | sepVertexC | sepEdge1 | sepEdge2 | sepEdge3;
  295.        
  296.         return !separated;
  297.     }
  298.  
  299.  
  300. private:
  301.     // for P9.1
  302.     bool isSeparatedByVertex(const TriangleCollider& other, vec3 vertex) {
  303.  
  304.         using Kore::pow;
  305.  
  306.         // 1. distance from vertex (A, B, or C) to sphere's center (P) is greater than the sphere's radius
  307.         vec3 diff = center - vertex;
  308.         float relative_dist = pow(diff.x(), 2) + pow(diff.y(), 2) + pow(diff.z(), 2);
  309.         bool distance_greater_radius = relative_dist > pow(radius, 2);
  310.  
  311.         // 2. the neighbor's of 'vertex' lie on the opposite direction of the sphere's center (P)
  312.             // note: two vectors (v and w) point in the opposite direction if the angle between them is > 90°
  313.             // ... this is the case when dot(v, w) < 0
  314.             // (> 0 implies same direction)
  315.  
  316.         // calculate vectors which point from 'vertex' to P and its two neighbors; then calculate the angle between them
  317.         vec3 vertex_to_center = center - vertex;    // AP, BP, or CP
  318.         vec3 vertex_to_neighbor1;
  319.         vec3 vertex_to_neighbor2;
  320.  
  321.         if (vertex == other.A) {
  322.             vertex_to_neighbor1 = other.B - vertex; // AB
  323.             vertex_to_neighbor2 = other.C - vertex; // AC
  324.         } else if (vertex == other.B) {
  325.             vertex_to_neighbor1 = other.A - vertex; // BA
  326.             vertex_to_neighbor2 = other.C - vertex; // BC
  327.         } else if (vertex == other.C) {
  328.             vertex_to_neighbor1 = other.A - vertex; // CA
  329.             vertex_to_neighbor2 = other.B - vertex; // CB
  330.         } else {
  331.             throw std::runtime_error("Supplied vertex does not match any vertex of the triangle in question.");
  332.         }
  333.  
  334.         bool isOpposite = vertex_to_center.dot(vertex_to_neighbor1) < 0 && vertex_to_center.dot(vertex_to_neighbor2) < 0;
  335.  
  336.         return distance_greater_radius && isOpposite;
  337.     }
  338.  
  339.     // for P9.2
  340.     vec3 closestPoint(BoxCollider other) {
  341.  
  342.         // figure out min/max coordinates of x-, y- and z-directions of our box
  343.         float length_half   = other.length / 2;
  344.         float height_half   = other.height / 2;
  345.         float depth_half    = other.depth / 2;
  346.  
  347.         float min_x = other.center.x() - length_half;
  348.         float max_x = other.center.x() + length_half;
  349.         float max_y = other.center.y() + height_half;
  350.         float min_y = other.center.y() - height_half;
  351.         float max_z = other.center.z() + depth_half;
  352.         float min_z = other.center.z() - depth_half;
  353.  
  354.         // the coordinates of the closest point
  355.         // the sphere's center-coordinates are simply clamped to the box (AABB)
  356.         float x;
  357.         float y;
  358.         float z;
  359.  
  360.         // x-coordinate
  361.         if (center.x() < min_x) {
  362.             x = min_x;
  363.         } else if (center.x() > max_x) {
  364.             x = max_x;
  365.         } else {
  366.             x = center.x();
  367.         }
  368.  
  369.         // y-coordinate
  370.         if (center.y() < min_y) {
  371.             y = min_y;
  372.         }
  373.         else if (center.y() > max_y) {
  374.             y = max_y;
  375.         }
  376.         else {
  377.             y = center.y();
  378.         }
  379.  
  380.         // z-coordinate
  381.         if (center.z() < min_z) {
  382.             z = min_z;
  383.         } else if (center.z() > max_z) {
  384.             z = max_z;
  385.         } else {
  386.             z = center.z();
  387.         }
  388.  
  389.         return vec3(x,y,z);
  390.     }
  391. };
Advertisement
Add Comment
Please, Sign In to add comment