Texture Translucency Controls

Currently on Roblox, it’s impossible to indicate how texture translucency should be handled, which means games often lose out on large amounts of performance and have to deal with depth sorting errors unnecessarily.

(disclaimer: I’m not a graphics engineer, so everything in this post is based on my (limited) understanding of how the Roblox rendering system works based on my own observations. If any Roblox engineers are here, feel free to provide or correct any details if you’d like!)

This will be a long post, so go grab a snack or something, and enjoy:

The translucent rendering path

We’re all familiar with this effect; it needs no introduction:

As humans, we know the ocean does not belong in a tree. Unfortunately, it’s really hard to communicate that to a computer - translucent depth sorting is a really hard problem in computer graphics. The solution which Roblox (and pretty much any other engine like it) choose to use is called the Painter’s algorithm, where you draw the translucent objects in the scene from back to front. In other words, the translucent objects in the scene will be sorted based on their perpendicular distance from the camera, furthest first.

Usually, this works great! As you can see here, we have two translucent blocks, and from this camera angle, it works well:

Other camera angles are less impressive.

This is where those depth sorting errors come from, like the one in the screenshot at the top of this section. It’s not really ideal, but it’s not easy to fix either. In addition, with the Painter’s algorithm you’re likely going to end up drawing over the same pixels many times, which means bad performance.

Luckily, most things in Roblox aren’t translucent. You can think of two rendering paths, opaque and translucent. The opaque rendering path is highly efficient and can sort depth accurately, thanks to some smart tech called the ‘z-buffer’, but only works with things which are fully opaque. The translucent rendering path is what we discussed above, and is generally the slower, less attractive option. Common wisdom is to only use the translucent rendering path when you really need it, for those reasons.

Unfortunately, with textures on invisible parts especially, we’re stuck on the translucent rendering path, since we need to do alpha blending. What if we want to put a texture on an invisible part, but don’t mind giving up that alpha blending?

Introducing cutout rendering

The core of this suggestion is about cutout rendering. Cutout rendering is an alternative way of dealing with transparency in textures. It can be found everywhere, from older console games right up to modern day implementations in Unity. It allows developers and builders to use transparency in textures in a way that lets you stay on the opaque rendering path. We established previously that this is desirable for the performance gains and accurate depth sorting, so how does it work?

Here’s a cool texture with an alpha ramp from 0 to 255:
A

We’re going to composite that texture over this background:
image

Using normal alpha blending, we get this nice fade, as expected:
image

Using cutout rendering, any pixels with an alpha of 128 or greater will be fully opaque, and any pixels less than that will be fully transparent:
image

This is a simple enough concept to grasp. It’s a tried and tested method of allowing transparency without having to resort to the translucent render path. But how would it look with an actual texture, for example a chain link fence texture?

Here it is with normal alpha blending:
image

And here it is with cutout rendering:
image

It looks really good! What’s more, it can be rendered on the opaque rendering path, which means no depth sorting errors and higher framerates! One characteristic of textures using cutout rendering is the clean edge, as opposed to the blurrier, fuzzier edges that tend to come with alpha blended textures.

So, how would this apply to the Roblox API, so we could let developers harness this power?

Improving textures, decals and mesh parts

To enable developers and builders to take advantage of cutout rendering, a new property can be introduced for Textures and Decals, called TranslucencyMode. This is an enum with two values:

  • Translucent - the default value, exactly matches the current behaviour of textures and decals. If the part supporting this texture is opaque, the texture is put on the opaque rendering path. Otherwise, the texture is put on the translucent rendering path for alpha blending with any objects in the background.

  • Cutout - regardless of the transparency of the part supporting this texture, the texture is put on the opaque rendering path. Every point on the texture is either fully opaque or fully transparent, determined by using a threshold on the alpha component at that point. If the alpha component is larger or equal to the threshold value, the point is fully opaque, otherwise it is fully transparent. The threshold used may be either hardcoded as 128, or variable from 0-255 based on the Transparency of the texture.

If the threshold was to be based on the Transparency of the texture, this could open up a wide range of new special effects possibilities for creative builders and developers, for example overlays with morphing shapes, made possible by using a texture with a varied alpha channel and modulating the threshold with perlin noise.

Mesh parts could also receive a TranslucencyMode property of their own. Since there are already feature requests for greater control over mesh part translucency, they could be combined into four values for mesh parts:

  • Opaque - the mesh part is opaque, and the part transparency controls the transparency of the mesh part and texture. The mesh part would be on the opaque rendering path when transparency = 0, and the translucent rendering path otherwise.

  • Cutout - the mesh part is fully transparent, and the texture uses a cutout rendering system where the part’s transparency is used as a threshold. Similar to above, the mesh part can stay on the opaque rendering path.

  • Translucent - the mesh part is fully transparent, and the texture is blended normally with the background. The mesh part is put onto the translucent rendering path.

  • Automatic - the default value, which matches the current Roblox behaviour. When part transparency is 0, or when no texture is used, behaves like Opaque, otherwise behaves like Translucent.

This means that mesh parts can benefit from the same cutout rendering as textures, and developers and builders get more control over the transparency of the mesh part when used with a texture. Two birds, one stone!

Widespread benefits for general cases

Look at this bush.

It’s a very nice (free model) bush, but it looks kinda funky. Even though most of the texture is fully opaque and the rest is fully transparent, we’re unnecessarily putting it on the translucent rendering path. Using the cutout rendering mode discussed before, we could get a result closer to this (simulated):

Much prettier!
You also see this a lot with ‘realistic trees’. These tree leaves are being sorted incorrectly.

But also, look how many leaf textures there are! This would almost certainly murder performance on mobile.

Taking a closer look at those textures, you can see that they, too, are mostly either fully opaque or fully transparent:

This makes the tree another great candidate for cutout rendering.
There’s also this very common chain link texture you see all over Roblox. Take a look:

Yet another great candidate for cutout rendering! Imagine how clean the edges of those wires would be.

Of course, I couldn’t forget Roblox’s very own Endorsed Model, which even appears in their own template places, the Stop Sign:

That diagonal would be so much cleaner with cutout rendering. It’d also be much more performant and less prone to sorting errors!

These are just a couple examples I picked from some top results in the Toolbox, and they demonstrate that cutout rendering isn’t just for niche use cases - Roblox places across the site would benefit from this addition by allowing developers and builders to better optimise their builds and reduce those sorting errors! (there’s a theme here :stuck_out_tongue:)

If those general use cases weren’t enough to convince you, there’s also some more niche use cases which could change the game, for certain kinds of genres, entirely.

Extreme speed ups in niche cases

Cutout rendering would solve one specific longtime problem with textures and parts, which could vastly improve the performance of games which use textures heavily. It’s easiest seen with a case study, so here’s my own game, Blox, which uses a pretty decent number of textures:

While it’s true that we could use materials instead, they’re highly inflexible. The aesthetic achieved above is unique to textures. The downside is there’s all these unnecessarily rendered parts underneath:

Those parts take up valuable triangles to render. Let’s do some calculations on a simplified world model to see an example of that. Assume we have a 128x128 flat plane of blocks with only their top textures showing. Accounting for backface culling, in the most common case, we’ll need 8 triangles in total to render each block; 6 for the 3 visible faces of the part and 2 for the single visible texture:

However, thanks to smart optimisations in the rendering scripts, those parts will never be visible unless you clip out of the playable area - so those parts don’t actually need to be rendered. Optimally, we would just render the 2 texture tris, but we’re unnecessarily rendering 6 extra tris for a part you’ll never see:

Multiply those numbers by the area of that flat plane, and you get the grand totals:

  • With parts rendered: ‭131,072‬ triangles
  • Without parts rendered: 32,768 triangles

Those small savings add up at scale. Keep in mind that this is the simplest case, though also for your consideration, most blocks in your typical Blox world only have a few faces visible, which amplifies this issue.

Usually the solution to this kind of situation would be setting the part’s transparency to 1, since fully transparent parts aren’t rendered. However, as we established earlier, this would cause the textures to move to the translucent rendering path, which gave my GPU render diarrhoea and caused my framerate to tank instantly, defeating the entire point of the optimisation. :frowning:

However, all hope is not lost! Cutout rendering is extremely useful here; if we set all the textures and mesh parts to use cutout rendering, they stay on the opaque render path, even when the parts are fully transparent! This means no GPU render diarrhoea, no framerate tanks, and no depth sorting issues :smile:

Of course, this is all just fantasy at the moment, since this just a feature request. One day!

Considerations

I’ve talked a lot about the implementation and benefits of cutout texture rendering so far. What needs to be considered when implementing this?

Firstly, the question of newer developers and newer builders. Will this feature be easy enough to learn, and how will we stop them misusing it?

I don’t think those will be really large problems. Especially thanks to the direct nature of Studio, where you can see your changes reflected in real time in the game world, I think this would be decently easy to grasp, especially if it was backed up with a decent wiki article walking them through it’s functionality. It’s also hard to misuse cutout rendering because in most cases it works absolutely fine - not many textures on Roblox depend heavily on alpha blending, it’s mostly present in the form of antialiasing. Plus, cutout rendering is designed to make your game run better, so it’s not like spamming them everywhere will kill your machine - quite the opposite.

Secondly, would this actually be possible to implement into the Roblox engine? I’m honestly not qualified to talk about this, since I don’t know nearly enough. If any engineers drop useful information, I’ll quote it here in the future, but it shouldn’t be too difficult to implement I’d imagine. The main roadblock I can see are the upcoming rendering system updates:

but even in that new system I wouldn’t expect it to be extremely hard, especially since it’s focused around materials and not textures. Another consideration might be antialiasing, which I’m again not an expert on, but I can’t imagine it being much of an issue. It’d probably be better if someone with real experience working with the Roblox rendering pipeline dropped in to say a few words.

Thirdly, would there be demand for this? Of course, if you support it, there’s a poll at the end, and feel free to reply! From what I’ve seen so far though, I can’t imagine many people being against the change. I say that because it’s a non-breaking update (unlike others such as FIB), and does have many genuinely useful use cases, especially for performance. It would leave places which don’t rely on textures pretty much completely unaffected, while places more dependent on them would be able to reap performance rewards all over the place.

Finally, is it just API bloat? I don’t think so. We’re already getting new properties aimed specifically at rendering optimisations and fidelity, such as the aptly-named RenderFidelity property we’re now seeing on mesh parts. As I pointed out earlier, we can find cutout rendering in use in modern titles and engines. Plus, cutout rendering isn’t something we can already do with scripting. It therefore seems unwise to me to dismiss the entire suggestion, and its possible performance benefits and improvements in visual fidelity.

Conclusion

Overall, I feel like there’s no reason to not consider adding cutout rendering as an option for textures, decals and mesh parts.

It’s cheap, it’s widely applicable, and can even make some textures look better (think back to that chain link example earlier). It runs fast, and it eliminates tons of sources of depth sorting errors. It could even open up new possibilities with textures, unlocked by the performance gains of the system, as I demonstrated with my own game, though this is still a fairly niche category of game.

Thanks to it being an optional, non-breaking feature, I feel like it would simply add another tool to the toolbox of developers which they can use to make their games run faster, which has always been important for platforms such as mobile, where resources are very limited. I even imagine mobile games (or games targeted at the lower end) could end up with more details by their builders leveraging the speedy cutout rendering to emulate smaller details without sacrificing performance or triangle count.

61 Likes

I’m all too familiar with depth sorting errors :frowning:

As a 3D artist and long-time developer on Roblox, I strongly support this feature. Custom materials coming down the pipeline are great, but it still leaves a large gap in models that require some degree of transparency in the texture. My other option shouldn’t be to individually model blades of grass :stuck_out_tongue:

As a Champion, I’m always trying to promote best practices in 3D design, but it can be difficult with common cases of “well usually you’d do X, but this is Roblox so it’s Y

Again, huge support!!

18 Likes

Yes I’ve run into issues like this as well. Now roblox is flooded with tons of models that take advantage of glitches in MeshPart transparency, and it would be hard for roblox to remove that now. If we can make the mesh fully transparent and the texture semi transparent, that would be absolutely fantastic for making leaves and trees and all that great stuff. I think that this is long overdue

2 Likes

I searched the forums for the phrase “cutout rendering” and zeuxg has commented on it before. The gist of it is that it would hurt mobile performance.

4 Likes

From the last post you quoted, for reference:

Additionally, enabling alpha cutout has a non-trivial performance cost on mobile platforms. We - intentionally! - do not change the render mode of specific objects based on the contents of the texture, so this would require an additional property for the MeshPart to explicitly enable this mode for meshes that need it.

Something that I’d like clarified is whether the performance impact is due to the proposed auto-detection of alpha transparency mode or the cutout rendering itself.

For what my speculation is worth, I suspect that zeux was actually referring to the process of automatically selecting a transparency mode - which I’d like to clarify I’m not suggesting in this feature request. The automatic selection of a transparency mode would likely cause other frustrations other than performance, anyways, and I can see where the performance overhead comes in with auto-selection.

I can’t imagine that the actual cutout rendering would be costly if the automatic selection was removed - after all, as many people have correctly pointed out in those other feature request threads, there are heaps of examples of cutout rendering being applied in lower end scenarios.

Most notably, the feature is present in ancient game engines which were designed to run on potatoes (by current standards). The mobile devices we have today would almost certainly run any of those older game engines smoothly, given those engines run smoothly for the high-end computers of their days.

Of course, I could be wrong! I’m open to that possibility - but I think we really need some clarification about what exactly the performance killer would be.

I’m willing to drop some of the extra parts of this feature request w.r.t mesh parts if they’re deemed too expensive to render on lower end devices (specifically the Translucent option), but as long as the cutout rendering isn’t that expensive, I still don’t see any reason why it shouldn’t be implemented :slightly_smiling_face:

1 Like

Returning to this feature request as I needed it again today - this mesh, which would sort correctly using a cutout rendering system, is completely broken and unusable at the moment:

For reference, here’s how it should look (taken in Blender):

Since the only way to get transparency with mesh textures is by making the mesh translucent, it’s impossible to avoid depth sorting errors.

2 Likes

But why are there so many individual meshes in that single model? Do you plan on making in crumble or something? Otherwise, there is no reason not to combine it all into a single mesh and delete the internal faces.