public override void Execute( IRaySceneQueryListener listener ) { Vector3 dir = ray.Direction; Vector3 origin = ray.Origin; // Straight up / down? if ( dir == Vector3.UnitY || dir == Vector3.NegativeUnitY ) { float height = ( (TerrainSceneManager)creator ).GetHeightAt( origin, -1 ); if ( height != -1 && ( height <= origin.y && dir.y < 0 ) || ( height >= origin.y && dir.y > 0 ) ) { this.WorldFragment.SingleIntersection.x = origin.x; this.WorldFragment.SingleIntersection.z = origin.z; this.WorldFragment.SingleIntersection.y = height; if ( !listener.OnQueryResult( this.WorldFragment, ( this.WorldFragment.SingleIntersection - origin ).Length ) ) return; } } else { TerrainSceneManager tsm = (TerrainSceneManager)creator; this.WorldFragment.SingleIntersection = tsm.IntersectSegment( origin, origin + ( dir * 100000 ) ); if ( !listener.OnQueryResult( this.WorldFragment, ( this.WorldFragment.SingleIntersection - origin ).Length ) ) return; } }
public override void Execute(IRaySceneQueryListener listener) { Vector3 dir = ray.Direction; Vector3 origin = ray.Origin; // Straight up / down? if (dir == Vector3.UnitY || dir == Vector3.NegativeUnitY) { float height = ((TerrainSceneManager)creator).GetHeightAt(origin, -1); if (height != -1 && (height <= origin.y && dir.y < 0) || (height >= origin.y && dir.y > 0)) { this.WorldFragment.SingleIntersection.x = origin.x; this.WorldFragment.SingleIntersection.z = origin.z; this.WorldFragment.SingleIntersection.y = height; if (!listener.OnQueryResult(this.WorldFragment, (this.WorldFragment.SingleIntersection - origin).Length)) { return; } } } else { var tsm = (TerrainSceneManager)creator; this.WorldFragment.SingleIntersection = tsm.IntersectSegment(origin, origin + (dir * 100000)); if (!listener.OnQueryResult(this.WorldFragment, (this.WorldFragment.SingleIntersection - origin).Length)) { return; } } }
public override void Execute(IRaySceneQueryListener listener) { var list = new List <PCZSceneNode>(); //find the nodes that intersect the AAB ((PCZSceneManager)creator).FindNodesIn(ray, ref list, this.startZone, (PCZSceneNode)this.excludeNode); //grab all moveables from the node that intersect... foreach (PCZSceneNode node in list) { foreach (MovableObject m in node.Objects) { if ((m.QueryFlags & queryMask) != 0 && (m.TypeFlags & this.queryTypeMask) != 0 && m.IsAttached) { IntersectResult result = ray.Intersects(m.GetWorldBoundingBox()); if (result.Hit) { listener.OnQueryResult(m, result.Distance); // deal with attached objects, since they are not directly attached to nodes if (m.MovableType == "Entity") { //Check: not sure here... var e = (Entity)m; foreach (MovableObject c in e.SubEntities) { if ((c.QueryFlags & queryMask) > 0) { result = ray.Intersects(c.GetWorldBoundingBox()); if (result.Hit) { listener.OnQueryResult(c, result.Distance); } } } } } } } } // reset startzone and exclude node this.startZone = null; this.excludeNode = null; }
public override void Execute( IRaySceneQueryListener listener ) { MovableObjectFactoryMap factories = Root.Instance.MovableObjectFactories; foreach ( KeyValuePair<string, MovableObjectFactory> map in factories ) { MovableObjectCollection movableObjects = this.creator.GetMovableObjectCollection( map.Value.Type ); foreach ( MovableObject movableObject in movableObjects.Values ) { // skip group if query type doesn't match if ( ( this.QueryTypeMask & movableObject.TypeFlags ) == 0 ) { break; } // skip if unattached or filtered out by query flags if ( !movableObject.IsAttached || ( movableObject.QueryFlags & this.queryMask ) == 0 ) { continue; } // test the intersection against the world bounding box of the entity IntersectResult results = Utility.Intersects( this.ray, movableObject.GetWorldBoundingBox() ); // if the results came back positive, fire the event handler if ( results.Hit == true ) { listener.OnQueryResult( movableObject, results.Distance ); } } } }
public override void Execute( IRaySceneQueryListener listener ) { this.listener = listener; this.StopRayTracing = false; ProcessNode( ( (BspSceneManager)creator ).Level.RootNode, ray, float.PositiveInfinity, 0 ); }
public override void Execute( IRaySceneQueryListener listener ) { var list = new List<PCZSceneNode>(); //find the nodes that intersect the AAB ( (PCZSceneManager)creator ).FindNodesIn( ray, ref list, this.startZone, (PCZSceneNode)this.excludeNode ); //grab all moveables from the node that intersect... foreach ( PCZSceneNode node in list ) { foreach ( MovableObject m in node.Objects ) { if ( ( m.QueryFlags & queryMask ) != 0 && ( m.TypeFlags & this.queryTypeMask ) != 0 && m.IsAttached ) { IntersectResult result = ray.Intersects( m.GetWorldBoundingBox() ); if ( result.Hit ) { listener.OnQueryResult( m, result.Distance ); // deal with attached objects, since they are not directly attached to nodes if ( m.MovableType == "Entity" ) { //Check: not sure here... var e = (Entity)m; foreach ( MovableObject c in e.SubEntities ) { if ( ( c.QueryFlags & queryMask ) > 0 ) { result = ray.Intersects( c.GetWorldBoundingBox() ); if ( result.Hit ) { listener.OnQueryResult( c, result.Distance ); } } } } } } } } // reset startzone and exclude node this.startZone = null; this.excludeNode = null; }
/// <summary> /// Executes the query and returns each match through a listener interface. /// </summary> /// <remarks> /// Note that this method does not store the results of the query internally /// so does not update the 'last result' value. This means that this version of /// execute is more lightweight and therefore more efficient than the version /// which returns the results as a collection. /// </remarks> /// <param name="listener">Listener object to handle the result callbacks.</param> public abstract void Execute( IRaySceneQueryListener listener );
/// <summary> /// <see cref="RaySceneQuery"/> /// </summary> public void Execute(IRaySceneQueryListener listener, Camera camera) { clearFragmentList(); // if the world is not initialized, then just quit out now with no hits if (!TerrainManager.Instance.Initialized) { return; } ulong mask = QueryMask; SceneQuery.WorldFragment frag; bool terrainQuery = (mask & (ulong)RaySceneQueryType.AllTerrain) != 0 || (mask & (ulong)RaySceneQueryType.FirstTerrain) != 0; // if the query is a terrain query that is exactly vertical, then force it into the "Height" fastpath if (((mask & (ulong)RaySceneQueryType.Height) != 0) || (terrainQuery && (this.Ray.Direction.x == 0.0f) && (this.Ray.Direction.z == 0.0f))) { // we don't want to bother checking for entities because a // UNIT_Y ray is assumed to be a height test, not a ray test frag = new SceneQuery.WorldFragment(); fragmentList.Add(frag); frag.FragmentType = WorldFragmentType.SingleIntersection; Vector3 origin = this.Ray.Origin; origin.y = 0; // ensure that it's within bounds frag.SingleIntersection = getHeightAt(origin); listener.OnQueryResult(frag, Math.Abs(frag.SingleIntersection.y - this.Ray.Origin.y)); } else { // Check for all entity contacts if ((mask & (ulong)RaySceneQueryType.Entities) != 0) { base.Execute(listener); } // Check for contact with the closest entity triangle // or all entity triangles. Ignores entities that // don't have a TriangleIntersector associated with // their meshes. bool firstTriangleQuery = (mask & (ulong)(RaySceneQueryType.FirstEntityTriangle)) != 0; bool allTrianglesQuery = (mask & (ulong)(RaySceneQueryType.AllEntityTriangles)) != 0; if (firstTriangleQuery | allTrianglesQuery) { rayOrigin = this.ray.Origin; // Start by getting the entities whose bounding // boxes intersect the ray. If there are none, // we're done. List<MovableObject> candidates = new List<MovableObject>(); foreach (Dictionary<string, MovableObject> objectMap in creator.MovableObjectMaps) { foreach (MovableObject obj in objectMap.Values) { // skip if unattached or filtered out by query flags if (!obj.IsAttached || (obj.QueryFlags & queryMask) == 0) continue; // test the intersection against the world bounding box of the entity IntersectResult results = MathUtil.Intersects(ray, obj.GetWorldBoundingBox()); if (results.Hit) candidates.Add(obj); } } // Get the camera.Near value Camera cam = camera; float nearDistance = cam.Near; float closestDistance = float.MaxValue; Vector3 closestIntersection = Vector3.Zero; Entity closestEntity = null; List<EntityAndIntersection> allEntities = new List<EntityAndIntersection>(); foreach (MovableObject obj in candidates) { // skip if unattached or filtered out by query flags if (!obj.IsAttached || (obj.QueryFlags & queryMask) == 0) continue; Entity entity = obj as Entity; if (entity == null) continue; // skip if its mesh doesn't have triangles if (entity.Mesh == null || entity.Mesh.TriangleIntersector == null) continue; // transform the ray to the space of the mesh Matrix4 inverseTransform = entity.ParentNodeFullTransform.Inverse(); Matrix4 inverseWithoutTranslation = inverseTransform; inverseWithoutTranslation.Translation = Vector3.Zero; Vector3 transformedOrigin = inverseTransform * ray.Origin; Ray transformedRay = new Ray(transformedOrigin, (inverseWithoutTranslation * ray.Direction).ToNormalized()); // test the intersection against the world bounding box of the entity Vector3 untransformedIntersection; if (entity.Mesh.TriangleIntersector.ClosestRayIntersection(transformedRay, Vector3.Zero, nearDistance, out untransformedIntersection)) { Vector3 intersection = entity.ParentNodeFullTransform * untransformedIntersection; if (allTrianglesQuery) allEntities.Add(new EntityAndIntersection(entity, intersection)); float distance = (ray.Origin - intersection).Length; if (firstTriangleQuery && distance < closestDistance) { closestDistance = distance; closestEntity = entity; closestIntersection = intersection; } } } if (firstTriangleQuery && closestEntity != null) { frag = new SceneQuery.WorldFragment(); fragmentList.Add(frag); frag.FragmentType = WorldFragmentType.SingleIntersection; frag.SingleIntersection = closestIntersection; listener.OnQueryResult(frag, closestDistance); } else if (allTrianglesQuery && allEntities.Count > 0) { allEntities.Sort(distanceToCameraCompare); foreach (EntityAndIntersection ei in allEntities) listener.OnQueryResult(ei.entity, (rayOrigin - ei.intersection).Length); } } if (terrainQuery) { Vector3 ray = Ray.Origin; Vector3 land = getHeightAt(ray); float dist = 0, resFactor = TerrainManager.oneMeter; // find the larger of x and z directions of the ray direction float maxXZ = Math.Max(Math.Abs(Ray.Direction.x), Math.Abs(Ray.Direction.z)); // Only bother if the non-default mask has been set if ((mask & (ulong)RaySceneQueryType.OnexRes) != 0) { if ((mask & (ulong)RaySceneQueryType.TwoxRes) != 0) { resFactor = TerrainManager.oneMeter / 2; } else if ((mask & (ulong)RaySceneQueryType.FourxRes) != 0) { resFactor = TerrainManager.oneMeter / 4; } else if ((mask & (ulong)RaySceneQueryType.EightxRes) != 0) { resFactor = TerrainManager.oneMeter / 8; } } // this scales the res factor so that we move along the ray by a distance that results // in shift of one meter along either the X or Z axis (whichever is longer) resFactor = resFactor / maxXZ; SubPageHeightMap sp; // bool east = false; (unused) // bool south = false; (unused) // if ( Ray.Origin.x > 0 ) // { // east = true; // } // if ( Ray.Origin.z > 0 ) // { // south = true; // } ray = Ray.Origin; sp = TerrainManager.Instance.LookupSubPage(ray); while (sp != null) { SubPageHeightMap newsp; AxisAlignedBox tileBounds = sp.BoundingBox; IntersectResult intersect = MathUtil.Intersects(Ray, tileBounds); if (intersect.Hit) { // step through this tile while ((newsp = TerrainManager.Instance.LookupSubPage(RoundRay(ray))) == sp) { land = getHeightAt(ray); if (ray.y < land.y) { frag = new SceneQuery.WorldFragment(); fragmentList.Add(frag); frag.FragmentType = WorldFragmentType.SingleIntersection; frag.SingleIntersection = land; listener.OnQueryResult(frag, dist); if ((mask & (ulong)RaySceneQueryType.FirstTerrain) != 0) { return; } } ray += Ray.Direction * resFactor; dist += 1 * resFactor; } // if we fall off the end of the above loop without getting a hit, then the hit should be // right at the far edge of the tile, so handle that case. land = getHeightAt(ray); if (ray.y < land.y) { frag = new SceneQuery.WorldFragment(); fragmentList.Add(frag); frag.FragmentType = WorldFragmentType.SingleIntersection; frag.SingleIntersection = land; listener.OnQueryResult(frag, dist); //LogManager.Instance.Write("MVSM:RaySceneQuery:End of tile ray collision"); if ((mask & (ulong)RaySceneQueryType.FirstTerrain) != 0) { return; } } else { //LogManager.Instance.Write("MVSM:RaySceneQuery:End of tile reached without expected intersection"); } } else { // step over this tile while ((newsp = TerrainManager.Instance.LookupSubPage(RoundRay(ray))) == sp) { // XXX - this is not the most efficient method... ray += Ray.Direction * resFactor; dist += 1 * resFactor; } } sp = newsp; } } } }
/// <summary> /// <see cref="RaySceneQuery"/> /// </summary> public void Execute(IRaySceneQueryListener listener, Camera camera) { clearFragmentList(); // if the world is not initialized, then just quit out now with no hits if (!TerrainManager.Instance.Initialized) { return; } ulong mask = QueryMask; SceneQuery.WorldFragment frag; bool terrainQuery = (mask & (ulong)RaySceneQueryType.AllTerrain) != 0 || (mask & (ulong)RaySceneQueryType.FirstTerrain) != 0; // if the query is a terrain query that is exactly vertical, then force it into the "Height" fastpath if (((mask & (ulong)RaySceneQueryType.Height) != 0) || (terrainQuery && (this.Ray.Direction.x == 0.0f) && (this.Ray.Direction.z == 0.0f))) { // we don't want to bother checking for entities because a // UNIT_Y ray is assumed to be a height test, not a ray test frag = new SceneQuery.WorldFragment(); fragmentList.Add(frag); frag.FragmentType = WorldFragmentType.SingleIntersection; Vector3 origin = this.Ray.Origin; origin.y = 0; // ensure that it's within bounds frag.SingleIntersection = getHeightAt(origin); listener.OnQueryResult(frag, Math.Abs(frag.SingleIntersection.y - this.Ray.Origin.y)); } else { // Check for all entity contacts if ((mask & (ulong)RaySceneQueryType.Entities) != 0) { base.Execute(listener); } // Check for contact with the closest entity triangle // or all entity triangles. Ignores entities that // don't have a TriangleIntersector associated with // their meshes. bool firstTriangleQuery = (mask & (ulong)(RaySceneQueryType.FirstEntityTriangle)) != 0; bool allTrianglesQuery = (mask & (ulong)(RaySceneQueryType.AllEntityTriangles)) != 0; if (firstTriangleQuery | allTrianglesQuery) { rayOrigin = this.ray.Origin; // Start by getting the entities whose bounding // boxes intersect the ray. If there are none, // we're done. List <MovableObject> candidates = new List <MovableObject>(); foreach (Dictionary <string, MovableObject> objectMap in creator.MovableObjectMaps) { foreach (MovableObject obj in objectMap.Values) { // skip if unattached or filtered out by query flags if (!obj.IsAttached || (obj.QueryFlags & queryMask) == 0) { continue; } // test the intersection against the world bounding box of the entity IntersectResult results = MathUtil.Intersects(ray, obj.GetWorldBoundingBox()); if (results.Hit) { candidates.Add(obj); } } } // Get the camera.Near value Camera cam = camera; float nearDistance = cam.Near; float closestDistance = float.MaxValue; Vector3 closestIntersection = Vector3.Zero; Entity closestEntity = null; List <EntityAndIntersection> allEntities = new List <EntityAndIntersection>(); foreach (MovableObject obj in candidates) { // skip if unattached or filtered out by query flags if (!obj.IsAttached || (obj.QueryFlags & queryMask) == 0) { continue; } Entity entity = obj as Entity; if (entity == null) { continue; } // skip if its mesh doesn't have triangles if (entity.Mesh == null || entity.Mesh.TriangleIntersector == null) { continue; } // transform the ray to the space of the mesh Matrix4 inverseTransform = entity.ParentNodeFullTransform.Inverse(); Matrix4 inverseWithoutTranslation = inverseTransform; inverseWithoutTranslation.Translation = Vector3.Zero; Vector3 transformedOrigin = inverseTransform * ray.Origin; Ray transformedRay = new Ray(transformedOrigin, (inverseWithoutTranslation * ray.Direction).ToNormalized()); // test the intersection against the world bounding box of the entity Vector3 untransformedIntersection; if (entity.Mesh.TriangleIntersector.ClosestRayIntersection(transformedRay, Vector3.Zero, nearDistance, out untransformedIntersection)) { Vector3 intersection = entity.ParentNodeFullTransform * untransformedIntersection; if (allTrianglesQuery) { allEntities.Add(new EntityAndIntersection(entity, intersection)); } float distance = (ray.Origin - intersection).Length; if (firstTriangleQuery && distance < closestDistance) { closestDistance = distance; closestEntity = entity; closestIntersection = intersection; } } } if (firstTriangleQuery && closestEntity != null) { frag = new SceneQuery.WorldFragment(); fragmentList.Add(frag); frag.FragmentType = WorldFragmentType.SingleIntersection; frag.SingleIntersection = closestIntersection; listener.OnQueryResult(frag, closestDistance); } else if (allTrianglesQuery && allEntities.Count > 0) { allEntities.Sort(distanceToCameraCompare); foreach (EntityAndIntersection ei in allEntities) { listener.OnQueryResult(ei.entity, (rayOrigin - ei.intersection).Length); } } } if (terrainQuery) { Vector3 ray = Ray.Origin; Vector3 land = getHeightAt(ray); float dist = 0, resFactor = TerrainManager.oneMeter; // find the larger of x and z directions of the ray direction float maxXZ = Math.Max(Math.Abs(Ray.Direction.x), Math.Abs(Ray.Direction.z)); // Only bother if the non-default mask has been set if ((mask & (ulong)RaySceneQueryType.OnexRes) != 0) { if ((mask & (ulong)RaySceneQueryType.TwoxRes) != 0) { resFactor = TerrainManager.oneMeter / 2; } else if ((mask & (ulong)RaySceneQueryType.FourxRes) != 0) { resFactor = TerrainManager.oneMeter / 4; } else if ((mask & (ulong)RaySceneQueryType.EightxRes) != 0) { resFactor = TerrainManager.oneMeter / 8; } } // this scales the res factor so that we move along the ray by a distance that results // in shift of one meter along either the X or Z axis (whichever is longer) resFactor = resFactor / maxXZ; SubPageHeightMap sp; // bool east = false; (unused) // bool south = false; (unused) // if ( Ray.Origin.x > 0 ) // { // east = true; // } // if ( Ray.Origin.z > 0 ) // { // south = true; // } ray = Ray.Origin; sp = TerrainManager.Instance.LookupSubPage(ray); while (sp != null) { SubPageHeightMap newsp; AxisAlignedBox tileBounds = sp.BoundingBox; IntersectResult intersect = MathUtil.Intersects(Ray, tileBounds); if (intersect.Hit) { // step through this tile while ((newsp = TerrainManager.Instance.LookupSubPage(RoundRay(ray))) == sp) { land = getHeightAt(ray); if (ray.y < land.y) { frag = new SceneQuery.WorldFragment(); fragmentList.Add(frag); frag.FragmentType = WorldFragmentType.SingleIntersection; frag.SingleIntersection = land; listener.OnQueryResult(frag, dist); if ((mask & (ulong)RaySceneQueryType.FirstTerrain) != 0) { return; } } ray += Ray.Direction * resFactor; dist += 1 * resFactor; } // if we fall off the end of the above loop without getting a hit, then the hit should be // right at the far edge of the tile, so handle that case. land = getHeightAt(ray); if (ray.y < land.y) { frag = new SceneQuery.WorldFragment(); fragmentList.Add(frag); frag.FragmentType = WorldFragmentType.SingleIntersection; frag.SingleIntersection = land; listener.OnQueryResult(frag, dist); //LogManager.Instance.Write("MVSM:RaySceneQuery:End of tile ray collision"); if ((mask & (ulong)RaySceneQueryType.FirstTerrain) != 0) { return; } } else { //LogManager.Instance.Write("MVSM:RaySceneQuery:End of tile reached without expected intersection"); } } else { // step over this tile while ((newsp = TerrainManager.Instance.LookupSubPage(RoundRay(ray))) == sp) { // XXX - this is not the most efficient method... ray += Ray.Direction * resFactor; dist += 1 * resFactor; } } sp = newsp; } } } }
/// <summary> /// <see cref="RaySceneQuery"/> /// </summary> public override void Execute(IRaySceneQueryListener listener) { clearFragmentList( ); ulong mask = QueryMask; SceneQuery.WorldFragment frag; if ((mask & (ulong)RaySceneQueryType.Height) != 0) { // we don't want to bother checking for entities because a // UNIT_Y ray is assumed to be a height test, not a ray test frag = new SceneQuery.WorldFragment( ); fragmentList.Add(frag); frag.FragmentType = WorldFragmentType.SingleIntersection; Vector3 origin = this.Ray.Origin; origin.y = 0; // ensure that it's within bounds frag.SingleIntersection = getHeightAt(origin); listener.OnQueryResult(frag, Math.Abs(frag.SingleIntersection.y - this.Ray.Origin.y)); } else { // Check for entity contacts if ((mask & (ulong)RaySceneQueryType.Entities) != 0) { base.Execute(listener); } if ((mask & (ulong)RaySceneQueryType.AllTerrain) != 0 || (mask & (ulong)RaySceneQueryType.FirstTerrain) != 0) { Vector3 ray = Ray.Origin; Vector3 land = getHeightAt(ray); float dist = 0, resFactor = 1; // Only bother if the non-default mask has been set if ((mask & (ulong)RaySceneQueryType.OnexRes) != 0) { if ((mask & (ulong)RaySceneQueryType.TwoxRes) != 0) { resFactor = 0.5F; } else if ((mask & (ulong)RaySceneQueryType.FourxRes) != 0) { resFactor = 0.25F; } else if ((mask & (ulong)RaySceneQueryType.EightxRes) != 0) { resFactor = 0.125F; } } while (land.y != -1) { ray += Ray.Direction * resFactor; dist += 1 * resFactor; land = getHeightAt(ray); if (ray.y < land.y) { frag = new SceneQuery.WorldFragment( ); fragmentList.Add(frag); frag.FragmentType = WorldFragmentType.SingleIntersection; frag.SingleIntersection = land; listener.OnQueryResult(frag, dist); if ((mask & (ulong)RaySceneQueryType.FirstTerrain) != 0) { return; } } } } } }
public override void Execute(IRaySceneQueryListener listener) { // Note that becuase we have no scene partitioning, we actually // perform a complete scene search even if restricted results are // requested; smarter scene manager queries can utilise the paritioning // of the scene in order to reduce the number of intersection tests // required to fulfil the query // TODO: BillboardSets? Will need per-billboard collision most likely // Entities only for now foreach (Dictionary<string, MovableObject> objectMap in creator.MovableObjectMaps) { foreach (MovableObject obj in objectMap.Values) { // skip if unattached or filtered out by query flags if (!obj.IsAttached || (obj.QueryFlags & queryMask) == 0) { continue; } // test the intersection against the world bounding box of the entity IntersectResult results = MathUtil.Intersects(ray, obj.GetWorldBoundingBox()); // if the results came back positive, fire the event handler if (results.Hit == true) { listener.OnQueryResult(obj, results.Distance); } } } }
/// <summary> /// <see cref="RaySceneQuery"/> /// </summary> public override void Execute( IRaySceneQueryListener listener ) { clearFragmentList( ); ulong mask = QueryMask; SceneQuery.WorldFragment frag; if ( (mask & (ulong)RaySceneQueryType.Height) != 0) { // we don't want to bother checking for entities because a // UNIT_Y ray is assumed to be a height test, not a ray test frag = new SceneQuery.WorldFragment( ); fragmentList.Add( frag ); frag.FragmentType = WorldFragmentType.SingleIntersection; Vector3 origin = this.Ray.Origin; origin.y = 0; // ensure that it's within bounds frag.SingleIntersection = getHeightAt( origin ); listener.OnQueryResult( frag, Math.Abs(frag.SingleIntersection.y - this.Ray.Origin.y) ); } else { // Check for entity contacts if ( (mask & (ulong)RaySceneQueryType.Entities) != 0 ) { base.Execute( listener ); } if ( (mask & (ulong)RaySceneQueryType.AllTerrain) != 0 || (mask & (ulong)RaySceneQueryType.FirstTerrain) !=0 ) { Vector3 ray = Ray.Origin; Vector3 land = getHeightAt( ray ); float dist = 0, resFactor = 1; // Only bother if the non-default mask has been set if ( ( mask & (ulong)RaySceneQueryType.OnexRes ) != 0 ) { if ( (mask & (ulong)RaySceneQueryType.TwoxRes) != 0 ) { resFactor = 0.5F; } else if ( (mask & (ulong)RaySceneQueryType.FourxRes) !=0 ) { resFactor = 0.25F; } else if ( (mask & (ulong)RaySceneQueryType.EightxRes) != 0 ) { resFactor = 0.125F; } } while ( land.y != -1 ) { ray += Ray.Direction * resFactor; dist += 1 * resFactor; land = getHeightAt( ray ); if ( ray.y < land.y ) { frag = new SceneQuery.WorldFragment( ); fragmentList.Add( frag ); frag.FragmentType = WorldFragmentType.SingleIntersection; frag.SingleIntersection = land; listener.OnQueryResult( frag, dist ); if ( (mask & (ulong)RaySceneQueryType.FirstTerrain )!= 0) { return; } } } } } }
/// <summary> /// Executes the query and returns each match through a listener interface. /// </summary> /// <remarks> /// Note that this method does not store the results of the query internally /// so does not update the 'last result' value. This means that this version of /// execute is more lightweight and therefore more efficient than the version /// which returns the results as a collection. /// </remarks> /// <param name="listener">Listener object to handle the result callbacks.</param> public abstract void Execute(IRaySceneQueryListener listener);