Search Unity

  1. If you have experience with import & exporting custom (.unitypackage) packages, please help complete a survey (open until May 15, 2024).
    Dismiss Notice
  2. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice

Drawing from data without Hybrid Renderer

Discussion in 'Graphics for ECS' started by 5argon, Feb 2, 2020.

  1. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,556
    I have a situation where it is difficult to attach RenderMesh and LocalToWorld to my data entities that I would like to draw. Instead, I would like to iterate through my data with EntityQuery then call some drawing methods without using any Hybrid Renderer systems.

    I have never used any manual drawing methods before, I have look at the Graphics API (https://docs.unity3d.com/ScriptReference/Graphics.html) I got some questions :

    https://docs.unity3d.com/ScriptReference/Graphics.DrawMesh.html

    - If I submit in wrong Z ordering, will they get sorted correctly as a part of "normal rendering process"? (e.g. use DrawMesh for character before the mountains behind)

    https://docs.unity3d.com/ScriptReference/Graphics.DrawMeshInstanced.html

    - What is the draw order among instanced meshes? Is it according to Matrix4x4[] matrices ordering?
    - What is z efficiency?
    - Would the draw order of latter DrawMeshInstanced be completely over the prior one? Or are they sorted together as a part of normal rendering process like the DrawMesh situation I assumed?

    https://docs.unity3d.com/ScriptReference/Graphics.DrawMeshInstancedProcedural.html

    - How could I specify position for each of the `count` instances here?

    - How can solve ordering problem when drawing an overlapping mesh with Graphics API? For example if I have a cylinder and a cube Mesh and would like to get this result :

    upload_2020-2-2_11-33-38.png

    https://docs.unity3d.com/2019.3/Documentation/ScriptReference/Rendering.BatchRendererGroup.html

    - I see that HybridRenderer use this at the end without touching any Graphics API. Are there any other methods outside of Graphics API worth taking a look?
    - Am I right that inside the source code of BatchRendererGroup, they would finally ended up calling Graphics API? And therefore if I could just use Graphics API, it would be more possible to get optimized rendering? Anything that BatchRendererGroup could but Graphics could not? (One thing I noticed is that I could use NativeArray<Matrix4x4> instead of managed one in Graphics)

    Thank you.
     
    andywatts and Opeth001 like this.
  2. sngdan

    sngdan

    Joined:
    Feb 7, 2014
    Posts:
    1,154
    Good starting points (sorry no links, I am on mobile)
    - some posts on sprite rendering here (200k sprites / 1000k sprites)
    - Joachim animation system on github

    they all use the graphics api draw mesh, draw mesh instanced, draw mesh instanced indirect. Some z sorting coverage as well. Although a few of those examples have been optimized for sprite rendering, they in principle work with 3D meshes (some have ltw calculation on gpu and only for 2d for optimization, but you can just remove this)

    unfortunately it’s not clear what hybrid tenderer V2 uses under the hood (v1 used drawmeshinstanced with mpb’s but I would ditch this and use dmii with compute buffers)

    Active in this area = @GilCat @Sarkahn @FabrizioSpadaro
     
    Last edited: Feb 2, 2020
    5argon likes this.
  3. Sarkahn

    Sarkahn

    Joined:
    Jan 9, 2013
    Posts:
    440
    As far as I know with DrawInstanced they are always drawn in the order the matrices exist in the array you pass in. That's certainly how it is with DrawMeshInstancedIndirect - everything is simply drawn in order. So if you want object "behind" other objects (in terms of their z position) then you need to manually sort the array before you call DrawMesh.

    By "z efficiency" I think they're saying it doesn't do any culling to prevent drawing an object that is completely covered by another opaque object. It just draws everything in order, period.

    I'm not sure about the plain "DrawMesh", I'm assuming it's the same principal and will just draw everything in the order it gets called. Should be easy to test.

    You should read this doc page if you want to better understand DrawMeshInstanced*, I basically learned by copying their example and playing around with it.

    Edit: As per @GilCat 's post below, I was wrong about this. This is only true if you're using a transparent shader. If you're using an opaque shader it will properly sort your geometry based on distance to camera.
     
    Last edited: Feb 2, 2020
    xOrfe and 5argon like this.
  4. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    I'm very far from being an expert on graphics but here are my insights.
    I don't think it is exactly like that. The shader has a role here where if the shader is "Opaque" the objects will draw in the correct order no matter the order they are submitted to the Graphics API but if the shader is "Transparent" the order will matter. I have done tests on this using DrawMeshInstancedIndirect using HDRP and URP.
    I have also asked about this issue here.
    I believe this applies to DrawMesh, DrawMeshInstanced, DrawMeshInstancedProcedural and DrawMeshInstancedIndirect.
    Also some here about DrawMeshNow order with subMeshes.

    Those have some good insights and great work already done around it.
    I'll add the links:
    - some posts on sprite rendering here (200k sprites / 1000k sprites)
    - Joachim animation system on github

    HybridRenderer V3 will solve this issues for sure but until then we have to use custom Renderers if we want to go beyond.

    @5argon you can also have look all the implementations around this forum including my own found here
     
    Sarkahn and 5argon like this.
  5. officialfonee

    officialfonee

    Joined:
    May 22, 2018
    Posts:
    44
    I did some informal tests and it seems like at this moment DrawMeshInstancedIndirect is the fastest option when comparing the BatchRendererGroup and the other Graphics.Draw... functions. I am not sure if this was intended but I could not get BatchRendererGroup to work on URP only the default built pipeline whereas DrawMeshInstancedIndirect was working on both.

    In terms of the test, it was drawing 1 million static cubes where I would fill the matricies for both methods beforehand (so the only overhead was the rendering calls) and DrawMeshInstanced rendered in around around 70.0 ms whereas BatchRendererGroup was in the 600 ms. BatchRendererGroup does a ton of calls to the graphics jobs before rendering which took around 300-400 ms. Im running a GTX 970.

    Even with the raw rendering results, BatchRendererGroup can still nice as it has a callback which allows you to implement culling and LOD easily while bypassing all the CommandBuffers and Shader shenanigans you have to do to implement to use DrawMeshInstancedIndirect. And this is especially nice if you don't necessarily need 1 million meshes on screen but instead need a way to maintain and render these 1 million meshes throughout the world.

    The downside of BatchRendererGroup right now is its lack of documentation and examples although there is a nice article that explains it. (日本語話せますか?): https://virtualcast.jp/blog/2019/10/batchrenderergroup/