无法使用 Direct2D 在其他位图之上绘制位图
Unable to draw bitmaps on top of other bitmap using Direct2D
我想编写一个使用 SharpDX 在背景图像上绘制许多对象的 Direct2D 应用程序。但是在绘制了一定数量的对象之后,Direct2D 将忽略所有其他对象。但是,前提是至少有 1 个对象与背景图像重叠。
这是我的渲染功能的简化版本:
private void Draw()
{
var zoom = 0.6f;
var destRect = new RectangleF(0, 0, _windowWidth, _windowHeight);
RenderTarget2D.DrawBitmap(_backgroundBitmap, destRect, 1.0f, BitmapInterpolationMode.Linear);
for (var j = 0; j < 10; j++)
{
for (var i = 0; i < 100; i++)
{
var d = (j % 10);
destRect = new RectangleF(i * 22 * zoom, j* 40 * zoom, 22 * zoom, 40 * zoom);
var srcRect = new RectangleF(d * 22, 40, 22, 40);
RenderTarget2D.DrawBitmap(_digits, destRect, 1.0f, BitmapInterpolationMode.Linear, srcRect);
}
}
}
The result is
第 9 行仅绘制了一部分,而第 10 行根本未绘制。
然而,当没有背景图像或没有前景对象接触背景图像时,所有 1000 个对象都会被正确渲染。
Result without background image
更令人困惑的是,当我将行数减少到 3 时,第 3 行不再绘制其所有对象,这在绘制超过 3 行时不会发生。
Result with 3 rows
我的申请有什么问题?
下面是源代码的其余部分(以防相关)...
private void Render()
{
RenderTarget2D.BeginDraw();
_deviceContext.Rasterizer.SetViewport(new Viewport(0, 0, _windowWidth, _windowHeight));
_deviceContext.OutputMerger.SetTargets(_backBufferView);
Draw();
_swapChain.Present(0, PresentFlags.None);
RenderTarget2D.EndDraw();
}
// Initialize DX objects
public void InitDX()
{
// SwapChain description
var desc = new SwapChainDescription()
{
BufferCount = 1,
ModeDescription = new ModeDescription(_windowWidth, _windowHeight, new Rational(60, 1), Format.R8G8B8A8_UNorm),
IsWindowed = true,
OutputHandle = DisplayHandle,
SampleDescription = new SampleDescription(1, 0),
SwapEffect = SwapEffect.Discard,
Usage = Usage.RenderTargetOutput
};
// Create Device and SwapChain
Factory2D = new SharpDX.Direct2D1.Factory();
SharpDX.Direct3D11.Device.CreateWithSwapChain(DriverType.Hardware, DeviceCreationFlags.BgraSupport, new[] { SharpDX.Direct3D.FeatureLevel.Level_10_0 }, desc, out _device, out _swapChain);
_deviceContext = _device.ImmediateContext;
// Ignore all windows events
SharpDX.DXGI.Factory factory = _swapChain.GetParent<SharpDX.DXGI.Factory>();
factory.MakeWindowAssociation(DisplayHandle, WindowAssociationFlags.IgnoreAll);
ResizeSwapChain(_windowWidth, _windowHeight);
}
// Resizes the swap-chain
public void ResizeSwapChain(int width, int height)
{
RenderTarget2D?.Dispose();
_backBuffer?.Dispose();
_backBufferView?.Dispose();
_surface?.Dispose();
_swapChain.ResizeBuffers(1, width, height, Format.Unknown, SwapChainFlags.AllowModeSwitch);
_backBuffer = Resource.FromSwapChain<Texture2D>(_swapChain, 0);
_backBufferView = new RenderTargetView(_device, _backBuffer);
_surface = _backBuffer.QueryInterface<Surface>();
var dpi = Factory2D.DesktopDpi;
RenderTarget2D = new RenderTarget(Factory2D, _surface, new RenderTargetProperties(RenderTargetType.Hardware, new PixelFormat(Format.Unknown, AlphaMode.Premultiplied), dpi.Width, dpi.Height, RenderTargetUsage.None, SharpDX.Direct2D1.FeatureLevel.Level_DEFAULT));
}
// Loads a Direct2D Bitmap from a file
public static Bitmap LoadBitmapFromFile(string file)
{
var winBitmap = (System.Drawing.Bitmap)System.Drawing.Image.FromFile(file);
var dxBitmap = CreateDirect2DBitmap(winBitmap, true);
dxBitmap.Tag = file;
winBitmap.Dispose();
return dxBitmap;
}
// Creates a Direct2D from a System.Drawing.Bitmap
public static Bitmap CreateDirect2DBitmap(System.Drawing.Bitmap src, bool swapChannels)
{
var sourceArea = new System.Drawing.Rectangle(0, 0, src.Width, src.Height);
var bitmapProperties = new BitmapProperties(new PixelFormat(Format.R8G8B8A8_UNorm, AlphaMode.Premultiplied));
var size = new Size2(src.Width, src.Height);
// Transform pixels from BGRA to RGBA
int stride = src.Width * sizeof(int);
using (var tempStream = new DataStream(src.Height * stride, true, true))
{
// Lock System.Drawing.Bitmap
var bitmapData = src.LockBits(sourceArea, ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
// Convert all pixels
if (swapChannels)
{
for (int y = 0; y < src.Height; y++)
{
int offset = bitmapData.Stride * y;
for (int x = 0; x < src.Width; x++)
{
// Not optimized
byte b = Marshal.ReadByte(bitmapData.Scan0, offset++);
byte g = Marshal.ReadByte(bitmapData.Scan0, offset++);
byte r = Marshal.ReadByte(bitmapData.Scan0, offset++);
byte a = Marshal.ReadByte(bitmapData.Scan0, offset++);
int rgba = r | (g << 8) | (b << 16) | (a << 24);
tempStream.Write(rgba);
}
}
}
Bitmap result;
if (swapChannels)
{
tempStream.Position = 0;
result = new Bitmap(RenderTarget2D, size, tempStream, stride, bitmapProperties);
}
else
{
result = new Bitmap(RenderTarget2D, size, new DataStream(bitmapData.Scan0, stride * src.Height, true, false), stride, bitmapProperties);
}
src.UnlockBits(bitmapData);
return result;
}
}
我觉得问题是你还没画完就present了。您应该重新排序这些电话:
RenderTarget2D.EndDraw();
_swapChain.Present(0, PresentFlags.None);
我想编写一个使用 SharpDX 在背景图像上绘制许多对象的 Direct2D 应用程序。但是在绘制了一定数量的对象之后,Direct2D 将忽略所有其他对象。但是,前提是至少有 1 个对象与背景图像重叠。
这是我的渲染功能的简化版本:
private void Draw()
{
var zoom = 0.6f;
var destRect = new RectangleF(0, 0, _windowWidth, _windowHeight);
RenderTarget2D.DrawBitmap(_backgroundBitmap, destRect, 1.0f, BitmapInterpolationMode.Linear);
for (var j = 0; j < 10; j++)
{
for (var i = 0; i < 100; i++)
{
var d = (j % 10);
destRect = new RectangleF(i * 22 * zoom, j* 40 * zoom, 22 * zoom, 40 * zoom);
var srcRect = new RectangleF(d * 22, 40, 22, 40);
RenderTarget2D.DrawBitmap(_digits, destRect, 1.0f, BitmapInterpolationMode.Linear, srcRect);
}
}
}
The result is
第 9 行仅绘制了一部分,而第 10 行根本未绘制。
然而,当没有背景图像或没有前景对象接触背景图像时,所有 1000 个对象都会被正确渲染。
Result without background image
更令人困惑的是,当我将行数减少到 3 时,第 3 行不再绘制其所有对象,这在绘制超过 3 行时不会发生。
Result with 3 rows
我的申请有什么问题?
下面是源代码的其余部分(以防相关)...
private void Render()
{
RenderTarget2D.BeginDraw();
_deviceContext.Rasterizer.SetViewport(new Viewport(0, 0, _windowWidth, _windowHeight));
_deviceContext.OutputMerger.SetTargets(_backBufferView);
Draw();
_swapChain.Present(0, PresentFlags.None);
RenderTarget2D.EndDraw();
}
// Initialize DX objects
public void InitDX()
{
// SwapChain description
var desc = new SwapChainDescription()
{
BufferCount = 1,
ModeDescription = new ModeDescription(_windowWidth, _windowHeight, new Rational(60, 1), Format.R8G8B8A8_UNorm),
IsWindowed = true,
OutputHandle = DisplayHandle,
SampleDescription = new SampleDescription(1, 0),
SwapEffect = SwapEffect.Discard,
Usage = Usage.RenderTargetOutput
};
// Create Device and SwapChain
Factory2D = new SharpDX.Direct2D1.Factory();
SharpDX.Direct3D11.Device.CreateWithSwapChain(DriverType.Hardware, DeviceCreationFlags.BgraSupport, new[] { SharpDX.Direct3D.FeatureLevel.Level_10_0 }, desc, out _device, out _swapChain);
_deviceContext = _device.ImmediateContext;
// Ignore all windows events
SharpDX.DXGI.Factory factory = _swapChain.GetParent<SharpDX.DXGI.Factory>();
factory.MakeWindowAssociation(DisplayHandle, WindowAssociationFlags.IgnoreAll);
ResizeSwapChain(_windowWidth, _windowHeight);
}
// Resizes the swap-chain
public void ResizeSwapChain(int width, int height)
{
RenderTarget2D?.Dispose();
_backBuffer?.Dispose();
_backBufferView?.Dispose();
_surface?.Dispose();
_swapChain.ResizeBuffers(1, width, height, Format.Unknown, SwapChainFlags.AllowModeSwitch);
_backBuffer = Resource.FromSwapChain<Texture2D>(_swapChain, 0);
_backBufferView = new RenderTargetView(_device, _backBuffer);
_surface = _backBuffer.QueryInterface<Surface>();
var dpi = Factory2D.DesktopDpi;
RenderTarget2D = new RenderTarget(Factory2D, _surface, new RenderTargetProperties(RenderTargetType.Hardware, new PixelFormat(Format.Unknown, AlphaMode.Premultiplied), dpi.Width, dpi.Height, RenderTargetUsage.None, SharpDX.Direct2D1.FeatureLevel.Level_DEFAULT));
}
// Loads a Direct2D Bitmap from a file
public static Bitmap LoadBitmapFromFile(string file)
{
var winBitmap = (System.Drawing.Bitmap)System.Drawing.Image.FromFile(file);
var dxBitmap = CreateDirect2DBitmap(winBitmap, true);
dxBitmap.Tag = file;
winBitmap.Dispose();
return dxBitmap;
}
// Creates a Direct2D from a System.Drawing.Bitmap
public static Bitmap CreateDirect2DBitmap(System.Drawing.Bitmap src, bool swapChannels)
{
var sourceArea = new System.Drawing.Rectangle(0, 0, src.Width, src.Height);
var bitmapProperties = new BitmapProperties(new PixelFormat(Format.R8G8B8A8_UNorm, AlphaMode.Premultiplied));
var size = new Size2(src.Width, src.Height);
// Transform pixels from BGRA to RGBA
int stride = src.Width * sizeof(int);
using (var tempStream = new DataStream(src.Height * stride, true, true))
{
// Lock System.Drawing.Bitmap
var bitmapData = src.LockBits(sourceArea, ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
// Convert all pixels
if (swapChannels)
{
for (int y = 0; y < src.Height; y++)
{
int offset = bitmapData.Stride * y;
for (int x = 0; x < src.Width; x++)
{
// Not optimized
byte b = Marshal.ReadByte(bitmapData.Scan0, offset++);
byte g = Marshal.ReadByte(bitmapData.Scan0, offset++);
byte r = Marshal.ReadByte(bitmapData.Scan0, offset++);
byte a = Marshal.ReadByte(bitmapData.Scan0, offset++);
int rgba = r | (g << 8) | (b << 16) | (a << 24);
tempStream.Write(rgba);
}
}
}
Bitmap result;
if (swapChannels)
{
tempStream.Position = 0;
result = new Bitmap(RenderTarget2D, size, tempStream, stride, bitmapProperties);
}
else
{
result = new Bitmap(RenderTarget2D, size, new DataStream(bitmapData.Scan0, stride * src.Height, true, false), stride, bitmapProperties);
}
src.UnlockBits(bitmapData);
return result;
}
}
我觉得问题是你还没画完就present了。您应该重新排序这些电话:
RenderTarget2D.EndDraw();
_swapChain.Present(0, PresentFlags.None);