SpiderPig Posted September 7, 2023 Share Posted September 7, 2023 I want to be able have physics working on various different platforms that each have there own velocity and rotations happening. (In this example I'm just turning the floor object, so that might be the wrong way to do that.) On each platform I'd want to have physics working normally as though each platform is it's own little physics world, oblivious to the fact that it's platform is moving about. Just like we can walk on Earth and not feel like were hurtling around the sun and around the Earths axis. I guess this is similar to parenting a player controller to an elevator that moves left and right so the player doesn't slide off the platform as it moves. As the GIF shows, simply parenting the box to the floor breaks the physics sim I think. But the concept is what I'm trying to achieve. The same goes for parenting the player controller to the floor. It looks like it wants to work the way I intend, it just keeps bouncing back and forth. Any one know if this might be possible? #include "UltraEngine.h" using namespace UltraEngine; Vec3 mousepos = Vec3(0.0f); float move_adjustment = 0.1f; float move_speed = 1.0f; float lookspeed = 0.1f; float looksmoothing = 0.5f; bool enable_camera = true; int main(int argc, const char* argv[]) { auto displays = GetDisplays(); auto window = CreateWindow("Ultra Engine", 0, 0, 1280, 720, displays[0], WINDOW_CENTER | WINDOW_TITLEBAR); auto world = CreateWorld(); auto framebuffer = CreateFramebuffer(window); auto camera = CreateCamera(world); camera->SetClearColor(0.125); camera->SetFov(70); camera->SetPosition(0, 10, -5); auto light = CreateDirectionalLight(world); light->SetRotation(35, 45, 0); auto floor = CreateBox(world, 10.0f, 0.1f, 10.0f); floor->SetPosition(0.0f, -3.0f, 0.0f); floor->SetMaterial(LoadMaterial("Materials\\Developer\\bluegrid.mat")); auto box = CreateBox(world); box->SetMass(1.0f); box->SetPosition(2.0f, 2.0f, 0.0f); box->SetParent(floor); auto player = CreateCylinder(world); player->SetPhysicsMode(PHYSICS_PLAYER); player->SetPosition(0.0f, 5.0f, 0.0f); player->SetMass(1.0f); auto cam_pivot = CreatePivot(world); cam_pivot->SetParent(player); cam_pivot->SetPosition(0.0f, 1.8f, 0.0f); camera->SetParent(cam_pivot); camera->SetPosition(0.0f, 0.0f, -3.0f); camera->SetDebugPhysicsMode(true); bool stage = 0; while (window->Closed() == false and window->KeyDown(KEY_ESCAPE) == false) { if (window->KeyHit(KEY_F2) == true) { camera->SetWireframe(!camera->GetWireframe()); } if (window->KeyHit(KEY_F3) == true) { camera->SetDebugPhysicsMode(!camera->GetDebugPhysicsMode()); } if (window->KeyHit(KEY_F4) == true) { enable_camera = !enable_camera; } if (enable_camera) { auto _displaySize = window->GetSize(); float cx = Round((float)_displaySize.x / 2.0f); float cy = Round((float)_displaySize.y / 2.0f); auto mpos = Vec3(window->GetMousePosition().x, window->GetMousePosition().y, window->GetMousePosition().z); window->SetMousePosition(cx, cy); mpos = mpos * looksmoothing + mousepos * (1 - looksmoothing); auto dx = (mpos.x - cx) * lookspeed; auto dy = (mpos.y - cy) * lookspeed; auto camrot = cam_pivot->GetRotation(); camrot.x += dy; camrot.y += dx; cam_pivot->SetRotation(camrot); mousepos = mpos; } floor->Turn(0.0f, 0.1f, 0.0f); auto y_angle = cam_pivot->GetRotation().y; auto move = 0.0f, strafe = 0.0f; if (window->KeyDown(KEY_W)) { move = 1.0f; } else if (window->KeyDown(KEY_S)) { move = -1.0f; } if (window->KeyDown(KEY_A)) { strafe = -1.0f; } else if (window->KeyDown(KEY_D)) { strafe = 1.0f; } player->SetInput(y_angle, move, strafe); world->Update(); world->Render(framebuffer); } return 0; } Quote Link to comment Share on other sites More sharing options...
SpiderPig Posted September 7, 2023 Author Share Posted September 7, 2023 I think I actually might have solved this. I'm reluctant to party until I've tested it further but I can use a 2nd world for physics that has non-moving platforms, then I can transform positions and rotations into the main world which is rendered. Should work for controllers and multiple gravity directions I would think... I wonder if there is a downside to doing it this way...? #include "UltraEngine.h" using namespace UltraEngine; Vec3 mousepos = Vec3(0.0f); float move_adjustment = 0.1f; float move_speed = 1.0f; float lookspeed = 0.1f; float looksmoothing = 0.5f; bool enable_camera = true; int main(int argc, const char* argv[]) { auto displays = GetDisplays(); auto window = CreateWindow("Ultra Engine", 0, 0, 1280, 720, displays[0], WINDOW_CENTER | WINDOW_TITLEBAR); auto world = CreateWorld(); auto framebuffer = CreateFramebuffer(window); auto camera = CreateCamera(world); camera->SetClearColor(0.125); camera->SetFov(70); camera->SetPosition(0, 10, -5); auto light = CreateDirectionalLight(world); light->SetRotation(35, 45, 0); auto floor = CreateBox(world, 10.0f, 0.1f, 10.0f); floor->SetPosition(0.0f, -3.0f, 0.0f); floor->SetMaterial(LoadMaterial("Materials\\Developer\\bluegrid.mat")); auto box = CreateBox(world); box->SetCollider(nullptr); // box->SetMass(1.0f); box->SetPosition(2.0f, 2.0f, 0.0f); // box->SetParent(floor); auto player = CreateCylinder(world); player->SetPhysicsMode(PHYSICS_PLAYER); player->SetPosition(0.0f, 5.0f, 0.0f); player->SetMass(1.0f); auto cam_pivot = CreatePivot(world); cam_pivot->SetParent(player); cam_pivot->SetPosition(0.0f, 1.8f, 0.0f); camera->SetParent(cam_pivot); camera->SetPosition(0.0f, 0.0f, -3.0f); camera->SetDebugPhysicsMode(true); auto world_2 = CreateWorld(); auto f2 = CreateBox(world_2, 10.0f, 0.1f, 10.0f); f2->SetPosition(0, -3, 0); auto b2 = CreateBox(world_2); b2->SetMass(1.0f); b2->SetPosition(2.0f, 2.0f, 0.0f); world_2->Update();//No random crash with this? bool stage = 0; while (window->Closed() == false and window->KeyDown(KEY_ESCAPE) == false) { if (window->KeyHit(KEY_F2) == true) { camera->SetWireframe(!camera->GetWireframe()); } if (window->KeyHit(KEY_F3) == true) { camera->SetDebugPhysicsMode(!camera->GetDebugPhysicsMode()); } if (window->KeyHit(KEY_F4) == true) { enable_camera = !enable_camera; } if (enable_camera) { auto _displaySize = window->GetSize(); float cx = Round((float)_displaySize.x / 2.0f); float cy = Round((float)_displaySize.y / 2.0f); auto mpos = Vec3(window->GetMousePosition().x, window->GetMousePosition().y, window->GetMousePosition().z); window->SetMousePosition(cx, cy); mpos = mpos * looksmoothing + mousepos * (1 - looksmoothing); auto dx = (mpos.x - cx) * lookspeed; auto dy = (mpos.y - cy) * lookspeed; auto camrot = cam_pivot->GetRotation(); camrot.x += dy; camrot.y += dx; cam_pivot->SetRotation(camrot); mousepos = mpos; } floor->Turn(0.0f, 0.1f, 0.0f); auto y_angle = cam_pivot->GetRotation().y; auto move = 0.0f, strafe = 0.0f; if (window->KeyDown(KEY_W)) { move = 1.0f; } else if (window->KeyDown(KEY_S)) { move = -1.0f; } if (window->KeyDown(KEY_A)) { strafe = -1.0f; } else if (window->KeyDown(KEY_D)) { strafe = 1.0f; } player->SetInput(y_angle, move, strafe); if (window->KeyHit(KEY_P)) { b2->AddForce(0,200,0); } world_2->Update(); auto p = b2->GetPosition(); auto r = b2->GetRotation(); auto matrix = floor->GetMatrix(); matrix = matrix.Inverse(); matrix.t = Vec4(0, 0, 0, 1); p = TransformPoint(p, Mat4(), matrix); auto rr = TransformRotation(r, Mat4(), matrix); box->SetPosition(p); box->SetRotation(rr); world->Update(); world->Render(framebuffer); } return 0; } Quote Link to comment Share on other sites More sharing options...
klepto2 Posted September 7, 2023 Share Posted September 7, 2023 I think the Physicsmatrix is only updated for the box itself, not taking the parent into account. You can see this in the first sample: While the box is moving you can actually move through it even though the collision shape is displayed correct. When you move to the original Position the collison will occur. Quote Windows 10 Pro 64-Bit-Version NVIDIA Geforce 1080 TI Link to comment Share on other sites More sharing options...
SpiderPig Posted September 7, 2023 Author Share Posted September 7, 2023 Yeah I see what you mean. I think the 2nd example solves it. 🙂 Quote Link to comment Share on other sites More sharing options...
Josh Posted September 7, 2023 Share Posted September 7, 2023 If the platform uses physics to move, the box would just automatically turn since it is resting on it....? Quote My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
klepto2 Posted September 7, 2023 Share Posted September 7, 2023 yes, but that would mean, that the floor itself needs a mass otherwise the force methods will have no impact. To make it physically correct, ( i believe i read that somewhere on the Newtondynamics forums back in Blitzmax times ) Would be to turn off gravity at all and for each object apply a force pointing to the center of your "planet" or maybe in this case just downwards. Of course in the case of a plane you need to conquer the forces applied to the plane to make it stable. Quote Windows 10 Pro 64-Bit-Version NVIDIA Geforce 1080 TI Link to comment Share on other sites More sharing options...
SpiderPig Posted September 7, 2023 Author Share Posted September 7, 2023 Yeah it would need a mass. I could turn off gravity and it might work for the box on the platform but dosn't for the controller. Also it wouldn't work for a custom collider as they are static. I think I can make my idea work, even without a 2nd world. Quote Link to comment Share on other sites More sharing options...
SpiderPig Posted September 7, 2023 Author Share Posted September 7, 2023 Got it working with the player controller. I'm going to expand on this and make a complex level with a lot going on to see if it holds up. You can see in the animation that the physics objects don't rotate and none of the rendered objects have colliders. It's just a matter of getting the physics matrix's and transforming them based on what platform is moving. Quote Link to comment Share on other sites More sharing options...
SpiderPig Posted September 7, 2023 Author Share Posted September 7, 2023 This is what I'm doing to transform the objects. void UpdatePhysics(shared_ptr<Entity> source, shared_ptr<Entity> target, shared_ptr<Entity> platform = nullptr) { auto pos = source->GetPosition(); auto rot = source->GetRotation(); if (platform != nullptr) { auto matrix = platform->GetMatrix(); matrix = matrix.Inverse(); matrix.t = Vec4(0, 0, 0, 1); pos = TransformPoint(pos, Mat4(), matrix); rot = TransformRotation(rot, Mat4(), matrix); } target->SetPosition(pos); target->SetRotation(rot); } This may yet not work for all cases, but I wonder if a simple callback system between the physics thread and the rendered world could do this? Basically it would mean we could offset the rendered object away from it's collider. Just thinking out loud. Quote Link to comment Share on other sites More sharing options...
SpiderPig Posted September 7, 2023 Author Share Posted September 7, 2023 On second thought I think it'll introduce too many complications. Quote Link to comment Share on other sites More sharing options...
Josh Posted September 7, 2023 Share Posted September 7, 2023 I thought about doing something similar with navigation meshes, to do something like spherical pac-man. 1 Quote My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
SpiderPig Posted September 11, 2023 Author Share Posted September 11, 2023 I got this to work. I'm pleased with the result. I also (finally) got a custom player controller working with different gravity directions. https://youtu.be/XUKbSHf3e6k Quote Link to comment Share on other sites More sharing options...
klepto2 Posted September 11, 2023 Share Posted September 11, 2023 If i remember correctly (@Josh correct me if i am wrong) , the gravity is applied to each object in the "NewtonBodySetForceAndTorqueCallback" which means, that while currently only a fixed gravity force is applied, this could be extended to add several "Attractors" or planets. So in theory you could simulate whole a whole universe with planets. and correct gravity. Maybe it would be an option to open up the Callback to override the force calculation for gravity? Maybe something like this (more or less pseudo code): vec3 world_gravity_callback(vec3 pos) { vec3 force = vec3(0); for(auto p : planets) { float distanceToPlanet = calcDistance(pos); force += calcForce(pos, distanceToPlanet); // as Newton engine uses real world units, you can actually use the real physics equations here } return force; } void cb_applyForce(const NewtonBody* const body, dFloat timestep, int threadIndex) { // Fetch user data and body position. UserData *mydata = (UserData*)NewtonBodyGetUserData(body); dFloat pos[4]; NewtonBodyGetPosition(body, pos); // Apply gravity. dFloat force[3] = world->Gravity; if(world->HasGravityCallback) // if custom gravity is used calculate this instead of the fixed gravity { force = world->CalculateGravityForPosition(pos); } NewtonBodySetForce(body, force); } 1 Quote Windows 10 Pro 64-Bit-Version NVIDIA Geforce 1080 TI Link to comment Share on other sites More sharing options...
SpiderPig Posted September 11, 2023 Author Share Posted September 11, 2023 Yes that should work well. I disable world gravity and use AddForce() in a loop elsewhere for now, it works but overwriting the default world gravity would be much cleaner. Quote Link to comment Share on other sites More sharing options...
klepto2 Posted September 11, 2023 Share Posted September 11, 2023 small experiment, i couldn't resist #include "UltraEngine.h" #include "Components/Player/CameraControls.hpp" using namespace UltraEngine; const float G = 667.4f; const float planet_mass = 1000.0; Vec3 calculateForce(shared_ptr<Entity> planet, shared_ptr<Entity> target) { Vec3 direction = (planet->GetPosition() - target->GetPosition()); float distance = direction.Length(); if (distance == 0) return Vec3(0.0); float forceMagnitude = G * (target->GetMass() * planet_mass) / pow(distance, 2); Vec3 force = direction.Normalize() * forceMagnitude; return force; } int main(int argc, const char* argv[]) { auto displays = GetDisplays(); auto window = CreateWindow("Ultra Engine", 0, 0, 1280, 720, displays[0], WINDOW_CENTER | WINDOW_TITLEBAR); auto world = CreateWorld(); auto framebuffer = CreateFramebuffer(window); auto camera = CreateCamera(world); camera->SetClearColor(0.125); camera->SetFov(70); camera->SetPosition(0, 10, -5); auto light = CreateDirectionalLight(world); light->SetRotation(35, 45, 0); world->SetGravity(0.0, 0.0, 0.0); auto planet = CreateSphere(world, 100.0, 128); planet->SetMass(FLT_MAX - 1); planet->SetPosition(0.0f, -100.0f, 0.0f); planet->SetMaterial(LoadMaterial("Materials\\Developer\\bluegrid.mat")); camera->SetPosition(0.0f, 0.0f, -3.0f); camera->AddComponent<CameraControls>(); camera->SetDebugPhysicsMode(true); vector<shared_ptr<Entity>> boxes; auto box_main = CreateBox(world, 4.0); for(int i = 0; i < 200; i ++) { auto box = box_main->Instantiate(world); box->SetMass(1.0); box->SetColor(1.0, 0.0, 0.0, 1.0); box->SetPosition(Random(120.0, -120.0), Random(120.0, -120.0), Random(120.0, -120.0)); box->Move(0.0, -100.0, 0.0); boxes.push_back(box); } box_main = NULL; bool stage = 0; while (window->Closed() == false and window->KeyDown(KEY_ESCAPE) == false) { if (window->KeyHit(KEY_F2) == true) { camera->SetWireframe(!camera->GetWireframe()); } if (window->KeyHit(KEY_F3) == true) { camera->SetDebugPhysicsMode(!camera->GetDebugPhysicsMode()); } bool hit_space = window->KeyHit(KEY_SPACE); for each (auto box in boxes) { box->AddForce(calculateForce(planet, box)); if (hit_space) { Vec3 direction = (planet->GetPosition() - box->GetPosition()).Normalize(); box->AddForce(-direction * 2500.0); } } world->Update(); world->Render(framebuffer); } return 0; } 3 Quote Windows 10 Pro 64-Bit-Version NVIDIA Geforce 1080 TI Link to comment Share on other sites More sharing options...
SpiderPig Posted September 11, 2023 Author Share Posted September 11, 2023 Gravity is cool I wonder if the jitter of the boxes is because the sphere is too small for there to be a flat enough face to rest on. Quote Link to comment Share on other sites More sharing options...
klepto2 Posted September 11, 2023 Share Posted September 11, 2023 I think so. Thts why i increased the sphere segments a bit. Otherwise the jitter is much more obvious at the segment points. 1 Quote Windows 10 Pro 64-Bit-Version NVIDIA Geforce 1080 TI Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.