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; }
//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; }
private static void CheckDegenerate(Matrix3x2 matrix) { if (TransformUtilities.IsDegenerate(matrix)) { throw new DegenerateTransformException("Matrix is degenerate. Check input values."); } }
/// <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)); }
/// <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(); }
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; }
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); }
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); }
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 }
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); }
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); }
/// <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));
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); }
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(); } } }
/// <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));
//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); } } }
/// <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));
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); }