Most people working with 3D modeling software are not aware of how heavy textures can impact performance in the modeling process and the end-user experience.
When generating textures I always recommend creating them at a higher resolution than the final product. The reasoning is that you can always down-sample the image (Reduce number of pixels) later on but you can never scale the image back up.
For procedural modeling in Esri CityEngine and generating your libraries optimizing texture and model asset size as much as possible is key for ensuring fast performance and the ability to model massive environments.
The following script takes the difficulty out of manually scaling the images in your pipeline enabling complete automation allowing you to continue focusing on the design aspect of your project you know and love...
# ------------------------------------------------------------------------------- # Name: ImageAutoResize.py # Purpose: Script for batch optimizing image for optimal performance in 3D software # # Author: Geoff Taylor # # Created: 11/19/2018 # Copyright: (c) Esri 2018 # updated: # Required: # License: Apache # ------------------------------------------------------------------------------- import os, sys from math import ceil from PIL import Image, ImageStat inFolder = r'inputFolderPathGoesHere!' outFolder = r'outputFolderPathGoesHere!' ''' Max Width and height are only relative for a single side of the image. if one side of the image is larger then the smaller side will be scaled to the minimum value and larger scaled fractionally to the smaller side''' minWidth = 300 minHeight = 300 fileFormats = ['.jpg'] # Currently only Supports .jpg ############### # Definitions # ############### def update_progress(progress): barLength = 10 # Modify this to change the length of the progress bar status = "" if isinstance(progress, int): progress = float(progress) if not isinstance(progress, float): progress = 0 status = "error: progress var must be float\r\n" if progress < 0: progress = 0 status = "Halt...\r\n" if progress >= 1: progress = 1 status = "Done...\r\n" block = int(round(barLength*progress)) text = "\rPercent Complete: [{0}] {1}% {2}".format("#"*block + "-"*(barLength-block), progress*100, status) sys.stdout.write(text) sys.stdout.flush() def fileExt(inFile): ''' [0] returns fileName, [1] returns Extension ''' filename, file_extension = os.path.splitext(inFile) return filename, file_extension.lower() def genDirectory(inPath): if not os.path.exists(inPath): os.makedirs(inPath) def delIfFileExists(inFile,outFolder): fullFilePath = os.path.join(outFolder, inFile) if os.path.exists(fullFilePath): try: os.remove(fullFilePath) except: print("Could not remove {0}".format(fullFilePath)) else: pass def imageColorType(pilImg): thumb_size = 40 MSE_cutoff = 22 adjust_color_bias = True bands = pilImg.getbands() if bands == ('R', 'G', 'B') or bands == ('R', 'G', 'B', 'A'): thumb = pilImg.resize((thumb_size, thumb_size)) SSE, bias = 0, [0, 0, 0] if adjust_color_bias: bias = ImageStat.Stat(thumb).mean[:3] bias = [b - sum(bias)/3 for b in bias] for pixel in thumb.getdata(): mu = sum(pixel)/3 SSE += sum((pixel - mu - bias)*(pixel - mu - bias) for i in [0, 1, 2]) MSE = float(SSE)/(thumb_size*thumb_size) if MSE <= MSE_cutoff: return "grayscale" else: return "color" elif len(bands) == 1: return "bw" else: return "unknown" def imageFitsDimensions(inPilImg, minWidth, minHeight): width, height = inPilImg.size if width <= minWidth or height < minHeight: return True else: return False def imageScaling(inPilImg, minWidth, minHeight): width, height = inPilImg.size if height > width: scaleFactor = minWidth / width return minWidth, ceil(scaleFactor*height) elif width > height: scaleFactor = minHeight / height return ceil(scaleFactor*width), minHeight else: return minWidth, minHeight ################ # Begin Script # ################ genDirectory(outFolder) imageFiles = [f for f in os.listdir(inFolder) if os.path.isfile(os.path.join(inFolder, f)) and fileExt(f)[1] in fileFormats] count = 0 for imageFile in imageFiles: if count > 0: update_progress(count/len(imageFiles)) delIfFileExists(imageFile, outFolder) inFile = os.path.join(inFolder, imageFile) outFile = os.path.join(outFolder, imageFile) count += 1 try: im = Image.open(inFile) if imageColorType(im) != "color": im.convert('RGB') if imageFitsDimensions(im, minWidth, minHeight): im.save(outFile, "JPEG") else: imageScaling(im, minWidth, minHeight) im.save(outFile, "JPEG") outImg = im.resize((imageScaling(im, minWidth, minHeight)[0], imageScaling(im, minWidth, minHeight)[1]), Image.ANTIALIAS) # outImg.save(outFile, quality=95) outImg.save(outFile, optimize=True, quality=95) except IOError: print("cannot resample image for" % imageFile) update_progress(100)
Just install the Python Imaging Library fork "Pillow" https://python-pillow.org/ and run the script on the folder containing your textures.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.