Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 6 of 6

Thread: how to conditional render different mesh LODs

  1. #1
    Member Regular Contributor
    Join Date
    May 2016
    Posts
    435

    how to conditional render different mesh LODs

    hi,

    lets say i have a mesh in different levels of details (each being a separate mesh / drawcall). to save performance, i first want to render a simple box around the mesh to check for the number of samples passed. depending on the samples passed, i want openGL to select a suitable LOD of that mesh. (a mesh has about 4..5 LODs, the lowest LOD has just a hand full of faces / vertices [maybe 100], the highest LOD about up to about 50K faces)

    the only way to do that (that i'm aware of) is without "conditional rendering", but to use a kind of "double-buffered query object". in frame X, i render the box around the mesh, capture the samples in query X. next frame, i use result of query X to determine the LOD to draw, and draw the box again, capturing the samples passed into query X+1.

    is there another way with "conditional rendering" of so ?
    if not, is it a "good" approach if i have a couple of hundreds of meshes in my scene ?

    thanks for any advice !
    Last edited by john_connor; 07-14-2017 at 01:31 AM.

  2. #2
    Member Regular Contributor
    Join Date
    Jul 2012
    Posts
    425
    You might be interested in this.

    What you're trying to do looks interesting. Mainly if you use the occlusion queries for managing occlusion at the same time. Otherwise, you'll slow things down as it is a 2 passes algorithm, which then might not be as efficient. Other things to take into account is the popping effect that will probably happen since you'll switch from a model with N faces to the 'same' model but with only M faces where M << N. You'll then have to see if that happen, and if so, if this is acceptable for you. To prevent this, algorithm as continuous LOD or adaptative LODs exist. One of them is called ROAM but is known to be old and not to provide any real benefits anymore (so avoid this latter one).

  3. #3
    Senior Member OpenGL Guru Dark Photon's Avatar
    Join Date
    Oct 2004
    Location
    Druidia
    Posts
    4,156
    Quote Originally Posted by john_connor View Post
    lets say i have a mesh in different levels of details (each being a separate mesh / drawcall) ...
    i want openGL to select a suitable LOD of that mesh. ...
    i have a couple of hundreds of meshes in my scene ..
    Ok, so lots of models, each model has multiple mesh LODs, each mesh LOD is a draw call. And you want to do LOD selection based on some "screen size" heuristic.

    to save performance, i first want to render a simple box around the mesh to check for the number of samples passed. depending on the samples passed, i want openGL to select a suitable LOD of that mesh.
    You could use this as a LOD selection heuristic. However, think about a long thin feature like a table top (with no legs or thin legs). When you're looking top-down it hits a lot of samples. When you're looking near edge-on, it hardly hits any samples. Do you really want to render a different and much lower-resolution LOD for that? That's when you need the edge profile detail.

    I suspect you may be happier with a LOD selection heuristic based on the size of the model's bounding sphere on-the-screen (in the view frustum), or based on a distance-to-model-center heuristic. Both are super-cheap to evaluate in a shader, and the former has the benefit of dynamically adapting to field-of-view (frustum) changes. With either of these, you don't need to rasterize the model to be able to tell which LOD you want to use.

    If you think one of those LOD selection criterias (or something similar) might work for you, you can do the model culling and LOD selection on the GPU using a geometry shader in a first pass (this builds a list of instances). And immediately after that, you can launch one instanced draw call per unique LOD mesh (e.g. 5) and in doing so render all of your models (e.g. 100+), each one rendering with the correct LOD.

    This all happens on the GPU side so it's very fast, and in the end you end up rendering a lot of models with very few draw calls.

    For more on this, read this thread (including the linked tutorial pages):

    * Instance Shader
    Last edited by Dark Photon; 07-14-2017 at 06:27 AM.

  4. #4
    Member Regular Contributor
    Join Date
    May 2016
    Posts
    435
    thank you both for your answers !!


    Quote Originally Posted by Dark Photon View Post
    Ok, so lots of models, each model has multiple mesh LODs, each mesh LOD is a draw call. And you want to do LOD selection based on some "screen size" heuristic.



    You could use this as a LOD selection heuristic. However, think about a long thin feature like a table top (with no legs or thin legs). When you're looking top-down it hits a lot of samples. When you're looking near edge-on, it hardly hits any samples. Do you really want to render a different and much lower-resolution LOD for that? That's when you need the edge profile detail.

    I suspect you may be happier with a LOD selection heuristic based on the size of the model's bounding sphere on-the-screen (in the view frustum), or based on a distance-to-model-center heuristic. Both are super-cheap to evaluate in a shader, and the former has the benefit of dynamically adapting to field-of-view (frustum) changes. With either of these, you don't need to rasterize the model to be able to tell which LOD you want to use.

    If you think one of those LOD selection criterias (or something similar) might work for you, you can do the model culling and LOD selection on the GPU using a geometry shader in a first pass (this builds a list of instances). And immediately after that, you can launch one instanced draw call per unique LOD mesh (e.g. 5) and in doing so render all of your models (e.g. 100+), each one rendering with the correct LOD.

    This all happens on the GPU side so it's very fast, and in the end you end up rendering a lot of models with very few draw calls.

    For more on this, read this thread (including the linked tutorial pages):

    * Instance Shader
    "instance shader" .. "model culling" .. sounds very interesting
    something like:


    pass 1: build instances
    for each object
    determine model type, add transformation matrix to temp array

    put all temp arrays of model instances into array buffer (or uniform buffer)

    for each model type
    use compute shader or transform feedback to determine if model center is in view frustum, feedback if so, and determine LOD dependent on the "depth" value = (MVP * vec4(0, 0, 0, 1)).z / w


    pass 2:
    for each model type
    for each mesh
    for each LOD
    drawinstanced() (maybe indirect if i'm getting it right)


    .. right ?! i'll try that approach .. thanks again !
    Last edited by john_connor; 07-15-2017 at 02:17 PM. Reason: replaced "modelcenter" with vec4(0, 0, 0, 1)

  5. #5
    Senior Member OpenGL Guru Dark Photon's Avatar
    Join Date
    Oct 2004
    Location
    Druidia
    Posts
    4,156
    Quote Originally Posted by john_connor View Post
    Code :
    pass 1: build instances
       for each object
         determine model type, add transformation matrix to temp array
     
       put all temp arrays of model instances into array buffer (or uniform buffer)
     
       for each model type
         use compute shader or transform feedback to determine if model center is in view frustum, feedback if so, 
          and determine LOD dependent on the "depth" value = (MVP * vec4(0, 0, 0, 1)).z / w
     
    pass 2:
       for each model type 
           for each mesh
               for each LOD
                   drawinstanced() (maybe indirect if i'm getting it right)
     
    .. right ?!
    Something like that. Re indirect, yes (it's an instanced indirect draw call).

    However, the way you wrote this prompts a question: when you say you have "hundreds of meshes in my scene", do you mean hundreds of instances of a small set of unique meshes? Or hundreds of "unique" meshes?

    Where this approach is going to help you most is with many mesh instances drawn from a small set of unique meshes. I was assuming this before, but it occurs to me that perhaps I shouldn't have been. For lots of mesh instances, this approach yields very few draw calls and state changes.

    However, if all of your meshes are unique, then this isn't going to help you so much. In fact it's going to be overkill.

    What prompted this question is your "for each mesh" loop in pass 2. If here "mesh" is a mesh instance, then no; this loop should not be here. The instanced draw covers rendering multiple instances of the same mesh LOD.
    Last edited by Dark Photon; 07-16-2017 at 01:55 PM.

  6. #6
    Member Regular Contributor
    Join Date
    May 2016
    Posts
    435
    Quote Originally Posted by Dark Photon View Post
    However, the way you wrote this prompts a question: when you say you have "hundreds of meshes in my scene", do you mean hundreds of instances of a small set of unique meshes? Or hundreds of "unique" meshes?

    ...

    However, if all of your meshes are unique, then this isn't going to help you so much. In fact it's going to be overkill.
    no, not "unique", consider a space sim:
    there are several ships in the scene (up to hundred+ maybe), each ship has a "hull", a set of guns, thats it essencially (maybe 1 particle emitter). each hull has about 4..5 LODs, and each gun about 3 LODs or so. many ships are of the same type, that means the same meshes, and different model types can use similar gun types.
    Code :
    std::vector<...> meshes = .. all possible meshes in the scene
     
    pass 2:
    for (auto& mesh : meshes) {
      for (auto& lod: mesh.LODs) {
        apply material
        drawinstanced(... lod.drawcall ..., lod.instancecount)
      }
    }

    so i'll definitely get several instances (up to max hundreds maybe) per mesh, spread over a hand full LODs per mesh. never heared about "model culling" / "instance shader" before, the idea is great (i tried that about a year ago, but very simplified on the cpu: if (modelcenter behind camera) then cull)
    Last edited by john_connor; 07-15-2017 at 05:18 PM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •