From e847590fd2e3fe6f06e7f7c88d19ad3c93fed8ed Mon Sep 17 00:00:00 2001 From: Davidterhuerne Date: Fri, 28 Feb 2025 19:49:42 +0100 Subject: [PATCH 1/3] Fixed gameObject leak in aiming task The aimAt script used to create two gameObject every time an aiming task was started, of which only one got destroyed after stopping. I changed it to use two Vectors instead as no new gameObject is actuall needed --- .../Runtime/Scripts/Aiming&Gazing/AimAt.cs | 74 +++++++++---------- .../Scripts/Aiming&Gazing/AimAtBonePresets.cs | 12 +-- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/Assets/Virtual Agents Framework/Runtime/Scripts/Aiming&Gazing/AimAt.cs b/Assets/Virtual Agents Framework/Runtime/Scripts/Aiming&Gazing/AimAt.cs index 519a739d..e4826f27 100644 --- a/Assets/Virtual Agents Framework/Runtime/Scripts/Aiming&Gazing/AimAt.cs +++ b/Assets/Virtual Agents Framework/Runtime/Scripts/Aiming&Gazing/AimAt.cs @@ -2,6 +2,7 @@ using System; using UnityEngine; using UnityEngine.AI; +using UnityEngine.Serialization; namespace i5.VirtualAgents { @@ -17,7 +18,7 @@ public abstract class AimAt : MonoBehaviour [SerializeField] protected Transform targetTransform; /// - /// The Transform of the agent childobjects that should directly aim at the target + /// The Transform of the agent childobjects that should directly aim at the target, e.g. the tip of a finger /// [Tooltip("The Transform of the agent childobjects that should directly aim at the target")] [SerializeField] protected Transform aimTransform; @@ -28,9 +29,9 @@ public abstract class AimAt : MonoBehaviour protected AimDirection aimDirection = AimDirection.Y; /// - /// The Transform that is acutally looked at and will follow the target smootly + /// The Position that is actually looked at and which will follow the target smoothly /// - protected Transform targetFollower; + protected Vector3 targetFollower = Vector3.zero; /// /// The speed at which the agent looks at the target @@ -66,10 +67,10 @@ public abstract class AimAt : MonoBehaviour [SerializeField] protected float distanceLimit = 1.5f; /// - /// The postion where the targetFollower should be placed when no target is set + /// The position where the targetFollower should be placed when no target is set /// - [Tooltip("The postion where the targetFollower should be placed when no target is set")] - [SerializeField] protected Transform startingTransform; + [Tooltip("The position where the targetFollower should be placed when no target is set")] + [SerializeField] protected Vector3 startingPosition = Vector3.zero; /// /// The bones that should be moved to accomplish the aiming @@ -122,7 +123,7 @@ protected virtual void Start() public void SetupAndStart(Transform target, bool shouldDestroyItself = true) { SetBonePreset(); - this.ShouldDestroyItself = shouldDestroyItself; + ShouldDestroyItself = shouldDestroyItself; SetTargetTransform(target); } @@ -131,7 +132,7 @@ public void SetupAndStart(Transform target, bool shouldDestroyItself = true) /// public void Stop() { - this.targetTransform = null; + targetTransform = null; } // LateUpdate is called once per frame, after Update @@ -139,7 +140,7 @@ protected void LateUpdate() { TemporarilyIncreaseLookSpeed(navMeshAgent.velocity.magnitude); - if (targetFollower != null) + if (targetFollower != Vector3.zero) { UpdateTargetFollower(); @@ -161,7 +162,7 @@ protected void LateUpdate() protected Vector3 CalculateWhereToLook() { - Vector3 targetDirection = targetFollower.position - aimTransform.position; + Vector3 targetDirection = targetFollower - aimTransform.position; Vector3 aimDirection = GetAimDirectionVector(); float blendOut = 0.0f; float targetAngle = Vector3.Angle(targetDirection, aimDirection); @@ -186,18 +187,18 @@ protected void UpdateTargetFollower() Vector3 targetPosition; // If targetTransform was not removed in Stop() - if (targetTransform != null) + if (targetTransform) { targetPosition = targetTransform.position; increaseLookSpeedBy = 1; } else { - // Return to the starting posiont - targetPosition = startingTransform.position; + // Return to the starting point + targetPosition = transform.TransformPoint(startingPosition);; - if (Vector3.Distance(targetFollower.position, targetPosition) >= 0.05f) + if (Vector3.Distance(targetFollower, targetPosition) >= 0.05f) { // increase LookSpeed over time to finish up the movement increaseLookSpeedBy = Math.Min(10, increaseLookSpeedBy + 0.7f); @@ -205,11 +206,11 @@ protected void UpdateTargetFollower() } else { + targetFollower = transform.TransformPoint(startingPosition); // When target position of the standard look is reached destroy this component Weight = 0f; if (ShouldDestroyItself) { - Destroy(targetFollower.gameObject); Destroy(this); } } @@ -217,7 +218,7 @@ protected void UpdateTargetFollower() } // Smooth transition to target position - targetFollower.transform.position = Vector3.Lerp(targetFollower.transform.position, targetPosition, Time.deltaTime * (currentLookSpeed * increaseLookSpeedBy)); + targetFollower = Vector3.Lerp(targetFollower, targetPosition, Time.deltaTime * (currentLookSpeed * increaseLookSpeedBy)); } @@ -232,11 +233,11 @@ protected void AimAtTarget(Transform bone, Vector3 targetPosition, float weight) protected Vector3 GetAimDirectionVector() { - if (this.aimDirection == AimDirection.Y) + if (aimDirection == AimDirection.Y) return aimTransform.up.normalized; - if (this.aimDirection == AimDirection.X) + if (aimDirection == AimDirection.X) return aimTransform.right.normalized; - if (this.aimDirection == AimDirection.Z) + if (aimDirection == AimDirection.Z) return aimTransform.forward; return aimTransform.up.normalized; @@ -245,27 +246,21 @@ protected Vector3 GetAimDirectionVector() public void SetTargetTransform(Transform targetTransform) { // If there is no targetFollower, create one - if (targetFollower == null) + if (targetFollower == Vector3.zero) { - targetFollower = new GameObject().transform; - targetFollower.gameObject.name = "TargetFollower"; - DebugDrawTransformSphere targetVisualizer = targetFollower.gameObject.AddComponent(); - targetVisualizer.color = Color.red; - targetVisualizer.radius = 0.50f; - - // Set starting position of targetFollower 1 unit along the current aiming direction getAimDirectionVektor() * 1f + - this.startingTransform = new GameObject().transform; - this.startingTransform.gameObject.name = "StartingPositon"; - this.startingTransform.position = aimTransform.position + (GetAimDirectionVector() * 1f); - this.startingTransform.parent = this.transform; - this.targetFollower.position = startingTransform.position; + targetFollower = new Vector3(); + + // Set starting position of targetFollower 1 unit along the current aiming direction getAimDirectionVector() * 1f + startingPosition = new Vector3(); + startingPosition = transform.InverseTransformPoint(aimTransform.position + (GetAimDirectionVector() * 1f)); + targetFollower = transform.TransformPoint(startingPosition); } this.targetTransform = targetTransform; } public void TemporarilyIncreaseLookSpeed(float increase) { - this.currentLookSpeed = LookSpeed + increase; + currentLookSpeed = LookSpeed + increase; } /// @@ -290,7 +285,7 @@ public void UseNewBoneset(HumanBone[] humanBones, AimDirection aimDirection, Tra public abstract void SetBonePreset(); - protected void GetBoneTransformsFromAnimatior(HumanBodyBones aimingTip) + protected void GetBoneTransformsFromAnimator(HumanBodyBones aimingTip) { Animator animator = GetComponent(); boneTransforms = new Transform[humanBones.Length]; @@ -305,10 +300,15 @@ protected void GetBoneTransformsFromAnimatior(HumanBodyBones aimingTip) protected void OnDrawGizmos() { Gizmos.color = Color.green; - if (startingTransform) + if (startingPosition != Vector3.zero) + { + Gizmos.DrawWireSphere(transform.TransformPoint(startingPosition), 0.25f); + Gizmos.DrawLine(aimTransform.position, transform.TransformPoint(startingPosition)); + } + Gizmos.color = Color.red; + if (targetFollower != Vector3.zero) { - Gizmos.DrawWireSphere(startingTransform.position, 0.25f); - Gizmos.DrawLine(aimTransform.position, startingTransform.position); + Gizmos.DrawWireSphere(targetFollower, 0.25f); } } } diff --git a/Assets/Virtual Agents Framework/Runtime/Scripts/Aiming&Gazing/AimAtBonePresets.cs b/Assets/Virtual Agents Framework/Runtime/Scripts/Aiming&Gazing/AimAtBonePresets.cs index 960b55f6..89ecfb6d 100644 --- a/Assets/Virtual Agents Framework/Runtime/Scripts/Aiming&Gazing/AimAtBonePresets.cs +++ b/Assets/Virtual Agents Framework/Runtime/Scripts/Aiming&Gazing/AimAtBonePresets.cs @@ -46,7 +46,7 @@ public override void SetBonePreset() aimDirection = AimDirection.Y; angleLimit = 180f; - GetBoneTransformsFromAnimatior(HumanBodyBones.RightIndexDistal); + GetBoneTransformsFromAnimator(HumanBodyBones.RightIndexDistal); } } public class LeftArmPreset : AimAt @@ -93,7 +93,7 @@ public override void SetBonePreset() aimDirection = AimDirection.Y; angleLimit = 180f; - GetBoneTransformsFromAnimatior(HumanBodyBones.LeftIndexDistal); + GetBoneTransformsFromAnimator(HumanBodyBones.LeftIndexDistal); } } @@ -135,7 +135,7 @@ public override void SetBonePreset() aimDirection = AimDirection.Y; angleLimit = 180f; - GetBoneTransformsFromAnimatior(HumanBodyBones.RightToes); + GetBoneTransformsFromAnimator(HumanBodyBones.RightToes); } } public class LeftLegPreset : AimAt @@ -175,7 +175,7 @@ public override void SetBonePreset() }; aimDirection = AimDirection.Y; angleLimit = 180f; - GetBoneTransformsFromAnimatior(HumanBodyBones.LeftToes); + GetBoneTransformsFromAnimator(HumanBodyBones.LeftToes); } } @@ -203,7 +203,7 @@ public override void SetBonePreset() angleLimit = 100f; aimDirection = AimDirection.Z; - GetBoneTransformsFromAnimatior(HumanBodyBones.Head); + GetBoneTransformsFromAnimator(HumanBodyBones.Head); } } public class BaseLayerPreset : AimAt @@ -230,7 +230,7 @@ public override void SetBonePreset() angleLimit = 90.0f; aimDirection = AimDirection.Z; - GetBoneTransformsFromAnimatior(HumanBodyBones.Chest); + GetBoneTransformsFromAnimator(HumanBodyBones.Chest); } } } From 7f6e6a9047e34af46e575dea3696810f35ce679e Mon Sep 17 00:00:00 2001 From: Davidterhuerne Date: Fri, 28 Feb 2025 20:35:29 +0100 Subject: [PATCH 2/3] Fixed major performance issue found by code analysis tool Fixed the only major and one moderate performance issue identified by https://github.com/Unity-Technologies/ProjectAuditor --- .../Scripts/Aiming&Gazing/AdaptiveGaze.cs | 94 +++++++++---------- 1 file changed, 46 insertions(+), 48 deletions(-) diff --git a/Assets/Virtual Agents Framework/Runtime/Scripts/Aiming&Gazing/AdaptiveGaze.cs b/Assets/Virtual Agents Framework/Runtime/Scripts/Aiming&Gazing/AdaptiveGaze.cs index 4f1ae11d..65d6e4b5 100644 --- a/Assets/Virtual Agents Framework/Runtime/Scripts/Aiming&Gazing/AdaptiveGaze.cs +++ b/Assets/Virtual Agents Framework/Runtime/Scripts/Aiming&Gazing/AdaptiveGaze.cs @@ -1,7 +1,9 @@ +using System; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.SceneManagement; +using Random = UnityEngine.Random; namespace i5.VirtualAgents { @@ -63,7 +65,7 @@ private class AdaptiveGazeTargetInfo /// The maximum number of targets in range that are considered for the gaze /// [Tooltip("The maximum number of targets in range that are considered for the gaze")] - [SerializeField] private int maxNumberOfTargetsInRange = 50; + [SerializeField] private const int maxNumberOfTargetsInRange = 50; /// /// The interval in seconds in which the agent looks for new targets when not moving @@ -183,7 +185,7 @@ private void Start() /// public void Activate() { - if (aimScript != null) + if (aimScript) aimScript.enabled = true; this.enabled = true; @@ -194,7 +196,7 @@ public void Activate() /// public void Deactivate() { - if (aimScript != null) + if (aimScript) aimScript.Stop(); this.enabled = false; @@ -233,7 +235,7 @@ private void AdjustIntervalBasedOnWalkingSpeed() private void UpdatePositionOfTarget() { - if (OverwriteGazeTarget != null) + if (OverwriteGazeTarget) { aimScript.SetTargetTransform(OverwriteGazeTarget); } @@ -246,7 +248,8 @@ private void UpdatePositionOfTarget() aimScript.Stop(); } } - + + private Collider[] colliders = new Collider[maxNumberOfTargetsInRange]; private void CheckWhichTargetsAreNearbyAndVisible() { timer += Time.deltaTime; @@ -264,7 +267,7 @@ private void CheckWhichTargetsAreNearbyAndVisible() // Check for nearby targets - Collider[] colliders = new Collider[maxNumberOfTargetsInRange]; + Array.Clear(colliders, 0, colliders.Length); // center is calculated so that corner of the bounding cube is at the position of the agent Vector3 center = transform.position + transform.forward * Mathf.Sqrt(2 * detectionRadius * detectionRadius); @@ -282,7 +285,7 @@ private void CheckWhichTargetsAreNearbyAndVisible() { AdaptiveGazeTarget target = colliders[i].GetComponent(); // Check that the object has an PossibleLookAtTarget component and that it is not picked up - if (target == null || !target.canCurrentlyBeLookedAt) + if (!target || !target.canCurrentlyBeLookedAt) { continue; } @@ -325,13 +328,8 @@ private void CheckWhichTargetsAreNearbyAndVisible() } // Remove targets that are no longer within the detection radius - foreach (AdaptiveGazeTargetInfo targetInfo in nearbyLookAtTargets.ToList()) - { - if (targetInfo.isCurrentlyNearby == false) - { - nearbyLookAtTargets.Remove(targetInfo); - } - } + nearbyLookAtTargets.RemoveAll(targetInfo => targetInfo.isCurrentlyNearby == false); + // Calculate the most interesting target and select one by chance from the list CalculateInterestInTargetAndSelectOne(); } @@ -385,44 +383,44 @@ private AdaptiveGazeTargetInfo SelectFromListWithProbability() // No objects available return null; } - else + + double randomValue = Random.value; + + if (randomValue <= chanceHighestRankedTarget) { - double randomValue = Random.value; + // Select the first target + return nearbyLookAtTargets[0]; + } - if (randomValue <= chanceHighestRankedTarget) - { - // Select the first target - return nearbyLookAtTargets[0]; - } - else if (chanceHighestRankedTarget < randomValue && randomValue <= chanceSecondHighestTarget) - { - // Select the second target or first target when second target is not available - if (nearbyLookAtTargets.Count > 1) - return nearbyLookAtTargets[1]; - else - return nearbyLookAtTargets[0]; - } - else if (chanceSecondHighestTarget < randomValue && randomValue <= chanceThirdHighestTarget) - { - // Select the third target or first target when second target is not available - if (nearbyLookAtTargets.Count > 2) - return nearbyLookAtTargets[2]; - else - return nearbyLookAtTargets[0]; - } - else if (chanceThirdHighestTarget < randomValue && randomValue <= chanceRandomTarget) - { - // Select a random target - int randomIndex = Random.Range(0, nearbyLookAtTargets.Count); - return nearbyLookAtTargets[randomIndex]; - } - else if (chanceRandomTarget < randomValue && randomValue <= chanceIdleTarget) - { - // Select no target and idle - return null; - } + if (chanceHighestRankedTarget < randomValue && randomValue <= chanceSecondHighestTarget) + { + // Select the second target or first target when second target is not available + if (nearbyLookAtTargets.Count > 1) + return nearbyLookAtTargets[1]; + return nearbyLookAtTargets[0]; + } + + if (chanceSecondHighestTarget < randomValue && randomValue <= chanceThirdHighestTarget) + { + // Select the third target or first target when second target is not available + if (nearbyLookAtTargets.Count > 2) + return nearbyLookAtTargets[2]; + return nearbyLookAtTargets[0]; + } + + if (chanceThirdHighestTarget < randomValue && randomValue <= chanceRandomTarget) + { + // Select a random target + int randomIndex = Random.Range(0, nearbyLookAtTargets.Count); + return nearbyLookAtTargets[randomIndex]; + } + + if (chanceRandomTarget < randomValue && randomValue <= chanceIdleTarget) + { + // Select no target and idle return null; } + return null; } } } From 95ae06aaa256900047ed6c0070c06c0dae4d5d62 Mon Sep 17 00:00:00 2001 From: Davidterhuerne Date: Fri, 28 Feb 2025 20:45:52 +0100 Subject: [PATCH 3/3] Fixed Test failing unnecessary --- Assets/Virtual Agents Framework/Tests/Runtime/TestAllSamples.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Virtual Agents Framework/Tests/Runtime/TestAllSamples.cs b/Assets/Virtual Agents Framework/Tests/Runtime/TestAllSamples.cs index cca97767..ef1dfb8b 100644 --- a/Assets/Virtual Agents Framework/Tests/Runtime/TestAllSamples.cs +++ b/Assets/Virtual Agents Framework/Tests/Runtime/TestAllSamples.cs @@ -168,7 +168,7 @@ public IEnumerator VerifySceneAdaptiveGaze() Assert.That(Agent, Is.Not.Null); //Check if the agent is moving after 5 seconds - yield return new WaitForSeconds(5); + yield return new WaitForSeconds(8); bool isMoving = Agent.GetComponent().velocity != Vector3.zero; Assert.That(isMoving, Is.True);