private void CreateAndBindTargets(int sizeX, int sizeY) { _d3dImageSource.SetRenderTargetDX10(null); Disposer.RemoveAndDispose(ref _renderTargetView); Disposer.RemoveAndDispose(ref _renderTargetIntermediateView); Disposer.RemoveAndDispose(ref _renderTargetIntermediateShaderResourceView); Disposer.RemoveAndDispose(ref _depthStencilView); Disposer.RemoveAndDispose(ref _renderTarget); Disposer.RemoveAndDispose(ref _renderTargetIntermediate); Disposer.RemoveAndDispose(ref _depthStencil); Disposer.RemoveAndDispose(ref _gammaCorrector); if (sizeX >= 2 && sizeY >= 2) { var colordesc = new Texture2DDescription { BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource, Format = Format.B8G8R8A8_UNorm, Width = sizeX, Height = sizeY, MipLevels = 1, SampleDescription = new SampleDescription(1, 0), Usage = ResourceUsage.Default, OptionFlags = ResourceOptionFlags.Shared, CpuAccessFlags = CpuAccessFlags.None, ArraySize = 1 }; var renderTextureDescriptionForD3D9 = new Texture2DDescription { BindFlags = BindFlags.None, Format = Format.B8G8R8A8_UNorm, Width = sizeX, Height = sizeY, MipLevels = 1, SampleDescription = new SampleDescription(1, 0), Usage = ResourceUsage.Staging, OptionFlags = ResourceOptionFlags.Shared, CpuAccessFlags = CpuAccessFlags.Read, ArraySize = 1 }; var depthdesc = new Texture2DDescription { BindFlags = BindFlags.DepthStencil, Format = Format.D32_Float_S8X24_UInt, Width = sizeX, Height = sizeY, MipLevels = 1, SampleDescription = new SampleDescription(1, 0), Usage = ResourceUsage.Default, OptionFlags = ResourceOptionFlags.None, CpuAccessFlags = CpuAccessFlags.None, ArraySize = 1, }; _renderTarget = new Texture2D(_device, colordesc); _renderTargetIntermediate = new Texture2D(_device, colordesc); _depthStencil = new Texture2D(_device, depthdesc); _renderTargetIntermediateView = new RenderTargetView(_device, _renderTargetIntermediate); _renderTargetIntermediateShaderResourceView = new ShaderResourceView(_device, _renderTargetIntermediate); _renderTargetView = new RenderTargetView(_device, _renderTarget); _depthStencilView = new DepthStencilView(_device, _depthStencil); _gammaCorrector = new D3D10GammaCorrector(_device, "Altaxo.CompiledShaders.Effects.GammaCorrector.cso"); _d3dImageSource.SetRenderTargetDX10(_renderTarget); } }
/// <summary> /// Saves the project item as image to the provided stream. /// </summary> /// <param name="item">The item to export, for instance an item of type <see cref="Altaxo.Graph.Gdi.GraphDocument"/> or <see cref="Altaxo.Graph.Graph3D.GraphDocument"/>.</param> /// <param name="options">The export options.</param> /// <param name="toStream">The stream to save the image to.</param> public (int PixelsX, int PixelsY) ExportAsImageToStream(Altaxo.Main.IProjectItem item, Altaxo.Graph.Gdi.GraphExportOptions options, System.IO.Stream toStream) { // SharpDX.Configuration.EnableObjectTracking = true; // var listOfActiveObjects = SharpDX.Diagnostics.ObjectTracker.FindActiveObjects(); if (item == null) { throw new ArgumentNullException(nameof(item)); } if (!(item is Altaxo.Graph.Graph3D.GraphDocument)) { throw new ArgumentException(string.Format("Expected item of type {0}, but it is of type {1}", typeof(Altaxo.Graph.Graph3D.GraphDocument), item.GetType())); } var doc = (Altaxo.Graph.Graph3D.GraphDocument)item; double sourceDpi = options.SourceDpiResolution; Viewing.D3D10Scene scene = null; D3D10GraphicsContext g = null; try { scene = new Viewing.D3D10Scene(); g = new D3D10GraphicsContext(); doc.Paint(g); var matrix = doc.Camera.LookAtRHMatrix; var rect = new RectangleD3D(PointD3D.Empty, doc.RootLayer.Size); var bounds = RectangleD3D.NewRectangleIncludingAllPoints(rect.Vertices.Select(x => matrix.Transform(x))); int pixelsX = (int)Math.Ceiling(sourceDpi * bounds.SizeX / 72.0); pixelsX = (int)(4 * Math.Ceiling((pixelsX + 3) / 4.0)); int pixelsY = (int)(sourceDpi * bounds.SizeY / 72.0); double aspectRatio = pixelsY / (double)pixelsX; var sceneCamera = doc.Camera; if (sceneCamera is OrthographicCamera) { var orthoCamera = (OrthographicCamera)sceneCamera; orthoCamera = (OrthographicCamera)orthoCamera.WithWidthAtZNear(bounds.SizeX); double offsX = -(1 + 2 * bounds.X / bounds.SizeX); double offsY = -(1 + 2 * bounds.Y / bounds.SizeY); sceneCamera = orthoCamera.WithScreenOffset(new PointD2D(offsX, offsY)); } else if (sceneCamera is PerspectiveCamera) { var viewProj = sceneCamera.GetViewProjectionMatrix(1); // here we transform the points with AspectRatio=1, in order to get the AspectRatio of the ScreenBounds var screenBounds = RectangleD3D.NewRectangleIncludingAllPoints(rect.Vertices.Select(x => viewProj.Transform(x))); aspectRatio = screenBounds.SizeY / screenBounds.SizeX; // this is the aspectRatio of our image viewProj = sceneCamera.GetViewProjectionMatrix(aspectRatio); // now we get the transform with our aspectRatio determined above screenBounds = RectangleD3D.NewRectangleIncludingAllPoints(rect.Vertices.Select(x => viewProj.Transform(x))); // this are our actual screenBounds, of course in relative screen coordinates, thus the ratio of sizeX and sizeY should now be 1 double scaleFactor = 2 / screenBounds.SizeX; // since SizeX and SizeY should now be the same, we could have used SizeY alternatively double offsX = -(1 + scaleFactor * screenBounds.X); double offsY = -(1 + scaleFactor * screenBounds.Y); pixelsY = (int)(4 * Math.Ceiling((aspectRatio * pixelsX + 3) / 4.0)); // now calculate the size of the image in y direction from the aspectRatio var perspCamera = (PerspectiveCamera)sceneCamera; sceneCamera = perspCamera.WithWidthAtZNear(perspCamera.WidthAtZNear / scaleFactor); sceneCamera = sceneCamera.WithScreenOffset(new PointD2D(offsX, offsY)); } else { throw new NotImplementedException(); } scene.SetCamera(sceneCamera); scene.SetLighting(doc.Lighting); scene.SetDrawing(g); Export(pixelsX, pixelsY, scene, options, toStream); return(pixelsX, pixelsY); } finally { Disposer.RemoveAndDispose(ref g); Disposer.RemoveAndDispose(ref scene); } }
private static void EndD3D() { Disposer.RemoveAndDispose(ref D3D10ImageSource._d3DDevice); Disposer.RemoveAndDispose(ref D3D10ImageSource._d3DContext); }
public void Export(int sizeX, int sizeY, ID3D10Scene scene, Altaxo.Graph.Gdi.GraphExportOptions options, System.IO.Stream toStream) { Device device = null; Texture2D renderTarget = null; Texture2D renderTarget2 = null; Texture2D depthStencil = null; RenderTargetView renderTargetView = null; DepthStencilView depthStencilView = null; try { //device = new Device(DriverType.Hardware, DeviceCreationFlags.BgraSupport, FeatureLevel.Level_10_0); device = D3D10DeviceFactory.Instance.BorrowDevice(); // try to get the highest MSAA level with the highest quality int sampleCount = 32; int qlevel_sampleCount = 0; for (; sampleCount >= 0; sampleCount /= 2) { if (0 != (qlevel_sampleCount = device.CheckMultisampleQualityLevels(Format.B8G8R8A8_UNorm, sampleCount))) // quality level for sample count { break; } } var colordesc = new Texture2DDescription { BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource, Format = Format.B8G8R8A8_UNorm_SRgb, Width = sizeX, Height = sizeY, MipLevels = 1, SampleDescription = new SampleDescription(sampleCount, qlevel_sampleCount - 1), Usage = ResourceUsage.Default, OptionFlags = ResourceOptionFlags.Shared, CpuAccessFlags = CpuAccessFlags.None, ArraySize = 1 }; var depthdesc = new Texture2DDescription { BindFlags = BindFlags.DepthStencil, Format = Format.D32_Float_S8X24_UInt, Width = sizeX, Height = sizeY, MipLevels = 1, SampleDescription = new SampleDescription(sampleCount, qlevel_sampleCount - 1), Usage = ResourceUsage.Default, OptionFlags = ResourceOptionFlags.None, CpuAccessFlags = CpuAccessFlags.None, ArraySize = 1, }; renderTarget = new Texture2D(device, colordesc); depthStencil = new Texture2D(device, depthdesc); renderTargetView = new RenderTargetView(device, renderTarget); depthStencilView = new DepthStencilView(device, depthStencil); // Rendering device.OutputMerger.SetTargets(depthStencilView, renderTargetView); device.Rasterizer.SetViewports(new Viewport(0, 0, sizeX, sizeY, 0.0f, 1.0f)); var clearColor = new Color4(1, 1, 1, 0); // Transparent if (options.BackgroundBrush != null) { var axoColor = options.BackgroundBrush.Color.Color; clearColor = new Color4(axoColor.ScR, axoColor.ScG, axoColor.ScB, axoColor.ScA); } device.ClearRenderTargetView(renderTargetView, clearColor); device.ClearDepthStencilView(depthStencilView, DepthStencilClearFlags.Depth | DepthStencilClearFlags.Stencil, 1.0f, 0); scene.Attach(device, new PointD2D(sizeX, sizeY)); scene.Render(); device.Flush(); scene.Detach(); if (sampleCount > 1) // if renderTarget is an MSAA render target, we first have to copy it into a non-MSAA render target before we can copy it to a CPU texture and then hope to save it { // create a non-MSAA render target with the same size var renderTarget2Description = new Texture2DDescription { BindFlags = BindFlags.RenderTarget | BindFlags.ShaderResource, Format = Format.B8G8R8A8_UNorm_SRgb, Width = sizeX, Height = sizeY, MipLevels = 1, SampleDescription = new SampleDescription(1, 0), // non MSAA Usage = ResourceUsage.Default, OptionFlags = ResourceOptionFlags.Shared, CpuAccessFlags = CpuAccessFlags.None, ArraySize = 1 }; renderTarget2 = new Texture2D(device, renderTarget2Description); // create non-MSAA render target device.ResolveSubresource(renderTarget, 0, renderTarget2, 0, renderTarget.Description.Format); // copy from MSAA render target to the non-MSAA render target var h = renderTarget; // exchange renderTarget with renderTarget2 renderTarget = renderTarget2; renderTarget2 = h; } // renderTarget is now a non-MSAA renderTarget Texture2DExtensions.SaveToStream(renderTarget, options.ImageFormat, options.DestinationDpiResolution, toStream); } finally { Disposer.RemoveAndDispose(ref depthStencilView); Disposer.RemoveAndDispose(ref renderTargetView); Disposer.RemoveAndDispose(ref renderTarget2); Disposer.RemoveAndDispose(ref renderTarget); Disposer.RemoveAndDispose(ref depthStencil); device.ClearState(); D3D10DeviceFactory.Instance.PassbackDevice(ref device); //device.QueryInterface<DeviceDebug>().ReportLiveDeviceObjects(ReportingLevel.Summary) // Disposer.RemoveAndDispose(ref device); //var activeObjects = SharpDX.Diagnostics.ObjectTracker.FindActiveObjects(); } }