Hi, everyone.

Here's my "version 1.0" Pixelation script. Also attached are two images showing the basic functionality.

Of course, Suzanne isn't the best example - cambo mentioned that it is not a closed mesh because the eyes are non manifold. But the script mostly works for Suzanne. For any fully closed mesh, however, it should work without any errors.

The GUI allows you to choose the "brick" sizing in all three axes, to choose the destination layer for the bricks, and whether or not you want the original object removed.

Note that it can be quite slow. I received a few suggestions from cambo for speed ups that I'll look into next.

Some of the key parts of this code are from cambo, with minor/tiny modifications.

BEFORE:

AFTER:

Code:#!BPY """ Name: 'Pixelate' Blender: 241 Group: 'Mesh' Tooltip: '3D Pixelation of Meshes' """ __author__ = "David Levine" __url__ = ("blender", "elysiun") __version__ = "1.0 02/24/06" __bpydoc__ = """\ This script takes closed meshes and 'pixelates' them in 3D. Usage: Select the mesh and run this script. You can specify the size of the blocks used. You can specify the destination layer for those blocks. You can also specify that the original object is removed. Upon hitting the PIXELATE button, a 'blocky' version of your original mesh will be created. Thanks to: cambo, RipSting, JM Soler """ from Blender import * from Blender.BGL import * from Blender.Draw import * from Blender.Noise import * def ptInFaceXYBounds(f, pt): co= f.v[0].co xmax= xmin= co.x ymax= ymin= co.y co= f.v[1].co xmax= max(xmax, co.x) xmin= min(xmin, co.x) ymax= max(ymax, co.y) ymin= min(ymin, co.y) co= f.v[2].co xmax= max(xmax, co.x) xmin= min(xmin, co.x) ymax= max(ymax, co.y) ymin= min(ymin, co.y) if len(f.v)==4: co= f.v[3].co xmax= max(xmax, co.x) xmin= min(xmin, co.x) ymax= max(ymax, co.y) ymin= min(ymin, co.y) # Now we have the bounds, see if the point is in it. if\ pt.x < xmin or\ pt.y < ymin or\ pt.x > xmax or\ pt.y > ymax: return False # point is outside face bounds else: return True # point inside. def pointInsideMesh(ob, pt): obMat = Mathutils.Matrix(ob.matrixWorld) obInvMat = obMat.invert() obSpaceVec = pt* obInvMat obSpacePt = Mathutils.Vector(obSpaceVec[0], obSpaceVec[1], obSpaceVec[2]) Intersect = Mathutils.Intersect # 2 less dict lookups. Vector = Mathutils.Vector ray = Vector(0,0,-1) def faceIntersect(f): isect= Intersect(f.v[0].co, f.v[1].co, f.v[2].co, ray, obSpacePt, 1) # Clipped. if not isect and len(f.v) == 4: isect= Intersect(f.v[0].co, f.v[2].co, f.v[3].co, ray, obSpacePt, 1) # Clipped. if isect and isect.z > obSpacePt.z: # This is so the ray only counts if its above the point. return True else: return False me= ob.getData(mesh=1) # Here we find the number on intersecting faces, return true if an odd number (inside), false (outside) if its true. return len([None for f in me.faces if ptInFaceXYBounds(f, obSpacePt) if faceIntersect(f)]) % 2 def findminmaxxyz(obj): minx= 999999999 maxx= -999999999 miny= 999999999 maxy= -999999999 minz= 999999999 maxz= -999999999 boundBox= obj.getBoundBox() for v in boundBox: minx= min(minx, v.x) maxx= max(maxx, v.x) miny= min(miny, v.y) maxy= max(maxy, v.y) minz= min(minz, v.z) maxz= max(maxz, v.z) minV= Mathutils.Vector(minx,miny,minz) maxV= Mathutils.Vector(maxx,maxy,maxz) return [minV,maxV] def makeblock(name='blockModel',mat=None,min=[-1.0,-1.0,-1.0],max=[1.0,1.0,1.0]): vertices_list=[ [min[0],min[1],min[2]], [min[0],max[1],min[2]], [max[0],max[1],min[2]], [max[0],min[1],min[2]], [min[0],min[1],max[2]], [min[0],max[1],max[2]], [max[0],max[1],max[2]], [max[0],min[1],max[2]] ] faces_list=[ [0,1,2,3], [4,5,6,7], [0,4,7,3], [1,2,6,5], [0,1,5,4], [3,7,6,2] ] blockobj= Object.New('Mesh',name) Scene.getCurrent().link(blockobj) blockobj.layers = [NumberL.val] blockmesh= blockobj.getData() for v in vertices_list: vert= NMesh.Vert(v[0],v[1],v[2]) blockmesh.verts.append(vert) for f in faces_list: meshface= NMesh.Face() for vv in f: meshface.append(blockmesh.verts[vv]) blockmesh.faces.append(meshface) if mat: blockmesh.addMaterial(mat) blockmesh.update() return blockobj def faceCent(f): x= y= z= 0 for v in f.v: x+= v.co[0] y+= v.co[1] z+= v.co[2] return Mathutils.Vector([x/len(f.v), y/len(f.v), z/len(f.v)]) def nearestFace(ob, pt): obMat= Mathutils.Matrix(ob.matrixWorld) obInvMat= obMat.invert() obSpaceVec= pt* obInvMat obSpacePt= Mathutils.Vector(obSpaceVec[0], obSpaceVec[1], obSpaceVec[2]) mesh= ob.getData() closedist= 999999999 for f in mesh.faces: fc = faceCent(f) dist = obSpacePt - fc if (dist.length < closedist): closedist = dist.length closeface = f return closeface def pix(): editmode= Window.EditMode() if editmode: Window.EditMode(0) Window.WaitCursor(1) Window.DrawProgressBar(0.0, '') count= 1 spacingx= NumberX.val spacingy= NumberY.val spacingz= NumberZ.val objectList= Object.GetSelected() for obj in objectList: if obj.getType() == 'Mesh': minmax= findminmaxxyz(obj) x= minmax[0].x while x < (minmax[1].x - (spacingx/4.0)): progress= (x - minmax[0].x) / (minmax[1].x - minmax[0].x) Window.DrawProgressBar(progress, "Pixelating...") y= minmax[0].y while y < (minmax[1].y - (spacingy/4.0)): z= minmax[0].z while z < (minmax[1].z - (spacingz/4.0)): posvec= Mathutils.Vector([x + (spacingx/2.0),y + (spacingy/2.0),z + (spacingz/2.0), 1.0]) if pointInsideMesh(obj, posvec): nearFaceMaterial= nearestFace(obj, posvec).materialIndex if len(obj.getData().getMaterials()) > 1: nextblock= makeblock('block' + str(count),obj.getData().getMaterials()[nearFaceMaterial],Mathutils.Vector([x,y,z]),Mathutils.Vector([x + spacingx,y + spacingy,z + spacingz])) else: nextblock= makeblock('block' + str(count),None,Mathutils.Vector([x,y,z]),Mathutils.Vector([x + spacingx,y + spacingy,z + spacingz])) count= count + 1 z= z + spacingz y= y + spacingy x= x + spacingx if Replace.val == 1: Scene.getCurrent().unlink(obj) Window.DrawProgressBar(1.0, '') Window.WaitCursor(0) if editmode: Window.EditMode(1) Window.RedrawAll() Replace= Create(0) NumberZ= Create(0.20) NumberY= Create(0.20) NumberX= Create(0.20) NumberL= Create(1) EVENT_NOEVENT = 1 EVENT_PIXELATE = 2 def draw(): global Button, Replace, NumberZ, NumberY, NumberX, NumberL global EVENT_NOEVENT, EVENT_PIXELATE glClearColor(0.753, 0.753, 0.753, 0.0) glClear(GL_COLOR_BUFFER_BIT) glColor3f(0.000, 0.000, 0.000) glRasterPos2i(108, 54) Text('Select this toggle to completely replace the original mesh.') glRasterPos2i(108, 86) Text('Z Spacing (0.05 to 10.00)') glRasterPos2i(108, 118) Text('Y Spacing (0.05 to 10.00)') glRasterPos2i(108, 150) Text('X Spacing (0.05 to 10.00)') glRasterPos2i(108, 182) Text('Layer for New Pixels (1 to 20)') Button('Pixelate!', EVENT_PIXELATE, 16, 10, 83, 23, '') Replace= Toggle('Replace', EVENT_NOEVENT, 16, 42, 83, 23, Replace.val, '') NumberZ= Number('', EVENT_NOEVENT, 16, 74, 83, 23, NumberZ.val, 0.05, 10.05, '') NumberY= Number('', EVENT_NOEVENT, 16, 106, 83, 23, NumberY.val, 0.05, 10.05, '') NumberX= Number('', EVENT_NOEVENT, 16, 138, 83, 23, NumberX.val, 0.05, 10.05, '') NumberL= Number('', EVENT_NOEVENT, 16, 170, 83, 23, NumberL.val, 1, 20, '') def event(evt, val): if (evt == QKEY and not val): Exit() def bevent(evt): if evt == EVENT_PIXELATE: pix() Redraw() Register(draw, event, bevent)

## Bookmarks