def add_asset(self, obj): model_configuration = None base_matrix = obj.matrix_basis.inverted() free, derived_objects = create_derived_objects(self._scene, obj) if derived_objects is None: return None, None asset = Asset(id_=tools.safe_query_selector_id(obj.data.name)) if len(derived_objects) == 1: (derived_object, matrix) = derived_objects[0] asset.matrix = base_matrix * matrix model_configuration = self.add_asset_data(asset, derived_object) else: for derived_object, matrix in derived_objects: model_configuration = ModelConfiguration() if derived_object.type not in { 'MESH', 'CURVE', 'SURFACE', 'FONT', 'META' }: continue submodel_configuration = self.add_subasset( asset, derived_object, base_matrix * matrix) model_configuration.children.append(submodel_configuration) if free: free_derived_objects(obj) self.assets.append(asset) return asset.id, model_configuration
def add_asset(self, obj): model_configuration = None base_matrix = obj.matrix_basis.inverted() free, derived_objects = create_derived_objects(self._scene, obj) if derived_objects is None: return None, None asset = Asset(id_=tools.safe_query_selector_id(obj.data.name)) if len(derived_objects) == 1: (derived_object, matrix) = derived_objects[0] asset.matrix = base_matrix * matrix model_configuration = self.add_asset_data(asset, derived_object) else: for derived_object, matrix in derived_objects: model_configuration = ModelConfiguration() if derived_object.type not in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META'}: continue submodel_configuration = self.add_subasset(asset, derived_object, base_matrix * matrix) model_configuration.children.append(submodel_configuration) if free: free_derived_objects(obj) self.assets.append(asset) return asset.id, model_configuration
def build_entities( self ): from bpy_extras.io_utils import create_derived_objects, free_derived_objects for ob in self.objects: # The object represents a mesh if ob.type == 'MESH': # get derived objects free, derived = create_derived_objects( self.scene, ob ) if derived is None: continue # create a binding entity parentEntityIdx = -1 parentArmatureObject = ob.find_armature() if parentArmatureObject is not None: parentEntityIdx = self.add_armature_entity( parentArmatureObject ) else: parentEntityIdx = self.add_node_entity( ob ) # create meshes for obDerived, objectMtx in derived: try: derivedBlenderMesh = obDerived.to_mesh( self.scene, False, 'PREVIEW' ) except: derivedBlenderMesh = None if derivedBlenderMesh: self.map_materials( derivedBlenderMesh ) meshes = [] meshName = "%s" % ob.name tamy_mesh.create_tamy_meshes( meshName, obDerived, derivedBlenderMesh, self.materialsDict, meshes ) self.add_geometry_component( obDerived, meshes, parentEntityIdx ) # cleanup if free: free_derived_objects( derivedBlenderMesh ) # The object represents a light elif ob.type == 'LAMP': self.add_light_entity( ob ) elif ob.type == 'ARMATURE': self.add_armature_entity( ob)
def exportMeshes(scene, file): if bpy.ops.object.mode_set.poll(): bpy.ops.object.mode_set(mode='OBJECT') mesh_objects = [] for obj in scene.objects: free, derived = create_derived_objects(scene, obj) if derived is None: continue for ob_derived, matrix in derived: if obj.type == 'EMPTY': pass elif obj.type == 'LIGHT': light = obj.data # file.write("light: \"%s\"\n" % str(light.name)) # file.write("%s " % str(round(obj.location.x, 6))) # file.write("%s " % str(round(obj.location.y, 6))) # file.write("%s\n" % str(round(obj.location.z, 6))) # file.write("%s " % str(round(light.color.r, 2))) # file.write("%s " % str(round(light.color.g, 2))) # file.write("%s\n" % str(round(light.color.b, 2))) # file.write("\n") elif obj.type in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META'}: theMesh = ob_derived.to_mesh() if theMesh is None: continue theMesh.transform(matrix) try: dumpMesh(theMesh, file, ob_derived) except Exception as e: if hasattr(e, 'message'): errorMsg = e.message else: errorMsg = str(e) sys.stderr.write( f"Skipping mesh: '{theMesh.name}' ({errorMsg})\n") file.write("\n") else: sys.stderr.write("Skipping unknown type: '%s'\n" % str(obj.type)) if free: free_derived_objects(obj)
def build_entities_and_materials( scene, objects, outMaterials, outEntities, outMaterialsDict, outTexturesDict, outEntitiesDict ): from bpy_extras.io_utils import create_derived_objects, free_derived_objects for ob in objects: # get derived objects free, derived = create_derived_objects(scene, ob) if derived is None: continue for obDerived, objectMtx in derived: tamyEntity = None tamyEntityType = '' # The object represents a mesh if ob.type in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META'}: try: derivedBlenderMesh = obDerived.to_mesh( scene, True, 'PREVIEW' ) except: derivedBlenderMesh = None if derivedBlenderMesh: build_materials( derivedBlenderMesh, outMaterials, outMaterialsDict, outTexturesDict ) meshes = [] meshName = "%s" % ob.name tamy_mesh.create_tamy_meshes( meshName, derivedBlenderMesh, outMaterialsDict, meshes ) tamyEntity = tamy_entities.TamyGeometry( meshes, ob.name ) tamyEntityType = 'MESH' # cleanup if free: free_derived_objects( derivedBlenderMesh ) # The object represents a light elif ob.type == 'LAMP': tamyEntityType = 'LIGHT' tamyEntity = tamy_entities.TamyLight( ob.name, ob.data ) # add new entity to our list if tamyEntity is not None: entityIdx = len( outEntities ) outEntitiesDict[ob] = entityIdx outEntities.append( ( tamyEntityType, obDerived, objectMtx, tamyEntity ) )
def save( operator, context, filepath="", use_selection=True, global_matrix=None, ): import bpy import mathutils import time from bpy_extras.io_utils import create_derived_objects, free_derived_objects """Save the Blender scene to a 3ds file.""" # Time the export time1 = time.clock() #Blender.Window.WaitCursor(1) if global_matrix is None: global_matrix = mathutils.Matrix() if bpy.ops.object.mode_set.poll(): bpy.ops.object.mode_set(mode='OBJECT') # Initialize the main chunk (primary): primary = _3ds_chunk(PRIMARY) # Add version chunk: version_chunk = _3ds_chunk(VERSION) version_chunk.add_variable("version", _3ds_uint(3)) primary.add_subchunk(version_chunk) # init main object info chunk: object_info = _3ds_chunk(OBJECTINFO) ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX # init main key frame data chunk: kfdata = make_kfdata() ''' # Make a list of all materials used in the selected meshes (use a dictionary, # each material is added once): materialDict = {} mesh_objects = [] scene = context.scene depsgraph = context.evaluated_depsgraph_get() if use_selection: objects = (ob for ob in scene.objects if ob.is_visible(scene) and ob.select) else: objects = (ob for ob in scene.objects if ob.is_visible(scene)) for ob in objects: # get derived objects free, derived = create_derived_objects(scene, ob) if derived is None: continue for ob_derived, mat in derived: if ob.type not in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META'}: continue ob_derived_eval = ob_derived.evaluated_get(depsgraph) try: data = ob_derived_eval.to_mesh() except: data = None if data: matrix = global_matrix * mat data.transform(matrix) mesh_objects.append((ob_derived, data, matrix)) mat_ls = data.materials mat_ls_len = len(mat_ls) # get material/image tuples. if data.tessface_uv_textures: if not mat_ls: mat = mat_name = None for f, uf in zip(data.tessfaces, data.tessface_uv_textures.active.data): if mat_ls: mat_index = f.material_index if mat_index >= mat_ls_len: mat_index = f.mat = 0 mat = mat_ls[mat_index] mat_name = None if mat is None else mat.name # else there already set to none img = uf.image img_name = None if img is None else img.name materialDict.setdefault((mat_name, img_name), (mat, img)) else: for mat in mat_ls: if mat: # material may be None so check its not. materialDict.setdefault((mat.name, None), (mat, None)) # Why 0 Why! for f in data.tessfaces: if f.material_index >= mat_ls_len: f.material_index = 0 ob_derived_eval.to_mesh_clear() if free: free_derived_objects(ob) # Make material chunks for all materials used in the meshes: for mat_and_image in materialDict.values(): object_info.add_subchunk( make_material_chunk(mat_and_image[0], mat_and_image[1])) # Give all objects a unique ID and build a dictionary from object name to object id: """ name_to_id = {} for ob, data in mesh_objects: name_to_id[ob.name]= len(name_to_id) #for ob in empty_objects: # name_to_id[ob.name]= len(name_to_id) """ # Create object chunks for all meshes: i = 0 for ob, blender_mesh, matrix in mesh_objects: # create a new object chunk object_chunk = _3ds_chunk(OBJECT) # set the object name object_chunk.add_variable("name", _3ds_string(sane_name(ob.name))) # make a mesh chunk out of the mesh: object_chunk.add_subchunk( make_mesh_chunk(blender_mesh, matrix, materialDict)) # ensure the mesh has no over sized arrays # skip ones that do!, otherwise we cant write since the array size wont # fit into USHORT. if object_chunk.validate(): object_info.add_subchunk(object_chunk) else: operator.report({'WARNING'}, "Object %r can't be written into a 3DS file") ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX # make a kf object node for the object: kfdata.add_subchunk(make_kf_obj_node(ob, name_to_id)) ''' if not blender_mesh.users: bpy.data.meshes.remove(blender_mesh) #blender_mesh.vertices = None i += i # Create chunks for all empties: ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX for ob in empty_objects: # Empties only require a kf object node: kfdata.add_subchunk(make_kf_obj_node(ob, name_to_id)) pass ''' # Add main object info chunk to primary chunk: primary.add_subchunk(object_info) ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX # Add main keyframe data chunk to primary chunk: primary.add_subchunk(kfdata) ''' # At this point, the chunk hierarchy is completely built. # Check the size: primary.get_size() # Open the file for writing: file = open(filepath, 'wb') # Recursively write the chunks to file: primary.write(file) # Close the file: file.close() # Clear name mapping vars, could make locals too del name_unique[:] name_mapping.clear() # Debugging only: report the exporting time: #Blender.Window.WaitCursor(0) print("3ds export time: %.2f" % (time.clock() - time1)) # Debugging only: dump the chunk hierarchy: #primary.dump() return {'FINISHED'}
def save(operator, context, filepath="", use_selection=True, global_matrix=None, ): import bpy import mathutils import time from bpy_extras.io_utils import create_derived_objects, free_derived_objects '''Save the Blender scene to a 3ds file.''' # Time the export time1 = time.clock() # Blender.Window.WaitCursor(1) if global_matrix is None: global_matrix = mathutils.Matrix() if bpy.ops.object.mode_set.poll(): bpy.ops.object.mode_set(mode='OBJECT') # Initialize the main chunk (primary): primary = _3ds_chunk(PRIMARY) # Add version chunk: version_chunk = _3ds_chunk(VERSION) version_chunk.add_variable("version", _3ds_uint(3)) primary.add_subchunk(version_chunk) # init main object info chunk: object_info = _3ds_chunk(OBJECTINFO) ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX # init main key frame data chunk: kfdata = make_kfdata() ''' # Make a list of all materials used in the selected meshes (use a dictionary, # each material is added once): materialDict = {} mesh_objects = [] scene = context.scene if use_selection: objects = (ob for ob in scene.objects if ob.is_visible(scene) and ob.select) else: objects = (ob for ob in scene.objects if ob.is_visible(scene)) for ob in objects: # get derived objects free, derived = create_derived_objects(scene, ob) if derived is None: continue for ob_derived, mat in derived: if ob.type not in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META'}: continue try: data = ob_derived.to_mesh(scene, True, 'PREVIEW') except: data = None if data: matrix = global_matrix * mat data.transform(matrix) mesh_objects.append((ob_derived, data, matrix)) mat_ls = data.materials mat_ls_len = len(mat_ls) # get material/image tuples. if data.tessface_uv_textures: if not mat_ls: mat = mat_name = None for f, uf in zip(data.tessfaces, data.tessface_uv_textures.active.data): if mat_ls: mat_index = f.material_index if mat_index >= mat_ls_len: mat_index = f.mat = 0 mat = mat_ls[mat_index] mat_name = None if mat is None else mat.name # else there already set to none img = uf.image img_name = None if img is None else img.name materialDict.setdefault((mat_name, img_name), (mat, img)) else: for mat in mat_ls: if mat: # material may be None so check its not. materialDict.setdefault((mat.name, None), (mat, None)) # Why 0 Why! for f in data.tessfaces: if f.material_index >= mat_ls_len: f.material_index = 0 if free: free_derived_objects(ob) # Make material chunks for all materials used in the meshes: for mat_and_image in materialDict.values(): object_info.add_subchunk(make_material_chunk(mat_and_image[0], mat_and_image[1])) # Give all objects a unique ID and build a dictionary from object name to object id: """ name_to_id = {} for ob, data in mesh_objects: name_to_id[ob.name]= len(name_to_id) #for ob in empty_objects: # name_to_id[ob.name]= len(name_to_id) """ # Create object chunks for all meshes: i = 0 for ob, blender_mesh, matrix in mesh_objects: # create a new object chunk object_chunk = _3ds_chunk(OBJECT) # set the object name object_chunk.add_variable("name", _3ds_string(sane_name(ob.name))) # make a mesh chunk out of the mesh: object_chunk.add_subchunk(make_mesh_chunk(blender_mesh, matrix, materialDict)) # ensure the mesh has no over sized arrays # skip ones that do!, otherwise we cant write since the array size wont # fit into USHORT. if object_chunk.validate(): object_info.add_subchunk(object_chunk) else: operator.report({'WARNING'}, "Object %r can't be written into a 3DS file") ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX # make a kf object node for the object: kfdata.add_subchunk(make_kf_obj_node(ob, name_to_id)) ''' if not blender_mesh.users: bpy.data.meshes.remove(blender_mesh) # blender_mesh.vertices = None i += i # Create chunks for all empties: ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX for ob in empty_objects: # Empties only require a kf object node: kfdata.add_subchunk(make_kf_obj_node(ob, name_to_id)) pass ''' # Add main object info chunk to primary chunk: primary.add_subchunk(object_info) ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX # Add main keyframe data chunk to primary chunk: primary.add_subchunk(kfdata) ''' # At this point, the chunk hierarchy is completely built. # Check the size: primary.get_size() # Open the file for writing: file = open(filepath, 'wb') # Recursively write the chunks to file: primary.write(file) # Close the file: file.close() # Clear name mapping vars, could make locals too name_unique[:] = [] name_mapping.clear() # Debugging only: report the exporting time: # Blender.Window.WaitCursor(0) print("3ds export time: %.2f" % (time.clock() - time1)) # Debugging only: dump the chunk hierarchy: #primary.dump() return {'FINISHED'}
def export_object(obj_main_parent, obj_main, obj_children): """Export Object Hierarchy (recursively called).""" matrix_fallback = mathutils.Matrix() world = scene.world free, derived = create_derived_objects(scene, obj_main) obj_main_matrix_world = obj_main.matrix_world if obj_main_parent: obj_main_matrix = obj_main_parent.matrix_world.inverted(matrix_fallback) * obj_main_matrix_world else: obj_main_matrix = obj_main_matrix_world obj_main_matrix_world_invert = obj_main_matrix_world.inverted(matrix_fallback) obj_main_id = unique_name(obj_main, obj_main.name, uuid_cache_object, clean_func=slugify, sep='_') (skipUselessTransform, supplementaryCurvyBracket) = write_transform_begin(obj_main, obj_main_matrix if obj_main_parent else global_matrix * obj_main_matrix, obj_main_id) for obj, obj_matrix in (() if derived is None else derived): obj_type = obj.type obj_matrix = obj_main_matrix_world_invert * obj_matrix # Make transform node relative. if obj_type in {'MESH', 'CURVE', 'SURFACE', 'FONT'}: if (obj_type != 'MESH') or (use_mesh_modifiers and obj.is_modified(scene, 'PREVIEW')): me = obj.to_mesh(scene, use_mesh_modifiers, 'PREVIEW') do_remove = True else: me = obj.data do_remove = False if me is not None: # ensure unique name, we could also do this by # postponing mesh removal, but clearing data - TODO if do_remove: me.name = obj.name.rstrip('1234567890').rstrip('.') me_name_new = me_name_org = me.name count = 0 while me_name_new in mesh_name_set: me.name = '%.17s.%03d' % (me_name_org, count) me_name_new = me.name count += 1 mesh_name_set.add(me_name_new) del me_name_new, me_name_org, count write_indexed_face_set(obj, me, obj_matrix, world) # Rree mesh created with create_mesh() if do_remove: bpy.data.meshes.remove(me) else: # print('Info: Ignoring [%s], object type [%s] not handle yet' % (object.name,object.getType)) pass if free: free_derived_objects(obj_main) # Write out children recursively for obj_child, obj_child_children in obj_children: export_object(obj_main, obj_child, obj_child_children) if not skipUselessTransform: write_transform_end(supplementaryCurvyBracket)
def save( operator, context, filepath="", use_selection=True, enable_corona=False, enable_flares=True, enable_environment=True, center_objects_to_origin=False, ): import bpy import mathutils import time from bpy_extras.io_utils import create_derived_objects, free_derived_objects #get the folder where file will be saved and add a log in that folder workingpath = '\\'.join(filepath.split('\\')[0:-1]) log_file = open(workingpath + "//export-log.txt", 'a') # Time the export time1 = time.clock() date = datetime.datetime.now() log_file.write("Started exporting on " + date.strftime("%d-%m-%Y %H:%M:%S") + "\n" + "File path: " + filepath + "\n") global_matrix = mathutils.Matrix() if bpy.ops.object.mode_set.poll(): bpy.ops.object.mode_set(mode='OBJECT') # Make a list of all materials used in the selected meshes materials_list = ["colwhite"] mesh_objects = [] lamp_objects = [] collfound = False shadfound = False meshes_list = "" scene = context.scene if use_selection: objects = (ob for ob in scene.objects if ob.is_visible(scene) and ob.select) else: objects = (ob for ob in scene.objects if ob.is_visible(scene)) for ob in objects: free, derived = create_derived_objects(scene, ob) if derived is None: continue for ob_derived, mat in derived: if ob.type == 'MESH': try: data = ob_derived.to_mesh(scene, True, 'PREVIEW') except: data = None if "mainshad" in ob.name: shadfound = True elif "maincoll" in ob.name: collfound = True meshes_list += ob.name + " " if data: matrix = global_matrix * mat data.transform(matrix) mesh_objects.append((ob_derived, data, matrix)) mat_ls = data.materials mat_ls_len = len(mat_ls) # get material/image tuples. if data.tessface_uv_textures: if not mat_ls: mat = mat_name = None for f, uf in zip( data.tessfaces, data.tessface_uv_textures.active.data): if mat_ls: mat_index = f.material_index if mat_index >= mat_ls_len: mat_index = f.mat = 0 mat = mat_ls[mat_index] mat_name = None if mat is None else mat.name # else there already set to none if mat_name not in materials_list: materials_list.append(mat_name) else: log_file.write("No UVs found on mesh" + str(ob.name) + ". Using default UVs.\n") for mat in mat_ls: if mat: # material may be None so check its not. if mat.name not in materials_list: materials_list.append(mat.name) # Why 0 Why! for f in data.tessfaces: if f.material_index >= mat_ls_len: f.material_index = 0 if ob.type == 'LAMP': lamp_objects.append(ob) if free: free_derived_objects(ob) #write all the meshes list into the log, so we can use it when setting up the carinfo.cca log_file.write("Meshes: " + meshes_list + "\n") # Initialize the main chunk (primary): primary = _3ds_chunk(sane_name("P3D"), write_size=False) tex = _3ds_chunk(sane_name("TEX")) tex_array = _3ds_bytearray() for m in materials_list: tex_array.add(_3ds_string(sane_name(m + ".tga"))) tex.add_variable("textures", tex_array) lights = _3ds_chunk(sane_name("LIGHTS")) lights_array = _3ds_array() for l in lamp_objects: lamp = _3ds_unnamed_chunk() lamp.add_variable("name", _3ds_string(sane_name(l.name))) pos = l.matrix_world.to_translation() lamp.add_variable("pos", _3ds_point_3d((pos[0], pos[2], pos[1]))) lamp.add_variable("range", _3ds_float(l.data.energy)) lamp.add_variable( "color", _3ds_uint( int( '%02x%02x%02x' % (int(l.data.color[0] * 255), int(l.data.color[1] * 255), int(l.data.color[2] * 255)), 16))) lamp.add_variable("corona", _3ds_byte(int(enable_corona))) lamp.add_variable("flares", _3ds_byte(int(enable_flares))) lamp.add_variable("environment", _3ds_byte(int(enable_environment))) lights_array.add(lamp) lights.add_variable("lights", lights_array) meshes = _3ds_chunk(sane_name("MESHES")) meshes_array = _3ds_array() length = 0.0 height = 0.0 depth = 0.0 objcenterx = 0.0 objcentery = 0.0 objcenterz = 0.0 #we have to get the main meshes dimensions before #we save all the other meshes, so we could properly center them if needed for ob, blender_mesh, matrix in mesh_objects: if ob.name == "main": v = blender_mesh.vertices[0].co lowx = v[0] highx = v[0] lowy = v[1] highy = v[1] lowz = v[2] highz = v[2] for vert in blender_mesh.vertices: pos = vert.co if pos[0] < lowx: lowx = pos[0] elif pos[0] > highx: highx = pos[0] if pos[1] < lowy: lowy = pos[1] elif pos[1] > highy: highy = pos[1] if pos[2] < lowz: lowz = pos[2] elif pos[2] > highz: highz = pos[2] length = highx - lowx height = highz - lowz depth = highy - lowy objcenterx = (highx + lowx) / 2 objcentery = (highy + lowy) / 2 objcenterz = (highz + lowz) / 2 for ob, blender_mesh, matrix in mesh_objects: submesh = _3ds_chunk(sane_name("SUBMESH")) # Extract the triangles from the mesh: tri_list = extract_triangles(blender_mesh, materials_list) material_size = [] for i in range(len(materials_list)): material_size.append(0) polys = _3ds_array() for tri in tri_list: poly = _3ds_unnamed_chunk() n = materials_list.index(blender_mesh.materials[tri.mat].name) material_size[n] += 1 poly.add_variable("p1", _3ds_short(tri.vertex_index[0])) poly.add_variable("uv1", _3ds_point_uv(tri.faceuvs[0])) poly.add_variable("p2", _3ds_short(tri.vertex_index[2])) poly.add_variable("uv2", _3ds_point_uv(tri.faceuvs[2])) poly.add_variable("p3", _3ds_short(tri.vertex_index[1])) poly.add_variable("uv3", _3ds_point_uv(tri.faceuvs[1])) polys.add(poly) flags = 0 #if "coll" not in ob.name and "shad" not in ob.name: flags = flags | 2 if "shad" in ob.name: flags = flags | 4 elif "coll" in ob.name: flags = flags | 8 elif "main" in ob.name: flags = flags | 3 if shadfound == False: flags = flags | 4 log_file.write( "! shadow mesh was not found, using main mesh for shadow.\n" ) if collfound == False: flags = flags | 8 log_file.write( "! collision mesh was not found, using main mesh for collisions.\n" ) else: flags = flags | 2 #for some reason these are not used? """if "det_" in ob.name: flags = flags | 16 if "gls_" in ob.name: flags = flags | 32 if "plas_" in ob.name: flags = flags | 64 if "wood_" in ob.name: flags = flags | 128 if "metl_" in ob.name: flags = flags | 256 if "expl_" in ob.name: flags = flags | 256 #???? if "headl_" in ob.name: flags = flags | 1024 if "brakel_" in ob.name: flags = flags | 2048""" submesh.add_variable("name", _3ds_string(sane_name(ob.name))) submesh.add_variable("flags", _3ds_uint(flags)) v = blender_mesh.vertices[0].co lowx = v[0] highx = v[0] lowy = v[1] highy = v[1] lowz = v[2] highz = v[2] vertices = _3ds_array() #find dimensions of every mesh for vert in blender_mesh.vertices: pos = vert.co if pos[0] < lowx: lowx = pos[0] elif pos[0] > highx: highx = pos[0] if pos[1] < lowy: lowy = pos[1] elif pos[1] > highy: highy = pos[1] if pos[2] < lowz: lowz = pos[2] elif pos[2] > highz: highz = pos[2] #construct vertices array for vert in blender_mesh.vertices: pos = vert.co if (center_objects_to_origin == True): vertices.add( _3ds_point_3d((pos[0] - (highx + lowx) / 2, pos[2] - (highz + lowz) / 2, pos[1] - (highy + lowy) / 2))) else: vertices.add(_3ds_point_3d((pos[0], pos[2], pos[1]))) #construct mesh positions array pos = ob.matrix_world.to_translation() if (center_objects_to_origin == True): submesh.add_variable( "pos", _3ds_point_3d(((highx + lowx) / 2 - objcenterx, (highz + lowz) / 2 - objcenterz, (highy + lowy) / 2 - objcentery))) else: submesh.add_variable("pos", _3ds_point_3d( (pos[0], pos[2], pos[1]))) #save mesh dimensions submesh.add_variable("Length", _3ds_float(highx - lowx)) submesh.add_variable("Height", _3ds_float(highz - lowz)) submesh.add_variable("Depth", _3ds_float(highy - lowy)) s = 0 for i in range(len(materials_list)): submesh.add_variable("texstart", _3ds_short(s)) submesh.add_variable("numflat", _3ds_short(0)) submesh.add_variable("numflatmetal", _3ds_short(0)) submesh.add_variable("gourad", _3ds_short(material_size[i])) submesh.add_variable("gouradmetal", _3ds_short(0)) submesh.add_variable("gouradmetalenv", _3ds_short(0)) submesh.add_variable("shining", _3ds_short(0)) s += material_size[i] submesh.add_variable("vertices", vertices) submesh.add_variable("polygons", polys) if submesh.validate(): meshes_array.add(submesh) else: operator.report({'WARNING'}, "Object %r can't be written into a 3DS file") if not blender_mesh.users: bpy.data.meshes.remove(blender_mesh) meshes.add_variable("meshes", meshes_array) user = _3ds_chunk(sane_name("USER")) user.add_variable("userdatasize", _3ds_uint(0)) user.add_variable("userdata", _3ds_stringtag(sane_name(""))) primary.add_variable("version", _3ds_byte(2)) primary.add_variable("Length", _3ds_float(length)) primary.add_variable("Height", _3ds_float(height)) primary.add_variable("Depth", _3ds_float(depth)) primary.add_subchunk(tex) primary.add_subchunk(lights) primary.add_subchunk(meshes) primary.add_subchunk(user) #calculate all the sizes primary.get_size() # Open the file for writing: file = open(filepath, 'wb') # Recursively write the chunks to file: primary.write(file) # Close the file: file.close() # Clear name mapping vars, could make locals too del name_unique[:] name_mapping.clear() print("p3d export time: %.2f" % (time.clock() - time1)) log_file.write("Finished p3d export. Time taken: %.2f \n\n\n" % (time.clock() - time1)) log_file.close() return {'FINISHED'}
def save( context, filepath, *, use_selection=True, global_matrix=None, ): ## import bpy import mathutils import struct import bmesh from bpy_extras.io_utils import create_derived_objects, free_derived_objects ## file = open(filepath, 'wb') ## depsgraph = context.evaluated_depsgraph_get() scene = context.scene #exit edit mode if bpy.ops.object.mode_set.poll(): bpy.ops.object.mode_set(mode='OBJECT') frame = scene.frame_current if use_selection: objects = context.selected_objects else: objects = scene.objects if global_matrix is None: global_matrix = mathutils.Matrix() mesh_objects = [] print(f"Processing {len(objects)} objects...") for ob in objects: print(f"Object type: {ob.type}") if ob.type not in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META'}: continue # get derived ojects free, derived = create_derived_objects(scene, ob) if derived is None: continue print(f"Processing {len(derived)} derived objects...") for ob_derived, mat in derived: try: data = ob_derived.evaluated_get(depsgraph).to_mesh() except: data = None if data: print("Got data...") matrix = global_matrix @ mat data.transform(matrix) mesh_objects.append((ob_derived, data, matrix)) if free: free_derived_objects(ob) faces = [] vertices = [] submeshes = [] print(f"Processing {len(mesh_objects)} mesh objects...") for ob, blender_mesh, matrix in mesh_objects: submeshOffset = len(faces) * 3 submeshCount = 0 # explicitly triangulate the mesh bm = bmesh.new() bm.from_mesh(blender_mesh) bmesh.ops.triangulate(bm, faces=bm.faces[:]) bm.to_mesh(blender_mesh) bm.free() blender_mesh.calc_loop_triangles() blender_mesh.calc_tangents() for i, face in enumerate(blender_mesh.loop_triangles): faceVertices = [] for vertIdx, loopIdx in zip(face.vertices, face.loops): position = (-blender_mesh.vertices[vertIdx].co.x, blender_mesh.vertices[vertIdx].co.y, blender_mesh.vertices[vertIdx].co.z) normal = (-blender_mesh.vertices[vertIdx].normal.x, blender_mesh.vertices[vertIdx].normal.y, blender_mesh.vertices[vertIdx].normal.z) tangent = (blender_mesh.loops[loopIdx].tangent.x, blender_mesh.loops[loopIdx].tangent.y, blender_mesh.loops[loopIdx].tangent.z) uvLayer0 = blender_mesh.uv_layers.active.data uvs = (uvLayer0[loopIdx].uv[0], uvLayer0[loopIdx].uv[1]) faceVertices.append( Vertex(vertIdx, position, normal, tangent, uvs)) submeshCount = submeshCount + 1 faces.append(Face(faceVertices)) submeshes.append(Submesh(submeshOffset, submeshCount)) print( f"Added submesh with offset = {submeshOffset}, count = {submeshCount}" ) ## indices = [] indexMap = {} for f in faces: ind = [] for v in f.vertices: vTuple = v.get_tuple() if vTuple in indexMap: ind.append(indexMap[vTuple]) else: ind.append(len(vertices)) indexMap[vTuple] = len(vertices) vertices.append(v) indices.append(ind[0]) indices.append(ind[2]) indices.append(ind[1]) # write header numIndices = len(indices) formatSpecifier = None if numIndices <= 256: formatSpecifier = '<B' indexFormat = IndexFormat.UINT8 else: if numIndices > 0xffff: formatSpecifier = '<I' indexFormat = IndexFormat.UINT32 else: formatSpecifier = '<H' indexFormat = IndexFormat.UINT16 file.write( struct.pack('<B', int(VertexFormat.POSITION_NORMAL_TANGENT_TEXCOORD0))) file.write(struct.pack( '<B', int(indexFormat))) # @NOTE assumption of 2 byte indices file.write(struct.pack('<Q', len(vertices))) file.write(struct.pack('<Q', numIndices)) file.write(struct.pack('<I', len(submeshes))) # write bounding box bbox = AABB( Vec3(vertices[0].position[0], vertices[0].position[1], vertices[0].position[2]), Vec3(vertices[0].position[0], vertices[0].position[1], vertices[0].position[2])) for v in vertices: if v.position[0] < bbox.min.x: bbox.min.x = v.position[0] if v.position[1] < bbox.min.y: bbox.min.y = v.position[1] if v.position[2] < bbox.min.z: bbox.min.z = v.position[2] if v.position[0] > bbox.max.x: bbox.max.x = v.position[0] if v.position[1] > bbox.max.y: bbox.max.y = v.position[1] if v.position[2] > bbox.max.z: bbox.max.z = v.position[2] file.write(struct.pack('<f', bbox.max.x)) file.write(struct.pack('<f', bbox.max.y)) file.write(struct.pack('<f', bbox.max.z)) file.write(struct.pack('<f', bbox.min.x)) file.write(struct.pack('<f', bbox.min.y)) file.write(struct.pack('<f', bbox.min.z)) print( f"Writing mesh with {len(vertices)} vertices, {len(indices)} indices, {len(submeshes)} submeshes." ) # write vertices for i, v in enumerate(vertices): # position file.write(struct.pack('<f', v.position[0])) file.write(struct.pack('<f', v.position[1])) file.write(struct.pack('<f', v.position[2])) # normal file.write(struct.pack('<f', v.normal[0])) file.write(struct.pack('<f', v.normal[1])) file.write(struct.pack('<f', v.normal[2])) # tangent file.write(struct.pack('<f', v.tangent[0])) file.write(struct.pack('<f', v.tangent[1])) file.write(struct.pack('<f', v.tangent[2])) file.write(struct.pack('<f', 0)) # uvs file.write(struct.pack('<f', v.uvs[0])) file.write(struct.pack('<f', v.uvs[1])) # write indices for i in indices: file.write(struct.pack(formatSpecifier, i)) # write submeshes for submesh in submeshes: print( f"Write submesh with offset = {submesh.offset}, count = {submesh.count}" ) file.write(struct.pack('<Q', submesh.offset)) file.write(struct.pack('<Q', submesh.count)) file.close() return {'FINISHED'}
def exportMesh(scene, filepath=""): if bpy.ops.object.mode_set.poll(): bpy.ops.object.mode_set(mode='OBJECT') # Make a list of all materials used in the selected meshes (use a dictionary, # each material is added once): materialDict = {} mesh_objects = [] objects = (ob for ob in scene.objects if ob.is_visible(scene)) for ob in objects: # get derived objects free, derived = create_derived_objects(scene, ob) if derived is None: continue for ob_derived, mat in derived: if ob.type not in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META'}: continue try: data = ob_derived.to_mesh(scene, True, 'PREVIEW') except: data = None if data: matrix = mat data.transform(matrix) mesh_objects.append((ob_derived, data, matrix)) mat_ls = data.materials mat_ls_len = len(mat_ls) # get material/image tuples. if data.tessface_uv_textures: if not mat_ls: mat = mat_name = None for f, uf in zip(data.tessfaces, data.tessface_uv_textures.active.data): if mat_ls: mat_index = f.material_index if mat_index >= mat_ls_len: mat_index = f.mat = 0 mat = mat_ls[mat_index] mat_name = None if mat is None else mat.name # else there already set to none img = uf.image img_name = None if img is None else img.name materialDict.setdefault((mat_name, img_name), (mat, img)) else: for mat in mat_ls: if mat: # material may be None so check its not. materialDict.setdefault((mat.name, None), (mat, None)) # Why 0 Why! for f in data.tessfaces: if f.material_index >= mat_ls_len: f.material_index = 0 if free: free_derived_objects(ob) assert (len(mesh_objects) == 1) # Create object chunks for all meshes: (ob, blender_mesh, matrix) = mesh_objects[0] # make a mesh chunk out of the mesh: dumpMesh(blender_mesh, filepath)
def save(operator, context, filepath="", use_selection=True, global_matrix=None): file = open(filepath, 'wb') import bpy import mathutils import struct import bmesh from bpy_extras.io_utils import create_derived_objects, free_derived_objects if global_matrix is None: global_matrix = mathutils.Matrix() mesh_objects = [] scene = context.scene if use_selection: objects = (ob for ob in scene.objects if ob.is_visible(scene) and ob.select) else: objects = (ob for ob in scene.objects if ob.is_visible(scene)) for ob in objects: # get derived objects free, derived = create_derived_objects(scene, ob) if derived is None: continue for ob_derived, mat in derived: if ob.type not in {'MESH', 'CURVE', 'SURFACE', 'FONT', 'META'}: continue try: data = ob_derived.to_mesh(scene, True, 'PREVIEW') except: data = None if data: matrix = global_matrix * mat data.transform(matrix) mesh_objects.append((ob_derived, data, matrix)) if free: free_derived_objects(ob) # write number of meshes file.write(struct.pack('<I', len(mesh_objects))) id = 0 for ob, blender_mesh, matrix in mesh_objects: # convert all faces to triangles and extract UVs bm = bmesh.new() bm.from_mesh(blender_mesh) bmesh.ops.triangulate(bm, faces=bm.faces[:], quad_method=0, ngon_method=0) bm.verts.index_update() bm.to_mesh(blender_mesh) bm.free() blender_mesh.calc_normals() # calculate normals blender_mesh.update(calc_tessface=True) # extract faces faces = [] for i, face in enumerate(blender_mesh.tessfaces): faceVertices = [] for n, vertIdx in enumerate(face.vertices): position = (blender_mesh.vertices[vertIdx].co.x, blender_mesh.vertices[vertIdx].co.y, blender_mesh.vertices[vertIdx].co.z) normal = (blender_mesh.vertices[vertIdx].normal.x, blender_mesh.vertices[vertIdx].normal.y, blender_mesh.vertices[vertIdx].normal.z) tex = blender_mesh.tessface_uv_textures[0] uvs = (tex.data[i].uv[n][0], tex.data[i].uv[n][1]) blendWeights = [1.0, 0.0, 0.0, 0.0] blendIndices = [0, 0, 0, 0] groups = sorted(blender_mesh.vertices[vertIdx].groups, key=lambda item: item.weight, reverse=True) sumweights = 0 for g, group in enumerate(groups): if g > 3: break sumweights += group.weight for g, group in enumerate(groups) if g > 3: print("data loss: vertex with more than 4 bones assigned") break blendWeights[g] = group.weight/sumweights blendIndices[g] = ArmatureList[0].object.data.bones.find(objpar) faceVertices.append(Vertex(vertIdx, position, normal, uvs, blendWeights, blendIndices)) faces.append(Face(faceVertices)) vertices = [] indices = [] indexMap = {} for f in faces: ind = [] for v in f.vertices: vTuple = v.get_tuple() if vTuple in indexMap: ind.append(indexMap[vTuple]) else: ind.append(len(vertices)) indexMap[vTuple] = len(vertices) vertices.append(v) indices.append(ind[0]) indices.append(ind[1]) indices.append(ind[2]) # write submesh id file.write(struct.pack('<I', id)) # write number of vertices file.write(struct.pack('<I', len(vertices))) # write interleaved vertex data as (position)(normal)(uvs) for i, v in enumerate(vertices): # position file.write(struct.pack('<f', v.position[0])) file.write(struct.pack('<f', v.position[1])) file.write(struct.pack('<f', v.position[2])) # normal file.write(struct.pack('<f', v.normal[0])) file.write(struct.pack('<f', v.normal[1])) file.write(struct.pack('<f', v.normal[2])) # uvs file.write(struct.pack('<f', v.uvs[0])) file.write(struct.pack('<f', v.uvs[1])) # blend weights file.write(struct.pack('<f', v.blendWeights[0])) file.write(struct.pack('<f', v.blendWeights[1])) file.write(struct.pack('<f', v.blendWeights[2])) file.write(struct.pack('<f', v.blendWeights[3])) # blend indices file.write(struct.pack('<I', v.blendIndices[0])) file.write(struct.pack('<I', v.blendIndices[1])) file.write(struct.pack('<I', v.blendIndices[2])) file.write(struct.pack('<I', v.blendIndices[3])) # write indices file.write(struct.pack('<I', len(indices))) for i in indices: file.write(struct.pack('<I', i)) id = id + 1 file.close() return {'FINISHED'}