Ejemplo n.º 1
0
def write(filename, objects):
    def veckey3d(v):
        return round(v.x, 6), round(v.y, 6), round(v.z, 6)

    def veckey2d(v):
        return round(v.x, 6), round(v.y, 6)

    print 'OBJ Export path: "%s"' % filename
    temp_mesh_name = '~tmp-mesh'

    time1 = sys.time()
    scn = Scene.GetCurrent()

    file = open(filename, "w")

    # Write Header
    file.write('# Blender3D v%s EOL Armature File: %s\n' %
               (Blender.Get('version'),
                Blender.Get('filename').split('/')[-1].split('\\')[-1]))
    file.write('# www.blender3d.org\n')

    # Get all armatures
    for ob_main in objects:
        for ob, ob_mat in BPyObject.getDerivedObjects(ob_main):
            write_armature(file, ob)
            write_poses(file, ob)

    file.close()

    print "Armature Export time: %.2f" % (sys.time() - time1)
def write(filename, objects):
	
	def veckey3d(v):
		return round(v.x, 6), round(v.y, 6), round(v.z, 6)
		
	def veckey2d(v):
		return round(v.x, 6), round(v.y, 6)
	
	print 'OBJ Export path: "%s"' % filename
	temp_mesh_name = '~tmp-mesh'

	time1 = sys.time()
	scn = Scene.GetCurrent()

	file = open(filename, "w")
	
	# Write Header
	file.write('# Blender3D v%s EOL Armature File: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1] ))
	file.write('# www.blender3d.org\n')
	
	# Get all armatures
	for ob_main in objects:
		for ob, ob_mat in BPyObject.getDerivedObjects(ob_main):
				write_armature(file,ob)
				write_poses(file,ob)
			
	file.close()
	
	print "Armature Export time: %.2f" % (sys.time() - time1)
Ejemplo n.º 3
0
def collect_edges(edges):
    """Gets the max-min coordinates of the mesh"""

    """Getting the extremes of the mesh to be exported"""

    maxX = maxY = maxZ = -1000000000
    minX = minY = minZ = 1000000000

    FGON = Blender.Mesh.EdgeFlags.FGON

    me = bpy.data.meshes.new()
    for ob_base in bpy.data.scenes.active.objects.context:
        for ob in BPyObject.getDerivedObjects(ob_base):
            me.verts = None
            try:
                me.getFromObject(ob[0])
            except:
                pass

            if me.edges:
                me.transform(ob[1])

                for ed in me.edges:
                    if not ed.flag & FGON:
                        x, y, z = v1 = tuple(ed.v1.co)
                        maxX = max(maxX, x)
                        maxY = max(maxY, y)
                        maxZ = max(maxZ, z)
                        minX = min(minX, x)
                        minY = min(minY, y)
                        minZ = min(minZ, z)

                        x, y, z = v2 = tuple(ed.v2.co)
                        maxX = max(maxX, x)
                        maxY = max(maxY, y)
                        maxZ = max(maxZ, z)
                        minX = min(minX, x)
                        minY = min(minY, y)
                        minZ = min(minZ, z)

                        edges.append((v1, v2))

    me.verts = None  # free memory
    return maxX, maxY, maxZ, minX, minY, minZ
Ejemplo n.º 4
0
def collect_edges(edges):
    """Gets the max-min coordinates of the mesh"""

    """Getting the extremes of the mesh to be exported"""

    maxX=maxY=maxZ = -1000000000
    minX=minY=minZ =  1000000000

    FGON= Blender.Mesh.EdgeFlags.FGON

    me = bpy.data.meshes.new()
    for ob_base in bpy.data.scenes.active.objects.context:
        for ob in BPyObject.getDerivedObjects(ob_base):
            me.verts = None
            try:    me.getFromObject(ob[0])
            except: pass

            if me.edges:
                me.transform(ob[1])

                for ed in me.edges:
                    if not ed.flag & FGON:
                        x,y,z = v1 = tuple(ed.v1.co)
                        maxX = max(maxX, x)
                        maxY = max(maxY, y)
                        maxZ = max(maxZ, z)
                        minX = min(minX, x)
                        minY = min(minY, y)
                        minZ = min(minZ, z)

                        x,y,z = v2 = tuple(ed.v2.co)
                        maxX = max(maxX, x)
                        maxY = max(maxY, y)
                        maxZ = max(maxZ, z)
                        minX = min(minX, x)
                        minY = min(minY, y)
                        minZ = min(minZ, z)

                        edges.append( (v1, v2) )

    me.verts = None # free memory
    return maxX,maxY,maxZ,minX,minY,minZ
Ejemplo n.º 5
0
def write(filename, objects,\
EXPORT_NORMALS_HQ=False,\
EXPORT_MTL=True,  EXPORT_COPY_IMAGES=False,\
EXPORT_APPLY_MODIFIERS=True, EXPORT_BLEN_OBS=True,\
EXPORT_GROUP_BY_OB=False):
    '''
    Basic write function. The context and options must be alredy set
    This can be accessed externaly
    eg.
    write( 'c:\\test\\foobar.obj', Blender.Object.GetSelected() ) # Using default options.
    '''
    def veckey3d(v):
        return round(v.x, 6), round(v.y, 6), round(v.z, 6)

    def veckey2d(v):
        return round(v.x, 6), round(v.y, 6)

    print 'WTF Export path: "%s"' % filename
    temp_mesh_name = '~tmp-mesh'

    time1 = sys.time()
    scn = Scene.GetCurrent()

    file = open(filename, "w")
    file.write('<?xml version="1.0"?>\n')
    file.write('<OPEN_TRACK>\n')

    # Write Header
    # file.write('\n<!--\n'
    #            + '  Blender3D v%s WTF File: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1] )
    #            + '  www.blender3d.org\n'
    #            + '-->\n\n')

    # Get the container mesh. - used for applying modifiers and non mesh objects.
    containerMesh = meshName = tempMesh = None
    for meshName in Blender.NMesh.GetNames():
        if meshName.startswith(temp_mesh_name):
            tempMesh = Mesh.Get(meshName)
            if not tempMesh.users:
                containerMesh = tempMesh
    if not containerMesh:
        containerMesh = Mesh.New(temp_mesh_name)

    del meshName
    del tempMesh

    # Initialize totals, these are updated each object
    totverts = totuvco = totno = 0

    face_vert_index = 0

    globalNormals = {}

    file.write('\n<library_objects>\n')
    # Get all meshs
    for ob_main in objects:
        obnamestring = fixName(ob_main.name)
        file.write('\t<object id="%s">\n' % obnamestring)  # Write Object name

        for ob, ob_mat in BPyObject.getDerivedObjects(ob_main):
            # Will work for non meshes now! :)
            # getMeshFromObject(ob, container_mesh=None, apply_modifiers=True, vgroups=True, scn=None)
            me = BPyMesh.getMeshFromObject(ob, containerMesh,
                                           EXPORT_APPLY_MODIFIERS, False, scn)
            if not me:
                file.write('\t\t<loc>%.6f %.6f %.6f</loc>\n' %
                           tuple(ob_main.loc))  # Write Object name
                file.write('\t\t<rot>%.6f %.6f %.6f</rot>\n' %
                           tuple(ob_main.rot))  # Write Object name
                continue

            faceuv = me.faceUV

            # We have a valid mesh
            if me.faces:
                # Add a dummy object to it.
                has_quads = False
                for f in me.faces:
                    if len(f) == 4:
                        has_quads = True
                        break

                if has_quads:
                    oldmode = Mesh.Mode()
                    Mesh.Mode(Mesh.SelectModes['FACE'])

                    me.sel = True
                    tempob = scn.objects.new(me)
                    me.quadToTriangle(0)  # more=0 shortest length
                    oldmode = Mesh.Mode(oldmode)
                    scn.objects.unlink(tempob)

                    Mesh.Mode(oldmode)

            # Make our own list so it can be sorted to reduce context switching
            faces = [f for f in me.faces]
            edges = me.edges

            if not (len(faces) + len(edges) +
                    len(me.verts)):  # Make sure there is somthing to write
                continue  # dont bother with this mesh.

            me.transform(ob_mat)

            # High Quality Normals
            if faces:
                if EXPORT_NORMALS_HQ:
                    BPyMesh.meshCalcNormals(me)
                else:
                    # transforming normals is incorrect
                    # when the matrix is scaled,
                    # better to recalculate them
                    me.calcNormals()

            # # Crash Blender
            #materials = me.getMaterials(1) # 1 == will return None in the list.
            materials = me.materials

            materialNames = []
            materialItems = materials[:]
            if materials:
                for mat in materials:
                    if mat:  # !=None
                        materialNames.append(mat.name)
                    else:
                        materialNames.append(None)
                # Cant use LC because some materials are None.
                # materialNames = map(lambda mat: mat.name, materials) # Bug Blender, dosent account for null materials, still broken.

            # Possible there null materials, will mess up indicies
            # but at least it will export, wait until Blender gets fixed.
            materialNames.extend((16 - len(materialNames)) * [None])
            materialItems.extend((16 - len(materialItems)) * [None])

            # Sort by Material, then images
            # so we dont over context switch in the obj file.
            if faceuv:
                try:
                    faces.sort(key=lambda a: (a.mat, a.image, a.smooth))
                except:
                    faces.sort(lambda a, b: cmp((a.mat, a.image, a.smooth),
                                                (b.mat, b.image, b.smooth)))
            elif len(materials) > 1:
                try:
                    faces.sort(key=lambda a: (a.mat, a.smooth))
                except:
                    faces.sort(lambda a, b: cmp((a.mat, a.smooth),
                                                (b.mat, b.smooth)))
            else:
                # no materials
                try:
                    faces.sort(key=lambda a: a.smooth)
                except:
                    faces.sort(lambda a, b: cmp(a.smooth, b.smooth))

            # Set the default mat to no material and no image.
            contextMat = (
                0, 0
            )  # Can never be this, so we will label a new material teh first chance we get.
            contextSmooth = None  # Will either be true or false,  set bad to force initialization switch.

            if len(faces) > 0:
                file.write('\t\t<mesh>\n')
            else:
                file.write('\t\t<curve>\n')

            vertname = "%s-Vertices" % obnamestring
            vertarrayname = "%s-Array" % vertname
            normname = "%s-Normals" % obnamestring
            normarrayname = "%s-Array" % normname
            texname = "%s-TexCoord" % obnamestring
            texarrayname = "%s-Array" % texname

            # Vert
            file.write('\t\t\t<float_array count="%d" id="%s">' %
                       (len(me.verts), vertarrayname))
            for v in me.verts:
                file.write(' %.6f %.6f %.6f' % tuple(v.co))
            file.write('</float_array>\n')
            file.write('\t\t\t<vertices id="%s" source="#%s" />\n' %
                       (vertname, vertarrayname))

            # UV
            if faceuv:
                file.write('\t\t\t<float_array id="%s">' % texarrayname)
                uv_face_mapping = [[0, 0, 0, 0] for f in faces
                                   ]  # a bit of a waste for tri's :/

                uv_dict = {}  # could use a set() here
                for f_index, f in enumerate(faces):

                    for uv_index, uv in enumerate(f.uv):
                        uvkey = veckey2d(uv)
                        try:
                            uv_face_mapping[f_index][uv_index] = uv_dict[uvkey]
                        except:
                            uv_face_mapping[f_index][uv_index] = uv_dict[
                                uvkey] = len(uv_dict)
                            file.write(' %.6f %.6f' % tuple(uv))

                uv_unique_count = len(uv_dict)
                del uv, uvkey, uv_dict, f_index, uv_index
                # Only need uv_unique_count and uv_face_mapping
                file.write('</float_array>\n')
                file.write('\t\t\t<texcoords id="%s" source="#%s" />\n' %
                           (texname, texarrayname))

            # NORMAL, Smooth/Non smoothed.
            if len(faces) > 0:
                file.write('\t\t\t<float_array id="%s">' % normarrayname)
                for f in faces:
                    if f.smooth:
                        for v in f:
                            noKey = veckey3d(v.no)
                            if not globalNormals.has_key(noKey):
                                globalNormals[noKey] = totno
                                totno += 1
                                file.write(' %.6f %.6f %.6f' % noKey)
                    else:
                        # Hard, 1 normal from the face.
                        noKey = veckey3d(f.no)
                        if not globalNormals.has_key(noKey):
                            globalNormals[noKey] = totno
                            totno += 1
                            file.write(' %.6f %.6f %.6f' % noKey)
                file.write('</float_array>\n')
                file.write('\t\t\t<normals id="%s" source="#%s" />\n' %
                           (normname, normarrayname))

            if not faceuv:
                f_image = None
            in_triangles = False

            for f_index, f in enumerate(faces):
                f_v = f.v
                f_smooth = f.smooth
                f_mat = min(f.mat, len(materialNames) - 1)
                if faceuv:
                    f_image = f.image
                    f_uv = f.uv

                # MAKE KEY
                if faceuv and f_image:  # Object is always true.
                    key = materialNames[f_mat], f_image.name
                else:
                    key = materialNames[
                        f_mat], None  # No image, use None instead.

                # CHECK FOR CONTEXT SWITCH
                if key == contextMat:
                    pass  # Context alredy switched, dont do anythoing
                else:
                    if key[0] == None and key[1] == None:
                        # Write a null material, since we know the context has changed.
                        if in_triangles:
                            file.write('</p>\n')
                            file.write('\t\t\t</triangles>\n')
                        file.write('\t\t\t<triangles id="%s_%s">\n' %
                                   (fixName(ob.name), fixName(ob.getData(1))))
                        in_triangles = True
                    else:
                        mat_data = MTL_DICT.get(key)
                        if not mat_data:
                            # First add to global dict so we can export to mtl
                            # Then write mtl

                            # Make a new names from the mat and image name,
                            # converting any spaces to underscores with fixName.

                            # If none image dont bother adding it to the name
                            if key[1] == None:
                                mat_data = MTL_DICT[key] = ('%s' % fixName(
                                    key[0])), materialItems[f_mat], f_image
                            else:
                                mat_data = MTL_DICT[key] = (
                                    '%s_%s' %
                                    (fixName(key[0]), fixName(key[1]))
                                ), materialItems[f_mat], f_image
                        if in_triangles:
                            file.write('</p>\n')
                            file.write('\t\t\t</triangles>\n')
                        file.write(
                            '\t\t\t<triangles id="%s_%s_%s" material="#%s">\n'
                            % (fixName(ob.name), fixName(
                                ob.getData(1)), mat_data[0], mat_data[0]))
                        in_triangles = True

                    file.write(
                        '\t\t\t\t<input offset="0" semantic="VERTEX" source="#%s" />\n'
                        % vertname)
                    file.write(
                        '\t\t\t\t<input offset="1" semantic="NORMAL" source="#%s" />\n'
                        % normname)
                    if faceuv:
                        file.write(
                            '\t\t\t\t<input offset="2" semantic="TEXCOORD" source="#%s" />\n'
                            % texname)
                    file.write('\t\t\t\t<p>')

                contextMat = key
                if f_smooth != contextSmooth:
                    if f_smooth:  # on now off
                        # file.write('s 1\n')
                        contextSmooth = f_smooth
                    else:  # was off now on
                        # file.write('s off\n')
                        contextSmooth = f_smooth

                if faceuv:
                    if f_smooth:  # Smoothed, use vertex normals
                        for vi, v in enumerate(f_v):
                            file.write( ' %d %d %d' % (\
                                v.index+totverts,\
                                totuvco + uv_face_mapping[f_index][vi],\
                                globalNormals[ veckey3d(v.no) ])) # vert, uv, normal

                    else:  # No smoothing, face normals
                        no = globalNormals[veckey3d(f.no)]
                        for vi, v in enumerate(f_v):
                            file.write( ' %d %d %d' % (\
                                v.index+totverts,\
                                totuvco + uv_face_mapping[f_index][vi],\
                                no)) # vert, uv, normal

                    face_vert_index += len(f_v)

                else:  # No UV's
                    if f_smooth:  # Smoothed, use vertex normals
                        for v in f_v:
                            file.write( ' %d %d' % (\
                                v.index+totverts,\
                                globalNormals[ veckey3d(v.no) ]))
                    else:  # No smoothing, face normals
                        no = globalNormals[veckey3d(f.no)]
                        for v in f_v:
                            file.write( ' %d %d' % (\
                                v.index+totverts,\
                                no))
            if in_triangles:
                file.write('</p>\n')
                file.write('\t\t\t</triangles>\n')

            # Write edges.
            LOOSE = Mesh.EdgeFlags.LOOSE
            has_edge = False
            for ed in edges:
                if ed.flag & LOOSE:
                    has_edge = True
            if has_edge:
                file.write('\t\t\t<edges>\n')
                file.write(
                    '\t\t\t\t<input offset="0" semantic="VERTEX" source="#%s" />\n'
                    % vertname)
                file.write('\t\t\t\t<p>')
                for ed in edges:
                    if ed.flag & LOOSE:
                        file.write(
                            ' %d %d' %
                            (ed.v1.index + totverts, ed.v2.index + totverts))
                file.write('</p>\n')
                file.write('\t\t\t</edges>\n')

            # Make the indicies global rather then per mesh
            # totverts += len(me.verts)
            # if faceuv:
            #     totuvco += uv_unique_count
            me.verts = None
            if len(faces) > 0:
                file.write('\t\t</mesh>\n')
            else:
                file.write('\t\t</curve>\n')
        file.write('\t</object>\n')
    file.write('</library_objects>\n\n')

    # Now we have all our materials, save them
    if EXPORT_MTL:
        write_library_materials(file)

    # Save the groups
    write_library_groups(file)

    file.write('</OPEN_TRACK>\n')
    file.close()

    if EXPORT_COPY_IMAGES:
        dest_dir = filename
        # Remove chars until we are just the path.
        while dest_dir and dest_dir[-1] not in '\\/':
            dest_dir = dest_dir[:-1]
        if dest_dir:
            copy_images(dest_dir)
        else:
            print '\tError: "%s" could not be used as a base for an image path.' % filename

    print "WTF Export time: %.2f" % (sys.time() - time1)
Ejemplo n.º 6
0
def write(filename, objects,\
EXPORT_TRI=False,  EXPORT_EDGES=False,  EXPORT_NORMALS=False,  EXPORT_NORMALS_HQ=False,\
EXPORT_UV=True,  EXPORT_MTL=True,  EXPORT_COPY_IMAGES=False,\
EXPORT_APPLY_MODIFIERS=True, EXPORT_ROTX90=True, EXPORT_BLEN_OBS=True,\
EXPORT_GROUP_BY_OB=False,  EXPORT_GROUP_BY_MAT=False, EXPORT_KEEP_VERT_ORDER=False,\
EXPORT_POLYGROUPS=False, EXPORT_CURVE_AS_NURBS=True):
	'''
	Basic write function. The context and options must be alredy set
	This can be accessed externaly
	eg.
	write( 'c:\\test\\foobar.obj', Blender.Object.GetSelected() ) # Using default options.
	'''
	
	def veckey3d(v):
		return round(v.x, 6), round(v.y, 6), round(v.z, 6)
		
	def veckey2d(v):
		return round(v.x, 6), round(v.y, 6)
	
	def findVertexGroupName(face, vWeightMap):
		"""
		Searches the vertexDict to see what groups is assigned to a given face.
		We use a frequency system in order to sort out the name because a given vetex can
		belong to two or more groups at the same time. To find the right name for the face
		we list all the possible vertex group names with their frequency and then sort by
		frequency in descend order. The top element is the one shared by the highest number
		of vertices is the face's group 
		"""
		weightDict = {}
		for vert in face:
			vWeights = vWeightMap[vert.index]
			for vGroupName, weight in vWeights:
				weightDict[vGroupName] = weightDict.get(vGroupName, 0) + weight
		
		if weightDict:
			alist = [(weight,vGroupName) for vGroupName, weight in weightDict.iteritems()] # sort least to greatest amount of weight
			alist.sort()
			return(alist[-1][1]) # highest value last
		else:
			return '(null)'


	print 'OBJ Export path: "%s"' % filename
	temp_mesh_name = '~tmp-mesh'

	time1 = sys.time()
	scn = Scene.GetCurrent()

	file = open(filename, "w")
	
	# Write Header
	file.write('# Blender3D v%s OBJ File: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1] ))
	file.write('# www.blender3d.org\n')

	# Tell the obj file what material file to use.
	if EXPORT_MTL:
		mtlfilename = '%s.mtl' % '.'.join(filename.split('.')[:-1])
		file.write('mtllib %s\n' % ( mtlfilename.split('\\')[-1].split('/')[-1] ))
	
	# Get the container mesh. - used for applying modifiers and non mesh objects.
	containerMesh = meshName = tempMesh = None
	for meshName in Blender.NMesh.GetNames():
		if meshName.startswith(temp_mesh_name):
			tempMesh = Mesh.Get(meshName)
			if not tempMesh.users:
				containerMesh = tempMesh
	if not containerMesh:
		containerMesh = Mesh.New(temp_mesh_name)
	
	if EXPORT_ROTX90:
		mat_xrot90= Blender.Mathutils.RotationMatrix(-90, 4, 'x')
		
	del meshName
	del tempMesh
	
	# Initialize totals, these are updated each object
	totverts = totuvco = totno = 1
	
	face_vert_index = 1
	
	globalNormals = {}
	
	# Get all meshes
	for ob_main in objects:
		for ob, ob_mat in BPyObject.getDerivedObjects(ob_main):
			
			# Nurbs curve support
			if EXPORT_CURVE_AS_NURBS and test_nurbs_compat(ob):
				if EXPORT_ROTX90:
					ob_mat = ob_mat * mat_xrot90
				
				totverts += write_nurb(file, ob, ob_mat)
				
				continue
			# end nurbs
			
			# Will work for non meshes now! :)
			# getMeshFromObject(ob, container_mesh=None, apply_modifiers=True, vgroups=True, scn=None)
			me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, EXPORT_POLYGROUPS, scn)
			if not me:
				continue
			
			if EXPORT_UV:
				faceuv= me.faceUV
			else:
				faceuv = False
			
			# We have a valid mesh
			if EXPORT_TRI and me.faces:
				# Add a dummy object to it.
				has_quads = False
				for f in me.faces:
					if len(f) == 4:
						has_quads = True
						break
				
				if has_quads:
					oldmode = Mesh.Mode()
					Mesh.Mode(Mesh.SelectModes['FACE'])
					
					me.sel = True
					tempob = scn.objects.new(me)
					me.quadToTriangle(0) # more=0 shortest length
					oldmode = Mesh.Mode(oldmode)
					scn.objects.unlink(tempob)
					
					Mesh.Mode(oldmode)
			
			# Make our own list so it can be sorted to reduce context switching
			faces = [ f for f in me.faces ]
			
			if EXPORT_EDGES:
				edges = me.edges
			else:
				edges = []
			
			if not (len(faces)+len(edges)+len(me.verts)): # Make sure there is somthing to write
				continue # dont bother with this mesh.
			
			if EXPORT_ROTX90:
				me.transform(ob_mat*mat_xrot90)
			else:
				me.transform(ob_mat)
			
			# High Quality Normals
			if EXPORT_NORMALS and faces:
				if EXPORT_NORMALS_HQ:
					BPyMesh.meshCalcNormals(me)
				else:
					# transforming normals is incorrect
					# when the matrix is scaled,
					# better to recalculate them
					me.calcNormals()
			
			# # Crash Blender
			#materials = me.getMaterials(1) # 1 == will return None in the list.
			materials = me.materials
			
			materialNames = []
			materialItems = materials[:]
			if materials:
				for mat in materials:
					if mat: # !=None
						materialNames.append(mat.name)
					else:
						materialNames.append(None)
				# Cant use LC because some materials are None.
				# materialNames = map(lambda mat: mat.name, materials) # Bug Blender, dosent account for null materials, still broken.	
			
			# Possible there null materials, will mess up indicies
			# but at least it will export, wait until Blender gets fixed.
			materialNames.extend((16-len(materialNames)) * [None])
			materialItems.extend((16-len(materialItems)) * [None])
			
			# Sort by Material, then images
			# so we dont over context switch in the obj file.
			if EXPORT_KEEP_VERT_ORDER:
				pass
			elif faceuv:
				try:	faces.sort(key = lambda a: (a.mat, a.image, a.smooth))
				except:	faces.sort(lambda a,b: cmp((a.mat, a.image, a.smooth), (b.mat, b.image, b.smooth)))
			elif len(materials) > 1:
				try:	faces.sort(key = lambda a: (a.mat, a.smooth))
				except:	faces.sort(lambda a,b: cmp((a.mat, a.smooth), (b.mat, b.smooth)))
			else:
				# no materials
				try:	faces.sort(key = lambda a: a.smooth)
				except:	faces.sort(lambda a,b: cmp(a.smooth, b.smooth))
			
			# Set the default mat to no material and no image.
			contextMat = (0, 0) # Can never be this, so we will label a new material teh first chance we get.
			contextSmooth = None # Will either be true or false,  set bad to force initialization switch.
			
			if EXPORT_BLEN_OBS or EXPORT_GROUP_BY_OB:
				name1 = ob.name
				name2 = ob.getData(1)
				if name1 == name2:
					obnamestring = fixName(name1)
				else:
					obnamestring = '%s_%s' % (fixName(name1), fixName(name2))
				
				if EXPORT_BLEN_OBS:
					file.write('o %s\n' % obnamestring) # Write Object name
				else: # if EXPORT_GROUP_BY_OB:
					file.write('g %s\n' % obnamestring)
			
			
			# Vert
			for v in me.verts:
				file.write('v %.6f %.6f %.6f\n' % tuple(v.co))
			
			# UV
			if faceuv:
				uv_face_mapping = [[0,0,0,0] for f in faces] # a bit of a waste for tri's :/
				
				uv_dict = {} # could use a set() here
				for f_index, f in enumerate(faces):
					
					for uv_index, uv in enumerate(f.uv):
						uvkey = veckey2d(uv)
						try:
							uv_face_mapping[f_index][uv_index] = uv_dict[uvkey]
						except:
							uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] = len(uv_dict)
							file.write('vt %.6f %.6f\n' % tuple(uv))
				
				uv_unique_count = len(uv_dict)
				del uv, uvkey, uv_dict, f_index, uv_index
				# Only need uv_unique_count and uv_face_mapping
			
			# NORMAL, Smooth/Non smoothed.
			if EXPORT_NORMALS:
				for f in faces:
					if f.smooth:
						for v in f:
							noKey = veckey3d(v.no)
							if not globalNormals.has_key( noKey ):
								globalNormals[noKey] = totno
								totno +=1
								file.write('vn %.6f %.6f %.6f\n' % noKey)
					else:
						# Hard, 1 normal from the face.
						noKey = veckey3d(f.no)
						if not globalNormals.has_key( noKey ):
							globalNormals[noKey] = totno
							totno +=1
							file.write('vn %.6f %.6f %.6f\n' % noKey)
			
			if not faceuv:
				f_image = None
			
			if EXPORT_POLYGROUPS:
				# Retrieve the list of vertex groups
				vertGroupNames = me.getVertGroupNames()

				currentVGroup = ''
				# Create a dictionary keyed by face id and listing, for each vertex, the vertex groups it belongs to
				vgroupsMap = [[] for _i in xrange(len(me.verts))]
				for vertexGroupName in vertGroupNames:
					for vIdx, vWeight in me.getVertsFromGroup(vertexGroupName, 1):
						vgroupsMap[vIdx].append((vertexGroupName, vWeight))

			for f_index, f in enumerate(faces):
				f_v= f.v
				f_smooth= f.smooth
				f_mat = min(f.mat, len(materialNames)-1)
				if faceuv:
					f_image = f.image
					f_uv= f.uv
				
				# MAKE KEY
				if faceuv and f_image: # Object is always true.
					key = materialNames[f_mat],  f_image.name
				else:
					key = materialNames[f_mat],  None # No image, use None instead.
				
				# Write the vertex group
				if EXPORT_POLYGROUPS:
					if vertGroupNames:
						# find what vertext group the face belongs to
						theVGroup = findVertexGroupName(f,vgroupsMap)
						if	theVGroup != currentVGroup:
							currentVGroup = theVGroup
							file.write('g %s\n' % theVGroup)

				# CHECK FOR CONTEXT SWITCH
				if key == contextMat:
					pass # Context alredy switched, dont do anything
				else:
					if key[0] == None and key[1] == None:
						# Write a null material, since we know the context has changed.
						if EXPORT_GROUP_BY_MAT:
							file.write('g %s_%s\n' % (fixName(ob.name), fixName(ob.getData(1))) ) # can be mat_image or (null)
						file.write('usemtl (null)\n') # mat, image
						
					else:
						mat_data= MTL_DICT.get(key)
						if not mat_data:
							# First add to global dict so we can export to mtl
							# Then write mtl
							
							# Make a new names from the mat and image name,
							# converting any spaces to underscores with fixName.
							
							# If none image dont bother adding it to the name
							if key[1] == None:
								mat_data = MTL_DICT[key] = ('%s'%fixName(key[0])), materialItems[f_mat], f_image
							else:
								mat_data = MTL_DICT[key] = ('%s_%s' % (fixName(key[0]), fixName(key[1]))), materialItems[f_mat], f_image
						
						if EXPORT_GROUP_BY_MAT:
							file.write('g %s_%s_%s\n' % (fixName(ob.name), fixName(ob.getData(1)), mat_data[0]) ) # can be mat_image or (null)

						file.write('usemtl %s\n' % mat_data[0]) # can be mat_image or (null)
					
				contextMat = key
				if f_smooth != contextSmooth:
					if f_smooth: # on now off
						file.write('s 1\n')
						contextSmooth = f_smooth
					else: # was off now on
						file.write('s off\n')
						contextSmooth = f_smooth
				
				file.write('f')
				if faceuv:
					if EXPORT_NORMALS:
						if f_smooth: # Smoothed, use vertex normals
							for vi, v in enumerate(f_v):
								file.write( ' %d/%d/%d' % (\
								  v.index+totverts,\
								  totuvco + uv_face_mapping[f_index][vi],\
								  globalNormals[ veckey3d(v.no) ])) # vert, uv, normal
							
						else: # No smoothing, face normals
							no = globalNormals[ veckey3d(f.no) ]
							for vi, v in enumerate(f_v):
								file.write( ' %d/%d/%d' % (\
								  v.index+totverts,\
								  totuvco + uv_face_mapping[f_index][vi],\
								  no)) # vert, uv, normal
					
					else: # No Normals
						for vi, v in enumerate(f_v):
							file.write( ' %d/%d' % (\
							  v.index+totverts,\
							  totuvco + uv_face_mapping[f_index][vi])) # vert, uv
					
					face_vert_index += len(f_v)
				
				else: # No UV's
					if EXPORT_NORMALS:
						if f_smooth: # Smoothed, use vertex normals
							for v in f_v:
								file.write( ' %d//%d' % (\
								  v.index+totverts,\
								  globalNormals[ veckey3d(v.no) ]))
						else: # No smoothing, face normals
							no = globalNormals[ veckey3d(f.no) ]
							for v in f_v:
								file.write( ' %d//%d' % (\
								  v.index+totverts,\
								  no))
					else: # No Normals
						for v in f_v:
							file.write( ' %d' % (\
							  v.index+totverts))
						
				file.write('\n')
			
			# Write edges.
			if EXPORT_EDGES:
				LOOSE= Mesh.EdgeFlags.LOOSE
				for ed in edges:
					if ed.flag & LOOSE:
						file.write('f %d %d\n' % (ed.v1.index+totverts, ed.v2.index+totverts))
				
			# Make the indicies global rather then per mesh
			totverts += len(me.verts)
			if faceuv:
				totuvco += uv_unique_count
			me.verts= None
	file.close()
	
	
	# Now we have all our materials, save them
	if EXPORT_MTL:
		write_mtl(mtlfilename)
	if EXPORT_COPY_IMAGES:
		dest_dir = filename
		# Remove chars until we are just the path.
		while dest_dir and dest_dir[-1] not in '\\/':
			dest_dir = dest_dir[:-1]
		if dest_dir:
			copy_images(dest_dir)
		else:
			print '\tError: "%s" could not be used as a base for an image path.' % filename
	
	print "OBJ Export time: %.2f" % (sys.time() - time1)
def saveBR2(filename):
	if not filename.lower().endswith('.br2'):
		filename += '.br2'
	
	if not BPyMessages.Warning_SaveOver(filename):
		return
	
	print "Start BR2 Export..."
	Blender.Window.WaitCursor(1)
	file = open( filename, 'wb')
	
	scene = Blender.Scene.GetCurrent()
	allObjects = scene.objects
	
	filedata = "// Nexus Buddy BR2 - Exported from Blender for import to Nexus Buddy 2\n"
	
	modelObs = {}
	modelMeshes = {}
	
	# will need list of these for multi-skeleton
	boneIds = {}
	
	for object in allObjects:
		if object.type == 'Armature':
			modelObs[object.name] = object
			
		if object.type == 'Mesh':
			print "Getting parent for mesh: %s" % object.name
			parentArmOb = BPyObject.getObjectArmature(object)
			if not parentArmOb.name in modelMeshes:
				modelMeshes[parentArmOb.name] = []
			modelMeshes[parentArmOb.name].append(object)

	for modelObName in modelObs.keys():
	
		# Write Skeleton
		filedata += "skeleton\n"
			
		armOb = modelObs[modelObName]
		armature = armOb.data
		
		# Calc bone depths and sort
		boneDepths = []
		for bone in armature.bones.values():
			boneDepth = getBoneTreeDepth(bone, 0)
			boneDepths.append((bone, boneDepth))
		
		boneDepths = sorted(boneDepths, key=lambda k: k[0].name)
		boneDepths = sorted(boneDepths, key=lambda k: k[1])
		sortedBones = boneDepths
		
		for boneid, boneTuple in enumerate(sortedBones):
			boneIds[boneTuple[0].name] = boneid

		boneIds[armOb.name] = -1 # Add entry for World Bone
			
		# Write World Bone
		filedata += '%d "%s" %d ' % (0, armOb.name, -1)   
		filedata += '%.8f %.8f %.8f ' % (0.0, 0.0, 0.0)
		filedata += '%.8f %.8f %.8f %.8f ' % (0.0, 0.0, 0.0, 1.0)
		filedata += '%.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f\n' % (1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0)
		
		for boneid, boneTuple in enumerate(sortedBones):
			bone = boneTuple[0]
			boneDepth = boneTuple[1]
			#boneid = boneid + 1 # World bone is zero
			
			position, orientationQuat = getTranslationOrientation(bone)
			
			# Get Inverse World Matrix for bone
			t = bone.matrix['ARMATURESPACE'].copy().invert()
			invWorldMatrix = Matrix([t[0][1], -t[0][0], t[0][2], t[0][3]],
								[t[1][1], -t[1][0], t[1][2], t[1][3]],
								[t[2][1], -t[2][0], t[2][2], t[2][3]],
								[t[3][1], -t[3][0], t[3][2], t[3][3]])
			
			outputBoneName = bone.name
			if len(outputBoneName) == 29:
				for item in armOb.getAllProperties():
					if (("B_" + outputBoneName) == item.getName()):
						outputBoneName = item.getData()
						print 'Decode Bone Name: "%s" >' % item.getName()
						print '                  "%s"' % item.getData()
						break
			
			filedata += '%d "%s" ' % (boneid + 1, outputBoneName)   # Adjust bone ids + 1 as zero is the World Bone
			
			parentBoneId = 0
			if bone.hasParent():
				parentBoneId = boneIds[bone.parent.name] + 1   # Adjust bone ids + 1 as zero is the World Bone
			
			filedata += '%d ' % parentBoneId
			filedata +='%.8f %.8f %.8f ' % (position[0], position[1] , position[2])
			filedata +='%.8f %.8f %.8f %.8f ' % (orientationQuat[1], orientationQuat[2], orientationQuat[3], orientationQuat[0]) # GR2 uses x,y,z,w for Quaternions rather than w,x,y,z
			filedata += '%.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f' % (
								invWorldMatrix[0][0], invWorldMatrix[0][1], invWorldMatrix[0][2], invWorldMatrix[0][3], 
								invWorldMatrix[1][0], invWorldMatrix[1][1], invWorldMatrix[1][2], invWorldMatrix[1][3],
								invWorldMatrix[2][0], invWorldMatrix[2][1], invWorldMatrix[2][2], invWorldMatrix[2][3],
								invWorldMatrix[3][0], invWorldMatrix[3][1], invWorldMatrix[3][2], invWorldMatrix[3][3])
			#End of bone line
			filedata += "\n"
		
		filedata += 'meshes:%d\n' % len(modelMeshes[modelObName])
		
		for meshObject in modelMeshes[modelObName]:
			
			mesh = meshObject.data
			meshName = meshObject.name
			
			filedata += 'mesh:"%s"\n' % meshName
			
			parentArmOb = BPyObject.getObjectArmature(meshObject)
			
			# Fetch long mesh names from Armature properties
			if len(meshName) == 19:
				for item in parentArmOb.getAllProperties():
					if ("M_" + meshName == item.getName()):
						meshName = item.getData()
						print 'Decode Mesh Name: %s > %s' % (item.getName(), item.getData())
						break
			
			#file.write('meshname:%s\n' % meshName)
			#file.write('parent Arm:%s\n' % parentArmOb)
			
			weights = meshNormalizedWeights(mesh)
			vertexBoneWeights = {}
			for boneName in boneIds.keys():
				vgroupDataForBone = getBoneWeights(boneName, weights)
				#file.write('bone:%s vg:%s\n' % (boneName, vgroupDataForBone))
				
				for vgData in vgroupDataForBone:
					vertexId = vgData[0]
					weight = vgData[1]
					if not vertexId in vertexBoneWeights:
						vertexBoneWeights[vertexId] = []
					vertexBoneWeights[vertexId].append((boneName, weight))
					#file.write('vert:%d bone:%s \n' % (vertexId, (boneName, weight)))
			
			grannyVertexBoneWeights = {}
			for vertId in vertexBoneWeights.keys():
				#file.write('vert:%d ' % vertId)
				
				rawBoneIdWeightTuples = []
				firstBoneId = 0
				for i in range(max(4,len(vertexBoneWeights[vertId]))):
					if i < len(vertexBoneWeights[vertId]):
						vertexBoneWeightTuple = vertexBoneWeights[vertId][i]
						boneName = vertexBoneWeightTuple[0]
						rawBoneIdWeightTuples.append((boneIds[boneName] + 1, vertexBoneWeightTuple[1]))
						if i == 0:
							firstBoneId = boneIds[boneName] + 1
					else:
						rawBoneIdWeightTuples.append((firstBoneId, 0))
				
				# Sort bone mappings by weight highest to lowest
				sortedBoneIdWeightTuples = sorted(rawBoneIdWeightTuples, key=lambda rawBoneIdWeightTuple: rawBoneIdWeightTuple[1], reverse=True)
				
				#if len(vertexBoneWeights[vertId]) > 4:
				#	print  "len(vertexBoneWeights[vertId]): %s" % len(vertexBoneWeights[vertId])
				#	print  "sortedBoneIdWeightTuples: %s" % sortedBoneIdWeightTuples
				
				# Pick first four highest weighted bones
				boneIdsList = []
				rawBoneWeightsList = []
				for i in range(4): 
					boneIdsList.append(sortedBoneIdWeightTuples[i][0])
					rawBoneWeightsList.append(sortedBoneIdWeightTuples[i][1])
				
				rawWeightTotal = 0
				for weight in rawBoneWeightsList:
					rawWeightTotal = rawWeightTotal + weight
				
				boneWeightsList = []
				for weight in rawBoneWeightsList:
					calcWeight = round(255 * weight / rawWeightTotal)
					boneWeightsList.append(calcWeight)
					
				# Ensure that total of vertex bone weights is 255
				runningTotal = 0
				for i, weight in enumerate(boneWeightsList):
					runningTotal = runningTotal + weight
					if runningTotal > 255:
						boneWeightsList[i] = weight - 1
						break
				
				if runningTotal < 255:
					boneWeightsList[0] = boneWeightsList[0] + 1
				
				runningTotal = 0
				for i, weight in enumerate(boneWeightsList):
					runningTotal = runningTotal + weight
				
				if runningTotal != 255:
					raise "Error: Vertex bone weights do not total 255!"
				
				if not vertId in grannyVertexBoneWeights:
					grannyVertexBoneWeights[vertId] = []
				grannyVertexBoneWeights[vertId] = (boneIdsList, boneWeightsList)
				
				#file.write('%s %s ' % (boneIdsList, boneWeightsList))
				#file.write("\n")
			
			position, orientationQuat = getTranslationOrientation(meshObject)
			
			#file.write('position:%.8f %.8f %.8f\n' % (position[0], position[1], position[2]))
			#file.write('orientationQuat:%.8f %.8f %.8f %.8f\n' % (orientationQuat[1], orientationQuat[2], orientationQuat[3], orientationQuat[0]))
			#file.write(meshName+"\n")
			
			filedata += "vertices\n"

			# Determine unique vertex/UVs for output
			uniqueVertSet = set()
			uniqueVertUVIndexes = {}
			uniqueVertUVs = []
			currentVertUVIndex = 0
			
			currentTriangleId = 0
			triangleVertUVIndexes = []
			
			for triangle in mesh.faces:
				vertIds = [v.index for v in triangle]
				vertIds = tuple(vertIds)
				triangleVertUVIndexes.append([])
				
				for i, uv in enumerate(triangle.uv):
					vertexId = vertIds[i]
					uvt = tuple(uv)
					vertSig = '%i|%.8f|%.8f' % (vertexId, uvt[0], uvt[1])
					
					if vertSig in uniqueVertSet:
						triangleVertUVIndex = uniqueVertUVIndexes[vertSig]
					else:
						uniqueVertSet.add(vertSig)
						uniqueVertUVIndexes[vertSig] = currentVertUVIndex
						uniqueVertUVs.append((vertexId, uvt[0], uvt[1]))
						triangleVertUVIndex = currentVertUVIndex
						currentVertUVIndex = currentVertUVIndex + 1
					
					triangleVertUVIndexes[currentTriangleId].append(triangleVertUVIndex)
				currentTriangleId = currentTriangleId + 1
			
			meshVerts = {}
			for i,vert in enumerate(mesh.verts):
				meshVerts[i] = vert
				
			# Write Vertices
			for uniqueVertUV in uniqueVertUVs:
			
				index = uniqueVertUV[0]
				vert = meshVerts[index]
				vertCoord = tuple(vert.co)
				vertNormal = tuple(vert.no)
				filedata +='%.8f %.8f %.8f ' % (vertCoord[0] + position[0], vertCoord[1] + position[1], vertCoord[2] +  position[2])
				filedata +='%.8f %.8f %.8f ' % vertNormal
				filedata +='%.8f %.8f ' % (uniqueVertUV[1], 1 - uniqueVertUV[2])

				if index in grannyVertexBoneWeights:
					vBoneWeightTuple = grannyVertexBoneWeights[index]
				else:
					raise "Error: Mesh has unweighted vertices!"
					#vBoneWeightTuple = ([-1,-1,-1,-1],[-1,-1,-1,-1]) # Unweighted vertex - raise error
				
				filedata +='%d %d %d %d ' % (vBoneWeightTuple[0][0], vBoneWeightTuple[0][1],vBoneWeightTuple[0][2],vBoneWeightTuple[0][3]) # Bone Ids
				filedata +='%d %d %d %d\n' % (vBoneWeightTuple[1][0], vBoneWeightTuple[1][1],vBoneWeightTuple[1][2],vBoneWeightTuple[1][3]) # Bone Weights
			
			# Write Triangles
			filedata += "triangles\n"
			for triangle in triangleVertUVIndexes:
				#filedata += '%i %i %i\n' % tuple(triangle)
				filedata += '%i %i %i\n' % (triangle[0],triangle[1],triangle[2])
	
	filedata += "end"
	file.write(filedata)
	file.close()
	Blender.Window.WaitCursor(0)
	print "End BR2 Export."
Ejemplo n.º 8
0
def write(directory, filename, objects):
    def v_n_uv_key(v, n, uv):
        return round(v.x,
                     6), round(v.y, 6), round(v.z, 6), round(n.x, 6), round(
                         n.y, 6), round(n.z, 6), round(uv[0],
                                                       6), round(uv[1], 6)

    def v_n_key(v, n):
        return round(v.x,
                     6), round(v.y,
                               6), round(v.z,
                                         6), round(n.x,
                                                   6), round(n.y,
                                                             6), round(n.z, 6)

    def adjust_key(key, obCenter):
        keyList = list(key)
        keyList[0] -= obCenter[0]
        keyList[1] -= obCenter[1]
        keyList[2] -= obCenter[2]
        return tuple(keyList)

    temp_mesh_name = '~tmp-mesh'

    scn = Scene.GetCurrent()

    # Get the container mesh. - used for applying modifiers and non mesh objects.
    containerMesh = meshName = tempMesh = None
    for meshName in Blender.NMesh.GetNames():
        if meshName.startswith(temp_mesh_name):
            tempMesh = Mesh.Get(meshName)
            if not tempMesh.users:
                containerMesh = tempMesh
    if not containerMesh:
        containerMesh = Mesh.New(temp_mesh_name)

    del meshName
    del tempMesh

    try:
        armature = Blender.Object.Get("Armature")
        write_armature(directory + filename, armature)
    except:
        armature = None

# Get all meshs
    for ob_main in objects:
        for ob, ob_mat in BPyObject.getDerivedObjects(ob_main):
            me = BPyMesh.getMeshFromObject(ob, containerMesh, True, False, scn)
            if not me:
                continue

            # Initialize globalVertices and globalMaterials dictionaries
            vertIndex = 0
            matIndex = 0
            globalVertices = {}
            globalMaterials = {}
            # Dictionary of materials: (material.name, image.name):matname_imagename
            # matname_imagename has fixed names.
            materialDict = {}

            # We have a valid mesh
            if me.faces:
                # Add a dummy object to it.
                has_quads = False
                for f in me.faces:
                    if len(f) == 4:
                        has_quads = True
                        break

                if has_quads:
                    oldmode = Mesh.Mode()
                    Mesh.Mode(Mesh.SelectModes['FACE'])

                    me.sel = True
                    tempob = scn.objects.new(me)
                    me.quadToTriangle(0)  # more=0 shortest length
                    oldmode = Mesh.Mode(oldmode)
                    scn.objects.unlink(tempob)

                    Mesh.Mode(oldmode)
            else:
                continue

            # High Quality Normals
            BPyMesh.meshCalcNormals(me)

            # Make our own list so it can be sorted to reduce context switching
            faces = [f for f in me.faces]
            faceuv = me.faceUV
            edges = me.edges

            materials = me.materials
            materialNames = []
            materialItems = materials[:]
            if materials:
                for mat in materials:
                    if mat:
                        materialNames.append(mat.name)
                    else:
                        materialNames.append(None)

            # Possible there null materials, will mess up indicies
            # but at least it will export, wait until Blender gets fixed.
            materialNames.extend((16 - len(materialNames)) * [None])
            materialItems.extend((16 - len(materialItems)) * [None])

            # Sort by Material, then images
            # so we dont over context switch in the obj file.
            if faceuv:
                try:
                    faces.sort(key=lambda a: (a.mat, a.image, a.smooth))
                except:
                    faces.sort(lambda a, b: cmp((a.mat, a.image, a.smooth),
                                                (b.mat, b.image, b.smooth)))
            elif len(materials) > 1:
                try:
                    faces.sort(key=lambda a: (a.mat, a.smooth))
                except:
                    faces.sort(lambda a, b: cmp((a.mat, a.smooth),
                                                (b.mat, b.smooth)))
            else:  # no materials
                try:
                    faces.sort(key=lambda a: a.smooth)
                except:
                    faces.sort(lambda a, b: cmp(a.smooth, b.smooth))

            # Set the default mat to no material and no image.
            contextMat = (
                0, 0
            )  # Can never be this, so we will label a new material the first chance we get.
            contextSmooth = None  # Will either be true or false,  set bad to force initialization switch.

            name1 = ob.name
            name2 = ob.getData(1)
            obnamestring = fixName(name1)
            file = open(directory + obnamestring + ".drkMesh", "w")

            # Fill globalVertices dictionary by creating (vert, normal, uv) tuple for all vertices of all faces
            vertString = ""
            obCenter = ob.getLocation()
            if faceuv:
                vOutputFormat = 'v %.6f %.6f %.6f %.6f %.6f %.6f %.6f %.6f\n'
            else:
                vOutputFormat = 'v %.6f %.6f %.6f %.6f %.6f %.6f\n'
                f_image = None

            #Loop through all faces
            submeshCount = 0
            faceCount = 0
            faceCounts = []
            for face in faces:
                if faceuv:
                    faceUVs = list(face.uv)
                faceUVindex = 0
                faceIndices = []
                for v in face:
                    if face.smooth:
                        vno = v.no
                    else:
                        vno = face.no
                    if faceuv:
                        key = v_n_uv_key(v.co, v.no, faceUVs[faceUVindex])
                        faceUVindex += 1
                    else:
                        key = v_n_key(v.co, v.no)
                    if not globalVertices.has_key(key):
                        globalVertices[key] = vertIndex
                        vertString += vOutputFormat % key
                        faceIndices.append(vertIndex)
                        vertIndex += 1
                    else:
                        faceIndices.append(globalVertices[key])

                # Make material,texture key
                f_mat = min(face.mat, len(materialNames) - 1)
                if faceuv:
                    f_image = face.image
                if faceuv and f_image:
                    matKey = materialNames[f_mat], f_image.name
                else:
                    matKey = materialNames[f_mat], None

            # Check for context switch
                if matKey != contextMat:
                    submeshCount += 1
                    if matKey[0] == None and matKey[1] == None:
                        # Write a null material, since we know the context has changed.
                        faceString += 'use (null)\n'  # mat, image

                    else:
                        mat_data = materialDict.get(matKey)
                        if not mat_data:
                            mat_data = materialDict[matKey] = fixName(
                                matKey[0]), materialItems[f_mat], f_image

                        vertString += 'use %d\n' % matIndex
                        globalMaterials[mat_data[0]] = matIndex
                        matIndex += 1
                    if faceCount != 0:
                        faceCounts.append(faceCount)
                        faceCount = 0

                contextMat = matKey
                vertString += 'face %d %d %d\n' % tuple(faceIndices)
                faceCount += 1
            faceCounts.append(faceCount)
            file.write('count %d\n' % vertIndex)
            if faceuv:
                file.write('uvs\n')
            file.write('submeshes %d\n' % submeshCount)
            for faceCount in faceCounts:
                file.write('faces %d\n' % faceCount)
            file.write(vertString)

            me.verts = None
            write_mtl(file, materialDict, globalMaterials)
            file.close()
Ejemplo n.º 9
0
def write(filename, objects,\
EXPORT_TRI=False,  EXPORT_EDGES=False,  EXPORT_NORMALS=False,  EXPORT_NORMALS_HQ=False,\
EXPORT_UV=True,  EXPORT_MTL=True,  EXPORT_COPY_IMAGES=False,\
EXPORT_APPLY_MODIFIERS=True, EXPORT_ROTX90=True, EXPORT_BLEN_OBS=True,\
EXPORT_GROUP_BY_OB=False,  EXPORT_GROUP_BY_MAT=False, EXPORT_MORPH_TARGET=False, EXPORT_ARMATURE=False):
	'''
	Basic write function. The context and options must be alredy set
	This can be accessed externaly
	eg.
	write( 'c:\\test\\foobar.obj', Blender.Object.GetSelected() ) # Using default options.
	'''
	
	def veckey3d(v):
		return round(v.x, 6), round(v.y, 6), round(v.z, 6)
		
	def veckey2d(v):
		return round(v.x, 6), round(v.y, 6)
	
	print 'OBJ Export path: "%s"' % filename
	temp_mesh_name = '~tmp-mesh'

	time1 = sys.time()
	scn = Scene.GetCurrent()

	file = open(filename, "w")
	
	# Write Header
	file.write('# Blender3D v%s OBJ File: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1] ))
	file.write('# www.blender3d.org\n')

	# Tell the obj file what material file to use.
	if EXPORT_MTL:
		mtlfilename = '%s.mtl' % '.'.join(filename.split('.')[:-1])
		file.write('mtllib %s\n' % ( mtlfilename.split('\\')[-1].split('/')[-1] ))
	
	# Get the container mesh. - used for applying modifiers and non mesh objects.
	containerMesh = meshName = tempMesh = None
	for meshName in Blender.NMesh.GetNames():
		if meshName.startswith(temp_mesh_name):
			tempMesh = Mesh.Get(meshName)
			if not tempMesh.users:
				containerMesh = tempMesh
	if not containerMesh:
		containerMesh = Mesh.New(temp_mesh_name)
	
	if EXPORT_ROTX90:
		mat_xrot90= Blender.Mathutils.RotationMatrix(-90, 4, 'x')
		
	del meshName
	del tempMesh
	
	# Initialize totals, these are updated each object
	totverts = totuvco = totno = 1
	
	face_vert_index = 1
	
	globalNormals = {}
	
	# Get all meshs
	for ob_main in objects:
		for ob, ob_mat in BPyObject.getDerivedObjects(ob_main):
			# Will work for non meshes now! :)
			# getMeshFromObject(ob, container_mesh=None, apply_modifiers=True, vgroups=True, scn=None)
                        if EXPORT_ARMATURE:
				write_armature(file,ob)
				write_poses(file,ob)
			me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, False, scn)
			if not me:
				continue
			
			if EXPORT_UV:
				faceuv= me.faceUV
			else:
				faceuv = False
			
			# We have a valid mesh
			if EXPORT_TRI and me.faces:
				# Add a dummy object to it.
				has_quads = False
				for f in me.faces:
					if len(f) == 4:
						has_quads = True
						break
				
				if has_quads:
					oldmode = Mesh.Mode()
					Mesh.Mode(Mesh.SelectModes['FACE'])
					
					me.sel = True
					tempob = scn.objects.new(me)
					me.quadToTriangle(0) # more=0 shortest length
					oldmode = Mesh.Mode(oldmode)
					scn.objects.unlink(tempob)
					
					Mesh.Mode(oldmode)
			

			faces = [ f for f in me.faces ]
			
			if EXPORT_EDGES:
				edges = me.edges
			else:
				edges = []
			
			if not (len(faces)+len(edges)+len(me.verts)): # Make sure there is somthing to write
				continue # dont bother with this mesh.
			
			if EXPORT_ROTX90:
                                me.transform(ob_mat*mat_xrot90)
			else:
				me.transform(ob_mat)
			
			# High Quality Normals
			if EXPORT_NORMALS and faces:
				if EXPORT_NORMALS_HQ:
					BPyMesh.meshCalcNormals(me)
				else:
					# transforming normals is incorrect
					# when the matrix is scaled,
					# better to recalculate them
					me.calcNormals()
			
			# # Crash Blender
			#materials = me.getMaterials(1) # 1 == will return None in the list.
			materials = me.materials
			
			materialNames = []
			materialItems = materials[:]
			if materials:
				for mat in materials:
					if mat: # !=None
						materialNames.append(mat.name)
					else:
						materialNames.append(None)
				# Cant use LC because some materials are None.
				# materialNames = map(lambda mat: mat.name, materials) # Bug Blender, dosent account for null materials, still broken.  
			
			# Possible there null materials, will mess up indicies
			# but at least it will export, wait until Blender gets fixed.
			materialNames.extend((16-len(materialNames)) * [None])
			materialItems.extend((16-len(materialItems)) * [None])
			
			# Sort by Material, then images
			# so we dont over context switch in the obj file.
			if EXPORT_MORPH_TARGET:
				pass
			elif faceuv:
				try:	faces.sort(key = lambda a: (a.mat, a.image, a.smooth))
				except: faces.sort(lambda a,b: cmp((a.mat, a.image, a.smooth), (b.mat, b.image, b.smooth)))
			elif len(materials) > 1:
				try:	faces.sort(key = lambda a: (a.mat, a.smooth))
				except: faces.sort(lambda a,b: cmp((a.mat, a.smooth), (b.mat, b.smooth)))
			else:
				# no materials
				try:	faces.sort(key = lambda a: a.smooth)
				except: faces.sort(lambda a,b: cmp(a.smooth, b.smooth))
			
			# Set the default mat to no material and no image.
			contextMat = (0, 0) # Can never be this, so we will label a new material teh first chance we get.
			contextSmooth = None # Will either be true or false,  set bad to force initialization switch.
			
			if EXPORT_BLEN_OBS or EXPORT_GROUP_BY_OB:
				name1 = ob.name
				name2 = ob.getData(1)
				if name1 == name2:
					obnamestring = fixName(name1)
				else:
					obnamestring = '%s_%s' % (fixName(name1), fixName(name2))
				
				if EXPORT_BLEN_OBS:
					file.write('o %s\n' % obnamestring) # Write Object name
				else: # if EXPORT_GROUP_BY_OB:
					file.write('g %s\n' % obnamestring)
			
			
			
			# Vert
			mesh = ob.getData()
                        objmat = ob.getMatrix()
                        for i in objmat:
		          file.write('obm: %.6f %.6f %.6f %.6f\n' % tuple(i))
			vgrouplist = mesh.getVertGroupNames()
			file.write('vgroupcount: %i\n' % len(vgrouplist))
			for vgname in vgrouplist:
				file.write('vgroup: %s\n' % vgname)
			for v in mesh.verts:
				file.write('v %.6f %.6f %.6f\n' % tuple(v.co))
				influences = mesh.getVertexInfluences(v.index)
				file.write('influence: %i\n' % len(influences))
				for name,weight in influences:
					file.write('GroupName: %s\n' % name)
					file.write('Weight: %f\n' % weight)
			
			# UV
			if faceuv:
				uv_face_mapping = [[0,0,0,0] for f in faces] # a bit of a waste for tri's :/
				
				uv_dict = {} # could use a set() here
				for f_index, f in enumerate(faces):
					
					for uv_index, uv in enumerate(f.uv):
						uvkey = veckey2d(uv)
						try:
							uv_face_mapping[f_index][uv_index] = uv_dict[uvkey]
						except:
							uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] = len(uv_dict)
							file.write('vt %.6f %.6f\n' % tuple(uv))
				
				uv_unique_count = len(uv_dict)
				del uv, uvkey, uv_dict, f_index, uv_index
				# Only need uv_unique_count and uv_face_mapping
			
			# NORMAL, Smooth/Non smoothed.
			if EXPORT_NORMALS:
				for f in faces:
					if f.smooth:
						for v in f:
							noKey = veckey3d(v.no)
							if not globalNormals.has_key( noKey ):
								globalNormals[noKey] = totno
								totno +=1
								file.write('vn %.6f %.6f %.6f\n' % noKey)
					else:
						# Hard, 1 normal from the face.
						noKey = veckey3d(f.no)
						if not globalNormals.has_key( noKey ):
							globalNormals[noKey] = totno
							totno +=1
							file.write('vn %.6f %.6f %.6f\n' % noKey)
			
			if not faceuv:
				f_image = None
			
			for f_index, f in enumerate(faces):
				f_v= f.v
				f_smooth= f.smooth
				f_mat = min(f.mat, len(materialNames)-1)
				if faceuv:
					f_image = f.image
					f_uv= f.uv
				
				# MAKE KEY
				if faceuv and f_image: # Object is always true.
					key = materialNames[f_mat],  f_image.name
				else:
					key = materialNames[f_mat],  None # No image, use None instead.
				
				# CHECK FOR CONTEXT SWITCH
				if key == contextMat:
					pass # Context alredy switched, dont do anythoing
				else:
					if key[0] == None and key[1] == None:
						# Write a null material, since we know the context has changed.
						if EXPORT_GROUP_BY_MAT:
							file.write('g %s_%s\n' % (fixName(ob.name), fixName(ob.getData(1))) ) # can be mat_image or (null)
						file.write('usemtl (null)\n') # mat, image
						
					else:
						mat_data= MTL_DICT.get(key)
						if not mat_data:
							# First add to global dict so we can export to mtl
							# Then write mtl
							
							# Make a new names from the mat and image name,
							# converting any spaces to underscores with fixName.
							
							# If none image dont bother adding it to the name
							if key[1] == None:
								mat_data = MTL_DICT[key] = ('%s'%fixName(key[0])), materialItems[f_mat], f_image
							else:
								mat_data = MTL_DICT[key] = ('%s_%s' % (fixName(key[0]), fixName(key[1]))), materialItems[f_mat], f_image
						
						if EXPORT_GROUP_BY_MAT:
							file.write('g %s_%s_%s\n' % (fixName(ob.name), fixName(ob.getData(1)), mat_data[0]) ) # can be mat_image or (null)
						file.write('usemtl %s\n' % mat_data[0]) # can be mat_image or (null)
					
				contextMat = key
				if f_smooth != contextSmooth:
					if f_smooth: # on now off
						file.write('s 1\n')
						contextSmooth = f_smooth
					else: # was off now on
						file.write('s off\n')
						contextSmooth = f_smooth
				
				file.write('f')
				if faceuv:
					if EXPORT_NORMALS:
						if f_smooth: # Smoothed, use vertex normals
							for vi, v in enumerate(f_v):
								file.write( ' %d/%d/%d' % (\
								  v.index+totverts,\
								  totuvco + uv_face_mapping[f_index][vi],\
								  globalNormals[ veckey3d(v.no) ])) # vert, uv, normal
							
						else: # No smoothing, face normals
							no = globalNormals[ veckey3d(f.no) ]
							for vi, v in enumerate(f_v):
								file.write( ' %d/%d/%d' % (\
								  v.index+totverts,\
								  totuvco + uv_face_mapping[f_index][vi],\
								  no)) # vert, uv, normal
					
					else: # No Normals
						for vi, v in enumerate(f_v):
							file.write( ' %d/%d' % (\
							  v.index+totverts,\
							  totuvco + uv_face_mapping[f_index][vi])) # vert, uv
					
					face_vert_index += len(f_v)
				
				else: # No UV's
					if EXPORT_NORMALS:
						if f_smooth: # Smoothed, use vertex normals
							for v in f_v:
								file.write( ' %d//%d' % (\
								  v.index+totverts,\
								  globalNormals[ veckey3d(v.no) ]))
						else: # No smoothing, face normals
							no = globalNormals[ veckey3d(f.no) ]
							for v in f_v:
								file.write( ' %d//%d' % (\
								  v.index+totverts,\
								  no))
					else: # No Normals
						for v in f_v:
							file.write( ' %d' % (\
							  v.index+totverts))
						
				file.write('\n')
			
			# Write edges.
			if EXPORT_EDGES:
				LOOSE= Mesh.EdgeFlags.LOOSE
				for ed in edges:
					if ed.flag & LOOSE:
						file.write('f %d %d\n' % (ed.v1.index+totverts, ed.v2.index+totverts))
				
			# Make the indicies global rather then per mesh
			totverts += len(me.verts)
			if faceuv:
				totuvco += uv_unique_count
			me.verts= None
	file.close()
	
	
	# Now we have all our materials, save them
	if EXPORT_MTL:
		write_mtl(mtlfilename)
	if EXPORT_COPY_IMAGES:
		dest_dir = filename
		# Remove chars until we are just the path.
		while dest_dir and dest_dir[-1] not in '\\/':
			dest_dir = dest_dir[:-1]
		if dest_dir:
			copy_images(dest_dir)
		else:
			print '\tError: "%s" could not be used as a base for an image path.' % filename
	
	print "OBJ Export time: %.2f" % (sys.time() - time1)
Ejemplo n.º 10
0
 def export(self, scene, world, alltextures,\
         EXPORT_APPLY_MODIFIERS = False,\
         EXPORT_TRI=             False,\
     ):
     
     print "Info: starting X3D export to " + self.filename + "..."
     self.writeHeader()
     # self.writeScript()
     self.writeNavigationInfo(scene)
     self.writeBackground(world, alltextures)
     self.writeFog(world)
     self.proto = 0
     
     
     # COPIED FROM OBJ EXPORTER
     if EXPORT_APPLY_MODIFIERS:
         temp_mesh_name = '~tmp-mesh'
     
         # Get the container mesh. - used for applying modifiers and non mesh objects.
         containerMesh = meshName = tempMesh = None
         for meshName in Blender.NMesh.GetNames():
             if meshName.startswith(temp_mesh_name):
                 tempMesh = Mesh.Get(meshName)
                 if not tempMesh.users:
                     containerMesh = tempMesh
         if not containerMesh:
             containerMesh = Mesh.New(temp_mesh_name)
     # -------------------------- 
     
     
     for ob_main in scene.objects.context:
         for ob, ob_mat in BPyObject.getDerivedObjects(ob_main):
             objType=ob.type
             objName=ob.name
             self.matonly = 0
             if objType == "Camera":
                 self.writeViewpoint(ob, ob_mat, scene)
             elif objType in ("Mesh", "Curve", "Surf", "Text") :
                 if  EXPORT_APPLY_MODIFIERS or objType != 'Mesh':
                     me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, False, scene)
                 else:
                     me = ob.getData(mesh=1)
                 
                 self.writeIndexedFaceSet(ob, me, ob_mat, world, EXPORT_TRI = EXPORT_TRI)
             elif objType == "Lamp":
                 data= ob.data
                 datatype=data.type
                 if datatype == Lamp.Types.Lamp:
                     self.writePointLight(ob, ob_mat, data, world)
                 elif datatype == Lamp.Types.Spot:
                     self.writeSpotLight(ob, ob_mat, data, world)
                 elif datatype == Lamp.Types.Sun:
                     self.writeDirectionalLight(ob, ob_mat, data, world)
                 else:
                     self.writeDirectionalLight(ob, ob_mat, data, world)
             # do you think x3d could document what to do with dummy objects?
             #elif objType == "Empty" and objName != "Empty":
             #   self.writeNode(ob, ob_mat)
             else:
                 #print "Info: Ignoring [%s], object type [%s] not handle yet" % (object.name,object.getType)
                 pass
     
     self.file.write("\n</Scene>\n</X3D>")
     
     if EXPORT_APPLY_MODIFIERS:
         if containerMesh:
             containerMesh.verts = None
     
     self.cleanup()
Ejemplo n.º 11
0
def write(filename, objects,\
EXPORT_NORMALS_HQ=False,\
EXPORT_MTL=True,  EXPORT_COPY_IMAGES=False,\
EXPORT_APPLY_MODIFIERS=True, EXPORT_BLEN_OBS=True,\
EXPORT_GROUP_BY_OB=False):
    '''
    Basic write function. The context and options must be alredy set
    This can be accessed externaly
    eg.
    write( 'c:\\test\\foobar.obj', Blender.Object.GetSelected() ) # Using default options.
    '''
    
    def veckey3d(v):
        return round(v.x, 6), round(v.y, 6), round(v.z, 6)
        
    def veckey2d(v):
        return round(v.x, 6), round(v.y, 6)
    
    print 'WTF Export path: "%s"' % filename
    temp_mesh_name = '~tmp-mesh'

    time1 = sys.time()
    scn = Scene.GetCurrent()

    file = open(filename, "w")
    file.write('<?xml version="1.0"?>\n')
    file.write('<OPEN_TRACK>\n')

    # Write Header
    # file.write('\n<!--\n'
    #            + '  Blender3D v%s WTF File: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1] )
    #            + '  www.blender3d.org\n'
    #            + '-->\n\n')

    # Get the container mesh. - used for applying modifiers and non mesh objects.
    containerMesh = meshName = tempMesh = None
    for meshName in Blender.NMesh.GetNames():
        if meshName.startswith(temp_mesh_name):
            tempMesh = Mesh.Get(meshName)
            if not tempMesh.users:
                containerMesh = tempMesh
    if not containerMesh:
        containerMesh = Mesh.New(temp_mesh_name)
    
    del meshName
    del tempMesh
    
    # Initialize totals, these are updated each object
    totverts = totuvco = totno = 0
    
    face_vert_index = 0
    
    globalNormals = {}
    
    file.write('\n<library_objects>\n')
    # Get all meshs
    for ob_main in objects:
        obnamestring = fixName(ob_main.name)
        file.write('\t<object id="%s">\n' % obnamestring) # Write Object name

        for ob, ob_mat in BPyObject.getDerivedObjects(ob_main):
            # Will work for non meshes now! :)
            # getMeshFromObject(ob, container_mesh=None, apply_modifiers=True, vgroups=True, scn=None)
            me = BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, False, scn)
            if not me:
                file.write('\t\t<loc>%.6f %.6f %.6f</loc>\n' % tuple(ob_main.loc)) # Write Object name
                file.write('\t\t<rot>%.6f %.6f %.6f</rot>\n' % tuple(ob_main.rot)) # Write Object name
                continue
            
            faceuv = me.faceUV
            
            # We have a valid mesh
            if me.faces:
                # Add a dummy object to it.
                has_quads = False
                for f in me.faces:
                    if len(f) == 4:
                        has_quads = True
                        break
                
                if has_quads:
                    oldmode = Mesh.Mode()
                    Mesh.Mode(Mesh.SelectModes['FACE'])
                    
                    me.sel = True
                    tempob = scn.objects.new(me)
                    me.quadToTriangle(0) # more=0 shortest length
                    oldmode = Mesh.Mode(oldmode)
                    scn.objects.unlink(tempob)
                    
                    Mesh.Mode(oldmode)
            
            # Make our own list so it can be sorted to reduce context switching
            faces = [ f for f in me.faces ]
            edges = me.edges
            
            if not (len(faces)+len(edges)+len(me.verts)): # Make sure there is somthing to write
                continue # dont bother with this mesh.
            
            me.transform(ob_mat)
            
            # High Quality Normals
            if faces:
                if EXPORT_NORMALS_HQ:
                    BPyMesh.meshCalcNormals(me)
                else:
                    # transforming normals is incorrect
                    # when the matrix is scaled,
                    # better to recalculate them
                    me.calcNormals()
            
            # # Crash Blender
            #materials = me.getMaterials(1) # 1 == will return None in the list.
            materials = me.materials
            
            materialNames = []
            materialItems = materials[:]
            if materials:
                for mat in materials:
                    if mat: # !=None
                        materialNames.append(mat.name)
                    else:
                        materialNames.append(None)
                # Cant use LC because some materials are None.
                # materialNames = map(lambda mat: mat.name, materials) # Bug Blender, dosent account for null materials, still broken.  
            
            # Possible there null materials, will mess up indicies
            # but at least it will export, wait until Blender gets fixed.
            materialNames.extend((16-len(materialNames)) * [None])
            materialItems.extend((16-len(materialItems)) * [None])
            
            # Sort by Material, then images
            # so we dont over context switch in the obj file.
            if faceuv:
                try:    faces.sort(key = lambda a: (a.mat, a.image, a.smooth))
                except: faces.sort(lambda a,b: cmp((a.mat, a.image, a.smooth), (b.mat, b.image, b.smooth)))
            elif len(materials) > 1:
                try:    faces.sort(key = lambda a: (a.mat, a.smooth))
                except: faces.sort(lambda a,b: cmp((a.mat, a.smooth), (b.mat, b.smooth)))
            else:
                # no materials
                try:    faces.sort(key = lambda a: a.smooth)
                except: faces.sort(lambda a,b: cmp(a.smooth, b.smooth))
            
            # Set the default mat to no material and no image.
            contextMat = (0, 0) # Can never be this, so we will label a new material teh first chance we get.
            contextSmooth = None # Will either be true or false,  set bad to force initialization switch.
            
            if len(faces) > 0:
                file.write('\t\t<mesh>\n')
            else:
                file.write('\t\t<curve>\n')

            vertname = "%s-Vertices" % obnamestring
            vertarrayname = "%s-Array" % vertname
            normname = "%s-Normals" % obnamestring
            normarrayname = "%s-Array" % normname
            texname = "%s-TexCoord" % obnamestring
            texarrayname = "%s-Array" % texname
            
            # Vert
            file.write('\t\t\t<float_array count="%d" id="%s">' % (len(me.verts), vertarrayname))
            for v in me.verts:
                file.write(' %.6f %.6f %.6f' % tuple(v.co))
            file.write('</float_array>\n')
            file.write('\t\t\t<vertices id="%s" source="#%s" />\n' % (vertname, vertarrayname))
            
            # UV
            if faceuv:
                file.write('\t\t\t<float_array id="%s">' % texarrayname)
                uv_face_mapping = [[0,0,0,0] for f in faces] # a bit of a waste for tri's :/
                
                uv_dict = {} # could use a set() here
                for f_index, f in enumerate(faces):
                    
                    for uv_index, uv in enumerate(f.uv):
                        uvkey = veckey2d(uv)
                        try:
                            uv_face_mapping[f_index][uv_index] = uv_dict[uvkey]
                        except:
                            uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] = len(uv_dict)
                            file.write(' %.6f %.6f' % tuple(uv))
                
                uv_unique_count = len(uv_dict)
                del uv, uvkey, uv_dict, f_index, uv_index
                # Only need uv_unique_count and uv_face_mapping
                file.write('</float_array>\n')
                file.write('\t\t\t<texcoords id="%s" source="#%s" />\n' % (texname, texarrayname))
            
            # NORMAL, Smooth/Non smoothed.
            if len(faces) > 0:
                file.write('\t\t\t<float_array id="%s">' % normarrayname)
                for f in faces:
                    if f.smooth:
                        for v in f:
                            noKey = veckey3d(v.no)
                            if not globalNormals.has_key( noKey ):
                                globalNormals[noKey] = totno
                                totno +=1
                                file.write(' %.6f %.6f %.6f' % noKey)
                    else:
                        # Hard, 1 normal from the face.
                        noKey = veckey3d(f.no)
                        if not globalNormals.has_key( noKey ):
                            globalNormals[noKey] = totno
                            totno +=1
                            file.write(' %.6f %.6f %.6f' % noKey)
                file.write('</float_array>\n')
                file.write('\t\t\t<normals id="%s" source="#%s" />\n' % (normname, normarrayname))
            
            if not faceuv:
                f_image = None
            in_triangles = False
            
            for f_index, f in enumerate(faces):
                f_v= f.v
                f_smooth= f.smooth
                f_mat = min(f.mat, len(materialNames)-1)
                if faceuv:
                    f_image = f.image
                    f_uv= f.uv
                
                # MAKE KEY
                if faceuv and f_image: # Object is always true.
                    key = materialNames[f_mat],  f_image.name
                else:
                    key = materialNames[f_mat],  None # No image, use None instead.
                
                # CHECK FOR CONTEXT SWITCH
                if key == contextMat:
                    pass # Context alredy switched, dont do anythoing
                else:
                    if key[0] == None and key[1] == None:
                        # Write a null material, since we know the context has changed.
                        if in_triangles:
                            file.write('</p>\n')
                            file.write('\t\t\t</triangles>\n')
                        file.write('\t\t\t<triangles id="%s_%s">\n' % (fixName(ob.name), fixName(ob.getData(1))))
                        in_triangles = True
                    else:
                        mat_data= MTL_DICT.get(key)
                        if not mat_data:
                            # First add to global dict so we can export to mtl
                            # Then write mtl
                            
                            # Make a new names from the mat and image name,
                            # converting any spaces to underscores with fixName.
                            
                            # If none image dont bother adding it to the name
                            if key[1] == None:
                                mat_data = MTL_DICT[key] = ('%s'%fixName(key[0])), materialItems[f_mat], f_image
                            else:
                                mat_data = MTL_DICT[key] = ('%s_%s' % (fixName(key[0]), fixName(key[1]))), materialItems[f_mat], f_image
                        if in_triangles:
                            file.write('</p>\n')
                            file.write('\t\t\t</triangles>\n')
                        file.write('\t\t\t<triangles id="%s_%s_%s" material="#%s">\n' %
                                   (fixName(ob.name), fixName(ob.getData(1)), mat_data[0], mat_data[0]) )
                        in_triangles = True

                    file.write('\t\t\t\t<input offset="0" semantic="VERTEX" source="#%s" />\n' % vertname)
                    file.write('\t\t\t\t<input offset="1" semantic="NORMAL" source="#%s" />\n' % normname)
                    if faceuv:
                        file.write('\t\t\t\t<input offset="2" semantic="TEXCOORD" source="#%s" />\n' % texname)
                    file.write('\t\t\t\t<p>')
                    
                contextMat = key
                if f_smooth != contextSmooth:
                    if f_smooth: # on now off
                        # file.write('s 1\n')
                        contextSmooth = f_smooth
                    else: # was off now on
                        # file.write('s off\n')
                        contextSmooth = f_smooth
                
                if faceuv:
                    if f_smooth: # Smoothed, use vertex normals
                        for vi, v in enumerate(f_v):
                            file.write( ' %d %d %d' % (\
                                v.index+totverts,\
                                totuvco + uv_face_mapping[f_index][vi],\
                                globalNormals[ veckey3d(v.no) ])) # vert, uv, normal
                        
                    else: # No smoothing, face normals
                        no = globalNormals[ veckey3d(f.no) ]
                        for vi, v in enumerate(f_v):
                            file.write( ' %d %d %d' % (\
                                v.index+totverts,\
                                totuvco + uv_face_mapping[f_index][vi],\
                                no)) # vert, uv, normal
                    
                    face_vert_index += len(f_v)
                
                else: # No UV's
                    if f_smooth: # Smoothed, use vertex normals
                        for v in f_v:
                            file.write( ' %d %d' % (\
                                v.index+totverts,\
                                globalNormals[ veckey3d(v.no) ]))
                    else: # No smoothing, face normals
                        no = globalNormals[ veckey3d(f.no) ]
                        for v in f_v:
                            file.write( ' %d %d' % (\
                                v.index+totverts,\
                                no))
            if in_triangles:
                file.write('</p>\n')
                file.write('\t\t\t</triangles>\n')
            
            # Write edges.
            LOOSE = Mesh.EdgeFlags.LOOSE
            has_edge = False
            for ed in edges:
                if ed.flag & LOOSE:
                    has_edge = True
            if has_edge:
                file.write('\t\t\t<edges>\n')
                file.write('\t\t\t\t<input offset="0" semantic="VERTEX" source="#%s" />\n' % vertname)
                file.write('\t\t\t\t<p>')
                for ed in edges:
                    if ed.flag & LOOSE:
                        file.write(' %d %d' % (ed.v1.index+totverts, ed.v2.index+totverts))
                file.write('</p>\n')
                file.write('\t\t\t</edges>\n')
                
            # Make the indicies global rather then per mesh
            # totverts += len(me.verts)
            # if faceuv:
            #     totuvco += uv_unique_count
            me.verts= None
            if len(faces) > 0:
                file.write('\t\t</mesh>\n')
            else:
                file.write('\t\t</curve>\n')
        file.write('\t</object>\n')
    file.write('</library_objects>\n\n')
    
    # Now we have all our materials, save them
    if EXPORT_MTL:
        write_library_materials(file)

    # Save the groups
    write_library_groups(file)

    file.write('</OPEN_TRACK>\n')
    file.close()

    if EXPORT_COPY_IMAGES:
        dest_dir = filename
        # Remove chars until we are just the path.
        while dest_dir and dest_dir[-1] not in '\\/':
            dest_dir = dest_dir[:-1]
        if dest_dir:
            copy_images(dest_dir)
        else:
            print '\tError: "%s" could not be used as a base for an image path.' % filename
    
    print "WTF Export time: %.2f" % (sys.time() - time1)
Ejemplo n.º 12
0
    def export(self, scene, world, alltextures,\
      EXPORT_APPLY_MODIFIERS = False,\
      EXPORT_TRI=    False,\
     ):

        print "Info: starting X3D export to " + self.filename + "..."
        self.writeHeader()
        # self.writeScript()
        self.writeNavigationInfo(scene)
        self.writeBackground(world, alltextures)
        self.writeFog(world)
        self.proto = 0

        # COPIED FROM OBJ EXPORTER
        if EXPORT_APPLY_MODIFIERS:
            temp_mesh_name = '~tmp-mesh'

            # Get the container mesh. - used for applying modifiers and non mesh objects.
            containerMesh = meshName = tempMesh = None
            for meshName in Blender.NMesh.GetNames():
                if meshName.startswith(temp_mesh_name):
                    tempMesh = Mesh.Get(meshName)
                    if not tempMesh.users:
                        containerMesh = tempMesh
            if not containerMesh:
                containerMesh = Mesh.New(temp_mesh_name)
        # --------------------------

        for ob_main in scene.objects.context:
            for ob, ob_mat in BPyObject.getDerivedObjects(ob_main):
                objType = ob.type
                objName = ob.name
                self.matonly = 0
                if objType == "Camera":
                    self.writeViewpoint(ob, ob_mat, scene)
                elif objType in ("Mesh", "Curve", "Surf", "Text"):
                    if EXPORT_APPLY_MODIFIERS or objType != 'Mesh':
                        me = BPyMesh.getMeshFromObject(ob, containerMesh,
                                                       EXPORT_APPLY_MODIFIERS,
                                                       False, scene)
                    else:
                        me = ob.getData(mesh=1)

                    self.writeIndexedFaceSet(ob,
                                             me,
                                             ob_mat,
                                             world,
                                             EXPORT_TRI=EXPORT_TRI)
                elif objType == "Lamp":
                    data = ob.data
                    datatype = data.type
                    if datatype == Lamp.Types.Lamp:
                        self.writePointLight(ob, ob_mat, data, world)
                    elif datatype == Lamp.Types.Spot:
                        self.writeSpotLight(ob, ob_mat, data, world)
                    elif datatype == Lamp.Types.Sun:
                        self.writeDirectionalLight(ob, ob_mat, data, world)
                    else:
                        self.writeDirectionalLight(ob, ob_mat, data, world)
                # do you think x3d could document what to do with dummy objects?
                #elif objType == "Empty" and objName != "Empty":
                #	self.writeNode(ob, ob_mat)
                else:
                    #print "Info: Ignoring [%s], object type [%s] not handle yet" % (object.name,object.getType)
                    pass

        self.file.write("\n</Scene>\n</X3D>")

        if EXPORT_APPLY_MODIFIERS:
            if containerMesh:
                containerMesh.verts = None

        self.cleanup()
Ejemplo n.º 13
0
def saveBR2(filename):
  if not filename.lower().endswith('.br2'):
    filename += '.br2'

  if not BPyMessages.Warning_SaveOver(filename):
    return

  print "Start BR2 Export..."
  Blender.Window.WaitCursor(1)
  file = open( filename, 'wb')

  scene = Blender.Scene.GetCurrent()
  allObjects = scene.objects

  filedata = "// Nexus Buddy BR2 - Exported from Blender for import to Nexus Buddy 2\n"

  modelObs = {}
  modelMeshes = {}

  # will need list of these for multi-skeleton
  boneIds = {}

  for object in allObjects:
    if object.type == 'Armature':
      modelObs[object.name] = object

    if object.type == 'Mesh':
      parentArmOb = BPyObject.getObjectArmature(object)
      if not parentArmOb.name in modelMeshes:
        modelMeshes[parentArmOb.name] = []
      modelMeshes[parentArmOb.name].append(object)

  for modelObName in modelObs.keys():

    # Write Skeleton
    filedata += "skeleton\n"

    armOb = modelObs[modelObName]
    armature = armOb.data

    # Calc bone depths and sort
    boneDepths = []
    for bone in armature.bones.values():
      boneDepth = getBoneTreeDepth(bone, 0)
      boneDepths.append((bone, boneDepth))

    boneDepths = sorted(boneDepths, key=lambda k: k[0].name)
    boneDepths = sorted(boneDepths, key=lambda k: k[1])
    sortedBones = boneDepths

    for boneid, boneTuple in enumerate(sortedBones):
      boneIds[boneTuple[0].name] = boneid
      #print 'boneId: %d: %s (depth:%s)' % (boneid, boneTuple[0].name, sortedBones[boneid][1])

    # Write World Bone
    filedata += '%d "%s" %d ' % (0, armOb.name, -1)
    filedata += '%.8f %.8f %.8f ' % (0.0, 0.0, 0.0)
    filedata += '%.8f %.8f %.8f %.8f ' % (0.0, 0.0, 0.0, 1.0)
    filedata += '%.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f\n' % (1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0)

    for boneid, boneTuple in enumerate(sortedBones):
      bone = boneTuple[0]
      boneDepth = boneTuple[1]
      #boneid = boneid + 1 # World bone is zero

      position, orientationQuat = getTranslationOrientation(bone, file)

      # Get Inverse World Matrix for bone
      t = bone.matrix['ARMATURESPACE'].copy().invert()
      invWorldMatrix = Matrix([t[0][1], -t[0][0], t[0][2], t[0][3]],
                [t[1][1], -t[1][0], t[1][2], t[1][3]],
                [t[2][1], -t[2][0], t[2][2], t[2][3]],
                [t[3][1], -t[3][0], t[3][2], t[3][3]])

      outputBoneName = bone.name
      if len(outputBoneName) == 29:
        for item in armOb.getAllProperties():
          if (("B_" + outputBoneName) == item.getName()):
            outputBoneName = item.getData()
            print 'Decode Bone Name: "%s" >' % item.getName()
            print '                  "%s"' % item.getData()
            break

      filedata += '%d "%s" ' % (boneid + 1, outputBoneName)   # Adjust bone ids + 1 as zero is the World Bone

      parentBoneId = 0
      if bone.hasParent():
        parentBoneId = boneIds[bone.parent.name] + 1   # Adjust bone ids + 1 as zero is the World Bone

      filedata += '%d ' % parentBoneId
      filedata +='%.8f %.8f %.8f ' % (position[0], position[1], position[2])
      filedata +='%.8f %.8f %.8f %.8f ' % (orientationQuat[1], orientationQuat[2], orientationQuat[3], orientationQuat[0]) # GR2 uses x,y,z,w for Quaternions rather than w,x,y,z
      filedata += '%.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f %.8f' % (invWorldMatrix[0][0], invWorldMatrix[0][1], invWorldMatrix[0][2], invWorldMatrix[0][3],
                                        invWorldMatrix[1][0], invWorldMatrix[1][1], invWorldMatrix[1][2], invWorldMatrix[1][3],
                                        invWorldMatrix[2][0], invWorldMatrix[2][1], invWorldMatrix[2][2], invWorldMatrix[2][3],
                                        invWorldMatrix[3][0], invWorldMatrix[3][1], invWorldMatrix[3][2], invWorldMatrix[3][3])
      #End of bone line
      filedata += "\n"

    filedata += 'meshes:%d\n' % len(modelMeshes[modelObName])

    for meshObject in modelMeshes[modelObName]:

      mesh = meshObject.data
      meshName = meshObject.name

      filedata += 'mesh:"%s"\n' % meshName

      parentArmOb = BPyObject.getObjectArmature(meshObject)

      # Fetch long mesh names from Armature properties
      if len(meshName) == 19:
        for item in parentArmOb.getAllProperties():
          if ("M_" + meshName == item.getName()):
            meshName = item.getData()
            print 'Decode Mesh Name: %s > %s' % (item.getName(), item.getData())
            break

      #file.write('meshname:%s\n' % meshName)
      #file.write('parent Arm:%s\n' % parentArmOb)

      weights = meshNormalizedWeights(mesh)
      vertexBoneWeights = {}
      for boneName in parentArmOb.data.bones.keys():
        vgroupDataForBone = getBoneWeights(boneName, weights)
        #file.write('bone:%s vg:%s\n' % (boneName, vgroupDataForBone))

        for vgData in vgroupDataForBone:
          vertexId = vgData[0]
          weight = vgData[1]
          if not vertexId in vertexBoneWeights:
            vertexBoneWeights[vertexId] = []
          vertexBoneWeights[vertexId].append((boneName, weight))
          #file.write('vert:%d bone:%s \n' % (vertexId, (boneName, weight)))

      grannyVertexBoneWeights = {}
      for vertId in vertexBoneWeights.keys():
        #file.write('vert:%d ' % vertId)

        boneIdsList = []
        boneWeightsList = []
        firstBoneId = 0
        for i in range(4):
          if i < len(vertexBoneWeights[vertId]):
            vertexBoneWeightTuple = vertexBoneWeights[vertId][i]
            boneName = vertexBoneWeightTuple[0]
            boneIdsList.append(boneIds[boneName] + 1)
            boneWeightsList.append(round(vertexBoneWeightTuple[1] * 255))
            if i == 0:
              firstBoneId = boneIds[boneName] + 1
          else:
            boneIdsList.append(firstBoneId)
            boneWeightsList.append(0)

        runningTotal = 0
        for i, weight in enumerate(boneWeightsList):
          runningTotal = runningTotal + weight
          if runningTotal > 255:
            boneWeightsList[i] = weight - 1
            break

        if not vertId in grannyVertexBoneWeights:
          grannyVertexBoneWeights[vertId] = []
        grannyVertexBoneWeights[vertId] = (boneIdsList, boneWeightsList)

        #file.write('%s %s ' % (boneIdsList, boneWeightsList))
        #file.write("\n")

      position, orientationQuat = getTranslationOrientation(meshObject, file)

      #file.write('position:%.8f %.8f %.8f\n' % (position[0], position[1], position[2]))
      #file.write('orientationQuat:%.8f %.8f %.8f %.8f\n' % (orientationQuat[1], orientationQuat[2], orientationQuat[3], orientationQuat[0]))
      #file.write(meshName+"\n")

      filedata += "vertices\n"

      # Determine unique vertex/UVs for output
      uniqueVertSet = set()
      uniqueVertUVIndexes = {}
      uniqueVertUVs = []
      currentVertUVIndex = 0

      currentTriangleId = 0
      triangleVertUVIndexes = []

      for triangle in mesh.faces:
        vertIds = [v.index for v in triangle]
        vertIds = tuple(vertIds)
        triangleVertUVIndexes.append([])

        for i, uv in enumerate(triangle.uv):
          vertexId = vertIds[i]
          uvt = tuple(uv)
          vertSig = '%i|%.8f|%.8f' % (vertexId, uvt[0], uvt[1])

          if vertSig in uniqueVertSet:
            triangleVertUVIndex = uniqueVertUVIndexes[vertSig]
          else:
            uniqueVertSet.add(vertSig)
            uniqueVertUVIndexes[vertSig] = currentVertUVIndex
            uniqueVertUVs.append((vertexId, uvt[0], uvt[1]))
            triangleVertUVIndex = currentVertUVIndex
            currentVertUVIndex = currentVertUVIndex + 1

          triangleVertUVIndexes[currentTriangleId].append(triangleVertUVIndex)
        currentTriangleId = currentTriangleId + 1

      meshVerts = {}
      for i,vert in enumerate(mesh.verts):
        meshVerts[i] = vert

      # Write Vertices
      for uniqueVertUV in uniqueVertUVs:

        index = uniqueVertUV[0]
        vert = meshVerts[index]
        vertCoord = tuple(vert.co)
        vertNormal = tuple(vert.no)
        filedata +='%.8f %.8f %.8f ' % (vertCoord[0] + position[0], vertCoord[1] + position[1], vertCoord[2] +  position[2])
        filedata +='%.8f %.8f %.8f ' % vertNormal
        filedata +='%.8f %.8f ' % (uniqueVertUV[1], 1 - uniqueVertUV[2])

        if index in grannyVertexBoneWeights:
          vBoneWeightTuple = grannyVertexBoneWeights[index]
        else:
          raise "Error: Mesh has unweighted vertices!"
          #vBoneWeightTuple = ([-1,-1,-1,-1],[-1,-1,-1,-1]) # Unweighted vertex - raise error

        filedata +='%d %d %d %d ' % (vBoneWeightTuple[0][0], vBoneWeightTuple[0][1],vBoneWeightTuple[0][2],vBoneWeightTuple[0][3]) # Bone Ids
        filedata +='%d %d %d %d\n' % (vBoneWeightTuple[1][0], vBoneWeightTuple[1][1],vBoneWeightTuple[1][2],vBoneWeightTuple[1][3]) # Bone Weights

      # Write Triangles
      filedata += "triangles\n"
      for triangle in triangleVertUVIndexes:
        #filedata += '%i %i %i\n' % tuple(triangle)
        filedata += '%i %i %i\n' % (triangle[0],triangle[1],triangle[2])

  filedata += "end"
  file.write(filedata)
  file.close()
  Blender.Window.WaitCursor(0)
  print "End BR2 Export."
Ejemplo n.º 14
0
def write(filename, objects,\
EXPORT_APPLY_MODIFIERS=True, EXPORT_ROTX90=True):
    '''
	Basic write function. The context and options must be alredy set
	This can be accessed externaly
	eg.
	write( 'c:\\test\\foobar.obj', Blender.Object.GetSelected() ) # Using default options.
	'''
    def veckey3d(v):
        return round(v.x, 6), round(v.y, 6), round(v.z, 6)

    def veckey2d(v):
        return round(v.x, 6), round(v.y, 6)

    print 'EOL MESH Export path: "%s"' % filename
    temp_mesh_name = '~tmp-mesh'
    time1 = sys.time()
    scn = Scene.GetCurrent()
    file = open(filename, "w")

    # Write Header
    file.write('# Blender3D v%s EOL MESH File: %s\n' %
               (Blender.Get('version'),
                Blender.Get('filename').split('/')[-1].split('\\')[-1]))
    file.write('# www.blender3d.org\n')

    # Get the container mesh. - used for applying modifiers and non mesh objects.
    containerMesh = meshName = tempMesh = None
    for meshName in Blender.NMesh.GetNames():
        if meshName.startswith(temp_mesh_name):
            tempMesh = Mesh.Get(meshName)
            if not tempMesh.users:
                containerMesh = tempMesh
    if not containerMesh:
        containerMesh = Mesh.New(temp_mesh_name)

    if EXPORT_ROTX90:
        mat_xrot90 = Blender.Mathutils.RotationMatrix(-90, 4, 'x')

    del meshName
    del tempMesh

    # Initialize totals, these are updated each object
    totverts = totuvco = totno = 1

    face_vert_index = 1

    globalNormals = {}

    # Get all meshs
    for ob_main in objects:
        for ob, ob_mat in BPyObject.getDerivedObjects(ob_main):
            # Will work for non meshes now! :)
            # getMeshFromObject(ob, container_mesh=None, apply_modifiers=True, vgroups=True, scn=None)
            me = BPyMesh.getMeshFromObject(ob, containerMesh,
                                           EXPORT_APPLY_MODIFIERS, False, scn)
            if not me:
                continue

            faceuv = me.faceUV
            has_quads = False
            for f in me.faces:
                if len(f) == 4:
                    has_quads = True
                    break
            if has_quads:
                oldmode = Mesh.Mode()
                Mesh.Mode(Mesh.SelectModes['FACE'])
                me.sel = True
                tempob = scn.objects.new(me)
                me.quadToTriangle(0)  # more=0 shortest length
                oldmode = Mesh.Mode(oldmode)
                scn.objects.unlink(tempob)
                Mesh.Mode(oldmode)
            edges = me.edges

            faces = [f for f in me.faces]
            if EXPORT_ROTX90:
                me.transform(ob_mat * mat_xrot90)
            else:
                me.transform(ob_mat)

            # Vert
            mesh = ob.getData()
            objmat = ob.getMatrix()
            for i in objmat:
                file.write('obm: %.6f %.6f %.6f %.6f\n' % tuple(i))
            vgrouplist = mesh.getVertGroupNames()
            file.write('vgroupcount: %i\n' % len(vgrouplist))
            for vgname in vgrouplist:
                file.write('vgroup: %s\n' % vgname)
            file.write('vertexcount: %i\n' % len(mesh.verts))
            for v in mesh.verts:
                file.write('v %.6f %.6f %.6f\n' % tuple(v.co))
                influences = mesh.getVertexInfluences(v.index)
                file.write('influence: %i\n' % len(influences))
                for name, weight in influences:
                    file.write('groupname: %s\n' % name)
                    file.write('weight: %f\n' % weight)

            # UV
            if faceuv:
                uv_face_mapping = [[0, 0, 0, 0] for f in faces
                                   ]  # a bit of a waste for tri's :/

                uv_dict = {}  # could use a set() here
                for f_index, f in enumerate(faces):

                    for uv_index, uv in enumerate(f.uv):
                        uvkey = veckey2d(uv)
                        try:
                            uv_face_mapping[f_index][uv_index] = uv_dict[uvkey]
                        except:
                            uv_face_mapping[f_index][uv_index] = uv_dict[
                                uvkey] = len(uv_dict)
                            file.write('vt %.6f %.6f\n' % tuple(uv))

                uv_unique_count = len(uv_dict)
                del uv, uvkey, uv_dict, f_index, uv_index
                # Only need uv_unique_count and uv_face_mapping
                file.write('uvcount: %i\n' % uv_unique_count)
            # NORMAL, Smooth/Non smoothed.
            for f in faces:
                if f.smooth:
                    for v in f:
                        noKey = veckey3d(v.no)
                        if not globalNormals.has_key(noKey):
                            globalNormals[noKey] = totno
                            totno += 1
                            file.write('vn %.6f %.6f %.6f\n' % noKey)
                else:
                    # Hard, 1 normal from the face.
                    noKey = veckey3d(f.no)
                    if not globalNormals.has_key(noKey):
                        globalNormals[noKey] = totno
                        totno += 1
                        file.write('vn %.6f %.6f %.6f\n' % noKey)
            file.write('normalcount: %i\n' % len(globalNormals))

            if not faceuv:
                f_image = None

            file.write('facecount: %i\n' % len(faces))
            for f_index, f in enumerate(faces):
                f_v = f.v
                f_smooth = f.smooth
                if faceuv:
                    f_uv = f.uv

                file.write('f')
                if faceuv:
                    if f_smooth:  # Smoothed, use vertex normals
                        for vi, v in enumerate(f_v):
                            file.write( ' %d/%d/%d' % (\
                             v.index+totverts,\
                             totuvco + uv_face_mapping[f_index][vi],\
                             globalNormals[ veckey3d(v.no) ])) # vert, uv, normal

                    else:  # No smoothing, face normals
                        no = globalNormals[veckey3d(f.no)]
                        for vi, v in enumerate(f_v):
                            file.write( ' %d/%d/%d' % (\
                             v.index+totverts,\
                             totuvco + uv_face_mapping[f_index][vi],\
                             no)) # vert, uv, normal

                    face_vert_index += len(f_v)

                else:  # No UV's
                    if f_smooth:  # Smoothed, use vertex normals
                        for v in f_v:
                            file.write( ' %d//%d' % (\
                             v.index+totverts,\
                             globalNormals[ veckey3d(v.no) ]))
                    else:  # No smoothing, face normals
                        no = globalNormals[veckey3d(f.no)]
                        for v in f_v:
                            file.write( ' %d//%d' % (\
                             v.index+totverts,\
                             no))

                file.write('\n')

            # Write edges.
            LOOSE = Mesh.EdgeFlags.LOOSE
            for ed in edges:
                if ed.flag & LOOSE:
                    file.write(
                        'f %d %d\n' %
                        (ed.v1.index + totverts, ed.v2.index + totverts))

            # Make the indicies global rather then per mesh
            totverts += len(me.verts)
            if faceuv:
                totuvco += uv_unique_count
            me.verts = None
    file.close()

    # Now we have all our materials, save them

    print "MESH Export time: %.2f" % (sys.time() - time1)
Ejemplo n.º 15
0
def write(filename, objects,\
EXPORT_APPLY_MODIFIERS=True, EXPORT_ROTX90=True):
	'''
	Basic write function. The context and options must be alredy set
	This can be accessed externaly
	eg.
	write( 'c:\\test\\foobar.obj', Blender.Object.GetSelected() ) # Using default options.
	'''
	
	def veckey3d(v):
		return round(v.x, 6), round(v.y, 6), round(v.z, 6)
		
	def veckey2d(v):
		return round(v.x, 6), round(v.y, 6)
	
	print 'EOL MESH Export path: "%s"' % filename
	temp_mesh_name = '~tmp-mesh'
	time1 = sys.time()
	scn = Scene.GetCurrent()
	file = open(filename, "w")
	
	# Write Header
	file.write('# Blender3D v%s EOL MESH File: %s\n' % (Blender.Get('version'), Blender.Get('filename').split('/')[-1].split('\\')[-1] ))
	file.write('# www.blender3d.org\n')
	
	# Get the container mesh. - used for applying modifiers and non mesh objects.
	containerMesh = meshName = tempMesh = None
	for meshName in Blender.NMesh.GetNames():
		if meshName.startswith(temp_mesh_name):
			tempMesh = Mesh.Get(meshName)
			if not tempMesh.users:
				containerMesh = tempMesh
	if not containerMesh:
		containerMesh = Mesh.New(temp_mesh_name)
	
	if EXPORT_ROTX90:
		mat_xrot90= Blender.Mathutils.RotationMatrix(-90, 4, 'x')
		
	del meshName
	del tempMesh
	
	# Initialize totals, these are updated each object
	totverts = totuvco = totno = 1
	
	face_vert_index = 1
	
	globalNormals = {}
	
	# Get all meshs
	for ob_main in objects:
		for ob, ob_mat in BPyObject.getDerivedObjects(ob_main):
			# Will work for non meshes now! :)
			# getMeshFromObject(ob, container_mesh=None, apply_modifiers=True, vgroups=True, scn=None)
			me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, False, scn)
			if not me:
				continue
			
			faceuv= me.faceUV
			has_quads = False
			for f in me.faces:
				if len(f) == 4:
					has_quads = True
					break
			if has_quads:
				oldmode = Mesh.Mode()
				Mesh.Mode(Mesh.SelectModes['FACE'])
				me.sel = True
				tempob = scn.objects.new(me)
				me.quadToTriangle(0) # more=0 shortest length
				oldmode = Mesh.Mode(oldmode)
				scn.objects.unlink(tempob)
				Mesh.Mode(oldmode)
			edges = me.edges
			
			faces = [ f for f in me.faces ]
			if EXPORT_ROTX90:
				me.transform(ob_mat*mat_xrot90)
			else:
				me.transform(ob_mat)
			
			# Vert
			mesh = ob.getData()
			objmat = ob.getMatrix()
			for i in objmat:
				file.write('obm: %.6f %.6f %.6f %.6f\n' % tuple(i))
			vgrouplist = mesh.getVertGroupNames()
			file.write('vgroupcount: %i\n' % len(vgrouplist))
			for vgname in vgrouplist:
				file.write('vgroup: %s\n' % vgname)
			file.write('vertexcount: %i\n' % len(mesh.verts))
			for v in mesh.verts:
				file.write('v %.6f %.6f %.6f\n' % tuple(v.co))
				influences = mesh.getVertexInfluences(v.index)
				file.write('influence: %i\n' % len(influences))
				for name,weight in influences:
					file.write('groupname: %s\n' % name)
					file.write('weight: %f\n' % weight)
			
			# UV
			if faceuv:
				uv_face_mapping = [[0,0,0,0] for f in faces] # a bit of a waste for tri's :/
				
				uv_dict = {} # could use a set() here
				for f_index, f in enumerate(faces):
					
					for uv_index, uv in enumerate(f.uv):
						uvkey = veckey2d(uv)
						try:
							uv_face_mapping[f_index][uv_index] = uv_dict[uvkey]
						except:
							uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] = len(uv_dict)
							file.write('vt %.6f %.6f\n' % tuple(uv))
				
				uv_unique_count = len(uv_dict)
				del uv, uvkey, uv_dict, f_index, uv_index
				# Only need uv_unique_count and uv_face_mapping
				file.write('uvcount: %i\n' % uv_unique_count)
			# NORMAL, Smooth/Non smoothed.
			for f in faces:
				if f.smooth:
					for v in f:
						noKey = veckey3d(v.no)
						if not globalNormals.has_key( noKey ):
							globalNormals[noKey] = totno
							totno +=1
							file.write('vn %.6f %.6f %.6f\n' % noKey)
				else:
					# Hard, 1 normal from the face.
					noKey = veckey3d(f.no)
					if not globalNormals.has_key( noKey ):
						globalNormals[noKey] = totno
						totno +=1
						file.write('vn %.6f %.6f %.6f\n' % noKey)
			file.write('normalcount: %i\n' % len(globalNormals))
			
			if not faceuv:
				f_image = None
			
			file.write('facecount: %i\n' % len(faces))
			for f_index, f in enumerate(faces):
				f_v= f.v
				f_smooth= f.smooth
				if faceuv:
					f_uv= f.uv
				
				file.write('f')
				if faceuv:
					if f_smooth: # Smoothed, use vertex normals
						for vi, v in enumerate(f_v):
							file.write( ' %d/%d/%d' % (\
								v.index+totverts,\
								totuvco + uv_face_mapping[f_index][vi],\
								globalNormals[ veckey3d(v.no) ])) # vert, uv, normal

					else: # No smoothing, face normals
						no = globalNormals[ veckey3d(f.no) ]
						for vi, v in enumerate(f_v):
							file.write( ' %d/%d/%d' % (\
								v.index+totverts,\
								totuvco + uv_face_mapping[f_index][vi],\
								no)) # vert, uv, normal
					
					face_vert_index += len(f_v)
				
				else: # No UV's
					if f_smooth: # Smoothed, use vertex normals
						for v in f_v:
							file.write( ' %d//%d' % (\
								v.index+totverts,\
								globalNormals[ veckey3d(v.no) ]))
					else: # No smoothing, face normals
						no = globalNormals[ veckey3d(f.no) ]
						for v in f_v:
							file.write( ' %d//%d' % (\
								v.index+totverts,\
								no))
						
				file.write('\n')
			
			# Write edges.
			LOOSE= Mesh.EdgeFlags.LOOSE
			for ed in edges:
				if ed.flag & LOOSE:
					file.write('f %d %d\n' % (ed.v1.index+totverts, ed.v2.index+totverts))
				
			# Make the indicies global rather then per mesh
			totverts += len(me.verts)
			if faceuv:
				totuvco += uv_unique_count
			me.verts= None
	file.close()
	
	
	# Now we have all our materials, save them
	
	print "MESH Export time: %.2f" % (sys.time() - time1)