Forum Moderators: Staff
Poser Python Scripting F.A.Q (Last Updated: 2024 Sep 18 2:50 am)
FVerbaas posted at 4:23 PM Tue, 7 December 2021 - #4431434
That sounds so familiar.Just found out myfavorite vertex order mangler (Marvelous Designer loading an existing .obj as a garment) has bettered its ways and now returns objects with verts in the order it received them. May take a tad longer and a little more pushing before I can try the script.
By the way, I forgot to mention that the script does not only fix mangled vertex orders, but can also deal with missing or extra connected components (or loose parts in Blender parlance). Imagine the following scenario:
I export Antonia's head and eyes separately from Poser, then import both into Blender and make the eyes un-selectable so that I can see them while morphing the face but not accidentally deform them. The extra eyebrow geometry bothers me so I delete it. Oops, should have hidden it instead, but now I've already started morphing. Also, I forget to check "selected only" when I export.
Now I have an output mesh with the brows missing but the eyes added to the head. When I try to load that as a morph target, Poser is so confused it can't even. But my applyMorph script happily transfers vertex positions between the matching parts and ignores the rest.
-- I'm not mad at you, just Westphalian.
I think I've now figured out how to properly implement the part that I had left to SciPy. Interestingly, it kind of looks as if the algorithm is in the high school curriculum here in Australia, because I found dozens of YouTube videos that explain all the easy steps in great detail but don't say a word about how to actually do the one interesting step in practice*.
* From reading the original papers and fast-forwarding to modern terminology, it turns out to be the max-flow min-cut principle applied to maximal bipartite matchings, which I guess may not be in the high school curriculum.
-- I'm not mad at you, just Westphalian.
So familiar. They probably copied and had no idea where the crux was. Same here.....Interestingly, it kind of looks as if the algorithm is in the high school curriculum here in Australia, because I found dozens of YouTube videos that explain all the easy steps in great detail but don't say a word about how to actually do the one interesting step in practice*. :smile:
odf posted at 5:10 PM Tue, 7 December 2021 - #4431436
That sounds so familiar. :smile:
By the way, I forgot to mention that the script does not only fix mangled vertex orders, but can also deal with missing or extra connected components (or loose parts in Blender parlance). ....
I think I will make a small test rig that can swap vertex numbers in a mesh. Let's say let original vertex numbers 3 and 8 change place. That is a simple process that can be applied a number of times with different vertex numbers. Such would yield a consistent mangled result with controlled degree of difference from the original. From there, jitter along the normal can provide a morph target and of course additions and deletions can be applied.
Little heads-up: I've now written some replacement code for the one SciPy function I'm using in the script, which honestly was a lot of fun (yes, I like algorithms, sue me ). If you're curious, google "assignment problem."
It's only really needed for fairly extreme cases, like when you have a creature with lots of teeth that all have the same topology, then do a radical change in the head shape and need to come up with a reasonable guess of which tooth went where.
I've written some randomized tests for it, so I am quite confident that it works correctly. If all goes well, I'll make the change to the main script tomorrow and add new version tags v0.9.1 and v0.9.1_py27. Version v0.9.1_py27 should theoretically work with all Poser version from whenever the switch from Numeric to numpy was made.
-- I'm not mad at you, just Westphalian.
Here's a quick test and demo of what the tie breaking does. I made five copies of a (slightly beveled) cube in Blender, then moved the leftmost copy all the way to the right and also rotated all the cubes around. The image on the top left shows the initial state, the one on the bottom right the final state.
The top right shows what happens if I load the original export from Blender as a morph target and dial it to 0.5. The bottom left shows the corrected morph target, also at 0.5. The strategy here is to minimize the sum of squared distances travelled by the individual vertices.
-- I'm not mad at you, just Westphalian.
I think I'll try putting the type annotations into comments next, so I can have just one version that works with both Python 2 and Python 3, but still can run mypy on it to check the types.
Also, I'm thinking about putting all the code into one big file. Not my preference, but that way it's easier for folks who just want to use it as a script from outside Poser. That would mean though that when it's used from inside Poser, there's a bit of extra code (270 lines, at the moment) that's being loaded in but never used.
In the JavaScript world, I'd keep the files separate for development and run a precompile thingie that bunches them all together into one for deployment, but I'm not sure such a beast exists for Python.
Thoughts?
-- I'm not mad at you, just Westphalian.
*taps micro* Is this thing on?
I've found some old conforming clothes and props that have non-manifold parts according to my script, but in the ones I checked so far I haven't been able to find the offending edges easily. Not great for testing if they are so hidden. I've also discovered another problem with clothes, which is that there can be parts with ridiculous numbers of topological symmetries. This can easily happen if one uses deformed tubes, UV spheres or, worst of all, tori for parts of garments. I have to take a closer look to identify the offending parts and see if I can think of any solution. The script still works in those cases, but it takes ages.
Anyway, I also remembered that Apollo's eyes aren't manifolds, which should make them a great test/demo case. They're also, as it turns out, completely asymmetric, which was confusing because at first I thought my script not reporting any symmetries was due to a bug. Anyway, here's a morph for Apollo's left eye done in Blender, again without checking any of the "keep vertex order" boxes. Unmorphed eye at the top, raw Blender export fed into Poser in the middle, fixed at the bottom.
I think I'll probably have to mull over the algorithm a bit more and try to build meshes that break it, because I'm not a hundred percent convinced yet that it can really handle any non-manifold meshes I throw at it. Anyway, the new code is in the "non-manifold" branch of the Github repo if you'd like to give it a whirl.
-- I'm not mad at you, just Westphalian.
This site uses cookies to deliver the best experience. Our own cookies make user accounts and other features possible. Third-party cookies are used to display relevant ads and to analyze how Renderosity is used. By using our site, you acknowledge that you have read and understood our Terms of Service, including our Cookie Policy and our Privacy Policy.
Okay, it seems I've got some working code for fixing vertex orders in morph targets. Typical example: I export a character's head from Poser, spend a few hours reshaping it in Blender, and then realize I haven't checked "keep vertex order" when importing. Now with my script, I can still apply the morph by reconstructing the correct order, even if the mesh shape has changed drastically so that simple distance-based methods don't work.
If anyone is keen on trying it out, the code can be found at https://github.com/odf/pydeltamesh. Look for tags v0.9.0 and v0.9.0_py27 for the Python-3-only version (with type annotations) and the backported one that works in both Python 2 and Python 3, respectively. If you're unfamiliar with git or the github interface, let me know and I'll post some instructions.
There's a stand-alone script "applyMorph" that takes two OBJ files and produces a new OBJ file as output, and there's the core "match" module that can be used by other scripts, for example a fancy Python-based Poser morph loader. I haven't tested it with Poser yet (and probably won't any time soon), so if there are any problems, let me know. SciPy is used at one point, which I think may not be available in Poser versions before 12? If that's a problem, let me know and I'll come up with a workaround. Other than that, only Numpy is required. For a usage example, just check applyMorph.py.
At the moment the mesh must be a manifold. Adding support for non-manifold meshes (e.g. certain kinds of garment) will be my next mission.
-- I'm not mad at you, just Westphalian.