blender/release/scripts/tex2uvbaker.py
Campbell Barton d26d0e2889 Update to JMSs scripts fixed bug 5419.
Optimized 3ds_export.py
  newstyle classes and fixed an error where objects with no material would fail to export.
2007-01-04 20:44:33 +00:00

683 lines
21 KiB
Python
Raw Blame History

#!BPY
""" Registration info for Blender menus:
Name: 'UV 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.3 2005/09/10"
__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 print
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.3 , 2006/09/10 , 15h20
#---------------------------------------------
#---------------------------------------------
# (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.3
# blender 2.40 update to deal with the object module refactory
# some probleme with the relatif render directory
#
# 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=[]
BLOCK={'limit': [Blender.Draw.Create(0),""],
'ObjPos' : [Blender.Draw.Create(100.0),""],
'RenderLayer' : [Blender.Draw.Create(20),""],
'DisplayRes' : [Blender.Draw.Create(1024),""],
'ImageName' : [Blender.Draw.Create("uvtext"),""],
'NoReplaceImag' : [Blender.Draw.Create(0),""],
'RemoveMorphMesh' : [Blender.Draw.Create(0),""],
'RemoveShootCamera' : [Blender.Draw.Create(0),""],
'Debug' : [Blender.Draw.Create(0),""]}
block = []
block.append(("limit",BLOCK['limit'][0],""))
block.append(("Obj Pos :",BLOCK['ObjPos'][0], 0.0, 1000.0))
block.append(("Render Layer :",BLOCK['RenderLayer'][0],1, 20))
block.append(("Display Res :",BLOCK['DisplayRes'][0],16, 4096))
block.append(("Replace Img Name",BLOCK['NoReplaceImag'][0],""))
block.append(("Remove Morph Mesh",BLOCK['RemoveMorphMesh'][0],""))
block.append(("Remove Shoot Camera",BLOCK['RemoveShootCamera'][0],""))
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()
if RENDERDIR.find('//')==0 :
print 'filename', Blender.Get('filename'),'/n', Blender.sys.dirname(Blender.Get('filename'))
RDIR=RENDERDIR.replace('//',DIRNAME)
elif len(RENDERDIR)==1 and RENDERDIR.find('/')==0:
print 'filename', Blender.Get('filename'),'/n', Blender.sys.dirname(Blender.Get('filename'))
RDIR=RENDERDIR.replace('/',DIRNAME)
print 'RDIR=',RDIR
else:
RDIR=RENDERDIR[:]
RDIR = RDIR.replace('\\','/')
if DEBUG : print 'RDIR : ', RDIR
HOMEDIR=Blender.Get('homedir')
if DEBUG : print 'HOMEDIR', HOMEDIR
rc.setRenderPath(RDIR + MYDIR)
if DEBUG : print "Render folder:", RDIR + 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==1 :
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(RDIR)
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
"""
global BLOCK
#----------------------------------------------
# Create the object CAM only if it does not
# exist already . Get the current scene in the
# same time .
#----------------------------------------------
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.RotX=0.0 #setEuler ((0.0, 0.0, 0.0))
CAM.RotY=0.0
CAM.RotZ=0.0
context = SC.getRenderingContext()
Camold = SC.getCurrentCamera()
SC.setCurrentCamera(CAM)
OLDy = context.imageSizeY()
OLDx = context.imageSizeX()
res=BLOCK['DisplayRes'][0].val
SCENELAYERS=SC.layers
SC.layers = [20]
Blender.Window.EditMode(1)
Blender.Window.EditMode(0)
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, BLOCK, block
if Object.GetSelected() and Object.GetSelected()[0].getType()=='Mesh':
retval = Blender.Draw.PupBlock("PupBlock test", block)
if retval==1 :
LIMIT = BLOCK['limit'][0].val
imagename = BLOCK['ImageName'][0].val
result = BLOCK['NoReplaceImag'][0].val
MESH3D = Object.GetSelected()[0]
[O.select(0) for O in Object.GetSelected()]
MESH = MESH3D.getData()
if MESH.hasFaceUV():
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))
NewOBJECT.RotX=0.0 #setEuler ((0.0, 0.0, 0.0))
NewOBJECT.RotY=0.0
NewOBJECT.RotZ=0.0
MESH2.removeAllKeys()
MESH2.update()
MESH2.insertKey (1, 'absolute')
MESH2.update()
NewOBJECT.select(1)
NewOBJECT.makeDisplayList()
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 : Active object is not a mesh or has no UV coordinates'
else:
name = "Error%t| nothing do . Push << OK >> button ."
result = Draw.PupMenu(name)
#except:
else :
name = "Error%t|No Active object or it is not a mesh "
result = Draw.PupMenu(name)
print 'problem : no object selected or not mesh'
Mesh2UVCoord(LIMIT)