This is a very basic example of exporting mesh geometry data to an external text file. The file can then be parsed back by MAXScript or any other 3D application supporting scripting and reading of ASCII files. In Part One, we will export only the vertex and face list to a fixed path name. In Part Two, we will enhance the code to let the user select a destination file, and will support several other mesh features (edge visibility, smoothing groups, texture coordinates, and others).
In a separate tutorial, we will develop a script to import back the geometry data and recreate the mesh in the scene.
Related Topics:
Editable_Mesh : GeometryClass and TriMesh : Value
NATURAL LANGUAGE
Get a snapshot of the first selected object.
Define an output file name.
Create a new file using the file name.
Get the number of vertices and faces in the mesh.
Output the vertex and face count to the file.
Step through all vertices.
Read the position into a variable.
Write out the vertex position to the file.
Step through all faces.
Read the face definition into a variable.
Write out the face definition to the file.
Close the file.
Open the file to take a look at the result.
MAXSCRIPT
tmesh = snapshotAsMesh selection[1] out_name = ((GetDir #export)+"/testmesh.dat") out_file = createfile out_name num_verts = tmesh.numverts num_faces = tmesh.numfaces format "%,%\n" num_verts num_faces to:out_file for v = 1 to num_verts do ( vert = getVert tmesh v format "%," vert to:out_file ) format "\n" to:out_file for f = 1 to num_faces do ( face = getFace tmesh f format "%," face to:out_file ) close out_file delete tmesh edit out_name
tmesh = snapshotAsMesh selection[1]
We create a TriMesh snapshot of the first object found in the scene selection. This method evaluates the state on top of the modifier stack including any Space Warp bindings. The result is a TriMesh value which is stored in memory (does not exist in the scene). We will be able to access all its vertices and faces as if it is a scene object.
Note that we still do not check whether the user has selected an object in the scene and whether the first selected object is of geometry class. This is just a rough sketch of the final code. The user has to make sure a valid object is selected. We will add such tests in Part Two of the tutorial.
out_name = ((GetDir #export)+"/testmesh.dat")
Next, we define a variable containing the destination path for exporting. We use the GetDir function with the keyword #export to get the 3ds Max system path set up for export operations. We add to it the file name testmesh.dat. This name can be any valid name you might want to use. In Part Two, we will let the user select a path and name using an open file dialog.
out_file = createfile out_name
Using the defined output path, we create a new file and store the resulting fileStream value in a user variable called out_file. Using this variable as the destination, we will be able to output to the file.
num_verts = tmesh.numverts num_faces = tmesh.numfaces
The TriMesh value we created has the properties .numverts and .numfaces like each mesh object in the scene. We get both values and store in user variables because we are going to need them multiple times.
Editable_Mesh : GeometryClass and TriMesh : Value
format "%,%\n" num_verts num_faces to:out_file
Now, we can output to the file for the first time – we define a formatting pattern specifying that there will be two user elements written out, divided by a comma. The line will end with a new line control character specified by backslash-n. After the formatting string, we have to provide as many output expressions as % symbols in the formatting string – each of the variables we supply will be evaluated and the result will replace the % character.
If the numbers of vertices and faces are 8 and 12 respectively (a typical Box), the result of the output will be
8,12
At the end of the format function we provide a to: destination. If we do not do this, the output will go by default to the Scripting Listener.
for v = 1 to num_verts do (
The next step would be to output all vertices of the mesh. We will step through all vertices by using a for loop starting with 1 and ending with the number of vertices in the TriMesh. The variable v will change its value from 1 to num_verts each time the loop is repeated. It will end when the num_verts value is exceeded.
vert = getVert tmesh v
Using the value currently stored in the loop’s v variable, we get the respective indexed vertex by calling the getVert method on the tmesh value. The result will be stored in a user variable and will be a Point3 value (3D Position value) representing the world position of the vertex.
Editable_Mesh : GeometryClass and TriMesh : Value
format "%," vert to:out_file
The vertex position has to be written out to the file. We specify a formatting string telling the format function to output the value of the vert variable followed by a comma. We do not want a new line – all vertex positions will appear in a single line, divided by commas.
)
At this place, the v loop ends and returns to the for v statement unless the v variable has reached the num_verts value. This means that the block enclosed in the brackets will be repeated num_verts times.
format "\n" to:out_file
To separate the vertex list from the face list, we output a single New Line character to the file. The formatting string expects no user expressions as we do not include any % placeholders.
for f = 1 to num_faces do (
The output of the face list is very similar to the vertex list code. We just use the other variable,
face = getFace tmesh f
and get the face definition instead of the vertex position. A face definition is also a Point3 value, but it contains indices to the 3 vertices defining the face instead of a position. The numbers stored in the Point3 value will be thus integers between 1 and num_verts. We store the result in a user variable called face,
format "%," face to:out_file
and output it to the file just like we did with the vertex.
)
At this place, the f loop ends and returns to the for f statement unless the f variable has reached the num_faces value. This means that the block enclosed in the brackets will be repeated num_faces times.
close out_file
Finally, we close the file so that we can open it for reading. If we do not do this, the file will be marked as open by the Windows OS and MAXScript will be unable to read from it. If a script causes an error before a file is closed explicitly, you can call gc()
to perform garbage collection - as a side effect, any locked files will be released.
delete tmesh
Delete the TriMesh value to release the used memory for garbage collection. Otherwise, running the script multiple times can cause memory leaks.
edit out_name
To make sure the output looks like expected, we open the file name defined in the beginning of the script in a Scripting Editor.
For a simple cube at the world origin, the output looks like:
SAMPLE OUTPUT OF A CUBE
8,12 [-50,-50,0],[50,-50,0],[-50,50,0],[50,50,0],[-50,-50,100],[50,-50,100],[-50,50,100],[50,50,100], [1,3,4],[4,2,1],[5,6,8],[8,7,5],[1,2,6],[6,5,1],[2,4,8],[8,6,2],[4,3,7],[7,8,4],[3,1,5],[5,7,3],
To test the script, create a geometry object, select it in the scene, then select Tools > Evaluate from the Scripting Editor's menu or alternatively, press Ctrl+E. The resulting output file must open in a new Scripting Editor.
As already mentioned, this is the basic code for geometry output. Still it can be made even more compact. Below is a shorter version of the same code without the opening in Editor for preview. Please compare the two scripts and see why both of them do the same thing although expressed slightly differently.
MAXSCRIPT
tmesh = snapshotAsMesh selection[1] out_file = createfile ((GetDir #export)+"/testmesh.dat") format "%,%\n" tmesh.numverts tmesh.numfaces to:out_file for v = 1 to tmesh.numverts do format "%," (getVert tmesh v)to:out_file format "\n" to:out_file for f = 1 to tmesh.numfaces do format "%," (getFace tmesh f) to:out_file close out_file
Now, that we have some output, we can go on and write a corresponding input script to read back the data and create a new scene object.
How To ... Read Geometry Data From Text File - Part One
Also, in Part Two of the Geometry Output tutorial, we will make the code more robust and add some more features.
Back to
Next
How To ... Read Geometry Data From Text File - Part One