BeRo1985 / kraft

Kraft Physics Engine is an open source Object Pascal physics engine library that can be used in 3D games.
107 stars 21 forks source link

Feature Request TKraftShapeCone, TKraftShapeCylinder #31

Open PascalCorpsman opened 1 year ago

PascalCorpsman commented 1 year ago

Looking at "TKraftShapeType" i am missing Cone and Cylinder.

Are you looking forward to implement these two ?

If not i can / will try to implement them in the way you did TKraftShapeBox using a ConvexHull and then use a Pull Request to share..

BeRo1985 commented 1 year ago

Thank you for your interest in the KRAFT physics engine and for your suggestion to implement Cone and Cylinder shapes.

The reason why Cone and Cylinder shapes are not directly implemented in KRAFT is due to the extreme complexity they introduce in collision detection algorithms. Specifically, the computation of the Minkowski difference, which is used in algorithms like Gilbert-Johnson-Keerthi (GJK) and Minkowski Portal Refinement (MPR), and direct computational intersections with the other convex shapes with implicit collision algorithms, becomes significantly far more complex for all shapes in sum.

The support functions for Cone and Cylinder shapes, which are used to compute the Minkowski difference and direct computational intersections with the other convex shapes such as boxes, spheres, capsules, and meshes (where each triangle is treated as a cached on-demand convex hull), will be far more complex. This can lead to increased computational cost and potential issues with numerical stability.

Moreover, implementing these shapes would require a substantial amount of work to ensure that they interact correctly with all other shapes in the engine. This would involve not only the implementation of the shapes themselves, but also the modification of the collision detection and resolution algorithms to handle these new cases with the rest of the shapes as well, pair-wise.

That being said, these shapes can be approximated using Convex Hulls. This approach allows us to leverage the existing infrastructure of the engine without introducing the complexities associated with the direct implementation of Cones and Cylinders. While this may not be a perfect representation, it often provides a good balance between accuracy and computational efficiency.

If you're interested in implementing these shapes, I would recommend starting with the Convex Hull approach. However, please be aware that this is a non-trivial task that will require a deep understanding of the engine's internals and the mathematics of collision detection.

For more details about the complexities involved in collision detection with a so such set of shapes, I recommend checking out this document: http://media.steampowered.com/apps/valve/2015/DirkGregorius_Contacts.pdf.

I hope this provides some insight into the design decisions behind KRAFT.

PascalCorpsman commented 1 year ago

So Long story short we go with the hull approach ;)

I would suggest this version:

Type

  { TKraftShapeCone }

  TKraftShapeCone = Class(TKraftShapeConvexHull)
  public
    Constructor Create(Const APhysics: TKraft; Const ARigidBody: TKraftRigidBody; Const ARadius, AHeight: TKraftScalar; Const Refinement: integer = 16); reintroduce; overload;
  End;

  { TKraftShapeCylinder }

  TKraftShapeCylinder = Class(TKraftShapeConvexHull)
  public
    Constructor Create(Const APhysics: TKraft; Const ARigidBody: TKraftRigidBody; Const ARadius, AHeight: TKraftScalar; Const Refinement: integer = 16); reintroduce; overload;
  End;

  { TKraftShapeCone }

Constructor TKraftShapeCone.Create(Const APhysics: TKraft;
  Const ARigidBody: TKraftRigidBody; Const ARadius, AHeight: TKraftScalar;
  Const Refinement: integer);
Var
  Hull: TKraftConvexHull;
  i: Integer;
  angle: Single;
Begin
  Hull := TKraftConvexHull.Create(APhysics);
  hull.AddVertex(Vector3(0, AHeight / 2, 0));
  For i := 0 To Refinement - 1 Do Begin
    angle := 2 * pi * i / Refinement;
    hull.AddVertex(Vector3(cos(angle) * ARadius, -AHeight / 2, sin(angle) * ARadius));
  End;
  hull.Build();
  hull.Finish;
  Inherited Create(APhysics, ARigidBody, Hull);
End;

{ TKraftShapeCylinder }

Constructor TKraftShapeCylinder.Create(Const APhysics: TKraft;
  Const ARigidBody: TKraftRigidBody; Const ARadius, AHeight: TKraftScalar;
  Const Refinement: integer);
Var
  Hull: TKraftConvexHull;
  i: Integer;
  angle: Single;
Begin
  Hull := TKraftConvexHull.Create(APhysics);
  // This could also be done in one single loop, but so the hull is 2 Discs instead of on "Roll"
  For i := 0 To Refinement - 1 Do Begin
    angle := 2 * pi * i / Refinement;
    hull.AddVertex(Vector3(cos(angle) * ARadius, AHeight / 2, sin(angle) * ARadius));
  End;
  For i := 0 To Refinement - 1 Do Begin
    angle := 2 * pi * i / Refinement;
    hull.AddVertex(Vector3(cos(angle) * ARadius, -AHeight / 2, sin(angle) * ARadius));
  End;
  hull.Build();
  hull.Finish;
  Inherited Create(APhysics, ARigidBody, Hull);
End;  

i tested it with my basic example from here: https://github.com/PascalCorpsman/kraft_examples and so far its looking good enough for me.

So if you are willing to add this into your codebase you could either direct copy it or i will create a pull request what you prever the most ;)

cone Cylinder