[docs]defmove_collection(parent,collection):# from https://blender.stackexchange.com/questions/157828/how-to-duplicate-a-certain-collection-using-pythondef_move_collection(parent,collection):# re-link objectsforoincollection.objects:collection.objects.unlink(o)parent.objects.link(o)forcincollection.children:# Create child and link itcc=bpy.data.collections.new(c.name)parent.children.link(cc)# Fix naming: blender appends .001, .002, etc. to new namesorig_name=c.namecreated_name=cc.namec.name=created_namecc.name=orig_name# Recursively move everything that is inside_move_collection(cc,c)forcincollection.children:bpy.data.collections.remove(c,do_unlink=True)_move_collection(parent,collection)
[docs]defparse_camera_from_blendfile(obj:bpy.types.Object,resolution:np.ndarray):"""Parse camera parameters from blender object. Args: obj (bpy.types.Object): Blender object with camera data resolution (np.ndarray): array of [resolution_x, resolution_y] Returns: camera_type (str): ORTHO, PRESP or NONE camera_dict (dict): dictionary with camera parameters """camera_dict=dict()camera_dict["tag"]=obj.namecamera_dict["resolution"]=resolution# positioncamera_dict["translation"]=np.array(obj.location)ifobj.rotation_mode=="QUATERNION":camera_dict["rotation"]=np.array(obj.rotation_quaternion)elifobj.rotation_mode=="AXIS_ANGLE":rotvec=np.array(obj.rotation_axis_angle)angle,axis=rotvec[0],rotvec[1:]rotvec=(axis/np.linalg.norm(axis))*anglerot=Rotation.from_rotvec(rotvec)camera_dict["rotation"]=np.roll(rot.as_quat(),1)else:# euler anglesrot_data=obj.rotation_eulermode=rot_data.orderangles=np.array(rot_data[:])rot=Rotation.from_euler(mode.lower(),angles,degrees=False)camera_dict["rotation"]=np.roll(rot.as_quat(),1)# camera parametersifobj.data.type=="ORTHO":# scalecamera_dict["ortho_scale"]=obj.data.ortho_scale# near / farcamera_dict["near"]=obj.data.clip_startcamera_dict["far"]=obj.data.clip_endelifobj.data.type=="PERSP":# sensor paramsfov_x,fov_y=None,Nonesensor_fit=obj.data.sensor_fit# determine sensor fitifsensor_fit=="AUTO":sensor_fit="HORIZONTAL"ifresolution[0]>=resolution[1]else"VERTICAL"# determine fovifsensor_fit=="HORIZONTAL":ifobj.data.lens_unit=="MILLETERS":fov_x=2*math.atan(0.5*obj.data.sensor_width/obj.data.lens)else:fov_x=obj.data.angle_xelse:# VERTICALifobj.data.lens_unit=="MILLETERS":fov_y=2*math.atan(0.5*obj.data.sensor_height/obj.data.lens)else:fov_y=obj.data.angle_ycamera_dict["fov_x"]=fov_xcamera_dict["fov_y"]=fov_y# centerideal_center=resolution/2.center_offset=np.array([obj.data.shift_x,obj.data.shift_y])camera_dict["center"]=ideal_center/resolution-center_offset# near / farcamera_dict["near"]=obj.data.clip_startcamera_dict["far"]=obj.data.clip_endreturnobj.data.type,camera_dict
[docs]defparse_light_from_blendfile(obj:bpy.types.Object):# Parse common parameterstranslation,quaternion,scale=obj.matrix_world.decompose()# "scale", "multiple_importance", "shadow_caustics" are not supportedlight_dict={"strength":obj.data.energy,"color":np.array(obj.data.color),"cast_shadows":obj.data.cycles.cast_shadow,"rotation":quaternion,"translation":translation,"tag":obj.name}# Parse type specific parameterslight_type=obj.data.typeiflight_type=="POINT":light_dict["shadow_soft_size"]=obj.data.shadow_soft_sizeeliflight_type=="SUN":light_dict["angular_diameter"]=obj.data.angleeliflight_type=="SPOT":light_dict["spot_size"]=obj.data.spot_sizelight_dict["spot_blend"]=obj.data.spot_blendlight_dict["shadow_soft_size"]=obj.data.shadow_soft_sizeeliflight_type=="AREA":light_dict["shape"]=obj.data.shape.lower()iflight_dict["shape"]in["RECTANGLE","ELLIPSE"]:light_dict["size"]=np.array([obj.data.size,obj.data.size_y],dtype=np.float32)else:light_dict["size"]=obj.data.sizereturnlight_type,light_dict