This is an update to the importer/exporter of Milkshape .ms3d files into
3ds Max and Gmax. Monkwarrior and I have added two new buttons
for importing and exporting geometry only parts of a model and along
the way found and corrected three bugs (described below). You can
find the script and some other files here:
The zip file contains the MaxScript ms3dimportexport_ver1_1.ms,
the original readme.txt file, now called readme_ver1_0.txt, a
readme_ver1_1.txt file which contains the information from this post
in a little more detail, and two files needed by Gmax users but not
by 3ds Max users. The script can be placed in your scripts
subdirectory or any place convenient to your workflow. Click
the Max Script menu item, then Run Script, then mouse to the
directory containing ms3dimportexport_ver1_1.ms and double click
to run it. It will display a simple rollout with "import ms3d file",
"export ms3d file", and the two new buttons, "import geometry only"
and "export geometry only".
The two new buttons can be used this way. Suppose one likes a shield
on one model and wants to use it on another model or several other
models. Import the full model using "import ms3d file" and then click
"export geometry only". This will display a listbox containing the meshes
in the scene. Double click an entry to select it. Your selection will be
echoed in the listener. You are not limited to a single selection so
double click all the meshes you wish to export; they will also be echoed
in the listener. The script does check if you select an item twice which
it doesn't allow. Click the "finished selecting" button when done.
(1) If you are a 3ds Max user the script will open a file chooser for you to
enter a name for the .ms3d file to save to. It will then write the file.
(2) If you are a Gmax user the script exports the data to the listener just
like exporting a full model. You then have to use the supplied
GMaxSLGRAB.exe utility to copy the data from the listener into an
ASCII text file that you name. Then you have to run the Python
ascii2ms3dconverter.py utility to convert it into a binary .ms3d file with
the same name but .ms3d extension.
You can then reset and import a desired model you want to add your
saved shield to. Delete the shield you don't want and then click the
"import geometry only" button and select the file you saved previously.
The desired object should appear in the scene. If you exported a
fully defined object, that is, one with uv coordinates and bone assignments
and weighting, that information is preserved and a skin modifier will be
put on the object.
MORE ERROR CHECKING
On export the script now checks for defined grouptypes and groupflags.
Rather than just stopping with an error, it now prompts you to enter
these. On exporting a full model without a bounding sphere, it tells you
it is supplying a default one. If it finds an unassigned vertex, it will
inform you which mesh the problem occurs in and then terminate.
Fix 1: Most glaring bug is that the uv maps are upside down in version 1_0.
The correct transformation was in Vercingetorix's script, I just didn't
see it. Monkwarrior showed me how to see uv coordinates on textures
through the UI where it is pretty obvious what is going on. It is
v -> 1 - v when converting from meshes and Milkshape to
3ds Max and Gmax. This is now done for all imports and exports.
Fix 2: A more subtle bug, again correctly done in Verc's script, is that
texture vertices and geometry vertices have no 1-1 correspondence in
3ds Max. You don't notice this if you just import a model and then export
it because they do have a 1-1 correspondence in a mesh file. Here's the
documentation on the subject.
The release notes in the header comments of ms3dImportExport_ver1_1.msIt is very important to note that
A - There can be more or less texture and color vertices than there are mesh vertices
B - There are always exactly as many mesh faces as there are texture and color faces!
So there is no one-to-one correspondence between mesh vertices and texture and color vertices.
You cannot take vertex number 10 from the mesh and expect that texture vertex 10 will store
the information about its texturing or color vertex 10 would define its vertex color.
As mentioned in B , the number of faces is always identical. Not only this, the indices of
the mesh and texture resp. color faces have a one-to-one correspondence! If face 5 has 3 mesh
vertices you are interested in, their corresponding texture vertices will be the 3 vertices
referenced by the texture face number 5.
This is the key to access to texture and color information in 3ds Max!
Finding the corresponding vertices
In order to find out which texture vertex corresponds to a mesh vertex, you have to do the following:
1. Take the index of the mesh vertex.
2. Find out which faces reference the index of the face.
3. Note the number of the vertex (1st, 2nd or 3rd - .x, .y or .z) inside each face.
4. For each face referencing the vertex, get the texture face with the same index.
5. Get the index of the respective texture vertex from the face - 1st, 2nd or 3rd / .x, .y or .z
6. The vertex you got corresonds to the mesh vertex we started with.
7. Repeat steps 3 to 6 for all faces found.
Same applies to color vertices.
have the commands you have to use to implement the above algorithm.
Fix 3: For animated files I said I had computed the basevert_array so that
on back conversion you obtain the basepose when you open the file in
Milkshape. Well, that was half true, you get the basepose if you are a
Gmax user but I forgot to implement that for the 3ds Max side. There
you get the regular vert_array which would be whatever animation frame
was displayed when you exported. The animation data in the bones was
still correct, you just got a distorted mesh that would look terrible if you
played the animation in Milkshape. Now on the 3ds Max side, it looks at
a flag to decide if there is animation data present and stored in the root
bone (an animheader entry). If so, it writes out the basevert_array.