GetPoint() public méthode

Gets the position of a point t units along the ray.
public GetPoint ( Real t ) : Vector3
t Real
Résultat Vector3
Exemple #1
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;
		}
Exemple #2
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 );
				}
			}
		}
Exemple #3
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 );
		}
Exemple #4
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 );
		}
Exemple #5
0
		// 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;
		}