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.
  2. The 2023.1 beta is now available for testing. To find out what's new, have a look at our 2023.1 feature highlights.
    Dismiss Notice

GPU Instancing

Discussion in '5.4 Beta' started by djarcas, Dec 29, 2015.

  1. djarcas

    djarcas

    Joined:
    Nov 15, 2012
    Posts:
    225
  2. yuanxing_cai

    yuanxing_cai

    Unity Technologies

    Joined:
    Sep 26, 2014
    Posts:
    335
    There are dozens of reasons for the breaking of a batch, and honestly most of the time we ourselves can't tell without debugging the native engine code. The solution we are currently discussing is to add some extra information to each batch in Frame Debugger to indicate "why the heck this is another new draw call", this way you as the user could have an idea about what's happening under the hood and potentially optimize your scene setup to make it more batching friendly. This of course will take some time to implement, but we are seriously considering doing it.
     
  3. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Yeah lots more tools for diagnostics across the board, across Unity, enable the developer to make Unity games look better. It's indirect but it's a measurable thing...
     
    PeterB likes this.
  4. Riderfan

    Riderfan

    Joined:
    Jan 10, 2013
    Posts:
    514
    I would imagine that's quite true when dealing with a more complex object like that posters wheeled vehical. But I've shown that there are problems simply Instancing 10,000 2tri / 4 vert planes with no textures, and just using just a default material with the Unity generated stock Instancing shader. It's the simplest object we could possibly have created.

    Lack of working mesh instancing - on all platforms - has become our #1 issue right now.

    Unity released the final build of 5.4 today (or last night depending on where you are) and yet this feature isn't complete.
     
  5. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    This is a bit out of scope but one major thing I would love is some profiling for shaders / bandwidth etc.
     
  6. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    Cube Mark Results For Comparison

    5.3.5f1



    5.4.RC2 using Instancing



    Note this is on my aging hardware and only applied to spinning cubes, so mileage may vary.
     
  7. Riderfan

    Riderfan

    Joined:
    Jan 10, 2013
    Posts:
    514
    How would you feel about letting me send you a sample project of mine and running tests on your system so that we can compare results?

    I'm only getting about 25 frames a second with 10k 2D, camera face planes. My rig is hardly bleeding edge, but it should be doing better than that.

    if you're getting 60FPS with about 58k cubes, I should be getting at least that with just 10k forward facing planes.

    thanks
     
  8. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
  9. Riderfan

    Riderfan

    Joined:
    Jan 10, 2013
    Posts:
    514
    Thanks!

    Gave it a run and there's definately something strange happening. My numbers are lower than yours simply becuase my video card isn't as good. But still, these numbers are waaayyyy higher than I'm getting on my tests.

    I'm assuming that this test is using something along the lines of;

    Code (CSharp):
    1.  
    2. for(int x=0; x<=count; x++)
    3.      Graphics.DrawMesh(various,paramaters,here);
    4.  


    I also noticed that when you're doing the tests on the quads, that they don't face the camera and that the objects move out of view.

    thanks
     
  10. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    No just vanilla Instantiation of cube/quad prefabs with an Standard Instanced Shader.
     
  11. Riderfan

    Riderfan

    Joined:
    Jan 10, 2013
    Posts:
    514
    Hmmmm okay.. .then maybe DrawMesh isn't working?

    I've edited my sample to create 5,000 quads as game objects and applied the instancing material. I am now getting 60 frames a second. However the frame rates drop substantially as I add more. At 30,000 instances, I am only getting 25 Frames a Second.

    The stats dialog says there are 61 batches (shouldn't that be a lot, lot lower?)

    But there's no code running in the update method. According to the docs, Graphics.DrawMesh(...) should also function allowing you to update rotations (so the quads face the camera). However when I use this approach never produces anywhere near the same frame rates.
     
  12. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    It looks like only draw procedural supports instancing -> http://docs.unity3d.com/540/Documentation/ScriptReference/SystemInfo-supportsInstancing.html
     
  13. Riderfan

    Riderfan

    Joined:
    Jan 10, 2013
    Posts:
    514
    Okay, maybe I don't understand something...

    From the RC2 release notes...
    Graphics: Basic GPU Instancing Support
    • Use GPU instancing to draw a large amount of identical geometries with very few draw calls.
    • Works with MeshRenderers that use the same material and the same mesh.
    • Only needs a few changes to your shader to enable it for instancing. Supports both custom vertex/fragment shader and surface shader.
    • Set per-instance shader properties from script via MaterialPropertyBlock.
    • Supports Graphics.DrawMesh command.
    • Supports DX11/DX12 with SM 4.0 and up on Windows, OpenGL 4.1 and up on Windows/OSX/Linux, PlayStation 4 and Xbox One.
    Are we talking about different things here? Or is this something else that isn't implemented?
     
  14. yuanxing_cai

    yuanxing_cai

    Unity Technologies

    Joined:
    Sep 26, 2014
    Posts:
    335
    @Riderfan Are you getting suboptimal performance using Graphics.DrawMesh or objects you drew didn't instance at all?
    Objects drawn with Graphics.DrawMesh should work with instancing in 5.4.

    In 5.5 we'll have a Graphics.DrawMeshInstanced which takes an array of world matrices as input and it will be more efficient than calling Graphics.DrawMesh multiple times in one frame.
     
  15. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    Docs need updating e.g.

    here -> http://docs.unity3d.com/540/Documentation/ScriptReference/SystemInfo-supportsInstancing.html

    Will there be good examples on how to use these commands as docs are a bit minimal at the moment?
     
  16. yuanxing_cai

    yuanxing_cai

    Unity Technologies

    Joined:
    Sep 26, 2014
    Posts:
    335
    Point taken. SystemInfo.supportsInstancing exists even before instancing is implemented. It meant something different back then. But now it tells correctly if the system you're running on supports 5.4 GPU instancing. So yes, outdated doc.

    What's in that piece of pseudo code is basically it. @Riderfan send us the test project if you need help figuring out what's missing. BTW we now have a comprehensive manual page for instancing, check it out if you haven't: http://docs.unity3d.com/540/Documentation/Manual/GPUInstancing.html
     
    Last edited: Jul 22, 2016
  17. Riderfan

    Riderfan

    Joined:
    Jan 10, 2013
    Posts:
    514
    Thanks.. a few points

    There's a sample project attached to bug #814797 It's a console example but obviously easy enough to switch players. That sample is drawing a mere 10,000 2 tris / 4 vert planes via a mesh exported from blender. If I recall correctly the mesh doesn't even have a texture applied. It uses the stock Instancing shader that unity generates (which is different to the one that is now in the documentation you noted above)

    - Frame rates are much higher using created game objects than using DrawMesh(). That function works in that it draws the meshes, but it's very slow (probably because of the size of the loop you need to itterate through every frame).

    - I've noticed that frame rates go up after rendering the scene for a few minutes. I don't know why that would be the case, but I can watch a steady encrease in fps as time progresses. Not sure how that would work in a real-world case.

    - Instancing on primitives seems much faster than instancing imported meshes. Even a primitive quad renders faster than an imported quad from Blender. I have no idea why that would happen.

    Keep in mind that these objects need to be animated somehow. It's no good having static things (specially when they're people) in the scene. I've tried a couple of approaches to this but what I have now is the following;

    I create 50,000 game objects (I need between 30 and 60k spectactors for our stadiums) and I 'chunk' them up into arrays of 250 objects. This also allows me to have different meshes for the spectators. 2D Camera facing billboards on the top decks, 3d meshes on the lower ones closer to the camera.

    In FixedUpdate(), I process a 250 itteartion loop and update 1 group, then in the next FixedUpdate() I process the next group, and so on and so on. It's not possible to update all 60,000 meshes in one go and maintain the frame rate, so updating chunks at a time 'helps' although it's not a very good solution. I use FixedUpdate() because it's called fewer times per frame and helps overall performance (by a small amount) and still maintains the illusion of animation.

    Right now, because the performance of DrawMesh() is so low, it's only possible for me to use 2D quads and change the texture UV via SetPropertyBlock(); So rendering a sprite map on a quad in 3d space. My stadiums look very '2004 quality' and that needs to improve. It needs to compare to current sports titles in terms of visuals.

    Once DrawMeshInstanced is working hopefully I've be able to animate 3D meshes by rendering different meshes baked as different animation frames. But, that means that I will need to loop through 60,000 items every frame because DrawMesh() and its ilk need to be called every frame for the object to render. Not sure how you'd solve that.

    The issue though is I don't think we have the time to wait until 5.5. That's what? A year a way? That's too long.

    Updating instanced objects is always going to be a bottleneck. You're always going to need to do something to them every frame even if it's a simple call to face a quad towards the camera. So anything that can be done to make that part more efficent would be a win.
     
    Last edited: Jul 22, 2016
  18. djarcas

    djarcas

    Joined:
    Nov 15, 2012
    Posts:
    225
    That would be helpful. However, if there's dozens of reasons, a list of them would be helpful. Right now, I'm planning on making absolutely HUGE use of this instanced rendering (I've been waiting 4 years...), and the initial results are more than a little disappointing.

    What are, say, the 3 more likely causes of the objects just deciding not to batch?

    There's 72 identical objects in my scene, lit, shadowed, not scaled or rotated differently, all using the same material, modulated with Material Property Blocks.
     
  19. katoun

    katoun

    Joined:
    Dec 26, 2012
    Posts:
    87
    Hello everyone,
    I started testing for this new Instancing feature and I got no where. It seemed that the Instancing reported in the Profiler was 0 instanced elements.
    So I started making my own derived shaders from the Default one and using the doc file as reference. I got the SpeedTree and the Standard shaders to work with the GPU Instancing. I hope I have not missed anything out, but seems to work.
    Here are the derived one for 5.4.0f2.
    Regards
     

    Attached Files:

  20. Olafson

    Olafson

    Joined:
    Aug 7, 2012
    Posts:
    252
    I haven't tested your shaders yet, but did you manage to get the LOD fading to work on the Speedtree?
     
  21. Riderfan

    Riderfan

    Joined:
    Jan 10, 2013
    Posts:
    514
    I compared tests with these shaders to the stock Instance shader that Unity generates and the stock one gets much better performance. 10,000 objects with the generated shader on a PC gets about 40 FPS (given my outdated harware). The StandardInstanced shader provided above only gets about 14 FPS.

    Also, shouldn't the SpeedTreeBillboard shader always face the camera? It's not doing that for me so I might not have it set up right.
     
  22. Riderfan

    Riderfan

    Joined:
    Jan 10, 2013
    Posts:
    514
    Hi Everyone.

    So I've attached a sample project that I put together to show Mesh Instancing. It was created in Beta.23. It contains just the scene file, C# code, and shaders. I've removed all the files that Unity automatically adds to a project folder so hopefully this still loads for people.

    Some caveats
    • It currently only deals with 10,000 objects when really, the requirements are for 60,000. 60k quads shouldn't be a challenge for today's hardware but on my machine Unity bogs down with anything over 10k.

    • The final product must be able to cycle through a texture map via the shader. The C# code is there, but the shader code for doing that isn't complete yet (because I haven't figured it out). Right now, to fake animation frames, I'm flickering the emission. Looks like Christmas but gets the point across.

    • The C# code does the camera facing billboard. It would be faster if the shader did that but haven't figured that out yet.

    • I've tried to document the code as best as I can but feel free to ask questions.

    This only works on desktops - GPU Instancing is not functional on other platforms (which is contrary to the release notes).

    thanks
    David
     

    Attached Files:

    Last edited: Jul 23, 2016
  23. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,324
    I believe using many GameObject's adds a lot of pressure and I wouldn't recommend going this route. That's at least my experience with Unity.

    While I can't really help with the instancing problem, I can describe how we implemented rendering of many spectators in this game (developed 2011). We didn't use Unity at this time, we used in-house technology, but the idea can be transferred to Unity as well.

    We generated several meshes that contained lots of quads, where each quad was used as a billboard to display one character. One mesh was used to represent a (big) spectators group/chunk. I can't remember how many billboards we had in one chunk, maybe 1000, 2000 or 5000? So we only had to issue very few draw-calls to render a lot of spectators.

    We used an atlas texture, which was generated every frame, where we rendered animated 3D characters into. I believe we rendered around 5 different characters/animations into the atlas. Billboards/quads mapped to different UV areas, to display different characters, to get variation into a spectator group. Using an atlas had the benefit that all chunks were using the same material.

    Each character could use a different color for t-shirt/shorts. We did this by encoding in a texture different regions which was then showing up with a "random" color. These colors were already baked into the mesh.

    Each billboard was already sorted by distance inside the mesh, so it appeared front-to-back, to avoid overdraw. This worked for us, because the camera was always positioned in the inner area of the stadium and never moved into the spectator groups.

    I believe billboarding of each quad was implemented in a shader, at least on PS3 and Xbox360 I would assume. Not sure how this was implemented for Wii.

    This was a very efficient implementation to render a lot of character billboards. We used pretty much the same technique even for PS2 titles in 2008.

    Hope it helps!
     
    Last edited: Jul 24, 2016
    hippocoder likes this.
  24. katoun

    katoun

    Joined:
    Dec 26, 2012
    Posts:
    87
    No, I haven't. I read about that problem on this forum after I made these shaders. I must admit I am not that experienced in render programming, but I do have some years experience in game dev/programming, enough of not being "scared" of doing a lot of thing (game dev related). I just did all the changes required to add the instancing support "by the book" (exactly as it says in the documentation provided by Unity). It seemed to make a difference in the profiler reports, but it still feel it not working quite properly.
    In the end I thought I would share my effort, as someone else might make a good use of it, using as a start base for further improvements.
     
  25. Riderfan

    Riderfan

    Joined:
    Jan 10, 2013
    Posts:
    514
    Thanks. This is close to what I'm trying to do here. Although I'm trying to simplify it on one hand, and complicate it on the other.

    We need between 30 and 60,000 spectators. There's just no avoiding that. Those are just typical stadium sizes. And while they won't all be on screen all the time, there are instances where you'll see most of them. Look at any sports game made in the past 10 years and you'll see that

    I'm really a bit surprised there's not already a stock package you can buy that does this...

    What I'm trying to do (in that sample I gave) is just simply have camera facing billboards that cycle through pre-rendered texture maps.

    I've created a texture map that contains 10 rows. Each row is a different variation of a spectator. Each row also has 30 columns where each column is one frame of animation for that spectator. This avoids the need to generate a texture map every frame, but admitadly impacts some of the visual quality of the spectators. Luckly our camera doesn't get too up close and personal with the crowd.

    If 10 spectator variants doesn't looks random enough we can split the whole thing in 2 and have 2 separate instances running of 2 different 10 spectator variant sprite maps (if that makes any sense). Adding more variations to spectators is the lowest concern I have right now.

    The shader needs to be able to be told what row and column to draw per instance, per update (the plan is to use PropertyBlocks for that because of its speed. It would also be better if the shader handled the billboarding too. - These parts are what I'm stuck on now. Trying to get a shader to render just one frame of the texture map to the quad primitive.

    The other big issue that I'm running into (other than it doesn't work on all platforms) is that I'm already running into bottle necks with large numbers of quads. 10,000 isn't a large number, but Unity is bogging down already.

    I've worked on a lot of sports titles over the years and this is always one of the tricky parts....and clearly something new to unity. The ability to do this sort of thing has been around for a decade, but you need GPU Instancing to make it work.
     
    Last edited: Jul 23, 2016
  26. katoun

    katoun

    Joined:
    Dec 26, 2012
    Posts:
    87
    Riderfan: Your test scene works fine. My conclusion: though I made those shader changes exactly as the documentation says, the Instancing does not work with SpeedTrees or objects placed into the scene from editor. I must make some more tests.

    EDIT: I made a few more tests and I got the Instancing to work. It seems than my "Instanced" Standard shader work, but If I have a skinned mesh in the scene (that does not support Instancing) the Instancing "brakes" also, Meshes that have 2 submeshe (2 materials) "brakes" the Instancing again.
     
    Last edited: Jul 23, 2016
  27. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,324
    I'd implement the sprite sheet animation in the shader as well. If each vertex contains a "starting index" (stored in an unused vertex channel), you can use _Time and some simple math to advance to the next index/frame over time. Modifying UV's would be entirely on the GPU in this case and can be done in the vertex shader, which is often cheaper than doing it per pixel, unless there are more vertices than pixels.
     
  28. Riderfan

    Riderfan

    Joined:
    Jan 10, 2013
    Posts:
    514
    This is what I'm trying to do with the shader at this point.

    I've simplified the sprite map with different colour rows (so each colour would be a spectator variant) and each character represents a frame of animation. Hopefully that makes sense.

    [edit]

    Well, I managed to get it to work... Image1.png

    What you're seeing is 6250 Quad Primitives being rendered with an instancing shader that cycles through a spritemap and renders individual frames of the animation. While there's a small difference between the Unity frame count (40.5) and my own counter (34), the take away is that it's not 60.

    While not even rendering 10,000 quads I'm unable to get 60 frames a second. I should be getting 60 frames a second with 4 time that number.

    There's no change in frame rate by removing the FixedUpdate() code (because most everything is done in the shader).

    Extremely dissapointing.
     
    Last edited: Jul 23, 2016
    dreamerflyer likes this.
  29. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,324
    I created an Unity example of the technique I described earlier. I think this is how I would implement to render lots of animated spectator billboards, with very little CPU processing.

    You can find a download link to the Unity project at the bottom of this post.





    The idea is to generate a mesh that contains lots of quads. Each vertex of the mesh has additional data that is used in the shader to billboard, colorize and animate it.

    The mesh is generated in an offline step, but could be generated at runtime/initialization as well. Once the mesh is generated, nothing is manipulating it anymore on the CPU side. Nothing is changing the material as well.

    As a bonus, I also implemented instancing to draw the same mesh efficiently without CPU to GPU transfer. The example uses about 70 GameObject's where each displays the same mesh, due to instancing, it's only one draw-call on the CPU.

    Download latest version from:
    http://www.console-dev.de/bin/Unity5_Example_Coins.zip

    PS: I didn't try to optimize anything in the shader. There is most likely room for improvement.
     
    Last edited: Jul 23, 2016
  30. Riderfan

    Riderfan

    Joined:
    Jan 10, 2013
    Posts:
    514
    Yikes!

    That's looking pretty impressive.. great job.. I'll have to spend some time disecting that sample..

    I'll be back with questions :)
     
  31. Riderfan

    Riderfan

    Joined:
    Jan 10, 2013
    Posts:
    514
    Peter, so I took a look at this and yeah, really impressive stuff. Thanks for providing it.

    I did run into a couple of issues, maybe you can suggestion some direction?

    The quads I'm using are not in random locations. They'll have predefined transforms within the game. The Meshmaker doesn't seem to work well with that sort of system, so what I thought about doing was add all my quads where I need them, then using MeshCombine() to add them into a single mesh.

    That works for performance but the billboarding in the shader breaks because you're adding data to the meshes in Meshmaker that you can't add with primitives (local positions for example). I'm wondering if you could suggest some changes to the shader for that.

    Beyond that though, it's working quite well. I'm getting 60,000 spectators running at about 750 frames a second (according to the FPS counter on the little stats dialog - and with vsync swtiched off).

    thanks
    David
     
    Last edited: Jul 24, 2016
  32. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,324
    In MakeMesh.cs, there is this line, where I should have put a comment:
    var s = new Vector3(x, Random.Range(-10, 10+1), z)*1.5f;

    This is the center position of one quad/billboard/spectator in local space within the mesh. The idea would be that a mesh represents a group or slice of spectators on the grandstand like in the image below.

    Think of that 's' vector as the position of a seat and it is relative to the cyan point, which represents the origin xyz=0,0,0 in the mesh.

    The 'localPos' variable in MakeMesh.cs is really just the vertex offset to create the quad around the position 's' and really just describes the size of a quad (x=width, y=height, z=unused because a quad is flat).



    The yellow bounds indicate that this could be the same mesh. Then the (same) mesh is placed at different positions using the Transform component. You could also use custom meshes everywhere, which should still be really fast but adds a few more draw-calls. But if the entire stadium is build with eg 20 spectator slices only, this should not be the bottleneck.

    What you want to do is to replace MakeMesh.cs with a script/tool that is able to generate a mesh for one or multiple of these yellow'ish marked areas. Eg shooting rays to figure out where a spectator can be on the grandstand and store this position as 's' (relative to the mesh origin) in the mesh.


    Good to hear, glad it solved the performance issues :)
     
  33. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    Will instancing work with vertex painting?
     
  34. Riderfan

    Riderfan

    Joined:
    Jan 10, 2013
    Posts:
    514
    Thanks.

    I'm likely going to need to go with the MeshCombine() method rather than mesh maker. The stadiums I'm using are not built from uniform blocks of people. The seating arrangments are all on different angles, there's entry ways in the middle, there's separated areas, etc... So I have to use MeshCombine in this case I think. It just allows me to arrange the specators where I need them directly in the editor.

    The bit I'm getting confused on, is that in your sample, you're assigning mesh.uv3 from a Vector2 list of frame numbers. (converted to an array). And this is what you're using in the billboarding function of the shader. I don't see where the positions come in.

    if I change the line in the shader from;
    Code (csharp):
    1. const float3 local = float3(v.localpos.x, v.localpos.y, 0);
    to
    Code (csharp):
    1. const float3 local = float3(v.vertex.x, v.vertex.y, 0);
    The image is always camera facing, but the mesh doesn't maintain its shape as a cube. It compresses and expands in a wave. (interesting effect, but not what I'm after).

    Any thoughts?
    thanks
    David
     
  35. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,324
    That's why I wrote you would need to write a script/tool that generates the mesh, MeshMaker.cs is just an example to show how to build such mesh that works with the shader. It uses random positions, because it was faster for me to generate a mesh with randomly positioned quads, rather than writing some sort of paint-tool first.

    The shader does not require evenly distributed positions or a specific arrangement. The position of each quad in the mesh can be anything that is needed, but the additional meta-information is important for billboarding and animation. It's possible to change the size of each quad, but the example uses hard-coded values for simplicity.

    If every chunk (grandstand slice) in the stadium has to be unique, then you need to generate individual meshes for it, matching the stadium geometry. Where each mesh corresponds to a specific slice or area of the grandstand where N spectators are located.

    This won't work with instancing, because it's different meshes, but I'm very sure it will still be really fast to render it (eg 30 chunks with 2000 spectators each)


    Here is what is assigned to the mesh in MeshMaker.cs:
    Code (CSharp):
    1. mesh.vertices = vertices.ToArray();
    2. mesh.uv = uvs.ToArray();
    3. mesh.triangles = triangles.ToArray();
    4. mesh.uv2 = localPos.ToArray();
    5. mesh.uv3 = frameIndices.ToArray();
    6. mesh.colors = colors.ToArray();
    The shader takes these vertex-channels as input, it's declared as:
    Code (CSharp):
    1. struct appdata_t {
    2.     ...
    3.     float4 vertex : POSITION; // vertex position in local space, mesh.vertices indexed by mesh.triangles
    4.     float2 localpos : TEXCOORD1; // mesh.uv2
    5.     float2 frameindex : TEXCOORD2; // mesh.uv3, x=frameindex, y=unsed
    6. };
    mesh.uv3 corresponds to TEXCOORD2 in the shader, which is named frameindex.

    appdata_t.localpos stores the vertex offset to build a quad (only x and y, because a quad has no depth).
    Code (CSharp):
    1. // 4 vertices representing the shape of a quad
    2. var v0 = new Vector3(-0.5f, -0.5f, 0);
    3. var v1 = new Vector3(-0.5f, 0.5f, 0);
    4. var v2 = new Vector3(0.5f, 0.5f, 0);
    5. var v3 = new Vector3(0.5f, -0.5f, 0);
    If you connect these coordinates on a paper, you paint a square. These offsets are added to the spectator position called 's' in MeshMaker and the result is stored into the vertices array.

    This is because v.localpos holds this:
    Code (CSharp):
    1. var v0 = new Vector3(-0.5f, -0.5f, 0);
    2. var v1 = new Vector3(-0.5f, 0.5f, 0);
    3. var v2 = new Vector3(0.5f, 0.5f, 0);
    4. var v3 = new Vector3(0.5f, -0.5f, 0);
    but v.vertex the actual vertex positions:
    Code (CSharp):
    1. var s = new Vector3(x, Random.Range(-10, 10+1), z)*1.5f;
    2. vertices.Add(v0 + s);
    3. vertices.Add(v1 + s);
    4. vertices.Add(v2 + s);
    5. vertices.Add(v3 + s);
    My thought would be to write a tool that generates the correct mesh data in an offline-step. Imaging a gigantic watering can emptied over the stadium, whenever a drop impacts the grandstand, it's a spectator position. The watering can represents raycasts and drop impact where the raycast intersects with the grandstand, which represents the spectator position.

    You could build on top of MeshBaker as a starting point or throw it away and start from scratch. If you use MeshMaker, then you position a spectator with this line:
    Code (CSharp):
    1. var s = new Vector3(x, Random.Range(-10, 10+1), z)*1.5f;
    If 's' stores world-coordinates, you just need to set the Transform component to XYZ=0,0,0 and it should still work with the shader, but instancing of the individual chunks wouldn't work anymore. But if you only have one gigantic mesh that contains all spectators in world-space, there is no need for instancing anyway.

    In order to give every spectator a different size, you have to change this:
    Code (CSharp):
    1.  
    2. var v0 = new Vector3(-0.5f, -0.5f, 0);
    3. var v1 = new Vector3(-0.5f, 0.5f, 0);
    4. var v2 = new Vector3(0.5f, 0.5f, 0);
    5. var v3 = new Vector3(0.5f, -0.5f, 0);
    with the size you want each spectator to be.

    Hope it makes sense :)
     
    Last edited: Jul 24, 2016
    crudeMe likes this.
  36. Riderfan

    Riderfan

    Joined:
    Jan 10, 2013
    Posts:
    514
    Yes it does thanks.

    With your help this is finally working as expected. I swapped out my use of CombineMesh and now just have a Meshbuilt for each spectator type. I just converted the sample class to one that can generate these meshes at run time by accepting an array of vectors. Works well and is very fast.

    I had to flip your UV's around because the textures were upside down.
    Code (csharp):
    1.  
    2. // add tex-coords
    3. Vector2 uv0 = new Vector2(0, 0);
    4. Vector2 uv1 = new Vector2(0, 1);
    5. Vector2 uv2 = new Vector2(1, 1);
    6. Vector2 uv3 = new Vector2(1, 0);
    7.  
    But other than that, this system is working very well now. Thanks for your assistance. I'm even getting respectable frame rates on the console and it doesn't support Instancing...

    thanks again
     
    Peter77 likes this.
  37. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,324
    You're welcome, awesome that it works now!

    I'd be interested to see how the final stadium with a gazillion spectators looks like. If you're allowed to show that, perhaps somewhen in the future once the title is released, that would be neat :)
     
  38. Riderfan

    Riderfan

    Joined:
    Jan 10, 2013
    Posts:
    514
    I'll post some in-game screens once I get the spectator textures finished. In the mean time, there's this...



    That giant blob of horrible is 50,000 animated and camera facing 'spectators' (represented with characters because I don't have the textures done yet). Frame rates are quite good but will be much better on the console once Instancing is finished. Ony my desktop I'm getting over 350 frames a second.

    I've updated the shader so that ambient lighting works, but shadows are causing problems. I'll have to play around with that.
     
    nxrighthere, Peter77 and Arowx like this.
  39. djarcas

    djarcas

    Joined:
    Nov 15, 2012
    Posts:
    225
    Any chance of a mod stepping in and branching the conversation about crowds and combinemesh into it's own thread?

    In the meantime, I'm still stuck with a fancy-pants new headline feature that is managing an average of about 1.2 instances per batch, and no clue what I could potentially change to fix it.
     
  40. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Uh we'll leave the thread as it is. It's better for Unity to see one thread full of use cases than many.
    But regarding talk about crowds which does not involve instancing, please feel free to make a separate thread.
     
  41. Riderfan

    Riderfan

    Joined:
    Jan 10, 2013
    Posts:
    514
    The shader is an instanced shader and even with using mesh combine you can't do this effectively without it. Creating crowds with billboards is rather an obsolete way of doing it now. It's not been done that way in years. Sadly, this is the only way Unity can do it right now.
     
    awesomedata and laurentlavigne like this.