Modern Planet Rendering : Editor, Physics and Clouds

It’s been a few weeks since I last posted about this project, I tought I’d write a quick update to share some of the progress and difficulties I’ve had so far. One of the major challenge that quickly became apparent was how to edit a scene in a planet with such a large radius. When you think about it, you could add millions of object scattered around randomly on a planet and still have hard time locating even one, the scale is just that big. The usual solution to this is to procedurally place the objects as you are generating/moving around the planet, but I did not want to rely on procedural content when it comes to actual scene editing, this should really be done by an artist. Another restriction I had was that, in order to avoid precision artifacts, I need to draw the smaller objects using a camera from the center of the world (x, y, z), and then copy this camera and offset it (x, y + r, z) to draw the planet, kinda like a local coordinate system based on an offset vec3. And the final restriction was that you simply can’t iterate trough millions of objects in a standard container such as a standard vector.

Sector Paging System:

The first part of the solution was to use the concept of a sector to represent the root of a scene at an arbitrary offset point on the planet, this way all the camera offsetting stuff are abstracted away in this object. Now for the second part of the solution, I had already done some experiments with using a kdtree to handle large scene in the past and actually got some very decent results, the drawback was that doing a radius search based on the camera position every frame was brutal on the CPU. To fix this, I can now register a callback whenever a new tile is created during the culling traversal of the planet, when the tile level is equal to (max_level – 2), I use the bounding box of this new tile to get the center and perform a radius search around this point, this reduce the overhead to almost zero, even when having millions of sector indexed.

self.faces_[i] = root.Terrain(radius, max_level, i - 1)
 root.connect(self.faces_[i].on_page_in, function(tile)
 
     if tile.level == max_level - 2 then
         local deformed_center = tile.owner:get_face_matrix() * tile.owner:get_deformation():local_to_deformed(tile:get_center())
         self.active_sectors_ = {}
 
         local matches = self.sectors_point_cloud_:radius_search(deformed_center * self.sectors_point_cloud_scale_, 0.01) 
         for i = 1, table.getn(matches) do
             self.active_sectors_[i] = self.loaded_sectors_[matches[i]]
             self.active_sectors_[i]:page_in()
         end
     end
 end)

 

Editor:

To implement the editor, I simply added a new script that instantiate an editor object when allocated. When starting the framework, you can choose to define the scripting entry point, by default it’ll search for the file client.lua, but if you pass a script path in the arguments, it’ll start with this script instead. It’s then possible to load/reload/unload the client script from the editor to quickly drop in game and test things out. I used GWEN for the GUI and wrote a custom renderer based on a SpriteBatch, I also used fontstash for the text rendering. One of the neat features that GWEN offers is the ability to redraw the GUI only when it’s modified, this allows you to draw into a texture by using a framebuffer, drastically improving the performance. Since we now have two entry points, there’s some scripts that’ll be shared between the sub-applications, those are now located in the shared folder.

editor

Physics:

For now the physics are done on the client side since the network is not implemented yet, but it’ll eventually be cloned in a server sub-application in order to have a fully authoritative server. I’m using Bullet 2.85 built with the BT_USE_DOUBLE_PRECISION preprocessor. To create a tile collider, I again use the new tile callback described above, but this time I check for tiles with the max level, I then read back the height value from the GPU and use the planet’s deformation class to create a spherical btTriangleMesh. For the player I’m using a regular btKinematicCharacterController, but I’m planning on using a spring system to handle the slope better.

Clouds:

For the clouds, I ported kode80’s volumetric clouds to glsl and wrote the planet_clouds.h script object to implement it. The clouds are drawn during the post processing stage and are applied during the sky pass so that they can be properly blended with the atmosphere. I also blend the clouds coverage shadow with the sun shadow for even more realism. It’s a very heavy shader, so I had to downsample and reduce the number of iteration from 128 to 80 in order to keep a stable >120 FPS on my 970, so it can look much better if you have the right GPU.

clouds_hq

Conclusion:

There’s a lot I did not cover in this post, I spent a lot of time trying to get SSLR working but in the end I decided to drop it entirely, because let’s be honnest, the fact that you can only reflect what’s visible on the screen introduces way too much artifacts, and does not outweigh the visual gain. I really liked the idea of Cone Tracing in order to reduce the artifacts, but while it looks awesome in box-shaped area, it did not work really well with distance. I know that games such as the latest Doom uses SSLR combined with cubemaps (or maybe environment probes? not sure) as a fallback, but I think it only really works in more enclosed space where it’s possible to use technique such as parallax corrected cubemap. The next available option is to render the scene flipped on a plane, but the way I render a planet makes this really hard to achieve. I also did some work to allow script and shader dynamic hot-swapping, this’ll be very useful because the next step is proper BRDF.

3 thoughts on “Modern Planet Rendering : Editor, Physics and Clouds

  1. Pingback: Modern Planet Rendering : Reflections, Object Picking and Serialization | hiredk's blog

  2. Mila Anne LE ROY

    Oh, the clouds are definitely my favorite!!! On my side… working to implement a Bullet physics camera, bumping in objects and walls. Did you use a combination of rigid body for the collisions and raycast for the height? Or you used the btKinematicCharacterController? Would you mind sharing some of your code to put us on the track? Thank you!

    Like

    Reply
    1. HiredK Post author

      Thanks for the feedback! As you guessed it, I’m using the z-aligned btKinematicCharacterController capsule controller, it does the job pretty well but there’s still room for improvement. One way to improve it would be to add a spring constraint coupled with a ray cast, this allows smoother behaviors when walking down a hill or when walking on stairs, I’m currently working on this. Right now my bullet implementation is pretty messy and undocumented, but if it can help you a bit, here’s the binding file. Good luck!

      Like

      Reply

Leave a comment