private void OnDXSceneViewInitialized() { if (MainDXViewportView.UsedGraphicsProfile.DriverType == GraphicsProfile.DriverTypes.Wpf3D) { HouseWithThreesWireframeVisual.RemoveDuplicateLines = true; // This is recommended setting for WPF because it reduces the number of lines PersonWireframeVisual.RemoveDuplicateLines = true; return; } HouseWithThreesWireframeVisual.RemoveDuplicateLines = false; // Rendering lines in DXEngine is very cheap so we can skip the process of finding and removing duplicates PersonWireframeVisual.RemoveDuplicateLines = false; // Get the SceneNodes (WpfWireframeVisual3DNode) used by DXScene // This way we can access some properties that are specific to DirectX and are not used in WPF WireframeVisual3D (like depth bias properties) _wpfHouseWithThreesWireframeVisualNode = MainDXViewportView.GetSceneNodeForWpfObject(HouseWithThreesWireframeVisual) as WpfWireframeVisual3DNode; if (_wpfHouseWithThreesWireframeVisualNode != null) { _wpfHouseWithThreesWireframeVisualNode.Name = "HouseWithThreesWireframeVisualNode"; } _wpfPersonWireframeVisualNode = MainDXViewportView.GetSceneNodeForWpfObject(PersonWireframeVisual) as WpfWireframeVisual3DNode; if (_wpfPersonWireframeVisualNode != null) { _wpfPersonWireframeVisualNode.Name = "PersonWireframeVisualNode"; } UpdateDepthBias(); }
private SceneNode GetSceneNodeForWpfObject(object wpfObject) { if (wpfObject == null) { return(null); } SceneNode sceneNode = null; // Use _sceneNodesDictionary if possible if (_sceneNodesDictionary != null) { _sceneNodesDictionary.TryGetValue(wpfObject, out sceneNode); } // If SceneNode is not found, we an use the GetSceneNodeForWpfObject method. // Note that this method is very slow because it goes through each SceneNode in the scene // and for each SceneNode calls IsMyWpfObject method. if (sceneNode == null) { sceneNode = MainDXViewportView.GetSceneNodeForWpfObject(wpfObject); } return(sceneNode); }
private void SetIsHitTestVisible(ModelVisual3D modelVisual3D, bool isHitTestVisible) { var sceneNode = MainDXViewportView.GetSceneNodeForWpfObject(modelVisual3D); if (sceneNode == null) { return; } sceneNode.IsHitTestVisible = isHitTestVisible; }
private void UpdateSelectedMaps() { if (!this.IsLoaded) { return; } bool isChanged = UpdateMap(_multiMapMaterial, (DiffuseMapCheckBox.IsChecked ?? false), TextureMapTypes.DiffuseColor, _diffuseShaderResourceView); isChanged |= UpdateMap(_multiMapMaterial, (NormalMapCheckBox.IsChecked ?? false), TextureMapTypes.NormalMap, _normalShaderResourceView); isChanged |= UpdateMap(_multiMapMaterial, (SpecularMapCheckBox.IsChecked ?? false), TextureMapTypes.SpecularColor, _specularShaderResourceView); if (isChanged) { // When we change DXEngine's material, we need to notify the SceneNode that is using the material about the change. var plane1SceneNode = MainDXViewportView.GetSceneNodeForWpfObject(Plane1); if (plane1SceneNode != null) { plane1SceneNode.NotifySceneNodeChange(SceneNode.SceneNodeDirtyFlags.MaterialChanged); } } }
public ShadowRenderingSample() { InitializeComponent(); // Default values can be get before Loaded event _shadowMapSize = 512; _shadowDepthBluringSize = 4; _shadowTreshold = 0.2f; CreateCustomScene(); CreateLights(); CreateLightSphere(); _isShadowEnabled = true; UpdateCastingShadowLight(); MainDXViewportView.DXSceneInitialized += delegate(object sender, EventArgs args) { if (MainDXViewportView.DXScene == null) { return; // Probably WPF 3D rendering } // The DXScene.InitializeShadowRendering method must be called with the VarianceShadowRenderingProvider. // The VarianceShadowRenderingProvider controls the rendering of shadows. // // Variance shadow rendering technique can produce nice shadows with soft edges and without the artifacts that are common for some other shadow rendering (Peter panning or Self shadowing). // More info can be read in the GPU Gems3 "Chapter 8. Summed-Area Variance Shadow Maps" (https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch08.html) _varianceShadowRenderingProvider = new VarianceShadowRenderingProvider(); // ShadowMapSize represents the size of a shadow depth map texture. For example value 512 means that a 512 x 512 texture will be used. // The shadow depth map texture is used to store depth information - distance of a pixel from the light. // Bigger texture will produce more detailed shadows but will be slower to render. // Also, to bigger texture will require bigger blur amount to achieve nice soft edges. // NOTE: Changing the ShadowMapSize after the VarianceShadowRenderingProvider has been initialized has no effect - see UpdateShadowSettings method in this file to see how to change the value _varianceShadowRenderingProvider.ShadowMapSize = _shadowMapSize; // ShadowDepthBluringSize specifies the blur amount that is applied on the shadow depth map and can produce shadows with nice soft edges. // Default value is 4. _varianceShadowRenderingProvider.ShadowDepthBluringSize = _shadowDepthBluringSize; // ShadowTreshold is a float value that helps prevent light bleeding (having areas that should be in shadow fully illuminated) for variance shadow mapping. // The value is used to map all shadow values from 0 ... ShadowTreshold to 0 and then linearly rescale the values from ShadowTreshold to 1 into 0 to 1. // For more info see "Shadow bleeding" in "Chapter 8. Summed-Area Variance Shadow Maps" (https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch08.html) _varianceShadowRenderingProvider.ShadowTreshold = _shadowTreshold; // Initialize shadow rendering MainDXViewportView.DXScene.InitializeShadowRendering(_varianceShadowRenderingProvider); // When the scene is initialized, we can get the SceneNode that is created from WPF teapot model. // This will be used later (in OnObjectsFilterValueChanged) to enable or disable casting and receiving shadow. _teapotSceneNode = MainDXViewportView.GetSceneNodeForWpfObject(_teapotModel) as WpfGeometryModel3DNode; // To use FilterObjectsFunction to filter which objects are casting and receiving shadow, uncomment the lines below (see comment in OnObjectsFilterValueChanged method for more info): //_varianceShadowRenderingProvider.RenderShadowDepthRenderingStep.FilterObjectsFunction = FilterNonTeapotObjectsFunction; //_varianceShadowRenderingProvider.RenderNonShadowObjectsRenderingStep.FilterObjectsFunction = FilterTeapotObjectsFunction; //MainDXViewportView.DXScene.DefaultRenderObjectsRenderingStep.FilterObjectsFunction = FilterNonTeapotObjectsFunction; // IMPORTANT: // Af least one light need to set to cast shadow. This can be done with the following code: //_directionalLight.SetDXAttribute(DXAttributeType.IsCastingShadow, true); }; StartLightAnimation(); this.Unloaded += delegate(object sender, RoutedEventArgs args) { StopLightAnimation(); if (_varianceShadowRenderingProvider != null) { _varianceShadowRenderingProvider.Dispose(); } MainDXViewportView.Dispose(); }; this.PreviewKeyDown += OnPreviewKeyDown; // This will allow receiving keyboard events this.Focusable = true; this.Focus(); }
private void ProcessMouseHit(System.Windows.Point mousePosition) { bool isVertexColorDataChanged; RayMeshGeometry3DHitTestResult hitTestResult; if (double.IsNaN(mousePosition.X)) // if mousePosition.X is NaN, then we consider this as mouse did not hit the model { hitTestResult = null; } else { hitTestResult = VisualTreeHelper.HitTest(MainViewport, mousePosition) as RayMeshGeometry3DHitTestResult; BeamLine1.X2 = mousePosition.X; BeamLine1.Y2 = mousePosition.Y; BeamLine1.Visibility = Visibility.Visible; BeamLine2.X2 = mousePosition.X; BeamLine2.Y2 = mousePosition.Y; BeamLine2.Visibility = Visibility.Visible; } if (hitTestResult != null) { var hitPoint3D = hitTestResult.PointHit; // Update the _positionColorsArray (array of colors for each vertex) so that each color is calculated as distance from the hitPoint3D. // Colors are set to the distances between 0 and 50; after 50 the lase color (light blue) is assigned. CalculatePositionColorsFromDistance(_objectGeometry3D.Positions, hitPoint3D, 50, _positionColorsArray); isVertexColorDataChanged = true; _isLastMousePositionHit = true; BeamLine1.Stroke = Brushes.Red; BeamLine2.Stroke = Brushes.Red; } else { // Show Gray line for missed position BeamLine1.Stroke = Brushes.Gray; BeamLine2.Stroke = Brushes.Gray; if (_isLastMousePositionHit) { // If before the mouse position hit the 3D mode, then the 3D model was colored // But now the position do not hit the 3D mode any more - so we need to color the 3D mode with the last color - the one that is used for the biggest beam distance (light blue) var lastColor = _gradientColor4Array[_gradientColor4Array.Length - 1]; FillPositionColorsArray(lastColor); isVertexColorDataChanged = true; } else { isVertexColorDataChanged = false; } _isLastMousePositionHit = false; } if (isVertexColorDataChanged) { //_vertexColorMaterial.PositionColors = _positionColorsArray; // PositionColors property was already set before // Update method on the VertexColorMaterial will update the underlying DirectX vertex buffer that // is created from PositionColors array and is sent to graphics card to render the 3D model. _vertexColorMaterial.Update(); // Because we have manually updated the DXEngine material we need to notify the DXEngine's SceneNode that is using this material about the change. var sceneNode = MainDXViewportView.GetSceneNodeForWpfObject(_vertexColorGeometryModel3D); if (sceneNode != null) { sceneNode.NotifySceneNodeChange(SceneNode.SceneNodeDirtyFlags.MaterialChanged); } } }