private void CreateScene(bool useDXEngineHitTesting) { ObjectsPlaceholder.Children.Clear(); if (_dxEventManager3D != null) { _dxEventManager3D.ResetEventSources3D(); _dxEventManager3D = null; } if (_wpfEventManager != null) { _wpfEventManager.ResetEventSources3D(); _wpfEventManager = null; } if (_instancedMeshGeometryVisual3D != null) { _instancedMeshGeometryVisual3D.Dispose(); } _stopwatch = new Stopwatch(); _stopwatch.Start(); Mouse.OverrideCursor = Cursors.Wait; // Create InstancedGeometryVisual3D _instancedMeshGeometryVisual3D = new InstancedMeshGeometryVisual3D(_instanceMeshGeometry3D); _instancedMeshGeometryVisual3D.InstancesData = _instancedData; // Setup hit testing if (useDXEngineHitTesting) { // Use DXEventManager3D from Ab3d.DXEngine - it has optimized hit testing for instanced objects _dxEventManager3D = new Ab3d.DirectX.Utilities.DXEventManager3D(MainDXViewportView); var visualEventSource3D = new Ab3d.DirectX.Utilities.VisualEventSource3D(_instancedMeshGeometryVisual3D); visualEventSource3D.MouseEnter += delegate(object sender, DirectX.Common.EventManager3D.Mouse3DEventArgs e) { var dxRayInstancedHitTestResult = e.RayHitResult as DXRayInstancedHitTestResult; if (dxRayInstancedHitTestResult != null) { ProcessMouseEnter(dxRayInstancedHitTestResult.HitInstanceIndex); } }; visualEventSource3D.MouseMove += delegate(object sender, DirectX.Common.EventManager3D.Mouse3DEventArgs e) { var dxRayInstancedHitTestResult = e.RayHitResult as DXRayInstancedHitTestResult; if (dxRayInstancedHitTestResult != null) { ProcessMouseMove(dxRayInstancedHitTestResult.HitInstanceIndex); } }; visualEventSource3D.MouseLeave += delegate(object sender, DirectX.Common.EventManager3D.Mouse3DEventArgs e) { ProcessMouseLeave(); }; _dxEventManager3D.RegisterEventSource3D(visualEventSource3D); } else { // // IMPORTANT: // // To make WPF hit testing work (also used by EventManager3D), you need to set the IsWpfHitTestVisible to true. // This increases initialization time because WPF objects needs to be created for each instance, but this makes the WPF hit testing work. _instancedMeshGeometryVisual3D.IsWpfHitTestVisible = true; _wpfEventManager = new Ab3d.Utilities.EventManager3D(MainViewport); // Because Viewport3D is actually not shown, we need to specify different WPF's object for the source of mouse events - this could be MainDXViewportView or even better a parent Border _wpfEventManager.CustomEventsSourceElement = MainDXViewportView; var visualEventSource3D = new Ab3d.Utilities.VisualEventSource3D(_instancedMeshGeometryVisual3D); visualEventSource3D.MouseEnter += delegate(object sender, Mouse3DEventArgs e) { if (e.RayHitResult == null || e.RayHitResult.ModelHit == null) { return; // This should not happen, but it is safer to have this check anyway } // Get instance index of the hit object int hitInstanceIndex = GetHitInstanceIndex(e.RayHitResult); ProcessMouseEnter(hitInstanceIndex); }; visualEventSource3D.MouseMove += delegate(object sender, Mouse3DEventArgs e) { if (e.RayHitResult == null || e.RayHitResult.ModelHit == null) { return; // This should not happen, but it is safer to have this check anyway } // Get instance index of the hit object int hitInstanceIndex = GetHitInstanceIndex(e.RayHitResult); ProcessMouseMove(hitInstanceIndex); }; visualEventSource3D.MouseLeave += delegate(object sender, Mouse3DEventArgs e) { ProcessMouseLeave(); }; _wpfEventManager.RegisterEventSource3D(visualEventSource3D); } ObjectsPlaceholder.Children.Add(_instancedMeshGeometryVisual3D); Mouse.OverrideCursor = null; // If we would only change the InstancedData we would need to call Update method (but here this is not needed because we have set the data for the first time) //_instancedGeometryVisual3D.Update(); }
public DXEventManager3DSample() { InitializeComponent(); Box1Visual3D.SetName("Box1Visual3D"); BoxesGroupVisual3D.SetName("BoxesGroupVisual3D"); Box2Visual3D.SetName("Box2Visual3D"); Box3Visual3D.SetName("Box3Visual3D"); Box4Visual3D.SetName("Box4Visual3D"); Line1.SetName("Line1"); Line2.SetName("Line2"); Rectangle1.SetName("Rectangle1"); var meshGeometry3D = new Ab3d.Meshes.SphereMesh3D(centerPosition: new Point3D(0, 0, 0), radius: 5, segments: 20, generateTextureCoordinates: false).Geometry; // The following method prepare InstanceData array with data for each instance (WorldMatrix and Color) InstanceData[] instancedData = CreateInstancesData(new Point3D(0, 0, 0), new Size3D(200, 50, 50), modelScaleFactor: 1f, xCount: 10, yCount: 3, zCount: 3, useTransparency: false); // Create InstancedGeometryVisual3D with selected meshGeometry and InstancesData _instancedMeshGeometryVisual3D = new InstancedMeshGeometryVisual3D(meshGeometry3D); _instancedMeshGeometryVisual3D.InstancesData = instancedData; _instancedMeshGeometryVisual3D.SetName("InstancedMeshGeometryVisual3D"); _instancedMeshGeometryVisual3D.Transform = new TranslateTransform3D(0, 50, 0); MainViewport3D.Children.Add(_instancedMeshGeometryVisual3D); _selectedInstanceIndex = -1; var model3DGroup = new Model3DGroup(); model3DGroup.SetName("Model3DGroup"); var frozenModel3DGroup = new Model3DGroup(); frozenModel3DGroup.SetName("FrozenModel3DGroup"); var box1Material = new DiffuseMaterial(Brushes.LightPink); var box2Material = new DiffuseMaterial(Brushes.LightCyan); var boxModel3D = Ab3d.Models.Model3DFactory.CreateBox(new Point3D(-100, 2, 25), new Size3D(60, 4, 50), box2Material); frozenModel3DGroup.Children.Add(boxModel3D); var pyramidModel3D = Ab3d.Models.Model3DFactory.CreatePyramid(new Point3D(-100, 2, 20), new Size3D(20, 20, 20), box2Material); frozenModel3DGroup.Children.Add(pyramidModel3D); for (int i = 0; i < 5; i++) { var geometryModel3D = new GeometryModel3D(meshGeometry3D, box1Material); geometryModel3D.Transform = new TranslateTransform3D(-130 + i * 15, 5, 80); geometryModel3D.SetName("GroupedSphere_" + i.ToString()); model3DGroup.Children.Add(geometryModel3D); geometryModel3D = new GeometryModel3D(meshGeometry3D, box2Material); geometryModel3D.Transform = new TranslateTransform3D(-130 + i * 15, 10, 50); geometryModel3D.SetName("FrozenGroupedSphere_" + i.ToString()); frozenModel3DGroup.Children.Add(geometryModel3D); } frozenModel3DGroup.Freeze(); MainViewport3D.Children.Add(model3DGroup.CreateModelVisual3D()); MainViewport3D.Children.Add(frozenModel3DGroup.CreateModelVisual3D()); _dxEventManager3D = new DXEventManager3D(MainDXViewportView); RegisterEventSource(Box1Visual3D); RegisterEventSource(BoxesGroupVisual3D); RegisterEventSource(Line1); RegisterEventSource(Line2); RegisterEventSource(Rectangle1); RegisterEventSource(_instancedMeshGeometryVisual3D); RegisterEventSource(model3DGroup); RegisterEventSource(frozenModel3DGroup); // Prevent TransparentPlaneVisual3D to be used by hit-testing _dxEventManager3D.RegisterExcludedVisual3D(TransparentPlaneVisual3D); this.PreviewMouseMove += delegate(object sender, MouseEventArgs args) { var position = args.GetPosition(this); MousePositionTextBlock.Text = $"Mouse pos: {position.X:0} {position.Y:0}"; }; this.PreviewMouseDown += delegate(object sender, MouseButtonEventArgs e) { var position = e.GetPosition(this); if (position == _lastMouseDownPosition) { return; } System.Diagnostics.Debug.WriteLine("Mouse position: " + position.ToString()); _lastMouseDownPosition = position; }; // IMPORTANT: // It is very important to call Dispose method on DXSceneView after the control is not used any more (see help file for more info) this.Unloaded += (sender, args) => MainDXViewportView.Dispose(); }