0

I am implementing a sphere to sphere collision resolution and I am a little confused on where to start. First question, is there a standard way that games/engines do sphere to sphere collision resolution? Is there only like a couple standard ways to do it? Or does the resolution vary very heavily based on whats needed?

I want to implement this in my engine and I wrote a basic one that pushes a sphere and another sphere (so basically the one interacting can push the other) but this was just a super simple concept. How exactly can I improve this to make it more accurate? (Mind you the code isn't optimized since I am still testing)

It seems like there is a lack of solid documentation on collision resolution in general as it's a more niche topic. Most resources I found only concern the detection part.

bool isSphereInsideSphere(glm::vec3 sphere, float sphereRadius, glm::vec3 otherSphere, float otherSphereRadius, Entity* e1, Entity* e2)
{
    float dist = glm::sqrt((sphere.x - otherSphere.x) * (sphere.x - otherSphere.x) + (sphere.y - otherSphere.y) * (sphere.y - otherSphere.y) + (sphere.z - otherSphere.z) * (sphere.z - otherSphere.z));
    if (dist <= (sphereRadius + otherSphereRadius))
    {
        //Push code
        e1->move(-e1->xVelocity / 2, 0, -e1->zVelocity / 2);
        e2->move(e1->xVelocity / 2, 0, e1->zVelocity / 2);
    }
    return dist <= (sphereRadius + otherSphereRadius);
}
Nicol Bolas
  • 378,677
  • 53
  • 635
  • 829
  • I am not sure what the rules are, but it may be more appropriate to ask this question on [gamedev.stackexchange.com](https://gamedev.stackexchange.com/). – Andreas Wenzel Sep 26 '20 at 23:53
  • 1
    Dont use sqrt, square dist and check against that – Yamahari Sep 26 '20 at 23:58
  • I'm not exactly sure what you mean by don't use square root and square distance. If I don't use square root I can't get the distance and if I dont have the distance I can't square it. Can you be more specific and maybe give an example? – user943201213 Sep 27 '20 at 00:05
  • 1
    Don't compare distances (which requires the slow square root), compare the _squares_ of the distances (which will be faster). – 1201ProgramAlarm Sep 27 '20 at 00:30
  • See [this question](https://stackoverflow.com/questions/7724061/how-slow-how-many-cycles-is-calculating-a-square-root) for more information on how slow the square root operation is. – Andreas Wenzel Sep 27 '20 at 00:32

2 Answers2

2

Using std::sqrt is unnecessary and it's probably a lot quicker to compare the squared length against (sphereRadius + otherSphereRadius)2.

Example:

#include <glm/glm.hpp>
#include <iostream>
#include <cstdlib>

auto squared_length(const glm::vec3& v) {
    return std::abs(v.x * v.x + v.y * v.y + v.z * v.z);
}

class Sphere {
public:
    Sphere(const glm::vec3& Position, float Radius) :
        position{Position}, radius(Radius) {}

    bool isSphereInsideSphere(const Sphere& other) const {
        auto dist = squared_length(position - other.position);

        // compare the squared values
        if(dist <= (radius + other.radius) * (radius + other.radius)) {
            // Push code ...
            return true;
        }
        return false;
    }

private:
    glm::vec3 position;
    float radius;
};

int main() {
    Sphere a({2, 3, 0}, 2.5);
    Sphere b({5, 7, 0}, 2.5);
    std::cout << std::boolalpha << a.isSphereInsideSphere(b) << '\n'; // prints true
}
Ted Lyngmo
  • 37,764
  • 5
  • 23
  • 50
0

Here is a simpler example (without involving new classes).

bool isSphereInsideSphere(glm::vec3 sphere, float sphereRadius, glm::vec3 otherSphere, float otherSphereRadius, Entity* e1, Entity* e2)
{
    auto delta = otherSphere - sphere;
    auto r2 = (sphereRadius + otherSphereRadius)*(sphereRadius + otherSphereRadius);
    if (glm::dot(delta,delta) <= r2)
    {
        //Push code
        
        return true;
    }
    return false;
}
Ted Lyngmo
  • 37,764
  • 5
  • 23
  • 50
apple apple
  • 5,557
  • 1
  • 12
  • 31