Thursday, July 21, 2016

ARC and what to do about it

Hello again,

Lately Linden Lab added a new feature to the SL viewer that would automatically simplify the rendering of all avatars which rendering cost is above a threshold that you set in your preferences. Every avatar above that threshold is rendered without its attachments, save for their rigged ones, and without any texture. Instead the look like gummy bears, or jelly dolls, or whatever the term is. Although the calculation of the rendering cost is rather old (5 years old at the time of this writing), it had always been purely informative. Now the viewer automatically acts upon the result of this calculation.

This is all good and well as it lightens the load on the rendering part of your viewer, meaning more FPS for you. Very useful in clubs, it helps trimming down the costly attachments that you might not be aware of, and motivates content creators to optimize their stuff (I'm talking about future products, of course, it is very difficult to optimize what has already been made and released since you must make the customers update, when at all possible).

The formula and invisible surfaces

Only, the formula used for the calculation gives alpha-blended textures a high weight. I understand the reasoning behind this, as alpha-blended textures (aka 32-bit textures, textures with a 8-bit alpha channel so they can be partly transparent, as opposed to 24-bit textures that can only be opaque) are very heavy on the rendering, and not only on the SL rendering engine. If you've played a game with explosions that are rendered with sprites of fire and smoke, your computer would likely slow down when you were close enough. This is because of a high number of partly transparent textures stacked upon each other, which makes the renderer suffer, even worse as they are close to your camera.

What I find weird is that completely invisible surfaces (i.e. surfaces which alpha is 0, or "Transparency 100" in the viewer, regardless of whether the actual texture is 24 or 32 bits) are also rendered. Why ? No clue. Why render what you can't see in the first place, right ? But it doesn't matter, the formula punishes invisible surfaces the same as partly transparent ones.

Now, I'm not saying that invisible surfaces should not be counted in the formula at all, because even if they are not rendered, they are still managed by the viewer every frame. It has to decompose the scene into objects, objects into prims, prims into surfaces, group surfaces into pools, and only then can it check whether a surface is invisible or not. The rendering is only a part of the computation cost of a surface. So to me invisible surfaces should be counted in the formula, but not as high as partly transparent ones.

This has a direct impact on some of my products like the Deluxe Straps and the Deluxe Gag. These are the two products with the most invisible surfaces, simply because they morph a lot (they are the products offering you the most customization). Their rendering cost, according to the formula, is rather high : individual attachments in this set are worth 34k average. This is not due to a poor design though, I have optimized the topology of the deluxe straps prior to release, knowing that there would be a LOT of straps. There could certainly be fewer triangles but not a lot fewer or the straps would look blocky. So why the high cost ? Because most surfaces are invisible, so they are taken as transparent surfaces, regardless of whether their textures are opaque or not.

But there is no reason to render these surfaces at all unless they are actually visible, right ? Yet they are rendered anyway and this makes people think those items are badly optimized because it sounds like there are many times more triangles to render than there really are. And it makes other people around you derender you automatically if their threshold is set too low. It is detrimental to my work in the long run.

I am not the only creator to be harmed by that formula. Any item that has options (for example weapons) have parts that hide and show themselves, most use transparency to do that, very few actually shrink prims and move them inside the bulk of the object. Some do, but it isn't always possible for technical and usability reasons.

So what to do about it ?

Update of my products

I mentioned a way to mitigate that in this post. In short, I said that I was thinking of a way to let the user detach the items that are not used in the current lock. For example, when you are locked in "Arms tight" in the Deluxe Straps, you do not need to actually wear the chest part, so this would let you remove it. Problem is, what if you got yourself locked in "Box" afterwards ? Well, you'd be able to re-attach the chest part after being locked, it would become visible and what's more, its textures would synchronize if the colors were changed in the meantime. And you'd be able to remove the upper arm part afterwards since it would not be locked anymore, always allowing you to wear only the required attachments but not necessarily the whole set all the time. This has the added benefit of sparing some attachment slots for you to use otherwise.

This works well now, after days of coding and testing, I have yet to release that update to all my products, it will take a few more days because there are a few other things to do first. The downside is that it will require full replacements, including the secondary items. I know it is a pain, and I'm afraid there is no way around that since the "slave" script of every single secondary item needs an update. And since they are no-mod and their names contain their parameters, I cannot not give away a template script for you to replace the old ones with. Of course that update will not be mandatory, it's just for convenience. Another downside is that this trick does not help the Deluxe Gag at all since it is in one piece. A third downside is that it doesn't help other creators, since it is an update to my products only.

I had been suggested to transform my "set alpha to 0 when unlocked" to "set texture to transparent and alpha blend mode to alpha mask when unlocked". While this is a good idea because fully alpha masked textures are not rendered (not even with "highlight invisible", which is also beyond me), this requires me to make a script that retains all the textures to set when the item is locked again. After giving it much thought, I decided not to do it, because it would make the products a lot more fragile. It would be very difficult to resit a reset, a relink or a texture change with such a feature. Possible, but very costly and error-prone, and would not allow you to customize with your own textures anymore (some people like to do that and I hope they continue).

Update of the RLV

I have just released a new version of the RLV that does not render invisible surfaces at all, i.e. surfaces which alpha is 0, or "transparency" is 100 in the viewer. Well, except when "highlight invisible" is active (that's Ctrl-Alt-T, to see invisible surfaces in red). Really, it is as simple as that. I have detailed the change here with a patch file that is very small, and to my knowledge, without any side-effects. I have run benchmarks and they do demonstrate that invisible surfaces are indeed not rendered. I have also tested that it doesn't interfere with the ability to touch such a surface. It makes sense not to render invisible surfaces anyway, because invisible surfaces on rigged mesh attachments are already not rendered and therefore do not have as high a weight in the ARC formula.

Please note that if a surface does not have its transparency set to 100 but bears a fully invisible texture (such as the "*Default transparent texture" one in the Library), it WILL be rendered even if you won't see it. The change only checks the alpha, not the actual data of the texture, it would be too slow and defeat the purpose. This makes sense, also, because such a texture may be useful when you want to render clear plastic. The texture itself is invisible but may shine in the light.

I understand what modifying this formula means though. There is at least one LSL function that uses it (llGetObjectDetails with OBJECT_RENDER_WEIGHT), so suddenly it would return different results... So if LL decided to make that change to the formula, they would have to modify the viewer and possibly the sim software at the same time, after thinking hard about the consequences on the values fed to the scripts. I have also no idea how much lighter invisible surfaces are on the viewer when you include my modification, all I have is some FPS benchmarks which are a bit extreme (more than 100 surfaces stacked upon each other, you don't see that in public places unless someone wants to grief you). Which means tests have to be made and it takes time and money.

Of course, I will be the first to admit that the modification I made is pretty basic, if LL decided to implement this change they would certainly not do it the same way. But they know the rendering engine well, I don't. I know other parts but the rendering engine is like black magic to me. I didn't really pay much attention during my OpenGL classes, I admit.

So, to recapitulate :

- My whole RealRestraint line of products will get a full update in the near future. This update won't be mandatory (no update is), but if you want the ability to lower the number of attachments in a set, and by extension your rendering cost, this is the way to go. The update is not available yet, I will send a notice and write a blog post when it is.

- The RLV no longer renders invisible surfaces unless you highlight them. It may increase your FPS a little, depending on the amount of invisible surfaces around you. Frankly, I did not see a difference unless I had a hundred surfaces stacked upon each other, but I'm pretty sure it will help in clubs. Unlike my products, the update of the RLV is available already so have at it (you can download it here).

Have fun !