Beispiel #1
0
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()
Beispiel #2
0
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)
Beispiel #3
0
 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
Beispiel #4
0
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)
Beispiel #5
0
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()
Beispiel #7
0
    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
Beispiel #9
0
def setObjEulerRotation(obj: bpy.types.Object, rotation: Vector3f):
    obj.rotation_mode  = kImEulerOrder
    obj.rotation_euler = makeEulerRotation(rotation)
Beispiel #10
0
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'])
Beispiel #11
0
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)