I've been hanging out in NiNtoxicated's Max .m3 script thread while developing a .m3 Import plugin for Cinema 4D... I thought I'd go ahead and create a new thread, so as not to hijack that thread with any questions/comments about this plugin.
What is m3IO?
m3IO development started out as mostly a curiosity for me, but also because I was/am developing a .dds bitmap file Import/Export plugin for CInema 4D and I was looking for various games/apps that used that format, to test my (bitmap) plugin. The plugin now Imports .m3 files, but there are no plans at this time to create an Export plugin.
Where to find/get it:
The functionality of m3IO has been incorporated into my (commercial) "I/Ogre" plugin - since it uses some of the Tags that that plugin provides - but "m3IO" is a stand-alone version of that module and is available as FreeWare from my site.
Disclaimer:
As mentioned in the various documentation and postings, the plugin should be considered 'BETA' software - while there are no known existing bugs that would cause C4D to crash, you should always save any important data before using the plugin - use at your own risk.
As I mentioned earlier, my interest and work with the .m3 file format was mostly "out of curiosity" - and to get some animated models to test .dds bitmaps (and thier use in various programs) with...
Now that I have a basic Cinema 4D .m3 Importer, I think I'm basically 'done' (I have no plans for an Exporter). Anyway, for anyone curious, the Importer has been merged into my I/Ogre plugin for Cinema 4D. I/Ogre is a game-oriented file-format Import/Export plugin that supports the following file types:
Ogre3D - Import/Export of fully rigged and animated figures as .mesh, .skeleton, .material files (the ascii-based .xml versions of those files).
VALVe:Source Engine - Import/Export of fully rigged and animated figures as .smd files.
MilkShape3D - Import/Export of fully rigged and animated figures as .ms3d files.
...and now...
Blizzard - Import (only) of fully rigged and animated figures from .m3 files.
...I/Ogre is an (inexpensive) commercial plugin - I only included the .m3 Import in it as a bonus, since it uses some of the additional mechanisms that my plugin supplies (a "Figure Export Tag" and an "Animation Clip Tag", etc). I may still create a separate / stand-alone (and free) .m3 Import plugin.
All file formats (now including .m3) create the exact same workflow / Object Manager hierarchy within Cinema 4D - despite vast differences in the file-types - making it easy to convert between the various formats (and if you own MilkShape3D, it opens up dozens of other game-oriented file-formats).
Anyway, I didn't mean to go on an advertising rant here or otherwise detract from the thread - I just wanted to let people know what I was working on... I/Ogre and my other plugins can be found on my site.
Cheers. (I'm sure I'll still be lurking... :) )
EDIT: BTW, I never did get "scaling" working quite right.. any/all of the WoW-exported figures import fine, but my plugin still has some trouble with the SCII-native .m3 files that use joint-scaling.
Frankly, I don't think there is a solution - as you noted with the carrier. I think if you look closely enough at the other models that use mirroring, you'll find the same issue (what's COH?). I could be wrong, but if it's not 'automatically' being handled by the game code, then there would have to be hinting data in the .m3 file and any sort of 'fix/hinting' in the .m3 file would have to be at the polygon or even vertex level and that would be a tedious thing to implement (ie. you'd need some method inside Max to specify a "reverse uv-winding-order" type flag on individual polygons, that would produce some lookup-table or set of flags for each polygon in the .m3 file).
...just doesn't seem overly likely to me, but... who knows? ;)
Thanks, I'll take a look at that. In the meantime... if you are generating these models from scratch, why not just 'fix' (ie. to not share/mirror) the uv-mapping from the start? I assume it's being done this way to optimize pixel-space, but the model is not highly detailed and the 'bottom' of it wouldn't need to be as hi-res as the top, so you could afford to give the top more real-estate, if needed. Something more like one of the images below...
What model is that? I wasn't able to find the Defiler in the demo version data. I'd like to find one of these examples so I can see the actual Normal Map(s) and uv-mapping.
As mentioned, I hadn't really used any of nVidia's plugins or tools but I am familiar with the sample code nVidia supplies (I'm using it in my own plugin). I'm a little surprised to hear what it's doing when you choose DXT5nm, but...
Basically, there are two 'Normal Map' related issues:
1. as we've been discussing, Channel-swapping / rearranging is needed. It sounds like the plugin is not really doing this (or at least not doing it correctly) for you.
2. a separate issue related to Normal Map storage in .dds files is... the type of compression used. When you tell the plugin to save in the DXT5nm format, the overall format is the same as regular DXT5, but the path through the compression code is slightly different, to help keep the XYZ Normal data from being inappropriately smoothed/averaged/blended (in other words, it knows that it's going to be used as Normal Map data, instead of 'color' data).
...since it's not really handling the channel-swapping (correctly) for you, my suggestion would be to just do that by hand (manually copy the red->alpha, then clear the red and fill the blue), then just save it as regular DXT5. By using DXT5, you don't get the (mostly minimal) benefit of item #2, above, but in many/most cases you might not be able to tell the difference anyway.
Now, having said all that... I'm still not clear how what you're doing will help with the "shared-uv but mirrored polys" issue... unless the map looked bad on both sides - you could correct the part that got mapped incorrectly/inconsistently, but the other side of the mesh would still need an entirely separate (and inverted) bitmap to correct it.
So... saving in DXT5n (or DXT5nm) didn't automatically swap the channel data around for you? I hadn't tried any of nVidia's tools or plugins - but my own plugin (for Cinema 4D) does the swapping for you.
Anyway, it sounds like you figured it out, so I'm happy to hear that my post was useful :).
Regarding the normal map, I sort of multiplied the blue channel over the green and red for the defiler. Somehow it works. Though, I'm not sure if this is how it should be done, or how Blizzard does their normal maps.
I'm not sure I'm following that, but you might find my post at the bottom of this thread of interest, regarding how SCII normal maps are stored in .dds files.
Note that the blue (Z) value will be 're-computed' by the app after loading the .dds file (based on the red/green channels), so what you describe above would be... a bit odd :).
BTW, unrelated to anything above, but I added some additional bone info tracking and noticed that the value before the Name (that everyone is referring to as 'd1') is NOT always -1... here's a bone out of the Zergling:
...I added code to prepend a bunch of asterix if the value was not -1, to make it easier to find them... note the value is '6' in the above bone. In that same mesh, I also found values of 5, 8, 9 and 0. Kinda seems like some index value, but I have no idea what it's used for - just thought I'd pass that info along while I was thinking about it. So far, s1, d2, d3 and d4 all seem to just be 0.
In 3dsmax, there's dialog options under Hierarchy -> Link Info where you can turn off scaling inheritance. So, for example, if you had a sphere object that was the parent of a cube object, and you added some scaling to the sphere to make it look like an ellipsoid, you wouldn't want that nasty scaling to pass down to the cube.
It seems this inheritance information is also store in the M3 BONE chunk as flags. I was wondering if anyone has found any models that make use of these flags, such as not passing along scale? If so, what M3 models?
That's an interesting question... and (as you mentioned) the bones do have a 'flags' member that would seem to include flag bits for the above (see: http://code.google.com/p/libm3/wiki/BONE ), but interestingly, those flags don't seem to be set on the models I've looked at so far - at least I haven't noticed any. I'm currently logging lots of info when reading .m3 files, so I get something similar to the following for each bone...
...(those are my own internal variable names and in some cases user-import-scaling (and axis-swapping) has been applied to the logged values to make it easier for me to debug/compare to what I'm seeing in the app).
So far, I'm mostly seeing the UNKNOWN (bit 14) flag set on most bones (unless the m_flags == 0) and then ANIMATED for bones that have animation data and SKINNED for any that are involved in mesh skinning, but I'm not seeing any other flags set (though I'm sure one or both of the BILLBOARD flags are used on some models).
...combined with the above, your function named "M3I_Bones_Bindpose" is actually setting the 'base' pose :) (that likely changed at some point during development). Nothing wrong with that.. it's just confused me from time to time...
Speaking of the above... again, I don't know exactly how Max works, but it appears that when your script calls "M3I_Create_Skin", the "current frame" is still set at the "base pose" frame (frame 1) and not the "bind pose" frame (frame 0) - I didn't see anything between the call to "M3I_Bones_Poses" and creating the skin that changed the current frame. If it makes a difference, I think you want to use the bind-pose frame to skin the meshes (ie. set to the IREF matrices).
... snip ... I think your suggestion/description above (and thus script coding) is actually wrong about those pos/rot/scale values that are attached to the bones...
Your suggestion (and script) 'combines' (multiplies) those values with the IREF (bind) matrices, to come up with a 'base pose'... I'm almost positive that you should not be combining them with the IREF matrices - they simply make up a 'local' bone matrix - just like any other keyframe data does. If you think about how the (your) exporter script works, you'll come to the same conclusion, I think. It simply converts 'global' bone matrices into 'local' bone matrices, by removing the parent matrix (multiplying by the inverse of the parent). If you need to convert them back to global matrices, they should be multiplied by the parent bone values (not the IREF matrices). ...snip...
The above quote (from me) is either misleading or just wrong on some points... partly due to my own confusion and/or not tracking exactly what your script was doing (and what the conditions were at the time, etc). I don't know much about Max - let alone Max script - so I'm having to read up on it as I go and/or make some assumptions. There's also some confusion (on my part, or at least my description is sometimes confusing) related to Local vs Global matrices/transforms.
Anyway, what I said about the bone transform values (pos/rot/scale in the bone structure, that you use to make a 'base' pose) is correct - they make up essentially the exact same pose as the first frame of the first animation (which makes me wonder why they exist at all). The part that I mis-stated is when I suggested that it was wrong to combine those values with the IREF matrices - I hereby take that back :) - your script is doing that correctly.
The confusion is/was due to several factors...
as mentioned, there was some confusion about whether you were creating Local or Global matrices for the poses/animation keys. In fact, you appear to be mixing methods to come up with the 3 needed key types - translation and scale use Local (in coordsys parent) and rotations are computed by setting the bone's 'transform' value, which appears to be a Global (in coordsys world) operation.
combined with the above, your function named "M3I_Bones_Bindpose" is actually setting the 'base' pose :) (that likely changed at some point during development). Nothing wrong with that.. it's just confused me from time to time.
after reviewing your script again, it appears that you have the IREF (bind) pose set prior to setting up keyframes - or the base pose... contrary to my previous reply (quoted above), I now see/agree that that is correct, for what you are doing (ie. you already _are_ treating the bone values the same way you do the keyframe data).
...aside from the axis-swapping that I need to do for Cinema 4D, there are other differences that I need to handle or keep in mind that probably also add to my confusing explanations. For example, when I'm creating keyframes, I always need 'Local' (in coordsys parent) transforms... and that's actually how the data (rotations, in particular) is supplied already, so *I* don't need to combine the rotations with the IREF matrices, but for what you're doing, that's correct, etc. Frankly, I'm still confused why you need to do what you're doing with rotations - I would think that you could just set the .rotation values (in coordsys parent) instead of doing the .transform thing, but from your comments in the script, apparently you had some trouble with that.
Anyway, sorry for rambling - I just wanted to try to clarify that somewhat.
0
BTW, does anyone know how (or IF I can) to enable an e-mail notification when/if anyone replies to a thread I've subscribed to?
0
Hi gang,
I've been hanging out in NiNtoxicated's Max .m3 script thread while developing a .m3 Import plugin for Cinema 4D... I thought I'd go ahead and create a new thread, so as not to hijack that thread with any questions/comments about this plugin.
What is m3IO?
m3IO development started out as mostly a curiosity for me, but also because I was/am developing a .dds bitmap file Import/Export plugin for CInema 4D and I was looking for various games/apps that used that format, to test my (bitmap) plugin. The plugin now Imports .m3 files, but there are no plans at this time to create an Export plugin.
Where to find/get it:
The functionality of m3IO has been incorporated into my (commercial) "I/Ogre" plugin - since it uses some of the Tags that that plugin provides - but "m3IO" is a stand-alone version of that module and is available as FreeWare from my site.
Disclaimer: As mentioned in the various documentation and postings, the plugin should be considered 'BETA' software - while there are no known existing bugs that would cause C4D to crash, you should always save any important data before using the plugin - use at your own risk.
Cheers.
0
Hey guys,
As I mentioned earlier, my interest and work with the .m3 file format was mostly "out of curiosity" - and to get some animated models to test .dds bitmaps (and thier use in various programs) with...
Now that I have a basic Cinema 4D .m3 Importer, I think I'm basically 'done' (I have no plans for an Exporter). Anyway, for anyone curious, the Importer has been merged into my I/Ogre plugin for Cinema 4D. I/Ogre is a game-oriented file-format Import/Export plugin that supports the following file types:
Ogre3D - Import/Export of fully rigged and animated figures as .mesh, .skeleton, .material files (the ascii-based .xml versions of those files).
VALVe:Source Engine - Import/Export of fully rigged and animated figures as .smd files.
MilkShape3D - Import/Export of fully rigged and animated figures as .ms3d files.
...and now...
Blizzard - Import (only) of fully rigged and animated figures from .m3 files.
...I/Ogre is an (inexpensive) commercial plugin - I only included the .m3 Import in it as a bonus, since it uses some of the additional mechanisms that my plugin supplies (a "Figure Export Tag" and an "Animation Clip Tag", etc). I may still create a separate / stand-alone (and free) .m3 Import plugin.
All file formats (now including .m3) create the exact same workflow / Object Manager hierarchy within Cinema 4D - despite vast differences in the file-types - making it easy to convert between the various formats (and if you own MilkShape3D, it opens up dozens of other game-oriented file-formats).
Anyway, I didn't mean to go on an advertising rant here or otherwise detract from the thread - I just wanted to let people know what I was working on... I/Ogre and my other plugins can be found on my site.
Cheers. (I'm sure I'll still be lurking... :) )
EDIT: BTW, I never did get "scaling" working quite right.. any/all of the WoW-exported figures import fine, but my plugin still has some trouble with the SCII-native .m3 files that use joint-scaling.
0
Frankly, I don't think there is a solution - as you noted with the carrier. I think if you look closely enough at the other models that use mirroring, you'll find the same issue (what's COH?). I could be wrong, but if it's not 'automatically' being handled by the game code, then there would have to be hinting data in the .m3 file and any sort of 'fix/hinting' in the .m3 file would have to be at the polygon or even vertex level and that would be a tedious thing to implement (ie. you'd need some method inside Max to specify a "reverse uv-winding-order" type flag on individual polygons, that would produce some lookup-table or set of flags for each polygon in the .m3 file).
...just doesn't seem overly likely to me, but... who knows? ;)
0
Here's a quickie .obj file remap (similar to the first image above)...
(note: I took the liberty of 'welding' the points of the mesh while I was at it)
0
Thanks, I'll take a look at that. In the meantime... if you are generating these models from scratch, why not just 'fix' (ie. to not share/mirror) the uv-mapping from the start? I assume it's being done this way to optimize pixel-space, but the model is not highly detailed and the 'bottom' of it wouldn't need to be as hi-res as the top, so you could afford to give the top more real-estate, if needed. Something more like one of the images below...
0
What model is that? I wasn't able to find the Defiler in the demo version data. I'd like to find one of these examples so I can see the actual Normal Map(s) and uv-mapping.
0
Ok, a couple thoughts...
As mentioned, I hadn't really used any of nVidia's plugins or tools but I am familiar with the sample code nVidia supplies (I'm using it in my own plugin). I'm a little surprised to hear what it's doing when you choose DXT5nm, but...
Basically, there are two 'Normal Map' related issues:
1. as we've been discussing, Channel-swapping / rearranging is needed. It sounds like the plugin is not really doing this (or at least not doing it correctly) for you.
2. a separate issue related to Normal Map storage in .dds files is... the type of compression used. When you tell the plugin to save in the DXT5nm format, the overall format is the same as regular DXT5, but the path through the compression code is slightly different, to help keep the XYZ Normal data from being inappropriately smoothed/averaged/blended (in other words, it knows that it's going to be used as Normal Map data, instead of 'color' data).
...since it's not really handling the channel-swapping (correctly) for you, my suggestion would be to just do that by hand (manually copy the red->alpha, then clear the red and fill the blue), then just save it as regular DXT5. By using DXT5, you don't get the (mostly minimal) benefit of item #2, above, but in many/most cases you might not be able to tell the difference anyway.
Now, having said all that... I'm still not clear how what you're doing will help with the "shared-uv but mirrored polys" issue... unless the map looked bad on both sides - you could correct the part that got mapped incorrectly/inconsistently, but the other side of the mesh would still need an entirely separate (and inverted) bitmap to correct it.
0
So... saving in DXT5n (or DXT5nm) didn't automatically swap the channel data around for you? I hadn't tried any of nVidia's tools or plugins - but my own plugin (for Cinema 4D) does the swapping for you.
Anyway, it sounds like you figured it out, so I'm happy to hear that my post was useful :).
0
I'm not sure I'm following that, but you might find my post at the bottom of this thread of interest, regarding how SCII normal maps are stored in .dds files.
Note that the blue (Z) value will be 're-computed' by the app after loading the .dds file (based on the red/green channels), so what you describe above would be... a bit odd :).
0
BTW, unrelated to anything above, but I added some additional bone info tracking and noticed that the value before the Name (that everyone is referring to as 'd1') is NOT always -1... here's a bone out of the Zergling:
...I added code to prepend a bunch of asterix if the value was not -1, to make it easier to find them... note the value is '6' in the above bone. In that same mesh, I also found values of 5, 8, 9 and 0. Kinda seems like some index value, but I have no idea what it's used for - just thought I'd pass that info along while I was thinking about it. So far, s1, d2, d3 and d4 all seem to just be 0.
0
That's an interesting question... and (as you mentioned) the bones do have a 'flags' member that would seem to include flag bits for the above (see: http://code.google.com/p/libm3/wiki/BONE ), but interestingly, those flags don't seem to be set on the models I've looked at so far - at least I haven't noticed any. I'm currently logging lots of info when reading .m3 files, so I get something similar to the following for each bone...
...(those are my own internal variable names and in some cases user-import-scaling (and axis-swapping) has been applied to the logged values to make it easier for me to debug/compare to what I'm seeing in the app).
So far, I'm mostly seeing the UNKNOWN (bit 14) flag set on most bones (unless the m_flags == 0) and then ANIMATED for bones that have animation data and SKINNED for any that are involved in mesh skinning, but I'm not seeing any other flags set (though I'm sure one or both of the BILLBOARD flags are used on some models).
0
Speaking of the above... again, I don't know exactly how Max works, but it appears that when your script calls "M3I_Create_Skin", the "current frame" is still set at the "base pose" frame (frame 1) and not the "bind pose" frame (frame 0) - I didn't see anything between the call to "M3I_Bones_Poses" and creating the skin that changed the current frame. If it makes a difference, I think you want to use the bind-pose frame to skin the meshes (ie. set to the IREF matrices).
0
The above quote (from me) is either misleading or just wrong on some points... partly due to my own confusion and/or not tracking exactly what your script was doing (and what the conditions were at the time, etc). I don't know much about Max - let alone Max script - so I'm having to read up on it as I go and/or make some assumptions. There's also some confusion (on my part, or at least my description is sometimes confusing) related to Local vs Global matrices/transforms.
Anyway, what I said about the bone transform values (pos/rot/scale in the bone structure, that you use to make a 'base' pose) is correct - they make up essentially the exact same pose as the first frame of the first animation (which makes me wonder why they exist at all). The part that I mis-stated is when I suggested that it was wrong to combine those values with the IREF matrices - I hereby take that back :) - your script is doing that correctly.
The confusion is/was due to several factors...
...aside from the axis-swapping that I need to do for Cinema 4D, there are other differences that I need to handle or keep in mind that probably also add to my confusing explanations. For example, when I'm creating keyframes, I always need 'Local' (in coordsys parent) transforms... and that's actually how the data (rotations, in particular) is supplied already, so *I* don't need to combine the rotations with the IREF matrices, but for what you're doing, that's correct, etc. Frankly, I'm still confused why you need to do what you're doing with rotations - I would think that you could just set the .rotation values (in coordsys parent) instead of doing the .transform thing, but from your comments in the script, apparently you had some trouble with that.
Anyway, sorry for rambling - I just wanted to try to clarify that somewhat.
0
nvm... found it.