I have various buildable 3D items in my game like so:

enter image description here

These are just a few, but there will eventually be hundreds of them. The models of each of these items are displayed to the user as part of a list of constructible items in the UI like in Valheim and many other survival building games:

enter image description here

Due to the sheer amount of assets, I want to keep my iteration speed fast. To facilitate that, I don't want to be manually generating images of each constructible item and several times on top of that because items can have variants based on the material they're constructed out of. So how can I automate this process to use the already-existing 3D blueprints I have for each item?

There is the SceneCapture2D object that can output objects in its frustum to a RenderTarget2D which can then then be used in a Material:

enter image description here

This saves me from having to manually screenshot the items or have to get an artist to design icons for them. Great! Except I can't reuse the same three: moving the SceneCapture2D to target something else will overwrite the previous item's RenderTarget2D and Material -- the UI will only be able to show one item at a time. In order to use this solution for all of my items, I need to duplicate these per each constructible item. The SceneCapture2D is okay since I can create that at runtime without issue. The other two, unfortunately, need to be created at edit time.

Option 1: For every constructible item I introduce, I create a RenderTarget2D and material. This isn't too much of an impact to my workflow, as I already need to create a material & mesh in principle for any 3D item I create. The challenge comes in with variants. If I decide that only one variant can be displayed in the UI at any given time, this is fine, but if I want to show the Oak Wood Wall, the Birch Wood Wall, and the Pine Wood Wall at the same time in some comparison, I'm out of luck. I could create separate blueprints for each variant, but that introduces the same problem I'm trying to avoid here where for every game material I introduce, I need to go create N=number-of-materials blueprints.

Option 2: I create a folder of 250, 500, 1000, or some large number (however many items can be on-screen in the UI at once) RenderTarget2Ds and Materials. I then have some central resource manager which provisions and relinquishes access to the next available RenderTarget2D+Material whenever I need to render some 3D object in the UI. This eliminates the limitation from option 1, and now I can show as many variants as I need to at the same time. However, the downside it addresses from the prior option is replaced with something new: resource allocation is prone to error and complicates implementation. It also has a magic number limitation that is prone to cause issues if more items somehow show on the screen at once (e.g. a future 8K monitor would be able to show more items in a menu than some maximum designed around a 4K monitor). Between the two, I would probably pick option 1 just in the name of predictability / stability.

However, that's not the end of our problems. Both options struggle when it comes to higher DPI screens. If I'm on a screen with a really high resolution, I'd probably like to increase the UI scale. However, all of the images are rendered via the RenderTarget2D at a hardcoded resolution, and the images will look blurry when scaled up. I could globally 2X the hardcoded resolution on the RenderTarget2Ds, but that burns memory for everyone, and not just users with the UI scale turned up. It also doesn't help if someone comes along with 300% scale due to accessibility reasons or future hyper-res monitors. I could create multiple RenderTarget2Ds per each UI scale I want to support, but again that starts to introduce the process bloat I wanted to avoid to begin with.

There is a third, common solution to this problem where e.g. FPS games often draw the first person model on top of the rest of the world. We could do something similar and add our objects to some layer that renders on top of the UI, right? Well, while a common solution in other engines, this does not seem to be realistically possible in Unreal, and is instead solved through other tricks like encapsulating the weapon in the player collision capsule or scaling which don't help us in this case for rendering 3D objects on top of UI.

Each of these options seems unbearably painful to use in one way or another. Is there a more practical way to get these 3D items to show up in the UI without taking all of these tradeoffs?

  • \$\begingroup\$ Why can't you display variants in option 1? \$\endgroup\$
    – Jay
    Dec 7 '21 at 0:09

You must log in to answer this question.

Browse other questions tagged .