forked from bartvdbraak/blender
6b65e39a44
- switching the define on in buildsystems (NaN, auto and msvc are done) - again import _Blender, which is the C module, from the Python modules
251 lines
6.8 KiB
Python
251 lines
6.8 KiB
Python
"""The Blender Mesh module
|
|
|
|
This module provides routines for more extensive mesh manipulation.
|
|
Later, this Mesh type will also allow interactive access (like in
|
|
EditMode).
|
|
In the Publisher, Ngons will also be supported (and converted to
|
|
triangles on mesh.update(). The following code demonstrates
|
|
creation of an Ngon.
|
|
|
|
Example::
|
|
|
|
from Blender import Mesh, Object, Scene
|
|
|
|
m = Mesh.New() # new empty mesh
|
|
vlist = []
|
|
vlist.append(m.addVert((-0.0, -1.0, 0.0)))
|
|
vlist.append(m.addVert((1.0, 0.0, 0.0)))
|
|
vlist.append(m.addVert((1.0, 1.0, 0.0)))
|
|
vlist.append(m.addVert((0.0, 3.0, 0.0)))
|
|
vlist.append(m.addVert((-1.0, 2.0, 0.0)))
|
|
vlist.append(m.addVert((-3.0, 1.0, 0.0)))
|
|
vlist.append(m.addVert((-3.0, 3.0, 0.0)))
|
|
vlist.append(m.addVert((-4.0, 3.0, 0.0)))
|
|
vlist.append(m.addVert((-4.0, 0.0, 0.0)))
|
|
|
|
f = m.addFace(vlist)
|
|
|
|
# do some calculations: top project vertex coordinates to
|
|
# UV coordinates and normalize them to the square [0.0, 1.0]*[0.0, 1.0]
|
|
|
|
uvlist = map(lambda x: (x.co[0], x.co[1]), vlist)
|
|
maxx = max(map(lambda x: x[0], uvlist))
|
|
maxy = max(map(lambda x: x[1], uvlist))
|
|
minx = min(map(lambda x: x[0], uvlist))
|
|
miny = min(map(lambda x: x[1], uvlist))
|
|
|
|
len = max((maxx - minx), (maxy - miny))
|
|
offx = -minx / len
|
|
offy = -miny / len
|
|
|
|
f.uv = map(lambda x: (x[0]/len + offx, x[1]/len + offy), uvlist) # assign UV coordinates by 'top' projection
|
|
|
|
m.update() # update and triangulate mesh
|
|
|
|
ob = Object.New('Mesh') # create new Object
|
|
ob.link(m) # link mesh data
|
|
sc = Scene.getCurrent() # get current Scene
|
|
sc.link(ob) # link Object to scene
|
|
"""
|
|
|
|
from Blender.Types import NMFaceType
|
|
import Blender.Material as Material
|
|
|
|
from _Blender import NMesh as _NMesh
|
|
|
|
FACEFLAGS = _NMesh.Const
|
|
DEFAULTFLAGS = FACEFLAGS.LIGHT + FACEFLAGS.DYNAMIC
|
|
|
|
import shadow
|
|
|
|
def makeFace(f):
|
|
face = _NMesh.Face()
|
|
for v in f:
|
|
face.v.append(v)
|
|
face.uv.append((v.uvco[0], v.uvco[1]))
|
|
return face
|
|
|
|
def toTriangles(ngon):
|
|
from utils import tesselation
|
|
# This should be a Publisher only feature...once the tesselation
|
|
# is improved. The GLU tesselator of Mesa < 4.0 is crappy...
|
|
if len(ngon.uv) == len(ngon.v):
|
|
i = 0
|
|
for v in ngon.v:
|
|
v.uvco = ngon.uv[i]
|
|
i += 1
|
|
|
|
return tesselation.NgonAsTriangles(ngon, makeFace) # return triangles
|
|
|
|
def Color(r, g, b, a = 1.0):
|
|
return _NMesh.Col(255 * r, 255 * g, 255 * b, 255 * a)
|
|
|
|
class Vert: #shadow NMVert class for the tesselator
|
|
"""Vertex wrapper class
|
|
This class emulates a float coordinate vector triple
|
|
"""
|
|
def __init__(self):
|
|
self.vert = None
|
|
self.uv = []
|
|
def __len__(self):
|
|
return 3
|
|
def __setitem__(self, i, val):
|
|
self.vert[i] = val
|
|
def __getitem__(self, i):
|
|
return self.vert.co[i]
|
|
|
|
class Face:
|
|
"""Face wrapper class
|
|
This class emulates a list of vertex references
|
|
"""
|
|
def __init__(self, vlist):
|
|
self.v= vlist
|
|
self.uv = []
|
|
|
|
def __len__(self):
|
|
return len(self.v)
|
|
|
|
def __setitem__(self, i, val):
|
|
self.v[i] = val
|
|
|
|
def __getitem__(self, i):
|
|
return self.v[i]
|
|
|
|
# override:
|
|
|
|
Vert = _NMesh.Vert
|
|
Face = _NMesh.Face
|
|
|
|
class rawMesh:
|
|
"""Wrapper for raw Mesh data"""
|
|
def __init__(self, object = None):
|
|
if object:
|
|
self._object = object
|
|
else:
|
|
self._object = _NMesh.GetRaw()
|
|
|
|
self.flags = DEFAULTFLAGS
|
|
self.smooth = 0
|
|
self.recalc_normals = 1
|
|
self.faces = self._object.faces[:]
|
|
|
|
def __getattr__(self, name):
|
|
if name == 'vertices':
|
|
return self._object.verts
|
|
elif name == 'has_col':
|
|
return self._object.hasVertexColours()
|
|
elif name == 'has_uv':
|
|
return self._object.hasFaceUV()
|
|
else:
|
|
return getattr(self._object, name)
|
|
|
|
def __repr__(self):
|
|
return "Mesh: %d faces, %d vertices" % (len(self.faces), len(self.verts))
|
|
|
|
def hasFaceUV(self, true = None):
|
|
"""Sets the per-face UV texture flag, if 'true' specified (either
|
|
0 or 1). Returns the texture flag in any case."""
|
|
if true == None:
|
|
return self._object.hasFaceUV()
|
|
return self._object.hasFaceUV(true)
|
|
|
|
def hasVertexUV(self, true = None):
|
|
"""Sets the per-vertex UV texture flag, if 'true' specified (either
|
|
0 or 1). Returns the texture flag in any case."""
|
|
if true == None:
|
|
return self._object.hasVertexUV()
|
|
return self._object.hasVertexUV(true)
|
|
|
|
def hasVertexColours(self, true = None):
|
|
"""Sets the per-face UV texture flag, if 'true' specified (either
|
|
0 or 1). Returns the texture flag in any case."""
|
|
if true == None:
|
|
return self._object.hasVertexColours()
|
|
return self._object.hasVertexColours(true)
|
|
|
|
def addVert(self, v):
|
|
"""Adds a vertex to the mesh and returns a reference to it. 'v' can
|
|
be a float triple or any data type emulating a sequence, containing the
|
|
coordinates of the vertex. Note that the returned value references an
|
|
*owned* vertex"""
|
|
vert = _NMesh.Vert(v[0], v[1], v[2])
|
|
self._object.verts.append(vert)
|
|
return vert
|
|
|
|
def addFace(self, vlist, flags = None, makedefaultUV = 0):
|
|
"""Adds a face to the mesh and returns a reference to it. 'vlist'
|
|
must be a list of vertex references returned by addVert().
|
|
Note that the returned value references an *owned* face"""
|
|
if type(vlist) == NMFaceType:
|
|
face = vlist
|
|
else:
|
|
n = len(vlist)
|
|
face = _NMesh.Face(vlist)
|
|
if makedefaultUV:
|
|
face.uv = defaultUV[:n]
|
|
|
|
self.faces.append(face)
|
|
# turn on default flags:
|
|
if not flags:
|
|
face.mode = self.flags
|
|
else:
|
|
face.mode = flags
|
|
return face
|
|
|
|
def update(self):
|
|
"""Updates the mesh datablock in Blender"""
|
|
o = self._object
|
|
o = self._object
|
|
o.faces = []
|
|
smooth = self.smooth
|
|
for f in self.faces:
|
|
if len(f) > 4: #it's a NGON
|
|
faces = toTriangles(f)
|
|
for nf in faces:
|
|
nf.smooth = smooth
|
|
o.faces.append(nf)
|
|
else:
|
|
o.faces.append(f)
|
|
o.update()
|
|
|
|
def link(self, material):
|
|
"""Link material 'material' with the mesh. Note that a mesh can
|
|
currently have up to 16 materials, which are referenced by
|
|
Face().materialIndex"""
|
|
mats = self._object.materials
|
|
if material in mats:
|
|
print "material already assigned to mesh"
|
|
return
|
|
mats.append(material._object)
|
|
|
|
def unlink(self, material):
|
|
"""Unlink (remove) material 'material' from the mesh. Note
|
|
that the material indices per face need to be updated."""
|
|
self._object.materials.remove(material._object)
|
|
|
|
def setMaterials(self, materials = []):
|
|
"""Sets materials. 'materials' must be a list of valid material objects
|
|
Note that a mesh can currently have up to 16 materials, which are referenced
|
|
by Face().materialIndex"""
|
|
|
|
self._object.materials = (map(lambda x: x._object, materials))
|
|
|
|
def getMaterials(self, materials = []):
|
|
"""Returns materials assigned to the mesh"""
|
|
return shadow._List(self._object.materials, Material.Material)
|
|
|
|
def New():
|
|
return rawMesh()
|
|
|
|
def get(name = None):
|
|
"""If 'name' given, the Mesh 'name' is returned if existing, 'None' otherwise."""
|
|
if name:
|
|
ob = _NMesh.GetRaw(name)
|
|
if ob:
|
|
return rawMesh(ob)
|
|
else:
|
|
return None
|
|
else:
|
|
raise SystemError, "get() for Meshes is not yet supported"
|
|
|