Home Artists Posts Import Register

Content

Prior to last week our engine had no support for heightmaps, which meant the terrain in yesterday's video was rendered using a slow, naive approach. I spent the next 5 days optimising heightmaps, trying new tree models and battling my arch enemy: shadows.

Day One - Heightmap Optimisation

I spent the day pushing OpenGL to its limits to get heightmaps rendering as fast as possible. One thing I learned from SE is that less data means faster rendering, so I packed and optimised heightmap data so that it now uses 3x less vertices and 2x less memory per triangle. This increased rendering speed by ~4x.

As always this optimisation process went smoothly, producing beautiful terrain like this.

Unfortunately this style of terrain had a few holes in it, so I tried another approach, similar to how SE renders voxels.

This approach rendered terrain incredibly quickly but was only capable of rendering the same mesh over and over again.

I fell back to Plan B, which involved using an OpenGL function I hadn't used before. After a bit of experimentation I found it was able to render the entire visible terrain in one command! This means the CPU time required to render the entire terrain is near-instant. Modern OpenGL is my best friend.

Rocks and Grass

The next step was to optimise rock and grass rendering by switching to a method called Instanced Rendering, which is where one base model is rendered in multiple different positions. This is the same method used to render thousands of particles in Sector's Edge, so I adapted that particle code to render rocks and grass.

At first the grass was nowhere to be seen, and after much debugging and confusion I noticed they were in the sky.

Trees

The final step was to switch trees over to Instanced Rendering as well. This worked great for the tree trunks, but the leaves were nowhere to be seen.

Yep, they were in the sky.

We now have a nice, simple little scene!

Day Two - Visual Changes

I wasn't a fan of the cubes, so I used the same heightmap mesh to create rounded rocks and tree trunks.

I'm not a fan of the look, but I made a new shader that cuts out parts of the leaf planes.

Days Three to Five - Shadows

On day three I decided it was time to pull the shadow code apart and implement it properly. Shadow rendering in Sector's Edge works, but it's very slow and can be improved in many areas.

After reading through articles, papers and example shadow rendering projects, I felt I understood how shadows were meant to work. I set up a basic scene with four rocks and started again from the beginning.

In this approach, the scene is rendered from the point-of-view of the sun. The distance from each pixel to the sun is then stored in a texture, where darker values represent smaller distances:

When rendering the scene from our point-of-view, we use this texture to check if the sun can see what we can see. For example we can see the ground underneath a tree, but the sun can't, therefore that part of the ground should be in shadow.

This is a very simplified explanation and glosses over a lot of the details, but I don't fully understand it enough to put it into my own words. Rendering shadows is difficult!

Over the next few days I faced issues with flickering, pixelation and all sorts of shadow rendering artifacts. Some things clicked and made sense, but some things just weren't working.

By this point shadows were far from perfect, but they were rendering ~2x faster than before and were capable of rendering over much larger distances.

I placed a sun in the sky to help see which way the shadows were meant to be facing. On the right side of the picture below you can see some nice bumpy lighting.

A debugging technique that was very helpful was to paint the entire scene red, making it much easier to see which parts of the terrain were in shadow:

Day Four - World Generation

By this stage I was fed up with shadows and decided to experiment with larger terrain generation and biomes. As heightmap rendering was much faster than before, I could experiment with larger render distances.

Can't have water without beaches!

Try adding mountains:

Successfully add mountains:

Add some snow:

Even more snow!

Day Five - Trees

I discovered a Blender extension called Sapling, which generates trees like this:

By using the same export/import scripts I wrote for SE - having our own engine is awesome - I was able to quickly put this tree in game.

These look 10x better than my dodgy square trees:

To reduce monotony I gave each tree a randomised size, rotation and colour:

After experimenting with colours some more, I took my favourite screenshot so far:

I didn't expect this post to be so long! I was addicted to these rendering experiments, waking up early and working late into the night. Fun times for sure, I am loving working on something new.

Thank you for reading, see you tomorrow in the next post!

Files

Comments

Anonymous

I know there's a lot you left out but I thought the part you described regarding how the player's POV calculates whether an area is in a shadow or not was interesting. The picture where the shadows are dancing across the Cliffside on the right is my favorite

Anonymous

It's amazing to see how flexible your engine is and how fast you've made this much progress, it's looking awesome!