Home Artists Posts Import Register
Join the new SimpleX Chat Group!

Content

Ever since playing Valheim I have been fascinated by how such a beautiful world can be created from low-poly models and pixelated textures.

When you look at it closely you can see the low-poly style, but as soon as you're immersed in the game you forget all about it. Achieving realistic rendering via immersion is more impressive to me than via expensive raytracing.

In this post I’ll attempt to recreate some aspects of Valheim’s rendering. It’s surprising how much detail goes into stylised low poly worlds.

Assets

I tried creating some low poly rocks in Blender but my patience soon wore out, so I searched for some free models online. I discovered Sketchfab and OpenGameArt and started making a scene, focusing purely on rendering since the assets were already created:


Clean Slate

I created a brand new project, starting with nothing but the engine and these assets. The first step was to import some models and apply textures to them. I created two shaders - one for 2D plants and one for models - and as usual it was highly broken:


I then fixed the house textures and applied a flowery grass texture to the ground.


Since the pixelated plant texture contains 64 different plants, I wanted to have different clumps of plants around the world.


This is way too crop-circle-like, so I reduced the amount of plants in each clump until I couldn't tell the clumps were circular.


I replaced the house with some rocks, and attempted enabling shadows at the same time. As expected, this produced a volcano.


Shadows

After much debugging, shadows were working again. This took a while even though the bulk of the work with shadows was already done a few months ago in this post. Shadows are still my enemy.


I'm using cascaded shadow maps, with some tricks like depth readback to increase the quality. It's far from perfect and I don't fully understand the maths, but it works great for a small scene like this.


I then rendered shadows for the plants, but forgot to apply the texture to the shadow shader. This broke the illusion and you can tell the plants are really just textured flat squares:


I fixed that and added some fog to the scene.


Floating Islands

I wasn't happy with the fog because it felt like it restricted the world. I instead modelled a basic flat-topped rock model and decided this world would be on a floating island in the sky:


I coloured the island and the rocks yellow and added some bright yellow lighting. Welcome to the wild west in the sky!


This felt a bit dry so I recoloured the island green and added some trees.


I didn't like having the rock as the centrepiece of the island, so I replaced it with rocks that are scattered around the island.


Clouds

The next step was to add some clouds, and rather than model them in Blender I created them in-game from a bunch of white cubes. Basic, but acceptable for this low poly style!


At this point I started to understand how Valheim's aesthetic is built from lots and lots of carefully crafted elements - terrain, rocks, vegetation, fog, dust, water, trees, sky, weather. etc. 


Feedback

I sent this scene to Poly Knight - a game dev and 3D artist - for feedback, and he said:

  • The scene only has direct specular light from the sun - no diffuse or ambient lighting
  • The pixelated foliage conflicts with the low poly models
  • The plants blend into the ground colour but the rocks and trees don't

He suggested lighting the scene from the skybox too, which was an awesome idea that I never considered. I also changed the sunlight to a more mellow colour. Here's before and after:


I then tried blending the trees and rocks into the ground, but it didn't match the low poly style:


Pixelated Noise

Instead, I applied pixelated noise over the entire scene. This runs in the fragment shader, and converts the world-space position to a random value between 0 and 1 using this funky random number generator I found:

But world positions are 3D and this function only takes in a 2D vector. I want the pixelation to apply over each surface in 2D space, so I needed a way to know which world space units to use: XZ, XY or YZ?

There's probably a much better way of doing this, but I used these three rules:

  • If the surface's Y normal is the largest - e.g. the surface is facing up or down - apply the pixelation over the X and Z world position
  • If the surface's X normal is the largest, use the Y and Z world position
  • If the surface's Z normal is the largest, use the X and Y world position

This noise darkens the models in a pixelated fashion, and I also used the Y position (altitude) to blend it to green when close to the ground.


I also used this pixelated noise to offset the surface's normal, so the lighting from the sun looks more interesting.


Lastly, I increased the reflectiveness of the rock and reduced it for the green moss.


These rocks feel rocky, is this Valheim now or what!


That's all for now, next I'd like to try:

  • adding a river with a funky water shader with refraction
  • ambient floating particles
  • animated low-poly animals
  • expand this out into an infinite world with non-flat terrain
  • place a player-controlled character in this world
  • player collision with the trees and rocks
  • recreate Valheim

I also animated the grass so it blows in the wind, check out the videos and high res screenshots on Dropbox.

Files

Comments

Anonymous

Would it be possible to get the source for this project? I'd like to follow along as the series continues (:

vercidium

Absolutely! I’ve been working on lighting and larger worlds recently and will share the source code soon. It’s fresh code though so it won’t be very clean!