def deriveCollision(obj): """This function derives the collision information from an object. :param obj: The blender object to derive the collision information from. :type obj: bpy_types.Object :return: dict """ try: collision = initObjectProperties(obj, phobostype='collision', ignoretypes='geometry') collision['geometry'] = deriveGeometry(obj) collision['pose'] = deriveObjectPose(obj) # the bitmask is cut to length = 16 and reverted for int parsing try: collision['bitmask'] = int( ''.join([ '1' if group else '0' for group in obj.rigid_body.collision_groups[:16] ])[::-1], 2) for group in obj.rigid_body.collision_groups[16:]: if group: log(( 'Object {0} is on a collision layer higher than ' + '16. These layers are ignored when exporting.').format( obj.name), "WARNING") break except AttributeError: pass except KeyError: log("Missing data in collision object " + obj.name, "ERROR") return None return collision
def deriveCollision(obj): """This function derives the collision information from an object. :param obj: The blender object to derive the collision information from. :type obj: bpy_types.Object :return: dict """ try: collision = initObjectProperties(obj, phobostype='collision', ignoretypes='geometry') collision['geometry'] = deriveGeometry(obj) collision['pose'] = deriveObjectPose(obj) # the bitmask is cut to length = 16 and reverted for int parsing try: collision['bitmask'] = int( ''.join([ '1' if group else '0' for group in obj.rigid_body.collision_groups[:16] ])[::-1], 2) except AttributeError: pass except KeyError: log("Missing data in collision object " + obj.name, "ERROR", "deriveCollision") return None return collision
def deriveVisual(obj): """This function derives the visual information from an object. :param obj: The blender object to derive the visuals from. :type obj: bpy_types.Object :return: dict """ try: visual = initObjectProperties(obj, phobostype='visual', ignoretypes='geometry') visual['geometry'] = deriveGeometry(obj) visual['pose'] = deriveObjectPose(obj) if obj.lod_levels: if 'lodmaxdistances' in obj: maxdlist = obj['lodmaxdistances'] else: maxdlist = [ obj.lod_levels[i + 1].distance for i in range(len(obj.lod_levels) - 1) ] + [100.0] lodlist = [] for i in range(len(obj.lod_levels)): filename = obj.lod_levels[ i].object.data.name + ioUtils.getOutputMeshtype() lodlist.append({ 'start': obj.lod_levels[i].distance, 'end': maxdlist[i], 'filename': os.path.join('meshes', filename) }) visual['lod'] = lodlist except KeyError: log("Missing data in visual object " + obj.name, "ERROR") return None return visual
def deriveCollision(obj): """Returns the collision information from the specified object. Args: obj(bpy.types.Object): object to derive the collision information from Returns: : dict -- phobos representation of the collision object """ collision = initObjectProperties(obj, phobostype='collision', ignoretypes='geometry') collision['geometry'] = deriveGeometry(obj) collision['pose'] = deriveObjectPose(obj) # the bitmask is cut to length = 16 and reverted for int parsing if 'collision_groups' in dir(obj.rigid_body): collision['bitmask'] = int( ''.join(['1' if group else '0' for group in obj.rigid_body.collision_groups[:16]])[ ::-1 ], 2, ) for group in obj.rigid_body.collision_groups[16:]: if group: log( ( "Object {0} is on a collision layer higher than 16. These layers are " + "ignored when exporting." ).format(obj.name), 'WARNING', ) break return collision
def createHelperInertialObjects(link, autocalc=True): """Creates inertial representations for helper inertials from the visual/ collision objects of a link. The new inertials can be calculated automatically or remain empty (based on the autocalc parameter) :param link: the link which contains the visual/collision objects :type link: bpy_types.Object :param autocalc: If set to False the new inertial object will contain no inertia information. :type autocalc: bool """ viscols = getInertiaRelevantObjects(link) for obj in viscols: inertialdata = { 'mass': 0, 'inertia': [0, 0, 0, 0, 0, 0], 'pose': { 'translation': obj.matrix_local.to_translation() } } if autocalc: mass = obj['mass'] if 'mass' in obj else None geometry = deriveGeometry(obj) data = geometry if geometry['type'] != 'mesh' else obj.data if mass is not None and data is not None: inert = calculateInertia(mass, data) if inert is not None: inertialdata['mass'] = mass inertialdata['inertia'] = inert createInertial(obj.name, inertialdata, parentobj=obj, helper=True)
def deriveEntity(primitive, outpath): """This function handles a primitive entity in a scene to export it # TODO is this even a heightmap? Args: smurf(bpy.types.Object): The heightmap root object. outpath(str): The path to export to. Not used for primitives savetosubfolder(bool): If True data will be exported into subfolders. Not used for primitives primitive: Returns: dict - An entry for the scenes entitiesList """ entity = models.initObjectProperties(primitive, 'entity', ['geometry']) pose = deriveObjectPose(primitive) entity['geometry'] = deriveGeometry(primitive) entity['position'] = {'x': pose['translation'][0], 'y': pose['translation'][1], 'z': pose['translation'][2]} entity['rotation'] = {'w': pose['rotation_quaternion'][0], 'x': pose['rotation_quaternion'][1], 'y': pose['rotation_quaternion'][2], 'z': pose['rotation_quaternion'][3]} if 'radius' in entity['geometry']: entity['radius'] = entity['geometry']['radius'] #entity['extend'] = {'x': entity['geometry']['size'][0], # 'y': entity['geometry']['size'][1], # 'z': entity['geometry']['size'][2]} entity['extend'] = {'x': primitive.dimensions[0], 'y': primitive.dimensions[1], 'z': primitive.dimensions[2]} return entity
def calculateInertia(obj, mass, geometry=None): """Calculates the inertia of an object using the specified mass and optionally geometry. Args: obj(bpy.types.Object): object to calculate inertia from mass(float): mass of object geometry(dict, optional): geometry part of the object dictionary Returns(tuple): tuple(6) of upper diagonal of the inertia 3x3 tensor """ inertia = None if not geometry: geometry = deriveGeometry(obj) if not geometry: return None if geometry['type'] == 'box': inertia = calculateBoxInertia(mass, geometry['size']) elif geometry['type'] == 'cylinder': inertia = calculateCylinderInertia(mass, geometry['radius'], geometry['length']) elif geometry['type'] == 'sphere': inertia = calculateSphereInertia(mass, geometry['radius']) elif geometry['type'] == 'capsule': inertia = calculateCapsuleInertia(mass, geometry['radius'], geometry['length']) elif geometry['type'] == 'mesh': sUtils.selectObjects((obj,), clear=True, active=0) inertia = calculateMeshInertia(mass, obj.data) return inertia
def createInertials(link, empty=False, preserve_children=False): """Creates inertial representations for visual and collision objects in link. :param link: The link you want to create the inertial for. :type link: bpy_types.Object :param empty: If set to True the new inertial object will contain no information. :type empty: bool :param preserve_children: If set to False existing inertial objects will be deleted. :type preserve_children: bool """ viscols = getInertiaRelevantObjects(link) # clean existing data if not preserve_children: oldinertials = sUtils.getImmediateChildren(link, ['inertial']) else: try: oldinertials = [bpy.data.objects['inertial_' + link.name]] except KeyError: oldinertials = None if oldinertials: sUtils.selectObjects(oldinertials, clear=True, active=0) bpy.ops.object.delete() if not preserve_children: for obj in viscols: if not empty: mass = obj['mass'] if 'mass' in obj else None geometry = deriveGeometry(obj) if mass is not None and geometry is not None: if geometry['type'] == 'mesh': sUtils.selectObjects([obj]) bpy.context.scene.objects.active = obj inert = calculateMeshInertia(obj.data, mass) else: inert = calculateInertia(mass, geometry) if inert is not None: inertial = createInertial(obj) inertial['mass'] = mass inertial['inertia'] = inert else: createInertial(obj) # compose inertial object for link if not empty: mass, com, inert = fuseInertiaData( sUtils.getImmediateChildren(link, ['inertial'])) if mass and com and inert: inertial = createInertial(link) com_translate = mathutils.Matrix.Translation(com) inertial.matrix_local = com_translate bpy.ops.transform.translate(value=( 0, 0, 0 )) # FIXME: this is a trick to force Blender to apply matrix_local inertial['inertial/mass'] = mass inertial['inertial/inertia'] = inertiaMatrixToList(inert) else: createInertial(link)
def calculateInertia(obj, mass, geometry_dict=None, errors=None, adjust=False, logging=False): """Calculates the inertia of an object using the specified mass and optionally geometry. Args: obj(bpy.types.Object): object to calculate inertia from mass(float): mass of object geometry_dict(dict, optional): geometry part of the object dictionary Returns(tuple): (Default value = None) geometry_dict(dict, optional): geometry part of the object dictionary Returns(tuple): tuple(6) of upper diagonal of the inertia 3x3 tensor (Default value = None) errors: (Default value = None) adjust: (Default value = False) logging: (Default value = False) Returns: """ if errors and not adjust: if logging: log("Can not calculate inertia from object.", 'ERROR') return None inertia = None if not geometry_dict: geometry = deriveGeometry(obj) # Get the rotation of the object object_rotation = obj.rotation_euler.to_matrix() if geometry['type'] == 'box': inertia = calculateBoxInertia(mass, geometry['size']) elif geometry['type'] == 'cylinder': inertia = calculateCylinderInertia(mass, geometry['radius'], geometry['length']) elif geometry['type'] == 'sphere': inertia = calculateSphereInertia(mass, geometry['radius']) elif geometry['type'] == 'mesh': sUtils.selectObjects((obj, ), clear=True, active=0) inertia = calculateMeshInertia(mass, obj.data, scale=obj.scale) # Correct the inertia orientation to account for Cylinder / mesh orientation issues inertia = object_rotation * inertiaListToMatrix( inertia) * object_rotation.transposed() return inertiaMatrixToList(inertia)
def deriveVisual(obj, logging=True, **kwargs): """This function derives the visual information from an object. Contains these keys: *name*: name of the visual *geometry*: derived according to `deriveGeometry` *pose*: derived according to `deriveObjectPose` *lod*: (opt.) level of detail levels Args: obj(bpy.types.Object): object to derive the visual representation from logging: (Default value = True) **kwargs: Returns: : dict -- model representation of the visual object """ visual = initObjectProperties(obj, phobostype='visual', ignoretypes='geometry') visual['geometry'] = deriveGeometry(obj, logging=logging) visual['pose'] = deriveObjectPose(obj, logging=logging) # check for material of the visual material = deriveMaterial(obj.active_material, logging=logging) if material: visual['material'] = material['name'] if obj.lod_levels: if 'lodmaxdistances' in obj: maxdlist = obj['lodmaxdistances'] else: maxdlist = [ obj.lod_levels[i + 1].distance for i in range(len(obj.lod_levels) - 1) ] + [100.0] lodlist = [] for i in range(len(obj.lod_levels)): filename = obj.lod_levels[ i].object.data.name + ioUtils.getOutputMeshtype() lodlist.append({ 'start': obj.lod_levels[i].distance, 'end': maxdlist[i], 'filename': os.path.join('meshes', filename), }) visual['lod'] = lodlist return visual
def calculateInertia(obj, mass, geometry_dict=None, errors=None, adjust=False, logging=False): """Calculates the inertia of an object using the specified mass and optionally geometry. Args: obj(bpy.types.Object): object to calculate inertia from mass(float): mass of object geometry_dict(dict, optional): geometry part of the object dictionary Returns(tuple): (Default value = None) geometry_dict(dict, optional): geometry part of the object dictionary Returns(tuple): tuple(6) of upper diagonal of the inertia 3x3 tensor (Default value = None) errors: (Default value = None) adjust: (Default value = False) logging: (Default value = False) Returns: """ if errors and not adjust: if logging: log("Can not calculate inertia from object.", 'ERROR') return None inertia = None if not geometry_dict: geometry = deriveGeometry(obj) # Get the rotation of the object object_rotation = obj.rotation_euler.to_matrix() if geometry['type'] == 'box': inertia = calculateBoxInertia(mass, geometry['size']) elif geometry['type'] == 'cylinder': inertia = calculateCylinderInertia(mass, geometry['radius'], geometry['length']) elif geometry['type'] == 'sphere': inertia = calculateSphereInertia(mass, geometry['radius']) elif geometry['type'] == 'mesh': sUtils.selectObjects((obj,), clear=True, active=0) inertia = calculateMeshInertia(mass, obj.data) # Correct the inertia orientation to account for Cylinder / mesh orientation issues inertia = object_rotation * inertiaListToMatrix(inertia) * object_rotation.transposed() return inertiaMatrixToList(inertia)
def calculateInertia(obj, mass, geometry_dict=None, errors=None, adjust=False, logging=False): """Calculates the inertia of an object using the specified mass and optionally geometry. Args: obj(bpy.types.Object): object to calculate inertia from mass(float): mass of object geometry_dict(dict, optional): geometry part of the object dictionary Returns(tuple): (Default value = None) geometry_dict(dict, optional): geometry part of the object dictionary Returns(tuple): tuple(6) of upper diagonal of the inertia 3x3 tensor (Default value = None) errors: (Default value = None) adjust: (Default value = False) logging: (Default value = False) Returns: """ if errors and not adjust: if logging: log("Can not calculate inertia from object.", 'ERROR') return None inertia = None if not geometry_dict: geometry = deriveGeometry(obj) if geometry['type'] == 'box': inertia = calculateBoxInertia(mass, geometry['size']) elif geometry['type'] == 'cylinder': inertia = calculateCylinderInertia(mass, geometry['radius'], geometry['length']) elif geometry['type'] == 'sphere': inertia = calculateSphereInertia(mass, geometry['radius']) elif geometry['type'] == 'mesh': sUtils.selectObjects((obj, ), clear=True, active=0) inertia = calculateMeshInertia(mass, obj.data) return inertia
def createInertialObjects(link, autocalc=True): """Creates inertial objects from inertials of the visual/collision objects of a link. The new inertials can be calculated automatically or remain empty (based on the autocalc parameter). :param link: the link which contains the visual/collision objects :type link: bpy_types.Object :param autocalc: If set to False the new inertial object will contain no inertia information. :type autocalc: bool :return: the newly created inertial objects :rtype: list of bpy.types.Object """ assert link.phobostype == 'link', 'Not a link object: ' + link.phobostype + '.' viscols = getInertiaRelevantObjects(link) inertialobjs = [] for obj in viscols: inertialdata = { 'mass': 0, 'inertia': [0, 0, 0, 0, 0, 0], 'pose': { 'translation': obj.matrix_local.to_translation() } } if autocalc: mass = obj['mass'] if 'mass' in obj else None geometry = deriveGeometry(obj) if mass and geometry: inert = calculateInertia(obj, mass, geometry) if inert is not None: inertialdata['mass'] = mass inertialdata['inertia'] = inert # Create the object as a child of the parent object inertialobjs.append( createInertial(obj.name, inertialdata, parentobj=obj, effectiveParent=link)) if not inertialobjs: log('No objects to calculate inertias from.', 'WARNING') return inertialobjs
def deriveEntity(primitive, outpath): """This function handles a primitive entity in a scene to export it # TODO is this even a heightmap? Args: smurf(bpy.types.Object): The heightmap root object. outpath(str): The path to export to. Not used for primitives savetosubfolder(bool): If True data will be exported into subfolders. Not used for primitives primitive: Returns: : dict - An entry for the scenes entitiesList """ entity = models.initObjectProperties(primitive, 'entity', ['geometry']) pose = deriveObjectPose(primitive) entity['geometry'] = deriveGeometry(primitive) entity['position'] = { 'x': pose['translation'][0], 'y': pose['translation'][1], 'z': pose['translation'][2], } entity['rotation'] = { 'w': pose['rotation_quaternion'][0], 'x': pose['rotation_quaternion'][1], 'y': pose['rotation_quaternion'][2], 'z': pose['rotation_quaternion'][3], } if 'radius' in entity['geometry']: entity['radius'] = entity['geometry']['radius'] # entity['extend'] = {'x': entity['geometry']['size'][0], # 'y': entity['geometry']['size'][1], # 'z': entity['geometry']['size'][2]} entity['extend'] = { 'x': primitive.dimensions[0], 'y': primitive.dimensions[1], 'z': primitive.dimensions[2], } return entity
def deriveEntity(entity, outpath, savetosubfolder): """This function handles a primitive entity in a scene to export it :param smurf: The heightmap root object. :type smurf: bpy.types.Object :param outpath: The path to export to. Not used for primitives :type outpath: str :param savetosubfolder: If True data will be exported into subfolders. Not used for primitives :type savetosubfolder: bool :return: dict - An entry for the scenes entitiesList """ primitive = entity log( "Exporting " + nUtils.getObjectName(primitive, 'entity') + " as entity of type 'primitive", "INFO") entity = models.initObjectProperties(primitive, 'entity', ['geometry']) pose = deriveObjectPose(primitive) entity['geometry'] = deriveGeometry(primitive) entity['position'] = { 'x': pose['translation'][0], 'y': pose['translation'][1], 'z': pose['translation'][2] } entity['rotation'] = { 'w': pose['rotation_quaternion'][0], 'x': pose['rotation_quaternion'][1], 'y': pose['rotation_quaternion'][2], 'z': pose['rotation_quaternion'][3] } entity['extend'] = { 'x': entity['geometry']['size'][0], 'y': entity['geometry']['size'][1], 'z': entity['geometry']['size'][2] } return entity
def deriveEntity(primitive, outpath, savetosubfolder=True): """This function handles a primitive entity in a scene to export it :param smurf: The heightmap root object. :type smurf: bpy.types.Object :param outpath: The path to export to. Not used for primitives :type outpath: str :param savetosubfolder: If True data will be exported into subfolders. Not used for primitives :type savetosubfolder: bool :return: dict - An entry for the scenes entitiesList """ entity = models.initObjectProperties(primitive, 'entity', ['geometry']) pose = deriveObjectPose(primitive) entity['geometry'] = deriveGeometry(primitive) entity['position'] = { 'x': pose['translation'][0], 'y': pose['translation'][1], 'z': pose['translation'][2] } entity['rotation'] = { 'w': pose['rotation_quaternion'][0], 'x': pose['rotation_quaternion'][1], 'y': pose['rotation_quaternion'][2], 'z': pose['rotation_quaternion'][3] } if 'radius' in entity['geometry']: entity['radius'] = entity['geometry']['radius'] #entity['extend'] = {'x': entity['geometry']['size'][0], # 'y': entity['geometry']['size'][1], # 'z': entity['geometry']['size'][2]} entity['extend'] = { 'x': primitive.dimensions[0], 'y': primitive.dimensions[1], 'z': primitive.dimensions[2] } return entity