Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Rotate Towards C# Jobs

Discussion in 'Entity Component System' started by CosmicStud, Feb 27, 2020.

  1. CosmicStud

    CosmicStud

    Joined:
    Jun 13, 2017
    Posts:
    55
    Very constant jittering caused when changing the rotation of an abject to forward face another object in 3D vectors. Also, when I don't have the quaternion normalized. As well as the quaternion being only the "lookrotation" quaternion does it ever face the object. But with errors about "Rotation quaternions must be unit length." but it works. Currently I am not using the ECS side of the data stack only C# jobs. Just wanting to figure out what is needed...

    My Overall objective is just a simple "lookrotation" with a "slerp" inside a job to smoothly rotate an objects Vector3.forward towards the other object. I've also used only float3 as vector3s, used both versions of "Quaternion and quaternion" and used methods from "Quaternion.Slerp/lerp and math.slerp/lerp"

    Am I overthinking this, Whats missing? lol. Thanks for any help!

    OLD WAY (Works Perfect):
    Code (CSharp):
    1. //Quaternion targetRotation = Quaternion.LookRotation(ai.targetPoint - transform.position);
    2. //Quaternion newRotation = Quaternion.Slerp(transform.rotation, rotation, rotationSpeed);


    NEW WAY:
    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using Unity.Collections;
    4. using Unity.Burst;
    5. using Unity.Mathematics;
    6. using UnityEngine.Jobs;
    7.  
    8. [BurstCompile]
    9. public struct AIRotationJob : IJobParallelForTransform
    10. {
    11.     public NativeArray<Vector3> rotationTargets;
    12.     public NativeArray<Quaternion> newRotations;
    13.  
    14.     public NativeArray<float> rotationSpeeds;
    15.  
    16.     public float deltaTime;
    17.  
    18.     public void Execute(int index, TransformAccess transform)
    19.     {
    20.         Vector3 targetDirection = rotationTargets[index] - transform.position;
    21.  
    22.         float rotationSpeed = deltaTime * rotationSpeeds[index];
    23.  
    24.         quaternion rotation = quaternion.LookRotation(targetDirection, Vector3.up);
    25.  
    26.         quaternion smoothRotation = math.slerp(transform.rotation, rotation, rotationSpeed);
    27.  
    28.         transform.rotation = smoothRotation;
    29.  
    30.         //Ive also store it here, and attempted to rotate the object outside the job
    31.         //newRotations[index] = rotation;
    32.     }
    33. }
    34.  
    35.  
    Code (CSharp):
    1. rotationHandle.Complete();
    2.  
    3.             if (rotationHandle.IsCompleted)
    4.             {
    5.                 Quaternion rotation = newRotations[0].normalized;
    6.  
    7.                 rb.MoveRotation(rotation);
    8.             }
     
  2. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,993
    First, you are mixing the old and new math libraries. Stick to one or the other.

    Second, when using the new math library, you need to either normalize targetDirection or us LookRotationSafe.
     
  3. CosmicStud

    CosmicStud

    Joined:
    Jun 13, 2017
    Posts:
    55
    @DreamingImLatios

    Okay thanks for the quick reply! Ive redone this both ways, using "vectors and Quaternions" and using "float3 and quaternions" Im still having trouble getting the rotation to actually apply. Any examples?

    Old Library
    Code (CSharp):
    1. Vector3 targetDirection = rotationTargets[index] - transform.position;
    2.         float rotationSpeed = deltaTime * rotationSpeeds[index];
    3.         Quaternion rotation = Quaternion.LookRotation(targetDirection);
    4.         Quaternion smoothRotation = Quaternion.Slerp(transform.rotation, rotation, rotationSpeed);
    5.         transform.rotation = smoothRotation;
    **actually works when rotation speed is above 15, it rotates to target although instantly, when i have it set to .5 for example, it slightly moves like a 5th of the way.

    New Library using Unity.Mathematics
    Code (CSharp):
    1. float3 currentRotation = new float3(transform.rotation.x, transform.rotation.y, transform.rotation.z);
    2.         float3 targetRotation = new float3(rotationTargets[index].x, rotationTargets[index].y, rotationTargets[index].z);
    3.  
    4.         float3 targetDirection = targetRotation - currentRotation;
    5.  
    6.         float rotationSpeed = deltaTime * rotationSpeeds[index];
    7.  
    8.         float3 up = new float3(0, 1, 0);
    9.  
    10.         quaternion rotation = quaternion.LookRotationSafe(targetDirection, up);
    11.  
    12.         float3 newRotation = new float3(rotation.value.x, rotation.value.y, rotation.value.z);
    13.  
    14.         float3 smoothRotation = math.lerp(currentRotation, newRotation, deltaTime * 5);
    15.  
    16.         transform.rotation = quaternion.Euler(smoothRotation);
    **Doesnt move at all
     
  4. Zeraphan

    Zeraphan

    Joined:
    Nov 20, 2019
    Posts:
    14
    This is what I have in my RotationSystem and my ships are orbiting their bases smoothly.

    Code (CSharp):
    1.  
    2.                 ship.Theta += .0175f;
    3.                 float3 delta = new float3(
    4.                     ship.Radius * Mathf.Sin(ship.Theta) * Mathf.Cos(ship.Phi),
    5.                     ship.Radius * Mathf.Cos(ship.Theta),
    6.                     ship.Radius * Mathf.Sin(ship.Theta) * Mathf.Sin(ship.Phi));
    7.  
    8.                 float3 previousPos = shipPosition.Value;
    9.  
    10.                 shipPosition.Value = ship.OrbitTarget + delta;
    11.  
    12.                 rotation.Value = Quaternion.Slerp(rotation.Value, Quaternion.LookRotation(
    13.                     shipPosition.Value - previousPos,
    14.                     ship.OrbitTarget - shipPosition.Value), 0.5f);
     
  5. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,993
    Is there a reason why this doesn't work?
    Code (CSharp):
    1. float3 targetDirection = rotationTargets[index] - transform.position;
    2. float rotationSpeed = deltaTime * rotationSpeeds[index];
    3. float3 up = new float3(0f, 1f, 0f);
    4. quaternion rotation = quaternion.LookRotationSafe(targetDirection, up);
    5. quaternion smoothRotation = math.slerp(transform.rotation, rotation, rotationSpeed);
    6. transform.rotation = smoothRotation;
     
  6. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,655
    Code (CSharp):
    1.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    2.         public static quaternion RotateTowards(
    3.             quaternion from,
    4.             quaternion to,
    5.             float maxDegreesDelta)
    6.         {
    7.             float num = Angle(from, to);
    8.             return num < float.Epsilon ? to : math.slerp(from, to, math.min(1f, maxDegreesDelta / num));
    9.         }
    10.      
    11.         [MethodImpl(MethodImplOptions.AggressiveInlining)]
    12.         public static float Angle(this quaternion q1, quaternion q2)
    13.         {
    14.             var dot    = math.dot(q1, q2);
    15.             return !(dot > 0.999998986721039) ? (float) (math.acos(math.min(math.abs(dot), 1f)) * 2.0) : 0.0f;
    16.         }

    var newRotation = MMExtensions.RotateTowards(rotation.Value, lookAt, dt * rotationSpeed);
     
    kidi0892, tcz8, varnon and 7 others like this.
  7. CosmicStud

    CosmicStud

    Joined:
    Jun 13, 2017
    Posts:
    55
    So for some odd reason, using a IJobParallelForTransform does not implement the rotation calculations. BUT when I converted to an IJobParallelFor does it actually work as expected... thanks for your help, much appreciated!

    Code (CSharp):
    1. [BurstCompile]
    2. public struct AIRotationJob : IJobParallelFor
    3. {
    4.     public NativeArray<Vector3> currentPositions;
    5.     public NativeArray<Vector3> rotationTargets;
    6.  
    7.     public NativeArray<quaternion> oldRotations;
    8.     public NativeArray<quaternion> newRotations;
    9.  
    10.     public NativeArray<float> rotationSpeeds;
    11.  
    12.     public float deltaTime;
    13.  
    14.     public void Execute(int index)
    15.     {
    16.         float3 targetDirection = rotationTargets[index] - currentPositions[index];
    17.         float rotationSpeed = deltaTime * rotationSpeeds[index];
    18.         float3 up = new float3(0f, 1f, 0f);
    19.         newRotations[index] = math.slerp(oldRotations[index], quaternion.LookRotationSafe(targetDirection, up), rotationSpeed);
    20.     }
    21. }
    Code (CSharp):
    1.                 rotationHandle.Complete();
    2.  
    3.                 if (rotationHandle.IsCompleted)
    4.                 {
    5.                     rb.MoveRotation(newRotations[0]);
    6.                 }
     
  8. ExNinja

    ExNinja

    Joined:
    Dec 4, 2013
    Posts:
    29
    Thank you, @eizenhorn! This is exactly what I was looking for. Thank goodness for extension methods!
     
  9. ExNinja

    ExNinja

    Joined:
    Dec 4, 2013
    Posts:
    29
    @eizenhorn Is it correct that your method deals in radians and not degrees?
     
  10. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,655
    Yes. Angle returns radians.
    maxDegreesDelta
    just bad naming, because I have both versions with maxDegreesDelta as degrees and as radians and I'm just lazy for rename that :)
     
  11. tcz8

    tcz8

    Joined:
    Aug 20, 2015
    Posts:
    504
    Thank you for posting this!