Representation of a ray in space, ie a line with an origin and direction.
예제 #1
0
		public bool ClosestRayIntersection( Ray ray, Matrix4 transform, float ignoreDistance, out Vector3 intersection )
		{
			var intersects = false;
			intersection = Vector3.Zero;
			var minDistSquared = float.MaxValue;
			var ignoreDistanceSquared = ignoreDistance*ignoreDistance;
			var where = Vector3.Zero;

			// Iterate over the triangles
			for ( var i = 0; i < this.triangles.Count; i++ )
			{
				var t = this.triangles[ i ];
				if ( RayIntersectsTriangle( ray, t.Vertices, ref transform, ref where ) )
				{
					float distSquared = ( where - ray.Origin ).LengthSquared;
					if ( distSquared > ignoreDistanceSquared && distSquared < minDistSquared )
					{
						minDistSquared = distSquared;
						intersection = where;
						intersects = true;
					}
				}
			}
			return intersects;
		}
예제 #2
0
		public abstract void FindNodes( Ray t, ref List<PCZSceneNode> list, List<Portal> visitedPortals, bool includeVisitors,
		                                bool recurseThruPortals, PCZSceneNode exclude );
예제 #3
0
		/// <summary>
		///    Creates a query to return objects found along the ray.
		/// </summary>
		/// <param name="ray">Ray to use for the intersection query.</param>
		/// <returns>A specialized implementation of RaySceneQuery for this scene manager.</returns>
		public virtual RaySceneQuery CreateRayQuery( Ray ray )
		{
			return this.CreateRayQuery( ray, 0xffffffff );
		}
예제 #4
0
		public void GetCameraToViewportRay( float screenX, float screenY, out Ray ray )
		{
			var inverseVP = ( _projectionMatrix*_viewMatrix ).Inverse();

#if !AXIOM_NO_VIEWPORT_ORIENTATIONMODE
			// We need to convert screen point to our oriented viewport (temp solution)
			Real tX = screenX;
			Real a = (int)OrientationMode*System.Math.PI*0.5f;
			screenX = System.Math.Cos( a )*( tX - 0.5f ) + System.Math.Sin( a )*( screenY - 0.5f ) + 0.5f;
			screenY = System.Math.Sin( a )*( tX - 0.5f ) + System.Math.Cos( a )*( screenY - 0.5f ) + 0.5f;
			if ( ( ( (int)OrientationMode ) & 1 ) == 1 )
			{
				screenY = 1.0f - screenY;
			}
#endif

			Real nx = ( 2.0f*screenX ) - 1.0f;
			Real ny = 1.0f - ( 2.0f*screenY );
			var nearPoint = new Vector3( nx, ny, -1.0f );
			// Use midPoint rather than far point to avoid issues with infinite projection
			var midPoint = new Vector3( nx, ny, 0.0f );

			// Get ray origin and ray target on near plane in world space

			var rayOrigin = inverseVP*nearPoint;
			var rayTarget = inverseVP*midPoint;

			var rayDirection = rayTarget - rayOrigin;
			rayDirection.Normalize();

			ray = new Ray( rayOrigin, rayDirection );
		}
예제 #5
0
		protected virtual void ProcessLeaf( BspNode leaf, Ray tracingRay, float maxDistance, float traceDistance )
		{
			//Check ray against objects
			foreach ( MovableObject obj in leaf.Objects.Values )
			{
				// Skip this object if collision not enabled
				if ( ( obj.QueryFlags & queryMask ) == 0 )
				{
					continue;
				}

				//Test object as bounding box
				IntersectResult result = tracingRay.Intersects( obj.GetWorldBoundingBox() );
				// if the result came back positive and intersection point is inside
				// the node, fire the event handler
				if ( result.Hit && result.Distance <= maxDistance )
				{
					this.listener.OnQueryResult( obj, result.Distance + traceDistance );
				}
			}

			var boundedVolume = new PlaneBoundedVolume( PlaneSide.Positive );
			BspBrush intersectBrush = null;
			float intersectBrushDist = float.PositiveInfinity;

			if ( ( QueryTypeMask & (ulong)SceneQueryTypeMask.WorldGeometry ) != 0 )
			{
				// Check ray against brushes
				if ( ( QueryTypeMask & (ulong)SceneQueryTypeMask.WorldGeometry ) != 0 )
				{
					for ( int brushPoint = 0; brushPoint < leaf.SolidBrushes.Length; brushPoint++ )
					{
						BspBrush brush = leaf.SolidBrushes[ brushPoint ];

						if ( brush == null )
						{
							continue;
						}

						boundedVolume.planes = brush.Planes;

						IntersectResult result = tracingRay.Intersects( boundedVolume );
						// if the result came back positive and intersection point is inside
						// the node, check if this brush is closer
						if ( result.Hit && result.Distance <= maxDistance )
						{
							if ( result.Distance < intersectBrushDist )
							{
								intersectBrushDist = result.Distance;
								intersectBrush = brush;
							}
						}
					}

					if ( intersectBrush != null )
					{
						this.listener.OnQueryResult( intersectBrush.Fragment, intersectBrushDist + traceDistance );
						this.StopRayTracing = true;
					}
				}
			}

			if ( intersectBrush != null )
			{
				this.listener.OnQueryResult( intersectBrush.Fragment, intersectBrushDist + traceDistance );
				this.StopRayTracing = true;
			}
		}
예제 #6
0
		public override void FindNodes( Ray t, ref List<PCZSceneNode> list, List<Portal> visitedPortals, bool includeVisitors, bool recurseThruPortals, PCZSceneNode exclude )
		{
			// if this zone has an enclosure, check against the enclosure AABB first
			if ( null != mEnclosureNode )
			{
				IntersectResult nsect = t.Intersects( mEnclosureNode.WorldAABB );
				if ( !nsect.Hit )
				{
					// AABB of zone does not intersect t, just return.
					return;
				}
			}

			// use the Octree to more efficiently find nodes intersecting the ray
			rootOctree._findNodes( t, ref list, exclude, includeVisitors, false );

			// if asked to, recurse through portals
			if ( recurseThruPortals )
			{
				foreach ( Portal portal in mPortals )
				{
					// check portal versus boundign box
					if ( portal.intersects( t ) )
					{
						// make sure portal hasn't already been recursed through

						if ( !visitedPortals.Contains( portal ) )
						{
							// save portal to the visitedPortals list
							visitedPortals.Add( portal );
							// recurse into the connected zone
							portal.getTargetZone().FindNodes( t,
															  ref list,
															  visitedPortals,
															  includeVisitors,
															  recurseThruPortals,
															  exclude );
						}
					}
				}
			}

		}
예제 #7
0
		private static Intersection intersect( Ray one, AxisAlignedBox two )
		{
			// Null box?
			if ( two.IsNull )
			{
				return Intersection.OUTSIDE;
			}
			// Infinite box?
			if ( two.IsInfinite )
			{
				return Intersection.INTERSECT;
			}

			bool inside = true;
			Vector3 twoMin = two.Minimum;
			Vector3 twoMax = two.Maximum;
			Vector3 origin = one.Origin;
			Vector3 dir = one.Direction;

			var maxT = new Vector3( -1, -1, -1 );

			int i = 0;
			for ( i = 0; i < 3; i++ )
			{
				if ( origin[ i ] < twoMin[ i ] )
				{
					inside = false;
					if ( dir[ i ] > 0 )
					{
						maxT[ i ] = ( twoMin[ i ] - origin[ i ] )/dir[ i ];
					}
				}
				else if ( origin[ i ] > twoMax[ i ] )
				{
					inside = false;
					if ( dir[ i ] < 0 )
					{
						maxT[ i ] = ( twoMax[ i ] - origin[ i ] )/dir[ i ];
					}
				}
			}

			if ( inside )
			{
				return Intersection.INTERSECT;
			}
			int whichPlane = 0;
			if ( maxT[ 1 ] > maxT[ whichPlane ] )
			{
				whichPlane = 1;
			}
			if ( maxT[ 2 ] > maxT[ whichPlane ] )
			{
				whichPlane = 2;
			}

			if ( ( ( (int)maxT[ whichPlane ] ) & 0x80000000 ) != 0 )
			{
				return Intersection.OUTSIDE;
			}
			for ( i = 0; i < 3; i++ )
			{
				if ( i != whichPlane )
				{
					float f = origin[ i ] + maxT[ whichPlane ]*dir[ i ];
					if ( f < ( twoMin[ i ] - 0.00001f ) || f > ( twoMax[ i ] + 0.00001f ) )
					{
						return Intersection.OUTSIDE;
					}
				}
			}

			return Intersection.INTERSECT;
		}
예제 #8
0
		public void WidenRectByVector( Vector3 vec, Rectangle inRect, Real minHeight, Real maxHeight, ref Rectangle outRect )
		{
			outRect = inRect;

			var p = new Plane();
			switch ( Alignment )
			{
				case Alignment.Align_X_Y:
					p.Redefine( Vector3.UnitZ, new Vector3( 0, 0, vec.z < 0.0f ? minHeight : maxHeight ) );
					break;

				case Alignment.Align_X_Z:
					p.Redefine( Vector3.UnitY, new Vector3( 0, vec.y < 0.0f ? minHeight : maxHeight, 0 ) );
					break;

				case Alignment.Align_Y_Z:
					p.Redefine( Vector3.UnitX, new Vector3( vec.x < 0.0f ? minHeight : maxHeight, 0, 0 ) );
					break;
			}
			var verticalVal = vec.Dot( p.Normal );

			if ( Utility.RealEqual( verticalVal, 0.0f ) )
			{
				return;
			}

			var corners = new Vector3[4];
			var startHeight = verticalVal < 0.0f ? maxHeight : minHeight;
			GetPoint( inRect.Left, inRect.Top, startHeight, ref corners[ 0 ] );
			GetPoint( inRect.Right - 1, inRect.Top, startHeight, ref corners[ 1 ] );
			GetPoint( inRect.Left, inRect.Bottom - 1, startHeight, ref corners[ 2 ] );
			GetPoint( inRect.Right - 1, inRect.Bottom - 1, startHeight, ref corners[ 3 ] );

			for ( int i = 0; i < 4; ++i )
			{
				var ray = new Ray( corners[ i ] + this.mPos, vec );
				var rayHit = ray.Intersects( p );
				if ( rayHit.Hit )
				{
					var pt = ray.GetPoint( rayHit.Distance );
					// convert back to terrain point
					var terrainHitPos = Vector3.Zero;
					GetTerrainPosition( pt, ref terrainHitPos );
					// build rectangle which has rounded down & rounded up values
					// remember right & bottom are exclusive
					var mergeRect = new Rectangle( (long)terrainHitPos.x*( this.mSize - 1 ), (long)terrainHitPos.y*( this.mSize - 1 ),
												   (long)( terrainHitPos.x*(float)( this.mSize - 1 ) + 0.5f ) + 1,
												   (long)( terrainHitPos.y*(float)( this.mSize - 1 ) + 0.5f ) + 1 );
					outRect.Merge( mergeRect );
				}
			}
		}
예제 #9
0
		public PixelBox CalculateLightMap( Rectangle rect, Rectangle extraTargetRect, ref Rectangle outFinalRect )
		{
			// as well as calculating the lighting changes for the area that is
			// dirty, we also need to calculate the effect on casting shadow on
			// other areas. To do this, we project the dirt rect by the light direction
			// onto the minimum height

			var lightVec = TerrainGlobalOptions.LightMapDirection;
			var widenedRect = new Rectangle();
			WidenRectByVector( lightVec, rect, ref widenedRect );

			//merge in the extra area (e.g. from neighbours)
			widenedRect.Merge( extraTargetRect );

			// widenedRect now contains terrain point space version of the area we
			// need to calculate. However, we need to calculate in lightmap image space
			var terrainToLightmapScale = (float)this.mLightmapSizeActual/(float)this.mSize;
			widenedRect.Left = (long)( widenedRect.Left*terrainToLightmapScale );
			widenedRect.Right = (long)( widenedRect.Right*terrainToLightmapScale );
			widenedRect.Top = (long)( widenedRect.Top*terrainToLightmapScale );
			widenedRect.Bottom = (long)( widenedRect.Bottom*terrainToLightmapScale );

			//clamp
			widenedRect.Left = Utility.Max( 0L, widenedRect.Left );
			widenedRect.Top = Utility.Max( 0L, widenedRect.Top );
			widenedRect.Right = Utility.Min( (long)this.mLightmapSizeActual, widenedRect.Right );
			widenedRect.Bottom = Utility.Min( (long)this.mLightmapSizeActual, widenedRect.Bottom );

			outFinalRect = widenedRect;

			// allocate memory (L8)
			var pData = new byte[widenedRect.Width*widenedRect.Height];
			var pDataPtr = BufferBase.Wrap( pData );
			var pixbox = new PixelBox( (int)widenedRect.Width, (int)widenedRect.Height, 1, PixelFormat.L8, pDataPtr );

			var heightPad = ( MaxHeight - MinHeight )*1.0e-3f;

			for ( var y = widenedRect.Top; y < widenedRect.Bottom; ++y )
			{
				for ( var x = widenedRect.Left; x < widenedRect.Right; ++x )
				{
					var litVal = 1.0f;

					// convert to terrain space (not points, allow this to go between points)
					var Tx = (float)x/(float)( this.mLightmapSizeActual - 1 );
					var Ty = (float)y/(float)( this.mLightmapSizeActual - 1 );

					// get world space point
					// add a little height padding to stop shadowing self
					var wpos = Vector3.Zero;
					GetPosition( Tx, Ty, GetHeightAtTerrainPosition( Tx, Ty ) + heightPad, ref wpos );
					wpos += Position;
					// build ray, cast backwards along light direction
					var ray = new Ray( wpos, -lightVec );

					// Cascade into neighbours when casting, but don't travel further
					// than world size
					var rayHit = RayIntersects( ray, true, this.mWorldSize );

					if ( rayHit.Key )
					{
						litVal = 0.0f;
					}

					// encode as L8
					// invert the Y to deal with image space
					var storeX = x - widenedRect.Left;
					var storeY = widenedRect.Bottom - y - 1;

					using ( var wrap = pDataPtr + ( ( storeY*widenedRect.Width ) + storeX ) )
					{
						var pStore = (ITypePointer<byte>)wrap;
						pStore[ 0 ] = (byte)( litVal*255.0 );
					}
				}
			}
			pDataPtr.Dispose();
			return pixbox;
		}
예제 #10
0
		/// <see cref="Terrain.RayIntersects(Ray, bool, Real)"/>
		public KeyValuePair<bool, Vector3> RayIntersects( Ray ray, bool cascadeToNeighbours )
		{
			return RayIntersects( ray, cascadeToNeighbours, 0 );
		}
예제 #11
0
		protected KeyValuePair<bool, Vector3> CheckQuadIntersection( int x, int z, Ray ray )
		{
			// build the two planes belonging to the quad's triangles
			Vector3 v1 = new Vector3( x, this.mHeightData[ z + this.mSize*x ], z ),
					v2 = new Vector3( x + 1, this.mHeightData[ z + this.mSize*( x + 1 ) ], z ),
					v3 = new Vector3( x, this.mHeightData[ ( z + 1 ) + this.mSize*x ], z + 1 ),
					v4 = new Vector3( x + 1, this.mHeightData[ ( z + 1 ) + this.mSize*( x + 1 ) ], z + 1 );

			Plane p1 = new Plane(), p2 = new Plane();
			var oddRow = false;
			if ( z%2 != 0 )
			{
				/* odd
					3---4
					| \ |
					1---2
					*/
				p1.Redefine( v2, v4, v3 );
				p2.Redefine( v1, v2, v3 );
				oddRow = true;
			}
			else
			{
				/* even
					3---4
					| / |
					1---2
					*/
				p1.Redefine( v1, v2, v4 );
				p2.Redefine( v1, v4, v3 );
			}
			// Test for intersection with the two planes. 
			// Then test that the intersection points are actually
			// still inside the triangle (with a small error margin)
			// Also check which triangle it is in
			var planeInt = ray.Intersects( p1 );
			if ( planeInt.Hit )
			{
				var where = ray.GetPoint( planeInt.Distance );
				var rel = where - v1;
				if ( rel.x >= -0.01 && rel.x <= 1.01 && rel.z >= -0.01 && rel.z <= 1.01 // quad bounds
					 && ( ( rel.x >= rel.z && !oddRow ) || ( rel.x >= ( 1 - rel.z ) && oddRow ) ) ) // triangle bounds
				{
					return new KeyValuePair<bool, Vector3>( true, where );
				}
			}
			planeInt = ray.Intersects( p2 );
			if ( planeInt.Hit )
			{
				var where = ray.GetPoint( planeInt.Distance );
				var rel = where - v1;
				if ( rel.x >= -0.01 && rel.x <= 1.01 && rel.z >= -0.01 && rel.z <= 1.01 // quad bounds
					 && ( ( rel.x <= rel.z && !oddRow ) || ( rel.x <= ( 1 - rel.z ) && oddRow ) ) ) // triangle bounds
				{
					return new KeyValuePair<bool, Vector3>( true, where );
				}
			}

			return new KeyValuePair<bool, Vector3>( false, Vector3.Zero );
		}
예제 #12
0
		/// <see cref="Terrain.RayIntersects(Ray, bool, Real)"/>
		public KeyValuePair<bool, Vector3> RayIntersects( Ray ray )
		{
			return RayIntersects( ray, false, 0 );
		}
예제 #13
0
		public KeyValuePair<bool, Vector3> RayIntersects( Ray ray, bool cascadeToNeighbours, Real distanceLimit )
		{
			KeyValuePair<bool, Vector3> Result;
			// first step: convert the ray to a local vertex space
			// we assume terrain to be in the x-z plane, with the [0,0] vertex
			// at origin and a plane distance of 1 between vertices.
			// This makes calculations easier.
			var rayOrigin = ray.Origin - Position;
			var rayDirection = ray.Direction;
			// change alignment
			Vector3 tmp;
			switch ( Alignment )
			{
				case Alignment.Align_X_Y:
					Utility.Swap<Real>( ref rayOrigin.y, ref rayOrigin.z );
					Utility.Swap<Real>( ref rayDirection.y, ref rayDirection.z );
					break;

				case Alignment.Align_Y_Z:
					// x = z, z = y, y = -x
					tmp.x = rayOrigin.z;
					tmp.z = rayOrigin.y;
					tmp.y = -rayOrigin.x;
					rayOrigin = tmp;
					tmp.x = rayDirection.z;
					tmp.z = rayDirection.y;
					tmp.y = -rayDirection.x;
					rayDirection = tmp;
					break;

				case Alignment.Align_X_Z:
					// already in X/Z but values increase in -Z
					rayOrigin.z = -rayOrigin.z;
					rayDirection.z = -rayDirection.z;
					break;
			}
			// readjust coordinate origin
			rayOrigin.x += this.mWorldSize/2;
			rayOrigin.z += this.mWorldSize/2;
			// scale down to vertex level
			rayOrigin.x /= this.mScale;
			rayOrigin.z /= this.mScale;
			rayDirection.x /= this.mScale;
			rayDirection.z /= this.mScale;
			rayDirection.Normalize();
			var localRay = new Ray( rayOrigin, rayDirection );

			// test if the ray actually hits the terrain's bounds
			var maxHeight = MaxHeight;
			var minHeight = MinHeight;

			var aabb = new AxisAlignedBox( new Vector3( 0, minHeight, 0 ), new Vector3( this.mSize, maxHeight, this.mSize ) );
			var aabbTest = localRay.Intersects( aabb );
			if ( !aabbTest.Hit )
			{
				if ( cascadeToNeighbours )
				{
					var neighbour = RaySelectNeighbour( ray, distanceLimit );
					if ( neighbour != null )
					{
						return neighbour.RayIntersects( ray, cascadeToNeighbours, distanceLimit );
					}
				}
				return new KeyValuePair<bool, Vector3>( false, new Vector3() );
			}
			// get intersection point and move inside
			var cur = localRay.GetPoint( aabbTest.Distance );

			// now check every quad the ray touches
			var quadX = Utility.Min( Utility.Max( (int)( cur.x ), 0 ), (int)this.mSize - 2 );
			var quadZ = Utility.Min( Utility.Max( (int)( cur.z ), 0 ), (int)this.mSize - 2 );
			var flipX = ( rayDirection.x < 0 ? 0 : 1 );
			var flipZ = ( rayDirection.z < 0 ? 0 : 1 );
			var xDir = ( rayDirection.x < 0 ? -1 : 1 );
			var zDir = ( rayDirection.z < 0 ? -1 : 1 );

			Result = new KeyValuePair<bool, Vector3>( true, Vector3.Zero );
			var dummyHighValue = (Real)this.mSize*10000;

			while ( cur.y >= ( minHeight - 1e-3 ) && cur.y <= ( maxHeight + 1e-3 ) )
			{
				if ( quadX < 0 || quadX >= (int)this.mSize - 1 || quadZ < 0 || quadZ >= (int)this.mSize - 1 )
				{
					break;
				}

				Result = CheckQuadIntersection( quadX, quadZ, localRay );
				if ( Result.Key )
				{
					break;
				}

				// determine next quad to test
				var xDist = Utility.RealEqual( rayDirection.x, 0.0f ) ? dummyHighValue : ( quadX - cur.x + flipX )/rayDirection.x;
				var zDist = Utility.RealEqual( rayDirection.z, 0.0f ) ? dummyHighValue : ( quadZ - cur.z + flipZ )/rayDirection.z;
				if ( xDist < zDist )
				{
					quadX += xDir;
					cur += rayDirection*xDist;
				}
				else
				{
					quadZ += zDir;
					cur += rayDirection*zDist;
				}
			}
			var resVec = Vector3.Zero;

			if ( Result.Key )
			{
				// transform the point of intersection back to world space
				resVec = Result.Value;
				resVec.x *= this.mScale;
				resVec.z *= this.mScale;
				resVec.x -= this.mWorldSize/2;
				resVec.z -= this.mWorldSize/2;
				switch ( Alignment )
				{
					case Alignment.Align_X_Y:
						Utility.Swap<Real>( ref resVec.y, ref resVec.z );
						break;

					case Alignment.Align_Y_Z:
						// z = x, y = z, x = -y
						tmp.x = -rayOrigin.y;
						tmp.y = rayOrigin.z;
						tmp.z = rayOrigin.x;
						rayOrigin = tmp;
						break;

					case Alignment.Align_X_Z:
						resVec.z = -resVec.z;
						break;
				}
				resVec += Position;
			}
			else if ( cascadeToNeighbours )
			{
				var neighbour = RaySelectNeighbour( ray, distanceLimit );
				if ( neighbour != null )
				{
					Result = neighbour.RayIntersects( ray, cascadeToNeighbours, distanceLimit );
				}
			}
			return new KeyValuePair<bool, Vector3>( Result.Key, resVec );
		}
예제 #14
0
		// Given line pq and ccw triangle abc, return whether line pierces triangle. If
		// so, also return the barycentric coordinates (u,v,w) of the intersection point
		protected bool RayIntersectsTriangle( Ray ray, Vector3[] Vertices, ref Matrix4 transform, ref Vector3 where )
		{
			// Place the end beyond any conceivable triangle, 1000 meters away
			var a = transform*Vertices[ 0 ];
			var b = transform*Vertices[ 1 ];
			var c = transform*Vertices[ 2 ];
			var start = ray.Origin;
			var end = start + ray.Direction*1000000f;
			var pq = end - start;
			var pa = a - start;
			var pb = b - start;
			var pc = c - start;
			// Test if pq is inside the edges bc, ca and ab. Done by testing
			// that the signed tetrahedral volumes, computed using scalar triple
			// products, are all positive
			float u = pq.Cross( pc ).Dot( pb );
			if ( u < 0.0f )
			{
				return false;
			}
			float v = pq.Cross( pa ).Dot( pc );
			if ( v < 0.0f )
			{
				return false;
			}
			float w = pq.Cross( pb ).Dot( pa );
			if ( w < 0.0f )
			{
				return false;
			}
			var denom = 1.0f/( u + v + w );
			// Finally fill in the intersection point
			where = ( u*a + v*b + w*c )*denom;
			return true;
		}
예제 #15
0
		public void FindNodesIn( Ray r, ref List<PCZSceneNode> list, PCZone startZone, PCZSceneNode exclude )
		{
			var visitedPortals = new List<Portal>();
			if ( null != startZone )
			{
				// start in startzone, and recurse through portals if necessary
				startZone.FindNodes( r, ref list, visitedPortals, true, true, exclude );
			}
			else
			{
				foreach ( PCZone zone in this.zones )
				{
					zone.FindNodes( r, ref list, visitedPortals, false, false, exclude );
				}
			}
		}
예제 #16
0
		public Terrain RaySelectNeighbour( Ray ray, Real distanceLimit )
		{
			var modifiedRay = new Ray( ray.Origin, ray.Direction );
			// Move back half a square - if we're on the edge of the AABB we might
			// miss the intersection otherwise; it's ok for everywhere else since
			// we want the far intersection anyway
			modifiedRay.Origin = modifiedRay.GetPoint( -this.mWorldSize/this.mSize*0.5f );

			// transform into terrain space
			var tPos = Vector3.Zero;
			var tDir = Vector3.Zero;
			ConvertPosition( Space.WorldSpace, modifiedRay.Origin, Space.TerrainSpace, ref tPos );
			ConvertDirection( Space.WorldSpace, modifiedRay.Direction, Space.TerrainSpace, ref tDir );
			// Discard rays with no lateral component
			if ( Utility.RealEqual( tDir.x, 0.0f, 1e-4 ) && Utility.RealEqual( tDir.y, 0.0f, 1e-4 ) )
			{
				return null;
			}

			var terrainRay = new Ray( tPos, tDir );
			// Intersect with boundary planes 
			// Only collide with the positive (exit) side of the plane, because we may be
			// querying from a point outside ourselves if we've cascaded more than once
			var dist = Real.MaxValue;
			IntersectResult intersectResult;
			if ( tDir.x < 0.0f )
			{
				intersectResult = Utility.Intersects( terrainRay, new Plane( Vector3.UnitX, Vector3.Zero ) );
				if ( intersectResult.Hit && intersectResult.Distance < dist )
				{
					dist = intersectResult.Distance;
				}
			}
			else if ( tDir.x > 0.0f )
			{
				intersectResult = Utility.Intersects( terrainRay, new Plane( Vector3.NegativeUnitX, Vector3.UnitX ) );
				if ( intersectResult.Hit && intersectResult.Distance < dist )
				{
					dist = intersectResult.Distance;
				}
			}
			if ( tDir.y < 0.0f )
			{
				intersectResult = Utility.Intersects( terrainRay, new Plane( Vector3.UnitY, Vector3.Zero ) );
				if ( intersectResult.Hit && intersectResult.Distance < dist )
				{
					dist = intersectResult.Distance;
				}
			}
			else if ( tDir.y > 0.0f )
			{
				intersectResult = Utility.Intersects( terrainRay, new Plane( Vector3.NegativeUnitY, Vector3.UnitY ) );
				if ( intersectResult.Hit && intersectResult.Distance < dist )
				{
					dist = intersectResult.Distance;
				}
			}

			// discard out of range
			if ( dist*this.mWorldSize > distanceLimit )
			{
				return null;
			}

			var terrainIntersectPos = terrainRay.GetPoint( dist );
			var x = terrainIntersectPos.x;
			var y = terrainIntersectPos.y;
			var dx = tDir.x;
			var dy = tDir.y;

			// Never return diagonal directions, we will navigate those recursively anyway
			if ( Utility.RealEqual( x, 1.0f, 1e-4f ) && dx > 0 )
			{
				return GetNeighbour( NeighbourIndex.East );
			}

			else if ( Utility.RealEqual( x, 0.0f, 1e-4f ) && dx < 0 )
			{
				return GetNeighbour( NeighbourIndex.West );
			}

			else if ( Utility.RealEqual( y, 1.0f, 1e-4f ) && dy > 0 )
			{
				return GetNeighbour( NeighbourIndex.North );
			}

			else if ( Utility.RealEqual( y, 0.0f, 1e-4f ) && dy < 0 )
			{
				return GetNeighbour( NeighbourIndex.South );
			}

			return null;
		}
예제 #17
0
		public bool CalculateCurrentLod( Camera cam, Real cFactor )
		{
			this.mSelfOrChildRendered = false;

			//check children first.
			int childrenRenderedOut = 0;
			if ( !IsLeaf )
			{
				for ( int i = 0; i < 4; ++i )
				{
					if ( this.mChildren[ i ].CalculateCurrentLod( cam, cFactor ) )
					{
						++childrenRenderedOut;
					}
				}
			}

			if ( childrenRenderedOut == 0 )
			{
				// no children were within their LOD ranges, so we should consider our own
				Vector3 localPos = cam.DerivedPosition - this.mLocalCentre - this.mTerrain.Position;
				Real dist;
				if ( TerrainGlobalOptions.UseRayBoxDistanceCalculation )
				{
					// Get distance to this terrain node (to closest point of the box)
					// head towards centre of the box (note, box may not cover mLocalCentre because of height)
					var dir = this.mAABB.Center - localPos;
					dir.Normalize();
					var ray = new Ray( localPos, dir );
					var intersectRes = ray.Intersects( this.mAABB );

					// ray will always intersect, we just want the distance
					dist = intersectRes.Distance;
				}
				else
				{
					// distance to tile centre
					dist = localPos.Length;
					// deduct half the radius of the box, assume that on average the 
					// worst case is best approximated by this
					dist -= ( this.mBoundingRadius*0.5f );
				}

				// Do material LOD
				var material = Material;
				LodStrategy str = material.LodStrategy;
				Real lodValue = str.GetValue( this.mMovable, cam );
				// Get the index at this biased depth
				this.mMaterialLodIndex = (ushort)material.GetLodIndex( lodValue );


				// For each LOD, the distance at which the LOD will transition *downwards*
				// is given by 
				// distTransition = maxDelta * cFactor;
				int lodLvl = 0;
				this.mCurrentLod = -1;
				foreach ( LodLevel i in this.mLodLevels )
				{
					// If we have no parent, and this is the lowest LOD, we always render
					// this is the 'last resort' so to speak, we always enoucnter this last
					if ( lodLvl + 1 == this.mLodLevels.Count && this.mParent == null )
					{
						CurrentLod = lodLvl;
						this.mSelfOrChildRendered = true;
						this.mLodTransition = 0;
					}
					else
					{
						//check the distance
						LodLevel ll = i;
						// Calculate or reuse transition distance
						Real distTransition;
						if ( Utility.RealEqual( cFactor, ll.LastCFactor ) )
						{
							distTransition = ll.LastTransitionDist;
						}
						else
						{
							distTransition = ll.MaxHeightDelta*cFactor;
							ll.LastCFactor = cFactor;
							ll.LastTransitionDist = distTransition;
						}

						if ( dist < distTransition )
						{
							// we're within range of this LOD
							CurrentLod = lodLvl;
							this.mSelfOrChildRendered = true;

							if ( this.mTerrain.IsMorphRequired )
							{
								// calculate the transition percentage
								// we need a percentage of the total distance for just this LOD, 
								// which means taking off the distance for the next higher LOD
								// which is either the previous entry in the LOD list, 
								// or the largest of any children. In both cases these will
								// have been calculated before this point, since we process
								// children first. Distances at lower LODs are guaranteed
								// to be larger than those at higher LODs

								Real distTotal = distTransition;
								if ( IsLeaf )
								{
									// Any higher LODs?
									if ( !i.Equals( this.mLodLevels[ 0 ] ) )
									{
										int prev = lodLvl - 1;
										distTotal -= this.mLodLevels[ prev ].LastTransitionDist;
									}
								}
								else
								{
									// Take the distance of the lowest LOD of child
									LodLevel childLod =
										this.mChildWithMaxHeightDelta.GetLodLevel( (ushort)( this.mChildWithMaxHeightDelta.LodCount - 1 ) );
									distTotal -= childLod.LastTransitionDist;
								}
								// fade from 0 to 1 in the last 25% of the distance
								Real distMorphRegion = distTotal*0.25f;
								Real distRemain = distTransition - dist;

								this.mLodTransition = 1.0f - ( distRemain/distMorphRegion );
								this.mLodTransition = System.Math.Min( 1.0f, this.mLodTransition );
								this.mLodTransition = System.Math.Max( 0.0f, this.mLodTransition );

								// Pass both the transition % and target LOD (GLOBAL current + 1)
								// this selectively applies the morph just to the
								// vertices which would drop out at this LOD, even 
								// while using the single shared vertex data
								this.mRend.SetCustomParameter( Terrain.LOD_MORPH_CUSTOM_PARAM,
								                               new Vector4( this.mLodTransition, this.mCurrentLod + this.mBaseLod + 1, 0, 0 ) );
							} //end if

							// since LODs are ordered from highest to lowest detail, 
							// we can stop looking now
							break;
						} //end if
					} //end else
					++lodLvl;
				} //end for each
			} //end if
			else
			{
				// we should not render ourself
				this.mCurrentLod = -1;
				this.mSelfOrChildRendered = true;
				if ( childrenRenderedOut < 4 )
				{
					// only *some* children decided to render on their own, but either 
					// none or all need to render, so set the others manually to their lowest
					for ( int i = 0; i < 4; ++i )
					{
						TerrainQuadTreeNode child = this.mChildren[ i ];
						if ( !child.IsSelfOrChildrenRenderedAtCurrentLod )
						{
							child.CurrentLod = child.LodCount - 1;
							child.LodTransition = 1.0f;
						}
					}
				} //(childRenderedCount < 4)
			} // (childRenderedCount == 0)

			return this.mSelfOrChildRendered;
		}
예제 #18
0
		/// <see cref="Terrain.RaySelectNeighbour(Ray, Real)"/>
		public Terrain RaySelectNeighbour( Ray ray )
		{
			return RaySelectNeighbour( ray, 0 );
		}
예제 #19
0
		public override bool FrameRenderingQueued( FrameEventArgs evt )
		{
			if ( this.mode != Mode.Normal )
			{
				// fire ray
				Ray ray;
				ray = TrayManager.GetCursorRay( Camera );

				var rayResult = this.terrainGroup.RayIntersects( ray );
				if ( rayResult.Hit )
				{
					this.editMarker.IsVisible = true;
					this.editNode.Position = rayResult.Position;

					// figure out which terrains this affects
					List<Axiom.Components.Terrain.Terrain> terrainList;
					var brushSizeWorldSpace = TerrainWorldSize*this.brushSizeTerrainSpace;
					var sphere = new Sphere( rayResult.Position, brushSizeWorldSpace );
					this.terrainGroup.SphereIntersects( sphere, out terrainList );

					foreach ( var ti in terrainList )
					{
						DoTerrainModify( ti, rayResult.Position, evt.TimeSinceLastFrame );
					}
				}
				else
				{
					this.editMarker.IsVisible = false;
				}
			}

			if ( !this.fly )
			{
				// clamp to terrain
				var camPos = Camera.Position;
				var ray = new Ray( new Vector3( camPos.x, this.terrainPos.y + 10000, camPos.z ), Vector3.NegativeUnitY );

				TerrainGroup.RayResult rayResult = this.terrainGroup.RayIntersects( ray );
				Real distanceAboveTerrain = 50;
				Real fallSpeed = 300;
				Real newy = camPos.y;
				if ( rayResult.Hit )
				{
					if ( camPos.y > rayResult.Position.y + distanceAboveTerrain )
					{
						this.fallVelocity += evt.TimeSinceLastFrame*20;
						this.fallVelocity = Utility.Min( this.fallVelocity, fallSpeed );
						newy = camPos.y - this.fallVelocity*evt.TimeSinceLastFrame;
					}
					newy = Utility.Max( rayResult.Position.y + distanceAboveTerrain, newy );
					Camera.Position = new Vector3( camPos.x, newy, camPos.z );
				}
			}

			if ( this.heightUpdateCountDown > 0 )
			{
				this.heightUpdateCountDown -= evt.TimeSinceLastFrame;
				if ( this.heightUpdateCountDown <= 0 )
				{
					this.terrainGroup.Update();
					this.heightUpdateCountDown = 0;
				}
			}

			if ( this.terrainGroup.IsDerivedDataUpdateInProgress )
			{
				TrayManager.MoveWidgetToTray( this.infoLabel, TrayLocation.Top, 0 );
				this.infoLabel.Show();
				if ( this.terrainsImported )
				{
					this.infoLabel.Caption = "Building terrain, please wait...";
				}
				else
				{
					this.infoLabel.Caption = "Updating textures, patience...";
				}
			}
			else
			{
				TrayManager.RemoveWidgetFromTray( this.infoLabel );
				this.infoLabel.Hide();
				if ( this.terrainsImported )
				{
					SaveTerrains( true );
					this.terrainsImported = false;
				}
			}

			return base.FrameRenderingQueued( evt );
		}
예제 #20
0
		/// <summary>
		///    Creates a query to return objects found along the ray.
		/// </summary>
		/// <param name="ray">Ray to use for the intersection query.</param>
		/// <returns>A specialized implementation of RaySceneQuery for this scene manager.</returns>
		public override RaySceneQuery CreateRayQuery( Ray ray )
		{
			return CreateRayQuery( ray, 0xffffffff );
		}
예제 #21
0
		public void _findNodes( Ray t, ref List<PCZSceneNode> list, PCZSceneNode exclude, bool includeVisitors, bool full )
		{
			if ( !full )
			{
				AxisAlignedBox obox;
				_getCullBounds( out obox );

				Intersection isect = intersect( t, obox );

				if ( isect == Intersection.OUTSIDE )
				{
					return;
				}

				full = ( isect == Intersection.INSIDE );
			}

			foreach ( PCZSceneNode on in this.nodeList.Values )
			{
				if ( on != exclude && ( on.HomeZone == this.zone || includeVisitors ) )
				{
					if ( full )
					{
						// make sure the node isn't already on the list
						list.Add( on );
					}

					else
					{
						Intersection nsect = intersect( t, on.WorldAABB );

						if ( nsect != Intersection.OUTSIDE )
						{
							// make sure the node isn't already on the list
							list.Add( on );
						}
					}
				}
			}

			Octree child;

			if ( ( child = this.Children[ 0, 0, 0 ] ) != null )
			{
				child._findNodes( t, ref list, exclude, includeVisitors, full );
			}

			if ( ( child = this.Children[ 1, 0, 0 ] ) != null )
			{
				child._findNodes( t, ref list, exclude, includeVisitors, full );
			}

			if ( ( child = this.Children[ 0, 1, 0 ] ) != null )
			{
				child._findNodes( t, ref list, exclude, includeVisitors, full );
			}

			if ( ( child = this.Children[ 1, 1, 0 ] ) != null )
			{
				child._findNodes( t, ref list, exclude, includeVisitors, full );
			}

			if ( ( child = this.Children[ 0, 0, 1 ] ) != null )
			{
				child._findNodes( t, ref list, exclude, includeVisitors, full );
			}

			if ( ( child = this.Children[ 1, 0, 1 ] ) != null )
			{
				child._findNodes( t, ref list, exclude, includeVisitors, full );
			}

			if ( ( child = this.Children[ 0, 1, 1 ] ) != null )
			{
				child._findNodes( t, ref list, exclude, includeVisitors, full );
			}

			if ( ( child = this.Children[ 1, 1, 1 ] ) != null )
			{
				child._findNodes( t, ref list, exclude, includeVisitors, full );
			}
		}
예제 #22
0
		/// <summary>
		///    Creates a query to return objects found along the ray.
		/// </summary>
		/// <param name="ray">Ray to use for the intersection query.</param>
		/// <returns>A specialized implementation of RaySceneQuery for this scene manager.</returns>
		public override RaySceneQuery CreateRayQuery( Ray ray, uint mask )
		{
			var query = new TerrainRaySceneQuery( this );
			query.Ray = ray;
			query.QueryMask = mask;
			return query;
		}
예제 #23
0
		protected virtual void ProcessNode( BspNode node, Ray tracingRay, float maxDistance, float traceDistance )
		{
			// check if ray already encountered a solid brush
			if ( this.StopRayTracing )
			{
				return;
			}

			if ( node.IsLeaf )
			{
				ProcessLeaf( node, tracingRay, maxDistance, traceDistance );
				return;
			}

			IntersectResult result = tracingRay.Intersects( node.SplittingPlane );
			if ( result.Hit )
			{
				if ( result.Distance < maxDistance )
				{
					if ( node.GetSide( tracingRay.Origin ) == PlaneSide.Negative )
					{
						ProcessNode( node.BackNode, tracingRay, result.Distance, traceDistance );
						Vector3 splitPoint = tracingRay.Origin + tracingRay.Direction*result.Distance;
						ProcessNode( node.FrontNode, new Ray( splitPoint, tracingRay.Direction ), maxDistance - result.Distance,
						             traceDistance + result.Distance );
					}
					else
					{
						ProcessNode( node.FrontNode, tracingRay, result.Distance, traceDistance );
						Vector3 splitPoint = tracingRay.Origin + tracingRay.Direction*result.Distance;
						ProcessNode( node.BackNode, new Ray( splitPoint, tracingRay.Direction ), maxDistance - result.Distance,
						             traceDistance + result.Distance );
					}
				}
				else
				{
					ProcessNode( node.GetNextNode( tracingRay.Origin ), tracingRay, maxDistance, traceDistance );
				}
			}
			else
			{
				ProcessNode( node.GetNextNode( tracingRay.Origin ), tracingRay, maxDistance, traceDistance );
			}
		}
예제 #24
0
 /// <summary>
 /// 
 /// </summary>
 /// <param name="ray"></param>
 /// <returns></returns>
 public RayResult RayIntersects(Ray ray)
 {
     return RayIntersects(ray, 0);
 }
예제 #25
0
		/// <summary>
		///		Creates a RaySceneQuery for this scene manager.
		/// </summary>
		/// <remarks>
		///		This method creates a new instance of a query object for this scene manager,
		///		looking for objects which fall along a ray. See SceneQuery and RaySceneQuery
		///		for full details.
		/// </remarks>
		/// <param name="ray">Details of the ray which describes the region for this query.</param>
		/// <param name="mask">The query mask to apply to this query; can be used to filter out certain objects; see SceneQuery for details.</param>
		public override RaySceneQuery CreateRayQuery( Ray ray, uint mask )
		{
			var q = new BspRaySceneQuery( this );
			q.Ray = ray;
			q.QueryMask = mask;

			return q;
		}
예제 #26
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="ray"></param>
        /// <param name="distanceLimit"></param>
        /// <returns></returns>
        public RayResult RayIntersects(Ray ray, float distanceLimit)
        {
            long curr_x = 0, curr_z = 0;
            ConvertWorldPositionToTerrainSlot(ray.Origin, out curr_x, out curr_z);
            TerrainSlot slot = GetTerrainSlot(curr_x, curr_z);

            RayResult result = new RayResult(false, null, Vector3.Zero);

            Vector3 tmp, localRayDir, centreOrigin, offset;
            tmp = localRayDir = centreOrigin = offset = Vector3.Zero;
            ConvertTerrainSlotToWorldPosition(curr_x, curr_z, out centreOrigin);
            offset = ray.Origin - centreOrigin;
            localRayDir = ray.Direction;
            switch (Alignment)
            {
                case Alignment.Align_X_Y:
                    float t1 = localRayDir.x, t2 = localRayDir.z;
                    Swap(t1, t2);
                    localRayDir = new Vector3(t1, localRayDir.y, t2);
                    t1 = offset.x;
                    t2 = offset.z;
                    Swap(t1, t2);
                    localRayDir = new Vector3(t1, offset.y, t2);
                    break;
                case Alignment.Align_Y_Z:
                    // x = z, z = y, y = -x
                    tmp.x = localRayDir.z; 
                    tmp.z = localRayDir.y; 
                    tmp.y = -localRayDir.x; 
                    localRayDir = tmp;
                    tmp.x = offset.z; 
                    tmp.z = offset.y; 
                    tmp.y = -offset.x; 
                    offset = tmp;
                    break;
                case Alignment.Align_X_Z:
                    // already in X/Z but values increase in -Z
                    localRayDir.z = -localRayDir.z;
                    offset.z = -offset.z;
                    break;
            }

            offset /= _terrainWorldSize;
            offset = new Vector3(offset.x +0.5f,offset.y + 0.5f, offset.z +0.5f);
            Vector3 inc = new Vector3(Math.Utility.Abs(localRayDir.x), Math.Utility.Abs(localRayDir.y), Math.Utility.Abs(localRayDir.z));
            long xdir = localRayDir.x > 0.0f ? 1 : -1;
            long zdir = localRayDir.z > 0.0f ? 1 : -1;

            // We're always counting from 0 to 1 regardless of what direction we're heading
	                if (xdir < 0)
	                        offset.x = 1.0f - offset.x;
	                if (zdir < 0)
	                        offset.z = 1.0f - offset.z;
	
	                // find next slot
	                bool keepSearching = true;
	                int numGaps = 0;
                    while (keepSearching)
                    {
                        if (Math.Utility.RealEqual(inc.x, 0.0f) && Math.Utility.RealEqual(inc.z, 0.0f))
                            keepSearching = false;

                        while ((slot != null || slot.Instance != null) && keepSearching)
                        {
                            ++numGaps;
                            /// if we don't find any filled slot in 6 traversals, give up
                            if (numGaps > 6)
                            {
                                keepSearching = false;
                                break;
                            }
                            // find next slot
                            Vector3 oldoffset = offset;
                            while (offset.x < 1.0f && offset.z < 1.0f)
                                offset += inc;
                            if (offset.x >= 1.0f && offset.z >= 1.0f)
                            {
                                // We crossed a corner, need to figure out which we passed first
                                Real diffz = 1.0f - oldoffset.z;
                                Real diffx = 1.0f - oldoffset.x;
                                Real distz = diffz / inc.z;
                                Real distx = diffx / inc.x;
                                if (distx < distz)
                                {
                                    curr_x += xdir;
                                    offset.x -= 1.0f;
                                }
                                else
                                {
                                    curr_z += zdir;
                                    offset.z -= 1.0f;
                                }

                            }
                            else if (offset.x >= 1.0f)
                            {
                                curr_x += xdir;
                                offset.x -= 1.0f;
                            }
                            else if (offset.z >= 1.0f)
                            {
                                curr_z += zdir;
                                offset.z -= 1.0f;
                            }
                            if (distanceLimit > 0)
                            {
                                Vector3 worldPos;
                                ConvertTerrainSlotToWorldPosition(curr_x, curr_z, out worldPos);
                                if (ray.Origin.Distance(worldPos) > distanceLimit)
                                {
                                    keepSearching = false;
                                    break;
                                }
                            }
                            slot = GetTerrainSlot(curr_x, curr_z);
                        }
                        if (slot != null && slot.Instance != null)
                        {
                            numGaps = 0;
                            // don't cascade into neighbours
                            KeyValuePair<bool, Vector3> raypair = slot.Instance.RayIntersects(ray, false, distanceLimit);
                            if (raypair.Key)
                            {
                                keepSearching = false;
                                result.Hit = true;
                                result.Terrain = slot.Instance;
                                result.Position = raypair.Value;
                                break;
                            }
                            else
                            {
                                // not this one, trigger search for another slot
                                slot = null;
                            }
                        }

                    }
	
	
	                return result;
        }
예제 #27
0
		public override void FindNodes( Ray t,
									  ref List<PCZSceneNode> list,
									  List<Portal> visitedPortals,
									  bool includeVisitors,
									  bool recurseThruPortals,
									  PCZSceneNode exclude )
		{
			// if this zone has an enclosure, check against the enclosure AABB first
			if ( null != mEnclosureNode )
			{
				IntersectResult nsect = t.Intersects( mEnclosureNode.WorldAABB );
				if ( !nsect.Hit )
				{
					// AABB of zone does not intersect t, just return.
					return;
				}
			}

			// check nodes at home in this zone
			foreach ( PCZSceneNode pczsn in mHomeNodeList )
			{
				if ( pczsn != exclude )
				{
					// make sure node is not already in the list (might have been added in another
					// zone it was visiting)
					if ( !list.Contains( pczsn ) )
					{
						IntersectResult nsect = t.Intersects( pczsn.WorldAABB );
						if ( nsect.Hit )
						{
							list.Add( pczsn );
						}
					}
				}
			}

			if ( includeVisitors )
			{
				// check visitor nodes
				foreach ( PCZSceneNode pczsn in mVisitorNodeList )
				{
					if ( pczsn != exclude )
					{
						// make sure node is not already in the list (might have been added in another
						// zone it was visiting)

						if ( !list.Contains( pczsn ) )
						{
							IntersectResult nsect = t.Intersects( pczsn.WorldAABB );
							if ( nsect.Hit )
							{
								list.Add( pczsn );
							}
						}
					}
				}
			}

			// if asked to, recurse through portals
			if ( recurseThruPortals )
			{
				foreach ( Portal portal in mPortals )
				{
					// check portal versus boundign box
					if ( portal.intersects( t ) )
					{
						// make sure portal hasn't already been recursed through
						if ( !visitedPortals.Contains( portal ) )
						{
							// save portal to the visitedPortals list
							visitedPortals.Add( portal );
							// recurse into the connected zone
							portal.getTargetZone().FindNodes( t,
																ref list,
																visitedPortals,
																includeVisitors,
																recurseThruPortals,
																exclude );
						}
					}
				}
			}

		}
예제 #28
0
		protected override void OnFrameStarted( object source, FrameEventArgs evt )
		{
			buildingTranslate = new Vector3( 0, 0, 0 );
			if ( input.IsKeyPressed( KeyCodes.U ) )
			{
				buildingTranslate = new Vector3( 0, -10, 0 );
			}
			if ( input.IsKeyPressed( KeyCodes.I ) )
			{
				buildingTranslate = new Vector3( 0, 10, 0 );
			}

			if ( input.IsKeyPressed( KeyCodes.LeftShift ) ||
				input.IsKeyPressed( KeyCodes.RightShift ) )
			{
				mMoveSpeed = 150;
			}
			else
			{
				mMoveSpeed = 15;
			}

			// test the ray scene query by showing bounding box of whatever the camera is pointing directly at
			// (takes furthest hit)
			Ray updateRay = new Ray();
			updateRay.Origin = camera.ParentSceneNode.Position;
			updateRay.Direction = camera.ParentSceneNode.Orientation * Vector3.NegativeUnitZ;
			raySceneQuery.Ray = updateRay;
			PCZone zone = ( (PCZSceneNode)( camera.ParentSceneNode ) ).HomeZone;
			( (PCZRaySceneQuery)raySceneQuery ).StartZone = zone;
			( (PCZRaySceneQuery)raySceneQuery ).ExcludeNode = camera.ParentSceneNode;
			raySceneQuery.Execute( l );

			base.OnFrameStarted( source, evt );
		}
예제 #29
0
	    /// <summary>
	    ///    Creates a query to return objects found along the ray.
	    /// </summary>
	    /// <param name="ray">Ray to use for the intersection query.</param>
	    /// <param name="mask"></param>
	    /// <returns>A specialized implementation of RaySceneQuery for this scene manager.</returns>
	    public virtual RaySceneQuery CreateRayQuery( Ray ray, uint mask )
		{
			DefaultRaySceneQuery query = new DefaultRaySceneQuery( this );
			query.Ray = ray;
			query.QueryMask = mask;
			return query;
		}
예제 #30
0
파일: Portal.cs 프로젝트: WolfgangSt/axiom
		// Check if a portal intersects a ray
		// NOTE: Kinda using my own invented routine here for quad portals... Better do a lot of testing!
		public bool intersects( Ray ray )
		{
			// Only check if portal is open
			if ( mOpen )
			{
				if ( mType == PORTAL_TYPE.PORTAL_TYPE_QUAD )
				{
					// since ogre doesn't have built in support for a quad, I'm going to first
					// find the intersection point (if any) of the ray and the portal plane.  Then
					// using the intersection point, I take the cross product of each side of the portal
					// (0,1,intersect), (1,2, intersect), (2,3, intersect), and (3,0,intersect).  If
					// all 4 cross products have vectors pointing in the same direction, then the
					// intersection point is within the portal, otherwise it is outside.

					IntersectResult result = ray.Intersects( mDerivedPlane );

					if ( result.Hit )
					{
						// the ray intersects the plane, now walk around the edges
						Vector3 isect = ray.GetPoint( result.Distance );
						Vector3 cross, vect1, vect2;
						Vector3 cross2, vect3, vect4;
						vect1 = mDerivedCorners[ 1 ] - mDerivedCorners[ 0 ];
						vect2 = isect - mDerivedCorners[ 0 ];
						cross = vect1.Cross( vect2 );
						vect3 = mDerivedCorners[ 2 ] - mDerivedCorners[ 1 ];
						vect4 = isect - mDerivedCorners[ 1 ];
						cross2 = vect3.Cross( vect4 );
						if ( cross.Dot( cross2 ) < 0 )
						{
							return false;
						}
						vect1 = mDerivedCorners[ 3 ] - mDerivedCorners[ 2 ];
						vect2 = isect - mDerivedCorners[ 2 ];
						cross = vect1.Cross( vect2 );
						if ( cross.Dot( cross2 ) < 0 )
						{
							return false;
						}
						vect1 = mDerivedCorners[ 0 ] - mDerivedCorners[ 3 ];
						vect2 = isect - mDerivedCorners[ 3 ];
						cross = vect1.Cross( vect2 );
						if ( cross.Dot( cross2 ) < 0 )
						{
							return false;
						}
						// all cross products pointing same way, so intersect
						// must be on the inside of the portal!
						return true;
					}

					return false;
				}
				else if ( mType == PORTAL_TYPE.PORTAL_TYPE_AABB )
				{
					AxisAlignedBox aabb = new AxisAlignedBox( mDerivedCorners[ 0 ], mDerivedCorners[ 1 ] );
					IntersectResult result = ray.Intersects( aabb );
					return result.Hit;
				}
				else // sphere
				{
					IntersectResult result = ray.Intersects( mDerivedSphere );
					return result.Hit;
				}
			}
			return false;
		}