Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace Newton Dynamics with Jolt Physics #287

Merged
merged 3 commits into from
Jun 24, 2024

Conversation

Lamakaio
Copy link
Contributor

@Lamakaio Lamakaio commented May 29, 2024

I am making this PR to track the work on replacing Newton Dynamics with Jolt Physics.
If it's not the right way to track things, feel free to remove it.

  • Add JoltPhysics to the repo as a submodule
  • Make it compile with the project
  • Write the interface to Jolt, similar to ospnewton
  • Write the Session for ospjolt, similar to newton
  • Change scenarios to use Jolt instead of Newton
  • Fix remaining bugs
  • Find out what I forgot in this list

@jonesmz
Copy link
Member

jonesmz commented May 29, 2024

Really great start to this! I applaud your communication and consistency thereof!

.gitmodules Outdated
@@ -37,3 +37,6 @@
[submodule "3rdparty/freetype"]
path = 3rdparty/freetype
url = https://github.com/freetype/freetype
[submodule "3rdparty/JoltPhysics"]
path = 3rdparty/JoltPhysics
url = [email protected]:jrouwe/JoltPhysics.git
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you didn't already do this, please make sure you track an "official" release by git-tag, if that exists for Jolt.

For all the other submodules, except the Magnum graphics related ones, I Just track whatever the latest official release tag is.

For magnum, they just kind of stopped doing releases, so i just periodically bump to the latest commit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be tracking v5.0.0 ? hopefully

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Jolt submodule is set to use a git+ssh protocol, and this only works if your client is setup with a valid GitHub SSH credential (e.g. it cannot be cloned anonymously this way)

Like the other dependencies I'm assuming this should be using the HTTPS URI of https://github.com/jrouwe/JoltPhysics.git so that it can be cloned anonymously

@@ -201,15 +201,15 @@ VehicleData VehicleBuilder::finalize_release()

// reserve node-to-machine partitions
rPerNodeType.nodeToMach.data_reserve(rPerNodeType.m_connectCountTotal);
for (NodeId node : rPerNodeType.nodeIds.bitview().zeros())
for (NodeId node : rPerNodeType.nodeIds)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't disagree with this change, but I'm not really sure how related to the Jolt physics change it is.

Maybe this should be in it's own stand-alone PR?

Copy link
Contributor Author

@Lamakaio Lamakaio May 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is ! Sorry it is not the cleanest, I have two other PRs open and this is one of them. I kinda figured I would start with the most advanced version of the code I could, as this PR will take me quite some time anyway. I'll just rebase whenever it is merged.

@Lamakaio Lamakaio marked this pull request as ready for review June 6, 2024 18:07
@Lamakaio
Copy link
Contributor Author

Lamakaio commented Jun 6, 2024

I am mostly finished here, but I get some weird behavior in Release mode only. Valgrind doesn't tell me anything, so I'm not sure where to look. If I could get some additional testing / a review it would be great.

Jolt produces compilation warnings on Windows with Wall, so I disabled warnings in Jolt (at least, hopefully, I don't have MSVC to test it locally).
It still fails on some builds only, and I'm a bit at loss as to why.

Currently I left all the Newton code up, and examples simply have to include Jolt.h or Newton.h to switch physics engine. I'm not sure how relevant that is, though.

src/ospjolt/activescene/joltinteg.h Fixed Show resolved Hide resolved
Copy link
Contributor

@Capital-Asterisk Capital-Asterisk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work! I'd assume the Newton submodule should be kept around for benchmarking? Fairly simple to just make a copy of each test scenario. I don't mind this being merged in a non-final state as long as it mostly works; I'd like to figure out how to get around doing planet terrain colliders.

src/ospjolt/activescene/joltinteg.h Outdated Show resolved Hide resolved
va_end(list);

// Print to the TTY
std::cout << buffer << std::endl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be OSP_LOG_*, though I'm wondering if spdlog or fmt has a built-in function for va_list

src/ospjolt/activescene/joltinteg.h Outdated Show resolved Hide resolved
src/ospjolt/activescene/joltinteg.h Outdated Show resolved Hide resolved
static constexpr ObjectLayer NON_MOVING = 0;
static constexpr ObjectLayer MOVING = 1;
static constexpr ObjectLayer NUM_LAYERS = 2;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not important right now, though I'm wondering if we're going to need to dynamically reassign these and filters at runtime eventually.

case EShape::Cylinder:
//cylinder needs to be internally rotated 90° to match with graphics
joltShape = (Shape *) new CylinderShape(1.0f, 2.0f);
joltShape = (Shape *) new RotatedTranslatedShape(Vec3Arg::sZero(), Quat::sRotation(Vec3::sAxisX(), JPH_PI/2), joltShape);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just put new CylinderShape(1.0f, 2.0f) into the constructor

Quat joltRotation(rawQuat[0], rawQuat[1], rawQuat[2], rawQuat[3]);

//scale the shape directly
pJoltShape->mShape = pJoltShape->mShape->ScaleShape(Vec3Arg(scale.x(), scale.y(), scale.z())).Get();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unnecessary comment + huh, that's a knockoff Rust Result? (not really)

I'm not sure if this is an absolute or relative scale. I have a feeling it's relative, which is not what we want to do here.

Or wouldn't this continuously accumulate more and more layers of ScaledShape each time orient_shape is called? eg: each time a compound shape is modified

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create_primitive and orient_shape previously exists to fit around Newton Dynamic's model. The way to just 'make a shape given a position/rotation/scale' in Jolt is likely different.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the compound shape (collider) transform supposed to be absolute ? I assumed it was relative to the compound shape transform (mostly because the recursive function starts with identity transform)
That is, the final absolute transform needs to be "compound shape transform" * "relative subshape transform".

I do agree that there are better ways to handle this though. I'll scrap orient_shape and create_primitive to make something that only adds ScaledShape wrapper when it is needed (ie when we are not creating the shape in the same spot, and when the shape is not already scaled).

src/ospjolt/activescene/joltinteg.h Outdated Show resolved Hide resolved

//TODO this is locking on all bodies. Is it bad ?
//The easy fix is to provide multiple step listeners for disjoint sets of bodies, which can then run in parallel.
//It might not be worth it considering this function should be quite fast.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now this works, but maybe a custom Constraint is the way to go later on for ForceFactors?

Docs says all bodies are all locked within PhysicsStepListener, and bodies can be accessed directly.

src/testapp/sessions/jolt.cpp Outdated Show resolved Hide resolved
@jonesmz
Copy link
Member

jonesmz commented Jun 7, 2024

Nice work! I'd assume the Newton submodule should be kept around for benchmarking? Fairly simple to just make a copy of each test scenario. I don't mind this being merged in a non-final state as long as it mostly works; I'd like to figure out how to get around doing planet terrain colliders.

I think keeping newton for a short amount of time might be worth doing, but we should definitely be removing it if jolt is working at a similar level or better. Newton doesn't compile on a bunch of targets, and it's code is a bonkers mess. I'd rather just be done with it.

@@ -0,0 +1,39 @@
/**
* Open Space Program
* Copyright © 2019-2024 Open Space Program Project
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arguably the copyright date for this file only starts in 2024, not 2019.

I'm not a lawyer, so i'm not 100% certain how this should be done.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I copied some things straight from the forcefactor.h in ospnewton which starts in 2019, but honestly I have no idea either.

// These determine which physics calculations are required for a certain
// rigid body, such as gravity, thurst, or aerodynamics.
// Forces are assignable at runtime in ACtxJoltWorld::m_factors
using ForceFactors_t = std::array<uint64_t, 1u>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why use an array of size one?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this to provide a strong typedef? or is the goal here to generically support any number of items in the array, but start with only 1?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(not my code, so I can't be 100% sure)
I think the intent is to be able to have a bigger array, so that more than 64 forces can be supported. Currently some things break if the array is bigger though.

static void TraceImpl(const char *inFMT, ...)
{
// Format the message
va_list list;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm very, very, very, wary of C++ code using va_list / va_start.

What's driving the use of a C-style variadic function instead of a C++ template function?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Somehow, there don't seem to be another way.

Basically, I updated it to use spdlog, and the problem is, the spdlog function takes 2 arguments then variadics, and jolt expects 1 argument then variadics. So the only way seem to be to "unwrap" the variadics using vsnprintf, then call spdlog::trace.
I just looked into it and I'm pretty annoyed there isn't a simpler way.

Template function can't be used here, as Jolt expects a generic function pointer that can be used for any type of values.

*/
namespace Layers
{
static constexpr ObjectLayer NON_MOVING = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason not to use an enum class for these constants? They look a lot like enum values?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jolt expects "ObjectLayer" values, which is basically u16. Is there a way to make an enum which can be compared against another type easily in c++ ? For exemple in a switch statement

#include <osp/activescene/basic.h>
#include <osp/core/id_map.h>

#include <Jolt/Jolt.h>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from https://github.com/jrouwe/JoltPhysics/blob/master/HelloWorld/HelloWorld.cpp

// The Jolt headers don't include Jolt.h. Always include Jolt.h before including any other Jolt header.
// You can use Jolt.h in your precompiled header to speed up compilation.
#include <Jolt/Jolt.h>

wow, what an absolutely bullshit decision.

case Layers::MOVING:
return true; // Moving collides with everything
default:
JPH_ASSERT(false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Outside the scope of this PR, but we should probably make a more advanced ASSERT implementation for OSP that automatically does fun things like generating coredumps, generating back traces, and so on.


TransformedShapePtr_t SysJolt::create_primitive(ACtxJoltWorld &rCtxWorld, osp::EShape shape)
{
Shape* joltShape;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

std::unique_ptr

src/testapp/scenarios.cpp Outdated Show resolved Hide resolved
src/testapp/scenarios.cpp Outdated Show resolved Hide resolved
@jonesmz
Copy link
Member

jonesmz commented Jun 7, 2024

To fix the msvc analyzer workflow, we'll need to link against the debug build of the microsoft libraries when building the Debug config.

See: https://stackoverflow.com/questions/35793622/lnk2019unresolved-external-symbol-crtdbgreport-referenced-in-function-crt-rtc

That's controlled by https://cmake.org/cmake/help/latest/variable/CMAKE_MSVC_RUNTIME_LIBRARY.html

but it doesn't seem to be working properly?

@Lamakaio
Copy link
Contributor Author

Lamakaio commented Jun 12, 2024

This should be mostly done, except for the windows build issue, which I can't seem to find a solution to. If no new idea arise, I will probably setup the project on my windows machine to do some more in-depth testing. I'm still a bit unsure of some design decision (like the jolt / osp ids), but it's the best I could come up with that compiles.

BroadPhaseLayer GetBroadPhaseLayer(ObjectLayer inLayer) const override
{
JPH_ASSERT(inLayer < Layers::NUM_LAYERS);
return mObjectToBroadPhase[inLayer];

Check warning

Code scanning / PREfast

Reading invalid data from 'this->mObjectToBroadPhase'. Warning

Reading invalid data from 'this->mObjectToBroadPhase'.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this is covered by the assert?

The only constructor initializes the array up to Layers::NUM_LAYERS.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've seen clang-tidy do similar things on custom asserts. Under the 'show paths' button, it says it's assuming that the condition inLayer < Layers::NUM_LAYERS is false, and doesn't know the program should just panic in that case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's specifically a function attribute to tag functions like that as "If you get here, assume everything after it is unreachable".

but i don't think there's an attribute like that for MSVC... (if someone knows about one, please tell me, as i really would like to use it at work...)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that these code scanners are scanning based on MSVC, not clang / gcc.

Github requires "Sarif" output to be able to ingest analyzer results, and clang / gcc don't support that format for their analyzer tools.

@Lamakaio
Copy link
Contributor Author

I did one more pass on the code and rebased it. I feel like it's pretty much done on my end.

@Capital-Asterisk
Copy link
Contributor

One thing I forgot to note, is that the rockets in the vehicle test scenario have a bit of a pendulum effect on them. Something is up with the center-of-mass or torque calculations. I don't mind this being fixed later.

does this PR still need WIP in the title?

@jonesmz
Copy link
Member

jonesmz commented Jun 23, 2024

I have no objection to merging this code as is.

@Lamakaio can you please do three (relatively) minor things so we can merge it?

  1. Change the title to remove "wip".
  2. Change the PR from draft to normal.
  3. Rebase against master one last time, and this time squash/fixup your commits into a more "publicly facing" format. You don't need to squish everything into a single commit, just try to reduce the quantity, and maybe add some more elaborated commit messages if you feel like it.

@Lamakaio
Copy link
Contributor Author

Lamakaio commented Jun 23, 2024

Absolutely ! I'll do that tomorrow.
I'll check the center of mass / inertia calculation quickly in case I missed something obvious.

@Lamakaio Lamakaio changed the title WIP replace Newton Dynamics with Jolt Physics Replace Newton Dynamics with Jolt Physics Jun 24, 2024
@Lamakaio
Copy link
Contributor Author

Lamakaio commented Jun 24, 2024

Should be all done. I also fixed the pendulum effect, there was a stray minus sign in the center of mass calculations.

(sorry for the multiple pushes I broke some things while rebasing and rewriting the history apparently...)

@jonesmz jonesmz merged commit c70effd into TheOpenSpaceProgram:master Jun 24, 2024
22 checks passed
@jonesmz
Copy link
Member

jonesmz commented Jun 24, 2024

Ok, passing CI, approval from CapitalAsterisk and myself, and nice commit organization.

Lets merge it!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants