Follow Target

I would like object a to orient/face to object b rotating only in z-axis. It should update every tick and object a should look at object b. The application should be embedded in a extension. Object a does some rotation, but then also translate, but it should stay at the initial position, whereas object b is able to move.

Thanks for helping!

    def on_startup(self, ext_id):
        print("[xxx.20230907] xxx 20230907 startup")

        self._count = 0

        self._window = ui.Window("Rotate Tracker", width=300, height=300)
        with self._window.frame:
            with ui.VStack():
                label = ui.Label("")


                def on_click():
                    stage = omni.usd.get_context().get_stage()
                    cube_prim = stage.GetPrimAtPath("/World/Cube")
                    #label.text = f"count: {cube_prim.orientation}"

                def on_reset():
                    self._count = 0
                    label.text = "empty"

                def onrotate():##works with defined angle
                    stage = omni.usd.get_context().get_stage()
                    AT_path = "/World/SampleScene/Geometry/Xform"  # Replace with the path to your target object
                    AS_path = "/World/SampleScene/Geometry/Xform_01"  # Replace with the path to your object to be rotated

                    # Find the target and rotate objects in the stage
                    
                    AT = stage.GetPrimAtPath(AT_path)
                    AS = stage.GetPrimAtPath(AS_path)
                    xformable = UsdGeom.Xformable(AT)
                    AT_translation = omni.usd.get_local_transform_matrix(AT)
                    AS_translation = omni.usd.get_local_transform_matrix(AS)

                    if AT is not None and AS is not None:
                        # Get the positions of the target and rotate objects in world coordinates
                        AT_translation_Vec = UsdGeom.XformCommonAPI(AT).GetXformVectors(
                            time=Usd.TimeCode.Default())[0]
                        AS_translation_Vec = UsdGeom.XformCommonAPI(AS).GetXformVectors(
                            time=Usd.TimeCode.Default())[0]
                        
                    
                    # Calculate the direction vector from the rotate_object to the target_object
                    AB = AT_translation_Vec - AS_translation_Vec

                    AB[2] = 0
                    AB = Gf.GetNormalized(AB)
                    AC = Gf.Vec3f(0.0, 1.0, 0.0)
                    dot = np.dot(AB, AC)
                    theta = math.acos(dot)
                    Degrees = math.degrees(theta)
                    # Clear transforms


                    xformable.SetXformOpOrder([])

                    #xformable.AddTranslateOp().Set(Gf.Vec3d(0, 0, 0))
                    # Rotate
                    xformable.AddRotateXYZOp().Set(Gf.Vec3d(0, 0, Degrees))
                    #Newrotation = xformable.AddRotateXYZOp().Set(Gf.Vec3d(0, 0, Degrees))
                    #xformable.AddScaleOp().Set((0.01, 0.01, 0.01))

                    label.text = f"count: {Degrees, AT_translation_Vec}"
 
                on_reset()

                with ui.HStack():
                    ui.Button("Add", clicked_fn=on_click)
                    ui.Button("Reset", clicked_fn=on_reset)
                    ui.Button("Onrotate", clicked_fn=onrotate)

    def on_shutdown(self):
        print("[xx.20230907] xxx20230907 shutdown")

Hi @raphael.zuercher - Your code seems to be on the right track. However, it seems like you’re adding a new rotation operation every time you click the “Onrotate” button. This could be the reason why your object A is translating. Instead of adding a new rotation operation every time, you should update the existing rotation operation.

Here’s a modified version of your code:

def onrotate():
    stage = omni.usd.get_context().get_stage()
    AT_path = "/World/SampleScene/Geometry/Xform"  # Replace with the path to your target object
    AS_path = "/World/SampleScene/Geometry/Xform_01"  # Replace with the path to your object to be rotated

    # Find the target and rotate objects in the stage
    AT = stage.GetPrimAtPath(AT_path)
    AS = stage.GetPrimAtPath(AS_path)
    xformable = UsdGeom.Xformable(AT)

    if AT is not None and AS is not None:
        # Get the positions of the target and rotate objects in world coordinates
        AT_translation_Vec = UsdGeom.XformCommonAPI(AT).GetXformVectors(time=Usd.TimeCode.Default())[0]
        AS_translation_Vec = UsdGeom.XformCommonAPI(AS).GetXformVectors(time=Usd.TimeCode.Default())[0]

        # Calculate the direction vector from the rotate_object to the target_object
        AB = AT_translation_Vec - AS_translation_Vec
        AB[2] = 0
        AB = Gf.GetNormalized(AB)
        AC = Gf.Vec3f(0.0, 1.0, 0.0)
        dot = np.dot(AB, AC)
        theta = math.acos(dot)
        Degrees = math.degrees(theta)

        # Clear transforms
        xformable.SetXformOpOrder([])

        # Get the existing rotation operation or create a new one if it doesn't exist
        rotation_op = xformable.GetRotateXYZOp()
        if not rotation_op:
            rotation_op = xformable.AddRotateXYZOp()

        # Update the rotation
        rotation_op.Set(Gf.Vec3d(0, 0, Degrees))

        label.text = f"count: {Degrees, AT_translation_Vec}"