public void Update(float time) { try { if (_actor != null) { desc.Origin = _actor.WorldPose.Translation + origin; for (int i = iter; i < iter + 108; i++) { //Origin offset Transform desc.Direction = _actor.WorldPose.Matrix * rayVec[i]; result = _world.RayCastClosest(desc); if (result == null) _player.saveLIDAR(30, i); else _player.saveLIDAR((result.Distance > 30 ? 30 : result.Distance), i); } iter += 108; if (iter > 972) { _player.publishLIDAR(); _player.setIMU(_drone.CurrentPitch, _drone.CurrentYaw, _drone.CurrentRoll); _player.setGPS(_drone.GPS); iter = 0; } } } catch (SystemException e) { Console.WriteLine("Exception: " + e.ToString()); return; } }
public BaseBxdf GetBsdf(ref RayData pathRay, ref RayHit hit, ref MediumInfo med, bool fromLight, float u0) { var currentTriangleIndex = (int) hit.Index; bool isLight = scene.IsLight(currentTriangleIndex); var mesh = scene.GetMeshByTriangleIndex(currentTriangleIndex); if (mesh == null) //|| mesh.MeshName.Equals("COL254_01", StringComparison.InvariantCultureIgnoreCase)) { //ii.Color = new RgbSpectrum(1f); //Debugger.Break(); throw new ApplicationException("Invalid triangle index " + currentTriangleIndex + " Mesh not found"); } UV TexCoords; Normal normal = new Normal(), shadeN = new Normal(); mesh.InterpolateTriUV(currentTriangleIndex, hit.U, hit.V, out TexCoords); //normal = -scene.Triangles[currentTriangleIndex].ComputeNormal(scene.Vertices).Normalize(); mesh.InterpolateTriangleNormal((int)hit.Index, hit.U, hit.V, ref normal); //normal = -normal; shadeN = (Normal.Dot(ref pathRay.Dir, ref normal) > 0f) ? -normal : normal; var bsdf = mesh.Material.GetBsdf(ref pathRay, ref hit, ref normal, ref shadeN, ref TexCoords, ref med, fromLight,u0); bsdf.SetLight(isLight); return bsdf; }
public PathVertexData CreateVertex(ref RayRecord ray, ref RayHit rayHit) { var wo = -ray.Direction; if (rayHit.Miss()) { return new PathVertexData() { Flags = (byte)PathVertexType.Environment, Emission = context.Scene.SampleEnvironment(ref wo) }; } var vertex = new PathVertexData { HitPoint = ray.Point(rayHit.Distance) }; var mesh = context.Scene.GetMeshByTriangleIndex((int)rayHit.Index); if (mesh.MeshProfile is SurfaceProfile) { vertex.Flags = (byte)PathVertexType.Surface; vertex.SurfaceHit = new UV(rayHit.U, rayHit.V); var meshMat = mesh.MaterialID; var MMaterial = context.Scene.MatLib.GetSurfMat(meshMat); var matInfo = context.Scene.MaterialProvider.Get(meshMat); mesh.InterpolateTriangleNormal((int)rayHit.Index, rayHit.U, rayHit.V, ref vertex.GeoNormal); var rayDir = ray.Direction; vertex.ShadingNormal = (Normal.Dot(ref rayDir, ref vertex.GeoNormal) > 0f) ? -vertex.GeoNormal : vertex.GeoNormal; UV texCoord; mesh.InterpolateTriUV((int)rayHit.Index, rayHit.U, rayHit.V, out texCoord); vertex.Brdf = MMaterial; vertex.MaterialInfo = matInfo; var diffuseTex = context.Scene.Query(meshMat, TextureType.Diffuse); if (diffuseTex != null) { texSampler.SampleTexture(texCoord.U, texCoord.V, diffuseTex, out vertex.Color); //ii.Color = diffuseTex.Sample(ii.TexCoords.U, ii.TexCoords.V); //ii.Color = diffuseTex.Sample(hit.U, hit.V); } else { vertex.Color = RgbSpectrum.Max(ref matInfo.Ks, ref matInfo.Kd); } } else if (mesh.MeshProfile is LightsourceProfile) { vertex.Flags = (byte)PathVertexType.Light; var light = context.Scene.GetLightByIndex((int)rayHit.Index); vertex.LightId = context.Scene.Lights.ToList().IndexOf(light); vertex.Emission = (RgbSpectrum)(light.Le(ref wo)); } else if (mesh.MeshProfile is VolumeProfile) { vertex.Flags = (byte)PathVertexType.Volume; } return vertex; }
public static RayHit QueryRayFirst(Vector2f Start, Vector2f End) { RayHit Ret = new RayHit(); Engine.Space.RayCast((Fix, Point, Norm, Frac) => { Ret = new RayHit(Fix, Point.ToVec(), Norm.ToVec(), Frac); return 0; }, Start.ToVec(), End.ToVec()); return Ret; }
protected BaseBxdf(ref RayHit rh, ref RayData ray, ref Normal ng, ref Normal ns, ref UV texCoord, MaterialInfo mi, SurfaceTextureInfo texData, bool fromLight) { #if VERBOSE if (ng.Length > 1f || ns.Length > 1f) { Console.WriteLine("Normals in bsdf arent normalized"); } #endif this.Init(ref rh, ref ray, ref ng, ref ns, ref texCoord, mi, texData, fromLight); }
public override void Process(ref RayHit rh, ref Vector wo, out bool finishPath, out float pdf) { var lt = PathSampler.scene.GetLightByIndex((int)rh.Index); pdf = 0; if (lt != null) { var le = lt.Emittance(ref wo, out pdf);//* hitInfo.Color //Radiance += Throughput * le; if (!le.IsBlack()) PathSampler.mutate = true; PathSampler.Radiance.MAdd(ref PathSampler.Throughput, ref le); } finishPath = true; }
public RayIntersection EvalIntersection(RayDifferential ray, ref RayHit rh, RayIntersection isect) { var ii = isect ?? (isect = new RayIntersection()); var currentTriangleIndex = (int) rh.Index; var obj = GetObjectByTriangleIndex(currentTriangleIndex); ii.Hitpoint = ray.Point(rh.Distance); ii.BaryCentricPoint = new UV(rh.U, rh.V); obj.Entity.InterpolateTriangleNormal(currentTriangleIndex, rh.U, rh.V, ref ii.ShadingNormal); obj.Entity.InterpolateTriUV(currentTriangleIndex, rh.U, rh.V, out ii.TextureCoords); ii.GeoNormal = scene.sceneData.Triangles[currentTriangleIndex].ComputeNormal(scene.sceneData.GeoData.Vertices); ii.ComputeDifferential(ray); return ii; }
internal void Init(ref RayHit rh, ref RayData ray, ref Normal ng, ref Normal ns, ref UV texCoord, MaterialInfo mi, SurfaceTextureInfo texData, bool fromLight) { if (rh.Miss()) { throw new ArgumentException("RayHit missed geometry!"); } //if (HitPoint == null) //{ HitPoint = new HitPointInfo { Color = RgbSpectrum.Max(ref mi.Kd, ref mi.Ks), HitPoint = ray.Point(rh.Distance), TexCoord = texCoord, FromDirection = -ray.Dir, GeoNormal = ng, ShadingNormal = ns, FromLight = fromLight }; //} //else //{ // HitPoint.HitPoint = ray.Point(rh.Distance); // HitPoint.TexCoord = texCoord; // HitPoint.FromDirection = -ray.Dir; // HitPoint.GeoNormal = ng; // HitPoint.ShadingNormal = ns; // HitPoint.FromLight = fromLight; //}; this.MaterialInfo = mi; this.TexData = texData; if (Frame == null) this.Frame = new ONB(ref HitPoint.GeoNormal); else Frame.SetFromZ(ref HitPoint.GeoNormal); }
/// <summary> /// Sweeps a convex shape against the entry. /// </summary> /// <param name="castShape">Swept shape.</param> /// <param name="startingTransform">Beginning location and orientation of the cast shape.</param> /// <param name="sweep">Sweep motion to apply to the cast shape.</param> /// <param name="hit">Hit data of the cast on the entry, if any.</param> /// <returns>Whether or not the cast hit the entry.</returns> public abstract bool ConvexCast(ConvexShape castShape, ref RigidTransform startingTransform, ref Vector3 sweep, out RayHit hit);
private bool IsLocalRayOriginInMeshHelper(ref Ray ray, out RayHit hit) { var overlapList = Resources.GetIntList(); if (triangleMesh.Tree.GetOverlaps(ray, overlapList)) { var hits = Resources.GetRayHitList(); hit = new RayHit(); hit.T = float.MaxValue; for (int i = 0; i < overlapList.Count; i++) { Vector3 vA, vB, vC; triangleMesh.Data.GetTriangle(overlapList[i], out vA, out vB, out vC); RayHit tempHit; if (Toolbox.FindRayTriangleIntersection(ref ray, float.MaxValue, TriangleSidedness.DoubleSided, ref vA, ref vB, ref vC, out tempHit) && IsHitUnique(hits, ref tempHit) && //Adds if unique. tempHit.T < hit.T) { hit = tempHit; } } int hitCount = hits.count; Resources.GiveBack(hits); Resources.GiveBack(overlapList); //An odd number of hits implies that the object started inside. return hitCount % 2 != 0; } Resources.GiveBack(overlapList); hit = new RayHit() { T = float.MaxValue }; return false; }
public override bool ConvexCast(ConvexShape castShape, ref MathExtensions.RigidTransform startingTransform, ref Vector3 sweep, out RayHit hit) { hit = new RayHit(); BoundingBox boundingBox; Toolbox.GetExpandedBoundingBox(ref castShape, ref startingTransform, ref sweep, out boundingBox); var tri = Resources.GetTriangle(); var hitElements = Resources.GetIntList(); if (triangleMesh.Tree.GetOverlaps(boundingBox, hitElements)) { hit.T = float.MaxValue; for (int i = 0; i < hitElements.Count; i++) { triangleMesh.Data.GetTriangle(hitElements[i], out tri.vA, out tri.vB, 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; Resources.GiveBack(tri); Resources.GiveBack(hitElements); return hit.T != float.MaxValue; } Resources.GiveBack(tri); Resources.GiveBack(hitElements); return false; }
///<summary> /// Tests a ray against the terrain shape. ///</summary> ///<param name="ray">Ray to test against the shape.</param> ///<param name="maximumLength">Maximum length of the ray in units of the ray direction's length.</param> ///<param name="transform">Transform to apply to the terrain shape during the test.</param> ///<param name="sidedness">Sidedness of the triangles to use when raycasting.</param> ///<param name="hit">Hit data of the ray cast, if any.</param> ///<returns>Whether or not the ray hit the transformed terrain shape.</returns> public bool RayCast(ref Ray ray, float maximumLength, ref AffineTransform transform, TriangleSidedness sidedness, out RayHit hit) { hit = new RayHit(); //Put the ray into local space. Ray localRay; AffineTransform inverse; AffineTransform.Invert(ref transform, out inverse); Matrix3X3.Transform(ref ray.Direction, ref inverse.LinearTransform, out localRay.Direction); AffineTransform.Transform(ref ray.Position, ref inverse, out localRay.Position); //Use rasterizey traversal. //The origin is at 0,0,0 and the map goes +X, +Y, +Z. //if it's before the origin and facing away, or outside the max and facing out, early out. float maxX = heights.GetLength(0) - 1; float maxZ = heights.GetLength(1) - 1; Vector3 progressingOrigin = localRay.Position; float distance = 0; //Check the outside cases first. if (progressingOrigin.X < 0) { if (localRay.Direction.X > 0) { //Off the left side. float timeToMinX = -progressingOrigin.X / localRay.Direction.X; distance += timeToMinX; Vector3 increment; Vector3.Multiply(ref localRay.Direction, timeToMinX, out increment); Vector3.Add(ref increment, ref progressingOrigin, out progressingOrigin); } else return false; //Outside and pointing away from the terrain. } else if (progressingOrigin.X > maxX) { if (localRay.Direction.X < 0) { //Off the left side. float timeToMinX = -(progressingOrigin.X - maxX) / localRay.Direction.X; distance += timeToMinX; Vector3 increment; Vector3.Multiply(ref localRay.Direction, timeToMinX, out increment); Vector3.Add(ref increment, ref progressingOrigin, out progressingOrigin); } else return false; //Outside and pointing away from the terrain. } if (progressingOrigin.Z < 0) { if (localRay.Direction.Z > 0) { float timeToMinZ = -progressingOrigin.Z / localRay.Direction.Z; distance += timeToMinZ; Vector3 increment; Vector3.Multiply(ref localRay.Direction, timeToMinZ, out increment); Vector3.Add(ref increment, ref progressingOrigin, out progressingOrigin); } else return false; } else if (progressingOrigin.Z > maxZ) { if (localRay.Direction.Z < 0) { float timeToMinZ = -(progressingOrigin.Z - maxZ) / localRay.Direction.Z; distance += timeToMinZ; Vector3 increment; Vector3.Multiply(ref localRay.Direction, timeToMinZ, out increment); Vector3.Add(ref increment, ref progressingOrigin, out progressingOrigin); } else return false; } if (distance > maximumLength) return false; //By now, we should be entering the main body of the terrain. int xCell = (int)progressingOrigin.X; int zCell = (int)progressingOrigin.Z; //If it's hitting the border and going in, then correct the index //so that it will initially target a valid quad. //Without this, a quad beyond the border would be tried and failed. if (xCell == heights.GetLength(0) - 1 && localRay.Direction.X < 0) xCell = heights.GetLength(0) - 2; if (zCell == heights.GetLength(1) - 1 && localRay.Direction.Z < 0) zCell = heights.GetLength(1) - 2; while (true) { //Check for a miss. if (xCell < 0 || zCell < 0 || xCell >= heights.GetLength(0) - 1 || zCell >= heights.GetLength(1) - 1) return false; //Test the triangles of this cell. Vector3 v1, v2, v3, v4; // v3 v4 // v1 v2 GetLocalPosition(xCell, zCell, out v1); GetLocalPosition(xCell + 1, zCell, out v2); GetLocalPosition(xCell, zCell + 1, out v3); GetLocalPosition(xCell + 1, zCell + 1, out v4); RayHit hit1, hit2; bool didHit1; bool didHit2; //Don't bother doing ray intersection tests if the ray can't intersect it. float highest = v1.Y; float lowest = v1.Y; if (v2.Y > highest) highest = v2.Y; else if (v2.Y < lowest) lowest = v2.Y; if (v3.Y > highest) highest = v3.Y; else if (v3.Y < lowest) lowest = v3.Y; if (v4.Y > highest) highest = v4.Y; else if (v4.Y < lowest) lowest = v4.Y; if (!(progressingOrigin.Y > highest && localRay.Direction.Y > 0 || progressingOrigin.Y < lowest && localRay.Direction.Y < 0)) { if (quadTriangleOrganization == QuadTriangleOrganization.BottomLeftUpperRight) { //Always perform the raycast as if Y+ in local space is the way the triangles are facing. didHit1 = Toolbox.FindRayTriangleIntersection(ref localRay, maximumLength, sidedness, ref v1, ref v2, ref v3, out hit1); didHit2 = Toolbox.FindRayTriangleIntersection(ref localRay, maximumLength, sidedness, ref v2, ref v4, ref v3, out hit2); } else //if (quadTriangleOrganization == CollisionShapes.QuadTriangleOrganization.BottomRightUpperLeft) { didHit1 = Toolbox.FindRayTriangleIntersection(ref localRay, maximumLength, sidedness, ref v1, ref v2, ref v4, out hit1); didHit2 = Toolbox.FindRayTriangleIntersection(ref localRay, maximumLength, sidedness, ref v1, ref v4, ref v3, out hit2); } if (didHit1 && didHit2) { if (hit1.T < hit2.T) { Vector3.Multiply(ref ray.Direction, hit1.T, out hit.Location); Vector3.Add(ref hit.Location, ref ray.Position, out hit.Location); Matrix3X3.TransformTranspose(ref hit1.Normal, ref inverse.LinearTransform, out hit.Normal); hit.T = hit1.T; return true; } Vector3.Multiply(ref ray.Direction, hit2.T, out hit.Location); Vector3.Add(ref hit.Location, ref ray.Position, out hit.Location); Matrix3X3.TransformTranspose(ref hit2.Normal, ref inverse.LinearTransform, out hit.Normal); hit.T = hit2.T; } else if (didHit1) { Vector3.Multiply(ref ray.Direction, hit1.T, out hit.Location); Vector3.Add(ref hit.Location, ref ray.Position, out hit.Location); Matrix3X3.TransformTranspose(ref hit1.Normal, ref inverse.LinearTransform, out hit.Normal); hit.T = hit1.T; return true; } else if (didHit2) { Vector3.Multiply(ref ray.Direction, hit2.T, out hit.Location); Vector3.Add(ref hit.Location, ref ray.Position, out hit.Location); Matrix3X3.TransformTranspose(ref hit2.Normal, ref inverse.LinearTransform, out hit.Normal); hit.T = hit2.T; return true; } } //Move to the next cell. float timeToX; if (localRay.Direction.X < 0) timeToX = -(progressingOrigin.X - xCell) / localRay.Direction.X; else if (ray.Direction.X > 0) timeToX = (xCell + 1 - progressingOrigin.X) / localRay.Direction.X; else timeToX = float.MaxValue; float timeToZ; if (localRay.Direction.Z < 0) timeToZ = -(progressingOrigin.Z - zCell) / localRay.Direction.Z; else if (localRay.Direction.Z > 0) timeToZ = (zCell + 1 - progressingOrigin.Z) / localRay.Direction.Z; else timeToZ = float.MaxValue; //Move to the next cell. if (timeToX < timeToZ) { if (localRay.Direction.X < 0) xCell--; else xCell++; distance += timeToX; if (distance > maximumLength) return false; Vector3 increment; Vector3.Multiply(ref localRay.Direction, timeToX, out increment); Vector3.Add(ref increment, ref progressingOrigin, out progressingOrigin); } else { if (localRay.Direction.Z < 0) zCell--; else zCell++; distance += timeToZ; if (distance > maximumLength) return false; Vector3 increment; Vector3.Multiply(ref localRay.Direction, timeToZ, out increment); Vector3.Add(ref increment, ref progressingOrigin, out progressingOrigin); } } }
/// <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(CollisionShapes.ConvexShapes.ConvexShape castShape, ref RigidTransform startingTransform, ref Vector3 sweep, out RayHit hit) { hit = new RayHit(); BoundingBox boundingBox; Toolbox.GetExpandedBoundingBox(ref castShape, ref startingTransform, ref sweep, out boundingBox); var hitElements = Resources.GetCompoundChildList(); if (hierarchy.Tree.GetOverlaps(boundingBox, hitElements)) { hit.T = float.MaxValue; for (int i = 0; i < hitElements.count; i++) { var candidate = hitElements.Elements[i].CollisionInformation; RayHit tempHit; if (candidate.ConvexCast(castShape, ref startingTransform, ref sweep, out tempHit) && tempHit.T < hit.T) { hit = tempHit; } } Resources.GiveBack(hitElements); return hit.T != float.MaxValue; } Resources.GiveBack(hitElements); return false; }
protected override bool ShadowRayTest(ref RayHit shadowRayHit, ref RayData shadowRay, out RgbSpectrum attenuation, out bool continueTrace) { var hit = shadowRayHit.Index == 0xffffffffu || scene.IsLight((int)shadowRayHit.Index); attenuation = new RgbSpectrum(1f); continueTrace = false; if (hit) return true; var mesh = scene.GetMeshByTriangleIndex((int)shadowRayHit.Index); var mat = //SurfaceMaterials.CreateMaterial(scene.MaterialProvider.Get(mesh.MaterialName)); scene.MatLib.GetSurfMat(mesh != null ? mesh.MaterialName : "default"); shadowRayEvent = mat.Type.TypeToEvent(); if (mat.TransparentShadows) { continueTrace = true; return true; } //if (shadowRayEvent.Has(BsdfEvent.Transmit)) //{ // var att = MathLab.Exp(-0.1f*shadowRayHit.Distance); // attenuation *= att + att* hitInfo.TextureData.Transmittance; // continueTrace = true; // return true; //} //if (mat.AlphaTexture != null) //{ // continueTrace = true; // this.SurfaceSampler.GetIntersection(ref shadowRay, ref shadowRayHit, ref hitInfo, IntersectionOptions.ResolveTextures); // attenuation = (RgbSpectrum) hitInfo.TextureData.Alpha; // hit = true; // //mat.MaterialData.Kt.Filter() < Sample.GetLazyValue(); //} return hit; }
private bool ShadowRayTest(ref RayHit shadowRayHit, out RgbSpectrum attenuation) { var hit = shadowRayHit.Index == 0xffffffffu || scene.IsLight((int)shadowRayHit.Index); attenuation = new RgbSpectrum(1f); if (hit) return true; var mesh = scene.GetMeshByTriangleIndex((int)shadowRayHit.Index); var mat = //SurfaceMaterials.CreateMaterial(scene.MaterialProvider.Get(mesh.MaterialName)); scene.MatLib.GetSurfMat(mesh != null ? mesh.MaterialName : "default"); if (mat.AlphaTexture != null) { attenuation = (RgbSpectrum) (mat.AlphaTexture as ConstTextureInfo).Color; hit = true; //mat.MaterialData.Kt.Filter() < Sample.GetLazyValue(); } return hit; }
///<summary> /// Tests a ray against the triangle mesh. ///</summary> ///<param name="ray">Ray to test against the mesh.</param> /// <param name="maximumLength">Maximum length of the ray in units of the ray direction's length.</param> /// <param name="sidedness">Sidedness to apply to the mesh for the ray cast.</param> ///<param name="rayHit">Hit data for the ray, if any.</param> ///<returns>Whether or not the ray hit the mesh.</returns> public bool RayCast(Ray ray, float maximumLength, TriangleSidedness sidedness, out RayHit rayHit) { var rayHits = CommonResources.GetRayHitList(); bool toReturn = RayCast(ray, maximumLength, sidedness, rayHits); if (toReturn) { rayHit = rayHits[0]; for (int i = 1; i < rayHits.Count; i++) { RayHit hit = rayHits[i]; if (hit.T < rayHit.T) { rayHit = hit; } } } else { rayHit = new RayHit(); } CommonResources.GiveBack(rayHits); return(toReturn); }
///<summary> /// Tests a ray against the triangle mesh. ///</summary> ///<param name="ray">Ray to test against the mesh.</param> /// <param name="maximumLength">Maximum length of the ray in units of the ray direction's length.</param> ///<param name="rayHit">Hit data for the ray, if any.</param> ///<returns>Whether or not the ray hit the mesh.</returns> public bool RayCast(Ray ray, float maximumLength, out RayHit rayHit) { return(RayCast(ray, maximumLength, TriangleSidedness.DoubleSided, out rayHit)); }
/// <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="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="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, Func <BroadPhaseEntry, bool> filter, out RayHit hit) { RayCastResult result; bool toReturn = Shape.ConvexCast(castShape, ref startingTransform, ref sweep, filter, out result); hit = result.HitData; return(toReturn); }
/// <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 override bool RayCast(Ray ray, float maximumLength, Func <BroadPhaseEntry, bool> filter, out RayHit rayHit) { RayCastResult result; bool toReturn = Shape.RayCast(ray, maximumLength, filter, out result); rayHit = result.HitData; return(toReturn); }
/// <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); }
/// <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); }
///<summary> /// Tests a ray against the surface of the mesh. This does not take into account solidity. ///</summary> ///<param name="ray">Ray to test.</param> ///<param name="maximumLength">Maximum length of the ray to test; in units of the ray's direction's length.</param> ///<param name="sidedness">Sidedness to use during the ray cast. This does not have to be the same as the mesh's sidedness.</param> ///<param name="rayHit">The hit location of the ray on the mesh, if any.</param> ///<returns>Whether or not the ray hit the mesh.</returns> public bool RayCast(Ray ray, float maximumLength, TriangleSidedness sidedness, 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.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); }
public virtual void Process(ref RayHit rh, ref Vector wo, out bool finishPath, out float pdf) { finishPath = true; pdf = 0f; }
/// <summary> /// Gets the intersection between the triangle and the ray. /// </summary> /// <param name="ray">Ray to test against the triangle.</param> /// <param name="transform">Transform to apply to the triangle shape for the test.</param> /// <param name="maximumLength">Maximum distance to travel in units of the direction vector's length.</param> /// <param name="hit">Hit data of the ray cast, 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) { Matrix3X3 orientation; Matrix3X3.CreateFromQuaternion(ref transform.Orientation, out orientation); Ray localRay; Quaternion conjugate; Quaternion.Conjugate(ref transform.Orientation, out conjugate); Vector3.Transform(ref ray.Direction, ref conjugate, out localRay.Direction); Vector3.Subtract(ref ray.Position, ref transform.Position, out localRay.Position); Vector3.Transform(ref localRay.Position, ref conjugate, out localRay.Position); bool toReturn = Toolbox.FindRayTriangleIntersection(ref localRay, maximumLength, sidedness, ref vA, ref vB, ref vC, out hit); //Move the hit back into world space. Vector3.Multiply(ref ray.Direction, hit.T, out hit.Location); Vector3.Add(ref ray.Position, ref hit.Location, out hit.Location); Vector3.Transform(ref hit.Normal, ref transform.Orientation, out hit.Normal); return toReturn; }
///<summary> /// Tests a ray against the triangle mesh. ///</summary> ///<param name="ray">Ray to test against the mesh.</param> /// <param name="sidedness">Sidedness to apply to the mesh for the ray cast.</param> ///<param name="rayHit">Hit data for the ray, if any.</param> ///<returns>Whether or not the ray hit the mesh.</returns> public bool RayCast(Ray ray, TriangleSidedness sidedness, out RayHit rayHit) { return(RayCast(ray, float.MaxValue, sidedness, out rayHit)); }
/// <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(CollisionShapes.ConvexShapes.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; AffineTransform transform = new AffineTransform(); transform.Translation = worldTransform.Position; Matrix3X3.CreateFromQuaternion(ref worldTransform.Orientation, out transform.LinearTransform); castShape.GetSweptLocalBoundingBox(ref startingTransform, ref transform, ref sweep, out boundingBox); var tri = Resources.GetTriangle(); var hitElements = Resources.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(); triangleTransform.Orientation = Quaternion.Identity; triangleTransform.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; Resources.GiveBack(tri); Resources.GiveBack(hitElements); return hit.T != float.MaxValue; } Resources.GiveBack(tri); Resources.GiveBack(hitElements); return false; }
public static RayHit Trace(Ray cameraRay, SpatialGrid spatialGrid, List <int> geometryIndexList, List <RTTriangle_t> geometryList, int exclude) { RayHit bestHit = RayHit.CreateRayHit(); float t0 = float.NegativeInfinity; float t1 = float.PositiveInfinity; if (RayBoxIntersectionCompute.RayBoxIntersection(cameraRay, spatialGrid.min, spatialGrid.max, ref t0, ref t1)) { Vector3 entry = cameraRay.GetPoint(t1); GridStep step = DetermineGridStep(cameraRay); Ray entryToBoundaryRay = CreateRay(entry, cameraRay.direction); SpatialGridIndex entryGridIndex = SpatialGridCompute.GetGridIndexAtPoint(spatialGrid, entry); RayHit deltaX = new RayHit(); RayHit deltaY = new RayHit(); RayHit deltaZ = new RayHit(); SpatialGridCompute.GetDeltaToBoundary( entryGridIndex, spatialGrid, entryToBoundaryRay, step, ref deltaX, ref deltaY, ref deltaZ); RayHit distToNextX = new RayHit(); RayHit distToNextY = new RayHit(); RayHit distToNextZ = new RayHit(); SpatialGridCompute.DistanceBetweenBoundary( cameraRay, step, entryGridIndex, spatialGrid, deltaX.hitPoint, deltaY.hitPoint, deltaZ.hitPoint, ref distToNextX, ref distToNextY, ref distToNextZ ); float tx = deltaX.distance; float ty = deltaY.distance; float tz = deltaZ.distance; SpatialGridIndex current = entryGridIndex; #region Debug CubeController currentGridController = CubeGlobalData.Instance.GetGridAtIndex(current); JoeRayCaster.voxelsHitList.Clear(); JoeRayCaster.voxelsHitList.Add(currentGridController); #endregion //Debug bool hasHit = false; bool outside = false; do { bestHit = LocalGridTrace( cameraRay, current, geometryIndexList, geometryList, spatialGrid, -1); if (tx < ty) { if (tx < tz) { // Move On X current.x = current.x + step.x; tx += distToNextX.distance; } else { // Move On Z current.z = current.z + step.z; tz += distToNextZ.distance; } } else { if (ty < tz) { // Move On Y current.y = current.y + step.y; ty += distToNextY.distance; } else { // Move On Z current.z = current.z + step.z; tz += distToNextZ.distance; } } #region Debug currentGridController = CubeGlobalData.Instance.GetGridAtIndex(current); if (currentGridController != null) { JoeRayCaster.voxelsHitList.Add(currentGridController); } #endregion hasHit = (bestHit.distance < float.PositiveInfinity); outside = SpatialGridCompute.IsGridIndexOutsideGrid(spatialGrid, current); }while(!hasHit && !outside); } else { JoeRayCaster.voxelsHitList.Clear(); } return(bestHit); }
//TODO: Substantial redundancy here. If a change is ever needed, compress them down. /// <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="rayHit">Hit location of the ray on the collidable, if any.</param> /// <returns>Whether or not the ray hit the collidable.</returns> public override bool RayCast(Ray ray, float maximumLength, Func<BroadPhaseEntry, bool> filter, out RayHit rayHit) { rayHit = new RayHit(); if (filter(this)) { var hitElements = Resources.GetCompoundChildList(); if (hierarchy.Tree.GetOverlaps(ray, maximumLength, hitElements)) { rayHit.T = float.MaxValue; for (int i = 0; i < hitElements.count; i++) { RayHit tempHit; if (hitElements.Elements[i].CollisionInformation.RayCast(ray, maximumLength, filter, out tempHit) && tempHit.T < rayHit.T) { rayHit = tempHit; } } Resources.GiveBack(hitElements); return rayHit.T != float.MaxValue; } Resources.GiveBack(hitElements); } return false; }
/// <summary> /// Gets the intersection between the triangle and the ray. /// </summary> /// <param name="ray">Ray to test against the triangle.</param> /// <param name="transform">Transform to apply to the triangle shape for the test.</param> /// <param name="maximumLength">Maximum distance to travel in units of the direction vector's length.</param> /// <param name="hit">Hit data of the ray cast, if any.</param> /// <returns>Whether or not the ray hit the target.</returns> public override bool RayTest(ref Ray ray, ref RigidTransform transform, Fix64 maximumLength, out RayHit hit) { Matrix3x3 orientation; Matrix3x3.CreateFromQuaternion(ref transform.Orientation, out orientation); Ray localRay; Quaternion conjugate; Quaternion.Conjugate(ref transform.Orientation, out conjugate); Quaternion.Transform(ref ray.Direction, ref conjugate, out localRay.Direction); Vector3.Subtract(ref ray.Position, ref transform.Position, out localRay.Position); Quaternion.Transform(ref localRay.Position, ref conjugate, out localRay.Position); bool toReturn = Toolbox.FindRayTriangleIntersection(ref localRay, maximumLength, sidedness, ref vA, ref vB, ref vC, out hit); //Move the hit back into world space. Vector3.Multiply(ref ray.Direction, hit.T, out hit.Location); Vector3.Add(ref ray.Position, ref hit.Location, out hit.Location); Quaternion.Transform(ref hit.Normal, ref transform.Orientation, out hit.Normal); return(toReturn); }
///<summary> /// Tests a ray against the mesh. ///</summary> ///<param name="ray">Ray to test.</param> ///<param name="maximumLength">Maximum length to test in units of the ray direction's length.</param> ///<param name="sidedness">Sidedness to use when raycasting. Doesn't have to be the same as the mesh's own sidedness.</param> ///<param name="rayHit">Data about the ray's intersection with the mesh, if any.</param> ///<returns>Whether or not the ray hit the mesh.</returns> public bool RayCast(Ray ray, float maximumLength, TriangleSidedness sidedness, out RayHit rayHit) { return(mesh.RayCast(ray, maximumLength, sidedness, out rayHit)); }
/// <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) { return(Shape.RayCast(ref ray, maximumLength, ref worldTransform, out rayHit)); }
public override bool RayCast(Ray ray, float maximumLength, out RayHit rayHit) { return triangleMesh.RayCast(ray, maximumLength, TriangleSidedness.DoubleSided, out rayHit); }
/// <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(CollisionShapes.ConvexShapes.ConvexShape castShape, ref RigidTransform startingTransform, ref Vector3 sweep, out RayHit hit) { hit = new RayHit(); BoundingBox localSpaceBoundingBox; castShape.GetSweptLocalBoundingBox(ref startingTransform, ref worldTransform, ref sweep, out localSpaceBoundingBox); var tri = PhysicsThreadResources.GetTriangle(); var hitElements = new QuickList <int>(BufferPools <int> .Thread); if (Shape.GetOverlaps(localSpaceBoundingBox, ref hitElements)) { hit.T = float.MaxValue; for (int i = 0; i < hitElements.Count; i++) { Shape.GetTriangle(hitElements.Elements[i], ref worldTransform, out tri.vA, out tri.vB, 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; PhysicsThreadResources.GiveBack(tri); hitElements.Dispose(); return(hit.T != float.MaxValue); } PhysicsThreadResources.GiveBack(tri); hitElements.Dispose(); return(false); }
/// <summary> /// Tests to see if a ray's origin is contained within the mesh. /// If it is, the hit location is found. /// If it isn't, the hit location is still valid if a hit occurred. /// If the origin isn't inside and there was no hit, the hit has a T value of float.MaxValue. /// </summary> /// <param name="ray">Ray in the local space of the shape to test.</param> /// <param name="hit">The first hit against the mesh, if any.</param> /// <returns>Whether or not the ray origin was in the mesh.</returns> public bool IsLocalRayOriginInMesh(ref Ray ray, out RayHit hit) { if (IsLocalRayOriginInMeshHelper(ref ray, out hit)) { if (numberOfContainmentChecks > 1 && hit.T > DepthDoubleCheckLimit) { //It's an extremely deep penetration... Suspicious. //Send the ray in the other direction to corroborate the result. //A false positive can sometimes occur Ray alternateRay; Vector3.Negate(ref ray.Direction, out alternateRay.Direction); alternateRay.Position = ray.Position; RayHit alternateHit; if (!IsLocalRayOriginInMeshHelper(ref alternateRay, out alternateHit)) { //The double check didn't hit anything. It's very unlikely that the object is actually inside the shape. return false; } else if (numberOfContainmentChecks > 2) { //It found a hit in the other direction. Triple checking is enabled though, so let's try a third direction! //This one will be perpendicular to the current ray direction. Vector3.Cross(ref ray.Direction, ref Toolbox.UpVector, out alternateRay.Direction); float lengthSquared = alternateRay.Direction.LengthSquared(); if (lengthSquared < Toolbox.Epsilon) { //The ray direction was already pointing nearly up. Pick a different direction. Vector3.Cross(ref ray.Direction, ref Toolbox.RightVector, out alternateRay.Direction); lengthSquared = alternateRay.Direction.LengthSquared(); } Vector3.Divide(ref alternateRay.Direction, (float)Math.Sqrt(lengthSquared), out alternateRay.Direction); alternateRay.Position = ray.Position; if (!IsLocalRayOriginInMeshHelper(ref alternateRay, out alternateHit)) { //No hit was found on the third test! The fact that we had two false positives is extremely improbable, //but it's better to assume that it is not intersecting. return false; } } } return true; } return false; }
public override bool ConvexCast(ConvexShape castShape, ref RigidTransform startingTransform, ref System.Numerics.Vector3 sweep, out RayHit hit) { return(MPRToolbox.Sweep(castShape, Shape, ref sweep, ref Toolbox.ZeroVector, ref startingTransform, ref worldTransform, out hit)); }
internal bool IsHitUnique(RawList<RayHit> hits, ref RayHit hit) { for (int i = 0; i < hits.count; i++) { if (Math.Abs(hits.Elements[i].T - hit.T) < MeshHitUniquenessThreshold) return false; } hits.Add(hit); return true; }
/// <summary> /// Gets the intersection between the sphere and the ray. /// </summary> /// <param name="ray">Ray to test against the sphere.</param> /// <param name="transform">Transform applied to the convex for the test.</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) { return(Toolbox.RayCastSphere(ref ray, ref transform.Position, collisionMargin, maximumLength, out hit)); }
public override bool ConvexCast(ConvexShape castShape, ref MathExtensions.RigidTransform startingTransform, ref Vector3 sweep, out RayHit hit) { return MPRToolbox.Sweep(castShape, Shape, ref sweep, ref Toolbox.ZeroVector, ref startingTransform, ref worldTransform, out hit); }
/// <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) { return(RayCast(ray, maximumLength, sidedness, out rayHit)); }
/// <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); }
///<summary> /// Tests a ray against the instance. ///</summary> ///<param name="ray">Ray to test.</param> ///<param name="maximumLength">Maximum length of the ray to test; in units of the ray's direction's length.</param> ///<param name="sidedness">Sidedness to use during the ray cast. This does not have to be the same as the mesh's sidedness.</param> ///<param name="rayHit">The hit location of the ray on the mesh, if any.</param> ///<returns>Whether or not the ray hit the mesh.</returns> public bool RayCast(Ray ray, float maximumLength, TriangleSidedness sidedness, out RayHit rayHit) { //Put the ray into local space. Ray localRay; AffineTransform inverse; AffineTransform.Invert(ref worldTransform, out inverse); Matrix3X3.Transform(ref ray.Direction, ref inverse.LinearTransform, out localRay.Direction); AffineTransform.Transform(ref ray.Position, ref inverse, out localRay.Position); 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.TransformTranspose(ref rayHit.Normal, ref inverse.LinearTransform, out rayHit.Normal); return(true); } rayHit = new RayHit(); return(false); }
/// <summary> /// Helper to add ray hit in a Tri (triangle). /// </summary> private void AddRayInTri(Tri triProj, RayTrans rayTrans, ref List<RayHit> rayHits) { // Check for hit in triangle Vector3 posHitProj; Vector3 normalProj; if (HitRayInTri(triProj, rayTrans.Position1RayProj, rayTrans.VectorRayProj, out posHitProj, out normalProj)) { // Hack to circumvent ghost face bug in PrimMesher by removing hits in (ghost) face plane through shape center if (Math.Abs(Vector3.Dot(posHitProj, normalProj)) < m_floatToleranceInCastRay && !rayTrans.ShapeNeedsEnds) return; // Transform hit and normal to region coordinate system Vector3 posHit = rayTrans.PositionPart + (posHitProj * rayTrans.ScalePart) * rayTrans.RotationPart; Vector3 normal = Vector3.Normalize((normalProj * rayTrans.ScalePart) * rayTrans.RotationPart); // Remove duplicate hits at triangle intersections float distance = Vector3.Distance(rayTrans.Position1Ray, posHit); for (int i = rayHits.Count - 1; i >= 0; i--) { if (rayHits[i].PartId != rayTrans.PartId) break; if (Math.Abs(rayHits[i].Distance - distance) < m_floatTolerance2InCastRay) return; } // Build result data set RayHit rayHit = new RayHit(); rayHit.PartId = rayTrans.PartId; rayHit.GroupId = rayTrans.GroupId; rayHit.Link = rayTrans.Link; rayHit.Position = posHit; rayHit.Normal = normal; rayHit.Distance = distance; rayHits.Add(rayHit); } }
/// <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(CollisionShapes.ConvexShapes.ConvexShape castShape, ref RigidTransform startingTransform, ref Vector3 sweep, out RayHit hit) { hit = new RayHit(); BoundingBox boundingBox; castShape.GetSweptLocalBoundingBox(ref startingTransform, ref worldTransform, ref sweep, out boundingBox); var tri = Resources.GetTriangle(); var hitElements = Resources.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 worldTransform, out tri.vA); AffineTransform.Transform(ref tri.vB, ref worldTransform, out tri.vB); AffineTransform.Transform(ref tri.vC, ref worldTransform, 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(); triangleTransform.Orientation = Quaternion.Identity; triangleTransform.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; Resources.GiveBack(tri); Resources.GiveBack(hitElements); return(hit.T != float.MaxValue); } Resources.GiveBack(tri); Resources.GiveBack(hitElements); return(false); }
///<summary> /// Tests a ray against the surface of the mesh. This does not take into account solidity. ///</summary> ///<param name="ray">Ray to test.</param> ///<param name="maximumLength">Maximum length of the ray to test; in units of the ray's direction's length.</param> ///<param name="sidedness">Sidedness to use during the ray cast. This does not have to be the same as the mesh's sidedness.</param> ///<param name="rayHit">The hit location of the ray on the mesh, if any.</param> ///<returns>Whether or not the ray hit the mesh.</returns> public bool RayCast(Ray ray, float maximumLength, TriangleSidedness sidedness, 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.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; }
/// <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 abstract bool RayCast(Ray ray, float maximumLength, out RayHit rayHit);
/// <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; case MobileMeshSolidity.DoubleSided: 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; }
public override void registerHit(RayHit hit) { m_hits.Add(hit); m_lightTexture.SetPixel(hit.pixel.x, hit.pixel.y, hit.ray.color); }
protected override bool ShadowRayTest(ref RayHit shadowRayHit, ref RayData shadowRay, out RgbSpectrum attenuation, out bool continueTrace) { var hit = shadowRayHit.Index == 0xffffffffu || scene.IsLight((int)shadowRayHit.Index); attenuation = new RgbSpectrum(1f); continueTrace = false; if (hit) return true; var mesh = scene.GetMeshByTriangleIndex((int)shadowRayHit.Index); var mat = //SurfaceMaterials.CreateMaterial(scene.MaterialProvider.Get(mesh.MaterialName)); scene.MatLib.GetSurfMat(mesh != null ? mesh.MaterialName : "default"); if (mat.TransparentShadows) { continueTrace = true; return true; } if (mat.AlphaTexture != null) { continueTrace = true; this.SurfaceSampler.GetIntersection(ref shadowRay, ref shadowRayHit, ref hitInfo, IntersectionOptions.ResolveTextures); attenuation = (RgbSpectrum) hitInfo.TextureData.Alpha; hit = true; //mat.MaterialData.Kt.Filter() < Sample.GetLazyValue(); } return hit; }
/// <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="rayHit">Hit data, if any.</param> /// <param name="hitChild">Child collidable hit by the ray, if any.</param> /// <returns>Whether or not the ray hit the entry.</returns> public bool RayCast(Ray ray, float maximumLength, out RayHit rayHit, out CompoundChild hitChild) { rayHit = new RayHit(); hitChild = null; var hitElements = Resources.GetCompoundChildList(); if (hierarchy.Tree.GetOverlaps(ray, maximumLength, hitElements)) { rayHit.T = float.MaxValue; for (int i = 0; i < hitElements.count; i++) { EntityCollidable candidate = hitElements.Elements[i].CollisionInformation; RayHit tempHit; if (candidate.RayCast(ray, maximumLength, out tempHit) && tempHit.T < rayHit.T) { rayHit = tempHit; hitChild = hitElements.Elements[i]; } } Resources.GiveBack(hitElements); return rayHit.T != float.MaxValue; } Resources.GiveBack(hitElements); return false; }
/// <summary> /// Sweeps a convex shape against the entry. /// </summary> /// <param name="castShape">Swept shape.</param> /// <param name="startingTransform">Beginning location and orientation of the cast shape.</param> /// <param name="sweep">Sweep motion to apply to the cast shape.</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="hit">Hit data of the cast on the entry, if any.</param> /// <returns>Whether or not the cast hit the entry.</returns> public virtual bool ConvexCast(ConvexShape castShape, ref RigidTransform startingTransform, ref Vector3 sweep, Func <BroadPhaseEntry, bool> filter, out RayHit hit) { if (filter(this)) { return(ConvexCast(castShape, ref startingTransform, ref sweep, out hit)); } hit = new RayHit(); return(false); }
/// <summary> /// Sweeps a convex shape against the entry. /// </summary> /// <param name="castShape">Swept shape.</param> /// <param name="startingTransform">Beginning location and orientation of the cast shape.</param> /// <param name="sweep">Sweep motion to apply to the cast shape.</param> /// <param name="hit">Hit data of the ray on the entry, if any.</param> /// <returns>Whether or not the ray hit the entry.</returns> public abstract bool ConvexCast(ConvexShape castShape, ref RigidTransform startingTransform, ref Vector3 sweep, out RayHit hit);
/// <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 System.Numerics.Vector3 sweep, out RayHit hit) { hit = new RayHit(); BoundingBox boundingBox; castShape.GetSweptBoundingBox(ref startingTransform, ref sweep, out boundingBox); var tri = PhysicsThreadResources.GetTriangle(); var hitElements = CommonResources.GetIntList(); if (Mesh.Tree.GetOverlaps(boundingBox, hitElements)) { hit.T = float.MaxValue; for (int i = 0; i < hitElements.Count; i++) { mesh.Data.GetTriangle(hitElements[i], out tri.vA, out tri.vB, out tri.vC); System.Numerics.Vector3 center; Vector3Ex.Add(ref tri.vA, ref tri.vB, out center); Vector3Ex.Add(ref center, ref tri.vC, out center); Vector3Ex.Multiply(ref center, 1f / 3f, out center); Vector3Ex.Subtract(ref tri.vA, ref center, out tri.vA); Vector3Ex.Subtract(ref tri.vB, ref center, out tri.vB); Vector3Ex.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 = System.Numerics.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; PhysicsThreadResources.GiveBack(tri); CommonResources.GiveBack(hitElements); return(hit.T != float.MaxValue); } PhysicsThreadResources.GiveBack(tri); CommonResources.GiveBack(hitElements); return(false); }
/// <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 try on the entry. 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); else { rayHit = new RayHit(); return false; } }
/// <summary> /// Gets the intersection between the box and the ray. /// </summary> /// <param name="ray">Ray to test against the box.</param> /// <param name="transform">Transform of the shape.</param> /// <param name="maximumLength">Maximum distance to travel in units of the direction vector's length.</param> /// <param name="hit">Hit data for the raycast, 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) { hit = new RayHit(); Quaternion conjugate; Quaternion.Conjugate(ref transform.Orientation, out conjugate); Vector3 localOrigin; Vector3.Subtract(ref ray.Position, ref transform.Position, out localOrigin); Vector3.Transform(ref localOrigin, ref conjugate, out localOrigin); Vector3 localDirection; Vector3.Transform(ref ray.Direction, ref conjugate, out localDirection); Vector3 normal = Toolbox.ZeroVector; float temp, tmin = 0, tmax = maximumLength; if (Math.Abs(localDirection.X) < Toolbox.Epsilon && (localOrigin.X < -halfWidth || localOrigin.X > halfWidth)) { return(false); } float inverseDirection = 1 / localDirection.X; float t1 = (-halfWidth - localOrigin.X) * inverseDirection; float t2 = (halfWidth - localOrigin.X) * inverseDirection; var tempNormal = new Vector3(-1, 0, 0); if (t1 > t2) { temp = t1; t1 = t2; t2 = temp; tempNormal *= -1; } temp = tmin; tmin = Math.Max(tmin, t1); if (temp != tmin) { normal = tempNormal; } tmax = Math.Min(tmax, t2); if (tmin > tmax) { return(false); } if (Math.Abs(localDirection.Y) < Toolbox.Epsilon && (localOrigin.Y < -halfHeight || localOrigin.Y > halfHeight)) { return(false); } inverseDirection = 1 / localDirection.Y; t1 = (-halfHeight - localOrigin.Y) * inverseDirection; t2 = (halfHeight - localOrigin.Y) * inverseDirection; tempNormal = new Vector3(0, -1, 0); if (t1 > t2) { temp = t1; t1 = t2; t2 = temp; tempNormal *= -1; } temp = tmin; tmin = Math.Max(tmin, t1); if (temp != tmin) { normal = tempNormal; } tmax = Math.Min(tmax, t2); if (tmin > tmax) { return(false); } if (Math.Abs(localDirection.Z) < Toolbox.Epsilon && (localOrigin.Z < -halfLength || localOrigin.Z > halfLength)) { return(false); } inverseDirection = 1 / localDirection.Z; t1 = (-halfLength - localOrigin.Z) * inverseDirection; t2 = (halfLength - localOrigin.Z) * inverseDirection; tempNormal = new Vector3(0, 0, -1); if (t1 > t2) { temp = t1; t1 = t2; t2 = temp; tempNormal *= -1; } temp = tmin; tmin = Math.Max(tmin, t1); if (temp != tmin) { normal = tempNormal; } tmax = Math.Min(tmax, t2); if (tmin > tmax) { return(false); } hit.T = tmin; Vector3.Multiply(ref ray.Direction, tmin, out hit.Location); Vector3.Add(ref hit.Location, ref ray.Position, out hit.Location); Vector3.Transform(ref normal, ref transform.Orientation, out normal); hit.Normal = normal; return(true); }