本文整理汇总了C#中BEPUutilities.Ray类的典型用法代码示例。如果您正苦于以下问题:C# Ray类的具体用法?C# Ray怎么用?C# Ray使用的例子?那么恭喜您, 这里精选的类代码示例或许可以为您提供帮助。
Ray类属于BEPUutilities命名空间,在下文中一共展示了Ray类的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C#代码示例。
示例1: RayCast
/// <summary>
/// Computes the intersection, if any, between a ray and the objects in the character's bounding box.
/// </summary>
/// <param name="ray">Ray to test.</param>
/// <param name="length">Length of the ray to use in units of the ray's length.</param>
/// <param name="earliestHit">Earliest intersection location and information.</param>
/// <param name="hitObject">Collidable intersected by the ray, if any.</param>
/// <returns>Whether or not the ray hit anything.</returns>
public bool RayCast(Ray ray, float length, out RayHit earliestHit, out Collidable hitObject)
{
earliestHit = new RayHit();
earliestHit.T = float.MaxValue;
hitObject = null;
foreach (var collidable in characterBody.CollisionInformation.OverlappedCollidables)
{
//Check to see if the collidable is hit by the ray.
float t;
if (ray.Intersects(ref collidable.boundingBox, out t) && t < length)
{
//Is it an earlier hit than the current earliest?
RayHit hit;
if (collidable.RayCast(ray, length, SupportRayFilter, out hit) && hit.T < earliestHit.T)
{
earliestHit = hit;
hitObject = collidable;
}
}
}
if (earliestHit.T == float.MaxValue)
return false;
return true;
}
示例2: RayCast
///<summary>
/// Tests a ray against the triangle mesh.
///</summary>
///<param name="ray">Ray to test against the mesh.</param>
///<param name="hitCount">Number of hits between the ray and the mesh.</param>
///<returns>Whether or not the ray hit the mesh.</returns>
public bool RayCast(Ray ray, out int hitCount)
{
var rayHits = CommonResources.GetRayHitList();
bool toReturn = RayCast(ray, rayHits);
hitCount = rayHits.Count;
CommonResources.GiveBack(rayHits);
return toReturn;
}
示例3: RayCast
/// <summary>
/// Finds all intersections between the ray and broad phase entries.
/// </summary>
/// <param name="ray">Ray to test against the structure.</param>
/// <param name="maximumLength">Maximum length of the ray in units of the ray's direction's length.</param>
/// <param name="entries">Entries which have bounding boxes that overlap the ray.</param>
public bool RayCast(Ray ray, float maximumLength, IList<BroadPhaseEntry> entries)
{
if (hierarchy.root != null)
{
hierarchy.root.GetOverlaps(ref ray, maximumLength, entries);
return entries.Count > 0;
}
return false;
}
示例4: RayCastAgainstAll
/// <summary>
///
/// </summary>
/// <param name="from"></param>
/// <param name="to"></param>
/// <param name="normal"></param>
/// <param name="pos"></param>
/// <returns></returns>
public bool RayCastAgainstAll( Vector3 from, Vector3 to, out Vector3 normal, out Vector3 pos, out Entity hitEntity, Entity skipEntity = null )
{
hitEntity = null;
var dir = to - from;
var dist = dir.Length();
var ndir = dir.Normalized();
Ray ray = new Ray( from, ndir );
normal = Vector3.Zero;
pos = to;
Func<BroadPhaseEntry, bool> filterFunc = delegate(BroadPhaseEntry bpe)
{
if (skipEntity==null) return true;
ConvexCollidable cc = bpe as ConvexCollidable;
if (cc==null) return true;
Entity ent = cc.Entity.Tag as Entity;
if (ent==null) return true;
if (ent==skipEntity) return false;
return true;
};
var rcr = new RayCastResult();
var bRay = MathConverter.Convert( ray );
bool result = physSpace.RayCast( bRay, dist, filterFunc, out rcr );
if (!result) {
return false;
}
var convex = rcr.HitObject as ConvexCollidable;
normal = MathConverter.Convert( rcr.HitData.Normal ).Normalized();
pos = MathConverter.Convert( rcr.HitData.Location );
hitEntity = (convex == null) ? null : convex.Entity.Tag as Entity;
return true;
}
示例5: RayCast
/// <summary>
/// Tests a ray against the collidable.
/// </summary>
/// <param name="ray">Ray to test.</param>
/// <param name="maximumLength">Maximum length, in units of the ray's direction's length, to test.</param>
/// <param name="result">Hit data, if any.</param>
/// <returns>Whether or not the ray hit the entry.</returns>
public bool RayCast(Ray ray, float maximumLength, out RayCastResult result)
{
var outputOverlappedElements = PhysicsResources.GetCollidableList();
CollidableTree.GetOverlaps(ray, maximumLength, outputOverlappedElements);
result = new RayCastResult();
result.HitData.T = float.MaxValue;
for (int i = 0; i < outputOverlappedElements.Count; ++i)
{
RayHit hit;
if (outputOverlappedElements.Elements[i].RayCast(ray, maximumLength, out hit))
{
if (hit.T < result.HitData.T)
{
result.HitData = hit;
result.HitObject = outputOverlappedElements.Elements[i];
}
}
}
PhysicsResources.GiveBack(outputOverlappedElements);
return result.HitData.T < float.MaxValue;
}
示例6: GetRayPlaneIntersection
/// <summary>
/// Finds the intersection between the given ray and the given plane.
/// </summary>
/// <param name="ray">Ray to test against the plane.</param>
/// <param name="p">Plane for comparison.</param>
/// <param name="t">Interval along line to intersection (A + t * AB).</param>
/// <param name="q">Intersection point.</param>
/// <returns>Whether or not the line intersects the plane. If false, the line is parallel to the plane's surface.</returns>
public static bool GetRayPlaneIntersection(ref Ray ray, ref Plane p, out float t, out Vector3 q)
{
float denominator;
Vector3.Dot(ref p.Normal, ref ray.Direction, out denominator);
if (denominator < Epsilon && denominator > -Epsilon)
{
//Surface of plane and line are parallel (or very close to it).
q = new Vector3();
t = float.MaxValue;
return false;
}
float numerator;
Vector3.Dot(ref p.Normal, ref ray.Position, out numerator);
t = (p.D - numerator) / denominator;
//Compute the intersection position.
Vector3.Multiply(ref ray.Direction, t, out q);
Vector3.Add(ref ray.Position, ref q, out q);
return t >= 0;
}
示例7: FindRayTriangleIntersection
/// <summary>
/// Determines the intersection between a ray and a triangle.
/// </summary>
/// <param name="ray">Ray to test.</param>
/// <param name="maximumLength">Maximum length to travel in units of the direction's length.</param>
/// <param name="sidedness">Sidedness of the triangle to test.</param>
/// <param name="a">First vertex of the triangle.</param>
/// <param name="b">Second vertex of the triangle.</param>
/// <param name="c">Third vertex of the triangle.</param>
/// <param name="hit">Hit data of the ray, if any</param>
/// <returns>Whether or not the ray and triangle intersect.</returns>
public static bool FindRayTriangleIntersection(ref Ray ray, float maximumLength, TriangleSidedness sidedness, ref Vector3 a, ref Vector3 b, ref Vector3 c, out RayHit hit)
{
hit = new RayHit();
Vector3 ab, ac;
Vector3.Subtract(ref b, ref a, out ab);
Vector3.Subtract(ref c, ref a, out ac);
Vector3.Cross(ref ab, ref ac, out hit.Normal);
if (hit.Normal.LengthSquared() < Epsilon)
return false; //Degenerate triangle!
float d;
Vector3.Dot(ref ray.Direction, ref hit.Normal, out d);
d = -d;
switch (sidedness)
{
case TriangleSidedness.DoubleSided:
if (d <= 0) //Pointing the wrong way. Flip the normal.
{
Vector3.Negate(ref hit.Normal, out hit.Normal);
d = -d;
}
break;
case TriangleSidedness.Clockwise:
if (d <= 0) //Pointing the wrong way. Can't hit.
return false;
break;
case TriangleSidedness.Counterclockwise:
if (d >= 0) //Pointing the wrong way. Can't hit.
return false;
Vector3.Negate(ref hit.Normal, out hit.Normal);
d = -d;
break;
}
Vector3 ap;
Vector3.Subtract(ref ray.Position, ref a, out ap);
Vector3.Dot(ref ap, ref hit.Normal, out hit.T);
hit.T /= d;
if (hit.T < 0 || hit.T > maximumLength)
return false;//Hit is behind origin, or too far away.
Vector3.Multiply(ref ray.Direction, hit.T, out hit.Location);
Vector3.Add(ref ray.Position, ref hit.Location, out hit.Location);
// Compute barycentric coordinates
Vector3.Subtract(ref hit.Location, ref a, out ap);
float ABdotAB, ABdotAC, ABdotAP;
float ACdotAC, ACdotAP;
Vector3.Dot(ref ab, ref ab, out ABdotAB);
Vector3.Dot(ref ab, ref ac, out ABdotAC);
Vector3.Dot(ref ab, ref ap, out ABdotAP);
Vector3.Dot(ref ac, ref ac, out ACdotAC);
Vector3.Dot(ref ac, ref ap, out ACdotAP);
float denom = 1 / (ABdotAB * ACdotAC - ABdotAC * ABdotAC);
float u = (ACdotAC * ABdotAP - ABdotAC * ACdotAP) * denom;
float v = (ABdotAB * ACdotAP - ABdotAC * ABdotAP) * denom;
return (u >= -Toolbox.BigEpsilon) && (v >= -Toolbox.BigEpsilon) && (u + v <= 1 + Toolbox.BigEpsilon);
}
示例8: RayCastHitAnything
/// <summary>
/// Determines if a ray intersects any object in the character's bounding box.
/// </summary>
/// <param name="ray">Ray to test.</param>
/// <param name="length">Length of the ray to use in units of the ray's length.</param>
/// <returns>Whether or not the ray hit anything.</returns>
public bool RayCastHitAnything(ref Ray ray, float length)
{
foreach (var collidable in characterBody.CollisionInformation.OverlappedCollidables)
{
//Check to see if the collidable is hit by the ray.
float t;
if (ray.Intersects(ref collidable.boundingBox, out t) && t < length)
{
RayHit hit;
if (collidable.RayCast(ray, length, SupportRayFilter, out hit))
{
return true;
}
}
}
return false;
}
示例9: TryDownCast
bool TryDownCast(ref Ray ray, float length, out bool hasTraction, out SupportRayData supportRayData)
{
RayHit earliestHit;
Collidable earliestHitObject;
supportRayData = new SupportRayData();
hasTraction = false;
if (QueryManager.RayCast(ray, length, out earliestHit, out earliestHitObject))
{
float lengthSquared = earliestHit.Normal.LengthSquared();
if (lengthSquared < Toolbox.Epsilon)
{
//Don't try to continue if the support ray is stuck in something.
return false;
}
Vector3Ex.Divide(ref earliestHit.Normal, (float)Math.Sqrt(lengthSquared), out earliestHit.Normal);
//A collidable was hit! It's a support, but does it provide traction?
earliestHit.Normal.Normalize();
float dot;
Vector3Ex.Dot(ref ray.Direction, ref earliestHit.Normal, out dot);
if (dot < 0)
{
//Calibrate the normal so it always faces the same direction relative to the body.
Vector3Ex.Negate(ref earliestHit.Normal, out earliestHit.Normal);
dot = -dot;
}
//This down cast is only used for finding supports and traction, not for finding side contacts.
//If the detected normal is too steep, toss it out.
if (dot > ContactCategorizer.TractionThreshold)
{
//It has traction!
hasTraction = true;
supportRayData = new SupportRayData { HitData = earliestHit, HitObject = earliestHitObject, HasTraction = true };
}
else if (dot > ContactCategorizer.SupportThreshold)
supportRayData = new SupportRayData { HitData = earliestHit, HitObject = earliestHitObject };
else
return false; //Too steep! Toss it out.
return true;
}
return false;
}
示例10: RayCast
/// <summary>
/// Tests a ray against the entry.
/// </summary>
/// <param name="ray">Ray to test.</param>
/// <param name="maximumLength">Maximum length, in units of the ray's direction's length, to test.</param>
/// <param name="filter">Test to apply to the entry. If it returns true, the entry is processed, otherwise the entry is ignored. If a collidable hierarchy is present
/// in the entry, this filter will be passed into inner ray casts.</param>
/// <param name="rayHit">Hit location of the ray on the entry, if any.</param>
/// <returns>Whether or not the ray hit the entry.</returns>
public virtual bool RayCast(Ray ray, float maximumLength, Func<BroadPhaseEntry, bool> filter, out RayHit rayHit)
{
if (filter(this))
return RayCast(ray, maximumLength, out rayHit);
rayHit = new RayHit();
return false;
}
示例11: RayCast
/// <summary>
/// Tests a ray against the entry.
/// </summary>
/// <param name="ray">Ray to test.</param>
/// <param name="maximumLength">Maximum length, in units of the ray's direction's length, to test.</param>
/// <param name="rayHit">Hit location of the ray on the entry, if any.</param>
/// <returns>Whether or not the ray hit the entry.</returns>
public override bool RayCast(Ray ray, float maximumLength, out RayHit rayHit)
{
//Put the ray into local space.
Ray localRay;
Matrix3x3 orientation;
Matrix3x3.CreateFromQuaternion(ref worldTransform.Orientation, out orientation);
Matrix3x3.TransformTranspose(ref ray.Direction, ref orientation, out localRay.Direction);
Vector3.Subtract(ref ray.Position, ref worldTransform.Position, out localRay.Position);
Matrix3x3.TransformTranspose(ref localRay.Position, ref orientation, out localRay.Position);
if (Shape.solidity == MobileMeshSolidity.Solid)
{
//Find all hits. Use the count to determine the ray started inside or outside.
//If it starts inside and we're in 'solid' mode, then return the ray start.
//The raycast must be of infinite length at first. This allows it to determine
//if it is inside or outside.
if (Shape.IsLocalRayOriginInMesh(ref localRay, out rayHit))
{
//It was inside!
rayHit = new RayHit() { Location = ray.Position, Normal = Vector3.Zero, T = 0 };
return true;
}
else
{
if (rayHit.T < maximumLength)
{
//Transform the hit into world space.
Vector3.Multiply(ref ray.Direction, rayHit.T, out rayHit.Location);
Vector3.Add(ref rayHit.Location, ref ray.Position, out rayHit.Location);
Matrix3x3.Transform(ref rayHit.Normal, ref orientation, out rayHit.Normal);
}
else
{
//The hit was too far away, or there was no hit (in which case T would be float.MaxValue).
return false;
}
return true;
}
}
else
{
//Just do a normal raycast since the object isn't solid.
TriangleSidedness sidedness;
switch (Shape.solidity)
{
case MobileMeshSolidity.Clockwise:
sidedness = TriangleSidedness.Clockwise;
break;
case MobileMeshSolidity.Counterclockwise:
sidedness = TriangleSidedness.Counterclockwise;
break;
default:
sidedness = TriangleSidedness.DoubleSided;
break;
}
if (Shape.TriangleMesh.RayCast(localRay, maximumLength, sidedness, out rayHit))
{
//Transform the hit into world space.
Vector3.Multiply(ref ray.Direction, rayHit.T, out rayHit.Location);
Vector3.Add(ref rayHit.Location, ref ray.Position, out rayHit.Location);
Matrix3x3.Transform(ref rayHit.Normal, ref orientation, out rayHit.Normal);
return true;
}
}
rayHit = new RayHit();
return false;
}
示例12: RayTest
/// <summary>
/// Gets the intersection between the convex shape and the ray.
/// </summary>
/// <param name="ray">Ray to test.</param>
/// <param name="transform">Transform of the convex shape.</param>
/// <param name="maximumLength">Maximum distance to travel in units of the ray direction's length.</param>
/// <param name="hit">Ray hit data, if any.</param>
/// <returns>Whether or not the ray hit the target.</returns>
public override bool RayTest(ref Ray ray, ref RigidTransform transform, float maximumLength, out RayHit hit)
{
//Put the ray into local space.
Quaternion conjugate;
Quaternion.Conjugate(ref transform.Orientation, out conjugate);
Ray localRay;
Vector3.Subtract(ref ray.Position, ref transform.Position, out localRay.Position);
Quaternion.Transform(ref localRay.Position, ref conjugate, out localRay.Position);
Quaternion.Transform(ref ray.Direction, ref conjugate, out localRay.Direction);
//Check for containment.
if (localRay.Position.Y >= -halfHeight && localRay.Position.Y <= halfHeight && localRay.Position.X * localRay.Position.X + localRay.Position.Z * localRay.Position.Z <= radius * radius)
{
//It's inside!
hit.T = 0;
hit.Location = localRay.Position;
hit.Normal = new Vector3(hit.Location.X, 0, hit.Location.Z);
float normalLengthSquared = hit.Normal.LengthSquared();
if (normalLengthSquared > 1e-9f)
Vector3.Divide(ref hit.Normal, (float)Math.Sqrt(normalLengthSquared), out hit.Normal);
else
hit.Normal = new Vector3();
//Pull the hit into world space.
Quaternion.Transform(ref hit.Normal, ref transform.Orientation, out hit.Normal);
RigidTransform.Transform(ref hit.Location, ref transform, out hit.Location);
return true;
}
//Project the ray direction onto the plane where the cylinder is a circle.
//The projected ray is then tested against the circle to compute the time of impact.
//That time of impact is used to compute the 3d hit location.
Vector2 planeDirection = new Vector2(localRay.Direction.X, localRay.Direction.Z);
float planeDirectionLengthSquared = planeDirection.LengthSquared();
if (planeDirectionLengthSquared < Toolbox.Epsilon)
{
//The ray is nearly parallel with the axis.
//Skip the cylinder-sides test. We're either inside the cylinder and won't hit the sides, or we're outside
//and won't hit the sides.
if (localRay.Position.Y > halfHeight)
goto upperTest;
if (localRay.Position.Y < -halfHeight)
goto lowerTest;
hit = new RayHit();
return false;
}
Vector2 planeOrigin = new Vector2(localRay.Position.X, localRay.Position.Z);
float dot;
Vector2.Dot(ref planeDirection, ref planeOrigin, out dot);
float closestToCenterT = -dot / planeDirectionLengthSquared;
Vector2 closestPoint;
Vector2.Multiply(ref planeDirection, closestToCenterT, out closestPoint);
Vector2.Add(ref planeOrigin, ref closestPoint, out closestPoint);
//How close does the ray come to the circle?
float squaredDistance = closestPoint.LengthSquared();
if (squaredDistance > radius * radius)
{
//It's too far! The ray cannot possibly hit the capsule.
hit = new RayHit();
return false;
}
//With the squared distance, compute the distance backward along the ray from the closest point on the ray to the axis.
float backwardsDistance = radius * (float)Math.Sqrt(1 - squaredDistance / (radius * radius));
float tOffset = backwardsDistance / (float)Math.Sqrt(planeDirectionLengthSquared);
hit.T = closestToCenterT - tOffset;
//Compute the impact point on the infinite cylinder in 3d local space.
Vector3.Multiply(ref localRay.Direction, hit.T, out hit.Location);
Vector3.Add(ref hit.Location, ref localRay.Position, out hit.Location);
//Is it intersecting the cylindrical portion of the capsule?
if (hit.Location.Y <= halfHeight && hit.Location.Y >= -halfHeight && hit.T < maximumLength)
{
//Yup!
hit.Normal = new Vector3(hit.Location.X, 0, hit.Location.Z);
float normalLengthSquared = hit.Normal.LengthSquared();
if (normalLengthSquared > 1e-9f)
Vector3.Divide(ref hit.Normal, (float)Math.Sqrt(normalLengthSquared), out hit.Normal);
else
hit.Normal = new Vector3();
//Pull the hit into world space.
Quaternion.Transform(ref hit.Normal, ref transform.Orientation, out hit.Normal);
RigidTransform.Transform(ref hit.Location, ref transform, out hit.Location);
return true;
//.........这里部分代码省略.........
示例13: ConvexCast
/// <summary>
/// Casts a convex shape against the collidable.
/// </summary>
/// <param name="castShape">Shape to cast.</param>
/// <param name="startingTransform">Initial transform of the shape.</param>
/// <param name="sweep">Sweep to apply to the shape.</param>
/// <param name="hit">Hit data, if any.</param>
/// <returns>Whether or not the cast hit anything.</returns>
public override bool ConvexCast(ConvexShape castShape, ref RigidTransform startingTransform, ref Vector3 sweep, out RayHit hit)
{
if (Shape.solidity == MobileMeshSolidity.Solid)
{
//If the convex cast is inside the mesh and the mesh is solid, it should return t = 0.
var ray = new Ray() { Position = startingTransform.Position, Direction = Toolbox.UpVector };
if (Shape.IsLocalRayOriginInMesh(ref ray, out hit))
{
hit = new RayHit() { Location = startingTransform.Position, Normal = new Vector3(), T = 0 };
return true;
}
}
hit = new RayHit();
BoundingBox boundingBox;
var transform = new AffineTransform {Translation = worldTransform.Position};
Matrix3x3.CreateFromQuaternion(ref worldTransform.Orientation, out transform.LinearTransform);
castShape.GetSweptLocalBoundingBox(ref startingTransform, ref transform, ref sweep, out boundingBox);
var tri = PhysicsResources.GetTriangle();
var hitElements = CommonResources.GetIntList();
if (this.Shape.TriangleMesh.Tree.GetOverlaps(boundingBox, hitElements))
{
hit.T = float.MaxValue;
for (int i = 0; i < hitElements.Count; i++)
{
Shape.TriangleMesh.Data.GetTriangle(hitElements[i], out tri.vA, out tri.vB, out tri.vC);
AffineTransform.Transform(ref tri.vA, ref transform, out tri.vA);
AffineTransform.Transform(ref tri.vB, ref transform, out tri.vB);
AffineTransform.Transform(ref tri.vC, ref transform, out tri.vC);
Vector3 center;
Vector3.Add(ref tri.vA, ref tri.vB, out center);
Vector3.Add(ref center, ref tri.vC, out center);
Vector3.Multiply(ref center, 1f / 3f, out center);
Vector3.Subtract(ref tri.vA, ref center, out tri.vA);
Vector3.Subtract(ref tri.vB, ref center, out tri.vB);
Vector3.Subtract(ref tri.vC, ref center, out tri.vC);
tri.MaximumRadius = tri.vA.LengthSquared();
float radius = tri.vB.LengthSquared();
if (tri.MaximumRadius < radius)
tri.MaximumRadius = radius;
radius = tri.vC.LengthSquared();
if (tri.MaximumRadius < radius)
tri.MaximumRadius = radius;
tri.MaximumRadius = (float)Math.Sqrt(tri.MaximumRadius);
tri.collisionMargin = 0;
var triangleTransform = new RigidTransform {Orientation = Quaternion.Identity, Position = center};
RayHit tempHit;
if (MPRToolbox.Sweep(castShape, tri, ref sweep, ref Toolbox.ZeroVector, ref startingTransform, ref triangleTransform, out tempHit) && tempHit.T < hit.T)
{
hit = tempHit;
}
}
tri.MaximumRadius = 0;
PhysicsResources.GiveBack(tri);
CommonResources.GiveBack(hitElements);
return hit.T != float.MaxValue;
}
PhysicsResources.GiveBack(tri);
CommonResources.GiveBack(hitElements);
return false;
}
示例14: UpdateSupports
/// <summary>
/// Updates the collection of supporting contacts.
/// </summary>
public void UpdateSupports(ref System.Numerics.Vector3 movementDirection)
{
bool hadTraction = HasTraction;
//Reset traction/support.
HasTraction = false;
HasSupport = false;
System.Numerics.Vector3 downDirection = characterBody.orientationMatrix.Down;
System.Numerics.Vector3 bodyPosition = characterBody.position;
//Compute the character's radius, minus a little margin. We want the rays to originate safely within the character's body.
//Assume vertical rotational invariance. Spheres, cylinders, and capsules don't have varying horizontal radii.
System.Numerics.Vector3 extremePoint;
var convexShape = characterBody.CollisionInformation.Shape as ConvexShape;
Debug.Assert(convexShape != null, "Character bodies must be convex.");
//Find the lowest point on the collision shape.
convexShape.GetLocalExtremePointWithoutMargin(ref Toolbox.DownVector, out extremePoint);
BottomDistance = -extremePoint.Y + convexShape.collisionMargin;
convexShape.GetLocalExtremePointWithoutMargin(ref Toolbox.RightVector, out extremePoint);
float rayCastInnerRadius = Math.Max((extremePoint.X + convexShape.collisionMargin) * 0.8f, extremePoint.X);
//Vertically, the rays will start at the same height as the character's center.
//While they could be started lower on a cylinder, that wouldn't always work for a sphere or capsule: the origin might end up outside of the shape!
tractionContacts.Clear();
supportContacts.Clear();
sideContacts.Clear();
headContacts.Clear();
foreach (var pair in characterBody.CollisionInformation.Pairs)
{
//Don't stand on things that aren't really colliding fully.
if (pair.CollisionRule != CollisionRule.Normal)
continue;
ContactCategorizer.CategorizeContacts(pair, characterBody.CollisionInformation, ref downDirection, ref tractionContacts, ref supportContacts, ref sideContacts, ref headContacts);
}
HasSupport = supportContacts.Count > 0;
HasTraction = tractionContacts.Count > 0;
//Only perform ray casts if the character has fully left the surface, and only if the previous frame had traction.
//(If ray casts are allowed when support contacts still exist, the door is opened for climbing surfaces which should not be climbable.
//Consider a steep slope. If the character runs at it, the character will likely be wedged off of the ground, making it lose traction while still having a support contact with the slope.
//If ray tests are allowed when support contacts exist, the character will maintain traction despite climbing the wall.
//The VerticalMotionConstraint can stop the character from climbing in many cases, but it's nice not to have to rely on it.
//Disallowing ray tests when supports exist does have a cost, though. For example, consider rounded steps.
//If the character walks off a step such that it is still in contact with the step but is far enough down that the slope is too steep for traction,
//the ray test won't recover traction. This situation just isn't very common.)
if (!HasSupport && hadTraction)
{
float supportRayLength = maximumAssistedDownStepHeight + BottomDistance;
SupportRayData = null;
//If the contacts aren't available to support the character, raycast down to find the ground.
if (!HasTraction)
{
//TODO: could also require that the character has a nonzero movement direction in order to use a ray cast. Questionable- would complicate the behavior on edges.
Ray ray = new Ray(bodyPosition, downDirection);
bool hasTraction;
SupportRayData data;
if (TryDownCast(ref ray, supportRayLength, out hasTraction, out data))
{
SupportRayData = data;
HasTraction = data.HasTraction;
HasSupport = true;
}
}
//If contacts and the center ray cast failed, try a ray offset in the movement direction.
bool tryingToMove = movementDirection.LengthSquared() > 0;
if (!HasTraction && tryingToMove)
{
Ray ray = new Ray(
characterBody.Position +
movementDirection * rayCastInnerRadius, downDirection);
//Have to test to make sure the ray doesn't get obstructed. This could happen if the character is deeply embedded in a wall; we wouldn't want it detecting things inside the wall as a support!
Ray obstructionRay;
obstructionRay.Position = characterBody.Position;
obstructionRay.Direction = ray.Position - obstructionRay.Position;
if (!QueryManager.RayCastHitAnything(obstructionRay, 1))
{
//The origin isn't obstructed, so now ray cast down.
bool hasTraction;
SupportRayData data;
if (TryDownCast(ref ray, supportRayLength, out hasTraction, out data))
{
if (SupportRayData == null || data.HitData.T < SupportRayData.Value.HitData.T)
{
//Only replace the previous support ray if we now have traction or we didn't have a support ray at all before,
//or this hit is a better (sooner) hit.
if (hasTraction)
{
SupportRayData = data;
//.........这里部分代码省略.........
示例15: RayCast
//TODO: Consider changing the termination epsilons on these casts. Epsilon * Modifier is okay, but there might be better options.
///<summary>
/// Tests a ray against a convex shape.
///</summary>
///<param name="ray">Ray to test against the shape.</param>
///<param name="shape">Shape to test.</param>
///<param name="shapeTransform">Transform to apply to the shape for the test.</param>
///<param name="maximumLength">Maximum length of the ray in units of the ray direction's length.</param>
///<param name="hit">Hit data of the ray cast, if any.</param>
///<returns>Whether or not the ray hit the shape.</returns>
public static bool RayCast(Ray ray, ConvexShape shape, ref RigidTransform shapeTransform, float maximumLength,
out RayHit hit)
{
//Transform the ray into the object's local space.
Vector3.Subtract(ref ray.Position, ref shapeTransform.Position, out ray.Position);
Quaternion conjugate;
Quaternion.Conjugate(ref shapeTransform.Orientation, out conjugate);
Quaternion.Transform(ref ray.Position, ref conjugate, out ray.Position);
Quaternion.Transform(ref ray.Direction, ref conjugate, out ray.Direction);
Vector3 extremePointToRayOrigin, extremePoint;
hit.T = 0;
hit.Location = ray.Position;
hit.Normal = Toolbox.ZeroVector;
Vector3 closestOffset = hit.Location;
RaySimplex simplex = new RaySimplex();
float vw, closestPointDotDirection;
int count = 0;
//This epsilon has a significant impact on performance and accuracy. Changing it to use BigEpsilon instead increases speed by around 30-40% usually, but jigging is more evident.
while (closestOffset.LengthSquared() >= Toolbox.Epsilon * simplex.GetErrorTolerance(ref ray.Position))
{
if (++count > MaximumGJKIterations)
{
//It's taken too long to find a hit. Numerical problems are probable; quit.
hit = new RayHit();
return false;
}
shape.GetLocalExtremePoint(closestOffset, out extremePoint);
Vector3.Subtract(ref hit.Location, ref extremePoint, out extremePointToRayOrigin);
Vector3.Dot(ref closestOffset, ref extremePointToRayOrigin, out vw);
//If the closest offset and the extreme point->ray origin direction point the same way,
//then we might be able to conservatively advance the point towards the surface.
if (vw > 0)
{
Vector3.Dot(ref closestOffset, ref ray.Direction, out closestPointDotDirection);
if (closestPointDotDirection >= 0)
{
hit = new RayHit();
return false;
}
hit.T = hit.T - vw / closestPointDotDirection;
if (hit.T > maximumLength)
{
//If we've gone beyond where the ray can reach, there's obviously no hit.
hit = new RayHit();
return false;
}
//Shift the ray up.
Vector3.Multiply(ref ray.Direction, hit.T, out hit.Location);
Vector3.Add(ref hit.Location, ref ray.Position, out hit.Location);
hit.Normal = closestOffset;
}
RaySimplex shiftedSimplex;
simplex.AddNewSimplexPoint(ref extremePoint, ref hit.Location, out shiftedSimplex);
//Compute the offset from the simplex surface to the origin.
shiftedSimplex.GetPointClosestToOrigin(ref simplex, out closestOffset);
}
//Transform the hit data into world space.
Quaternion.Transform(ref hit.Normal, ref shapeTransform.Orientation, out hit.Normal);
Quaternion.Transform(ref hit.Location, ref shapeTransform.Orientation, out hit.Location);
Vector3.Add(ref hit.Location, ref shapeTransform.Position, out hit.Location);
return true;
}