asimes
|
|
« on: April 24, 2012, 08:20:07 AM » |
|
I'm trying to make a Mandelbox for the first time. I was using this as reference: http://www.fractalforums.com/3d-fractal-generation/amazing-fractal/45/Here is my code so far. If anyone has Processing installed you can see it: float bScale = 2; float minRad = 0.5; float fixedRad = 1.0; float xmin = -2.0; float ymin = -2.0; float wh = 4; int maxIterations = 100;
void setup() { size(800, 800, P2D); }
void draw() { loadPixels(); float xmax = xmin+wh; float ymax = ymin+wh; float dx = (xmax-xmin)/width; float dy = (ymax-ymin)/height; float x = xmin; float highestVal = 0; float[] pixVals = new float[width*height]; for (int i = 0; i < width; i++) { float y = ymin; for (int j = 0; j < height; j++) { float nx = x; float ny = y; float nMag = 0; int n = 0; while (n < maxIterations) { if (nx > 1) nx = bScale-nx; else if (nx < -1) nx = -bScale-nx; if (ny > 1) ny = bScale-ny; else if (ny < -1) ny = -bScale-ny; nMag = sqrt(nx*nx+ny*ny); if (nMag < minRad) { float t = (fixedRad*fixedRad)/(minRad*minRad); nx *= t; ny *= t; } else if (nMag < 1) { float t = (fixedRad*fixedRad)/(nMag*nMag); nx *= t; ny *= t; } if (nx*nx+ny*ny > 2) break; n++; } if (nMag > highestVal) highestVal = nMag; if (n == maxIterations) pixVals[i+j*width] = 0; else pixVals[i+j*width] = nMag; y += dy; } x += dx; } for (int i = 0; i < width*height; i++) { int val = (int)(pixVals[i]/highestVal*255); pixels[i] = (val<<16)+(val<<8)+val; } updatePixels(); println("Time: "+millis()); noLoop(); } If not, here is a sample image for scale = 2.0, minRad = 0.5, and fixedRad = 1.0: What I am wondering: - Is this a normal output for a Mandelbox in 2D? - My bailout doesn't work when I set it to 4 (black screen), is this bad? I am used to this for Mandelbrot. - Does Mandelbox require internal coloring or can typical Mandelbrot coloring techniques be used? How do people normally color a Mandelbox for that matter, right now I'm just using the magnitude after a bail. - For anyone patient enough to look at my code, am I doing this correctly? I have seen examples like this before (linked below), not sure if they are the same or not, they don't make as much sense as what I was referring to in the link I put above: http://www.geeks3d.com/20100427/do-you-know-the-mandelbox-fractal/
|
|
|
Logged
|
|
|
|
asimes
|
|
« Reply #1 on: April 24, 2012, 08:38:59 PM » |
|
Ok, significant improvement. I discovered that I don't need to test if a point hit the maximum number of iterations... also I discovered that log coloring looks a million times nicer. Still some questions, I will ask below. New version of bailout for if (x*x+y*y > 2): Correctly working bailout for if (x*x+y*y > 4): New code (if anyone is interested and has Processing): float bScale = 2.0; float minRad = 0.5; float fixedRad = 1.0; float xmin = -2.0; float ymin = -2.0; float wh = 4; int maxIterations = 100;
void setup() { size(800, 800, P2D); }
void draw() { loadPixels(); float xmax = xmin+wh; float ymax = ymin+wh; float dx = (xmax-xmin)/width; float dy = (ymax-ymin)/height; float x = xmin; float highestVal = 0; float[] pixVals = new float[width*height]; for (int i = 0; i < width; i++) { float y = ymin; for (int j = 0; j < height; j++) { float nx = x; float ny = y; float nMag = 0; int n = 0; while (n < maxIterations) { if (nx > 1) nx = bScale-nx; else if (nx < -1) nx = -bScale-nx; if (ny > 1) ny = bScale-ny; else if (ny < -1) ny = -bScale-ny; nMag = sqrt(nx*nx+ny*ny); if (nMag < minRad) { float t = (fixedRad*fixedRad)/(minRad*minRad); nx *= t; ny *= t; } else if (nMag < 1) { float t = (fixedRad*fixedRad)/(nMag*nMag); nx *= t; ny *= t; } if (nx*nx+ny*ny > 4) break; nMag = nx*nx+ny*ny; n++; } if (nMag > highestVal) highestVal = nMag; pixVals[i+j*width] = nMag; y += dy; } x += dx; } for (int i = 0; i < width*height; i++) { int val = (int)(log(pixVals[i])/log(highestVal)*255); pixels[i] = (val<<16)+(val<<8)+val; } updatePixels(); println("Time: "+millis()); noLoop(); } Questions: - What are normal coloring techniques for a 2D Mandelbox? The images above are using the magnitude after a bailout. - Is it useful to think of a Mandelbox as having an inside / outside? - Does normal Mandelbox code assume that the range of points used per axis goes from -2 to 2 (or less)? - Still wondering if this is normal output for a 2D Mandelbox
|
|
« Last Edit: April 24, 2012, 08:46:16 PM by asimes »
|
Logged
|
|
|
|
cKleinhuis
|
|
« Reply #2 on: April 24, 2012, 09:39:39 PM » |
|
ok, for the bailout test: mandelbox is having a range of -4 to 4 i think, and bailout would then be 16 .... cant say if it really is 2d output, i think you have area -2 to 2 rendered ? zoom out! and show us then ... as i said, mandelbox goes from -4 to 4... - coloring techniques are basically the same as for mandelbrot .. but since it is a folding operation that leads to hard-cuts they could behave oddly ... - rendering techniques: the mandelbox is just the black area, the same as with the mandelbrot ... you are painting/coloring the outside area, this is not used very much in 3d rendering because it is heavy volume rendering stuff, when rendering 3d you are just interested in retrieving a color for the exact cut point ... - give any distance estimation method a chance and enjoy what the offer for results ... search for "distance estimation coloring" - and please render image a litte zoomed out .... so we can check visually if your code is correct if you wanna us re-check something always include exact parameter lists and exact locations ... - do not forget that iteration count has severe influence on the image, using higher iteration counts yields chaotic results, e.g. just pixel crap .... when zoomed out.... - it is always the black area of interest
|
|
|
Logged
|
---
divide and conquer - iterate and rule - chaos is No random!
|
|
|
visual.bermarte
|
|
« Reply #3 on: April 25, 2012, 11:15:51 PM » |
|
Nice images ! this is one crazy test..a sort of mandelbox-painter actually mouseX and mouseY are not that useful would be better using smaller numbers (and not int!) float xmin = -2.5; float ymin = -2.5; float wh = 5; void setup() { size(800, 800, P2D); loop(); background(0); // Make sure we can write to the pixels[] array. // Only need to do this once since we don't do any other drawing. loadPixels(); } void draw() { // Maximum number of iterations for each point on the complex plane int maxiterations = 9; // x goes from xmin to xmax float xmax = xmin + wh; // y goes from ymin to ymax float ymax = ymin + wh; // Calculate amount we increment x,y for each pixel float dx = (xmax - xmin) / (width); float dy = (ymax - ymin) / (height); // Start y float y = ymin; for (int j = 0; j < height; j++) { // Start x float x = xmin; for (int i = 0; i < width; i++) { float a = x; float b = y; int n = 0; float xx,yy,r2,mr,scaleb; //float zz,DEfactor; float fr, fr2, mr2; scaleb=-2.7; mr2=mouseX; fr2=mr2*2.; xx=a;yy=b; while (n < maxiterations) { if (a > mouseX)a = mouseY - a; else if (a < -mouseX)a = -mouseY - a; if (b > mouseX) b = mouseY - b; else if (b < -mouseX) b = -mouseY - b; r2=a*a+b*b; if(r2<mr2){ a=a*fr2/mr2; b=b*fr2/mr2; //z=z*fr2/mr2; //DEfactor=DEfactor*fr2/mr2; } else if(r2<fr2){ a=a*fr2/r2; b=b*fr2/r2; //z=z*fr2/r2; // DEfactor=DEfactor*fr2/r2; } a=a*scaleb+xx; b=b*scaleb+yy; //z=z*scaleb+zz; //DEfactor=DEfactor*abs(scaleb)+1; // r2=x*x+y*y+z*z; //repeat r2 babe! //r2=a*a+b*b; //} //return sqrt(r2)/DEfactor; if(r2 > 5555) {//// Bail me! break; } n++; } if (n == maxiterations) { colorMode(HSB, width, height, 32); float ca = color(165, 167, 20); float cb = color(77, 86, 59); //float cc = color(42, 106, 105); //float cd = color(165, 89, 20); //float ce = color(146, 150, 127); pixels[i+j*width] = (int)lerp((int)ca,(int)cb,mouseY); } else { //mothing here //colorMode(HSB); } x += dx; } y += dy; } updatePixels(); } in 3d would be something like that? float minThreshold = 0.0001,maxDepth=8.0;//8.0 is about right for most fractals
void setup() { size(800, 600, P2D); noLoop(); } float DE(float x, float y, float z){//this is our old friend menger int n,iters=12; float xx,yy,zz,DEfactor,r2,mr,scaleb; float fr, fr2, mr2; scaleb=3.2; mr2=0.5; fr2=1.2; xx=0.;yy=0.;zz=0.; r2=x*x+y*y+z*z; DEfactor=1.;
for(n=0;n<iters;n++){ if(x>1) x=2-x; else if(x<-1) x=-2-x; if(y>1) y=2-y; else if(y<-1) y=-2-y; if(z>1) z=2-z; else if(z<-1) z=-2-z; r2=x*x+y*y+z*z; if(r2<mr2){ x=x*fr2/mr2; y=y*fr2/mr2; z=z*fr2/mr2; DEfactor=DEfactor*fr2/mr2; } else if(r2<fr2){ x=x*fr2/r2; y=y*fr2/r2; z=z*fr2/r2; DEfactor=DEfactor*fr2/r2; } x=x*scaleb+xx; y=y*scaleb+yy; z=z*scaleb+zz; DEfactor=DEfactor*abs(scaleb)+1; r2=x*x+y*y+z*z; } return sqrt(r2)/DEfactor;
} void draw() { loadPixels(); for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { float dx=(float)i/(float)width-0.5; float dy=((float)j/(float)height-0.5)*(float)height/(float)width; float dz=1.0,r=1.0/sqrt(dx*dx+dy*dy+1.0);dx*=r;dy*=r;dz*=r; float x=0,y=0,z=0,rayLen=0,dist=maxDepth; int steps = 255; while (steps-- > 0 && dist>=minThreshold && rayLen < maxDepth) { rayLen += dist = DE(x,y,z-4.0)*0.5; x=dx*rayLen;y=dy*rayLen;z=dz*rayLen; } if(dist<minThreshold){//eventually you will want to do more here //... like find the surface normal and calculate lighting pixels[i+j*width] = (steps<<16)+(steps<<8)+steps; } } } updatePixels(); }
PS: thanx 2 Knighty
|
|
« Last Edit: April 25, 2012, 11:34:46 PM by visual.bermarte, Reason: adding 3d »
|
Logged
|
|
|
|
asimes
|
|
« Reply #4 on: April 26, 2012, 04:09:46 AM » |
|
cKleinhuis, thanks for the tips. If I understood correctly, I'm only interested in points that never hit the bailout? Also, I'm having a very difficult time finding a distance estimation tutorial that doesn't assume I rock at math, do you know a nice one? visual.bermarte, I made some changes to the first code you posted, it is pretty fun! It works in Processing now, I'll post it below. The biggest change was multiplying mouseX by dx and the same for mouseY but with dy (I took off the colors, a bit too psychedelic for me, ha ha). I'll have to go through your Mandelbox code a few more times to make sure I make sense of why it works now though: float xmin = -4; float ymin = -4; float wh = 8; int maxiterations = 10;
void setup() { size(800, 800, P2D); }
void draw() { loadPixels(); background(0); float xmax = xmin + wh; float ymax = ymin + wh; float dx = (xmax - xmin) / (width); float dy = (ymax - ymin) / (height); float y = ymin; for (int j = 0; j < height; j++) { float x = xmin; for (int i = 0; i < width; i++) { float a = x; float b = y; int n = 0; float xx, yy, r2, mr, scaleb; float fr, fr2, mr2; scaleb = -2.7; mr2 = mouseX*dx; fr2 = mr2*2; xx = a; yy = b; while (n < maxiterations) { if (a > mouseX*dx) a = mouseX*dx - a; else if (a < -mouseX*dx) a = -mouseX*dx - a; if (b > mouseY*dx) b = mouseY*dx - b; else if (b < -mouseY*dx) b = -mouseY*dx - b; r2 = a*a+b*b; if (r2 < mr2) { a = a*fr2/mr2; b = b*fr2/mr2; } else if (r2 < fr2) { a = a*fr2/r2; b = b*fr2/r2; } a = a*scaleb+xx; b = b*scaleb+yy; if (r2 > 5555) break; n++; } if (n == maxiterations) pixels[i+j*width] = 0xffffff; x += dx; } y += dy; } updatePixels(); } I didn't realize you could make an interactive Mandelbox. I am familiar with the second code you posted but for a Menger Sponge instead (same Raymarching code). I'm gonna leave off playing with 3D for a while until 2D makes a lot more sense.
|
|
« Last Edit: April 26, 2012, 09:45:58 PM by asimes »
|
Logged
|
|
|
|
asimes
|
|
« Reply #5 on: April 26, 2012, 09:05:50 AM » |
|
I think I got it. I just threw in: nx = nx*bScale+x; ny = ny*bScale+y; before my bailout and I got completely different images. Here is a sample (areas that bailed are red): My screen goes from -4 to 4 on both axes, the bailout is 16, and it looks more like what I was expecting for a Mandelbox. Is it a Mandelbox yet? Here's code again: float bScale = 2.0; float minRad = 0.5; float fixedRad = 1.0; float xmin = -4.0; float ymin = -4.0; float wh = 8; int maxIterations = 3;
void setup() { size(800, 800, P2D); }
void draw() { loadPixels(); float xmax = xmin+wh; float ymax = ymin+wh; float dx = (xmax-xmin)/width; float dy = (ymax-ymin)/height; float x = xmin; float highestVal = 0; float[] pixVals = new float[width*height]; for (int i = 0; i < width; i++) { float y = ymin; for (int j = 0; j < height; j++) { float nx = x; float ny = y; float nMag = 0; int n = 0; while (n < maxIterations) { if (nx > 1) nx = bScale-nx; else if (nx < -1) nx = -bScale-nx; if (ny > 1) ny = bScale-ny; else if (ny < -1) ny = -bScale-ny; nMag = sqrt(nx*nx+ny*ny); if (nMag < minRad) { float t = (fixedRad*fixedRad)/(minRad*minRad); nx *= t; ny *= t; } else if (nMag < fixedRad) { float t = (fixedRad*fixedRad)/(nMag*nMag); nx *= t; ny *= t; } nx = nx*bScale+x; ny = ny*bScale+y; if (nx*nx+ny*ny > 16) break; nMag = nx*nx+ny*ny; n++; } if (nMag > highestVal) highestVal = nMag; if (n == maxIterations) pixVals[i+j*width] = nMag; else pixVals[i+j*width] = -1; y += dy; } x += dx; } for (int i = 0; i < width*height; i++) { if (pixVals[i] == -1) pixels[i] = 0xff0000; else { int val = (int)(log(pixVals[i])/log(highestVal)*255); pixels[i] = (val<<16)+(val<<8)+val; } } updatePixels(); println("Time: "+millis()); noLoop(); } Next step is still figuring out distance estimation coloring. Oy
|
|
|
Logged
|
|
|
|
DarkBeam
Global Moderator
Fractal Senior
Posts: 2512
Fragments of the fractal -like the tip of it
|
|
« Reply #6 on: April 26, 2012, 01:02:53 PM » |
|
I see some discontinuities on your images - that's impossible because mandelbox never breaks continuity. Or maybe it's a visual effect? Anyway it looks significantly different from what you did.
|
|
|
Logged
|
No sweat, guardian of wisdom!
|
|
|
visual.bermarte
|
|
« Reply #7 on: April 26, 2012, 09:18:39 PM » |
|
maybe it's a visual effect? no, no it's not my fault! it's ok, just increase a bit maxIteration and bailout value and try removing sqrt as well inside nMag (but 4 me the 2 of them work fine; with or without sqrt). To be able to obtain negative scales you should remove bScale here, so just: if (nx > 1) nx = 2-nx; else if (nx < -1) nx = -2-nx; if (ny > 1) ny = 2-ny; else if (ny < -1) ny = -2-ny;
|
|
« Last Edit: April 26, 2012, 09:52:17 PM by visual.bermarte »
|
Logged
|
|
|
|
asimes
|
|
« Reply #8 on: April 26, 2012, 09:45:13 PM » |
|
I actually don't really know what you guys mean when you say a fractal is continuous, I've seen that term on this board a lot. If it's not continuous it probably isn't a visual effect, I just don't know wtf I'm doing attempting to make this fractal, ha ha. On that note, could someone post a picture of what a 2D Mandelbox is "supposed" to look like with scale = 2.0, min radius = 0.5, and fixed radius = 1.0 please? It would make my life a lot easier if I knew what exactly it was that I was aiming for instead of asking / posting every time it feels close. I tried out the method that uses the boxFold() and ballFold() functions: http://www.geeks3d.com/20100427/do-you-know-the-mandelbox-fractal/v = s * ballFold(r, f*boxFold(v)) + c It gave me a result that looks like this: If anyone wants to see what I tried to do coding wise interpreting the link, here it is: float bScale = 2.0; float minRad = 0.5; float fixedRad = 1.0; float xmin = -4.0; float ymin = -4.0; float wh = 8; int maxIterations = 3;
void setup() { size(800, 800, P2D); }
void draw() { loadPixels(); float xmax = xmin+wh; float ymax = ymin+wh; float dx = (xmax-xmin)/width; float dy = (ymax-ymin)/height; float x = xmin; float highestVal = 0; float[] pixVals = new float[width*height]; for (int i = 0; i < width; i++) { float y = ymin; for (int j = 0; j < height; j++) { float nx = x; float ny = y; float nMag = 0; int n = 0; while (n < maxIterations) { nx = fixedRad*boxFold(nx); ny = fixedRad*boxFold(ny); nMag = sqrt(nx*nx+ny*ny); float transform = bScale*ballFold(nMag); nx = nx*transform+x; ny = ny*transform+y; nMag = nx*nx+ny*ny; if (nMag > 16) break; n++; } if (nMag > highestVal) highestVal = nMag; if (n == maxIterations) pixVals[i+j*width] = nMag; else pixVals[i+j*width] = -1; y += dy; } x += dx; } for (int i = 0; i < width*height; i++) { if (pixVals[i] == -1) pixels[i] = 0xff0000; else { int val = (int)(log(pixVals[i])/log(highestVal)*255); pixels[i] = (val<<16)+(val<<8)+val; } } updatePixels(); println("Time: "+millis()); noLoop(); }
float boxFold(float v) { if (v > 1) v = bScale-v; else if (v < -1) v = -bScale-v; return v; }
float ballFold(float m) { if (m < minRad) m = m/(minRad*minRad); else if (m < fixedRad) m = fixedRad/(m*m); return m; }
|
|
|
Logged
|
|
|
|
visual.bermarte
|
|
« Reply #9 on: April 26, 2012, 10:24:33 PM » |
|
sqrt and no sqrt ver. side by side There's also this one (with code) > http://www.antispork.com/
|
|
« Last Edit: April 26, 2012, 10:31:38 PM by visual.bermarte »
|
Logged
|
|
|
|
asimes
|
|
« Reply #10 on: April 27, 2012, 06:09:48 AM » |
|
I think I have it for real! It seems like I just had to flip: nMag = nx*nx+ny*ny; if (nMag > 16) break; to be: if (nMag > 16) break; nMag = nx*nx+ny*ny; Thanks visual.bermarte! I will look into the code you put too, that one looks really nice On a side note, doing: if (sqrt(nMag) > 16) break; nMag = nx*nx+ny*ny; Gives me this: Happy, happy, happy, happy
|
|
|
Logged
|
|
|
|
DarkBeam
Global Moderator
Fractal Senior
Posts: 2512
Fragments of the fractal -like the tip of it
|
|
« Reply #11 on: April 27, 2012, 09:28:49 AM » |
|
Latest images look a lot better
|
|
|
Logged
|
No sweat, guardian of wisdom!
|
|
|
|