Announcement

Collapse
No announcement yet.

The Re-Inventing the Wheel Thread

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    #16
    Originally posted by 0lento View Post
    I don't really see how this is an issue unless you need to use some really stiff springs and large delta time.. ..which wouldn't be ideal in the first place. If you can guarantee that physics step is using fixed delta time, you can find safe operating range for spring forces. Of course you could handle the integration yourself with better integration method for this specific task (RK4?) if that really is a concern and do as many steps on your own calcs as needed to keep it stable. You can even inject your own velocity values to physx scene if you use c++ and substepping using https://github.com/EpicGames/UnrealEngine/pull/585.

    To be honest, for regular vehicles on unreal, this does seem a bit like premature optimization/fool-proofing and I really wouldn't worry about it beforehand unless you'll find it's actually causing you trouble.
    In my latest demo it can be easily seen if you just set t.maxFPS to something around 20-30. Suspension of Ripsaw after spawn, just doesn't stop bouncing at 15 fps. Take into account that it's 10 suspension systems here, not 4 as on regular car. Car's weight less, but as it can accelerate to higher speeds, relative mass will grow too and can be comparable to tank.
    It won't be enjoyable experience to play game with such refresh rate but the point is that occasional dip in fps can lead to abnormal behavior of vehicle physics. I'm not even taking into account possible replications issues and hack detection. Adding sub-stepping won't really help because setup of suspension depends on DeltaTime. It means it will behave differently, more time steps can only mask it. This isn't really about physics bug but how controllable vehicle will be.
    Last edited by BoredEngineer; 11-05-2015, 02:46 PM.
    Youtube Channel

    Comment


      #17
      I realized that what I said was only if you do fixed time steps for substepped physics. If you use substepping as is, you can have potentially situations where you'd get bigger delta times, so sorry if I misunderstood the original point
      https://github.com/0lento/UnrealEngine (GameWorks tech merges & upgrades, UE4 physics modifications)

      Comment


        #18
        Originally posted by BoredEngineer View Post
        Adding sub-stepping won't really help because setup of suspension depends on DeltaTime. It means it will behave differently, more time steps can only mask it. This isn't really about physics bug but how controllable vehicle will be.
        Are you talking about adding substeps but not applying the suspension forces on the physics steps itself? I think so, as your example is BP only. For example I'm doing my current prototype's vehicle suspension force updates at 100 steps per second at the moment and it's pretty responsive. I update the suspension calcs on each substep. If I updated those suspension forces only 20-30 times per second, I'd lose most of the benefits of using substepping and it wouldn't solve the inaccuracy issues at all, 10 times per second wouldn't work at all and would result in forces overshooting all the time. Of course if you are using only blueprints, you don't have much options and you have to live with less optimal update rates.
        Last edited by 0lento; 11-05-2015, 03:46 PM.
        https://github.com/0lento/UnrealEngine (GameWorks tech merges & upgrades, UE4 physics modifications)

        Comment


          #19
          But that's the thing. Regardless of how many physics update steps per second you run. If you tune your spring parameters to 50 fps, it won't behave the same at 25 fps. It's not about accuracy but magnitude of forces which are produced. This is not the case where at 100 fps your suspension force will be fluctuating at some decimal number and at 25 fps it will be an order of magnitude higher but the case where value will be totally different. The reason for this is because first term of spring and damping equation can change rapidly regardless of your fps - if vehicle drives over the box on the road, the length of suspension will change as fast as wheel hits the box. In case of vehicle falling on the ground, the lower your fps the higher spring force will be as difference in spring length will be higher at lower fps. This means that "smoothness" of the suspension is related to your fps, combined with weight distribution because of change in acceleration the driving will just feel different. It might look just fine and don't have any visible glitches but controls will feel different.
          Your approach will work just fine for a lot of use cases, especially if you can enforce a certain min/max frequency of physics update. I'm just looking into more general case of using physics in games like Bad Piggies or Kerbal Space Program, where you would have to build a different vehicle to solve the puzzle just because there is performance difference between your laptop and PC.
          Youtube Channel

          Comment


            #20
            I think I lost the point here, if I run physics at fixed 100 steps per second, I don't really have to take any other scenarios into account, I just tune the values to behave well at 100 steps on physics engine and it will run the simulation the same if target hw renders graphics 10 or 120 frames per second (as long as physics engine keeps up and we don't take floating point inaccuracies into account).
            Last edited by 0lento; 11-05-2015, 05:24 PM.
            https://github.com/0lento/UnrealEngine (GameWorks tech merges & upgrades, UE4 physics modifications)

            Comment


              #21
              Originally posted by BoredEngineer View Post
              I'm just looking into more general case of using physics in games like Bad Piggies or Kerbal Space Program, where you would have to build a different vehicle to solve the puzzle just because there is performance difference between your laptop and PC.
              Bad Piggies and KSP both use Unity which actually has fixed timestepping on physics btw.

              Edit-> Well, actually it's not truly fixed timestep on unity either but at least it's trying to run the physics at fixed rate there by default vs UE4 which has variable update rate on physics unless you manually change it.
              Last edited by 0lento; 11-05-2015, 05:52 PM.
              https://github.com/0lento/UnrealEngine (GameWorks tech merges & upgrades, UE4 physics modifications)

              Comment


                #22
                so, trying to learn from mine and other peoples experiences with suspension,
                a problem lies in getting the velocity. since you cant access a components physics velocity you have to cheat and use deltatime. when deltatime becomes too big due to low framerate, the calculations become 'corrupt' so to speak and there are issues.
                this is why i messed up in my original screenshots, i was trying all sorts of ways to get a reliable velocity and accidentally moved that part out of the screenshot as i thought it was just part of the mess that didnt work.
                every time the car looked as if it had good suspension it would at some point look like a plane going through turbulence or a low rider with a monkey at the controls.

                since you cant access sub step in blueprints ive been trying to do it in code, which leads to probably the most important question...
                how do you access sub step in code?

                i found only an old post with not quite enough information, also it says
                that feature and it should be present in engine versions 4.6 and up
                but of course there is nothing in the documentation and no examples of how to use this feature, or even if it is present in the current engine version at all

                also the idea of using a constraint seems more logical/reliable than applying an upwards force to the chassis.
                i think that using a wheel with actual collision constrained to the chassis would be far more reliable or less prone to launching the vehicle into the air than a line trace and addforce.
                tegleg.co.uk - indie electronic music label
                Android + HTML5 WIP Physics Game
                PC Games - Android Apps

                Comment


                  #23
                  Do you mean that sample code provided by toxygen is not enough? His pull request was closed long time ago, so I think correction to the code was added.
                  I'm planning to try this spring and damper approach:
                  http://www.gamedev.net/page/resource...e-spring-r3227
                  was thinking about it today and I don't see a reason why I need to calculate variable effective mass as simply providing equally distributed mass of the vehicle in passive state should be enough. The main benefit of such formulation is that amplitude of force become depended on the value of delta time and should scale with it. Another nice befit is that damping is not related to time more than to speed which means that spring can produce X amount of force at Y amount of time. This is really nice because if one wants to have collision on wheels, you would have a nice formulation of how wheel impact force should be distributed between suspension spring, then shock absorber and what is left will go into chassis.

                  Regarding wheels collision. I know that PhysX doesn't provide cylinder as a collision primitive. Do you guys think it's possible to imitate it by filtering results of collision query using cube and a capsule?
                  Something like this:
                  - query multi-collision on capsule and box into two separate arrays
                  - transform collision points into object space of the wheel
                  - filter out capsule collision points on their values of Y axis (assuming that Y is a right vector and Z is up vector of wheel)
                  - filter out box collision points on the distance from center of the wheel in YZ plane
                  - somehow chose a single collision point or pass all of them as output (can be used to generate patch for tire simulation)
                  Last edited by BoredEngineer; 11-06-2015, 05:28 PM.
                  Youtube Channel

                  Comment


                    #24
                    Originally posted by BoredEngineer View Post
                    Do you mean that sample code provided by toxygen is not enough?
                    yes
                    probably because i really dont know what im doing with ue4's c++. i tried to copy what was there and got compilation errors, and im not totally sure where to put what tbh.
                    might just stick with blueprints for now and try a few different formulas
                    tegleg.co.uk - indie electronic music label
                    Android + HTML5 WIP Physics Game
                    PC Games - Android Apps

                    Comment


                      #25
                      Originally posted by tegleg View Post
                      so, trying to learn from mine and other peoples experiences with suspension,
                      a problem lies in getting the velocity. since you cant access a components physics velocity you have to cheat and use deltatime.
                      What you mean by access? You've already accessed rb velocity on your screenshots. Only issue I've seen on BPs that you can't read the (physx) physics changes faster than Tick which itself can vary a lot based on actual rendering frame rate (well, on top of obvious performance issues).


                      Originally posted by tegleg View Post
                      how do you access sub step in code?
                      It's not that tricky, most of the code needed has been already posted on the pull request itself, just things on header are missing from the example. I will make a simple step by step example and post the code on this thread later on (today or tomorrow).


                      Originally posted by tegleg View Post
                      i think that using a wheel with actual collision constrained to the chassis would be far more reliable or less prone to launching the vehicle into the air than a line trace and addforce.
                      If you make open wheel vehicle, you of course need to cover the line trace. If you don't do that, you'll get behaviour like that. You could probably cover the wheel with cylinder collider that have collision setup that doesn't block traces and actual road etc surfaces. That way colliders wouldn't affect the regular simulation and you could still handle cases where wheels hit something like fences, railings etc. You could even handle some more specific scenarios with hit events where another vehicle has wheel on top of your vehicles wheels etc.
                      https://github.com/0lento/UnrealEngine (GameWorks tech merges & upgrades, UE4 physics modifications)

                      Comment


                        #26
                        Originally posted by BoredEngineer View Post
                        Do you mean that sample code provided by toxygen is not enough? His pull request was closed long time ago, so I think correction to the code was added.
                        It's been added to the engine since 4.7.

                        Originally posted by BoredEngineer View Post
                        Regarding wheels collision. I know that PhysX doesn't provide cylinder as a collision primitive. Do you guys think it's possible to imitate it by filtering results of collision query using cube and a sphere?
                        Something like this:
                        - query multi-collision on sphere and box into two separate arrays
                        - transform collision points into object space of the wheel
                        - filter out sphere collision points on their values of Y axis (assuming that Y is a right vector and Z is up vector of wheel)
                        - filter out box collision points on the distance from center of the wheel in YZ plane
                        - somehow chose a single collision point or pass all of them as output (can be used to generate patch for tire simulation)
                        There is collision filtering, callbacks etc built-in to physx but I haven't done research how that all works. Pretty sure you'll find more info on that if you study physx sdk docs. If you could do that, wouldn't you want use capsule collision instead of sphere though?
                        https://github.com/0lento/UnrealEngine (GameWorks tech merges & upgrades, UE4 physics modifications)

                        Comment


                          #27
                          Originally posted by 0lento View Post
                          What you mean by access? You've already accessed rb velocity on your screenshots.
                          in the screenshot its for the chassis, or the root component of the car. i tried to get velocity from the wheel meshes but of course they dont have physics, and a line trace is just that. so getting the velocity of a 'spring' has to be some kind of hack using deltatime.

                          thanks both of you for all your input so far in this thread its very interesting, there's lots to think about, lots to learn and lots to try
                          tegleg.co.uk - indie electronic music label
                          Android + HTML5 WIP Physics Game
                          PC Games - Android Apps

                          Comment


                            #28
                            Originally posted by 0lento View Post
                            There is collision filtering, callbacks etc built-in to physx but I haven't done research how that all works. Pretty sure you'll find more info on that if you study physx sdk docs. If you could do that, wouldn't you want use capsule collision instead of sphere though?
                            Yeap, I mean capsule, not sphere. [Corrected]
                            Youtube Channel

                            Comment


                              #29
                              Originally posted by tegleg View Post
                              in the screenshot its for the chassis, or the root component of the car. i tried to get velocity from the wheel meshes but of course they dont have physics, and a line trace is just that. so getting the velocity of a 'spring' has to be some kind of hack using deltatime.
                              Oh right, I think that when cars body doesn't lean into any direction, velocity measured from main chassis should still give correct results. Meaning that it should work fine on even and inclined surfaces, but would give wrong data on bumps or if body leans in to some direction. Of course that's not ideal but it seemed to work well enough to kill the bouncy springs when I used it like that on my earlier prototypes, I never tested it on very rough terrain though.

                              I wouldn't consider calculating velocity using deltatime to be a hack, you may get precision issues but that's something you always have to deal with when you do real-time physics.

                              Btw, if you want to simulate wheels as rigidbodies (which are set to not collide directly with the ground), you could connect rigidbodies to main chassis using constraints and still use traces or overlap events (I should check how you could access this data directly on substeps) to figure out the forces needed. This is more sim approach and will require more complex setup.
                              https://github.com/0lento/UnrealEngine (GameWorks tech merges & upgrades, UE4 physics modifications)

                              Comment


                                #30
                                I made a simple c++ component example that uses substepping. I tried to remake this hover component tutorial.

                                Main difference is that it uses StaticMeshComponent as base and static mesh with collider needs to be Actors (or Pawns) root component. There has to be some better way to handle this, but I didn't bother looking further on that as it's more of an example how to use custom physics with substepping. Damping also uses the -b*v formula instead of dampling everything like on that hover component tutorial.

                                Steps for any existing or blank project (BP or c++):

                                1) Make sure you have substepping enabled from your Project Settings, you probably want to crank the max substeps to 16 right away for this.

                                2) Add new C++ class and select Scene Component (you could use the same code on c++ actor/pawn mostly as is btw, just few lines would change, but let's do the scene component now). You can do this from File menu or by clicking Add New on content browser.

                                3) Make sure your new Scene Component is named as SuspensionComponent (so you can just copy paste the code as is):

                                Click image for larger version  Name:	add_new_scene_component.png Views:	1 Size:	49.6 KB ID:	1092871

                                4) Open SuspensionComponent.h and find line that begins with something like: "class SUBSTEPEXAMPLE_API USuspensionComponent : public USceneComponent". Yours will have different projectname_API on it. Paste the following code into SuspensionComponent.h but replace SUBSTEPEXAMPLE_API with your original projectname_API:

                                NOTE: In case you run this on UE 4.22+, change PhysSceneStep(FPhysScene* PhysScene, uint32 SceneType, float DeltaTime) to PhysSceneStep(FPhysScene* PhysScene, float DeltaTime) from the following code snippets as there's no SceneType anymore in 4.22.
                                Code:
                                #pragma once
                                
                                #include "CoreMinimal.h"
                                #include "Components/SceneComponent.h"
                                #include "SuspensionComponent.generated.h"
                                
                                
                                UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
                                class SUBSTEPEXAMPLE_API USuspensionComponent : public USceneComponent
                                {
                                    GENERATED_BODY()
                                
                                private:
                                    FHitResult Trace(FVector TraceStart, FVector TraceDirection);
                                    FBodyInstance *BodyInstance;
                                    bool CacheBodyInstance();
                                    FDelegateHandle OnPhysSceneStepHandle;
                                    void PhysSceneStep(FPhysScene* PhysScene, uint32 SceneType, float DeltaTime);
                                
                                    UPROPERTY()
                                    float PreviousDistance;
                                
                                public:    
                                    virtual void BeginPlay() override;
                                    virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
                                
                                    UPROPERTY(EditAnywhere, Category = "Suspension")
                                    float TraceLength = 100.0f;
                                    UPROPERTY(EditAnywhere, Category = "Suspension")
                                    float SpringCoeff = 1000000.0f;
                                    UPROPERTY(EditAnywhere, Category = "Suspension")
                                    float DamperCoeff = 500.0f;
                                };
                                5) Open SuspensionComponent.cpp, find first include line which is something like #include "yourprojectname.h". Leave that include in place but replace the rest with this:

                                Code:
                                #include "SuspensionComponent.h"
                                #include "PhysicsPublic.h"
                                
                                void USuspensionComponent::BeginPlay()
                                {
                                    Super::BeginPlay();
                                
                                    UWorld* World = GetWorld();
                                    if (World)
                                    {
                                        FPhysScene* PScene = World->GetPhysicsScene();
                                        if (PScene)
                                        {
                                            // Register UE 4.15+ substep delegate
                                            OnPhysSceneStepHandle = PScene->OnPhysSceneStep.AddUObject(this, &USuspensionComponent::PhysSceneStep);
                                        }
                                    }
                                }
                                
                                void USuspensionComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
                                {
                                    UWorld* World = GetWorld();
                                    if (World)
                                    {
                                        FPhysScene* PScene = World->GetPhysicsScene();
                                        if (PScene)
                                        {
                                            // Unregister substep delegate when component is removed
                                            PScene->OnPhysSceneStep.Remove(OnPhysSceneStepHandle);
                                        }
                                    }
                                
                                    Super::EndPlay(EndPlayReason);
                                }
                                
                                FHitResult USuspensionComponent::Trace(FVector TraceStart, FVector TraceDirection)
                                {
                                    FHitResult Hit(ForceInit);
                                    FCollisionQueryParams TraceParams(true);
                                    TraceParams.bTraceAsyncScene = true;
                                    TraceParams.bReturnPhysicalMaterial = false;
                                    FVector TraceEnd = TraceStart + (TraceDirection * TraceLength);
                                    GetWorld()->LineTraceSingleByChannel(Hit, TraceStart, TraceEnd, ECC_WorldDynamic, TraceParams);
                                    return Hit;
                                }
                                
                                bool USuspensionComponent::CacheBodyInstance()
                                {
                                    // Get the primitive component from actors root (mesh or collider)
                                    UPrimitiveComponent* PrimitiveComponent = Cast<UPrimitiveComponent>(GetOwner()->GetRootComponent());
                                
                                    // Cache the BodyInstance
                                    if (PrimitiveComponent)
                                    {
                                        BodyInstance = PrimitiveComponent->GetBodyInstance();
                                    }
                                    if (!BodyInstance)
                                    {
                                        return false;
                                    }
                                    return true;
                                }
                                
                                // Called every physics substep
                                void USuspensionComponent::PhysSceneStep(FPhysScene* PhysScene, uint32 SceneType, float DeltaTime)
                                {
                                    // Make sure we have a valid BodyInstance
                                    if (!BodyInstance)
                                    {
                                        if (!CacheBodyInstance())
                                        {
                                            return;
                                        }
                                    }
                                    // Get up-to-date location directly from BodyInstance's transform
                                    FVector WorldLocation = BodyInstance->GetUnrealWorldTransform().GetLocation();
                                
                                    FHitResult Hit = Trace(WorldLocation, -FVector::UpVector);
                                    if (!Hit.bBlockingHit)
                                    {
                                        PreviousDistance = TraceLength;
                                        return;
                                    }
                                    float CurrentDistance = (WorldLocation - Hit.Location).Size();
                                    float DamperVelocity = (CurrentDistance - PreviousDistance) / DeltaTime;
                                    PreviousDistance = CurrentDistance;
                                
                                    // Calculate spring force
                                    float SpringForce = (1 - (CurrentDistance / TraceLength)) * SpringCoeff;
                                
                                    // Apply damper force
                                    SpringForce -= DamperVelocity * DamperCoeff;
                                
                                    FVector TotalForce = SpringForce * Hit.ImpactNormal;
                                
                                    // You need to set bAllowSubstepping param to false on AddForce, only use it when calling AddForce from Tick
                                    BodyInstance->AddForce(TotalForce, false);
                                }
                                6) Save .cpp and .h changes and compile. Hot-reload will probably not work for the first time, so prepare to compile from the code environment.

                                7) Create a new blank Blueprint Class and select Actor (Pawn should work just fine as well).

                                8) Go to Viewport mode and using Add Component add a Sphere and make it the root component on the BP. Also make sure you enable physics simulation for the Sphere.

                                9) Using Add Component, now add Suspension (our new component which we just made) and attach it to Sphere.

                                10) Save and Compile the BP, it should now look like this:

                                Click image for larger version  Name:	bp_actor.png Views:	1 Size:	234.2 KB ID:	1092877

                                11. Drag your new BP to your scene and hit play or simulate. It should now hover a ball, like on that hover tutorial. That's it.

                                Do note that I tried to make this a very minimalistic example how to run physics directly from substeps, there isn't many checks in place and there may be some small errors. If you find anything odd, drop me a note and I'll correct it.
                                Last edited by 0lento; 04-04-2019, 12:08 PM.
                                https://github.com/0lento/UnrealEngine (GameWorks tech merges & upgrades, UE4 physics modifications)

                                Comment

                                Working...
                                X