# My donut has holes in it!

More than one hole, I mean…

I’m trying to export from Mathematica into the X3D format, with the longer term goal of generating 3D figures for PDF inclusion. But I'm stuck at the first step:

p = ParametricPlot3D[{(2 + Cos[v]) Sin[u], (2 + Cos[v]) Cos[u],
Sin[v]}, {u, 0, 2 Pi}, {v, 0, 2 Pi}, PlotStyle -> Red];
Export["test.x3d", p];


The donut thus generated has holes in it (as visualized here with FreeWRL):

and the same is true for every 3D surface I've tried to export. MeshLab complains that the file contains “4 degenerated faces”, but I doubt it's the same issue, as there are a lot more than 4 holes!

I am not a 3D format expert, so I don't really know where to go. Exporting to VRML gives the same issue, so I suspect something generic is going on, but I don't really know how to investigate. I tried importing back the files into Mathematica, but 3D graphics formats are apparently write-only.

So, how do you advise me to tackle the issue? Do you have any experience in this kind of export?

-
Probably you should switch to jelly doughnuts. – Daniel Lichtblau Apr 4 '12 at 22:00
I predict an SE "hot question" in a few hours... – R. M. Apr 4 '12 at 22:08
OK, it's an interesting question, but it would've gotten my +1 just for the title! – Pillsy Apr 5 '12 at 10:43

Apparently, the mesh lines generate points which are too close to the triangle vertices, and VRML is not being able to handle them correctly.

To prove the theory, try the example without meshes:

p = ParametricPlot3D[{(2 + Cos[v]) Sin[u], (2 + Cos[v]) Cos[u],
Sin[v]}, {u, 0, 2 Pi}, {v, 0, 2 Pi}, PlotStyle -> Red, Mesh -> None];

Export["test.x3d", p];


It should look OK using FreeWRL:

So the possible solution is to isolate meshes from the surface, i.e. generate them separately and let them be two different graphics complex so that they wouldn't share any points.

We already know how to generate the surface without mesh. To generate only meshes, this would do it (plotting with PlotStyle->None):

p2 = ParametricPlot3D[{(2 + Cos[v]) Sin[u], (2 + Cos[v]) Cos[u],
Sin[v]}, {u, 0, 2 Pi}, {v, 0, 2 Pi}, PlotStyle -> None]


The result is:

Now, combine those two using Show and export.

Export["test.x3d", Show[p, p2]];


The result is perfect:

Now, you got your wholly donut back. Enjoy!

Note: I am using Windows version of FreeWRL so the result may be different on other platform. In that case, it may as well a bug in FreeWRL, not Mathematica's problem.

## Bonus

OK. I shouldn't advocate the use of undocumented features. But if you really want more solid looking meshes, not shamble lines (many format/renderer is not so great at pure line drawing, more so with 3D printing...), this syntax may help you: MeshStyle->Tube[thickness] (thickness in user coordinate scale).

For instance:

p2 = ParametricPlot3D[{(2 + Cos[v]) Sin[u], (2 + Cos[v]) Cos[u],
Sin[v]}, {u, 0, 2 Pi}, {v, 0, 2 Pi}, PlotStyle -> None, MeshStyle -> Tube[.02]]


will create:

Disclaimer There is no guarantee that the syntax will work on the future version of Mathematica. So if you value compatibility, you should not use this. But the resulting 3D graphics will be always valid since it is using our Tube primitive. Tube is supported for export formats. For instance, if you export it to x3d:

Export["test.x3d", Show[p, p2]];


(It may take quite a while, since Mathematica is converting tubes into polygons for compatibility during exports), the result will be:

Again, it is not a permanent solution but if you really need better mesh lines for export or 3d printing, it will give you a temporary relief.

-
What happens if you use Mesh -> Full instead of the default? – Brett Champion Apr 5 '12 at 2:28
It also creates holes. Less, for sure. I actually hoped that it won't make any hole, but still it does. On the other hands, Mesh->All doesn't create any holes, but then exported version does not have any meshes, since it is nothing more than polygons with EdgeForm enabled... – Yu-Sung Chang Apr 5 '12 at 2:35
Just so I improve rather than just avoid the issue in the future, how did you diagnose the problem? – F'x Apr 5 '12 at 13:00
Normal problems can be diagnosed by many means, including FaceForm or explicit VertexNormals. Which leaves a geometry problem. I usually isolate problems by: 1. turn on/off meshes (meshes introduce a lot of extra geometry, because the way M- is handling them), 2. turn on/off recursions using MaxRecursion->0 to create simpler geometry, 3. turn on/off Exclusions (but not in this case)... Also, trying other format would help too. I already knew that the shape is fine with formats like OBJ or PLY... – Yu-Sung Chang Apr 5 '12 at 16:50

It seams that the normals of those faces are reversed for some reason. Thing you can try... 1) Increasing quality instead of performance of video card. 2) Updating GL driver. 3) If the software can render those faces double sided you can switch that option on. 4) Import to an other software or edit it and flip the normals.

-
An easy way to check flipped normal is to use FaceForm[front, back] syntax with PlotStyle: PlotStyle->FaceForm[Red, Blue] for instance. If it gives you a single color then normal is OK. Besides, this may not work for exported file (not many 3D formats support different properties for front/back of triangles). – Yu-Sung Chang Apr 5 '12 at 0:56
Besides, on Windows, Mathematica uses DirectX, instead of OpenGL. OpenGL for other OSes, for sure, though. And having the updated driver is always a good idea, I agree. – Yu-Sung Chang Apr 5 '12 at 0:58
It does not seem to be due to the normals, as plotting the graph with Yu-Sung's trick shows all blue, no red. Also, I've consistently reproduced those across graphics cards (and with up-to-date drivers), so I really think that's not it. – F'x Apr 5 '12 at 8:16