Jump to content
  • Advertisement
  • entries
  • comments
  • views

Updating the Noise Library

Sign in to follow this  


In light of the last post about seamless mappings of noise functions, I've begun yet another re-vamp of the noise library aspect of the Accidental Engine.

The new reorganization formalizes a few conventions that have slowly evolved as I've used the thing over the last couple years. I've imposed a few divisions based on the way I use it. The library has always been a sort of modular system, inspired by my early days of using libnoise. Generators, combiners, modifiers, etc... all exist as "pluggable" modules that can be attached together in chains or trees of arbitrary complexity, with the end result being a possibly complex noise function. I've continued with that paradigm in the new revision, with some enhancements. I'm working toward constructing a visual, GUI-based tool somewhat like MapZone, that can construct definitions files that my various games and projects using the library can load in order to recreate the module chain.

Here is the way the New Order works.

I have split the library into 4 divisions or categories of modules based on function:

1) Implicit modules
-- Based on standard noise functions, the Implicit modules generate or act upon a set of Perlin noise generators and modifiers. These modules operate in N-dimenstional spaces, and are "accessed" via one of three "get" functions: a 2D version of "get", a 4D version, and a 6D version. The modules encapsulate 2D, 4D and 6D versions of the basis functions upon which they operate, which include: Value noise (values specified at integer boundaries), Gradient noise (Perlin's original gradient noise), Simplex noise (Perlin's improved gradient noise), Cellular (Cellular function of 4 terms; god-awful slow in 6 dimensions; like, you can't even imagine), White noise, Constant (sometimes you need a module source with a constant output). I've got a few others in the works, mostly port-overs of some of my old pattern generators. Also included are turbulence modules, fractal combiners, select/blend operations, etc... These Implicit modules form the guts of the noise generation for the library.

2) Greyscale Map Modules
-- These modules operate on explicit 2D buffers of greyscale (range -1 to 1) data. Patterns are supported (wave generators, fuzzy disks, bars, lines, grids, checkers, etc... quite a lot, actually) as well as combiners (Add to sum an arbitrary list of sources, Mult, Average, Min, Max, FractalCombine (versions of Perlin fractals for 2D maps), etc... I repeat a lot of functionality that is included in the Implicit space. Sometimes you get the results you need by performing turbulence in Implicit space, other times you need it performed in explicit space.

3) RGBA Map Modules
-- These modules operate on explicit buffers of RGBA(color) data. Supported are operations to mix using various methods (mostly modeled on the mixing operations supported by the Gimp: Soft Light, Hard Light, etc...)

4) Output module
-- Only one module in this space, it operates as the final root node of any module chain/tree, providing the interface by which the user interacts with the output data.

The Greyscale space includes an Adapter that interfaces with an Implicit module. This adapter performs the mapping of an arbitrary Implicit function chain to an explicit buffer of data. Controls are provided to specify how the function is to be mapped. Part of the functionality of this adapter class is to specify the seamless mapping of implicit noise. Buffers can seamlessly loop in the X axis, or the Y axis, or both. They can also be mapped so that the buffer is part of a "chain" of mappings that loops seamlessly in the "Z" direction as well; ie, by changing the current MapZ value and evaluating the function, a succession of animated-over-time seamlessly looping frames can be generated. The choice of mapping determines the dimensionality of the underlying implicit functions.

If no seamlessness is specified in the adapter, then the 2D versions of the underlying implicit functions are called. If X,Y or X AND Y seamless mapping is called for, the 4D versions are called. If X,Y AND Z is called for, the 6D versions are called.

The RGBA space contains a handful of Adapters that accept Greyscale modules as input, mapping the inputs to RGBA values. Included is an adapter to convert 4 separate Greyscale sources to the R,G,B and A channels of color, an adapter to convert a single Greyscale source to a greyscale color output (shades of grey based on input value), an adapter to convert 3 channels of Greyscale to H,S,V plus another for alpha, an adapter to convert a single Greyscale source to a color channel by mapping it to a color curve, and so forth. I'm also experimenting with other color spaces such as XYZ, CIELAB, etc...

In previous iterations of the library, I frequently fell back to a pattern of building a module chain to work out a couple noise functions, mapping them explicitly to buffers, then doing a lot of various work by hand on the buffers: bump-map creation, blurring, blending, color-mapping, etc... So the formalization of a module chain to perform these tasks has eliminated a lot of grunt work and error-prone detail work from many of my texture chains.

A typical workflow of a texture chain works like this:

Various Implicit modules are set up to provide the basic Perlin noise for the texture.

Adapters are connected to the Implicit module root nodes to map the implicit functions to 2D buffers.

Operations are performed on these mapped adapters: bump-maps calculated, values mapped to curves, combined with 2D generated patterns, turbulence applied, blurring, etc... lots of options here.

Adapters are hooked up to the Greyscale buffers to convert the greyscale maps to color maps. Mapping to color scales, combining alpha channels, multiplying by bump maps to provide shading detail, Taking the gradient and calculating a normal map, and so forth.

The final mixing RGBA module is hooked into the input of the Output Module which can be used to specify the final output: resolution (size of the 2D buffers), color output (RGB, RGBA, RGBA Premultiplied Alpha), and destination (provided color buffer, save to file, etc...)

The whole thing, of course, is hooked into a Lua interface to make serializing/deserializing and quick prototyping of module sets easier.

The revamp is still underway, as I have yet to port over a bunch of my existing 2D pattern functions. One current problem area for me lies with my implementation of 6D simplex noise, as I am currently having trouble calculating the weighting factors per vertex properly. I may have to revisit the entire algorithm. Unfortunately, online resources for simplex noise greater than 4 dimensions are almost non-existent. I found an implementation in Python, from which I derived my weighting factor calculations; for 4D or less, the calculations work correctly, but for 6D the weighting is incorrect, resulting in artifacts. I've attempted to derive the weighting factor empirically by modifying a constant and checking the output many times in succession, with no success. I can achieve results that look good in one usage but look bad in another; missing is the "consistency" of results characteristic of lower dimensional forms of simplex noise.

For now, I get by with defaulting to gradient noise; however, this has computational consequences when doing animated-over-time maps such as waves or flowing lava, as the number of linear interpolations performed to evaluate a 6D gradient function are enormous. Multiply that complexity by 10 or more octaves of a fractal function, and bleh. Animated over time maps are SLOW. I made the mistake the other day of trying to evaluate a 10-octave cellular-noise-based fractal at 2048x2048 resolution, animated over time. My hell. Took, like, 30 mins.

Another problem, as illustrated by the previous scenario, is my slow-ass cellular function. For sanity's sake, I provided a 2D version of the cellular function that operates in Greyscale module space; "most" applications can get by with this one. Because you do NOT want to try to get anything done with cellular noise on the animated-over-time 6 dimensional space.

Anyway, that's what I'm working on, besides tinkering with various RPG game stuffs and playing around with Ogre. One of these days I'll finish the library and make it available for public consumption. Might not be for awhile, though.

Sign in to follow this  


Recommended Comments

There are no comments to display.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!