Cell-Based Rendering System

Continuing the discussion from How big can a game get before i start to have problems?:

I just read that thread and saw the dreaded “I went too far from the spawn and the rendering started getting funky” issue pop up again. This is disappointing because the problem is a serious bane to any large-scale game. My understanding of the bug is that it’s caused by loss of precision when position values get really big. Skyrim has a really big exterior world, but it never exhibits a similar problem – this is becasue the world is divided into cells. IIRC, Skyrim’s world is 128x128 cells (-64 to 64 on each axis), positions are relative to the cell, and each cell has a limited size to prevent positions from getting big enough to be unmanageable. I’m guessing to do the rendering, Skyrim renders stuff based on the center point of the cell instead of the origin of the entire world. It makes sense that Cell,Position = <64,64>,<5000,5000,5000> is easier to manage than <20.48 mil, 20.48 mil, 20.48 mil>. Could this be a solution ROBLOX could put into effect?

I imagine there might be some issues making it a seamless transition i.e. what do we display in the properties window? What do we do when you set a part’s position to something large enough that it’d be in another cell?, so it might have to be an opt-in change like PGS, or ROBLOX could just cleverly adapt existing usage to the new system (i.e. add an internal check to setting something’s position/cframe to swap cells if it goes beyond the bound of the current cell, etc)

6 Likes

My opinion on this is that models should have their own origin rather than predefined cells. Anything inside that model is not positioned relative to the world but relative to the models origin. Of course a new instance container might be worthwhile for this but I can definitely see many benefits to it.

1 Like

Just having descendants of a model be rendered relative to the top model’s CFrame might help.
Maybe all parts will be rendered 2 studs off at (100M,50,100M), but at least it looks right.
(Well, if the characters also get rendered 2 studs off, else it would look very weird)
Maybe pick a nearby position for the camera and (just for rendering interally) convert world space to local space?
That would make characters also be off but in sync with everything around them.

idk, I’m not someone that knows too much about rendering

There’s nothing preventing model origins from being at super large positions in that case. Relative positions might be fine, but as einsteinK mentioned, you’ll have things studs out of place.

I’m wondering how many games this would benefit and in what magnitude, when weighing it against the de-optimization and re-optimization efforts needed and performance deficiencies overall for all games (since you’re making rendering more complex). For relative positions also, because instead of having 1 CFrame value you’d need to perform several more matrix transforms before you can do your draw call for each part. (If we’re going to combine the transforms, we end up at the exact same inaccuracy problems that we wanted to avoid)

Matrix transformations? Performance decreases?

I’m imagining the current rendering system is just drawing everything in relativity to <0,0,0>

The cell-based rendering would only change that to:

local cellOrigins = {{0,0},{5000,5000},{-5000,5000},{-5000,-5000},{5000,-5000}} (just a 2D array)
drawPartInRelativityTo(cellOrigins[cellX][cellY])

which would hardly affect performance. There wouldn’t be any inaccuracy issues because positions are constrained to values that are manageable. Of course, I know nothing about the rendering system – none of us do – so we’ll need an engineer to confirm how much something like this truly would affect performance.

I talked about both ideas. In the first idea that you mention in OP, the rendering would have to take into account where each part is and would have to draw parts for each cell. You can imagine this is less straightforward then when you have a single origin and all parts just have a position. The code is more complex and you have to take into account that updating the cell-part relations takes time too.

For the second idea (relative positions), underlying thought: whenever you want to draw something at a certain position, you first issue a transform to set the draw position at wherever you want to draw and the right rotation. Then you actually draw the thing with a draw call.
If I have a model which is 4 layers deep into Workspace, I would have to do 4 transforms before I can draw the nested model. Obviously that can be optimized since you can draw all children of a model at the same time, but you’re still doing more transforms overall than if you just had 1 per part.

TLDR; Overall both methods will have performance impacts. That’s not necessarily a bad thing if it’s necessary or useful, but I was just wondering if it is actually worth it since most games do not really put parts at far-away positions.

edit: I’m reading this over again and I’m thinking that you’ll also need to modify physics and other aspects of the game, otherwise it’s not going to work out for moving parts, and you’ll need to have the user fill every position out using cell coordinates as well. So no this won’t work like this :S

First, haven’t read all of the replies, so sorry if this is addressed.

Skyrim, even on High End Gaming Beasts, has loading screens. For a game like ROBLOX, that could kill the gameplay.

Loading screens are not related to cells. They exist to squeeze out extra performance when it’s safe to unload unnecessary areas, but aren’t required. The exterior cells of Skyrim can be walked from one end to the other without a single loading screen.

2 Likes

Cells, chunks, etc. only work well if you have tons of static objects, let alone the very notion of a static object exists.

Also, rendering would be the least complicated part in such a transition.

3 Likes

This is not really solved, because the problem has no easy solution. But we actually did discuss the problem of faraway precision quite a few times.

Just to illustrate, the easiest approach would probably be “oh well, let’s switch to doubles everywhere”. This helped a few games out there, like LockOn: Modern Air Combat. For roblox however, this approach has an implication that physics suddenly becomes at least 2x slower.

Another approach is to subdivide the world into physics cells with each cell having its own “physics world”, relative to a local pivot. This is what Space Engineers appear to be doing, because they use Havok, which AFAIR just uses floats without any far-away provisions. This approach is fairly complex, as parts need to be transitioned between such “physics worlds”. Add clumps and constraints to the equation, add the already distributed nature of physics in Roblox - and you’re in a huge mess.

Space Engineers still have not completely solved the problem of seamless transitions - e.g. if you build a spacecraft with (unlocked) pistons, rotors, etc. and fly at max speed, you’ll notice your ship jerking a bit every time it transitions the world boundary.

2 Likes

What effect would this have on memory usage?

A double has double the precision of a float. It uses twice as many bits to accomplish that, 32 vs 64. So I can imagine memory usage would also increase significantly.