Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.

Why is the rendering performance when using ecs worse than when using monobehaviour?

Discussion in 'Entity Component System' started by programmer119, Mar 10, 2022.

  1. programmer119

    programmer119

    Joined:
    Sep 27, 2021
    Posts:
    84
    1.Render 5 meshs using subscenes
    SLOW ( 17~18 ms )
    upload_2022-3-10_11-23-20.png

    2.Render 5 meshs on mono behavior environment
    FAST ( 8~9 ms )
    upload_2022-3-10_11-22-53.png


    Is it normal for the rendering performance to deteriorate further if the shapes of the meshes displayed on the screen are all different?
    In the ECS environment, can the rendering performance improve only when the same mesh is used?
    There are 5 subscenes, each with a different mesh.
    Each mesh has a similar number of Tris and Verts, but is a completely different mesh. Materials use the same material.

    [Rough information about 1 mesh]
    Tris : 14k
    Verts : 40k

    [TEST Environment]
    -Unity 2021.2.14f1
    -PC Unity Editor
    : AMD Ryzen 9 5900HX with Radeon Graphics 3.30 GHz
    : 16.0GB
    : Windows 10 Pro
    -USE URP
    -DEFINE : ENABLE_HYBRID_RENDERER_V2
    -IMPORTANT Packages
    "com.unity.entities": "0.17.0-preview.42",
    "com.unity.platforms.windows": "0.10.0-preview.10",
    "com.unity.render-pipelines.universal": "12.1.5",
    "com.unity.rendering.hybrid": "0.11.0-preview.44",
     
    tmonestudio likes this.
  2. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,480
    The difference appears to be on the CPU on the main thread from what I can tell. Check the timeline view of the profiler which will give you a better idea of who the culprit is.
     
  3. programmer119

    programmer119

    Joined:
    Sep 27, 2021
    Posts:
    84

    Are you saying that it is normal for ecs objects to have poor rendering performance in an environment like this?
     
  4. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,480
    I'm saying it is common for user error to cause performance to tank in an ECS project. Right now I don't have enough info to provide more insight into why you are seeing this.
     
    MNNoxMortem likes this.
  5. programmer119

    programmer119

    Joined:
    Sep 27, 2021
    Posts:
    84
    waht mean user error? my setting error? or unity bug?
    Do you have any workarounds or links to documentation or discussion to refer to?
     
  6. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,480
    Likely a setting or how you are using it.

    Anyways, you need to open the profiler timeline view and get a pretty graph like this. The main thread will show all the systems and how long they take and what jobs they might be waiting on. If I see that, I can make a much better guess at what issue you are seeing and how you might fix it.
     
  7. programmer119

    programmer119

    Joined:
    Sep 27, 2021
    Posts:
    84
    Is this right? if not this i can provide you my project or anything else you want.

    MonoBehavior
    upload_2022-3-10_17-12-32.png

    upload_2022-3-10_17-57-55.png



    ECS
    upload_2022-3-10_17-11-50.png

    upload_2022-3-10_17-57-29.png
     
    Last edited: Mar 10, 2022
  8. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,480
    In both cases, two thirds of your processing time is spent doing editor things. So your framerates don't actually mean anything. You should really make builds and profile there.
     
    Krajca likes this.
  9. programmer119

    programmer119

    Joined:
    Sep 27, 2021
    Posts:
    84
    I know what you mean. And I already tried the android build and see the result. As with the build result, the performance of ecs was not good as in the editor.

    And I'll ask you again. In essence, in a situation where several different objects are output, is it faster when using ECS than when not using ECS? Isn't it inherently normal to be slow?
     
  10. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,480
    It can be slower on mobile if the mobile hardware doesn't like SSBOs on the GPU.

    Otherwise normally ECS is a tiny bit slower for a small number of objects and significantly faster for a larger number.
     
  11. programmer119

    programmer119

    Joined:
    Sep 27, 2021
    Posts:
    84
    In the end, what you are trying to say is, "It is right that ECS is slow in the situation above." In this situation, it is correct not to use ECS.
     
  12. MNNoxMortem

    MNNoxMortem

    Joined:
    Sep 11, 2016
    Posts:
    723
    Dots is not just about the rendering. There are many different parts involved, some faster, some slower. Some not even possible before Dots. It depends on what your use case is.

    The Hybrid Renderer alone still has many limitations that are required to overcome for a wider range of applications.
     
  13. DreamersINC

    DreamersINC

    Joined:
    Mar 4, 2015
    Posts:
    129
    I don't see that it has been brought up but you are comparing in editor performance. I find DOTS project to run a lot slower in editor that'll build. I believe this is due to safety checks and reporting that are turned on editor.
     
  14. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,480
    Nope. I am saying that it can be slightly slower. Or in the case of mobile it can be much slower. But right now I don't really know what your situation is.
     
    MNNoxMortem likes this.
  15. programmer119

    programmer119

    Joined:
    Sep 27, 2021
    Posts:
    84
    The important thing is that both the Android environment and the editor environment are slow.
    Opinions keep coming out that the editor environment is slow, but I wish they would stop talking about the environment. Again, it's slow even in the Android build environment.
    What I suspect through testing is that the rendering in the current environment is slower in the hybrid renderer than in the monobehavior renderer.
     
  16. programmer119

    programmer119

    Joined:
    Sep 27, 2021
    Posts:
    84
    i made zip file by myproject
     

    Attached Files:

  17. programmer119

    programmer119

    Joined:
    Sep 27, 2021
    Posts:
    84
    If you can solve the poor performance compared to monobehavior, please let me know how to solve it. It's okay to conclude that Monobehavior is faster when outputting less than 10 objects of different kinds. If performance can be improved by using ecs, pure ecs is good and changing options is also good, so please tell me how
     
  18. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,480
    I don't target android so unfortunately I cannot provide much insight that you will find actually helpful.
     
  19. programmer119

    programmer119

    Joined:
    Sep 27, 2021
    Posts:
    84
    Again, it doesn't matter if it's Android or the editor. Which method is faster when tested in the editor? What is the official position of Unity Technologies?
     
  20. programmer119

    programmer119

    Joined:
    Sep 27, 2021
    Posts:
    84
    Can you check the MyProject.zip I posted and conclude that it's faster on Android like you said?
     
  21. programmer119

    programmer119

    Joined:
    Sep 27, 2021
    Posts:
    84
    No one gives a clear answer. Even in Unity there is no answer.
     
  22. MostHated

    MostHated

    Joined:
    Nov 29, 2015
    Posts:
    1,188
    Is Burst enabled, and things like job debugger / full stacktraces turned off?
     
  23. Fribur

    Fribur

    Joined:
    Jan 5, 2019
    Posts:
    119
    Maybe it has also something to do with how you ask the question? To me it comes across as you expect someone owes you a response / you made up your mind already anyhow, which personally turns me off to even try to answer.
     
    hippocoder likes this.
  24. programmer119

    programmer119

    Joined:
    Sep 27, 2021
    Posts:
    84
    Again, the topic is off. What we need to talk about is the situation where the frame with the monobehavior is higher than DOTS when outputting 5 different objects. No one is answering whether this is normal or not.
     
  25. programmer119

    programmer119

    Joined:
    Sep 27, 2021
    Posts:
    84
    The answer I want is too simplistic.

    1. In the above situation, it is normal or abnormal that the mono behavior is faster than DOTS.
     
  26. programmer119

    programmer119

    Joined:
    Sep 27, 2021
    Posts:
    84
    you may be right I'm very tired of vague answers
     
  27. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    18,360
    Yes, but they're slow for different reasons which seems to be the part you are missing. The editor is slow due to all of the time it has to spend updating the interface. Between all of the tabs and windows you had open in the project download it was taking 2 to 3 milliseconds. Closing all but the scene view drops it to 0.5.

    Naturally that makes the editor less useful which is why people don't do that and instead recommend making a build. Unfortunately your Android device appears to be lacking too and none of us can test this properly without the same device. So I recommend making standalone builds for your tests.
     
    Last edited: Mar 20, 2022
  28. programmer119

    programmer119

    Joined:
    Sep 27, 2021
    Posts:
    84
    Ryiah, Thank's for Test My Project.
    Then i'll ask you just one.
    Ecs more faster than MonoBehavior when rendering 5 each other mesh? no have systembase update & its not all same 100000 objects its just rendering 5 each other objects situation.
    Can you show me the performance test results that ECS is faster than MonoBehavior in the above situation?
     
  29. rivFox

    rivFox

    Joined:
    Nov 16, 2016
    Posts:
    6
    Okey, I downloaded you project and I don't see the difference on PC. But like the people said before, you need test build.
    So... I tested on Poco X3 Pro. FPS Target set o 120.

    Legacy:
    0-2 => 8.4ms/120fps
    3-5 => <9.3ms / >108fps

    DOTS:
    0-5 => 8.4 - 9.4ms / 108 - 120fps (but avg is near to 120fps)

    Conclusion? The test is stupid. In this case you have only one batch (because you use SRP Batcher). It's only rendering, there is more bound by GPU than CPU. CPU is only for batching. But for small amount of meshes this is no important. Probably DOTS is worse (but it's the know true that dots is a little slower for small amount of entities).

    For my the result is the same for both examples. If you don't agree, you can connect the profiler and look where is the problem. I think that DOTS run some additional stuff e.g. for calculate "Transform".

    DOTS is probably better if you think about memory. It's valuable. DOTS is not a silver bullet. If you want to better compare DOTS / MB in rendering, IMHO you should use a lot of small meshes and test batching. And probably you should do the test on different devices (my phone has a good CPU)

    EDIT. I tested again Legacy (after DOTS) and for 5 objects, FPS is 9_-11_. Probably device heat problem ;) And my test show now that DOTS is better (because FPS is never <100). But I think that result is the same.
     
    Last edited: Mar 22, 2022
  30. DreamersINC

    DreamersINC

    Joined:
    Mar 4, 2015
    Posts:
    129
    The intention for dots on mobile was never to be faster. The idea was to reduce CPU clock speed by Distributing workloads over multiple cores by doing that you reduce the power draw of the CPU. All cores working at a lower clock speed is more energy efficient then one or two cores running at Max
     
    rivFox and Krajca like this.
  31. programmer119

    programmer119

    Joined:
    Sep 27, 2021
    Posts:
    84
    yes, DOTS is not a silver bullet. you right.
    In some situations DOTS is fast, in others DOTS is slow.
    and in this situation dots are more slow.

    I tested on my lg v30 mobile device

    1.DOTS

    DOTS.png

    2.MonoBehavior
    MonoBehavior.png
     
  32. rivFox

    rivFox

    Joined:
    Nov 16, 2016
    Posts:
    6
    Wow, looks like a bug. You should make a dev build and connect profiler to look where is a problem.
     
  33. programmer119

    programmer119

    Joined:
    Sep 27, 2021
    Posts:
    84
    if see log, gpu waiting cpu work.
    upload_2022-3-27_17-45-7.png
     
  34. mikaelK

    mikaelK

    Joined:
    Oct 2, 2013
    Posts:
    278
    I have to say that I don't see a problem. You can use ecs for tiny objects. Monos for few objects that needs special attention.

    I use it like this. A hybrid setup where you only optimize what needs to be optimized.
    Need something and doesn't matter if its cutting edge fast >> monob's.
    Need something fast and thousands of them -> ecs.

    If ecs doesn't work on the platform? report a bug and hope Unity will answer.

    ECS is on the preview and it looks like it wont be ready in another few years.
    Its already few yeas and we are on 0.50. Most of us can't even install 0.50, because it will break our projects even if we follow the upgrade instructions.

    I wouldn't put too much faith in preview technologies, unless you have enough money to hire few Unity consultants, in case you get in to big trouble. Even then I would double think.

    I have not tried the sub scene workflow a lot, but from my personal experience, ecs is really fast with il2cpp on windows platform, if you are doing things procedural.

    Doing it on mobile? You just need to test your target mobiles. I recommend that if you are crazy enough to build a whole game on it to lock your version on something that is proven to work or write a lot of tests. So at least you will be notified about all the things are breaking
     
  35. programmer119

    programmer119

    Joined:
    Sep 27, 2021
    Posts:
    84
  36. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    1,845
    So this test is just 5 meshes rendering, right? No fancy code anywhere that runs every frame?

    In that case: don't jump to conclusions! This isn't a real-world-scenario test and shouldn't be used to compare MB with DOTS!

    The Hybrid Renderer is far from complete (heck, I just learned today it doesn't support Point/Spot lights yet!) and with any preview software, it may be unexpectedly slow in cases where the "old" system excels due to developers having extra checks enabled, or not having optimized the performance of features yet, and so on.

    Moreover, it really depends on how those meshes are set up. I can't see it from the pictures but they may be each a single mesh with many triangles (or submeshes), or just many many triangles but not using a material that has the GPU instancing flag enabled. I think that's what @DreamingImLatios refers to regarding "setup".

    Lastly, this test doesn't really test DOTS! DOTS is primarily about speeding up CPU computations rather than speeding up rendering.

    You got to have many small jobs (Entities.ForEach) running which update component data of many entities every frame to see the benefit of DOTS. If you don't do any massively parallel computations every frame, you don't need DOTS, period.

    UPDATE:
    I looked into the project and indeed: you have 5 individual meshes (with ~3.300 random triangles each) and even if the materials had GPU instancing enabled, it wouldn't matter because you're not rendering individual triangles, but 5 unique meshes. So all you are comparing is the URP renderer (production-ready) with the HybridRenderer v2 (incomplete preview, not for production use) with an EXTREMELY artificial test (no lighting, no textures, no post-processing, no scripting, no nothing!!) using just 5 meshes.

    This is not a quantifiable performance comparison of ANY two renderers!

    Besides that, I already get 120 fps in the Editor playmode with 5 meshes displayed for both HR v2 and URP rendering modes (Ryzen 9 3900X 12-core with GTX 1070 and 32 GB RAM). Interestingly the frame time is always ~8.5 ms on the CPU and 2 ms on the render thread with no meshes displayed, and 2.5 ms render thread with all 5 meshes. So this test is not even stress-testing the renderer at all (at least not on desktop).


    For what it's worth: I've been recently trying out homing missiles (with movement prediction and random deviation and using physics bodies/collisions) and was able to have about 2.500 cylinders (no instancing) follow an animated target using URP and single-threaded Unity at around 30 fps in a build.

    I converted this to DOTS with homing missiles being Entities processed in parallel, and using the Hybrid Renderer with GPU instancing enabled. I got 100.000 (!!) missiles running at a relatively steady 90 fps (!!!!) in a build.



    I have a couple more tests on this channel. A few hundred permanently colliding physics bodies would KILL your fps in regular Unity, but with DOTS physics, you can have 20.000 colliding bodies every frame and it will run smoothly (120 fps in that case)!
     
    Last edited: Apr 2, 2022
    Niter88, lclemens and bb8_1 like this.
  37. SurprisedPikachu

    SurprisedPikachu

    Joined:
    Mar 12, 2020
    Posts:
    84
    @SteffenItterheim Your test is designed to favor DOTS.
    In a real game, there are not 100000 objects flying around unless you make that kind of game. In most games, there are only a couple of meshes that have a lot of triangles.

    You should build for mobile. As you can see, @programmer119 has built for mobile and is getting 2 FPS.

    And to this:
    I should say that's just wrong. DOTS provides massive architectural benefits beside performance benefits and is being designed to be a new way to make any kind of game. If it's slow in any scenario it needs to be addressed.
     
    Niter88 and Occuros like this.
  38. programmer119

    programmer119

    Joined:
    Sep 27, 2021
    Posts:
    84

    Are you god? How do you know my intentions so precisely?
    that's what i mean.
     
  39. programmer119

    programmer119

    Joined:
    Sep 27, 2021
    Posts:
    84

    I was very lonely and sad, but your clear answer gave me hope.
     
  40. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    1,845
    @SurprisedPikachu My test was designed to learn how much DOTS can scale up. I posted it here as an example to show what the real strength of DOTS is, in stark contrast to the "performance test" that @programmer119 made.

    So, let me go back to the original question before I indulge in TL;DR; ... :eek:
    Is it normal for the rendering performance to deteriorate further if the shapes of the meshes displayed on the screen are all different?

    AFAIK the hybrid renderer's strength is with GPU instancing. So I would rather say: if you render many identical objects then yes, Hybrid Renderer could be increasingly faster. But the demo project isn't testing that.

    Note: to really benefit from GPU instancing it was said (somewhere in some manual) that the instanced models should have >256 vertices. Otherwise the overhead of instancing could actually lower performance.


    But (a very important "but"): Hybrid Renderer is still in preview (aka experimental). You should not judge its performance against a production-ready package. The manual (v0.50) cautions us in several places and hints at issues with mobile, too:
    • "Hybrid Renderer is not yet validated on mobile and console platforms."
      • => That voids any comparison to begin with.
    • "For Android [..], you should use Vulkan."
      • => Were both MB and DOTS builds using Vulkan?
    • "This [Vulkan support] limits the platform coverage Hybrid Renderer can currently offer on Android devices."
      • Just something to consider: the type of Android device could make a huge difference.
    • "Hybrid Renderer is not a render pipeline: it is a system that collects the data necessary for rendering ECS entities"
      • Means: if you do not use Entities with Component data and code Systems there is absolutely no point in using ECS/HRv2 (the point I made in my first post). In this test in particular, it's as if you pit URP against "URP with additional layers of complexity" - no wonder it is slower!

    Yes, I agree Hybrid Renderer should not have substantial performance drawbacks on any platform once it is final, but obviously as with URP vs HDRP there will be certain strengths and benefits at the cost of something else and it is up to us to choose the right one.

    For instance, no one would choose HDRP for a mobile game. I hope. :rolleyes:

    What I really dislike about this test case (and I think this came across, although probably more rude than I intended, sorry about that) is that it is completely arbitrary to begin with! It doesn't even use real-world models, just random, textureless, individual (!) triangles stuffed into a single mesh. That's no good to test any renderer with. I stick to that.

    And speaking of architecture: I really see DOTS as an innovation enabler more than anything (but only/mainly on desktop). Besides, we've also seen that we can build very solid architectures with MonoBehaviours / ScriptableObjects too.

    Architecture-wise DOTS is ... different, and generally speaking it is also more difficult to grasp and easier to shoot yourself in the foot, too. An artist/designer with programming skills will find herself at odds with DOTS, while a pedal-to-the-metal programmer will love it (once grasped)!

    It really depends on who you are, and what you plan on making. Case in point: one half of the DOTS demos I've seen thus far were ... programmer's porn. Mine included. :cool: The other half were Minecraft worlds or base defense games with ridiculous numbers of enemies. Certainly nothing that innovates on gameplay or visualization in any way ... yet!

    As to "real games" this offers a dumb pun: the opposite of a "real game" is an "Unreal game", right? :D
     
    Last edited: Apr 5, 2022
  41. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    1,845
    Soooooo ... I was experimenting with Entities and Hybrid Renderer v2 today and got some unexpected results.

    I created this:
    upload_2022-4-5_15-58-20.png

    Don't jump to any conclusions just yet! :p

    What resembles a stairway of Minecraft blocks, eight blocks wide and six blocks high, is actually a staircase of eight times six chunks of 16x16x16 blocks of, well, cubes (voxels)! So where the details in a Minecraft block are drawn from a texture, in this example these details are individual blocks. There are no textures used!

    This means ~74k cubes for full 6-sided chunks!

    Since I mainly wanted to quickly check how much of an effect/benefit dynamic culling of backfaces in a voxel-world could have, I also made a version with 3-sided chunks. This cuts the number of cubes in half (~37k) and should give me a ballpark number of how much faster omitting non-visible faces/meshes could be.

    Here's the stair's backside of the "3-sided chunks" version:

    upload_2022-4-5_16-58-1.png

    Note: these blocks aren't "built-in" cube meshes!

    Since there's only 63 possible combinations of omitted faces for a cube (depending on its neighbours) I generate the meshes in advance, and then pick the mesh for each cube based on the cube's neighbours (adjacent chunks are not considered).

    Since chunks are hollow, practically all cubes in this demo have only 2 opposing faces drawn: front and back, left and right, top and bottom. Each face is the usual: 4 vertices, 4 normals and 2 triangles, but no UVs in this demo.

    This should enable GPU instancing (materials have it enabled) though somewhere in the manual there is a note regarding instancing: instanced meshes should have >250 vertices due to instancing overhead. It's another thing I wanted to test: how much of an effect do I get from GPU instancing especially when the meshes are between 4 to 24 vertices?


    I made release builds (Windows) for 4 configurations: 3-sided and 6-sided chunks, and one each for URP (no Entities) and Hybrid Renderer v2 (with Entities, one per Cube).

    Editor game stats gives me for each scene:
    3-sided chunk stairs: 175k tris, 350k verts
    6-sided chunk stairs: 300k tris, 600k verts

    Here's the results in Windows release builds running windowed at 2560x1440 in "Fantastic" quality on a Ryzen 9 3900X (12-core, 3.8-4.2 GHz) and Nvidia GTX 1070 with the camera rendering what you see in the first screenshot:

    URP 6-sided: 25 fps
    URP 3-sided: 50 fps
    HR2 6-sided: 340 fps
    HR2 3-sided: 570 fps

    Errr ... what? :eek:
    These HR2 framerates blow my mind! :D

    It's pretty obvious that HR2 is doing a great job at instancing these meshes! Or is it? I turned off "GPU instancing" in these materials and made another ECS build of the 6-sided chunks => I still get 340 fps. Hmmm ... maybe it does instancing regardless??

    Without further analysis, I just blame it on DOTS generally providing "performance by default". For now, I'm happy to know that I can not only scale up the number of "game objects" as entities to unprecedented numbers, HR2 also speeds up rendering of same (and simple) meshes significantly.

    Next, I want to be able to destroy all those cubes and have some (Havok) physics fun ... :cool:
     
    Niter88 likes this.
  42. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,480
    It does a form of instancing regardless. But the way it gathers what needs to be drawn and dispatches draw calls is very different and a lot faster.

    Small vertex counts can leave your GPU underutilized. However, you weren't GPU-bound, but instead draw call bound. The scene is simple enough geometry-wise where the GPU can still keep up despite the inefficient workload. That doesn't fully explain the numbers you are seeing. But hopefully gives you a little more insight into what is happening.
     
  43. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    1,845
    @DreamingImLatios Thanks for the pointers! I was so happy with the performance out of the box I didn't bother analysing it further.

    I re-read the section in the "regular" manual regarding batching etc. Turns out the GPU Instancing checkbox does not have an effect while SRP Batcher is enabled.

    Also another thread pointed out that HRv2 supports dynamic occlusion culling, I need to check that out too!

    In the meantime I've implemented generating mip-map chunks, that should further cut down the load. Though mipmapping may not be feasible with voxels already being memory restrained to begin with.
     
  44. venesectrixzero

    venesectrixzero

    Joined:
    Feb 7, 2017
    Posts:
    7
    @SteffenItterheim would you mind sharing your homing missile project? I would love to try that on my system. I’ve been experimenting with DOTS and can’t get that kind of performance so I’m trying to figure out what I’m doing wrong.
     
  45. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    1,845
    Can't share the entire project since it's over 2 gigs by now and really messy since I do various tests in it. But I'll gladly share the relevant code:

    Code (CSharp):
    1. using Unity.Entities;
    2. using Unity.Mathematics;
    3. using Unity.Physics;
    4. using Unity.Transforms;
    5. using UnityEngine;
    6. using Random = Unity.Mathematics.Random;
    7.  
    8. public struct HomingMissileData : IComponentData
    9. {
    10.     public float NextDeviationUpdate;
    11.     public float3 RandomUnitSpherePos;
    12. }
    13.  
    14. [UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
    15. public partial class HomingMissileSystem : SystemBase
    16. {
    17.     public Entity TargetEntity;
    18.     public MissileLauncherSettings.MissileParameters Missile;
    19.     public MissileLauncherSettings.AimAheadParameters AimAhead;
    20.     public MissileLauncherSettings.DeviationParameters Deviation;
    21.  
    22.     protected override void OnCreate() =>
    23.         RequireForUpdate(GetEntityQuery(new EntityQueryDesc { All = new ComponentType[] { typeof(HomingMissileData) } }));
    24.  
    25.     protected override void OnUpdate()
    26.     {
    27.         var targetPosition = GetComponentDataFromEntity<LocalToWorld>(true)[TargetEntity].Position;
    28.         var targetVelocity = GetComponentDataFromEntity<PhysicsVelocity>(true)[TargetEntity].Linear;
    29.  
    30.         var aimAheadEnabled = AimAhead.Enabled;
    31.         var aimAheadFalloff = AimAhead.FalloffDistance;
    32.         var aimAheadTime = AimAhead.PredictionTimeMax;
    33.  
    34.         var deviationEnabled = Deviation.Enabled;
    35.         var deviationFalloff = Deviation.FalloffDistance;
    36.         var deviationMax = Deviation.DeviationMax;
    37.         var deviationFrequency = Deviation.ChangeFrequency;
    38.         var deviationFrequencyVariation = Deviation.ChangeFrequencyVariation;
    39.  
    40.         var rotationSpeed = Missile.RotationSpeed;
    41.         var movementSpeed = Missile.MovementSpeed;
    42.  
    43.         var time = UnityEngine.Time.time;
    44.         var fixedDeltaTime = Time.fixedDeltaTime;
    45.         var up = new float3(0f, 1f, 0f);
    46.         var random = new Random((uint)UnityEngine.Time.frameCount);
    47.  
    48.         Entities
    49.             .WithName("HomingMissileSystem")
    50.             .WithBurst()
    51.             .ForEach((ref Translation translation, ref Rotation rotation, ref PhysicsVelocity velocity, ref HomingMissileData missile) =>
    52.             {
    53.                 // all the variables we'll need more than once
    54.                 var myPosition = translation.Value;
    55.                 var targetedPosition = targetPosition;
    56.                 var vectorToTarget = targetedPosition - myPosition;
    57.  
    58.                 // determine the "aim ahead" position based on distance to target (the farther away the more we have to aim ahead)
    59.                 if (aimAheadEnabled)
    60.                 {
    61.                     var aimAheadPercent = Mathf.InverseLerp(aimAheadFalloff.Min, aimAheadFalloff.Max, math.length(vectorToTarget));
    62.                     var predictionTime = Mathf.Lerp(0, aimAheadTime, aimAheadPercent);
    63.                     targetedPosition = targetedPosition + targetVelocity * predictionTime;
    64.                     vectorToTarget = targetedPosition - myPosition;
    65.                 }
    66.  
    67.                 if (deviationEnabled)
    68.                 {
    69.                     var spherePos = missile.RandomUnitSpherePos;
    70.                     if (time > missile.NextDeviationUpdate)
    71.                     {
    72.                         missile.RandomUnitSpherePos = random.NextFloat3Direction();
    73.                         missile.NextDeviationUpdate = time + deviationFrequency + random.NextFloat() * deviationFrequencyVariation;
    74.                     }
    75.  
    76.                     var deviationPercent = Mathf.InverseLerp(deviationFalloff.Min, deviationFalloff.Max, math.length(vectorToTarget));
    77.                     var deviation = Mathf.Lerp(0, deviationMax, deviationPercent);
    78.                     targetedPosition = targetedPosition + spherePos * deviation;
    79.                     vectorToTarget = targetedPosition - myPosition;
    80.                 }
    81.  
    82.                 // rotate towards target with given rotation speed
    83.                 var toTargetLookRotation = quaternion.LookRotation(math.normalize(vectorToTarget), up);
    84.                 var rotationTowardsTarget = Quaternion.RotateTowards(rotation.Value, toTargetLookRotation, rotationSpeed * fixedDeltaTime);
    85.  
    86.                 rotation.Value = rotationTowardsTarget;
    87.                 velocity.Linear = math.forward(rotationTowardsTarget) * movementSpeed;
    88.             })
    89.             .ScheduleParallel();
    90.     }
    91. }
    I stitched this together from the ideas and code snippets presented in this video:


    What you'll need to know:
    • choose a target entity somehow, or just use a fixed position at first
    • turn off aimAhead and deviation initially to get the basic "follow target" behaviour working first
    • missiles can be any entity, any collider, but their Layer should be one that has no self-collisions (see Project Settings => Physics => matrix at the bottom)
    • missiles PhysicsBody should have high Angular Damping (start with 10) to prevent them from going "wild" if any collision (or code) adds an angular spin to them - though I really like the effect of a missile going haywire, so play around with that. You probably won't see that unless you make the missile not disappear/explode when it hits anything.
    • if target is not moving or you don't want missiles to predict the future position of target you can ignore the "aimAhead" stuff or set aimAheadEnabled to false
    • deviation simply picks a random offset a distance away from target to make missiles feel like they're having trouble to move in a straight line. It certainly helps missiles not getting clustered in a single blob. The "frequency" determines how often it changes course.
    • Falloff distances determine how much of an impact deviation and aim ahead have depending on missile's distance to target. The closer it gets the narrower the deviation/prediction should be. In my case I set Min falloff for deviation to negative so missiles do not hit the target straight at the center and could even miss the target, causing them to turn around - of course the size of the target needs to be considered when setting the falloff values.
    • if the missile is not facing the target make sure its mesh or parent game object makes it point forward (not up) when you place it in the scene. Though I'm not sure forward on which axis, must be either (1,0,0) or (0,0,1).
    The authoring component is straightforward:
    Code (CSharp):
    1. using Unity.Entities;
    2. using UnityEngine;
    3.  
    4. [DisallowMultipleComponent]
    5. public class EntityMissileAuthoring : MonoBehaviour, IConvertGameObjectToEntity
    6. {
    7.     public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem) =>
    8.         dstManager.AddComponentData(entity, new HomingMissileData());
    9. }
    The MissileLauncher spawns new missiles from a MonoBehaviour:
    Code (CSharp):
    1.     public sealed class EntityMissileLauncher : MonoBehaviour
    2.     {
    3.         private float _nextLaunchTime;
    4.         private MissileLauncherSettings _settings;
    5.         private int _missileCount;
    6.  
    7.         private Transform _target;
    8.         private Vector3 _targetPreviousPosition;
    9.  
    10.         private World _injectionWorld;
    11.         private EntityManager _entityManager;
    12.         private Entity _prefabMissile;
    13.         private HomingMissileSystem _missileSystem;
    14.  
    15.         private void Start()
    16.         {
    17.             _settings = GetComponentInParent<MissileLauncherSettings>();
    18.             _target = _settings.Launcher.Target;
    19.  
    20.             _injectionWorld = World.DefaultGameObjectInjectionWorld;
    21.             _entityManager = _injectionWorld.EntityManager;
    22.  
    23.             var conversionSystem = _injectionWorld.GetExistingSystem<ConvertToEntitySystem>();
    24.             var settings = GameObjectConversionSettings.FromWorld(_injectionWorld, conversionSystem.BlobAssetStore);
    25.             _prefabMissile = GameObjectConversionUtility.ConvertGameObjectHierarchy(_settings.Launcher.MissilePrefab.gameObject, settings);
    26.  
    27.             _missileSystem = _injectionWorld.GetExistingSystem<HomingMissileSystem>();
    28.             _missileSystem.Missile = _settings.Missile;
    29.             _missileSystem.Deviation = _settings.Deviation;
    30.             _missileSystem.AimAhead = _settings.AimAhead;
    31.  
    32.             StartCoroutine(LaunchMissiles());
    33.         }
    34.  
    35.         private IEnumerator LaunchMissiles()
    36.         {
    37.             while (_missileCount < _settings.Launcher.MissileCount)
    38.             {
    39.                 var batchCount = _settings.Launcher.MissileSpawnBatchCount;
    40.                 _missileCount += batchCount;
    41.  
    42.                 for (var i = 0; i < batchCount; i++)
    43.                 {
    44.                     var missile = _entityManager.Instantiate(_prefabMissile);
    45.                     _entityManager.SetComponentData(missile, new Translation { Value = transform.position });
    46.                 }
    47.  
    48.                 yield return new WaitForSeconds(_settings.Launcher.LaunchFrequency);
    49.             }
    50.         }
    51. }
    And here's the MissileLauncherSettings that's on the launcher's parent game object since the settings are all the same for all launchers:
    Code (CSharp):
    1. using RapidFire.Utility;
    2. using System;
    3. using UnityEngine;
    4.  
    5. public class MissileLauncherSettings : MonoBehaviour
    6. {
    7.     public LauncherParameters Launcher;
    8.     public MissileParameters Missile;
    9.     public AimAheadParameters AimAhead;
    10.     public DeviationParameters Deviation;
    11.  
    12.     [Serializable]
    13.     public class LauncherParameters
    14.     {
    15.         public bool LauncherMovesMissiles = false;
    16.         public bool UseJobs = true;
    17.  
    18.         public Transform Target;
    19.         public Transform MissilePrefab;
    20.         public int MissileCount = 1000;
    21.         public int MissileSpawnBatchCount = 10;
    22.         public float LaunchFrequency = 0.05f;
    23.     }
    24.  
    25.     [Serializable]
    26.     public class MissileParameters
    27.     {
    28.         public float RotationSpeed;
    29.         public float MovementSpeed;
    30.     }
    31.  
    32.     [Serializable]
    33.     public class AimAheadParameters
    34.     {
    35.         [Tooltip("Whether to aim towards (true) a predicted future position of the target or (false) always at target's current position.")]
    36.         public bool Enabled = false;
    37.  
    38.         [Tooltip("Maximum time in seconds to extrapolate target's future position based on its current position and velocity. Optimal value depends" +
    39.                  "on average / maximum speed of target and how frequently and abruptly it can change direction as well as projectile's" +
    40.                  " velocity and rotation speed.")]
    41.         public float PredictionTimeMax = 5f;
    42.  
    43.         [Tooltip("If distance to target is >= Max the target's velocity will be extrapolated by the PredictionTimeMax to predict future position " +
    44.                  "of the target. As distance to target gets closer to Min the projectile will gradually aim more towards target's actual position.")]
    45.         public Range<float> FalloffDistance = new Range<float>(10f, 200f);
    46.     }
    47.  
    48.     [Serializable]
    49.     public class DeviationParameters
    50.     {
    51.         public bool Enabled = false;
    52.         public float DeviationMax = 5f;
    53.         public float ChangeFrequency = 0.1f;
    54.         public float ChangeFrequencyVariation = 0.02f;
    55.         public Range<float> FalloffDistance = new Range<float>(10f, 200f);
    56.     }
    57. }
    58.  
    Lastly here's the current settings:
    upload_2022-4-8_11-12-53.png

    So this may not work out of the box but should be enough to get you started. Let me know if you have any questions.

    Oh and ... I do assign values directly to the MissileSystem from the MissileLauncher which probably isn't best practice. ;)

    Side note: the missile prefab can be changed easily. I had this running with fish, which made it seem like flocking though it isn't. I also tried busses, ships, buildings. trains, animals and people because I'm cruel. :D
     
    Last edited: Apr 8, 2022
    dwulff, NotaNaN, lclemens and 2 others like this.
  46. venesectrixzero

    venesectrixzero

    Joined:
    Feb 7, 2017
    Posts:
    7
    Thank you, I will try this out! I am curious what version of DOTS you are using with this? Are you using the latest 0.50 packages? Oh, and what version of Unity? Just trying to make sure I’m matching your settings.
     
  47. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    1,845
    yes 0.50 in 2020.3.32 (33 as of today)
     
    venesectrixzero likes this.
  48. venesectrixzero

    venesectrixzero

    Joined:
    Feb 7, 2017
    Posts:
    7
    @SteffenItterheim Hey, thanks for the great examples and writeup you posted. That helped me a lot! I took a shot at recreating the most basic functionality, and I have attached what I made. Some notes:
    • When I get up to 100k missiles I'm at 17-18 FPS on a build (not editor)
    • I commented out aim and deviation stuff because I didn't have access to the RapidFire.Utility library you were using
    • You said "missiles can be any entity, any collider, but their Layer should be one that has no self-collisions..." I didn't follow that part. I saw the matrix you were talking about, but they were all checked, and I wasn't sure how to set a layer on the missile prefab anyway. What does this part do? I set the collision filters on the missiles to not run into themselves, but I'm not sure if that's the same.
    So I'm curious if you have any ideas what might be different. Your video of 100k missiles at 90FPS looks great, so I was hoping to recreate that.
     

    Attached Files:

  49. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    1,845
    @venesectrixzero
    • Speed: it strongly depends on the CPU and memory I suppose. I have a Ryzen 9 3900X with 12 cores / 24 threads, 32GB DDR4 at 3600 rate and a GTX 1070. What's your setup?
    • Collisions: see image, I created a physics layer "Bullets" and made sure that colliders in layer "Bullets" do not collide with other colliders in "Bullets" by unchecking the box (see: Project Settings => Physics)
    • upload_2022-4-9_12-58-47.png
    The collision layer is not strictly necessary but if you spawn many you'll want to avoid them colliding with each other. First it will lead to unexpected behaviour, second it costs performance due to physics simulation having to process and resolve contacts. This could also explain why the fps is so low in your version.

    You may also see decreasing fps when missiles keep hitting the target or possibly "getting stuck on it". I have a version where I purposefully made a huge sphere that missiles ran into and got attached to the surface to test that. I had to tune it down to 20k missiles constantly hitting the sphere but it ran at 90 fps - with 100k missiles it was below 10 fps if I remember correctly. Switching from regular Unity Physics to Havok may also speed things up noticably.

    To do so: install the com.havok.physics package, add a Physics Step somewhere in the subscene with the missiles, and change dropdown to Havok physics.

    Let me know what the issue is with aimAhead + deviation. I may have overlooked something. Though the processing is all in the System code, everything you need should simply be the additional settings for both aim and deviation.
     
    Last edited: Apr 9, 2022
    venesectrixzero likes this.
  50. MaNaRz

    MaNaRz

    Joined:
    Aug 24, 2017
    Posts:
    114
    Is the Layer Collision Matrix working for Unity Physics? I thought I need to use the Collision Filter in PhysicsShape to ignore Collisions.

    upload_2022-4-9_15-54-59.png
     
    venesectrixzero likes this.