Metaballs script



  • Hi! I'm really Interested in this.
    Will you make it compatible with octane render?



  • Hello Spartan; I'm not sure how Octane works, so it's difficult to predict.

    For rendering a single frame I'd say most probably yes, because that field is just a regular prop with regular texture nodes, which is regenerated on each frame.

    For rendering a movie that will have to be seen, as the prop has variable geometry, so it has to be fully regenerated on each frame. That's done through a Python callback. So if Octane refreshes everything for each frame, then it should work, but if it retains information from the previous frame then it might not work.

    One thing I'm thinking, though, to avoid the trouble with the callback, is to build the field as a series of props, and just hide/make them visible in the right frames. That way it should be compatible with any renderers.



  • What a pain in the rear is SeoGeometry() and Python callbacks!!! The thing will crash randomly on you with no information of what's wrong, and the manual provides minimum insights on any of the callbacks. For example, it has this very useless description of a typical callback:

    SetVertexCallback
    Explanation
    Set a per-update callback to process actor (vertices) while in local deformed
    space. The user-defined function will be called back on each full update of an
    actor and allows for manipulation of the vertices (or other information) at the
    point in the display pipeline of Poser which processes vertex level deformations.
    Arguments
    The callback function should take an actor object and make desired
    modifications to it.

    It refers to a "display pipeline" but gives no information of how that pipeline is, so I have no clue where this actually fits in the flow. It tells I can make "desired modifications" on "other information" but doesn't say what I can change - can I change textures? geometry? only vertex coordinates? Also, what's a "full update"? If the frame changes but the actor is static will it update?

    The Python API is incredibly vague and limited about geometry changes! What a shame! It seems that whoever wrote it thought paper was expensive, so he/she limited the description to the smallest amount possible.

    So because someone didnt' want to spend 15 minutes describing an API function fully, I (and probably other customers) had to spend 15 hours of my life trying to identify what I can and cannot do inside a callback.

    I'm giving up on this sleazy function. Mission now is to dynamically change the geometry of a prop without using that loser of a function which is SetGeometry().



  • @fbs7 would you like me to see whether the Mac version is less prone to the crashes you are experiencing? I'm quite happy to bulk the think up with debugging statements, and I have unbuffered logging routines that write to an external file which can be externally monitored in real time, so Poser crashing won't prevent any of the previously issued logging being swallowed by the output buffering.
    I could, alternatively, send the logging routines to you, if you prefer.



  • @fbs7 have you made progress on transferring material trees? I have developed Python routines which can save and load pose, character and scene files to and from the library, bypassing Poser's own load and save routines, but have yet to implement the material tree creation. It's been a while since I last looked at it, but IIRC I found something missing from the Python materials API which meant I couldn't just create all the nodes and trees. I'll have another look, but the simplest solution for transferring materials may end up being just save from the field prop and reload them from the library onto the metaball prop(s).



  • @anomalaus said in Metaballs script:

    @fbs7 would you like me to see whether the Mac version is less prone to the crashes you are experiencing? I'm quite happy to bulk the think up with debugging statements, and I have unbuffered logging routines that write to an external file which can be externally monitored in real time, so Poser crashing won't prevent any of the previously issued logging being swallowed by the output buffering.

    That's a good idea. Try these two scripts, if you would. This one is "Create Metaball.py":

    import poser
    from numpy import oldnumeric
    
    #
    # This script creates a cube to limit an isosurface, and a handler for a metaball
    # fbs 12/7/2017
    #
    
    # Check if 'IsoField' already exists, if not create one
    scene = poser.Scene()
    try:
    	isoField = scene.Actor('IsoField')
    except:
    	# Vertices of a cube
    	c = 1.0         # Cube size
    	verts = oldnumeric.array( [[0,0,0],[0,0,c],[0,c,0],[0,c,c],[c,0,0],[c,0,c],[c,c,0],[c,c,c]] )
    
    	# Sets = vertex indexes
    	sets = numpy.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] )
    
    	# Polys = faces, index to sets
    	polys = oldnumeric.array( [[0,4],[4,4],[8,4],[12,4],[16,4],[20,4]] )
    
    	# Create the geometry
    	meshGeom = poser.NewGeometry()
    	meshGeom.AddGeneralMesh( polys, sets, verts )
    
    	# Create the prop
    	isoField = scene.CreatePropFromGeom(meshGeom,'IsoField')
    
    	# Set draw style to wireframe
    	isoField.SetDisplayStyle( poser.kDisplayCodeWIREFRAME )
    
    	# End Frame
    	parmEndFrame = isoField.CreateValueParameter('End Frame')
    	parmEndFrame.SetValue(30)
    	parmEndFrame.SetMinValue(1)
    	parmEndFrame.SetSensitivity(1)
    	parmEndFrame.SetForceLimits(1)
    
    	# Start Frame
    	parmStartFrame = isoField.CreateValueParameter('Start Frame')
    	parmStartFrame.SetValue(1)
    	parmStartFrame.SetMinValue(1)
    	parmStartFrame.SetSensitivity(1)
    	parmStartFrame.SetForceLimits(1)
    
    	# Resolution
    	parmResolution = isoField.CreateValueParameter('Resolution')
    	parmResolution.SetValue(10)
    	parmResolution.SetMinValue(1)
    	parmResolution.SetMaxValue(20)
    	parmResolution.SetSensitivity(1)
    	parmResolution.SetForceLimits(1)
    
    	# Threshold
    	parmThreshold = isoField.CreateValueParameter('Threshold')
    	parmThreshold.SetValue(1)
    	scene.DrawAll()
    
    # Find the smallest N that 'MetaBallN' does not already exist as children of the iso field
    childList = isoField.Children()
    found = 0
    for n in xrange(1,101):
    	metaBallName = u'MetaBall' + str(n)	# Poser needs Unicode
    	found = 0
    	for child in childList:
    		if child.Name() == metaBallName:
    			found = 1
    			break
    	if found == 0:
    		break
    
    # Now let's create a metaball handler; it will be a little cube; code is the same as above
    c = 0.01
    verts = oldnumeric.array( [[0,0,0],[0,0,c],[0,c,0],[0,c,c],[c,0,0],[c,0,c],[c,c,0],[c,c,c]] ) - c/2
    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] )
    polys = oldnumeric.array( [[0,4],[4,4],[8,4],[12,4],[16,4],[20,4]] )
    
    # Create the geometry
    meshGeom = poser.NewGeometry()
    meshGeom.AddGeneralMesh( polys, sets, verts )
    
    # Create the prop and make it a child of isoField
    metaBall = scene.CreatePropFromGeom(meshGeom,metaBallName )
    parmStickness = metaBall.CreateValueParameter('Stickness')
    parmStickness.SetValue(2.0)
    metaBall.SetParent(isoField, 0, 0)
    parmStrength = metaBall.CreateValueParameter('Strength')
    parmStrength.SetValue(5.0)
    
    # Position the prop in the middle of the iso field
    geom = isoField.Geometry()
    vertex7 = geom.Vertex(7)
    sX = vertex7.X()
    sY = vertex7.Y()
    sZ = vertex7.Z()
    metaBall.SetParameter('xTran',sX/2)
    metaBall.SetParameter('yTran',sY/2)
    metaBall.SetParameter('zTran',sZ/2)
    
    # All done; now we have a the cube for the iso field, and a smaller cube to center metaballs in that field
    


  • hmm... can't post Run Metaballs.py; too large; and can't attach .txt or .py either...

    let's see if I can find some file sharing service somewhere



  • @fbs7 I use DropBox



  • Try this guy:

    link text



  • Now, these crashes are sporadic. In my last test it took some 3 hours of continuous running and some 20 simulations to get it to crash, so it's not like it runs once and crashes. Some people might live with a crash in 3 hours, but that's not good enough.

    I've disabled some aspects of it to see if the crashes would go away, so testing will have to be in a particular sequence.

    Suggest this:
    (a) Start from blank document
    (b) Execute "Create Metaball" 3 times; it will create a big wireframe box and 3 small boxes one on top of the other
    (c) At frame 1, separate the 3 small boxes into 3 positions within the big wireframe
    (d) Check the big frame "isoField" properties; set threshold=1, resolution=20, start frame=1, end frame=20
    (e) Check the small boxes "Metaball n" properties; set strength=1.0, stickness=2.0
    (d) At frame 20, move the metaballs to other positions, rotate and scale them, can change the field strength (a field strength=10 means the metaball diameter covers the whole field, =1 means its diameter is 10% of the field), change stickness slightly (stickness=2 means it will stick to other metaballs up to 2x of its radius away)
    (e) Save the file so you don't have to redo this again
    (f) Execute "Run Metaballs"; once it says "Generate mesh frame 20" it's done; then click on Play to play the animation
    (g) repeat (d) to (f); eventually it will crash

    Thanks for the help!



  • @fbs7 first problem is numpy namespace definition

    Traceback (most recent call last):
      File "/Applications/Poser 11/Runtime/Python/poserScripts/ScriptsMenu/Partners/FBS/Create Metaball.py", line 19, in <module>
        sets = numpy.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] )
    NameError: name 'numpy' is not defined
    

    I'll try just:

    import numpy
    


  • Hmm.. how odd; that works ok for me; I took that import from one of the samples in PP11, but some of these samples look broken



  • 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.