private void GetAgentMatches(RayData ray, RayTestHitFlags flags, List <RayResult> results) { foreach (IAgent agent in m_Scene.RootAgents) { BoundingBox bbox; agent.GetBoundingBox(out bbox); bbox.CenterOffset = agent.GlobalPosition; bbox.Size *= agent.GlobalRotation; bbox.Size = bbox.Size.ComponentMax(-bbox.Size); double dist = IntersectBox(ray, ref bbox); if (dist < 0) { continue; } results.Add(new RayResult { IsTerrain = false, ObjectId = agent.ID, PartId = agent.ID, HitPointWorld = ray.Origin + ray.Direction * dist }); } }
public RayResult[] RayTest(Vector3 rayFromWorld, Vector3 rayToWorld, RayTestHitFlags flags, uint maxHits) { var results = new List <RayResult>(); RayData ray = new RayData(rayFromWorld, rayToWorld); if ((flags & RayTestHitFlags.Avatar) != 0) { GetAgentMatches(ray, flags, results); } if ((flags & (RayTestHitFlags.NonPhantom | RayTestHitFlags.Phantom | RayTestHitFlags.NonPhantom | RayTestHitFlags.Phantom | RayTestHitFlags.Character)) != 0) { GetObjectMatches(ray, flags, results); } results.Sort((r1, r2) => (r1.HitPointWorld - rayFromWorld).LengthSquared.CompareTo((r2.HitPointWorld - rayFromWorld).LengthSquared)); if (results.Count > maxHits) { results.RemoveRange((int)maxHits, results.Count - (int)maxHits); } return(results.ToArray()); }
private void GetObjectMatches(RayData ray, RayTestHitFlags flags, List <RayResult> results) { foreach (ObjectGroup grp in m_Scene.ObjectGroups) { if (grp.IsAttached) { /* ignore attachments */ continue; } /* flag checks are cheap so do those first */ if (((flags & RayTestHitFlags.NonPhantom) != 0 && !grp.IsPhantom) || ((flags & RayTestHitFlags.Phantom) != 0 && grp.IsPhantom) || ((flags & RayTestHitFlags.NonPhysical) != 0 && !grp.IsPhysics) || ((flags & RayTestHitFlags.Physical) != 0 && grp.IsPhysics)) { /* found a flag match */ } else { continue; } BoundingBox bbox; grp.GetBoundingBox(out bbox); bbox.CenterOffset = grp.GlobalPosition; bbox.Size *= grp.GlobalRotation; bbox.Size = bbox.Size.ComponentMax(-bbox.Size); double distance = IntersectBox(ray, ref bbox); if (distance < 0) { /* only process if linkset bounding box is hit */ continue; } foreach (ObjectPart part in grp.ValuesByKey1) { part.GetBoundingBox(out bbox); distance = IntersectBox(ray, ref bbox); if (distance < 0) { /* skip if not hit */ continue; } var res = new RayResult { ObjectId = grp.ID, PartId = part.ID }; /* calculate actual HitPoint and HitNormal */ ObjectPart.PrimitiveShape shape = part.Shape; MeshLOD lod = null; if (shape.Type == PrimitiveShapeType.Sculpt && shape.SculptType == PrimitiveSculptType.Mesh) { var m = new LLMesh(m_Scene.AssetService[shape.SculptMap]); foreach (LLMesh.LodLevel level in LodOrder) { if (m.HasLOD(level)) { lod = m.GetLOD(level); break; } } } else { lod = shape.ToMesh(m_Scene.AssetService); } if (lod != null) { lod.Optimize(); Vector3 normal; foreach (Triangle tri in lod.Triangles) { double dist = IntersectTri(ray, lod.Vertices[tri.Vertex1], lod.Vertices[tri.Vertex2], lod.Vertices[tri.Vertex3], out normal); if (dist >= 0) { res.HitNormalWorld = normal; res.HitPointWorld = ray.Origin + ray.Direction * dist; results.Add(res); break; } } } } } }
private void GetTerrainMatches(RayData ray, RayTestHitFlags flags, List <RayResult> results) { var pos = new List <ulong>(); var regionExtents = new Vector3(m_Scene.SizeX, m_Scene.SizeY, 0); double d; for (d = 0; d < ray.RayLength; d += 0.5) { BoundingBox bbox = new BoundingBox(); bbox.CenterOffset = ray.Origin + (ray.Direction * d); bbox.CenterOffset.X = Math.Floor(bbox.CenterOffset.X) + 0.5; bbox.CenterOffset.Y = Math.Floor(bbox.CenterOffset.Y) + 0.5; ulong tPos = (((ulong)bbox.CenterOffset.Y) << 32) + (ulong)bbox.CenterOffset.X; if (pos.Contains(tPos)) { /* skip if already tested */ continue; } pos.Add(tPos); if (bbox.CenterOffset.X < 0 || bbox.CenterOffset.X > regionExtents.X + 1 || bbox.CenterOffset.Y < 0 || bbox.CenterOffset.Y > regionExtents.Y + 1) { /* skip */ continue; } var t0 = new Vector3(bbox.CenterOffset.X - 0.5, bbox.CenterOffset.Y - 0.5, 0); var t1 = new Vector3(bbox.CenterOffset.X + 0.5, bbox.CenterOffset.Y - 0.5, 0); var t2 = new Vector3(bbox.CenterOffset.X - 0.5, bbox.CenterOffset.Y + 0.5, 0); var t3 = new Vector3(bbox.CenterOffset.X + 0.5, bbox.CenterOffset.Y + 0.5, 0); t0.Z = m_Scene.Terrain[t0]; t1.Z = m_Scene.Terrain[t1]; t2.Z = m_Scene.Terrain[t2]; t3.Z = m_Scene.Terrain[t3]; Vector3 tmin = t0.ComponentMin(t1).ComponentMin(t2).ComponentMin(t3); Vector3 tmax = t0.ComponentMax(t1).ComponentMax(t2).ComponentMax(t3); bbox.CenterOffset.Z = (tmin.Z + tmax.Z) / 2; bbox.Size = tmax - tmin; double dist = IntersectBox(ray, ref bbox); if (dist < 0) { /* not hitting terrain at all */ continue; } Vector3 normal; dist = IntersectTri(ray, t0, t1, t2, out normal); if (dist < 0) { dist = IntersectTri(ray, t0, t3, t2, out normal); } if (dist < 0) { continue; } results.Add(new RayResult { HitNormalWorld = normal, HitPointWorld = ray.Origin + ray.Direction * dist, IsTerrain = true, ObjectId = UUID.Zero, PartId = UUID.Zero }); } }
public RayResult[] RayTest(Vector3 rayFromWorld, Vector3 rayToWorld, RayTestHitFlags flags) => RayTest(rayFromWorld, rayToWorld, flags, uint.MaxValue);