• February 27, 2021, 11:16:22 PM

Login with username, password and session length

Author Topic:  Algorithm for Rendering Slope in a Fractal  (Read 3621 times)

0 Members and 1 Guest are viewing this topic.

Offline superheal

  • Strange Attractor
  • ******
  • Posts: 94
Re: Algorithm for Rendering Slope in a Fractal
« Reply #30 on: March 12, 2020, 01:07:24 PM »
In my opinion just try to make bump mapping work, initially,  and then focus on light.

Offline LionHeart

  • Uploader
  • *
  • Posts: 164
    • ManpWIN Fractal Generator
Re: Algorithm for Rendering Slope in a Fractal
« Reply #31 on: March 12, 2020, 09:07:24 PM »
Hi superheal

I will investigate the new code and see how I go. If I need to, I'll send you my code. There must be something silly going on :)

I'll keep you posted.

Many thanks.
Paul the LionHeart

Offline LionHeart

  • Uploader
  • *
  • Posts: 164
    • ManpWIN Fractal Generator
Re: Algorithm for Rendering Slope in a Fractal
« Reply #32 on: March 13, 2020, 03:02:33 AM »
Hi superheal,

Okay, ignoring light(), I still get some improvement with the correct initial values. However, the palette changes substantially and there's a section in the middle of the image where slope doesn't seem to work very well.



So it is time to share my code. I can't see what I am doing wrong.

Here are the meanings of some of my variables:
xdots, ydots  are the pixel size of the image
wpixels is an array of iteration counts for each pixel
TrueCol.PalettePtr is the RGB value of the palette at a specific iteration count
threshold is the maximum iteration count

Code: [Select]
#define     MAX_BUMP_MAPPING_DEPTH  100
#define     DEFAULT_BUMP_MAPPING_STRENGTH 50

    // https://github.com/hrkalona/Fractal-Zoomer/blob/master/src/fractalzoomer/core/ThreadDraw.java#L3640
    // https://github.com/hrkalona/Fractal-Zoomer/blob/master/src/fractalzoomer/main/app_settings/BumpMapSettings.java

int CPixel::DoSlope2(void)
    {
    double dotp, gradAbs, gradCorr, cosAngle, sizeCorr, smoothGrad, lightAngleRadians, lightx, lighty;
    double gradx, grady;

    double bumpMappingDepth = 50; // future add to dialogue box
    double bumpMappingStrength = 50; // future add to dialogue box
    double lightDirectionDegrees = 0.0; // future add to dialogue box

    int x, y;
    int index;
    int modified;
    int iterations;

    unsigned char r, g, b;
    RGBTRIPLE colour;

    sizeCorr = 0.0;
    lightx = 0.0;
    lighty = 0.0;

    gradCorr = pow(2, (bumpMappingStrength - DEFAULT_BUMP_MAPPING_STRENGTH) * 0.05);
    sizeCorr = ydots / pow(2, (MAX_BUMP_MAPPING_DEPTH - bumpMappingDepth) * 0.16);
    lightAngleRadians = lightDirectionDegrees * PI / 180.0;
    lightx = cos(lightAngleRadians) * gradCorr;
    lighty = sin(lightAngleRadians) * gradCorr;
    for (y = 1; y < ydots - 1; y++) // don't do first and last pixel as it crashes slope calculations
{
for (x = 1; x < xdots - 1; x++)
    {
    if (user_data(GlobalHwnd) < 0) // trap user input
return -1;

    index = ((DWORD)y * (DWORD)width) + (DWORD)x;
    iterations = *(wpixels + index);
    // modified = rgbs[index];
    modified = 0xFF | ((DWORD)*(TrueCol.PalettePtr + (BYTE)((iterations) % 256) * 3 + 0) << 16) | ((DWORD)*(TrueCol.PalettePtr + (BYTE)((iterations) % 256) * 3 + 1) << 8) | *(TrueCol.PalettePtr + (BYTE)((iterations) % 256) * 3 + 2);
    gradx = getGradientX(wpixels, index, ydots);
    grady = getGradientY(wpixels, index, ydots);
    dotp = gradx * lightx + grady * lighty;
    int original_color = modified;
    if (dotp != 0)
{
gradAbs = sqrt(gradx * gradx + grady * grady);
cosAngle = dotp / gradAbs;
smoothGrad = -2.3562 / (gradAbs * sizeCorr + 1.5) + 1.57;
//smoothGrad = Math.atan(gradAbs * sizeCorr);
modified = changeBrightnessOfColorScaling(modified, cosAngle * smoothGrad);
}
//     else if (dotp != 0 || (dotp == 0 && !isInt(image_iterations[index])))
// {
// gradAbs = sqrt(gradx * gradx + grady * grady);
// cosAngle = dotp / gradAbs;
// smoothGrad = -2.3562 / (gradAbs * sizeCorr + 1.5) + 1.57;
// //smoothGrad = Math.atan(gradAbs * sizeCorr);
// modified = changeBrightnessOfColorBlending(modified, cosAngle * smoothGrad);
// }
//     modified = postProcessingSmoothing(modified, image_iterations, original_color, y, x, image_size, bms.bm_noise_reducing_factor);
    // compute  pixel color (24 bit = 3 bytes)
//     rgbs[index] = modified;
    r = (modified >> 16) & 0xFF;
    g = (modified >> 8) & 0xFF;
    b = modified & 0xFF;

    if (iterations >= threshold)
{ //  interior of Mandelbrot set = inside_color = blue
colour.rgbtRed = (BYTE)TrueCol.InsideRed; // M_waves
colour.rgbtGreen = (BYTE)TrueCol.InsideGreen;
colour.rgbtBlue = (BYTE)TrueCol.InsideBlue;
}
    else
{
colour.rgbtRed = r;
colour.rgbtGreen = g;
colour.rgbtBlue = b;
}
    outRGBpoint(x, y, colour);
    }
}
    return 0;
    }

Am I doing anything wrong? Please let me know. Thanks.

Offline C0ryMcG

  • Uploader
  • *
  • Posts: 243
Re: Algorithm for Rendering Slope in a Fractal
« Reply #33 on: March 13, 2020, 03:28:05 AM »
One thing I notice is that you have an opportunity to speed up rendering by putting all of those expensive (relatively) calculations inside the If statement that decides whether to use inside-color or the calculated bump mapping color.

But I know that's not the real priority right now...

I see that there's still some light calculations happening, just some simple diffuse shading I think? Light angle times gradient... but for the sake of simplicity, and seeing what your code is doing, would you be able to select the colors from only the gradx and grady vars, and not multiply in light?
My hope is that you'd be able to create a normal map image from it, which can be easily examined for errors, or, if it turns out looking nice, we'd be able to identify the lighting as the culprit (although it looks simple and accurate, so I don't expect this to happen)

If grad x and y work the way I think they might, you should be able to convert gradx from [-1, 1] to [0, 255], and the same for grad y. Then use converted gradx for Red and y for Green, and set blue to 128 for a normal map.
(Ideally you'd scale back blue a bit to make the color vector a unit length'ed vector, but for our visual purposes it doesn't matter)

Offline LionHeart

  • Uploader
  • *
  • Posts: 164
    • ManpWIN Fractal Generator
Re: Algorithm for Rendering Slope in a Fractal
« Reply #34 on: March 13, 2020, 07:12:07 AM »
Thanks C0ryMcG,

I must admit I like the final result I got from Adam Majewski's code. The main drawbacks seem to be the need to calculate derivatives and the need to store all the derivatives for post processing.

I should have put superheel's slope functions in the code segment as well so you can see how they work.

Code: [Select]
double transformResultToHeight(DWORD iteration, long size)
    {
    return (double)iteration;
//    if (size > 0L)
// return (double)iteration / (double)size;
//    else return -1;
    }

double getGradientX(DWORD *wpixels, int index, int size)
    {
    // size = ydots
    int x = index % size;
    double it = /*ColorAlgorithm.*/transformResultToHeight(*(wpixels + index), threshold);

    if (x == 0) {
return (/*ColorAlgorithm.*/transformResultToHeight(*(wpixels + index + 1), threshold) - it) * 2;
}
    else if (x == size - 1) {
return (it - /*ColorAlgorithm.*/transformResultToHeight(*(wpixels + index - 1), threshold)) * 2;
}
    else {
double diffL = it - /*ColorAlgorithm.*/transformResultToHeight(*(wpixels + index - 1), threshold);
double diffR = it - /*ColorAlgorithm.*/transformResultToHeight(*(wpixels + index + 1), threshold);
return diffL * diffR >= 0 ? 0 : diffL - diffR;
}
    }

double getGradientY(DWORD *wpixels, int index, int size) {

    int y = index / size;
    double it = /*ColorAlgorithm.*/transformResultToHeight(*(wpixels + index), threshold);

    if (y == 0) {
return (it - /*ColorAlgorithm.*/transformResultToHeight(*(wpixels + index + size), threshold)) * 2;
}
    else if (y == size - 1) {
return (/*ColorAlgorithm.*/transformResultToHeight(*(wpixels + index - size), threshold) - it) * 2;
}
    else {
double diffU = it - /*ColorAlgorithm.*/transformResultToHeight(*(wpixels + index - size), threshold);
double diffD = it - /*ColorAlgorithm.*/transformResultToHeight(*(wpixels + index + size), threshold);
return diffD * diffU >= 0 ? 0 : diffD - diffU;
}
    }


Here is the code written by Adam Majewski that I used to get the early results:

Code: [Select]
/*
   c program: console, 1-file
   normal.c
   
   normal = Normal map effect  Mandelbrot set
   
   https://www.math.univ-toulouse.fr/~cheritat/wiki-draw/index.php/Mandelbrot_set
   thx for help:
   * Claude Heiland-Allen http://mathr.co.uk/blog/
   
   --------------------------------
   1. draws Mandelbrot set for Fc(z)=z*z +c
   using Mandelbrot algorithm ( boolean escape time )
   -------------------------------         
   2. technique of creating ppm file is  based on the code of Claudio Rocchini
   http://en.wikipedia.org/wiki/Image:Color_complex_plot.jpg
   create 24 bit color graphic file ,  portable pixmap file = PPM
   see http://en.wikipedia.org/wiki/Portable_pixmap
   to see the file use external application ( graphic viewer)
-----
 it is example  for :
 https://www.math.univ-toulouse.fr/~cheritat/wiki-draw/index.php/Mandelbrot_set
 
 -------------
 compile :

 gcc normal.c -lm -Wall

 ./a.out
*/
#include < stdio.h >
#include < math.h >
#include < complex.h >

#define M_PI 3.14159265358979323846 /* pi */

/* screen ( integer) coordinate */
int iX, iY;
const int iXmax = 10000;
const int iYmax = 10001; // for main antenna
/* world ( double) coordinate = parameter plane*/
double Cx, Cy;
const double CxMin = -2.2;
const double CxMax = 0.8;
const double CyMin = -1.5;
const double CyMax = 1.5;
/* */
double PixelWidth; //=(CxMax-CxMin)/iXmax;
double PixelHeight; // =(CyMax-CyMin)/iYmax;
/* color component ( R or G or B) is coded from 0 to 255 */
/* it is 24 bit color RGB file */
const int MaxColorComponentValue = 255;
FILE * fp;
char * filename = "n10000.ppm"; // https://www.math.univ-toulouse.fr/~cheritat/wiki-draw/index.php/File:M-bump-1.png
char * comment = "# "; /* comment should start with # */

static unsigned char color[3]; // 24-bit rgb color

/*  */

const int IterationMax = 2000; //  N in wiki

/* bail-out value for the bailout test for escaping points
 radius of circle centered ad the origin, exterior of such circle is a target set  */
const double EscapeRadius = 1000; // big !!!!

double complex give_c(int iX, int iY) {
  double Cx, Cy;
  Cy = CyMax - iY * PixelHeight;
  Cx = CxMin + iX * PixelWidth;

  return Cx + Cy * I;
}

/*
 The dot product of two vectors a = [a1, a2, ..., an] and b = [b1, b2, ..., bn] is defined as:[1]
 d = a1b1 + a2b2
*/
double cdot(double complex a, double complex b) {
  return creal(a) * creal(b) + cimag(a) * cimag(b);
}

//
// output
//
double GiveReflection(double complex C, int iMax) {
  int i = 0; // iteration

  double complex Z = 0.0; // initial value for iteration Z0
  double complex dC = 0.0; // derivative with respect to c
  double reflection = FP_ZERO; // inside

  double h2 = 1.5; // height factor of the incoming light
  double angle = 45.0 / 360.0; // incoming direction of light in turns
  double complex v = cexp(2.0 * angle * M_PI * I); // = exp(1j*angle*2*pi/360)  // unit 2D vector in this direction
  // incoming light 3D vector = (v.re,v.im,h2)

  double complex u;

  for (i = 0; i < iMax; i++) {
    dC = 2.0 * dC * Z + 1.0;
    Z = Z * Z + C;

    if (cabs(Z) > EscapeRadius) { // exterior of M set
      u = Z / dC;
      u = u / cabs(u);
      reflection = cdot(u, v) + h2;
      reflection = reflection / (1.0 + h2); // rescale so that t does not get bigger than 1
      if (reflection < 0.0) reflection = 0.0;
      break;

    }
  }

  return reflection;
}

int compute_color(complex double c, unsigned char color[3]) {

  double reflection;
  unsigned char b;

  // compute
  reflection = GiveReflection(c, IterationMax);

  if (reflection == FP_ZERO) { /*  interior of Mandelbrot set = inside_color = blue */
    color[0] = 0; // M_waves
    color[1] = 0;
    color[2] = 127;
  } else // exterior of Mandelbrot set = normal

  {

    b = 255 * reflection;
    //b = (unsigned char) (255 - 255*potential );

    color[0] = b; /* Red*/
    color[1] = b; /* Green */
    color[2] = b; /* Blue */

  };

  return 0;
}

void setup() {
  PixelWidth = (CxMax - CxMin) / iXmax;
  PixelHeight = (CyMax - CyMin) / iYmax;

  /*create new file,give it a name and open it in binary mode  */
  fp = fopen(filename, "wb"); /* b -  binary mode */
  /*write ASCII header to the file*/
  fprintf(fp, "P6\n %s\n %d\n %d\n %d\n", comment, iXmax, iYmax, MaxColorComponentValue);
}

void info() {

  double distortion;
  // widt/height
  double PixelsAspectRatio = (double) iXmax / iYmax; // https://en.wikipedia.org/wiki/Aspect_ratio_(image)
  double WorldAspectRatio = (CxMax - CxMin) / (CyMax - CyMin);
  printf("PixelsAspectRatio = %.16f \n", PixelsAspectRatio);
  printf("WorldAspectRatio = %.16f \n", WorldAspectRatio);
  distortion = PixelsAspectRatio - WorldAspectRatio;
  printf("distortion = %.16f ( it should be zero !)\n", distortion);

  // file 
  printf("file %s saved. It is called M-bump-1.png in  A Cheritat wiki\n", filename);

}

void close() {
  fclose(fp);
  info();
}

// ************************************* main *************************
int main() {
  complex double c;

  setup();

  printf(" render = compute and write image data bytes to the file \n");

  for (iY = 0; iY < iYmax; iY++)
    for (iX = 0; iX < iXmax; iX++) { // compute pixel coordinate       
      c = give_c(iX, iY);
      /* compute  pixel color (24 bit = 3 bytes) */
      compute_color(c, color);
      /*write color to the file*/
      fwrite(color, 1, 3, fp);
    }

  close();

  return 0;
}

However, it relies on derivative of the original fractal and is calculated in real time. In order to use this algorithm in post processing, I don't know how to transform the outputs from superheel's slope calculations to be the equivalent to the "reflection" calculations the above code.

I have tried to merge the two approaches without success.

Any suggestions? Thanks.


Offline superheal

  • Strange Attractor
  • ******
  • Posts: 94
Re: Algorithm for Rendering Slope in a Fractal
« Reply #35 on: March 13, 2020, 10:21:19 AM »
I think the problem is here DWORD *wpixels
As I said you need the continuous iteration count, which means that the iteration are not integers anymore but floating point numbers.

For example check this (Method 2 for Escaping Type Fractals):
https://en.wikibooks.org/wiki/Fractals/fractalzoomer#Escape_Time

This is related to https://en.wikipedia.org/wiki/Plotting_algorithms_for_the_Mandelbrot_set#Continuous_(smooth)_coloring but in more generalized way to cover all escaping type fractals.

as you can see in my code image_iterations is double[] and not int[] !

You dont need to implement the function transformResultToHeight, right now, all it does for you is to scale the actual integer iteration number to a value between 0 and 1. But all the areas that have the same iteration number will still have the same floating point value, which basically does nothing for you!

Also dont forget to use a high bailout value, to get even smoother color transitions!

Offline superheal

  • Strange Attractor
  • ******
  • Posts: 94
Re: Algorithm for Rendering Slope in a Fractal
« Reply #36 on: March 13, 2020, 10:47:10 AM »
Also if you have continuous iteration counts, then you can make the palette colors look smooth as well, and remove the bands.
check here:
https://en.wikibooks.org/wiki/Fractals/fractalzoomer#Color

Offline Adam Majewski

  • Fractal Frogurt
  • ******
  • Posts: 452
Re: Algorithm for Rendering Slope in a Fractal
« Reply #37 on: March 13, 2020, 06:49:39 PM »
Slopes rendering is originally a screen-space post-processing effect, using differences between neighbouring pixels' smooth iteration counts.  More recently it can use directional distance estimate (normalized by pixel spacing) instead, which I think gerrit proved is equivalent in the limit of infinitely fine pixel grid.

Relevant part of the source code:
https://code.mathr.co.uk/kalles-fraktaler-2/blob/c78c224a4a3ae7f10ed03aa3948f0cd6b740adcb:/fraktal_sft/fraktal_sft.cpp#l933 lines 933 to 998


what means m_b in the code ?

Online claude

  • 3f
  • ******
  • Posts: 1784
    • mathr.co.uk
Re: Algorithm for Rendering Slope in a Fractal
« Reply #38 on: March 13, 2020, 07:30:27 PM »
what means m_b in the code ?

m_ means it's part of "this" object structure (as opposed to local or global variable - globals often start with g_)
b means it's a boolean value, either true or false.

Offline LionHeart

  • Uploader
  • *
  • Posts: 164
    • ManpWIN Fractal Generator
Re: Algorithm for Rendering Slope in a Fractal
« Reply #39 on: March 14, 2020, 12:40:00 AM »
Wow superheal,

This is a huge paradigm shift for me. But I can see the what you mean. It takes all the quantising out of the slope making it continuous. I have some serious programming to do as all my code is based on integer iteration count. However, if this is what's needed, so be it.

Thanks for picking the issue so quickly.

However, there's still the issue of palette change. Is there a different cause for this or will it be fixed with the upgrade of iteration count to double float?

Thanks for your help.

Offline C0ryMcG

  • Uploader
  • *
  • Posts: 243
Re: Algorithm for Rendering Slope in a Fractal
« Reply #40 on: March 14, 2020, 03:16:01 AM »
Okay, so slope works like I'd expect. It takes the difference of neighboring pixel 'heights' in X and Y direction, with height being a result of the coloring function.
Since I have a few different color functions that require smooth coloring effects, I broke the relevant code into its own function.

Here it is in Javascript
Code: [Select]
LogPotential = function(distance, iteration, escapeLimit, order){
var r = Math.log(distance) / Math.log(escapeLimit*escapeLimit);
r = iteration - (r-1)/(order-1);
r = r / Math.log(2);
return r;

}

//
So distance is complex abs function for the pixel, escapeRadius is how far the pixel moves before we consider it to be proven to escape (For mandelbrot, this is 2), iteration is the number of iteration upon which the point escaped past escapeRadius, and order is the highest power that Z might be brought to (2 for Mandelbrot)

So the only real difference between smooth coloring and what I call fast coloring is that fast coloring choses a color based on Iteration, and smooth coloring choses it based on LogPotential(dist, i, escapeRadius, 2);

I do still want to see how your Normal map looks, by the way! If you can, convert the results from GetGradientX and Y to Red and Green. We'll be able to tell what's working and what's not right away from that.

Offline LionHeart

  • Uploader
  • *
  • Posts: 164
    • ManpWIN Fractal Generator
Re: Algorithm for Rendering Slope in a Fractal
« Reply #41 on: March 14, 2020, 06:03:46 AM »
Hi C0ryMcG.

Here is my normal palette without any processing.



Quote
If you can, convert the results from GetGradientX and Y to Red and Green.

I'm not sure how to separate them. The outputs immediately do a dot product with the light vector and further processing that makes them hard to separate.

Offline LionHeart

  • Uploader
  • *
  • Posts: 164
    • ManpWIN Fractal Generator
Re: Algorithm for Rendering Slope in a Fractal
« Reply #42 on: March 14, 2020, 06:58:16 AM »
Dear Friends,

Progress is slow. When I use integer iteration count, the slope function doesn't work very well. Bailout was set at 1000.0. No interpolation was done at this stage.



When I use a double float iteration count, the slope function is far better, but there are many nasty artifacts in the image.



Here is the code added to calculate the changes to iteration and wpixels after converting them to double float:

Code: [Select]

    // sqrt of inner term removed using log simplification rules.
    log_zn = log(z.x * z.x + z.y * z.y) / 2;
    nu = log(log_zn / log(2.0)) / log(2.0);
    // Rearranging the potential function.
    // Dividing log_zn by log(2) instead of log(N = 1<<8)
    // because we want the entire palette to range from the
    // center to radius 2, NOT our bailout radius.
    iteration = iteration + 1 - nu;
    /*
color1 : = palette[floor(iteration)]
color2 : = palette[floor(iteration) + 1]
// iteration % 1 = fractional part of iteration.
color : = linear_interpolate(color1, color2, iteration % 1)
plot(Px, Py, color)
    */

    index = ((DWORD)row * (DWORD)width) + (DWORD)col;
    if (col >= 0 && col < xdots - 1 && row >= 0 && row < ydots - 1)
*(wpixels + index) = iteration;


The palette still looks different to the original as shown in the previous message.

Offline superheal

  • Strange Attractor
  • ******
  • Posts: 94
Re: Algorithm for Rendering Slope in a Fractal
« Reply #43 on: March 16, 2020, 09:17:59 AM »
First of all, after changing your code to use the continuous iteration counts, make sure that you get smoother color transitions without using bump mapping.
The palette should be looking as the original image. Once you get that then you can focus on the post processing part.

There are two things,
about the artifacts its usually because there might be a missmatch of which pixel you are processing and on which pixel you are storing the new result.
As for the color change, make sure that when you are converting from r,g,b to the single value and back, you are doing the conversion correctly. It might be a case of mixing the color channels.

If you have an updated code, please sent to me again so I can have a look!

Offline sergioct

  • Fractal Fanatic
  • ***
  • Posts: 24
    • FractalFun Project
Re: Algorithm for Rendering Slope in a Fractal
« Reply #44 on: March 16, 2020, 08:21:43 PM »
Hello everyone, I have been following your conversation for a long time and I have finally decided to try it for myself. I have made an algorithm like the one described here: https://www.math.univ-toulouse.fr/~cheritat/wiki-draw/index.php/Mandelbrot_set#Normal_map_effect

I would like to know what you think about some high points and other sunken points that appear when using my algorithm in disconnected Julia sets.

I'm not sure if those points should show up, or if it's an error in my algorithm. I show you an image so you can see what I'm talking about.

Thank you!


clip
Algorithm for Full Exploration of 3D Fractal in Realtime

Started by AranLeer on Fractal Mathematics And New Theories

13 Replies
837 Views
Last post April 26, 2019, 07:34:08 AM
by TGlad
xx
Custom 3D Fractal Formula Rendering on Mac

Started by jmseight on Noob's Corner

5 Replies
345 Views
Last post May 11, 2020, 04:30:34 AM
by kosalos
xx
Travel around 3d fractal world. Realtime rendering.

Started by sanbase on Fractal movie gallery

4 Replies
210 Views
Last post February 18, 2021, 06:12:08 AM
by sanbase
xx
How would quantum computing affect fractal rendering?

Started by greentexas on Programming

1 Replies
723 Views
Last post December 12, 2017, 01:40:20 AM
by eiffie
question
How to Generate a Derivative Slope for Mandelbar (Tricorn)

Started by LionHeart on Programming

12 Replies
353 Views
Last post January 08, 2021, 08:25:36 PM
by LionHeart