Search Unity

Approach to render pedestrians like in Cities Skylines?

Discussion in 'Scripting' started by NathanJSmith, Sep 13, 2018.

  1. NathanJSmith

    NathanJSmith

    Joined:
    May 11, 2018
    Posts:
    57
    I see a video showing pedestrians like in Cities Skylines


    So which approach should I use to render these pedestrians and keep the FPS so that the player won't complain about lagging.
    Requirements:
    Each ped (or group of ped) can move on his path.
    Each ped (or group of ped) can disappear when a specific event happens.

    This thread focuses about the approach to render pedestrians (I think if I include the AI here, the topic will be too broad). I think of some approaches but I don't know which one is possible or better.

    Approach 1: Use DrawMeshInstancedIndirect, here is the example on github, I really want to use this approach but I don't know if it's possible to simulate the pedestrians with this approach. I see that DrawMeshInstancedIndirect move the object with shader code instead of C# code.
    Note: this is the most powerful way to render crowd, but I don't know if it's possible to simulate ped.

    Approach 2: Use DrawMesh, this is pretty good, I can easily set the position & rotation of the pedestrians through the function DrawMesh.
    Note: like the docs said: Use DrawMesh in situations where you want to draw large amount of meshes, but don't want the overhead of creating and managing game objects.

    Approach 3: Just create each ped as a game object like every other mesh object in the scene. I once tried to test how many animated characters with physic Unity can handle, and I see that the number of characters is not large enough, maybe I'll remove the Physic for the pedestrians to improve FPS.
    Note: This is the simplest way and I can make use of the Unity's animation system.

    Please share which approach you will take (maybe none of the approach above) if you have to create the game Cities Skylines.
     
  2. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Certainly do not apply physics to each pedestrian! That's just madness.

    Yes, for something like this you want to think of them like particles in a particle system. Not literally a ParticleSystem, as I don't believe you'll be able to get them to move the way you want with that — but similar, a mesh (or use of DrawMesh) where each pair of triangles is one pedestrian, with an appropriate position in the world and a texture that looks approximately right given the camera angle, pedestrian angle, and pedestrian type/animation frame.

    It's a lot of work to set up, but will enable you to render a large number of these little guys with good performance.

    Moving it onto the CPU might be even better, but I don't know how to do that... if you figure it out, please write it up! :)
     
  3. NathanJSmith

    NathanJSmith

    Joined:
    May 11, 2018
    Posts:
    57
    I think it's better to go with Approach 1, but use DrawMeshInstanced() instead of DrawMeshInstancedIndirect(). I can easily call DrawMeshInstanced() multiple time per frame while DrawMeshInstancedIndirect() is pretty trouble to do this.
    With DrawMeshInstanced(), I can pass the array of transform (position/rotation/size, use Matrix4x4.TRS() to set each of them) to control the peds movement.

    DrawMeshInstanced() is easy to use, check SupahPOW31 on reddit for demo.

    About peds animation, thanks to zulfajuniadi for his incredible open source Animation-Texture-Baker on github.

    Edit: About animation, it's just the shader play animation from an image file: check this project Animation-Texture-Baker of sugi-cho which is simpler and easier to understand.
     
    Last edited: Sep 14, 2018
  4. NathanJSmith

    NathanJSmith

    Joined:
    May 11, 2018
    Posts:
    57
  5. MisterSkitz

    MisterSkitz

    Joined:
    Sep 2, 2015
    Posts:
    833
    You can tag them all. Use enums function something like:

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public enum PedType
    4. {// you can store every tagged pedestrian here
    5.  
    6. ped1,
    7. ped2,
    8. ped3
    9.  
    10. }
    11.  
    12. public class YourClassNameHere : MonoBehaviour{
    13.  
    14.  
    15. public PedType currentPedTag;
    16.  
    17.  
    18. void Awake(){
    19.  
    20. AssignPeds();
    21. // This will grab EVERY tagged object listed
    22. // inside the enum above and fill them with the stats below
    23.  
    24. }
    25.  
    26. public void AssignStats() // Assigns the enemy HP and enemy damge
    27.     {
    28.  
    29.         if (currentPedTag == PedType.ped1)
    30.         {
    31.           // set animations, stats, anything here
    32.          // for Ped1 tag
    33.         }
    34.  
    35.         else if (currentPedTag == PedType.ped2)
    36.         {
    37.  
    38.          // Load your ped2 tag class here        
    39.  
    40.         }
    41. else if (currentPedTag == PedType.ped3)
    42.         {
    43.  
    44.          // Load your ped3 tag class here        
    45.  
    46.         }
    47.  
    48.     }
    49.  
    50.  
    51.  
    52. }
    I found this is the quick way for me to load an entire scene with stats.

    I use it for EnemyMaxHp, EnemyHp, EnemyDmg, etc...

    But you can use this to set your animations and stuff for MANY different tags.