Announcement

Collapse
No announcement yet.

Faster way to instance 10,000 objects

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

    Faster way to instance 10,000 objects

    I need a way to create 10,000 instances of the same mesh and add a component witch rotate teach of them (so the engine should check each component update) without freezing UDK.

    I was testing Godot, Cryengine and Unigine with a basic scene composed of 100 X 100 instances of a 546 polygons mesh, each of then has a script/component attached, so at start the'll get a float speed between 0.05 and 0.20 and on every frame they will rotate on Z axys the speed multiplier. The scene also has a directional light with shadows, and a camera that move up.

    This is what i'm doing on UDK. I have a component (SceneSetup) that spawn instances of MyClassActor

    for (float y = 0; y < height; y++)
    for (float x = 0; x < width; x++) {
    auto item = GetWorld()->SpawnActor(MyClassActor::StaticClass() );
    // then change position
    }



    And MyClassActor Constructor atach to himself a StaticMeshComponent and a CustomRotationComponent

    static ConstructorHelpers::FObjectFinder<UStaticMesh> model(TEXT("/Game/MyActorMesh"));

    // i think it is copying a new mesh everytime
    UStaticMeshComponent* comp = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("VisualRepresentation"));
    comp->SetupAttachment(RootComponent);
    comp->SetStaticMesh(model.Object);
    // then add the other component, and set the speed


    On Godot (gdscript) i get 27-30 FPS
    on Unigine (c#) between 60-78 FPS

    Unreal just Freeze.
    Last edited by arqlz; 04-23-2020, 09:00 AM.

    #2
    Why? This is terrible no matter how you implement it. Use an instanced static mesh, add the instances, then rotate in the shader.

    Comment


      #3
      1. Instanced mesh, how? I was looking for some kind of instance/proxy system, no luck, godot use some kind of instances on scenes nodes, so they are free for the new user, and unigine references rae created on a blitz (Reference.create(path) ), i cant find the same on UDK.

      This is my last night code:

      static ConstructorHelpers::FObjectFinder<UStaticMesh> model(TEXT("/Game/MyModel"));
      UInstancedStaticMeshComponent* comp = CreateDefaultSubobject<UInstancedStaticMeshComponent>(TEXT("VisualRepresentation"));
      comp->SetupAttachment(RootComponent);
      comp->SetStaticMesh(model.Object);

      FTransform pos = FTransform();
      comp->AddInstance(pos);

      On debug mode i get 1-2 FPS, (20-30 godot, unigine 60-80, ill try c# cryengine to see how technical should i go before getting a good FPS)


      2. No shader transformation, also no main loop for rotations, all entity's should be called on each frame.

      Last edited by arqlz; 04-23-2020, 10:32 AM.

      Comment


        #4
        Tell us some more about what you want to test.

        If you do not need to alter the mesh on the fly, use a static mesh instance like Zeblote advised.

        If you need to create or modify the mesh frequently use the UProceduralMeshComponent. Once this work switch to RuntimeMeshComponent (https://github.com/Koderz/RuntimeMeshComponent -> Look at URuntimeMeshComponentStatic) for optimal performance.

        If these 10k game objects represent tiles of your terrain, you want those to be actual individual components of a single world actor.

        If unreal freezes check your Task Manager if the unreal engine process still utilizes CPU. If yes it does things in the background. Than you should either run your editor in debug mode and add a breakpoint along the way. Also you can write to the log. Even if you have to kill of the process you will see in the Output Log (Window->Developer Tools->Output Log) the entries of your scene.

        Does it freeze in the Editor or when you hit play? If former, you want to create the actors in the BeginPlay method and if you already do it and it still freezes, do it in the tick method. Please also verify if the world is already there so GetWorld() provides you with a useful pointer. Depending when and how you create your actor spawning other actors, your world might not be available yet and not always (but mostly) this should result in a crash report if this is the case).

        Try to put your code into the tick method and instead of spawning all actor at once, spawn a couple of them every tick. You can log out your timings to the Output Log. By spawning a single actor you can check if you have a different problem. Also use the console command 'stat raw' or in the left upper corner the button with the downward arrow press and select STAT > Engine > RAW before you hit the play button. These stats show you how long the frame takes and where the engine spends its time.

        Rotating independent objects in the shader is not necessary. Ticking 10k objects individually to update their rotators is nothing that should concern you or the engine.

        Comment


          #5
          I would add ... if you need actually need10k+ transient objects in the game a common approach is to pre-allocate them into an object pool. Then hide/show them as needed. That avoids the performance hits of allocating/destroying memory.

          Comment


            #6
            This is what i'm doing (photos attached are from unigine), I forced the polycount of an old model, so its fine that has a lot of unnecessary polygons.


            I don't need to modify the meshes, only rotate them. I tryed with UInstancedStaticMeshComponent, no luck, its also slow, between 1-2 FPS on a RTX 2060 Super.


            Thankyou, both, in advance, this is a really good community.
            Attached Files
            Last edited by arqlz; 04-24-2020, 09:31 AM.

            Comment


              #7
              Okay that looks more like terrain to me. Please check if using scene components attached to a single actor rather than creating many actors is possible. Actors are a bit more costly as the engine does some additional overhead on actors. I also had 2fps for my terrain consisting of 64k independent actors at the beginning. Moving to 64k components improved it slightly since the problem was elsewhere:

              Since you have a version working, remember unreal is optimized for static scenery (even if animated) and prebuild lightmaps. Sadly if you have a lot of dynamic actors the interactions of the render logic with the scene becomes dead slow. Try first to use the console commands 'stat gpu' and 'profilegpu' to get more information what is actually happening. For me 90% of the time it spend with shadow and lighting. The other 10% were mostly visibility command stuff that became important once lighting + shadow was fixed.

              In the main toolbar under Settings > 'Engine Scalability Settings' you can furthermore switch between some predefined render profiles that allow you to switch off shadows by chosing the low setting. If you see an increase when going low quality then you know its not the amount of geometry or the action that cripples the engine.

              The best solution I know of for highly dynamic scenes without any prebuild lighting is switching all light sources from static to moveable (or at least static). In your case this is most likely the directional (sun) light and the sky light if you start with an empty scene. Switching is done in the Details Panel view once you have selected the light source in the World Outliner.

              You can chose from static, stationary and moveable giving the engine hints what to expect from these components and using different means of optimization depending on the moveability and changeability of each object. In your case having static lights with solely moveable geometry just backfires greatly (as it did for me). This is a somewhat known problem I fought with for two weeks recently until I came around a single line in a reddit thread saving my Unreal career... .

              Since my landscape tiles do not spin, I set my tiles to stationary rather then movable as they change in form (on deformation) but do not move:

              Code:
              meshComponent->SetMobility(EComponentMobility::Stationary);
              For me switching the terrain components from moveable (default) to stationary reduced the visibility command portion from >10ms to <2ms so its worth trying for you as well.

              Remember the root component is actually what defines the actors location and orientation, so you want to set all components to stationary or moveable(which is the default).

              PS: Please report your findings, I would be interested.

              Comment


                #8
                Also do a "stat collision". Collision is expensive for mobile actors.

                We found collision was bottlenecking our FPS so we turn collision on only for mobile actors that are in the vicinity of something that can collide with them. (only players in our case)

                Comment

                Working...
                X