public OptimizedTubePathSample() { InitializeComponent(); _disposables = new DisposeList(); MainDXViewportView.DXSceneDeviceCreated += delegate(object sender, EventArgs args) { _solidColorEffect = MainDXViewportView.DXScene.DXDevice.EffectsManager.GetEffect <SolidColorEffect>(); _disposables.Add(_solidColorEffect); _stopwatch = new Stopwatch(); _stopwatch.Start(); AddSpirals_MeshObjectNode(10, 10, 5000, useMultiThreading: true); // Uncomment to see how the tubes are created in a standard Ab3d.PowerToys way. //AddSpirals_TubePathVisual3D(10, 10, 5000); // To see how to use instancing to draw tube paths, uncomment the following line. // Note: In this case is instancing slower then rendering a fixed geometry because the task for the GPU is much more complicated in case of instancing. //AddInstancedSpirals(10, 10, 5000); }; // Subscribe to get event when the first frame is rendered MainDXViewportView.SceneRendered += MainDXViewportViewOnSceneRendered; this.Unloaded += delegate(object sender, RoutedEventArgs args) { _disposables.Dispose(); }; }
private void MainDxViewportViewOnDxSceneDeviceCreated(object sender, EventArgs e) { // Create a SolidColorEffect that will be used to render each objects with a color from object's id _solidColorEffect = new SolidColorEffect(); _solidColorEffect.OverrideModelColor = true; // We will overwrite the object's color with color specified in SolidColorEffect.Color _disposables.Add(_solidColorEffect); MainDXViewportView.DXScene.DXDevice.EffectsManager.RegisterEffect(_solidColorEffect); // Create a custom rendering step that will be used instead of standard rendering step _objectIdRenderingStep = new CustomActionRenderingStep("ObjectIdRenderingStep") { CustomAction = ObjectIdRenderingAction, IsEnabled = false }; MainDXViewportView.DXScene.RenderingSteps.AddAfter(MainDXViewportView.DXScene.DefaultRenderObjectsRenderingStep, _objectIdRenderingStep); // In this sample we render Object ids to a custom bitmap, // so for standard rendering, we disable our custom rendering. // But if you went you can enable it and disabled the standard rendering - this will always render objects ids: //_objectIdRenderingStep.IsEnabled = true; //MainDXViewportView.DXScene.DefaultRenderObjectsRenderingStep.IsEnabled = false; }
public SolidColorInstanceRendering() { InitializeComponent(); MainDXViewportView.DXSceneDeviceCreated += delegate(object sender, EventArgs args) { _currentRenderingType = GetCurrentRenderingType(); CreateInstances(); ChangeRenderingType(); }; // 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) => { if (_solidColorEffectWithOutline != null) { _solidColorEffectWithOutline.Dispose(); _solidColorEffectWithOutline = null; } MainDXViewportView.Dispose(); }; }
private void ChangeRenderingType() { if (MainDXViewportView.DXScene == null) { return; // Probably WPF 3D rendering } var color = GetColorFromComboBox(SolidModelColorComboBox); if (_currentRenderingType == RenderingTypes.SolidColorEffect) { MainDXViewportView.DXScene.DefaultRenderObjectsRenderingStep.OverrideEffect = null; } _currentRenderingType = GetCurrentRenderingType(); if (_currentRenderingType == RenderingTypes.SolidColorEffect) { _solidColorEffectWithOutline = new Ab3d.DirectX.Effects.SolidColorEffect { Color = color.ToColor4(), OverrideModelColor = true }; _solidColorEffectWithOutline.InitializeResources(MainDXViewportView.DXScene.DXDevice); MainDXViewportView.DXScene.DefaultRenderObjectsRenderingStep.OverrideEffect = _solidColorEffectWithOutline; } else if (_currentRenderingType == RenderingTypes.UseSingleObjectColor) { // Set IsSolidColorMaterial to render tube instances with solid color without any shading based on lighting _instancedMeshGeometryVisual3D.IsSolidColorMaterial = IsSolidColorMaterialCheckBox.IsChecked ?? false; var instancesData = _instancedMeshGeometryVisual3D.InstancesData; int instancesCount = instancesData.Length; for (var i = 0; i < instancesCount; i++) { instancesData[i].DiffuseColor = color.ToColor4(); } _instancedMeshGeometryVisual3D.Update(0, instancesCount, updateBounds: false); } else { CreateInstances(); } }
private SolidColorEffect EnsureSolidColorEffect() { if (MainDXViewportView.DXScene == null) { return(null); } if (_blackOutlineEffect == null) { _blackOutlineEffect = new SolidColorEffect() { Color = Color4.Black, OverrideModelColor = true, // This will render all objects with Black color; when false then object's color is used }; _disposables.Add(_blackOutlineEffect); _blackOutlineEffect.InitializeResources(MainDXViewportView.DXScene.DXDevice); } return(_blackOutlineEffect); }
private void SetupSolidColorEffectWithOutlines() { // One way to show object outlines is to render the whole scene with black color (using SolidColorEffect) // and with expanding the geometry of each object in the direction of triangle normals (setting SolidColorEffect.OutlineThickness property) // Then the standard 3D scene is rendered on top of the black 3D scene. var dxScene = MainDXViewportView.DXScene; _blackOutlineEffect = EnsureSolidColorEffect(); // Set _blackOutlineEffect properties based on the user controls UpdateBlackOutlineEffectForOutlineThickness(); // Add another RenderObjectsRenderingStep that will render black scene ... _renderObjectOutlinesRenderingStep = EnsureRenderObjectsRenderingStep(dxScene); // ... and add it before standard RenderObjectsRenderingStep if (dxScene != null && !dxScene.RenderingSteps.Contains(_renderObjectOutlinesRenderingStep)) { dxScene.RenderingSteps.AddBefore(dxScene.DefaultRenderObjectsRenderingStep, _renderObjectOutlinesRenderingStep); } }
private void SetupObjectOutlinesRenderingStep() { // One way to show object outlines is to render the whole scene with black color (using SolidColorEffect) // and with expanding the geometry of each object in the direction of triangle normals (setting SolidColorEffect.OutlineThickness property) // Then the standard 3D scene is rendered on top of the black 3D scene. _blackOutlineEffect = new SolidColorEffect() { Color = Color4.Black, OverrideModelColor = true, // This will render all objects with Black color; when false then object's color is used OutlineThickness = 3, // Use the following 3 settings to show outline for the whole 3D scene: WriteMaxDepthValue = true, // the black objects will be written to the back of all the objects (using max depth value). OverrideRasterizerState = _mainDXViewportView.DXScene.DXDevice.CommonStates.CullNone // render front and back triangles }; _disposables.Add(_blackOutlineEffect); _blackOutlineEffect.InitializeResources(_mainDXViewportView.DXScene.DXDevice); // Add another RenderObjectsRenderingStep that will render black scene ... _renderObjectOutlinesRenderingStep = new RenderObjectsRenderingStep("RenderObjectOutlinesRenderingStep") { OverrideEffect = _blackOutlineEffect, FilterRenderingQueuesFunction = delegate(RenderingQueue queue) { return(queue != _mainDXViewportView.DXScene.LineGeometryRenderingQueue); // Render all objects except 3D lines } }; _disposables.Add(_blackOutlineEffect); // ... and add it before standard RenderObjectsRenderingStep _mainDXViewportView.DXScene.RenderingSteps.AddBefore(_mainDXViewportView.DXScene.DefaultRenderObjectsRenderingStep, _renderObjectOutlinesRenderingStep); // Uncomment the following line to prevent rendering standard 3D objects: //MainDXViewportView.DXScene.DefaultRenderObjectsRenderingStep.IsEnabled = false; }
private void OnDxSceneDeviceCreated(object sender, EventArgs e) { // // !!! IMPORTANT !!! // // Some rendering queues are being sorted by material. // This improves performance by rendering objects with similar material one after another and // this reduces number of DirectX state changes. // But when using ObjectId map, we need to disable rendering queues by material. // If this is not done, the objects rendered in the standard rendering pass and // objects rendered for object id map will be rendered in different order. // Because of this we would not be able to get the original object id from the back. // // Therefore go through all MaterialSortedRenderingQueue and disable sorting. // // Note the we do not need to disable sorting by camera distance (TransparentRenderingQueue) // because the object order does not change when rendering object id map. foreach (var materialSortedRenderingQueue in MainDXViewportView.DXScene.RenderingQueues.OfType <MaterialSortedRenderingQueue>()) { materialSortedRenderingQueue.IsSortingEnabled = false; } // Create a SolidColorEffect that will be used to render each objects with a color from object's id _solidColorEffect = new SolidColorEffect { // We will overwrite the object's color with color specified in SolidColorEffect.Color OverrideModelColor = true, // Always use Opaque blend state even if alpha is less then 1 (usually PremultipliedAlphaBlend is used in this case). // This will allow us to also use alpha component for the object id (in our case RenderingQueue id) OverrideBlendState = MainDXViewportView.DXScene.DXDevice.CommonStates.Opaque, // By default for alpha values less then 1, the color components are multiplied with alpha value to produce pre-multiplied colors. // This will allow us to also use alpha component for the object id (in our case RenderingQueue id) PremultiplyAlphaColors = false }; _disposables.Add(_solidColorEffect); MainDXViewportView.DXScene.DXDevice.EffectsManager.RegisterEffect(_solidColorEffect); // Create a custom rendering step that will be used instead of standard rendering step. // It will be used in the CreateObjectIdBitmapButton_OnClick method below _objectIdRenderingStep = new CustomActionRenderingStep("ObjectIdRenderingStep") { CustomAction = ObjectIdRenderingAction, IsEnabled = false // IMPORTANT: disable this custom rendering step - it will be enabled when rendering to bitmap }; MainDXViewportView.DXScene.RenderingSteps.AddAfter(MainDXViewportView.DXScene.DefaultRenderObjectsRenderingStep, _objectIdRenderingStep); // In this sample we render Object ids to a custom bitmap, // so for standard rendering, we disable our custom rendering. // But if you went you can enable it and disabled the standard rendering - this will always render objects ids: // //_objectIdRenderingStep.IsEnabled = true; //MainDXViewportView.DXScene.DefaultRenderObjectsRenderingStep.IsEnabled = false; }
private void SetupOutlineRenderingStep() { _solidColorEffectWithOutline = new SolidColorEffect(); _solidColorEffectWithOutline.Color = Colors.Orange.ToColor4(); _solidColorEffectWithOutline.OverrideModelColor = true; _solidColorEffectWithOutline.OutlineThickness = 0; _solidColorEffectWithOutline.WriteMaxDepthValue = false; _solidColorEffectWithOutline.InitializeResources(MainDXViewportView.DXScene.DXDevice); _disposables.Add(_solidColorEffectWithOutline); _backgroundColor = new Color4(1, 1, 1, 0); var stencilSetToOneDescription = new DepthStencilStateDescription() { IsDepthEnabled = true, DepthWriteMask = DepthWriteMask.All, DepthComparison = Comparison.LessEqual, IsStencilEnabled = true, StencilReadMask = 0xFF, StencilWriteMask = 0xFF, FrontFace = { Comparison = Comparison.Always, DepthFailOperation = StencilOperation.Keep, FailOperation = StencilOperation.Keep, PassOperation = StencilOperation.Replace // The value that is set as reference is set in the ContextStateManger when _deviceContext.OutputMerger.SetDepthStencilState is called - the value is set to 1. } }; stencilSetToOneDescription.BackFace = stencilSetToOneDescription.FrontFace; _stencilSetToOneDepthStencilState = new DepthStencilState(MainDXViewportView.DXScene.Device, stencilSetToOneDescription); if (MainDXViewportView.DXScene.DXDevice.IsDebugDevice) { _stencilSetToOneDepthStencilState.DebugName = "StencilSetToOneDepthStencilState"; } _disposables.Add(_stencilSetToOneDepthStencilState); var renderWhenStencilIsNotOneDescription = new DepthStencilStateDescription() { IsDepthEnabled = true, DepthWriteMask = DepthWriteMask.All, DepthComparison = Comparison.LessEqual, IsStencilEnabled = true, StencilReadMask = 0xFF, StencilWriteMask = 0xFF, FrontFace = { Comparison = Comparison.Greater, // render only when 1 is greater then stencil value DepthFailOperation = StencilOperation.Keep, FailOperation = StencilOperation.Keep, PassOperation = StencilOperation.Keep } }; renderWhenStencilIsNotOneDescription.BackFace = stencilSetToOneDescription.FrontFace; _renderWhenStencilIsNotOneState = new DepthStencilState(MainDXViewportView.DXScene.Device, renderWhenStencilIsNotOneDescription); if (MainDXViewportView.DXScene.DXDevice.IsDebugDevice) { _renderWhenStencilIsNotOneState.DebugName = "RenderWhenStencilIsNotOneState"; } _disposables.Add(_renderWhenStencilIsNotOneState); var renderingStepsGroup = new RenderingStepsGroup("Render outline group", MainDXViewportView.DXScene.RenderingSteps); renderingStepsGroup.BeforeRunningStep += (object sender, DirectX.RenderingEventArgs args) => { var renderingContext = args.RenderingContext; // Set new back buffer where we will render outline objects SetupOutlineBackBuffers(renderingContext); // Set new DepthStencilState that will also set stencil value to 1 for each rendered pixel renderingContext.ContextStatesManager.DepthStencilState = _stencilSetToOneDepthStencilState; _addOutlineRenderingStep.SourceTexture = _outlineShaderResourceView; }; renderingStepsGroup.AfterRunningStep += (object sender, DirectX.RenderingEventArgs args) => { var renderingContext = args.RenderingContext; // Reset the saved back buffer RestoreBackBuffers(renderingContext); }; // The first step in rendering outlines is to render selected objects with the selected solid color. // This is done with creating a custom RenderObjectsRenderingStep // and overriding the OverrideEffect to use SolidColorEffect and _stencilSetToOneDepthStencilState. // We also render only the selected objects - this is done with using FilterObjectsFunction. var renderOutlinesObjectsRenderingStep = new RenderObjectsRenderingStep("Render outlined objects") { OverrideEffect = _solidColorEffectWithOutline, OverrideDepthStencilState = _stencilSetToOneDepthStencilState, FilterObjectsFunction = delegate(RenderablePrimitiveBase objectToRender) { // IMPORTANT: // This delegate is highly performance critical because it is called for each object in each frame. // Therefore do not access any WPF's DependencyProperties there. var wpfGeometryModel3DNode = objectToRender.OriginalObject as WpfGeometryModel3DNode; if (wpfGeometryModel3DNode == null) { return(false); } // NOTE: // Here we do a simple check for object name in a List<string>. // If you have a lot of selected objects, use HashSet<string> instead. // // The reason why the check is done by the object name is that this way // we can simply connect the WPF object (that is selected) and the SceneNode object that is created from the WPF object. // So if we define the name for the WPF objects, then the SceneNode objects that are created from them will also have the same name. // // But if it is not possible to name WPF objects of if you have duplicate names, // then you will need to store SceneNode objects in HashSet instead of object names. // // To use this we need to get the SceneNode instances that are created from WPF objects. // One option is to call MainDXViewportView.GetSceneNodeForWpfObject(wpfObject) for each WPF object (this must be called after the SceneNodes are initialized - for example in DXSceneInitialized). // Another option is to wait until SceneNodes are created from WPF objects (in DXSceneInitialized event handler or if the scene was already created after calling MainDXViewportView.Update()). // Then go through all SceneNodes in the hierarchy (you can use MainDXViewportView.DXScene.RootNode.ForEachChildNode method) // and for each WpfGeometryModel3DNode gets its GeometryModel3D and build a Dictionary with WPF (GeometryModel3D) and SceneNode (WpfGeometryModel3DNode) objects. // Then when you select for which WPF objects you want to draw outline, create a HashSet<WpfGeometryModel3DNode> with list of WpfGeometryModel3DNode objects. return(_selectedObjectNames.Contains(wpfGeometryModel3DNode.Name)); } }; renderingStepsGroup.Children.Add(renderOutlinesObjectsRenderingStep); // Add two ExpandPostProcess that will make the outline bigger int outlineWidth = (int)OutlineSizeSlider.Value; _horizontalExpandPostProcess = new Ab3d.DirectX.PostProcessing.ExpandPostProcess(isVerticalRenderingPass: false, expansionWidth: outlineWidth, backgroundColor: _backgroundColor); _verticalExpandPostProcess = new Ab3d.DirectX.PostProcessing.ExpandPostProcess(isVerticalRenderingPass: true, expansionWidth: outlineWidth, backgroundColor: _backgroundColor); _disposables.Add(_horizontalExpandPostProcess); _disposables.Add(_verticalExpandPostProcess); var expandPostProcesses = new List <PostProcessBase>(); expandPostProcesses.Add(_horizontalExpandPostProcess); expandPostProcesses.Add(_verticalExpandPostProcess); // We could also blur the outline to make it bigger, but Expand creates better results //var horizontalBlurPostProcess = new Ab3d.DirectX.PostProcessing.SimpleBlurPostProcess(isVerticalBlur: false, filterWidth: 5); //var verticalBlurPostProcess = new Ab3d.DirectX.PostProcessing.SimpleBlurPostProcess(isVerticalBlur: true, filterWidth: 5); //horizontalBlurPostProcess.InitializeResources(MainDXViewportView.DXScene.DXDevice); //verticalBlurPostProcess.InitializeResources(MainDXViewportView.DXScene.DXDevice); //blurPostProcesses.Add(horizontalBlurPostProcess); //blurPostProcesses.Add(verticalBlurPostProcess); _expandObjectsPostProcessesRenderingSteps = new RenderPostProcessingRenderingStep("Expand objects rendering step", expandPostProcesses); renderingStepsGroup.Children.Add(_expandObjectsPostProcessesRenderingSteps); MainDXViewportView.DXScene.RenderingSteps.AddAfter(MainDXViewportView.DXScene.DefaultInitializeRenderingStep, renderingStepsGroup); _addOutlineRenderingStep = new RenderTextureRenderingStep(RenderTextureRenderingStep.TextureChannelsCount.FourChannels, "Render outline over 3D scene") { Offsets = new Vector4(0, 0, 0, 0), // preserve original colors Factors = new Vector4(1, 1, 1, 1), TargetViewport = new ViewportF(0, 0, 1f, 1f), // render to full screen CustomBlendState = MainDXViewportView.DXScene.DXDevice.CommonStates.NonPremultipliedAlphaBlend, // alpha blend CustomDepthStencilState = _renderWhenStencilIsNotOneState, // only render when stencil value is less then 1 (not where the objects are rendered) }; _addOutlineRenderingStep.BeforeRunningStep += delegate(object sender, DirectX.RenderingEventArgs args) { var renderingContext = args.RenderingContext; renderingContext.SetBackBuffer(renderingContext.CurrentBackBuffer, renderingContext.CurrentBackBufferDescription, renderingContext.CurrentRenderTargetView, _outlineDepthStencilView, false); //renderingContext.DeviceContext.OutputMerger.SetTargets(_outlineDepthStencilView, renderingContext.CurrentRenderTargetView); }; MainDXViewportView.DXScene.RenderingSteps.AddBefore(MainDXViewportView.DXScene.DefaultCompleteRenderingStep, _addOutlineRenderingStep); }
private void SetupExpandPostProcessOutlines() { var dxScene = MainDXViewportView.DXScene; _blackOutlineEffect = EnsureSolidColorEffect(); if (_blackOutlineEffect == null) { return; } // Reset values that may be changed when using SolidColorEffectWithOutlines _blackOutlineEffect.DepthBias = 0; _blackOutlineEffect.OverrideRasterizerState = null; _blackOutlineEffect.OutlineThickness = 0; _blackOutlineEffect.WriteMaxDepthValue = true; _renderObjectOutlinesRenderingStep = EnsureRenderObjectsRenderingStep(dxScene); if (!dxScene.RenderingSteps.Contains(_renderObjectOutlinesRenderingStep)) { dxScene.RenderingSteps.AddBefore(dxScene.DefaultRenderObjectsRenderingStep, _renderObjectOutlinesRenderingStep); } int outlineWidth = (int)OutlineWidthComboBox.SelectedItem; if (_prepareExpandObjectsPostProcessingRenderingStep == null) { // Expand post process is done in two passes (one horizontal and one vertical) _horizontalExpandPostProcess = new Ab3d.DirectX.PostProcessing.ExpandPostProcess(isVerticalRenderingPass: false, expansionWidth: outlineWidth, backgroundColor: dxScene.BackgroundColor); _verticalExpandPostProcess = new Ab3d.DirectX.PostProcessing.ExpandPostProcess(isVerticalRenderingPass: true, expansionWidth: outlineWidth, backgroundColor: dxScene.BackgroundColor); _disposables.Add(_horizontalExpandPostProcess); _disposables.Add(_verticalExpandPostProcess); var expandPostProcesses = new PostProcessBase[] { _horizontalExpandPostProcess, _verticalExpandPostProcess }; // To execute the post processes we need to rendering steps: // 1) PreparePostProcessingRenderingStep that creates required RenderTargets and ShaderResourceViews and sets that to the RenderPostProcessingRenderingStep // 2) RenderPostProcessingRenderingStep that actually executed all the post-processes // Because we will execute post-processes before the standard scene rendering, // we also need to make sure that the Destination buffer is correctly set (see _prepareExandObjectsPostProcessingRenderingStep.BeforeRunningStep) // and that the DepthStencilView is reset after the post-processes are rendered (see _expandObjectsPostProcessesRenderingSteps.AfterRunningStep). // First create the RenderPostProcessingRenderingStep because it is needed in the constructor of the PreparePostProcessingRenderingStep _expandObjectsPostProcessesRenderingSteps = new RenderPostProcessingRenderingStep("Expand objects rendering step", expandPostProcesses); _expandObjectsPostProcessesRenderingSteps.AfterRunningStep += delegate(object sender, RenderingEventArgs args) { // Post-processes are usually executed at the end of rendering process and work on 2D textures so they do not require DepthStencil. // The CurrentBackBuffer / Description and RenderTargetView are already correct because they are sent by PreparePostProcessingRenderingStep, // but we need to set the _savedDepthStencilView and SupersamplingCount. args.RenderingContext.SetBackBuffer(args.RenderingContext.CurrentBackBuffer, args.RenderingContext.CurrentBackBufferDescription, args.RenderingContext.CurrentRenderTargetView, _savedDepthStencilView, dxScene.SupersamplingCount, bindNewRenderTargetsToDeviceContext: true); }; _disposables.Add(_expandObjectsPostProcessesRenderingSteps); _prepareExpandObjectsPostProcessingRenderingStep = new PreparePostProcessingRenderingStep(_expandObjectsPostProcessesRenderingSteps, "Prepare expand post process"); _prepareExpandObjectsPostProcessingRenderingStep.BeforeRunningStep += delegate(object sender, RenderingEventArgs args) { // Because after the post-processes are executed we will continue with rendering the scene, // we need to set the DestinationBackBuffer (there will be the final result of the post-processes) // to the currently used BackBuffer. If this is not done, then RenderingContext.FinalBackBuffer is used as destination back buffer. _prepareExpandObjectsPostProcessingRenderingStep.SetCustomDestinationBackBuffer(args.RenderingContext.CurrentBackBuffer, args.RenderingContext.CurrentBackBufferDescription, args.RenderingContext.CurrentRenderTargetView); // Save CurrentDepthStencilView _savedDepthStencilView = args.RenderingContext.CurrentDepthStencilView; }; _disposables.Add(_prepareExpandObjectsPostProcessingRenderingStep); } else { _horizontalExpandPostProcess.ExpansionWidth = outlineWidth; _verticalExpandPostProcess.ExpansionWidth = outlineWidth; } if (!dxScene.RenderingSteps.Contains(_prepareExpandObjectsPostProcessingRenderingStep)) { dxScene.RenderingSteps.AddAfter(_renderObjectOutlinesRenderingStep, _prepareExpandObjectsPostProcessingRenderingStep); dxScene.RenderingSteps.AddAfter(_prepareExpandObjectsPostProcessingRenderingStep, _expandObjectsPostProcessesRenderingSteps); } }