Skip to content

Implement Recipe Tree Culling#1112

Open
milkev wants to merge 3 commits intoemilyploszaj:1.21from
milkev:1.21
Open

Implement Recipe Tree Culling#1112
milkev wants to merge 3 commits intoemilyploszaj:1.21from
milkev:1.21

Conversation

@milkev
Copy link

@milkev milkev commented Jan 22, 2026

Creates a bounding box surrounding everything rendered by each node of the recipe tree, and if the bounding box doesnt collide with the visible screen, it simply doesnt render the node.

Added dev config to enable viewing of the bounding boxes. I only know english, so i only added a translation for the config in english.

Everything is rendered on the first frame after tree rebuild as I was encountering an issue where itemstack renders would only be controlled on the first frame of rebuild, and could not dynamically be culled (atleast not with my knowledge). This means that all the itemstacks of a recipe tree are always rendered. If this is able to be implemented then viewing recipe tree's of any size should not cause any performance impact at all.

Visually it is identical to current EMI functionality. The only difference is a massive performance improvement when viewing large trees, allowing the user to view recipe tree's of basically unlimited size with little performance loss.

I have noticed one bug, and that is that when you change the window size while viewing a recipe tree, it still uses the old resolution to determine bounding boxes causing some nodes to be culled which should not be culled and vice versa, simply going out and back into the tree fixes this though and my knowledge is to limited to tackle this bug.

Tested in a minimal environment on windows 10 on Minecraft 1.21.1 on neoforge as well as a large scale modpack (custom 700+mods) on minecraft 1.21.1 neoforge. I was able to view full recipe tree's for items such as the Quantum Upgrade from Modern Industrialization which has thousands of crafting steps, consumes millions of crafting ingredients and still have over 120fps.
image

now with no performance losses when viewing massive trees
this wasnt supposed to be uploaded, just needed it to build emi on my system
Copy link
Owner

@emilyploszaj emilyploszaj left a comment

Choose a reason for hiding this comment

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

EMI has a Bounds class, please use that, it'll be more portable. Creating a Bounds object for the screen and checking for intersections should also be cleaner, codewise.
Please adjust code to be following the coding style in the rest of the codebase.
EMI has a batched rendering system, which is what is causing the issue you're noticing with the first frame, though strictly that is not the only scenario where it gets invalidated. A more comprehensive implementation would deal with this more directly or, potentially, remove batching in favor of culling (profile this?).
Additionally, I'm not sure what's causing the resolution culling bug, but that'd need to be fixed before this could be merged.

Requested changes notwithstanding, this is a great addition to EMI, thank you.

@milkev
Copy link
Author

milkev commented Jan 23, 2026

I love the bounds class, refactored all my changes to use bounds instead of vector4d and cleaned up the collision code. Screen reference was removed. Culling also no longer breaks when changing window sizes.

Only remaining thing is potentially making the itemStack renders culled instead of batched. I don't think it would be a massive performance improvement (although it should be noticeable in benchmarks) as most of the performance losses came from all the line draws. I don't have the knowledge or energy to get into that though, especially since it doesn't seem to be needed to obtain satisfactory performance.

@aMelonRind
Copy link

I love the idea of culling the recipe tree. Since it looks like you've paused developing it, I decided to push my skill limits into enhancing it (but not on the latest version because I play on 1.20.1 forge modpack). You can download it from GitHub Actions to test it.

Now, besides of a whole node, it also culls the individual component like lines, stacks and amount texts. It'll now cache the amount text that was otherwise constructed from raw data every frame. Instead of scaledScreenBounds, I renamed it to camera and created methods to check overlap faster. Most importantly, instead of keeping the batcher or drop it for culling, I implemented culled batcher (surprisingly easy to do), which solves the lagspike from reloading while keeping the benefit of batching.

The render bounding box in dev mode is also revamped, added 12 colors so the boxes won't be too hard to see. The cameras are shrinked in this mode and the border are rendered to see the culling border easily. Text info like FPS, USPF and the batcher repopulate frame time are rendered on the top left.

Lastly, I think the possible improvements could be implementing line batcher and text batcher just like the StackBatcher, but that's beyond my skills because I'm not familiar with internal rendering mechanics like vertex, render layer, sprite, framebuffer, etc.

I'm actually not sure how this performs on an extremely large recipe tree, because I'm not that deep into the modpack. Can someone test it?

Not going to create a PR because of duplicate, and I'm not sure if Emi approves my codestyle, I kind of let myself go on this one.

Here's a screenshot of a recipe tree in dev mode:
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants