Example #1
0
    def build_resources(self):
        # ray line node
        line_loader = avango.gua.nodes.LineStripLoader()
        self.ray_line = line_loader.create_empty_geometry(
            'ray_line', 'ray.lob')
        self.ray_line.ScreenSpaceLineWidth.value = 5.0
        self.ray_line.RenderVolumetric.value = False
        self.ray_line.Material.value.set_uniform(
            'Color', avango.gua.Vec4(1.0, 0.0, 0.0, 1.0))
        self.ray_line.Tags.value.append('invisible')
        self.controller_node.Children.value.append(self.ray_line)

        # intersection geometry
        self.intersection_pos_node = avango.gua.nodes.TransformNode(
            Name='intersection_position')
        self.scenegraph.Root.value.Children.value.append(
            self.intersection_pos_node)

        loader = avango.gua.nodes.TriMeshLoader()
        self.intersection_sphere = loader.create_geometry_from_file(
            'intersection_sphere', 'data/objects/sphere.obj',
            avango.gua.LoaderFlags.LOAD_MATERIALS)
        self.intersection_sphere.Transform.value = avango.gua.make_scale_mat(
            0.1)
        self.intersection_sphere.Material.value.set_uniform(
            'Color', avango.gua.Vec4(1.0, 0.0, 0.0, 1.0))
        self.intersection_sphere.Tags.value.append('invisible')
        self.intersection_pos_node.Children.value.append(
            self.intersection_sphere)

        # picker
        self.picker = Picker(self.scenegraph)
        self.always_evaluate(True)
Example #2
0
    def evaluate(self):
        now = time.time()
        picker = Picker(self.scenegraph)
        temporary_sf_output_matrix_value = self.sf_output_matrix.value

        elapsed = now - self.lf_time
        self.lf_time = now

        # Height alignment
        vertical_pick = picker.compute_pick_result(
            self.scenegraph['/navigation_node/avatar'].WorldTransform.value.
            get_translate(), avango.gua.Vec3(0, -1, 0), 100, ['invisible'])

        self.climbing_lock = False
        if vertical_pick and vertical_pick.Object.value.Name.value == 'ball':
            #Checking balls
            vertical_pick.Object.value.Tags.value.append('invisible')
            self.collected_balls += 1
            if self.collected_balls >= 6:
                print("Task completed in",
                      time.time() - self.start_time, "seconds")
        elif vertical_pick and vertical_pick.Distance.value < 2:
            #Climb
            temporary_sf_output_matrix_value *= avango.gua.make_trans_mat(
                0, .01, 0)
            self.falling_velocity = 0
            self.climbing_lock = True
        else:
            #Fall
            self.falling_velocity += 0.00005
            temporary_sf_output_matrix_value *= avango.gua.make_trans_mat(
                0, -self.falling_velocity, 0)

        self.velocity.x = self.sf_input_x.value * .000025
        self.velocity.z = self.sf_input_z.value * .000025

        starting_position = self.scenegraph[
            '/navigation_node/avatar'].WorldTransform.value
        target_movement = avango.gua.make_trans_mat(self.velocity.x, 0,
                                                    self.velocity.z)
        target_position = starting_position * target_movement
        direction = target_position.get_translate(
        ) - starting_position.get_translate()
        normalized_direction = direction
        normalized_direction.normalize()
        horizontal_pick = picker.compute_pick_result(
            starting_position.get_translate(), normalized_direction, 10.0,
            ['ball'])

        if not horizontal_pick or horizontal_pick.Distance.value > .5:
            if not self.climbing_lock:
                temporary_sf_output_matrix_value *= target_movement
            self.sf_output_matrix.value = temporary_sf_output_matrix_value

        self.rotation_velocity.y = self.sf_input_ry.value * -0.0005
        rx_rotation = self.sf_input_rx.value * (90 / 350) - 25
        self.sf_rotation_output_matrix.value = avango.gua.make_rot_mat(
            rx_rotation, 1, 0, 0)
        self.sf_output_matrix.value *= avango.gua.make_rot_mat(
            self.rotation_velocity.y, 0, 1, 0)
Example #3
0
    def set_inputs(self, scenegraph, head_node, controller_node,
                   controller_sensor):
        # store references and add geometries to scenegraph
        self.scenegraph = scenegraph
        self.head_node = head_node
        self.controller_node = controller_node
        self.controller_sensor = controller_sensor
        self.controller_node.Children.value.append(self.hand_node_translate)
        self.sf_dragging_trigger.connect_from(self.controller_sensor.Button4)

        # create picker
        self.picker = Picker(self.scenegraph)
        self.always_evaluate(True)
    def set_inputs(self, scenegraph, head_node, controller_node, controller_sensor):
        # store references and add geometries to scenegraph
        self.scenegraph = scenegraph
        self.head_node = head_node
        self.controller_node = controller_node
        self.controller_sensor = controller_sensor
        self.controller_node.Children.value.append(self.ray_line)
        self.controller_node.Children.value.append(self.depth_marker)
        self.sf_touchpad_button.connect_from(self.controller_sensor.Button4)
        self.sf_touchpad_y.connect_from(self.controller_sensor.Value2)
        self.sf_grip_button.connect_from(self.controller_sensor.Button2)

        # create picker
        self.picker = Picker(self.scenegraph)
        self.always_evaluate(True)
Example #5
0
class JumpingNavigation(avango.script.Script):

    # input field
    sf_touchpad_button = avango.SFBool()
    sf_touchpad_button.value = False

    # output field
    sf_navigation_matrix = avango.gua.SFMatrix4()
    sf_navigation_matrix.value = avango.gua.make_identity_mat()

    def __init__(self):
        self.super(JumpingNavigation).__init__()
        self.transition_mode = 'instant'
        self.ray_max_distance = 2000.0  # m
        self.animation_speed = 20.0  # m/s
        self.active = False
        self.animation_start_time = None
        self.animation_start_pos = None
        self.animation_target_pos = None

    # sets the inputs to be used for navigation
    def set_inputs(self, scenegraph, navigation_node, head_node,
                   controller_node, controller_sensor):
        self.scenegraph = scenegraph
        self.navigation_node = navigation_node
        self.head_node = head_node
        self.controller_node = controller_node
        self.controller_sensor = controller_sensor
        self.build_resources()
        self.sf_touchpad_button.connect_from(self.controller_sensor.Button4)

    # builds the line node and intersection geometries
    def build_resources(self):
        # ray line node
        line_loader = avango.gua.nodes.LineStripLoader()
        self.ray_line = line_loader.create_empty_geometry(
            'ray_line', 'ray.lob')
        self.ray_line.ScreenSpaceLineWidth.value = 5.0
        self.ray_line.RenderVolumetric.value = False
        self.ray_line.Material.value.set_uniform(
            'Color', avango.gua.Vec4(1.0, 0.0, 0.0, 1.0))
        self.ray_line.Tags.value.append('invisible')
        self.controller_node.Children.value.append(self.ray_line)

        # intersection geometry
        self.intersection_pos_node = avango.gua.nodes.TransformNode(
            Name='intersection_position')
        self.scenegraph.Root.value.Children.value.append(
            self.intersection_pos_node)

        loader = avango.gua.nodes.TriMeshLoader()
        self.intersection_sphere = loader.create_geometry_from_file(
            'intersection_sphere', 'data/objects/sphere.obj',
            avango.gua.LoaderFlags.LOAD_MATERIALS)
        self.intersection_sphere.Transform.value = avango.gua.make_scale_mat(
            0.1)
        self.intersection_sphere.Material.value.set_uniform(
            'Color', avango.gua.Vec4(1.0, 0.0, 0.0, 1.0))
        self.intersection_sphere.Tags.value.append('invisible')
        self.intersection_pos_node.Children.value.append(
            self.intersection_sphere)

        # picker
        self.picker = Picker(self.scenegraph)
        self.always_evaluate(True)

    # enables or disables the navigation technique
    def enable(self, boolean):
        if boolean:
            self.sf_navigation_matrix.value = self.navigation_node.Transform.value
            self.navigation_node.Transform.disconnect()
            self.navigation_node.Transform.connect_from(
                self.sf_navigation_matrix)
        self.active = boolean

    # switches between instant and animated transition
    def set_transition_mode(self, mode):
        if mode == 'instant':
            self.transition_mode = 'instant'
        elif mode == 'animated':
            self.transition_mode = 'animated'
        self.animation_start_time = None
        self.animation_start_pos = None
        self.animation_target_pos = None

    # called every frame because of self.always_evaluate(True)
    # updates sf_navigation_matrix by processing the inputs
    # YOUR CODE - BEGIN (Exercises 6.2, 6.3 - Jumping Navigation)
    def evaluate(self):
        ray_direction = (
            self.controller_node.WorldTransform.value *
            avango.gua.make_trans_mat(0, 0, -1)).get_translate(
            ) - self.controller_node.WorldTransform.value.get_translate()
        pick_results = self.picker.compute_all_pick_results(
            self.controller_node.WorldTransform.value.get_translate(),
            ray_direction, self.ray_max_distance, [])
        if pick_results:
            self.intersection_pos_node.Transform.value = avango.gua.make_trans_mat(
                pick_results[0].WorldPosition.value)
            self.ray_line.start_vertex_list()
            self.ray_line.enqueue_vertex(0.0, 0.0, 0.0)
            self.ray_line.enqueue_vertex(0.0, 0.0,
                                         -pick_results[0].Distance.value)
            self.ray_line.end_vertex_list()
        else:
            self.ray_line.start_vertex_list()
            self.ray_line.enqueue_vertex(0.0, 0.0, 0.0)
            self.ray_line.enqueue_vertex(0.0, 0.0, -self.ray_max_distance)
            self.ray_line.end_vertex_list()

        if self.animation_start_pos:
            path = self.animation_target_pos - self.animation_start_pos
            travel_time = path.length() / self.animation_speed
            elapsed_time = time.time() - self.animation_start_time

            self.navigation_node.Transform.value = avango.gua.make_trans_mat(
                self.animation_start_pos.x +
                (elapsed_time / travel_time) * path.x, 0,
                self.animation_start_pos.z +
                (elapsed_time / travel_time) * path.z)

            if elapsed_time > travel_time:
                self.animation_start_time = None
                self.animation_start_pos = None
                self.animation_target_pos = None

    # called whenever sf_touchpad_button changes
    @field_has_changed(sf_touchpad_button)
    def sf_touchpad_button_changed(self):
        if self.active:
            if self.sf_touchpad_button.value:
                self.ray_line.Tags.value.remove('invisible')
                self.intersection_sphere.Tags.value.remove('invisible')
            else:
                destination = self.navigation_node.Transform.value
                destination.set_element(
                    0, 3,
                    self.intersection_pos_node.WorldTransform.value.
                    get_translate().x -
                    self.head_node.Transform.value.get_translate().x)
                destination.set_element(
                    2, 3,
                    self.intersection_pos_node.WorldTransform.value.
                    get_translate().z -
                    self.head_node.Transform.value.get_translate().z)
                if self.transition_mode == 'animated':
                    self.animation_start_time = time.time()
                    self.animation_start_pos = self.head_node.WorldTransform.value.get_translate(
                    )
                    self.animation_target_pos = destination.get_translate()
                else:
                    self.navigation_node.Transform.value = destination
                self.ray_line.Tags.value.append('invisible')
                self.intersection_sphere.Tags.value.append('invisible')
Example #6
0
    def evaluate(self):
        now = time.time()
        elapsed = now - self.lf_time
        rocker_value = self.controller1_sensor.Value3.value
        button_value = self.controller1_sensor.Value1.value
        self.lf_time = now
        picker = Picker(self.scenegraph)

        # Check state change
        if button_value != 0.0:
            head_angle = self.get_y_rotation(self.head_node)
            target_position = self.navigation_node.WorldTransform.value * avango.gua.make_rot_mat(
                head_angle, 0, 1, 0) * avango.gua.make_trans_mat(
                    0, 0, -.005) * avango.gua.make_rot_mat(
                        -head_angle, 0, 1, 0)
            starting_position = self.navigation_node.WorldTransform.value
            direction = target_position.get_translate(
            ) - starting_position.get_translate()
            normalized_direction = direction
            normalized_direction.normalize()
            horizontal_pick = picker.compute_pick_result(
                starting_position.get_translate(), normalized_direction,
                direction.length(), ['ball'])

            if not horizontal_pick:
                self.sf_output_matrix.value = target_position

        # Rocker Button
        if rocker_value != 0.0:
            pointer_position = self.controller1_node.WorldTransform.value.get_translate(
            )
            head_position = self.head_node.WorldTransform.value.get_translate()
            pointer_direction = pointer_position - head_position
            pointer_direction *= 0.01

            starting_position = self.scenegraph[
                '/navigation_node'].WorldTransform.value
            target_position = self.sf_output_matrix.value * avango.gua.make_trans_mat(
                pointer_direction.x, 0, pointer_direction.z)
            direction = target_position.get_translate(
            ) - starting_position.get_translate()
            normalized_direction = direction
            normalized_direction.normalize()
            horizontal_pick = picker.compute_pick_result(
                starting_position.get_translate(), normalized_direction,
                direction.length(), ['ball'])

            if not horizontal_pick:
                self.sf_output_matrix.value = target_position

        # Height alignment
        vertical_pick = picker.compute_pick_result(
            self.scenegraph['/navigation_node'].WorldTransform.value.
            get_translate(), avango.gua.Vec3(0, -1, 0), 20, ['invisible'])

        if vertical_pick and vertical_pick.Object.value.Name.value == 'ball':
            vertical_pick.Object.value.Tags.value.append('invisible')
            self.collected_balls += 1
            if self.collected_balls >= 6:
                print("Task completed in",
                      time.time() - self.start_time, "seconds")
        elif vertical_pick and vertical_pick.Distance.value <= 2:
            self.sf_output_matrix.value *= avango.gua.make_trans_mat(
                0, 0.005, 0)
            self.falling_velocity = 0
        else:
            self.falling_velocity += 0.000007
            self.sf_output_matrix.value *= avango.gua.make_trans_mat(
                0, -self.falling_velocity, 0)
Example #7
0
class VirtualHandInteraction(avango.script.Script):

    # input field
    sf_dragging_trigger = avango.SFBool()
    sf_dragging_trigger.value = False

    def __init__(self):
        self.super(VirtualHandInteraction).__init__()
        # YOUR CODE - BEGIN (Add additional variables if necessary)
        # ...
        # YOUR CODE - END (Add additional variables if necessary)
        self.highlighted_object = None
        self.dragging_object = None
        self.enable_flag = False
        self.create_resources()

    # enables and disables this interaction technique
    def enable(self, boolean):
        if boolean:
            self.hand_node.Tags.value.remove('invisible')
        else:
            self.hand_node.Tags.value.append('invisible')
        self.enable_flag = boolean

    # creates the necessary geometries for this interaction technique
    def create_resources(self):
        self.hand_node_translate = avango.gua.nodes.TransformNode(
            Name='hand_translate')
        self.hand_node_translate.Transform.value = avango.gua.make_identity_mat(
        )

        loader = avango.gua.nodes.TriMeshLoader()
        self.hand_node = loader.create_geometry_from_file(
            'hand_node', 'data/objects/hand.obj',
            avango.gua.LoaderFlags.LOAD_MATERIALS)
        self.hand_node.Material.value.set_uniform('Roughness', 0.6)
        self.hand_node.Tags.value.append('invisible')
        self.hand_node_translate.Children.value.append(self.hand_node)

    # sets the correct inputs to be used for this interaction technique
    def set_inputs(self, scenegraph, head_node, controller_node,
                   controller_sensor):
        # store references and add geometries to scenegraph
        self.scenegraph = scenegraph
        self.head_node = head_node
        self.controller_node = controller_node
        self.controller_sensor = controller_sensor
        self.controller_node.Children.value.append(self.hand_node_translate)
        self.sf_dragging_trigger.connect_from(self.controller_sensor.Button4)

        # create picker
        self.picker = Picker(self.scenegraph)
        self.always_evaluate(True)

    # called every frame because of self.always_evaluate(True)
    def evaluate(self):
        if self.enable_flag:
            self.apply_gogo(0.5)

            if self.dragging_object is not None:
                self.dragging_update()
            else:
                pick_result = self.compute_pick_result()
                self.update_highlights(pick_result)

    # updates the position of the virtual hand with respect to the GoGo mapping
    def apply_gogo(self, threshold):
        hand_pos = self.controller_node.WorldTransform.value.get_translate()
        head_pos = self.head_node.WorldTransform.value.get_translate()
        # YOUR CODE - BEGIN (Exercise 5.3 - GoGo)
        orientation = hand_pos - head_pos
        orientation.y = 0
        distance = orientation.length()
        if distance >= 0.3:
            self.hand_node_translate.Transform.value = avango.gua.make_trans_mat(
                0, 0, -20 * (distance - 0.3)**2)
        # YOUR CODE - END (Exercise 5.3 - GoGo)

    # computes intersections of the hand with the scene
    def compute_pick_result(self):
        # YOUR CODE - BEGIN (Exercise 5.1 - Compute pick result)
        direction = (self.hand_node.WorldTransform.value *
                     avango.gua.make_trans_mat(0, 0, -1)).get_translate(
                     ) - self.hand_node.WorldTransform.value.get_translate()
        result = self.picker.compute_all_pick_results(
            self.hand_node.WorldTransform.value.get_translate(), direction,
            0.2, [])
        if result:
            return result[0]
        return None
        # YOUR CODE - END (Exercise 5.1 - Compute pick result)

    # updates the object highlights with respect to a pick result
    def update_highlights(self, pick_result):
        if pick_result is not None:
            if self.highlighted_object is not None and \
               pick_result.Object.value.Name.value != self.highlighted_object.Name.value:
                self.remove_highlight()
            self.highlight_object(pick_result.Object.value)
        else:
            self.remove_highlight()

    # highlights an object
    def highlight_object(self, node):
        node.Material.value.set_uniform('Color',
                                        avango.gua.Vec4(1.0, 1.0, 1.0, 1.0))
        self.highlighted_object = node

    # removes the current object highlight
    def remove_highlight(self):
        if self.highlighted_object is not None:
            color_id = int(self.highlighted_object.Tags.value[0])
            self.highlighted_object.Material.value.set_uniform(
                'Color', config.OBJECT_COLORS[color_id])
            self.highlighted_object = None

    # called once when the dragging button is pressed
    def start_dragging(self):
        if self.highlighted_object is not None:
            # YOUR CODE - BEGIN (Exercise 5.2 - Object Dragging)
            self.dragging_object = self.highlighted_object
            position = avango.gua.make_inverse_mat(
                self.hand_node.WorldTransform.value
            ) * self.dragging_object.Transform.value
            self.hand_node.Children.value.append(self.dragging_object)
            self.dragging_object.Transform.value = position
            self.scenegraph.Root.value.Children.value.remove(
                self.dragging_object)
            # YOUR CODE - END (Exercise 5.2 - Object Dragging)

    # called during every frame of a dragging operation
    def dragging_update(self):
        # YOUR CODE - BEGIN (Exercise 5.2 - Object Dragging)
        pass
        # YOUR CODE - END (Exercise 5.2 - Object Dragging)

    # called once when the dragging button is released
    def stop_dragging(self):
        # YOUR CODE - BEGIN (Exercise 5.2 - Object Dragging)
        if self.dragging_object:
            position = self.dragging_object.WorldTransform.value
            self.scenegraph.Root.value.Children.value.append(
                self.dragging_object)
            self.dragging_object.Transform.value = position
            self.hand_node.Children.value.remove(self.dragging_object)
            self.dragging_object = None
        # YOUR CODE - END (Exercise 5.2 - Object Dragging)

    # called whenever sf_dragging_trigger changes and calls start_dragging()
    # or stop_dragging() depending on the current button state
    @field_has_changed(sf_dragging_trigger)
    def sf_dragging_trigger_changed(self):
        if self.sf_dragging_trigger.value:
            self.start_dragging()
        else:
            self.stop_dragging()
class VirtualRayInteraction(avango.script.Script):

    # input fields
    sf_touchpad_button = avango.SFBool()
    sf_touchpad_button.value = False

    sf_touchpad_y = avango.SFFloat()
    sf_touchpad_y.value = 0.0

    sf_grip_button = avango.SFBool()
    sf_grip_button.value = False

    def __init__(self):
        self.super(VirtualRayInteraction).__init__()
        # YOUR CODE - BEGIN (Add additional variables if necessary)
        self.teleportable_object = None
        # YOUR CODE - END (Add additional variables if necessary)
        self.ray_max_distance = 10.0
        self.highlighted_object = None
        self.enable_flag = False
        self.create_resources()

    # enables and disables this interaction technique
    def enable(self, boolean):
        if boolean:
            self.ray_line.Tags.value.remove('invisible')
            self.depth_marker.Tags.value.remove('invisible')
        else:
            self.ray_line.Tags.value.append('invisible')
            self.depth_marker.Tags.value.append('invisible')
        self.enable_flag = boolean

    # creates the necessary geometries for this interaction technique
    def create_resources(self):
        line_loader = avango.gua.nodes.LineStripLoader()
        self.ray_line = line_loader.create_empty_geometry('ray_line', 'ray.lob')
        self.ray_line.ScreenSpaceLineWidth.value = 5.0
        self.ray_line.RenderVolumetric.value = False
        self.ray_line.Material.value.set_uniform(
            'Color', avango.gua.Vec4(1.0, 0.0, 0.0, 1.0))
        self.ray_line.start_vertex_list()
        self.ray_line.enqueue_vertex(0.0, 0.0, 0.0)
        self.ray_line.enqueue_vertex(0.0, 0.0, -self.ray_max_distance)
        self.ray_line.end_vertex_list()
        self.ray_line.Tags.value.append('invisible')

        loader = avango.gua.nodes.TriMeshLoader()
        self.depth_marker = loader.create_geometry_from_file('depth_marker',
                                                             'data/objects/sphere.obj',
                                                             avango.gua.LoaderFlags.LOAD_MATERIALS)
        self.depth_marker.Material.value.set_uniform(
            'Color', avango.gua.Vec4(1.0, 0.0, 0.0, 1.0))
        self.depth_marker.Tags.value.append('invisible')

    # sets the correct inputs to be used for this interaction technique
    def set_inputs(self, scenegraph, head_node, controller_node, controller_sensor):
        # store references and add geometries to scenegraph
        self.scenegraph = scenegraph
        self.head_node = head_node
        self.controller_node = controller_node
        self.controller_sensor = controller_sensor
        self.controller_node.Children.value.append(self.ray_line)
        self.controller_node.Children.value.append(self.depth_marker)
        self.sf_touchpad_button.connect_from(self.controller_sensor.Button4)
        self.sf_touchpad_y.connect_from(self.controller_sensor.Value2)
        self.sf_grip_button.connect_from(self.controller_sensor.Button2)

        # create picker
        self.picker = Picker(self.scenegraph)
        self.always_evaluate(True)

    # called every frame because of self.always_evaluate(True)
    def evaluate(self):
        if self.enable_flag:
            self.update_depth_marker()
            pick_result = self.compute_pick_result()
            self.update_highlights(pick_result)

    # updates the depth marker with respect to button inputs
    def update_depth_marker(self):
        # YOUR CODE - BEGIN (Exercises 5.5 - Depth Marker)
        if self.sf_touchpad_button.value:
            temporary_transform = self.depth_marker.Transform.value * avango.gua.make_trans_mat(0,0,-self.sf_touchpad_y.value*0.01)
            if temporary_transform.get_translate().z > -self.ray_max_distance and temporary_transform.get_translate().z < 0:
                self.depth_marker.Transform.value = temporary_transform
        # YOUR CODE - END (Exercises 5.5 - Depth Marker)

    # computes intersections of the ray with the scene
    def compute_pick_result(self):
        # YOUR CODE - BEGIN (Exercises 5.4, 5.5 - Compute pick result)
        direction = (self.controller_node.WorldTransform.value * avango.gua.make_trans_mat(0,0,-1)).get_translate() - self.controller_node.WorldTransform.value.get_translate()
        results = self.picker.compute_all_pick_results(self.controller_node.WorldTransform.value.get_translate(),direction,self.ray_max_distance,[])
        result = None
        minimum = self.ray_max_distance
        for pick in results:
            vector = pick.Object.value.WorldTransform.value.get_translate() - self.depth_marker.WorldTransform.value.get_translate()
            distance = vector.length()
            if distance < minimum:
                result = pick
                minimum = distance
            if distance > minimum:
                break
        if result:
            return result
        # YOUR CODE - END (Exercises 5.4, 5.5 - Compute pick result)

    # updates the object highlights with respect to a pick result
    def update_highlights(self, pick_result):
        if pick_result is not None:
            if self.highlighted_object is not None and \
               pick_result.Object.value.Name.value != self.highlighted_object.Name.value:
                self.remove_highlight()
            self.highlight_object(pick_result.Object.value)
        else:
            self.remove_highlight()

    # highlights an object when hit with the intersection ray
    def highlight_object(self, node):
        node.Material.value.set_uniform(
            'Color', avango.gua.Vec4(1.0, 1.0, 1.0, 1.0))
        self.highlighted_object = node

    # removes the current object highlight
    def remove_highlight(self):
        if self.highlighted_object is not None:
            color_id = int(self.highlighted_object.Tags.value[0])
            self.highlighted_object.Material.value.set_uniform(
                'Color', config.OBJECT_COLORS[color_id])
            self.highlighted_object = None

    # called whenever sf_grip_button button changes
    @field_has_changed(sf_grip_button)
    def sf_grip_button_changed(self):
        if self.sf_grip_button.value:
            # YOUR CODE - BEGIN (Exercise 5.6 - Object Teleport)
            if self.teleportable_object:
                new_mat = self.teleportable_object.Transform.value
                new_mat.set_element(0,3,self.depth_marker.WorldTransform.value.get_translate().x)
                new_mat.set_element(1,3,self.depth_marker.WorldTransform.value.get_translate().y)
                new_mat.set_element(2,3,self.depth_marker.WorldTransform.value.get_translate().z)
                self.teleportable_object.Transform.value = new_mat
                self.teleportable_object.Tags.value.remove('invisible')
                self.teleportable_object = None
            elif self.highlighted_object:
                self.teleportable_object = self.highlighted_object
                self.teleportable_object.Tags.value.append('invisible')