Author: kbobnis

  • Unreal optimization

    Finding the performance bottleneck (CPU vs GPU)

    To properly test performance:

    • disable vsync (r.vsync 0)
    • and frame limiter (t.MaxFPS 0)
    • disable smooth framerate (Project > Engine > General Settings, disabled by default)

    Unit stat

    To turn on unit stat, click the three lines (top left corner three lines -> show stats)

    When looking at the unit stat, the frame is total time of frame. But look at the next ones. The biggest number will hint that this is the bottleneck. In case of this screenshot, the bottlenect might be the game thread: CPU.

    UnitGraph

    There is a nice timing graph in unreal (bottom left of the corner):

    To change the budget, use console command: “t.TargetFrameTimeThreshold <milliseconds>” and “t.UnacceptableFrameTimeThreshold <milliseconds>”

    Here’s how to enable it:

    Unreal insights

    For finding bottlenecks, look for CPU wait for tasks and in GPU gaps. Those will tell you how much this specific hardware is waiting.

    It’s not clearly visible here, but the game thread calculates a frame and in the next frame the rendering thread is rendering. So on the screen you see a frame that is already one frame old.

    Useful things to do when profiling:

    • test GPU load – change screen resolution (r.screenpercentage 10)
    • test CPU load – pause the game (pause)
    • add more information to the profiling session: console command: “stat namedevents”
    a console command “trace.screenshot <name>” can be used to create a screenshot bookmark in insights

    There is a benchmark launch arguments to run a benchmark level right from windows

    https://dev.epicgames.com/documentation/en-us/unreal-engine/unreal-engine-command-line-arguments-reference

    Improving performance

    Significance Manager is a tool to work on level of detail of actors.

  • Unreal Development

    Table of Contents

      Debugging

      Disabling optimization of c++ files

      To enable automatic disabling of optimizations, edit BuildConfiguration.xml

      <?xml version="1.0" encoding="utf-8" ?>
      <Configuration xmlns="https://www.unrealengine.com/BuildConfiguration">
          <BuildConfiguration>
              <bAdaptiveUnityDisablesOptimizations>true</bAdaptiveUnityDisablesOptimizations>
          </BuildConfiguration>
      </Configuration>

      This will disable optimization for all files that are checked out in perforce.

      More info here: https://dev.epicgames.com/community/learning/tutorials/dXl5/advanced-debugging-in-unreal-engine

      UObject debugger object descriptions

      It is easier to use Debugger uses UObject->GetName(). So if you will Rename() UObject, then debugger will conveniently show this nice name to you.

      Non UObject debugger object descriptions

      If you want nice debugger info about an object that is not a UObject and you can’t Rename this object, then you can use natvis file to override how debugger prints this object.

      natvis location

      1. For game types: Open <Engine>Extras\VisualStudioDebugging\Unreal.natvis file and add entry for your object. This will work in Rider debugger. I am adding entry for my FMyObject
      2. For plugin types: create a new file: <plugin name>/Source/<your module name><module name>.natvis

      <?xml version="1.0" encoding="utf-8"?>
      <AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
      
      <Type Name="FMyObject">
         <DisplayString>(Table={DataTableName} Row={RowName})</DisplayString>
       </Type>
      
      </AutoVisualizer>

      Where DataTableName and RowName are FName types in a struct.

      More info here:

      Printing value of enum

      To print a human readable value of an enum, it must be marked as UENUM(). Example

      UENUM()
      enum class EOptions
      {
      	Option1,
      	Option2,
      	Option3
      };
      EOptions SelectedOption = EOptions::Option1
      
      UE_LOGFMT(LogTemp, Log, "Current option is {Options}", UEnum::GetValueAsName(SelectedOption));
      
      //this will print "Current option is Option1"

      To print the display name of an UEnum:

      UENUM()
      enum class ECreatureType
      {
      	IsRobot UMETA(DisplayName = "Is a robot"),
      	IsHuman UMETA(DisplayName = "Is a human")
      };
      const ECreatureType CreatureType = ECreatureType::IsRobot;
      
      FString::Format(TEXT("This creature type is a {0}"), StaticEnum<ECreatureType>()->GetDisplayNameTextByValue(static_cast<int64>(CreatureType )).ToString());

      Tests

      Disable functional test

      Functional tests are disabled in the <Project root>/Config/DefaultEngine.ini file.
      Under the [AutomationTestExcludelist] section add a new line:

      The test value is a path. If the test is added to a map, then the path looks like “Project.Functional”<map path above the content directory, so Content/Tests/Assets/map.umap will be Tests.Assets><name of the map><outline structure, so if your test is in a directory in the level called test, then “Test” is added><name of the test in the level>

      Example:
      – level: Content/Tests/Maps1/TestMap1.umap
      – in the map: Test/Test_1
      Then this is Test=”Project.Functional Tests.Maps1.TestMap1.Test.Test_1″

      +ExcludeTest=(Map="",Test="Project.Functional Tests.Maps1.TestMap1.Test.Test_1",Reason="This test will be disabled now",RHIs=(),Warn=False)
      

      Validators

      C++ validators

      Here’s a minimal c++ validator header file

      UCLASS()
      class UAssetValidator_Filenames : public UEditorValidatorBase
      {
          GENERATED_BODY()
      
          virtual bool CanValidateAsset_Implementation(const FAssetData& InAssetData, UObject* InAsset, FDataValidationContext& InContext) const override;
          virtual EDataValidationResult ValidateLoadedAsset_Implementation(const FAssetData& InAssetData, UObject* InAsset, FDataValidationContext& InContext) override;
      };

      How to check can validate asset

      Check if asset is data table of my specific type:
      bool UAssetValidator_Filenames::CanValidateAsset_Implementation(const FAssetData& InAssetData, UObject* InAsset, FDataValidationContext& InContext) const
      {
          if (const UDataTable* LocalDataTable = Cast<UDataTable>(InAsset))
          {
              return FMyDataTableRowStruct::StaticStruct() == LocalDataTable->RowStruct;
          }
      
          return false;
      }

      Write own settings in c++

      UCLASS(Config = Game, defaultconfig)
      class MYPLUGIN_API UMySettings : public UDeveloperSettings
      {
      	GENERATED_UCLASS_BODY()
      
      	UPROPERTY(Config, EditAnywhere)
      	TArray<FDirectoryPath> Paths;
      }

      By declaring this class, you will find an array of paths in the UE -> Project Settings -> MyPlugin

      Logs

      Declare log verbosity. If you want to print Verbose logs, in any .h file write:

      MYPLUGIN_API DECLARE_LOG_CATEGORY_EXTERN(LogMyPlugin, Verbose, All);

      Unreal Asserts

      Check

      Using check will crash the game with the message you provided in check. Not called in shipping build

      Verify

      Crashes the game, the same as check, but is called in all builds.

      Ensure

      Posts an error in the log

      example of ensure with text that will post error to console each time it is encountered:

      ensureAlwaysMsgf(true, TEXT("This is error message posted to logs %s"), *MyString)

      Editor settings

      auto load last opened level

      Editor Preferences – General – Loading & Saving – Load Level at Startup – Last Opened

      don’t quit PIE with Esc

      Editor Preferences – General – Keyboard Shortcuts – Play World (PIE/SIE) – Stop (Stop simulation) – Change from Escape to Ctrl +

      Customizing editor

      virtual void CustomizeHeader(TSharedRef<class IPropertyHandle> InStructPropertyHandle, class FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils) override;
      
      HeaderRow.NameContent()[InStructPropertyHandle->CreatePropertyNameWidget()]

      Dropdown instead of FName in function parameters

      	UFUNCTION(BlueprintCallable)
      	static void MethodName(UPARAM(meta = (GetOptions = "GetSlotNameOptions")) FName SlotName);
      
      	UFUNCTION()
      	static TArray<FName> GetSlotNameOptions();
      

      This method will generate a dropdown instead of a text box in the blueprint context when calling this method.

      GAS

      Filtering gameplay tags in function parameters

      If you want to filter a GameplayTag (or GameplayTagContainer) parameter in a function, use the UFUNCTION specifier Meta = (GameplayTagFilter = "ItemType").

      Packaging the game

      To pack the game locally, on the main UE window click Platforms -> Windows -> Package project

      Maps to include in the package are:

      • listed in the <game_root>/Config/DefaultGame.ini, +MapsToCook= lines
      • Edit -> Project Settings -> Project – Packaging -> List of maps to include in a packaged build