Example #1
0
        // alternative way, 3.36 times slower
        protected bool MyHitTest(Ray rayWS, ref List <HitTestResult> hits)
        {
            LineGeometry3D lineGeometry3D;
            Viewport3DX    viewport;

            if (this.Visibility == Visibility.Collapsed ||
                this.IsHitTestVisible == false ||
                (viewport = FindVisualAncestor <Viewport3DX>(this.renderHost as DependencyObject)) == null ||
                (lineGeometry3D = this.Geometry as LineGeometry3D) == null)
            {
                return(false);
            }

            var result = new HitTestResult {
                IsValid = false, Distance = double.MaxValue
            };
            var lastDist = double.MaxValue;
            var index    = 0;

            foreach (var line in lineGeometry3D.Lines)
            {
                var     t0 = Vector3.TransformCoordinate(line.P0, this.ModelMatrix);
                var     t1 = Vector3.TransformCoordinate(line.P1, this.ModelMatrix);
                Vector3 sp, tp;
                float   sc, tc;
                var     distance = LineBuilder.GetRayToLineDistance(rayWS, t0, t1, out sp, out tp, out sc, out tc);
                var     svpm     = viewport.GetScreenViewProjectionMatrix();
                Vector4 sp4;
                Vector4 tp4;
                Vector3.Transform(ref sp, ref svpm, out sp4);
                Vector3.Transform(ref tp, ref svpm, out tp4);
                var sp3  = sp4.ToVector3();
                var tp3  = tp4.ToVector3();
                var tv2  = new Vector2(tp3.X - sp3.X, tp3.Y - sp3.Y);
                var dist = tv2.Length();
                if (dist < lastDist && dist <= this.HitTestThickness)
                {
                    lastDist           = dist;
                    result.PointHit    = sp.ToPoint3D();
                    result.NormalAtHit = (sp - tp).ToVector3D(); // not normalized to get length
                    result.Distance    = distance;
                    result.ModelHit    = this;
                    result.IsValid     = true;
                    result.Tag         = index; // ToDo: LineHitTag with additional info
                }

                index++;
            }

            if (result.IsValid)
            {
                hits.Add(result);
            }

            return(result.IsValid);
        }
        // alternative way, 3.36 times slower
        protected bool MyHitTest(Ray rayWS, ref List<HitTestResult> hits)
        {
            LineGeometry3D lineGeometry3D;
            Viewport3DX viewport;

            if (this.Visibility == Visibility.Collapsed ||
                this.IsHitTestVisible == false ||
                (viewport = FindVisualAncestor<Viewport3DX>(this.renderHost as DependencyObject)) == null ||
                (lineGeometry3D = this.Geometry as LineGeometry3D) == null)
            {
                return false;
            }

            var result = new HitTestResult { IsValid = false, Distance = double.MaxValue };
            var lastDist = double.MaxValue;
            var index = 0;
            foreach (var line in lineGeometry3D.Lines)
            {
                var t0 = Vector3.TransformCoordinate(line.P0, this.ModelMatrix);
                var t1 = Vector3.TransformCoordinate(line.P1, this.ModelMatrix);
                Vector3 sp, tp;
                float sc, tc;
                var distance = LineBuilder.GetRayToLineDistance(rayWS, t0, t1, out sp, out tp, out sc, out tc);
                var svpm = viewport.GetScreenViewProjectionMatrix();
                Vector4 sp4;
                Vector4 tp4;
                Vector3.Transform(ref sp, ref svpm, out sp4);
                Vector3.Transform(ref tp, ref svpm, out tp4);
                var sp3 = sp4.ToVector3();
                var tp3 = tp4.ToVector3();
                var tv2 = new Vector2(tp3.X - sp3.X, tp3.Y - sp3.Y);
                var dist = tv2.Length();
                if (dist < lastDist && dist <= this.HitTestThickness)
                {
                    lastDist = dist;
                    result.PointHit = sp.ToPoint3D();
                    result.NormalAtHit = (sp - tp).ToVector3D(); // not normalized to get length
                    result.Distance = distance;
                    result.ModelHit = this;
                    result.IsValid = true;
                    result.Tag = index; // ToDo: LineHitTag with additional info
                }

                index++;
            }

            if (result.IsValid)
            {
                hits.Add(result);
            }

            return result.IsValid;
        }
        public override bool HitTest(Ray rayWS, ref List <HitTestResult> hits)
        {
            LineGeometry3D lineGeometry3D;
            Viewport3DX    viewport;

            if (this.Visibility == Visibility.Collapsed ||
                this.IsHitTestVisible == false ||
                (viewport = FindVisualAncestor <Viewport3DX>(this.renderHost as DependencyObject)) == null ||
                (lineGeometry3D = this.Geometry as LineGeometry3D) == null)
            {
                return(false);
            }

            // revert unprojection; probably better: overloaded HitTest() for LineGeometryModel3D?
            var svpm        = viewport.GetScreenViewProjectionMatrix();
            var smvpm       = this.modelMatrix * svpm;
            var clickPoint4 = new Vector4(rayWS.Position + rayWS.Direction, 1);

            Vector4.Transform(ref clickPoint4, ref svpm, out clickPoint4);
            var clickPoint = clickPoint4.ToVector3();

            var result = new HitTestResult {
                IsValid = false, Distance = double.MaxValue
            };
            var maxDist  = this.HitTestThickness;
            var lastDist = double.MaxValue;
            var index    = 0;

            foreach (var line in lineGeometry3D.Lines)
            {
                var     p0 = Vector3.TransformCoordinate(line.P0, smvpm);
                var     p1 = Vector3.TransformCoordinate(line.P1, smvpm);
                Vector3 hitPoint;
                float   t;

                var dist = LineBuilder.GetPointToLineDistance2D(ref clickPoint, ref p0, ref p1, out hitPoint, out t);
                if (dist < lastDist && dist <= maxDist)
                {
                    lastDist = dist;
                    Vector4 res;
                    var     lp0 = line.P0;
                    Vector3.Transform(ref lp0, ref this.modelMatrix, out res);
                    lp0 = res.ToVector3();

                    var lp1 = line.P1;
                    Vector3.Transform(ref lp1, ref this.modelMatrix, out res);
                    lp1 = res.ToVector3();

                    var lv         = lp1 - lp0;
                    var hitPointWS = lp0 + lv * t;
                    result.Distance = (rayWS.Position - hitPointWS).Length();
                    result.PointHit = hitPointWS.ToPoint3D();
                    result.ModelHit = this;
                    result.IsValid  = true;
                    result.Tag      = index; // ToDo: LineHitTag with additional info
                }

                index++;
            }

            if (result.IsValid)
            {
                hits.Add(result);
            }

            return(result.IsValid);
        }
Example #4
0
 public MouseMove3DEventArgs(object source, HitTestResult hitTestResult, Point position, Viewport3DX viewport = null)
     : base(GeometryModel3D.MouseMove3DEvent, source, hitTestResult, position, viewport)
 {
 }
Example #5
0
        /// <summary>
        /// Initial implementation of hittest for billboard. Needs further improvement.
        /// </summary>
        /// <param name="rayWS"></param>
        /// <param name="hits"></param>
        /// <returns></returns>
        public override bool HitTest(Ray rayWS, ref List <HitTestResult> hits)
        {
            if (this.Visibility == Visibility.Collapsed || this.Visibility == Visibility.Hidden)
            {
                return(false);
            }
            if (this.IsHitTestVisible == false)
            {
                return(false);
            }

            var g      = this.Geometry as IBillboardText;
            var h      = false;
            var result = new HitTestResult();

            result.Distance = double.MaxValue;
            Viewport3DX viewport;

            if ((viewport = FindVisualAncestor <Viewport3DX>(this.renderHost as DependencyObject)) == null || g.Width == 0 || g.Height == 0)
            {
                return(false);
            }

            if (g != null)
            {
                var   visualToScreen = viewport.GetViewProjectionMatrix() * viewport.GetViewportMatrix();
                float heightScale    = 1;
                var   screenToVisual = visualToScreen.Inverted();

                var center      = new Vector4(g.Positions[0], 1);
                var screenPoint = Vector4.Transform(center, visualToScreen);
                var spw         = screenPoint.W;
                var spx         = screenPoint.X;
                var spy         = screenPoint.Y;
                var spz         = screenPoint.Z;
                var left        = -g.Width / 2;
                var right       = g.Width / 2;
                var top         = -g.Height / 2 * heightScale;
                var bottom      = g.Height / 2 * heightScale;
                Debug.WriteLine(spw);
                Debug.WriteLine(string.Format("Z={0}; W={1}", spz, spw));
                var bl = new Vector4(spx + left * spw, spy + bottom * spw, spz, spw);
                bl  = Vector4.Transform(bl, screenToVisual);
                bl /= bl.W;

                var br = new Vector4(spx + right * spw, spy + bottom * spw, spz, spw);
                br  = Vector4.Transform(br, screenToVisual);
                br /= br.W;

                var tr = new Vector4(spx + right * spw, spy + top * spw, spz, spw);
                tr  = Vector4.Transform(tr, screenToVisual);
                tr /= tr.W;

                var tl = new Vector4(spx + left * spw, spy + top * spw, spz, spw);
                tl  = Vector4.Transform(tl, screenToVisual);
                tl /= tl.W;

                var b = BoundingBox.FromPoints(new Vector3[] { tl.ToVector3(), tr.ToVector3(), bl.ToVector3(), br.ToVector3() });

                // this all happens now in world space now:
                Debug.WriteLine(string.Format("RayPosition:{0}; Direction:{1};", rayWS.Position, rayWS.Direction));
                if (rayWS.Intersects(ref b))
                {
                    float distance;
                    if (Collision.RayIntersectsBox(ref rayWS, ref b, out distance))
                    {
                        h = true;
                        result.ModelHit = this;
                        result.IsValid  = true;
                        result.PointHit = (rayWS.Position + (rayWS.Direction * distance)).ToPoint3D();
                        result.Distance = distance;
                        Debug.WriteLine(string.Format("Hit; HitPoint:{0}; Bound={1}; Distance={2}", result.PointHit, b, distance));
                    }
                }
            }
            if (h)
            {
                hits.Add(result);
            }
            return(h);
        }
 public MouseMove3DEventArgs(object source, HitTestResult hitTestResult, Point position, Viewport3DX viewport = null)
     : base(GeometryModel3D.MouseMove3DEvent, source, hitTestResult, position, viewport)
 { }
 public Mouse3DEventArgs(RoutedEvent routedEvent, object source, HitTestResult hitTestResult, Point position, Viewport3DX viewport = null)
     : base(routedEvent, source)
 {
     this.HitTestResult = hitTestResult;
     this.Position = position;
     this.Viewport = viewport;
 }
        private void SetSelectedElement(Helix.HitTestResult hit)
        {
            var model = hit?.ModelHit as Helix.Element3D;

            SetSelectedElement(model);
        }
Example #9
0
 public MouseMove3DEventArgs(object source, HitTestResult hitTestResult, Point position, Viewport3DX viewport = null, InputEventArgs originalInputEventArgs = null)
     : base(Element3D.MouseMove3DEvent, source, hitTestResult, position, viewport, originalInputEventArgs)
 {
 }
        /// <summary>
        /// Checks if the ray hits the geometry of the model.
        /// If there a more than one hit, result returns the hit which is nearest to the ray origin.
        /// </summary>
        /// <param name="rayWS">Hitring ray from the camera.</param>
        /// <param name="result">results of the hit.</param>
        /// <returns>True if the ray hits one or more times.</returns>
        public override bool HitTest(Ray rayWS, ref List<HitTestResult> hits)
        {
            PointGeometry3D pointGeometry3D;
            Viewport3DX viewport;

            if (this.Visibility == Visibility.Collapsed ||
                this.IsHitTestVisible == false ||
                (viewport = FindVisualAncestor<Viewport3DX>(this.renderHost as DependencyObject)) == null ||
                (pointGeometry3D = this.Geometry as PointGeometry3D) == null)
            {
                return false;
            }

            var svpm = viewport.GetScreenViewProjectionMatrix();
            var smvpm = this.modelMatrix * svpm;

            var clickPoint4 = new Vector4(rayWS.Position + rayWS.Direction, 1);
            var pos4 = new Vector4(rayWS.Position, 1);
            var dir3 = new Vector3();
            Vector4.Transform(ref clickPoint4, ref svpm, out clickPoint4);
            Vector4.Transform(ref pos4, ref svpm, out pos4);
            Vector3.TransformNormal(ref rayWS.Direction, ref svpm, out dir3);
            dir3.Normalize();

            var clickPoint = clickPoint4.ToVector3();

            var result = new HitTestResult { IsValid = false, Distance = double.MaxValue };
            var maxDist = this.HitTestThickness;
            var lastDist = double.MaxValue;
            var index = 0;

            foreach (var point in pointGeometry3D.Points)
            {
                var p0 = Vector3.TransformCoordinate(point.P0, smvpm);
                var pv = p0 - clickPoint;
                var dist = pv.Length();
                if (dist < lastDist && dist <= maxDist)
                {
                    lastDist = dist;
                    Vector4 res;
                    var lp0 = point.P0;
                    Vector3.Transform(ref lp0, ref this.modelMatrix, out res);
                    var pvv = res.ToVector3();
                    var dst = DistanceRayToPoint(rayWS, pvv);
                    result.Distance = dst;
                    result.PointHit = pvv.ToPoint3D();
                    result.ModelHit = this;
                    result.IsValid = true;
                    result.Tag = index;
                }

                index++;
            }

            if (result.IsValid)
            {
                hits.Add(result);
            }

            return result.IsValid;
        }
Example #11
0
 public MouseUp3DEventArgs(object source, HitTestResult hitTestResult, Point position, Viewport3DX viewport = null)
     : base(Element3D.MouseUp3DEvent, source, hitTestResult, position, viewport)
 {
 }
Example #12
0
        /// <summary>
        /// Checks if the ray hits the geometry of the model.
        /// If there a more than one hit, result returns the hit which is nearest to the ray origin.
        /// </summary>
        /// <param name="rayWS">Hitring ray from the camera.</param>
        /// <param name="result">results of the hit.</param>
        /// <returns>True if the ray hits one or more times.</returns>
        public override bool HitTest(Ray rayWS, ref List <HitTestResult> hits)
        {
            PointGeometry3D pointGeometry3D;
            Viewport3DX     viewport;

            if (this.Visibility == Visibility.Collapsed ||
                this.IsHitTestVisible == false ||
                (viewport = FindVisualAncestor <Viewport3DX>(this.renderHost as DependencyObject)) == null ||
                (pointGeometry3D = this.Geometry as PointGeometry3D) == null)
            {
                return(false);
            }

            var svpm  = viewport.GetScreenViewProjectionMatrix();
            var smvpm = this.modelMatrix * svpm;

            var clickPoint4 = new Vector4(rayWS.Position + rayWS.Direction, 1);
            var pos4        = new Vector4(rayWS.Position, 1);
            var dir3        = new Vector3();

            Vector4.Transform(ref clickPoint4, ref svpm, out clickPoint4);
            Vector4.Transform(ref pos4, ref svpm, out pos4);
            Vector3.TransformNormal(ref rayWS.Direction, ref svpm, out dir3);
            dir3.Normalize();

            var clickPoint = clickPoint4.ToVector3();

            var result = new HitTestResult {
                IsValid = false, Distance = double.MaxValue
            };
            var maxDist  = this.HitTestThickness;
            var lastDist = double.MaxValue;
            var index    = 0;

            foreach (var point in pointGeometry3D.Points)
            {
                var p0   = Vector3.TransformCoordinate(point.P0, smvpm);
                var pv   = p0 - clickPoint;
                var dist = pv.Length();
                if (dist < lastDist && dist <= maxDist)
                {
                    lastDist = dist;
                    Vector4 res;
                    var     lp0 = point.P0;
                    Vector3.Transform(ref lp0, ref this.modelMatrix, out res);
                    var pvv = res.ToVector3();
                    var dst = DistanceRayToPoint(rayWS, pvv);
                    result.Distance = dst;
                    result.PointHit = pvv.ToPoint3D();
                    result.ModelHit = this;
                    result.IsValid  = true;
                    result.Tag      = index;
                }

                index++;
            }

            if (result.IsValid)
            {
                hits.Add(result);
            }

            return(result.IsValid);
        }
Example #13
0
        protected override bool OnHitTest(IRenderMatrices context, Ray rayWS, ref List <HitTestResult> hits)
        {
            var  g     = this.geometryInternal as MeshGeometry3D;
            bool isHit = false;

            if (g.Octree != null)
            {
                isHit = g.Octree.HitTest(context, this, ModelMatrix, rayWS, ref hits);
            }
            else
            {
                var result = new HitTestResult();
                result.Distance = double.MaxValue;
                if (g != null)
                {
                    var modelInvert = this.modelMatrix.Inverted();
                    //transform ray into model coordinates
                    var rayModel = new Ray(Vector3.TransformCoordinate(rayWS.Position, modelInvert), Vector3.TransformNormal(rayWS.Direction, modelInvert));

                    var b = Bounds;
                    //Do hit test in local space
                    if (rayModel.Intersects(ref b))
                    {
                        int index = 0;
                        foreach (var t in g.Triangles)
                        {
                            float d;
                            var   v0 = t.P0;
                            var   v1 = t.P1;
                            var   v2 = t.P2;
                            if (Collision.RayIntersectsTriangle(ref rayModel, ref v0, ref v1, ref v2, out d))
                            {
                                if (d > 0 && d < result.Distance) // If d is NaN, the condition is false.
                                {
                                    result.IsValid  = true;
                                    result.ModelHit = this;
                                    // transform hit-info to world space now:
                                    var pointWorld = Vector3.TransformCoordinate(rayModel.Position + (rayModel.Direction * d), modelMatrix);
                                    result.PointHit = pointWorld.ToPoint3D();
                                    result.Distance = (rayWS.Position - pointWorld).Length();
                                    var p0 = Vector3.TransformCoordinate(v0, modelMatrix);
                                    var p1 = Vector3.TransformCoordinate(v1, modelMatrix);
                                    var p2 = Vector3.TransformCoordinate(v2, modelMatrix);
                                    var n  = Vector3.Cross(p1 - p0, p2 - p0);
                                    n.Normalize();
                                    // transform hit-info to world space now:
                                    result.NormalAtHit     = n.ToVector3D();// Vector3.TransformNormal(n, m).ToVector3D();
                                    result.TriangleIndices = new System.Tuple <int, int, int>(g.Indices[index], g.Indices[index + 1], g.Indices[index + 2]);
                                    result.Tag             = index / 3;
                                    isHit = true;
                                }
                            }
                            index += 3;
                        }
                    }
                }
                if (isHit)
                {
                    hits.Add(result);
                }
            }
            return(isHit);
        }
        public override bool HitTest(Ray rayWS, ref List<HitTestResult> hits)
        {
            LineGeometry3D lineGeometry3D;
            Viewport3DX viewport;

            if (this.Visibility == Visibility.Collapsed ||
                this.IsHitTestVisible == false ||
                (viewport = FindVisualAncestor<Viewport3DX>(this.renderHost as DependencyObject)) == null ||
                (lineGeometry3D = this.Geometry as LineGeometry3D) == null)
            {
                return false;
            }

            // revert unprojection; probably better: overloaded HitTest() for LineGeometryModel3D?
            var svpm = viewport.GetScreenViewProjectionMatrix();
            var smvpm = this.modelMatrix * svpm;
            var clickPoint4 = new Vector4(rayWS.Position + rayWS.Direction, 1);
            Vector4.Transform(ref clickPoint4, ref svpm, out clickPoint4);
            var clickPoint = clickPoint4.ToVector3();

            var result = new HitTestResult { IsValid = false, Distance = double.MaxValue };
            var maxDist = this.HitTestThickness;
            var lastDist = double.MaxValue;
            var index = 0;

            foreach (var line in lineGeometry3D.Lines)
            {
                var p0 = Vector3.TransformCoordinate(line.P0, smvpm);
                var p1 = Vector3.TransformCoordinate(line.P1, smvpm);
                Vector3 hitPoint;
                float t;

                var dist = LineBuilder.GetPointToLineDistance2D(ref clickPoint, ref p0, ref p1, out hitPoint, out t);
                if (dist < lastDist && dist <= maxDist)
                {
                    lastDist = dist;
                    Vector4 res;
                    var lp0 = line.P0;
                    Vector3.Transform(ref lp0, ref this.modelMatrix, out res);
                    lp0 = res.ToVector3();

                    var lp1 = line.P1;
                    Vector3.Transform(ref lp1, ref this.modelMatrix, out res);
                    lp1 = res.ToVector3();

                    var lv = lp1 - lp0;
                    var hitPointWS = lp0 + lv * t;
                    result.Distance = (rayWS.Position - hitPointWS).Length();
                    result.PointHit = hitPointWS.ToPoint3D();
                    result.ModelHit = this;
                    result.IsValid = true;
                    result.Tag = index; // ToDo: LineHitTag with additional info
                }

                index++;
            }

            if (result.IsValid)
            {
                hits.Add(result);
            }

            return result.IsValid;
        }
        /// <summary>
        /// Checks if the ray hits the geometry of the model.
        /// If there a more than one hit, result returns the hit which is nearest to the ray origin.
        /// </summary>
        /// <param name="rayWS">Hitring ray from the camera.</param>
        /// <param name="result">results of the hit.</param>
        /// <returns>True if the ray hits one or more times.</returns>
        public virtual bool HitTest(Ray rayWS, ref List<HitTestResult> hits)
        {
            if (this.Visibility == Visibility.Collapsed)
            {
                return false;
            }
            if (this.IsHitTestVisible == false)
            {
                return false;
            }

            var g = this.Geometry as MeshGeometry3D;
            var isHit = false;
            var result = new HitTestResult();
            result.Distance = double.MaxValue;

            if (g != null)
            {
                var m = this.modelMatrix;

                // put bounds to world space
                var b = BoundingBox.FromPoints(this.Bounds.GetCorners().Select(x => Vector3.TransformCoordinate(x, m)).ToArray());

                //var b = this.Bounds;

                // this all happens now in world space now:
                if (rayWS.Intersects(ref b))
                {
                    int index = 0;
                    foreach (var t in g.Triangles)
                    {
                        float d;
                        var p0 = Vector3.TransformCoordinate(t.P0, m);
                        var p1 = Vector3.TransformCoordinate(t.P1, m);
                        var p2 = Vector3.TransformCoordinate(t.P2, m);
                        if (Collision.RayIntersectsTriangle(ref rayWS, ref p0, ref p1, ref p2, out d))
                        {
                            if (d > 0 && d < result.Distance) // If d is NaN, the condition is false.
                            {
                                result.IsValid = true;
                                result.ModelHit = this;
                                // transform hit-info to world space now:
                                result.PointHit = (rayWS.Position + (rayWS.Direction * d)).ToPoint3D();
                                result.Distance = d;

                                var n = Vector3.Cross(p1 - p0, p2 - p0);
                                n.Normalize();
                                // transform hit-info to world space now:
                                result.NormalAtHit = n.ToVector3D();// Vector3.TransformNormal(n, m).ToVector3D();
                                result.TriangleIndices = new System.Tuple<int, int, int>(g.Indices[index], g.Indices[index + 1], g.Indices[index + 2]);
                                isHit = true;
                            }
                        }
                        index += 3;
                    }
                }
            }
            if (isHit)
            {
                hits.Add(result);
            }
            return isHit;
        }
        /// <summary>
        /// Initial implementation of hittest for billboard. Needs further improvement.
        /// </summary>
        /// <param name="rayWS"></param>
        /// <param name="hits"></param>
        /// <returns></returns>
        protected override bool OnHitTest(IRenderMatrices context, Ray rayWS, ref List <HitTestResult> hits)
        {
            var g      = this.geometryInternal as IBillboardText;
            var h      = false;
            var result = new HitTestResult();

            result.Distance = double.MaxValue;

            if (context == null || g.Width == 0 || g.Height == 0)
            {
                return(false);
            }

            if (g != null)
            {
                BoundingBox b      = new BoundingBox();
                var         left   = -g.Width / 2;
                var         right  = -left;
                var         top    = -g.Height / 2;
                var         bottom = -top;
                if (FixedSize)
                {
                    var viewportMatrix   = context.ViewportMatrix;
                    var projectionMatrix = context.ProjectionMatrix;
                    var viewMatrix       = context.ViewMatrix;
                    var visualToScreen   = viewMatrix * projectionMatrix * viewportMatrix;

                    var center      = new Vector4(g.Positions[0], 1);
                    var screenPoint = Vector4.Transform(center, visualToScreen);
                    var spw         = screenPoint.W;
                    var spx         = screenPoint.X;
                    var spy         = screenPoint.Y;
                    var spz         = screenPoint.Z / spw / projectionMatrix.M33;

                    var     matrix = CameraExtensions.InverseViewMatrix(ref viewMatrix);
                    var     width  = (float)context.ActualWidth;
                    var     height = (float)context.ActualHeight;
                    Vector3 v      = new Vector3();

                    var x = spx + left * spw;
                    var y = spy + bottom * spw;
                    v.X = (2 * x / width / spw - 1) / projectionMatrix.M11;
                    v.Y = -(2 * y / height / spw - 1) / projectionMatrix.M22;
                    v.Z = spz;

                    Vector3 bl;
                    Vector3.TransformCoordinate(ref v, ref matrix, out bl);


                    x   = spx + right * spw;
                    y   = spy + bottom * spw;
                    v.X = (2 * x / width / spw - 1) / projectionMatrix.M11;
                    v.Y = -(2 * y / height / spw - 1) / projectionMatrix.M22;
                    v.Z = spz;

                    Vector3 br;
                    Vector3.TransformCoordinate(ref v, ref matrix, out br);

                    x   = spx + right * spw;
                    y   = spy + top * spw;
                    v.X = (2 * x / width / spw - 1) / projectionMatrix.M11;
                    v.Y = -(2 * y / height / spw - 1) / projectionMatrix.M22;
                    v.Z = spz;

                    Vector3 tr;
                    Vector3.TransformCoordinate(ref v, ref matrix, out tr);

                    x   = spx + left * spw;
                    y   = spy + top * spw;
                    v.X = (2 * x / width / spw - 1) / projectionMatrix.M11;
                    v.Y = -(2 * y / height / spw - 1) / projectionMatrix.M22;
                    v.Z = spz;

                    Vector3 tl;
                    Vector3.TransformCoordinate(ref v, ref matrix, out tl);

                    b = BoundingBox.FromPoints(new Vector3[] { tl, tr, bl, br });

                    /*
                     * var visualToScreen = viewport.GetViewProjectionMatrix() * viewport.GetViewportMatrix();
                     *
                     * var screenToVisual = visualToScreen.Inverted();
                     *
                     * var center = new Vector4(g.Positions[0], 1);
                     * var screenPoint = Vector4.Transform(center, visualToScreen);
                     * var spw = screenPoint.W;
                     * var spx = screenPoint.X;
                     * var spy = screenPoint.Y;
                     * var spz = screenPoint.Z;
                     *
                     * //Debug.WriteLine(spw);
                     * // Debug.WriteLine(string.Format("Z={0}; W={1}", spz, spw));
                     * var bl = new Vector4(spx + left * spw, spy + bottom * spw, spz, spw);
                     * bl = Vector4.Transform(bl, screenToVisual);
                     * bl /= bl.W;
                     *
                     * var br = new Vector4(spx + right * spw, spy + bottom * spw, spz, spw);
                     * br = Vector4.Transform(br, screenToVisual);
                     * br /= br.W;
                     *
                     * var tr = new Vector4(spx + right * spw, spy + top * spw, spz, spw);
                     * tr = Vector4.Transform(tr, screenToVisual);
                     * tr /= tr.W;
                     *
                     * var tl = new Vector4(spx + left * spw, spy + top * spw, spz, spw);
                     * tl = Vector4.Transform(tl, screenToVisual);
                     * tl /= tl.W;
                     *
                     * b = BoundingBox.FromPoints(new Vector3[] { tl.ToVector3(), tr.ToVector3(), bl.ToVector3(), br.ToVector3() });
                     */
                }
                else
                {
                    var center     = new Vector4(g.Positions[0], 1);
                    var viewMatrix = context.ViewMatrix;

                    var vcenter = Vector4.Transform(center, viewMatrix);
                    var vcX     = vcenter.X;
                    var vcY     = vcenter.Y;

                    var bl            = new Vector4(vcX + left, vcY + bottom, vcenter.Z, vcenter.W);
                    var br            = new Vector4(vcX + right, vcY + bottom, vcenter.Z, vcenter.W);
                    var tr            = new Vector4(vcX + right, vcY + top, vcenter.Z, vcenter.W);
                    var tl            = new Vector4(vcX + left, vcY + top, vcenter.Z, vcenter.W);
                    var invViewMatrix = CameraExtensions.InverseViewMatrix(ref viewMatrix);

                    bl  = Vector4.Transform(bl, invViewMatrix);
                    bl /= bl.W;
                    br  = Vector4.Transform(br, invViewMatrix);
                    br /= br.W;
                    tr  = Vector4.Transform(tr, invViewMatrix);
                    tr /= tr.W;
                    tl  = Vector4.Transform(tl, invViewMatrix);
                    tl /= tl.W;
                    b   = BoundingBox.FromPoints(new Vector3[] { tl.ToVector3(), tr.ToVector3(), bl.ToVector3(), br.ToVector3() });
                }

                // this all happens now in world space now:
                //Debug.WriteLine(string.Format("RayPosition:{0}; Direction:{1};", rayWS.Position, rayWS.Direction));
                if (rayWS.Intersects(ref b))
                {
                    float distance;
                    if (Collision.RayIntersectsBox(ref rayWS, ref b, out distance))
                    {
                        h = true;
                        result.ModelHit = this;
                        result.IsValid  = true;
                        result.PointHit = (rayWS.Position + (rayWS.Direction * distance)).ToPoint3D();
                        result.Distance = distance;
                        Debug.WriteLine(string.Format("Hit; HitPoint:{0}; Bound={1}; Distance={2}", result.PointHit, b, distance));
                    }
                }
            }
            if (h)
            {
                hits.Add(result);
            }
            return(h);
        }
Example #17
0
        /// <summary>
        /// Checks if the ray hits the geometry of the model.
        /// If there a more than one hit, result returns the hit which is nearest to the ray origin.
        /// </summary>
        /// <param name="rayWS">Hitring ray from the camera.</param>
        /// <param name="result">results of the hit.</param>
        /// <returns>True if the ray hits one or more times.</returns>
        public virtual bool HitTest(Ray rayWS, ref List <HitTestResult> hits)
        {
            if (this.Visibility == Visibility.Collapsed)
            {
                return(false);
            }
            if (this.IsHitTestVisible == false)
            {
                return(false);
            }

            var g      = this.Geometry as MeshGeometry3D;
            var isHit  = false;
            var result = new HitTestResult();

            result.Distance = double.MaxValue;

            if (g != null)
            {
                var m = this.modelMatrix;

                // put bounds to world space
                var b = BoundingBox.FromPoints(this.Bounds.GetCorners().Select(x => Vector3.TransformCoordinate(x, m)).ToArray());

                //var b = this.Bounds;

                // this all happens now in world space now:
                if (rayWS.Intersects(ref b))
                {
                    int index = 0;
                    foreach (var t in g.Triangles)
                    {
                        float d;
                        var   p0 = Vector3.TransformCoordinate(t.P0, m);
                        var   p1 = Vector3.TransformCoordinate(t.P1, m);
                        var   p2 = Vector3.TransformCoordinate(t.P2, m);
                        if (Collision.RayIntersectsTriangle(ref rayWS, ref p0, ref p1, ref p2, out d))
                        {
                            if (d > 0 && d < result.Distance) // If d is NaN, the condition is false.
                            {
                                result.IsValid  = true;
                                result.ModelHit = this;
                                // transform hit-info to world space now:
                                result.PointHit = (rayWS.Position + (rayWS.Direction * d)).ToPoint3D();
                                result.Distance = d;

                                var n = Vector3.Cross(p1 - p0, p2 - p0);
                                n.Normalize();
                                // transform hit-info to world space now:
                                result.NormalAtHit     = n.ToVector3D();// Vector3.TransformNormal(n, m).ToVector3D();
                                result.TriangleIndices = new System.Tuple <int, int, int>(g.Indices[index], g.Indices[index + 1], g.Indices[index + 2]);
                                isHit = true;
                            }
                        }
                        index += 3;
                    }
                }
            }
            if (isHit)
            {
                hits.Add(result);
            }
            return(isHit);
        }