// sponge
/*
Ok, here's the deal. The problem with the sponge shape is that as the
recursion gets deep
it quickly gets quite complex in the number of objects needed to create
it. Using the
stuff described below I've made an iteration 8 sponge and I think 10 is
possible. Here
are the major optimizations I used:
1. Don't use any CSGCSGdiferences, make it only out of additive CSG
(helps in rendering, not in parsing).
2. The shape as a whole is mirrored on all three axi, use this fact and
render one 1/8th of the
whole as an object and rotate it and translate it to make the whole.
3. The actual shape could be made out of boxes but the mesh is much more
effecient for memory and
and rendering so use it instead. This does make the process a bit more
complex.
4. Because a sponge in a fractal it is a self referential shape, that
is, the whole is made up of
many smaller shapes that are similar to the whole. This fact can be used
to create a small sponge
of a medium iteration (e.g., 4) and use that smaller shape as a building
block to create the
large sponge at a similar iteration level. 2 level 4 sponges are much
less complex than 1 level 8
shape. This could even be done a third time for higher levels.
*/
#include "colors.inc"
#declare SKIN = 0.00001;
// use these 2 interations setting together for the total (e.g., 3 and 3
would be a total of 6)
#declare iterations = 3;
#declare iterationsB = 3;
#declare res = pow(3, iterations);
#declare resB = pow(3, iterationsB);
#declare total = res * resB;
#declare single = 10 / total;
// since the box is mirrored in X, Y, and Z we only need 1/2 on all
sides (1/8th memory)
#declare res2 = int( res / 2 ) + 1;
#declare it = array[res2][res2][res2]
#declare size = 10 / res / resB;
// init array
#macro init( arr, dx, dy, dz )
#declare X = 0;
#while( X < dx )
#declare Y = 0;
#while( Y < dy )
#declare Z = 0;
#while( Z < dz )
#declare it[X][Y][Z] = 1;
#declare Z = Z + 1;
#end
#declare Y = Y + 1;
#end
#declare X = X + 1;
#render concat( "Init ", str(X,1,0), "/", str(dx,1,0), "\r" )
#end
#end
#macro cut( p1, diff )
#local X = p1.x;
#while( X < min( res2, p1.x + diff.x ) )
#local Y = p1.y;
#while( Y < min( res2, p1.y + diff.y ) )
#local Z = p1.z;
#while( Z < min(res2, p1.z + diff.z) )
#declare it[X][Y][Z] = 0;
#local Z = Z + 1;
#end
#local Y = Y + 1;
#end
#local X = X + 1;
#end
#end
#macro sponge( p1, diff, iter )
#local dd = diff / 3;
cut( p1 + <0, dd.y, dd.z>, dd )
cut( p1 +
, dd )
cut( p1 + , dd )
cut( p1 + , dd )
cut( p1 + , dd )
cut( p1 + , dd )
cut( p1 + , dd )
#if( iter > 1 & p1.x < res2 & p1.y < res2 & p1.z < res2 )
#if (iter > 2 )
#render concat( "\nIter ", str(iter,1,0), " <", str(p1.x,1,0), ",",
str(p1.y,1,0), ",", str(p1.z,1,0), ">\n" )
#else
#render concat( str(iter,1,0), "<", str(p1.x,1,0), ",",
str(p1.y,1,0), ",", str(p1.z,1,0), "> " )
#end
sponge( p1 + <0, 0, 0>, dd, iter - 1 )
sponge( p1 + <0, 0, dd.z>, dd, iter - 1 )
sponge( p1 + <0, 0, 2 * dd.z>, dd, iter - 1 )
sponge( p1 + <0, dd.y, 0>, dd, iter -1 )
sponge( p1 + <0, dd.y, 2 * dd.z>, dd, iter -1 )
sponge( p1 + <0, 2 * dd.y, 0>, dd, iter -1 )
sponge( p1 + <0, 2 * dd.y, dd.z>, dd, iter -1 )
sponge( p1 + <0, 2 * dd.y, 2 * dd.z>, dd, iter -1 )
sponge( p1 + , dd, iter - 1 )
sponge( p1 + , dd, iter - 1 )
sponge( p1 + , dd, iter -1 )
sponge( p1 + , dd, iter -1 )
sponge( p1 + <2 * dd.x, 0, 0>, dd, iter - 1 )
sponge( p1 + <2 * dd.x, 0, dd.z>, dd, iter - 1 )
sponge( p1 + <2 * dd.x, 0, 2 * dd.z>, dd, iter - 1 )
sponge( p1 + <2 * dd.x, dd.y, 0>, dd, iter -1 )
sponge( p1 + <2 * dd.x, dd.y, 2 * dd.z>, dd, iter -1 )
sponge( p1 + <2 * dd.x, 2 * dd.y, 0>, dd, iter -1 )
sponge( p1 + <2 * dd.x, 2 * dd.y, dd.z>, dd, iter -1 )
sponge( p1 + <2 * dd.x, 2 * dd.y, 2 * dd.z>, dd, iter -1 )
#end
#end
// this translates from the 1/8th array until a full one
#macro retr( X, Y, Z )
#local rX = X;
#local rY = Y;
#local rZ = Z;
#if( rX >= res2 )
#local rX = res2 + res2 - rX - 2;
#end
#if( rY >= res2 )
#local rY = res2 + res2 - rY - 2;
#end
#if( rZ >= res2 )
#local rZ = res2 + res2 - rZ - 2;
#end
it[rX][rY][rZ]
#end
// make boxes
#macro make_eigth( it, res2, size, obj, MESH )
#if( MESH )
mesh {
#else
union {
#end
#declare X = 0;
#while( X < res2 )
#declare Y = 0;
#while( Y < res2 )
#declare Z = 0;
#while( Z < res2 )
#if( it[X][Y][Z] = 1 )
#if( MESH )
#if( X = 0 ? 1 : it[max(0,X-1)][Y][Z] )
triangle { * size, * size, * size
}
triangle { * size, * size, * size
}
#end
#if( Y = 0 ? 1 : it[X][max(0,Y-1)][Z] )
triangle { * size, * size, * size
}
triangle { * size, * size, * size
}
#end
#if( Z = 0 ? 1 : it[X][Y][max(0,Z-1)] )
triangle { * size, * size, * size
}
triangle { * size, * size, * size
}
#end
#if( X = res2 ? 1 : !it[min(res2 - 1,X+1)][Y][Z] )
triangle { * size, * size, *
size }
triangle { * size, * size, *
size }
#end
#if( Y = res2 ? 1 : !it[X][min(res2 - 1,Y+1)][Z] )
triangle { * size, * size, *
size }
triangle { * size, * size, *
size }
#end
#if( Z = res2 ? 1 : !it[X][Y][min(res2 - 1,Z+1)] )
triangle { * size, * size, *
size }
triangle { * size, * size, *
size }
#end
/* This was the start of some more optimizations to reduce the number of
triangles in the mesh
#local z1 = Z;
#while( Z < res2 - 1 & it[X][Y][Z] = 1 ) //retr( X, Y, Z ) =
1 )
#declare it[X][Y][Z] = 0;
#declare Z = Z + 1;
#end
#local z2 = Z;
box { * size, * size }
*/
#else
object {
obj
translate * size
}
#end
#end
#declare Z = Z + 1;
#end
#declare Y = Y + 1;
#end
#declare X = X + 1;
#render concat( "Make ", str(X,1,0), "/", str(res2,1,0), "\r" )
#end
#if( MESH )
}
#else
}
#end
#end
//
// now put it all together
//
init( it, res2, res2, res2 )
#render "\n"
sponge( <0,0,0>, , iterations )
#render "\n\n"
#declare eighth = make_eigth( it, res2, size, 0, 1 )
#render "\n\n"
// this might clear up some memory...well, it would in a real language
#undef it
#declare half = union {
object {
eighth
}
object {
eighth
rotate y * -90
translate x * size * res
}
object {
eighth
rotate y * 90
translate z * size * res
}
object {
eighth
rotate y * 180
translate
}
}
#declare obj = union {
object {
half
}
object {
half
rotate x * 180
translate z * size * res
translate y * size * res
}
}
// since the box is mirrored in X, Y, and Z we only need 1/2 on all
sides (1/8th memory)
#declare res2 = int( resB / 2 ) + 1;
#declare it = array[res2][res2][res2]
#declare size = 10 / resB;
init( it, res2, res2, res2 )
#render "\n"
sponge( <0,0,0>, , iterationsB )
#render "\n\n"
#declare eighth = make_eigth( it, res2, size, obj, 0 )
#render "\n\n"
#undef it
#declare half = union {
object {
eighth
}
object {
eighth
rotate y * -90
translate x * size * resB
}
object {
eighth
rotate y * 90
translate z * size * resB
}
object {
eighth
rotate y * 180
translate
}
}
#declare whole = union {
object {
half
}
object {
half
rotate x * 180
translate z * size * resB
translate y * size * resB
}
}
object {
whole
texture {
pigment {
color Red
}
finish {
phong 1
phong_size 90
}
}
}
box {
<-20, 0, -20>, <30, 30, 30>
texture {
pigment {
checker <1,1,1>, <0,0,1>
scale 2
}
finish {
phong 1
phong_size 90
}
}
hollow
}
light_source {
<1, 6, -5>
White
}
light_source {
<-10, 29, 5>
color <1,1,1>
}
camera
{
up y
// top full
location <-7, 13, -10>
location <-2, 12, -2>
right 4/3*x
look_at <5, 6, 4>
}