Metaballs script



  • Actually, scrap that; that was my typo; I copying stuff to the Python script a bit ago and touched that line; please chaneg to this

    	# Sets = vertex indexes
    	sets = oldnumeric.array( [0,1,3,2,  0,4,5,1,  0,2,6,4,  7,5,4,6,  7,3,1,5,  7,6,2,3] )
    


  • Anomalous, have you tried anything about using that SetGeometry() little monster to set a dynamic geometry?

    If that thing worked reliably, then it would be easy to manipulate any geometry dynamically. Just bake it in memory, and do the switcharoo in an appropriate callback.

    For example, one could do 3D Join and Minus operations with solids, or switch figures with a reduced poly version of them for faster preview.



  • @fbs7 OK, that explains that, I had success just importing numpy, but none of my other scripts did any more than oldnumeric.

    First crash report: Segmentation fault

    Looks like memory (mis)management, for which Poser is renowned (or at least some of the libraries they are forced to use, if not actual SMS code).

    Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
    0 SMArtSkinBase.dylib ... MEM_IsMemBlock + 9
    1 SMArtSkinBase.dylib ... GEOM_VerifyAndFix(GEOM*) + 28
    2 com.SmithMicro.Poser ... PEActor3D::SetGeom(GEOM*, VERTEX*, bool, BArray<long>) + 384
    3 com.SmithMicro.Poser ... setGeometry(actorObject
    , _object*) + 267

    Had run Create Metaball.py (with import numpy), and changed the metaBall1 strength from 5.0 to 1.0, yScale from 100 to 50% and xScale from 100 to 200% at frame 30.
    Ran 'Run Metaballs.py' which created the isoSurfaces, clicked Run and got through 2 cycles of frames before Poser crashed.

    The previous iteration, I had made no metaball parameter changes and Poser cycled through all of the identical isoSurfaces without any crashing, so it definitely looks like a problem with memory management. Whether this can be worked around, I am unsure. Perhaps, as you suggested, cycling the visibility of a series of once created props will be an interim solution. I'd definitely be reporting this kind of memory fault to SMS, though. Once you've sent your report in, I can follow up with mine, so they know it's across platforms and focus on how SetGeom() garbage collection happens.



  • @fbs7 I have not played with "dynamic" geometry since I changed my figures from Poser Traditional to Unimesh, and noticed that Geometry switching no longer worked for body parts.

    The only other time I've used SetGeometry() was when trying to modify an existing mesh tesselation routine to preserve the UV mapping of existing vertices and interpolate the UV mapping for the new tesselation vertices.

    If anything, I think the Mac platform is less robust than Windows, where Poser memory management is concerned. Though, I guess the pendulum swings occasionally.



  • Oh.. that's a pretty nice stack trace you got there. You always get tht in the Mac, or do you use an external tool to get it?

    In Windows I only get "Your application has crashed, dummy! Do you want to find a solution at Microsoft?" or something like that



  • Hmmm... sooo... if that's indeed in SetGeometry... maybe that means that the list I use to keep geometries has been reclaimed, but I'm still keeping a pointer to it... hmm...

    Time to check the inner workings of memory management and object lifecycle in Python.



  • @fbs7 the stack trace is a very useful feature of MacOS, though the trace probably only gets sent to Apple (I'd love them to all be automatically sent to SMS, so they'd get real-time feedback of what the poor Poser slobs have to go through.

    0_1513400800140_Screen Shot 2017-12-16 at 4.04.21 pm.png



  • @fbs7 just to clarify, I did not have to resort to your full suggested list of actions to induce Poser to crash. Just these:

    (a) Start from blank document (I have a New Construct scene without Andy, which I load, replacing the default scene).
    (b) Executed "Create Metaball.py" just once.
    (f) Executed "Run Metaballs.py"; it generated 30 frames. Turned off skip frames. Clicked play, and waited till I got bored with unchanging, identical isoSurfaces before terminating the loop.
    (d-2nd) Changed the metaball1 strength from 5.0 to 1.0, xScale from 100% to 200%, yScale from 100% to 50% at frame 30.
    (g) Re-executed "Run Metaballs.py" and clicked play when it had regenerated to 30 frames. Got through 2-3 iterations of the 30 frame loop before Poser crashed.

    So, it seems to me that the Mac platform is more prone to memory management issues that PC. BTW, I have 32GB RAM, and I can guarantee that there is absolutely no way Poser was using all of that, so it's probably not a recursion problem, but may be an inaccurate memory allocation issue. I very frequently see Poser crashes with attempts to free unallocated pointers.



  • Wow, that's pretty neat!!

    A beautiful stack trace, indeed; one could even get a glimpse of what Poser is doing by forcing these exceptions!

    movie loop -> computer scene transformations (probably a camera thingie) -> apply parameters to actors -> calculate local matrices for the actors -> (grabs in our callback) -> set geometry -> crash

    Maybe we really can't call SetGeometry() within any of the callbacks... but at the very bottom of the trace it seems it's handling some event... let's see if there's some undocumented event callback that shows when a frame has changed... hmm....



  • Hmm.. check this:

    def eventCallback(scene, code):
    	if code <> 16:
    		print 'Code = ',code
    
    ...
    scene.SetEventCallback(eventCallback)
    

    It will display a continuous series of code = 16, even when nothing's happening. No idea yet what is that 16. Whenever you change frames manually, it sends a code = 17.



  • So, 1 = kEventCodeKEYSCHANGED, 16 = undocumented... but 16 keeps happening all the time, so it must be Draw or something like that. Let's see how the thing behaves if I hook on event = 16, haha...



  • @fbs7 from my Poser Pro 11.0.8.34338 Python 2.7.2 Shell

    >>> poser.kEventCodeACTORADDED
    64
    >>> poser.kEventCodeACTORDELETED
    4
    >>> poser.kEventCodeACTORSELECTIONCHANGED
    8
    >>> poser.kEventCodeANIMSETSCHANGED
    4096
    >>> poser.kEventCodeITEMRENAMED
    256
    >>> poser.kEventCodeKEYSCHANGED
    1
    >>> poser.kEventCodePARMADDED
    128
    >>> poser.kEventCodePARMDELETED
    32
    >>> poser.kEventCodeSCENECLOSING
    1048576
    >>> poser.kEventCodeSETUPMODE
    8192
    

    Looking at one of @bagginsbill 's Parmatic scripts, he uses the explicit constant 16 and it's bitwise inverse ~16 in his event decoding callback, so yes, it's undocumented. My guess would be it coincides with a "ProcessSomeEvents" or idle moment.



  • Followed the instructions to the letter this time, except before pressing play, I manually incremented through all the frames beforehand and Poser then refused to crash. Last time I had just closed a largish scene, and this attempt was immediately after launching Poser.

    Applied a SuperFly volumetric glass shader to the isoSurface and made the isoField prop invisible in Render and Camera then rendered this sequence with low samples (10).



  • @fbs7 just noticed if I rotate the isoField prop, which the metaBall props are parented to, during the animation frames, the isoSurface does not follow the field's orientation, but acts as though there had been no isoField rotation, probably due to the UNIVERSE parenting during the isoSurface geometry creation.

    What are the possibilities of using a mesh as the field delimiter? Are the field constraints based on coordinate axis limits, or are you doing volume containment calculations?

    I know I should answer my own questions by looking at the code, but I'm about to nod off, so I'll look again tomorrow.



  • @anomalaus said in Metaballs script:

    @fbs7 just noticed if I rotate the isoField prop, which the metaBall props are parented to, during the animation frames, the isoSurface does not follow the field's orientation, but acts as though there had been no isoField rotation, probably due to the UNIVERSE parenting during the isoSurface geometry creation.

    What are the possibilities of using a mesh as the field delimiter? Are the field constraints based on coordinate axis limits, or are you doing volume containment calculations?

    I know I should answer my own questions by looking at the code, but I'm about to nod off, so I'll look again tomorrow.

    Yeah, that's the part I commented out, as I thought it might be a cause for the crashes. The code is easy to put back in, though; it's just two lines.



  • @anomalaus said in Metaballs script:

    @fbs7 from my Poser Pro 11.0.8.34338 Python 2.7.2 Shell

    Looking at one of @bagginsbill 's Parmatic scripts, he uses the explicit constant 16 and it's bitwise inverse ~16 in his event decoding callback, so yes, it's undocumented. My guess would be it coincides with a "ProcessSomeEvents" or idle moment.

    I tried to hook into that constant 16 to do the mesh update, because the event processing is way down in the loop sequence in the stack you posted, so it should have a better memory setup I thought, but... alas... the thing stops issuing 16 (or any other events) while it's in the run preview loop.

    So hooling in event processing will not do. I'll do one last attempt to change the darned SetGeometry() to be CreatePropFromGeometry() instead, as I don't remember crashes with that, but I fear it will kill the preview speed, as there's no single function to call to copy a material tree - it will have to be node by node I think.



  • The only other alternative I see is to create 100 props during baking (instead of in the callback), as set visibility. But then the user will be left with 100 static props around.

    I'm thinking that direction would involve having 4 scripts, probably:

    Create Metaball
    Create Surfaces (which was Run Metaball)
    Hide/Unhide Surfaces
    Remove Surfaces

    So instead of being dynamic the whole thing is static; but then you add 100 (or more) objects in the hierarchy window (although all of them are parented the same), and you have 100 things to save/load in the file...



  • On the other hand, because everything would be static, one would be able to drag and drop across the timeline without having to recalculate the simulation.

    Also it should be compatible with any renderer, given that now you just have 100 props around.



  • Alright, I can't manipulate the parameter "Visible" before it becomes animating parameter:

    >>> scene = poser.Scene()
    >>> a = scene.Actor('IsoField')
    >>> a.Parameter('Visible')
    >>> b = a.Parameter('Visible')
    >>> print b
    None
    

    Once Visible is set to animating in the GUI then the print b returns a parameter, but not before. But, there's no API to make the "Visible" property animating. So can't do it.

    Of course can still do within a callback, but once burned by the callback thingie, twice scared of it. So let's see how it works if I set scale = 0, X/Y/Z = 1000000 for the points where the pre-generated props should not be visible...



  • So enough of that! Time for me to stop complaining and start programming. Just a change a direction.