def convert_obj(src: gltf.Coodinate, dst: gltf.Coodinate, bl_obj: bpy.types.Object): if dst == gltf.Coodinate.BLENDER_ROTATE: if src == gltf.Coodinate.VRM0: bl_obj.rotation_euler = (math.pi * 0.5, 0, math.pi) elif src == gltf.Coodinate.VRM1: bl_obj.rotation_euler = (math.pi * 0.5, 0, 0) else: raise NotImplementedError() else: raise NotImplementedError()
def insert_keyframe( obj: bpy.types.Object, vec: np.ndarray, datapath: str, frame: int = bpy.context.scene.frame_current) -> np.ndarray: bpy.context.scene.frame_set(frame) if datapath == "rotation": if obj.rotation_mode == "AXIS_ANGLE": datapath = "rotation_axis_angle" elif obj.rotation_mode == "QUATERNION": datapath = "rotation_quaternion" else: datapath = "rotation_euler" if datapath == "location": obj.location = (vec[0], vec[1], vec[2]) elif datapath == "rotation_euler": obj.rotation_mode = "XYZ" obj.rotation_euler = (vec[0], vec[1], vec[2]) elif datapath == "rotation_quaternion": obj.rotation_mode = "QUATERNION" obj.rotation_quaternion = (vec[0], vec[1], vec[2], vec[3]) elif datapath == "rotation_axis_angle": obj.rotation_mode = "AXIS_ANGLE" obj.rotation_axis_angle = (vec[0], vec[1], vec[2], vec[3]) elif datapath == "scale": obj.scale = (vec[0], vec[1], vec[2]) else: raise NotImplementedError("Illegal datapath!") obj.keyframe_insert(data_path=datapath, frame=frame)
def apply_ob_props(ob: bpy.types.Object, new_name: str = name) -> bpy.types.Object: ob.name = new_name ob.location = [location[0] * 0.01, location[1] * -0.01, location[2] * 0.01] ob.rotation_mode = 'XYZ' ob.rotation_euler = [radians(rotation[2]), radians(-rotation[0]), radians(-rotation[1])] ob.scale = scale return ob
def setObjectRotationQuaternion(obj: bpy.types.Object, rot: Quaternion): if obj.rotation_mode == "QUATERNION": obj.rotation_quaternion = rot elif obj.rotation_mode == "AXIS_ANGLE": obj.rotation_axis_angle = rot.to_axis_angle() else: obj.rotation_euler = rot.to_euler(obj.rotation_mode)
def set_transformation(obj: bpy.types.Object, transf: Dict[str, str]) -> None: """set the transformation of an object""" trans = transf['translation'] rot = transf['rotation'] obj.location = trans # blender.point_at(cam, root_obj, 'TRACK_NEGATIVE_Z', 'UP_Y') if isinstance(rot, dict): point_at_obj = blender.get_obj_by_name(rot['point_at']) blender.point_at(obj, point_at_obj, blender.TRACK_AXIS[rot.get('track_axis', '-z')], blender.UP_AXIS[rot.get('up_axis', 'y')]) else: if len(rot) == 3: # I think Panda3D's HPR is intrinsic # If Blender is extrinsic, the order can just be reversed, LOL # rot is in HPR form # H -> Z # P -> X # R -> Y obj.rotation_mode = 'ZXY' obj.rotation_euler = ( math.radians(rot[1]), # X == (ZXY)[1] math.radians(rot[2]), # Y == (ZXY)[2] math.radians(rot[0]), # Z == (ZXY)[0] ) else: obj.rotation_mode = 'QUATERNION' obj.rotation_quaternion = rot
def look_at(obj: bpy.types.Object, target: Vector): """Rotate an object such that it looks at a target. The object's Y axis will point upwards, and the -Z axis towards the target. This is the 'correct' rotation for cameras and lights.""" t = obj.location dir = target - t quat = dir.to_track_quat('-Z', 'Y') obj.rotation_euler = quat.to_euler()
def check_pose_for_object(obj: bpy.types.Object, position: mathutils.Vector, rotation: mathutils.Vector, bvh_cache: dict, objects_to_check_against: list, list_of_objects_with_no_inside_check: list): """ Checks if a object placed at the given pose intersects with any object given in the list. The bvh_cache adds all current objects to the bvh tree, which increases the speed. If an object is already in the cache it is removed, before performing the check. :param obj: Object which should be checked. Type: :class:`bpy.types.Object` :param position: 3D Vector of the location of the object. Type: :class:`mathutils.Vector` :param rotation: 3D Vector of the rotation in euler angles. If this is None, the rotation is not changed \ Type: :class:`mathutils.Vector` :param bvh_cache: Dict of all the bvh trees, removes the `obj` from the cache before adding it again. \ Type: :class:`dict` :param objects_to_check_against: List of objects which the object is checked again \ Type: :class:`list` :param list_of_objects_with_no_inside_check: List of objects on which no inside check is performed. \ This check is only done for the objects in \ `objects_to_check_against`. Type: :class:`list` :return: Type: :class:`bool`, True if no collision was found, false if at least one collision was found """ # assign it a new pose obj.location = position if rotation: obj.rotation_euler = rotation bpy.context.view_layer.update() # Remove bvh cache, as object has changed if obj.name in bvh_cache: del bvh_cache[obj.name] no_collision = True # Now check for collisions for already_placed in objects_to_check_against: # First check if bounding boxes collides intersection = check_bb_intersection(obj, already_placed) # if they do if intersection: skip_inside_check = already_placed in list_of_objects_with_no_inside_check # then check for more refined collisions intersection, bvh_cache = check_intersection( obj, already_placed, bvh_cache=bvh_cache, skip_inside_check=skip_inside_check) if intersection: no_collision = False break return no_collision
def set_rotation(blender_object: bpy.types.Object, rotation: Any, rotation_mode: str) -> None: """ Sets the rotation of a Blender Object and takes care of picking which rotation type to give the value to """ if rotation_mode == "AXIS_ANGLE": assert len(rotation[1]) == 3 blender_object.rotation_axis_angle = rotation elif rotation_mode == "QUATERNION": assert len(rotation) == 4 blender_object.rotation_quaternion = rotation elif set(rotation_mode) == {"X", "Y", "Z"}: assert len(rotation) == 3 blender_object.rotation_euler = rotation else: assert False, "Unsupported rotation mode: " + blender_object.rotation_mode
def setObjEulerRotation(obj: bpy.types.Object, rotation: Vector3f): obj.rotation_mode = kImEulerOrder obj.rotation_euler = makeEulerRotation(rotation)
def setup_material(material: bpy.types.Material, empty: bpy.types.Object = None): """Setup material nodes for the metal tool cap""" # TODO: refactor into smaller node-creation functions that can be re-used elsewhere # logger = get_logger() tree = material.node_tree nodes = tree.nodes # check if we have default nodes n_output, n_bsdf = mutil.check_default_material(material) # set BSDF default values n_bsdf.inputs['Subsurface'].default_value = 0.6 n_bsdf.inputs['Subsurface Color'].default_value = (0.8, 0.444, 0.444, 1.0) n_bsdf.inputs['Metallic'].default_value = 1.0 # thin metallic surface lines (used primarily for normal/bump map computation) n_texcoord_bump = nodes.new('ShaderNodeTexCoord') # setup empty (reference for distance computations) if empty is None: # get currently selected object obj = bpy.context.object # add empty bpy.ops.object.empty_add(type='PLAIN_AXES') empty = bpy.context.object # locate at the top of the object v0 = Vector(obj.bound_box[1]) v1 = Vector(obj.bound_box[2]) v2 = Vector(obj.bound_box[5]) v3 = Vector(obj.bound_box[6]) empty.location = (v0 + v1 + v2 + v3) / 4 # rotate into object space. afterwards we'll have linkage via parenting empty.location = obj.matrix_world @ empty.location # copy rotation empty.rotation_euler = obj.rotation_euler # deselect all bpy.ops.object.select_all(action='DESELECT') # take care to re-select everything empty.select_set(state=True) obj.select_set(state=True) # make obj active again (will become parent of all selected objects) bpy.context.view_layer.objects.active = obj # make parent, keep transform bpy.ops.object.parent_set(type='OBJECT', xmirror=False, keep_transform=True) # set the empty as input for the texture n_texcoord_bump.object = empty # (dot)^2 (distance from empty) n_dot = nodes.new('ShaderNodeVectorMath') n_dot.operation = 'DOT_PRODUCT' tree.links.new(n_texcoord_bump.outputs['Object'], n_dot.inputs[0]) tree.links.new(n_texcoord_bump.outputs['Object'], n_dot.inputs[1]) n_pow = nodes.new('ShaderNodeMath') n_pow.operation = 'POWER' tree.links.new(n_dot.outputs[1], n_pow.inputs[0]) # mapping input from empty to noise n_mapping = nodes.new('ShaderNodeMapping') tree.links.new(n_texcoord_bump.outputs['Object'], n_mapping.inputs[0]) # generate and link up required noise textures n_noise0 = nodes.new('ShaderNodeTexNoise') n_noise0.inputs['Scale'].default_value = 1.0 n_noise0.inputs['Detail'].default_value = 1.0 n_noise0.inputs['Distortion'].default_value = 2.0 tree.links.new(n_pow.outputs[0], n_noise0.inputs[0]) n_noise1 = nodes.new('ShaderNodeTexNoise') n_noise1.inputs['Scale'].default_value = 300.0 n_noise1.inputs['Detail'].default_value = 0.0 n_noise1.inputs['Distortion'].default_value = 0.0 tree.links.new(n_pow.outputs[0], n_noise1.inputs[0]) # XXX: is this noise required? n_noise2 = nodes.new('ShaderNodeTexNoise') n_noise2.inputs['Scale'].default_value = 0.0 n_noise2.inputs['Detail'].default_value = 0.0 n_noise2.inputs['Distortion'].default_value = 0.1 tree.links.new(n_mapping.outputs['Vector'], n_noise2.inputs[0]) n_noise3 = nodes.new('ShaderNodeTexNoise') n_noise3.inputs['Scale'].default_value = 5.0 n_noise3.inputs['Detail'].default_value = 2.0 n_noise3.inputs['Distortion'].default_value = 0.0 tree.links.new(n_mapping.outputs['Vector'], n_noise3.inputs[0]) # color output n_colorramp_col = nodes.new('ShaderNodeValToRGB') n_colorramp_col.color_ramp.color_mode = 'RGB' n_colorramp_col.color_ramp.interpolation = 'LINEAR' n_colorramp_col.color_ramp.elements[0].position = 0.118 n_colorramp_col.color_ramp.elements[1].position = 0.727 tree.links.new(n_noise0.outputs['Fac'], n_colorramp_col.inputs['Fac']) n_output_color = nodes.new('ShaderNodeMixRGB') n_output_color.inputs['Fac'].default_value = 0.400 n_output_color.inputs['Color1'].default_value = (0.485, 0.485, 0.485, 1.0) tree.links.new(n_colorramp_col.outputs['Color'], n_output_color.inputs['Color2']) # roughness finish n_mul_r = nodes.new('ShaderNodeMath') n_mul_r.operation = 'MULTIPLY' n_mul_r.inputs[1].default_value = 0.100 tree.links.new(n_noise3.outputs['Fac'], n_mul_r.inputs[0]) n_output_roughness = nodes.new('ShaderNodeMath') n_output_roughness.operation = 'ADD' n_output_roughness.inputs[1].default_value = 0.050 tree.links.new(n_mul_r.outputs[0], n_output_roughness.inputs[0]) # math nodes to mix noise with distance and get ring-effect (modulo), leading to bump map n_add0 = nodes.new('ShaderNodeMath') n_add0.operation = 'ADD' tree.links.new(n_pow.outputs[0], n_add0.inputs[0]) tree.links.new(n_noise2.outputs['Fac'], n_add0.inputs[1]) n_mul0 = nodes.new('ShaderNodeMath') n_mul0.operation = 'MULTIPLY' n_mul0.inputs[1].default_value = 300.000 tree.links.new(n_add0.outputs[0], n_mul0.inputs[0]) n_mod0 = nodes.new('ShaderNodeMath') n_mod0.operation = 'MODULO' n_mod0.inputs[1].default_value = 2.000 tree.links.new(n_mul0.outputs[0], n_mod0.inputs[0]) n_mul1 = nodes.new('ShaderNodeMath') n_mul1.operation = 'MULTIPLY' tree.links.new(n_noise1.outputs['Fac'], n_mul1.inputs[0]) tree.links.new(n_mod0.outputs[0], n_mul1.inputs[1]) n_min_n = nodes.new('ShaderNodeMath') n_min_n.operation = 'MINIMUM' tree.links.new(n_noise1.outputs['Fac'], n_min_n.inputs[0]) tree.links.new(n_mul1.outputs[0], n_min_n.inputs[1]) n_colorramp_rough = nodes.new('ShaderNodeValToRGB') n_colorramp_rough.color_ramp.color_mode = 'RGB' n_colorramp_rough.color_ramp.interpolation = 'LINEAR' n_colorramp_rough.color_ramp.elements[0].position = 0.159 n_colorramp_rough.color_ramp.elements[1].position = 0.541 tree.links.new(n_min_n.outputs[0], n_colorramp_rough.inputs[0]) n_output_normal = nodes.new('ShaderNodeBump') n_output_normal.inputs['Strength'].default_value = 0.075 n_output_normal.inputs['Distance'].default_value = 1.000 tree.links.new(n_colorramp_rough.outputs['Color'], n_output_normal.inputs['Height']) # output nodes: # n_output_color -> color / outputs['Color'] # n_output_roughness -> roughness / outputs['Value'] # n_output_normal -> normal / outputs['Normal'] # hook to bsdf shader node tree.links.new(n_output_color.outputs['Color'], n_bsdf.inputs['Base Color']) tree.links.new(n_output_roughness.outputs['Value'], n_bsdf.inputs['Roughness']) tree.links.new(n_output_normal.outputs['Normal'], n_bsdf.inputs['Normal'])
def set_key(bl_obj: bpy.types.Object, frame: int, euler: Tuple[float, float, float]): print('set_key', bl_obj, frame, euler) bl_obj.rotation_euler = euler bl_obj.keyframe_insert(data_path="rotation_euler", frame=frame)