Jump to content

Recommended Posts

Posted

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?

 

ParentedPhysicsObject.gif.dcf746d27915661e131f0af1f500e64b.gif

#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;
}

 

Posted

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

ParentedPhysicsObject_002.gif.d055740bc8e90ba080338110127be7e0.gif

#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;
}

 

Posted

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.

  • Windows 10 Pro 64-Bit-Version
  • NVIDIA Geforce 1080 TI
Posted

If the platform uses physics to move, the box would just automatically turn since it is resting on it....?

My job is to make tools you love, with the features you want, and performance you can't live without.

Posted

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.

  • Windows 10 Pro 64-Bit-Version
  • NVIDIA Geforce 1080 TI
Posted

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.

Posted

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.

ParentedPhysicsObject_003.gif.1f40aa464c6d8112dce93aaedd50917c.gif

Posted

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. :)

Posted

I thought about doing something similar with navigation meshes, to do something like spherical pac-man.

  • Like 1

My job is to make tools you love, with the features you want, and performance you can't live without.

Posted

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

 

  • Upvote 1
  • Windows 10 Pro 64-Bit-Version
  • NVIDIA Geforce 1080 TI
Posted

small experiment, i couldn't resist ;)

image.thumb.gif.768a10902fea2bf5b51142ff5dba960b.gif

#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;
}

 

  • Like 3
  • Windows 10 Pro 64-Bit-Version
  • NVIDIA Geforce 1080 TI

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...