/// <summary> /// A convex-shaped ray-trace method for the special case of needing to handle Voxel collision types. /// </summary> /// <param name="shape">The shape of the convex ray source object.</param> /// <param name="start">The start of the ray.</param> /// <param name="dir">The normalized vector of the direction of the ray.</param> /// <param name="len">The length of the ray.</param> /// <param name="considerSolid">What materials are 'solid'.</param> /// <param name="filter">A function to identify what entities should be filtered out.</param> /// <param name="rayHit">Outputs the result of the ray trace.</param> /// <returns>Whether there was a collision.</returns> public bool SpecialCaseConvexTrace(ConvexShape shape, Location start, Location dir, double len, MaterialSolidity considerSolid, Func <BroadPhaseEntry, bool> filter, out RayCastResult rayHit) { RigidTransform rt = new RigidTransform(start.ToBVector(), BEPUutilities.Quaternion.Identity); BEPUutilities.Vector3 sweep = (dir * len).ToBVector(); RayCastResult best = new RayCastResult(new RayHit() { T = len }, null); bool hA = false; if (considerSolid.HasFlag(MaterialSolidity.FULLSOLID)) { if (PhysicsWorld.ConvexCast(shape, ref rt, ref sweep, filter, out RayCastResult rcr)) { best = rcr; hA = true; } } if (considerSolid == MaterialSolidity.FULLSOLID) { rayHit = best; return(hA); } sweep = dir.ToBVector(); AABB box = new AABB() { Min = start, Max = start }; box.Include(start + dir * len); foreach (KeyValuePair <Vector3i, Chunk> chunk in LoadedChunks) { if (chunk.Value == null || chunk.Value.FCO == null) { continue; } if (!box.Intersects(new AABB() { Min = chunk.Value.WorldPosition.ToLocation() * Chunk.CHUNK_SIZE, Max = chunk.Value.WorldPosition.ToLocation() * Chunk.CHUNK_SIZE + new Location(Chunk.CHUNK_SIZE, Chunk.CHUNK_SIZE, Chunk.CHUNK_SIZE) })) { continue; } if (chunk.Value.FCO.ConvexCast(shape, ref rt, ref sweep, len, considerSolid, out RayHit temp)) { hA = true; if (temp.T < best.HitData.T) { best.HitData = temp; best.HitObject = chunk.Value.FCO; } } } rayHit = best; return(hA); }
/// <summary> /// A ray-trace method for the special case of needing to handle Voxel collision types. /// </summary> /// <param name="start">The start of the ray.</param> /// <param name="dir">The normalized vector of the direction of the ray.</param> /// <param name="len">The length of the ray.</param> /// <param name="considerSolid">What materials are 'solid'.</param> /// <param name="filter">A function to identify what entities should be filtered out.</param> /// <param name="rayHit">Outputs the result of the ray trace.</param> /// <returns>Whether there was a collision.</returns> public bool SpecialCaseRayTrace(Location start, Location dir, double len, MaterialSolidity considerSolid, Func <BroadPhaseEntry, bool> filter, out RayCastResult rayHit) { Ray ray = new Ray(start.ToBVector(), dir.ToBVector()); RayCastResult best = new RayCastResult(new RayHit() { T = len }, null); bool hA = false; if (considerSolid.HasFlag(MaterialSolidity.FULLSOLID)) { if (PhysicsWorld.RayCast(ray, len, filter, out RayCastResult rcr)) { best = rcr; hA = true; } } if (considerSolid == MaterialSolidity.FULLSOLID) { rayHit = best; return(hA); } AABB box = new AABB() { Min = start, Max = start }; box.Include(start + dir * len); foreach (Dictionary <Vector3i, Chunk> chkmap in LoadedChunks) { foreach (Chunk chunk in chkmap.Values) { if (chunk == null || chunk.FCO == null) { continue; } if (!box.Intersects(new AABB() { Min = chunk.WorldPosition.ToLocation() * Chunk.CHUNK_SIZE, Max = chunk.WorldPosition.ToLocation() * Chunk.CHUNK_SIZE + new Location(Chunk.CHUNK_SIZE, Chunk.CHUNK_SIZE, Chunk.CHUNK_SIZE) })) { continue; } if (chunk.FCO.RayCast(ray, len, null, considerSolid, out RayHit temp)) { hA = true; if (temp.T < best.HitData.T) { best.HitData = temp; best.HitObject = chunk.FCO; } } } } rayHit = best; return(hA); }
public bool SpecialCaseRayTrace(Location start, Location dir, float len, MaterialSolidity considerSolid, Func<BroadPhaseEntry, bool> filter, out RayCastResult rayHit) { Ray ray = new Ray(start.ToBVector(), dir.ToBVector()); RayCastResult best = new RayCastResult(new RayHit() { T = len }, null); bool hA = false; if (considerSolid.HasFlag(MaterialSolidity.FULLSOLID)) { RayCastResult rcr; if (PhysicsWorld.RayCast(ray, len, filter, out rcr)) { best = rcr; hA = true; } } AABB box = new AABB(); box.Min = start; box.Max = start; box.Include(start + dir * len); foreach (KeyValuePair<Vector3i, Chunk> chunk in LoadedChunks) { if (chunk.Value == null || chunk.Value.FCO == null) { continue; } if (!box.Intersects(new AABB() { Min = chunk.Value.WorldPosition.ToLocation() * Chunk.CHUNK_SIZE, Max = chunk.Value.WorldPosition.ToLocation() * Chunk.CHUNK_SIZE + new Location(Chunk.CHUNK_SIZE) })) { continue; } RayHit temp; if (chunk.Value.FCO.RayCast(ray, len, null, considerSolid, out temp)) { hA = true; //temp.T *= len; if (temp.T < best.HitData.T) { best.HitData = temp; best.HitObject = chunk.Value.FCO; } } } rayHit = best; return hA; }
public bool SpecialCaseConvexTrace(ConvexShape shape, Location start, Location dir, float len, MaterialSolidity considerSolid, Func<BroadPhaseEntry, bool> filter, out RayCastResult rayHit) { RigidTransform rt = new RigidTransform(start.ToBVector(), BEPUutilities.Quaternion.Identity); BEPUutilities.Vector3 sweep = (dir * len).ToBVector(); RayCastResult best = new RayCastResult(new RayHit() { T = len }, null); bool hA = false; if (considerSolid.HasFlag(MaterialSolidity.FULLSOLID)) { RayCastResult rcr; if (PhysicsWorld.ConvexCast(shape, ref rt, ref sweep, filter, out rcr)) { best = rcr; hA = true; } } sweep = dir.ToBVector(); AABB box = new AABB(); box.Min = start; box.Max = start; box.Include(start + dir * len); foreach (KeyValuePair<Vector3i, Chunk> chunk in LoadedChunks) { if (chunk.Value == null || chunk.Value.FCO == null) { continue; } if (!box.Intersects(new AABB() { Min = chunk.Value.WorldPosition.ToLocation() * Chunk.CHUNK_SIZE, Max = chunk.Value.WorldPosition.ToLocation() * Chunk.CHUNK_SIZE + new Location(Chunk.CHUNK_SIZE) })) { continue; } RayHit temp; if (chunk.Value.FCO.ConvexCast(shape, ref rt, ref sweep, len, considerSolid, out temp)) { hA = true; //temp.T *= len; if (temp.T < best.HitData.T) { best.HitData = temp; best.HitObject = chunk.Value.FCO; } } } rayHit = best; return hA; }
public bool ConvexCast(ConvexShape castShape, ref RigidTransform startingTransform, ref Vector3 sweepnorm, double slen, MaterialSolidity solidness, out RayHit hit) { RigidTransform rot = new RigidTransform(Vector3.Zero, startingTransform.Orientation); castShape.GetBoundingBox(ref rot, out BoundingBox bb); double adv = 0.1f; double max = slen + adv; bool gotOne = false; RayHit BestRH = default(RayHit); Vector3 sweep = sweepnorm * slen; for (double f = 0; f < max; f += adv) { Vector3 c = startingTransform.Position + sweepnorm * f; int mx = (int)Math.Ceiling(c.X + bb.Max.X); for (int x = (int)Math.Floor(c.X + bb.Min.X); x <= mx; x++) { if (x < 0 || x >= ChunkSize.X) { continue; } int my = (int)Math.Ceiling(c.Y + bb.Max.Y); for (int y = (int)Math.Floor(c.Y + bb.Min.Y); y <= my; y++) { if (y < 0 || y >= ChunkSize.Y) { continue; } int mz = (int)Math.Ceiling(c.Z + bb.Max.Z); for (int z = (int)Math.Floor(c.Z + bb.Min.Z); z <= mz; z++) { if (z < 0 || z >= ChunkSize.Z) { continue; } BlockInternal bi = Blocks[BlockIndex(x, y, z)]; if (solidness.HasFlag(((Material)bi.BlockMaterial).GetSolidity())) { EntityShape es = BlockShapeRegistry.BSD[bi.BlockData].GetShape(bi.Damage, out Location offs, false); if (es == null) { continue; } Vector3 adj = new Vector3(x + (double)offs.X, y + (double)offs.Y, z + (double)offs.Z); EntityCollidable coll = es.GetCollidableInstance(); //coll.LocalPosition = adj; RigidTransform rt = new RigidTransform(Vector3.Zero, Quaternion.Identity); coll.LocalPosition = Vector3.Zero; coll.WorldTransform = rt; coll.UpdateBoundingBoxForTransform(ref rt); RigidTransform adjusted = new RigidTransform(startingTransform.Position - adj, startingTransform.Orientation); bool b = coll.ConvexCast(castShape, ref adjusted, ref sweep, out RayHit rhit); if (b && (!gotOne || rhit.T * slen < BestRH.T) && rhit.T >= 0) { gotOne = true; BestRH = rhit; BestRH.Location += adj; BestRH.T *= slen; // TODO: ??? BestRH.Normal = -BestRH.Normal; // TODO: WHY?! } } } } } if (gotOne) { hit = BestRH; return(true); } } hit = new RayHit() { Location = startingTransform.Position + sweep, Normal = new Vector3(0, 0, 0), T = slen }; return(false); }
public bool ConvexCast(ConvexShape castShape, ref RigidTransform startingTransform, ref Vector3 sweepnorm, double slen, MaterialSolidity solidness, out RayHit hit) { BoundingBox bb; RigidTransform rot = new RigidTransform(Vector3.Zero, startingTransform.Orientation); castShape.GetBoundingBox(ref rot, out bb); double adv = 0.1f; double max = slen + adv; bool gotOne = false; RayHit BestRH = default(RayHit); Vector3 sweep = sweepnorm * slen; for (double f = 0; f < max; f += adv) { Vector3 c = startingTransform.Position + sweepnorm * f; int mx = (int)Math.Ceiling(c.X + bb.Max.X); for (int x = (int)Math.Floor(c.X + bb.Min.X); x <= mx; x++) { if (x < 0 || x >= ChunkSize.X) { continue; } int my = (int)Math.Ceiling(c.Y + bb.Max.Y); for (int y = (int)Math.Floor(c.Y + bb.Min.Y); y <= my; y++) { if (y < 0 || y >= ChunkSize.Y) { continue; } int mz = (int)Math.Ceiling(c.Z + bb.Max.Z); for (int z = (int)Math.Floor(c.Z + bb.Min.Z); z <= mz; z++) { if (z < 0 || z >= ChunkSize.Z) { continue; } BlockInternal bi = Blocks[BlockIndex(x, y, z)]; if (solidness.HasFlag(((Material)bi.BlockMaterial).GetSolidity())) { Location offs; EntityShape es = BlockShapeRegistry.BSD[bi.BlockData].GetShape(bi.Damage, out offs, false); if (es == null) { continue; } Vector3 adj = new Vector3(x + (double)offs.X, y + (double)offs.Y, z + (double)offs.Z); EntityCollidable coll = es.GetCollidableInstance(); //coll.LocalPosition = adj; RigidTransform rt = new RigidTransform(Vector3.Zero, Quaternion.Identity); coll.LocalPosition = Vector3.Zero; coll.WorldTransform = rt; coll.UpdateBoundingBoxForTransform(ref rt); RayHit rhit; RigidTransform adjusted = new RigidTransform(startingTransform.Position - adj, startingTransform.Orientation); bool b = coll.ConvexCast(castShape, ref adjusted, ref sweep, out rhit); if (b && (!gotOne || rhit.T * slen < BestRH.T) && rhit.T >= 0) { gotOne = true; BestRH = rhit; BestRH.Location += adj; BestRH.T *= slen; // TODO: ??? BestRH.Normal = -BestRH.Normal; // TODO: WHY?! } } } } } if (gotOne) { hit = BestRH; return true; } } hit = new RayHit() { Location = startingTransform.Position + sweep, Normal = new Vector3(0, 0, 0), T = slen }; return false; }