public void Update(DXViewportView MainDXViewportView)
            {
                Color4 preC = Color4.White;

                for (int i = 0; i < colors.Count; i++)
                {
                    Color4 c = colors[i];
                    colors[i] = WColor.GetColor(i, preC);
                    preC      = colors[i];
                }

                if (material == null)
                {
                    return;
                }

                material.PositionColors = colors.ToArray();
                material.Update();

                var sceneNode = MainDXViewportView.GetSceneNodeForWpfObject(node.GetGeometryModel3D());

                if (sceneNode != null)
                {
                    sceneNode.NotifySceneNodeChange(SceneNode.SceneNodeDirtyFlags.MaterialChanged);
                }
            }
        // This method can be used to change the depth bias value after the Visual3D (line visual or WireframeVisual3D) has already been rendered by DXEngine (or at least the DXEngine has already initialized the 3D SceneNodes).
        // To set initial line depth bias value, it is much easier to use the the following (see also the CreateScene method above):
        // _multiLineVisual3D.SetDXAttribute(DXAttributeType.LineDepthBias, depthBias);
        public static void SetDepthBias(DXViewportView parentDXViewportView, BaseVisual3D lineVisual3D, double depthBiasValue)
        {
            var lineSceneNode = parentDXViewportView.GetSceneNodeForWpfObject(lineVisual3D);

            if (lineSceneNode == null)
            {
                return;
            }


            // First check if we got WpfWireframeVisual3DNode that is created from WireframeVisual3D
            // This is handled differently then LineVisual3D objects because WpfWireframeVisual3DNode defines the DepthBias property
            var wpfWireframeVisual3DNode = lineSceneNode as WpfWireframeVisual3DNode;

            if (wpfWireframeVisual3DNode != null)
            {
                wpfWireframeVisual3DNode.DepthBias = (float)depthBiasValue;
                return;
            }


            // Handle other 3D lines Visual3D objects:

            // To change the DepthBias we need to get to the used LineMaterial
            // LineMaterial is used on the ScreenSpaceLineNode (in the DXEngine's scene nodes hierarchy).
            // Currently the MultiLineVisual3D is converted into WpfModelVisual3DNode with one ScreenSpaceLineNode set as child.
            // But this might be optimized in the future so that WpfModelVisual3DNode would be converted directly into ScreenSpaceLineNode.
            // Thefore here we check both options:

            var screenSpaceLineNode = lineSceneNode as ScreenSpaceLineNode;

            if (screenSpaceLineNode == null && lineSceneNode.ChildNodesCount == 1)
            {
                screenSpaceLineNode = lineSceneNode.ChildNodes[0] as ScreenSpaceLineNode;
            }


            if (screenSpaceLineNode != null)
            {
                // Get line material
                // The LineMaterial is of type ILineMaterial that does not provide setters for properties
                // Therefore we need to cast that into the actual LineMaterial object
                var lineMaterial = screenSpaceLineNode.LineMaterial as LineMaterial;

                if (lineMaterial != null)
                {
                    lineMaterial.DepthBias = (float)depthBiasValue; // Finally we can set DepthBias

                    // When we change properties on the DXEngine objects, we need to manually notify the DXEngine about the changes
                    // We do that with NotifySceneNodeChange method
                    screenSpaceLineNode.NotifySceneNodeChange(SceneNode.SceneNodeDirtyFlags.MaterialChanged);
                }
            }
        }
        protected override void CheckMouseOverElement(Point viewboxMousePosition, List <BaseEventSource3D> eventSources, List <Visual3D> excludedVisuals, bool checkOnlyDragSurfaces)
        {
            EnsureRayMeshGeometry3DHitTestResultConstructor();

            if (IsUsingWpfHitTesting)
            {
                base.CheckMouseOverElement(viewboxMousePosition, eventSources, excludedVisuals, checkOnlyDragSurfaces);
                return;
            }

            if (_dxViewportView.DXScene == null) // We need to wait until DXScene is initialized
            {
                return;
            }


            var pickRay = _dxViewportView.DXScene.GetRayFromCamera((int)viewboxMousePosition.X, (int)viewboxMousePosition.Y);


            DXRayHitTestResult dxRayHitTestResult = null;

            lastHitEventSource3D = null;
            lastRayHitResult     = null;


            if (!checkOnlyDragSurfaces)
            {
                if (excludedVisuals != null)
                {
                    // Use filter to exclude Visual3D objects from excludedVisuals
                    _dxViewportView.DXScene.DXHitTestOptions.HitTestFilterCallback = delegate(SceneNode node)
                    {
                        var wpfModelVisual3DNode = node as WpfModelVisual3DNode;

                        if (wpfModelVisual3DNode != null)
                        {
                            for (var i = 0; i < excludedVisuals.Count; i++)
                            {
                                if (ReferenceEquals(wpfModelVisual3DNode.ModelVisual3D, excludedVisuals[i]))
                                {
                                    return(DXHitTestOptions.HitTestFilterResult.ContinueSkipSelfAndChildren);
                                }
                            }
                        }

                        return(DXHitTestOptions.HitTestFilterResult.Continue);
                    };
                }
                else
                {
                    _dxViewportView.DXScene.DXHitTestOptions.HitTestFilterCallback = null;
                }

                dxRayHitTestResult = _dxViewportView.DXScene.GetClosestHitObject(pickRay);


                if (dxRayHitTestResult != null)
                {
                    lastRayHitResult = CreateRayMeshGeometry3DHitTestResult(dxRayHitTestResult);

                    var visualHit = lastRayHitResult.VisualHit;

                    // First check if any TargetVisual3D was hit
                    if (visualHit != null)
                    {
                        for (int i = 0; i < eventSources.Count; i++)
                        {
                            BaseEventSource3D oneEventSource3D = eventSources[i];
                            if (oneEventSource3D.IsMyVisual(visualHit))
                            {
                                // Hit oneEventSource3D
                                lastHitEventSource3D = oneEventSource3D; // Get the hit object
                                break;
                            }
                        }
                    }

                    if (lastHitEventSource3D == null)
                    {
                        var modelHit = lastRayHitResult.ModelHit as GeometryModel3D;

                        if (modelHit != null)
                        {
                            int eventSourcesCount = eventSources.Count;
                            for (int i = 0; i < eventSourcesCount; i++) // use for instead of foreach to prevent creating new object in foreach
                            {
                                BaseEventSource3D oneEventSource3D = eventSources[i];

                                // First find the hit object (_lastHitObject)
                                if (lastHitEventSource3D == null)
                                {
                                    if (oneEventSource3D.IsMyGeometryModel3D(modelHit))
                                    {
                                        lastHitEventSource3D = oneEventSource3D;
                                    }
                                }
                            }
                        }
                    }
                }
            }


            if (lastHitEventSource3D == null && (dxRayHitTestResult != null || checkOnlyDragSurfaces))
            {
                // When there is is an object hit, but it is not one that is subscribed,
                // and there is an eventSources that is defined as a DragSource, we need to check each DragSurface if it is hit and found the closest

                // First collect all SceneNodes that need to be checked (SceneNodes that are created from DragSurfaces)
                if (_sceneNodesToCheck == null)
                {
                    _sceneNodesToCheck = new List <SceneNode>(); // Reuse array so we do not create it on each hit test check
                }
                BaseEventSource3D  closestEventSource3D = null;
                DXRayHitTestResult closestRayHit        = null;
                float closestDistanceToRayOrigin        = float.MaxValue;


                for (var i = 0; i < eventSources.Count; i++)
                {
                    var eventSource = eventSources[i];

                    if (!eventSource.IsDragSurface)
                    {
                        continue;
                    }

                    var multiVisualEventSource3D = eventSource as MultiVisualEventSource3D;
                    if (multiVisualEventSource3D != null)
                    {
                        for (var i1 = 0; i1 < multiVisualEventSource3D.TargetVisuals3D.Count; i1++)
                        {
                            var sceneNode = _dxViewportView.GetSceneNodeForWpfObject(multiVisualEventSource3D.TargetVisuals3D[i1]);
                            if (sceneNode != null)
                            {
                                _sceneNodesToCheck.Add(sceneNode);
                            }
                        }
                    }
                    else
                    {
                        var visualEventSource3D = eventSource as VisualEventSource3D;
                        if (visualEventSource3D != null)
                        {
                            var sceneNode = _dxViewportView.GetSceneNodeForWpfObject(visualEventSource3D.TargetVisual3D);
                            if (sceneNode != null)
                            {
                                _sceneNodesToCheck.Add(sceneNode);
                            }
                        }
                    }


                    // Now check if SceneNodes intersect with the pickRay
                    for (var i1 = 0; i1 < _sceneNodesToCheck.Count; i1++)
                    {
                        var sceneNode = _sceneNodesToCheck[i1];

                        // We cannot test WpfModelVisual3DNode because it does not implement IRayHitTestedNode.
                        // Therefore we need to test its child WpfGeometryModel3DNode instead
                        var wpfModelVisual3DNode = sceneNode as WpfModelVisual3DNode;
                        if (wpfModelVisual3DNode != null && wpfModelVisual3DNode.ChildNodesCount == 1)
                        {
                            sceneNode = wpfModelVisual3DNode.ChildNodes[0];
                        }

                        var oneHitResult = _dxViewportView.DXScene.HitTestSceneNode(pickRay, sceneNode);

                        if (oneHitResult != null && oneHitResult.DistanceToRayOrigin < closestDistanceToRayOrigin)
                        {
                            // When we tested the ModelVisual3D,
                            // we need to revert ModelVisual3D.Transform on HitPosition,
                            // because it is applied again in the MouseDrag3DEventArgs constructor
                            if (wpfModelVisual3DNode != null && wpfModelVisual3DNode.Transform != null)
                            {
                                var matrix = wpfModelVisual3DNode.Transform.Value;
                                matrix.Invert();

                                var transformation = new Transformation(matrix);
                                transformation.Transform(ref oneHitResult.HitPosition, out oneHitResult.HitPosition);
                            }

                            closestEventSource3D = eventSource;
                            closestRayHit        = oneHitResult;

                            closestDistanceToRayOrigin = oneHitResult.DistanceToRayOrigin;
                        }
                    }

                    _sceneNodesToCheck.Clear();
                }

                if (closestEventSource3D != null)
                {
                    lastHitEventSource3D = closestEventSource3D;
                    lastRayHitResult     = CreateRayMeshGeometry3DHitTestResult(closestRayHit);
                }
            }
        }