Thoroughly Useful Macros

    Thanks to the POV-Ray #macro directive and support for arrays, operations that formerly had to be done with in-line code, #include files, or even external programs, can now be done with simple macro calls. I put several of these functions into an .INC file, which makes them a lot easier to use.
    Here's the file:

macs.zip

2985 bytes, unzips to 11361 bytes

Objects

These macros build more complex objects out of simpler primitives. These are kinds of objects I often find myself making.

Connect(StartPoint,StartRadius,EndPoint,EndRadius)

    This macro creates a cone object which will smoothly connect two spheres. An example:
object {
  Connect(y*4,2,y*9,3)
  texture { MyTexture }
}
    This macro does not generate the spheres at each point, just the cone that connects them.

RoundedBar(StartCorner,EndCorner,Radius)

    This macro creates a bar with four of its edges rounded. It fills the same space as box { Startcorner, EndCorner }, except that the edges running along the y-axis are rounded. StartCorner and EndCorner are opposite corners of the box, and Radius is the radius of the rounded edges.
    The bar is made up of a prism object and four cylinder objects that run parallel to the y-axis. If you want the bar to run along any other axis, you will have to transform it just as you would any prism object. There is no merge or union declared around them, to leave the choice up to the user; merge is better for applications with transparency, union is better for others. Here is an example of the macro's use:
union {
  RoundedBar(<-10,0,0>,<10,40,20>,2)
  pigment { rgb .75 }
}
    Although the example code uses vector literals for StartCorner and EndCorner, you can use any vector expression, and scalars will be promoted to full vectors.

RoundedBox(StartCorner,EndCorner,Radius)

    This macro creates a box with all of its edges and corners rounded. It fills the same space as box { StartCorner,EndCorner }, except that the edges and corners are rounded. StartCorner and EndCorner are opposite corners of the box, and Radius is the radius of the rounded edges.
    The box is made up of three box objects, twelve cylinder objects, and eight sphere objects. There is no merge or union declared around them, to leave the choice up to the user; merge is better for applications with transparency, union is better for others. Here is an example:
union {
  RoundedBox(<-10,0,0>,<10,40,20>,2)
  pigment { rgb .75 }
}
    Although the example code uses vector literals for StartCorner and EndCorner, you can use any vector expression, and scalars will be promoted to full vectors.

BevelBox(StartCorner,EndCorner,BevelWidth)

    This macro creates an box with all twelve edges beveled. It fills the same space as box { StartCorner,EndCorner }, except that the edges are shaved flat. StartCorner and EndCorner are opposite corners of the box, and BevelWidth is the width of the bevel when measured across the edge. The beveling is at a 45-degree angle to the coordinate axes.
    The box is made of an intersection of three box objects, bounded with a fourth. As with the RoundedBar( ) and the RoundedBox( ) objects above, some form of syntax container is needed if you want to texture or transform the object. When using just one of these in an object, the object { } syntax is needed, but when used in CSG it can stand alone. Here is an example:
object {
  BevelBox(<-10,0,0>,<10,40,20>,2)
  pigment { rgb .75 }
}
    Although the example code uses vector literals for StartCorner and EndCorner, you can use any vector expression, and scalars will be promoted to full vectors.

BiRoundedBox(Start,End,MajorRadius,MinorRadius)

    This macro creates an object like the RoundedBar( ) macro above, except that the edges at the end of the bar are themselves rounded to a smaller radius. MajorRadius sets the rounding of the edges parallel to the y-axis, and MinorRadius sets the rounding of the other edges.

RoundedCylinder(Start,End,MajorRadius,MinorRadius)

    This macro creates a cylinder with rounded edges. Start, End, and MajorRadius are the parameters for the basic shape, and MinorRadius specifies the amount of rounding.

CylinderSpan(Start1,End1,Start2,End2,Radius)

    If you have two cylinders that lie in one plane, but aren't parallel to each other, you can connect them with this macro. It will create a prism object that fills the gap.

CutSphere(Center,Radius,InsideRadius,Direction)

    Quite often I find myself placing an intersection of a sphere and either a plane or a box, in order to create a hemisphere, quadrant, or octant. This macro simplifies this. Center specifies the center of the sphere, and Radius specifies its radius. InsideRadius allows you to carve out the inside of the sphere; specify a value greater than zero to do so. Direction specifies the direction the partial sphere faces:

CutCylinder(Start,End,Radius,InsideRadius,Direction)

    I also use cylinders that are cut into halves or quarters. This macro simplifies this. Start, End, and Radius specify the usual parameters for cylinders. InsideRadius allows you to carve out the inside of the cylinder; specify a value greater than zero to do so. Direction specifies the portion to be left:     If the cylinder is not parallel to the coordinate axes, the cutting may look funny, but maybe that's what you want.

CutTorus(MajorRadius,MinorRadius,InsideRadius,Direction)

    And from time to time I cut torii as well. MajorRadius and MinorRadius are the usual parameters for torii. InsideRadius allows you to carve out the inside of the torus; specify a value greater than zero to do so. Direction specifies the portion to be left:     The object is created at the origin with its axis along the y-axis. If you want it somewhere else, transform it just like any torus.

Transforms

Many of the Thoroughly Useful Macros that did transformations are now distributed with the standard release of POV-Ray. Where this is the case, I have pointed out the new macro to use.

Matrix(VectorX,VectorY,VectorZ,VectorL)

    This macro is included in transforms.inc under the name Matrix_Trans( ). Click here to read more about the matrix transform, and how you can use matrices to do many different things.

AxisRotate(Axis,Angle)

        This macro is included in transforms.inc under the name Axis_Rotate_Trans( ).

Reorient(StartAxis,EndAxis)

        This macro is included in transforms.inc under the name Reorient_Trans( ).

Point(ModelUp,ModelForward,SceneUp,Direction)

    The Reorient( ) macro does a direct rotation from one vector another, and does not take into account any idea of "up." If that's not what you want, try this one instead. ModelUp is the vector that was considered up when the object was modeled, ModelForward is the vector that was forward when the object was modeled, SceneUp is the up vector for the object's placement, and Direction is the new direction for pointing the object. Like all the other forms of rotation, it presumes that the object is at the origin; if the object away from the origin, the usual consequences will follow.

Stretch(Vector,Amount)

    This macro is included in transforms.inc under the name Axial_Scale_Trans( ).

FlipXY
FlipXZ
FlipYZ

    These three items are not macros, but because they are thoroughly useful I have included them here. They are declared transforms, and do to an object, texture, or texture component what the name describes: It flips thems along two of the axes, leaving the object unchanged along the third axis. Many objects in POV-Ray are oriented along the y or z axis by default; these transforms will orient them along the other axes as well. FlipYZ can also be used to change an object designed in a y-up scene to an object that will work fine in a z-up scene, and vice versa.
object { MyLeftHandedObject
  transform FlipYZ
} // the object is now right-handed

Other stuff

Transition(Start,End,Swerve,Phase)

    This is a "semi-spline" function, useful mainly for animation work. The user selects the Start and End points for a movement, and supplies a Phase value to say how far along the movement has gone. The Swerve parameter allows you to specify the amount by which motion will move to the side, so that motion can be along an arc instead of along a straight line. At Phase<=0 the macro returns the Start point, at Phase>=1 the macro returns the End point, and for intermediate values of Phase the macro returns intermediate values. The macros uses the cosine function to provide smooth motion from Start to End.
    My animation entries in the Internet Raytracing Contest use this macro extensively.

Linear(Start,End,Index)

    This allows for linear interpolation between two points or values. It returns Start when Index is less than or equal to zero, and End when Index is greater than or equal to one, and a linearly-interpolated value for values of Index between zero and one.

GentleLoc(Distance,Duration,Time)
GentleVel(Distance,Duration,Time)
GentleAcc(Distance,Duration,Time)

    A more generalized version of the Transition( ) macro, these three macros model the motion of an object from rest at one point to rest at another point, with no discontinuities of velocity or acceleration along the way. Distance specifies the total distance of the motion. Duration specifies how long the motion takes. Time specifies the amount of time since the start of motion. Time is internally clipped to lie between zero and Duration. The different macros yield the location along the path, the velocity along the path, or the accleration along the path, respectively.

SmoothSeed(Array,Frequency)
SmoothRand(Array)

    This pair of macros will yield a random-number that varies smoothly over time. To use these macros, first invoke SmoothSeed( ). Array needs to be declared as an array; the macro will use the array to hold the seed( ) values for the four random-number sequences derived from the clock variable. Sequence is used to select the sequence to be used for generating the random numbers.
    Once SmoothSeed( ) is called, SmoothRand( ) will return a random number from -1 to 1. Subsequent calls to the macro within an animation frame will vary as much as rand( ) calls, but the values themselves will vary smoothly from frame to frame.
//example scene code

#declare MyArray=array[9]
SmoothSeed(MyArray,2)
sphere {
  y*(10+10*SmoothRand(MyArray)),1
  pigment { MyPigment }
}
    When animated, this will give a sphere that rises and falls randomly.

vmatrix(op,vx,vy,vz,vl)

    This macro allows you to apply matrix-style transformation to individual points. op is the original point. vx is the vector along which the x-component of op is applied, vy is the vector along which the y-component of op is applied, vz is the vector along which the z-component of op is applied, and finally vl is added to the sum. Click here to read more about the matrix transform, and how you can use matrices to do many different things.

FindKnee(Ankle,Hip,Thigh,Shin,Direction)

   A useful vector for animations, FindKnee( ) will return the location of a joint in a limb when the other particulars of the limb are known. Ankle is the location of one joint at one end of the limb, Hip is the location of the joint at the other end, Thigh is the distance from Hip to the knee, Shin is the distance from Ankle to the knee, and Direction is the direction in which the knee should point. The macro will return the location of the knee. The distance from Hip to Ankle and the lengths of Thigh and Shin must form a valid triangle, or a fatal error will occur.

sgn(arg)

    When the POV-Ray team was writing POV, they forgot the sign function, a common function in most programming languages. It returns a 1 when arg is positive, -1 when arg is negative, and 0 when arg is zero.

POV Team members: This looks like a function that could be easily added to POV.


Back to John's Freeloading Home Page