Useful Python Script

  • @adp I've just been setting limits and forceLimits to do that kind of thing for rotations. I guess it would work as well for translations, provided Poser will apply the forced limits (I seem to remember there being some things it didn't enforce).

    On your Im/Exporter, I was just looking at your post in the other thread and it reminded me I'd recently done something relevant with creating a 2-manifold version of a hair prop from the original transmapped, non-manifold version, because I wanted to be able to use SuperFly Volumetrics for wet hair effects without getting transmap artifacts (due to transparency only applying to UV mapped surface facets, not the volume enclosed by the model). Anyway, TL;DR, the code I have specifically detects facet seams with duplicated vertices in the geometry, and has code for direct import and export of wavefront obj geometry, if you're interested, I will post the file.

  • @adp

    from the comment header:

    # Convert the currently selected prop from an open (non-manifold) surface to a 2-manifold enclosed volume.
    # Non-2-manifolds are detected by a non-zero count of edges which border only one facet. The vertices on such edges
    # remain unchanged, while all other vertices are duplicated and offset by a user-specified distance along the inverse
    # of the original vertex's normal. All facets will be duplicated, incorporating either duplicate vertices or original
    # edge vertices. All morphs will have the additional vertices appended, with delta values identical to the original
    # deltas of the vertex from which they were derived. 

    The script contains an object class definition which collects lots of additional analysis information of the mesh, such as seams and borders, and methods to load from in-scene geometry or direct from .obj file. Within the CreateManifold() method, there's a pure .obj file creation section which bypasses Poser's obj export routines and writes the object class instance geometry straight to a .obj file, so it can be subsequently loaded by Poser's import routine, which is the only way to create new facet groups within the current Python API (without resorting to manually using the Grouping Tool).

    The script can also preserve existing morphs on the newly cloned object.

  • @adp I should add that Make2Manifold is not particularly optimised for speed (though it does make use of frozensets), so please don't hesitate to suggest ways to improve performance. :-) Please feel free to use anything you find beneficial.

  • @anomalaus Sounds useful. Where is the code? :)

  • @anomalaus Oh, I'm blind... Overlooked the link.

  • @anomalaus Sorry, can't load anything from with any of my browsers on no machine I have. This is what I get:
    0_1531062175656_Bildschirmfoto vom 2018-07-08 17-01-04.png

  • @adp Oh, that's frustrating. I've not seen that before. Do you have an ad blocker or something that's preventing javascript?

    I see this when I click the link (though I have a mega account so that may be relevant):
    0_1531063007359_Screen Shot 2018-07-09 at 1.15.04 am.png

    OK, try this first time I've uploaded anything to ShareCG!

  • @anomalaus I disabled adblockers in firefox and chromium, tried with a very simple webbrowser (without any extensions), and tried with tablets/smartphones.
    But: I'm behind a firewall that blocks .ru and .cn IPs and rejects calls to/from IPs listed as malicious.
    I can ping and get the first part from their index-page. But it seems they do load something from somewhere my firewall calls "malicious".

    Anyway, thanks for uploading to ShareCG. Now I'm off for a moment or two, looking at your script...

  • I think I'll go with a binary searched list to get a pseudo-sorted vertexlist.
    In a test I was able to compute and write an OBJ file with a vertexlist (no tex-vertices jet) and new constructed polygon-indices from Roxie (~30000 vertices) within rund about 2 seconds (but the polygons are not correctly constructed yet :)).

    Tested with an older laptop (SSD, 8 gig Memory, I5 processor), Poser Python, empty scene, just plain Roxie loaded.
    With a "busy" Poser scene and more vertices it may last a bit longer because of memory swapping. I'll test that later. First I have to look why I get a polygonset that looks like a pot full of spaghetti. :)

  • @adp assuming you don't have an out-by-one error in your vertex indexing (that happened to me all the time, in development, because the memory array indices are zero based, but the vertex references in the obj file are one based), make sure you haven't re-ordered any of the vertex references in the facets, because that could randomise the normals (reverse vertex order flips the normal, determined by curled Right Hand fingers match the vertex winding and RH thumb gives the normal direction).

  • @anomalaus No, it wasn't this well know "out-by-one" thing :)
    I simply didn't change the polygon-sets right. Now, if I export Roxie, I get:

    Export to: F:\Python\Morphs+Mags\OBJ-TRANSFER\Roxie.obj
    Time used to export: 1.927 seconds.

    Aaaaand: I can load it perfectly well into my modeler. Without groups, without duplicate vertices!
    :) :) :) :) :) :) :) :) (and a lot more of this...)

    Ok, still no tex-vertices written, but for morphs this is not required.

    Next step is to import the changed model and create a FBM. But only for the actors with moved vertices.

  • @anomalaus said in Useful Python Script:

    @adp make sure you haven't re-ordered any of the vertex references in the facets, because that could randomise the normals (reverse vertex order flips the normal, determined by curled Right Hand fingers match the vertex winding and RH thumb gives the normal direction).

    I construct and write a complete different mesh. I have to, because I have to remove the doubled vertices on groups-boundaries. And I have to create a new set of polygons.

    I do not write normals, because my modeller constructs normals automatically. As far as I know, Poser ignores normales in an OBJ file.

  • @adp it is correct that Poser ignores the OBJ file, vn x y z normal lines, as it creates the normals based on the implicit winding of the facets (which could, theoretically contradict vertex normals), so in effect, poser uses facet normals, rather than vertex normals.

    The other thing to note is that poser IS perfectly capable of creating (and subsequently exporting without corruption) an internal geometry mesh from python scripts (without recourse to writing and reading obj files manually in python), as long as you don't use groups at all (the Python API does not yet support mesh group creation).

    Have you compared the vertex order you generate with that of the original obj file for the figure? Are you able to reconstruct that order so that external morphs you create can load on the original obj version of the figure?

  • @anomalaus Goal is, to remove double vertices and get a watertight mesh. No groups. So the new vertexorder is different and will be reconstructed on input.

    I mark Poly-groups with "o" or "usemtl". What to use depends on what the other app does with "o". By default C4D splits a mesh if an "o" is seen (adding vertices!). Others may not. Using materialzones for the posergroups makes it easier to morph in certain situations.

    This is useful only for creating morphs if ZBrush is not an option.

  • @adp I understand, but the original figure's obj file is presumably without any duplicated vertices. If you load that in with an OBJ reading python script and just ignore the group definition lines, while creating the mesh you've just read, you'll get a mesh whose vertices match the original order. If that process parallels parsing (and eliminating duplicated vertices) the already loaded figure, you could directly map vertex indices and acquire all of the figure's morphs onto the new, ungrouped geometry you've created.

    That was the secondary premise of the Make2Manifold script (apart from creating a second shell to enclose a volume) and would work on a figure too.

  • But the original file is not what I'm after.

    What I try to do is all about morphing.
    I want to be able to fix a posed and morphed figure. Or cloth on a figure. Importing both into the modeller, fix an issue and move it back to Poser.

  • @adp so your workflow is just for your own use and will never be distributed? I've been focused on mechanisms that can validly produce distributable morphs for third party figures. Once a scheme departs from the original geometry, no one else can make use of it. Am I wrong in thinking that once you've exported, modified, re-imported and applied externally created morphs to a figure with modified geometry in Poser, you can't make use of those morphs on another instance of the original figure. [Apologies if I'm slow to catch on. Chronic sleep debt is my life, sigh X-/ ]

    As a side note, while I was investigating a DSON bypass for Poser, by reading Genesis figure .duf & .dsf files directly, I noticed that DSON was making extensive use of CustomData in the Poser files it was creating. Following this, I came to the logical conclusion that that was the most appropriate mechanism for storing a per-actor vertex index translation table, to convert morph delta indices to (original, ungrouped, unduplicated) figure geometry vertex indices.

    When [hopelessly optimistic] Poser finally goes fully unimesh internally, these dramas will all seem like a particularly disturbing cheese dream, no doubt. ;-)

  • @adp since ShareCG rejected my original post due to reasons, I've re-uploaded it with an image attached to meet their current posting policy. Here's the link for anyone that comes across this thread and finds a dead link. Make2Manifold zip archive with instructions

  • @adp ColorCurvature's Pose Morph Loader has done this for years. It's an excellent piece of python programming that I used extensively.

    While it isn't available at a brokerage now, I have had several folks I'm helping contact him and he sold them the package privately.

    There's an email address on his page here.

  • @Glitterati3D
    I want to have an open source script. Usable by anyone, hopefully to extend it further. Or use it for things I didn't think of.