| | | 1 | | //======================================================================= |
| | | 2 | | // GravitasQuery3DService.Raycast.cs |
| | | 3 | | //======================================================================= |
| | | 4 | | // MIT License, Copyright (c) 2026–present David Oravsky (mrdav30) |
| | | 5 | | // See LICENSE file in the project root for full license information. |
| | | 6 | | //======================================================================= |
| | | 7 | | |
| | | 8 | | using FixedMathSharp; |
| | | 9 | | using Gravitas.Colliders; |
| | | 10 | | using Gravitas.CollisionHandling; |
| | | 11 | | using Gravitas.Support; |
| | | 12 | | using GridForge.Grids; |
| | | 13 | | using GridForge.Spatial; |
| | | 14 | | using GridForge.Utility; |
| | | 15 | | using SwiftCollections; |
| | | 16 | | using System.Runtime.CompilerServices; |
| | | 17 | | |
| | | 18 | | namespace Gravitas.Queries; |
| | | 19 | | |
| | | 20 | | /// <summary> |
| | | 21 | | /// Owns 3D raycast, swept-sphere, and X/Z circle query buffers for one <see cref="GravitasWorldContext"/>. |
| | | 22 | | /// </summary> |
| | | 23 | | public sealed partial class GravitasQuery3DService |
| | | 24 | | { |
| | | 25 | | private readonly GravitasWorldContext _context; |
| | 5083 | 26 | | private readonly RaycastSegmentWorker _worker = new(); |
| | 5083 | 27 | | private readonly SweptSphereQueryWorker _sweepWorker = new(); |
| | 5083 | 28 | | private readonly ConvexSweepQueryWorker _convexSweepWorker = new(); |
| | 5083 | 29 | | private SwiftList<Vector3d> _bufferIntersectionPoints = new(); |
| | 5083 | 30 | | private readonly SwiftList<int> _meshTriangleCandidates = new(16); |
| | 5083 | 31 | | private readonly SwiftList<int> _planarCircleCandidates = new(); |
| | 5083 | 32 | | private readonly SwiftHashSet<int> _redundantColliderCheck = new(); |
| | 5083 | 33 | | private readonly SwiftHashSet<WorldVoxelIndex> _redundantVoxelCheck = new(); |
| | 5083 | 34 | | private readonly SwiftList<Voxel> _coveredVoxels = new(); |
| | 5083 | 35 | | private readonly GridTraceScratch _traceScratch = new(); |
| | | 36 | | |
| | | 37 | | private PhysicsLayerMask _currentLayerMask; |
| | | 38 | | private LSCollider? _currentExcludedCollider; |
| | | 39 | | private LSCollider? _currentSweepSourceCollider; |
| | | 40 | | private bool _currentStaticSweepTargetsOnly; |
| | | 41 | | private bool _currentIncludeTriggers; |
| | | 42 | | |
| | | 43 | | /// <summary> |
| | | 44 | | /// Initializes a new raycast service for the supplied context. |
| | | 45 | | /// </summary> |
| | | 46 | | /// <param name="context">The owning world context.</param> |
| | 5083 | 47 | | public GravitasQuery3DService(GravitasWorldContext context) |
| | | 48 | | { |
| | 5083 | 49 | | SwiftThrowHelper.ThrowIfNull(context, nameof(context)); |
| | 5083 | 50 | | _context = context; |
| | 5083 | 51 | | } |
| | | 52 | | |
| | | 53 | | /// <summary> |
| | | 54 | | /// Gets the owning world context. |
| | | 55 | | /// </summary> |
| | 1 | 56 | | public GravitasWorldContext Context => _context; |
| | | 57 | | |
| | | 58 | | /// <summary> |
| | | 59 | | /// Gets the context-local raycast/sweep query version. |
| | | 60 | | /// </summary> |
| | | 61 | | public uint RaycastVersion { get; internal set; } |
| | | 62 | | |
| | | 63 | | /// <summary> |
| | | 64 | | /// Gets the context-local partition-traversed sphere/cone deduplication version. |
| | | 65 | | /// </summary> |
| | | 66 | | public uint CircleVersion { get; internal set; } |
| | | 67 | | |
| | | 68 | | internal int LastQueryCandidateCount { get; private set; } |
| | | 69 | | |
| | | 70 | | internal int LastMeshTriangleCandidateCount { get; private set; } |
| | | 71 | | |
| | | 72 | | /// <summary> |
| | | 73 | | /// Resets context-local raycast query buffers. |
| | | 74 | | /// </summary> |
| | | 75 | | public void Reset() |
| | | 76 | | { |
| | 32 | 77 | | ResetColliderRaycastVersions(); |
| | 32 | 78 | | ResetColliderCircleVersions(); |
| | 32 | 79 | | RaycastVersion = 0; |
| | 32 | 80 | | CircleVersion = 0; |
| | 32 | 81 | | ResetLastQueryCounters(); |
| | 32 | 82 | | ResetBatchCounters(0); |
| | 32 | 83 | | _bufferIntersectionPoints.FastClear(); |
| | 32 | 84 | | _meshTriangleCandidates.FastClear(); |
| | 32 | 85 | | _planarCircleCandidates.FastClear(); |
| | 32 | 86 | | _batch3DHits.FastClear(); |
| | 32 | 87 | | _redundantColliderCheck.Clear(); |
| | 32 | 88 | | _redundantVoxelCheck.Clear(); |
| | 32 | 89 | | _coveredVoxels.FastClear(); |
| | 32 | 90 | | _traceScratch.Clear(); |
| | 32 | 91 | | } |
| | | 92 | | |
| | | 93 | | /// <summary> |
| | | 94 | | /// Performs a raycast from an origin in a direction up to a maximum distance. |
| | | 95 | | /// </summary> |
| | | 96 | | public bool Raycast( |
| | | 97 | | Vector3d origin, |
| | | 98 | | Vector3d direction, |
| | | 99 | | Fixed64 maxDistance, |
| | | 100 | | out Physics3DHit raycastHit, |
| | | 101 | | PhysicsLayerMask layerMask) |
| | | 102 | | { |
| | 25 | 103 | | _currentLayerMask = layerMask; |
| | 25 | 104 | | if (direction == Vector3d.Zero || maxDistance <= Fixed64.Zero) |
| | | 105 | | { |
| | 3 | 106 | | ResetLastQueryCounters(); |
| | 3 | 107 | | raycastHit = default; |
| | 3 | 108 | | return false; |
| | | 109 | | } |
| | | 110 | | |
| | 22 | 111 | | Vector3d rayDirection = direction.Normalized; |
| | 22 | 112 | | Vector3d requestedDisplacement = rayDirection * maxDistance; |
| | 22 | 113 | | if (!Vector3d.TryAdd(origin, requestedDisplacement, out Vector3d end)) |
| | | 114 | | { |
| | 1 | 115 | | ResetLastQueryCounters(); |
| | 1 | 116 | | raycastHit = default; |
| | 1 | 117 | | return false; |
| | | 118 | | } |
| | | 119 | | |
| | 21 | 120 | | BeginRaycastTrace(origin, end); |
| | 21 | 121 | | bool hit = TryFindClosestHit(origin, end, rayDirection, out raycastHit); |
| | 21 | 122 | | _context.Diagnostics.EmitRayQuery( |
| | 21 | 123 | | origin, |
| | 21 | 124 | | end, |
| | 21 | 125 | | Fixed64.Zero, |
| | 21 | 126 | | layerMask.Bits, |
| | 21 | 127 | | hit, |
| | 21 | 128 | | hit ? 1 : 0, |
| | 21 | 129 | | raycastHit); |
| | 21 | 130 | | return hit; |
| | | 131 | | } |
| | | 132 | | |
| | | 133 | | /// <summary> |
| | | 134 | | /// Executes a raycast between two points and writes hits from closest to farthest into caller-owned storage. |
| | | 135 | | /// </summary> |
| | | 136 | | public int RaycastAll( |
| | | 137 | | Vector3d start3d, |
| | | 138 | | Vector3d end3d, |
| | | 139 | | PhysicsLayerMask layerMask, |
| | | 140 | | SwiftList<Physics3DHit> results) |
| | | 141 | | { |
| | 1084 | 142 | | SwiftThrowHelper.ThrowIfNull(results, nameof(results)); |
| | | 143 | | |
| | 1084 | 144 | | _currentLayerMask = layerMask; |
| | 1084 | 145 | | results.FastClear(); |
| | | 146 | | |
| | 1084 | 147 | | if (!Vector3d.TrySubtract(end3d, start3d, out Vector3d segment) |
| | 1084 | 148 | | || !Vector3d.TryGetMagnitude(segment, out Fixed64 segmentLength) |
| | 1084 | 149 | | || segmentLength == Fixed64.Zero) |
| | | 150 | | { |
| | 75 | 151 | | ResetLastQueryCounters(); |
| | 75 | 152 | | return 0; |
| | | 153 | | } |
| | | 154 | | |
| | 1009 | 155 | | BeginRaycastTrace(start3d, end3d); |
| | 1009 | 156 | | AddAllHits(start3d, end3d, segment.Normalized, results); |
| | 1009 | 157 | | Physics3DHitSorter.SortByDistance(results); |
| | 1009 | 158 | | _context.Diagnostics.EmitRayQuery( |
| | 1009 | 159 | | start3d, |
| | 1009 | 160 | | end3d, |
| | 1009 | 161 | | Fixed64.Zero, |
| | 1009 | 162 | | layerMask.Bits, |
| | 1009 | 163 | | results.Count > 0, |
| | 1009 | 164 | | results.Count, |
| | 1009 | 165 | | results.Count > 0 ? results[0] : default); |
| | 1009 | 166 | | return results.Count; |
| | | 167 | | } |
| | | 168 | | |
| | | 169 | | /// <summary> |
| | | 170 | | /// Sweeps a sphere from an origin in a direction up to a maximum distance and returns the closest hit. |
| | | 171 | | /// </summary> |
| | | 172 | | public bool SweepSphere( |
| | | 173 | | Vector3d origin, |
| | | 174 | | Fixed64 radius, |
| | | 175 | | Vector3d direction, |
| | | 176 | | Fixed64 maxDistance, |
| | | 177 | | out Physics3DHit sweepHit, |
| | | 178 | | PhysicsLayerMask layerMask, |
| | | 179 | | LSCollider? excludedCollider = null) |
| | | 180 | | { |
| | 22 | 181 | | if (direction == Vector3d.Zero || maxDistance <= Fixed64.Zero) |
| | | 182 | | { |
| | 3 | 183 | | ResetLastQueryCounters(); |
| | 3 | 184 | | sweepHit = default; |
| | 3 | 185 | | return false; |
| | | 186 | | } |
| | | 187 | | |
| | 19 | 188 | | Vector3d sweepDirection = direction.Normalized; |
| | 19 | 189 | | Vector3d requestedDisplacement = sweepDirection * maxDistance; |
| | 19 | 190 | | if (!Vector3d.TryAdd(origin, requestedDisplacement, out Vector3d end)) |
| | | 191 | | { |
| | 1 | 192 | | ResetLastQueryCounters(); |
| | 1 | 193 | | sweepHit = default; |
| | 1 | 194 | | return false; |
| | | 195 | | } |
| | 18 | 196 | | bool hit = SweepSphere(origin, end, radius, layerMask, excludedCollider, out sweepHit); |
| | 18 | 197 | | _context.Diagnostics.EmitRayQuery( |
| | 18 | 198 | | origin, |
| | 18 | 199 | | end, |
| | 18 | 200 | | radius, |
| | 18 | 201 | | layerMask.Bits, |
| | 18 | 202 | | hit, |
| | 18 | 203 | | hit ? 1 : 0, |
| | 18 | 204 | | sweepHit); |
| | 18 | 205 | | return hit; |
| | | 206 | | } |
| | | 207 | | |
| | | 208 | | /// <summary> |
| | | 209 | | /// Sweeps a sphere between two points and writes hits from closest to farthest into caller-owned storage. |
| | | 210 | | /// </summary> |
| | | 211 | | public int SweepSphereAll( |
| | | 212 | | Vector3d start3d, |
| | | 213 | | Vector3d end3d, |
| | | 214 | | Fixed64 radius, |
| | | 215 | | PhysicsLayerMask layerMask, |
| | | 216 | | SwiftList<Physics3DHit> results, |
| | | 217 | | LSCollider? excludedCollider = null) |
| | | 218 | | { |
| | 7909 | 219 | | return SweepSphereAllCore( |
| | 7909 | 220 | | start3d, |
| | 7909 | 221 | | end3d, |
| | 7909 | 222 | | radius, |
| | 7909 | 223 | | layerMask, |
| | 7909 | 224 | | results, |
| | 7909 | 225 | | excludedCollider, |
| | 7909 | 226 | | includeTriggers: true, |
| | 7909 | 227 | | staticTargetsOnly: false); |
| | | 228 | | } |
| | | 229 | | |
| | | 230 | | internal int SweepSphereAgainstStaticAll( |
| | | 231 | | Vector3d start3d, |
| | | 232 | | Vector3d end3d, |
| | | 233 | | Fixed64 radius, |
| | | 234 | | PhysicsLayerMask layerMask, |
| | | 235 | | SwiftList<Physics3DHit> results, |
| | | 236 | | LSCollider? excludedCollider = null, |
| | | 237 | | bool includeTriggers = true) |
| | | 238 | | { |
| | 6565 | 239 | | return SweepSphereAllCore( |
| | 6565 | 240 | | start3d, |
| | 6565 | 241 | | end3d, |
| | 6565 | 242 | | radius, |
| | 6565 | 243 | | layerMask, |
| | 6565 | 244 | | results, |
| | 6565 | 245 | | excludedCollider, |
| | 6565 | 246 | | includeTriggers, |
| | 6565 | 247 | | staticTargetsOnly: true); |
| | | 248 | | } |
| | | 249 | | |
| | | 250 | | internal int SweepExactSourceAgainstStaticAll( |
| | | 251 | | LSCollider source, |
| | | 252 | | Vector3d displacement, |
| | | 253 | | PhysicsLayerMask layerMask, |
| | | 254 | | SwiftList<Physics3DHit> results, |
| | | 255 | | LSCollider? excludedCollider = null, |
| | | 256 | | bool includeTriggers = true) |
| | | 257 | | { |
| | 106 | 258 | | SwiftThrowHelper.ThrowIfNull(source, nameof(source)); |
| | 106 | 259 | | SwiftThrowHelper.ThrowIfNull(results, nameof(results)); |
| | 106 | 260 | | EnsureSourceBelongsToContext(source); |
| | 106 | 261 | | PrepareConvexSweepSource(source, displacement); |
| | 106 | 262 | | return SweepPreparedConvexSourceAll( |
| | 106 | 263 | | source, |
| | 106 | 264 | | displacement, |
| | 106 | 265 | | layerMask, |
| | 106 | 266 | | results, |
| | 106 | 267 | | excludedCollider, |
| | 106 | 268 | | includeTriggers, |
| | 106 | 269 | | staticTargetsOnly: true); |
| | | 270 | | } |
| | | 271 | | |
| | | 272 | | /// <summary> |
| | | 273 | | /// Sweeps a capsule source by <paramref name="displacement"/> and returns the closest 3D target hit. |
| | | 274 | | /// </summary> |
| | | 275 | | public bool SweepCapsule( |
| | | 276 | | LSCapsuleCollider source, |
| | | 277 | | Vector3d displacement, |
| | | 278 | | PhysicsLayerMask layerMask, |
| | | 279 | | out Physics3DHit sweepHit, |
| | | 280 | | LSCollider? excludedCollider = null, |
| | | 281 | | bool includeTriggers = true) |
| | | 282 | | { |
| | 1 | 283 | | SwiftThrowHelper.ThrowIfNull(source, nameof(source)); |
| | 1 | 284 | | return SweepPrimitiveSource(source, displacement, layerMask, out sweepHit, excludedCollider, includeTriggers); |
| | | 285 | | } |
| | | 286 | | |
| | | 287 | | /// <summary> |
| | | 288 | | /// Writes all 3D targets hit by sweeping a capsule source into caller-owned storage. |
| | | 289 | | /// </summary> |
| | | 290 | | public int SweepCapsuleAll( |
| | | 291 | | LSCapsuleCollider source, |
| | | 292 | | Vector3d displacement, |
| | | 293 | | PhysicsLayerMask layerMask, |
| | | 294 | | SwiftList<Physics3DHit> results, |
| | | 295 | | LSCollider? excludedCollider = null, |
| | | 296 | | bool includeTriggers = true) |
| | | 297 | | { |
| | 1 | 298 | | SwiftThrowHelper.ThrowIfNull(source, nameof(source)); |
| | 1 | 299 | | SwiftThrowHelper.ThrowIfNull(results, nameof(results)); |
| | 1 | 300 | | return SweepPrimitiveSourceAll(source, displacement, layerMask, results, excludedCollider, includeTriggers); |
| | | 301 | | } |
| | | 302 | | |
| | | 303 | | /// <summary> |
| | | 304 | | /// Sweeps a cuboid source by <paramref name="displacement"/> and returns the closest 3D target hit. |
| | | 305 | | /// </summary> |
| | | 306 | | public bool SweepCuboid( |
| | | 307 | | LSCuboidCollider source, |
| | | 308 | | Vector3d displacement, |
| | | 309 | | PhysicsLayerMask layerMask, |
| | | 310 | | out Physics3DHit sweepHit, |
| | | 311 | | LSCollider? excludedCollider = null, |
| | | 312 | | bool includeTriggers = true) |
| | | 313 | | { |
| | 6 | 314 | | SwiftThrowHelper.ThrowIfNull(source, nameof(source)); |
| | 6 | 315 | | return SweepPrimitiveSource(source, displacement, layerMask, out sweepHit, excludedCollider, includeTriggers); |
| | | 316 | | } |
| | | 317 | | |
| | | 318 | | /// <summary> |
| | | 319 | | /// Writes all 3D targets hit by sweeping a cuboid source into caller-owned storage. |
| | | 320 | | /// </summary> |
| | | 321 | | public int SweepCuboidAll( |
| | | 322 | | LSCuboidCollider source, |
| | | 323 | | Vector3d displacement, |
| | | 324 | | PhysicsLayerMask layerMask, |
| | | 325 | | SwiftList<Physics3DHit> results, |
| | | 326 | | LSCollider? excludedCollider = null, |
| | | 327 | | bool includeTriggers = true) |
| | | 328 | | { |
| | 4 | 329 | | SwiftThrowHelper.ThrowIfNull(source, nameof(source)); |
| | 4 | 330 | | SwiftThrowHelper.ThrowIfNull(results, nameof(results)); |
| | 4 | 331 | | return SweepPrimitiveSourceAll(source, displacement, layerMask, results, excludedCollider, includeTriggers); |
| | | 332 | | } |
| | | 333 | | |
| | | 334 | | /// <summary> |
| | | 335 | | /// Sweeps a finite-cylinder source by <paramref name="displacement"/> and returns the closest 3D target hit. |
| | | 336 | | /// </summary> |
| | | 337 | | public bool SweepCylinder( |
| | | 338 | | LSCylinderCollider source, |
| | | 339 | | Vector3d displacement, |
| | | 340 | | PhysicsLayerMask layerMask, |
| | | 341 | | out Physics3DHit sweepHit, |
| | | 342 | | LSCollider? excludedCollider = null, |
| | | 343 | | bool includeTriggers = true) |
| | | 344 | | { |
| | 1 | 345 | | SwiftThrowHelper.ThrowIfNull(source, nameof(source)); |
| | 1 | 346 | | return SweepPrimitiveSource(source, displacement, layerMask, out sweepHit, excludedCollider, includeTriggers); |
| | | 347 | | } |
| | | 348 | | |
| | | 349 | | /// <summary> |
| | | 350 | | /// Writes all 3D targets hit by sweeping a finite-cylinder source into caller-owned storage. |
| | | 351 | | /// </summary> |
| | | 352 | | public int SweepCylinderAll( |
| | | 353 | | LSCylinderCollider source, |
| | | 354 | | Vector3d displacement, |
| | | 355 | | PhysicsLayerMask layerMask, |
| | | 356 | | SwiftList<Physics3DHit> results, |
| | | 357 | | LSCollider? excludedCollider = null, |
| | | 358 | | bool includeTriggers = true) |
| | | 359 | | { |
| | 1 | 360 | | SwiftThrowHelper.ThrowIfNull(source, nameof(source)); |
| | 1 | 361 | | SwiftThrowHelper.ThrowIfNull(results, nameof(results)); |
| | 1 | 362 | | return SweepPrimitiveSourceAll(source, displacement, layerMask, results, excludedCollider, includeTriggers); |
| | | 363 | | } |
| | | 364 | | |
| | | 365 | | /// <summary> |
| | | 366 | | /// Sweeps a finite-cone source by <paramref name="displacement"/> and returns the closest 3D target hit. |
| | | 367 | | /// </summary> |
| | | 368 | | public bool SweepCone( |
| | | 369 | | LSConeCollider source, |
| | | 370 | | Vector3d displacement, |
| | | 371 | | PhysicsLayerMask layerMask, |
| | | 372 | | out Physics3DHit sweepHit, |
| | | 373 | | LSCollider? excludedCollider = null, |
| | | 374 | | bool includeTriggers = true) |
| | | 375 | | { |
| | 1 | 376 | | SwiftThrowHelper.ThrowIfNull(source, nameof(source)); |
| | 1 | 377 | | return SweepPrimitiveSource(source, displacement, layerMask, out sweepHit, excludedCollider, includeTriggers); |
| | | 378 | | } |
| | | 379 | | |
| | | 380 | | /// <summary> |
| | | 381 | | /// Writes all 3D targets hit by sweeping a finite-cone source into caller-owned storage. |
| | | 382 | | /// </summary> |
| | | 383 | | public int SweepConeAll( |
| | | 384 | | LSConeCollider source, |
| | | 385 | | Vector3d displacement, |
| | | 386 | | PhysicsLayerMask layerMask, |
| | | 387 | | SwiftList<Physics3DHit> results, |
| | | 388 | | LSCollider? excludedCollider = null, |
| | | 389 | | bool includeTriggers = true) |
| | | 390 | | { |
| | 1 | 391 | | SwiftThrowHelper.ThrowIfNull(source, nameof(source)); |
| | 1 | 392 | | SwiftThrowHelper.ThrowIfNull(results, nameof(results)); |
| | 1 | 393 | | return SweepPrimitiveSourceAll(source, displacement, layerMask, results, excludedCollider, includeTriggers); |
| | | 394 | | } |
| | | 395 | | |
| | | 396 | | /// <summary> |
| | | 397 | | /// Sweeps a convex mesh source by <paramref name="displacement"/> and returns the closest 3D target hit. |
| | | 398 | | /// </summary> |
| | | 399 | | public bool SweepConvexMesh( |
| | | 400 | | LSMeshCollider source, |
| | | 401 | | Vector3d displacement, |
| | | 402 | | PhysicsLayerMask layerMask, |
| | | 403 | | out Physics3DHit sweepHit, |
| | | 404 | | LSCollider? excludedCollider = null, |
| | | 405 | | bool includeTriggers = true) |
| | | 406 | | { |
| | 11 | 407 | | SwiftThrowHelper.ThrowIfNull(source, nameof(source)); |
| | 11 | 408 | | return SweepConvexMeshSource(source, displacement, layerMask, out sweepHit, excludedCollider, includeTriggers); |
| | | 409 | | } |
| | | 410 | | |
| | | 411 | | /// <summary> |
| | | 412 | | /// Writes all 3D targets hit by sweeping a convex mesh source into caller-owned storage. |
| | | 413 | | /// </summary> |
| | | 414 | | public int SweepConvexMeshAll( |
| | | 415 | | LSMeshCollider source, |
| | | 416 | | Vector3d displacement, |
| | | 417 | | PhysicsLayerMask layerMask, |
| | | 418 | | SwiftList<Physics3DHit> results, |
| | | 419 | | LSCollider? excludedCollider = null, |
| | | 420 | | bool includeTriggers = true) |
| | | 421 | | { |
| | 2 | 422 | | SwiftThrowHelper.ThrowIfNull(source, nameof(source)); |
| | 2 | 423 | | SwiftThrowHelper.ThrowIfNull(results, nameof(results)); |
| | 2 | 424 | | return SweepConvexMeshSourceAll(source, displacement, layerMask, results, excludedCollider, includeTriggers); |
| | | 425 | | } |
| | | 426 | | |
| | | 427 | | /// <summary> |
| | | 428 | | /// Sweeps an authored compound source by <paramref name="displacement"/> and returns the closest 3D target hit. |
| | | 429 | | /// </summary> |
| | | 430 | | public bool SweepCompound( |
| | | 431 | | LSCompoundCollider source, |
| | | 432 | | Vector3d displacement, |
| | | 433 | | PhysicsLayerMask layerMask, |
| | | 434 | | out Physics3DHit sweepHit, |
| | | 435 | | LSCollider? excludedCollider = null, |
| | | 436 | | bool includeTriggers = true) |
| | | 437 | | { |
| | 1 | 438 | | SwiftThrowHelper.ThrowIfNull(source, nameof(source)); |
| | 1 | 439 | | return SweepCompoundSource(source, displacement, layerMask, out sweepHit, excludedCollider, includeTriggers); |
| | | 440 | | } |
| | | 441 | | |
| | | 442 | | /// <summary> |
| | | 443 | | /// Writes all 3D targets hit by sweeping an authored compound source into caller-owned storage. |
| | | 444 | | /// </summary> |
| | | 445 | | public int SweepCompoundAll( |
| | | 446 | | LSCompoundCollider source, |
| | | 447 | | Vector3d displacement, |
| | | 448 | | PhysicsLayerMask layerMask, |
| | | 449 | | SwiftList<Physics3DHit> results, |
| | | 450 | | LSCollider? excludedCollider = null, |
| | | 451 | | bool includeTriggers = true) |
| | | 452 | | { |
| | 1 | 453 | | SwiftThrowHelper.ThrowIfNull(source, nameof(source)); |
| | 1 | 454 | | SwiftThrowHelper.ThrowIfNull(results, nameof(results)); |
| | 1 | 455 | | return SweepCompoundSourceAll(source, displacement, layerMask, results, excludedCollider, includeTriggers); |
| | | 456 | | } |
| | | 457 | | |
| | | 458 | | private bool SweepPrimitiveSource( |
| | | 459 | | LSCollider source, |
| | | 460 | | Vector3d displacement, |
| | | 461 | | PhysicsLayerMask layerMask, |
| | | 462 | | out Physics3DHit sweepHit, |
| | | 463 | | LSCollider? excludedCollider, |
| | | 464 | | bool includeTriggers) |
| | | 465 | | { |
| | 9 | 466 | | EnsureSourceBelongsToContext(source); |
| | 9 | 467 | | _convexSweepWorker.PreparePrimitiveSource(source, displacement); |
| | 9 | 468 | | return SweepPreparedConvexSource(source, displacement, layerMask, out sweepHit, excludedCollider, includeTrigger |
| | | 469 | | } |
| | | 470 | | |
| | | 471 | | private int SweepPrimitiveSourceAll( |
| | | 472 | | LSCollider source, |
| | | 473 | | Vector3d displacement, |
| | | 474 | | PhysicsLayerMask layerMask, |
| | | 475 | | SwiftList<Physics3DHit> results, |
| | | 476 | | LSCollider? excludedCollider, |
| | | 477 | | bool includeTriggers) |
| | | 478 | | { |
| | 7 | 479 | | EnsureSourceBelongsToContext(source); |
| | 7 | 480 | | _convexSweepWorker.PreparePrimitiveSource(source, displacement); |
| | 7 | 481 | | return SweepPreparedConvexSourceAll(source, displacement, layerMask, results, excludedCollider, includeTriggers) |
| | | 482 | | } |
| | | 483 | | |
| | | 484 | | private bool SweepConvexMeshSource( |
| | | 485 | | LSMeshCollider source, |
| | | 486 | | Vector3d displacement, |
| | | 487 | | PhysicsLayerMask layerMask, |
| | | 488 | | out Physics3DHit sweepHit, |
| | | 489 | | LSCollider? excludedCollider, |
| | | 490 | | bool includeTriggers) |
| | | 491 | | { |
| | 11 | 492 | | EnsureSourceBelongsToContext(source); |
| | 11 | 493 | | _convexSweepWorker.PrepareConvexMeshSource(source, displacement); |
| | 10 | 494 | | return SweepPreparedConvexSource(source, displacement, layerMask, out sweepHit, excludedCollider, includeTrigger |
| | | 495 | | } |
| | | 496 | | |
| | | 497 | | private int SweepConvexMeshSourceAll( |
| | | 498 | | LSMeshCollider source, |
| | | 499 | | Vector3d displacement, |
| | | 500 | | PhysicsLayerMask layerMask, |
| | | 501 | | SwiftList<Physics3DHit> results, |
| | | 502 | | LSCollider? excludedCollider, |
| | | 503 | | bool includeTriggers) |
| | | 504 | | { |
| | 2 | 505 | | EnsureSourceBelongsToContext(source); |
| | 2 | 506 | | _convexSweepWorker.PrepareConvexMeshSource(source, displacement); |
| | 2 | 507 | | return SweepPreparedConvexSourceAll(source, displacement, layerMask, results, excludedCollider, includeTriggers) |
| | | 508 | | } |
| | | 509 | | |
| | | 510 | | private bool SweepCompoundSource( |
| | | 511 | | LSCompoundCollider source, |
| | | 512 | | Vector3d displacement, |
| | | 513 | | PhysicsLayerMask layerMask, |
| | | 514 | | out Physics3DHit sweepHit, |
| | | 515 | | LSCollider? excludedCollider, |
| | | 516 | | bool includeTriggers) |
| | | 517 | | { |
| | 1 | 518 | | EnsureSourceBelongsToContext(source); |
| | 1 | 519 | | _convexSweepWorker.PrepareCompoundSource(source, displacement); |
| | 1 | 520 | | return SweepPreparedConvexSource(source, displacement, layerMask, out sweepHit, excludedCollider, includeTrigger |
| | | 521 | | } |
| | | 522 | | |
| | | 523 | | private int SweepCompoundSourceAll( |
| | | 524 | | LSCompoundCollider source, |
| | | 525 | | Vector3d displacement, |
| | | 526 | | PhysicsLayerMask layerMask, |
| | | 527 | | SwiftList<Physics3DHit> results, |
| | | 528 | | LSCollider? excludedCollider, |
| | | 529 | | bool includeTriggers) |
| | | 530 | | { |
| | 1 | 531 | | EnsureSourceBelongsToContext(source); |
| | 1 | 532 | | _convexSweepWorker.PrepareCompoundSource(source, displacement); |
| | 1 | 533 | | return SweepPreparedConvexSourceAll(source, displacement, layerMask, results, excludedCollider, includeTriggers) |
| | | 534 | | } |
| | | 535 | | |
| | | 536 | | private int SweepSphereAllCore( |
| | | 537 | | Vector3d start3d, |
| | | 538 | | Vector3d end3d, |
| | | 539 | | Fixed64 radius, |
| | | 540 | | PhysicsLayerMask layerMask, |
| | | 541 | | SwiftList<Physics3DHit> results, |
| | | 542 | | LSCollider? excludedCollider, |
| | | 543 | | bool includeTriggers, |
| | | 544 | | bool staticTargetsOnly) |
| | | 545 | | { |
| | 14474 | 546 | | SwiftThrowHelper.ThrowIfNull(results, nameof(results)); |
| | | 547 | | |
| | 14474 | 548 | | results.FastClear(); |
| | 14474 | 549 | | if (!Vector3d.TrySubtract(end3d, start3d, out Vector3d segment) |
| | 14474 | 550 | | || !Vector3d.TryGetMagnitude(segment, out Fixed64 segmentLength) |
| | 14474 | 551 | | || segmentLength <= Fixed64.Epsilon |
| | 14474 | 552 | | || radius <= Fixed64.Zero) |
| | | 553 | | { |
| | 116 | 554 | | ResetLastQueryCounters(); |
| | 116 | 555 | | return 0; |
| | | 556 | | } |
| | | 557 | | |
| | 14358 | 558 | | BeginSweepTrace(start3d, end3d, radius, layerMask, excludedCollider, includeTriggers, staticTargetsOnly); |
| | 14358 | 559 | | AddAllSweepHits(start3d, end3d, segment.Normalized, radius, results); |
| | 14358 | 560 | | Physics3DHitSorter.SortByDistance(results); |
| | 14358 | 561 | | _context.Diagnostics.EmitRayQuery( |
| | 14358 | 562 | | start3d, |
| | 14358 | 563 | | end3d, |
| | 14358 | 564 | | radius, |
| | 14358 | 565 | | layerMask.Bits, |
| | 14358 | 566 | | results.Count > 0, |
| | 14358 | 567 | | results.Count, |
| | 14358 | 568 | | results.Count > 0 ? results[0] : default); |
| | 14358 | 569 | | return results.Count; |
| | | 570 | | } |
| | | 571 | | |
| | | 572 | | private bool SweepPreparedConvexSource( |
| | | 573 | | LSCollider source, |
| | | 574 | | Vector3d displacement, |
| | | 575 | | PhysicsLayerMask layerMask, |
| | | 576 | | out Physics3DHit sweepHit, |
| | | 577 | | LSCollider? excludedCollider, |
| | | 578 | | bool includeTriggers) |
| | | 579 | | { |
| | 20 | 580 | | sweepHit = default; |
| | 20 | 581 | | if (!Vector3d.TryGetMagnitude(displacement, out Fixed64 displacementLength) |
| | 20 | 582 | | || displacementLength <= Fixed64.Epsilon) |
| | | 583 | | { |
| | 2 | 584 | | ResetLastQueryCounters(); |
| | 2 | 585 | | return false; |
| | | 586 | | } |
| | | 587 | | |
| | 18 | 588 | | BeginConvexSweepTrace(source, layerMask, excludedCollider, includeTriggers); |
| | 18 | 589 | | bool hit = TryFindClosestConvexSweepHit(source, displacement, out sweepHit); |
| | 18 | 590 | | _context.Diagnostics.EmitRayQuery( |
| | 18 | 591 | | source.Center, |
| | 18 | 592 | | source.Center + displacement, |
| | 18 | 593 | | source.ScaledRadius, |
| | 18 | 594 | | layerMask.Bits, |
| | 18 | 595 | | hit, |
| | 18 | 596 | | hit ? 1 : 0, |
| | 18 | 597 | | sweepHit); |
| | 18 | 598 | | return hit; |
| | | 599 | | } |
| | | 600 | | |
| | | 601 | | private int SweepPreparedConvexSourceAll( |
| | | 602 | | LSCollider source, |
| | | 603 | | Vector3d displacement, |
| | | 604 | | PhysicsLayerMask layerMask, |
| | | 605 | | SwiftList<Physics3DHit> results, |
| | | 606 | | LSCollider? excludedCollider, |
| | | 607 | | bool includeTriggers, |
| | | 608 | | bool staticTargetsOnly = false) |
| | | 609 | | { |
| | 116 | 610 | | results.FastClear(); |
| | 116 | 611 | | if (!Vector3d.TryGetMagnitude(displacement, out Fixed64 displacementLength) |
| | 116 | 612 | | || displacementLength <= Fixed64.Epsilon) |
| | | 613 | | { |
| | 2 | 614 | | ResetLastQueryCounters(); |
| | 2 | 615 | | return 0; |
| | | 616 | | } |
| | | 617 | | |
| | 114 | 618 | | BeginConvexSweepTrace(source, layerMask, excludedCollider, includeTriggers, staticTargetsOnly); |
| | 114 | 619 | | AddAllConvexSweepHits(source, displacement, results); |
| | 114 | 620 | | Physics3DHitSorter.SortByDistance(results); |
| | 114 | 621 | | _context.Diagnostics.EmitRayQuery( |
| | 114 | 622 | | source.Center, |
| | 114 | 623 | | source.Center + displacement, |
| | 114 | 624 | | source.ScaledRadius, |
| | 114 | 625 | | layerMask.Bits, |
| | 114 | 626 | | results.Count > 0, |
| | 114 | 627 | | results.Count, |
| | 114 | 628 | | results.Count > 0 ? results[0] : default); |
| | 114 | 629 | | return results.Count; |
| | | 630 | | } |
| | | 631 | | |
| | | 632 | | private void BeginConvexSweepTrace( |
| | | 633 | | LSCollider source, |
| | | 634 | | PhysicsLayerMask layerMask, |
| | | 635 | | LSCollider? excludedCollider, |
| | | 636 | | bool includeTriggers, |
| | | 637 | | bool staticTargetsOnly = false) |
| | | 638 | | { |
| | 148 | 639 | | _currentLayerMask = layerMask; |
| | 148 | 640 | | _currentExcludedCollider = excludedCollider; |
| | 148 | 641 | | _currentSweepSourceCollider = source; |
| | 148 | 642 | | _currentIncludeTriggers = includeTriggers; |
| | 148 | 643 | | _currentStaticSweepTargetsOnly = staticTargetsOnly; |
| | 148 | 644 | | _redundantColliderCheck.Clear(); |
| | 148 | 645 | | _redundantVoxelCheck.Clear(); |
| | 148 | 646 | | ResetLastQueryCounters(); |
| | 148 | 647 | | NextRaycastVersion(); |
| | 148 | 648 | | } |
| | | 649 | | |
| | | 650 | | private void BeginRaycastTrace(Vector3d start, Vector3d end) |
| | | 651 | | { |
| | 1869 | 652 | | _redundantColliderCheck.Clear(); |
| | 1869 | 653 | | _redundantVoxelCheck.Clear(); |
| | 1869 | 654 | | _bufferIntersectionPoints.FastClear(); |
| | 1869 | 655 | | _currentExcludedCollider = null; |
| | 1869 | 656 | | _currentSweepSourceCollider = null; |
| | 1869 | 657 | | _currentStaticSweepTargetsOnly = false; |
| | 1869 | 658 | | _currentIncludeTriggers = true; |
| | 1869 | 659 | | ResetLastQueryCounters(); |
| | 1869 | 660 | | NextRaycastVersion(); |
| | 1869 | 661 | | _worker.PrepareSegmentCheck(start, end); |
| | 1869 | 662 | | } |
| | | 663 | | |
| | | 664 | | private void BeginSweepTrace( |
| | | 665 | | Vector3d start, |
| | | 666 | | Vector3d end, |
| | | 667 | | Fixed64 radius, |
| | | 668 | | PhysicsLayerMask layerMask, |
| | | 669 | | LSCollider? excludedCollider, |
| | | 670 | | bool includeTriggers = true, |
| | | 671 | | bool staticTargetsOnly = false) |
| | | 672 | | { |
| | 14379 | 673 | | _currentLayerMask = layerMask; |
| | 14379 | 674 | | _currentExcludedCollider = excludedCollider; |
| | 14379 | 675 | | _currentSweepSourceCollider = null; |
| | 14379 | 676 | | _currentIncludeTriggers = includeTriggers; |
| | 14379 | 677 | | _currentStaticSweepTargetsOnly = staticTargetsOnly; |
| | 14379 | 678 | | _redundantColliderCheck.Clear(); |
| | 14379 | 679 | | _redundantVoxelCheck.Clear(); |
| | 14379 | 680 | | ResetLastQueryCounters(); |
| | 14379 | 681 | | NextRaycastVersion(); |
| | 14379 | 682 | | _sweepWorker.Prepare(start, end, radius); |
| | 14379 | 683 | | } |
| | | 684 | | |
| | | 685 | | private bool SweepSphere( |
| | | 686 | | Vector3d start, |
| | | 687 | | Vector3d end, |
| | | 688 | | Fixed64 radius, |
| | | 689 | | PhysicsLayerMask layerMask, |
| | | 690 | | LSCollider? excludedCollider, |
| | | 691 | | out Physics3DHit sweepHit) |
| | | 692 | | { |
| | 25 | 693 | | sweepHit = default; |
| | 25 | 694 | | if (radius <= Fixed64.Zero) |
| | | 695 | | { |
| | 2 | 696 | | ResetLastQueryCounters(); |
| | 2 | 697 | | return false; |
| | | 698 | | } |
| | | 699 | | |
| | 23 | 700 | | if (!Vector3d.TrySubtract(end, start, out Vector3d segment) |
| | 23 | 701 | | || !Vector3d.TryGetMagnitude(segment, out Fixed64 segmentLength) |
| | 23 | 702 | | || segmentLength <= Fixed64.Epsilon) |
| | | 703 | | { |
| | 4 | 704 | | ResetLastQueryCounters(); |
| | 4 | 705 | | return false; |
| | | 706 | | } |
| | | 707 | | |
| | 19 | 708 | | Vector3d direction = segment.Normalized; |
| | 19 | 709 | | BeginSweepTrace(start, end, radius, layerMask, excludedCollider); |
| | 19 | 710 | | return TryFindClosestSweepHit(start, end, radius, direction, out sweepHit); |
| | | 711 | | } |
| | | 712 | | |
| | | 713 | | private bool TryFindClosestSweepHit( |
| | | 714 | | Vector3d start, |
| | | 715 | | Vector3d end, |
| | | 716 | | Fixed64 radius, |
| | | 717 | | Vector3d direction, |
| | | 718 | | out Physics3DHit sweepHit) |
| | | 719 | | { |
| | 19 | 720 | | bool found = false; |
| | 19 | 721 | | Physics3DHit closestHit = default; |
| | | 722 | | |
| | 19 | 723 | | TraceSweepForClosestHit(start, end, radius, direction, ref found, ref closestHit); |
| | | 724 | | |
| | 19 | 725 | | sweepHit = closestHit; |
| | 19 | 726 | | return found; |
| | | 727 | | } |
| | | 728 | | |
| | | 729 | | private bool TryFindClosestHit(Vector3d start, Vector3d end, Vector3d direction, out Physics3DHit raycastHit) |
| | | 730 | | { |
| | 439 | 731 | | bool found = false; |
| | 439 | 732 | | Physics3DHit closestHit = default; |
| | | 733 | | |
| | 439 | 734 | | TraceLineForClosestHit(start, end, direction, ref found, ref closestHit); |
| | | 735 | | |
| | 439 | 736 | | raycastHit = closestHit; |
| | 439 | 737 | | return found; |
| | | 738 | | } |
| | | 739 | | |
| | | 740 | | private void AddAllHits(Vector3d start, Vector3d end, Vector3d direction, SwiftList<Physics3DHit> results) |
| | | 741 | | { |
| | 1430 | 742 | | TraceLineForAllHits(start, end, direction, results); |
| | 1430 | 743 | | } |
| | | 744 | | |
| | | 745 | | private void AddAllSweepHits( |
| | | 746 | | Vector3d start, |
| | | 747 | | Vector3d end, |
| | | 748 | | Vector3d direction, |
| | | 749 | | Fixed64 radius, |
| | | 750 | | SwiftList<Physics3DHit> results) |
| | | 751 | | { |
| | 14360 | 752 | | TraceSweepForAllHits(start, end, radius, direction, results); |
| | 14360 | 753 | | } |
| | | 754 | | |
| | | 755 | | private bool TryFindClosestConvexSweepHit( |
| | | 756 | | LSCollider source, |
| | | 757 | | Vector3d displacement, |
| | | 758 | | out Physics3DHit sweepHit) |
| | | 759 | | { |
| | 26 | 760 | | bool found = false; |
| | 26 | 761 | | Physics3DHit closestHit = default; |
| | | 762 | | |
| | 26 | 763 | | TraceConvexSweepForClosestHit(source, displacement, ref found, ref closestHit); |
| | | 764 | | |
| | 26 | 765 | | sweepHit = closestHit; |
| | 26 | 766 | | return found; |
| | | 767 | | } |
| | | 768 | | |
| | | 769 | | private void AddAllConvexSweepHits( |
| | | 770 | | LSCollider source, |
| | | 771 | | Vector3d displacement, |
| | | 772 | | SwiftList<Physics3DHit> results) |
| | | 773 | | { |
| | 122 | 774 | | TraceConvexSweepForAllHits(source, displacement, results); |
| | 122 | 775 | | } |
| | | 776 | | |
| | | 777 | | private bool TryBuildHitForCollider( |
| | | 778 | | int colliderId, |
| | | 779 | | Vector3d origin, |
| | | 780 | | Vector3d direction, |
| | | 781 | | out Physics3DHit hit) |
| | | 782 | | { |
| | 4845 | 783 | | hit = default; |
| | 4845 | 784 | | return _context.Physics.TryGetColliderById(colliderId, out LSCollider? current) |
| | 4845 | 785 | | && DoesCurrentColliderIntersectRay(current!) |
| | 4845 | 786 | | && TryBuildHit(current!, origin, direction, out hit); |
| | | 787 | | } |
| | | 788 | | |
| | | 789 | | private bool TryBuildSweepHitForCollider( |
| | | 790 | | int colliderId, |
| | | 791 | | Vector3d origin, |
| | | 792 | | Vector3d direction, |
| | | 793 | | out Physics3DHit hit) |
| | | 794 | | { |
| | 583152 | 795 | | hit = default; |
| | 583152 | 796 | | return _context.Physics.TryGetColliderById(colliderId, out LSCollider? current) |
| | 583152 | 797 | | && IsSweepCandidate(current!) |
| | 583152 | 798 | | && TryBuildSweepHit(current!, origin, direction, out hit); |
| | | 799 | | } |
| | | 800 | | |
| | | 801 | | private bool TryBuildConvexSweepHitForCollider(int colliderId, out Physics3DHit hit) |
| | | 802 | | { |
| | 3399 | 803 | | hit = default; |
| | 3399 | 804 | | if (!_context.Physics.TryGetColliderById(colliderId, out LSCollider? current) |
| | 3399 | 805 | | || !IsSweepCandidate(current!)) |
| | | 806 | | { |
| | 3304 | 807 | | return false; |
| | | 808 | | } |
| | | 809 | | |
| | 95 | 810 | | bool found = _convexSweepWorker.TrySweepPreparedSource(current!, out hit); |
| | 95 | 811 | | LastMeshTriangleCandidateCount += _convexSweepWorker.LastMeshTriangleCandidateCount; |
| | 95 | 812 | | return found; |
| | | 813 | | } |
| | | 814 | | |
| | | 815 | | private bool TryBuildHit( |
| | | 816 | | LSCollider collider, |
| | | 817 | | Vector3d origin, |
| | | 818 | | Vector3d direction, |
| | | 819 | | out Physics3DHit raycastHit) |
| | | 820 | | { |
| | 2025 | 821 | | Fixed64 closestDistance = Fixed64.MaxValue; |
| | 2025 | 822 | | Vector3d closestIntersection = Vector3d.Zero; |
| | | 823 | | |
| | 10994 | 824 | | for (int i = _bufferIntersectionPoints.Count - 1; i >= 0; i--) |
| | | 825 | | { |
| | 3472 | 826 | | Fixed64 dist = Vector3d.Distance(_bufferIntersectionPoints[i], origin); |
| | 3472 | 827 | | if (dist < closestDistance) |
| | | 828 | | { |
| | 3470 | 829 | | closestDistance = dist; |
| | 3470 | 830 | | closestIntersection = _bufferIntersectionPoints[i]; |
| | | 831 | | } |
| | | 832 | | } |
| | | 833 | | |
| | 2025 | 834 | | if (closestDistance == Fixed64.MaxValue) |
| | | 835 | | { |
| | 2 | 836 | | raycastHit = default; |
| | 2 | 837 | | return false; |
| | | 838 | | } |
| | | 839 | | |
| | 2023 | 840 | | Vector3d normal = collider.GetNormalAtPoint(closestIntersection); |
| | 2023 | 841 | | raycastHit = new Physics3DHit(collider, closestIntersection, normal, closestDistance, direction); |
| | 2023 | 842 | | return true; |
| | | 843 | | } |
| | | 844 | | |
| | | 845 | | private bool TryBuildSweepHit( |
| | | 846 | | LSCollider collider, |
| | | 847 | | Vector3d origin, |
| | | 848 | | Vector3d direction, |
| | | 849 | | out Physics3DHit sweepHit) |
| | | 850 | | { |
| | 9122 | 851 | | sweepHit = default; |
| | 9122 | 852 | | bool found = _sweepWorker.TrySweep(collider, out Vector3d sweepCenter, out Fixed64 distance); |
| | 9122 | 853 | | LastMeshTriangleCandidateCount += _sweepWorker.LastMeshTriangleCandidateCount; |
| | 9122 | 854 | | if (!found) |
| | 1942 | 855 | | return false; |
| | | 856 | | |
| | 7180 | 857 | | if (!ContinuousCollisionContactPolicy.TryResolveSweptSphereContact( |
| | 7180 | 858 | | collider, |
| | 7180 | 859 | | sweepCenter, |
| | 7180 | 860 | | direction, |
| | 7180 | 861 | | out ContactAnchor anchor, |
| | 7180 | 862 | | out Vector3d normal)) |
| | | 863 | | { |
| | 1 | 864 | | return false; |
| | | 865 | | } |
| | | 866 | | |
| | 7179 | 867 | | sweepHit = new Physics3DHit(collider, anchor, normal, distance, direction); |
| | 7179 | 868 | | return true; |
| | | 869 | | } |
| | | 870 | | |
| | | 871 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 872 | | private void ResetLastQueryCounters() |
| | | 873 | | { |
| | 17287 | 874 | | LastQueryCandidateCount = 0; |
| | 17287 | 875 | | LastMeshTriangleCandidateCount = 0; |
| | 17287 | 876 | | } |
| | | 877 | | |
| | | 878 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 879 | | private uint NextRaycastVersion() |
| | | 880 | | { |
| | 16396 | 881 | | RaycastVersion++; |
| | 16396 | 882 | | if (RaycastVersion == 0) |
| | | 883 | | { |
| | 1 | 884 | | ResetColliderRaycastVersions(); |
| | 1 | 885 | | RaycastVersion = 1; |
| | | 886 | | } |
| | | 887 | | |
| | 16396 | 888 | | return RaycastVersion; |
| | | 889 | | } |
| | | 890 | | |
| | | 891 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 892 | | private uint NextCircleVersion() |
| | | 893 | | { |
| | 583 | 894 | | CircleVersion++; |
| | 583 | 895 | | if (CircleVersion == 0) |
| | | 896 | | { |
| | 1 | 897 | | ResetColliderCircleVersions(); |
| | 1 | 898 | | CircleVersion = 1; |
| | | 899 | | } |
| | | 900 | | |
| | 583 | 901 | | return CircleVersion; |
| | | 902 | | } |
| | | 903 | | |
| | | 904 | | private void ResetColliderRaycastVersions() |
| | | 905 | | { |
| | 70 | 906 | | for (int i = 0; i < _context.Physics.ColliderCount; i++) |
| | 2 | 907 | | _context.Physics.GetColliderByServiceIndex(i).RaycastVersion = 0; |
| | 33 | 908 | | } |
| | | 909 | | |
| | | 910 | | private void ResetColliderCircleVersions() |
| | | 911 | | { |
| | 70 | 912 | | for (int i = 0; i < _context.Physics.ColliderCount; i++) |
| | 2 | 913 | | _context.Physics.GetColliderByServiceIndex(i).CircleQueryVersion = 0; |
| | 33 | 914 | | } |
| | | 915 | | |
| | | 916 | | private bool DoesCurrentColliderIntersectRay(LSCollider current) |
| | | 917 | | { |
| | 4845 | 918 | | if (!_currentLayerMask.Includes(current.Layer) |
| | 4845 | 919 | | || current.RaycastVersion == RaycastVersion |
| | 4845 | 920 | | || !_redundantColliderCheck.Add(current.Id)) |
| | | 921 | | { |
| | 2729 | 922 | | return false; |
| | | 923 | | } |
| | | 924 | | |
| | 2116 | 925 | | current.RaycastVersion = RaycastVersion; |
| | 2116 | 926 | | _bufferIntersectionPoints.FastClear(); |
| | 2116 | 927 | | return current.ColliderOverlapsRay(_worker, ref _bufferIntersectionPoints); |
| | | 928 | | } |
| | | 929 | | |
| | | 930 | | private bool IsSweepCandidate(LSCollider current) |
| | | 931 | | { |
| | 586524 | 932 | | if (ReferenceEquals(current, _currentExcludedCollider) |
| | 586524 | 933 | | || ReferenceEquals(current, _currentSweepSourceCollider) |
| | 586524 | 934 | | || IsExcludedByCurrentSweepSource(current) |
| | 586524 | 935 | | || !_currentLayerMask.Includes(current.Layer) |
| | 586524 | 936 | | || current.RaycastVersion == RaycastVersion |
| | 586524 | 937 | | || !_redundantColliderCheck.Add(current.Id)) |
| | | 938 | | { |
| | 577304 | 939 | | return false; |
| | | 940 | | } |
| | | 941 | | |
| | 9220 | 942 | | if (!_currentIncludeTriggers && current.IsTrigger) |
| | 2 | 943 | | return false; |
| | | 944 | | |
| | 9218 | 945 | | if (_currentStaticSweepTargetsOnly && !IsStaticStyleSweepTarget(current)) |
| | 1 | 946 | | return false; |
| | | 947 | | |
| | 9217 | 948 | | current.RaycastVersion = RaycastVersion; |
| | 9217 | 949 | | LastQueryCandidateCount++; |
| | 9217 | 950 | | return true; |
| | | 951 | | } |
| | | 952 | | |
| | | 953 | | private bool IsExcludedByCurrentSweepSource(LSCollider current) |
| | | 954 | | { |
| | 237925 | 955 | | if (_currentSweepSourceCollider != null |
| | 237925 | 956 | | && _context.Constraints3D.ShouldExcludeLinkedCollision(_currentSweepSourceCollider, current)) |
| | | 957 | | { |
| | 27 | 958 | | return true; |
| | | 959 | | } |
| | | 960 | | |
| | 237898 | 961 | | return _currentExcludedCollider != null |
| | 237898 | 962 | | && _context.Constraints3D.ShouldExcludeLinkedCollision(_currentExcludedCollider, current); |
| | | 963 | | } |
| | | 964 | | |
| | | 965 | | private void EnsureSourceBelongsToContext(LSCollider source) |
| | | 966 | | { |
| | 165 | 967 | | SwiftThrowHelper.ThrowIfArgument( |
| | 165 | 968 | | !ReferenceEquals(source.Context, _context), |
| | 165 | 969 | | nameof(source), |
| | 165 | 970 | | "Sweep source collider must belong to this query service context."); |
| | 165 | 971 | | } |
| | | 972 | | |
| | | 973 | | private void PrepareConvexSweepSource(LSCollider source, Vector3d displacement) |
| | | 974 | | { |
| | | 975 | | switch (source) |
| | | 976 | | { |
| | | 977 | | case LSMeshCollider mesh: |
| | 8 | 978 | | _convexSweepWorker.PrepareConvexMeshSource(mesh, displacement); |
| | 8 | 979 | | return; |
| | | 980 | | case LSCompoundCollider compound: |
| | 7 | 981 | | _convexSweepWorker.PrepareCompoundSource(compound, displacement); |
| | 7 | 982 | | return; |
| | | 983 | | default: |
| | 117 | 984 | | _convexSweepWorker.PreparePrimitiveSource(source, displacement); |
| | 117 | 985 | | return; |
| | | 986 | | } |
| | | 987 | | } |
| | | 988 | | |
| | | 989 | | [MethodImpl(MethodImplOptions.AggressiveInlining)] |
| | | 990 | | private static bool IsStaticStyleSweepTarget(LSCollider collider) |
| | | 991 | | { |
| | 6470 | 992 | | SolidBody? body = collider.Body; |
| | 6470 | 993 | | return collider.IsStatic || body!.IsKinematic; |
| | | 994 | | } |
| | | 995 | | |
| | | 996 | | } |