Sometimes we want to make an object that does not have perfectly sharp edges like a box does. Then, the superquadric ellipsoid shape made by the superellipsoid
is a useful object. It is described by the simple syntax:
superellipsoid {
<
Value_E,
Value_N >}
Where Value_E and Value_N are float values greater than zero and less than or equal to one. Let's make a superellipsoid and experiment with the values of Value_E and Value_N to see what kind of shapes we can make.
We create a file called supellps.pov
and edit it as follows:
#include "colors.inc" camera { location <10, 5, -20> look_at 0 angle 15 } background { color rgb <.5, .5, .5> } light_source { <10, 50, -100> White }
The addition of a gray background makes it a little easier to see our object. We now type:
superellipsoid { <.25, .25> pigment { Red } }
We save the file and trace it at 200x150 -A
to see the shape. It will look like a box, but the edges will be rounded off. Now let's experiment with different values of Value_E and Value_N. For the next trace, try <1, 0.2>. The shape now looks like a cylinder, but the top edges are rounded. Now try <0.1, 1>. This shape is an odd one! We don't know exactly what to call it, but it is interesting. Finally, lets try <1, 1>. Well, this is more familiar... a sphere!
There are a couple of facts about superellipsoids we should know. First, we should not use a value of 0 for either Value_E nor Value_N. This will cause POV-Ray to incorrectly make a black box instead of our desired shape. Second, very small values of Value_E and Value_N may yield strange results so they should be avoided. Finally, the Sturmian root solver will not work with superellipsoids.
Superellipsoids are finite objects so they respond to auto-bounding and can be used in CSG.
Now let's use the superellipsoid to make something that would be useful in a scene. We will make a tiled floor and place a couple of superellipsoid objects hovering over it. We can start with the file we have already made.
We rename it to tiles.pov
and edit it so that it reads as follows:
#include "colors.inc" #include "textures.inc" camera { location <10, 5, -20> look_at 0 angle 15 } background { color rgb <.5, .5, .5> } light_source{ <10, 50, -100> White }
Note that we have added #include "textures.inc"
so we can use pre-defined textures. Now we want to define the superellipsoid which will be our tile.
#declare Tile = superellipsoid { <0.5, 0.1> scale <1, .05, 1> }
Superellipsoids are roughly 2*2*2 units unless we scale them otherwise. If we wish to lay a bunch of our tiles side by side, they will have to be offset from each other so they don't overlap. We should select an offset value that is slightly more than 2 so that we have some space between the tiles to fill with grout. So we now add this:
#declare Offset = 2.1;
We now want to lay down a row of tiles. Each tile will be offset from the original by an ever-increasing amount in both the +z and -z directions. We refer to our offset and multiply by the tile's rank to determine the position of each tile in the row. We also union these tiles into a single object called Row
like this:
#declare Row = union { object { Tile } object { Tile translate z*Offset } object { Tile translate z*Offset*2 } object { Tile translate z*Offset*3 } object { Tile translate z*Offset*4 } object { Tile translate z*Offset*5 } object { Tile translate z*Offset*6 } object { Tile translate z*Offset*7 } object { Tile translate z*Offset*8 } object { Tile translate z*Offset*9 } object { Tile translate z*Offset*10 } object { Tile translate -z*Offset } object { Tile translate -z*Offset*2 } object { Tile translate -z*Offset*3 } object { Tile translate -z*Offset*4 } object { Tile translate -z*Offset*5 } object { Tile translate -z*Offset*6 } }
This gives us a single row of 17 tiles, more than enough to fill the screen. Now we must make copies of the Row
and translate them, again by the offset value, in both the +x and -x directions in ever increasing amounts in the same manner.
object { Row } object { Row translate x*Offset } object { Row translate x*Offset*2 } object { Row translate x*Offset*3 } object { Row translate x*Offset*4 } object { Row translate x*Offset*5 } object { Row translate x*Offset*6 } object { Row translate x*Offset*7 } object { Row translate -x*Offset } object { Row translate -x*Offset*2 } object { Row translate -x*Offset*3 } object { Row translate -x*Offset*4 } object { Row translate -x*Offset*5 } object { Row translate -x*Offset*6 } object { Row translate -x*Offset*7 }
Finally, our tiles are complete. But we need a texture for them. To do this we union all of the Rows
together and apply a White Marble
pigment and a somewhat shiny reflective surface to it:
union{ object { Row } object { Row translate x*Offset } object { Row translate x*Offset*2 } object { Row translate x*Offset*3 } object { Row translate x*Offset*4 } object { Row translate x*Offset*5 } object { Row translate x*Offset*6 } object { Row translate x*Offset*7 } object { Row translate -x*Offset } object { Row translate -x*Offset*2 } object { Row translate -x*Offset*3 } object { Row translate -x*Offset*4 } object { Row translate -x*Offset*5 } object { Row translate -x*Offset*6 } object { Row translate -x*Offset*7 } pigment { White_Marble } finish { phong 1 phong_size 50 reflection .35 } }
We now need to add the grout. This can simply be a white plane. We have stepped up the ambient here a little so it looks whiter.
plane { y, 0 //this is the grout pigment { color White } finish { ambient .4 diffuse .7 } }
To complete our scene, let's add five different superellipsoids, each a different color, so that they hover over our tiles and are reflected in them.
superellipsoid { <0.1, 1> pigment { Red } translate <5, 3, 0> scale .45 } superellipsoid { <1, 0.25> pigment { Blue } translate <-5, 3, 0> scale .45 } superellipsoid { <0.2, 0.6> pigment { Green } translate <0, 3, 5> scale .45 } superellipsoid { <0.25, 0.25> pigment { Yellow } translate <0, 3, -5> scale .45 } superellipsoid { <1, 1> pigment { Pink } translate y*3 scale .45 }
Some superellipsoids hovering above a tiled floor.
We trace the scene at 320x200 -A
to see the result. If we are happy with that, we do a final trace at 640x480 +A0.2
.