import bpy
import bmesh
import math
# this assumes you have the vertexAccumulator.py source in a text buffer named "vertexAccumulator.py"
bufferName = 'vertexAccumulator.py'
lib1 = bpy.data.texts[bufferName].as_string()
exec(lib1)
class Voxels:
def __init__(self):
self.dict = {}
def set(self, x, y, z, val):
key = self.key_for(x, y, z)
self.dict[key] = val
@staticmethod
def key_for(x, y, z):
return "%d,%d,%d" % (x, y, z)
def get(self, x, y, z):
key = self.key_for(x, y, z)
return self.dict.get(key)
#
#
def image_for_stuff(name, c1, c2):
"""
:param c1: an rgba tuple
:param c2: the other rgba tuple
:return: a blender image
"""
if (len(c1)!=4):
raise "c1 is not RGBA tuple"
if (len(c2)!=4):
raise "c2 is not RGBA tuple"
i1 = bpy.data.images.get(name)
if i1 is not None:
return i1
else:
i1 = bpy.data.images.new(name, 64, 64)
for u in range(64):
for v in range(64):
x = abs(((u/63)-0.5)*2)
y = abs(((v/63)-0.5)*2)
q = x*x*x + y*y*y
#print(q)
offset = 4*(u+v*64)
if 0.8 > q > 0.4:
i1.pixels[offset:offset+4] = c1
else:
i1.pixels[offset:offset+4] = c2
#print(pixels)
# if we don't pack the image, it will be missing the next time you load the .blend file.
i1.pack(True)
return i1
def material_for_something(name, c1=(1, 0, 0, 1), c2=(1, 0.5, 0.5, 1)):
mat = bpy.data.materials.get(name)
if mat is not None:
return mat
else:
mat = bpy.data.materials.new(name)
mat.texture_slots.add()
# create a texture for the image
t1 = bpy.data.textures.new("stripe", 'IMAGE')
t1.image = image_for_stuff(name, c1, c2)
# give it sharp uninterpolated edges.
t1.use_interpolation = False
t1.filter_type = 'BOX'
mat.texture_slots[0].texture = t1
mat.texture_slots[0].texture_coords = 'UV'
mat.texture_slots[0].uv_layer = 'uv'
#mat.texture_slots[0].use_map_alpha = True
mat.emit = 0.2
mat.diffuse_intensity = 0.9-mat.emit
mat.preview_render_type='CUBE'
return mat
def material_for_alpha():
return material_for_something("layer alpha")
def material_for_beta():
return material_for_something("layer beta", (0, 0.7, 0, 1), (0.5, 1, 0.5, 1))
def material_for_gamma():
rval = material_for_something("layer gamma", (0, 0, 0.7, 1), (0.5, 0.5, 1, 1))
rval.use_transparency = False
rval.alpha = 0.2
return rval
def material_for_delta():
rval = material_for_something("layer delta", (0.5, 0.5, 0, 1), (1, 1, 0.5, 1))
return rval
#
#
def add_for_cell(x, y, z, va, grid, faces):
code = grid.get(x, y, z)
if code is None:
return
if code==1:
if math.ceil(z/2) % 2 == 0:
material_index = 0
else:
material_index = 1
else:
material_index = code
z2 = (z + 0.5)/2
z1 = (z - 0.5)/2
if grid.get(x-1, y, z) is None:
i1 = va.idxFor((x-0.5, y-0.5, z2))
i2 = va.idxFor((x-0.5, y+0.5, z2))
i3 = va.idxFor((x-0.5, y+0.5, z1))
i4 = va.idxFor((x-0.5, y-0.5, z1))
faces.append( { "vi": [i1,i2,i3,i4], "mi":material_index })
if grid.get(x+1, y, z) is None:
i1 = va.idxFor((x+0.5, y+0.5, z1))
i2 = va.idxFor((x+0.5, y+0.5, z2))
i3 = va.idxFor((x+0.5, y-0.5, z2))
i4 = va.idxFor((x+0.5, y-0.5, z1))
faces.append( { "vi": [i1,i2,i3,i4], "mi":material_index} )
if grid.get(x,y-1,z) is None:
i1 = va.idxFor((x+0.5, y-0.5, z1))
i2 = va.idxFor((x+0.5, y-0.5, z2))
i3 = va.idxFor((x-0.5, y-0.5, z2))
i4 = va.idxFor((x-0.5, y-0.5, z1))
faces.append( { "vi": [i4,i3,i2,i1], "mi":material_index} )
if grid.get(x,y+1,z) is None:
i1 = va.idxFor((x+0.5, y+0.5, z1))
i2 = va.idxFor((x+0.5, y+0.5, z2))
i3 = va.idxFor((x-0.5, y+0.5, z2))
i4 = va.idxFor((x-0.5, y+0.5, z1))
faces.append( { "vi": [i1,i2,i3,i4], "mi":material_index} )
if grid.get(x, y, z+1) is None:
i1 = va.idxFor((x+0.5, y-0.5, z2) )
i2 = va.idxFor((x+0.5, y+0.5, z2) )
i3 = va.idxFor((x-0.5, y+0.5, z2) )
i4 = va.idxFor((x-0.5, y-0.5, z2) )
faces.append( { "vi": [i1,i2,i3,i4], "mi":material_index} )
if (grid.get(x, y, z-1) is None):
i1 = va.idxFor((x+0.5, y-0.5, z1) )
i2 = va.idxFor((x+0.5, y+0.5, z1) )
i3 = va.idxFor((x-0.5, y+0.5, z1) )
i4 = va.idxFor((x-0.5, y-0.5, z1) )
faces.append( { "vi": [i4,i3,i2,i1], "mi":material_index} )
def guess_uvs_z(face, uvl, axis1, axis2):
x0 = face.verts[0].co[axis1]
y0 = face.verts[0].co[axis2]
for v in face.verts:
x0 = min(x0, v.co[axis1])
y0 = min(y0, v.co[axis2])
x0 = math.floor(x0-0.5)+0.5
if (axis2==2):
y0 = math.floor(y0-0.25)+0.25
else:
y0 = math.floor(y0-0.5)+0.5
for i in range(len(face.verts)):
face.loops[i][uvl].uv = ( face.verts[i].co[axis1] - x0 ,
face.verts[i].co[axis2] - y0)
def guess_uvs(face, uvl):
va = face.verts[0].co - face.verts[1].co
vb = face.verts[2].co - face.verts[1].co
cross = va.cross(vb)
if (abs(cross[2]) > abs(cross[1])):
if (abs(cross[2]) > abs(cross[0])):
guess_uvs_z(face, uvl, 0, 1)
else:
guess_uvs_z(face, uvl, 1, 2)
elif (abs(cross[1]) > abs(cross[0])):
guess_uvs_z(face, uvl, 0, 2)
else:
guess_uvs_z(face, uvl, 1, 2)
def adjacent_z2(radius, x2, y2):
zsq = radius*radius - x2*x2 - y2*y2
if (zsq<0):
return 0
return math.sqrt(zsq)
def adjacent_z(radius, x,y):
if (x<0):
z1 = adjacent_z2(radius, x-1, y)
else:
z1 = adjacent_z2(radius, x+1, y)
if (y<0):
z2 = adjacent_z2(radius, x, y-1)
else:
z2 = adjacent_z2(radius, x, y+1)
return min(z1, z2)
def sphere_minecraft_mesh(name, radius):
verts =[]
faces = []
va = VertexAccumulator()
over = math.ceil(radius)
grid = Voxels()
for x in range (-over, over+1):
for y in range(x, over+1):
zsq = radius * radius - x * x - y * y
if (zsq<0):
continue
z = math.sqrt(zsq)
z2 = math.ceil(z*2)
mi2 = 1
if (x%5==0 and y%5==0):
mi2 = 3
grid.set(x,y,-z2, 1)
grid.set(x,y,-z2+1, mi2)
z3 = math.ceil( 2* adjacent_z(radius, x,y))
for i in range(-z2+2, -z3):
grid.set(x,y,i, 2)
for x in range(-over, over+1):
for y in range(-over, over+1):
for z in range(-2*over, 1):
add_for_cell(x,y,z, va, grid, faces)
verts = va.verts()
mesh = bpy.data.meshes.new(name)
mesh.from_pydata(verts, [], [ f["vi"] for f in faces])
#
for i in range(len(faces)):
mesh.polygons[i].material_index = faces[i]["mi"]
mesh.materials.append(material_for_alpha())
mesh.materials.append(material_for_beta())
mesh.materials.append(material_for_gamma())
mesh.materials.append(material_for_delta())
#
mesh.uv_textures.new("uv")
bm = bmesh.new()
bm.from_mesh(mesh)
bm.faces.ensure_lookup_table()
uvl = bm.loops.layers.uv[0]
for fi in range(len(bm.faces)):
for i in range(len(bm.faces[fi].loops)):
guess_uvs(bm.faces[fi], uvl)
bm.to_mesh(mesh)
#
return mesh
def cliche(scn, name):
mesh = sphere_minecraft_mesh(name, 20.5)
obj = bpy.data.objects.new(name, mesh)
scn.objects.link(obj)
scn = bpy.context.scene
name = "sphere"
cliche(scn, name)
|
Blender python API quick-start
Syntax highlighting by Pygments.