Example #1
0
    def toSMPX(self, path):
        defDict = self.toJSON()
        jsString = json.dumps(defDict)

        arch = OArchive(str(path))  # alembic does not like unicode filepaths
        try:
            par = OXform(arch.getTop(), str(self.name))
            props = par.getSchema().getUserProperties()
            prop = OStringProperty(props, "simplex")
            prop.setValue(str(jsString))
            mesh = OPolyMesh(par, str(self.name))

            faces = Int32TPTraits.arrayType(len(self._faces))
            for i, f in enumerate(self._faces):
                faces[i] = f

            counts = Int32TPTraits.arrayType(len(self._counts))
            for i, c in enumerate(self._counts):
                counts[i] = c

            schema = mesh.getSchema()
            for shape in self.shapes:
                verts = shape.toSMPX()
                abcSample = OPolyMeshSchemaSample(verts, faces, counts)
                schema.set(abcSample)
        except:
            raise

        finally:
            del arch
Example #2
0
def buildAlembicArchiveData(path, name, jsString, ogawa):
	''' Set up an output alembic archive with a mesh ready for writing

	Parameters
	----------
	path : str
		The output file path
	name : str
		The name of the system
	jsString : str
		The simplex definition string
	ogawa : bool
		Whether to open in Ogawa (True) or HDF5 (False) mode

	Returns
	-------
	: OArchive
		The opened alembic output archive
	: OPolyMesh
		The mesh to write the shape data to

	'''
	arch = OArchive(str(path), ogawa)
	par, props, abcMesh = [None] * 3
	try:
		par = OXform(arch.getTop(), str(name))
		props = par.getSchema().getUserProperties()
		writeStringProperty(props, 'simplex', jsString, ogawa)
		abcMesh = OPolyMesh(par, str(name))
	except Exception:
		arch, par, props, abcMesh = [None] * 4
		raise
	return arch, abcMesh
Example #3
0
def exportUnsub(inPath, outPath, newFaces, kept, shapePrefix=None, pBar=None):
    ''' Export the unsubdivided simplex '''
    iarch = IArchive(str(inPath))  # because alembic hates unicode
    top = iarch.getTop()
    ixfo = IXform(top, top.children[0].getName())

    iprops = ixfo.getSchema().getUserProperties()
    iprop = iprops.getProperty("simplex")
    jsString = iprop.getValue()

    if shapePrefix is not None:
        d = json.loads(jsString)
        if d['encodingVersion'] > 1:
            for shape in d['shapes']:
                shape['name'] = shapePrefix + shape['name']
        else:
            d['shapes'] = [shapePrefix + i for i in d['shapes']]
        jsString = json.dumps(d)

    imesh = IPolyMesh(ixfo, ixfo.children[0].getName())

    verts = getSampleArray(imesh)
    verts = verts[:, kept]

    indices = []
    counts = []
    for f in newFaces:
        indices.extend(f)
        counts.append(len(f))

    abcCounts = mkArray(IntArray, counts)
    abcIndices = mkArray(IntArray, indices)

    # `False` for HDF5 `True` for Ogawa
    oarch = OArchive(str(outPath), False)
    oxfo = OXform(oarch.getTop(), ixfo.getName())
    oprops = oxfo.getSchema().getUserProperties()
    oprop = OStringProperty(oprops, "simplex")
    oprop.setValue(str(jsString))
    omesh = OPolyMesh(oxfo, imesh.getName())
    osch = omesh.getSchema()

    if pBar is not None:
        pBar.setValue(0)
        pBar.setMaximum(len(verts))
        pBar.setLabelText("Exporting Unsubdivided Shapes")
        QApplication.processEvents()

    for i, v in enumerate(verts):
        if pBar is not None:
            pBar.setValue(i)
            QApplication.processEvents()
        else:
            print "Exporting Unsubdivided Shape {0: <4}\r".format(i + 1),
        sample = OPolyMeshSchemaSample(mkSampleVertexPoints(v), abcIndices,
                                       abcCounts)
        osch.set(sample)
    if pBar is None:
        print "Exporting Unsubdivided Shape {0: <4}".format(len(verts))
Example #4
0
    def exportABC(self, path):
        defDict = self.simplex.buildDefinition()
        jsString = json.dumps(defDict)

        arch = OArchive(str(path))  # alembic does not like unicode filepaths
        try:
            par = OXform(arch.getTop(), str(self.name))
            props = par.getSchema().getUserProperties()
            prop = OStringProperty(props, "simplex")
            prop.setValue(str(jsString))
            mesh = OPolyMesh(par, str(self.name))
            self.DCC.exportABC(mesh, defDict)

        finally:
            del arch
Example #5
0
def mismatchedTransfer(sourcePath, matchPath, outPath, invertMatch=False):
    ''' Transfer shape data from the sourcePath using the numpy int array
	at matchPath to make the final output at outPath
	'''
    print "Loading Simplex"
    sourceArch = IArchive(str(sourcePath))  # because alembic hates unicode
    sourceShapes = getShapes(sourceArch)
    jsString = loadJSString(sourceArch)
    sFaces, counts = getMesh(sourceArch)
    sFaces = np.array(sFaces)

    print "Loading Correspondence"
    c = np.load(matchPath)
    c = c[c[:, 0].argsort()].T[1]
    ci = c.argsort()
    if invertMatch:
        ci, c = c, ci

    print "Reordering"
    targetShapes = sourceShapes[:, c, :]
    faces = mkSampleIntArray(ci[sFaces])

    print "Writing"
    oarch = OArchive(str(outPath))  # alembic does not like unicode filepaths
    try:
        _writeSimplex(oarch, 'Face', jsString, faces, counts, targetShapes)
    finally:
        del oarch
        gc.collect()
Example #6
0
    def extractExternal(self, path, dccMesh):
        # Extract shapes from an arbitrary mesh based on the current simplex
        defDict = self.simplex.buildDefinition()
        jsString = json.dumps(defDict)

        arch = OArchive(str(path))  # alembic does not like unicode filepaths
        try:
            par = OXform(arch.getTop(), str(self.name))
            props = par.getSchema().getUserProperties()
            prop = OStringProperty(props, "simplex")
            prop.setValue(str(jsString))
            abcMesh = OPolyMesh(par, str(self.name))
            self.DCC.exportABC(dccMesh, abcMesh, defDict)

        finally:
            del arch
Example #7
0
def writeSimplex(inPath, outPath, newShapes, name='Face', pBar=None):
    '''Write a simplex file with new shapes

	Parameters
	----------
	inPath : str
		The input .smpx file path
	outPath : str
		The output .smpx file path
	newShapes : np.array
		A numpy array of shapes to write
	name : str
		The name of the new system
	pBar : QProgressDialog, optional
		An optional progress dialog

	Returns
	-------

	'''
    if not os.path.isfile(str(inPath)):
        raise IOError("File does not exist: " + str(inPath))
    iarch = IArchive(str(inPath))
    jsString = loadJSString(iarch)
    faces, counts = loadMesh(iarch)
    del iarch

    oarch = OArchive(str(outPath),
                     OGAWA)  # alembic does not like unicode filepaths
    try:
        _writeSimplex(oarch, name, jsString, faces, counts, newShapes, pBar)
    finally:
        del oarch
        gc.collect()
Example #8
0
def hdf5Convert(inPath, outPath, ogawa=False):
    '''Load and parse all the data from a simplex file

	Parameters
	----------
	inPath : str
		The input .smpx file path
	outPath : str
		The output .smpx file path
	ogawa : bool
		Whether to write out in Ogawa format. Defaults False

	Returns
	-------

	'''
    if not os.path.isfile(str(inPath)):
        raise IOError("File does not exist: " + str(inPath))
    iarch = IArchive(str(inPath))
    jsString = loadJSString(iarch)
    shapes = loadSmpx(iarch)
    faces, counts = loadMesh(iarch)
    del iarch

    oarch = OArchive(str(outPath),
                     ogawa)  # alembic does not like unicode filepaths
    try:
        _writeSimplex(oarch, 'Face', jsString, faces, counts, shapes)
    finally:
        del oarch
        gc.collect()
Example #9
0
	def toSMPX(self, path, pBar=None):
		defDict = self.toJSON()
		jsString = json.dumps(defDict)

		# `False` for HDF5 `True` for Ogawa
		arch = OArchive(str(path), False) # alembic does not like unicode filepaths
		try:
			par = OXform(arch.getTop(), str(self.name))
			props = par.getSchema().getUserProperties()
			prop = OStringProperty(props, "simplex")
			prop.setValue(str(jsString))
			mesh = OPolyMesh(par, str(self.name))

			faces = Int32TPTraits.arrayType(len(self._faces))
			for i, f in enumerate(self._faces):
				faces[i] = f

			counts = Int32TPTraits.arrayType(len(self._counts))
			for i, c in enumerate(self._counts):
				counts[i] = c

			schema = mesh.getSchema()

			if pBar is not None:
				pBar.setMaximum(len(self.shapes))
				pBar.setValue(0)
				pBar.setLabelText("Exporting Split Shapes")
				QApplication.processEvents()

			for i, shape in enumerate(self.shapes):
				if pBar is not None:
					pBar.setValue(i)
					QApplication.processEvents()
				else:
					print "Exporting Shape {0} of {1}\r".format(i+1, len(self.shapes)),
				verts = shape.toSMPX()
				abcSample = OPolyMeshSchemaSample(verts, faces, counts)
				schema.set(abcSample)
			if pBar is None:
				print
		except:
			raise

		finally:
			del arch
Example #10
0
def _exportUnsub(outPath,
                 xfoName,
                 meshName,
                 jsString,
                 faces,
                 verts,
                 uvFaces,
                 uvs,
                 pBar=None):
    oarch = OArchive(str(outPath), OGAWA)  # False for HDF5
    oxfo = OXform(oarch.getTop(), xfoName)
    oprops = oxfo.getSchema().getUserProperties()
    oprop = OStringProperty(oprops, "simplex")
    oprop.setValue(str(jsString))
    omesh = OPolyMesh(oxfo, meshName)
    osch = omesh.getSchema()

    if pBar is not None:
        pBar.setValue(0)
        pBar.setMaximum(len(verts))
        pBar.setLabelText("Exporting Unsubdivided Shapes")
        QApplication.processEvents()

    abcIndices = mkSampleIntArray(list(chain.from_iterable(faces)))
    abcCounts = mkSampleIntArray(map(len, faces))

    kwargs = {}
    if uvs is not None:
        # Alembic doesn't use None as the placeholder for un-passed kwargs
        # So I don't have to deal with that, I only set the kwarg dict if the uvs exist
        uvidx = None if uvFaces is None else list(chain.from_iterable(uvFaces))
        uvSample = mkUvSample(uvs, uvidx)
        kwargs['iUVs'] = uvSample

    for i, v in enumerate(verts):
        pbPrint(pBar, "Exporting Unsubdivided Shape", i)
        sample = OPolyMeshSchemaSample(mkSampleVertexPoints(v), abcIndices,
                                       abcCounts, **kwargs)
        osch.set(sample)

    pbPrint(pBar, "Done")
Example #11
0
def writeSimplex(inPath, outPath, newShapes, name='Face', pBar=None):
    ''' Write a simplex file with new shapes '''
    iarch = IArchive(str(inPath))
    jsString = loadJSString(iarch)
    faces, counts = loadMesh(iarch)
    del iarch

    oarch = OArchive(str(outPath))  # alembic does not like unicode filepaths
    try:
        _writeSimplex(oarch, name, jsString, faces, counts, newShapes, pBar)
    finally:
        del oarch
        gc.collect()
Example #12
0
def hdf5Convert(inPath, outPath):
    ''' Load and parse all the data from a simplex file '''
    iarch = IArchive(str(inPath))
    jsString = loadJSString(iarch)
    shapes = loadSmpx(iarch)
    faces, counts = loadMesh(iarch)
    del iarch

    oarch = OArchive(str(outPath),
                     False)  # alembic does not like unicode filepaths
    try:
        _writeSimplex(oarch, 'Face', jsString, faces, counts, shapes)
    finally:
        del oarch
        gc.collect()
Example #13
0
def reorderSimplexPoints(sourcePath, matchPath, outPath, invertMatch=False):
    '''Transfer shape data from the sourcePath using the numpy int array
		at matchPath to make the final output at outPath

	Parameters
	----------
	sourcePath : str
		The source .smpx file path
	matchPath : str
		The new vert order dumped from numpy
	outPath : str
		The new output .smpx path
	invertMatch : bool
		Whether to directly apply the match from matchPath, or whether to invert it

	Returns
	-------

	'''
    print "Loading Simplex"
    if not os.path.isfile(str(sourcePath)):
        raise IOError("File does not exist: " + str(sourcePath))
    sourceArch = IArchive(str(sourcePath))  # because alembic hates unicode
    sourceShapes = getShapes(sourceArch)
    jsString = loadJSString(sourceArch)
    sFaces, counts = getMesh(sourceArch)
    sFaces = np.array(sFaces)

    print "Loading Correspondence"
    c = np.load(matchPath)
    c = c[c[:, 0].argsort()].T[1]
    ci = c.argsort()
    if invertMatch:
        ci, c = c, ci

    print "Reordering"
    targetShapes = sourceShapes[:, c, :]
    faces = mkSampleIntArray(ci[sFaces])

    print "Writing"
    oarch = OArchive(str(outPath),
                     OGAWA)  # alembic does not like unicode filepaths
    try:
        _writeSimplex(oarch, 'Face', jsString, faces, counts, targetShapes)
    finally:
        del oarch
        gc.collect()
Example #14
0
def hdf5Convert(inPath, outPath, ogawa=False):
    ''' Load and parse all the data from a simplex file '''
    if not os.path.isfile(str(inPath)):
        raise IOError("File does not exist: " + str(inPath))
    iarch = IArchive(str(inPath))
    jsString = loadJSString(iarch)
    shapes = loadSmpx(iarch)
    faces, counts = loadMesh(iarch)
    del iarch

    oarch = OArchive(str(outPath),
                     ogawa)  # alembic does not like unicode filepaths
    try:
        _writeSimplex(oarch, 'Face', jsString, faces, counts, shapes)
    finally:
        del oarch
        gc.collect()
Example #15
0
def expandedExportAbc(path, mesh, master, clients=()):
    '''Export the alembic by re-building the deltas from all of the full shapes
		This is required for delta-mushing a system, because the sum of mushed shapes
		is not the same as the mushed sum-of-shapes

	Parameters
	----------
	path : str
		Output path for the .smpx
	mesh : str
		The maya shape node name
	master : Simplex
		The master simplex system
	clients : [Simplex, ...]
		The client simplex systems

	Returns
	-------

	'''
    # Convert clients to a list if need be
    if not clients:
        clients = []
    elif not isinstance(clients, list):
        if isinstance(clients, tuple):
            clients = list(clients)
        else:
            clients = [clients]

    faces, counts, uvs = getAbcFaces(mesh)
    shapeArray = buildShapeArray(mesh, master, clients)

    # export the data to alembic
    arch = OArchive(str(path),
                    OGAWA)  # alembic does not like unicode filepaths
    try:
        _exportAbc(arch, master, shapeArray, faces, counts, uvs)
    finally:
        del arch
Example #16
0
def buildAbc(outPath,
             points,
             faces,
             faceCounts=None,
             uvs=None,
             uvFaces=None,
             normals=None,
             normFaces=None,
             name='polymsh',
             shapeSuffix='Shape',
             transformSuffix='',
             propDict=None):
    '''
	Build a single-mesh alembic file from all of the non-alembic raw data

	Parameters
	----------
	outPath: str or OArchive
		The output path for the alembic file
	points: list or ndarray
		The list or array of points. Single multiple frames supported
	faces: list
		A list of lists of face indices, or a flattened list of indices.
		If flat, then faceCounts must be provided
	faceCounts: list
		A list of the number of vertices per face. Defaults to None
	uvs: list or ndarray
		The Uvs for this mesh. Defaults to None
	uvFaces: list
		A list of lists of face indices, or a flattened list of indices.
		If flat, then faceCounts must be provided. Defaults to None
	normals: list or ndarray
		The Normals for this mesh. Defaults to None
	normFaces: list
		A list of lists of face indices, or a flattened list of indices.
		If flat, then faceCounts must be provided. Defaults to None
	name: str
		The name to give this mesh. Defaults to "polymsh"
	shapeSuffix: str
		The suffix to add to the shape of this mesh. Defaults to "Shape"
	transformSuffix: str
		The suffix to add to the transform of this mesh. Defaults to ""
	propDict: dict
		A dictionary of properties to add to the xform object
	'''
    if faceCounts is None:
        # All the faces are in list-of-list format
        # put them in index-count format
        faceCounts, faces = _flattenFaces(faces)
        if uvFaces is not None:
            _, uvFaces = _flattenFaces(uvFaces)
        if normFaces is not None:
            _, normFaces = _flattenFaces(normFaces)

    faceCounts = mkSampleIntArray(faceCounts)
    faces = mkSampleIntArray(faces)

    if uvFaces is not None and uvs is not None:
        uvs = mkUvSample(uvs, indexes=uvFaces)
    if normFaces is not None and normals is not None:
        normals = mkNormalSample(normals, indexes=normFaces)

    if isinstance(outPath, basestring):
        oarch = OArchive(str(outPath), False)  #False for HDF5
    else:
        oarch = outPath

    parent = oarch.getTop()
    opar = OXform(parent, name + transformSuffix)
    if propDict:
        props = opar.getSchema().getUserProperties()
        for k, v in propDict.iteritems():
            prop = OStringProperty(props, str(k))
            prop.setValue(str(v))
    omesh = OPolyMesh(opar, name + shapeSuffix)

    if np is not None:
        points = np.array(points)
        if len(points.shape) == 2:
            points = points[None, ...]
    else:
        if not isinstance(points[0][0], (list, tuple)):
            points = [points]

    sch = omesh.getSchema()
    for frame in points:
        abcFrame = mkSampleVertexPoints(frame)
        setAlembicSample(sch,
                         abcFrame,
                         faces,
                         faceCounts,
                         uvs=uvs,
                         normals=normals)
    return oarch
Example #17
0
def simplexUvTransfer(srcSmpxPath,
                      tarPath,
                      outPath,
                      srcUvPath=None,
                      tol=0.0001,
                      pBar=None):
    """ Transfer a simplex system onto a mesh through UV space

	Arguments:
		srcSmpxPath (str): The path to the source .smpx file
		tarPath (str): The path to the mesh to recieve the blendshapes
		outPath (str): The .smpx path that will be written
		srcUvPath (str): If the .smpx file doesn't have UV's, then the UV's
			from this mesh wil be used. Defaults to None
		tol (float): The tolerance for checking if a UV is outside of a poly
		pBar (QProgressDialog): Optional progress bar
	"""
    if pBar is not None:
        pBar.setLabelText("Loading Source Mesh")
        from Qt.QtWidgets import QApplication
        QApplication.processEvents()

    srcUvPath = srcUvPath or srcSmpxPath
    if srcUvPath.endswith('.abc') or srcUvPath.endswith('.smpx'):
        src = Mesh.loadAbc(srcUvPath, ensureWinding=False)
    elif srcUvPath.endswith('.obj'):
        src = Mesh.loadObj(srcUvPath, ensureWinding=False)
    srcVerts = abc.getSampleArray(abc.getMesh(srcSmpxPath))

    if pBar is not None:
        pBar.setLabelText("Loading Target Mesh")
        from Qt.QtWidgets import QApplication
        QApplication.processEvents()
    if tarPath.endswith('.abc'):
        tar = Mesh.loadAbc(tarPath, ensureWinding=False)
    elif tarPath.endswith('.obj'):
        tar = Mesh.loadObj(tarPath, ensureWinding=False)

    srcFaces = src.faceVertArray
    srcUvFaces = src.uvFaceMap['default']
    srcUvs = np.array(src.uvMap['default'])

    tarFaces = tar.faceVertArray
    tarUvFaces = tar.uvFaceMap['default']
    tarUvs = np.array(tar.uvMap['default'])
    oldTarVerts = np.array(tar.vertArray)

    corr = getVertCorrelation(srcUvFaces,
                              srcUvs,
                              tarFaces,
                              tarUvFaces,
                              tarUvs,
                              tol=tol,
                              pBar=pBar)
    tarVerts = applyTransfer(srcVerts, srcFaces, corr, len(oldTarVerts))

    # Apply as a delta
    deltas = tarVerts - tarVerts[0][None, ...]
    writeVerts = oldTarVerts[None, ...] + deltas

    jsString, name = _loadJSString(srcSmpxPath)
    oarch = OArchive(str(outPath), OGAWA)  # false for HDF5
    abc.buildAbc(oarch,
                 writeVerts,
                 tarFaces,
                 uvs=tarUvs,
                 uvFaces=tarUvFaces,
                 name=name,
                 shapeSuffix='',
                 propDict=dict(simplex=jsString))
Example #18
0
def buildAbc(outPath, points, faces, faceCounts=None,
	uvs=None, uvFaces=None, normals=None, normFaces=None,
	name='polymsh', shapeSuffix='Shape', transformSuffix='',
	propDict=None, ogawa=True, pBar=None):
	'''
	Build a single-mesh alembic file from all of the non-alembic raw data

	Parameters
	----------
	outPath: str
		The output path for the alembic file
	points: list or ndarray
		The list or array of points. Single multiple frames supported
	faces: list
		A list of lists of face indices, or a flattened list of indices.
		If flat, then faceCounts must be provided
	faceCounts: list
		A list of the number of vertices per face. Defaults to None
	uvs: list or ndarray
		The Uvs for this mesh. Defaults to None
	uvFaces: list
		A list of lists of face indices, or a flattened list of indices.
		If flat, then faceCounts must be provided. Defaults to None
	normals: list or ndarray
		The Normals for this mesh. Defaults to None
	normFaces: list
		A list of lists of face indices, or a flattened list of indices.
		If flat, then faceCounts must be provided. Defaults to None
	name: str
		The name to give this mesh. Defaults to "polymsh"
	shapeSuffix: str
		The suffix to add to the shape of this mesh. Defaults to "Shape"
	transformSuffix: str
		The suffix to add to the transform of this mesh. Defaults to ""
	propDict: dict
		A dictionary of properties to add to the xform object
	ogawa : bool
		Whether to write to the Ogawa (True) or HDF5 (False) backend
	pBar : QProgressDialog, optional
		An optional progress dialog
	'''
	if faceCounts is None:
		# All the faces are in list-of-list format
		# put them in index-count format
		faceCounts, faces = flattenFaces(faces)
		if uvFaces is not None:
			_, uvFaces = flattenFaces(uvFaces)
		if normFaces is not None:
			_, normFaces = flattenFaces(normFaces)

	faceCounts = mkSampleIntArray(faceCounts)
	faces = mkSampleIntArray(faces)

	if not isinstance(uvs, OV2fGeomParamSample):
		if uvFaces is not None and uvs is not None:
			uvs = mkUvSample(uvs, indexes=uvFaces)

	if not isinstance(normals, ON3fGeomParamSample):
		if normFaces is not None and normals is not None:
			normals = mkNormalSample(normals, indexes=normFaces)

	oarch = OArchive(str(outPath), ogawa)
	parent, opar, props, omesh, sch = None, None, None, None, None
	try:
		parent = oarch.getTop()
		opar = OXform(parent, str(name+transformSuffix))
		if propDict:
			props = opar.getSchema().getUserProperties()
			for k, v in propDict.iteritems():
				writeStringProperty(props, str(k), str(v), ogawa)

		omesh = OPolyMesh(opar, str(name+shapeSuffix))

		if np is not None:
			points = np.array(points)
			if len(points.shape) == 2:
				points = points[None, ...]
		else:
			if not isinstance(points[0][0], (list, tuple)):
				points = [points]

		sch = omesh.getSchema()
		for i, frame in enumerate(points):
			pbPrint(pBar, message="Exporting Shape", val=i, maxVal=len(points))
			abcFrame = mkSampleVertexPoints(frame)
			setAlembicSample(sch, abcFrame, faceCounts, faces, uvs=uvs, normals=normals)

		pbPrint(pBar, message="Done Exporting")
	finally:
		# Make sure all this gets deleted so the file is freed
		del parent, opar, props, omesh, sch