Jump to content

Room-based Level of Detail


Latheeb

Recommended Posts

Hello, I am using DunGen to create procedurally generated dungeons at runtime and SECTR Vis to provide occlusion culling and it is working quite well so far.

To optimize things a bit further I was hoping to play around with a little room-based LOD system.

As a starting point I'd like to create 3 LODs for each room, then use LOD0 for the room the player is in, LOD1 for the rooms neighboring that room and LOD2 for all other rooms. I can get all the relationships between rooms and such through DunGen, but I had a few questions on the best way to integrate this into SECTR.

Is there an existing way to use the SECTR_Member component on the player to find out when they have entered a new sector?

As far as switching between LODs I can think of a few ways to do this, but I'm not sure what the best way would be.

I could make each LOD a sector and enable/disable the sectors at runtime. Would this cause problems for things like NPCs which have a SECTR_Member component, when the sector around them changes?

I could put all three LODs into the same sector and just enable/disable them at runtime. How does SECTR Vis handle culling on disabled GameObjects or when a GameObject within the sector is enabled/disabled?

I'd really appreciate any advice on a good way to go about doing this. Thank you for your time!

Link to comment
Share on other sites

I have been experimenting with trying to get something that will work for my purposes. What I'm hoping to accomplish is to reduce the overhead of sectors that are not culled due to lights and such, but are also not visible. Currently in my testing the SECTR_CullingCamera is loading at times 8-12 Sectors (with each sector being a room) with only perhaps 1-3 of these actually visible on screen.

I realize it is making these culling decisions for good reason, so I'd like to be able to use lower poly meshes in those rooms and hopefully reduce some heavier NPC behaviors.

Initially I was just trying to get the very simple room-based LOD system I mentioned above up and running and from my testing I think I could accomplish a very basic form of this, but it feels very hacky any way I could imagine setting it up.

I think a significantly better approach would be to try to run code to switch between detail levels when the SECTR_CullingCamera determines which portals are visible, since it is already doing this.

I had initially thought this was determined in the code starting on line 923 with "else if(!allPositive)" meaning that the portal intersects the current frustrum planes it is checking, but my testing seems to indicate that it is not doing what I think it is. It seems either all or nearly all portals that lead to sectors that will not be culled pass this test?

I've been reading through the SECTR_Chunk and SECTR_Hibernator components to try to understand how they create their more dynamic interactions with sectors to get some insight into the right why to set up something like this but it's just not clicking for me. What I'm trying to do isn't too dissimilar from what the SECTR_Chunk does with its proxies, I think.

Can anyone give me suggestions on a good way to determine when a portal is visible or to switch which mesh renderers SECTR is culling within a particular sector?

Link to comment
Share on other sites

I'm continuing to go through the code to see what has potential for implementing something like this and I see that SECTR_LOD has public public methods for adding and removing a LODEntry. I'm thinking maybe if I set up SECTR_LOD on each room with only a single LOD I may be able to use these methods to swap the LOD dynamically and get the behavior I want. In hindsight this was probably the most obvious place to start. I will test this out when I'm able to and see if it will work like I think it should.

I'm still a bit confused about where in the code the SECTR_CullingCamera determines if a portal is currently visible and I think this would be useful information for my purposes.

I'm also still a bit uncertain about a good way to determine which sector the player is in. Currently I'm using functionality provided by DunGen in order to determine which Tile the player is in (as each Tile in DunGen is its own sector the way I'm using it) and getting references to the sector containing the tile using that, but it relies on colliders to determine which Tile the player is in and I'm worried that having two independent systems interacting with the culling system may lead to desync or other strange behavior.

From reading the comments and my testing I think using the initialSectors in the SECTR_CullingCamera would reference only the sectors the camera is currently contained in. Would using initalSectors as my player location (considering I have no overlapping sectors it should always contain only a single sector, I think?) be a better way of doing this?

Edited by Latheeb
Fixed redundancy in wording.
Link to comment
Share on other sites

Well, I feel this was pretty obvious, but I'm guessing it's intended for me to use the MembershipChanged event on the SECTR_Member that gets added to the camera with the SECTR_CullingCamera to keep track of which sector the player is in. That seems like it will do what I need it to.

From what testing I've done it seems things like the SECTR_LOD component (for example) doesn't actually stop SECTR from working on the renderers on a disabled LOD. Is it not really worthwhile to try to accomplish this?

I think if I can just figure out how to tell when a portal in the current sector becomes visible that I can get this working how I want it to. I just can't seem to find the right place in SECTR_CullingCamera to run the code.

Link to comment
Share on other sites

Quote

I think if I can just figure out how to tell when a portal in the current sector becomes visible that I can get this working how I want it to. I just can't seem to find the right place in SECTR_CullingCamera to run the code.

@Latheeb, I think the following would work:

In line 666 and following, a node graph of the connected sectors is being build to check which sectors are visible, and which are not.


image.png

In there, starting at line 816, the portals of the current Node / Sector are being evaluated for visibility:

image.png

There are certain points in the code where a portal is being rejected....
image.png

and a lot of checks are being made, but if it passes all tests, the sector it connects to is added to the node graph.

image.png

However this would trigger whenever a portal IS visible, not when it BECOMES visible. To track that, you would need to keep a List / Dictionary / Array of portals, and track their last visibility state in there - if they do not exist in your list, you would need to add them, if they get rejected, you would need to track that they were not visible in the last frame. If a portal is visible and you got in your list that it was not visible before (or not logged in your list to begin with) then it just became visible in this frame.
Take this with a grain of salt because that is just my first thought how this might work, but I hope it helps!

Link to comment
Share on other sites

3 hours ago, Bryan said:

Sorry for the delay. 

I am looking into a theory but I need to check to see if it's possible or not. 
 

No problem at all, I understand you guys have a lot going on and I appreciate you taking the time to help very much!

Link to comment
Share on other sites

2 hours ago, Peter said:

@Latheeb, I think the following would work:

In line 666 and following, a node graph of the connected sectors is being build to check which sectors are visible, and which are not.


image.png

In there, starting at line 816, the portals of the current Node / Sector are being evaluated for visibility:

image.png

There are certain points in the code where a portal is being rejected....
image.png

and a lot of checks are being made, but if it passes all tests, the sector it connects to is added to the node graph.

image.png

However this would trigger whenever a portal IS visible, not when it BECOMES visible. To track that, you would need to keep a List / Dictionary / Array of portals, and track their last visibility state in there - if they do not exist in your list, you would need to add them, if they get rejected, you would need to track that they were not visible in the last frame. If a portal is visible and you got in your list that it was not visible before (or not logged in your list to begin with) then it just became visible in this frame.
Take this with a grain of salt because that is just my first thought how this might work, but I hope it helps!

Thank you very much for your consideration, @Peter 

When I initially went through the code I thought this would do exactly what I needed and my very basic initial testing seemed to suggest I was on the right track, but I'm not getting the behavior I want from anything I've tried.

I created a little script to keep a dictionary of the sectors at this point in the script. Maybe I am just doing something very obvious wrong?

Here is the script: https://codeshare.io/4eo1mL

I tried implementing it like this for testing purposes:

spacer.png

I think currentNode.sector would be the right thing to use here, but I've tried several other things as well to no avail.

Here's an example of the results with this:

spacer.png

SECTR_Testing_Debug is a script that just shows the contents of the dictionary. As you can see even though there are no portals in the camera's view frustrum, there are four sectors in the dictionary which I have color coded in the image.

Link to comment
Share on other sites

In case there is confusion in the above script I posted SectorDictionary is a serializable dictionary I made following this: https://odininspector.com/tutorials/serialize-anything/serializing-dictionaries

That looks like this:

[System.Serializable]
public class SectorDictionary : UnitySerializedDictionary<SECTR_Sector, bool> { }

This is unrelated to its functionality here and something I did during earlier testing so I could see its contents in the inspector. I just wanted to mention this as I realized it's used in SECTR_Testing without explanation.

Link to comment
Share on other sites

I probably should've included an example like this in my initial post, although I think I communicated what I'm trying to do well enough, at least. Still I want to include this and talk a little more about my goals mostly in case it illustrates that I either already am doing or am planning to do something very incorrectly.

spacer.png

This is in a sort of "worst case scenario", I think, for testing purposes where every room is pretty empty, there are no doors to obstruct visibility into any sectors and every light is in mixed mode with shadows set to update every frame.

My thought process is that since very little in any of the sectors outside of the sector the player is in appears on screen the rooms in those sectors could be replaced with lower quality versions to improve performance.

It seems it would be possible to use a combination of knowing which sector the player is in, which portals are visible and data collected when the dungeon is being generated about how the sectors are connected to dynamically swap between higher and lower quality versions of each room as needed depending on if any of their contents are actually visible and how many sectors away from the players current sector they are.

Also it's my understanding that the sectors which are not actually visible but also not culled are not culled probably because of the lights they contain and possible shadow casting. Is this correct and do my current lighting settings contribute to this or is it simply necessary?

My intent is to switch the lights to update on demand and only update lights in sectors I determine are near enough to the player myself using the same system that will swap the LOD on the rooms. Are there any special considerations you are aware of when doing something like this while using SECTR Vis since I know it interacts with lights?

Again thank you very much for your time guys!

Link to comment
Share on other sites

Hi @Latheeb, when looking at your "worst case scenario" it is a bit worse than I normally would expect - I would expect maybe the third room from the one the camera is in still to be visible, but nothing beyond that. Could you please check the following:
 

  •  Is "Simple Culling" active on the SECTR_Culling Camera component? If yes, this will fall back to a simpler frustum culling method that does not evaluate the portals etc.
  • Do you have real time lights in the rooms with a range larger than the sectors themselves? This might lead to them NOT being culled because they potentially might throw a shadow into another sector. You can try the following in the advanced culling demo scene to test this:
    • Open the advanced culling demo scene
    • Open the Window > Rendering > Light explorer dialog, deactivate all the lights in the scene
      image.png
    • Run the scene and observe the culling in the upper left corner of the screen - as you wander around in the darkness, you should see that the culling is very "tight" as no lights are being considered for shining through a portal into another sector
      image.png
    • You can then test the other extreme, stop the scene and activate one of the lights again, e.g. this point light in Room D, and set the range to 50:
      image.png
    • Note that the white box of the sector member component and the blue lines pointing to other sectors indicate that this member will influence the visibility of those sectors.
    • If you run the scene again, almost nothing will be culled anymore, because there potentially could be a shadow of that light somewhere through the portals.
    • image.png

I think you might have a setup like this in the scene of yours as well, otherwise those rooms should be culled normally. It might then be that this also explains the odd results you were getting from your sector visibility solution.


 

Link to comment
Share on other sites

1 hour ago, Peter said:

Hi @Latheeb, when looking at your "worst case scenario" it is a bit worse than I normally would expect - I would expect maybe the third room from the one the camera is in still to be visible, but nothing beyond that. Could you please check the following:
 

  •  Is "Simple Culling" active on the SECTR_Culling Camera component? If yes, this will fall back to a simpler frustum culling method that does not evaluate the portals etc.
  • Do you have real time lights in the rooms with a range larger than the sectors themselves? This might lead to them NOT being culled because they potentially might throw a shadow into another sector. You can try the following in the advanced culling demo scene to test this:
    • Open the advanced culling demo scene
    • Open the Window > Rendering > Light explorer dialog, deactivate all the lights in the scene
      image.png
    • Run the scene and observe the culling in the upper left corner of the screen - as you wander around in the darkness, you should see that the culling is very "tight" as no lights are being considered for shining through a portal into another sector
      image.png
    • You can then test the other extreme, stop the scene and activate one of the lights again, e.g. this point light in Room D, and set the range to 50:
      image.png
    • Note that the white box of the sector member component and the blue lines pointing to other sectors indicate that this member will influence the visibility of those sectors.
    • If you run the scene again, almost nothing will be culled anymore, because there potentially could be a shadow of that light somewhere through the portals.
    • image.png

I think you might have a setup like this in the scene of yours as well, otherwise those rooms should be culled normally. It might then be that this also explains the odd results you were getting from your sector visibility solution.


 

Thank you so much @Peter!

I will not be able to do tests until tomorrow but I am nearly certain you are right about the lights. I am not using Simple Culling,  but these rooms are originally from an asset pack and I recall that the default range on the lights is set to be very high and it is likely currently set to that default value. I guess I got a bit of tunnel vision and didn't even consider the role the lights play until last night, although it makes perfect sense to me after your explanation how this would be the problem. It just occur to me that it could give this result with the portal visibility.

I will verify that this is the problem in the morning, thank you again for providing me with so much helpful information.

Link to comment
Share on other sites

@Peter  Well, it would seem I was mistaken and I had already adjusted the range of the lights to be values I thought were appropriate (typically between 4 and 12). I've reimported some prefabs, including those containing the lights, a few times and thought maybe I had forgotten this.

I went through and further reduced some of them so that no light has a range greater than 5 and switched them from mixed to baked. This does not seem to have had any effect on either culling or visibility tracking.

Here are my settings for SECTR_CullingCamera: 

spacer.png

The lights (some have a shorter range of 2-4 but none over 5):

spacer.png

Here are some situations similar to the ones I shared above with these settings:

spacer.png

spacer.png

If there is any other information that could be helpful please let me know and thank you again so much for all of your help.

Link to comment
Share on other sites

@Peter I'm so sorry it was all my fault. I was trying to figure out what could possibly be the problem and going back through everything with the dungeon generation and realized what the problem was. DunGen uses a system where rooms have several potential doors and it will either place an actual door or a "blocker" to close off the doorway if there isn't going to be a room placed on the other side.

So I have to do some of the setup with the portals and I was setting the portal flags wrong. Once I fixed this the culling is now greatly improved and my visibility detection is working as expected.

I'm very sorry that it took me this long to realize I had made such a simple mistake. I set up this part a few weeks ago and hadn't really thought about it since.

The only remaining issue I have is that I haven't found a good way to add or remove objects from the culling process in a situation like this. Or is this something I should even worry about? So far everything I've tried either does not work if the objects are switched while culled or causes SECTR to enable/disable the renderers of both sets of objects whenever culling changes.

I apologize if this is something that should be obvious, but I've been going through the documentation and looking at how components like the SECTR_LOD and SECTR_Chunk work and am still not sure about how to do this.

Link to comment
Share on other sites

Hi @Latheeb,
 

Quote

I'm very sorry that it took me this long to realize I had made such a simple mistake. I set up this part a few weeks ago and hadn't really thought about it since.

No worries, the most important thing is that you figured it out, and the culling is now working as expected - I did not think about issues with the portal flags either when reading your description, but it makes sense.
 

Quote

The only remaining issue I have is that I haven't found a good way to add or remove objects from the culling process in a situation like this. Or is this something I should even worry about? 

I would dare to say this is something you would not need to worry about - if you look at the culling in action, I think you would be optimizing for very specific viewing angles only where there is another room visible next to the first immediate neighbor room through two portals. Adding extra logic just for that case seems to be overkill, I would only consider that if you have noticeable performance issues when you are in those special angles with the camera.
 

Quote

  I would love any input you have on doing something like in this script @Peter


I did have a short look at the code, and it looks like it would / should work, but to make a qualified statement I would need to try it out and implement the feature myself - this is something that exceeds what we can provide in the scope of product support unfortunately.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Tell a friend

    Love Canopy - Procedural Worlds? Tell a friend!
  • Need help?

    We work with some of the biggest brands in global gaming, automotive, technology, and government to create environments, games, simulations, and product launches for desktop, mobile, and VR.

    Our unique expertise and technology enable us to deliver solutions that look and run better at a fraction of the time and cost of a typical project.

    Check out some of our non-NDA work in the Gallery, and then Contact Us to accelerate your next project!

×
×
  • Create New...