Hi, I'm making this post to give some details of the technique I used for this images I posted to the gallery:
It's quite simple, no need of surface mapping or working with normals, as you will see.
To show how it works, I will use a DE system that renders a 3D model of a wagon that carries steels bars in the factory I work in. Why I did this model? Because I was talking about fractals with a co-worker that was interested in my works (he saw them on my Facebook), and he challenged me to make a fractal out of this wagon we have in our sector (as a sidenote, I work as an operator of a magnetic crane that loads this wagon with steel bars, among other tasks, and this bars are carried by rail to another sector and later used for making seamless tubes).
This is the plain rendering of the wagon (I used a DE combinate of simple geometric shapes to do it):
And the fractal one I did for my friend
:
First of all, what is a 3D Kaliset? Kaliset is the name I put to a simple formula I discovered to produce fractal patterns, much like the ones that Sam Monnier's "Ducks" formula produces, but Kaliset is extendable to any dimension.
The 3D version of it is difficult to represent, I will not discuss the reasons here, but you can check the original thread of the Kaliset formula:
http://www.fractalforums.com/new-theories-and-research/very-simple-formula-for-fractal-patterns/As the 2D version representation, using inside coloring methods, is a fractal that fills the plane with patterns, the same procedure applied to a 3D version fills the space with them too. But how to make them visible? only with slice cuts of the space, or... as distortions of the space itself that will change the shape of anything you draw on it. Also it can be used for coloring the surface of any shape or fractal.
This is the Kaliset sub-routine I made for Fragmentarium:
float Kaliset(vec3 pos) {
vec3 p = pos*Zoom+Offset; // Zoom and Offset values set the scale and relative position of the Kaliset fractal
int i=0;
float ln=0;
float lnprev=0;
float expsmooth=0;
for (i=0; i<Iterations; i++) {
// Kaliset formula (Scale and Julia are the params):
p=abs(p);
p=p/dot(p,p); // means that the vector is divided by the square of it's length (inversion)
p=p*Scale+Julia;
// Exp. smoothing calculation:
lnprev=ln;
ln=length(p);
expsmooth+=exp(-1/abs(lnprev-ln));
}
return expsmooth;
}
This will return a value computed by the exponential smoothing calculation of the values at each formula iteration for the 3D point defined on the vec3 parameter.
Let's call this value "k":
float k=Kaliset(p);
This value can be directly used for coloring. In Fragmentarium, I assign this value to the orbitTrap variable that is used by the default renderer for coloring:
orbitTrap=vec4(1,1,1,1)*(k*ColorScale+ColorOffset); // ColorScale and ColorOffset are used for color density and color shifting adjustments
(Note: For best results I must set "CycleColors" on, with some cycles added.)
Then, what I did is scaling the 3D vector currently being used in the distance estimator, in this way:
float sc=1+k*Strength // Strength is a factor to control the amount of distortion (usually very small value);
p*=sc // p is the vector we are working with on the DE system;
Then use "p" for any DE system you want, a fractal or whatever... but the result must be divided by "sc":
float d=length(p)-1; //DE for a sphere
return d/sc;
Let's see how it works with my wagon model...
Only coloring:
Only distortions:
Combination of both:
As for the distortions, this is the simplest way I found at first, but I'll try to find another method because the distortions are not equally distributed; they increase the more far the fractal is of the axis origin, as the obvious result of the scaling operation
(notice the top faces of the wagon are little affected because they are near z=0, and no effect on the floor that it's indeed on z=0)
Also another formulas could be used for this, the only rule is that it must produce patterns in all directions on space.
I hope my explanation was clear enough, maybe someone could find this useful/interesting so I wanted to share it.
Any comments or suggestions for improving this procedure will be very welcomed.