Example #1
0
 public override NodeState Evaluate()
 {
     currentTrapPos = (Vector3)blackboard.GetValue("currentTrapPointLocation");
     if (currentTrapPos == Vector3.zero || currentTrapPos != agent.destination)
     {
         return(NodeState.FAIL);
     }
     if (isSettingTrap)
     {
         if (timer >= attackAnimationLength)
         {
             GameObject spiderWeb = objectPooler.SpawnObject("SpiderWeb", currentTrapPos);
             TransformUtilities.RotateObjectPerpendicularToTheGround(spiderWeb.transform, groundLayerMask);
             spiderWebsManagement.SetPointAsUsed(currentTrapPos);
             return(NodeState.SUCCESS);
         }
         else
         {
             timer += Time.deltaTime;
         }
     }
     else
     {
         anim.SetTrigger("Attack");
         agent.isStopped = true;
         isSettingTrap   = true;
     }
     return(NodeState.RUNNING);
 }
        protected void UpdateHandRay(ManagedHandSkeleton hand)
        {
            //shoulder:
            float shoulderDistance = shoulderWidth * .5f;

            //swap for the left shoulder:
            if (ControllerHandedness == Handedness.Left)
            {
                shoulderDistance *= -1;
            }

            Transform camera = CameraCache.Main.transform;

            //source locations:
            Vector3 flatForward = Vector3.ProjectOnPlane(camera.forward, Vector3.up);
            Vector3 shoulder    = TransformUtilities.WorldPosition(camera.position, Quaternion.LookRotation(flatForward), new Vector2(shoulderDistance, Mathf.Abs(shoulderDistanceBelowHead) * -1));

            Vector3 pointerOrigin = Vector3.Lerp(hand.Thumb.Knuckle.positionFiltered, hand.Position, .5f);

            //direction:
            Quaternion orientation = Quaternion.LookRotation(Vector3.Normalize(pointerOrigin - shoulder), hand.Rotation * Vector3.up);

            currentPointerPose.Position = pointerOrigin;
            currentPointerPose.Rotation = orientation;
        }
Example #3
0
    //Loops:
    private void Update()
    {
        //wait for hand input to come online:
        if (!HandInput.Ready)
        {
            return;
        }

        //shoulder:
        float shoulderDistance = shoulderWidth * .5f;

        //swap for the left shoulder:
        if (handedness == MLHandType.Left)
        {
            shoulderDistance *= -1;
        }

        //source locations:
        Vector3 flatForward   = Vector3.ProjectOnPlane(_mainCamera.forward, Vector3.up);
        Vector3 shoulder      = TransformUtilities.RelativeOffset(_mainCamera.position, Quaternion.LookRotation(flatForward), new Vector2(shoulderDistance, Mathf.Abs(shoulderDistanceBelowHead) * -1));
        Vector3 pointerOrigin = Vector3.Lerp(Hand.Skeleton.Thumb.Knuckle.positionFiltered, Hand.Skeleton.Position, .5f);

        //direction:
        Quaternion orientation = Quaternion.LookRotation(Vector3.Normalize(pointerOrigin - shoulder), Hand.Skeleton.Rotation * Vector3.up);

        //application:
        transform.position = pointerOrigin;
        transform.rotation = orientation;
    }
Example #4
0
 private static void CheckDegenerate(Matrix3x2 matrix)
 {
     if (TransformUtilities.IsDegenerate(matrix))
     {
         throw new DegenerateTransformException("Matrix is degenerate. Check input values.");
     }
 }
Example #5
0
        /// <summary>
        /// Performs an affine transform of an image using the specified sampling algorithm.
        /// </summary>
        /// <param name="ctx">The <see cref="IImageProcessingContext"/>.</param>
        /// <param name="sourceRectangle">The source rectangle</param>
        /// <param name="builder">The affine transform builder.</param>
        /// <param name="sampler">The <see cref="IResampler"/> to perform the resampling.</param>
        /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
        public static IImageProcessingContext Transform(
            this IImageProcessingContext ctx,
            Rectangle sourceRectangle,
            AffineTransformBuilder builder,
            IResampler sampler)
        {
            Matrix3x2 transform        = builder.BuildMatrix(sourceRectangle);
            Size      targetDimensions = TransformUtilities.GetTransformedSize(sourceRectangle.Size, transform);

            return(ctx.Transform(sourceRectangle, transform, targetDimensions, sampler));
        }
Example #6
0
    /// <summary>
    /// Возвращает всех потомков для игрового объекта
    /// </summary>
    ///
    /// <returns>Массив потомков</returns>
    ///
    /// <exception cref="NullReferenceException">Параметр <param name="gameObject"/>>указывает на null</exception>
    /// <exception cref="MissingReferenceException">Параметр <param name="gameObject"/>>указывает на уничтоженный объект</exception>
    public static Transform[] GetChilds(this GameObject gameObject)
    {
        if (gameObject is null)
        {
            throw new NullReferenceException(nameof(gameObject));
        }
        if (!gameObject)
        {
            throw new MissingReferenceException(nameof(gameObject));
        }

        return(TransformUtilities.GetChildsWithoutChecks(gameObject.transform));
    }
    /// <summary>
    /// Возвращает всех потомков
    /// </summary>
    ///
    /// <returns>Массив потомков</returns>
    ///
    /// <exception cref="NullReferenceException">Параметр <param name="root"/>>указывает на null</exception>
    /// <exception cref="MissingReferenceException">Параметр <param name="root"/>>указывает на уничтоженный объект</exception>
    public static Transform[] GetChilds(this Transform transform)
    {
        if (transform is null)
        {
            throw new NullReferenceException(nameof(transform));
        }
        if (!transform)
        {
            throw new MissingReferenceException(nameof(transform));
        }

        return(TransformUtilities.GetChildsWithoutChecks(transform));
    }
    public static bool IsChildOf(this Transform self, Transform parent)
    {
        if (self is null)
        {
            throw new NullReferenceException(nameof(self));
        }
        if (!self)
        {
            throw new MissingReferenceException(nameof(self));
        }

        return(TransformUtilities.IsChildOfWithoutChecks(self, parent));
    }
    public Entity SpawnCharacterZombie(Entity zombiePrefabEntity, Entity startingMeleePrefabEntity, Entity dropOnDeathEntity)
    {
        float      randomAngle    = random.NextFloat(0f, 360f);
        float      randomDistance = random.NextFloat(SpawnRadiusMinMax.x, SpawnRadiusMinMax.y);
        float3     dir            = math.mul(quaternion.RotateY(randomAngle), new float3(0, 0, 1));
        float3     spawnPos       = dir * randomDistance;
        quaternion spawnRot       = quaternion.LookRotationSafe(math.normalizesafe(-spawnPos), new float3(0f, 1f, 0f));

        Entity charInstanceEntity = EntityManager.Instantiate(zombiePrefabEntity);

        EntityManager.SetComponentData(charInstanceEntity, new Translation {
            Value = spawnPos
        });
        EntityManager.SetComponentData(charInstanceEntity, new Rotation {
            Value = spawnRot
        });
        EntityManager.AddComponentData(charInstanceEntity, new AITag());
        EntityManager.AddComponentData(charInstanceEntity, new OwningAI {
            AIEntity = charInstanceEntity
        });

        // ~10% chance of drop
        if (random.NextInt(0, 10) == 1)
        {
            EntityManager.AddComponentData(charInstanceEntity, new DropOnDeath {
                toDrop = dropOnDeathEntity
            });
        }

        Character spawnedCharacter = EntityManager.GetComponentData <Character>(charInstanceEntity);

        // Give zombie the starting melee attack
        Entity meleeEntityInstance = EntityManager.Instantiate(startingMeleePrefabEntity);

        TransformUtilities.SetParent(EntityManager, spawnedCharacter.WeaponHoldPointEntity, meleeEntityInstance, false);
        EntityManager.AddComponentData(meleeEntityInstance, new OwningAI()
        {
            AIEntity = charInstanceEntity
        });

        // set active weapon on Character
        Character charData = EntityManager.GetComponentData <Character>(charInstanceEntity);

        charData.ActiveMeleeWeaponEntity = meleeEntityInstance;
        EntityManager.SetComponentData(charInstanceEntity, charData);

        LastSpawnTime[0] = LastSpawnTime[0] + 1f / SpawnRate;

        return(charInstanceEntity);
    }
    public static void GetChilds(this Transform transform, List <Transform> result)
    {
        if (transform is null)
        {
            throw new NullReferenceException(nameof(transform));
        }
        if (!transform)
        {
            throw new MissingReferenceException(nameof(transform));
        }

        if (result is null)
        {
            throw new ArgumentNullException(nameof(result));
        }

        TransformUtilities.GetChildsWithoutChecks(transform, result);
    }
    public void SpawnZombieBatch(int count)
    {
        NativeList <Entity> spawnedZombies = new NativeList <Entity>(Allocator.Persistent);

        for (int i = 0; i < count; i++)
        {
            spawnedZombies.Add(SpawnCharacterZombie(ZombiePrefab, MeleePrefabEntity, DropOnDeathEntities[random.NextInt(0, DropOnDeathEntities.Length) % DropOnDeathEntities.Length]));
        }

        TransformUtilities.UpdateTransformSystems(World);

        foreach (var z in spawnedZombies)
        {
            TransformUtilities.MakeEntityLinkedInHierarchy(EntityManager, z);
        }

        spawnedZombies.Dispose();
    }
Example #12
0
    public virtual void Initialize(int id, Vector3 startPosition, Vector3 targetPosition, float speed, GameObject modelPrefab)
    {
        base.Initialize(id);

        m_startPosition  = startPosition;
        m_targetPosition = targetPosition;

        m_speed = speed;

        if (modelPrefab != null)
        {
            GameObject go = Instantiate <GameObject>(modelPrefab, transform.position, transform.rotation, transform);
            m_modelTransform = go.transform;

            TransformUtilities.SetLayerToHierarchy(m_modelTransform, gameObject.layer);
        }

        m_isInitialized = true;
    }
Example #13
0
    public void SpawnCharacterForPlayer(EntityManager entityManager, Entity characterPrefabEntity, Entity startingGunPrefabEntity, Entity startingMeleePrefabEntity, Vector3 atPoint, Quaternion atRotation, Entity owningEntity)
    {
        // Spawn a character and assign to player
        Entity charInstanceEntity = entityManager.Instantiate(characterPrefabEntity);

        entityManager.SetComponentData(charInstanceEntity, new Translation {
            Value = atPoint
        });
        entityManager.SetComponentData(charInstanceEntity, new Rotation {
            Value = atRotation
        });
        entityManager.AddComponentData(charInstanceEntity, new OwningPlayer {
            PlayerEntity = owningEntity
        });
        entityManager.AddComponentData(charInstanceEntity, new CameraFocus());

        Character spawnedCharacter = entityManager.GetComponentData <Character>(charInstanceEntity);

        // Give players the starting range weapon
        Entity gunEntityInstance = entityManager.Instantiate(startingGunPrefabEntity);

        TransformUtilities.SetParent(entityManager, spawnedCharacter.WeaponHoldPointEntity, gunEntityInstance, true);
        entityManager.AddComponentData(gunEntityInstance, new OwningPlayer()
        {
            PlayerEntity = owningEntity
        });

        // Give players the starting melee attack
        Entity meleeEntityInstance = entityManager.Instantiate(startingMeleePrefabEntity);

        TransformUtilities.SetParent(entityManager, spawnedCharacter.WeaponHoldPointEntity, meleeEntityInstance, true);
        entityManager.AddComponentData(meleeEntityInstance, new OwningPlayer()
        {
            PlayerEntity = owningEntity
        });

        // set active weapons on Character
        Character charData = entityManager.GetComponentData <Character>(charInstanceEntity);

        charData.ActiveRangeWeaponEntity = gunEntityInstance;
        charData.ActiveMeleeWeaponEntity = meleeEntityInstance;
        entityManager.SetComponentData(charInstanceEntity, charData);
    }
Example #14
0
        public StrokeSegment[] OnPaint(Terrain terrain, IOnPaint editContext)
        {
            if (Event.current.type == EventType.MouseDown)
            {
                UpdateStartPosition(terrain, editContext);

                return(null);
            }


            if (m_StartTerrain == null)
            {
                return(null);
            }

            StrokeSegment[] segments = null;

            if (Event.current.type == EventType.MouseDrag && m_PreviousEvent == EventType.MouseDrag)
            {
                Vector2 uv = editContext.uv;

                float   height       = terrain.terrainData.GetInterpolatedHeight(uv.x, uv.y) / terrain.terrainData.size.y;
                Vector3 currentPoint = new Vector3(uv.x, uv.y, height);

                Vector2 currPointWS = TransformUtilities.transformToWorld(terrain, uv);
                Vector2 prevPointWS = TransformUtilities.transformToWorld(terrain, new Vector2(m_StartPoint.x, m_StartPoint.y));

                Vector2 paintDirection = currPointWS - prevPointWS;

                // TODO: collect positions and perform modifications in a batch in the background
                if (paintDirection.magnitude > 1) // 1 just a "magic number" for now; see also  int numSplats = 1;
                {
                    segments = GetStrokeSegments(terrain, editContext);

                    // next start position
                    UpdateStartPosition(terrain, editContext);
                }
            }

            m_PreviousEvent = Event.current.type;

            return(segments);
        }
Example #15
0
        override public void Update(StrokeSegment[] segments)
        {
#if VEGETATION_STUDIO_PRO
            if (segments.Length > 0)
            {
                StrokeSegment segment = segments[0];
                Bounds        bounds  = new Bounds(new Vector3(segment.currUV.x, 0, segment.currUV.y), Vector3.zero);;
                for (int i = 1; i < segments.Length; i++)
                {
                    segment = segments[i];

                    Vector2 boundsWS = TransformUtilities.transformToWorld(segment.currTerrain, segment.currUV);
                    bounds.Encapsulate(new Vector3(boundsWS.x, 0, boundsWS.y));
                }

                VegetationStudioManager.RefreshTerrainHeightMap(bounds);
            }
#endif
        }
Example #16
0
        public void AppendSkewDegrees_WithoutSpecificSkewCenter_SkewIsCenteredAroundImageCenter(
            int width,
            int height,
            float degreesX,
            float degreesY,
            float x,
            float y)
        {
            var      size    = new Size(width, height);
            TBuilder builder = this.CreateBuilder();

            this.AppendSkewDegrees(builder, degreesX, degreesY);

            Matrix3x2 matrix = TransformUtilities.CreateSkewMatrixDegrees(degreesX, degreesY, size);

            var     position = new Vector2(x, y);
            var     expected = Vector2.Transform(position, matrix);
            Vector2 actual   = this.Execute(builder, new Rectangle(Point.Empty, size), position);

            Assert.Equal(actual, expected, Comparer);
        }
Example #17
0
        public void AppendRotationDegrees_WithoutSpecificRotationCenter_RotationIsCenteredAroundImageCenter(
            int width,
            int height,
            float degrees,
            float x,
            float y)
        {
            var      size    = new Size(width, height);
            TBuilder builder = this.CreateBuilder();

            this.AppendRotationDegrees(builder, degrees);

            // TODO: We should also test CreateRotationMatrixDegrees() (and all TransformUtils stuff!) for correctness
            Matrix3x2 matrix = TransformUtilities.CreateRotationMatrixDegrees(degrees, size);

            var     position = new Vector2(x, y);
            var     expected = Vector2.Transform(position, matrix);
            Vector2 actual   = this.Execute(builder, new Rectangle(Point.Empty, size), position);

            Assert.Equal(actual, expected, Comparer);
        }
Example #18
0
 /// <summary>
 /// Appends a centered skew matrix from the give angles in degrees.
 /// </summary>
 /// <param name="degreesX">The X angle, in degrees.</param>
 /// <param name="degreesY">The Y angle, in degrees.</param>
 /// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
 public AffineTransformBuilder AppendSkewDegrees(float degreesX, float degreesY)
 => this.Append(size => TransformUtilities.CreateSkewMatrixDegrees(degreesX, degreesY, size));
Example #19
0
        private StrokeSegment[] GetStrokeSegments(Terrain terrain, IOnPaint editContext)
        {
            Vector2 uv = editContext.uv;

            //get the target position & height
            float   targetHeight = terrain.terrainData.GetInterpolatedHeight(uv.x, uv.y) / terrain.terrainData.size.y;
            Vector3 targetPos    = new Vector3(uv.x, uv.y, targetHeight);

            if (terrain != m_StartTerrain)
            {
                //figure out the stroke vector in uv,height space
                Vector2 targetWorld = TransformUtilities.transformToWorld(terrain, uv);
                Vector2 targetUVs   = TransformUtilities.transformToUVSpace(m_StartTerrain, targetWorld);
                targetPos.x = targetUVs.x;
                targetPos.y = targetUVs.y;
            }

            Vector3 stroke       = targetPos - m_StartPoint;
            float   strokeLength = stroke.magnitude;
            int     numSplats    = 1; // (int)(strokeLength / (0.001f * m_Spacing)); <= TODO keeping numsplats at 1 for now, otherwise it would drain performance in paint mode; see also paintDirection.magnitude > 1

            Terrain currTerrain = m_StartTerrain;

            Vector2 posOffset = new Vector2(0.0f, 0.0f);
            Vector2 currUV    = new Vector2();

            Vector2 jitterVec = new Vector2(-stroke.z, stroke.x); //perpendicular to stroke direction

            jitterVec.Normalize();

            Vector2 prevUV = Vector2.zero;

            StrokeSegment[] segments = new StrokeSegment[numSplats];

            for (int i = 0; i < numSplats; i++)
            {
                float pct = (float)i / (float)numSplats;

                float jitterOffset = jitterProfile.Evaluate(pct) / Mathf.Max(currTerrain.terrainData.size.x, currTerrain.terrainData.size.z);

                Vector3 currPos = m_StartPoint + pct * stroke;

                //add in jitter offset (needs to happen before tile correction)
                currPos.x += posOffset.x + jitterOffset * jitterVec.x;
                currPos.y += posOffset.y + jitterOffset * jitterVec.y;

                if (currPos.x >= 1.0f && (currTerrain.rightNeighbor != null))
                {
                    currTerrain  = currTerrain.rightNeighbor;
                    currPos.x   -= 1.0f;
                    posOffset.x -= 1.0f;
                }
                if (currPos.x <= 0.0f && (currTerrain.leftNeighbor != null))
                {
                    currTerrain  = currTerrain.leftNeighbor;
                    currPos.x   += 1.0f;
                    posOffset.x += 1.0f;
                }
                if (currPos.y >= 1.0f && (currTerrain.topNeighbor != null))
                {
                    currTerrain  = currTerrain.topNeighbor;
                    currPos.y   -= 1.0f;
                    posOffset.y -= 1.0f;
                }
                if (currPos.y <= 0.0f && (currTerrain.bottomNeighbor != null))
                {
                    currTerrain  = currTerrain.bottomNeighbor;
                    currPos.y   += 1.0f;
                    posOffset.y += 1.0f;
                }

                currUV.x = currPos.x;
                currUV.y = currPos.y;


                StrokeSegment ctx = new StrokeSegment();

                ctx.pct         = pct;
                ctx.currTerrain = currTerrain;
                ctx.currUV      = currUV;
                ctx.stroke      = stroke;
                ctx.prevUV      = prevUV;

                ctx.startPoint = m_StartPoint;

                segments[i] = ctx;

                prevUV = currUV;
            }

            return(segments);
        }
 /// <summary>
 /// Appends a centered rotation matrix using the given rotation in radians.
 /// </summary>
 /// <param name="radians">The amount of rotation, in radians.</param>
 /// <returns>The <see cref="ProjectiveTransformBuilder"/>.</returns>
 public ProjectiveTransformBuilder AppendRotationRadians(float radians)
 => this.Append(size => new Matrix4x4(TransformUtilities.CreateRotationMatrixRadians(radians, size)));
 /// <summary>
 /// Appends a matrix that performs a tapering projective transform.
 /// </summary>
 /// <param name="side">An enumeration that indicates the side of the rectangle that tapers.</param>
 /// <param name="corner">An enumeration that indicates on which corners to taper the rectangle.</param>
 /// <param name="fraction">The amount to taper.</param>
 /// <returns>The <see cref="ProjectiveTransformBuilder"/>.</returns>
 public ProjectiveTransformBuilder AppendTaper(TaperSide side, TaperCorner corner, float fraction)
 => this.Append(size => TransformUtilities.CreateTaperMatrix(size, side, corner, fraction));
 /// <summary>
 /// Appends a centered skew matrix from the give angles in radians.
 /// </summary>
 /// <param name="radiansX">The X angle, in radians.</param>
 /// <param name="radiansY">The Y angle, in radians.</param>
 /// <returns>The <see cref="ProjectiveTransformBuilder"/>.</returns>
 public ProjectiveTransformBuilder AppendSkewRadians(float radiansX, float radiansY)
 => this.Append(size => new Matrix4x4(TransformUtilities.CreateSkewMatrixRadians(radiansX, radiansY, size)));
        //Public Methods:
        public void Update()
        {
            //update keypoints and fingers:
            WristCenter.Update(_managedHand, _managedHand.Hand.Wrist.Center.Position, _managedHand.Hand.Center);
            HandCenter.Update(_managedHand, _managedHand.Hand.Center);
            _thumbMCP.Update(_managedHand, _managedHand.Hand.Thumb.MCP.Position, _managedHand.Hand.Index.MCP.Position, _managedHand.Hand.Center);
            _thumbPIP.Update(_managedHand, _managedHand.Hand.Thumb.IP.Position, _managedHand.Hand.Thumb.MCP.Position, _managedHand.Hand.Center);
            _thumbTip.Update(_managedHand, _managedHand.Hand.Thumb.Tip.Position, _managedHand.Hand.Thumb.IP.Position, _managedHand.Hand.Middle.Tip.Position, _managedHand.Hand.Thumb.MCP.Position, _managedHand.Hand.Center);
            Thumb.Update();
            _indexMCP.Update(_managedHand, _managedHand.Hand.Index.MCP.Position, _managedHand.Hand.Center);
            _indexPIP.Update(_managedHand, _managedHand.Hand.Index.PIP.Position, _managedHand.Hand.Index.MCP.Position, _managedHand.Hand.Center);
            _indexTip.Update(_managedHand, _managedHand.Hand.Index.Tip.Position, _managedHand.Hand.Index.PIP.Position, _managedHand.Hand.Index.MCP.Position, _managedHand.Hand.Center, _managedHand.Hand.Thumb.IP.Position, _managedHand.Hand.Middle.Tip.Position);
            Index.Update();
            _middleMCP.Update(_managedHand, _managedHand.Hand.Middle.MCP.Position, _managedHand.Hand.Center);
            _middlePIP.Update(_managedHand, _managedHand.Hand.Middle.PIP.Position, _managedHand.Hand.Middle.MCP.Position, _managedHand.Hand.Center);
            _middleTip.Update(_managedHand, _managedHand.Hand.Middle.Tip.Position, _managedHand.Hand.Middle.PIP.Position, _managedHand.Hand.Middle.MCP.Position, _managedHand.Hand.Ring.Tip.Position, _managedHand.Hand.Center);
            Middle.Update();
            _ringMCP.Update(_managedHand, _managedHand.Hand.Ring.MCP.Position, _managedHand.Hand.Center);
            _ringTip.Update(_managedHand, _managedHand.Hand.Ring.Tip.Position, _managedHand.Hand.Ring.MCP.Position, _managedHand.Hand.Pinky.Tip.Position, _managedHand.Hand.Middle.Tip.Position, _managedHand.Hand.Center);
            Ring.Update();
            _pinkyMCP.Update(_managedHand, _managedHand.Hand.Pinky.MCP.Position, _managedHand.Hand.Center);
            _pinkyTip.Update(_managedHand, _managedHand.Hand.Pinky.Tip.Position, _managedHand.Hand.Pinky.MCP.Position, _managedHand.Hand.Ring.Tip.Position, _managedHand.Hand.Center);
            Pinky.Update();

            //we need a hand to continue:
            if (!_managedHand.Visible)
            {
                return;
            }

            //correct distances:
            float thumbMcpToWristDistance = Vector3.Distance(_thumbMCP.positionFiltered, WristCenter.positionFiltered) * .5f;
            //fix the distance between the wrist and thumbMcp as it incorrectly expands as the hand gets further from the camera:
            float distancePercentage = Mathf.Clamp01(Vector3.Distance(_mainCamera.transform.position, WristCenter.positionFiltered) / .5f);

            distancePercentage       = 1 - Percentage(distancePercentage, .90f, 1) * .4f;
            thumbMcpToWristDistance *= distancePercentage;
            Vector3 wristToPalmDirection = Vector3.Normalize(Vector3.Normalize(HandCenter.positionFiltered - WristCenter.positionFiltered));
            Vector3 center = WristCenter.positionFiltered + (wristToPalmDirection * thumbMcpToWristDistance);
            Vector3 camToWristDirection = Vector3.Normalize(WristCenter.positionFiltered - _mainCamera.transform.position);

            //rays needed for planarity discovery for in/out palm facing direction:
            Vector3 camToWrist    = new Ray(WristCenter.positionFiltered, camToWristDirection).GetPoint(1);
            Vector3 camToThumbMcp = new Ray(_thumbMCP.positionFiltered, Vector3.Normalize(_thumbMCP.positionFiltered - _mainCamera.transform.position)).GetPoint(1);
            Vector3 camToPalm     = new Ray(center, Vector3.Normalize(center - _mainCamera.transform.position)).GetPoint(1);

            //discover palm facing direction to camera:
            Plane palmFacingPlane = new Plane(camToWrist, camToPalm, camToThumbMcp);

            if (_managedHand.Hand.Type == MLHandTracking.HandType.Left)
            {
                palmFacingPlane.Flip();
            }
            float palmForwardFacing = Mathf.Sign(Vector3.Dot(palmFacingPlane.normal, _mainCamera.transform.forward));

            //use thumb/palm/wrist alignment to determine amount of roll in the hand:
            Vector3 toThumbMcp     = Vector3.Normalize(_thumbMCP.positionFiltered - center);
            Vector3 toPalm         = Vector3.Normalize(center - WristCenter.positionFiltered);
            float   handRollAmount = (1 - Vector3.Dot(toThumbMcp, toPalm)) * palmForwardFacing;

            //where between the wrist and thumbMcp should we slide inwards to get the palm in the center:
            Vector3 toPalmOrigin = Vector3.Lerp(WristCenter.positionFiltered, _thumbMCP.positionFiltered, .35f);

            //get a direction from the camera to toPalmOrigin as psuedo up for use in quaternion construction:
            Vector3 toCam = Vector3.Normalize(_mainCamera.transform.position - toPalmOrigin);

            //construct a quaternion that helps get angles needed between the wrist and thumbMCP to point towards the palm center:
            Vector3    wristToThumbMcp       = Vector3.Normalize(_thumbMCP.positionFiltered - WristCenter.positionFiltered);
            Quaternion towardsCamUpReference = Quaternion.identity;

            if (wristToThumbMcp != Vector3.zero && toCam != Vector3.zero)
            {
                towardsCamUpReference = Quaternion.LookRotation(wristToThumbMcp, toCam);
            }

            //rotate the inwards vector depending on hand roll to know where to push the palm back:
            float inwardsVectorRotation = 90;

            if (_managedHand.Hand.Type == MLHandTracking.HandType.Left)
            {
                inwardsVectorRotation = -90;
            }
            towardsCamUpReference = Quaternion.AngleAxis(handRollAmount * inwardsVectorRotation, towardsCamUpReference * Vector3.forward) * towardsCamUpReference;
            Vector3 inwardsVector = towardsCamUpReference * Vector3.up;

            //slide palm location along inwards vector to get it into proper physical location in the center of the hand:
            center = toPalmOrigin - inwardsVector * thumbMcpToWristDistance;
            Vector3 deadCenter = center;

            //as the hand flattens back out balance corrected location with originally provided location for better forward origin:
            center = Vector3.Lerp(center, HandCenter.positionFiltered, Mathf.Abs(handRollAmount));

            //get a forward using the corrected palm location:
            Vector3 forward = Vector3.Normalize(center - WristCenter.positionFiltered);

            //switch back to physical center of hand - this reduces surface-to-surface movement of the center between back and palm:
            center = deadCenter;

            //get an initial hand up:
            Plane handPlane = new Plane(WristCenter.positionFiltered, _thumbMCP.positionFiltered, center);

            if (_managedHand.Hand.Type == MLHandTracking.HandType.Left)
            {
                handPlane.Flip();
            }
            Vector3 up = handPlane.normal;

            //find out how much the back of the hand is facing the camera so we have a safe set of features for a stronger forward:
            Vector3 centerToCam = Vector3.Normalize(_mainCamera.transform.position - WristCenter.positionFiltered);
            float   facingDot   = Vector3.Dot(centerToCam, up);

            if (facingDot > .5f)
            {
                float handBackFacingCamAmount = Percentage(facingDot, .5f, 1);

                //steer forward for more accuracy based on the visibility of the back of the hand:
                if (_middleMCP.Visible)
                {
                    Vector3 toMiddleMcp = Vector3.Normalize(_middleMCP.positionFiltered - center);
                    forward = Vector3.Lerp(forward, toMiddleMcp, handBackFacingCamAmount);
                }
                else if (_indexMCP.Visible)
                {
                    Vector3 inIndexMcp = Vector3.Normalize(_indexMCP.positionFiltered - center);
                    forward = Vector3.Lerp(forward, inIndexMcp, handBackFacingCamAmount);
                }
            }

            //make sure palm distance from wrist is consistant while also leveraging steered forward:
            center = WristCenter.positionFiltered + (forward * thumbMcpToWristDistance);

            //an initial rotation of the hand:
            Quaternion orientation = Quaternion.identity;

            if (forward != Vector3.zero && up != Vector3.zero)
            {
                orientation = Quaternion.LookRotation(forward, up);
            }

            //as the hand rolls counter-clockwise the thumbMcp loses accuracy so we need to interpolate to the back of the hand's features:
            if (_indexMCP.Visible && _middleMCP.Visible)
            {
                Vector3 knucklesVector = Vector3.Normalize(_middleMCP.positionFiltered - _indexMCP.positionFiltered);
                float   knucklesDot    = Vector3.Dot(knucklesVector, Vector3.up);
                if (knucklesDot > .5f)
                {
                    float counterClockwiseRoll = Percentage(Vector3.Dot(knucklesVector, Vector3.up), .35f, .7f);
                    center  = Vector3.Lerp(center, HandCenter.positionFiltered, counterClockwiseRoll);
                    forward = Vector3.Lerp(forward, Vector3.Normalize(_middleMCP.positionFiltered - HandCenter.positionFiltered), counterClockwiseRoll);
                    Plane backHandPlane = new Plane(HandCenter.positionFiltered, _indexMCP.positionFiltered, _middleMCP.positionFiltered);
                    if (_managedHand.Hand.Type == MLHandTracking.HandType.Left)
                    {
                        backHandPlane.Flip();
                    }
                    up          = Vector3.Lerp(up, backHandPlane.normal, counterClockwiseRoll);
                    orientation = Quaternion.LookRotation(forward, up);
                }
            }

            //as the wrist tilts away from the camera (with the thumb down) at extreme angles the hand center will move toward the thumb:
            float   handTiltAwayAmount          = 1 - Percentage(Vector3.Distance(HandCenter.positionFiltered, WristCenter.positionFiltered), .025f, .04f);
            Vector3 handTiltAwayCorrectionPoint = WristCenter.positionFiltered + camToWristDirection * thumbMcpToWristDistance;

            center  = Vector3.Lerp(center, handTiltAwayCorrectionPoint, handTiltAwayAmount);
            forward = Vector3.Lerp(forward, Vector3.Normalize(handTiltAwayCorrectionPoint - WristCenter.positionFiltered), handTiltAwayAmount);
            Plane wristPlane = new Plane(WristCenter.positionFiltered, _thumbMCP.positionFiltered, center);

            if (_managedHand.Hand.Type == MLHandTracking.HandType.Left)
            {
                wristPlane.Flip();
            }
            up = Vector3.Lerp(up, wristPlane.normal, handTiltAwayAmount);
            if (forward != Vector3.zero && up != Vector3.zero)
            {
                orientation = Quaternion.LookRotation(forward, up);
            }

            //steering for if thumb/index are not available from self-occlusion to help rotate the hand better outwards better:
            float forwardUpAmount = Vector3.Dot(forward, Vector3.up);

            if (forwardUpAmount > .7f && _indexMCP.Visible && _ringMCP.Visible)
            {
                float angle = 0;
                if (_managedHand.Hand.Type == MLHandTracking.HandType.Right)
                {
                    Vector3 knucklesVector = Vector3.Normalize(_ringMCP.positionFiltered - _indexMCP.positionFiltered);
                    angle  = Vector3.Angle(knucklesVector, orientation * Vector3.right);
                    angle *= -1;
                }
                else
                {
                    Vector3 knucklesVector = Vector3.Normalize(_indexMCP.positionFiltered - _ringMCP.positionFiltered);
                    angle = Vector3.Angle(knucklesVector, orientation * Vector3.right);
                }
                Quaternion selfOcclusionSteering = Quaternion.AngleAxis(angle, forward);
                orientation = selfOcclusionSteering * orientation;
            }
            else
            {
                //when palm is facing down we need to rotate some to compensate for an offset:
                float rollCorrection       = Mathf.Clamp01(Vector3.Dot(orientation * Vector3.up, Vector3.up));
                float rollCorrectionAmount = -30;
                if (_managedHand.Hand.Type == MLHandTracking.HandType.Left)
                {
                    rollCorrectionAmount = 30;
                }
                orientation = Quaternion.AngleAxis(rollCorrectionAmount * rollCorrection, forward) * orientation;
            }

            //inside the camera plane:
            InsideClipPlane = TransformUtilities.InsideClipPlane(center);

            //set pose:
            Position = center;
            Rotation = orientation;

            UpdateKeypointRotations();
        }
 void rotateBase(Transform myBase)
 {
     TransformUtilities.RotateObjectPerpendicularToTheGround(myBase, groundLayer);
 }
Example #25
0
        public void Update(ManagedHand managedHand, Vector3 keyPointLocation, params Vector3[] decayPoints)
        {
            if (!managedHand.Visible)
            {
                //lost:
                if (Visible)
                {
                    FireLostEvent();
                    _progress.locationHistory.Clear();
                }

                return;
            }

            //visibility status:
            bool currentVisibility = true;

            //too close to next joint in chain means visibility failed:
            if (Vector3.Distance(keyPointLocation, _mainCamera.transform.position) < _minHeadDistance)
            {
                currentVisibility = false;
            }
            else
            {
                for (int i = 0; i < decayPoints.Length; i++)
                {
                    if (Vector3.Distance(keyPointLocation, decayPoints[i]) < _lostKeyPointDistance)
                    {
                        currentVisibility = false;
                        break;
                    }
                }
            }

            positionRaw = keyPointLocation;

            //lost visibility:
            if (!currentVisibility && Visible)
            {
                FireLostEvent();
                _progress.locationHistory.Clear();
                return;
            }

            //history cache:
            _progress.locationHistory.Add(keyPointLocation);

            //only need 3 in our history:
            if (_progress.locationHistory.Count > 3)
            {
                _progress.locationHistory.RemoveAt(0);
            }

            //we have enough history:
            if (_progress.locationHistory.Count == 3)
            {
                //movement intent stats:
                Vector3 vectorA = _progress.locationHistory[_progress.locationHistory.Count - 2] - _progress.locationHistory[_progress.locationHistory.Count - 3];
                Vector3 vectorB = _progress.locationHistory[_progress.locationHistory.Count - 1] - _progress.locationHistory[_progress.locationHistory.Count - 2];
                float   delta   = Vector3.Distance(_progress.locationHistory[_progress.locationHistory.Count - 3], _progress.locationHistory[_progress.locationHistory.Count - 1]);
                float   angle   = Vector3.Angle(vectorA, vectorB);
                Stability = 1 - Mathf.Clamp01(delta / _maxDistance);

                //moving in a constant direction?
                if (angle < 90)
                {
                    _progress.target = _progress.locationHistory[_progress.locationHistory.Count - 1];
                }

                //snap or smooth:
                if (Stability == 0)
                {
                    positionFiltered = _progress.target;
                }
                else
                {
                    positionFiltered = Vector3.SmoothDamp(positionFiltered, _progress.target, ref _progress.velocity, _smoothTime * Stability);
                }
            }
            else
            {
                positionFiltered = keyPointLocation;
            }

            //inside the camera plane - flatten against the plane?
            InsideClipPlane = TransformUtilities.InsideClipPlane(positionFiltered);
            if (InsideClipPlane)
            {
                if (HideInsideClipPlane)
                {
                    positionFiltered = keyPointLocation;
                    FireLostEvent();
                    _progress.locationHistory.Clear();
                    return;
                }
                positionFiltered = TransformUtilities.LocationOnClipPlane(positionFiltered);
            }

            //gained visibility:
            if (currentVisibility && !Visible)
            {
                //we must also break distance for point proximity:
                for (int i = 0; i < decayPoints.Length; i++)
                {
                    if (Vector3.Distance(keyPointLocation, decayPoints[i]) < _foundKeyPointDistance)
                    {
                        currentVisibility = false;
                        break;
                    }
                }

                //still good?
                if (currentVisibility)
                {
                    FireFoundEvent();
                }
            }
        }
Example #26
0
 /// <summary>
 /// Appends a rotation matrix using the given rotation angle in radians
 /// and the image center point as rotation center.
 /// </summary>
 /// <param name="radians">The amount of rotation, in radians.</param>
 /// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
 public AffineTransformBuilder AppendRotationRadians(float radians)
 => this.Append(size => TransformUtilities.CreateRotationMatrixRadians(radians, size));
Example #27
0
    //Public Methods:
    public void Update()
    {
        if (!_managedHand.Visible)
        {
            return;
        }

        //pinch rotation offset mirror:
        Vector3 rotationOffset = _pinchAbsoluteRotationOffset;

        if (_managedHand.Hand.HandType == MLHandType.Left)
        {
            rotationOffset.y *= -1;
        }

        //holders:
        Vector3    pinchPosition = Vector3.zero;
        Quaternion pinchRotation = Quaternion.identity;

        //pinch interaction point radius:
        if (_managedHand.Skeleton.Thumb.Tip.Visible && _managedHand.Skeleton.Index.Tip.Visible)
        {
            Pinch.radius = Vector3.Distance(_managedHand.Skeleton.Thumb.Tip.positionFiltered, _managedHand.Skeleton.Index.Tip.positionFiltered);
        }

        if (_managedHand.Skeleton.Thumb.Tip.Visible) //absolute placement:
        {
            //are we swapping modes?
            if (_pinchIsRelative)
            {
                _pinchIsRelative          = false;
                _pinchTransitioning       = true;
                _pinchTransitionStartTime = Time.realtimeSinceStartup;
            }

            pinchPosition = _managedHand.Skeleton.Thumb.Tip.positionFiltered;
            pinchRotation = TransformUtilities.RotateQuaternion(_managedHand.Skeleton.Rotation, rotationOffset);

            //gather offset distance:
            if (_managedHand.Skeleton.Index.Knuckle.Visible && _managedHand.Skeleton.Thumb.Knuckle.Visible)
            {
                Vector3 mcpMidpoint = Vector3.Lerp(_managedHand.Skeleton.Index.Knuckle.positionFiltered, _managedHand.Skeleton.Thumb.Knuckle.positionFiltered, .5f);
                _pinchRelativePositionDistance = Vector3.Distance(mcpMidpoint, pinchPosition);
            }
        }
        else //relative placement:
        {
            //are we swapping modes?
            if (!_pinchIsRelative)
            {
                _pinchIsRelative          = true;
                _pinchTransitioning       = true;
                _pinchTransitionStartTime = Time.realtimeSinceStartup;
            }

            //place between available mcps:
            if (_managedHand.Skeleton.Index.Knuckle.Visible && _managedHand.Skeleton.Thumb.Knuckle.Visible)
            {
                pinchPosition = Vector3.Lerp(_managedHand.Skeleton.Index.Knuckle.positionFiltered, _managedHand.Skeleton.Thumb.Knuckle.positionFiltered, .5f);

                //rotate:
                pinchRotation = TransformUtilities.RotateQuaternion(_managedHand.Skeleton.Rotation, _pinchRelativeRotationOffset);

                //move out along rotation forward:
                pinchPosition += pinchRotation * Vector3.forward * _pinchRelativePositionDistance;
            }
            else
            {
                //just use previous:
                pinchPosition = Pinch.position;
                pinchRotation = Pinch.rotation;
            }
        }

        //sticky release reduction:
        if (_collapsed)
        {
            if (_managedHand.Skeleton.Thumb.Tip.Visible && _managedHand.Skeleton.Index.Tip.Visible)
            {
                //if starting to release, start using a point between the thumb and index tips:
                if (Vector3.Distance(_managedHand.Skeleton.Thumb.Tip.positionFiltered, _managedHand.Skeleton.Index.Tip.positionFiltered) > _dynamicReleaseDistance)
                {
                    pinchPosition = Vector3.Lerp(_managedHand.Skeleton.Thumb.Tip.positionFiltered, _managedHand.Skeleton.Index.Tip.positionFiltered, .3f);
                }
            }
        }

        //apply pinch pose - to avoid jumps when relative placement is used we smooth until close enough:
        if (_pinchTransitioning)
        {
            //position:
            Pinch.position = Vector3.SmoothDamp(Pinch.position, pinchPosition, ref _pinchArrivalPositionVelocity, _pinchTransitionTime);
            float positionDelta = Vector3.Distance(Pinch.position, pinchPosition);

            //rotation:
            Pinch.rotation = MotionUtilities.SmoothDamp(Pinch.rotation, pinchRotation, ref _pinchArrivalRotationVelocity, _pinchTransitionTime);
            float rotationDelta = Quaternion.Angle(Pinch.rotation, pinchRotation);

            //close enough to hand off?
            if (positionDelta < .001f && rotationDelta < 5)
            {
                _pinchTransitioning = false;
            }

            //taking too long?
            if (Time.realtimeSinceStartup - _pinchTransitionStartTime > _pinchTransitionMaxDuration)
            {
                _pinchTransitioning = false;
            }
        }
        else
        {
            Pinch.position = pinchPosition;
            Pinch.rotation = pinchRotation;
        }

        //grasp interaction point:
        Bounds graspBounds = CalculateGraspBounds
                             (
            _managedHand.Skeleton.Thumb.Knuckle,
            _managedHand.Skeleton.Thumb.Joint,
            _managedHand.Skeleton.Thumb.Tip,
            _managedHand.Skeleton.Index.Knuckle,
            _managedHand.Skeleton.Index.Joint,
            _managedHand.Skeleton.Index.Tip,
            _managedHand.Skeleton.Middle.Knuckle,
            _managedHand.Skeleton.Middle.Joint,
            _managedHand.Skeleton.Middle.Tip
                             );

        Grasp.position = _managedHand.Skeleton.Position;
        //when points are being initially found they can be wildly off and this could cause a massively large volume:
        Grasp.radius   = Mathf.Min(graspBounds.size.magnitude, _maxGraspRadius);
        Grasp.rotation = _managedHand.Skeleton.Rotation;

        //intent updated:
        if (_currentInteractionState != null)
        {
            _currentInteractionState.FireUpdate();
        }

        //keypose change proposed:
        if (_managedHand.Hand.KeyPose != VerifiedGesture && _managedHand.Hand.KeyPose != _proposedKeyPose)
        {
            //queue a new proposed change to keypose:
            _proposedKeyPose    = _managedHand.Hand.KeyPose;
            _keyPoseChangedTime = Time.realtimeSinceStartup;
        }

        //keypose change acceptance:
        if (_managedHand.Hand.KeyPose != VerifiedGesture && Time.realtimeSinceStartup - _keyPoseChangedTime > _keyPoseStabailityDuration)
        {
            //reset:
            Point.active = false;
            Pinch.active = false;
            Grasp.active = false;

            if (_collapsed)
            {
                //intent end:
                if (_managedHand.Hand.KeyPose == MLHandKeyPose.C || _managedHand.Hand.KeyPose == MLHandKeyPose.OpenHand || _managedHand.Hand.KeyPose == MLHandKeyPose.L || _managedHand.Hand.KeyPose == MLHandKeyPose.Finger)
                {
                    if (_managedHand.Skeleton.Thumb.Tip.Visible && _managedHand.Skeleton.Index.Tip.Visible)
                    {
                        //dynamic release:
                        if (Vector3.Distance(_managedHand.Skeleton.Thumb.Tip.positionFiltered, _managedHand.Skeleton.Index.Tip.positionFiltered) > _dynamicReleaseDistance)
                        {
                            //end intent:
                            _collapsed = false;
                            _currentInteractionState.FireEnd();
                            _currentInteractionState = null;

                            //accept keypose change:
                            VerifiedGesture  = _managedHand.Hand.KeyPose;
                            _proposedKeyPose = _managedHand.Hand.KeyPose;
                            OnVerifiedGestureChanged?.Invoke(_managedHand, VerifiedGesture);

                            if (_managedHand.Hand.KeyPose == MLHandKeyPose.Finger || _managedHand.Hand.KeyPose == MLHandKeyPose.L)
                            {
                                Intent = IntentPose.Pointing;
                                OnIntentChanged?.Invoke(_managedHand, Intent);
                            }
                            else if (_managedHand.Hand.KeyPose == MLHandKeyPose.C || _managedHand.Hand.KeyPose == MLHandKeyPose.OpenHand || _managedHand.Hand.KeyPose == MLHandKeyPose.Thumb)
                            {
                                Intent = IntentPose.Relaxed;
                                OnIntentChanged?.Invoke(_managedHand, Intent);
                            }
                        }
                    }
                }
            }
            else
            {
                //intent begin:
                if (_managedHand.Hand.KeyPose == MLHandKeyPose.Pinch || _managedHand.Hand.KeyPose == MLHandKeyPose.Ok || _managedHand.Hand.KeyPose == MLHandKeyPose.Fist)
                {
                    _collapsed = true;

                    if (_managedHand.Hand.KeyPose == MLHandKeyPose.Pinch || _managedHand.Hand.KeyPose == MLHandKeyPose.Ok)
                    {
                        Intent                   = IntentPose.Pinching;
                        Pinch.active             = true;
                        _currentInteractionState = Pinch.Touch;
                        _currentInteractionState.FireBegin();
                        OnIntentChanged?.Invoke(_managedHand, Intent);
                    }
                    else if (_managedHand.Hand.KeyPose == MLHandKeyPose.Fist)
                    {
                        Intent                   = IntentPose.Grasping;
                        Grasp.active             = true;
                        _currentInteractionState = Grasp.Touch;
                        _currentInteractionState.FireBegin();
                        OnIntentChanged?.Invoke(_managedHand, Intent);
                    }
                }

                if (_managedHand.Hand.KeyPose == MLHandKeyPose.Finger || _managedHand.Hand.KeyPose == MLHandKeyPose.L)
                {
                    Intent       = IntentPose.Pointing;
                    Point.active = true;
                    OnIntentChanged?.Invoke(_managedHand, Intent);
                }
                else if (_managedHand.Hand.KeyPose == MLHandKeyPose.C || _managedHand.Hand.KeyPose == MLHandKeyPose.OpenHand || _managedHand.Hand.KeyPose == MLHandKeyPose.Thumb)
                {
                    Intent = IntentPose.Relaxed;
                    OnIntentChanged?.Invoke(_managedHand, Intent);
                }

                //accept keypose change:
                VerifiedGesture  = _managedHand.Hand.KeyPose;
                _proposedKeyPose = _managedHand.Hand.KeyPose;
                OnVerifiedGestureChanged?.Invoke(_managedHand, VerifiedGesture);
            }
        }
    }
Example #28
0
 /// <summary>
 /// Appends a centered skew matrix from the give angles in radians.
 /// </summary>
 /// <param name="radiansX">The X angle, in radians.</param>
 /// <param name="radiansY">The Y angle, in radians.</param>
 /// <returns>The <see cref="AffineTransformBuilder"/>.</returns>
 public AffineTransformBuilder AppendSkewRadians(float radiansX, float radiansY)
 => this.Append(size => TransformUtilities.CreateSkewMatrixRadians(radiansX, radiansY, size));
Example #29
0
    private IEnumerator DelayedStart()
    {
        TechSupportService mysteryKeyService = GetComponent <TechSupportService>();

        while (!mysteryKeyService.SettingsLoaded)
        {
            yield return(null);
        }

        KMBossModule bossModule = GetComponent <KMBossModule>();

        string[] ignoredModules = bossModule.GetIgnoredModules(needyModule.ModuleDisplayName);

        if (ignoredModules == null || ignoredModules.Length == 0)
        {
            TechSupportLog.Log("Using backup ignorelist.");
            ignoredModules = backUpIgnoreList.text.Split('\n');
        }

        KMBombModule[] bombModules = FindObjectsOfType <KMBombModule>();

        foreach (KMBombModule bombModule in bombModules)
        {
            try
            {
                bool mustNotBeHidden = mysteryKeyService.MustNotBeHidden(bombModule.ModuleType);
                bool isIgnored       = ignoredModules.Contains(bombModule.ModuleDisplayName);

                // Ignored modules are ignored.
                if (mustNotBeHidden || isIgnored)
                {
                    TechSupportLog.LogFormat("Ignored module {0} - Must Not Be Hidden: {1}; Is Ignored {2}",
                                             bombModule.ModuleDisplayName,
                                             mustNotBeHidden,
                                             isIgnored);
                    continue;
                }

                // Collects the module's KMSelectable.
                KMSelectable selectable = bombModule.GetComponent <KMSelectable>();

                GameObject passLight   = TransformUtilities.FindChildIn(bombModule.transform, "Component_LED_PASS").gameObject;
                Transform  statusLight = passLight.transform.parent;
                GameObject strikeLight = TransformUtilities.FindChildIn(statusLight, "Component_LED_STRIKE").gameObject;
                GameObject errorLight  = Instantiate(
                    errorLightPrefab,
                    statusLight.position,
                    statusLight.rotation,
                    statusLight.transform);
                errorLight.SetActive(false);

                // Stores the acquired data.
                InterruptableModule interruptableModule = new InterruptableModule(bombModule, selectable, passLight, strikeLight, errorLight);

                interruptableModules.Add(interruptableModule);
            }
            catch (Exception exception)
            {
                TechSupportLog.LogFormat
                    ("Set-Up Interruptable ({0}) failed with message ({1}), at ({2}).",
                    bombModule.ModuleDisplayName,
                    exception.Message,
                    exception.StackTrace);
            }
        }

        TechSupportLog.LogFormat("Loaded total of {0} interruptable modules", interruptableModules.Count);
    }