private GeometryModel3D AddMeshNormalMaterialModel(MeshGeometry3D mesh, Point3D position, Color3 colorMask) { var diffuseMaterial = new DiffuseMaterial(Brushes.Red); var meshNormalMaterial = new MeshNormalMaterial() { ColorMask = colorMask }; diffuseMaterial.SetUsedDXMaterial(meshNormalMaterial); _disposeList.Add(meshNormalMaterial); var model3D = new GeometryModel3D(mesh, diffuseMaterial); model3D.Transform = new TranslateTransform3D(position.X, position.Y, position.Z); var modelVisual3D = new ModelVisual3D() { Content = model3D }; MainViewport.Children.Add(modelVisual3D); return(model3D); }
private void ShowOnlyHiddenLines() { var allTestLines = TestObjectsModelVisual3D.Children.OfType <BaseLineVisual3D>().ToList(); foreach (var lineVisual3D in allTestLines) { // Use _hiddenLineMaterial and put line into OverlayRenderingQueue (see comments in ShowVisibleAndHiddenLines for more info) ChangeLineMaterial(lineVisual3D, _hiddenLineMaterial, MainDXViewportView.DXScene.OverlayRenderingQueue); // We could also call SetDXAttribute and set the CustomRenderingQueue to OverlayRenderingQueue. //lineVisual3D.SetDXAttribute(DXAttributeType.CustomRenderingQueue, MainDXViewportView.DXScene.OverlayRenderingQueue); } if (_wireframeGeometryModel3D != null) { var newWpfWireframeMaterial = new DiffuseMaterial(Brushes.Red); newWpfWireframeMaterial.SetUsedDXMaterial(_hiddenLineMaterial); _wireframeGeometryModel3D.Material = newWpfWireframeMaterial; _wireframeGeometryModel3D.SetDXAttribute(DXAttributeType.CustomRenderingQueue, MainDXViewportView.DXScene.OverlayRenderingQueue); } // Change LineMaterial to _hiddenLineMaterial and move it to the OverlayRenderingQueue _screenSpaceLineNode.LineMaterial = _hiddenLineMaterial; _screenSpaceLineNode.CustomRenderingQueue = MainDXViewportView.DXScene.OverlayRenderingQueue; _screenSpaceLineNode.NotifySceneNodeChange(SceneNode.SceneNodeDirtyFlags.MaterialChanged | SceneNode.SceneNodeDirtyFlags.RenderingQueueChanged); }
private void AddTestModel() { var boxMesh3D = new Ab3d.Meshes.BoxMesh3D(new Point3D(0, 0, 0), new Size3D(1, 1, 1), 1, 1, 1).Geometry; int positionsCount = boxMesh3D.Positions.Count; var bounds = boxMesh3D.Bounds; // Create positionColorsArray that will define colors for each position var positionColorsArray = new Color4[positionsCount]; for (int i = 0; i < positionsCount; i++) { var position = boxMesh3D.Positions[i]; // Get colors based on the relative position inside the Bounds - in range from (0, 0, 0) to (1, 1, 1) float red = (float)((position.X - bounds.X) / bounds.SizeX); float green = (float)((position.Y - bounds.Y) / bounds.SizeY); float blue = (float)((position.Z - bounds.Z) / bounds.SizeZ); // Set Color this position positionColorsArray[i] = new Color4(red, green, blue, alpha: 1.0f); } // Now create the VertexColorMaterial that will be used instead of standard material // and will make the model render with special effect where each vertex can have its own color. _vertexColorMaterial = new VertexColorMaterial() { PositionColors = positionColorsArray, // The PositionColors property is used to specify colors for each vertex // To show specular effect set the specular data here: //SpecularPower = 16, //SpecularColor = Color3.White, //HasSpecularColor = true // If we would update the positionColorsArray very often, then set CreateDynamicBuffer to true //CreateDynamicBuffer = true, }; // Create standard WPF material and set the _vertexColorMaterial to be used when the model is rendered in DXEngine. var vertexColorDiffuseMaterial = new DiffuseMaterial(); vertexColorDiffuseMaterial.SetUsedDXMaterial(_vertexColorMaterial); // Create a GeometryModel3D that will be rendered with _vertexColorMaterial var vertexColorGeometryModel3D = new GeometryModel3D(boxMesh3D, vertexColorDiffuseMaterial); vertexColorGeometryModel3D.Transform = new ScaleTransform3D(100, 50, 80); // Scale the box var vertexColorModelVisual3D = new ModelVisual3D() { Content = vertexColorGeometryModel3D }; MainViewport.Children.Add(vertexColorModelVisual3D); }
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 DiffuseMaterial CreateDiffuseMaterial(string textureFileName) { DiffuseMaterial material; if (textureFileName.EndsWith(".dds", StringComparison.OrdinalIgnoreCase)) { var dxScene = MainDXViewportView.DXScene; if (dxScene == null) // In case of WPF 3D rendering { return(null); } // The easiest way to load image file and in the same time create a material with the loaded texture is to use the CreateStandardTextureMaterial method. var standardMaterial = Ab3d.DirectX.TextureLoader.CreateStandardTextureMaterial(MainDXViewportView.DXScene.DXDevice, textureFileName); // We need to manually dispose the created StandardMaterial and ShaderResourceView _disposables.Add(standardMaterial); _disposables.Add(standardMaterial.DiffuseTextures[0]); bool isAlphaToCoverageEnabled = AlphaToCoverageRadioButton.IsChecked ?? false; bool isAlphaClippingEnabled = AlphaClippingRadioButton.IsChecked ?? false; standardMaterial.AlphaClipThreshold = isAlphaClippingEnabled ? GetAlphaClippingThreshold() : 0; // 0 disables alpha clipping // When AlphaToCoverage is enabled, then we need to set the TextureBlendState to AlphaToCoverage. // If this is not done (if TextureBlendState is null), then the bend state is set to Opaque or PremultipliedAlphaBlend (when the texture has transparency) if (isAlphaToCoverageEnabled) { standardMaterial.TextureBlendState = dxScene.DXDevice.CommonStates.AlphaToCoverage; } material = new DiffuseMaterial(); material.SetUsedDXMaterial(standardMaterial); } else { var bitmapImage = new BitmapImage(new Uri(textureFileName, UriKind.Absolute)); material = new DiffuseMaterial(new ImageBrush(bitmapImage)); // When using WPF material, we need to set special DXEngine attributes with using SetDXAttribute (this is done in the following method): SetMaterialsDXAttributes(material); } return(material); }
private void ShowOnlyHiddenLines() { foreach (var lineVisual3D in TestObjectsModelVisual3D.Children.OfType <BaseLineVisual3D>()) { ChangeLineMaterial(lineVisual3D, _hiddenLineMaterial); } if (_wireframeGeometryModel3D != null) { var newWpfWireframeMaterial = new DiffuseMaterial(Brushes.Red); newWpfWireframeMaterial.SetUsedDXMaterial(_hiddenLineMaterial); _wireframeGeometryModel3D.Material = newWpfWireframeMaterial; } }
private void CreateSampleScene() { _physicallyBasedMaterial = new PhysicallyBasedMaterial(); // We need to dispose the PhysicallyBasedMaterial when this sample is uloaded _disposables.Add(_physicallyBasedMaterial); UpdateBaseColor(); UpdateMetalness(); UpdateRoughness(); var normalMapShaderResourceView = GetNormalMapShaderResourceView(); if (normalMapShaderResourceView != null) { _physicallyBasedMaterial.SetTextureMap(TextureMapTypes.NormalMap, normalMapShaderResourceView, "bricks_normal.png"); } var ambientOcclusionShaderResourceView = AmbientOcclusionShaderResourceView(); if (ambientOcclusionShaderResourceView != null) { _physicallyBasedMaterial.SetTextureMap(TextureMapTypes.AmbientOcclusion, ambientOcclusionShaderResourceView, "bricks_ao.png"); } var wpfMaterial = new DiffuseMaterial(Brushes.Red); wpfMaterial.SetUsedDXMaterial(_physicallyBasedMaterial); ModelPlaceholder.Content = null; ModelPlaceholder.Children.Clear(); var sphereVisual3D = new Ab3d.Visuals.SphereVisual3D() { CenterPosition = new Point3D(40, 12, 0), Radius = 12, Segments = 50, Material = wpfMaterial, FreezeMeshGeometry3D = false, UseCachedMeshGeometry3D = false }; ModelPlaceholder.Children.Add(sphereVisual3D); var boxVisual3D = new Ab3d.Visuals.BoxVisual3D() { CenterPosition = new Point3D(-40, 10, 0), Size = new Size3D(20, 20, 20), Material = wpfMaterial, FreezeMeshGeometry3D = false, UseCachedMeshGeometry3D = false }; ModelPlaceholder.Children.Add(boxVisual3D); var readerObj = new Ab3d.ReaderObj(); var readModel3D = (GeometryModel3D)readerObj.ReadModel3D(_modelsFolder + "teapot-hires.obj"); Ab3d.Utilities.ModelUtils.CenterAndScaleModel3D(readModel3D, new Point3D(0, 10, 0), new Size3D(40, 40, 40), true); //// This code is called for each GeometryModel3D inside Plane1 //var tangentVectors = Ab3d.DirectX.Utilities.MeshUtils.CalculateTangentVectors((MeshGeometry3D)readModel3D.Geometry); ////// Assign tangent array to the MeshGeometry3D //readModel3D.Geometry.SetDXAttribute(DXAttributeType.MeshTangentArray, tangentVectors); readModel3D.Material = wpfMaterial; //ModelPlaceholder.Content = null; ModelPlaceholder.Children.Add(readModel3D.CreateModelVisual3D()); // Rendering normal (bump) maps require tangent vectors. // The following code will generate tangent vectors and assign them to the MeshGeometry3D that form our 3D model. // If tangent vectors are not provided, they will be calculated on-demand in the pixel shader (slightly reducing performance). Ab3d.Utilities.ModelIterator.IterateGeometryModel3DObjects(ModelPlaceholder, delegate(GeometryModel3D geometryModel3D, Transform3D transform3D) { // This code is called for each GeometryModel3D inside Plane1 var tangentVectors = Ab3d.DirectX.Utilities.MeshUtils.CalculateTangentVectors((MeshGeometry3D)geometryModel3D.Geometry); // Assign tangent array to the MeshGeometry3D geometryModel3D.Geometry.SetDXAttribute(DXAttributeType.MeshTangentArray, tangentVectors); }); Camera1.Distance = 150; UpdateLights(); }
private void CreateLandscape(int gridSize, float noise, int randomSeed = 0) // is randomSeed is 0 or less, then random seed is used { _lastUsedGridSize = gridSize; // Generate height data with using DiamondSquare algorithm float[,] floatHeightData = DiamondSquareGrid(gridSize, seed: randomSeed, rMin: 0, rMax: 1, noise: noise); // To show height map we will use HeightMapMesh3D from Ab3d.PowerToys library // This class requires data in array of doubles. // NOTE: In the future version of DXEngine there will be an optimized version of HeightMesh that will take floats _heightData = new double[gridSize, gridSize]; for (int rowIndex = 0; rowIndex < gridSize; rowIndex++) { for (int columnIndex = 0; columnIndex < gridSize; columnIndex++) { _heightData[rowIndex, columnIndex] = (double)floatHeightData[rowIndex, columnIndex]; } } // We can use HeightMapMesh3D object from Ab3d.PowerToys library to create a MeshGeometry3D object from 2D array // We create Mesh with size 1 x 1 x 1 // This will allow us to scale it later to any size with ScaleTransform3D _heightMapMesh3D = new Meshes.HeightMapMesh3D(new Point3D(0, 0, 0), new Size3D(1, 1, 1), _heightData).Geometry; var vertexColorDiffuseMaterial = new DiffuseMaterial(); int positionsCount = _heightMapMesh3D.Positions.Count; // Create vertexColorsArray var vertexColorsArray = new Color4[positionsCount]; // Fill the vertexColorsArray with color values based on the data from _heightData CalculateVertexColors(_heightData, vertexColorsArray); // To show per-vertex color, we need to use a special VertexColorMaterial // Reuse VertexColorMaterial if possible. // Dispose old VertexColorMaterial and create a new one if (_vertexColorMaterial != null) { _vertexColorMaterial.Dispose(); } _vertexColorMaterial = new VertexColorMaterial() { PositionColors = vertexColorsArray }; // This material needs to be set to the WPF vertexColorDiffuseMaterial as UsedDXMaterial. // This means that when DXEngine will need to show WPF vertexColorDiffuseMaterial, it will use the vertexColorMaterial. vertexColorDiffuseMaterial.SetUsedDXMaterial(_vertexColorMaterial); // Now create GeometryModel3D and ModelVisual3D var vertexColorGeometryModel3D = new GeometryModel3D(_heightMapMesh3D, vertexColorDiffuseMaterial); vertexColorGeometryModel3D.Transform = new ScaleTransform3D(200, 200, 200); // To make the landscape colors visible from front and also back side, uncomment the line below (and comment the GeometryModel3D generation a few lines below): //vertexColorGeometryModel3D.BackMaterial = vertexColorDiffuseMaterial; var vertexColorModelVisual3D = new ModelVisual3D() { Content = vertexColorGeometryModel3D }; MainViewport.Children.Add(vertexColorModelVisual3D); // Add a new GeometryModel3D with the same _heightMapMesh3D // But this time render only back faces with gray material var backGeometryModel3D = new GeometryModel3D { Geometry = vertexColorGeometryModel3D.Geometry, // Same geometry as vertexColorGeometryModel3D Material = null, // Do not render front-faced triangles BackMaterial = new DiffuseMaterial(Brushes.DimGray), // Render only back faces Transform = vertexColorGeometryModel3D.Transform // Same scale transform as vertexColorGeometryModel3D }; var backModelVisual3D = new ModelVisual3D() { Content = backGeometryModel3D }; MainViewport.Children.Add(backModelVisual3D); // Refresh the camera in case we have removed the camera's light with MainViewport.Children.Clear(); Camera1.Refresh(); }
private void AddTestModels() { // Load teapot model from obj file var readerObj = new ReaderObj(); var geometryModel3D = readerObj.ReadModel3D(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Resources\Models\teapot.obj")) as GeometryModel3D; if (geometryModel3D == null) { return; } _objectGeometry3D = (MeshGeometry3D)geometryModel3D.Geometry; int positionsCount = _objectGeometry3D.Positions.Count; // Create and fill the _positionColorsArray with the last color (light blue) _positionColorsArray = new Color4[positionsCount]; var lastColor = _gradientColor4Array[_gradientColor4Array.Length - 1]; FillPositionColorsArray(lastColor); // Now create the VertexColorMaterial that will be used instead of standard material // and will make the model render with special effect where each vertex can have its own color. _vertexColorMaterial = new VertexColorMaterial() { PositionColors = _positionColorsArray, // The PositionColors property is used to specify colors for each vertex CreateDynamicBuffer = true, // Because we will update the _positionColorsArray on each frame, it is better to create a dynamic DirectX buffer // To show specular effect set the specular data here: //SpecularPower = 16, //SpecularColor = Color3.White, //HasSpecularColor = true }; // Create standard WPF material and set the _vertexColorMaterial to be used when the model is rendered in DXEngine. var vertexColorDiffuseMaterial = new DiffuseMaterial(); vertexColorDiffuseMaterial.SetUsedDXMaterial(_vertexColorMaterial); // Create a GeometryModel3D that will be rendered with _vertexColorMaterial _vertexColorGeometryModel3D = new GeometryModel3D(_objectGeometry3D, vertexColorDiffuseMaterial); var vertexColorModelVisual3D = new ModelVisual3D() { Content = _vertexColorGeometryModel3D }; MainViewport.Children.Add(vertexColorModelVisual3D); // Show the same MeshGeometry3D but this time with wireframe material var wireframeWpfMaterial = new DiffuseMaterial(); _lineMaterial = new LineMaterial() { LineThickness = 1, LineColor = Color4.Black, DepthBias = 0.1f, }; wireframeWpfMaterial.SetUsedDXMaterial(_lineMaterial); var wireframeGeometryModel3D = new GeometryModel3D(_objectGeometry3D, wireframeWpfMaterial); var wireframeModelVisual3D = new ModelVisual3D() { Content = wireframeGeometryModel3D }; MainViewport.Children.Add(wireframeModelVisual3D); }
private void CreateTeapotWireframeModel(Point3D centerPosition, Size3D size, DiffuseMaterial material) { // The most common way to show wireframe models in DXEngine is to use WireframeVisual3D from Ab3d.PowerToys - see commented code below: //var wireframeVisual3D = new WireframeVisual3D() //{ // WireframeType = WireframeVisual3D.WireframeTypes.WireframeWithOriginalSolidModel, // UseModelColor = false, // LineThickness = 1, // LineColor = Colors.Yellow, // Transform = new TranslateTransform3D(0, 0, -50) //}; // //wireframeVisual3D.OriginalModel = teapotModel; //// Set LineDepthBias to prevent rendering wireframe at the same depth as the 3D objects. //// This creates much nicer 3D lines. See the LineDepthBiasSample for more information. //wireframeVisual3D.SetDXAttribute(DXAttributeType.LineDepthBias, 0.1); // But in this sample we show special line rendering. // Therefore we will create standard WPF GeometryModel3D and then apply LineMaterial to it so the model will be rendered with wireframe lines // First read teapot model from Teapot.obj file var readerObj = new Ab3d.ReaderObj(); var teapotModel = readerObj.ReadModel3D(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Resources\Models\Teapot.obj")) as GeometryModel3D; if (teapotModel == null) { return; } // Get the teapot MeshGeometry3D var meshGeometry3D = (MeshGeometry3D)teapotModel.Geometry; // Get transformation to scale and position the model to the centerPosition and size var bounds = meshGeometry3D.Bounds; double scaleX = size.X / bounds.SizeX; double scaleY = size.Y / bounds.SizeY; double scaleZ = size.Z / bounds.SizeZ; double minScale = Math.Min(scaleX, Math.Min(scaleY, scaleZ)); scaleX = scaleY = scaleZ = minScale; var scaleTransform3D = new ScaleTransform3D(scaleX, scaleY, scaleZ); bounds = scaleTransform3D.TransformBounds(bounds); double cx = bounds.X + bounds.SizeX * 0.5; double cy = bounds.Y + bounds.SizeY * 0.5; double cz = bounds.Z + bounds.SizeZ * 0.5; var translateTransform3D = new TranslateTransform3D(centerPosition.X - cx, centerPosition.Y - cy, centerPosition.Z - cz); var transform3DGroup = new Transform3DGroup(); transform3DGroup.Children.Add(scaleTransform3D); transform3DGroup.Children.Add(translateTransform3D); // First create the standard solid model with the specified material var geometryModel3D = new GeometryModel3D(meshGeometry3D, material); geometryModel3D.Transform = transform3DGroup; var modelVisual3D = new ModelVisual3D() { Content = geometryModel3D }; TestObjectsModelVisual3D.Children.Add(modelVisual3D); // To render wireframe object, we first create a DXEngine material that is used to rendered lines or wireframe if (_dxLineMaterial == null) { _dxLineMaterial = new LineMaterial() { LineThickness = 1, LineColor = Colors.Yellow.ToColor4(), DepthBias = 0.1f // Set DepthBias to prevent rendering wireframe at the same depth as the 3D objects. This creates much nicer 3D lines because lines are rendered on top of 3D object and not in the same position as 3D object. }; } else { _dxLineMaterial.ReadZBuffer = true; } // Now create standard WPF material and assign DXEngine's LineMaterial to it. // This will use the dxLineMaterial when the wpfLineMaterial will be rendered in DXEngine var wpfWireframeMaterial = new DiffuseMaterial(Brushes.Red); wpfWireframeMaterial.SetUsedDXMaterial(_dxLineMaterial); // Finally, create another GeometryModel3D, but this time we will use DXEngine's LineMaterial to render it _wireframeGeometryModel3D = new GeometryModel3D(meshGeometry3D, wpfWireframeMaterial); _wireframeGeometryModel3D.Transform = transform3DGroup; modelVisual3D = new ModelVisual3D() { Content = _wireframeGeometryModel3D }; TestObjectsModelVisual3D.Children.Add(modelVisual3D); }
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); }