def exportOgreMesh(human, filepath, config, progressCallback=None): progress = Progress.begin(logging=True, timing=True) progress(0, 0.05, "Setting properties") config.setHuman(human) feetOnGround = config.feetOnGround config.feetOnGround = False # TODO account for config.scale in skeleton config.setupTexFolder(filepath) filename = os.path.basename(filepath) name = formatName(config.goodName(os.path.splitext(filename)[0])) progress(0.05, 0.2, "Collecting Objects") rmeshes = exportutils.collect.setupMeshes(name, human, config=config, subdivide=config.subdivide) config.feetOnGround = feetOnGround progress(0.2, 0.95 - 0.35 * bool(human.getSkeleton())) writeMeshFile(human, filepath, rmeshes, config) if human.getSkeleton(): progress(0.6, 0.95, "Writing Skeleton") writeSkeletonFile(human, filepath, config) progress(0.95, 0.99, "Writing Materials") writeMaterialFile(human, filepath, rmeshes, config) progress(1.0, None, "Ogre export finished.")
def export(self, human, filename): from . import mh2md5 cfg = MD5Config(self) cfg.selectedOptions(self) progress = Progress.begin() (0, 1) mh2md5.exportMd5(human, filename("md5mesh"), cfg)
def exportOgreMesh(filepath, config): progress = Progress.begin() progress(0, 0.05, "Setting properties") # TODO this leads to a disastrous amount of confusion among translators human = config.human feetOnGround = config.feetOnGround # TODO this is probably not even worth an option, always feet on ground should be a good default config.feetOnGround = False # TODO account for config.scale in skeleton config.setupTexFolder(filepath) # TODO unused filename = os.path.basename(filepath) name = formatName(os.path.splitext(filename)[0]) progress(0.05, 0.2, "Collecting Objects") meshes = human.getMeshes() config.feetOnGround = feetOnGround progress(0.2, 0.95 - 0.35*bool(human.getSkeleton())) writeMeshFile(human, filepath, meshes, config) if human.getSkeleton(): progress(0.6, 0.95, "Writing Skeleton") writeSkeletonFile(human, filepath, config) progress(0.95, 0.99, "Writing Materials") writeMaterialFile(human, filepath, meshes, config) progress(1.0, None, "Ogre export finished.")
def export(self, human, filename): reload(mh2md5) cfg = self.getConfig() cfg.setHuman(human) progress = Progress.begin()(0, 1) mh2md5.exportMd5(filename("md5mesh"), cfg)
def export(self, human, filename): reload(mh2md5) cfg = self.getConfig() cfg.setHuman(human) progress = Progress.begin() (0, 1) mh2md5.exportMd5(filename("md5mesh"), cfg)
def export(self, human, filename): from progress import Progress from . import mh2obj progress = Progress.begin() (0, 1) cfg = self.getConfig() cfg.setHuman(human) mh2obj.exportObj(filename("obj"), cfg)
def export(self, human, filename): from . import mh2stl from progress import Progress progress = Progress.begin()(0, 1) if self.stlAscii.selected: mh2stl.exportStlAscii(human, filename("stl"), STLConfig(self)) else: mh2stl.exportStlBinary(human, filename("stl"), STLConfig(self))
def export(self, human, filename): from . import mh2stl from progress import Progress progress = Progress.begin() (0, 1) cfg = self.getConfig() cfg.setHuman(human) if self.stlAscii.selected: mh2stl.exportStlAscii(filename("stl"), cfg) else: mh2stl.exportStlBinary(filename("stl"), cfg)
def export(self, human, filename): from . import mh2stl from progress import Progress progress = Progress.begin()(0, 1) cfg = self.getConfig() cfg.setHuman(human) if self.stlAscii.selected: mh2stl.exportStlAscii(filename("stl"), cfg) else: mh2stl.exportStlBinary(filename("stl"), cfg)
def export(self, human, filename): from . import mh2stl from progress import Progress progress = Progress.begin() (0, 1) cfg = self.getConfig() cfg.setHuman(human) if self.stlAscii.selected: try: mh2stl.exportStlAscii(filename("stl"), cfg) except MemoryError: log.error("Not enough memory to export the mesh. Try exporting a binary STL or disable mesh smoothing.") else: mh2stl.exportStlBinary(filename("stl"), cfg)
def export(self, human, filename): from . import mh2stl from progress import Progress progress = Progress.begin() (0, 1) cfg = self.getConfig() cfg.setHuman(human) if not self.stlBinary.selected: try: mh2stl.exportStlAscii(filename("stl"), cfg) except MemoryError: log.error("Not enough memory to export the mesh. Try exporting a binary STL or disable mesh smoothing.") else: mh2stl.exportStlBinary(filename("stl"), cfg)
def exportOgreMesh(filepath, config): progress = Progress.begin() progress(0, 0.05, "Preparing export") human = config.human # TODO account for config.scale in skeleton config.setupTexFolder(filepath) # TODO unused progress(0.05, 0.2, "Collecting Objects") objects = human.getObjects(excludeZeroFaceObjs=True) progress(0.2, 0.95 - 0.35 * bool(human.getSkeleton())) writeMeshFile(human, filepath, objects, config) if human.getSkeleton(): progress(0.6, 0.95, "Writing Skeleton") writeSkeletonFile(human, filepath, config) progress(0.95, 0.99, "Writing Materials") writeMaterialFile(human, filepath, objects, config) progress(1.0, None, "Ogre export finished.")
def exportOgreMesh(filepath, config): progress = Progress.begin() progress(0, 0.05, "Preparing export") human = config.human # TODO account for config.scale in skeleton config.setupTexFolder(filepath) # TODO unused progress(0.05, 0.2, "Collecting Objects") objects = human.getObjects(excludeZeroFaceObjs=True) progress(0.2, 0.95 - 0.35*bool(human.getSkeleton())) writeMeshFile(human, filepath, objects, config) if human.getSkeleton(): progress(0.6, 0.95, "Writing Skeleton") writeSkeletonFile(human, filepath, config) progress(0.95, 0.99, "Writing Materials") writeMaterialFile(human, filepath, objects, config) progress(1.0, None, "Ogre export finished.")
def exportOgreMesh(filepath, config): progress = Progress.begin() progress(0, 0.05, "Setting properties") # TODO this leads to a disastrous amount of confusion among translators human = config.human # TODO account for config.scale in skeleton config.setupTexFolder(filepath) # TODO unused progress(0.05, 0.2, "Collecting Objects") objects = human.getObjects(excludeZeroFaceObjs=True) progress(0.2, 0.95 - 0.35*bool(human.getSkeleton())) writeMeshFile(human, filepath, objects, config) if human.getSkeleton(): progress(0.6, 0.95, "Writing Skeleton") writeSkeletonFile(human, filepath, config) progress(0.95, 0.99, "Writing Materials") writeMaterialFile(human, filepath, objects, config) progress(1.0, None, "Ogre export finished.")
def exportOgreMesh(filepath, config): progress = Progress.begin() progress( 0, 0.05, "Setting properties" ) # TODO this leads to a disastrous amount of confusion among translators human = config.human # TODO account for config.scale in skeleton config.setupTexFolder(filepath) # TODO unused progress(0.05, 0.2, "Collecting Objects") objects = human.getObjects(excludeZeroFaceObjs=True) progress(0.2, 0.95 - 0.35 * bool(human.getSkeleton())) writeMeshFile(human, filepath, objects, config) if human.getSkeleton(): progress(0.6, 0.95, "Writing Skeleton") writeSkeletonFile(human, filepath, config) progress(0.95, 0.99, "Writing Materials") writeMaterialFile(human, filepath, objects, config) progress(1.0, None, "Ogre export finished.")
def export(self, human, filename): from progress import Progress from . import mh2obj progress = Progress.begin()(0, 1) mh2obj.exportObj(human, filename("obj"), ObjConfig(self))
def exportMd5(filepath, config): """ This function exports MakeHuman mesh and skeleton data to id Software's MD5 format. Parameters ---------- human: *Human*. The object whose information is to be used for the export. filepath: *string*. The filepath of the file to export the object to. config: *Config*. Export configuration. """ progress = Progress.begin(logging=True, timing=True) human = config.human obj = human.meshData config.zUp = True config.feetOnGround = True # TODO this only works when exporting MHX mesh (a design error in exportutils) config.scale = 1 config.setupTexFolder(filepath) filename = os.path.basename(filepath) name = config.goodName(os.path.splitext(filename)[0]) humanBBox = human.meshData.calcBBox() progress(0, 0.2, "Collecting Objects") rmeshes = exportutils.collect.setupMeshes( name, human, config=config, subdivide=config.subdivide) if human.getSkeleton(): numJoints = human.getSkeleton().getBoneCount() +1 # Amount of joints + the hardcoded origin below else: numJoints = 1 f = codecs.open(filepath, 'w', encoding="utf-8") f.write('MD5Version 10\n') f.write('commandline ""\n\n') f.write('numJoints %d\n' % numJoints) f.write('numMeshes %d\n\n' % (len(rmeshes))) f.write('joints {\n') # Hardcoded root joint f.write('\t"%s" %d ( %f %f %f ) ( %f %f %f )\n' % ('origin', -1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)) progress(0.2, 0.3, "Writing Bones") if human.getSkeleton(): bones = human.getSkeleton().getBones() boneprog = Progress(len(bones)) for bone in bones: writeBone(f, bone, human, config) boneprog.step() f.write('}\n\n') progress(0.3, 0.8, "Writing Objects") loopprog = Progress(len(rmeshes)) for rmeshIdx, rmesh in enumerate(rmeshes): # rmesh.type: None is human, "Proxymeshes" is human proxy, "Clothes" for clothing and "Hair" for hair objprog = Progress() objprog(0.0, 0.1, "Writing %s mesh." % rmesh.name) obj = rmesh.object obj.calcFaceNormals() obj.calcVertexNormals() obj.updateIndexBuffer() numVerts = len(obj.r_coord) if obj.vertsPerPrimitive == 4: # Quads numFaces = len(obj.r_faces) * 2 else: # Tris numFaces = len(obj.r_faces) f.write('mesh {\n') mat = rmesh.material if mat.diffuseTexture: tex = copyTexture(mat.diffuseTexture, human, config) f.write('\tshader "%s"\n' % tex) f.write('\n\tnumverts %d\n' % numVerts) # Collect vertex weights if human.getSkeleton(): objprog(0.1, 0.2, "Writing skeleton") bodyWeights = human.getVertexWeights() if rmesh.type: # Determine vertex weights for proxy weights = skeleton.getProxyWeights(rmesh.proxy, bodyWeights, obj) else: # Use vertex weights for human body weights = bodyWeights # Account for vertices that are filtered out if rmesh.vertexMapping != None: filteredVIdxMap = rmesh.vertexMapping weights2 = {} for (boneName, (verts,ws)) in weights.items(): verts2 = [] ws2 = [] for i, vIdx in enumerate(verts): if vIdx in filteredVIdxMap: verts2.append(filteredVIdxMap[vIdx]) ws2.append(ws[i]) weights2[boneName] = (verts2, ws2) weights = weights2 # Remap vertex weights to the unwelded vertices of the object (obj.coord to obj.r_coord) originalToUnweldedMap = obj.inverse_vmap # Build a weights list indexed per vertex jointIndexes = {} jointIndexes['origin'] = 0 joints = [None] + human.getSkeleton().getBones() # origin joint is None for idx,bone in enumerate(joints): if bone: jointIndexes[bone.name] = idx vertWeights = {} # = dict( vertIdx: [ (jointIdx1, weight1), ...]) for (jointName, (verts,ws)) in weights.items(): jointIdx = jointIndexes[jointName] for idx,v in enumerate(verts): try: for r_vIdx in originalToUnweldedMap[v]: if r_vIdx not in vertWeights: vertWeights[r_vIdx] = [] vertWeights[r_vIdx].append((jointIdx, ws[idx])) except: # unused coord pass for vert in xrange(numVerts): if vert not in vertWeights: # Weight vertex completely to origin joint vertWeights[vert] = [(0, 1.0)] else: vertWeights = None objprog(0.3, 0.7, "Writing vertices for %s." % rmesh.name) # Write vertices wCount = 0 for vert in xrange(numVerts): if obj.has_uv: u, v = obj.r_texco[vert] else: u, v = 0, 0 if vertWeights == None: numWeights = 1 else: numWeights = len(vertWeights[vert]) # vert [vertIndex] ( [texU] [texV] ) [weightIndex] [weightElem] f.write('\tvert %d ( %f %f ) %d %d\n' % (vert, u, 1.0-v, wCount, numWeights)) wCount = wCount + numWeights objprog(0.7, 0.8, "Writing faces for %s." % rmesh.name) # Write faces f.write('\n\tnumtris %d\n' % numFaces) fn = 0 for fv in obj.r_faces: # tri [triIndex] [vertIndex1] [vertIndex2] [vertIndex3] f.write('\ttri %d %d %d %d\n' % (fn, fv[2], fv[1], fv[0])) fn += 1 if fv[0] != fv[3]: f.write('\ttri %d %d %d %d\n' % (fn, fv[0], fv[3], fv[2])) fn += 1 objprog(0.8, 0.99, "Writing bone weights for %s." % rmesh.name) # Write bone weighting bwprog = Progress(len(obj.r_coord)).HighFrequency(200) if human.getSkeleton(): f.write('\n\tnumweights %d\n' % wCount) wCount = 0 for idx,co in enumerate(obj.r_coord): for (jointIdx, jointWght) in vertWeights[idx]: # Get vertex position in bone space if joints[jointIdx]: invbonematrix = joints[jointIdx].matRestGlobal.copy() invbonematrix[:3,3] = [0,0,0] invbonematrix = la.inv(invbonematrix) relPos = np.ones(4, dtype=np.float32) relPos[:3] = co[:3] relPos[:3] -= joints[jointIdx].getRestHeadPos() relPos[:3] *= scale #relPos = np.dot(relPos, invbonematrix) else: relPos = co[:3] * scale if config.zUp: relPos[:3] = relPos[[0,2,1]] * [1,-1,1] # weight [weightIndex] [jointIndex] [weightValue] ( [xPos] [yPos] [zPos] ) f.write('\tweight %d %d %f ( %f %f %f )\n' % (wCount, jointIdx, jointWght, relPos[0], relPos[1], relPos[2])) wCount = wCount +1 bwprog.step() else: # No skeleton selected: Attach all vertices to the root with weight 1.0 f.write('\n\tnumweights %d\n' % (numVerts)) for idx,co in enumerate(obj.r_coord): # weight [weightIndex] [jointIndex] [weightValue] ( [xPos] [yPos] [zPos] ) co = co.copy() * scale if config.feetOnGround: co[1] += (getFeetOnGroundOffset(human) * scale) if config.zUp: co = co[[0,2,1]] * [1,-1,1] f.write('\tweight %d %d %f ( %f %f %f )\n' % (idx, 0, 1.0, co[0], co[1], co[2])) # Note: MD5 has a z-up coordinate system bwprog.step() f.write('}\n\n') loopprog.step() f.close() progress(0.8, 0.99, "Writing Animations") if human.getSkeleton() and hasattr(human, 'animations'): animprog = Progress(len(human.animations)) for anim in human.animations: writeAnimation(filepath, human, humanBBox, config, anim.getAnimationTrack()) animprog.step() progress(1, None, "MD5 export finished. Exported file: %s", filepath)
def exportMd5(filepath, config): """ This function exports MakeHuman mesh and skeleton data to id Software's MD5 format. Parameters ---------- human: *Human*. The object whose information is to be used for the export. filepath: *string*. The filepath of the file to export the object to. config: *Config*. Export configuration. """ progress = Progress.begin(logging=True, timing=True) human = config.human config.setupTexFolder(filepath) filename = os.path.basename(filepath) name = config.goodName(os.path.splitext(filename)[0]) # TODO this should probably be the only option config.zUp = True config.feetOnGround = True config.scale = 5 # Override scale setting to a sensible default for doom-style engines humanBBox = human.meshData.calcBBox() objects = human.getObjects(excludeZeroFaceObjs=True) meshes = [obj.mesh.clone(config.scale, True) for obj in objects] # TODO set good names for meshes if human.getSkeleton(): numJoints = human.getSkeleton().getBoneCount() +1 # Amount of joints + the hardcoded origin below else: numJoints = 1 f = codecs.open(filepath, 'w', encoding="utf-8") f.write('MD5Version 10\n') f.write('commandline ""\n\n') f.write('numJoints %d\n' % numJoints) f.write('numMeshes %d\n\n' % (len(meshes))) f.write('joints {\n') # Hardcoded root joint f.write('\t"%s" %d ( %f %f %f ) ( %f %f %f )\n' % ('origin', -1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)) progress(0.2, 0.3, "Writing Bones") if human.getSkeleton(): bones = human.getSkeleton().getBones() boneprog = Progress(len(bones)) for bone in bones: writeBone(f, bone, human, config) boneprog.step() f.write('}\n\n') progress(0.3, 0.8, "Writing Objects") loopprog = Progress(len(meshes)) for meshIdx, mesh in enumerate(meshes): objprog = Progress() objprog(0.0, 0.1, "Writing %s mesh." % mesh.name) obj = mesh.object # Make sure r_... members are initiated mesh.updateIndexBuffer() numVerts = len(mesh.r_coord) if mesh.vertsPerPrimitive == 4: # Quads numFaces = len(mesh.r_faces) * 2 else: # Tris numFaces = len(mesh.r_faces) f.write('mesh {\n') mat = mesh.material if mat.diffuseTexture: tex = copyTexture(mat.diffuseTexture, human, config) f.write('\tshader "%s"\n' % tex) f.write('\n\tnumverts %d\n' % numVerts) # Collect vertex weights if human.getSkeleton(): objprog(0.1, 0.2, "Writing skeleton") rawWeights = human.getVertexWeights() # Remap vertex weights to mesh if obj.proxy: # Determine vertex weights for proxy parentWeights = obj.proxy.getVertexWeights(rawWeights) else: parentWeights = rawWeights # Account for vertices that are filtered out weights = mesh.getVertexWeights(parentWeights) # Remap vertex weights to the unwelded vertices of the object (mesh.coord to mesh.r_coord) originalToUnweldedMap = mesh.inverse_vmap # Build a weights list indexed per vertex # TODO this can be done easier by compiling VertexBoneWeights data jointIndexes = {} jointIndexes['origin'] = 0 joints = [None] + human.getSkeleton().getBones() # origin joint is None for idx,bone in enumerate(joints): if bone: jointIndexes[bone.name] = idx vertWeights = {} # = dict( vertIdx: [ (jointIdx1, weight1), ...]) for (jointName, (verts,ws)) in weights.data.items(): jointIdx = jointIndexes[jointName] for idx,v in enumerate(verts): try: for r_vIdx in originalToUnweldedMap[v]: if r_vIdx not in vertWeights: vertWeights[r_vIdx] = [] vertWeights[r_vIdx].append((jointIdx, ws[idx])) except: # unused coord pass for vert in xrange(numVerts): if vert not in vertWeights: # Weight vertex completely to origin joint vertWeights[vert] = [(0, 1.0)] else: vertWeights = None objprog(0.3, 0.7, "Writing vertices for %s." % mesh.name) # Write vertices wCount = 0 for vert in xrange(numVerts): if mesh.has_uv: u, v = mesh.r_texco[vert] else: u, v = 0, 0 if vertWeights == None: numWeights = 1 else: numWeights = len(vertWeights[vert]) # vert [vertIndex] ( [texU] [texV] ) [weightIndex] [weightElem] f.write('\tvert %d ( %f %f ) %d %d\n' % (vert, u, 1.0-v, wCount, numWeights)) wCount = wCount + numWeights objprog(0.7, 0.8, "Writing faces for %s." % mesh.name) # Write faces f.write('\n\tnumtris %d\n' % numFaces) fn = 0 for fv in mesh.r_faces: # tri [triIndex] [vertIndex1] [vertIndex2] [vertIndex3] f.write('\ttri %d %d %d %d\n' % (fn, fv[2], fv[1], fv[0])) fn += 1 if fv[0] != fv[3]: f.write('\ttri %d %d %d %d\n' % (fn, fv[0], fv[3], fv[2])) fn += 1 objprog(0.8, 0.99, "Writing bone weights for %s." % mesh.name) # Write bone weighting bwprog = Progress(len(mesh.r_coord)).HighFrequency(200) if human.getSkeleton(): f.write('\n\tnumweights %d\n' % wCount) wCount = 0 for idx,co in enumerate(mesh.r_coord): for (jointIdx, jointWght) in vertWeights[idx]: # Get vertex position in bone space if joints[jointIdx]: invbonematrix = joints[jointIdx].matRestGlobal.copy() invbonematrix[:3,3] = [0,0,0] invbonematrix = la.inv(invbonematrix) relPos = np.ones(4, dtype=np.float32) relPos[:3] = co[:3] relPos[:3] -= joints[jointIdx].getRestHeadPos() relPos[:3] *= config.scale #relPos = np.dot(relPos, invbonematrix) else: relPos = co[:3] * config.scale if config.zUp: relPos[:3] = relPos[[0,2,1]] * [1,-1,1] # weight [weightIndex] [jointIndex] [weightValue] ( [xPos] [yPos] [zPos] ) f.write('\tweight %d %d %f ( %f %f %f )\n' % (wCount, jointIdx, jointWght, relPos[0], relPos[1], relPos[2])) wCount = wCount +1 bwprog.step() else: # No skeleton selected: Attach all vertices to the root with weight 1.0 f.write('\n\tnumweights %d\n' % (numVerts)) for idx,co in enumerate(mesh.r_coord): # weight [weightIndex] [jointIndex] [weightValue] ( [xPos] [yPos] [zPos] ) co = co.copy() if config.feetOnGround: co += config.offset if config.zUp: co = co[[0,2,1]] * [1,-1,1] f.write('\tweight %d %d %f ( %f %f %f )\n' % (idx, 0, 1.0, co[0], co[1], co[2])) # Note: MD5 has a z-up coordinate system bwprog.step() f.write('}\n\n') loopprog.step() f.close() progress(0.8, 0.99, "Writing Animations") if human.getSkeleton() and hasattr(human, 'animations'): animprog = Progress(len(human.animations)) for anim in human.animations: writeAnimation(filepath, human, humanBBox, config, anim.getAnimationTrack()) animprog.step() progress(1, None, "MD5 export finished. Exported file: %s", filepath)
def Render(settings): progress = Progress.begin() if not mh.hasRenderToRenderbuffer(): settings['dimensions'] = (G.windowWidth, G.windowHeight) if settings['lightmapSSS']: progress(0, 0.05, "Storing data") import material human = G.app.selectedHuman materialBackup = material.Material(human.material) progress(0.05, 0.1, "Projecting lightmaps") diffuse = imgop.Image(data=human.material.diffuseTexture) lmap = projection.mapSceneLighting(settings['scene'], border=human.material.sssRScale) progress(0.1, 0.4, "Applying medium scattering") lmapG = imgop.blurred(lmap, human.material.sssGScale, 13) progress(0.4, 0.7, "Applying high scattering") lmapR = imgop.blurred(lmap, human.material.sssRScale, 13) lmap = imgop.compose([lmapR, lmapG, lmap]) if not diffuse.isEmpty: progress(0.7, 0.8, "Combining textures") lmap = imgop.resized(lmap, diffuse.width, diffuse.height, filter=image.FILTER_BILINEAR) progress(0.8, 0.9) lmap = imgop.multiply(lmap, diffuse) lmap.sourcePath = "Internal_Renderer_Lightmap_SSS_Texture" progress(0.9, 0.95, "Setting up renderer") human.material.diffuseTexture = lmap human.configureShading(diffuse=True) human.shadeless = True progress(0.95, 0.98, None) else: progress(0, 0.99, None) if not mh.hasRenderToRenderbuffer(): # Limited fallback mode, read from screen buffer log.message("Fallback render: grab screen") img = mh.grabScreen(0, 0, G.windowWidth, G.windowHeight) alphaImg = None else: # Render to framebuffer object renderprog = Progress() renderprog(0, 0.99 - 0.59 * settings['AA'], "Rendering") width, height = settings['dimensions'] log.message("Rendering at %sx%s", width, height) if settings['AA']: width = width * 2 height = height * 2 img = mh.renderToBuffer(width, height) alphaImg = mh.renderAlphaMask(width, height) img = imgop.addAlpha(img, imgop.getChannel(alphaImg, 0)) if settings['AA']: renderprog(0.4, 0.99, "AntiAliasing") # Resize to 50% using bi-linear filtering img = img.resized(width / 2, height / 2, filter=image.FILTER_BILINEAR) # TODO still haven't figured out where components get swapped, but this hack appears to be necessary img.data[:, :, :] = img.data[:, :, (2, 1, 0, 3)] renderprog.finish() if settings['lightmapSSS']: progress(0.98, 0.99, "Restoring data") human.material = materialBackup progress(1, None, 'Rendering complete') gui3d.app.getCategory('Rendering').getTaskByName('Viewer').setImage(img) mh.changeTask('Rendering', 'Viewer') gui3d.app.statusPersist('Rendering complete')
def Render(settings): progress = Progress.begin() if not mh.hasRenderToRenderbuffer(): settings['dimensions'] = (G.windowWidth, G.windowHeight) if settings['lightmapSSS']: progress(0, 0.05, "Storing data") import material human = G.app.selectedHuman materialBackup = material.Material(human.material) progress(0.05, 0.1, "Projecting lightmaps") diffuse = imgop.Image(data = human.material.diffuseTexture) lmap = projection.mapSceneLighting( settings['scene'], border = human.material.sssRScale) progress(0.1, 0.4, "Applying medium scattering") lmapG = imgop.blurred(lmap, human.material.sssGScale, 13) progress(0.4, 0.7, "Applying high scattering") lmapR = imgop.blurred(lmap, human.material.sssRScale, 13) lmap = imgop.compose([lmapR, lmapG, lmap]) if not diffuse.isEmpty: progress(0.7, 0.8, "Combining textures") lmap = imgop.resized(lmap, diffuse.width, diffuse.height, filter=image.FILTER_BILINEAR) progress(0.8, 0.9) lmap = imgop.multiply(lmap, diffuse) lmap.sourcePath = "Internal_Renderer_Lightmap_SSS_Texture" progress(0.9, 0.95, "Setting up renderer") human.material.diffuseTexture = lmap human.configureShading(diffuse = True) human.shadeless = True progress(0.95, 0.98, None) else: progress(0, 0.99, None) if not mh.hasRenderToRenderbuffer(): # Limited fallback mode, read from screen buffer log.message("Fallback render: grab screen") img = mh.grabScreen(0, 0, G.windowWidth, G.windowHeight) alphaImg = None else: # Render to framebuffer object renderprog = Progress() renderprog(0, 0.99 - 0.59 * settings['AA'], "Rendering") width, height = settings['dimensions'] log.message("Rendering at %sx%s", width, height) if settings['AA']: width = width * 2 height = height * 2 img = mh.renderToBuffer(width, height) alphaImg = mh.renderAlphaMask(width, height) img = imgop.addAlpha(img, imgop.getChannel(alphaImg, 0)) if settings['AA']: renderprog(0.4, 0.99, "AntiAliasing") # Resize to 50% using bi-linear filtering img = img.resized(width/2, height/2, filter=image.FILTER_BILINEAR) # TODO still haven't figured out where components get swapped, but this hack appears to be necessary img.data[:,:,:] = img.data[:,:,(2,1,0,3)] renderprog.finish() if settings['lightmapSSS']: progress(0.98, 0.99, "Restoring data") human.material = materialBackup progress(1, None, 'Rendering complete') gui3d.app.getCategory('Rendering').getTaskByName('Viewer').setImage(img) mh.changeTask('Rendering', 'Viewer') gui3d.app.statusPersist('Rendering complete')
def povrayExportMesh2(path, settings): """ This function exports data in the form of a mesh2 humanoid object. The POV-Ray file generated is fairly inflexible, but is highly efficient. Parameters ---------- path: *string*. The file system path to the output files that need to be generated. settings: *dictionary*. Settings passed from the GUI. """ progress = Progress.begin() # Prepare the output directory. progress(0, 0.01, "Preparing Filesystem") if not os.path.isdir(path): os.makedirs(path) log.debug('POV-Ray output folder: %s', path) # Cleanup output folder for f in os.listdir(path): temppath = os.path.join(path, f) if os.path.isfile(temppath) and not os.path.splitext(f)[1] == '.png': os.remove(temppath) # Make empty source output folder path = os.path.join(path, 'source/') if os.path.isdir(path): for f in os.listdir(path): os.remove(os.path.join(path, f)) else: os.makedirs(path) log.debug('POV-Ray source output folder: %s', path) # Open .inc file for writing. outputFileDescriptor = open(os.path.join(path, settings['name'] + ".inc"), 'w') # Write position and dimension constants. writeConstants(outputFileDescriptor, settings) # Collect and prepare all objects. progress(0.01, 0.2, "Analyzing Objects") rmeshes = collect.setupMeshes(settings['name'], gui3d.app.selectedHuman, hidden=False, subdivide=settings['subdivide']) # Analyze the materials of each richmesh to povray compatible format. MAfuncs = { 'diffusedef': lambda T, S: 'pigment {image_map {%(ft)s "%(fn)s" interpolate 2%(f)s%(t)s}}' % { 'ft': getImageFType(T.getSaveExt()), 'fn': T.getSaveName(), 'f': ' filter all ' + str(S['filter']) if 'filter' in S else "", 't': ' transmit all ' + str(S['transmit']) if 'transmit' in S else "" }, 'bumpdef': lambda T, S: 'normal {bump_map {%(ft)s "%(fn)s" interpolate 2} %(bi)f}' % { 'ft': getImageFType(T.getSaveExt()), 'fn': T.getSaveName(), 'bi': T.Object.rmesh.material.bumpMapIntensity if T.successfulAlternative == 0 else T.Object.rmesh.material.displacementMapIntensity }, 'alphadef': lambda T, S: 'image_map {%(ft)s "%(fn)s" interpolate 2}' % { 'ft': getImageFType(T.getSaveExt()), 'fn': T.getSaveName() }, 'colordef': lambda T, S: 'rgb%(bf)s%(bt)s <#color#%(f)s%(t)s>' % { 'bf': 'f' if 'filter' in S else "", 'bt': 't' if 'transmit' in S else "", 'f': ',' + str(S['filter']) if 'filter' in S else "", 't': ',' + str(S['transmit']) if 'transmit' in S else "" }, 'makecolor': lambda s, ct=(1, 1, 1): s.replace('#color#', '%s,%s,%s' % ct), 'getDiffuseColor': lambda T, S: T.Object.rmesh.material.diffuseColor.asTuple(), 'getAmbience': lambda T, S: tuple([(v1 * v2 * S['multiply'] if 'multiply' in S else v1 * v2) for (v1, v2) in zip(T.Object.rmesh.material.ambientColor.values, settings['scene'].environment.ambience)]), 'specular': lambda T, S: str( numpy.average(T.Object.rmesh.material.specularColor.values)), 'roughness': lambda T, S: str(1.0 - T.Object.rmesh.material.shininess), 'diffuseInt': lambda T, S: str(T.Object.rmesh.material.diffuseIntensity), 'pigment': lambda s: 'pigment {%s}' % s, 'lmap': lambda RM: projection.mapSceneLighting(settings['scene'], RM.object. object), 'blurlev': lambda img, mult: (mult * (float(img.width) / 1024)) if img else mult, 'GBlur': lambda RM: RM.material.sssGScale, 'RBlur': lambda RM: RM.material.sssRScale, 'mapmask': lambda RM: projection.mapMask() } MAfuncs.update(matanalyzer.imgopfuncs) materials = matanalyzer.MaterialAnalysis( rmeshes, map={ 'diffuse': (['mat.diffuse'], 'diffusedef', ('pigment', ('makecolor', 'colordef', 'getDiffuseColor'))), 'bump': (['mat.bump', 'mat.displacement'], 'bumpdef', None), 'alpha': (['mat.transparency', ('getAlpha', 'diffuse')], 'alphadef', ('makecolor', 'colordef', ('param', (1, 1, 1)))), 'lmap': [('getChannel', 'func.lmap', 1)], 'bllmap': [('blur', 'lmap', ('blurlev', 'lmap', 'func.GBlur'), 13)], 'bl2lmap': [('blur', 'bllmap', ('blurlev', 'lmap', 'func.RBlur'), 13)], 'sss_bluelmap': [('compose', ('list', 'black', 'black', 'lmap'))], 'sss_greenlmap': [('compose', ('list', 'black', 'bllmap', 'black'))], 'sss_redlmap': [('compose', ('list', 'bl2lmap', 'black', 'black')) ], 'sss_alpha': [('blur', ('shrinkMask', 'func.mapmask', 4), 4, 13)], 'sss_bluebump': ([('getChannel', 'bump', 1)], 'bumpdef', None), 'sss_greenbump': ([('blur', 'sss_bluebump', ('blurlev', 'sss_bluebump', 'func.GBlur'), 15) ], 'bumpdef', None), 'sss_redbump': ([('blur', 'sss_greenbump', ('blurlev', 'sss_bluebump', 'func.RBlur'), 15)], 'bumpdef', None), 'hairbump': (['bump'], 'bumpdef', 'alpha.bumpdef'), 'ambient': ([None], ('makecolor', 'colordef', 'getAmbience')), 'specular': ([None], 'specular'), 'roughness': ([None], 'roughness'), 'diffuseInt': ([None], 'diffuseInt'), 'black': [('black', 'lmap')] }, functions=MAfuncs) # If SSS is enabled, render the lightmaps. progress(0.25, 0.6, "Processing SubSurface Scattering") povrayProcessSSS(rmeshes, materials, path, settings) # Write mesh data for the object. progress(0.6, 0.9, "Writing Objects") povrayWriteMesh2(outputFileDescriptor, rmeshes) progress(0.9, 0.95, "Writing Materials") writeLights(settings['scene'], outputFileDescriptor) writeMaterials(outputFileDescriptor, rmeshes, materials, settings) outputFileDescriptor.close() # Write .pov scene file. writeScene(os.path.join(path, settings['name'] + ".pov"), rmeshes, settings) progress(0.95, 0.99, "Writing Textures") writeTextures(materials, path) progress(1.0, None, "Finished. Pov-Ray scene file exported successfully at %s" % path)
def exportMd5(filepath, config): """ This function exports MakeHuman mesh and skeleton data to id Software's MD5 format. Parameters ---------- human: *Human*. The object whose information is to be used for the export. filepath: *string*. The filepath of the file to export the object to. config: *Config*. Export configuration. """ progress = Progress.begin(logging=True, timing=True) human = config.human obj = human.meshData config.zUp = True config.feetOnGround = True # TODO this only works when exporting MHX mesh (a design error in exportutils) config.scale = 1 config.setupTexFolder(filepath) filename = os.path.basename(filepath) name = config.goodName(os.path.splitext(filename)[0]) humanBBox = human.meshData.calcBBox() progress(0, 0.2, "Collecting Objects") rmeshes = exportutils.collect.setupMeshes(name, human, config=config, subdivide=config.subdivide) if human.getSkeleton(): numJoints = human.getSkeleton().getBoneCount( ) + 1 # Amount of joints + the hardcoded origin below else: numJoints = 1 f = codecs.open(filepath, 'w', encoding="utf-8") f.write('MD5Version 10\n') f.write('commandline ""\n\n') f.write('numJoints %d\n' % numJoints) f.write('numMeshes %d\n\n' % (len(rmeshes))) f.write('joints {\n') # Hardcoded root joint f.write('\t"%s" %d ( %f %f %f ) ( %f %f %f )\n' % ('origin', -1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)) progress(0.2, 0.3, "Writing Bones") if human.getSkeleton(): bones = human.getSkeleton().getBones() boneprog = Progress(len(bones)) for bone in bones: writeBone(f, bone, human, config) boneprog.step() f.write('}\n\n') progress(0.3, 0.8, "Writing Objects") loopprog = Progress(len(rmeshes)) for rmeshIdx, rmesh in enumerate(rmeshes): # rmesh.type: None is human, "Proxymeshes" is human proxy, "Clothes" for clothing and "Hair" for hair objprog = Progress() objprog(0.0, 0.1, "Writing %s mesh." % rmesh.name) obj = rmesh.object obj.calcFaceNormals() obj.calcVertexNormals() obj.updateIndexBuffer() numVerts = len(obj.r_coord) if obj.vertsPerPrimitive == 4: # Quads numFaces = len(obj.r_faces) * 2 else: # Tris numFaces = len(obj.r_faces) f.write('mesh {\n') mat = rmesh.material if mat.diffuseTexture: tex = copyTexture(mat.diffuseTexture, human, config) f.write('\tshader "%s"\n' % tex) f.write('\n\tnumverts %d\n' % numVerts) # Collect vertex weights if human.getSkeleton(): objprog(0.1, 0.2, "Writing skeleton") bodyWeights = human.getVertexWeights() if rmesh.type: # Determine vertex weights for proxy weights = skeleton.getProxyWeights(rmesh.proxy, bodyWeights, obj) else: # Use vertex weights for human body weights = bodyWeights # Account for vertices that are filtered out if rmesh.vertexMapping != None: filteredVIdxMap = rmesh.vertexMapping weights2 = {} for (boneName, (verts, ws)) in weights.items(): verts2 = [] ws2 = [] for i, vIdx in enumerate(verts): if vIdx in filteredVIdxMap: verts2.append(filteredVIdxMap[vIdx]) ws2.append(ws[i]) weights2[boneName] = (verts2, ws2) weights = weights2 # Remap vertex weights to the unwelded vertices of the object (obj.coord to obj.r_coord) originalToUnweldedMap = obj.inverse_vmap # Build a weights list indexed per vertex jointIndexes = {} jointIndexes['origin'] = 0 joints = [ None ] + human.getSkeleton().getBones() # origin joint is None for idx, bone in enumerate(joints): if bone: jointIndexes[bone.name] = idx vertWeights = {} # = dict( vertIdx: [ (jointIdx1, weight1), ...]) for (jointName, (verts, ws)) in weights.items(): jointIdx = jointIndexes[jointName] for idx, v in enumerate(verts): try: for r_vIdx in originalToUnweldedMap[v]: if r_vIdx not in vertWeights: vertWeights[r_vIdx] = [] vertWeights[r_vIdx].append((jointIdx, ws[idx])) except: # unused coord pass for vert in xrange(numVerts): if vert not in vertWeights: # Weight vertex completely to origin joint vertWeights[vert] = [(0, 1.0)] else: vertWeights = None objprog(0.3, 0.7, "Writing vertices for %s." % rmesh.name) # Write vertices wCount = 0 for vert in xrange(numVerts): if obj.has_uv: u, v = obj.r_texco[vert] else: u, v = 0, 0 if vertWeights == None: numWeights = 1 else: numWeights = len(vertWeights[vert]) # vert [vertIndex] ( [texU] [texV] ) [weightIndex] [weightElem] f.write('\tvert %d ( %f %f ) %d %d\n' % (vert, u, 1.0 - v, wCount, numWeights)) wCount = wCount + numWeights objprog(0.7, 0.8, "Writing faces for %s." % rmesh.name) # Write faces f.write('\n\tnumtris %d\n' % numFaces) fn = 0 for fv in obj.r_faces: # tri [triIndex] [vertIndex1] [vertIndex2] [vertIndex3] f.write('\ttri %d %d %d %d\n' % (fn, fv[2], fv[1], fv[0])) fn += 1 if fv[0] != fv[3]: f.write('\ttri %d %d %d %d\n' % (fn, fv[0], fv[3], fv[2])) fn += 1 objprog(0.8, 0.99, "Writing bone weights for %s." % rmesh.name) # Write bone weighting bwprog = Progress(len(obj.r_coord)).HighFrequency(200) if human.getSkeleton(): f.write('\n\tnumweights %d\n' % wCount) wCount = 0 for idx, co in enumerate(obj.r_coord): for (jointIdx, jointWght) in vertWeights[idx]: # Get vertex position in bone space if joints[jointIdx]: invbonematrix = joints[jointIdx].matRestGlobal.copy() invbonematrix[:3, 3] = [0, 0, 0] invbonematrix = la.inv(invbonematrix) relPos = np.ones(4, dtype=np.float32) relPos[:3] = co[:3] relPos[:3] -= joints[jointIdx].getRestHeadPos() relPos[:3] *= scale #relPos = np.dot(relPos, invbonematrix) else: relPos = co[:3] * scale if config.zUp: relPos[:3] = relPos[[0, 2, 1]] * [1, -1, 1] # weight [weightIndex] [jointIndex] [weightValue] ( [xPos] [yPos] [zPos] ) f.write('\tweight %d %d %f ( %f %f %f )\n' % (wCount, jointIdx, jointWght, relPos[0], relPos[1], relPos[2])) wCount = wCount + 1 bwprog.step() else: # No skeleton selected: Attach all vertices to the root with weight 1.0 f.write('\n\tnumweights %d\n' % (numVerts)) for idx, co in enumerate(obj.r_coord): # weight [weightIndex] [jointIndex] [weightValue] ( [xPos] [yPos] [zPos] ) co = co.copy() * scale if config.feetOnGround: co[1] += (getFeetOnGroundOffset(human) * scale) if config.zUp: co = co[[0, 2, 1]] * [1, -1, 1] f.write('\tweight %d %d %f ( %f %f %f )\n' % (idx, 0, 1.0, co[0], co[1], co[2])) # Note: MD5 has a z-up coordinate system bwprog.step() f.write('}\n\n') loopprog.step() f.close() progress(0.8, 0.99, "Writing Animations") if human.getSkeleton() and hasattr(human, 'animations'): animprog = Progress(len(human.animations)) for anim in human.animations: writeAnimation(filepath, human, humanBBox, config, anim.getAnimationTrack()) animprog.step() progress(1, None, "MD5 export finished. Exported file: %s", filepath)
def exportMd5(filepath, config): """ This function exports MakeHuman mesh and skeleton data to id Software's MD5 format. Parameters ---------- human: *Human*. The object whose information is to be used for the export. filepath: *string*. The filepath of the file to export the object to. config: *Config*. Export configuration. """ progress = Progress.begin(logging=True, timing=True) human = config.human config.setupTexFolder(filepath) filename = os.path.basename(filepath) name = config.goodName(os.path.splitext(filename)[0]) # TODO this should probably be the only option config.zUp = True config.feetOnGround = True config.scale = 5 # Override scale setting to a sensible default for doom-style engines humanBBox = human.meshData.calcBBox() objects = human.getObjects(excludeZeroFaceObjs=True) meshes = [obj.mesh.clone(config.scale, True) for obj in objects] # TODO set good names for meshes if human.getSkeleton(): numJoints = human.getSkeleton().getBoneCount( ) + 1 # Amount of joints + the hardcoded origin below else: numJoints = 1 f = codecs.open(filepath, 'w', encoding="utf-8") f.write('MD5Version 10\n') f.write('commandline ""\n\n') f.write('numJoints %d\n' % numJoints) f.write('numMeshes %d\n\n' % (len(meshes))) f.write('joints {\n') # Hardcoded root joint f.write('\t"%s" %d ( %f %f %f ) ( %f %f %f )\n' % ('origin', -1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)) progress(0.2, 0.3, "Writing Bones") if human.getSkeleton(): bones = human.getSkeleton().getBones() boneprog = Progress(len(bones)) for bone in bones: writeBone(f, bone, human, config) boneprog.step() f.write('}\n\n') progress(0.3, 0.8, "Writing Objects") loopprog = Progress(len(meshes)) for meshIdx, mesh in enumerate(meshes): objprog = Progress() objprog(0.0, 0.1, "Writing %s mesh." % mesh.name) obj = mesh.object # Make sure r_... members are initiated mesh.updateIndexBuffer() numVerts = len(mesh.r_coord) if mesh.vertsPerPrimitive == 4: # Quads numFaces = len(mesh.r_faces) * 2 else: # Tris numFaces = len(mesh.r_faces) f.write('mesh {\n') mat = mesh.material if mat.diffuseTexture: tex = copyTexture(mat.diffuseTexture, human, config) f.write('\tshader "%s"\n' % tex) f.write('\n\tnumverts %d\n' % numVerts) # Collect vertex weights if human.getSkeleton(): objprog(0.1, 0.2, "Writing skeleton") rawWeights = human.getVertexWeights() # Remap vertex weights to mesh if obj.proxy: # Determine vertex weights for proxy parentWeights = obj.proxy.getVertexWeights(rawWeights) else: parentWeights = rawWeights # Account for vertices that are filtered out weights = mesh.getVertexWeights(parentWeights) # Remap vertex weights to the unwelded vertices of the object (mesh.coord to mesh.r_coord) originalToUnweldedMap = mesh.inverse_vmap # Build a weights list indexed per vertex # TODO this can be done easier by compiling VertexBoneWeights data jointIndexes = {} jointIndexes['origin'] = 0 joints = [ None ] + human.getSkeleton().getBones() # origin joint is None for idx, bone in enumerate(joints): if bone: jointIndexes[bone.name] = idx vertWeights = {} # = dict( vertIdx: [ (jointIdx1, weight1), ...]) for (jointName, (verts, ws)) in weights.data.items(): jointIdx = jointIndexes[jointName] for idx, v in enumerate(verts): try: for r_vIdx in originalToUnweldedMap[v]: if r_vIdx not in vertWeights: vertWeights[r_vIdx] = [] vertWeights[r_vIdx].append((jointIdx, ws[idx])) except: # unused coord pass for vert in xrange(numVerts): if vert not in vertWeights: # Weight vertex completely to origin joint vertWeights[vert] = [(0, 1.0)] else: vertWeights = None objprog(0.3, 0.7, "Writing vertices for %s." % mesh.name) # Write vertices wCount = 0 for vert in xrange(numVerts): if mesh.has_uv: u, v = mesh.r_texco[vert] else: u, v = 0, 0 if vertWeights == None: numWeights = 1 else: numWeights = len(vertWeights[vert]) # vert [vertIndex] ( [texU] [texV] ) [weightIndex] [weightElem] f.write('\tvert %d ( %f %f ) %d %d\n' % (vert, u, 1.0 - v, wCount, numWeights)) wCount = wCount + numWeights objprog(0.7, 0.8, "Writing faces for %s." % mesh.name) # Write faces f.write('\n\tnumtris %d\n' % numFaces) fn = 0 for fv in mesh.r_faces: # tri [triIndex] [vertIndex1] [vertIndex2] [vertIndex3] f.write('\ttri %d %d %d %d\n' % (fn, fv[2], fv[1], fv[0])) fn += 1 if fv[0] != fv[3]: f.write('\ttri %d %d %d %d\n' % (fn, fv[0], fv[3], fv[2])) fn += 1 objprog(0.8, 0.99, "Writing bone weights for %s." % mesh.name) # Write bone weighting bwprog = Progress(len(mesh.r_coord)).HighFrequency(200) if human.getSkeleton(): f.write('\n\tnumweights %d\n' % wCount) wCount = 0 for idx, co in enumerate(mesh.r_coord): for (jointIdx, jointWght) in vertWeights[idx]: # Get vertex position in bone space if joints[jointIdx]: invbonematrix = joints[jointIdx].matRestGlobal.copy() invbonematrix[:3, 3] = [0, 0, 0] invbonematrix = la.inv(invbonematrix) relPos = np.ones(4, dtype=np.float32) relPos[:3] = co[:3] relPos[:3] -= joints[jointIdx].getRestHeadPos() relPos[:3] *= config.scale #relPos = np.dot(relPos, invbonematrix) else: relPos = co[:3] * config.scale if config.zUp: relPos[:3] = relPos[[0, 2, 1]] * [1, -1, 1] # weight [weightIndex] [jointIndex] [weightValue] ( [xPos] [yPos] [zPos] ) f.write('\tweight %d %d %f ( %f %f %f )\n' % (wCount, jointIdx, jointWght, relPos[0], relPos[1], relPos[2])) wCount = wCount + 1 bwprog.step() else: # No skeleton selected: Attach all vertices to the root with weight 1.0 f.write('\n\tnumweights %d\n' % (numVerts)) for idx, co in enumerate(mesh.r_coord): # weight [weightIndex] [jointIndex] [weightValue] ( [xPos] [yPos] [zPos] ) co = co.copy() if config.feetOnGround: co += config.offset if config.zUp: co = co[[0, 2, 1]] * [1, -1, 1] f.write('\tweight %d %d %f ( %f %f %f )\n' % (idx, 0, 1.0, co[0], co[1], co[2])) # Note: MD5 has a z-up coordinate system bwprog.step() f.write('}\n\n') loopprog.step() f.close() progress(0.8, 0.99, "Writing Animations") if human.getSkeleton() and hasattr(human, 'animations'): animprog = Progress(len(human.animations)) for anim in human.animations: writeAnimation(filepath, human, humanBBox, config, anim.getAnimationTrack()) animprog.step() progress(1, None, "MD5 export finished. Exported file: %s", filepath)
def Render(settings): progress = Progress.begin() if not mh.hasRenderToRenderbuffer(): settings['dimensions'] = (G.windowWidth, G.windowHeight) if settings['lightmapSSS']: progress(0, 0.05, "Storing data") import material human = G.app.selectedHuman materialBackup = material.Material(human.material) progress(0.05, 0.1, "Projecting lightmaps") diffuse = imgop.Image(data=human.material.diffuseTexture) lmap = projection.mapSceneLighting(settings['scene'], border=human.material.sssRScale) progress(0.1, 0.4, "Applying medium scattering") lmapG = imgop.blurred(lmap, human.material.sssGScale, 13) progress(0.4, 0.7, "Applying high scattering") lmapR = imgop.blurred(lmap, human.material.sssRScale, 13) lmap = imgop.compose([lmapR, lmapG, lmap]) if not diffuse.isEmpty: progress(0.7, 0.8, "Combining textures") lmap = imgop.resized(lmap, diffuse.width, diffuse.height) progress(0.8, 0.9) lmap = imgop.multiply(lmap, diffuse) lmap.sourcePath = "Internal_Renderer_Lightmap_SSS_Texture" progress(0.9, 0.95, "Setting up renderer") human.material.diffuseTexture = lmap human.mesh.configureShading(diffuse=True) human.mesh.shadeless = True progress(0.95, 0.98, None) else: progress(0, 0.99, None) if not mh.hasRenderToRenderbuffer(): # Limited fallback mode, read from screen buffer log.message("Fallback render: grab screen") img = mh.grabScreen(0, 0, G.windowWidth, G.windowHeight) alphaImg = None else: # Render to framebuffer object renderprog = Progress() renderprog(0, 0.99 - 0.59 * settings['AA'], "Rendering") width, height = settings['dimensions'] log.message("Rendering at %sx%s", width, height) if settings['AA']: width = width * 2 height = height * 2 img = mh.renderToBuffer(width, height) alphaImg = mh.renderAlphaMask(width, height) img = imgop.addAlpha(img, imgop.getChannel(alphaImg, 0)) if settings['AA']: renderprog(0.4, 0.99, "AntiAliasing") # Resize to 50% using Qt image class qtImg = img.toQImage() del img # Bilinear filtered resize for anti-aliasing scaledImg = qtImg.scaled( width / 2, height / 2, transformMode=gui.QtCore.Qt.SmoothTransformation) del qtImg img = scaledImg #img = image.Image(scaledImg) # Convert back to MH image #del scaledImg renderprog.finish() if settings['lightmapSSS']: progress(0.98, 0.99, "Restoring data") human.material = materialBackup progress(1, None, 'Rendering complete') gui3d.app.getCategory('Rendering').getTaskByName('Viewer').setImage(img) mh.changeTask('Rendering', 'Viewer') gui3d.app.statusPersist('Rendering complete.')