Organic Shapes with Sphere-Sweeps
The waving tentacles of the alien brain above were constructed in Pov-Ray using sphere_sweeps
and some trigonometry.
Helix Algorithms
Consider the code below which generates a helix:
background { color White*0 }
light_source { <10,100,-100> color White*1 } light_source { <10,100,100> color White*1 }
global_settings { ambient_light <1,1,1>*1 }
camera { location <0, 0, -100> look_at <0, 0, 2> }
union{ #declare R = 5; #declare r = 1; #declare L = 5; #declare P = 2; sphere_sweep { b_spline 15 <0,0,0> r <R*cos(0),1*L,R*sin(0)>, r <R*cos(1*P),2*L,R*sin(1*P)>, r <R*cos(2*P),3*L,R*sin(2*P)>, r <R*cos(3*P),4*L,R*sin(3*P)>, r <R*cos(4*P),5*L,R*sin(4*P)>, r <R*cos(5*P),6*L,R*sin(5*P)>, r <R*cos(6*P),7*L,R*sin(6*P)>, r <R*cos(7*P),8*L,R*sin(7*P)>, r <R*cos(8*P),9*L,R*sin(8*P)>, r <R*cos(9*P),10*L,R*sin(9*P)>, r <R*cos(10*P),11*L,R*sin(10*P)>, r <R*cos(11*P),12*L,R*sin(11*P)>, r <R*cos(12*P),13*L,R*sin(12*P)>, r <R*cos(13*P),14*L,R*sin(13*P)>, r }
translate <0,-30,0> pigment { rgbt <2,1,0,0> } finish { ambient 0.5 phong 0.7 phong_size 20 reflection { 0.0 } } }
|
R = 5, P = 2
R = 5, P = 1
First a background colour, lights and camera are set-up as standard.
The helix is contained within the union. First 4 parameters are declared to enable changes to be
made easily:
R is the radius of the circle or helix;
r is the radius of the rod that is coiled to form the helix;
L is the length of the helix (the vertical or y-distance between each pair of points);
P is a phase multiplier, in other words how much we increment the parameter P between each pair
of points.
The sphere-sweep itself consists of a series of points <x,y,z> and an accompanying radius, r, through
which a mathematical curve (in this case a b_spline) is calculated, resulting in a smooth shape.
Finally we add a yellow-orange pigment (normally colours consist of a triple of RGB values, with each
value ranging from 0 to 1, however, giving values greater than 1 (here red = 2) makes the colours
appear luminous). Here we mix red and green to give a yellow colour. RGB colour charts can be used
if specific hues are required, though this also depends on the lighting, and with practise colour values
can be 'gestimated' quite closely. The finish adds a slightly shiny, slimy look which is good for many
living organisms.
This code is still a little clumsy, if we want a longer helix, then we need to add more points to our
sphere_sweep, but since we are using regular;y spaced points this can be done with a sinple while
loop:
To generate a circle (using parametric equations) we
simply plot:
x = R*cos(P) and z = R*sin(P) and y = constant
It does not matter which coordinates (x,y,z) we use,
this simply alters the plane of the circle, which we can
do later by rotating, but here I chose x and z which
generates a horizontal circle at height y (we can set y
= 0 and so forget about it for now). P is a parameter
and we advance P for each point (x,z) that we plot. In
Pov-Ray sin and cos take an argument in radians, so
P = 2*pi (about 6.28) radians correspond to 360
degrees or a complete circle. All we do to get a helix,
is keep plotting the circle over multiples of 360
degrees whilst advancing the height y and we get a
vertical helix.
union{ #declare R = 5; #declare r = 1; #declare L = 5; #declare P = 2;
#declare points = 20; #declare pt = 1;
sphere_sweep{ b_spline points <0,0,0>, 1 #while(pt < points) <R*cos(pt*P), pt*L, R*sin(pt*P)>, r #declare pt = pt + 1; #end }
translate <0,-50,0> pigment { rgbt <2,1,0,0> } finish { ambient 0.5 phong 0.7 phong_size 20 reflection { 0.0 } } }
|
Note that Pov-Ray requires us to set the first point of our sphere-sweep explicitly (otherwise the
compiler fails to recognise what we are trying to do). It is also useful to make sure that the first point
of our helix is at the origin, (0,0,0), since this makes it easy to rotate it around the origin to get the
desired orientation before we translate it to our desired position (otherwise our rotations may move
the helix into positions that are hard to predict - it is usually easiest to rotate first and then translate).
The optional alpha-channel, specified by t in an rgbt colour, gives the object transparency, currently
I have set this to zero (no transparency, the default value) but transparency is often a feature of
living tissues and so adding a bit can give realistic effects.
A helix is fine for representing such things as spirochaete bacteria (one type of which causes syphilis
and drills into the body's tissues!) and flagella, but usually biological structures will not be exactly
helical, but be capable of additional movement and flexing - we are only part-way to making a
tentacle!
Next we will look at two main ways to get more natural shapes:
1. Superposition of sine waves;
2. Partial randomisation.
Wave Equations and the Superposition of Waves
The general equation for a sine wave in 1D is:
Where, y is the height of the wave at each point (such as the displacement of water or of a guitar
string), w is the angular frequency, which determines how many oscillations occur in each interval of
the parameter t (t might be time, for say a buoy bobbing up and down on the water), p is the phase
(which specifies where the wave begins in its cycle at t = 0, if we wish to start level with the surface of
calm water then p = 0) and A is the amplitude (maximum height/depth of the wave above/below the
surface of calm water).
This would only give us a simple wave, like those we have already used, however, real waves consist
of a number (possibly infinite) of sine waves added together. By the Principle of Superposition
adding two or more waves together generates another wave. (See waves for more details of the
physics).
Let's see what happens in practice. I have changed the code for the union as shown below:
union{ #declare R = 5; #declare r = 1; #declare L = 10; #declare P = 1;
#declare points = 14; #declare pt = 0;
sphere_sweep{ b_spline points+1 <0,0,0>, 1 #while(pt < points) <R*cos(pt*P)+5*R*cos(pt*P*0.1), pt*L, R*sin(pt*P)+5*R*sin(pt*P*0.1)>, r #declare r = r + 0.2; #declare pt = pt + 1; #end }
translate <0,-60,0> pigment { rgbt <2,1,0,0> } finish { ambient 0.5 phong 0.7 phong_size 20 reflection { 0.0 } } }
|
There are an infinity of possibilities, but here I added the sine wave:
5*R*sin(pt*P*0.1)
to the z-coordinate and a corresponding cos wave to the x-coordinate.
(Remember that the only difference between sine and cosine is the phase:
cos(t) = sin(t + P) where P = pi/2 radians (90 degrees)). Adding two or more
waves together gives an apparently irregular waveform (though it does
repeat at intervals if we repeat the pattern far enough).
I have also increased r slightly for each point through the sweep, giving a
tapering tentacle.
[Finally, I took a few points off the end (setting points = 14) but then I added
one point to the start (setting pt = 0 initially) to get the desired look,
resulting in a total of 15 points (points + 1) in the sphere-sweep.]
Now we have something which looks much more like a tentacle!
Note: we can create a travelling wave to animate the tentacles (as in the alien brain at the top) by
incrementing the phase of one of the sine waves in each frame. Below is a simple animated GIF of 6
frames, where the phase of the smaller sine/cosine wave (the one we started with) by adding one each
time, e.g. the last frame was given by:
<R*cos(pt*P+5)+5*R*cos(pt*P*0.1), pt*L, R*sin(pt*P+5)+5*R*sin(pt*P*0.1)>, r
Note: the tentacle is off to one side because the first and last points of the sphere-sweep are not visible
(they are control points used to construct the b_spline curve) and so the first visible point is actually
<1,10,0> as cos(0) = 1, sin(0) = 0. (You can set the second point explicitly to <0,0,0> or translate <-1,0,0>
to move the tentacle back to the origin. [UnFREEz 2.1 has been used to create the animated GIFs and is
free software available online]. Note the 'kink; in the tail. This is neither an error nor is it necessary, it is due
to the first point of the sphere-sweep, <0,0,0>, set manually and is included to show you that you can
specify or randomise as many of the points in the sphere-sweep as you wish. Manually determined points
can be added to both ends if required, or the whole can be generated by the trig functions, to give an exact
sine wave.
Adding Randomisation
Randomisation can be a good tool to help with generating natural shapes.
This is a model of a bootlace worm, the longest of which are the
longest known animals on Earth (up to 30 to 60 metres in length)!
They have a habit of coiling themselves into knots and springs -
shapes that are clearly based on sine waves, but with a great deal
of variability thrown in. The main part of this worm's body was
modeled using the wave equation:
<amp1*sin(pt*freq1)+pt/2+RV1+RV5*sin(pt*0.5),
amp2*cos(RV4*freq2)+ptl/2+RV1+RV5*cos(pt*0.5), amp3*sin(pt*freq3)+pt/2+RV1>, rad
with:
#declare RV0 = RRand(1,2,1);
#declare RV4 = RRand(-10,10,1);
#declare RV5 = RRand(5,20,1);
#declare amp1 = RRand(5,15,0);
#declare amp3 = RRand(5,15,0);
Where the function RRand generates a random number between
the first two values specified in brackets and using the third
number as a random seed (changing the third number changes
the sequence of random numbers generated). New random
numbers being generated for each point (pt) plotted.
Helices have been used to generate the flagella of this swimming
bacterial cell (see bacteria). Adding some randomisation is useful
when the flagella fly apart as the cell tumbles to change its
direction at random.
Sphere_sweeps are also good for generating worm-like
(vermiform) shapes, as in this acorn worm.
There are many more examples of models generated using sphere-sweeps on Cronodon.com, from aliens
to weird and bizarre creatures (see BioTech).