<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      [WPF] 使用Silk.NET繪制D3D9或OpenGL內容并完美解決空域問題。

      可擴展渲染控件實現的基本思路(D3D、OpenGL繪制所使用的基類):

       

       

       

      首先創建一個抽象類 FramebufferBase,該類主要記錄當前控件寬高和圖像資源。

      public abstract class FramebufferBase : IDisposable
      {
          public abstract int FramebufferWidth { get; }
      
          public abstract int FramebufferHeight { get; }
      
          public abstract D3DImage D3dImage { get; }
      
          public abstract void Dispose();
      }
      View Code

      接下來創建一個基本繪制控件,我這邊取名為GameBase

      public abstract class GameBase<TFrame> : Control where TFrame : FramebufferBase

      當我們在繪制3d內容的時候,總是會先在繪制前做一個準備,比如加載Shader,設置頂點、紋理等等。。。

      所以我們應該加入 準備階段事件 和 繪制事件。

      當然如果當前幀繪制完成后,我們也可以做一些操作為下一次渲染做準備。

      public abstract event Action Ready;
      public abstract event Action<TimeSpan> Render;
      public abstract event Action<object, TimeSpan> UpdateFrame;
      View Code

      創建三個抽象方法 OnStart、OnDraw、OnSizeChanged

      因為D3D和OpenGL創建幀和繪制的方式不太一致,所以需要提出來在繼承類中做實現。

      protected abstract void OnStart();
      protected abstract void OnDraw(DrawingContext drawingContext);
      protected abstract void OnSizeChanged(SizeChangedInfo sizeInfo);
      View Code

      重載OnRenderSizeChanged、OnRender方法

      因為新版本VS加入后了設計時預覽,所以我判斷了下(DesignerProperties.GetIsInDesignMode)。

      protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
      {
          if (!DesignerProperties.GetIsInDesignMode(this))
          {
              OnSizeChanged(sizeInfo);
          }
      }
      
      protected override void OnRender(DrawingContext drawingContext)
      {
        if (DesignerProperties.GetIsInDesignMode(this))
        {
          DesignTimeHelper.DrawDesign(this, drawingContext);
        }
        else
        {
          if (Framebuffer != null && Framebuffer.D3dImage.IsFrontBufferAvailable)
          {
            OnDraw(drawingContext);
      
            _stopwatch.Restart();
          }
        }
      }
      View Code

      創建一個Start方法

      CompositionTarget.Rendering事件用于幀繪制并計算幀率。

      public void Start()
      {
        if (!DesignerProperties.GetIsInDesignMode(this))
        {
          IsVisibleChanged += (_, e) =>
          {
            if ((bool)e.NewValue)
            {
              CompositionTarget.Rendering += CompositionTarget_Rendering;
            }
            else
            {
              CompositionTarget.Rendering -= CompositionTarget_Rendering;
            }
          };
      
          Loaded += (_, _) => InvalidateVisual();
      
          OnStart();
        }
      }
      private void CompositionTarget_Rendering(object sender, EventArgs e)
      {
        RenderingEventArgs args = (RenderingEventArgs)e;
      
        if (_lastRenderTime != args.RenderingTime)
        {
          InvalidateVisual();
      
          _fpsSample.Add(Convert.ToInt32(1000.0d / (args.RenderingTime.TotalMilliseconds - _lastRenderTime.TotalMilliseconds)));
          // 樣本數 30
          if (_fpsSample.Count == 30)
          {
            Fps = Convert.ToInt32(_fpsSample.Average());
            _fpsSample.Clear();
          }
      
          _lastRenderTime = args.RenderingTime;
        }
      }
      View Code

      初期階段,做這些準備就夠了

      剩下一些變量和依賴屬性

      public static readonly DependencyProperty FpsProperty = DependencyProperty.Register(nameof(Fps), typeof(int), typeof(GameBase<TFrame>), new PropertyMetadata(0));
          
      protected readonly Stopwatch _stopwatch = Stopwatch.StartNew();
      private readonly List<int> _fpsSample = new();
      
      protected TimeSpan _lastRenderTime = TimeSpan.FromSeconds(-1);
      protected TimeSpan _lastFrameStamp;
      
      protected TFrame Framebuffer { get; set; }
      public int Fps
      {
          get { return (int)GetValue(FpsProperty); }
          set { SetValue(FpsProperty, value); }
      }
      View Code

      OK,基本思路就這樣,接下來我將講解具體實現。

      D3D9繪制:

      使用庫:Silk.NET.Direct3D9

      創建RenderContext類,此類主要功能是創建d3d設備及繪制格式。

      創建一個d3d9的實例。

      IDirect3D9Ex* direct3D9;
      D3D9.GetApi().Direct3DCreate9Ex(D3D9.SdkVersion, &direct3D9);

      獲取屏幕基本信息。

      Displaymodeex pMode = new((uint)sizeof(Displaymodeex));
      direct3D9->GetAdapterDisplayModeEx(D3D9.AdapterDefault, ref pMode, null);

      創建d3d9設備。

      重要參數:

      BackBufferFormat 這個要與獲取的屏幕信息里的格式一致。

      PresentParameters presentParameters = new()
      {
        Windowed = 1,
        SwapEffect = Swapeffect.Discard,
        HDeviceWindow = 0,
        PresentationInterval = 0,
        BackBufferFormat = pMode.Format,
        BackBufferWidth = 1,
        BackBufferHeight = 1,
        AutoDepthStencilFormat = Format.Unknown,
        BackBufferCount = 1,
        EnableAutoDepthStencil = 0,
        Flags = 0,
        FullScreenRefreshRateInHz = 0,
        MultiSampleQuality = 0,
        MultiSampleType = MultisampleType.MultisampleNone
      };
      direct3D9->CreateDeviceEx(D3D9.AdapterDefault, Devtype.Hal, 0, D3D9.CreateHardwareVertexprocessing | D3D9.CreateMultithreaded | D3D9.CreatePuredevice, ref presentParameters, (Displaymodeex*)IntPtr.Zero, &device);
      View Code

      完整代碼:

      public unsafe class RenderContext
      {
          public IDirect3DDevice9Ex* Device { get; }
      
          public Format Format { get; }
      
          public RenderContext()
          {
              IDirect3D9Ex* direct3D9;
              IDirect3DDevice9Ex* device;
              D3D9.GetApi().Direct3DCreate9Ex(D3D9.SdkVersion, &direct3D9);
      
              Displaymodeex pMode = new((uint)sizeof(Displaymodeex));
              direct3D9->GetAdapterDisplayModeEx(D3D9.AdapterDefault, ref pMode, null);
      
              PresentParameters presentParameters = new()
              {
                  Windowed = 1,
                  SwapEffect = Swapeffect.Discard,
                  HDeviceWindow = 0,
                  PresentationInterval = 0,
                  BackBufferFormat = pMode.Format,
                  BackBufferWidth = 1,
                  BackBufferHeight = 1,
                  AutoDepthStencilFormat = Format.Unknown,
                  BackBufferCount = 1,
                  EnableAutoDepthStencil = 0,
                  Flags = 0,
                  FullScreenRefreshRateInHz = 0,
                  MultiSampleQuality = 0,
                  MultiSampleType = MultisampleType.MultisampleNone
              };
              direct3D9->CreateDeviceEx(D3D9.AdapterDefault, Devtype.Hal, 0, D3D9.CreateHardwareVertexprocessing | D3D9.CreateMultithreaded | D3D9.CreatePuredevice, ref presentParameters, (Displaymodeex*)IntPtr.Zero, &device);
      
              Device = device;
              Format = pMode.Format;
          }
      }
      View Code

      繼承FramebufferBase創建Framebuffer

      這里就是根據傳入的寬高創建一個新的Surface并綁定到D3DImage

      public unsafe class Framebuffer : FramebufferBase
      {
          public RenderContext Context { get; }
      
          public override int FramebufferWidth { get; }
      
          public override int FramebufferHeight { get; }
      
          public override D3DImage D3dImage { get; }
      
          public Framebuffer(RenderContext context, int framebufferWidth, int framebufferHeight)
          {
              Context = context;
              FramebufferWidth = framebufferWidth;
              FramebufferHeight = framebufferHeight;
      
              IDirect3DSurface9* surface;
              context.Device->CreateRenderTarget((uint)FramebufferWidth, (uint)FramebufferHeight, context.Format, MultisampleType.MultisampleNone, 0, 0, &surface, null);
              context.Device->SetRenderTarget(0, surface);
      
              D3dImage = new D3DImage();
              D3dImage.Lock();
              D3dImage.SetBackBuffer(D3DResourceType.IDirect3DSurface9, (IntPtr)surface);
              D3dImage.Unlock();
          }
      
          public override void Dispose()
          {
              GC.SuppressFinalize(this);
          }
      }
      View Code

      創建GameControl,并繼承GameBase

      public unsafe class GameControl : GameBase<Framebuffer>
      private RenderContext _context;
      
      public IDirect3DDevice9Ex* Device { get; private set; }
      public Format Format { get; private set; }
      
      public override event Action Ready;
      public override event Action<TimeSpan> Render;
      public override event Action<object, TimeSpan> UpdateFrame;

      重載OnStart方法

      在使用時,OnStart只調用一次并創建RenderContext

      protected override void OnStart()
      {
        if (_context == null)
        {
          _context = new RenderContext();
          Device = _context.Device;
          Format = _context.Format;
      
          Ready?.Invoke();
        }
      }
      View Code

      重載OnSizeChanged方法

      每當控件大小方式改變時,將重新創建Framebuffer。

      protected override void OnSizeChanged(SizeChangedInfo sizeInfo)
      {
        if (_context != null && sizeInfo.NewSize.Width > 0 && sizeInfo.NewSize.Height > 0)
        {
          Framebuffer?.Dispose();
          Framebuffer = new Framebuffer(_context, (int)sizeInfo.NewSize.Width, (int)sizeInfo.NewSize.Height);
        }
      }
      View Code

      重載OnDraw方法

      首先鎖定D3dImage,執行Render進行繪制。

      繪制完成后,刷新D3dImage并解鎖。

      將D3dImage資源繪制到控件上。

      執行UpdateFrame,告訴使用者,已經繪制完成。

      protected override void OnDraw(DrawingContext drawingContext)
      {
        Framebuffer.D3dImage.Lock();
      
        Render?.Invoke(_stopwatch.Elapsed - _lastFrameStamp);
      
        Framebuffer.D3dImage.AddDirtyRect(new Int32Rect(0, 0, Framebuffer.FramebufferWidth, Framebuffer.FramebufferHeight));
        Framebuffer.D3dImage.Unlock();
      
        Rect rect = new(0, 0, Framebuffer.D3dImage.Width, Framebuffer.D3dImage.Height);
        drawingContext.DrawImage(Framebuffer.D3dImage, rect);
      
        UpdateFrame?.Invoke(this, _stopwatch.Elapsed - _lastFrameStamp);
      }
      View Code

      使用方式:

      <UserControl x:Class="SilkWPF.Direct3D9.Sample.MiniTri"
                   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                   xmlns:direct3D9="clr-namespace:SilkWPF.Direct3D9"
                   mc:Ignorable="d"
                   d:DesignHeight="450"
                   d:DesignWidth="800">
          <Grid>
              <direct3D9:GameControl x:Name="Game" />
              <TextBlock HorizontalAlignment="Left"
                         VerticalAlignment="Top"
                         Margin="10,5,0,0"
                         FontSize="30"
                         Foreground="Green"
                         Text="{Binding ElementName=Game, Path=Fps}" />
          </Grid>
      </UserControl>
      Xaml
      using Silk.NET.Direct3D9;
      using Silk.NET.Maths;
      using SilkWPF.Common;
      using System.Diagnostics;
      using System.Numerics;
      using System.Runtime.InteropServices;
      using System.Windows.Controls;
      
      namespace SilkWPF.Direct3D9.Sample;
      
      /// <summary>
      /// MiniTri.xaml 的交互邏輯
      /// </summary>
      public unsafe partial class MiniTri : UserControl
      {
          [StructLayout(LayoutKind.Sequential)]
          struct Vertex
          {
              public Vector4 Position;
              public uint Color;
          }
      
          private readonly Stopwatch _stopwatch = Stopwatch.StartNew();
          private readonly Vertex[] _vertices =
          {
              new Vertex() { Color = (uint)SilkColor.Red.ToBgra(), Position = new Vector4(400.0f, 100.0f, 0.5f, 1.0f) },
              new Vertex() { Color = (uint)SilkColor.Blue.ToBgra(), Position = new Vector4(650.0f, 500.0f, 0.5f, 1.0f) },
              new Vertex() { Color = (uint)SilkColor.Green.ToBgra(), Position = new Vector4(150.0f, 500.0f, 0.5f, 1.0f) }
          };
          private readonly Vertexelement9[] _vertexelements =
          {
              new Vertexelement9(0, 0, 3, 0, 9, 0),
              new Vertexelement9(0, 16, 4, 0, 10, 0),
              new Vertexelement9(255, 0, 17, 0, 0, 0)
          };
      
          private IDirect3DVertexBuffer9* _ppVertexBuffer;
          private IDirect3DVertexDeclaration9* _ppDecl;
      
          public MiniTri()
          {
              InitializeComponent();
      
              Game.Ready += Game_Ready;
              Game.Render += Game_Render;
              Game.Start();
          }
      
          private void Game_Ready()
          {
              fixed (Vertex* ptr = &_vertices[0])
              {
                  fixed (Vertexelement9* vertexElems = &_vertexelements[0])
                  {
                      void* ppbData;
                      Game.Device->CreateVertexBuffer(3 * 20, D3D9.UsageWriteonly, 0, Pool.Default, ref _ppVertexBuffer, null);
                      _ppVertexBuffer->Lock(0, 0, &ppbData, 0);
                      System.Runtime.CompilerServices.Unsafe.CopyBlockUnaligned(ppbData, ptr, (uint)(sizeof(Vertex) * _vertices.Length));
                      _ppVertexBuffer->Unlock();
      
                      Game.Device->CreateVertexDeclaration(vertexElems, ref _ppDecl);
                  }
              }
          }
      
          private void Game_Render(TimeSpan obj)
          {
              float hue = (float)_stopwatch.Elapsed.TotalSeconds * 0.15f % 1;
              Vector4 vector = new(1.0f * hue, 1.0f * 0.75f, 1.0f * 0.75f, 1.0f);
      
              Game.Device->Clear(0, null, D3D9.ClearTarget, (uint)SilkColor.FromHsv(vector).ToBgra(), 1.0f, 0);
              Game.Device->BeginScene();
      
              Game.Device->SetStreamSource(0, _ppVertexBuffer, 0, 20);
              Game.Device->SetVertexDeclaration(_ppDecl);
              Game.Device->DrawPrimitive(Primitivetype.Trianglelist, 0, 1);
      
              Game.Device->EndScene();
              Game.Device->Present((Rectangle<int>*)IntPtr.Zero, (Rectangle<int>*)IntPtr.Zero, 1, (RGNData*)IntPtr.Zero);
          }
      }
      C#

      運行代碼,你將得到一個漸變顏色的三角形(amd處理器上對d3d9的支持特別差,使用MediaElement播放視頻也卡的不行)。

      顯示幀數比較低,不用太在意(amd出來背鍋)。

       接下來時繪制OpenGL內容:

      分割一下 ——————————————————————————————————————————————————————————————————

      OpenGL繪制:

      實現思路:

      使用庫:Silk.NET.Direct3D9、OpenTK

      可能大家比較奇怪,為什么不用Silk.NET.OpenGL,

      目前Silk中的Wgl函數并不完整,我這里需要一些wgl的擴展函數用于關聯D3D9設備。

      所以我就先使用OpenTK做繪制。

      創建一個OpenGL的配置信息類 Settings

      public class Settings
      {
          public int MajorVersion { get; set; } = 3;
      
          public int MinorVersion { get; set; } = 3;
      
          public ContextFlags GraphicsContextFlags { get; set; } = ContextFlags.Default;
      
          public ContextProfile GraphicsProfile { get; set; } = ContextProfile.Core;
      
          public IGraphicsContext ContextToUse { get; set; }
      
          public static bool WouldResultInSameContext([NotNull] Settings a, [NotNull] Settings b)
          {
              if (a.MajorVersion != b.MajorVersion)
              {
                  return false;
              }
      
              if (a.MinorVersion != b.MinorVersion)
              {
                  return false;
              }
      
              if (a.GraphicsProfile != b.GraphicsProfile)
              {
                  return false;
              }
      
              if (a.GraphicsContextFlags != b.GraphicsContextFlags)
              {
                  return false;
              }
      
              return true;
      
          }
      }
      View Code

       創建RenderContext

      具體實現與d3d差不太多,主要是創建設備。

      不過要注意GetOrCreateSharedOpenGLContext方法,他是靜態的,

      我們在初始化wgl時需要一個窗體,所以我在這里讓所有繪制控件都使用一個窗體。

      public unsafe class RenderContext
      {
          private static IGraphicsContext _sharedContext;
          private static Settings _sharedContextSettings;
          private static int _sharedContextReferenceCount;
      
          public Format Format { get; }
      
          public IntPtr DxDeviceHandle { get; }
      
          public IntPtr GlDeviceHandle { get; }
      
          public IGraphicsContext GraphicsContext { get; }
      
          public RenderContext(Settings settings)
          {
              IDirect3D9Ex* direct3D9;
              IDirect3DDevice9Ex* device;
              D3D9.GetApi().Direct3DCreate9Ex(D3D9.SdkVersion, &direct3D9);
      
              Displaymodeex pMode = new((uint)sizeof(Displaymodeex));
              direct3D9->GetAdapterDisplayModeEx(D3D9.AdapterDefault, ref pMode, null);
              Format = pMode.Format;
      
              PresentParameters presentParameters = new()
              {
                  Windowed = 1,
                  SwapEffect = Swapeffect.Discard,
                  HDeviceWindow = 0,
                  PresentationInterval = 0,
                  BackBufferFormat = Format,
                  BackBufferWidth = 1,
                  BackBufferHeight = 1,
                  AutoDepthStencilFormat = Format.Unknown,
                  BackBufferCount = 1,
                  EnableAutoDepthStencil = 0,
                  Flags = 0,
                  FullScreenRefreshRateInHz = 0,
                  MultiSampleQuality = 0,
                  MultiSampleType = MultisampleType.MultisampleNone
              };
              direct3D9->CreateDeviceEx(D3D9.AdapterDefault, Devtype.Hal, 0, D3D9.CreateHardwareVertexprocessing | D3D9.CreateMultithreaded | D3D9.CreatePuredevice, ref presentParameters, (Displaymodeex*)IntPtr.Zero, &device);
      
              DxDeviceHandle = (IntPtr)device;
      
              GraphicsContext = GetOrCreateSharedOpenGLContext(settings);
              GlDeviceHandle = Wgl.DXOpenDeviceNV((IntPtr)device);
          }
      
          private static IGraphicsContext GetOrCreateSharedOpenGLContext(Settings settings)
          {
              if (_sharedContext == null)
              {
                  NativeWindowSettings windowSettings = NativeWindowSettings.Default;
                  windowSettings.StartFocused = false;
                  windowSettings.StartVisible = false;
                  windowSettings.NumberOfSamples = 0;
                  windowSettings.APIVersion = new Version(settings.MajorVersion, settings.MinorVersion);
                  windowSettings.Flags = ContextFlags.Offscreen | settings.GraphicsContextFlags;
                  windowSettings.Profile = settings.GraphicsProfile;
                  windowSettings.WindowBorder = WindowBorder.Hidden;
                  windowSettings.WindowState = WindowState.Minimized;
                  NativeWindow nativeWindow = new(windowSettings);
                  Wgl.LoadBindings(new GLFWBindingsContext());
      
                  _sharedContext = nativeWindow.Context;
                  _sharedContextSettings = settings;
      
                  _sharedContext.MakeCurrent();
              }
              else
              {
                  if (!Settings.WouldResultInSameContext(settings, _sharedContextSettings))
                  {
                      throw new ArgumentException($"The provided {nameof(Settings)} would result" +
                                                      $"in a different context creation to one previously created. To fix this," +
                                                      $" either ensure all of your context settings are identical, or provide an " +
                                                      $"external context via the '{nameof(Settings.ContextToUse)}' field.");
                  }
              }
      
              Interlocked.Increment(ref _sharedContextReferenceCount);
      
              return _sharedContext;
          }
      }
      View Code

      創建Framebuffer

      這里主要用d3d創建一個Surface,

      gl根據Surface生成一個Frame。 

      public unsafe class Framebuffer : FramebufferBase
      {
          public RenderContext Context { get; }
      
          public override int FramebufferWidth { get; }
      
          public override int FramebufferHeight { get; }
      
          public int GLFramebufferHandle { get; }
      
          public int GLSharedTextureHandle { get; }
      
          public int GLDepthRenderBufferHandle { get; }
      
          public IntPtr DxInteropRegisteredHandle { get; }
      
          public override D3DImage D3dImage { get; }
      
          public TranslateTransform TranslateTransform { get; }
      
          public ScaleTransform FlipYTransform { get; }
      
          public Framebuffer(RenderContext context, int framebufferWidth, int framebufferHeight)
          {
              Context = context;
              FramebufferWidth = framebufferWidth;
              FramebufferHeight = framebufferHeight;
      
              IDirect3DDevice9Ex* device = (IDirect3DDevice9Ex*)context.DxDeviceHandle;
              IDirect3DSurface9* surface;
              void* surfacePtr = (void*)IntPtr.Zero;
              device->CreateRenderTarget((uint)FramebufferWidth, (uint)FramebufferHeight, context.Format, MultisampleType.MultisampleNone, 0, 0, &surface, &surfacePtr);
      
              Wgl.DXSetResourceShareHandleNV((IntPtr)surface, (IntPtr)surfacePtr);
              GLFramebufferHandle = GL.GenFramebuffer();
              GLSharedTextureHandle = GL.GenTexture();
      
              DxInteropRegisteredHandle = Wgl.DXRegisterObjectNV(context.GlDeviceHandle, (IntPtr)surface, (uint)GLSharedTextureHandle, (uint)TextureTarget.Texture2D, WGL_NV_DX_interop.AccessReadWrite);
      
              GL.BindFramebuffer(FramebufferTarget.Framebuffer, GLFramebufferHandle);
              GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2D, GLSharedTextureHandle, 0);
      
              GLDepthRenderBufferHandle = GL.GenRenderbuffer();
              GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, GLDepthRenderBufferHandle);
              GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.Depth24Stencil8, FramebufferWidth, FramebufferHeight);
      
              GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthAttachment, RenderbufferTarget.Renderbuffer, GLDepthRenderBufferHandle);
              GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.StencilAttachment, RenderbufferTarget.Renderbuffer, GLDepthRenderBufferHandle);
              GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
      
              D3dImage = new D3DImage();
              D3dImage.Lock();
              D3dImage.SetBackBuffer(D3DResourceType.IDirect3DSurface9, (IntPtr)surface);
              D3dImage.Unlock();
      
              TranslateTransform = new TranslateTransform(0, FramebufferHeight);
              FlipYTransform = new ScaleTransform(1, -1);
          }
      
          public override void Dispose()
          {
              GL.DeleteFramebuffer(GLFramebufferHandle);
              GL.DeleteRenderbuffer(GLDepthRenderBufferHandle);
              GL.DeleteTexture(GLSharedTextureHandle);
              Wgl.DXUnregisterObjectNV(Context.GlDeviceHandle, DxInteropRegisteredHandle);
      
              GC.SuppressFinalize(this);
          }
      }
      View Code

      創建GameControl并繼承GameBase

      重載OnDraw方法

      跟d3d一樣,繪制前需要鎖定Frame。

      繪制完成后進行刷新。

      這里有一點不同的是,OpenGL的頂點在左下角(0,0)

      所以要對圖像進行翻轉。

      protected override void OnDraw(DrawingContext drawingContext)
      {
        Framebuffer.D3dImage.Lock();
      
        Wgl.DXLockObjectsNV(_context.GlDeviceHandle, 1, new[] { Framebuffer.DxInteropRegisteredHandle });
        GL.BindFramebuffer(FramebufferTarget.Framebuffer, Framebuffer.GLFramebufferHandle);
      
        GL.Viewport(0, 0, Framebuffer.FramebufferWidth, Framebuffer.FramebufferHeight);
        Render?.Invoke(_stopwatch.Elapsed - _lastFrameStamp);
      
        GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
        Wgl.DXUnlockObjectsNV(_context.GlDeviceHandle, 1, new[] { Framebuffer.DxInteropRegisteredHandle });
      
        Framebuffer.D3dImage.AddDirtyRect(new Int32Rect(0, 0, Framebuffer.FramebufferWidth, Framebuffer.FramebufferHeight));
        Framebuffer.D3dImage.Unlock();
      
        drawingContext.PushTransform(Framebuffer.TranslateTransform);
        drawingContext.PushTransform(Framebuffer.FlipYTransform);
      
        Rect rect = new(0, 0, Framebuffer.D3dImage.Width, Framebuffer.D3dImage.Height);
        drawingContext.DrawImage(Framebuffer.D3dImage, rect);
      
        drawingContext.Pop();
        drawingContext.Pop();
      
        UpdateFrame?.Invoke(this, _stopwatch.Elapsed - _lastFrameStamp);
      }
      View Code

      其余函數與d3d基本一致,我就不說了(沒想到寫文章這么累)

      完整代碼:

      public class GameControl : GameBase<Framebuffer>
      {
          private RenderContext _context;
      
          public Settings Setting { get; set; } = new Settings();
      
          public override event Action Ready;
          public override event Action<TimeSpan> Render;
          public override event Action<object, TimeSpan> UpdateFrame;
      
          protected override void OnStart()
          {
              if (_context == null)
              {
                  _context = new RenderContext(Setting);
      
                  Ready?.Invoke();
              }
          }
      
          protected override void OnSizeChanged(SizeChangedInfo sizeInfo)
          {
              if (_context != null && sizeInfo.NewSize.Width > 0 && sizeInfo.NewSize.Height > 0)
              {
                  Framebuffer?.Dispose();
                  Framebuffer = new Framebuffer(_context, (int)sizeInfo.NewSize.Width, (int)sizeInfo.NewSize.Height);
              }
          }
      
          protected override void OnDraw(DrawingContext drawingContext)
          {
              Framebuffer.D3dImage.Lock();
      
              Wgl.DXLockObjectsNV(_context.GlDeviceHandle, 1, new[] { Framebuffer.DxInteropRegisteredHandle });
              GL.BindFramebuffer(FramebufferTarget.Framebuffer, Framebuffer.GLFramebufferHandle);
      
              GL.Viewport(0, 0, Framebuffer.FramebufferWidth, Framebuffer.FramebufferHeight);
              Render?.Invoke(_stopwatch.Elapsed - _lastFrameStamp);
      
              GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);
              Wgl.DXUnlockObjectsNV(_context.GlDeviceHandle, 1, new[] { Framebuffer.DxInteropRegisteredHandle });
      
              Framebuffer.D3dImage.AddDirtyRect(new Int32Rect(0, 0, Framebuffer.FramebufferWidth, Framebuffer.FramebufferHeight));
              Framebuffer.D3dImage.Unlock();
      
              drawingContext.PushTransform(Framebuffer.TranslateTransform);
              drawingContext.PushTransform(Framebuffer.FlipYTransform);
      
              Rect rect = new(0, 0, Framebuffer.D3dImage.Width, Framebuffer.D3dImage.Height);
              drawingContext.DrawImage(Framebuffer.D3dImage, rect);
      
              drawingContext.Pop();
              drawingContext.Pop();
      
              UpdateFrame?.Invoke(this, _stopwatch.Elapsed - _lastFrameStamp);
          }
      }
      View Code

      使用示例:

       

      本文使用的代碼地址:

      c#版本:

      qian-o/SilkRenderer: WPF、WinUI3 Use Silk.NET to draw examples (OpenGL, DirectX) (github.com)

      posted @ 2023-02-13 15:47  o王先生o  閱讀(2702)  評論(5)    收藏  舉報
      主站蜘蛛池模板: 来安县| 熟女人妻精品一区二区视频| 亚洲AV无码不卡在线播放| 成人特黄A级毛片免费视频| 亚洲欧美牲交| 国产日本一区二区三区久久| 亚洲人成人伊人成综合网无码| 亚洲爆乳成av人在线视菜奈实 | 国产一区二区三区在线观看免费| 调兵山市| 亚洲性美女一区二区三区| 久久午夜无码鲁丝片午夜精品| 国产精品亚洲一区二区三区| 午夜福利在线永久视频| 中文字幕在线视频不卡一区二区 | 亚洲精品一区二区区别| 亚洲国产亚洲综合在线尤物| 亚洲国产日韩A在线亚洲| 99精品热在线在线观看视| 强插少妇视频一区二区三区| 亚洲人成在线观看| 精品国产乱码久久久久久浪潮| 人人超碰人摸人爱| 国产中文三级全黄| 国内精品人妻一区二区三区| 久久91精品牛牛| 综合久久av一区二区三区| 久久香蕉国产线看观看怡红院妓院| 凤凰县| 国产精品无码成人午夜电影| 欧美国产综合欧美视频| 国产成人啪精品午夜网站| 亚洲精品综合一区二区三区| 男女性高爱潮免费网站| 精品人妻午夜福利一区二区| 欧美乱强伦xxxx孕妇| 亚洲鸥美日韩精品久久| 无码AV无码免费一区二区| 大连市| 极品无码国模国产在线观看| 少妇特黄a一区二区三区|