Mtasa-blue: Bullet physics

Created on 21 Sep 2019  路  16Comments  路  Source: multitheftauto/mtasa-blue

Is your feature request related to a problem? Please describe.
Mta suffer from bad physics, doing own scripts will cause cpu suffer while are already exists ready physics libraries

Describe the solution you'd like
Add react physics, i though about bullet3 but it is overkill while this one i chosed is quite small and support everything what can be useful in mta
Lets use bullet3 physics to do for example skyscraper demolish simulation

Describe alternatives you've considered
/

Additional context
physics library i use: https://www.reactphysics3d.com/
demo i did: ~~https://github.com/CrosRoad95/mtasa-blue/tree/ReactPhysics3D https://github.com/CrosRoad95/mtasa-blue/tree/BulletPhysics3D
~~demo how it works in practice ( only wireframes are drawn and aren't precise) ~
~https://www.youtube.com/watch?v=sHYkTYfqADw&feature=youtu.be~~

As you can see on video, 120 boxes + 1 ground box and cause a bit lag ( what isn't needed very often and it is calculated each frame )

general idea is: you can create "physics world" which are independed from each other for purpuse like physics in gui, in world with set of functions to control it, get and set properties, link mta/gta element to rigid in physical world and vice versa
In general this feature can be finished fast due i just need to create lua implementation

I created this issue to get suggersions and list of functions and events which should be added in first place and get overall ideas about this feature

enhancement

Most helpful comment

Bullet Physics or not at all.

I was thinking of replacing the game's physics and collision detection with BP and bonus update ragdolls.

I can help you with that as I already did all above except replacing game's physics.

All 16 comments

I see in your video you have created a custom plane for all of the boxes to bounce off. Can you make "react" objects interact with GTA terrain, as well as (at the least) the bounding boxes of all objects (including custom ones) in the GTA world?

Wouldn't it make more sense to have a function like setPhysicsEnabled(element theElement, bool state), and these physics can be added to any element on the server?

Also, how complex can you make the physics shapes? For performance, would it be better to only follow the bounding box of GTA objects, or can you maybe grab the COL data of an object and reduce polygons (if needed)?

i some time ago did feature that let me get collision data in nearby area https://github.com/CrosRoad95/mtasa-blue/blob/856647b7423462cc4635f2850b7b76a74f63180e/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp#L9744
based on it i will add some function which will able to convert gta world to collision world.

it supports for example "Heightfield Shape" and "Concave Mesh Shape" ( second picture ) which looks really complex and could be used to cover terrain with collision and they could be generated by function mantioned above
image
image

Bullet Physics or not at all.

I was thinking of replacing the game's physics and collision detection with BP and bonus update ragdolls.

I can help you with that as I already did all above except replacing game's physics.

Like i said: RP has everything what you want, could you tell me what BP has what RP doesnt?

Based on my experience of game development over years, I tried small unpopular physics engine which had better documentation and they looked more simple but in the end I had to switch to BP and regret my decision.

Physics engine isn't something that you can trust it with just any library you find online. The library has to be tested over years and over AAA games to really understand what's going on.

Can you tell me which games use _RP_?

Edit: I'm uploading a video of my implementation of Bullet Physics inside San Andreas, it's a billiard game, I've also made a soccer game which is a perfect one (all rules and shit) maybe I will make a video of that too.

Mta team should decide, bullet or react physics. I cant find game which use this physics engine

https://youtu.be/yEtL8GAXECI

Go fly: https://youtu.be/yEtL8GAXECI?t=296
Capability: https://youtu.be/yEtL8GAXECI?t=541

Game object movement/rotation update rate: ~30FPS
Could be more smooth with higher FPS

@0x416c69 are u happy? https://github.com/CrosRoad95/mtasa-blue/tree/BulletPhysics3D
image
and it didn't crash after call from lua

Happiest possible

If you had problems in any stage of it let me know. (Euler to quaternion or vice-versa was a pain in the ass, you need a different algorithm)
Loading all GTA terrain will at least consume 200MB of memory (unless you use streaming) so you need to check for memory limitation before let the server control the physics.

Also use this premake script I have written before, place it in the directory of bullet.

-- AG:SAL Premake Script

project "BulletPhysics"
    language "C++"
    kind "StaticLib"
    targetname "bulletphysics"
    characterset "MBCS"

    disablewarnings {"4244", "4267"}
    floatingpoint "Fast"
    stringpooling "on"

    defines { "SKIP_SOFT_BODY_MULTI_BODY_DYNAMICS_WORLD", "NO_OPENGL3" }

    filter "system:not windows"
        links { "rt" }
        buildoptions { "-pthread", "-fPIC" }
        linkoptions { "-pthread" }

    filter {}

    includedirs { "./" }

    vpaths {
        ["Bullet3Collision/Headers/*"] = "Bullet3Collision/**.h",
        ["Bullet3Collision/Sources/*"] = "Bullet3Collision/**.cpp",
        ["Bullet3Dynamics/Headers/*"] = "Bullet3Dynamics/**.h",
        ["Bullet3Dynamics/Sources/*"] = "Bullet3Dynamics/**.cpp",
        ["LinearMath/Headers/*"] = "LinearMath/**.h",
        ["LinearMath/Sources/*"] = "LinearMath/**.cpp",
        ["*"] = {"premake5.lua", "btBulletCollisionCommon.h", "btBulletDynamicsCommon.h"}
    }

    files {
        "premake5.lua",

        -- Collisions:
        "Bullet3Collision/BroadPhaseCollision/b3BroadphaseCallback.h",
        "Bullet3Collision/BroadPhaseCollision/b3DynamicBvh.h",
        "Bullet3Collision/BroadPhaseCollision/b3DynamicBvhBroadphase.h",
        "Bullet3Collision/BroadPhaseCollision/b3OverlappingPair.h",
        "Bullet3Collision/BroadPhaseCollision/b3OverlappingPairCache.h",
        "Bullet3Collision/BroadPhaseCollision/shared/b3Aabb.h",
        "Bullet3Collision/NarrowPhaseCollision/shared/b3BvhSubtreeInfoData.h",
        "Bullet3Collision/NarrowPhaseCollision/shared/b3BvhTraversal.h",
        "Bullet3Collision/NarrowPhaseCollision/shared/b3ClipFaces.h",
        "Bullet3Collision/NarrowPhaseCollision/shared/b3Collidable.h",
        "Bullet3Collision/NarrowPhaseCollision/shared/b3Contact4Data.h",
        "Bullet3Collision/NarrowPhaseCollision/shared/b3ContactConvexConvexSAT.h",
        "Bullet3Collision/NarrowPhaseCollision/shared/b3ContactSphereSphere.h",
        "Bullet3Collision/NarrowPhaseCollision/shared/b3ConvexPolyhedronData.h",
        "Bullet3Collision/NarrowPhaseCollision/shared/b3FindConcaveSatAxis.h",
        "Bullet3Collision/NarrowPhaseCollision/shared/b3FindSeparatingAxis.h",
        "Bullet3Collision/NarrowPhaseCollision/shared/b3MprPenetration.h",
        "Bullet3Collision/NarrowPhaseCollision/shared/b3NewContactReduction.h",
        "Bullet3Collision/NarrowPhaseCollision/shared/b3QuantizedBvhNodeData.h",
        "Bullet3Collision/NarrowPhaseCollision/shared/b3ReduceContacts.h",
        "Bullet3Collision/NarrowPhaseCollision/shared/b3RigidBodyData.h",
        "Bullet3Collision/NarrowPhaseCollision/shared/b3UpdateAabbs.h",
        "Bullet3Collision/NarrowPhaseCollision/b3Config.h",
        "Bullet3Collision/NarrowPhaseCollision/b3Contact4.h",
        "Bullet3Collision/NarrowPhaseCollision/b3ConvexUtility.h",
        "Bullet3Collision/NarrowPhaseCollision/b3CpuNarrowPhase.h",
        "Bullet3Collision/NarrowPhaseCollision/b3RaycastInfo.h",
        "Bullet3Collision/NarrowPhaseCollision/b3RigidBodyCL.h",

        "Bullet3Collision/BroadPhaseCollision/b3DynamicBvh.cpp",
        "Bullet3Collision/BroadPhaseCollision/b3DynamicBvhBroadphase.cpp",
        "Bullet3Collision/BroadPhaseCollision/b3OverlappingPairCache.cpp",
        "Bullet3Collision/NarrowPhaseCollision/b3ConvexUtility.cpp",
        "Bullet3Collision/NarrowPhaseCollision/b3CpuNarrowPhase.cpp",

        -- Dynamics:
        "Bullet3Dynamics/b3CpuRigidBodyPipeline.h",
        "Bullet3Dynamics/ConstraintSolver/b3ContactSolverInfo.h",
        "Bullet3Dynamics/ConstraintSolver/b3FixedConstraint.h",
        "Bullet3Dynamics/ConstraintSolver/b3Generic6DofConstraint.h",
        "Bullet3Dynamics/ConstraintSolver/b3JacobianEntry.h",
        "Bullet3Dynamics/ConstraintSolver/b3PgsJacobiSolver.h",
        "Bullet3Dynamics/ConstraintSolver/b3Point2PointConstraint.h",
        "Bullet3Dynamics/ConstraintSolver/b3SolverBody.h",
        "Bullet3Dynamics/ConstraintSolver/b3SolverConstraint.h",
        "Bullet3Dynamics/ConstraintSolver/b3TypedConstraint.h",
        "Bullet3Dynamics/shared/b3ContactConstraint4.h",
        "Bullet3Dynamics/shared/b3ConvertConstraint4.h",
        "Bullet3Dynamics/shared/b3Inertia.h",
        "Bullet3Dynamics/shared/b3IntegrateTransforms.h",

        "Bullet3Dynamics/b3CpuRigidBodyPipeline.cpp",
        "Bullet3Dynamics/ConstraintSolver/b3FixedConstraint.cpp",
        "Bullet3Dynamics/ConstraintSolver/b3Generic6DofConstraint.cpp",
        "Bullet3Dynamics/ConstraintSolver/b3PgsJacobiSolver.cpp",
        "Bullet3Dynamics/ConstraintSolver/b3Point2PointConstraint.cpp",
        "Bullet3Dynamics/ConstraintSolver/b3TypedConstraint.cpp",

        "LinearMath/btAabbUtil2.h",
        "LinearMath/btAlignedAllocator.h",
        "LinearMath/btAlignedObjectArray.h",
        "LinearMath/btConvexHull.h",
        "LinearMath/btConvexHullComputer.h",
        "LinearMath/btDefaultMotionState.h",
        "LinearMath/btGeometryUtil.h",
        "LinearMath/btGrahamScan2dConvexHull.h",
        "LinearMath/btHashMap.h",
        "LinearMath/btIDebugDraw.h",
        "LinearMath/btList.h",
        "LinearMath/btMatrix3x3.h",
        "LinearMath/btMinMax.h",
        "LinearMath/btMotionState.h",
        "LinearMath/btPolarDecomposition.h",
        "LinearMath/btPoolAllocator.h",
        "LinearMath/btQuadWord.h",
        "LinearMath/btQuaternion.h",
        "LinearMath/btQuickprof.h",
        "LinearMath/btRandom.h",
        "LinearMath/btScalar.h",
        "LinearMath/btSerializer.h",
        "LinearMath/btStackAlloc.h",
        "LinearMath/btThreads.h",
        "LinearMath/btTransform.h",
        "LinearMath/btTransformUtil.h",
        "LinearMath/btVector3.h",
        "LinearMath/TaskScheduler/btThreadSupportInterface.h",

        "LinearMath/btAlignedAllocator.cpp",
        "LinearMath/btConvexHull.cpp",
        "LinearMath/btConvexHullComputer.cpp",
        "LinearMath/btGeometryUtil.cpp",
        "LinearMath/btPolarDecomposition.cpp",
        "LinearMath/btQuickprof.cpp",
        "LinearMath/btSerializer.cpp",
        "LinearMath/btSerializer64.cpp",
        "LinearMath/btThreads.cpp",
        "LinearMath/btVector3.cpp",
        "LinearMath/TaskScheduler/btTaskScheduler.cpp",
        "LinearMath/TaskScheduler/btThreadSupportPosix.cpp",
        "LinearMath/TaskScheduler/btThreadSupportWin32.cpp",

        "btBulletCollisionCommon.h",
        "btBulletDynamicsCommon.h"
    }

Can you already post code of quanternion to eular to quanternion? I know ill spend 99999hours with this piece of poop

i did changes in premake as you said, but not working, here's commit and screenshot in description https://github.com/CrosRoad95/mtasa-blue/commit/f8b7cf31feceb3a8637f091921fcebd29822c241

Yeah sorry that premake script is for something else, I'll give you the other one as soon as I could because right now you're using premake4 script of them which I think is outdated.

Here's the functions:

const btScalar ToRad = btScalar(PI / 180.f);
void EulerToQuat(btVector3 rotation, btQuaternion& result)
{
    rotation.setX(rotation.getX() * ToRad);
    rotation.setY(rotation.getY() * ToRad);
    rotation.setZ(rotation.getZ() * ToRad);

    btScalar cy = cos(.5f * rotation.getY()),
        sy = sin(.5f * rotation.getY()),
        cx = cos(.5f * rotation.getX()),
        sx = sin(.5f * rotation.getX()),
        cz = cos(.5f * rotation.getZ()),
        sz = sin(.5f * rotation.getZ());

    btScalar cycx = cy * cx,
        sysx = sy * sx,
        sxcy = sx * cy,
        cxsy = cx * sy;

    result.setW(cycx * cz - sysx * sz);
    result.setX(sxcy * cz - cxsy * sz);
    result.setY(cxsy * cz + sxcy * sz);
    result.setZ(cycx * sz + sysx * cz);
}

// Vehicles are different
void VehicleEulerToQuat(btVector3& rotation, btQuaternion& result)
{
    rotation.setX(rotation.getX() * ToRad);
    rotation.setY(rotation.getY() * ToRad);
    rotation.setZ(rotation.getZ() * ToRad);

    btScalar cx = cos(-.5f * rotation.getX()),
        sx = sin(-.5f * rotation.getX()),
        cy = cos(-.5f * rotation.getY()),
        sy = sin(-.5f * rotation.getY()),
        cz = cos(-.5f * rotation.getZ()),
        sz = sin(-.5f * rotation.getZ());

    btScalar cycx = cy * cx,
        sysx = sy * sx,
        sxcy = sx * cy,
        cxsy = cx * sy;

    result.setW(cycx * sx + sysx * sz);
    result.setX(cxsy * sz + sxcy * cz);
    result.setY(cxsy * cz - sxcy * sz);
    result.setZ(cycx * sz - sysx * cz);
}

float clip(float n, float lower, float upper)
{
    return std::max<float>(lower, std::min<float>(n, upper));
}

const btScalar PI = btScalar(3.14159265f);
const btScalar ToDegree = btScalar(180.f / PI);
void QuatToEuler(btQuaternion rotation, btVector3& result)
{
    float fDouble = 2.f * rotation.getY() * rotation.getZ() - 2.f * rotation.getX() * rotation.getW();
    if(fDouble >= 0.99999797344208f)
    {
        result.setX(-90.0f);
        result.setY(atan2(clip(rotation.getY(), -1.0f, 1.0f), clip(rotation.getW(), -1.0f, 1.0f)) * ToDegree);
        result.setZ(-atan2(clip(rotation.getZ(), -1.0f, 1.0f), clip(rotation.getW(), -1.0f, 1.0f)) * ToDegree);
    }
    else if(-fDouble >= 0.99999797344208f)
    {
        result.setX(90.0f);
        result.setY(atan2(clip(rotation.getY(), -1.0f, 1.0f), clip(rotation.getW(), -1.0f, 1.0f)) * ToDegree);
        result.setZ(-atan2(clip(rotation.getZ(), -1.0f, 1.0f), clip(rotation.getW(), -1.0f, 1.0f)) * ToDegree);
    }
    else
    {
        result.setX(-asin(clip(fDouble, -1.0f, 1.0f)) * ToDegree);
        result.setY(atan2(clip(rotation.getX() * rotation.getZ() + rotation.getY() * rotation.getW(), -1.0f, 1.0f), clip(0.5f - rotation.getX() * rotation.getX() - rotation.getY() * rotation.getY(), -1.0f, 1.0f)) * ToDegree);
        result.setZ(-atan2(clip(rotation.getX() * rotation.getY() + rotation.getZ() * rotation.getW(), -1.0f, 1.0f), clip(0.5f - rotation.getX() * rotation.getX() - rotation.getZ() * rotation.getZ(), -1.0f, 1.0f)) * ToDegree);
    }
}

For vehicle version of QuatToEuler, just reverse X and Y.

@0x416c69 QuatToEuler doesn't work for me. at the screenshot and video position and rotation of object is taken from rigid body every frame and set in same order to the object, check out video and screenshot https://www.youtube.com/watch?v=dvH7_J_Eti4
image

here's current code: https://github.com/CrosRoad95/mtasa-blue/blob/0d654e9c6ded49d241a5a3cdaaab833a5f18afe5/Client/mods/deathmatch/logic/lua/CLuaPhysicsRigidBody.cpp#L140-L179

That function is such a pain in the ASS

Everyone likes to have their own coordinate system, XYZ, XZY, RHS, LHS and for god motherfucking sake this gets complicated sometimes.

I think I had the right coordinate system for XYZ as for GTA:SA but I didn't quite remember if it was Right Handed or Left Handed, try reversing X & Y and find the proper value.

If you couldn't get it to work, PM me on discord AssassiN#6373

Everyone likes to have their own coordinate system, XYZ, XZY

Here's a great video that explains why we can't just can't have one: https://youtu.be/zc8b2Jo7mno

I'm aware of gimbal lock, that's why we use quaternion.
However changing Tait-Bryan angles order won't solve anything. It just shifts the problem. There is still a way to solve gimbal lock by using local rotation and calculating local to global.

Here is the new _working_ function (thanks to @IllidanS4)

void QuatToEuler(btQuaternion rotation, btVector3& result)
{
    rotation.setX(-rotation.getX());
    rotation.setY(-rotation.getY());
    rotation.setZ(-rotation.getZ());
    rotation.normalize();

    const double eps = 1e-7;
    const double pi = 3.14159265358979323846;
    double x, y, z;
    double qw = rotation.getW(),
        qx = rotation.getX(),
        qy = rotation.getY(),
        qz = rotation.getZ();

    double sqx = qx * qx,
        sqy = qy * qy,
        sqz = qz * qz;

    double test = (2.0 * qy * qz) - (2.0 * qx * qw);
    if (test >= 1 - eps)
    {
        x = pi / 2.0;
        y = -atan2(qy, qw);
        z = -atan2(qz, qw);
    }
    else if (-test >= 1 - eps)
    {
        x = -pi / 2.0;
        y = -atan2(qy, qw);
        z = -atan2(qz, qw);
    }
    else
    {
        x = asin(test);
        y = -atan2((qx * qz) + (qy * qw), 0.5 - sqx - sqy);
        z = -atan2((qx * qy) + (qz * qw), 0.5 - sqx - sqz);
    }

    x *= 180.0 / pi;
    y *= 180.0 / pi;
    z *= 180.0 / pi;

#pragma warning(push)
#pragma warning(disable:4244)
    result.setX(x);
    result.setY(y);
    result.setZ(z);
#pragma warning(pop)
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

ALw7sH picture ALw7sH  路  3Comments

PlatinMTA picture PlatinMTA  路  3Comments

LosFaul picture LosFaul  路  3Comments

CrosRoad95 picture CrosRoad95  路  3Comments

CrosRoad95 picture CrosRoad95  路  4Comments