private void OnDrawGizmos() { Vector2 from = FromAngle(angle) * distance + (Vector2)transform.position; Gizmos.DrawWireSphere(from, 0.2f); try { var corners = ColliderUtils.FindCorners(from, Collider); Gizmos.color = Color.cyan; for (int i = 0; i < corners.Length; i++) { Gizmos.DrawLine(from, corners[i]); } try { var normals = ColliderUtils.FindNormals(corners, Collider); Gizmos.color = Color.white; for (int i = 0; i < normals.Length; i++) { Gizmos.DrawRay(corners[i], normals[i]); } } catch { } } catch { } }
private void OnTriggerStay2D(Collider2D collision) { if (ColliderUtils.HasBallCollided(collision)) { GameObject player = this.gameObject.transform.parent.parent.parent.gameObject; GameObject ballGameObject = collision.gameObject; BallController ballControlerScript = BallUtils.FetchBallControllerScript(ballGameObject); PlayerStatus currentPlayerStatus = PlayerUtils.FetchPlayerStatusScript(player); GenericPlayerBehaviour genericPlayerBehaviourScript = PlayerUtils.FetchCorrespondingPlayerBehaviourScript(player, currentPlayerStatus); if (ballControlerScript.IsMoving && ballControlerScript.IsHit && !ballControlerScript.IsPitched) { if (PlayerUtils.HasPitcherPosition(player) && !ballControlerScript.IsTargetedByFielder && !ballControlerScript.IsInFoulState) { ballControlerScript.IsTargetedByPitcher = true; ((PitcherBehaviour)genericPlayerBehaviourScript).CalculatePitcherTriggerInterraction(ballGameObject, genericPlayerBehaviourScript, currentPlayerStatus); } if (PlayerUtils.HasFielderPosition(player) && !ballControlerScript.IsTargetedByFielder && !ballControlerScript.IsTargetedByPitcher && !ballControlerScript.IsInFoulState) { GameObject nearestFielder = TeamUtils.GetNearestFielderFromGameObject(ballGameObject); PlayerStatus nearestFielderStatus = PlayerUtils.FetchPlayerStatusScript(nearestFielder); if (nearestFielderStatus.PlayerFieldPosition == currentPlayerStatus.PlayerFieldPosition) { ((FielderBehaviour)genericPlayerBehaviourScript).CalculateFielderTriggerInterraction(genericPlayerBehaviourScript); } } } } }
private void OnCollisionExit2D(Collision2D collision) { if (PlayerUtils.HasRunnerPosition(this.gameObject) && ColliderUtils.IsBaseTile(collision.gameObject.name)) { PlayerStatus playerStatusScript = PlayerUtils.FetchPlayerStatusScript(this.gameObject); RunnerBehaviour runnerBehaviourScript = ((RunnerBehaviour)PlayerUtils.FetchCorrespondingPlayerBehaviourScript(this.gameObject, playerStatusScript)); runnerBehaviourScript.ToggleRunnerSafeStatus(); } }
private void OnTriggerEnter2D(Collider2D collision) { if (ColliderUtils.HasBallCollided(collision)) { GameObject ball = collision.gameObject; BallController ballControllerScript = BallUtils.FetchBallControllerScript(ball); if (ballControllerScript.IsHit) { ballControllerScript.IsInFoulState = true; } } }
private void OnTriggerExit2D(Collider2D collision) { if (ColliderUtils.HasBallCollided(collision)) { GameObject ball = collision.gameObject; BallController ballControllerScript = BallUtils.FetchBallControllerScript(ball); if (ballControllerScript.IsHit) { Debug.Log("the ball not foul any more"); ballControllerScript.IsInFoulState = false; timeElapsed = 0; } } }
private void OnTriggerExit2D(Collider2D collision) { if (ColliderUtils.HasBallCollided(collision)) { GameObject ballGameObject = collision.gameObject; BallController ballControlerScript = BallUtils.FetchBallControllerScript(ballGameObject); if (ballControlerScript.IsMoving && ballControlerScript.IsHit && !ballControlerScript.IsPitched) { GameObject player = this.gameObject.transform.parent.parent.parent.gameObject; if (PlayerUtils.HasPitcherPosition(player)) { ballControlerScript.IsTargetedByPitcher = false; PitcherBehaviour pitcherBehaviour = PlayerUtils.FetchPitcherBehaviourScript(player); pitcherBehaviour.Target = FieldUtils.GetTileCenterPositionInGameWorld(FieldUtils.GetPitcherBaseTilePosition()); pitcherBehaviour.HasSpottedBall = false; } } } }
private void OnTriggerStay2D(Collider2D collision) { if (ColliderUtils.HasBallCollided(collision) && !GameData.isPaused) { GameObject ball = collision.gameObject; BallController ballControllerScript = BallUtils.FetchBallControllerScript(ball); if (ballControllerScript.IsHit) { timeElapsed += Time.deltaTime; if (timeElapsed >= TIME_TO_WAIT_IN_FOUL_ZONE) { Debug.Log("the ball is foul"); timeElapsed = 0; DialogBoxManager dialogBoxManagerScript = GameUtils.FetchDialogBoxManager(); dialogBoxManagerScript.DisplayDialogAndTextForGivenAmountOfTime(1f, false, "FOUL!!"); PlayersTurnManager playersTurnManager = GameUtils.FetchPlayersTurnManager(); GameObject pitcher = TeamUtils.GetPlayerTeamMember(PlayerFieldPositionEnum.PITCHER, TeamUtils.GetPlayerIdFromPlayerFieldPosition(PlayerFieldPositionEnum.PITCHER)); GameManager gameManager = GameUtils.FetchGameManager(); GameObject currentBatter = gameManager.AttackTeamBatterListClone.First(); BatterBehaviour currentBatterBehaviour = PlayerUtils.FetchBatterBehaviourScript(currentBatter); GameObject bat = currentBatterBehaviour.EquipedBat; currentBatterBehaviour.FoulOutcomeCount += 1; currentBatter.transform.rotation = Quaternion.identity; bat.transform.position = FieldUtils.GetBatCorrectPosition(currentBatter.transform.position); bat.transform.rotation = Quaternion.Euler(0f, 0f, -70f); gameManager.ReinitPitcher(pitcher); gameManager.ReturnBallToPitcher(ballControllerScript.gameObject); gameManager.ReinitRunners(gameManager.AttackTeamRunnerList); ballControllerScript.IsInFoulState = false; playersTurnManager.TurnState = TurnStateEnum.PITCHER_TURN; PlayersTurnManager.IsCommandPhase = true; } } } }
private Vector3[] CutIntoVoxels() { Quaternion initialRotation = this.transform.rotation; this.transform.rotation = Quaternion.identity; Bounds bounds = this.collider.bounds; this.voxelSize.x = bounds.size.x * this.normalizedVoxelSize; this.voxelSize.y = bounds.size.y * this.normalizedVoxelSize; this.voxelSize.z = bounds.size.z * this.normalizedVoxelSize; int voxelsCountForEachAxis = Mathf.RoundToInt(1f / this.normalizedVoxelSize); List <Vector3> voxels = new List <Vector3>(voxelsCountForEachAxis * voxelsCountForEachAxis * voxelsCountForEachAxis); for (int i = 0; i < voxelsCountForEachAxis; i++) { for (int j = 0; j < voxelsCountForEachAxis; j++) { for (int k = 0; k < voxelsCountForEachAxis; k++) { float pX = bounds.min.x + this.voxelSize.x * (0.5f + i); float pY = bounds.min.y + this.voxelSize.y * (0.5f + j); float pZ = bounds.min.z + this.voxelSize.z * (0.5f + k); Vector3 point = new Vector3(pX, pY, pZ); if (ColliderUtils.IsPointInsideCollider(point, this.collider, ref bounds)) { voxels.Add(this.transform.InverseTransformPoint(point)); } } } } this.transform.rotation = initialRotation; return(voxels.ToArray()); }
private void OnCollisionEnter2D(Collision2D collision) { PlayerStatus playerStatusScript = PlayerUtils.FetchPlayerStatusScript(this.gameObject); GenericPlayerBehaviour genericPlayerBehaviourScript = PlayerUtils.FetchCorrespondingPlayerBehaviourScript(this.gameObject, playerStatusScript); if (ColliderUtils.HasBallCollided(collision.collider)) { GameObject ballGameObject = collision.collider.gameObject; BallController ballControllerScript = BallUtils.FetchBallControllerScript(ballGameObject); if (PlayerUtils.HasCatcherPosition(this.gameObject) && ballControllerScript.CurrentPasser != this.gameObject) { CatcherBehaviour catcherBehaviour = (CatcherBehaviour)genericPlayerBehaviourScript; if (catcherBehaviour.CatcherMode == ModeConstants.CATCHER_FIELDER_MODE) { PlayerActionsManager.InterceptBall(ballGameObject, ballControllerScript, genericPlayerBehaviourScript); catcherBehaviour.CatcherMode = ModeConstants.CATCHER_NORMAL_MODE; this.gameObject.transform.position = FieldUtils.GetTileCenterPositionInGameWorld(FieldUtils.GetCatcherZonePosition()); catcherBehaviour.IsoRenderer.ReinitializeAnimator(); } PlayersTurnManager playersTurnManager = GameUtils.FetchPlayersTurnManager(); playersTurnManager.TurnState = TurnStateEnum.CATCHER_TURN; PlayersTurnManager.IsCommandPhase = true; } else if (PlayerUtils.HasFielderPosition(this.gameObject) && !ballControllerScript.IsPitched && ballControllerScript.CurrentPasser != this.gameObject) { ((FielderBehaviour)genericPlayerBehaviourScript).CalculateFielderColliderInterraction(ballGameObject, ballControllerScript, genericPlayerBehaviourScript); } else if (PlayerUtils.HasPitcherPosition(this.gameObject) && !ballControllerScript.IsPitched && !ballControllerScript.IsPassed && ballControllerScript.CurrentPasser != this.gameObject) { ((PitcherBehaviour)genericPlayerBehaviourScript).CalculatePitcherColliderInterraction(ballGameObject, ballControllerScript, genericPlayerBehaviourScript); } } else if (ColliderUtils.HasPlayerCollided(collision)) { if (PlayerUtils.HasFielderPosition(this.gameObject) && genericPlayerBehaviourScript.IsHoldingBall && PlayerUtils.HasRunnerPosition(collision.gameObject)) { PlayerStatus runnerToTagOutStatus = PlayerUtils.FetchPlayerStatusScript(collision.transform.gameObject); RunnerBehaviour runnerBehaviourScript = ((RunnerBehaviour)PlayerUtils.FetchCorrespondingPlayerBehaviourScript(collision.transform.gameObject, runnerToTagOutStatus)); if (!runnerBehaviourScript.IsSafe) { ((FielderBehaviour)genericPlayerBehaviourScript).TagOutRunner(collision.transform.gameObject); } else { ((FielderBehaviour)genericPlayerBehaviourScript).ReplanAction(); } } } else { if (PlayerUtils.HasRunnerPosition(this.gameObject)) { if (!ColliderUtils.IsBaseTile(collision.gameObject.name)) { return; } if (genericPlayerBehaviourScript == null) { return; } if (!genericPlayerBehaviourScript.IsPrepared) { return; } RunnerBehaviour runnerBehaviour = ((RunnerBehaviour)genericPlayerBehaviourScript); BaseEnum baseReached = runnerBehaviour.NextBase; if (baseReached == BaseEnum.HOME_BASE && runnerBehaviour.HasPassedThroughThreeFirstBases()) { //win a point automaticaly without issuing commands if arrived at home base after a complete turn runnerBehaviour.CalculateRunnerColliderInterraction(FieldUtils.GetTileEnumFromName(collision.gameObject.name), true); } else if (baseReached == BaseEnum.FIRST_BASE && runnerBehaviour.IsInWalkState) { //Walk done after 4 ball from pitcher runnerBehaviour.CalculateRunnerColliderInterraction(FieldUtils.GetTileEnumFromName(collision.gameObject.name)); PlayersTurnManager playersTurnManager = GameUtils.FetchPlayersTurnManager(); playersTurnManager.TurnState = TurnStateEnum.PITCHER_TURN; PlayersTurnManager.IsCommandPhase = true; } else if (baseReached == BaseEnum.HOME_BASE) { //automaticaly run to next base, no need for command input runnerBehaviour.CalculateRunnerColliderInterraction(FieldUtils.GetTileEnumFromName(collision.gameObject.name)); runnerBehaviour.GoToNextBase(baseReached, true); } else { //Runner next turn runnerBehaviour.CalculateRunnerColliderInterraction(FieldUtils.GetTileEnumFromName(collision.gameObject.name), true); } } } }
public static unsafe void CollideAndIntegrate( CharacterControllerStepInput stepInput, float characterMass, bool affectBodies, Collider *collider, ref RigidTransform transform, ref float3 linearVelocity, ref NativeStream.Writer deferredImpulseWriter) { // Copy parameters float deltaTime = stepInput.DeltaTime; float3 up = stepInput.Up; PhysicsWorld world = stepInput.World; float remainingTime = deltaTime; float3 newPosition = transform.pos; quaternion orientation = transform.rot; float3 newVelocity = linearVelocity; float maxSlopeCos = math.cos(stepInput.MaxSlope); const float timeEpsilon = 0.000001f; for (int i = 0; i < stepInput.MaxIterations && remainingTime > timeEpsilon; i++) { NativeList <SurfaceConstraintInfo> constraints = new NativeList <SurfaceConstraintInfo>(k_DefaultConstraintsCapacity, Allocator.Temp); // Do a collider cast { float3 displacement = newVelocity * remainingTime; NativeList <ColliderCastHit> castHits = new NativeList <ColliderCastHit>(k_DefaultQueryHitsCapacity, Allocator.Temp); SelfFilteringAllHitsCollector <ColliderCastHit> collector = new SelfFilteringAllHitsCollector <ColliderCastHit>(stepInput.RigidBodyIndex, 1.0f, ref castHits); ColliderCastInput input = new ColliderCastInput() { Collider = collider, Orientation = orientation, Start = newPosition, End = newPosition + displacement }; world.CastCollider(input, ref collector); // Iterate over hits and create constraints from them for (int hitIndex = 0; hitIndex < collector.NumHits; hitIndex++) { ColliderCastHit hit = collector.AllHits[hitIndex]; if (ColliderUtils.IsTrigger(world.Bodies[hit.RigidBodyIndex].Collider, hit.ColliderKey)) { continue; } CreateConstraint(stepInput.World, stepInput.Up, hit.RigidBodyIndex, hit.ColliderKey, hit.Position, hit.SurfaceNormal, hit.Fraction * math.length(displacement), stepInput.SkinWidth, maxSlopeCos, ref constraints); } } // Then do a collider distance for penetration recovery, // but only fix up penetrating hits { // Collider distance query NativeList <DistanceHit> distanceHits = new NativeList <DistanceHit>(k_DefaultQueryHitsCapacity, Allocator.Temp); SelfFilteringAllHitsCollector <DistanceHit> distanceHitsCollector = new SelfFilteringAllHitsCollector <DistanceHit>( stepInput.RigidBodyIndex, stepInput.ContactTolerance, ref distanceHits); { ColliderDistanceInput input = new ColliderDistanceInput() { MaxDistance = stepInput.ContactTolerance, Transform = transform, Collider = collider }; world.CalculateDistance(input, ref distanceHitsCollector); } // Iterate over penetrating hits and fix up distance and normal int numConstraints = constraints.Length; for (int hitIndex = 0; hitIndex < distanceHitsCollector.NumHits; hitIndex++) { DistanceHit hit = distanceHitsCollector.AllHits[hitIndex]; if (hit.Distance < stepInput.SkinWidth) { bool found = false; // Iterate backwards to locate the original constraint before the max slope constraint for (int constraintIndex = numConstraints - 1; constraintIndex >= 0; constraintIndex--) { SurfaceConstraintInfo constraint = constraints[constraintIndex]; if (constraint.RigidBodyIndex == hit.RigidBodyIndex && constraint.ColliderKey.Equals(hit.ColliderKey)) { // Fix up the constraint (normal, distance) { if (ColliderUtils.IsTrigger(world.Bodies[hit.RigidBodyIndex].Collider, hit.ColliderKey)) { continue; } // Create new constraint CreateConstraintFromHit(world, hit.RigidBodyIndex, hit.ColliderKey, hit.Position, hit.SurfaceNormal, hit.Distance, stepInput.SkinWidth, out SurfaceConstraintInfo newConstraint); // Resolve its penetration ResolveConstraintPenetration(ref newConstraint); // Write back constraints[constraintIndex] = newConstraint; } found = true; break; } } // Add penetrating hit not caught by collider cast if (!found) { if (ColliderUtils.IsTrigger(world.Bodies[hit.RigidBodyIndex].Collider, hit.ColliderKey)) { continue; } CreateConstraint(stepInput.World, stepInput.Up, hit.RigidBodyIndex, hit.ColliderKey, hit.Position, hit.SurfaceNormal, hit.Distance, stepInput.SkinWidth, maxSlopeCos, ref constraints); } } } } // Min delta time for solver to break float minDeltaTime = 0.0f; if (math.lengthsq(newVelocity) > k_SimplexSolverEpsilonSq) { // Min delta time to travel at least 1cm minDeltaTime = 0.01f / math.length(newVelocity); } // Solve float3 prevVelocity = newVelocity; float3 prevPosition = newPosition; SimplexSolver.Solve(world, remainingTime, minDeltaTime, up, stepInput.MaxMovementSpeed, constraints, ref newPosition, ref newVelocity, out float integratedTime); // Apply impulses to hit bodies if (affectBodies) { CalculateAndStoreDeferredImpulses(stepInput, characterMass, prevVelocity, ref constraints, ref deferredImpulseWriter); } // Calculate new displacement float3 newDisplacement = newPosition - prevPosition; // If simplex solver moved the character we need to re-cast to make sure it can move to new position if (math.lengthsq(newDisplacement) > k_SimplexSolverEpsilon) { // Check if we can walk to the position simplex solver has suggested var newCollector = new SelfFilteringClosestHitCollector <ColliderCastHit>(stepInput.RigidBodyIndex, 1.0f); ColliderCastInput input = new ColliderCastInput() { Collider = collider, Orientation = orientation, Start = prevPosition, End = prevPosition + newDisplacement }; world.CastCollider(input, ref newCollector); if (newCollector.NumHits > 0) { ColliderCastHit hit = newCollector.ClosestHit; bool found = false; for (int constraintIndex = 0; constraintIndex < constraints.Length; constraintIndex++) { SurfaceConstraintInfo constraint = constraints[constraintIndex]; if (constraint.RigidBodyIndex == hit.RigidBodyIndex && constraint.ColliderKey.Equals(hit.ColliderKey)) { found = true; break; } } // Move character along the newDisplacement direction until it reaches this new contact if (!found) { Assert.IsTrue(hit.Fraction >= 0.0f && hit.Fraction <= 1.0f); integratedTime *= hit.Fraction; newPosition = prevPosition + newDisplacement * hit.Fraction; } } } // Reduce remaining time remainingTime -= integratedTime; } // Write back position and velocity transform.pos = newPosition; linearVelocity = newVelocity; }
public static unsafe void CheckSupport( ref PhysicsWorld world, ref PhysicsCollider collider, CharacterControllerStepInput stepInput, RigidTransform transform, float maxSlope, out CharacterSupportState characterState, out float3 surfaceNormal, out float3 surfaceVelocity) { surfaceNormal = float3.zero; surfaceVelocity = float3.zero; // Query the world NativeList <DistanceHit> distanceHits = new NativeList <DistanceHit>(k_DefaultQueryHitsCapacity, Allocator.Temp); SelfFilteringAllHitsCollector <DistanceHit> distanceHitsCollector = new SelfFilteringAllHitsCollector <DistanceHit>( stepInput.RigidBodyIndex, stepInput.ContactTolerance, ref distanceHits); { ColliderDistanceInput input = new ColliderDistanceInput() { MaxDistance = stepInput.ContactTolerance, Transform = transform, Collider = collider.ColliderPtr }; world.CalculateDistance(input, ref distanceHitsCollector); } // If no hits, proclaim unsupported state if (distanceHitsCollector.NumHits == 0) { characterState = CharacterSupportState.Unsupported; return; } // Downwards direction must be normalized float3 downwardsDirection = -stepInput.Up; Assert.IsTrue(Math.IsNormalized(downwardsDirection)); float maxSlopeCos = math.cos(maxSlope); // Iterate over distance hits and create constraints from them NativeList <SurfaceConstraintInfo> constraints = new NativeList <SurfaceConstraintInfo>(k_DefaultConstraintsCapacity, Allocator.Temp); for (int i = 0; i < distanceHitsCollector.NumHits; i++) { DistanceHit hit = distanceHitsCollector.AllHits[i]; if (ColliderUtils.IsTrigger(world.Bodies[hit.RigidBodyIndex].Collider, hit.ColliderKey)) { continue; } CreateConstraint(stepInput.World, stepInput.Up, hit.RigidBodyIndex, hit.ColliderKey, hit.Position, hit.SurfaceNormal, hit.Distance, stepInput.SkinWidth, maxSlopeCos, ref constraints); } float3 initialVelocity; { float velAlongDownwardsDir = math.dot(stepInput.CurrentVelocity, downwardsDirection); bool velocityIsAlongDownwardsDirection = velAlongDownwardsDir > 0.0f; if (velocityIsAlongDownwardsDirection) { float3 downwardsVelocity = velAlongDownwardsDir * downwardsDirection; initialVelocity = math.select(downwardsVelocity, downwardsDirection, math.abs(velAlongDownwardsDir) > 1.0f) + stepInput.Gravity * stepInput.DeltaTime; } else { initialVelocity = downwardsDirection; } } // Solve downwards (don't use min delta time, try to solve full step) float3 outVelocity = initialVelocity; float3 outPosition = transform.pos; SimplexSolver.Solve(stepInput.World, stepInput.DeltaTime, stepInput.DeltaTime, stepInput.Up, stepInput.MaxMovementSpeed, constraints, ref outPosition, ref outVelocity, out float integratedTime, false); // Get info on surface { int numSupportingPlanes = 0; for (int j = 0; j < constraints.Length; j++) { var constraint = constraints[j]; if (constraint.Touched && !constraint.IsTooSteep) { numSupportingPlanes++; surfaceNormal += constraint.Plane.Normal; surfaceVelocity += constraint.Velocity; } } if (numSupportingPlanes > 0) { float invNumSupportingPlanes = 1.0f / numSupportingPlanes; surfaceNormal *= invNumSupportingPlanes; surfaceVelocity *= invNumSupportingPlanes; surfaceNormal = math.normalize(surfaceNormal); } } // Check support state { if (math.lengthsq(initialVelocity - outVelocity) < k_SimplexSolverEpsilonSq) { // If velocity hasn't changed significantly, declare unsupported state characterState = CharacterSupportState.Unsupported; } else if (math.lengthsq(outVelocity) < k_SimplexSolverEpsilonSq) { // If velocity is very small, declare supported state characterState = CharacterSupportState.Supported; } else { // Check if sliding or supported outVelocity = math.normalize(outVelocity); float slopeAngleSin = math.max(0.0f, math.dot(outVelocity, downwardsDirection)); float slopeAngleCosSq = 1 - slopeAngleSin * slopeAngleSin; if (slopeAngleCosSq < maxSlopeCos * maxSlopeCos) { characterState = CharacterSupportState.Sliding; } else { characterState = CharacterSupportState.Supported; } } } }
public override Color GetColor(Raytracer raytracer, Ray ray, RaycastHit hit, TraceData traceData) { Vector2 texCoord; Vector3 surfaceNormal; Vector3 tangent, binormal; bool texCoordAndTangentRequired = NormalMap != null || DiffuseTexture != null || SpecularMap != null || ReflectionMap != null; texCoordAndTangentRequired = true; // DEBUG if (texCoordAndTangentRequired) { Vector3 localNormal; Vector3 localTangent; ColliderUtils.GetTexCoordAndTangent( hit, out texCoord, out localNormal, out localTangent ); tangent = hit.collider.transform.TransformDirection(localTangent); surfaceNormal = hit.collider.transform.TransformDirection(localNormal); binormal = Vector3.Cross(tangent, surfaceNormal); #region Debug Visualisation #if DEBUG_SHOW_TEX_COORDS return(new Color(texCoord.x, texCoord.y, 0, 1)); #endif #if DEBUG_SHOW_BARYCENTRIC_COORDS Vector3 dbgBc = hit.barycentricCoordinate; return(new Color(dbgBc.x, dbgBc.y, dbgBc.z, 1)); #endif #if DEBUG_SHOW_NORMALS Vector3 dbgLocalNormal = localNormal; //dbgLocalNormal = new Vector3 ( // Mathf.Abs ( dbgLocalNormal.x ), // Mathf.Abs ( dbgLocalNormal.y ), // Mathf.Abs ( dbgLocalNormal.z ) //); dbgLocalNormal = (dbgLocalNormal + Vector3.one) * 0.5f; return(new Color(dbgLocalNormal.x, dbgLocalNormal.y, dbgLocalNormal.z, 1)); #endif #if DEBUG_SHOW_TANGENTS Vector3 dbgLocalTangent = localTangent; if (false) { dbgLocalTangent = new Vector3( Mathf.Abs(dbgLocalTangent.x), Mathf.Abs(dbgLocalTangent.y), Mathf.Abs(dbgLocalTangent.z) ); } else if (false) { dbgLocalTangent = new Vector3( Mathf.Abs(dbgLocalTangent.x > 0 ? dbgLocalTangent.x : 0), Mathf.Abs(dbgLocalTangent.y > 0 ? dbgLocalTangent.y : 0), Mathf.Abs(dbgLocalTangent.z > 0 ? dbgLocalTangent.z : 0) ); } else { dbgLocalTangent = (dbgLocalTangent + Vector3.one) * 0.5f; } return(new Color(dbgLocalTangent.x, dbgLocalTangent.y, dbgLocalTangent.z, 1)); #endif #if DEBUG_SHOW_BINORMALS Vector3 localBinormal = Vector3.Cross(localTangent, localNormal); Vector3 dbgBinormal = localBinormal; dbgBinormal = new Vector3( Mathf.Abs(dbgBinormal.x), Mathf.Abs(dbgBinormal.y), Mathf.Abs(dbgBinormal.z) ); return(new Color(dbgBinormal.x, dbgBinormal.y, dbgBinormal.z, 1)); #endif #endregion Debug Visualisation } else { texCoord = Vector2.zero; surfaceNormal = hit.normal; tangent = Vector3.zero; binormal = Vector3.zero; } bool entering = Vector3.Dot(hit.normal, ray.direction) <= 0; surfaceNormal = entering ? surfaceNormal : -surfaceNormal; /* TODO: revise where "entering" calculated upon hit.normal should be replaced * with "entering" calculated upon surfaceNormal transformed with TBN. */ if (NormalMap != null && NormalMapInfluence > 0) { var normalMapRt = TextureCache.FromUnityTexture(NormalMap); Color normalMapColor = normalMapRt.GetFilteredPixel(texCoord.x, texCoord.y); Vector3 texNormal = new Vector3(normalMapColor.r, normalMapColor.g, normalMapColor.b); texNormal = 2 * texNormal - Vector3.one; texNormal.Normalize(); Vector3 texNormalWorld = Raytracer.TransformTbn(texNormal, tangent, binormal, surfaceNormal); float normalMapInfluence = Mathf.Clamp01(NormalMapInfluence); surfaceNormal = Vector3.Lerp(surfaceNormal, texNormalWorld, normalMapInfluence).normalized; #if DEBUG_SHOW_SURFACE_NORMALS Vector3 dbgSurfaceNormal = surfaceNormal; //dbgSurfaceNormal = new Vector3 ( // Mathf.Abs ( dbgSurfaceNormal.x ), // Mathf.Abs ( dbgSurfaceNormal.y ), // Mathf.Abs ( dbgSurfaceNormal.z ) //); dbgSurfaceNormal = (dbgSurfaceNormal + Vector3.one) * 0.5f; return(new Color(dbgSurfaceNormal.x, dbgSurfaceNormal.y, dbgSurfaceNormal.z, 1)); #endif } float specularIntensity = SpecularComponent; if (SpecularMap != null && SpecularMapInfluence > 0 && specularIntensity > 0) { var specularMapRt = TextureCache.FromUnityTexture(SpecularMap); Color specularMapColor = specularMapRt.GetFilteredPixel(texCoord.x, texCoord.y); specularIntensity *= specularMapColor.grayscale * specularMapColor.a; float specularMapInfluence = Mathf.Clamp01(SpecularMapInfluence); specularIntensity = Mathf.Lerp(SpecularComponent, specularIntensity, specularMapInfluence); } Color totalColor = Color.black; Color diffuseLightSumColor = raytracer.OverrideAmbientLight ? raytracer.AmbientLight : RenderSettings.ambientLight; diffuseLightSumColor *= DiffuseComponent; Color specularLightSumColor = Color.black; var lights = Light.GetLights(LightType.Point, 0); foreach (var light in lights) { Vector3 vToLight = light.transform.position - hit.point; float lightVolumeRadius = light.range * 0.00625f; // Empirical coefficient. float distance = vToLight.magnitude - lightVolumeRadius; if (distance < 0) { distance = 0; } else if (distance >= light.range) { continue; } Vector3 dirToLight = vToLight.normalized; float attenuation; attenuation = 1 - distance / light.range; attenuation = attenuation * attenuation; float lightIntensity = light.intensity * LightIntensityFactor; if (DiffuseComponent > 0) { float diffuseIntensity = Vector3.Dot(dirToLight, surfaceNormal); if (diffuseIntensity > 0) { diffuseIntensity = Mathf.Pow(diffuseIntensity, DiffuseExponent); Color diffuseLightColor = light.color * attenuation * diffuseIntensity * lightIntensity; diffuseLightSumColor += diffuseLightColor; } } if (specularIntensity > 0) { Vector3 reflectionDir = Vector3.Reflect(-dirToLight, surfaceNormal); Vector3 vToView = raytracer.Camera.transform.position - hit.point; Vector3 dirToView = vToView.normalized; float specularity = Vector3.Dot(reflectionDir, dirToView); if (specularity > 0) { specularity = Mathf.Pow(specularity, SpecularPower); Color specularLightColor = light.color * attenuation * specularity * lightIntensity; specularLightSumColor += specularLightColor; } } } Color diffuseColor; if (DiffuseTexture != null) { var diffuseTextureRt = TextureCache.FromUnityTexture(DiffuseTexture); // TODO: calculate miplevel, get the color according to its value. Color texColor = diffuseTextureRt.GetFilteredPixel(texCoord.x, texCoord.y); if (texColor.a < 1 && DiffuseColorIsBackground) { diffuseColor = Color.Lerp(this.DiffuseColor, texColor, texColor.a); } else { diffuseColor = Color.Lerp(Color.black, texColor, texColor.a); } diffuseColor.a = texColor.a; } else { diffuseColor = this.DiffuseColor; } totalColor = diffuseLightSumColor * diffuseColor * DiffuseComponent + specularLightSumColor * specularIntensity; if (raytracer.MustInterrupt(totalColor, traceData)) { return(totalColor); } bool willReflect; float reflectionIntensity; if (entering) { willReflect = ReflectionComponent > 0 && traceData.NumReflections < raytracer.MaxReflections; reflectionIntensity = ReflectionComponent; } else { willReflect = InnerReflectionComponent > 0 && traceData.NumInnerReflections < raytracer.MaxInnerReflections; reflectionIntensity = InnerReflectionComponent; } if (willReflect && ReflectionMap != null && ReflectionMapInfluence > 0) { var reflectionMapRt = TextureCache.FromUnityTexture(ReflectionMap); Color reflectionMapColor = reflectionMapRt.GetFilteredPixel(texCoord.x, texCoord.y); float reflectionMapIntensity = reflectionMapColor.grayscale * reflectionMapColor.a; float reflectionMapInfluence = Mathf.Clamp01(ReflectionMapInfluence); reflectionIntensity = Mathf.Lerp(reflectionIntensity, reflectionMapIntensity * reflectionIntensity, reflectionMapInfluence); willReflect = reflectionIntensity > 0; } float refractionIntensity = RefractionComponent; if (RefractWhereTranslucent) { refractionIntensity *= 1 - diffuseColor.a * DiffuseComponent; } bool willRefract = refractionIntensity > 0 && traceData.NumRefractions < raytracer.MaxRefractions; bool forkingRequired = willReflect && willRefract; TraceData tdForRefraction; if (forkingRequired) { tdForRefraction = traceData.Fork(); } else { tdForRefraction = traceData; } if (willReflect) { if (entering) { traceData.NumReflections++; traceData.Counters.Reflections++; } else { traceData.NumInnerReflections++; traceData.Counters.InnerReflections++; } Vector3 reflectionDir = Vector3.Reflect(ray.direction, surfaceNormal); Vector3 pushedOutPoint = hit.point + reflectionDir * Raytracer.PushOutMagnitude; Color reflectionColor = raytracer.Trace(new Ray(pushedOutPoint, reflectionDir), traceData); totalColor += reflectionColor * reflectionIntensity; if (raytracer.MustInterrupt(totalColor, traceData)) { return(totalColor); } } if (willRefract) { tdForRefraction.NumRefractions++; tdForRefraction.Counters.Refractions++; CoefficientOut = RefractionIndex; CoefficientIn = 1 / RefractionIndex; if (CoefficientOut > 1) { CriticalOutAngleCos = Mathf.Sqrt(1 - CoefficientIn * CoefficientIn); CriticalInAngleCos = 0; } else { CriticalOutAngleCos = 0; CriticalInAngleCos = Mathf.Sqrt(1 - CoefficientOut * CoefficientOut); } float criticalAngleCos = entering ? CriticalInAngleCos : CriticalOutAngleCos; Vector3 refractionDir; float nDotRay = Vector3.Dot(surfaceNormal, ray.direction); if (Mathf.Abs(nDotRay) >= criticalAngleCos) { if (entering) { tdForRefraction.PenetrationStack.Push(hit); } else { tdForRefraction.PenetrationStack.Pop(); } float k = entering ? CoefficientIn : CoefficientOut; refractionDir = Raytracer.Refract(ray.direction, surfaceNormal, nDotRay, k); refractionDir.Normalize(); } else // Total internal reflection. { refractionDir = Vector3.Reflect(ray.direction, surfaceNormal); } Vector3 pushedOutPoint = hit.point + refractionDir * Raytracer.PushOutMagnitude; Color refractionColor = raytracer.Trace(new Ray(pushedOutPoint, refractionDir), tdForRefraction); if (ColorAberration != 0 && entering) { //float rDotRay = Vector3.Dot ( refractionDir, ray.direction ); refractionColor = HsvColor.ChangeHue(refractionColor, (1 + nDotRay) * ColorAberration); } totalColor += refractionColor * refractionIntensity; if (raytracer.MustInterrupt(totalColor, tdForRefraction)) { return(totalColor); } } return(totalColor); }
public void Tick(Vector2 lineEndPosition) { RaycastHit2D hit; // Loops until line of sight to player is restored do { // Breaks if end position is inside a collider if (Physics2D.OverlapCircle(lineEndPosition, 0.001f, GroundMask) != null) { break; } Vector2 originPos = currentAnchor.Position; // Raycasts from last anchor to current player position hit = Physics2D.Raycast(originPos, (lineEndPosition - originPos).normalized, Vector2.Distance(originPos, lineEndPosition), GroundMask); // Checks if hitted something and ands anchor in that case if (hit.transform != null) { // Gets previous and current direction Vector2 previousDirection = previousPosition - originPos; Vector2 direction = lineEndPosition - originPos; // Ckecks if hit was clockwise or counter clockwise float angleBetweenRays = Vector2.SignedAngle(previousDirection, direction); bool clockwise = angleBetweenRays < 0; // Gets all corners for given collider and find correct one var corners = ColliderUtils.FindCorners(originPos, hit.collider); var cornerIndex = VectorUtils.FindFirstPointInCircularOrder(previousDirection, originPos, corners, clockwise); var corner = corners[cornerIndex]; Vector2 normal = ColliderUtils.FindNormal(corners[cornerIndex], cornerIndex, hit.collider); // Ads offset corner += normal * EdgeOffset; // Add new anchor to memory previousAnchors.Push(currentAnchor); currentAnchor = new Anchor(corner, normal, clockwise); AnchorAdded?.Invoke(currentAnchor); } } while (hit.transform != null); // Checks if last anchor should be deleted if (previousAnchors.Count > 0) { Anchor previousAnchor = previousAnchors.Peek(); Vector2 lastToCurrentAnchorPos = currentAnchor.Position - previousAnchor.Position; float angle = Vector2.SignedAngle(lastToCurrentAnchorPos, lineEndPosition - currentAnchor.Position); if (currentAnchor.Clockwise == angle > 0) { // Removes anchor from memory currentAnchor = previousAnchors.Pop(); AnchorRemoved?.Invoke(currentAnchor); } } if (DrawDebug) { // Debug Drawing var anchorArray = previousAnchors.ToArray(); for (int i = 0; i < previousAnchors.Count - 1; i++) { Debug.DrawLine(anchorArray[i].Position, anchorArray[i + 1].Position, Color.red); } if (previousAnchors.Count > 0) { Debug.DrawLine(previousAnchors.Peek().Position, currentAnchor.Position, Color.green); } Debug.DrawLine(currentAnchor.Position, lineEndPosition, Color.cyan); // ----------- } // Updates previous position previousPosition = lineEndPosition; }