4
\$\begingroup\$

I'm using a fractal generator to generate borders around a rectangular area. It works great, but my problem is with corners.

A naive implementation when the left border overlaps the top border: enter image description here

Obviously this doesn't look great. I tried averaging the weight of pixels from top and left border... not so great either.

My best shot was with iterating over a circle rather than over a line for corners, sort of like:

for(var i = 0; i < buffer.Length; i+= step) {
  for(var j = 0; j < buffer[(int)i]; j++) {
    PutPixel(Cos(i*CoeffStep)*CoeffRadius*j,
      Sin(i*CoeffStep)*CoeffRadius*j, ColorFor(j));
  }
}

Where PutPixel merges color into average if the pixel is already set. This however this skips some pixels at higher radii.

enter image description here

Example:

enter image description here

Setting smaller steps obviously helps, but not 100%. Anyone have any ideas what I can do?

\$\endgroup\$
3
  • 4
    \$\begingroup\$ Could you make clearer what looks bad and include a picture how you would like it to look? :) \$\endgroup\$
    – Roy T.
    Jun 18, 2014 at 13:28
  • \$\begingroup\$ Try using edge detection, and blend across the appropriate edges. I have had luck performing a similar task using a simple laplacian/gaussian edge detection. homepages.inf.ed.ac.uk/rbf/HIPR2/log.htm \$\endgroup\$
    – Evan
    Jun 18, 2014 at 13:40
  • \$\begingroup\$ I don't really understand the picture. The red is your rectangle right? What is wrong with the shape you got there? It looks nice to me. \$\endgroup\$
    – Marnix
    Jul 2, 2014 at 20:31

3 Answers 3

3
\$\begingroup\$

Another approach you can take for this is domain warping.

Rather than generating a 1D fractal along the edges, you generate a 2D fractal over the interior. For each pixel, you sample the fractal at that point to generate an offset vector, then you shade that pixel as if you were shading the nearby pixel at [pixel position + offset]. For pixels near the edge, this offset can change what would have been an "inside" pixel to "outside" and vice versa, changing the shape of the boundary.

Here is my rectangle before I apply any offset. Pixels inside the rectangle are coloured red, those outside are shaded in grey according to their distance from the rectangle's edge:

Undistorted

Applying varying amplitudes of warp, we get:

Varying distortion

Note that the fractal peaks & valleys don't get squashed into skinny spikes at the corners, the way they do when bending a 1D fractal along a circular arc. Here the corners aren't a special case, but get the same treatment as any other point.

What's happening under the hood is that our lookup into the rectangle's domain is being warped by the offset, as visualized by this grid:

Distortion grid

One risk with this method is, if the distortion amplitude is too high, you can get holes in the interior of the rectangle, or islands of rectangle separated from the main body. Lowering the frequency or amplitude of the fractal noise should take care of this.

\$\endgroup\$
1
\$\begingroup\$

You're getting aliasing in the second case since you're not rasterizing the circle correctly. Instead of iterating over r, theta, you need to iterate over pixels in the rectangle and determine from that their r, theta:

for(var i = 0; i < buffer.Length; i+= step) {
  for(var j = 0; j < buffer[(int)i]; j++) {
    var r = sqrt(i * i + j * j);
    var theta = atan2(j, i);
    PutPixel(i, j, ColorFor(r, theta));
  }
 }

And make ColorFor(r, theta)

determine the color for a particular pixel at radius r, angle theta.

\$\endgroup\$
-1
\$\begingroup\$

I don't know how well this would work but I think you could solve your problem by selecting the maximum of the two blend edges. Wherever they overlap use whichever one has a higher value so that the edges are full opacity and the inside is a clean blend.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .