Node Graph UI for Accidental Noise Library

Published October 09, 2017
Advertisement

So the last couple days I've been working on something that I've wanted to do for a long time now.

E3Wnvvp.png

I've been building it as part of a terrain editor I've been working on. It's still mostly uncomplete, but so far you can create nodes, drag links to link/unlink them, then output them to a greyscale image. In the works, I've got a few node types to implement, and a lot of glue code to implement saving/loading node graphs, hooking them up to generate terrain and terrain layer weights, etc... But it's coming along pretty nicely.

In the process, I have made a few fixes and additions to the noise library, to help with matters. One of the main additions is the Fractal node. The library, of course, has had fractals since the beginning, but the way they were implemented made it tough to allow them in the node graph editor. So instead, I implemented a special function type that can take as input a chain of functions for the layer noise, as well as other functions to provide the fractal parameters. Internally, the function will iterate over the number of octaves, and calculate the noise value. At each octave, the layer function chain is re-seeded with a new seed. This travels the function graph, and sets a new seed for any values of Seed type in the chain. This small change has opened up some easier ways of making fractals.

Additionally, I have added a Seeder module, which implements this internal re-seeding operation. I have implemented also a Randomize module. The randomize module takes a seed or seed chain, and uses it to randomize an output value from within a range.

It's kinda weird to talk about, so instead I'll demonstrate using a real-world solution to a common problem. Here is a fractal image of ridged noise:

nZYkXO3.png

This fractal is generated by layering successive layers, where the input is a Value noise basis passed through an Abs operation before being summed with previous layers. It creates the Ridged Multifractal variant, but you can see in that image that there are grid-based artifacts. These kinds of artifacts are common; each layer of noise is generated on a grid, and so the artifacts tend to sort of amplify as the fractal is built. You can mitigate it somewhat using different values for lacunarity (which is the value that scales the frequency for each successive layer) but that can only slightly reduce the visible appearance of artifacts, not eliminate them altogether. A long time ago, I advocated for applying a randomized axial rotation to each layer of noise, rotating the noise function around a specifiable axis in order to un-align the individual grid bases, and prevent the grid biases from amplifying one another. Previously, these rotations were built directly into the fractals, but that is no longer necessary. The new Randomizer and Fractal nodes now make this easy to incorporate in a more flexible way (or eliminate, if you really want artifacts):

49DwnX2.png

In this screenshot, you can see that I have set up a fractal node, and for the layer source I specify a gradient basis fed through an Abs function. That function in turn feeds a RotateDomain node, which feeds the layer input of the fractal. Attached to the angle input on the fractal is a Randomize node, that randomizes a value in the range 0 to 3. The result is this:

fbnNdcT.png

You can see that the grid artifacts are gone. The fractal iterates the layers, and at each layer it re-seeds the Layer input chain. This means that any node marked as a seed is re-set to a new value each time. This means that the Gradient basis node (which has a seed) is re-seeded, and the Randomize node that specifies the rotation angle is re-seeded. This means that each noise layer generates a different pattern than the other layers, and is rotated by a different amount around the Z axis. This misaligns the grid biases, preventing them from amplifying each other, and gives a nice non-artifacty fractal pattern.

I still have quite a bit to do in implementing the rest of the noise functions in ANL. But there you go, that's what I'm working on right now.

8 likes 7 comments

Comments

Servant of the Lord

That's very neat!

What do all those arrows and buttons on the Output node do?

October 10, 2017 05:39 PM
Servant of the Lord

It seems like for some formulas, the number of nodes might explode dramatically.

Have you considered a node where you can execute a single line of math, similar to Excel's cell formulas?

If you already have scripting in your engine, you could leverage the same scripting backend.

bc3aa9160b.png 

(Note: the math in the box is dumb and meaningless)

October 10, 2017 05:45 PM
JTippetts

I actually have considered it, yeah. As soon as I've got the existing stuff all wired up, I'll probably work on it. The functionality is mostly there, to parse out a string expression, so I don't think it'll be too troublesome.

As for the arrows and buttons on the output box... those are the first 64x64 block of pixels in the UI texture. I stuck a 64x64 BorderImage widget in there, with the idea that eventually it'll show a preview image of the noise module that automatically updates, and when you create a BorderImage in the Urho3D editor, it automatically assigns the UI texture. I'll change that soon.

October 10, 2017 07:10 PM
JTippetts

So, I decided I'd go ahead and implement the expression node now:

ZoRiPgz.png

It works pretty well. :D

October 10, 2017 07:30 PM
Servant of the Lord

That output window is incredible.

October 10, 2017 10:21 PM
Krohm

Wow! Everything is better with node graphs!

October 11, 2017 07:59 AM
noizex

One of really few usages where such visual graph node approach really shines for people who can actually write code instead of connecting nodes. Great job !

October 18, 2017 10:14 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement