# Easy way to export Graphics3D as triangles with VertexNormals?

I would like to export an arbitrary Graphics3D object as a text file containing:

• list of vertices
• vertex normals
• triangle faces

Export["foo.obj", g], Export["foo.pov", g], and Export["foo.stl", g] are all unsatisfactory as they lack the VertexNormal data.

I started writing my own exporter but it's getting a bit painful as it seems there is no easy way to convert GraphicsComplex object containing Polygons of order greater than 3 and converting them to triangles without recreating a triangle tessellation from scratch.

Has anyone done this before and would like to share their code? Or is there an undocumented function I could use?

Here is an example Graphics3D:

g = RegionPlot3D[(x^2 + y^4 + z^4) - (x^3 + y^2 + z) > 1/2, {x, -1, 1}, {y, -1, 1}, {z, -1, 1}]


• Have you tried exporting in X3D formats?
– kglr
Commented Oct 7, 2012 at 10:55
• Hi! Welcome to the site! Perhaps you could provide a minimal working example of your 3d graphics. Commented Oct 7, 2012 at 10:55
• You can't use NOFF? Commented Oct 7, 2012 at 10:57
• Thanks for the tips! I hadn't tried X3D or NOFF before. Commented Oct 7, 2012 at 11:03
• Dale : NOFF Stores a collection of planar polygons with possibly shared vertices and vertex normal data. Commented Oct 7, 2012 at 11:06

As already stated in the comments, you can surely find a 3d export format which stores the normals too. On the other hand, I believe the only information you are missing is, that there is a function Normal (which has nothing to do with the normals).

This function transforms a GraphicsComplex back to a form where all polygons are stored explicitly. Therefore, you take you Graphics3D, apply Normal and then you can via e.g. Cases and some rules extract all information you like.

OK, let's make this answer worth many upvotes: The triangle faces of your graphics are the first argument in all the Polygon calls after you applied Normal. The vertices are just in the first argument to GraphicsComplex. The normals are supplied as optional argument to Polygon.

Using TagSet to build a simple access to those information

Faces /: gr_Graphics3D.Faces :=
Cases[Normal[gr], Polygon[__], Infinity] /. Polygon[pts_, ___] :> pts;
Vertices /: gr_Graphics3D.Vertices :=
gr[[1, 1]] /; gr[[1, 0]] === GraphicsComplex;
Normals /: gr_Graphics3D.Normals :=
Cases[Normal[gr], Polygon[__], Infinity] /.
Polygon[pts_, VertexNormals -> normals_] :> {pts, normals}


This should work in basic examples. Please don't try to draw this with a full detailed graphics. Your system may explode.

gr = RegionPlot3D[(x^2 + y^4 + z^4) - (x^3 + y^2 + z) > 1/2, {x, -1,
1}, {y, -1, 1}, {z, -1, 1}, MaxRecursion -> 0, PlotPoints -> 5,
Mesh -> All];
drawNormals[{pts_, normals_}] := {Arrow[Tube[#, 0.01]] & /@
Transpose[{pts, pts + .5 normals}]};

(* And here comes the simple access: *)
Graphics3D[{Polygon /@ (gr.Faces), Red, drawNormals /@ (gr.Normals),
Blue, Sphere[#, 0.05] & /@ (gr.Vertices)}]