La Femme and clothroom problem


  • Poser Ambassadors

    @deecey once the sim is complete ... all the frames are "wrong".


  • Poser Ambassadors

    @deecey ... ok ... did the same dress same basic set up ... but with V4 and worked like a charm. Hmmm. Going to try V4-WM.


  • Poser Ambassadors

    @deecey 2 more tests. V4-WM, no problem. LF with file save as suggested, same problem. PE same problem. Works fine with V4/V4-WM.

    Note: will be off line till either early mornings this weekend or Monday.



  • which exact dress are you using? You said you are using a Fit LaFemme morph, did you zero that morph before the end of the sim. I have access to most of karatanas items and would like to check it out.
    Bill



  • If the dress does not default to LF, you should move down the timeline a bit before you invoke the morph. Do not add the morph at Frame0/1.


  • Poser Ambassadors

    It is the Mila dress, and I will try that next time I test the sim in my work machine.



  • Tr;y it with setting the lafemme morph to zero in the same frame you have the pose :D0_1560558036094_Mila Dress.jpg



  • Basicly, (assumng frame 15 for the pose), the dress fits lafemme in frame 15, if you do not remove it at that point it is doubling the morph
    Bill



  • @willyb53 I've long noticed that. Why does it do that? I assume it bakes the morphs into the mesh, then, at the end, there's the new mesh, to which Poser applies the morph. Wouldn't you want all morphs to that mesh turned off after the first frame, since they're all baked in and the mesh is now something other?



  • You want the morph in the dress to decrease slowly to allow it to fit, zero at the pose frame, and from there it does final draping.
    Bill



  • @willyb53 That's what I usually do. If it's something I'm going to use often, for a particular body shape, I export it as OBJ, then import it, and save the new prop, so I don't have to worry about fit morphs. "Tactically lazy"


  • Poser Ambassadors

    @willyb53 Tomorrow I will try adding the fit morphs to the dress and resaving it ... One never knows what might trigger this problem or alleviate it.



  • What i usually do is: After the simulation i go back to frame zero and set all additional fit or style morphs back to zero. The advantage over the ’fade out’ approach is that you get the right cloth fitting for all frames of the simulation.



  • @nagra_00_ I do that if I need all the frames (for an animation). Still, would be nice to have a simulation check box that "bakes all morphs in frame 0, for the duration of the simulation). In effect, it just zeros the morphs for that mesh (which it knows) for the frames (which it knows).
    I had always wished for 1) elasticity of the mesh. There is resistance but no force actively trying to return the vertices to their initial position. 2) some way to create "thickness" easily.



  • Poser does bake all morphs into the cloth before it starts its simulation. I just verified it by dialing in a style morph at frame 15 of the sim. This is just ignored and has no effect on the simulation itself at all. And yes it would be nice to have an option that Poser would zero any additional morphs automatically.



  • @nagra_00_ It would have to, to run a simulation, no? The part that would be nice would be the "turn off the morphs" since they're obviously already accounted for. Ahh well. As a victim (content dev wise) of the very old "obj file name cache bug", where poser only matches first filename of obj and not the path/filename Along with many segfaults while doing things like splitting morphs, copying morphs, deleting morphs in the morph tool GUI, I kind of hope the "crash and burn" bugs are fixed before they add a checkbox. Just sayin' :D



  • @thoennes Technical it would be possible to add morphs to a running sim, well most likely not with this old sim code implementation.

    Crashes are the least concern i have. Posers poor runtime performance especially when it comes to conformers does really bug me. And in the last version they introduced a new performance bug. Switching from pose room to the material room sometimes (and a way too often) leads to long delays and with each switch between rooms it becomes worse. I have not found the trigger for it yet and the only workaround is to restart Poser.



  • I found a LOT of the crashes in the morph room can be prevented by saving, closing, then reopening the scene. My impression is that when you do something though the GUI, there is a lag before all the bits of the scene in memory are actually updated. But the GUI allows you to continue. Which, if your next move somehow relies on the state being updated (say splitting a morph, then deleting half the resulting split), poser crashes. Probably because the morph split was not completely finished, in all its complexity. For instance, if the morph being split has a pile of dependencies that all have to be split. Another cause might be that the state is cached in memory and the cache is not updated, so when the next thing happens, memory does not match GUI. For instance, there are things done in python where the GUI does not pick it up, unless you selected, say, another parameter or actor, then select back. now the GUI is updated. And sometimes, in python, you change something then "save" and nothing saves because the scene has not been updated, as far as poser is concerned. I've changed internal names, tried to save and nothing happens. then poser crashes, and no changes were saved. Now, i force the save by selecting something else in the GUI, which sets "dirty" on the scene and allows a save, which updates those changes I made in python. Uhg. On the other hand, I was once doing a frame cleanup in python and had the animation window open, and going through each frame required the GUI to advance, slowly, though each frame. Never open that window when doing something like that. O.O
    (the script deleted key frames on actor.parms that never changed value. Some key operations key every parm on every actor at a frame. What a mess, when you later change those value. Then you have an initvalue key at some weird place.)



  • @thoennes Maybe you want to try the following Python script. It makes all morphtargets permanent and sets any morph to 0.

    (Source is a bit long, because I simply copied some standard-functions from my own Poser-Lib without optimization)

    Scroll down to function main:

    from __future__ import print_function
    try:
        import poser
        SCENE = poser.Scene()
    except ImportError:
        poser = SCENE = None
    
    import numpy as NP
    import re
    import types
    import sys
    
    REGEX_SEARCH_METHODE = "search"
    
    ########################################################################
    
    def create_regex(regex_string, default=".*"):
        if isinstance(regex_string, re._pattern_type):
            # Already a regex
            return regex_string
    
        if regex_string is None:
            # Use "catch-all" as default if not otherwise defined.
            regex_string = default
    
        if isinstance(regex_string, (list, tuple, types.GeneratorType)):
            for entry in regex_string:
                assert isinstance(entry, basestring), "Listmembers must be string."
            regex_string = "|".join(regex_string)
    
        if not isinstance(regex_string, basestring):
            raise TypeError("'create_regex' needs a <string> to compile regex")
    
        return re.compile(regex_string)
    
    
    ########################################################################
    
    def regex_search(regex, search_str, default=None):
        if regex is None:
            regex = ".*"
    
        if isinstance(regex, re._pattern_type):
            return getattr(regex, REGEX_SEARCH_METHODE)(search_str) or default
        if isinstance(regex, basestring):
            return getattr(re, REGEX_SEARCH_METHODE)(regex, search_str) or default
    
        raise AttributeError("<regex> must be type <str> or <regex> (result from re.compile(...))")
    
    ########################################################################
    
    def find_actor(actorname, BASE=SCENE, internal=None):
        """
        Return actor-object from <str|regex>actorname.
        If actorname is an actor already, this actor is returned immedeately.
    
        <str>actorname may contain a regular-expression.
    
        If internal is True, a search for InternalName is forced.
        This is also the case if actorname contains the character ":".
    
        Otherwise first a seach for InternalNames is done. If nothing
        was found, Display-Names are searched.
    
        e.g.:
            found = find_actor("BODY") # find body-actor
            found = find_actor(".*?B.*") # find first actorname containing "B".
            found = find_actor("[l|r]Collar:\d+") # first actor with matched InternalName
                    (one of lCollar:1 or rCollar:1, while "1" may be any number)
    
        :param actorname: str
        :param BASE: poser.Scene() or Figure() (where to search for actor, defaults to SCENE)
        :param internal: bool (search for InternalNames only)
        :return: poser.ActorType or None
        """
        if isinstance(actorname, poser.ActorType):
            # nothing to do
            return actorname
    
        if not isinstance(actorname, (re._pattern_type, basestring)):
            raise AttributeError("actorname must be type <str> or regex, not %s" % actorname)
    
        # choose between Name() or Internalname()
        if isinstance(actorname, basestring):
            internal = internal or (":" in actorname)
    
        if isinstance(actorname, basestring):
            # try to find a certain actor by Name or Internalname
            try:
                if internal:
                    return BASE.ActorByInternalName(actorname)
                else:
                    return BASE.Actor(actorname)
            except poser.error:
                return None
    
        # prepare regex-search
        regex = create_regex(actorname)
        name_func = ("Name", "InternalName")[bool(internal)]
    
        for actor in BASE.Actors():
            if regex_search(regex, actor.__getattribute__(name_func)()):
                return actor
    
        return None
    
    ########################################################################
    
    def find_morph(actor, morphname, ignore_zero_delta=True):
        """
        Find and return morph <morphname> from actor <actorname>, or None
    
        :param actor:
        :param morphname:
        :return: posermorph or None
        """
        if actor is not None:
            actor = find_actor(actor)
            assert isinstance(actor, poser.ActorType)
    
        # Get the morphname in case a morph is given, but another actor.
        # Means: Find a morph in actor A with the same name as in given morphtarget from actor B.
        if isinstance(morphname, poser.ParmType):
            morph = morphname
            if actor is None or actor.InternalName() == morph.Actor().InternalName():
                return morph
            else:
                morphname = morph.Name()
    
        assert isinstance(morphname, (re._pattern_type, basestring))
    
        if isinstance(morphname, basestring):
            morph = actor.Parameter(morphname)
            if morph is not None:
                # got it!
                if not ignore_zero_delta:
                    return morph
                elif morph.NumMorphTargetDeltas() > 0:
                    return morph
    
        regex = create_regex(morphname)
        for morph in iter_morphs(actor):
            if regex_search(regex, morph.InternalName()):
                if not ignore_zero_delta:
                    return morph
                elif morph.NumMorphTargetDeltas() > 0:
                    return morph
                break
    
        return None
    
    ########################################################################
    
    def iter_morphs(actor):
        """
        Generator.
    
        Yield all <poser.ParameterType>Morphtargets from given actor.
    
        :param actor: poser.ActorType or str/regex (actor-name).
        :param exclude: None or a list with Parameter.Name().
        :return: poser.ParameterType (morph-target)
        """
        actor = find_actor(actor)
    
        assert isinstance(actor, poser.ActorType)
        for param in actor.Parameters():
            if param.IsMorphTarget():
                yield param
    
    ########################################################################
    
    def morph2numarray(morphparam=None, actor=None, morphname=None):
        """
        Return morphdata as numpy-array.
    
        If <morphparam> is None, an <actor> and a <morphname> must be given.
        If <morphparam> is set, it must contain a Morph-Parameter object;
        <actor> and <morphname> are not required then.
    
        <morphparam> must be given as type <str> or <None>.
        <actor> can be given as type <str>, regex or actor-object.
    
        :param morphparam:
        :param actor:
        :param morphname:
        :return:
        """
        assert morphparam or actor is not None
    
        if morphparam is None:
            actor = find_actor(actor)
            if not isinstance(actor, poser.ActorType):
                raise ValueError("Given Actor must be <poser.ActorType> if 'morphname' is empty")
            # use morphname to get the parameter from Poser
            morphparam = actor.Parameter(morphname)
    
        try:
            if not morphparam.IsMorphTarget():
                raise ValueError("Given parameter must be morphtarget")
        except Exception as err:
            print("Given 'morphparam' is not a Poser morphparameter.")
            raise err
    
        geom = morphparam.Actor().Geometry()
        if geom is None or geom.NumVertices() == 0:
            return None
    
        return NP.array([morphparam.MorphTargetDelta(i)
                         for i in range(geom.NumVertices())], NP.float64)
    
    
    
    ########################################################################
    
    def all_morphs2array(actor, watch_value=True, morphlist=None):
        """
        Sum up all morphs from one actor to a single numpy array
        :param actor: poser.ActorType
        :param watch_value: boolean (Morph-Intensity/Parameter-Value)
        :return: NP.array
        """
        actor = find_actor(actor)
        assert isinstance(actor, poser.ActorType)
    
        try:
            geom = actor.Geometry()
        except Exception as err:
            print("Error in allMorphs2Array: No geometry", file=sys.stderr)
            raise err
    
        if morphlist is None:
            morphlist = iter_morphs(actor=actor)
    
        morph_len = geom.NumVertices()
    
        if morph_len > 0:
            morph = NP.zeros((morph_len, 3), NP.float64)
            for morphparam in morphlist:
                ar = morph2numarray(morphparam=morphparam)
                if ar is not None:
                    morph += ar * morphparam.Value() \
                        if watch_value \
                        else ar
        else:
            morph = None
    
        return morph
    
    
    ########################################################################
    
    def add_array2geometry(actor, ar_data):
        """
        Add <NP.array>morphdata to geometry for <poser.ActorType> actor.
        Morphdata may be collected with function 'morph2Array()'.
    
        !!! Changes actual actor-geometry !!!
    
        :param actor: poser.ActorType
        :param ar_data: NP.array
        :return: None or bool
        """
        actor = find_actor(actor)
        assert isinstance(actor, poser.ActorType)
        assert isinstance(ar_data, NP.ndarray)
    
        try:
            geom = actor.Geometry()
        except poser.error:
            return None
    
        if geom.NumVertices() != len(ar_data):
            raise ValueError("number of vertices for actor: '%s' does not match" % actor.InternalName())
    
        for ar_vertex, vertex in zip(ar_data, geom.Vertices()):
            vertex.SetX(vertex.X() + ar_vertex[0])
            vertex.SetY(vertex.Y() + ar_vertex[1])
            vertex.SetZ(vertex.Z() + ar_vertex[2])
    
        actor.MarkGeomChanged()
    
    ########################################################################
    
    def main():
        actor = SCENE.CurrentActor()
        res = poser.DialogSimple.YesNo("Add all morphs to actor %s's geometry?" % actor.Name())
        if res:
            # protect morph created from Cloth-Room:
            dynamics = find_morph(actor, "Dynamics", False)
            dyn_value = 0
            dyn_text = ""
            if dynamics is not None:
                dyn_value = dynamics.Value()
                dyn_text = "\n\nFYI: Morph 'Dynamics' is ignored."
                dynamics.SetValue(0)
    
            # get all morphdata into one numpy array
            morphdata=all_morphs2array(actor)
            # add morphdata to geometry
            add_array2geometry(actor=actor, ar_data=morphdata)
            # step through morphs and set to 0
            for morph in iter_morphs(actor):
                morph.SetValue(0)
            # set old value if required
            if dynamics is not None:
                dynamics.SetValue(dyn_value)
    
            SCENE.DrawAll()
            poser.DialogSimple.MessageBox("Ok, done. Remember to save this actor if you need a permanent copy."+dyn_text)
        else:
            print("Aborted.")
    
    if __name__ == "__main__":
        main()
    
    
    


  • @thoennes said in La Femme and clothroom problem:

    @nagra_00_ I do that if I need all the frames (for an animation). Still, would be nice to have a simulation check box that "bakes all morphs in frame 0, for the duration of the simulation). In effect, it just zeros the morphs for that mesh (which it knows) for the frames (which it knows).
    I had always wished for 1) elasticity of the mesh. There is resistance but no force actively trying to return the vertices to their initial position. 2) some way to create "thickness" easily.

    What you essentially look for I understand is fitting clothing, not in the sense of the fitting room where the geometry is stretched/shrunk to fit around the figure without building in the strain and pressure that goes with clothing worn on a body, but real fit with those effects included.
    Your best chances are with Marvelous Designer, where the model includes knowledge about the original flat pieces of fabric, and the sim takes stress from the strain between the original and the 3D model. I wrote the MBBridge for Poser with the objective to overcome exactly that hurdle. The published version of MDBridge works with PE. I have a beta working now supporting a choice of figures, including LaFemme, Pauline, and Antonia. If you are on a windows system and have MD8, I will be happy to send you a copy. The bridge supports export of 'thin' (single-centreplane mesh) and 'thick' (with separate facets for sides and edges of the fabric), as generated by MD, so that would fulfill both your two wishes. Collision-distance (thickness in simulation) can be set.
    An alternative is to start the simulation from a shape where the garment is in un-strained position and grow the figure onto it. For LaFemme and a garment where strain is important this would mean starting from a lithe body form and in the sim grow the body to the final size before posing into shape. In this way the Clothroom sim builds up the strain info itself and you do not have as much the 'worn' look that comes if you start from a garment already 'fitted'.

    BTW also other simulators (VWD, Blender) could derive the strain and stress of the clothing in the shape it has in from a .obj generated by MD. In the 2D representation in the .obj (AKA UV map), the length of the edges is the true unstrained length of the edges. (i.e. the size it was in the piece of fabric as it was cut before sewing). Of course if UV is unified one has to multiply with the scale, say for example one UV space unit is 1500 mm. Fabric properties in real world units (g-mm-sec) MD used come in a metafile.

    Making a 'thick' copy of a draped piece of clothing for the rendering should not be overly difficult to do in a script. One has to find the free edges of the mesh though. To my recollection for MD produced meshes the edges are given in the metafile.