Texture Painter

Run Settings
LanguagePython
Language Version
Run Command
''' Renders text from a CSV file to texture and applies they to multiple objects. Use snippets... No console Python do Blender: >>> import os, sys; sys.path.append(os.path.dirname(bpy.data.filepath)); import texture_painter >>> import importlib; importlib.reload(texture_painter); texture_painter.go() Abrindo o arquivo .csv no console Python do Blender: >>> import codecs >>> codecs.open('backers_10.csv', 'r', 'utf-8-sig') No meu ambiente, foi preciso usar: >>> codecs.open(os.path.dirname(bpy.data.filepath)+'/backers_10.csv', 'r', 'utf-8-sig') Outro usuário do curso criou a seguinte solução: directory = os.path.dirname(bpy.data.filepath) codecs.open(os.path.join(directory, 'backers.csv'), 'r' , 'utf-8-sig') Documentos para consulta: http://nvie.com/posts/iterators-vs-generators/ https://docs.python.org/3/library/csv.html https://stackoverflow.com/questions/231767/what-does-the-yield-keyword-do-in-python https://docs.python.org/3/tutorial/errors.html https://blender.stackexchange.com/questions/5781/how-to-list-all-selected-elements-in-python https://docs.python.org/3/library/functions.html#enumerate Dar preferência ao uso de Generators em detrenimento de Iterators sempre que possível. Uma vez que são mais rápidos e consomem nenos da RAM e da CPU. ''' import codecs, os, sys, bpy, csv from PIL import Image, ImageFont, ImageDraw basedir = os.path.dirname(bpy.data.filepath) + '/' basedir = basedir.replace('\\', '/') def get_backers(csv_filename): """ Ganarator retorna um dicionário contendo os valores de cada linha do arquivo .csv. Keyword arguments: csv_filename -- Nome do arquivo .csv de origem (não digitar a extensão) """ # Setando o caminho para o arquivo #basedir = os.path.dirname(bpy.data.filepath) + '\\' # theFile = csv_filename + '.csv' # fileToOpen = basedir + theFile # fileToOpen = fileToOpen.replace('\\', '/') fileName = basedir + csv_filename + '.csv' # codecs.open(fileToOpen, 'r', 'utf-8-sig') # print('Opened: ' + fileToOpen) #print(codecs.open(fileToOpen, 'r', 'utf-8-sig')) # O Generator propriamente dito with codecs.open(fileName, 'r', 'utf-8-sig') as stream: iterable = csv.reader(stream) header = next(iterable) for row in iterable: backer = dict(zip(header, row)) yield backer def render_text_to_file(text_to_render, to_filename): """ Generator as imagens baseadas nos textos. Keyword arguments: text_to_render -- Text for rendering the images to_filename -- File name to the images """ # basedir = os.path.dirname(bpy.data.filepath) + '/' # basedir = basedir.replace('\\', '/') # Create a image text_to_render = str(text_to_render) text_to_render = text_to_render.replace('{', '').replace('}', '').replace('\'', '') # largura = int(len(text_to_render)) * 27 # image = Image.new('RGB', (largura,64)) image = Image.new('RGB', (512, 64)) # Create a image draw and font objects draw = ImageDraw.Draw(image) fnt = ImageFont.truetype(basedir + 'Turtles.otf', 50) # Draw text to image draw.text((0,0), text_to_render, font=fnt, fill=(255,255,255)) # Save image to file fileName = basedir + 'image_cache/' + str(to_filename) + '.png' # print("Rendering", text_to_render, "to", fileName) image.save(fileName) def throw_invalid_selection(): """ Throw an exception and ends the execution if none or more than one object is selected """ if len(bpy.context.selected_objects) == 0 or len(bpy.context.selected_objects) > 1: raise Exception("Please select exactly one prototype object") else: print("One prototype object found.") def create_plaque(prototype, offset=(3,0,0)): """ Returns a copy of the original object, positioning it as set on the "offset" parameter. Keyword arguments: prototype -- offset -- A tuple (x,y,z) thats define the copied object, has its value (3,0,0) as default. """ prototype.select = True # Copying and positioning bpy.ops.object.duplicate_move(TRANSFORM_OT_translate={"value":tuple(offset)}) # Decelecting the copied object new_plaque = bpy.context.selected_objects[0] new_plaque.select = False return new_plaque def get_offset(num, rows, spacing): """ Returning offset from prototype position. Keyword arguments: num -- The number of the object starting from zero rows -- How many rows before wrapping spacing -- A tuple of (x,y) spacing between objects """ x_offset = (num % rows) * spacing[0] # x-spacing y_offset = (num // rows) * spacing[1] # y-spacing return (x_offset, y_offset) # def read_csv(): # """ # Loop modelo de passagem de argumentos para a função render_text_to_file(). Está usando um arquivo .csv de exemplo. # """ # # Chamando a função que contem o Generator # for backer in get_backers('backers_10'): # Nome do arquivo aqui # # print(backer) # # render_text_to_file(str(backer), str(backer['Number'])) # text_to_render = backer['Name'] + ', ' + backer['Country'] # render_text_to_file(text_to_render, backer['Number']) def swap_texture_blenderRender(blender_obj, img_filename): """ Método funciona somente com Blender Render Swaps the first texture, on the first material to supplied. Keyword arguments: blender_obj -- img_filename -- """ # texture_img = plaque.material_slots[0].material.texture_slots[0].texture.image # texture_img.filepath = '/image_cache/' + str(img_filename) + '.png' # Create a copy of the material in slot 0 new_material = blender_obj.material_slots[0].material.copy() # ensure new item has this new material applied blender_obj.material_slots[0].material = new_material # Create a new texture new_texture = new_material.texture_slots[0].texture.copy() # Substitui a textura original pela cópia new_material.texture_slots[0].texture = new_texture # Create a new image by loading an existing one # img_filename = basedir + 'image_cache/' + str(img_filename) + '.png' img_filename = '//image_cache\\' + str(img_filename) + '.png' # Could I use -> img_filename = new_image = bpy.data.images.load(img_filename) # Apply new image to the texture new_texture.image = new_image def swap_texture_cyclesRender(blender_obj, img_filename): """ Método funciona somente com Cycles Render Swaps the first texture, on the first material to supplied. Keyword arguments: blender_obj -- img_filename -- """ ''' bpy.context.selected_objects[0].material_slots[0].material .node_tree.nodes['Image Texture'].image ''' # Create a copy of the material in slot 0 new_material = blender_obj.material_slots[0].material.copy() # ensure new item has this new material applied blender_obj.material_slots[0].material = new_material # Create a new image by loading an existing one # img_filename = basedir + 'image_cache/' + str(img_filename) + '.png' img_filename = '//image_cache\\' + str(img_filename) + '.png' new_image = bpy.data.images.load(img_filename) # Apply new image to the texture new_material.node_tree.nodes['Image Texture'].image = new_image def swap_text(blender_obj, backer, index): """ Loop modelo de passagem de argumentos para a função render_text_to_file(). Está usando um arquivo .csv de exemplo. Keyword arguments: object -- Objeto atualmente selecionado no Blender backer -- Linha extraída do arquivo .csv index -- Inteiro que será usado para nomear as imagens (independente dos valores no arquivo csv) """ text_to_render = backer['Name'] + ', ' + backer['Country'] # render_text_to_file(text_to_render, backer['Number']) render_text_to_file(text_to_render, index) rendEng = bpy.data.scenes["Scene"].render.engine if rendEng == 'CYCLES': swap_texture_cyclesRender(blender_obj, index) else: swap_texture_blenderRender(blender_obj, index) def go(): """ Função inicial para testes. Faz a chamada para a função read_csv() que executará as demais. """ print("Texture Painter starting up.") # read_csv() throw_invalid_selection() # pass in selected object # create_plaque() # print(get_offset(3, 3, (10,10,0))) prototype = bpy.context.selected_objects[0] # Criando um sistema de numeração independente dos valores estarem ou não corretos no arquivo .csv for num, backer in enumerate(get_backers('backers_10')): # print(num, backer['Name'] + ', ' + backer['Country']) if num == 0: plaque = prototype else: # Função retorna uma tupla de 2 valores que serão atribuidos na ordem às variáveis x e y x, y = get_offset(num, 3, (-2, 2, 0)) plaque = create_plaque(prototype, (x, y, 0)) swap_text(plaque, backer, num) ''' Exibindo tds os atributos de um objeto: dir(nome_do_objeto) Ex: atual = bpy.context.selected_objects[0] dir(atual) # Exibirá tds os atributos do(s) objeto(s) selecionados dentre elas: atual.dimensions[0] -> Dimenssões no eixo X atual.dimensions[1] -> Dimenssões no eixo Y atual.dimensions[2] -> Dimenssões no eixo Z atual.name -> Exibe o nome do objeto atual.location -> Exibe a localização do objeto (X,Y,Z) '''
Editor Settings
Theme
Key bindings
Full width
Lines