Showing posts with label noise. Show all posts
Showing posts with label noise. Show all posts

Improving the 2D Noise page #

One of my goals for 2019 is to improve my existing pages. Yesterday I decided to work on my old 2D noise page. We normally use Perlin/Simplex noise to make terrain heightmaps, but on that page I used Fourier transforms instead. Perlin/Simplex noise are a fast approximation of the things you can get from Fourier transforms.

The 3D renderer on that page always bothered me. It was one of my early experiments with WebGL. I had never been able to figure out exactly what I didn't like or how to fix it.

I decided to improve the renderer.

Labels: ,

Mapgen4: elevation #

Last week I posted about mapgen4, the procedural map generation project I'm working on this summer. I had been trying to limit the scope of the project, and also shifting my thinking from maps for a game to maps that look pretty. I've been spending a lot of time optimizing and restructuring the code for this. It occurred to me that I'm approaching elevation all wrong.

Labels: , , ,

Notes on noise functions and map generation #

Over the summer I decided to study signal processing, with audio and music as potential applications. I should've realized that my brain would get back to maps somehow. I had been writing newbie-level notes for myself using emacs org-mode. Someone asked me about map generation, so I turned the signal processing notes into notes about map generation. Org-mode was really nice for writing notes. It let me mix notes and source code, and then I exported it all to HTML:

Notes on Noise Functions and Map Generation

Labels: , ,

Teleological vs. ontogenetic map generation #

Edit: The feedback from comments is that the names “teleological” and “ontogenetic” aren't good fits. I agree. There's an interpretation in which the terms work but there are also other ways to interpret them where it doesn't make sense. I had gotten the terms from the procedural content wiki, but in the future I'll avoid using these terms. I've changed the blog text to use “bottom up” and “top down”. Thanks for the feedback.

Long ago, I spent years working on the terrain generation for a game I worked on. I used earthquake faults, volcanoes, soil erosion, lava, river erosion, sediment deposition, water flow, weather simulation, vegetation (affected soil, which affected erosion), forest fires, floods, continental uplift, and other physical processes. This is the teleological approach bottom up approach to making maps.

To make good maps, I'd change parameters and run it to see if the maps looked good. I'd go back and change parameters again and again. Ideally I'd write a search/evolutionary algorithm that explored the parameter space. To do that I need to write code to determine whether a map will look to my eye, and I never did figure that out. I knew it when I saw it.

The other approach to map making is ontogenetic top down. Start with the structure you want to see, and make algorithms produce that directly and fill in the details. This is what I did with last year's simple map generation project. I had seen Perlin Noise, and thought, hm, that looks vaguely like a map — let's see how much work it takes to turn it into a map. Not much, it turns out!

For the past month I've been working on a new map generation project. I wanted island/continent maps with rivers, and Perlin Noise wasn't a good fit for that. I tried making random mountains come out of the ocean, and then using water flow algorithms to carve out rivers. I've been tweaking and testing, tweaking and testing, tweaking and testing, and finally realized that I'm back to using bottom up algorithms. It's incredibly addictive. It feels right: erosion, mountains, gravity, and all the other “realistic” things that form terrain.

Example island produced by map generator Example island's drainage vectors

The trouble is that I really don't need all of that. I'm working on 2D Flash games, and I don't need terrain; I need maps. It doesn't need to be completely realistic. It just has to be interesting. So I'm stepping back a bit and switching back to the top-down approach. I'm drawing some maps that I like, and then I'll find algorithms that generate maps like those, instead of modeling physical processes that produce realistic terrain. I think this will lead to better maps with less work.

Update: [2010-09-04] See my newer blog post to see the beginning of the new map generation project.

Labels: , ,

Noise in game art #

If you look at the artwork in old 2D 8-bit games, you see a lot of noise and dithering in the hand-drawn bitmap art. For an example, take a look at the grass or concrete in this Transport Tycoon screenshot:

Transport Tycoon screenshot

When the gaming world moved to 3D 32-bit vector art, we lost some of that level of detail. We got lots of smooth areas. Eventually we mostly got the detail back by applying textures to the polgons. However, it often looks worse to me than the old hand-drawn art.

With my Flash experiments, I've been playing with 2D procedural vector art, and I've been trying to figure out how to make it look nicer without drawing textures by hand. The simplest thing I found has been to apply noise to the art. On the left is some terrain without noise and on the right is some with noise:

Test image without noise Test image with noise

I like the noisy version much better.

The noise layer is fairly easy to apply; I use BitmapData.noise() to generate it, and then use BlendMode.ADD to add it to the original layer.

  var noiseTexture:BitmapData = new BitmapData(128, 128);
  noiseTexture.noise(Math.round(Math.random()*65536), 
                     0, 8, 7, true);
  var noise:Shape = new Shape();
  noise.graphics.beginBitmapFill(noiseTexture);
  noise.graphics.drawRect(0, 0, size, size);
  noise.graphics.endFill();
  layer.draw(noise, null, null, BlendMode.ADD);
  noiseTexture.dispose();

It's nice in that it inherits the color already there; the noise doesn't impose its own colors. However, this only works nicely on my background terrain, and it feels somewhat slow on my low-end machine.

For foreground sprites, the noise layer doesn't move when those sprites move or rotate. An alternative would be to draw the noise on top of my sprites, using Graphics.beginBitmapFill(), but that would require that I have a way to compute the outline of my procedural art, so that I can draw the noise on top as a polygon. Another alternative would be to use bitmap fills for every polygon, but that requires that I have a noise bitmap for each color. And yet another alternative is to draw every polygon twice, once for the color and once for the noise.

With Flash 10 I had hoped that the pixel shaders would allow me to apply noise to anything. I played around with them a bit. The shader receives the output coordinates in a function outCoord(), and can compute a color for that location. It can optionally include parameters (like a noise bitmap). The big problem is that the output coordinates are in screen space. This means that when the sprite moves or rotates, or if you zoom in, the noise would stay fixed relative to the screen. I tried both using shaders for fills and shaders for filters, and neither gave me what I wanted.

That's a serious problem for my use. To address this problem, I can pass in additional parameters like rotation and offset. However, I have to re-fill the shape every time I change the shader parameters. Even worse, the pixel shader is recompiled every time you fill.

So it looks like pixel shaders in Flash 10 just don't do what I want. I want a way to get the pixel's location in the sprite's coordinate system, after transforms are applied, but instead I only get the screen's coordinate system.

I think my best bet for performance is to not apply noise to vector backgrounds (applying noise to a bitmap won't impact performance). This will make me sad but smoothness matters a great deal. I should also try using tiles to see if that is any faster. For foreground objects, it's probably not too bad to draw everything twice, but I'll have to test this. It may not matter if I switch to bitmap sprites eventually; they'd let me draw a lot more details.

Labels: ,