Simplex noise, experiments towards procedural generation

[EDIT April 9, 2013
http://hexara.com/SimplexBuilder.html
will post GitHub url here [/url]]
original post follows


Not sure where to post this. I’m selecting “Game Design” as it is related to designing graphics (possibly animated) using Procedural Noise techniques.

I can see where there are a LOT of texture editors already out there, as well as Perlin & Simplex noise source generators. This post is more about learning about ways to combine noise “channels”, to have a “hands on” way to see what happens if I poke something this way or that.

As a consequence, this is very much “In Progress” and the Applet is next to useless due to trying to cram too much on the screen. No way yet to save or load files or generate images. Can only dabble and see what happens.

I’m taking as my “base octave” the value of x/width, where x is the number of the pixel, and width is the number of pixels in the display area. This gives a progression from 0 to 1. I’ve seen others that use an equation that instead gives -1 to 1 for their “base octave”. To progress more quickly across the Simplex space, one multiplies the x value by a scaling factor.

I made a provision to put in arbitrary scalings factors, as well as translators (values added to the x * scale), and made a display TextField to show the resulting equation that I could use if I want to program the display results procedurally.

This screen shot is of a well known example of combining octaves where the colors span from blue to white. (It CAN to other colors.) The values are added together in a way that tapers geometrically. The result: standard fluffy clouds.

http://hexara.com/Images/Simplex4OctaveClouds.JPG

The return value from the Simplex function ranges from -1 to 1, so to use it with designating a color value, a transform is common. Very common is (val + 1)/2, which shifts and compresses the -1 to 1 results to 0 to 1. Another common way is to use an ABS function: “|val|”. This operation seems to result in a more threadlike quality to the noise. In the example below, I select “|val|” on the second Simplex channel and flip the colors (via “<>” button between the RGB fields) so that the thread color is White.

http://hexara.com/Images/Simplex4OctaveCloudsWithABS.JPG

As I said, I wanted to experiment with other ways to make textures, not necessarily at octaves. I allow ADD vs LERP in the way values are combined. With ADD there is a possibility of overflow & underflow. The “Prevent Overflow” puts in a MIN function to prevent the color value from exceeding 255. So there are some interesting clamping effects. The slider value with ADD is divided by 64, thus as long as the four channel volumes add up to less than 64, you are okay (unless you allow the “no transform” option and are sending in negative values, potentially causing underflow).

The program could use a way to Save & Load, and to generate jpgs or ani gifs (am thinking of putting some “rollers” on the translator sliders that continuously move). It could use a Color Picker and ways to automatically copy values from one channel to another or set octaves since they are so powerful a construct. It could use a much better use of space, maybe popping up the thing you are working on, while letting other aspects that don’t have the focus stay smaller.

I want to maybe allow other panels in with other texture sources, as well as a way to explore using the Simplex to generate a value along a custom gradient (such as are used with “earth” colors to make topo maps), or the classic cloud demo on Perlin’s lecture site. But I don’t think I really want to invest a lot of time making yet another texture builder app. As I said, my main goal was just to get some “hands on” with noise textures which this code allows to a limited extent.

Food for thought:

check box to ‘lock’ X and Y scale values to be the same.
rotation: currently by having different X and Y scale values you can get anisotropic (directional) results but only aligned to X or Y axis.
keeping single channel values until the end and the applying that to some look-up is very effective.

Cool

Thanks for this, I wondered how to get whispy effects for gas clouds in darkvoid as well as the plain gas clouds already in there. Now I can play and see how the values effect things quickly, might have to have a play with the background generation again :slight_smile:

Cheers

Endolf

When I went down the procedural texture route myself I learned a LOT by fooling around with Genetica

@Roquen – Good suggestions. Thank you. I got busy again, hope to get back to project soon, to add these and some other ideas.

@endolf – Yay!

@krasse – Will check out. Thanks for the link.

This is awesome … it’s almost like programming a synth patch :smiley:

@keldon – Maybe this is not surprising given how many hours I spent with the DX7 & FM7 (my FM synths, hardware & software)!

I programmed the ability to make a reference gradient, with 8 color points (7 RGB gradients between them). But I am realizing I totally messed up the way the channels are being added together. I’m taking each channel and getting a color, then adding or lerping the color values. But I think for this effect, one has to add the numbers together first, before doing a lookup on the color bar at the end of the process. :stuck_out_tongue:

Well, this is why it is a hands-on learning project. Hope to have the next iteration within a few days.

On the whole, mapping at the end seems to be the more useful thing to do (but I’ve very rusty at all this stuff). Also modulation would be handy.

I’ve gone ahead and posted some modifications, even though I didn’t address the main issue yet: mapping to the color bar once at the end, after summing the channels.

I did add a “lock” checkbox to keep X & Y at the same ratio when scaling. (Thank you, Roquen for the suggestion.)

Slider for scaling goes up to 128 now, instead of just 64. But you can enter higher numbers in the text field, or by locking the slider at an unbalanced ratio and pushing the lower slider up to the max. Kind of cool, the way threadlike things can appear at higher settings.

Added a tool for making color bars with gradients. Click on the gradient bar at the top of the channel and you get a panel of color bars to choose from for that channel. The popup panel matches the panel in the lower right corner.

Click on a color bar in the lower right corner, then you get the ability to edit that color bar. Click on the gradient bar at the top of the edit area to get a color chooser to add a gradient point at that location (up to 8 points or 7 gradients allowed). Or click on the color pad on the row of gradient points to bring up the color chooser. Field on left is location on the bar (from 0 to 255 – the bar is 256 pixels wide). Three fields on the right are R, G, B.

It is possible to make a gradient to match topo-map colors without too much trouble. I was able to recreate the one in the AngryOctapus http://www.angryoctopus.co.nz/?p=11 Simplex tutorial (that he made via GIMP and imported) pretty easily. But as I wrote earlier, the attempt to display this was a mess due to the way I’m mis-handling the channels.

Am still pondering how to do the GUI layout to allow EITHER the current form of merging channels, each mapped individually, vs. doing the more correct thing of adding the noise (or adding it to a sin function or gradient function) prior to the mapping at the end. Maybe I should just do it right and let go of the current method, but I really like some of the textures I’ve been able to build this way, and want to keep this as an option. (Would like to figure out how to place a couple more channels, too.)

Re: rotation – yes, an important point. I came across this problem with the Night Sky Procedural. I had to figure out how to rotate the BufferedImage created via the SimplexNoise (the “galactic cloud”). And, this problem led to the work on the image rotation tool I posted earlier. (Still want to go back and clean that up!) But I think as far as this little app is concerned, it is moot until the functionality of saving an actual graphic is added.

Another thing about rotation is that defects will show up based on the underlying structure (particularity if the hashing function is poor)…and most notably if you’re doing some turbulence (sums of |noise©|). And any easy way to correct this is to insure that the structures of the various octaves are not aligned via rotation (again…just more food for thought) (I just modified the hash function in my simplex noise example code partially for this reason).

[quote]…in my simplex noise example code…
[/quote]
@Roquen – I’m very curious about the example code you mention. Do you have a link to share? Did you make an app or tool of some sort? Are you using textures in your games?

I’m not entirely clear what is meant by “defects” and why they would be more apparent with rotation. Can you explain what you mean?

I’m happy to say that I got the proper “summation” noise effects working last night. Was able to get a pretty close repeat of the ‘planet surface’ example by AngryOctapus (cited earlier) and a night “twilight clouds” effect (gradient from a sort of rosy/salmon to grey to blue instead of white to blue).

But the app has gotten really laggy. I want to try and improve the response a bit before I post the latest version. Also, I want the new version to be able to do either method of combining textures and have some coding to do before that happens.[update posted 9/4/12]

This shows the correct use of summation for a twilight cloud effect. Summation of the four channels is done prior to consulting the color map.

http://hexara.com/Images/croppedSunsetClouds.JPG

The next image (NOT CORRECT) combines the same four Simplexes as the above, but does the math using the color values, and brings up intermediate colors, the purples.

http://hexara.com/Images/sunsetCloudsLERP.JPG

Another misadventure: trying to make an Earth Map, but blending AFTER color mapping rather than before. It just overlays the four “octaves”.

http://hexara.com/Images/earthGradient1stAttempt.JPG

Better, with maybe a better ColorMap, too:

http://hexara.com/Images/EarthMap.JPG

First step towards a plasma fireball? (Some shaping and masking with the alpha channel will be an important step. Maybe animation via translating on the z-axis, too.)

http://hexara.com/Images/fireballBallpark.JPG

Hey, if its “procedural,” it’s coding, not goofing off, right? right? ::slight_smile:

Notes on updates, 9/4/12.

I have a two stage mixer in the lower left, and I acknowledge the non-intuitive design. Will ponder how to improve it.

Main thing, if two channels use the same Color Map in the same way (ADD/LERP/SIN), then they will be merged into the same “second stage” mixing line.

Second stage rows can be added together or averaged together (lerped).

Of the first stage mixing options, I still haven’t implemented the LERP & SIN options. For best results, try to get all the tracks that share a 2nd stage row to have their 1st stages add up to 64. :stuck_out_tongue:

The sliders on the top channels have become very laggy. Am pondering what to do about it. I suggest typing in values rather than sliding to them.

GUI design is hard. :frowning:

WRT: My code - just the example 3D simplex noise I’d put up here. I’m not doing anything with this…it was just a first pass before converting to Cg or GLSL…which I never got around to.

The quality of the hash function will effect the quality of the random vectors. And even if the hash is really good the code you’re using will probably be using gradient noise style vectors like: (+/-X,0) , (0, +/Y), (+/-X,+/-Y)…so there are defects in the X, Y and along diagonals. These shouldn’t be apparent unless they start to compound, so having octaves that are rotated with respect to each other will help to insure that they don’t compound (as long has the rotations aren’t multiples of pi/4). Having said all of that, if you’re not seeing any defects…it just doesn’t matter.

Really cool work you done here Philfrei, keep it up! :slight_smile:

Thank you Sammyster!

I posted some more progress. The lagginess was largely due to a rookie mistake: drawing parameter values from widgets from within the inner loops instead of having the widgets update a “model” and getting the values from the model.

I have a “striping” function working, but with no parameters, and it needs tuning in several regards (and for me to understand it better). I also have X-Gradient and Y-Gradient versions working, so one can use the noise in a more 1D fashion. To use it, though, the best settings for the lowest amplitude settings one can manage, otherwise the Noise functions max out the display.

I’m going to try and make some popup panels that have a palette of some of the most common usages, with explanatory text and have them automatically set up the GUI to get the effect.

The ColorBar/Gradient editor has improved a bit with a “negative” and a “flip” function. Also, it is possible to make a copy of a colorbar now, too. I am starting to get annoyed with the way RGB interpolation looks. Every end point sticks out as a saturation peak, I think, which works against smooth color transitions. For example: going from bright red (255, 0, 0) to bright green (0, 255, 0) – the brightness and saturation drops precipitously for the intermediate yellow (128, 128, 0) when a bright yellow makes more sense (255, 255, 0) as the midpoint visually, it seems to me.

So, we’ve got HSBtoRGB and RGBtoHSB built in to Color methods–I plan to make an option to allow one to select one or the other when calculating the interpolations.

Also very much want to do a radial gradient (center out) and work in some “perspective” effects by allowing the amount of scaling to vary.

[Edited multiple times–I think I’m done now.]
Continuing to work on this. New version has been posted and can be linked or downloaded (see top of first post).

There is a button on the bottom of the tool that says “Tutorial”. Press it, and a menu of “basic textures” will come up. When you click on the graphic for the texture, it will load that texture into the tool. I will experiment to see if I can make the Tutorial screen not be modal.

I plan to add two to three more “basic usages” before calling this done and moving on to other things.

When you go into the tutorial, it gives you code that generates a BufferedImage that is the same as the graphic at the top of that page.

I thought putting the code first makes sense since this is written for Java coders. I try not to over-explain in the text but know I have a tendency to verbosity.

I guess my main goal here is to have something that is worthy of being linked to in our wiki section on Noise, as a demo of the basics of how to work with noise.

Pretty cool stuff!

I’m just starting to explore Perlin noise for my game. I was able to get a simple version working but I definitely see the need for decent visualization in order to get the results I really want. I was wondering what direction you wanted to take your current project.

Were you planning to open source it an any manner? Would you be interested in any kind of collaborative effort? I can offer interface improvements, testing on the Mac platform, and additions to the tutorial that would help other devs learning this stuff for the first time.

[quote]Pretty cool stuff!
[/quote]
;D

[quote]I’m just starting to explore Perlin noise for my game. I was able to get a simple version working but I definitely see the need for decent visualization in order to get the results I really want. I was wondering what direction you wanted to take your current project.

Were you planning to open source it an any manner?
[/quote]
That seems like a definite possibility. I would love to discuss it more. There is a whole lot that could be done and would need to be done to make this into a real tool that other devs could make serious use of. Having more people involved could make it happen. However, I have absolutely NO experience with open source, and would need to learn from you and others how to go about setting that up.

[quote]Would you be interested in any kind of collaborative effort? I can offer interface improvements, testing on the Mac platform, and additions to the tutorial that would help other devs learning this stuff for the first time.
[/quote]
Yes, I would be interested in collaboration. I would love to discuss this more with you.

Only of interest for runtime creation - for rings, I’ve never noticed any defects introduced by just doing:

noiseValue = noiseValue - (int)noiseValue;

I still don’t get this…
(int) noiseValue will always be 0, because the input ranges from -1 to 1 (so actually -0.9999999999 to 0.999999 or something like that (even if that is not the case, it would be very unlikely that 1 or -1 existed)).