Forum: Poser Python Scripting


Subject: Hack: Cleam morphs covered by specific materials

adp001 opened this issue on Apr 06, 2021 ยท 3 posts


adp001 posted Tue, 06 April 2021 at 4:36 AM

For a special case I needed a script able to clean a morph if that morph touches a certain material. So I made one (not very well tested, but it seems to work):

from __future__ import division, print_function

try:
    import poser
except ImportError:
    from PoserLibs import POSER_FAKE as poser

import sys, wx
if sys.version_info.major > 2:
    # Python 3 (Poser 12 and above)
    basestring = str
    from importlib import reload

    map = lambda a, b: [a(_b) for _b in b]
    newIdRef = wx.NewIdRef
else:
    # Python 2 (Poser 11 and below)
    newIdRef = wx.NewId


def find_polys(polys, materialindexlist):
    """Find and return polygons with material index contained in materialindexlist."""
    poly_indices = list()
    for idx, poly in enumerate(polys): # type: (int, poser.PolygonType)
        if poly.MaterialIndex() in materialindexlist:
            poly_indices.append(idx)

    return poly_indices


def verts_from_polys(geom, polyindices):
    """Find and return vertices contained in polygons."""
    assert isinstance(geom, poser.GeomType)
    assert isinstance(polyindices, list)
    vertexindices = list()
    sets = geom.Sets()
    polys = geom.Polygons()

    for polyidx in polyindices:
        p = polys[polyidx]  # type: poser.PolygonType
        vertexindices.extend(sets[p.Start():p.Start()+p.NumVertices()])

    return vertexindices


def reset_morphs_in_material(figure, materiallist, morphlist=None):
    assert isinstance(figure, poser.FigureType)
    if isinstance(materiallist, basestring):
        materiallist = [materiallist, ]
    if isinstance(morphlist, basestring):
        morphlist = [morphlist, ]
    assert hasattr(materiallist, "__iter__")
    assert hasattr(morphlist, "__iter__")

    # Make a list of materialnames from figure.
    figure_matnames = [m.Name() for m in figure.Materials()]

    # Convert all materials in materiallist to index positions.
    # materiallist must contain strings or poser.Material objects.
    try:
        materiallist = [figure_matnames.index(m if isinstance(m, basestring) else m.Name())
                        for m in materiallist]
    except AttributeError:
        print("One or more materials is not string or ")
        return None
    except IndexError:
        print("One or more Materialnames could not be found.")
        return None

    for ac in [_ac for _ac in figure.Actors() if _ac.IsBodyPart()]:  # type: poser.ActorType
        if hasattr(ac, "Geometry"):
            geom = ac.Geometry()
            if not geom or geom.NumVertices() == 0:
                continue
            vertex_indices = verts_from_polys(geom, find_polys(geom.Polygons(), materiallist))
            if len(vertex_indices) != 0:
                for morph in [p for p in ac.Parameters() if p.IsMorphTarget()]:  # type: poser.ParmType
                    if morphlist is not None and morph not in morphlist:
                        continue

                    if morph.NumMorphTargetDeltas() != 0:
                        cnt = 0
                        for idx in range(geom.NumVertices()):
                            v = morph.MorphTargetDelta(idx)
                            if v[0] != 0 or v[1] != 0 or v[2] != 0:
                                if idx in vertex_indices:
                                    cnt += 1
                                    morph.SetMorphTargetDelta(idx, 0, 0, 0)
                        if cnt:
                            print(cnt, "morph vertices in", ac.Name(), ">", morph.Name())

Usage:

reset_morphs_in_material(figure, materiallist, morphlist)

"morphlist" is a list of morphnames or None. In case of None all morphs are used.

"materiallist" is a list of materialnames or poser.Materials(). Vertices contained in a morph and covered by one of the named materials are set to 0.

I used this to clean up morphs for hair with a lot of materialgroups. And for cloth to clean "buttons". It's faster and easier as using the morphbrush :)