public bool RayHitPlane(Ray ray, out double distanceToHit, out bool hitFrontOfPlane) { distanceToHit = double.PositiveInfinity; hitFrontOfPlane = false; double normalDotRayDirection = Vector3.Dot(planeNormal, ray.direction); if (normalDotRayDirection < TreatAsZero && normalDotRayDirection > -TreatAsZero) // the ray is parallel to the plane { return false; } if (normalDotRayDirection < 0) { hitFrontOfPlane = true; } double distanceToRayOriginFromOrigin = Vector3.Dot(planeNormal, ray.origin); double distanceToPlaneFromRayOrigin = distanceToPlaneFromOrigin - distanceToRayOriginFromOrigin; bool originInFrontOfPlane = distanceToPlaneFromRayOrigin < 0; bool originAndHitAreOnSameSide = originInFrontOfPlane == hitFrontOfPlane; if (!originAndHitAreOnSameSide) { return false; } distanceToHit = distanceToPlaneFromRayOrigin / normalDotRayDirection; return true; }
public void SetPrintLevelingEquation(Vector3 position0, Vector3 position1, Vector3 position2, Vector2 bedCenter) { if (position0 == position1 || position1 == position2 || position2 == position0) { return; } Plane planeOfPoints = new Plane(position0, position1, position2); Ray ray = new Ray(new Vector3(bedCenter, 0), Vector3.UnitZ); bool inFront; double distanceToPlaneAtBedCenter = planeOfPoints.GetDistanceToIntersection(ray, out inFront); Matrix4X4 makePointsFlatMatrix = Matrix4X4.CreateTranslation(-bedCenter.x, -bedCenter.y, -distanceToPlaneAtBedCenter); makePointsFlatMatrix *= Matrix4X4.CreateRotation(planeOfPoints.planeNormal, Vector3.UnitZ); makePointsFlatMatrix *= Matrix4X4.CreateTranslation(bedCenter.x, bedCenter.y, 0);//distanceToPlaneAtBedCenter); bedLevelMatrix = Matrix4X4.Invert(makePointsFlatMatrix); { // test that the points come back as 0 zs Vector3 outPosition0 = Vector3.TransformPosition(position0, makePointsFlatMatrix); Vector3 outPosition1 = Vector3.TransformPosition(position1, makePointsFlatMatrix); Vector3 outPosition2 = Vector3.TransformPosition(position2, makePointsFlatMatrix); Vector3 printPosition0 = new Vector3(ActiveSliceSettings.Instance.GetPrintLevelSamplePosition(0), 0); Vector3 printPosition1 = new Vector3(ActiveSliceSettings.Instance.GetPrintLevelSamplePosition(1), 0); Vector3 printPosition2 = new Vector3(ActiveSliceSettings.Instance.GetPrintLevelSamplePosition(2), 0); Vector3 leveledPositon0 = Vector3.TransformPosition(printPosition0, bedLevelMatrix); Vector3 leveledPositon1 = Vector3.TransformPosition(printPosition1, bedLevelMatrix); Vector3 leveledPositon2 = Vector3.TransformPosition(printPosition2, bedLevelMatrix); } }
internal void PlaneGetDistanceToIntersection() { Plane testPlane = new Plane(Vector3.UnitZ, 10); bool hitFrontOfPlane; double distanceToHit; Ray lookingAtFrontOfPlane = new Ray(new Vector3(0, 0, 11), new Vector3(0, 0, -1)); Assert.IsTrue(testPlane.RayHitPlane(lookingAtFrontOfPlane, out distanceToHit, out hitFrontOfPlane)); Assert.IsTrue(distanceToHit == 1); Assert.IsTrue(hitFrontOfPlane); Ray notLookingAtFrontOfPlane = new Ray(new Vector3(0, 0, 11), new Vector3(0, 0, 1)); Assert.IsTrue(!testPlane.RayHitPlane(notLookingAtFrontOfPlane, out distanceToHit, out hitFrontOfPlane)); Assert.IsTrue(distanceToHit == double.PositiveInfinity); Assert.IsTrue(!hitFrontOfPlane); Ray lookingAtBackOfPlane = new Ray(new Vector3(0, 0, 9), new Vector3(0, 0, 1)); Assert.IsTrue(testPlane.RayHitPlane(lookingAtBackOfPlane, out distanceToHit, out hitFrontOfPlane)); Assert.IsTrue(distanceToHit == 1); Assert.IsTrue(!hitFrontOfPlane); Ray notLookingAtBackOfPlane = new Ray(new Vector3(0, 0, 9), new Vector3(0, 0, -1)); Assert.IsTrue(!testPlane.RayHitPlane(notLookingAtBackOfPlane, out distanceToHit, out hitFrontOfPlane)); Assert.IsTrue(distanceToHit == double.PositiveInfinity); Assert.IsTrue(hitFrontOfPlane); }
private Ray GetRandomIntersectingRay() { double maxDist = 1000000; Vector3 origin = new Vector3( (rayOriginRand.NextDouble() * 2 - 1) * maxDist, (rayOriginRand.NextDouble() * 2 - 1) * maxDist, (rayOriginRand.NextDouble() * 2 - 1) * maxDist); Vector3 direction = Vector3.Normalize(-origin); Ray randomRay = new Ray(origin, direction, 0, double.MaxValue); return randomRay; }
public IntersectInfo GetClosestIntersection(Ray ray) { if (child != null) { Ray localRay = GetLocalSpaceRay(ray); IntersectInfo localIntersection = child.GetClosestIntersection(localRay); IntersectInfo globalIntersection = GetGlobalSpaceInfo(localIntersection); return globalIntersection; } return null; }
public Ray(Ray rayToCopy) { origin = rayToCopy.origin; directionNormal = rayToCopy.directionNormal; minDistanceToConsider = rayToCopy.minDistanceToConsider; maxDistanceToConsider = rayToCopy.maxDistanceToConsider; oneOverDirection = rayToCopy.oneOverDirection; isShadowRay = rayToCopy.isShadowRay; intersectionType = rayToCopy.intersectionType; sign[0] = rayToCopy.sign[0]; sign[1] = rayToCopy.sign[1]; sign[2] = rayToCopy.sign[2]; }
public IntersectInfo GetClosestIntersection(Ray ray) { IntersectInfo bestInfo = null; foreach (IPrimitive item in items) { IntersectInfo info = item.GetClosestIntersection(ray); if (info != null && info.hitType != IntersectionType.None && info.distanceToHit >= 0) { if (bestInfo == null || info.distanceToHit < bestInfo.distanceToHit) { bestInfo = info; } } } return bestInfo; }
public override IntersectInfo GetClosestIntersection(Ray ray) { bool inFront; double distanceToHit = plane.GetDistanceToIntersection(ray, out inFront); if (distanceToHit > 0) { IntersectInfo info = new IntersectInfo(); info.closestHitObject = this; info.hitType = IntersectionType.FrontFace; info.hitPosition = ray.origin + ray.directionNormal * distanceToHit; info.normalAtHit = plane.planeNormal; info.distanceToHit = distanceToHit; return info; } return null; }
public IntersectInfo GetClosestIntersection(Ray ray) { List<IntersectInfo> allPrimary = new List<IntersectInfo>(); Ray checkFrontAndBacks = new Ray(ray); checkFrontAndBacks.intersectionType = IntersectionType.Both; foreach (IntersectInfo info in primary.IntersectionIterator(checkFrontAndBacks)) { allPrimary.Add(info); } if (allPrimary.Count == 0) { // We did not hit the primary object. We are done. The subtract object does not mater. return null; } allPrimary.Sort(new CompareIntersectInfoOnDistance()); // we hit the primary object, did we hit the subtract object before (within error) hitting the primary. List<IntersectInfo> allSubtract = new List<IntersectInfo>(); foreach (IntersectInfo info in subtract.IntersectionIterator(checkFrontAndBacks)) { allSubtract.Add(info); } if (allSubtract.Count == 0) { // we did not hit the subtract so return the first primary return allPrimary[0]; } allSubtract.Sort(new CompareIntersectInfoOnDistance()); List<IntersectInfo> result = new List<IntersectInfo>(); IntersectInfo.Subtract(allPrimary, allSubtract, result); if (result.Count > 0) { return result[0]; } return null; }
public void SetPrintLevelingEquation(Vector3 position0, Vector3 position1, Vector3 position2, Vector2 bedCenter) { if (position0 == position1 || position1 == position2 || position2 == position0) { return; } Plane planeOfPoints = new Plane(position0, position1, position2); Ray ray = new Ray(new Vector3(bedCenter, 0), Vector3.UnitZ); bool inFront; double distanceToPlaneAtBedCenter = planeOfPoints.GetDistanceToIntersection(ray, out inFront); Matrix4X4 makePointsFlatMatrix = Matrix4X4.CreateTranslation(-bedCenter.x, -bedCenter.y, -distanceToPlaneAtBedCenter); makePointsFlatMatrix *= Matrix4X4.CreateRotation(planeOfPoints.PlaneNormal, Vector3.UnitZ); makePointsFlatMatrix *= Matrix4X4.CreateTranslation(bedCenter.x, bedCenter.y, 0);//distanceToPlaneAtBedCenter); bedLevelMatrix = Matrix4X4.Invert(makePointsFlatMatrix); }
private IntersectInfo FindNextIntersections(IPrimitive element, Ray ray, IntersectInfo info, IntersectionType intersectionType) { // get all the intersection for the object Ray currentRayCheckBackfaces = new Ray(ray); currentRayCheckBackfaces.intersectionType = intersectionType; currentRayCheckBackfaces.minDistanceToConsider = ((info.hitPosition + ray.directionNormal * Ray.sameSurfaceOffset) - ray.origin).Length; currentRayCheckBackfaces.maxDistanceToConsider = double.PositiveInfinity; return element.GetClosestIntersection(currentRayCheckBackfaces); }
public IEnumerable IntersectionIterator(Ray ray) { List<IntersectInfo> allPrimary = new List<IntersectInfo>(); Ray checkFrontAndBacks = new Ray(ray); checkFrontAndBacks.intersectionType = IntersectionType.Both; foreach (IntersectInfo info in primary.IntersectionIterator(checkFrontAndBacks)) { allPrimary.Add(info); } if (allPrimary.Count == 0) { // We did not hit the primary object. We are done. The subtract object does not mater. //yield break; } allPrimary.Sort(new CompareIntersectInfoOnDistance()); // we hit the primary object, did we hit the subtract object before (within error) hitting the primary. List<IntersectInfo> allSubtract = new List<IntersectInfo>(); foreach (IntersectInfo info in subtract.IntersectionIterator(checkFrontAndBacks)) { allSubtract.Add(info); } if (allSubtract.Count == 0) { // we did not hit the subtract so return the primary foreach (IntersectInfo primaryInfo in allPrimary) { yield return primaryInfo; } yield break; } allSubtract.Sort(new CompareIntersectInfoOnDistance()); List<IntersectInfo> results = new List<IntersectInfo>(); IntersectInfo.Subtract(allPrimary, allSubtract, results); foreach (IntersectInfo resultInfo in results) { yield return resultInfo; } }
public void DifferenceTestsForBox() { SolidMaterial redMaterial = new SolidMaterial(RGBA_Floats.Red, 0, 0, 0); SolidMaterial blueMaterial = new SolidMaterial(RGBA_Floats.Blue, 0, 0, 0); Ray castRay = new Ray(new Vector3(0, -1, 0), Vector3.UnitY); BoxShape box1X1 = new BoxShape(new Vector3(-.5, -.5, -.5), new Vector3(.5, .5, .5), blueMaterial); // just a box all by itself { IntersectInfo testInfo = box1X1.GetClosestIntersection(castRay); Assert.IsTrue(testInfo.hitType == IntersectionType.FrontFace, "Found Hit : Box No CSG"); Assert.IsTrue(testInfo.closestHitObject == box1X1, "Found Hit : Box No CSG"); Assert.IsTrue(testInfo.hitPosition == new Vector3(0, -.5, 0), "Hit position y = -.5 : Box No CSG"); Assert.IsTrue(testInfo.distanceToHit == .5, "Hit length = .5 : Box No CSG"); Assert.IsTrue(testInfo.normalAtHit == -Vector3.UnitY, "Normal Correct : Box No CSG"); } // one subtract from the front of a box, the front faces are aligned { BoxShape subtractBox = new BoxShape(new Vector3(-.5, -.5, -.5), new Vector3(.5, 0, .5), redMaterial); Difference merge = new Difference(box1X1, subtractBox); IntersectInfo testInfo = merge.GetClosestIntersection(castRay); Assert.IsTrue(testInfo.hitType == IntersectionType.FrontFace, "Found Hit : One Subtract"); Assert.IsTrue(testInfo.closestHitObject == subtractBox, "Found Hit : One Subtract"); Assert.IsTrue(testInfo.hitPosition == new Vector3(0, 0, 0), "Hit position y = 0 : One Subtract"); Assert.IsTrue(testInfo.distanceToHit == 1, "Hit length = 1 : One Subtract"); Assert.IsTrue(testInfo.normalAtHit == -Vector3.UnitY, "Normal Correct : One Subtract"); } #if false // An internal primary object that needs to be skipped over { List<IPrimitive> primaryShapes = new List<IPrimitive>(); BoxShape insideBox = new BoxShape(new Vector3(-.1, -.1, -.1), new Vector3(.1, .1, .1), blueMaterial); primaryShapes.Add(box1X1); primaryShapes.Add(insideBox); IPrimitive primamryGroup = BoundingVolumeHierarchy.CreateNewHierachy(primaryShapes); List<IPrimitive> subtractShapes = new List<IPrimitive>(); subtractShapes.Add(new BoxShape(new Vector3(-.5, -.5, -.5), new Vector3(.5, .4, .5), redMaterial)); IPrimitive subtractGroup = BoundingVolumeHierarchy.CreateNewHierachy(subtractShapes); Difference merge = new Difference(primamryGroup, subtractGroup); IntersectInfo testInfo = merge.GetClosestIntersection(castRay); Assert.IsTrue(testInfo.isHit == true, "Found Hit : 5 Subtracts"); //Assert.IsTrue(testInfo.closestHitObject == subtractBox, "Found Hit : 5 Subtracts"); Assert.IsTrue(testInfo.hitPosition == new Vector3(0, 0, 0), "Hit position y = 0 : 5 Subtracts"); Assert.IsTrue(testInfo.distanceToHit == 1, "Hit length = 1 : 5 Subtracts"); Assert.IsTrue(testInfo.normalAtHit == -Vector3.UnitY, "Normal Correct : 5 Subtracts"); } // Go through 5 subtract boxes to get to 1/2 way through the main box. { List<IPrimitive> subtractShapes = new List<IPrimitive>(); for (int i = 0; i < 5; i++) { subtractShapes.Add(new BoxShape(new Vector3(-.5, -.5 + i * .1, -.5), new Vector3(.5, -.4 + i * .1, .5), redMaterial)); } IPrimitive subtractGroup = BoundingVolumeHierarchy.CreateNewHierachy(subtractShapes); Difference merge = new Difference(box1X1, subtractGroup); IntersectInfo testInfo = merge.GetClosestIntersection(castRay); Assert.IsTrue(testInfo.isHit == true, "Found Hit : 5 Subtracts"); //Assert.IsTrue(testInfo.closestHitObject == subtractBox, "Found Hit : 5 Subtracts"); Assert.IsTrue(testInfo.hitPosition == new Vector3(0, 0, 0), "Hit position y = 0 : 5 Subtracts"); Assert.IsTrue(testInfo.distanceToHit == 1, "Hit length = 1 : 5 Subtracts"); Assert.IsTrue(testInfo.normalAtHit == -Vector3.UnitY, "Normal Correct : 5 Subtracts"); } #endif }
public bool GetCutLine(Plane cutPlane, out Vector3 start, out Vector3 end) { start = new Vector3(); end = new Vector3(); int splitCount = 0; FaceEdge prevEdge = null; bool prevInFront = false; bool first = true; FaceEdge firstEdge = null; bool firstInFront = false; foreach (FaceEdge faceEdge in FaceEdges()) { if (first) { prevEdge = faceEdge; prevInFront = cutPlane.GetDistanceFromPlane(prevEdge.firstVertex.Position) > 0; first = false; firstEdge = prevEdge; firstInFront = prevInFront; } else { FaceEdge curEdge = faceEdge; bool curInFront = cutPlane.GetDistanceFromPlane(curEdge.firstVertex.Position) > 0; if (prevInFront != curInFront) { // we crossed over the cut line Vector3 directionNormal = (curEdge.firstVertex.Position - prevEdge.firstVertex.Position).GetNormal(); Ray edgeRay = new Ray(prevEdge.firstVertex.Position, directionNormal); double distanceToHit; bool hitFrontOfPlane; if (cutPlane.RayHitPlane(edgeRay, out distanceToHit, out hitFrontOfPlane)) { splitCount++; if (splitCount == 1) { start = edgeRay.origin + edgeRay.directionNormal * distanceToHit; } else { end = edgeRay.origin + edgeRay.directionNormal * distanceToHit; } } } prevEdge = curEdge; prevInFront = curInFront; if (splitCount == 2) { break; } } } if (splitCount == 1 && prevInFront != firstInFront) { // we crossed over the cut line Vector3 directionNormal = (firstEdge.firstVertex.Position - prevEdge.firstVertex.Position).GetNormal(); Ray edgeRay = new Ray(prevEdge.firstVertex.Position, directionNormal); double distanceToHit; bool hitFrontOfPlane; if (cutPlane.RayHitPlane(edgeRay, out distanceToHit, out hitFrontOfPlane)) { splitCount++; end = edgeRay.origin + edgeRay.directionNormal * distanceToHit; } } if (splitCount == 2) { return true; } return false; }
Ray GetLocalSpaceRay(Ray ray) { // TODO: cache this. Matrix4X4 WorldToAxis = Matrix4X4.Invert(AxisToWorld); Vector3 transformedOrigin = Vector3.TransformPosition(ray.origin, WorldToAxis); Vector3 transformedDirecton = Vector3.TransformVector(ray.direction, WorldToAxis); return new Ray(transformedOrigin, transformedDirecton, ray.minDistanceToConsider, ray.maxDistanceToConsider, ray.intersectionType); }
public IEnumerable IntersectionIterator(Ray ray) { foreach (IPrimitive item in items) { foreach (IntersectInfo info in item.IntersectionIterator(ray)) { yield return info; } } }
public override IntersectInfo GetClosestIntersection(Ray ray) { double radiusSquared = radius * radius; Vector2 rayOrigin = new Vector2(ray.origin); Vector2 rayDirectionXY = new Vector2(ray.direction); Vector2 rayDirection = rayDirectionXY.GetNormal(); Vector2 thisPosition = Vector2.Zero; Vector2 deltaFromShpereCenterToRayOrigin = rayOrigin - thisPosition; double distanceFromCircleCenterToRayOrigin = Vector2.Dot(deltaFromShpereCenterToRayOrigin, rayDirection); // negative means the Circle is in front of the ray. double lengthFromRayOrginToCircleCenterSquared = Vector2.Dot(deltaFromShpereCenterToRayOrigin, deltaFromShpereCenterToRayOrigin); double lengthFromRayOrigintoNearEdgeOfCircleSquared = lengthFromRayOrginToCircleCenterSquared - radiusSquared; double distanceFromCircleCenterToRaySquared = distanceFromCircleCenterToRayOrigin * distanceFromCircleCenterToRayOrigin; double amountCircleCenterToRayIsGreaterThanRayOriginToEdgeSquared = distanceFromCircleCenterToRaySquared - lengthFromRayOrigintoNearEdgeOfCircleSquared; if (amountCircleCenterToRayIsGreaterThanRayOriginToEdgeSquared > 0) { { bool inFrontOfTop; double testDistanceToHit = topPlane.GetDistanceToIntersection(ray, out inFrontOfTop); bool wantFrontAndInFront = (ray.intersectionType & IntersectionType.FrontFace) == IntersectionType.FrontFace && inFrontOfTop; bool wantBackAndInBack = (ray.intersectionType & IntersectionType.BackFace) == IntersectionType.BackFace && !inFrontOfTop; if (wantFrontAndInFront || wantBackAndInBack) { Vector3 topHitPosition = ray.origin + ray.direction * testDistanceToHit; if (topHitPosition.x * topHitPosition.x + topHitPosition.y * topHitPosition.y < topRadius * topRadius) { IntersectInfo topHitInfo = new IntersectInfo(); topHitInfo.hitPosition = topHitPosition; topHitInfo.closestHitObject = this; if (ray.intersectionType == IntersectionType.FrontFace) { topHitInfo.hitType = IntersectionType.FrontFace; topHitInfo.normalAtHit = topPlane.planeNormal; } else { topHitInfo.hitType = IntersectionType.BackFace; topHitInfo.normalAtHit = -topPlane.planeNormal; } topHitInfo.distanceToHit = testDistanceToHit; return topHitInfo; } } } { bool inFrontOfBottom; double testDistanceToHit = bottomPlane.GetDistanceToIntersection(ray, out inFrontOfBottom); if (ray.intersectionType == IntersectionType.FrontFace && inFrontOfBottom || ray.intersectionType == IntersectionType.BackFace && !inFrontOfBottom) { Vector3 bottomHitPosition = ray.origin + ray.direction * testDistanceToHit; if (bottomHitPosition.x * bottomHitPosition.x + bottomHitPosition.y * bottomHitPosition.y < radius * radius) { IntersectInfo bottomHitInfo = new IntersectInfo(); bottomHitInfo.hitPosition = bottomHitPosition; bottomHitInfo.closestHitObject = this; if (ray.intersectionType == IntersectionType.FrontFace) { bottomHitInfo.hitType = IntersectionType.FrontFace; bottomHitInfo.normalAtHit = bottomPlane.planeNormal; } else { bottomHitInfo.hitType = IntersectionType.BackFace; bottomHitInfo.normalAtHit = -bottomPlane.planeNormal; } bottomHitInfo.distanceToHit = testDistanceToHit; return bottomHitInfo; } } } IntersectInfo info = new IntersectInfo(); info.closestHitObject = this; info.hitType = IntersectionType.FrontFace; if (ray.isShadowRay) { return info; } double distanceFromRayOriginToCircleCenter = -distanceFromCircleCenterToRayOrigin; double amountCircleCenterToRayIsGreaterThanRayOriginToEdge = Math.Sqrt(amountCircleCenterToRayIsGreaterThanRayOriginToEdgeSquared); double scaleRatio = ray.direction.Length / rayDirectionXY.Length; if (ray.intersectionType == IntersectionType.FrontFace) { double distanceToFrontHit = (distanceFromRayOriginToCircleCenter - amountCircleCenterToRayIsGreaterThanRayOriginToEdge) * scaleRatio; if (distanceToFrontHit > ray.maxDistanceToConsider || distanceToFrontHit < ray.minDistanceToConsider) { return null; } info.distanceToHit = distanceToFrontHit; info.hitPosition = ray.origin + ray.direction * info.distanceToHit; if (info.hitPosition.z < -height / 2 || info.hitPosition.z > height / 2) { return null; } info.normalAtHit = new Vector3(info.hitPosition.x, info.hitPosition.y, 0).GetNormal(); } else if (ray.intersectionType == IntersectionType.BackFace)// check back faces { double distanceToBackHit = (distanceFromRayOriginToCircleCenter + amountCircleCenterToRayIsGreaterThanRayOriginToEdge) * scaleRatio; if (distanceToBackHit > ray.maxDistanceToConsider || distanceToBackHit < ray.minDistanceToConsider) { return null; } info.hitType = IntersectionType.BackFace; info.distanceToHit = distanceToBackHit; info.hitPosition = ray.origin + ray.direction * info.distanceToHit; if (info.hitPosition.z < height / 2 || info.hitPosition.z > height / 2) { return null; } info.normalAtHit = -(new Vector3(info.hitPosition.x, info.hitPosition.y, 0).GetNormal()); } return info; } return null; }
public override IEnumerable IntersectionIterator(Ray ray) { double radiusSquared = radius * radius; Vector2 rayOrigin = new Vector2(ray.origin); Vector2 rayDirectionXY = new Vector2(ray.direction); Vector2 rayDirection = rayDirectionXY.GetNormal(); Vector2 thisPosition = Vector2.Zero; Vector2 deltaFromShpereCenterToRayOrigin = rayOrigin - thisPosition; double distanceFromCircleCenterToRayOrigin = Vector2.Dot(deltaFromShpereCenterToRayOrigin, rayDirection); double lengthFromRayOrginToCircleCenterSquared = Vector2.Dot(deltaFromShpereCenterToRayOrigin, deltaFromShpereCenterToRayOrigin); double lengthFromRayOrigintoNearEdgeOfCircleSquared = lengthFromRayOrginToCircleCenterSquared - radiusSquared; double distanceFromCircleCenterToRaySquared = distanceFromCircleCenterToRayOrigin * distanceFromCircleCenterToRayOrigin; double amountCircleCenterToRayIsGreaterThanRayOriginToEdgeSquared = distanceFromCircleCenterToRaySquared - lengthFromRayOrigintoNearEdgeOfCircleSquared; if (amountCircleCenterToRayIsGreaterThanRayOriginToEdgeSquared > 0) { double distanceFromRayOriginToCircleCenter = -distanceFromCircleCenterToRayOrigin; double amountCircleCenterToRayIsGreaterThanRayOriginToEdge = Math.Sqrt(amountCircleCenterToRayIsGreaterThanRayOriginToEdgeSquared); double scaleRatio = ray.direction.Length / rayDirectionXY.Length; if ((ray.intersectionType & IntersectionType.FrontFace) == IntersectionType.FrontFace) { IntersectInfo info = new IntersectInfo(); info.hitType = IntersectionType.FrontFace; info.closestHitObject = this; double distanceToFrontHit = (distanceFromRayOriginToCircleCenter - amountCircleCenterToRayIsGreaterThanRayOriginToEdge) * scaleRatio; info.distanceToHit = distanceToFrontHit; info.hitPosition = ray.origin + ray.direction * info.distanceToHit; if (info.hitPosition.z > -height / 2 && info.hitPosition.z < height / 2) { info.normalAtHit = new Vector3(info.hitPosition.x, info.hitPosition.y, 0).GetNormal(); yield return info; } } if ((ray.intersectionType & IntersectionType.BackFace) == IntersectionType.BackFace) { IntersectInfo info = new IntersectInfo(); info.hitType = IntersectionType.BackFace; info.closestHitObject = this; double distanceToBackHit = (distanceFromRayOriginToCircleCenter + amountCircleCenterToRayIsGreaterThanRayOriginToEdge) * scaleRatio; info.distanceToHit = distanceToBackHit; info.hitPosition = ray.origin + ray.direction * info.distanceToHit; if (info.hitPosition.z > -height / 2 && info.hitPosition.z < height / 2) { info.normalAtHit = -(new Vector3(info.hitPosition.x, info.hitPosition.y, 0).GetNormal()); yield return info; } } { bool inFrontOfTopFace; double testDistanceToHit = topPlane.GetDistanceToIntersection(ray, out inFrontOfTopFace); Vector3 topHitPosition = ray.origin + ray.direction * testDistanceToHit; if (topHitPosition.x * topHitPosition.x + topHitPosition.y * topHitPosition.y < topRadius * topRadius) { if ((ray.intersectionType & IntersectionType.FrontFace) == IntersectionType.FrontFace && inFrontOfTopFace) { IntersectInfo topHitInfo = new IntersectInfo(); topHitInfo.hitPosition = topHitPosition; topHitInfo.closestHitObject = this; topHitInfo.hitType = IntersectionType.FrontFace; topHitInfo.normalAtHit = topPlane.planeNormal; topHitInfo.distanceToHit = testDistanceToHit; yield return topHitInfo; } if ((ray.intersectionType & IntersectionType.BackFace) == IntersectionType.BackFace && !inFrontOfTopFace) { IntersectInfo topHitInfo = new IntersectInfo(); topHitInfo.hitPosition = topHitPosition; topHitInfo.closestHitObject = this; topHitInfo.hitType = IntersectionType.BackFace; topHitInfo.normalAtHit = -topPlane.planeNormal; topHitInfo.distanceToHit = testDistanceToHit; yield return topHitInfo; } } } { bool inFrontOfBottomFace; double testDistanceToHit = bottomPlane.GetDistanceToIntersection(ray, out inFrontOfBottomFace); Vector3 bottomHitPosition = ray.origin + ray.direction * testDistanceToHit; if (bottomHitPosition.x * bottomHitPosition.x + bottomHitPosition.y * bottomHitPosition.y < radius * radius) { if ((ray.intersectionType & IntersectionType.FrontFace) == IntersectionType.FrontFace && inFrontOfBottomFace) { IntersectInfo bottomHitInfo = new IntersectInfo(); bottomHitInfo.hitPosition = bottomHitPosition; bottomHitInfo.closestHitObject = this; bottomHitInfo.hitType = IntersectionType.FrontFace; bottomHitInfo.normalAtHit = bottomPlane.planeNormal; bottomHitInfo.distanceToHit = testDistanceToHit; yield return bottomHitInfo; } if ((ray.intersectionType & IntersectionType.BackFace) == IntersectionType.BackFace && !inFrontOfBottomFace) { IntersectInfo bottomHitInfo = new IntersectInfo(); bottomHitInfo.hitPosition = bottomHitPosition; bottomHitInfo.closestHitObject = this; bottomHitInfo.hitType = IntersectionType.BackFace; bottomHitInfo.normalAtHit = -bottomPlane.planeNormal; bottomHitInfo.distanceToHit = testDistanceToHit; yield return bottomHitInfo; } } } } }
public IEnumerable IntersectionIterator(Ray ray) { if (ray.Intersection(Aabb)) { IPrimitive checkFirst = nodeA; IPrimitive checkSecond = nodeB; if (ray.directionNormal[splitingPlane] < 0) { checkFirst = nodeB; checkSecond = nodeA; } foreach (IntersectInfo info in checkFirst.IntersectionIterator(ray)) { if (info != null && info.hitType != IntersectionType.None) { yield return info; } } if (checkSecond != null) { foreach (IntersectInfo info in checkSecond.IntersectionIterator(ray)) { if (info != null && info.hitType != IntersectionType.None) { yield return info; } } } } }
public abstract IEnumerable IntersectionIterator(Ray ray);
public abstract IntersectInfo GetClosestIntersection(Ray ray);
public MouseEvent3DArgs(MouseEventArgs mouseEvent2D, Ray mouseRay, IntersectInfo info) { this.info = info; this.MouseEvent2D = mouseEvent2D; this.mouseRay = mouseRay; }
public override IEnumerable IntersectionIterator(Ray ray) { double radiusSquared = radius * radius; Vector3 deltaFromShpereCenterToRayOrigin = ray.origin - this.position; double distanceFromSphereCenterToRayOrigin = Vector3.Dot(deltaFromShpereCenterToRayOrigin, ray.directionNormal); // negative means the sphere is in front of the ray. double lengthFromRayOrginToSphereCenterSquared = Vector3.Dot(deltaFromShpereCenterToRayOrigin, deltaFromShpereCenterToRayOrigin); double lengthFromRayOrigintoNearEdgeOfSphereSquared = lengthFromRayOrginToSphereCenterSquared - radiusSquared; double distanceFromSphereCenterToRaySquared = distanceFromSphereCenterToRayOrigin * distanceFromSphereCenterToRayOrigin; double amountSphereCenterToRayIsGreaterThanRayOriginToEdgeSquared = distanceFromSphereCenterToRaySquared - lengthFromRayOrigintoNearEdgeOfSphereSquared; if (amountSphereCenterToRayIsGreaterThanRayOriginToEdgeSquared > 0) { double distanceFromRayOriginToSphereCenter = -distanceFromSphereCenterToRayOrigin; double amountSphereCenterToRayIsGreaterThanRayOriginToEdge = Math.Sqrt(amountSphereCenterToRayIsGreaterThanRayOriginToEdgeSquared); if ((ray.intersectionType & IntersectionType.FrontFace) == IntersectionType.FrontFace) { IntersectInfo info = new IntersectInfo(); info.hitType = IntersectionType.FrontFace; info.closestHitObject = this; double distanceToFrontHit = distanceFromRayOriginToSphereCenter - amountSphereCenterToRayIsGreaterThanRayOriginToEdge; info.distanceToHit = distanceToFrontHit; info.hitPosition = ray.origin + ray.directionNormal * info.distanceToHit; info.normalAtHit = (info.hitPosition - position).GetNormal(); yield return info; } if ((ray.intersectionType & IntersectionType.BackFace) == IntersectionType.BackFace) { IntersectInfo info = new IntersectInfo(); info.hitType = IntersectionType.BackFace; info.closestHitObject = this; double distanceToBackHit = distanceFromRayOriginToSphereCenter + amountSphereCenterToRayIsGreaterThanRayOriginToEdge; info.distanceToHit = distanceToBackHit; info.hitPosition = ray.origin + ray.directionNormal * info.distanceToHit; info.normalAtHit = -(info.hitPosition - position).GetNormal(); yield return info; } } }
private bool FindInteractionVolumeHit(Ray ray, out int interactionVolumeHitIndex, out IntersectInfo info) { interactionVolumeHitIndex = -1; if (interactionVolumes.Count == 0 || interactionVolumes[0].CollisionVolume == null) { info = null; return false; } List<IPrimitive> mesheTraceables = new List<IPrimitive>(); foreach (InteractionVolume interactionVolume in interactionVolumes) { IPrimitive traceData = interactionVolume.CollisionVolume; mesheTraceables.Add(new Transform(traceData, interactionVolume.TotalTransform)); } IPrimitive allObjects = BoundingVolumeHierarchy.CreateNewHierachy(mesheTraceables); info = allObjects.GetClosestIntersection(ray); if (info != null) { for (int i = 0; i < interactionVolumes.Count; i++) { List<IPrimitive> insideBounds = new List<IPrimitive>(); interactionVolumes[i].CollisionVolume.GetContained(insideBounds, info.closestHitObject.GetAxisAlignedBoundingBox()); if (insideBounds.Contains(info.closestHitObject)) { interactionVolumeHitIndex = i; return true; } } } return false; }
/// <summary> /// This implementation of intersect uses the fastest ray-sphere intersection algorithm I could find /// on the internet. /// </summary> /// <param name="ray"></param> /// <returns></returns> public override IntersectInfo GetClosestIntersection(Ray ray) { double radiusSquared = radius * radius; Vector3 deltaFromShpereCenterToRayOrigin = ray.origin - this.position; double distanceFromSphereCenterToRayOrigin = Vector3.Dot(deltaFromShpereCenterToRayOrigin, ray.directionNormal); // negative means the sphere is in front of the ray. double lengthFromRayOrginToSphereCenterSquared = Vector3.Dot(deltaFromShpereCenterToRayOrigin, deltaFromShpereCenterToRayOrigin); double lengthFromRayOrigintoNearEdgeOfSphereSquared = lengthFromRayOrginToSphereCenterSquared - radiusSquared; double distanceFromSphereCenterToRaySquared = distanceFromSphereCenterToRayOrigin * distanceFromSphereCenterToRayOrigin; double amountSphereCenterToRayIsGreaterThanRayOriginToEdgeSquared = distanceFromSphereCenterToRaySquared - lengthFromRayOrigintoNearEdgeOfSphereSquared; if (amountSphereCenterToRayIsGreaterThanRayOriginToEdgeSquared > 0 || (ray.intersectionType == IntersectionType.BackFace && lengthFromRayOrginToSphereCenterSquared < radiusSquared)) // yes, that's it, we found the intersection! { IntersectInfo info = new IntersectInfo(); info.closestHitObject = this; info.hitType = IntersectionType.FrontFace; if (ray.isShadowRay) { return info; } double distanceFromRayOriginToSphereCenter = -distanceFromSphereCenterToRayOrigin; double amountSphereCenterToRayIsGreaterThanRayOriginToEdge = Math.Sqrt(amountSphereCenterToRayIsGreaterThanRayOriginToEdgeSquared); if (ray.intersectionType == IntersectionType.FrontFace) { double distanceToFrontHit = distanceFromRayOriginToSphereCenter - amountSphereCenterToRayIsGreaterThanRayOriginToEdge; if (distanceToFrontHit > ray.maxDistanceToConsider || distanceToFrontHit < ray.minDistanceToConsider) { return null; } info.distanceToHit = distanceToFrontHit; info.hitPosition = ray.origin + ray.directionNormal * info.distanceToHit; info.normalAtHit = (info.hitPosition - position).GetNormal(); } else // check back faces { double distanceToBackHit = distanceFromRayOriginToSphereCenter + amountSphereCenterToRayIsGreaterThanRayOriginToEdge; if (distanceToBackHit > ray.maxDistanceToConsider || distanceToBackHit < ray.minDistanceToConsider) { return null; } info.hitType = IntersectionType.BackFace; info.distanceToHit = distanceToBackHit; info.hitPosition = ray.origin + ray.directionNormal * info.distanceToHit; info.normalAtHit = -(info.hitPosition - position).GetNormal(); } return info; } return null; }
public Ray GetRay(double screenX, double screenY) { Vector3 origin = Origin; Vector3 direction = GetDirectionMinus1To1(screenX, screenY); direction = Vector3.TransformVector(direction, axisToWorld); Ray ray = new Ray(origin, direction); return ray; }
public IntersectInfo GetClosestIntersection(Ray ray) { if (ray.Intersection(Aabb)) { IPrimitive checkFirst = nodeA; IPrimitive checkSecond = nodeB; if (ray.directionNormal[splitingPlane] < 0) { checkFirst = nodeB; checkSecond = nodeA; } IntersectInfo infoFirst = checkFirst.GetClosestIntersection(ray); if (infoFirst != null && infoFirst.hitType != IntersectionType.None) { if (ray.isShadowRay) { return infoFirst; } else { ray.maxDistanceToConsider = infoFirst.distanceToHit; } } if (checkSecond != null) { IntersectInfo infoSecond = checkSecond.GetClosestIntersection(ray); if (infoSecond != null && infoSecond.hitType != IntersectionType.None) { if (ray.isShadowRay) { return infoSecond; } else { ray.maxDistanceToConsider = infoSecond.distanceToHit; } } if (infoFirst != null && infoFirst.hitType != IntersectionType.None && infoFirst.distanceToHit >= 0) { if (infoSecond != null && infoSecond.hitType != IntersectionType.None && infoSecond.distanceToHit < infoFirst.distanceToHit && infoSecond.distanceToHit >= 0) { return infoSecond; } else { return infoFirst; } } return infoSecond; // we don't have to test it because it didn't hit. } return infoFirst; } return null; }
public IEnumerable IntersectionIterator(Ray ray) { Ray localRay = GetLocalSpaceRay(ray); foreach (IntersectInfo localInfo in child.IntersectionIterator(localRay)) { IntersectInfo globalIntersection = GetGlobalSpaceInfo(localInfo); yield return globalIntersection; } }
public double GetDistanceToIntersection(Ray ray, out bool inFront) { inFront = false; double normalDotRayDirection = Vector3.Dot(planeNormal, ray.direction); if (normalDotRayDirection < TreatAsZero && normalDotRayDirection > -TreatAsZero) // the ray is parallel to the plane { return double.PositiveInfinity; } if (normalDotRayDirection < 0) { inFront = true; } return (distanceToPlaneFromOrigin - Vector3.Dot(planeNormal, ray.origin)) / normalDotRayDirection; }
public override IEnumerable IntersectionIterator(Ray ray) { throw new NotImplementedException(); }