Beispiel #1
0
def mapImage(imgMesh, mesh, leftTop, rightBottom):
    if mh.hasRenderSkin():
        try:
            return mapImageGL(imgMesh.mesh.object3d.textureTex, mesh, leftTop, rightBottom)
        except Exception as e:
            log.debug(e)
            log.debug("Hardware skin rendering failed, falling back to software render.")
            return mapImageSoft(mh.Image(imgMesh.getTexture()), mesh, leftTop, rightBottom)
    else:
        return mapImageSoft(mh.Image(imgMesh.getTexture()), mesh, leftTop, rightBottom)
Beispiel #2
0
def mapImage(imgMesh, mesh, leftTop, rightBottom):
    if mh.hasRenderSkin():
        return mapImageGL(imgMesh.mesh.object3d.textureTex, mesh, leftTop,
                          rightBottom)
    else:
        return mapImageSoft(mh.Image(imgMesh.getTexture()), mesh, leftTop,
                            rightBottom)
Beispiel #3
0
    def projectBackground(self):
        if not self.backgroundChooserView.isBackgroundShowing():
            gui3d.app.prompt("Warning", "You need to load a background for the current view before you can project it.", "OK")
            return

        mesh = self.human.getSeedMesh()

        # for all quads, project vertex to screen
        # if one vertex falls in bg rect, project screen quad into uv quad
        # warp image region into texture
        ((x0,y0,z0), (x1,y1,z1)) = self.backgroundImage.mesh.calcBBox()
        camera = mh.cameras[self.backgroundImage.mesh.cameraMode]
        x0, y0, _ = camera.convertToScreen(x0, y0, z0, self.backgroundImage.mesh)
        x1, y1, _ = camera.convertToScreen(x1, y1, z1, self.backgroundImage.mesh)
        leftTop = (x0, y1)
        rightBottom = (x1, y0)

        dstImg = projection.mapImage(self.backgroundImage, mesh, leftTop, rightBottom)
        texPath = mh.getPath('data/skins/projection.png')
        if os.path.isfile(texPath):
            oldImg = mh.Image(texPath)
        else:
            oldImg = None

        gui3d.app.do(ProjectionAction("Change projected background texture",
                self.human.getTexture(),
                texPath,
                oldImg,
                dstImg))
        log.debug("Enabling shadeless rendering on body")
        self.shadelessButton.setChecked(True)
        self.human.setShadeless(1)
        mh.redraw()
def mapMaskSoft(dimensions = (1024, 1024), mesh = None):
    """
    Create a texture mask for the selected human (software renderer).
    """
    progress = Progress() (0)
    if mesh is None:
        mesh = G.app.selectedHuman.mesh

    W = dimensions[0]
    H = dimensions[1]

    components = 4
    dstImg = mh.Image(width=W, height=H, components=components)
    dstImg.data[...] = np.tile([0,0,0,255], (H,W)).reshape((H,W,components))

    faces = getFaces(mesh)

    coords = np.asarray([0,H])[None,None,:] + mesh.texco[mesh.fuvs[faces]] * np.asarray([W,-H])[None,None,:]
    shape = mesh.fvert[faces].shape
    shape = tuple(list(shape) + [components])
    colors = np.repeat(1, np.prod(shape)).reshape(shape)

    log.debug("mapMask: begin render")

    progress(0.1, 0.55)
    RasterizeTriangles(dstImg, coords[:,[0,1,2],:], MaskShader())
    progress(0.55, 0.99)
    RasterizeTriangles(dstImg, coords[:,[2,3,0],:], MaskShader())

    log.debug("mapMask: end render")

    progress.finish()
    return dstImg
def mapImageSoft(srcImg, mesh, leftTop, rightBottom):
    progress = Progress() (0)
    dstImg = mh.Image(G.app.selectedHuman.getTexture())

    dstW = dstImg.width
    dstH = dstImg.height

    srcImg = srcImg.convert(dstImg.components)

    camera = getCamera(mesh)
    faces = getFaces(mesh)

    # log.debug('matrix: %s', G.app.modelCamera.getConvertToScreenMatrix())

    progress(0.05)
    texco = np.asarray([0,dstH])[None,None,:] + mesh.texco[mesh.fuvs[faces]] * np.asarray([dstW,-dstH])[None,None,:]
    matrix_ = np.asarray(G.app.modelCamera.getConvertToScreenMatrix(mesh))
    coord = np.concatenate((mesh.coord[mesh.fvert[faces]], np.ones((len(faces),4,1))), axis=-1)
    # log.debug('texco: %s, coord: %s', texco.shape, coord.shape)
    coord = np.sum(matrix_[None,None,:,:] * coord[:,:,None,:], axis = -1)
    # log.debug('coord: %s', coord.shape)
    coord = coord[:,:,:2] / coord[:,:,3:]
    progress(0.1)
    # log.debug('coord: %s', coord.shape)
    # log.debug('coords: %f-%f, %f-%f',
    #           np.amin(coord[...,0]), np.amax(coord[...,0]),
    #           np.amin(coord[...,1]), np.amax(coord[...,1]))
    # log.debug('rect: %s %s', leftTop, rightBottom)
    coord -= np.asarray([leftTop[0], leftTop[1]])[None,None,:]
    coord /= np.asarray([rightBottom[0] - leftTop[0], rightBottom[1] - leftTop[1]])[None,None,:]
    alpha = np.sum(mesh.vnorm[mesh.fvert[faces]] * camera[None,None,:], axis=-1)
    alpha = np.maximum(0, alpha)
    # alpha[...] = 1 # debug
    # log.debug('alpha: %s', alpha.shape)
    # log.debug('coords: %f-%f, %f-%f',
    #           np.amin(coord[...,0]), np.amax(coord[...,0]),
    #           np.amin(coord[...,1]), np.amax(coord[...,1]))
    progress(0.15)
    uva = np.concatenate((coord, alpha[...,None]), axis=-1)
    # log.debug('uva: %s', uva.shape)
    valid = np.any(alpha >= 0, axis=1)
    # log.debug('valid: %s', valid.shape)
    texco = texco[valid,:,:]
    uva = uva[valid,:,:]

    # log.debug('%s %s', texco.shape, uva.shape)
    # log.debug('src: %s, dst: %s', srcImg.data.shape, dstImg.data.shape)

    log.debug("mapImage: begin render")

    progress(0.2, 0.6)
    RasterizeTriangles(dstImg, texco[:,[0,1,2],:], UvAlphaShader(dstImg, srcImg, uva[:,[0,1,2],:]))
    progress(0.6, 0.99)
    RasterizeTriangles(dstImg, texco[:,[2,3,0],:], UvAlphaShader(dstImg, srcImg, uva[:,[2,3,0],:]))
    progress.finish()

    log.debug("mapImage: end render")

    return dstImg
Beispiel #6
0
def mapUVSoft(mesh=None):
    """
    Project the UV map topology of the selected human mesh onto a texture 
    (software rasterizer).
    """
    progress = Progress()(0)

    if mesh is None:
        mesh = G.app.selectedHuman.mesh

    W = 2048
    H = 2048

    dstImg = mh.Image(width=W, height=H, components=3)
    dstImg.data[...] = 0

    faces = getFaces(mesh)

    log.debug("mapUV: begin setup")

    fuvs = mesh.fuvs[faces]
    del faces
    edges = np.array([fuvs, np.roll(fuvs, 1, axis=-1)]).transpose([1, 2,
                                                                   0]).reshape(
                                                                       (-1, 2))
    del fuvs
    edges = np.where((edges[:, 0] < edges[:, 1])[:, None], edges,
                     edges[:, ::-1])
    ec = edges[:, 0] + (edges[:, 1] << 16)
    del edges
    ec = np.unique(ec)
    edges = np.array([ec & 0xFFFF, ec >> 16]).transpose()
    del ec
    edges = mesh.texco[edges] * (W, H)
    progress(0.05)

    delta = edges[:, 1, :] - edges[:, 0, :]
    vertical = np.abs(delta[:, 1]) > np.abs(delta[:, 0])
    horizontal = -vertical

    hdelta = delta[horizontal]
    vdelta = delta[vertical]
    del delta
    hedges = edges[horizontal]
    vedges = edges[vertical]
    del edges, horizontal, vertical

    log.debug("mapUV: begin render")

    progress(0.1, 0.55, "Projecting UV map")
    rasterizeHLines(dstImg, hedges, hdelta)
    progress(0.55, 0.99, "Projecting UV map")
    rasterizeVLines(dstImg, vedges, vdelta)
    progress(1)

    log.debug("mapUV: end render")

    return dstImg.convert(3)
Beispiel #7
0
def mapLightingSoft(progressCallback=None):
    """
    Create a lightmap for the selected human.
    """

    mesh = gui3d.app.selectedHuman.mesh

    W = 1024
    H = 1024

    dstImg = mh.Image(width=W, height=H, components=4)
    dstImg._data[...] = 0

    delta = (-10.99, 20.0, 20.0) - mesh.coord
    ld = vnorm(delta)
    del delta
    s = np.sum(ld * mesh.vnorm, axis=-1)
    del ld
    s = np.maximum(0, np.minimum(255, (s * 256))).astype(np.uint8)
    mesh.color[..., :3] = s[..., None]
    mesh.color[..., 3] = 255
    del s

    faces = getFaces(mesh)

    coords = np.asarray(
        [0, H])[None, None, :] + mesh.texco[mesh.fuvs[faces]] * np.asarray(
            [W, -H])[None, None, :]
    colors = mesh.color[mesh.fvert[faces]]
    # log.debug("mapLighting: %s %s %s", faces.shape, coords.shape, colors.shape)

    log.debug("mapLighting: begin render")

    def progress(base, i, n):
        if progressCallback == None:
            gui3d.app.progress(base + 0.5 * i / n, "Projecting lightmap")
        else:
            progressCallback(base + 0.5 * i / n)

    RasterizeTriangles(dstImg,
                       coords[:, [0, 1, 2], :],
                       ColorShader(colors[:, [0, 1, 2], :]),
                       progress=lambda i, n: progress(0.0, i, n))
    RasterizeTriangles(dstImg,
                       coords[:, [2, 3, 0], :],
                       ColorShader(colors[:, [2, 3, 0], :]),
                       progress=lambda i, n: progress(0.5, i, n))
    gui3d.app.progress(1.0)

    fixSeams(dstImg)

    log.debug("mapLighting: end render")

    mesh.setColor([255, 255, 255, 255])

    return dstImg
def combine(image, mhstx):
    f = open(mhstx, 'rU')
    try:
        subTextures = mh.parseINI(f.read(), [("(", "["), (")", "]")])
    except:
        log.warning("subtextures.combine(%s)", mhstx, exc_info=True)
        f.close()
        return mh.Image()
    f.close()

    texdir = os.path.dirname(mhstx)
    img = mh.Image(data=image.data)
    for subTexture in subTextures:
        path = os.path.join(texdir, subTexture['txt'])
        subImg = mh.Image(path)
        x, y = subTexture['dst']
        img.blit(subImg, x, y)

    return img
Beispiel #9
0
def mapLightingSoft(
        lightpos=(-10.99, 20.0, 20.0), mesh=None, res=(1024, 1024), border=1):
    """
    Create a lightmap for the selected human (software renderer).
    """
    progress = Progress()(0)

    if mesh is None:
        mesh = G.app.selectedHuman.mesh

    W = res[0]
    H = res[1]

    dstImg = mh.Image(width=W, height=H, components=4)
    dstImg.data[...] = 0

    delta = lightpos - mesh.coord
    ld = vnormalize(delta)
    del delta
    s = np.sum(ld * mesh.vnorm, axis=-1)
    del ld
    s = np.maximum(0, np.minimum(255, (s * 256))).astype(np.uint8)
    mesh.color[..., :3] = s[..., None]
    mesh.color[..., 3] = 255
    del s

    faces = getFaces(mesh)

    coords = np.asarray(
        [0, H])[None, None, :] + mesh.texco[mesh.fuvs[faces]] * np.asarray(
            [W, -H])[None, None, :]
    colors = mesh.color[mesh.fvert[faces]]
    # log.debug("mapLighting: %s %s %s", faces.shape, coords.shape, colors.shape)

    log.debug("mapLighting: begin render")

    progress(0.1, 0.5)
    RasterizeTriangles(dstImg, coords[:, [0, 1, 2], :],
                       ColorShader(colors[:, [0, 1, 2], :]))
    progress(0.5, 0.9)
    RasterizeTriangles(dstImg, coords[:, [2, 3, 0], :],
                       ColorShader(colors[:, [2, 3, 0], :]))

    progress(0.9, 0.99)
    dstImg = fixSeams(dstImg, mesh, border)

    log.debug("mapLighting: end render")

    mesh.setColor([255, 255, 255, 255])

    progress.finish()
    return dstImg
Beispiel #10
0
    def setEyes(self, human, mhstx):
        # TODO this will change, for now eyes might only be compatible with the original skin
        f = open(mhstx, 'rU')
        try:
            subTextures = mh.parseINI(f.read(), [("(", "["), (")", "]")])
        except:
            log.warning("setEyes(%s)", mhstx, exc_info=True)
            f.close()
            return
        f.close()

        texture = mh.getTexture(human.getTexture())
        img = mh.Image(human.getTexture())

        for subTexture in subTextures:
            path = os.path.join('data/eyes', subTexture['txt'])
            subImg = mh.Image(path)
            x, y = subTexture['dst']
            img.blit(subImg, x, y)

        texture.loadSubImage(img, 0, 0)
        self.eyeTexture = mhstx
Beispiel #11
0
    def projectUV(self):
        dstImg = projection.mapUV()
        #dstImg.resize(128, 128)
        texPath = mh.getPath('data/skins/uvtopo.png')
        if os.path.isfile(texPath):
            oldImg = mh.Image(texPath)
        else:
            oldImg = None

        gui3d.app.do(
            ProjectionAction("Change projected UV map texture",
                             self.human.getTexture(), texPath, oldImg, dstImg))
        log.debug("Enabling shadeless rendering on body")
        self.shadelessButton.setChecked(True)
        self.human.setShadeless(1)
        mh.redraw()
    def projectLighting(self):
        dstImg = projection.mapLighting()
        #dstImg.resize(128, 128)
        texPath = os.path.join(mh.getPath(''), 'data', 'skins', 'lighting.png')
        if os.path.isfile(texPath):
            oldImg = mh.Image(texPath)
        else:
            oldImg = None

        gui3d.app.do(
            ProjectionAction("Change projected lighting texture",
                             gui3d.app.selectedHuman.getTexture(), texPath,
                             oldImg, dstImg))
        log.debug("Enabling shadeless rendering on body")
        self.shadelessButton.setChecked(True)
        gui3d.app.selectedHuman.mesh.setShadeless(1)
Beispiel #13
0
    def getTexturePath(self, filePath, fromDir, isTexture, human):
        srcDir = os.path.realpath(os.path.expanduser(fromDir))
        filename = os.path.basename(filePath)

        if human and (filename == "texture.png"):
            fromPath = human.getTexture()
            fileDir = os.path.dirname(fromPath)
            filename = os.path.basename(fromPath)
            #print(filePath, fromDir, fileDir, fromPath)
            if fileDir == fromDir:
                fromPath = os.path.join(srcDir, filename)
        else:
            fromPath = os.path.join(srcDir, filename)

        if self.useTexFolder:
            if isTexture:
                toPath = os.path.join(self.texFolder, filename)
            else:
                toPath = os.path.join(self.outFolder, filename)
            try:
                self.copiedFiles[fromPath]
                done = True
            except:
                done = False
            if not done:
                if 0 and human:
                    img = mh.Image(human.getTexture())
                    log.debug("%s", dir(img))
                    img.save(toPath)
                    halt
                try:
                    shutil.copyfile(fromPath, toPath)
                except:
                    pass
                self.copiedFiles[fromPath] = True
            texPath = toPath
        else:
            texPath = os.path.abspath(fromPath)

        if not self.useRelPaths:
            return texPath
        else:
            return str(
                os.path.normpath(os.path.relpath(texPath, self.outFolder)))
Beispiel #14
0
    def changeBackgroundImage(self, side, texturePath):
        if not side:
            return

        if texturePath:
            # Determine aspect ratio of texture
            self.texture.loadImage(mh.Image(texturePath))
            aspect = 1.0 * self.texture.width / self.texture.height

            self.filenames[side] = (texturePath, aspect)
        else:
            self.filenames[side] = None

        #self.transformations[side] = [(0.0, 0.0), 1.0]

        if side == self.getCurrentSide():
            # Reload current texture
            self.setBackgroundImage(side)

        self.setBackgroundEnabled(self.isBackgroundSet())
Beispiel #15
0
def writeTextures(stuffs, outDir, progressCallback=None):
    def progress(prog):
        if progressCallback == None:
            gui3d.app.progress(prog)
        else:
            progressCallback(prog)

    progress(0)

    i = 0.0
    stuffnum = float(len(stuffs))
    for stuff in stuffs:
        if stuff.textureImage:
            teximg = stuff.textureImage
        elif stuff.texture:
            teximg = mh.Image(path=collect.getpath(stuff.texture))
        # Export diffuse texture, with subtextures.
        teximg.save(os.path.join(outDir, "%s_texture.png" % stuff.name))
        progress((i + 0.4) / stuffnum)
        # Export transparency map.
        imgop.getAlpha(teximg).save(
            path=os.path.join(outDir, "%s_alpha.png" % stuff.name))
        progress((i + 0.8) / stuffnum)
        # Export bump map.
        if stuff.bump:
            collect.copy(
                stuff.bump,
                os.path.join(
                    outDir, "%s_bump.%s" % (stuff.name,
                                            (stuff.bump[1].split("."))[1])))
        elif stuff.displacement:
            collect.copy(
                stuff.displacement,
                os.path.join(
                    outDir,
                    "%s_bump.%s" % (stuff.name,
                                    (stuff.displacement[1].split("."))[1])))
        i += 1.0
        progress(i / stuffnum)
Beispiel #16
0
def getOutFileName(filePath, fromDir, isTexture, human, config):
    srcDir = os.path.realpath(os.path.expanduser(fromDir))
    filename = os.path.basename(filePath)
    if human and (filename == "texture.png"):
        fromPath = human.getTexture()
        fileDir = os.path.dirname(fromPath)
        filename = os.path.basename(fromPath)
        #print(filePath, fromDir, fileDir, fromPath)
        if fileDir == fromDir:
            fromPath = os.path.join(srcDir, filename)
    else:
        fromPath = os.path.join(srcDir, filename)
    if config.separatefolder:
        if isTexture:
            toPath = os.path.join(config.texFolder, filename)
        else:
            toPath = os.path.join(config.outFolder, filename)
        try:
            config.copiedFiles[fromPath]
            done = True
        except:
            done = False
        if not done:
            if 0 and human:
                img = mh.Image(human.getTexture())
                log.debug("%s", dir(img))
                img.save(toPath)
                halt
            try:
                shutil.copyfile(fromPath, toPath)
            except:
                pass
            config.copiedFiles[fromPath] = True
        return toPath
    else:
        return fromPath
def mapSceneLighting(scn, progressCallback=None):
    """
    Create a lightmap for a scene with one or multiple lights.
    """
    def progress(prog):
        if (progressCallback is not None):
            progressCallback(prog)
        else:
            pass

    lnum = float(len(scn.lights))
    if (lnum > 0):  # Add up all the lightmaps.
        lmap = mapLighting(scn.lights[0].position,
                           lambda p: progress(p / lnum))
        i = 1.0
        for light in scn.lights[1:]:
            lmap = image_operations.mix(
                lmap,
                mapLighting(light.position, lambda p: progress(
                    (i + p) / lnum)), 1, 1)
            i += 1.0
        return image_operations.clipped(lmap)
    else:  # If the scene has no lights, return an empty lightmap.
        return mh.Image(data=np.zeros((1024, 1024, 1), dtype=np.uint8))
Beispiel #18
0

def mapImage(imgMesh, mesh, leftTop, rightBottom):
    if mh.hasRenderSkin():
        try:
            return mapImageGL(imgMesh.mesh.object3d.textureTex, mesh, leftTop,
                              rightBottom)
        except Exception, e:
            log.debug(e)
            log.debug(
                "Hardware skin rendering failed, falling back to software render."
            )
            return mapImageSoft(mh.Image(imgMesh.getTexture()), mesh, leftTop,
                                rightBottom)
    else:
        return mapImageSoft(mh.Image(imgMesh.getTexture()), mesh, leftTop,
                            rightBottom)


'''fixSeams

A function for removing UV seams from projected images.

When creating images through projection, interference with the
limits of the UV map tend to produce dark seams on the mesh
along the lines that define the limits. Using this procedure,
one can repair these seams by UV mask aided post-processing.

Pass the image to be fixed in the 'img' parameter, and the mesh
from which the UV mask will be projected in the 'mesh' parameter.
If you already have a mask projected, you can pass it in place
Beispiel #19
0
 def setEyes(self, human, mhstx):
     # TODO this will change, for now eyes might only be compatible with the original skin
     texture = mh.getTexture(human.getTexture())
     texture.loadSubImage(
         subtextures.combine(mh.Image(human.getTexture()),mhstx), 0, 0)
     self.eyeTexture = mhstx
Beispiel #20
0
def mapUVSoft():
    """
    Project the UV map topology of the selected human mesh onto a texture.
    """

    mesh = gui3d.app.selectedHuman.mesh

    W = 2048
    H = 2048

    dstImg = mh.Image(width=W, height=H, components=3)
    dstImg._data[...] = 0

    faces = getFaces(mesh)

    log.debug("mapUV: begin setup")

    fuvs = mesh.fuvs[faces]
    del faces
    edges = np.array([fuvs, np.roll(fuvs, 1, axis=-1)]).transpose([1, 2,
                                                                   0]).reshape(
                                                                       (-1, 2))
    del fuvs
    edges = np.where((edges[:, 0] < edges[:, 1])[:, None], edges,
                     edges[:, ::-1])
    ec = edges[:, 0] + (edges[:, 1] << 16)
    del edges
    ec = np.unique(ec)
    edges = np.array([ec & 0xFFFF, ec >> 16]).transpose()
    del ec
    edges = mesh.texco[edges] * (W, H)

    delta = edges[:, 1, :] - edges[:, 0, :]
    vertical = np.abs(delta[:, 1]) > np.abs(delta[:, 0])
    horizontal = -vertical

    hdelta = delta[horizontal]
    vdelta = delta[vertical]
    del delta
    hedges = edges[horizontal]
    vedges = edges[vertical]
    del edges, horizontal, vertical

    log.debug("mapUV: begin render")

    def progress(base, i, n):
        gui3d.app.progress(base + 0.5 * i / n, "Projecting UV map")

    rasterizeHLines(dstImg,
                    hedges,
                    hdelta,
                    progress=lambda i, n: progress(0.0, i, n))
    rasterizeVLines(dstImg,
                    vedges,
                    vdelta,
                    progress=lambda i, n: progress(0.5, i, n))
    gui3d.app.progress(1.0)

    log.debug("mapUV: end render")

    return dstImg.convert(3)
Beispiel #21
0
def setupObjects(name, human, config=None, rigfile=None, rawTargets=[], helpers=False, hidden=False, eyebrows=True, lashes=True, subdivide = False, progressCallback=None):
    global theStuff, theTextures, theTexFiles, theMaterials

    def progress(prog):
        if progressCallback == None:
            pass
        else:
            progressCallback (prog)

    if not config:
        config = Config()
        config.setHuman(human)
        
    obj = human.meshData
    theTextures = {}
    theTexFiles = {}
    theMaterials = {}
    
    stuffs = []
    stuff = CStuff(name, obj = human)

    if rigfile:
        stuff.boneInfo = getArmatureFromRigFile(rigfile, obj, config.scale)
        log.message("Using rig file %s" % rigfile)
            
    meshInfo = mh2proxy.getMeshInfo(obj, None, config, None, rawTargets, None)
    if stuff.boneInfo:
        meshInfo.weights = stuff.boneInfo.weights

    theStuff = stuff
    deleteGroups = []
    deleteVerts = None  # Don't load deleteVerts from proxies directly, we use the facemask set in the gui module3d
    _,deleteVerts = setupProxies('Clothes', None, obj, stuffs, meshInfo, config, deleteGroups, deleteVerts)
    _,deleteVerts = setupProxies('Hair', None, obj, stuffs, meshInfo, config, deleteGroups, deleteVerts)
    foundProxy,deleteVerts = setupProxies('Proxy', name, obj, stuffs, meshInfo, config, deleteGroups, deleteVerts)
    progress(0.06*(3-2*subdivide))
    if not foundProxy:
        if helpers:     # helpers override everything
            if config.scale == 1.0:
                stuff.meshInfo = meshInfo
            else:
                stuff.meshInfo = meshInfo.fromProxy(config.scale*obj.coord, obj.texco, obj.fvert, obj.fuvs, meshInfo.weights, meshInfo.shapes)
        else:
            stuff.meshInfo = filterMesh(meshInfo, config.scale, deleteGroups, deleteVerts, eyebrows, lashes, not hidden)
        stuffs = [stuff] + stuffs
    progbase = 0.12*(3-2*subdivide)
    progress(progbase)

    # Apply textures, and subdivide, if requested.
    stuffnum = float(len(stuffs))
    i = 0.0
    for stuff in stuffs:
        progress(progbase+(i/stuffnum)*(1-progbase))
        texture = stuff.object.mesh.texture
        stuff.texture = (os.path.dirname(texture), os.path.basename(texture))
        if subdivide:
            subMesh = cks.createSubdivisionObject(
                stuff.meshInfo.object, lambda p: progress(progbase+((i+p)/stuffnum)*(1-progbase)))
            stuff.meshInfo.fromObject(subMesh, stuff.meshInfo.weights, rawTargets)
        i += 1.0

    # Apply subtextures.
    stuffs[0].textureImage = mh.Image(os.path.join(stuffs[0].texture[0], stuffs[0].texture[1]))
    mhstx = mh.G.app.getCategory('Textures').getTaskByName('Texture').eyeTexture
    if mhstx:
        stuffs[0].textureImage = subtextures.combine(stuffs[0].textureImage, mhstx)
    
    progress(1)
    return stuffs