Version: 4.6.1 (binary release)
The AddTorque() method (Physics / Add Torque in blueprints) malfunctions with skeletal meshes if fixed time steps are being used (-UseFixedTimeStep command line option). Both C++ and Blueprint versions of AddTorque() are affected. AddForce() is not affected, nor is either of these methods with static meshes.
With default physics settings, the effective torque applied by USkeletalMeshComponent::AddTorque() approaches zero as the fixed delta time, set with FApp::SetFixedDeltaTime( dt ), approaches 0.02 from below (50 fps). With dt >= 0.02, AddTorque() will have no effect no matter how big the supplied force argument is.
The following videos illustrate the issue:
dt = 0.015: UE4 AddTorque() and fixed dt bug, dt = 0.015 - YouTube
dt = 0.019: UE4 AddTorque() and fixed dt bug, dt = 0.019 - YouTube
dt = 0.020: UE4 AddTorque() and fixed dt bug, dt = 0.02 - YouTube
If MaxPhysicsDeltaTime (MaxSubstepDeltaTime if using substepping) is set to be smaller than 0.02, then the bug disappears. MaxPhysicsDeltaTime (or MaxSubstepDeltaTime) does not seem to affect things otherwise.
Instructions for reproducing the issue
Initialize the project:
- Create a new project using the Basic Code (C++) template, with starter content
- Open the Content Examples demo project and migrate the Owen character to your newly created project
Set up the scene:
- Disable gravity: Settings (top panel) → World Settings → Override World Gravity = ON
- Raise the table into air, so that it does not touch anything
- Place an instance of Owen into the scene, in-air, and rename it to “TheOwen”
- Enable physics for the table and the Owen actors: select an actor, Details panel → Simulate Physics = ON
Apply torques and forces, Blueprint version:
(To do this in C++, skip this phase and instead copy the code at the end to your project.)
- Open the level blueprint, then drag the table (“Table”) and the Owen actor (“TheOwen”) from the Scene Outliner to the Event Graph of the Level Blueprint
- Drag from the blue pins of the newly created nodes and create Add Torque and Add Force nodes for both, then connect them properly to an Event Tick node. Set the Z torques/forces as follows:
Table Z torque = 100,000, Table Z force = 100, TheOwen Z torque = 1,000,000, TheOwen Z force = 100
Hit Play or Simulate so as to test the scene: the Table and the TheOwen actors should start to rotate and rise as seen in the first video.
Save everything and close the editor.
Set the fixed dt:
- Open your project in Visual Studio
- Open the YourProjectNameGameMode.h file, add this to the class body and recompile:
.
AYourProjectNameGameMode() :
AGameMode( FObjectInitializer() )
{
FApp::SetFixedDeltaTime( 0.015f );
}
Enable fixed time steps with the -UseFixedTimeStep command line option:
- Create a shortcut from your .uproject file and open the Properties of the newly created shortcut
- Edit the Target field to look something like this: “C:\enginepath\UE4Editor.exe” “C:\projectpath\YourProjectName.uproject” -UseFixedTimeStep
Now open your project via the shortcut and hit Play or Simulate. Everything should work normally, but if you change the dt to 0.02 in FApp::SetFixedDeltaTime(), then the bug should become visible.
Apply torques and forces, C++ version:
YourProjectNameGameMode.h, override Tick():
class ADDTORQUEANDDT461_API AAddTorqueAndDt461GameMode : public AGameMode
{
GENERATED_BODY()
AYourProjectNameGameMode() :
AGameMode( FObjectInitializer() )
{
FApp::SetFixedDeltaTime( 0.015f );
}
void Tick( float dt ) override;
};
YourProjectNameGameMode.cpp:
// Fill out your copyright notice in the Description page of Project Settings.
#include "AddTorqueAndDt461.h"
#include "AddTorqueAndDt461GameMode.h"
#include <Animation/SkeletalMeshActor.h>
void AAddTorqueAndDt461GameMode::Tick( float dt )
{
Super::Tick( dt );
UStaticMeshComponent * table = 0;
USkeletalMeshComponent * owen = 0;
for( TActorIterator<AStaticMeshActor> ActorItr( GetWorld() ); ActorItr; ++ActorItr )
{
if( ActorItr->GetName() == "Table" )
{
table = ActorItr->GetStaticMeshComponent();
break;
}
}
for( TActorIterator<ASkeletalMeshActor> ActorItr( GetWorld() ); ActorItr; ++ActorItr )
{
if( ActorItr->GetName() == "TheOwen" )
{
owen = ActorItr->GetSkeletalMeshComponent();
break;
}
}
if( !table || !owen ) {
UE_LOG( LogTemp, Error, TEXT( "Failed to locate the table or Owen!" ) );
return;
}
table->AddTorque( FVector( 0.f, 0.f, 1e5f ) );
table->AddForce( FVector( 0.f, 0.f, 100.f ) );
owen->AddTorque( FVector( 0.f, 0.f, 1e6f ) );
owen->AddForce( FVector( 0.f, 0.f, 100.f ) );
}