static void assert_same_hit(AxisAlignedBox3d aabox, Box3d obox, Ray3d ray, bool bIsAlwaysHit) { IntrRay3Box3 ohit = new IntrRay3Box3(ray, obox); ohit.Find(); if (bIsAlwaysHit) { Debug.Assert(ohit.Find() == true); } IntrRay3AxisAlignedBox3 aabbhit = new IntrRay3AxisAlignedBox3(ray, aabox); aabbhit.Find(); if (bIsAlwaysHit) { Debug.Assert(aabbhit.Find() == true); } Debug.Assert(ohit.Find() == aabbhit.Find()); Debug.Assert(ohit.Test() == ohit.Find()); Debug.Assert(aabbhit.Test() == aabbhit.Find()); if (ohit.Find()) { Debug.Assert(MathUtil.EpsilonEqual(ohit.RayParam0, aabbhit.RayParam0, MathUtil.ZeroTolerance)); } }
override public bool FindRayIntersection(Ray3f worldRay, out SORayHit hit) { hit = null; // project world ray into local coords FScene scene = GetScene(); Ray3f sceneRay = scene.ToSceneRay(worldRay); Ray3f localRay = SceneTransforms.SceneToObject(this, sceneRay); // also need width in local coords float sceneWidth = scene.ToSceneDimension(visibleWidth); float localWidth = SceneTransforms.SceneToObject(this, sceneWidth) * HitWidthMultiplier; // bounding-box hit test (would be nice to do w/o object allocation...) AxisAlignedBox3d hitBox = localBounds; hitBox.Expand(localWidth); IntrRay3AxisAlignedBox3 box_test = new IntrRay3AxisAlignedBox3(localRay, hitBox); if (box_test.Find() == false) { return(false); } // raycast against curve (todo: spatial data structure for this? like 2D polycurve bbox tree?) double rayHitT; if (CurveUtils.FindClosestRayIntersection(curve, localWidth, localRay, out rayHitT)) { hit = new SORayHit(); // transform local hit point back into world coords Vector3f rayPos = localRay.PointAt((float)rayHitT); Vector3f scenePos = SceneTransforms.ObjectToSceneP(this, rayPos); hit.hitPos = SceneTransforms.SceneToWorldP(scene, scenePos); hit.fHitDist = worldRay.Project(hit.hitPos); hit.hitNormal = Vector3f.Zero; hit.hitGO = root; hit.hitSO = this; return(true); } return(false); }
/// <summary> /// try to find intersection of ray with curves /// </summary> public int FindRayIntersection(Ray3d ray, double useRadius = -1) { double r = (useRadius > 0) ? useRadius : Radius; double nearest_t = double.MaxValue; int hit_i = -1; for (int i = 0; i < CurveSet.Length; ++i) { if (CurveSet[i].visible == false) { continue; } if (IntrRay3AxisAlignedBox3.Intersects(ref ray, ref CurveSet[i].bounds, r) == false) { continue; } int hitSeg; double ray_t; if (CurveSet[i].spatial.FindClosestRayIntersction(ray, r, out hitSeg, out ray_t)) { if (ray_t < nearest_t) { nearest_t = ray_t; hit_i = i; } } // brute-force version //double ray_t; //if ( CurveUtils.FindClosestRayIntersection(CurveSet[i].curve, r, ray, out ray_t )) { // if ( ray_t < nearest_t ) { // nearest_t = ray_t; // hit_i = i; // } //} } return(hit_i); }
// [RMS] this only tests some basic cases... public static void test_RayBoxIntersect() { Random rand = new Random(316136327); // check that box hit works for (int ii = 0; ii < 1000; ++ii) { // generate random triangle Triangle3d t = new Triangle3d(rand.PointInRange(10), rand.PointInRange(10), rand.PointInRange(10)); AxisAlignedBox3d bounds = new AxisAlignedBox3d(t.V0); bounds.Contain(t.V1); bounds.Contain(t.V2); Vector3d c = (t.V0 + t.V1 + t.V2) / 3.0; for (int jj = 0; jj < 1000; ++jj) { Vector3d d = rand.Direction(); Ray3d ray = new Ray3d(c - 100 * d, d); IntrRay3AxisAlignedBox3 bhit = new IntrRay3AxisAlignedBox3(ray, bounds); Debug.Assert(bhit.Find()); IntrRay3Triangle3 thit = new IntrRay3Triangle3(ray, t); Debug.Assert(thit.Find()); Debug.Assert(bhit.RayParam0 < thit.RayParameter); } } int N = 100; for (int ii = 0; ii < N; ++ii) { // generate random boxes Vector3d c = rand.PointInRange(10); Vector3d e = rand.PositivePoint(); AxisAlignedBox3d aabox = new AxisAlignedBox3d(c - e, c + e); Box3d obox = new Box3d(c, Vector3d.AxisX, Vector3d.AxisY, Vector3d.AxisZ, e); double r = aabox.DiagonalLength; // center-out tests for (int jj = 0; jj < N; ++jj) { Ray3d ray = new Ray3d(c, rand.Direction()); assert_same_hit(aabox, obox, ray, true); } // outside-in tests for (int jj = 0; jj < N; ++jj) { Vector3d p = c + 2 * r * rand.Direction(); Ray3d ray = new Ray3d(p, (c - p).Normalized); assert_same_hit(aabox, obox, ray, true); } } // random rays int hits = 0; int InnerN = 1000; for (int ii = 0; ii < N; ++ii) { // generate random boxe Vector3d c = rand.PointInRange(10); Vector3d e = rand.PositivePoint(); // every tenth box, set an axis to degenerate if (ii % 10 == 0) { e[rand.Next() % 3] = 0; } AxisAlignedBox3d aabox = new AxisAlignedBox3d(c - e, c + e); Box3d obox = new Box3d(c, Vector3d.AxisX, Vector3d.AxisY, Vector3d.AxisZ, e); double r = aabox.DiagonalLength; TrivialBox3Generator boxgen = new TrivialBox3Generator() { Box = obox }; boxgen.Generate(); DMesh3 mesh = new DMesh3(); boxgen.MakeMesh(mesh); for (int i = 0; i < InnerN; ++i) { Vector3d target = c + rand.PointInRange(r); Vector3d o = c + rand.PointInRange(10 * r); Ray3d ray = new Ray3d(o, (target - o).Normalized); assert_same_hit(aabox, obox, ray, false); int hitT = MeshQueries.FindHitTriangle_LinearSearch(mesh, ray); bool bMeshHit = (hitT != DMesh3.InvalidID); if (bMeshHit) { ++hits; } IntrRay3AxisAlignedBox3 aabbhit = new IntrRay3AxisAlignedBox3(ray, aabox); Debug.Assert(aabbhit.Find() == bMeshHit); Debug.Assert(aabbhit.Test() == bMeshHit); } } System.Console.WriteLine("hit {0} of {1} rays", hits, N * InnerN); }