// I have replaced the Mandelbox Formula by the 3DJulia formula to test the influence of different
// parameters of the strange spirals in real time.
// Distance estimation is removed, so it should be easy to define own fractals in computeDistAndColors().
// This function has only to decide, if a given point is inside or outside to fractal. Additional
// a surface color can be defined.
// You have to save this text in a file with name fragment.glsl and put it in the same directory as
// Boxplorer.exe
// Pressing q or w change a spiral parameter (fine tuning of this parameter is done with a and s).
// All other keys are used like the original shader.
// Mandelbox shader by Rrrola
// Original formula by Tglad
// -
http://www.fractalforums.com/3d-fractal-generation/amazing-fractal// Changed to formula 21 (3DJulia) by trafassel
// Camera position and direction.
varying vec3 eye, dir;
// Interactive parameters.
uniform float scale, // Fractal scale. Controls the appearance of the Mandelbox.
min_dist, // Distance at which sphere tracing stops.
eps; // Epsilon for surface normal approximation.
uniform int iters, // Number of fractal iterations.
max_steps; // Maximum sphere tracing steps.
// some parameters to change
// the default formula uses para1 and para2
static float para1;
static float para2;
static float para3;
static float para4;
static float para5;
static float para6;
static float para7;
static float para8;
// Colors.
vec3 backgroundColor = vec3(0.25, 0, 0.5),
glowColor = vec3(0, 0.75, 1),
objectColor1 = vec3(1, 0, 0.15),
objectColor2 = vec3(1, 0.66, 0),
specularColor = vec3(1, 1, 0.75);
// Compute the "distance" from `pos` to the Mandelbox.
// Because the is no default distance estimation for arbitrary functions,
// this method has only to know, if p is inside or outside the iterative set.
// retVal[0]>0 outside, retVal[0]<0 inside the fractal
// retVal[1], retVal[2], retVal[3] Components of the surface color
// retVal[1]=red
// retVal[2]=green
// retVal[3]=blue
vec4 computeDistAndColors(vec3 p) {
// a little bit scaling to get a nice start view
p=0.4*p;
vec4 retVal=vec4(0,0,0,0);
vec3 col=vec3(0,0,0);
// Preparation:
float xx=p.x*p.x;
float yy=p.y*p.y;
float zz=p.z*p.z;
float r=sqrt(xx+yy+zz);
float myI=0.0;
int myIters=5;
float lastr=0.0;
float bailoutr=300.0;
float myScale=scale/4.0;
for (int i=0; i<iters; i++) {
p.x=2.0*p.x*p.y*p.z;
p.y=yy-para1*(xx+zz);
p.z=zz-para1*(xx+yy);
xx=p.x*p.x;yy=p.y*p.y;zz=p.z*p.z;
p.y=2.0*p.x*p.y*p.z;
p.x=xx-para1*(yy+zz);
p.z=zz-para1*(xx+yy);
// Julia Seed
p.z+=para2;
xx=p.x*p.x;yy=p.y*p.y;zz=p.z*p.z;
float tempDist=xx+yy+zz;
float r=sqrt(tempDist);
if(i>2&&i<iters-1) {
col[0]+=xx/tempDist;
col[1]+=yy/tempDist;
col[2]+=zz/tempDist;
}
if(r>bailoutr) {
retVal[0]=1.0;
if(i>1) // near the surface
retVal[0]=2.0;
retVal[1]=col[0];
retVal[2]=col[1];
retVal[3]=col[2];
return retVal;
}
lastr=r;
}
retVal[0]=-1.0;
retVal[1]=col[0];
retVal[2]=col[1];
retVal[3]=col[2];
return retVal;
}
// Gets the distance from pos to the fractal.
// <0, if pos is inside
float d(vec3 pos) {
return computeDistAndColors(pos)[0];
}
// Get true, if the point p is element of the fractal.
bool isInSet(vec3 p) {
return (d(p)<=0.0);
}
// Moves p in direction, such that p is near the surface.
// Distance ist the maximal distance from p to the surface of the fractal.
vec3 fix(vec3 p,vec3 direction,float distance) {
float myDist=distance;
float minDist=0.000001;
bool inSet=true;
float mult=1.0;
while(myDist>minDist) {
inSet=isInSet(p);
if(inSet)
mult=-myDist;
else mult=myDist;
p+=mult*direction;
myDist*=0.5;
}
return p;
}
// Gets the normal of the surface on point p.
// using: eps,dir
vec3 getNormal(vec3 p,float dist) {
vec3 dp = normalize(dir);
vec3 tempVec=vec3(dir.y,-dir.z,dir.x);
vec3 dir1=normalize(cross(dir,tempVec));
vec3 dir2=normalize(cross(dir,dir1));
vec3 p1=fix(p+20.0*eps*dir1,dp,dist);
vec3 p2=fix(p+20.0*eps*dir2,dp,dist);
return normalize(cross(p1-p,p2-p));
}
// custom function to set the type of the changable parameter.
// The color of the background shows the type of parameters.
// To change the tape, the user has to press 'c' or 'v'.
void setPara() {
backgroundColor = vec3(0, 0, 0);
//int dType=(max_steps-50);
int add=180;
int dType=(max_steps-add);
if(dType<0)
dType=-1;
if(dType>add)
dType=-2;
switch(dType) {
case -1:
para1=1;
para2=1;
para3=1;
para4=1;
para5=1;
para6=1;
para7=1;
para8=1;
backgroundColor = vec3(1, 0, 0);
break;
case -2:
para1=1;
para2=1;
para3=1;
para4=1;
para5=1;
para6=1;
para7=1;
para8=1;
backgroundColor = vec3(1, 1, 1);
break;
case 0:
para1=0.17*(scale+min_dist);
backgroundColor = vec3(0, 0, 0);
glowColor = vec3(0, 0, 0);
break;
case 1:
para1=0.17*(scale+min_dist);
backgroundColor = vec3(0.25, 0, 0);
break;
case 2:
para1=0.3*scale;
para2=min_dist;
backgroundColor = vec3(0, 0.25, 0);
break;
case 3:
para4=scale+min_dist;
backgroundColor = vec3(0.25, 0.25, 0);
break;
case 4:
para5=scale+min_dist;
backgroundColor = vec3(0, 0.25, 0.25);
break;
case 5:
para6=scale+min_dist;
backgroundColor = vec3(0.25, 0,0.25);
break;
case 6:
para7=scale+min_dist;
backgroundColor = vec3(0.25, 0.25, 0.25);
break;
case 7:
para8=scale+min_dist;
backgroundColor = vec3(0.5, 0.5, 0);
break;
}
}
// This method is called for each pixel in the output bitmap.
void main() {
setPara();
vec3 p = eye, dp = normalize(dir);
// Using different accuracy for forground and background.
float dist = 0.03;
float mainDist=0.02;
float frontDist=0.01;
float backDistMult=1.05;
int steps;
int my_max_steps=160;
int front_steps=20;
int background_steps=110;
bool isOutside=true;
float estimatedDist=dist;
// Intersect the view ray with the Fractal.
for (steps=0; steps<my_max_steps; steps++) {
if(isOutside) {
if (steps<front_steps)
dist=frontDist;
else
if (steps<background_steps)
dist=mainDist;
else
dist*=backDistMult;
}
if (isInSet(p)) {
if(dist>mainDist) {
p -= dist * dp;
isOutside=false;
my_max_steps+=10;
dist=mainDist;
} else {
isOutside=false;
break;
}
}
p += dist * dp;
}
// Moves p to the surface of the fractal.
p=fix(p,dp,dist);
vec3 normal=getNormal(p,dist);
// Draw the surface.
vec3 color = specularColor;
if (!isOutside) {
// This time, we need the surface color.
vec4 mycol=computeDistAndColors(p);
normal=normalize(normal);
float frontLight=dot(normal,dp);
frontLight*=frontLight;
color[0]=mycol[1]; color[1]=mycol[2]; color[2]=mycol[3];
color=normalize(color);
color=frontLight*(0.5*color+vec3(0.5,0.5,0.5));
}
if(steps>my_max_steps)
steps=my_max_steps;
if(isOutside)
gl_FragColor = vec4(backgroundColor, 1);
else // surface gets a 'glow', if the corresponding points are far away.
gl_FragColor = vec4(mix(color, glowColor, float(steps)/float(my_max_steps)), 1);
}