Changeset 3950236 in opengl-game


Ignore:
Timestamp:
Apr 19, 2020, 3:39:41 AM (4 years ago)
Author:
Dmitry Portnoy <dmitry.portnoy@…>
Branches:
feature/imgui-sdl, master, points-test
Children:
7297892
Parents:
1f81ecc
Message:

Make a laser stop when it hits an asteroid

Files:
2 edited

Legend:

Unmodified
Added
Removed
  • vulkan-game.cpp

    r1f81ecc r3950236  
    779779   }
    780780
     781   if (leftLaserIdx != -1) {
     782      updateLaserTarget(leftLaserIdx);
     783   }
     784   if (rightLaserIdx != -1) {
     785      updateLaserTarget(rightLaserIdx);
     786   }
     787
    781788   for (SceneObject<AsteroidVertex, SSBO_Asteroid>& asteroid : this->asteroidObjects) {
    782789      if (!asteroid.ssbo.deleted) {
     
    15521559         {{-width / 2, 0.0f, 0.0f               }, {0.0f, 0.0f }},
    15531560         {{ width / 2, 0.0f, 0.0f               }, {1.0f, 0.0f }},
    1554         {{ width / 2, 0.0f, -length + width / 2}, {1.0f, 0.51f}},
     1561         {{ width / 2, 0.0f, -length + width / 2}, {1.0f, 0.51f}},
    15551562         {{-width / 2, 0.0f, -length + width / 2}, {0.0f, 0.51f}},
    15561563         {{ width / 2, 0.0f, -length,           }, {1.0f, 1.0f }},
     
    15801587   float zAxisRotation = -atan2(glm::dot(glm::cross(normal, laserToCam), glm::normalize(ray)), glm::dot(normal, laserToCam));
    15811588
     1589   laser.targetAsteroid = nullptr;
     1590
    15821591   laser.model_base =
    15831592      rotate(mat4(1.0f), zAxisRotation, vec3(0.0f, 0.0f, 1.0f));
     
    16211630
    16221631   laser.modified = true;
     1632}
     1633
     1634void VulkanGame::updateLaserTarget(size_t index) {
     1635   SceneObject<LaserVertex, SSBO_Laser>& laser = this->laserObjects[index];
     1636
     1637   // TODO: A lot of the values calculated here can be calculated once and saved when the laser is created,
     1638   // and then re-used here
     1639
     1640   vec3 start = vec3(laser.model_transform * vec4(0.0f, 0.0f, 0.0f, 1.0f));
     1641   vec3 end = vec3(laser.model_transform * vec4(0.0f, 0.0f, laser.vertices[6].pos.z, 1.0f));
     1642
     1643   vec3 intersection(0.0f), closestIntersection(0.0f);
     1644   SceneObject<AsteroidVertex, SSBO_Asteroid>* closestAsteroid = nullptr;
     1645   unsigned int closestAsteroidIndex = -1;
     1646
     1647   for (int i = 0; i < this->asteroidObjects.size(); i++) {
     1648      if (!this->asteroidObjects[i].ssbo.deleted &&
     1649            this->getLaserAndAsteroidIntersection(this->asteroidObjects[i], start, end, intersection)) {
     1650         // TODO: Implement a more generic algorithm for testing the closest object by getting the distance between the points
     1651         // TODO: Also check which intersection is close to the start of the laser. This would make the algorithm work
     1652         // regardless of which way -Z is pointing
     1653         if (closestAsteroid == nullptr || intersection.z > closestIntersection.z) {
     1654            // TODO: At this point, find the real intersection of the laser with one of the asteroid's sides
     1655            closestAsteroid = &asteroidObjects[i];
     1656            closestIntersection = intersection;
     1657            closestAsteroidIndex = i;
     1658         }
     1659      }
     1660   }
     1661
     1662   float width = laser.vertices[0].pos.x - laser.vertices[1].pos.x;
     1663
     1664   if (laser.targetAsteroid != closestAsteroid) {
     1665      laser.targetAsteroid = closestAsteroid;
     1666   }
     1667
     1668   // Make the laser go past the end of the screen if it doesn't hit anything
     1669   float length = closestAsteroid == nullptr ? 5.24f : glm::length(closestIntersection - start);
     1670
     1671   laser.vertices[4].pos.z = -length + width / 2;
     1672   laser.vertices[5].pos.z = -length + width / 2;
     1673   laser.vertices[6].pos.z = -length;
     1674   laser.vertices[7].pos.z = -length;
     1675
     1676   // TODO: Consider if I want to set a flag and do this update in in updateScene() instead
     1677   updateObjectVertices(this->laserPipeline, laser, index);
     1678}
     1679
     1680// TODO: Determine if I should pass start and end by reference or value since they don't get changed
     1681// Probably use const reference
     1682bool VulkanGame::getLaserAndAsteroidIntersection(SceneObject<AsteroidVertex, SSBO_Asteroid>& asteroid,
     1683      vec3& start, vec3& end, vec3& intersection) {
     1684   /*
     1685   ### LINE EQUATIONS ###
     1686   x = x1 + u * (x2 - x1)
     1687   y = y1 + u * (y2 - y1)
     1688   z = z1 + u * (z2 - z1)
     1689
     1690   ### SPHERE EQUATION ###
     1691   (x - x3)^2 + (y - y3)^2 + (z - z3)^2 = r^2
     1692
     1693   ### QUADRATIC EQUATION TO SOLVE ###
     1694   a*u^2 + b*u + c = 0
     1695   WHERE THE CONSTANTS ARE
     1696   a = (x2 - x1)^2 + (y2 - y1)^2 + (z2 - z1)^2
     1697   b = 2*( (x2 - x1)*(x1 - x3) + (y2 - y1)*(y1 - y3) + (z2 - z1)*(z1 - z3) )
     1698   c = x3^2 + y3^2 + z3^2 + x1^2 + y1^2 + z1^2 - 2(x3*x1 + y3*y1 + z3*z1) - r^2
     1699
     1700   u = (-b +- sqrt(b^2 - 4*a*c)) / 2a
     1701
     1702   If the value under the root is >= 0, we got an intersection
     1703   If the value > 0, there are two solutions. Take the one closer to 0, since that's the
     1704   one closer to the laser start point
     1705   */
     1706
     1707   vec3& center = asteroid.center;
     1708
     1709   float a = pow(end.x - start.x, 2) + pow(end.y - start.y, 2) + pow(end.z - start.z, 2);
     1710   float b = 2 * ((start.x - end.x) * (start.x - center.x) + (end.y - start.y) * (start.y - center.y) +
     1711            (end.z - start.z) * (start.z - center.z));
     1712   float c = pow(center.x, 2) + pow(center.y, 2) + pow(center.z, 2) + pow(start.x, 2) + pow(start.y, 2) +
     1713            pow(start.z, 2) - 2 * (center.x * start.x + center.y * start.y + center.z * start.z) -
     1714            pow(asteroid.radius, 2);
     1715   float discriminant = pow(b, 2) - 4 * a * c;
     1716
     1717   if (discriminant >= 0.0f) {
     1718      // In this case, the negative root will always give the point closer to the laser start point
     1719      float u = (-b - sqrt(discriminant)) / (2 * a);
     1720
     1721      // Check that the intersection is within the line segment corresponding to the laser
     1722      if (0.0f <= u && u <= 1.0f) {
     1723         intersection = start + u * (end - start);
     1724         return true;
     1725      }
     1726   }
     1727
     1728   return false;
    16231729}
    16241730
  • vulkan-game.hpp

    r1f81ecc r3950236  
    9696   vec3 center; // currently only matters for asteroids
    9797   float radius; // currently only matters for asteroids
     98   SceneObject<AsteroidVertex, SSBO_Asteroid>* targetAsteroid; // currently only used for lasers
    9899};
    99100
     
    271272      void addLaser(vec3 start, vec3 end, vec3 color, float width);
    272273      void translateLaser(size_t index, const vec3& translation);
     274      void updateLaserTarget(size_t index);
     275      bool getLaserAndAsteroidIntersection(SceneObject<AsteroidVertex, SSBO_Asteroid>& asteroid,
     276            vec3& start, vec3& end, vec3& intersection);
    273277
    274278      // TODO: Since addObject() returns a reference to the new object now,
Note: See TracChangeset for help on using the changeset viewer.