I'm going to describe the workflow with the aid of an example. In this example, my aim is to produce an accurate and beautiful ray traced image of Richmond's minimal surface (the variation with five "petals"). I want to include Mathematica's parameter grid lines and visually emphasize the surface's boundary. See here for a description of Richmond's surface: Wikipedia.
First step
Obtain some parametric equation for the surface and write Mathematica code for it. Since the actual process of deriving the parametric equation for Richmond's surface (via its Weierstrass-Enneper representation) lies outside the scope of this particular Stack Exchange, I will simply provide the code: rich[z_] := {-1/(2 z) - z^11/22, -I/(2 z) + I z^11/22, z^5/5}
. Note that I've chosen a surface that doesn't involve any complex branch cuts in evaluating its Weierstrass-Enneper integrals.
Second step
Next draw the surface with Mathematica, without any mesh lines, boundary, etc. For my example, this is accomplished as follows:
richmond =
ParametricPlot3D[
Re[rich[r Exp[I theta]]], {r, 0.5, 1.21}, {theta, 0, 2 Pi},
Mesh -> False, BoundaryStyle -> None, PlotPoints -> {380, 380}]
I've found the proper parameter domain by trial-and-error, fiddling with the parameter bounds until I obtained an aesthetically pleasing image. Better mathematicians than I will perhaps require less time doing this.
Third Step
Here's where things become interesting! I export the surface plot as a bunch of smooth triangles. A smooth triangle is a triangle which not only specifies its vertices, but also its vertex normals. In order to obtain aesthetically pleasing results, it is absolutely essential to include the vertex normals. Otherwise POV-Ray will seriously mess up things like phong shading, texturing and especially interior textures, so that things will look choppy. (Which is bad unless you want a "low polygon count" look.) I export to a POV-Ray include file, so as not to clutter up my main POV file with several thousand smooth triangle declarations. For this task, I use code adapted from one of the answers to this question: Mathematica's "POV" export format ignores ColorFunction.
vertices = richmond[[1, 1]];
triangles = richmond[[1, 2, 1, 1, 2, 1, 1, 1]];
normals = richmond[[1, 3, 2]];
AccString[x_List] :=
StringDrop[
StringJoin[
Map[ToString[AccountingForm[#, 20, NumberSigns -> {"-", ""}]] <>
"," &, x[[{1, 2, 3}]]]], -1]
POVsmoothtriangle[ind_List] :=
StringJoin[{"smooth_triangle{<", AccString[vertices[[ind[[1]]]]],
">,<", AccString[normals[[ind[[1]]]]], ">,<",
AccString[vertices[[ind[[2]]]]], ">,<",
AccString[normals[[ind[[2]]]]], ">,<",
AccString[vertices[[ind[[3]]]]], ">,<",
AccString[normals[[ind[[3]]]]], ">}"}]
Export["richmond.inc", Map[POVsmoothtriangle, triangles], "Lines"]
Next, I open the include file in a text editor (POV-Ray itself becomes horribly slow when dealing with large files) and enclose the smooth triangle statements in a #declare richmondsurface = mesh{ [here go all the triangles] }
declaration.
Fourth step
I draw just the parameter mesh lines without the surface itself being visible. This is accomplished by typing and executing:
richmondframe =
ParametricPlot3D[
Re[rich[r Exp[I theta]]], {r, 0.5, 1.16}, {theta, 0, 2 Pi},
Mesh -> 16, PlotStyle -> None, PlotPoints -> {600, 600}]
Following that, I export the mesh frame, this time as a POV file: Export["richmondframe.pov", richmondframe]
.
Fifth step
I clean up the resulting POV file (which contains a bunch of cylinder declarations) in my text editor. First, I remove all camera and lighting info. This is easy, because the info stands at the front of the POV file. Next, I replace (via the text editor's find-and-replace function) all pigment declarations for the cylinders by an empty expression. Additionally, I replace the cylinder's radius with the variable meshthickness
, which I will later declare in the main POV file. Then I enclose the cylinders in a statement #declare richmondframe = union{ [bunch of cylinders here] }
. Finally, I rename the POV file so that it ends in ".inc" instead of ".pov". This way I make another include file out of it.
Sixth step
I draw the surface boundary and essentially repeat step five. Of course I use a different variable, meshthickness2
(which is going to be larger than the first meshthickness
), for the cylinder's radius.
richmondboundary =
ParametricPlot3D[
Re[rich[r Exp[I theta]]], {r, 0.5, 1.16}, {theta, 0, 2 Pi},
Mesh -> None, PlotStyle -> None, BoundaryStyle -> Black, PlotPoints -> {100, 100}]
Seventh step
Create and edit the main POV file according to taste. POV-Ray's many procedures, options, and codes are of course entirely outside the scope of this Stack Exchange. Let me limit myself to reminding the readers that in order to include the objects created in Mathematica, you type things like:
#include "richmond.inc"
#include "richmondframe.inc"
#include "richmondboundary.inc"
object{richmondsurface
scale 2
texture{ [whatever] }
[etc.,etc.] }
Eighth step
When everything is as you imagined it, render the final image. Then simply lean back and enjoy the fruits of your hard work.

Epilogue
I would like to create a program or script that will perform most of the steps outlined here automatically. I'm especially interested in making something suited for the creation of animations. Any ideas, comments, or criticisms will be warmly appreciated.