Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve biome blending in 3D #1637

Merged
merged 10 commits into from
Dec 23, 2023
Merged

Conversation

aTom3333
Copy link
Member

This PR improves performance of doing biome blending during chunk loading.
The combined time of step 3 and 4 (loading chunks and finalization ; biome blending occurs during step 4) has roughly been halved based on my rough timings. (Sorry, no precise timings provided, I've been winging it a bit).
The improved performance and the improved asymptotic complexity of blur make it reasonable to do blur bigger than 333 so that's now possible and exposed in the UI.
As an added bonus that wasn't really intentional, memory usage has decreased when using trivial 3D biome structure (by virtue of not storing biome color for every block, more on that later).

The improved performances are achieved for 3 reasons:

  • When possible a 2D blur is used instead of a 3D one. To know when using a 2D blur can be used (will give the same result as the 3D one), I keep track of vertical biome transition during chunk loading, ie when the biome at a block is different than the biome at the block just under. When a transition occurs, for every y level that is close to transition (closer than the blur radius), a 3D blur is needed as the biomes are not vertically uniform. Basically, for each y at which a (vertical) biome transition occurs, there is an interval of y value for which a 3D blur must be used. But for every y level outside of all of those intervals, a 2D blur is enough. Even better, there is usually a lot of consecutive y levels with (vertically) uniform biomes, this means the 2D blur can be computed for only one of those levels and copied for the other levels. In practice I don't track biome transition for each (x, z) column but for each chunk, this means that if there is a biome transition in a single column of the chunk, the 3D blur will be used for the entire chunk (for the y levels around the transition). And even more, because neighboring chunks affect biome blending, a single biome transition in a column will affect the whole chunk of the block and the neighboring chunks. To be effective this optimization relies on the fact that there isn't a lot of vertical biome transition in a minecraft world (which seems to be the case in my very limited testing). (this optimization does nothing to help performance when using 2D biome only)
  • The blur computations, both 2D and 3D, have been changed to use a summed-area table to reduce the complexity, especially with bigger blur radius. (while writing this message I realized that in asymptotic sense, it doesn't actually improve the complexity the way I've done it. It's better then naive blur but maybe an separated blur is even better but that would be a separated PR). This optimization benefits the 2D biome only case as well.
  • Only compute the biome colors when needed. That's a very rough way to do it (it could be done more finaly later I guess), during loading chunk I keep track of the min and max y value for which at least one block of the chunk needs biome color. When comes times to compute biome color, I don't compute any color outside of this interval. This simple test can lead to big wins on some chunks (like when there is no water underground, the biome colors will only be computed around surface level). (doesn't help in the 2D biome case). This is the change that cause the memory usage reduction, because in some cases a lot less biomes colors are stored.

The setting for enabling/disabling biome blending has been replace for a setting to choose the biome blending radius (and a radius of 0 means biome blending is disabled)

Sorry no screenshot of bigger radius, I'm too lazy and my test scene is stupid looking anyway


@Override
public boolean useBiomeTint() {
return true; // (in reality it is only used for fern)
Copy link
Member

@leMaik leMaik Oct 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be fixed then (or does this method only check if the model uses it at all)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning true only for fern would be better. But from the function just above it seem the entityTag is needed to determine whether this is a fern or not. And because returning true when it should be false doesn't lead to a big adverse effect (it may lead to unnecessary work as more biome blending than necessary is performed), I just was lazy and made it simpler

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, this shouldn't be a problem at all. We replace all legacy blocks while loading a legacy chunk and let it create a new tag that takes the entity tag's information into account.

All the biome stuff is handled after converting the legacy blocks.

Copy link
Member

@leMaik leMaik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! 🤩

The third optimization is smart… Could that save memory in 2d biomes too because we could have a "don't care" biome then? Similar how we have any nodes in the octree?

@@ -989,6 +1003,9 @@ public synchronized void loadChunks(TaskTracker taskTracker, World world, Collec
int octNode = currentBlock;
Block block = palette.get(currentBlock);

if(block.useBiomeTint())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe?

Suggested change
if(block.useBiomeTint())
if(block.isBiomeDependant())

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not, wasn't too sure of the name myself

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about isBiomeTinted? Biome dependant sounds like a block "design" can change depending on the biome.

@aTom3333
Copy link
Member Author

aTom3333 commented Oct 14, 2023

The third optimization is smart… Could that save memory in 2d biomes too because we could have a "don't care" biome then? Similar how we have any nodes in the octree?

It could be applicable with limited changes to the 2D case as well, if no block in the chunk uses biome color, the color for the biome doesn't need to be stored. We don't even need a "don't care" thing, we just won't store the color in the world texture in the first place.

@leMaik
Copy link
Member

leMaik commented Dec 15, 2023

Something strange is happening with the biome colors…
image

@leMaik
Copy link
Member

leMaik commented Dec 23, 2023

Rebased and resolved conflicts, I'll test again and merge this if it works now. 👍

@leMaik leMaik merged commit 097cf54 into chunky-dev:master Dec 23, 2023
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants