User talk:Evercat/Buddhabrot.c
Complexification.net
[edit]http://complexification.net/gallery/machines/buddhabrot/ —Preceding unsigned comment added by 128.138.65.225 (talk) 19:44, 7 April 2011 (UTC)
Bugs
[edit]I recently came across your program for creating Buddhabrot images, and noticed unexpected behavior. I attempted to use the program to create large images, but noticed that it only evaluates within the bounds of the SOURCE_{direction}_{X/Y} defines. This creates an image of the set the same size as before, but bordered by black to fill the rest of the image.
My solution to this problem was to remove all references to the SOURCE_{direction}_{X/Y} defines and replace them with the target_{start/end}{x/y} variables. If you want, i can give you a diff of the changes I made. If not, I'll just keep them to myself.
Thanks,
xx3nvyxx (talk) 21:21, 8 October 2009 (UTC)
Unfortunately this program has numerous bugs in it. Namely,
- Doesn't work at arbitrary resolutions, such as 256x256
- Assumes a fixed aspect ratio (note the lack of pixel_height)
- Has a few fencepost (off by one) errors:
- The world to image space transform for multi-sampling has an off-by-one error in pixel_width,
- The <0,0> pixel is never updated, and
- Iterates the maximum depth by one too much in drawpath(). e.g. for (n = 0; n <= iterations; n++)
Fixes
[edit]1. Remove the following as they are completely unnecessary:
target_startx = CENTRE_X - ((double) WIDTH / (ZOOM * 2)); target_endx = CENTRE_X + ((double) WIDTH / (ZOOM * 2));
target_starty = CENTRE_Y - ((double) HEIGHT / (ZOOM * 2)); target_endy = CENTRE_Y + ((double) HEIGHT / (ZOOM * 2));
2. Replace:
pixel_width = (target_endx - target_startx) / WIDTH;
x_jump = ((double) SOURCE_RIGHT_X - SOURCE_LEFT_X) / SOURCE_COLUMNS; y_jump = ((double) SOURCE_BOTTOM_Y - SOURCE_TOP_Y) / SOURCE_ROWS;
With:
// Map Source (world space) to Pixels (image space) double world_2_image_x = (double)(WIDTH -1) / ((double) SOURCE_RIGHT_X - SOURCE_LEFT_X); double world_2_image_y = (double)(HEIGHT-1) / ((double) SOURCE_BOTTOM_Y - SOURCE_TOP_Y); x_jump = ((double) SOURCE_RIGHT_X - SOURCE_LEFT_X) / (SOURCE_COLUMNS - 1); y_jump = ((double) SOURCE_BOTTOM_Y - SOURCE_TOP_Y) / (SOURCE_ROWS - 1);
3. Replace:
double x0 = SOURCE_LEFT_X; for (source_column = 0; source_column < SOURCE_COLUMNS; source_column++, x0 += x_jump) { double y0 = SOURCE_TOP_Y; for (source_row = 0; source_row < SOURCE_ROWS; source_row++, y0 += y_jump)
With:
for( double x0 = SOURCE_LEFT_X; x0 < SOURCE_RIGHT_X; source_column++, x0 += x_jump ) { for( double y0 = SOURCE_TOP_Y; y0 < SOURCE_BOTTOM_Y; y0 += y_jump )
4. Replace:
xpixel = (r - target_startx) / pixel_width; ypixel = (s - target_starty) / pixel_width; if (xpixel > 0 && xpixel < WIDTH && ypixel > 0 && ypixel < HEIGHT)
With:
xpixel = (int) ((r - SOURCE_LEFT_X) * world_2_image_x ); ypixel = (int) ((i - SOURCE_TOP_Y ) * world_2_image_y ); if (xpixel >= 0 && xpixel < WIDTH && ypixel >= 0 && ypixel < HEIGHT)
5. Replace:
void drawpath(double x, double y, double target_startx, double target_starty, double pixel_width);
With:
void drawpath(double x, double y, double world_2_image_x, double world_2_image_y);
Replace:
drawpath(x, y, target_startx, target_starty, pixel_width);
With:
drawpath(x, y, world_2_image_x, world_2_image_y);
I've also fixed the constant divide per pixel with a multiply by the reciprocal when converting from world space to image space.
Further Work
[edit]There are still other inefficiences:
- 64-bit depth (luminance) buffer when a 16-bit one is more then enough.
- hard coded low-pass noise filter (instead of 3% of luminance)
- does a redundant check if 'Z' escapes in drawpath() when we already know the max depth of this pixel but those are left as an exercise for the reader. :-)
Selected Answers
[edit]- Speed up the luminance buffer:
Replace:
long long redcount[WIDTH][HEIGHT]; long long greencount[WIDTH][HEIGHT]; long long bluecount[WIDTH][HEIGHT];
With:
unsigned short redcount[WIDTH][HEIGHT]; unsigned short greencount[WIDTH][HEIGHT]; unsigned short bluecount[WIDTH][HEIGHT];
Multi-Threaded
[edit]I have single-threaded and multi-threaded versions of Buddhabrot rendering code on my GitHub account /Michaelangel007/buddhabrot. Here are some sample timings for the default resolution and depth:
Hardware | Original | Multi-threaded (OpenMP) |
---|---|---|
Intel i7 8-core @ 2.6 GHz | 0:57 | 0:10 |
AMD 955BE 4-core @ 3.5 GHz | 1:37 | 0:30 |
Thanks for providing the original version! Michael.Pohoreski (talk) 19:06, 10 June 2015 (UTC)