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:
We’re going to composite that texture over this background:
Using normal alpha blending, we get this nice fade, as expected:
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:
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:
And here it is with cutout rendering:
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):
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 )
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.
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
Of course, this is all just fantasy at the moment, since this just a feature request. One day!
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.
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.