在 C++ 物理引擎中,当另一个刚体之间的距离大于零时,刚体会滑落

问题描述 投票:0回答:1

我正在尝试用 C++ 制作一个物理引擎,并且我有一个刚体脚本和一个用于解决碰撞的函数。但是,当一个刚体与另一个刚体之间的距离稍微变大时,质量较小的刚体就会滑落。我当然不想要这个。请帮我。这是我解决冲突的函数:

void ResolveCollisions(Rigidbody& rigidbody, Rigidbody& boxRigidbody)
{
    float distance = glm::distance(rigidbody.getPosition(), boxRigidbody.getPosition());
    std::cout << distance;

    // Calculate minimum penetration depth based on combined radius/bounding box half size
    float minimumPenetrationDepth = rigidbody.getMass() + boxRigidbody.getMass();

    if (distance - minimumPenetrationDepth <= 0.01f)
    {
        glm::vec3 collisionNormal = glm::normalize(rigidbody.getPosition() - boxRigidbody.getPosition());

        // Calculate relative velocity
        glm::vec3 relativeVelocity = rigidbody.getVelocity() - boxRigidbody.getVelocity();
        float relativeVelocityNormal = glm::dot(relativeVelocity, collisionNormal);

        float restitution = 0.1f; // Adjust the coefficient as needed

        // Calculate impulse magnitude for normal direction
        float j = -(1 + restitution) * relativeVelocityNormal;
        j /= 1 / rigidbody.getMass() + 1 / boxRigidbody.getMass();

        // Apply impulse for normal direction
        glm::vec3 impulse = j * collisionNormal;

        // Update velocities for normal direction
        rigidbody.setVelocity(rigidbody.getVelocity() + impulse / rigidbody.getMass());

        // Resolve penetration
        (rigidbody.getMass() + boxRigidbody.getMass()); // Use combined mass for center of mass calculation
        const float percent = 0.2f; // Penetration percentage to correct
        const float slop = 0.1f; // Allowance to prevent jittering
        float penetrationDepth = calculatePenetrationDepth(rigidbody, boxRigidbody);
        glm::vec3 desiredDistance =
            0.5f * (rigidbody.getBoundingBoxMax() - rigidbody.getBoundingBoxMin()) +
            0.5f * (boxRigidbody.getBoundingBoxMax() - boxRigidbody.getBoundingBoxMin());; // Calculate desired non-penetration distance (e.g., sum of bounding box half sizes)
        float desiredDistanceMagnitude = glm::length(desiredDistance);
        float penetrationDepthBruh = desiredDistanceMagnitude - distance;

        if (penetrationDepthBruh > slop) {
            glm::vec3 correction = penetrationDepth * collisionNormal;
            rigidbody.setPosition(rigidbody.getPosition() + correction);
        }

        // Calculate relative velocity in the direction of the tangent (friction)
        glm::vec3 relativeVelocityTangent = relativeVelocity - (glm::dot(relativeVelocity, collisionNormal) * collisionNormal);
        float relativeVelocityTangentMagnitude = glm::length(relativeVelocityTangent);

        // Calculate friction coefficient
        float staticFrictionThreshold = 0.001f;
        float frictionCoefficient = 0.1f;

        // Apply friction impulse if there's relative tangential velocity
        if (relativeVelocityTangentMagnitude < staticFrictionThreshold) {
            // If relative tangential velocity is low, apply static friction to prevent sliding
            // Calculate static friction impulse
            glm::vec3 staticFrictionImpulseA = -relativeVelocityTangent * rigidbody.getMass(); // Opposes motion
            glm::vec3 staticFrictionImpulseB = -relativeVelocityTangent * boxRigidbody.getMass(); // Opposes motion

            // Apply static friction impulse
            rigidbody.setVelocity(rigidbody.getVelocity() + staticFrictionImpulseA / rigidbody.getMass());
        }
        else {
            // If relative tangential velocity is high, apply dynamic friction
            // Calculate friction coefficient
            float frictionCoefficient = 0.1f; // Adjust as needed

            // Apply friction impulse if there's relative tangential velocity
            // Calculate impulse magnitude for friction
            float frictionImpulseMagnitude = frictionCoefficient * j;

            // Clamp friction impulse magnitude to prevent reversal of relative motion
            frictionImpulseMagnitude = std::min(frictionImpulseMagnitude, relativeVelocityTangentMagnitude);

            // Calculate friction impulse vector
            glm::vec3 frictionImpulse = glm::normalize(relativeVelocityTangent) * frictionImpulseMagnitude;

            // Apply friction impulse
            rigidbody.setVelocity(rigidbody.getVelocity() - frictionImpulse / rigidbody.getMass());
        }

        // Calculate angular velocity change due to collision
        glm::vec3 rA = rigidbody.getPosition() - boxRigidbody.getPosition();
        glm::vec3 rB = boxRigidbody.getPosition() - rigidbody.getPosition();
        glm::vec3 angularVelocityChangeA = glm::cross(rA, impulse) / rigidbody.getMass();
        glm::vec3 angularVelocityChangeB = glm::cross(rB, -impulse) / boxRigidbody.getMass();

        // Apply angular velocity change
        rigidbody.setRotation(rigidbody.getRotation() + angularVelocityChangeA);
    }
}

如果您想知道,这是我的刚体脚本:

class Rigidbody {
private:
    glm::vec3 position;
    glm::vec3 velocity;
    glm::vec3 acceleration;
    glm::vec3 force;
    float mass;
    glm::vec3 gravity;
    glm::vec3 rotation;
 
    // Bounding box dimensions
    glm::vec3 boundingBoxMin;
    glm::vec3 boundingBoxMax;
    glm::vec3 colliderRotation;
 
    float radius;
 
public:
    Rigidbody(glm::vec3 initialPosition, float initialMass, glm::vec3 initialGravity,
        Model& model, glm::vec3 initialRotation)
        : position(initialPosition), mass(initialMass), velocity(glm::vec3(0.0f)),
        acceleration(glm::vec3(0.0f)), force(glm::vec3(0.0f)), gravity(initialGravity),
        rotation(initialRotation), colliderType(ColliderType::BoundingBox) {
        // Get bounding box from the model
        boundingBoxMax = model.GetMaxBoundingBox();
        boundingBoxMin = model.GetMinBoundingBox();
    }
 
    // Constructor for spherical collider
    Rigidbody(glm::vec3 initialPosition, float initialMass, glm::vec3 initialGravity,
        float initialRadius)
        : position(initialPosition), mass(initialMass), velocity(glm::vec3(0.0f)),
        acceleration(glm::vec3(0.0f)), force(glm::vec3(0.0f)), gravity(initialGravity),
        rotation(glm::vec3(0.0f)), radius(initialRadius), colliderType(ColliderType::Sphere) {}
 
    void applyForce(glm::vec3 externalForce) {
        force += externalForce;
    }
 
    void update(float deltaTime) {
        // Apply gravity
        force += mass * gravity;
 
        // Apply Newton's second law: F = ma
        acceleration = force / mass;
 
        // Update velocity
        velocity += acceleration * deltaTime;
 
        // Update position
        position += velocity * deltaTime;
 
        // Reset force for next update
        force = glm::vec3(0.0f);
 
    }
 
    //here would be all the getters and setters
 
    enum class ColliderType {
        BoundingBox,
        Sphere
    } colliderType;
 
    // Methods to get the bounding box dimensions
    glm::vec3 getBoundingBoxMin() const {
        // Apply rotation to the min bounding box coordinates
        glm::vec3 rotatedMin = boundingBoxMin;
        rotatedMin = glm::rotateX(rotatedMin, colliderRotation.x);
        rotatedMin = glm::rotateY(rotatedMin, colliderRotation.y);
        rotatedMin = glm::rotateZ(rotatedMin, colliderRotation.z);
        return rotatedMin;
    }
 
    glm::vec3 getBoundingBoxMax() const {
        // Apply rotation to the max bounding box coordinates
        glm::vec3 rotatedMax = boundingBoxMax;
        rotatedMax = glm::rotateX(rotatedMax, colliderRotation.x);
        rotatedMax = glm::rotateY(rotatedMax, colliderRotation.y);
        rotatedMax = glm::rotateZ(rotatedMax, colliderRotation.z);
        return rotatedMax;
    }
 
    // Bounding box collision detection
    bool checkCollision(const Rigidbody& other) const {
        // Get the bounding box of the other Rigidbody
        glm::vec3 minB = other.getPosition() + other.getBoundingBoxMin();
        glm::vec3 maxB = other.getPosition() + other.getBoundingBoxMax();
 
        // Check if this bounding box intersects with the other bounding box
        return (position.x + boundingBoxMax.x >= minB.x &&
            position.x + boundingBoxMin.x <= maxB.x &&
            position.y + boundingBoxMax.y >= minB.y &&
            position.y + boundingBoxMin.y <= maxB.y &&
            position.z + boundingBoxMax.z >= minB.z &&
            position.z + boundingBoxMin.z <= maxB.z);
    }
};
 
c++ game-physics physics-engine
1个回答
0
投票

1。缺少一些方法:

我想你只是为了让事情变得更容易而把它们排除在外, 但你必须假设以下几点:

Rigidbody.getPosition()
”返回变量“
glm::vec3 position
”。

Rigidbody.getMass()
”返回变量“
float mass;
”。

Rigidbody.setVelocity(glm::vec3)
”设置变量“
glm::vec3 velocity;
”。

calculatePenetrationDepth(rigidbody, boxRigidbody)
”有什么作用?

2。什么是“刚体.位置”?!

我认为这是刚体的中心点...... 但什么样的中心(质心或体积中心)我不知道......

3. getBoundingBoxMin() / -Max()

这里你要小心,这些方法不会返回真正的最小值/最大值。 “

getBoundingBoxMax()
”可能比“
getBoundingBoxMin()
”小(在所有维度上) 因此,我建议它要么在方法中内部计算,要么 它被命名为“
getBoundingBox1()
”和“
getBoundingBox2()

4。 “checkCollision(const Rigidbody& other)”

此方法仅适用于 AABB,这里我们又遇到了第三个问题...

5。第一个 if 语句

if (distance - minimumPenetrationDepth <= 0.01f)
” 在这里,您仍然应该在对象的距离中包含边界框,因为低 质量大,体积大,距离大,不计算碰撞。 或者,如果质量非常高而体积很小,则计算不需要的碰撞 待计算。

6。未使用的计算

(rigidbody.getMass() + boxRigidbody.getMass());
不予评论...

7。摩擦

也许您只是忘记考虑底座的摩擦力,并且 也因为问题 5,计算出的力通常小于惯性 以及身体的摩擦力

© www.soinside.com 2019 - 2024. All rights reserved.