View-aligned voronoi islands (for infinite forests, Eevee and Cycles)

A while back I posted an update about my Tenochtitlan project:
tmp

I’m showing the way I am generating a procedural infinite forest in a shader.
The underlying concept is what I’m calling view-aligned islands. Essentially,
I’m generating little UV islands which always look at the camera, but also stay anchored in their centers.

tmp

Let’s Begin

It starts with a voronoi node. This creates the cells as a basis for the islands.
A vector pointing towards the center of each island is created using this Vector Transform trick:

The node transforms (0,0,0) from camera space into world space, which gives me the position of the camera in the world.

Using a couple of cross products, I can create two important vectors:

  • One pointing to the right as seen from the camera
  • One pointing up, but along the camera’s plane

Note the first cross product with (0,0,1); this determines the up direction of the trees.

Next, we can use dot products to create two UV coordinates: One based on the actual world position, the other on the center of each voronoi island:

This is ok as is, but we need to correct a perspective mistake.
First, we divide both UV coordinates based on the original camera vector lengths:

Then, we scale it back up based just on the voronoi island camera vector length:

Result of step 1:

And we’re done here! Now we have little UV islands that face the camera:


We can use this coordinate to sample a texture:

Blending the borders:

If you find the harsh island borders off-putting, we can use a white noise texture to “blur” the borders.

This jitters each sample by a little bit, and when multiple render samples, the result should be a blur:

Looks great in Cycles, not so much in Eevee:

The borders are all mushy and grey. This is the result of mip-mapping. The noisy offsets trick Eevee into thinking the texture is very far away. Choose “smart” texture filtering, and the problem goes away:

Wrapping up:

So, these are view-aligned voronoi islands.

For my trees, I generated one big texture with trees, in various passes, like this:


Based on the desired tree density at any point I shift the UV a bit to the right.
I also have a random-per-tree texture, which I use to randomly colour my trees.

Additional tips:

The voronoi node has a “color” output, which returns a random color per island.
This is in turn 3 random values, in R G B.
You can use these values to randomly rotate, shift, and scale each island.

Combine this random color with a random color per tree to break up the tiling of the tree texture.

If you generate a normalmap from your trees, you can use the generated vector to construct a worldspace normal map. This helps with lighting.

Pro’s and Con’s

The cool thing about this is that the render cost is flat - the same for every pixel, not matter the size of your forest. This also means that iteration is super fast, much faster than using something like individual trees or even billboards.

The downside of course is that it is a hack; There’s no acutal volume, no correct shadows, no silhouetting.

.BLEND

Have fun and try for yourself:
ViewAlignedVoronoiIslands.blend (1.1 MB)

50 Likes

absolutely brilliant and much appreciated! :slight_smile: - I’ve been struggling to populate some vast Oregon forest scenes with infinite forests and this will help me immensely - your explanation has also clarified my understanding of vectors - thanks! - you are hereby added to the Thanks To list in the movie’s credits - movie’s called The Migrant, possibly released in late 2023 - all the best, Stephen Norrington

3 Likes

You really went above and beyond, this is better than some paid tutorials. Thank you!

2 Likes

Thank you so much for sharing and developing this technique. I’ve been struggling with ways to create large-scale environments. This will be a huge help!

This is very interesting. Thank you for posting.

This is a very cool technique. Thank you for sharing this.

While playing around, I added in some angle based effects, so forests seen at a glancing angle are more vertical, and looking down on them from above look more like an aerial view:

Thanks again @ThomasKole , there’s some powerful vector magic in there that is really cool.

8 Likes

Wow, looks great!

1 Like

I’d love to see the details on how you did this :slight_smile:

2 Likes

For my source image, I used the same density gradient effect that @ThomasKole was showing along the x axis, but I added an “angle” gradient on the y axis:

so the trees at the top of the image are seen from the side, and the ones at the bottom are seen from the top

Then I used the incoming normal to get the apparent angle of the surface as viewed from the camera:


I then used that as a factor to displace the uvmapping per voronoi cell on the Y axis, plus some randomness from the voronoi color

I used a noise node to generate density variations, and did the same displacement with some randomness on the X axis.

Since I rendered my scattered tree image as a transparent .png, I composited in a couple ground textures, influenced by the density noise texture

Here is my file, with textures reduced for upload:
ViewAlignedVoronoiIslands - aerial terrain rendering - CC-NC.blend (3.3 MB) (CC-NC license)

14 Likes

That is most informative. Ha, well over me head!
This is brilliant material to study. Thank you for your efforts.

I’ve been trying to break up the contours a bit with Geometry Nodes. I have this weird thing working…

6 Likes

Congratulations, really smart. Thanks for the deep explanation.