Brand New Method for True 3D Fractals.

  • 45 Replies
  • 1093 Views

0 Members and 1 Guest are viewing this topic.

Offline TylerSmith

  • *
  • Fractal Fanatic
  • ***
  • Posts: 24
« on: October 06, 2019, 05:27:49 PM »
Hi everyone. I recently discovered a new way to generate truly 3D fractals. It's actually really simple. Unlike other methods, the level of detail is evenly distributed along the x, y and z axis. There is no distortion of any kind.

I will post some pseudocode here to explain how I did it. I had to edit this post because they thought I was spamming so I can't add an image directly but I will post an image as a reply.

cr=x-coordinate;
cri=y-coordinate;
ci=z-coordinate;

zr=0;
zri=0;
zi=0;

repeat(iterations){
   
    tempzr=zr*zr-zri*zri+cr;
    tempzri=2*zr*zri+cri;
    zr=tempzr;
    zri=tempzri;

    tempzri=zri*zri-zi*zi+cri;
    tempzi=2*zri*zi+ci;
    zri=tempzri;
    zi=tempzi;

}

if(zri*zi<2){
    //is in the set
    return true;
}
else{
    //is not in the set
    return false;
}


It's essentially a different way of looking at it. Instead of seeing the set as a "set", see it as a transformation of 2D coordinates. And then apply two transformations to the coordinates. One transformation along x and y. And then transform it again along y and z.

If you use this in a volumetric renderer it makes what I think are the first truly flawless 3D fractals.

It works for any variation of the set.

Linkback: https://fractalforums.org/fractal-mathematics-and-new-theories/28/brand-new-method-for-true-3d-fractals/3118/
« Last Edit: October 06, 2019, 11:41:14 PM by TylerSmith »

Offline 3DickUlus

  • *
  • 3f
  • ******
  • Posts: 1404
    • Digilantism
« Reply #1 on: October 06, 2019, 10:41:26 PM »
We don't have a spam flag but I like the idea and will look into coding something up :D
Fragmentarium is not a toy, it is a very versatile tool that can be used to make toys ;)

https://en.wikibooks.org/wiki/Fractals/fragmentarium

Offline TylerSmith

  • *
  • Fractal Fanatic
  • ***
  • Posts: 24
« Reply #2 on: October 06, 2019, 11:36:43 PM »
Here is my reply with an image I generated of what I personally consider the first truly 3D Mandelbrot set.

[/img]

Offline TylerSmith

  • *
  • Fractal Fanatic
  • ***
  • Posts: 24
« Reply #3 on: October 07, 2019, 12:07:09 AM »
Here's a link to a youtube video I made with more fractals and a better explanation.

https://youtu.be/UcNpfabIpu4

Offline marcm200

  • *
  • Fractal Frogurt
  • ******
  • Posts: 488
« Reply #4 on: October 07, 2019, 10:08:11 AM »
Here is my reply with an image I generated of what I personally consider the first truly 3D Mandelbrot set.
[/img]
In what sense is it "truly" - or more true than David Makin's formula e.g. or any other 3D tricomplex formula that needs all three coordinates to display the object?

Does your object show smaller copies of itself when zooming ?

Have you defined higher powers ? And do those show small copies of the original version ? (since 2D Msets are everywhere).

Which of the common continuum laws (distributive, associative etc.) does your transformation hold ?

Offline TylerSmith

  • *
  • Fractal Fanatic
  • ***
  • Posts: 24
« Reply #5 on: October 07, 2019, 07:33:37 PM »
In what sense is it "truly" - or more true than David Makin's formula e.g. or any other 3D tricomplex formula that needs all three coordinates to display the object?

There is no distortion. No second coordinate system. There isn't anything being added.

Does your object show smaller copies of itself when zooming ?

Yes. Infinite detail as expected.

Have you defined higher powers ? And do those show small copies of the original version ? (since 2D Msets are everywhere).

Yea. But they don't show small copies of the 2d. They show small self similar copies of the overall 3d shape.

Which of the common continuum laws (distributive, associative etc.) does your transformation hold ?

Are you talking about Commutative, Associative and Distributive Laws? Those are just general mathematical principals.

Let me try to explain what this is doing.

x and y generate zr and zi like normal. we keep zr as kind of a placeholdee and we use rhe resulting zi and z coordinate to get the final point.

So all the points in the original set are still all there. They're just redistributed. Nothing is gained or lost.

Here's a whole julia set and here's a small part of that julia set.

Offline TylerSmith

  • *
  • Fractal Fanatic
  • ***
  • Posts: 24
« Reply #6 on: October 07, 2019, 07:40:45 PM »
Here's a  3D Julia set and a zoomed in part of that julia set. Same equation as what I posted.

Offline TylerSmith

  • *
  • Fractal Fanatic
  • ***
  • Posts: 24
« Reply #7 on: October 07, 2019, 07:45:56 PM »
Here's proof you can zoom in.

Offline marcm200

  • *
  • Fractal Frogurt
  • ******
  • Posts: 488
« Reply #8 on: October 07, 2019, 10:09:08 PM »
Are you talking about Commutative, Associative and Distributive Laws? Those are just general mathematical principals.
Yes, that's what I meant. I think a true 3D Mset should abide by as many of those laws as possible to mimick as much as possible an algebra in 3D (if I recall correctly, no algebra can abide all laws, so it would be interesting to know how many your transformations hold - the more the better I think.

if(zri*zi<2){
    //is in the set
    return true;
}
I do not understand your metric. I would have expected for an escape-time fractal something like (zr_new+zi_new+zri_new) < value (maybe those two metrics are equivalent - if it escapes in one, it does in the other, but I don't know).

Is the object completely enclosed in the region depicted by your metric and 2 - or does it change with the value ?

I tried to condense your iteration routine into a closed formula (I'd like to use it to compute some Julia sets myself if that's okay with you). I came up with the following (if it's wrong, please ignore what I write next):

    zr_new=zr_old^2-zri_old^2+cr;
    zri_new=(2*zr_old*zri_old+cri)^2-zi_old^2+cri;
    zi_new=2*(2*zr_old*zri_old+cri)*zi_old+ci;

Your zr_new depends on zr_old and zri_old but not on zi_old -  in the 2D complex multiplication both the new real and imaginary part depend on both the old real and imaginary. I would expect the same for a 3D MSet that each coordinate depends on all three old ones. Did you try altering your transformation in such a way ?

Offline TylerSmith

  • *
  • Fractal Fanatic
  • ***
  • Posts: 24
« Reply #9 on: October 08, 2019, 01:40:43 AM »
It is completely enclosed from -2,-2,-2 to 2,2,2 just like the 2D set.

The images I posted so far are all showing the whole set. I'm working out some kinks to be able to properly move the camera in 3d.

Here is the equation that you asked for. It's the same equation as before but with substitution. I just tested it and it generates the same images.


zr_new = zr_old * zr_old - zri_old * zri_old + cr;
zri_new = ( 2 * zr_old * zri_old + cri ) * ( 2 * zr_old * zri_old + cri ) - zi_old * zi_old + cri;
zi_new = 2 * ( 2 * zr_old * zri_old + cri ) * zi_old + ci;

This is in code.
* = multiplication

All three aren't dependent on each other. You are right but that's for a reason.

First of all, it iterates. So that lack of dependency is resolved once it iterates. You cold take the result of the first iteration and manually plug it back in to the second iteration if you want, but that's redundant.

Secondly, for a 2D set you need two components that behave differently. Real and imaginary. For a 3D set you need a third component. There is no number that is the opposite of 1 and the opposite of -1 that is neither of those numbers. So what we do is take the imaginary component and plug it in but only plug it in where the real component was and only for two of the values.

We've got a real component, an imaginary component and an imaginary component that pretends to be real.

Look at this part:
zri_new = ( 2 * zr_old * zri_old + cri ) * ( 2 * zr_old * zri_old + cri ) - zi_old * zi_old + cri;

If the value in brackets comes out as positive it stays positive as it is multiplied with itself. If it comes out as negative it gets switched to positive as it multiplies with itself.

Look at this part:
zi_new = 2 * ( 2 * zr_old * zri_old + cri ) * zi_old + ci;

In this case the value in brackets stays negative if it's negative and stays positive if it's positive.

So this creates a bit of a flux between positive and negative as it iterates.

I can't explain it better than that right now. I don't think in words lol.

But basically, the real component is generated from x and y as it would be in a 2d set as is the imaginary component. So we now have xyreal and xyimaginary. We set aside xyreal(isolate it from the rest of equation). We take xyimaginary and treat it like it's a real component and treat z as rhe new imaginary. So those two values create a new real and imaginary value. Then the whole thing iterates and xyreal comes back after being temporarily set aside.

Once you're done iterating you can use the escape time as normal to color a point. But you'd have to use the escape time to set an alpha/transparency value because if you just color them based on escape time and look at it in 3d you will be obscuring the shapes and you will just get a giant blob.

If you want to generate a slice of it in 2D using escape time, do that. Just use x and y as normal and fix z to any value you want (0 for the center, must be between 2 and -2.

Yes, that's what I meant. I think a true 3D Mset should abide by as many of those laws as possible to mimick as much as possible an algebra in 3D (if I recall correctly, no algebra can abide all laws, so it would be interesting to know how many your transformations hold - the more the better I think.
I do not understand your metric. I would have expected for an escape-time fractal something like (zr_new+zi_new+zri_new) < value (maybe those two metrics are equivalent - if it escapes in one, it does in the other, but I don't know).

Is the object completely enclosed in the region depicted by your metric and 2 - or does it change with the value ?

I tried to condense your iteration routine into a closed formula (I'd like to use it to compute some Julia sets myself if that's okay with you). I came up with the following (if it's wrong, please ignore what I write next):

    zr_new=zr_old^2-zri_old^2+cr;
    zri_new=(2*zr_old*zri_old+cri)^2-zi_old^2+cri;
    zi_new=2*(2*zr_old*zri_old+cri)*zi_old+ci;

Your zr_new depends on zr_old and zri_old but not on zi_old -  in the 2D complex multiplication both the new real and imaginary part depend on both the old real and imaginary. I would expect the same for a 3D MSet that each coordinate depends on all three old ones. Did you try altering your transformation in such a way ?

Offline Softology

  • *
  • Fractal Phenom
  • ****
  • Posts: 42
« Reply #10 on: October 08, 2019, 02:10:31 AM »
This is what I get from the formula in the original post


Using a brute force (ie no distance estimation) method to render the fractal.

Quick GLSL shader code follows

Code: [Select]
#version 120

//brute force fractal raytracer
//steps along each ray in fixed distance incrememnts
//no distance estimation used

uniform vec2 resolution;
uniform float time;
uniform vec2 mouse;
uniform int frames;

//unremark which render method you want to use
#define XYZtoRGB
#define Normal

//how many steps are made along each ray when looking for the fractal surface
#define RaySteps 10000000

//supersampling - 1=off
#define samplepixels 1

//rotations
//#define xrot 140.0
//#define yrot 0.0
//#define zrot 0.0
//uncomment the following 3 lines to auto-rotate the fractal
#define xrot time*90.0
#define yrot time*50.0
#define zrot time*70.0

float Power=2.0;
float Bailout=40.0;
int maxiter=10;
float CameraDistance=5.4;
#define minorbit 0.5 //higher value make darker crevices
#define maxorbit 1.0 //lower values make brighter surface

//global variables
bool inside=false;
vec3 z,c,CameraPosition,RayDirection;
float smallestorbit,stepsize;
float PI=3.14159265;
float pidiv180=PI/180.0;

void Rotate2(in float Rx, in float Ry, in float Rz, in float x, in float y, in float z, out float Nx, out float Ny, out float Nz) {
    float TempX,TempY,TempZ,SinX,SinY,SinZ,CosX,CosY,CosZ,XRadAng,YRadAng,ZRadAng;
    XRadAng=Rx*pidiv180;
    YRadAng=Ry*pidiv180;
    ZRadAng=Rz*pidiv180;
    SinX=sin(XRadAng);
    SinY=sin(YRadAng);
    SinZ=sin(ZRadAng);
    CosX=cos(XRadAng);
    CosY=cos(YRadAng);
    CosZ=cos(ZRadAng);
    TempY=y*CosY-z*SinY;
    TempZ=y*SinY+z*CosY;
    TempX=x*CosX-TempZ*SinX;
    Nz=x*SinX+TempZ*CosX;
    Nx=TempX*CosZ-TempY*SinZ;
    Ny=TempX*SinZ+TempY*CosZ;
}

void Rotate(in float Rx, in float Ry, in float Rz, in float x, in float y, in float z, in float ox, in float oy, in float oz, out float Nx, out float Ny, out float Nz){
    Rotate2(Rx,Ry,Rz,x-ox,y-oy,z-oz,Nx,Ny,Nz);
    Nx=Nx+ox;
    Ny=Ny+oy;
    Nz=Nz+oz;
}

//performs one iteration
void Iterate(inout vec3 z,in vec3 c) {
    float tempzr,tempzri,tempzi,zr,zri,zi,cr,cri,ci,r;
   
    zr=z.x;
    zri=z.y;
    zi=z.z;
   
    cr=c.x;
    cri=c.y;
    ci=c.z;
   
    //ambient occlusion
    r=length(z);
    if (r<smallestorbit) { smallestorbit=r; }

    // https://fractalforums.org/fractal-mathematics-and-new-theories/28/brand-new-method-for-true-3d-fractals/3118/msg17107
    tempzr=zr*zr-zri*zri+cr;
    tempzri=2*zr*zri+cri;
    zr=tempzr;
    zri=tempzri;
    tempzri=zri*zri-zi*zi+cri;
    tempzi=2*zri*zi+ci;
    zri=tempzri;
    zi=tempzi;

   
    z.x=zr;
    z.y=zri;
    z.z=zi;
}

//iterate the formula to determine if the passed point is inside the fractal
bool isinside(vec3 c){
    float lengthz;
    int itercount;
    z=c;

    //next line is a simple sphere to test
    //if (length(z)<1.0) { inside=true; } else { inside=false; }

   
    inside=true;
    for(int i=0;(i<maxiter);i++) {
       
        itercount=i;

        Iterate(z,c);
       
    }
   
    // https://fractalforums.org/fractal-mathematics-and-new-theories/28/brand-new-method-for-true-3d-fractals/3118/msg17107
    if(z.y*z.z<2){
    //is in the set
    inside=true;
    } else{
    //is not in the set
    inside=false;
    }       
       
   
    return inside;
}
 
//walks the ray and sets dist to how far the fractal surface is
void BruteForceDistance(inout vec3 dist,in float startdistance){
        float f=startdistance;
       
        smallestorbit=100000.0;

        //step along the ray - break when inside the fractal
        for(int i=0;i<RaySteps;i++){
            f+=stepsize*float(i);
            c=CameraPosition+RayDirection*f;
            dist=c-CameraPosition;
            if (isinside(c)==true) { break; }
            if (length(c)>Bailout) { break; }
    }
}

void main(void){
    int xsamp,ysamp;
    float xstep,ystep,rtot,gtot,btot,mx,my,lastdistance,p2dist,p3dist,p4dist,p5dist,p6dist,p7dist;
    vec2 vPos;
    vec3 dist,CameraUpVector,CameraRotation,ViewPlaneNormal,u,v,vcv,scrCoord,SurfaceNormal,p1,p2,p3,p4,p5,p6,p7;
    vec3 N,T,B,L,rO,rD,Ntmp,n,n1,n2;
    float thisr,thisg,thisb,aspect,beta,alpha,amin,amax,bmin,bmax,awidth,bheight,xp,yp,fov,DiffuseFactor;
    vec3 eye,lookat,up,lightpos,diffuse,VectorToLight,E,NdotL;

    lightpos=vec3(-25.0,-25.0,10.0);
   
    lookat=vec3(0.0,0.0,0.0);
    eye=vec3(0.0,0.0,1.0)*CameraDistance;
    up=vec3(0.0,1.0,0.0);
    fov=35.0;
       
    //construct the basis
    N=normalize(lookat-eye);
    T=normalize(up);
    B=cross(N,T);
    aspect=resolution.x/resolution.y;
    beta=tan(fov*pidiv180)/2.0;
    alpha=beta*aspect;
    amin=-alpha;
    amax=alpha;
    bmin=-beta;
    bmax=beta;
    awidth=amax-amin;
    bheight=bmax-bmin;
    xstep=awidth/resolution.x;
    ystep=bheight/resolution.y;
   
    rtot=0.0;
    gtot=0.0;
    btot=0.0;

    dist=vec3(0.0,0.0,0.0);

    for (xsamp=0;xsamp<samplepixels;xsamp++) {
        for (ysamp=0;ysamp<samplepixels;ysamp++) {
           
            //x and y locations
            //these are the coordinates the ray will go through in 3d space
            xp=(gl_FragCoord.x/resolution.x)*awidth-abs(amin)+(xstep*float(xsamp)/float(samplepixels))-xstep*0.5;
            yp=bheight-(gl_FragCoord.y/resolution.y)*bheight-abs(bmin)+(ystep*float(ysamp)/float(samplepixels))-ystep*0.5;

            //set ray direction vector
            rD=normalize(xp*T+yp*B+N);
            //ray origin - starts from the eye location
            rO=eye;
            //rotations
            Rotate(xrot,yrot,zrot,rO.x,rO.y,rO.z,0.0,0.0,0.0,rO.x,rO.y,rO.z);
            Rotate(xrot,yrot,zrot,rD.x,rD.y,rD.z,0.0,0.0,0.0,rD.x,rD.y,rD.z);
            //light rotates with camera
            //Rotate(xrot,yrot,zrot,lightpos.x,lightpos.y,lightpos.z,0.0,0.0,0.0,lightpos.x,lightpos.y,lightpos.z);
           
            CameraPosition=rO;
            RayDirection=rD;

            stepsize=CameraDistance*2.0/float(RaySteps);
           
            BruteForceDistance(dist,0.0);
            lastdistance=length(dist);
           
            if (inside==true){
               
            //Normal based color
                #ifdef Normal
               
                    p1=c;

                    //epsilon value
                    //float eps=xstep/samplepixels*2.0;
                    //float eps=0.001;
                    float eps=xstep/samplepixels;
                       

                    lastdistance=length(c-rO);
   
                    rD=normalize(xp*T+yp*B+N);
                    rD.x-=float(eps);
                    rO=eye;
                    Rotate(xrot,yrot,zrot,rO.x,rO.y,rO.z,0.0,0.0,0.0,rO.x,rO.y,rO.z);
                    CameraPosition=rO;

                    Rotate(xrot,yrot,zrot,rD.x,rD.y,rD.z,0.0,0.0,0.0,rD.x,rD.y,rD.z);
                    RayDirection=rD;
                    BruteForceDistance(dist,lastdistance*0.95);
                    //BruteForceDistance(dist,0);
                    p2=c;
               
                    rD=normalize(xp*T+yp*B+N);
                    rD.x+=float(eps);
                    Rotate(xrot,yrot,zrot,rD.x,rD.y,rD.z,0.0,0.0,0.0,rD.x,rD.y,rD.z);
                    CameraPosition=rO;
                    RayDirection=rD;
                    BruteForceDistance(dist,lastdistance*0.95);
                    //BruteForceDistance(dist,0);
                    p3=c;

                    rD=normalize(xp*T+yp*B+N);
                    rD.y-=float(eps);
                    Rotate(xrot,yrot,zrot,rD.x,rD.y,rD.z,0.0,0.0,0.0,rD.x,rD.y,rD.z);
                    CameraPosition=rO;
                    RayDirection=rD;
                    BruteForceDistance(dist,lastdistance*0.95);
                    //BruteForceDistance(dist,0);
                    p4=c;
               
                    rD=normalize(xp*T+yp*B+N);
                    rD.y+=float(eps);
                    Rotate(xrot,yrot,zrot,rD.x,rD.y,rD.z,0.0,0.0,0.0,rD.x,rD.y,rD.z);
                    CameraPosition=rO;
                    RayDirection=rD;
                    BruteForceDistance(dist,lastdistance*0.95);
                    //BruteForceDistance(dist,0);
                    p5=c;

                    rD=normalize(xp*T+yp*B+N);
                    rD.z-=float(eps);
                    Rotate(xrot,yrot,zrot,rD.x,rD.y,rD.z,0.0,0.0,0.0,rD.x,rD.y,rD.z);
                    CameraPosition=rO;
                    RayDirection=rD;
                    BruteForceDistance(dist,lastdistance*0.95);
                    //BruteForceDistance(dist,0);
                    p6=c;
               
                    rD=normalize(xp*T+yp*B+N);
                    rD.z+=float(eps);
                    Rotate(xrot,yrot,zrot,rD.x,rD.y,rD.z,0.0,0.0,0.0,rD.x,rD.y,rD.z);
                    CameraPosition=rO;
                    RayDirection=rD;
                    BruteForceDistance(dist,lastdistance*0.95);
                    //BruteForceDistance(dist,0);
                    p7=c;

                    vec3 grad;
                    grad.x=(p3.x*p3.x+p3.y*p3.y+p3.z*p3.z)-(p2.x*p2.x+p2.y*p2.y+p2.z*p2.z);
                    grad.y=(p5.x*p5.x+p5.y*p5.y+p5.z*p5.z)-(p4.x*p4.x+p4.y*p4.y+p4.z*p4.z);
                    grad.z=(p7.x*p7.x+p7.y*p7.y+p7.z*p7.z)-(p6.x*p6.x+p6.y*p6.y+p6.z*p6.z);
                    n=normalize(grad);
                   
                    diffuse.x=0.2;
                    diffuse.y=0.2;
                    diffuse.z=0.2;

                    //the vector to the first light
                    VectorToLight=normalize(lightpos-p1);
                    //the vector to the eye
                    E=normalize(eye-p1);
                    //the cosine of the angle between light and normal
                    //NdotL=n*VectorToLight;
                    NdotL = vec3(dot(VectorToLight,n));
                    DiffuseFactor=NdotL.x+NdotL.y+NdotL.z;
                    // compute the illumination using the Phong equation
                    //0.2 is ambient light - without it shadows are black
                    //diffuse=diffuse*max(DiffuseFactor,0.1)*2.0; //scale the light intensity
                    diffuse=diffuse*DiffuseFactor;
                   
                   
                    rtot+=diffuse.x;
                    gtot+=diffuse.y;
                    btot+=diffuse.z;

                #endif

                //XYZ to RGB mappping
                #ifdef XYZtoRGB
                    rtot+=float(abs(c.x));
                    gtot+=float(abs(c.y));
                    btot+=float(abs(c.z));
                #endif
               
               
            } else {
                //background color
                rtot+=0.1;
                gtot+=0.1;
                btot+=0.1;
            }
            //ambient occlusion based on min dist
                #ifdef AmbientOcclusion
                    if (smallestorbit<minorbit) { smallestorbit=minorbit; }
                    if (smallestorbit>maxorbit) { smallestorbit=maxorbit; }
                    smallestorbit=(smallestorbit-minorbit)/(maxorbit-minorbit);
                    rtot*=smallestorbit;
                    gtot*=smallestorbit;
                    btot*=smallestorbit;
                #endif

        }
    }
               
    rtot=rtot/float(samplepixels*samplepixels);
    gtot=gtot/float(samplepixels*samplepixels);
    btot=btot/float(samplepixels*samplepixels);

    gl_FragColor=vec4(rtot,gtot,btot,1.0);
}


Jason.

Offline TylerSmith

  • *
  • Fractal Fanatic
  • ***
  • Posts: 24
« Reply #11 on: October 08, 2019, 05:41:32 AM »
That looks like a less detailed version of what I got in that first image I posted with more accurate perspective.

Can you please swap the c values and the z values and make a julia set or two? I'd love to see those like that.
-0.3,-0.3,-0.3 for the starting values. Would be awesome hehe.

This is what I get from the formula in the original post


Using a brute force (ie no distance estimation) method to render the fractal.

Quick GLSL shader code follows

Code: [Select]
#version 120

//brute force fractal raytracer
//steps along each ray in fixed distance incrememnts
//no distance estimation used

uniform vec2 resolution;
uniform float time;
uniform vec2 mouse;
uniform int frames;

//unremark which render method you want to use
#define XYZtoRGB
#define Normal

//how many steps are made along each ray when looking for the fractal surface
#define RaySteps 10000000

//supersampling - 1=off
#define samplepixels 1

//rotations
//#define xrot 140.0
//#define yrot 0.0
//#define zrot 0.0
//uncomment the following 3 lines to auto-rotate the fractal
#define xrot time*90.0
#define yrot time*50.0
#define zrot time*70.0

float Power=2.0;
float Bailout=40.0;
int maxiter=10;
float CameraDistance=5.4;
#define minorbit 0.5 //higher value make darker crevices
#define maxorbit 1.0 //lower values make brighter surface

//global variables
bool inside=false;
vec3 z,c,CameraPosition,RayDirection;
float smallestorbit,stepsize;
float PI=3.14159265;
float pidiv180=PI/180.0;

void Rotate2(in float Rx, in float Ry, in float Rz, in float x, in float y, in float z, out float Nx, out float Ny, out float Nz) {
    float TempX,TempY,TempZ,SinX,SinY,SinZ,CosX,CosY,CosZ,XRadAng,YRadAng,ZRadAng;
    XRadAng=Rx*pidiv180;
    YRadAng=Ry*pidiv180;
    ZRadAng=Rz*pidiv180;
    SinX=sin(XRadAng);
    SinY=sin(YRadAng);
    SinZ=sin(ZRadAng);
    CosX=cos(XRadAng);
    CosY=cos(YRadAng);
    CosZ=cos(ZRadAng);
    TempY=y*CosY-z*SinY;
    TempZ=y*SinY+z*CosY;
    TempX=x*CosX-TempZ*SinX;
    Nz=x*SinX+TempZ*CosX;
    Nx=TempX*CosZ-TempY*SinZ;
    Ny=TempX*SinZ+TempY*CosZ;
}

void Rotate(in float Rx, in float Ry, in float Rz, in float x, in float y, in float z, in float ox, in float oy, in float oz, out float Nx, out float Ny, out float Nz){
    Rotate2(Rx,Ry,Rz,x-ox,y-oy,z-oz,Nx,Ny,Nz);
    Nx=Nx+ox;
    Ny=Ny+oy;
    Nz=Nz+oz;
}

//performs one iteration
void Iterate(inout vec3 z,in vec3 c) {
    float tempzr,tempzri,tempzi,zr,zri,zi,cr,cri,ci,r;
   
    zr=z.x;
    zri=z.y;
    zi=z.z;
   
    cr=c.x;
    cri=c.y;
    ci=c.z;
   
    //ambient occlusion
    r=length(z);
    if (r<smallestorbit) { smallestorbit=r; }

    // https://fractalforums.org/fractal-mathematics-and-new-theories/28/brand-new-method-for-true-3d-fractals/3118/msg17107
    tempzr=zr*zr-zri*zri+cr;
    tempzri=2*zr*zri+cri;
    zr=tempzr;
    zri=tempzri;
    tempzri=zri*zri-zi*zi+cri;
    tempzi=2*zri*zi+ci;
    zri=tempzri;
    zi=tempzi;

   
    z.x=zr;
    z.y=zri;
    z.z=zi;
}

//iterate the formula to determine if the passed point is inside the fractal
bool isinside(vec3 c){
    float lengthz;
    int itercount;
    z=c;

    //next line is a simple sphere to test
    //if (length(z)<1.0) { inside=true; } else { inside=false; }

   
    inside=true;
    for(int i=0;(i<maxiter);i++) {
       
        itercount=i;

        Iterate(z,c);
       
    }
   
    // https://fractalforums.org/fractal-mathematics-and-new-theories/28/brand-new-method-for-true-3d-fractals/3118/msg17107
    if(z.y*z.z<2){
    //is in the set
    inside=true;
    } else{
    //is not in the set
    inside=false;
    }       
       
   
    return inside;
}
 
//walks the ray and sets dist to how far the fractal surface is
void BruteForceDistance(inout vec3 dist,in float startdistance){
        float f=startdistance;
       
        smallestorbit=100000.0;

        //step along the ray - break when inside the fractal
        for(int i=0;i<RaySteps;i++){
            f+=stepsize*float(i);
            c=CameraPosition+RayDirection*f;
            dist=c-CameraPosition;
            if (isinside(c)==true) { break; }
            if (length(c)>Bailout) { break; }
    }
}

void main(void){
    int xsamp,ysamp;
    float xstep,ystep,rtot,gtot,btot,mx,my,lastdistance,p2dist,p3dist,p4dist,p5dist,p6dist,p7dist;
    vec2 vPos;
    vec3 dist,CameraUpVector,CameraRotation,ViewPlaneNormal,u,v,vcv,scrCoord,SurfaceNormal,p1,p2,p3,p4,p5,p6,p7;
    vec3 N,T,B,L,rO,rD,Ntmp,n,n1,n2;
    float thisr,thisg,thisb,aspect,beta,alpha,amin,amax,bmin,bmax,awidth,bheight,xp,yp,fov,DiffuseFactor;
    vec3 eye,lookat,up,lightpos,diffuse,VectorToLight,E,NdotL;

    lightpos=vec3(-25.0,-25.0,10.0);
   
    lookat=vec3(0.0,0.0,0.0);
    eye=vec3(0.0,0.0,1.0)*CameraDistance;
    up=vec3(0.0,1.0,0.0);
    fov=35.0;
       
    //construct the basis
    N=normalize(lookat-eye);
    T=normalize(up);
    B=cross(N,T);
    aspect=resolution.x/resolution.y;
    beta=tan(fov*pidiv180)/2.0;
    alpha=beta*aspect;
    amin=-alpha;
    amax=alpha;
    bmin=-beta;
    bmax=beta;
    awidth=amax-amin;
    bheight=bmax-bmin;
    xstep=awidth/resolution.x;
    ystep=bheight/resolution.y;
   
    rtot=0.0;
    gtot=0.0;
    btot=0.0;

    dist=vec3(0.0,0.0,0.0);

    for (xsamp=0;xsamp<samplepixels;xsamp++) {
        for (ysamp=0;ysamp<samplepixels;ysamp++) {
           
            //x and y locations
            //these are the coordinates the ray will go through in 3d space
            xp=(gl_FragCoord.x/resolution.x)*awidth-abs(amin)+(xstep*float(xsamp)/float(samplepixels))-xstep*0.5;
            yp=bheight-(gl_FragCoord.y/resolution.y)*bheight-abs(bmin)+(ystep*float(ysamp)/float(samplepixels))-ystep*0.5;

            //set ray direction vector
            rD=normalize(xp*T+yp*B+N);
            //ray origin - starts from the eye location
            rO=eye;
            //rotations
            Rotate(xrot,yrot,zrot,rO.x,rO.y,rO.z,0.0,0.0,0.0,rO.x,rO.y,rO.z);
            Rotate(xrot,yrot,zrot,rD.x,rD.y,rD.z,0.0,0.0,0.0,rD.x,rD.y,rD.z);
            //light rotates with camera
            //Rotate(xrot,yrot,zrot,lightpos.x,lightpos.y,lightpos.z,0.0,0.0,0.0,lightpos.x,lightpos.y,lightpos.z);
           
            CameraPosition=rO;
            RayDirection=rD;

            stepsize=CameraDistance*2.0/float(RaySteps);
           
            BruteForceDistance(dist,0.0);
            lastdistance=length(dist);
           
            if (inside==true){
               
            //Normal based color
                #ifdef Normal
               
                    p1=c;

                    //epsilon value
                    //float eps=xstep/samplepixels*2.0;
                    //float eps=0.001;
                    float eps=xstep/samplepixels;
                       

                    lastdistance=length(c-rO);
   
                    rD=normalize(xp*T+yp*B+N);
                    rD.x-=float(eps);
                    rO=eye;
                    Rotate(xrot,yrot,zrot,rO.x,rO.y,rO.z,0.0,0.0,0.0,rO.x,rO.y,rO.z);
                    CameraPosition=rO;

                    Rotate(xrot,yrot,zrot,rD.x,rD.y,rD.z,0.0,0.0,0.0,rD.x,rD.y,rD.z);
                    RayDirection=rD;
                    BruteForceDistance(dist,lastdistance*0.95);
                    //BruteForceDistance(dist,0);
                    p2=c;
               
                    rD=normalize(xp*T+yp*B+N);
                    rD.x+=float(eps);
                    Rotate(xrot,yrot,zrot,rD.x,rD.y,rD.z,0.0,0.0,0.0,rD.x,rD.y,rD.z);
                    CameraPosition=rO;
                    RayDirection=rD;
                    BruteForceDistance(dist,lastdistance*0.95);
                    //BruteForceDistance(dist,0);
                    p3=c;

                    rD=normalize(xp*T+yp*B+N);
                    rD.y-=float(eps);
                    Rotate(xrot,yrot,zrot,rD.x,rD.y,rD.z,0.0,0.0,0.0,rD.x,rD.y,rD.z);
                    CameraPosition=rO;
                    RayDirection=rD;
                    BruteForceDistance(dist,lastdistance*0.95);
                    //BruteForceDistance(dist,0);
                    p4=c;
               
                    rD=normalize(xp*T+yp*B+N);
                    rD.y+=float(eps);
                    Rotate(xrot,yrot,zrot,rD.x,rD.y,rD.z,0.0,0.0,0.0,rD.x,rD.y,rD.z);
                    CameraPosition=rO;
                    RayDirection=rD;
                    BruteForceDistance(dist,lastdistance*0.95);
                    //BruteForceDistance(dist,0);
                    p5=c;

                    rD=normalize(xp*T+yp*B+N);
                    rD.z-=float(eps);
                    Rotate(xrot,yrot,zrot,rD.x,rD.y,rD.z,0.0,0.0,0.0,rD.x,rD.y,rD.z);
                    CameraPosition=rO;
                    RayDirection=rD;
                    BruteForceDistance(dist,lastdistance*0.95);
                    //BruteForceDistance(dist,0);
                    p6=c;
               
                    rD=normalize(xp*T+yp*B+N);
                    rD.z+=float(eps);
                    Rotate(xrot,yrot,zrot,rD.x,rD.y,rD.z,0.0,0.0,0.0,rD.x,rD.y,rD.z);
                    CameraPosition=rO;
                    RayDirection=rD;
                    BruteForceDistance(dist,lastdistance*0.95);
                    //BruteForceDistance(dist,0);
                    p7=c;

                    vec3 grad;
                    grad.x=(p3.x*p3.x+p3.y*p3.y+p3.z*p3.z)-(p2.x*p2.x+p2.y*p2.y+p2.z*p2.z);
                    grad.y=(p5.x*p5.x+p5.y*p5.y+p5.z*p5.z)-(p4.x*p4.x+p4.y*p4.y+p4.z*p4.z);
                    grad.z=(p7.x*p7.x+p7.y*p7.y+p7.z*p7.z)-(p6.x*p6.x+p6.y*p6.y+p6.z*p6.z);
                    n=normalize(grad);
                   
                    diffuse.x=0.2;
                    diffuse.y=0.2;
                    diffuse.z=0.2;

                    //the vector to the first light
                    VectorToLight=normalize(lightpos-p1);
                    //the vector to the eye
                    E=normalize(eye-p1);
                    //the cosine of the angle between light and normal
                    //NdotL=n*VectorToLight;
                    NdotL = vec3(dot(VectorToLight,n));
                    DiffuseFactor=NdotL.x+NdotL.y+NdotL.z;
                    // compute the illumination using the Phong equation
                    //0.2 is ambient light - without it shadows are black
                    //diffuse=diffuse*max(DiffuseFactor,0.1)*2.0; //scale the light intensity
                    diffuse=diffuse*DiffuseFactor;
                   
                   
                    rtot+=diffuse.x;
                    gtot+=diffuse.y;
                    btot+=diffuse.z;

                #endif

                //XYZ to RGB mappping
                #ifdef XYZtoRGB
                    rtot+=float(abs(c.x));
                    gtot+=float(abs(c.y));
                    btot+=float(abs(c.z));
                #endif
               
               
            } else {
                //background color
                rtot+=0.1;
                gtot+=0.1;
                btot+=0.1;
            }
            //ambient occlusion based on min dist
                #ifdef AmbientOcclusion
                    if (smallestorbit<minorbit) { smallestorbit=minorbit; }
                    if (smallestorbit>maxorbit) { smallestorbit=maxorbit; }
                    smallestorbit=(smallestorbit-minorbit)/(maxorbit-minorbit);
                    rtot*=smallestorbit;
                    gtot*=smallestorbit;
                    btot*=smallestorbit;
                #endif

        }
    }
               
    rtot=rtot/float(samplepixels*samplepixels);
    gtot=gtot/float(samplepixels*samplepixels);
    btot=btot/float(samplepixels*samplepixels);

    gl_FragColor=vec4(rtot,gtot,btot,1.0);
}


Jason.

Offline TylerSmith

  • *
  • Fractal Fanatic
  • ***
  • Posts: 24
« Reply #12 on: October 08, 2019, 09:02:40 AM »
I coded up a program so that I could render the thing without losing any detail. It's got terribly lazy shading - is only shaded by distance from viewer and amount of points within a certain radius of the points.

But the benefit to it is that it is straight volumetric and every single point in the 3d space can be used to cough up new c values so the detail is only limited by the resolution of the render.

I changed the perspective to orthographic because I got lazy.

Here's what it looks like at 60 iterations.

Offline marcm200

  • *
  • Fractal Frogurt
  • ******
  • Posts: 488
« Reply #13 on: October 08, 2019, 09:04:46 AM »
Could you explain a little bit your metric zri*zi as being the judge of interior/exterior the set?

zr=0;
zri=0;
zi=0;
Is the origin a critical point for your transformation? From the condensed formulas I wouldn't be too surprised to have some cr, cri or ci in a partial derivative in the Jacobian, but maybe they all cancel out.

Is there a general property Julia sets from outside your object have or have not as compared to the ones inside (like (dis)connectivity in the 2D case)?

Don't get me wrong: I'm just trying to understand your "truly" claim. It's an interesting shape you found, looks almost like a space ship of an old game I used to play ages ago ("Elite" for the Amstrad/Schneider folks out there) :)

Offline TylerSmith

  • *
  • Fractal Fanatic
  • ***
  • Posts: 24
« Reply #14 on: October 08, 2019, 09:25:09 AM »
Well...the way that's worded I can't really work with it. You can make Julia sets out of it and the julia sets just outside the shape are disconected and the julia sets inside the shape are solid as far as what I've tested so far.

I'm attaching a low res render of a somewhat disconnected Julia set (hard to tell in 3d because closer parts obscure the further ones)

As far as the truly claim goes - I'm very confident that I got it right. It's a bold claim but I made this a goal of mine like 13 years ago and put more than enough thought into it lol. But if I'm wrong that's fine too it happens. Either way I'm having fun :)

Honestly, I have tried using different combinations of the values and it doesn't seem to make a difference if I use all three, or just two. It seems to work with 3 however the second part of the equation is essentially a mandelbrot equation which will output two values so that's why I'm using the second two.

I think they cancel out as far as I can tell but who knows I could be wrong.

Could you explain a little bit your metric zri*zi as being the judge of interior/exterior the set?
Is the origin a critical point for your transformation? From the condensed formulas I wouldn't be too surprised to have some cr, cri or ci in a partial derivative in the Jacobian, but maybe they all cancel out.

Is there a general property Julia sets from outside your object have or have not as compared to the ones inside (like (dis)connectivity in the 2D case)?

Don't get me wrong: I'm just trying to understand your "truly" claim. It's an interesting shape you found, looks almost like a space ship of an old game I used to play ages ago ("Elite" for the Amstrad/Schneider folks out there) :)



xx
Slightly extended Newton method fractals

Started by gannjondal on Fractal Mathematics And New Theories

6 Replies
253 Views
Last post September 29, 2019, 10:18:01 PM
by gerrit
xx
Is it possible to speed up rendering with this method?

Started by Fluoroantimonic_Acid on Fractal Mathematics And New Theories

3 Replies
202 Views
Last post April 19, 2019, 12:59:29 AM
by gerrit
xx
Out of band method to contact admins?

Started by pauldelbrot on Forum Help And Support

6 Replies
282 Views
Last post September 04, 2018, 08:37:11 AM
by quaz0r
clip
Neat variation of Newton's method

Started by Ebanflo on Share a fractal

1 Replies
325 Views
Last post April 17, 2018, 04:34:13 PM
by mrrudewords
xx
Method of Early Checking Whether a Point Is In the Set

Started by Byte11 on Fractal Mathematics And New Theories

12 Replies
701 Views
Last post December 24, 2017, 12:33:10 AM
by Byte11