blender/release/scripts/tex2uvbaker.py

645 lines
20 KiB
Python
Raw Normal View History

#!BPY
""" Registration info for Blender menus:
Name: 'Texture Baker'
Blender: 239
Group: 'UV'
Tooltip: 'Procedural to uvmapped texture baker'
"""
__author__ = "Jean-Michel Soler (jms)"
__url__ = ("blender", "elysiun",
"Official Page, http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_mesh3d2uv2d_en.htm",
"Communicate problems and errors, http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender")
__version__ = "0.3.2 2005/12/28"
__bpydoc__ = """\
This script "bakes" Blender procedural materials (including textures): it saves
them as 2d uv-mapped images.
This script saves an uv texture layout of the chosen mesh, that can be used as
an uv map for it. It is a way to export procedurals from Blender as normal
image textures that can be edited with a 2d image manipulation program or used
with the mesh in games and other 3d applications.
Usage:
a) Enter face mode and define uv coordinates for your mesh;<br>
b) Define its materials and textures ;
c) Run this script and check the console.
Global variables
a) FRAME integer, the last frame of the animation, autodocumented .
b) LIMIT integer, 0 or 1, uvcoords may exceed limits 0.0 to 1.0 , this variable
obliges the script to do a complete framing of the uvcoord .
Notes:<br>
This script was based on a suggestion by Martin (Theeth) Poirier;<br>
"""
#---------------------------------------------
# Last release : 0.3.1 , 2005/10/21 , 20h23
#---------------------------------------------
#---------------------------------------------
# (c) jm soler 07/2004 : 'Procedural Texture Baker'
# Based on a Martin 'Theeth' Poirier's really
# good idea : makes a rvk mesh with uv coords
# of the original mesh.
#
# Released under Blender Artistic Licence
#
# 0.3.2
# blender 2.40 update to deal with the new shape
# key system .
#
# 0.3.1
# stupid bug correction
#
# 0.3.0
# TAILLEIMAGE variable
#
# 0.2.9
# -- little probleme with the KEEPRENDERWINDOW variable .
# removed . script seems to works correctly now .
#
# 0.2.8
# -- added the forgotten image property in face
# data. a little longer but better.
# ( a remove double in the resulting mesh may be
# useful .)
# -- the data.update() function problem is
# corrected too
# -- no more layers problem . CAM and MESH are
# localised in layer 20 . This layer is
# the active one for the image rendering .
# -- mesh creation is cleaner, loop in double was
# removed and the abskey is set in frame 1
# only . This solves an other deform problem .
# -- if user does not want an autosaved image,
# the "no replace" option leaves the render
# window on the screen
#
# 0.2.7
# -- minor correction on line 147: "!=-1" added
#
# 0.2.6
# -- Creation of LAMP object is removed and replaced
# by the use of the shadeless option in material object
#
# -- helpmsg corrected : the aim of the script
# is to bake any type of textures so we have not
# to mapinput its textures on UV .
#
# --'pers' camera was replaced by an 'ortho' one.
#
# 0.2.5
# -- if a image file with the same name exits the
# system returns an error
#
# 0.2.4
# -- a LIMIT variable is added to unlock the uvcoords
# autoframing
#
#
# 0.2.3 :
# Great thanks for Apollux who sees a lot of these
# problems
#
# --Everytime you run the script a new set
# of objects is created. File size and memory
# consumption can go pretty high if you are
# not aware of that .
# Now it ONLY creates 3 objects: a flattened
# mesh, a camera and a lamp.
# --all the 3 objects was placed on layer 1, but if
# that layer was not visible while you used the script
# all you will get a is an empty render.
# Now the layer is tst and activated befor the shoot
# --The flattened mesh was really flattend only after
# frame 100 (if you playbacked the animation, you can
# actually see the mesh becoming flat on the first 100
# frames). No more.
# -- When the script is run, it changes temporary to
# the new cammera, set the render output to a square
# (i.e. 1024 x 1024 or else), does the render, and then
# resets the render output and the active camera to the
# original one. But if no original camera was found
# this produce an error.
#
# 0.2.2 :
# if the uv mesh objet exists it used,
# no creation of a new one. As the lamp and
# the camera
# 0.2.1 :
# This script automaticaly frame and shoot the
# new uv mesh . The image file is saved ine the
# /render folder.
#
#---------------------------------------------
# On user-friendly side :
#---------------------------------------------
#- Tadje Vobovnik adds the Select Image Size Menu
#
#---------------------------------------------
# Official Page :
# http://jmsoler.free.fr/didacticiel/blender/tutor/cpl_mesh3d2uv2d_en.htm
# For problems and errors:
# http://www.zoo-logique.org/3D.Blender/newsportal/thread.php?group=3D.Blender
#---------------------------------------------
import Blender
from Blender import NMesh, Draw, Object, Scene, Camera
#-----------------------------------
# Last release : 0.2.5 , 2005/05/22 , 20h00
#-----------------------------------
# la fonction Blender.sys.dirname pose un
# probleme lorsque la memoire est trop encombree
# ---
# It seems that the Blender.sys.dirname function
# poses a problem when the memory is too much encumbered
#-----------------------------------
try:
import nt
os = nt
os.sep='\\'
except:
import posix
os = posix
os.sep='/'
DIRNAME=Blender.Get('filename')
#-----------------------------------
# decoupage de la chaine en fragment
# de fa<66>on a isoler le nom du fichier
# du repertoire
# ---
# split string in fragments to isolate
# the file name from the path name
#-----------------------------------
if DIRNAME.find(os.sep)!=-1:
k0=DIRNAME.split(os.sep)
else:
k0=DIRNAME.split('/')
DIRNAME=DIRNAME.replace(k0[-1],'')
#-----------------------------------
# Last release : 0.2.5 , 2005/05/22 , end
#-----------------------------------
#-----------------------------------
# Last release : 0.2.4 , 2005/05/22 , 15h00
#-----------------------------------
FRAME = Blender.Get('endframe')
#-----------------------------------
# Last release : 0.2.4 , 2005/05/22 , end
#-----------------------------------
#-----------------------------------
# Last release : 0.2.4 , 2005/05/18 , 11h00
#
# Si LIMIT == 0 le script n'essaye pas de realiser
# un nouveau cadrage pour que l'image presente toute les
# coordonn<6E>es uv.
# ---
# if LIMIT == 0 the script do not try to make
# a new framing with all the uvcoord in only one
# shoot...
#-----------------------------------
LIMIT=0
#-----------------------------------
# Last release : 0.2.4 , 2005/05/18 , END
#-----------------------------------
XYLIMIT = [0.0, 0.0,1.0,1.0]
OBJPOS = 100.0
DEBUG=1
RENDERLAYER=20
SCENELAYERS=[]
helpmsg = """
Texture Baker:
This script saves an uv texture layout of the chosen mesh, that can be used as
an uv map for it. It is a way to export procedural textures from Blender as
normal image textures that can be edited with a 2d image manipulation program
or used with the mesh in games and other 3d applications.
Basic instructions:
- Enter face mode and define uv coordinates for your mesh (do not forget to
choose a development shape);
- Define its materials and textures ;
- Run this script and check the console.
"""
def GET_newobject (TYPE,NAME):
"""
# ---------------------------
# Function GET_newobject
#
# IN : TYPE string , object type ('Mesh','Empty',...)
# NAME string , name object
# OUT: OBJECT Blender objetc described in teh string TYPE
# SCENE Blender current scene object
# ---------------------------
Return and object and the current scene
"""
SCENE = Blender.Scene.getCurrent()
OBJECT = Blender.Object.New(TYPE,NAME)
SCENE.link(OBJECT)
return OBJECT, SCENE
def RenameImage(RDIR, MYDIR, FILENAME, name):
"""
# ---------------------------
# Function RenameImage
#
# IN : RDIR string , current render directory
# MYDIR string , new render dir for this shoot
# FILENAME string , last rendered image filename
# name string , new name for this image
# OUT: nothing
# ---------------------------
Rename the file pointed by the string name
recall the function if the file yet exists
"""
newfname = RDIR + MYDIR + name
if newfname.find('.png', -4) < 0 : newfname += '.png'
if not Blender.sys.exists(newfname):
os.rename(FILENAME, newfname)
else:
name = Draw.PupStrInput ('ReName Image, please :', name, 32)
RenameImage(RDIR, MYDIR, FILENAME, name)
def SAVE_image (rc, name, FRAME, result):
"""
# ---------------------------
# Function SAVE_image
#
# IN : rc current render context object
# name string , image name
# FRAME integer, last numbre of the curent animation
# OUT: nothing
# ---------------------------
"""
rc.enableExtensions(1)
MYDIR = ''
RENDERDIR = rc.getRenderPath().replace('\\','/')
if RENDERDIR.find('//')==0 :
print 'filename', Blender.Get('filename'),'/n', Blender.sys.dirname(Blender.Get('filename'))
RDIR=RENDERDIR.replace('//',DIRNAME)
else:
RDIR=RENDERDIR[:]
if DEBUG : print 'RDIR : ', RDIR
HOMEDIR=Blender.Get('homedir')
if DEBUG : print 'HOMEDIR', HOMEDIR
rc.setRenderPath(RENDERDIR + MYDIR)
if DEBUG : print "Render folder:", RENDERDIR + MYDIR
IMAGETYPE = Blender.Scene.Render.PNG
if DEBUG : print 'IMAGETYPE : ',IMAGETYPE
rc.setImageType(IMAGETYPE)
NEWFRAME = FRAME
OLDEFRAME = rc.endFrame()
OLDSFRAME = rc.startFrame()
rc.startFrame(NEWFRAME)
rc.endFrame(NEWFRAME)
rc.renderAnim()
if result!=2 :
Blender.Scene.Render.CloseRenderWindow()
FILENAME = "%04d" % NEWFRAME
FILENAME = FILENAME.replace (' ', '0')
FILENAME = RDIR + MYDIR + FILENAME + '.png'
RenameImage(RDIR, MYDIR, FILENAME, name)
rc.endFrame(OLDEFRAME)
rc.startFrame(OLDSFRAME)
rc.setRenderPath(RENDERDIR)
def SHOOT (XYlimit, frame, obj, name, FRAME, result):
"""
# ---------------------------
# Function SHOOT
#
# IN : XYlimit list of 4 floats, smallest and biggest
# uvcoords
# frame current frame
# obj for object location
# name image name
# FRAME the last animation's frame
# OUT: nothing
# ---------------------------
render and save the baked textures picture
"""
try:
CAM = Blender.Object.Get('UVCAMERA')
Cam = CAM.getData()
SC = Blender.Scene.getCurrent()
except:
Cam = Blender.Camera.New()
Cam.name = 'UVCamera'
CAM, SC = GET_newobject('Camera','UVCAMERA')
CAM.link(Cam)
CAM.setName('UVCAMERA')
CAM.layers=[RENDERLAYER]
Cam.lens = 30
Cam.name = 'UVCamera'
Cam.setType('ortho')
Cam.setScale(1.0)
CAM.setLocation(obj.getLocation())
CAM.LocX += XYlimit[2] * 0.500
CAM.LocY += XYlimit[3] * 0.500
CAM.LocZ += max (XYlimit[2], XYlimit[3])
CAM.setEuler (0.0, 0.0, 0.0)
context = SC.getRenderingContext()
Camold = SC.getCurrentCamera()
SC.setCurrentCamera(CAM)
OLDy = context.imageSizeY()
OLDx = context.imageSizeX()
TAILLEIMAGE='TEXTURE OUT RESOLUTION : %t |'
TAILLEIMAGE+='256 %x1 |'
TAILLEIMAGE+='512 %x2 |'
TAILLEIMAGE+='768 %x3 |'
TAILLEIMAGE+='1024 %x4 |'
TAILLEIMAGE+='2048 %x5 '
#TAILLEIMAGE+='| 4096 %x6 '
tres = Draw.PupMenu(TAILLEIMAGE)
if (tres) == 1: res = 256
elif (tres) == 2: res = 512
elif (tres) == 3: res = 768
elif (tres) == 4: res = 1024
elif (tres) == 5: res = 2048
# elif (tres) == 6: res = 4096
else: res = 512
#...
SCENELAYERS=SC.layers
SC.layers = [20]
context.imageSizeY(res)
context.imageSizeX(res)
SAVE_image (context, name, FRAME, result)
context.imageSizeY(OLDy)
context.imageSizeX(OLDx)
SC.layers = SCENELAYERS
if Camold : SC.setCurrentCamera(Camold)
Blender.Set ('curframe', frame)
#-----------------------------------
# release : 0.2.6 , 2005/05/29 , 00h00
#-----------------------------------
def PROV_Shadeless(MATList):
"""
# ---------------------------
# Function PROV_Shadeless
#
# IN : MATList a list of the mesh's materials
# OUT: SHADEDict a dictionnary of the materials' shadeles value
# ---------------------------
"""
SHADEDict={}
for mat in MATList:
SHADEDict[mat.name]=mat.mode
mat.mode |= Blender.Material.Modes.SHADELESS
return SHADEDict
#-----------------------------------
# Last release : 0.2.6 , 2005/05/29 , end
#-----------------------------------
#-----------------------------------
# release : 0.2.6 , 2005/05/29 , 00h00
#-----------------------------------
def REST_Shadeless(SHADEDict):
"""
# ---------------------------
# Function REST_Shadeless
#
# IN : SHADEDict a dictionnary of the materials' shadeles value
# OUT : nothing
# ---------------------------
"""
for m in SHADEDict.keys():
mat=Blender.Material.Get(m)
mat.mode=SHADEDict[m]
#-----------------------------------
# release : 0.2.6 , 2005/05/29 , end
#-----------------------------------
#-----------------------------------
# release : 0.3.2 , 2005/12/28 , 13h00
#-----------------------------------
def Blender240update(MESH2,FRAME):
"""
# ---------------------------
# Function Blender240update
#
# IN : MESH2 a mesh data bloc
# FRAME , the animation frame limit
#
# ADD : an ipo curve to the shape key
# named "Key 1"
#
# OUT : nothing
# ---------------------------
"""
# ---------------------------
# recuperation des clef de morphing pour ce mesh
# ---------------------------
key = MESH2.getKey()
# ---------------------------
# recuperation de l'Ipo
# ---------------------------
ipo = key.ipo
# ---------------------------
# si l'ipo n'existe pas on la cree
# ---------------------------
if ipo == None:
noipo = Blender.Ipo.New("Key","keyipo")
key.ipo = noipo
# ---------------------------
# raccourci de l'expression
# ---------------------------
ipo = key.ipo
# ---------------------------
# identification de la clef de morphing
# ---------------------------
keyidentity = "Key 1"
# ---------------------------
# recuperation de la courbe correspondante
# c'est toujours la courbe 0
# ---------------------------
ipocurve = ipo.getCurve(0)
# ---------------------------
# si la courbe n'existe pas (normalement, elle n'existe pas mais
# on g<>re le risque pour faciliter une eventuelle r<>cup<75>ration de
# cette fonction dans un autre script ou pour les cas , certe peu
# probable, ou blender viendrait a etre modifie pour les ajouter
# automatiquement ) on la cree ...
# ---------------------------
if ipocurve == None:
ipocurve = ipo.addCurve(keyidentity)
# ---------------------------
# On applique l'attribut d'inetrpolation qui permet d'avoir
# une ligne droite
# ---------------------------
ipocurve.setInterpolation("Linear")
# ---------------------------
# On retire tous les sommets qui pourraient se trouver sur la
# courbe (dans l'<27>tat actuel, cette op<6F>ration est une s<>curit<69>
# superflue ) .
# ---------------------------
while len(ipocurve.getPoints()) > 0:
ipocurve.delBezier(0)
ipocurve.recalc()
# ---------------------------
# On ajouter les sommets necessaires ...
# ---------------------------
ipocurve.addBezier((-1,1))
# ---------------------------
# ... ce dernire n'est peut-<2D>tre pas absolument obligatoire .
# ---------------------------
ipocurve.addBezier((FRAME+1,1))
#-----------------------------------
# release : 0.3.2 , 2005/12/28 , end
#-----------------------------------
def Mesh2UVCoord (LIMIT):
"""
# ---------------------------
# Function Mesh2UVCoord
#
# IN : LIMIT integer, create or not a new framing for uvcoords
# OUT: nothing
# ---------------------------
"""
global PUTRAW, FRAME, SCENELAYERS
try:
MESH3D = Object.GetSelected()[0]
if MESH3D.getType() == 'Mesh':
MESH = MESH3D.getData()
try:
NewOBJECT=Blender.Object.Get('UVOBJECT')
CurSCENE=Blender.Scene.getCurrent()
except:
NewOBJECT, CurSCENE = GET_newobject('Mesh','UVOBJECT')
MESH2 = NewOBJECT.getData()
MESH2.edges=[]
NewOBJECT.layers=[RENDERLAYER]
MESH2.faces=[]
for f in MESH.faces:
f1 = Blender.NMesh.Face()
for v in f.v:
v1 = Blender.NMesh.Vert (v.co[0], v.co[1], v.co[2])
MESH2.verts.append(v1)
f1.v.append(MESH2.verts[len(MESH2.verts) - 1])
MESH2.faces.append(f1)
f1.uv = f.uv[:]
f1.col = f.col[:]
f1.smooth = f.smooth
f1.mode = f.mode
f1.flag = f.flag
f1.mat = f.mat
#-----------------------------------
# release : 0.2.8 , 2005/07/19 , end
#-----------------------------------
try:
f1.image=f.image
except :
pass
MESH2.materials = MESH.materials[:]
NewOBJECT.setLocation (OBJPOS, OBJPOS, 0.0)
NewOBJECT.setEuler (0.0, 0.0, 0.0)
MESH2.removeAllKeys()
MESH2.update()
MESH2.insertKey (1, 'absolute')
MESH2.update()
for f in MESH2.faces:
for v in f.v:
for n in [0,1]:
v.co[n] = f.uv[f.v.index(v)][n]
exec "if v.co[%s] > XYLIMIT[%s]: XYLIMIT[%s] = v.co[%s]" % (n, n+2, n+2, n)
exec "if v.co[%s] < XYLIMIT[%s]: XYLIMIT[%s] = v.co[%s]" % (n, n, n, n)
v.co[2] = 0.0
print XYLIMIT
MESH2.update()
MESH2.insertKey (FRAME, 'absolute')
MESH2.update()
#-----------------------------------
# release : 0.3.2 , 2005/12/28 , 13h00
#-----------------------------------
Blender240update(MESH2,FRAME)
#-----------------------------------
# release : 0.3.2 , 2005/12/28 , end
#-----------------------------------
imagename = 'uvtext'
name = "CHANGE IMAGE NAME ? %t | Replace it | No replace | Script help"
result = Draw.PupMenu(name)
if result == 1:
imagename = Draw.PupStrInput ('Image Name:', imagename, 32)
if result != 3:
#-----------------------------------
# release : 0.2.6 , 2005/05/29 , 00h00
#-----------------------------------
SHADEDict=PROV_Shadeless(MESH2.materials)
#-----------------------------------
# release : 0.2.6 , 2005/05/29 , end
#-----------------------------------
if LIMIT :
SHOOT(XYLIMIT, FRAME, NewOBJECT, imagename, FRAME,result)
else :
SHOOT([0.0,0.0,1.0,1.0], FRAME, NewOBJECT, imagename, FRAME, result)
#-----------------------------------
# release : 0.2.6, 2005/05/29 , 00h00
#-----------------------------------
REST_Shadeless(SHADEDict)
#-----------------------------------
# release : 0.2.6 , 2005/05/29 , end
#-----------------------------------
Blender.Redraw()
else:
Draw.PupMenu("Ready%t|Please check console for instructions")
print helpmsg
else:
name = "Error%t|Active object is not a mesh or has no UV coordinates"
result = Draw.PupMenu(name)
print 'problem : no object selected or not mesh'
except:
name = "Error%t|Active object is not a mesh or has no UV coordinates"
result = Draw.PupMenu(name)
print 'problem : no object selected or not mesh'
Mesh2UVCoord(LIMIT)