multitheftauto / mtasa-blue

Multi Theft Auto is a game engine that incorporates an extendable network play element into a proprietary commercial single-player game.
https://multitheftauto.com
GNU General Public License v3.0
1.42k stars 437 forks source link

Bullet physics #1100

Closed CrosRoad95 closed 12 months ago

CrosRoad95 commented 5 years ago

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

Lpsd commented 5 years ago

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)?

CrosRoad95 commented 5 years ago

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

0x416c69 commented 5 years ago

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.

CrosRoad95 commented 5 years ago

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

0x416c69 commented 5 years ago

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.

CrosRoad95 commented 5 years ago

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

0x416c69 commented 5 years ago

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

CrosRoad95 commented 5 years ago

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

0x416c69 commented 5 years ago

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"
    }
CrosRoad95 commented 5 years ago

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

CrosRoad95 commented 5 years ago

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

0x416c69 commented 5 years ago

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.

CrosRoad95 commented 5 years ago

@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

0x416c69 commented 5 years ago

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

qaisjp commented 5 years ago

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

0x416c69 commented 5 years ago

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)
}