精华内容
参与话题
问答
  • SharpDx

    2019-11-21 16:06:59
    layout category title permalink posts_by_category SharpDX SharpDX 系列 /post/sharpdx
        
    layout category title permalink
    posts_by_category
    SharpDX
    SharpDX 系列
    /post/sharpdx
    展开全文
  • SharpDX, SharpDX GitHub知识库 SharpDX 官方网站:sharpdx.orgSharpDX是一个开源项目,为所有 Windows 平台提供 DirectX,允许开发高性能游戏。2D 和 3D 图形渲染以及实时声音应用。下载所有SharpDX软件包均可
  • sharpdx demo

    2018-11-19 11:05:58
    sharpdx demo (sharpdx-examples-master zip)
  • <div><p>Hi, I want to combine D3D11Image with SharpDX. I think it should be possible but I can not figure out how to properly implement OnRender handler. In Render event handler I receive IntPtr. Can ...
  • <div><p>There are a variety of features in SharpGenTools that were only used by SharpDX. Now that SharpDX is unmaintained, it would be nice for code cleanliness to remove some of the more obscure ...
  • SharpDX-Samples, 所有SharpDX示例的官方存储库 SharpDX示例这个库包含使用 SharpDX插件( github )的超过 100个代码示例这些示例的目的在于掌握每个 API/平台,以及如何从 C# 访问 DirectX API 。免责声明:这里所有...
  • WPF 使用 SharpDX

    千次阅读 2018-08-27 16:30:12
    本文告诉大家如何在 WPF 使用 SharpDX ,只是入门

    本文告诉大家如何在 WPF 使用 SharpDX ,只是入门

    本文是一个系列

    先介绍一下 SharpDx ,一个底层封装的 DirectX 库,支持 AnyCpu ,支持 Direct3D9, Direct3D11, Direct3D12,Direct2D1。支持 win32 程序和商店程序。

    环境

    需要 .NET 4.5 和以上的环境才可以使用。

    安装

    首先安装 SharpDX 的库,需要安装下面几个库

    创建工厂

    使用 SharpDX 和 DirectX 一样,开始都需要创建工厂,然后创建RenderTarget,之后才可以显示基础图形。

    先引用命名

    using D2D = SharpDX.Direct2D1;
    using WIC = SharpDX.WIC;
    using DW = SharpDX.DirectWrite;
    using DXGI = SharpDX.DXGI;

    需要在 Loaded 之后添加代码

                    var factory = new D2D.Factory();
    

    创建 RenderTarget

    创建 RenderTarget 可以尝试 WindowRenderTarget ,因为是入门博客,我不告诉大家如何使用其他几个 RenderTarget ,如果想知道,请自己多去看博客。

    创建 WindowRenderTarget 需要参数 RenderTargetProperties ,HwndRenderTargetProperties。所以需要先创建这两个。

    创建 RenderTargetProperties 需要参数 PixelFormat ,请看下面

                    var pixelFormat = new D2D.PixelFormat(DXGI.Format.B8G8R8A8_UNorm, D2D.AlphaMode.Straight);
    
                    var renderTargetProperties = new D2D.RenderTargetProperties(D2D.RenderTargetType.Default, pixelFormat,
                        96, 96, D2D.RenderTargetUsage.None, D2D.FeatureLevel.Level_DEFAULT);

    RenderTargetProperties 需要的参数是 RenderTargetType ,PixelFormat,dpiX,dpiY,RenderTargetUsage,FeatureLevel,参数大家看命名就知道是做什么的,在这里就不告诉大家。

    创建 HwndRenderTargetProperties 请看下面代码

                    var hwndRenderTargetProperties = new D2D.HwndRenderTargetProperties();
                    hwndRenderTargetProperties.Hwnd = new WindowInteropHelper(this).Handle;

    现在尝试创建 RenderTarget 请看代码

                   var renderTarget = new D2D.WindowRenderTarget(factory, renderTargetProperties, hwndRenderTargetProperties);

    因为需要拿到 RenderTarget 进行画基础图形,一般把 RenderTarget 放在字段。

            public MainWindow()
            {
                InitializeComponent();
    
                Loaded += (s, e) =>
                {
                    var factory = new D2D.Factory();
    
                    var pixelFormat = new D2D.PixelFormat(DXGI.Format.B8G8R8A8_UNorm, D2D.AlphaMode.Straight);
    
                    var hwndRenderTargetProperties = new D2D.HwndRenderTargetProperties();
                    hwndRenderTargetProperties.Hwnd = new WindowInteropHelper(this).Handle;
                    hwndRenderTargetProperties.Hwnd = new WindowInteropHelper(this).Handle;
                    hwndRenderTargetProperties.PixelSize = new Size2((int)ActualWidth, (int)ActualHeight);
    
                    var renderTargetProperties = new D2D.RenderTargetProperties(D2D.RenderTargetType.Default, pixelFormat,
                        96, 96, D2D.RenderTargetUsage.None, D2D.FeatureLevel.Level_DEFAULT);
    
                    _renderTarget = new D2D.WindowRenderTarget(factory, renderTargetProperties, hwndRenderTargetProperties);
                };
            }
    
            private D2D.RenderTarget _renderTarget;

    这里的 PixelFormat 使用 B8G8R8A8_UNorm 的意思是每个元素包含4个8位无符号分量,分量的取值范围在[0,1]区间内的浮点数,因为不是任何类型的数据都能存储到纹理中的,纹理只支持特定格式的数据存储。这里的 BGRA 的意思分别是 蓝色(Blue)、绿色(Green)、红色(Red)和 alpha(透明度),其他可以选的格式

    • DXGI_FORMAT_R32G32B32_FLOAT:每个元素包含3个32位浮点分量。
    • DXGI_FORMAT_R16G16B16A16_UNORM:每个元素包含4个16位分量,分量的取值范围在[0,1]区间内。
    • DXGI_FORMAT_R32G32_UINT:每个元素包含两个32位无符号整数分量。
    • DXGI_FORMAT_R8G8B8A8_UNORM:每个元素包含4个8位无符号分量,分量的取值范围在[0,1]区间内的浮点数。
    • DXGI_FORMAT_R8G8B8A8_SNORM:每个元素包含4个8位有符号分量,分量的取值范围在[−1,1] 区间内的浮点数。
    • DXGI_FORMAT_R8G8B8A8_SINT:每个元素包含4个8位有符号整数分量,分量的取值范围在[−128, 127] 区间内的整数。
    • DXGI_FORMAT_R8G8B8A8_UINT:每个元素包含4个8位无符号整数分量,分量的取值范围在[0, 255]区间内的整数

    更多概念请看DirectX11 Direct3D基本概念 - CSDN博客

    画圈

    现在就和 WPF 使用 Direct2D1 画图入门 差不多方法来画圈,如何可以画出来,那么就是成功使用 SharpDX 。不要问我为什么用画圈来判断是否可以使用 SharpDX,因为在所有基础的 draw 只有椭圆最耗性能。

    还是使用 CompositionTarget 来知道什么时候刷新,在函数添加下面代码

                CompositionTarget.Rendering += CompositionTarget_Rendering;
    
            private void CompositionTarget_Rendering(object sender, EventArgs e)
            {
            }

    因为画椭圆需要三个参数,第一个是 D2D.Ellipse ,第二个是 Brush ,第三个是线条宽度。

    因为 Brush 需要使用刚才的工厂创建,如果不使用工厂创建会异常

    先创建 SolidColorBrush 然后创建 D2D.Ellipse

                var ellipse = new D2D.Ellipse(new RawVector2(100,100),10,10 );
    
                var brush = new D2D.SolidColorBrush(_renderTarget, new RawColor4(1, 0, 0, 1));

    Ellipse 的三个参数是圆心和两个半径,上面是画出半径是 10 的圆。

    RawColor4 就是 rgba ,颜色是从 0 到 1 ,对应 WPF 的 RGB 从 0 到 255 ,所以需要转换。

    准备好几个参数,可以尝试画出来,在画之前需要使用 BeginDraw 。为什么需要调用这个函数,因为实际上调用 Draw 是不会立刻画出来,而是创建绘制命令,如果渲染是 CPU 渲染,那么就会根据命令让 CPU 在内存渲染。如果渲染 GPU 渲染,就会把命令发到 GPU ,让他渲染。

            private void CompositionTarget_Rendering(object sender, EventArgs e)
            {
                var ellipse = new D2D.Ellipse(new RawVector2(100, 100), 10, 10);
    
                var brush = new D2D.SolidColorBrush(_renderTarget, new RawColor4(1, 0, 0, 1));
                _renderTarget.BeginDraw();
    
                _renderTarget.DrawEllipse(ellipse, brush, 1);
    
                _renderTarget.EndDraw();
            }

    重新告诉大家如何画出。首先拿到窗口,在 WPF 能创建的 WindowRenderTarget 最简单是拿到窗口。因为通过几个属性设置如何渲染,在哪渲染,所以还需要多使用几个属性才可以创建 D2D.WindowRenderTarget 。因为需要一个时机对 WindowRenderTarget 画出,所以我就使用 CompositionTarget 对他进行画出。

    我搭建了自己的博客 https://lindexi.gitee.io/ 欢迎大家访问,里面有很多新的博客。只有在我看到博客写成熟之后才会放在csdn或博客园,但是一旦发布了就不再更新

    如果在博客看到有任何不懂的,欢迎交流,我搭建了 dotnet 职业技术学院 欢迎大家加入

    知识共享许可协议
    本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接:http://blog.csdn.net/lindexi_gd ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系

    展开全文
  • 我使用了SharpDX的示例创建SwapChain用于在屏幕上显示。 ```C# public static D2D.RenderTarget Target { get; private set; } public readonly Device device; public bool isFormClosed = false; private ...
  • 本文告诉大家如何在控制台使用 SharpDx 创建窗口,这是一个底层的博客,我会用很多博客告诉大家如何从控制台创建一个高性能渲染程序

    本文告诉大家如何在控制台使用 SharpDx 创建窗口,这是一个底层的博客,我会用很多博客告诉大家如何从控制台创建一个高性能渲染程序

    如果想看更多关于底层渲染的博客,请点击渲染系列

    首先创建一个控制台程序,选择 dotnet framework 为 4.5 这样就可以保证下面安装的库可以使用

    在这里插入图片描述

    下载

    最好是使用 VisualStudio 2017项目格式,这样就可以直接复制下面代码放在自己的项目文件,就可以快速使用 Nuget 安装而不是需要等待 VisualStudio 的安装

    <Project Sdk="Microsoft.NET.Sdk">
      <PropertyGroup>
        <OutputType>Exe</OutputType>
        <TargetFramework>net45</TargetFramework>
      </PropertyGroup>
      <ItemGroup>
        <PackageReference Include="SharpDX" Version="4.1.0" />
        <PackageReference Include="SharpDX.D3DCompiler" Version="4.1.0" />
        <PackageReference Include="SharpDX.Desktop" Version="3.1.1" />
        <PackageReference Include="SharpDX.Direct2D1" Version="4.1.0" />
        <PackageReference Include="SharpDX.Direct3D11" Version="4.1.0" />
        <PackageReference Include="SharpDX.DXGI" Version="4.1.0" />
      </ItemGroup>
      <ItemGroup>
        <Folder Include="Properties\" />
      </ItemGroup>
    </Project>
    

    如果使用的不是 VisualStudio 2017 的就通过 Nuget 安装下面几个库

    • SharpDX
    • SharpDX.D3DCompiler
    • SharpDX.Desktop
    • SharpDX.Direct2D1
    • SharpDX.Direct3D11
    • SharpDX.DXGI

    创建窗口

    首先创建一个简单的类,这个类主要使用 RenderForm 来创建窗口

       class KikuSimairme 
        {
            private RenderForm _renderForm;
    
            private const int Width = 1280;
            private const int Height = 720;
    
           
        }
    

    这个类的主要就是 RenderForm ,在使用的时候需要引用

    using SharpDX.Windows;
    
    

    现在还没有创建好窗口,需要在构造函数使用这个代码

            public KikuSimairme()
            {
                _renderForm = new RenderForm();
                _renderForm.ClientSize = new Size(Width, Height);
            }
    

    如果是在 WPF 创建一个窗口,除了创建还需要显示,下面来告诉大家如何显示窗口

    KikuSimairme添加两个方法

            public void Run()
            {
                RenderLoop.Run(_renderForm, RenderCallback);
            }
    
            private void RenderCallback()
            {
    
            }
    

    这样就可以在调用 Run 显示窗口,因为创建窗口需要开启循环,使用 RenderLoop.Run 就可以

    在不使用这个窗口时需要记得去掉

        class KikuSimairme : IDisposable
        {
        	// 其他代码
        	public void Dispose()
            {
                _renderForm?.Dispose();
            }
        }
    

    在 Main 函数创建类,然后显示窗口

            static void Main(string[] args)
            {
                using (var temp = new KikuSimairme())
                {
                    temp.Run();
                }
            }
    

    现在按下运行就可以看到显示了一个窗口

    虽然里面还没什么东西,但是已经可以显示窗口,在窗口里面也就可以进行画东西。以前很少在一个控制台创建窗口,现在使用 sharpDx 可以很简单在控制台创建窗口

    这是KikuSimairme类的全部代码

        class KikuSimairme : IDisposable
        {
            /// <inheritdoc />
            public KikuSimairme()
            {
                _renderForm = new RenderForm();
                _renderForm.ClientSize = new Size(Width, Height);
            }
    
            private const int Width = 1280;
    
            private const int Height = 720;
    
            public void Run()
            {
                RenderLoop.Run(_renderForm, RenderCallback);
            }
    
            private RenderForm _renderForm;
    
            private void RenderCallback()
            {
            }
    
            /// <inheritdoc />
            public void Dispose()
            {
                _renderForm?.Dispose();
            }
        }
    
    

    虽然已经创建窗口,但是现在还没有内容,在下一篇C# 从零开始写 SharpDx 应用 初始化dx修改颜色,我将会告诉大家如何在这个窗口修改颜色。更多SharpDx博客请到SharpDX 系列

    参见:SharpDX Beginners Tutorial Part 1: Setting up a SharpDX project in Visual Studio 2013 - Johan Falk

    下一篇 C# 从零开始写 SharpDx 应用 初始化dx修改颜色

    我搭建了自己的博客 https://lindexi.gitee.io/ 欢迎大家访问,里面有很多新的博客。只有在我看到博客写成熟之后才会放在csdn或博客园,但是一旦发布了就不再更新

    如果在博客看到有任何不懂的,欢迎交流,我搭建了 dotnet 职业技术学院 欢迎大家加入

    知识共享许可协议
    本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接:http://blog.csdn.net/lindexi_gd ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系

    展开全文
  • SharpDX_4.2_packages.rar

    2019-08-14 11:56:06
    SharpDX/xx.animation/xx.d3dcompiler/xx.desktop/xx.diagnotics/xx.direct2d1/xx.direct3d9/xx.direct3d10/xx.direct3d11/xx.direct3d11.effects/xx.direct3d12/directcomposition/xx.directmanipulation/xx.direct...
  • 如果只是使用 SharpDX 使用窗口渲染,就无法使用其它的 WPF 控件,实际使用经常只是使用 SharpDX 加快一些渲染,很多元素都是不需要 这是一个例子告诉大家如何使用
  • 本文告诉大家如何通过 SharpDx 进行异步渲染,但是因为在 WPF 是需要使用 D3DImage 画出来,所以渲染只是画出图片,最后的显示还是需要 WPF 在他自己的主线程渲染

    本文告诉大家如何通过 SharpDx 进行异步渲染,但是因为在 WPF 是需要使用 D3DImage 画出来,所以渲染只是画出图片,最后的显示还是需要 WPF 在他自己的主线程渲染

    本文是一个系列,希望大家从第一篇开始看

    更多请看 WPF 使用 SharpDx 渲染博客导航

    虽然上一篇告诉大家如何使用封装的 SharpDx 控件,但是大家也看到了核心是使用CompositionTarget告诉刷新的。

    这个方法适合不停变化的控件,如果是很少刷新的控件使用这个方法会降低 WPF 的性能。

    因为 CompositionTarget 刷新数太快了,而且每次都需要重复刷新一个图片,显示的性能比不过自带的控件。

    使用方法

    因为使用 SharpDx 在 WPF 除了使用 D3DImage 还可以使用 D3D11Image 但是这个需要分开 x86 和 x64 。现在使用的方法是把 D3DImage 作为图片画出来,如果使用 D3D11Image 也没有什么性能提升。

    所以本文就和WPF 使用封装的 SharpDx 控件使用的基类不同,原来的基类是 Image 现在的基类是 FrameworkElement 。但是如果使用 Image 而且每次刷新的都是比较小的,性能会比使用 FrameworkElement 画出高一些。

    这里因为封装没有告诉需要刷新的大小,所以只能每次都全部刷新,这样的性能使用 FrameworkElement 不会降低。

    下面创建一个类,继承 SharpDxMaynumaSejair ,这个 SharpDxMaynumaSejair 是继承 FrameworkElement 而不是图片,这个类的代码放在文章最后,使用这个类可以异步渲染。

        public abstract class SharpDxMaynumaSejair : FrameworkElement
    
    

    请随意写一个类继承 SharpDxMaynumaSejair 并且添加重写的 OnRender 函数。

    下面是 SharpDxMaynumaSejair 类的 OnRender 方法,通过继承他就可以使用 SharpDx 画出来。

    protected abstract void OnRender(SharpDX.Direct2D1.RenderTarget renderTarget);
    

    其他的代码和WPF 使用封装的 SharpDx 控件使用的差不多

    直接通过 OnRender 就可以进行渲染,但是 OnRender 是被触发的,触发的方法是调用基类 Rendering 函数,调用了这个函数会进入异步的 SharpDx 渲染,渲染完成再通过 WPF 渲染画出来。

    因为不需要使用 CompositionTarget.Rendering 渲染,所以可以提高 WPF 刷新速度。

    这个类可以在执行渲染计算复杂使用,假如需要渲染出 10000 个椭圆,而且有很多重叠,而且不需要立刻渲染。那么就可以使用本文的这个类,这个类可以在调用时异步渲染,不会卡 UI 线程,在 SharpDx 渲染完成再通过 WPF 渲染,这时 WPF 渲染也就是画出图片,性能比画出 10000 个椭圆快很多。通过这个方法可以提高渲染性能,提高软件打开的性能。

    但是通过这个方法建议软件是 x64 因为需要很多内存。

    下面来告诉大家本文这个类的原理。

    绑定

    如果需要使用 SharpDx 需要把 SharpDX.Direct3D11 和 D3DImage 绑定,调用时不能在这个控件的 Load 前,不然无法拿到大小。

    下面这个方法和WPF 使用封装的 SharpDx 控件使用相同,所以我就直接写代码不解释了。

            private void CreateAndBindTargets(int actualWidth, int actualHeight)
            {
                var width = Math.Max(actualWidth, 100);
                var height = Math.Max(actualHeight, 100);
    
                var renderDesc = new SharpDX.Direct3D11.Texture2DDescription
                {
                    BindFlags = SharpDX.Direct3D11.BindFlags.RenderTarget | SharpDX.Direct3D11.BindFlags.ShaderResource,
                    Format = SharpDX.DXGI.Format.B8G8R8A8_UNorm,
                    Width = width,
                    Height = height,
                    MipLevels = 1,
                    SampleDescription = new SharpDX.DXGI.SampleDescription(1, 0),
                    Usage = SharpDX.Direct3D11.ResourceUsage.Default,
                    OptionFlags = SharpDX.Direct3D11.ResourceOptionFlags.Shared,
                    CpuAccessFlags = SharpDX.Direct3D11.CpuAccessFlags.None,
                    ArraySize = 1
                };
    
                var device = new SharpDX.Direct3D11.Device(DriverType.Hardware,
                    SharpDX.Direct3D11.DeviceCreationFlags.BgraSupport);
    
                _device = device;
    
                var renderTarget = new SharpDX.Direct3D11.Texture2D(device, renderDesc);
    
                var surface = renderTarget.QueryInterface<SharpDX.DXGI.Surface>();
    
                var d2DFactory = new SharpDX.Direct2D1.Factory();
    
                var renderTargetProperties =
                    new SharpDX.Direct2D1.RenderTargetProperties(
                        new SharpDX.Direct2D1.PixelFormat(SharpDX.DXGI.Format.Unknown,
                            SharpDX.Direct2D1.AlphaMode.Premultiplied));
    
                _d2DRenderTarget = new SharpDX.Direct2D1.RenderTarget(d2DFactory, surface, renderTargetProperties);
    
                SetRenderTarget(renderTarget);
    
                device.ImmediateContext.Rasterizer.SetViewport(0, 0, width, height);
    
                CreationProperties creationProperties = new CreationProperties
                {
                    DebugLevel = DebugLevel.Error,
                    Options = DeviceContextOptions.EnableMultithreadedOptimizations,
                    ThreadingMode = ThreadingMode.MultiThreaded,
                };
    
    
                _d2dContext = new DeviceContext(surface, creationProperties);
    
                _d2DRenderTarget = _d2dContext;
    
                InvalidateVisual();
            }
    
    

    如果大家有对比两个函数,会发现有一个属性不相同,原来是 Direct3D11.Device 被我拿出一个字段,这个字段在下面会使用到。

    虽然已经写好 D3DImage 但是如何显示?

    继承 FrameworkElement 可以重写 OnRender 。通过 OnRender 可以画出图片,而 D3Dimage 就是 ImageSource,虽然可以看到我自己定义的也是 OnRender, 这个函数和自己定义的不相同,虽然我把自己定义的函数也是和他使用相同的命名。看到下面代码也许就知道我说的是什么。

    需要注意,如果因为_d3D.PixelWidth为0抛出异常,那么就可能是绑定的时候在 Load 之前,需要修改一下代码。

            protected override void OnRender(DrawingContext drawingContext)
            {
                drawingContext.DrawImage(_d3D, new Rect(new Size(_d3D.PixelWidth, _d3D.PixelHeight)));
            }
    

    渲染为什么空白

    现在已经完成了修改继承类,但是原来使用的渲染还是没有修改。如果大家尝试在一个按钮按下时,进行刷新。代码大概是在 按钮按下时调用Rendering函数,这个函数只执行一次

            public void Rendering()
            {
                
                _d2dContext.BeginDraw();
    
                OnRender(_d2dContext);
    
                _d2dContext.EndDraw();
    
    
                _d3D.Lock();
    
    
                _d3D.AddDirtyRect(new Int32Rect(0, 0, _d3D.PixelWidth, _d3D.PixelHeight));
    
                _d3D.Unlock();
    
                base.InvalidateVisual();
            }
    

    如果大家运行了代码,会发现现在的界面虽然有执行OnRender但是显示和希望的不一样。

    原因是没有等待 SharpDx 画完,虽然调用了EndDraw但是只是把渲染命令发给显卡。

    那么如何等待 SharpDx 画完

    等待画完

    如果刚才看到 CreateAndBindTargets 会看到把 Direct3D11.Device 放在字段,因为在 Rendering 就需要使用这个字段等待显卡刷新。

    请看下面的代码

            public void Rendering()
            {
                _d2dContext.BeginDraw();
    
                OnRender(_d2dContext);
    
                _d2dContext.EndDraw();
    
                _device.ImmediateContext.Flush();
    
    
                _d3D.Lock();
    
    
                _d3D.AddDirtyRect(new Int32Rect(0, 0, _d3D.PixelWidth, _d3D.PixelHeight));
    
                _d3D.Unlock();
    
                base.InvalidateVisual();
            }
    

    尝试修改代码运行一下,可以如果调用了一次函数就可以刷新一次。

    如果是在按钮按下是刷新,但是渲染很多内容,那么主线程会在 Flush 占用很多资源。

    在 WPF 的渲染,是把主线程和渲染线程分开,经常说的主线程是没有做渲染的,在 DrawingContext 实际上不是调用了显示,而且通过 Channel 发送到Dx渲染,也就是调用函数只是告诉显卡如何渲染。

    在这里也是需要做相同的方法。

    异步渲染

    大家也可以看到,只需要使用一个新的线程去等待渲染就可以,使用新线程的方法是 Task ,但是不能把 d3dImage 放在另一个线程,他必须在主线程。

    修改一下代码

            public async void Rendering()
            {
    
                await Task.Run(() =>
                {
                    _d2dContext.BeginDraw();
    
                    OnRender(_d2dContext);
    
                    _d2dContext.EndDraw();
    
                    _device.ImmediateContext.Flush();
                });
    
    
                _d3D.Lock();
    
    
                _d3D.AddDirtyRect(new Int32Rect(0, 0, _d3D.PixelWidth, _d3D.PixelHeight));
    
                _d3D.Unlock();
    
                base.InvalidateVisual();
            }
    
    

    现在就可以在另一个线程告诉 SharpDx 如何画,然后在另一个线程等待 SharpDx 画出来。这样可以做到异步渲染。

    需要告诉大家,异步渲染不是多线程渲染,原因是渲染还是需要显卡来做,如果显卡的资源有限,那么渲染需要的时间不会降低。

    如果需要设置多线程渲染,可以通过在CreationProperties使用ThreadingMode.MultiThreaded现在上面的代码已经这样使用。

    不过大家不要直接使用这个类,因为上面代码使用Task.Run,如果在线程池没有资源,那么这个代码可能会等很久,这样的性能比较差。

    这个控件可以用在不需要立刻渲染的资源,但是渲染很慢,可以在用户做其他的输入进行渲染。因为默认的渲染都会让用户感觉软件速度有些慢,不过和这个做法相同的是使用 RenderTargetBitmap ,在另一个线程渲染,然后在主线程显示。

    和 RenderTargetBitmap 不同的,本文的方法可以在显卡渲染,渲染性能比 RenderTargetBitmap 高。

    多线程渲染

    下面告诉大家如何使用 RenderTargetBitmap 多线程渲染

    首先创建一个字段,在这个字段为空就需要调用函数创建

            private RenderTargetBitmap _stouFa;
    
    

    这个方法适合只有进行很少的渲染,而且很慢的应用。实际上 RenderTargetBitmap 可以 Freeze ,所以在另一个线程渲染是可以。

            protected override void OnRender(DrawingContext drawingContext)
            {
                if (_stouFa == null)
                {
                    TesuFudresel();
                }
                else
                {
                    drawingContext.DrawImage(_stouFa, new Rect(new Size(ActualWidth, ActualHeight)));
                }
            }
    

    在方法 TesuFudresel 就是创建渲染

            private void TesuFudresel()
            {
    
                Task.Run(() =>
                {
                    var renderTargetBitmap = new RenderTargetBitmap(100, 100, 96, 96, new PixelFormat());
                    var drawingVisual = new DrawingVisual();
                    var drawingContext = drawingVisual.RenderOpen();
                    drawingContext.DrawRectangle(Brushes.Chartreuse, new Pen(Brushes.Chartreuse, 2),
                        new Rect(new Point(10, 10), new Size(100, 100)));
                    drawingContext.Close();
                    renderTargetBitmap.Render(drawingVisual);
                    renderTargetBitmap.Freeze();
    
                    _stouFa = renderTargetBitmap;
                });
    
            }
    

    代码主要就是使用 drawingVisual 画出来,然后让对象可以跨线程。

    本文就告诉大家如何使用 SharpDx 异步渲染,还告诉大家如何使用 WPF 自带的类进行多线程渲染,下面就是本文这个控件的代码

    建议大家自己写一个线程调度而不是使用 Task ,因为最近在写 Avalon 所以暂时我也没有把下面的类写的可以在产品使用。请大家参考代码而不是在项目使用这个代码,因为存在 Task 需要等很久和代码没有优化。

        public abstract class SharpDxMaynumaSejair : FrameworkElement
        {
            private D3DImage _d3D = new D3DImage();
    
            /// <inheritdoc />
            protected SharpDxMaynumaSejair()
            {
                Loaded += SharpDxMaynumaSejair_Loaded;
            }
    
            private void SharpDxMaynumaSejair_Loaded(object sender, RoutedEventArgs e)
            {
                CreateAndBindTargets((int) ActualWidth, (int) ActualHeight);
            }
    
            private void CreateAndBindTargets(int actualWidth, int actualHeight)
            {
                var width = Math.Max(actualWidth, 100);
                var height = Math.Max(actualHeight, 100);
    
                var renderDesc = new SharpDX.Direct3D11.Texture2DDescription
                {
                    BindFlags = SharpDX.Direct3D11.BindFlags.RenderTarget | SharpDX.Direct3D11.BindFlags.ShaderResource,
                    Format = SharpDX.DXGI.Format.B8G8R8A8_UNorm,
                    Width = width,
                    Height = height,
                    MipLevels = 1,
                    SampleDescription = new SharpDX.DXGI.SampleDescription(1, 0),
                    Usage = SharpDX.Direct3D11.ResourceUsage.Default,
                    OptionFlags = SharpDX.Direct3D11.ResourceOptionFlags.Shared,
                    CpuAccessFlags = SharpDX.Direct3D11.CpuAccessFlags.None,
                    ArraySize = 1
                };
    
                var device = new SharpDX.Direct3D11.Device(DriverType.Hardware,
                    SharpDX.Direct3D11.DeviceCreationFlags.BgraSupport);
    
                _device = device;
    
                var renderTarget = new SharpDX.Direct3D11.Texture2D(device, renderDesc);
    
                var surface = renderTarget.QueryInterface<SharpDX.DXGI.Surface>();
    
                var d2DFactory = new SharpDX.Direct2D1.Factory();
    
                var renderTargetProperties =
                    new SharpDX.Direct2D1.RenderTargetProperties(
                        new SharpDX.Direct2D1.PixelFormat(SharpDX.DXGI.Format.Unknown,
                            SharpDX.Direct2D1.AlphaMode.Premultiplied));
    
                _d2DRenderTarget = new SharpDX.Direct2D1.RenderTarget(d2DFactory, surface, renderTargetProperties);
    
                SetRenderTarget(renderTarget);
    
                device.ImmediateContext.Rasterizer.SetViewport(0, 0, width, height);
    
                CreationProperties creationProperties = new CreationProperties
                {
                    DebugLevel = DebugLevel.Error,
                    Options = DeviceContextOptions.EnableMultithreadedOptimizations,
                    ThreadingMode = ThreadingMode.MultiThreaded,
                };
    
    
                _d2dContext = new DeviceContext(surface, creationProperties);
    
                _d2DRenderTarget = _d2dContext;
    
                InvalidateVisual();
            }
    
            public new void InvalidateVisual()
            {
                Rendering();
            }
    
            /// <inheritdoc />
            protected override void OnRender(DrawingContext drawingContext)
            {
                drawingContext.DrawImage(_d3D, new Rect(new Size(_d3D.PixelWidth, _d3D.PixelHeight)));
            }
    
       
            protected abstract void OnRender(SharpDX.Direct2D1.RenderTarget renderTarget);
    
            private SharpDX.Direct3D9.Texture _renderTarget;
            private SharpDX.Direct2D1.RenderTarget _d2DRenderTarget;
            private DeviceContext _d2dContext;
    
            private SharpDX.Direct3D11.Device _device;
    
            private async void Rendering()
            {
                await Task.Run(() =>
                {
                    _d2dContext.BeginDraw();
    
                    OnRender(_d2dContext);
    
                    _d2dContext.EndDraw();
    
                    _device.ImmediateContext.Flush();
                });
    
    
                _d3D.Lock();
    
                _d3D.AddDirtyRect(new Int32Rect(0, 0, _d3D.PixelWidth, _d3D.PixelHeight));
    
                _d3D.Unlock();
    
                base.InvalidateVisual();
            }
    
            private void SetRenderTarget(SharpDX.Direct3D11.Texture2D target)
            {
                var format = TranslateFormat(target);
                var handle = GetSharedHandle(target);
    
                var presentParams = GetPresentParameters();
                var createFlags = SharpDX.Direct3D9.CreateFlags.HardwareVertexProcessing |
                                  SharpDX.Direct3D9.CreateFlags.Multithreaded |
                                  SharpDX.Direct3D9.CreateFlags.FpuPreserve;
    
                var d3DContext = new SharpDX.Direct3D9.Direct3DEx();
                var d3DDevice = new SharpDX.Direct3D9.DeviceEx(d3DContext, 0, SharpDX.Direct3D9.DeviceType.Hardware,
                    IntPtr.Zero, createFlags,
                    presentParams);
    
                _renderTarget = new SharpDX.Direct3D9.Texture(d3DDevice, target.Description.Width,
                    target.Description.Height, 1,
                    SharpDX.Direct3D9.Usage.RenderTarget, format, SharpDX.Direct3D9.Pool.Default, ref handle);
    
                using (var surface = _renderTarget.GetSurfaceLevel(0))
                {
                    _d3D.Lock();
                    _d3D.SetBackBuffer(D3DResourceType.IDirect3DSurface9, surface.NativePointer);
                    _d3D.Unlock();
                }
            }
    
            private static SharpDX.Direct3D9.PresentParameters GetPresentParameters()
            {
                var presentParams = new SharpDX.Direct3D9.PresentParameters();
    
                presentParams.Windowed = true;
                presentParams.SwapEffect = SharpDX.Direct3D9.SwapEffect.Discard;
                presentParams.DeviceWindowHandle = NativeMethods.GetDesktopWindow();
                presentParams.PresentationInterval = SharpDX.Direct3D9.PresentInterval.Default;
    
                return presentParams;
            }
    
            private IntPtr GetSharedHandle(SharpDX.Direct3D11.Texture2D texture)
            {
                using (var resource = texture.QueryInterface<SharpDX.DXGI.Resource>())
                {
                    return resource.SharedHandle;
                }
            }
    
            private static SharpDX.Direct3D9.Format TranslateFormat(SharpDX.Direct3D11.Texture2D texture)
            {
                switch (texture.Description.Format)
                {
                    case SharpDX.DXGI.Format.R10G10B10A2_UNorm:
                        return SharpDX.Direct3D9.Format.A2B10G10R10;
                    case SharpDX.DXGI.Format.R16G16B16A16_Float:
                        return SharpDX.Direct3D9.Format.A16B16G16R16F;
                    case SharpDX.DXGI.Format.B8G8R8A8_UNorm:
                        return SharpDX.Direct3D9.Format.A8R8G8B8;
                    default:
                        return SharpDX.Direct3D9.Format.Unknown;
                }
            }
    
            private static class NativeMethods
            {
                [DllImport("user32.dll", SetLastError = false)]
                public static extern IntPtr GetDesktopWindow();
            }
        }
    
    

    更多渲染博客请看 WPF 底层渲染

    特别感谢

    Direct2D - 随笔分类 - 万仓一黍 - 博客园

    Direct2D - 随笔分类 - 万一 - 博客园

    Direct2D - 随笔分类 - zdd - 博客园

    我搭建了自己的博客 https://blog.lindexi.com/ 欢迎大家访问,里面有很多新的博客。只有在我看到博客写成熟之后才会放在csdn或博客园,但是一旦发布了就不再更新

    如果在博客看到有任何不懂的,欢迎交流,我搭建了 dotnet 职业技术学院 欢迎大家加入

    知识共享许可协议
    本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接:http://blog.csdn.net/lindexi_gd ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系

    展开全文
  • WPF 使用 SharpDX 在 D3DImage 显示

    千次阅读 2018-11-19 15:41:12
    本文告诉大家如何使用 SharpDX 在 D3DImage 显示。在上一篇WPF 使用 SharpDX只是使用窗口,也就是无法使用其它的 WPF 控件。所以这一篇就来告诉大家如何使用 WPF 控件和使用 SharpDX
  • title author date CreateTime categories ... C# 从零开始写 SharpDx 应用 控制台创建 Sharpdx 窗口 lindexi 2018-8-17 9:3:36 +0800 2018-6-18 21:16:2 +0800 C# D2D DirectX S...
  • C# 从零开始写 SharpDx 应用 笔刷

    千次阅读 2019-08-30 08:51:35
    本文告诉大家如何在 SharpDx 里面使用笔刷,包括纯色笔刷、渐变笔刷和图片笔刷
  • SharpDX for Winform

    千次阅读 2018-03-26 12:17:03
    添加NuGet 依赖项 SharpDX ... 我这里大部分的都先添加进来3.查找可用的自定义组件 并添加到工具箱 (为了方便可视化开发,这里 我只找到了 RenderControl 组件)4.开始移植代码:...
  • C# 从零开始写 SharpDx 应用 画三角

    千次阅读 2018-09-30 18:31:57
    在当前的画面都是使用三角形,在开始就告诉大家如何画三角,本文告诉大家如何用像素著色器画
  • SharpDX的Winform窗口,渲染在Panel中。 使用的非原有例子中的自带窗口。 使用Effect,运用shader渲染三角形 。 自定义根图层和根图元 。添加图层列表。使用矩阵及自定义顶点格式。 使用顶点索引并添加纹理。添加了...
  • SharpDX在Winform中的第一个窗体例子。 使用的不是原例子中的自带Form,而是在Winform的panel控件渲染。

空空如也

1 2 3 4 5 ... 11
收藏数 214
精华内容 85
关键字:

SharpDX