1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633
|
import Blender
from Blender import Scene, sys, Camera, Object, Image
from Blender.Scene import Render
Vector= Blender.Mathutils.Vector
def extFromFormat(format):
if format == Render.TARGA: return 'tga'
if format == Render.RAWTGA: return 'tga'
if format == Render.HDR: return 'hdr'
if format == Render.PNG: return 'png'
if format == Render.BMP: return 'bmp'
if format == Render.JPEG: return 'jpg'
if format == Render.HAMX: return 'ham'
if format == Render.TIFF: return 'tif'
if format == Render.CINEON: return 'cine'
if format == Render.DPX: return 'tif'
if format == Render.OPENEXR: return 'exr'
if format == Render.IRIS: return 'rgb'
return ''
def imageFromObjectsOrtho(objects, path, width, height, smooth, alpha= True, camera_matrix= None, format=Render.PNG):
'''
Takes any number of objects and renders them on the z axis, between x:y-0 and x:y-1
Usefull for making images from a mesh without per pixel operations
- objects must be alredy placed
- smooth, anti alias True/False
- path renders to a PNG image
- alpha weather to render background as alpha
returns the blender image
'''
ext = '.' + extFromFormat(format)
print ext
# remove an extension if its alredy there
if path.lower().endswith(ext):
path= path[:-4]
path_expand= sys.expandpath(path) + ext
print path_expand, 'path'
# Touch the path
try:
f= open(path_expand, 'w')
f.close()
except:
raise 'Error, could not write to path:' + path_expand
# RENDER THE FACES.
scn= Scene.GetCurrent()
render_scn= Scene.New()
render_scn.makeCurrent()
render_scn.Layers |= (1<<20)-1 # all layers enabled
# Add objects into the current scene
for ob in objects:
render_scn.link(ob)
render_context= render_scn.getRenderingContext()
render_context.setRenderPath('') # so we can ignore any existing path and save to the abs path.
render_context.imageSizeX(width)
render_context.imageSizeY(height)
if smooth:
render_context.enableOversampling(True)
render_context.setOversamplingLevel(16)
else:
render_context.enableOversampling(False)
render_context.setRenderWinSize(100)
render_context.setImageType(format)
render_context.enableExtensions(True)
#render_context.enableSky() # No alpha needed.
if alpha:
render_context.alphaMode= 1
render_context.enableRGBAColor()
else:
render_context.alphaMode= 0
render_context.enableRGBColor()
render_context.displayMode= 0 # fullscreen
# New camera and object
render_cam_data= Camera.New('ortho')
render_cam_ob= Object.New('Camera')
render_cam_ob.link(render_cam_data)
render_scn.link(render_cam_ob)
render_scn.objects.camera = render_cam_ob
render_cam_data.type= 'ortho'
# Position the camera
if camera_matrix:
render_cam_ob.setMatrix(camera_matrix)
# We need to take into account the matrix scaling when setting the size
# so we get the image bounds defined by the matrix
# first get the x and y factors from the matrix.
# To render the correct dimensions we must use the aspy and aspy to force the matrix scale to
# override the aspect enforced by the width and weight.
cent= Vector() * camera_matrix
xvec= Vector(1,0,0) * camera_matrix
yvec= Vector(0,1,0) * camera_matrix
# zvec= Vector(0,0,1) * camera_matrix
xlen = (cent-xvec).length # half height of the image
ylen = (cent-yvec).length # half width of the image
# zlen = (cent-zvec).length # dist to place the camera? - just use the loc for now.
# less then 1.0 portrate, 1.0 or more is portrate
asp_cam_mat= xlen/ylen # divide by zero? - possible but scripters fault.
asp_image_res= float(width)/height
#print 'asp quad', asp_cam_mat, 'asp_image', asp_image_res
#print 'xylen', xlen, ylen, 'w/h', width, height
# Setup the aspect
if asp_cam_mat > asp_image_res:
# camera is wider then image res.
# to make the image wider, reduce the aspy
asp_diff= asp_image_res/asp_cam_mat
min_asp= asp_diff * 200
#print 'X', min_asp
elif asp_cam_mat < asp_image_res: # asp_cam_mat < asp_image_res
# camera is narrower then image res
# to make the image narrower, reduce the aspx
asp_diff= asp_cam_mat/asp_image_res
min_asp= asp_diff * 200
#print 'Y', min_asp
else:
min_asp= 200
# set the camera size
if xlen > ylen:
if asp_cam_mat > asp_image_res:
render_context.aspectX= 200 # get the greatest range possible
render_context.aspectY= min_asp # get the greatest range possible
else:
render_context.aspectY= 200 # get the greatest range possible
render_context.aspectX= min_asp # get the greatest range possible
#print "xlen bigger"
render_cam_data.scale= xlen * 2
elif xlen < ylen:# ylen is bigger
if asp_cam_mat > asp_image_res:
render_context.aspectX= 200 # get the greatest range possible
render_context.aspectY= min_asp # get the greatest range possible
else:
render_context.aspectY= 200 # get the greatest range possible
render_context.aspectX= min_asp # get the greatest range possible
#print "ylen bigger"
render_cam_data.scale= ylen *2
else:
# asppect 1:1
#print 'NOLEN Bigger'
render_cam_data.scale= xlen * 2
#print xlen, ylen, 'xlen, ylen'
else:
if width > height:
min_asp = int((float(height) / width) * 200)
render_context.aspectX= min_asp
render_context.aspectY= 200
else:
min_asp = int((float(width) / height) * 200)
render_context.aspectX= 200
render_context.aspectY= min_asp
render_cam_data.scale= 1.0
render_cam_ob.LocZ= 1.0
render_cam_ob.LocX= 0.5
render_cam_ob.LocY= 0.5
Blender.Window.RedrawAll()
render_context.render()
render_context.saveRenderedImage(path)
Render.CloseRenderWindow()
#if not B.sys.exists(PREF_IMAGE_PATH_EXPAND):
# raise 'Error!!!'
scn.makeCurrent()
Scene.Unlink(render_scn)
# NOW APPLY THE SAVED IMAGE TO THE FACES!
#print PREF_IMAGE_PATH_EXPAND
try:
target_image= Image.Load(path_expand)
return target_image
except:
raise 'Error: Could not render or load the image at path "%s"' % path_expand
return
#-----------------------------------------------------------------------------#
# UV Baking functions, make a picture from mesh(es) uvs #
#-----------------------------------------------------------------------------#
def mesh2uv(me_s, PREF_SEL_FACES_ONLY=False):
'''
Converts a uv mapped mesh into a 2D Mesh from UV coords.
returns a triple -
(mesh2d, face_list, col_list)
"mesh" is the new mesh and...
"face_list" is the faces that were used to make the mesh,
"material_list" is a list of materials used by each face
These are in alligned with the meshes faces, so you can easerly copy data between them
'''
render_me= Blender.Mesh.New()
render_me.verts.extend( [Vector(0,0,0),] ) # 0 vert uv bugm dummy vert
face_list= []
material_list= []
for me in me_s:
me_materials= me.materials
if PREF_SEL_FACES_ONLY:
me_faces= [f for f in me.faces if f.sel]
else:
me_faces= me.faces
face_list.extend(me_faces)
# Dittro
if me_materials:
material_list.extend([me_materials[f.mat] for f in me_faces])
else:
material_list.extend([None]*len(me_faces))
# Now add the verts
render_me.verts.extend( [ Vector(uv.x, uv.y, 0) for f in face_list for uv in f.uv ] )
# Now add the faces
tmp_faces= []
vert_offset= 1
for f in face_list:
tmp_faces.append( [ii+vert_offset for ii in xrange(len(f))] )
vert_offset+= len(f)
render_me.faces.extend(tmp_faces)
render_me.faceUV=1
return render_me, face_list, material_list
def uvmesh_apply_normals(render_me, face_list):
'''Worldspace normals to vertex colors'''
for i, f in enumerate(render_me.faces):
face_orig= face_list[i]
f_col= f.col
for j, v in enumerate(face_orig):
c= f_col[j]
nx, ny, nz= v.no
c.r= int((nx+1)*128)-1
c.g= int((ny+1)*128)-1
c.b= int((nz+1)*128)-1
def uvmesh_apply_image(render_me, face_list):
'''Copy the image and uvs from the original faces'''
for i, f in enumerate(render_me.faces):
f.uv= face_list[i].uv
f.image= face_list[i].image
def uvmesh_apply_vcol(render_me, face_list):
'''Copy the vertex colors from the original faces'''
for i, f in enumerate(render_me.faces):
face_orig= face_list[i]
f_col= f.col
for j, c_orig in enumerate(face_orig.col):
c= f_col[j]
c.r= c_orig.r
c.g= c_orig.g
c.b= c_orig.b
def uvmesh_apply_matcol(render_me, material_list):
'''Get the vertex colors from the original materials'''
for i, f in enumerate(render_me.faces):
mat_orig= material_list[i]
f_col= f.col
if mat_orig:
for c in f_col:
c.r= int(mat_orig.R*255)
c.g= int(mat_orig.G*255)
c.b= int(mat_orig.B*255)
else:
for c in f_col:
c.r= 255
c.g= 255
c.b= 255
def uvmesh_apply_col(render_me, color):
'''Get the vertex colors from the original materials'''
r,g,b= color
for i, f in enumerate(render_me.faces):
f_col= f.col
for c in f_col:
c.r= r
c.g= g
c.b= b
def vcol2image(me_s,\
PREF_IMAGE_PATH,\
PREF_IMAGE_SIZE,\
PREF_IMAGE_BLEED,\
PREF_IMAGE_SMOOTH,\
PREF_IMAGE_WIRE,\
PREF_IMAGE_WIRE_INVERT,\
PREF_IMAGE_WIRE_UNDERLAY,\
PREF_USE_IMAGE,\
PREF_USE_VCOL,\
PREF_USE_MATCOL,\
PREF_USE_NORMAL,\
PREF_USE_TEXTURE,\
PREF_SEL_FACES_ONLY):
def rnd_mat():
render_mat= Blender.Material.New()
mode= render_mat.mode
# Dont use lights ever
mode |= Blender.Material.Modes.SHADELESS
if PREF_IMAGE_WIRE:
# Set the wire color
if PREF_IMAGE_WIRE_INVERT:
render_mat.rgbCol= (1,1,1)
else:
render_mat.rgbCol= (0,0,0)
mode |= Blender.Material.Modes.WIRE
if PREF_USE_VCOL or PREF_USE_MATCOL or PREF_USE_NORMAL: # both vcol and material color use vertex cols to avoid the 16 max limit in materials
mode |= Blender.Material.Modes.VCOL_PAINT
if PREF_USE_IMAGE:
mode |= Blender.Material.Modes.TEXFACE
# Copy back the mode
render_mat.mode |= mode
return render_mat
render_me, face_list, material_list= mesh2uv(me_s, PREF_SEL_FACES_ONLY)
# Normals exclude all others
if PREF_USE_NORMAL:
uvmesh_apply_normals(render_me, face_list)
else:
if PREF_USE_IMAGE:
uvmesh_apply_image(render_me, face_list)
uvmesh_apply_vcol(render_me, face_list)
elif PREF_USE_VCOL:
uvmesh_apply_vcol(render_me, face_list)
elif PREF_USE_MATCOL:
uvmesh_apply_matcol(render_me, material_list)
elif PREF_USE_TEXTURE:
# if we have more then 16 materials across all the mesh objects were stuffed :/
# get unique materials
tex_unique_materials= dict([(mat.name, mat) for mat in material_list]).values()[:16] # just incase we have more then 16
tex_me= Blender.Mesh.New()
# Backup the original shadless setting
tex_unique_materials_shadeless= [ mat.mode & Blender.Material.Modes.SHADELESS for mat in tex_unique_materials ]
# Turn shadeless on
for mat in tex_unique_materials:
mat.mode |= Blender.Material.Modes.SHADELESS
# Assign materials
render_me.materials= tex_unique_materials
tex_material_indicies= dict([(mat.name, i) for i, mat in enumerate(tex_unique_materials)])
tex_me.verts.extend([Vector(0,0,0),]) # dummy
tex_me.verts.extend( [ Vector(v.co) for f in face_list for v in f ] )
# Now add the faces
tmp_faces= []
vert_offset= 1
for f in face_list:
tmp_faces.append( [ii+vert_offset for ii in xrange(len(f))] )
vert_offset+= len(f)
tex_me.faces.extend(tmp_faces)
# Now we have the faces, put materials and normal, uvs into the mesh
if len(tex_me.faces) != len(face_list):
# Should never happen
raise "Error face length mismatch"
# Copy data to the mesh that could be used as texture coords
for i, tex_face in enumerate(tex_me.faces):
orig_face= face_list[i]
# Set the material index
try:
render_face.mat= tex_material_indicies[ material_list[i].name ]
except:
# more then 16 materials
pass
# set the uvs on the texmesh mesh
tex_face.uv= orig_face.uv
orig_face_v= orig_face.v
# Set the normals
for j, v in enumerate(tex_face):
v.no= orig_face_v[j].no
# Set the texmesh
render_me.texMesh= tex_me
# END TEXMESH
# Handel adding objects
render_ob= Blender.Object.New('Mesh')
render_ob.link(render_me)
if not PREF_USE_TEXTURE: # textures use the original materials
render_me.materials= [rnd_mat()]
obs= [render_ob]
if PREF_IMAGE_WIRE_UNDERLAY:
# Make another mesh with the material colors
render_me_under, face_list, material_list= mesh2uv(me_s, PREF_SEL_FACES_ONLY)
uvmesh_apply_matcol(render_me_under, material_list)
# Handel adding objects
render_ob= Blender.Object.New('Mesh')
render_ob.link(render_me_under)
render_ob.LocZ= -0.01
# Add material and disable wire
mat= rnd_mat()
mat.rgbCol= 1,1,1
mat.alpha= 0.5
mat.mode &= ~Blender.Material.Modes.WIRE
mat.mode |= Blender.Material.Modes.VCOL_PAINT
render_me_under.materials= [mat]
obs.append(render_ob)
elif PREF_IMAGE_BLEED and not PREF_IMAGE_WIRE:
# EVIL BLEEDING CODE!! - Just do copys of the mesh and place behind. Crufty but better then many other methods I have seen. - Cam
BLEED_PIXEL= 1.0/PREF_IMAGE_SIZE
z_offset= 0.0
for i in xrange(PREF_IMAGE_BLEED):
for diag1, diag2 in ((-1,-1),(-1,1),(1,-1),(1,1), (1,0), (0,1), (-1,0), (0, -1)): # This line extends the object in 8 different directions, top avoid bleeding.
render_ob= Blender.Object.New('Mesh')
render_ob.link(render_me)
render_ob.LocX= (i+1)*diag1*BLEED_PIXEL
render_ob.LocY= (i+1)*diag2*BLEED_PIXEL
render_ob.LocZ= -z_offset
obs.append(render_ob)
z_offset += 0.01
image= imageFromObjectsOrtho(obs, PREF_IMAGE_PATH, PREF_IMAGE_SIZE, PREF_IMAGE_SIZE, PREF_IMAGE_SMOOTH)
# Clear from memory as best as we can
render_me.verts= None
if PREF_IMAGE_WIRE_UNDERLAY:
render_me_under.verts= None
if PREF_USE_TEXTURE:
tex_me.verts= None
# Restire Shadeless setting
for i, mat in enumerate(tex_unique_materials):
# we know there all on so turn it off of its not set
if not tex_unique_materials_shadeless[i]:
mat.mode &= ~Blender.Material.Modes.SHADELESS
return image
def bakeToPlane(sce, ob_from, width, height, bakemodes, axis='z', margin=0, depth=32):
'''
Bakes terrain onto a plane from one object
sce - scene to bake with
ob_from - mesh object
width/height - image size
bakemodes - list of baking modes to use, Blender.Scene.Render.BakeModes.NORMALS, Blender.Scene.Render.BakeModes.AO ... etc
axis - axis to allign the plane to.
margin - margin setting for baking.
depth - bit depth for the images to bake into, (32 or 128 for floating point images)
Example:
import Blender
from Blender import *
import BPyRender
sce = Scene.GetCurrent()
ob = Object.Get('Plane')
BPyRender.bakeToPlane(sce, ob, 512, 512, [Scene.Render.BakeModes.DISPLACEMENT, Scene.Render.BakeModes.NORMALS], 'z', 8 )
'''
# Backup bake settings
rend = sce.render
BACKUP_bakeDist = rend.bakeDist
BACKUP_bakeBias = rend.bakeBias
BACKUP_bakeMode = rend.bakeMode
BACKUP_bakeClear = rend.bakeClear
BACKUP_bakeMargin = rend.bakeMargin
BACKUP_bakeToActive = rend.bakeToActive
BACKUP_bakeNormalize = rend.bakeNormalize
# Backup object selection
BACKUP_obsel = list(sce.objects.selected)
BACKUP_obact = sce.objects.active
# New bake settings
rend.bakeClear = True
rend.bakeMargin = margin
rend.bakeToActive = True
rend.bakeNormalize = True
# Assume a mesh
me_from = ob_from.getData(mesh=1)
xmin = ymin = zmin = 10000000000
xmax = ymax = zmax =-10000000000
# Dont trust bounding boxes :/
#bounds = ob_from.boundingBox
#for v in bounds:
# x,y,z = tuple(v)
mtx = ob_from.matrixWorld
for v in me_from.verts:
x,y,z = tuple(v.co*mtx)
xmax = max(xmax, x)
ymax = max(ymax, y)
zmax = max(zmax, z)
xmin = min(xmin, x)
ymin = min(ymin, y)
zmin = min(zmin, z)
if axis=='x':
xmed = (xmin+xmax)/2.0
co1 = (xmed, ymin, zmin)
co2 = (xmed, ymin, zmax)
co3 = (xmed, ymax, zmax)
co4 = (xmed, ymax, zmin)
rend.bakeDist = ((xmax-xmin)/2.0) + 0.000001 # we need a euler value for this since it
elif axis=='y':
ymed = (ymin+ymax)/2.0
co1 = (xmin, ymed, zmin)
co2 = (xmin, ymed, zmax)
co3 = (xmax, ymed, zmax)
co4 = (xmax, ymed, zmin)
rend.bakeDist = ((ymax-ymin)/2.0) + 0.000001
elif axis=='z':
zmed = (zmin+zmax)/2.0
co1 = (xmin, ymin, zmed)
co2 = (xmin, ymax, zmed)
co3 = (xmax, ymax, zmed)
co4 = (xmax, ymin, zmed)
rend.bakeDist = ((zmax-zmin)/2.0) + 0.000001
else:
raise "invalid axis"
me_plane = Blender.Mesh.New()
ob_plane = Blender.Object.New('Mesh')
ob_plane.link(me_plane)
sce.objects.link(ob_plane)
ob_plane.Layers = ob_from.Layers
ob_from.sel = 1 # make active
sce.objects.active = ob_plane
ob_plane.sel = 1
me_plane.verts.extend([co4, co3, co2, co1])
me_plane.faces.extend([(0,1,2,3)])
me_plane.faceUV = True
me_plane_face = me_plane.faces[0]
uvs = me_plane_face.uv
uvs[0].x = 0.0; uvs[0].y = 0.0
uvs[1].x = 0.0; uvs[1].y = 1.0
uvs[2].x = 1.0; uvs[2].y = 1.0
uvs[3].x = 1.0; uvs[3].y = 0.0
images_return = []
for mode in bakemodes:
img = Blender.Image.New('bake', width, height, depth)
me_plane_face.image = img
rend.bakeMode = mode
rend.bake()
images_return.append( img )
# Restore bake settings
#'''
rend.bakeDist = BACKUP_bakeDist
rend.bakeBias = BACKUP_bakeBias
rend.bakeMode = BACKUP_bakeMode
rend.bakeClear = BACKUP_bakeClear
rend.bakeMargin = BACKUP_bakeMargin
rend.bakeToActive = BACKUP_bakeToActive
rend.bakeNormalize = BACKUP_bakeNormalize
# Restore obsel
sce.objects.selected = BACKUP_obsel
sce.objects.active = BACKUP_obact
me_plane.verts = None
sce.objects.unlink(ob_plane)
#'''
return images_return
|