private void LineTypesRadioButtonChanged(object sender, RoutedEventArgs e) { if (!this.IsLoaded) { return; } // First recreate all 3D objects to reset their attributes and settings CreateTest3DObjects(); MainDXViewportView.Update(); if (StandardLinesRadioButton.IsChecked ?? false) { // Nothing to do - just show standard lines } else if (OnlyHiddenLinesRadioButton.IsChecked ?? false) { ShowOnlyHiddenLines(); } else if (StandardAndHiddenLinesRadioButton.IsChecked ?? false) { ShowVisibleAndHiddenLines(); } else if (AlwaysVisibleLines1RadioButton.IsChecked ?? false) { ShowAlwaysVisibleLinesWithDXAttribute(); } else if (AlwaysVisibleLines2RadioButton.IsChecked ?? false) { ShowAlwaysVisibleLinesAdvanced(); } }
private void ShowVisibleAndHiddenLines() { // To show both visible and hidden lines we need to render each line twice: // once with standard settings to shew visible part of the one, // once with using HiddenLineMaterial to show the hidden part of the line. // Now we will clone the existing 3D lines var existingLineVisuals = TestObjectsModelVisual3D.Children.OfType <BaseLineVisual3D>().ToList(); var newLineVisuals = new List <BaseLineVisual3D>(); foreach (var lineVisual3D in existingLineVisuals) { var clonedLineVisual = CloneLineVisuals(lineVisual3D); TestObjectsModelVisual3D.Children.Add(clonedLineVisual); newLineVisuals.Add(clonedLineVisual); } // After adding new WPF objects to the scene, we need to manually call Update to create DXEngine's SceneNode objects that will be needed later MainDXViewportView.Update(); // We need to update the _sceneNodesDictionary because we have changed the scene CreateSceneNodesDictionary(); // Now change the materials of the clones lines to hiddenLineMaterial foreach (var newLineVisual3D in newLineVisuals) { ChangeLineMaterial(newLineVisual3D, _hiddenLineMaterial); } if (_wireframeGeometryModel3D != null) { // Clone the GeometryModel3D that shows teapot wireframe and use hiddenLineMaterial to render it var newWpfWireframeMaterial = new DiffuseMaterial(Brushes.Red); newWpfWireframeMaterial.SetUsedDXMaterial(_hiddenLineMaterial); var geometryModel3D = new GeometryModel3D(_wireframeGeometryModel3D.Geometry, newWpfWireframeMaterial); geometryModel3D.Transform = _wireframeGeometryModel3D.Transform; var modelVisual3D = new ModelVisual3D() { Content = geometryModel3D }; TestObjectsModelVisual3D.Children.Add(modelVisual3D); } }
private void GetClosestHitObject() { var dxScene = MainDXViewportView.DXScene; if (dxScene == null) // NO DXEngine rendering { return; } _hitLinesModelVisual3D.Children.Clear(); // After the 3D lines are cleared we need to call Update method to update SceneNodes before we call HitTest. // If this is not done manually, the SceneNodes would be updated before next rendering but after the HitTest and we could get hit the 3D line. MainDXViewportView.Update(); // DXHitTestOptions.MeshPositionsCountForOctTreeGeneration: // Gets or sets an integer value that specifies number of positions in a mesh (DXMeshGeometry3D) at which a OctTree is generated to speed up hit testing // (e.g. if mesh has more positions then a value specified with this property, then OctTree will be generated for the mesh). // Default value is 512. //dxScene.DXHitTestOptions.MeshPositionsCountForOctTreeGeneration = 1; //dxScene.DXHitTestOptions.GetOnlyFrontFacingTriangles = false; // Hit test center of the MainDXViewportView (we could also use mouse position) var positionInViewport3D = new Point(MainDXViewportView.ActualWidth / 2, MainDXViewportView.ActualHeight / 2); var pickRay = dxScene.GetRayFromCamera((int)positionInViewport3D.X, (int)positionInViewport3D.Y); // It is also possible to specify a hit test filter callback to skip testing some SceneNodes //dxScene.DXHitTestOptions.HitTestFilterCallback = delegate(SceneNode sceneNode) //{ // if (sceneNode == ...) // return DXHitTestOptions.HitTestFilterResult.ContinueSkipSelfAndChildren; // return DXHitTestOptions.HitTestFilterResult.Continue; //}; var dxRayHitTestResult = dxScene.GetClosestHitObject(pickRay); if (dxRayHitTestResult == null) { AddMessage("DXScene hit test result: no object hit"); } else { string message = string.Format("Ray.Start: {0:0.0}; Ray.Direction: {1:0.00}\r\nDXScene hit test result:\r\n PointHit: {2:0.0}; (distance: {3:0})\r\n SceneNode Id: {4}", pickRay.Position, pickRay.Direction, dxRayHitTestResult.HitPosition, dxRayHitTestResult.DistanceToRayOrigin, dxRayHitTestResult.HitSceneNode.Id); if (!string.IsNullOrEmpty(dxRayHitTestResult.HitSceneNode.Name)) { message += " ('" + dxRayHitTestResult.HitSceneNode.Name + "')"; } AddMessage(message); AddHitLineArrow(pickRay, dxRayHitTestResult, dxRayHitTestResult.HitPosition.ToWpfPoint3D()); } // NOTE: // If you want to manually do a hit testing on a mesh data with vertex and index buffer, // then you can use the Ab3d.DirectX.HitTester.HitTest method. // The method takes a Ray, various types of vertex buffers, index buffer and a few flags and returns a hit test result. }
private void GetAllHitTestObjects() { var dxScene = MainDXViewportView.DXScene; if (dxScene == null) // NO DXEngine rendering { return; } _hitLinesModelVisual3D.Children.Clear(); // After the 3D lines are cleared we need to call Update method to update SceneNodes before we call HitTest. // If this is not done manually, the SceneNodes would be updated before next rendering but after the HitTest and we could get hit the 3D line. MainDXViewportView.Update(); // DXHitTestOptions.MeshPositionsCountForOctTreeGeneration: // Gets or sets an integer value that specifies number of positions in a mesh (DXMeshGeometry3D) at which a OctTree is generated to speed up hit testing // (e.g. if mesh has more positions then a value specified with this property, then OctTree will be generated for the mesh). // Default value is 512. //dxScene.DXHitTestOptions.MeshPositionsCountForOctTreeGeneration = 1; // When GetOnlyFrontFacingTriangles is true, then only triangles that are facing the camera will be hit dxScene.DXHitTestOptions.GetOnlyFrontFacingTriangles = OnlyFrontTrianglesCheckBox.IsChecked ?? false; // By default multiple hit results can be returned per one SceneNode. // This can be changed by setting GetOnlyOneHitPerSceneNode to true. //dxScene.DXHitTestOptions.GetOnlyOneHitPerSceneNode = false; // It is also possible to specify a hit test filter callback to skip testing some SceneNodes //dxScene.DXHitTestOptions.HitTestFilterCallback = delegate(SceneNode sceneNode) //{ // if (sceneNode == ...) // return DXHitTestOptions.HitTestFilterResult.ContinueSkipSelfAndChildren; // return DXHitTestOptions.HitTestFilterResult.Continue; //}; // Hit test center of the MainDXViewportView (we could also use mouse position) var positionInViewport3D = new Point(MainDXViewportView.ActualWidth / 2, MainDXViewportView.ActualHeight / 2); var pickRay = dxScene.GetRayFromCamera((int)positionInViewport3D.X, (int)positionInViewport3D.Y); List <DXRayHitTestResult> allHitTests = dxScene.GetAllHitObjects(pickRay); if (allHitTests.Count == 0) { AddMessage("No object hit\r\n"); } else { var sb = new StringBuilder(); sb.AppendFormat("Ray.Start: {0:0.0}; Ray.Direction: {1:0.00}\r\n{2} hit results:\r\n", pickRay.Position, pickRay.Direction, allHitTests.Count); for (var i = 0; i < allHitTests.Count; i++) { var hitTest = allHitTests[i]; sb.AppendFormat("{0}. PointHit: {1:0.0}; Dist: {2:0}; SceneNode Id: {3}", i + 1, hitTest.HitPosition, hitTest.DistanceToRayOrigin, hitTest.HitSceneNode.Id); if (!string.IsNullOrEmpty(hitTest.HitSceneNode.Name)) { sb.AppendFormat(" ('{0}')", hitTest.HitSceneNode.Name); } var dxRayHitTestWpfModel3DResult = hitTest as DXRayHitTestWpfModel3DResult; if (dxRayHitTestWpfModel3DResult != null && dxRayHitTestWpfModel3DResult.HitGeometryModel3D != null) { var name = dxRayHitTestWpfModel3DResult.HitGeometryModel3D.GetName(); if (!string.IsNullOrEmpty(name)) { sb.Append(" GeometryModel3D.Name: ").Append(name); } } sb.AppendLine(); //if (_showHitArrows) //{ var wireCrossVisual3D = new Ab3d.Visuals.WireCrossVisual3D() { Position = hitTest.HitPosition.ToWpfPoint3D(), LineColor = Colors.Red, LineThickness = 1, LinesLength = 5 }; _hitLinesModelVisual3D.Children.Add(wireCrossVisual3D); //} } sb.AppendLine(); AddMessage(sb.ToString()); } var lineVisual3D = new Ab3d.Visuals.LineVisual3D() { StartPosition = pickRay.Position.ToWpfPoint3D(), EndPosition = pickRay.Position.ToWpfPoint3D() + pickRay.Direction.ToWpfVector3D() * dxScene.Camera.FarPlaneDistance, LineColor = Colors.Green, LineThickness = 1, EndLineCap = LineCap.ArrowAnchor }; _hitLinesModelVisual3D.Children.Add(lineVisual3D); }
private void ShowVisibleAndHiddenLines() { // To show both visible and hidden lines we need to render each line twice: // once with standard settings to shew visible part of the one, // once with using HiddenLineMaterial to show the hidden part of the line. // Now we will clone the existing 3D lines var existingLineVisuals = TestObjectsModelVisual3D.Children.OfType <BaseLineVisual3D>().ToList(); var newLineVisuals = new List <BaseLineVisual3D>(); foreach (var lineVisual3D in existingLineVisuals) { var clonedLineVisual = CloneLineVisuals(lineVisual3D); // To correctly show hidden lines, then need to be rendered after the objects in front of the lines // (they are rendered only in case when there are already some objects in front of them - line's depth is bigger then current depth value). // In case you want to show the hidden lines behind semi-transparent objects, you need to make sure that // the lines are put into the OverlayRenderingQueue. // This is needed because TransparentRenderingQueue is defined after LineGeometryRenderingQueue // and therefore all transparent objects are rendered after all 3D lines (this is needed so the lines are visible through transparent objects). // This can be done with using the SetDXAttribute method and setting the CustomRenderingQueue value. // Note that this value need to be set before the line is initialized by the DXEngine - so before the MainDXViewportView.Update call a few lines below. // (in case of using ScreenSpaceLineNode, you can set its CustomRenderingQueue). //clonedLineVisual.SetDXAttribute(DXAttributeType.CustomRenderingQueue, MainDXViewportView.DXScene.OverlayRenderingQueue); TestObjectsModelVisual3D.Children.Add(clonedLineVisual); newLineVisuals.Add(clonedLineVisual); } // After adding new WPF objects to the scene, we need to manually call Update to create DXEngine's SceneNode objects that will be needed later MainDXViewportView.Update(); // We need to update the _sceneNodesDictionary because we have changed the scene CreateSceneNodesDictionary(); // Now change the materials of the clones lines to hiddenLineMaterial foreach (var newLineVisual3D in newLineVisuals) { // Now we can change the material to _hiddenLineMaterial. // // We also need to put the hidden line to the OverlayRenderingQueue. // This is needed because to correctly show hidden lines, they need to be rendered after the objects in front of the lines // (they are rendered only in case when there are already some objects in front of them - line's depth is bigger then current depth value). // In case you want to show the hidden lines behind semi-transparent objects, you need to make sure that // the lines are put into the OverlayRenderingQueue. // This is needed because TransparentRenderingQueue is defined after LineGeometryRenderingQueue // and therefore all transparent objects are rendered after all 3D lines (this is needed so the lines are visible through transparent objects). // // Here this is done with setting the CustomRenderingQueue on the ScreenSpaceLineNode (see ChangeLineMaterial method). ChangeLineMaterial(newLineVisual3D, _hiddenLineMaterial, MainDXViewportView.DXScene.OverlayRenderingQueue); // We could also call SetDXAttribute and set the CustomRenderingQueue to OverlayRenderingQueue. // This can be done with uncommenting the following line // (but this is less efficient than setting the CustomRenderingQueue on the ScreenSpaceLineNode as done in the ChangeLineMaterial): //newLineVisual3D.SetDXAttribute(DXAttributeType.CustomRenderingQueue, MainDXViewportView.DXScene.OverlayRenderingQueue); } if (_wireframeGeometryModel3D != null) { // Clone the GeometryModel3D that shows teapot wireframe and use hiddenLineMaterial to render it var newWpfWireframeMaterial = new DiffuseMaterial(Brushes.Red); newWpfWireframeMaterial.SetUsedDXMaterial(_hiddenLineMaterial); var geometryModel3D = new GeometryModel3D(_wireframeGeometryModel3D.Geometry, newWpfWireframeMaterial); geometryModel3D.Transform = _wireframeGeometryModel3D.Transform; var modelVisual3D = new ModelVisual3D() { Content = geometryModel3D }; TestObjectsModelVisual3D.Children.Add(modelVisual3D); } // Create a new ScreenSpaceLineNode from the data for _screenSpaceLineNode // Set its material to _hiddenLineMaterial and move it to the OverlayRenderingQueue: var hiddenScreenSpaceLineNode = new ScreenSpaceLineNode(_screenSpaceLineNode.Positions, _screenSpaceLineNode.IsLineStrip, _screenSpaceLineNode.IsLineClosed, _hiddenLineMaterial); hiddenScreenSpaceLineNode.CustomRenderingQueue = MainDXViewportView.DXScene.OverlayRenderingQueue; var sceneNodeVisual3D = new SceneNodeVisual3D(hiddenScreenSpaceLineNode); TestObjectsModelVisual3D.Children.Add(sceneNodeVisual3D); }