Win2D:正确使用 CanvasVirtualControl
Win2D: Correct usage of CanvasVirtualControl
我想绘制取自 Win2D-Example-Gallery 的 mandelbrot-set 并稍微调整一下。
起初我有所有代码在 CreateResources
-CanvasAnimatedControl
方法中生成 mandelbrot,但由于性能问题,我继续使用着色器(HLSL 或 PixelShaderEffect
) 和 CanvasVirtualControl
:
public PixelShaderEffect _effectMandel;
CanvasVirtualImageSource _sdrc;
public async Task CreateResources(CanvasVirtualControl sender)
{
_sdrc = new CanvasVirtualImageSource(sender, new Size(_width, _height));
var arr = await FileHelper.ReadAllBytes("Shaders/Mandelbrot.bin");
if (arr != null)
{
_effectMandel = new PixelShaderEffect(arr);
using (CanvasDrawingSession drawingSession = sender.CreateDrawingSession(new Rect(0,0,_width,_height)))
{
drawingSession.DrawImage(_effectMandel);
}
}
}
当我 运行 应用程序时,我在使用部分得到一个 System.Runtime.InteropServices.COMException
并且 'App.g.i.cs' 文件打开告诉我:
我使用的shader代码是这样的:
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
// This shader has no input textures.
// It generates a mandelbrot fractal.
#define D2D_INPUT_COUNT 0
#define D2D_REQUIRES_SCENE_POSITION
#include "d2d1effecthelpers.hlsli"
float scale;
float2 translate;
static const float4 tapOffsetsX = float4(-0.25, 0.25, -0.25, 0.25);
static const float4 tapOffsetsY = float4(-0.25, -0.25, 0.25, 0.25);
static const int iterations = 100;
D2D_PS_ENTRY(main)
{
float2 pos = D2DGetScenePosition().xy;
// Improve visual quality by supersampling inside the pixel shader, evaluating four separate
// versions of the fractal in parallel, each at a slightly different position offset.
// The x, y, z, and w components of these float4s contain the four simultaneous computations.
float4 c_r = (pos.x + tapOffsetsX) * scale + translate.x;
float4 c_i = (pos.y + tapOffsetsY) * scale + translate.y;
float4 value_r = 0;
float4 value_i = 0;
// Evalulate the Mandelbrot fractal.
for (int i = 0; i < iterations; i++)
{
float4 new_r = value_r * value_r - value_i * value_i + c_r;
float4 new_i = value_r * value_i * 2 + c_i;
value_r = new_r;
value_i = new_i;
}
// Adjust our four parallel results to range 0:1.
float4 distanceSquared = value_r * value_r + value_i * value_i;
float4 vectorResult = isfinite(distanceSquared) ? saturate(1 - distanceSquared) : 0;
// Resolve the supersampling to produce a single scalar result.
float result = dot(vectorResult, 0.25);
if (result < 1.0 / 256)
return 0;
else
return float4(result, result, result, 1);
}
如果你知道为什么会这样,请回答。谢谢!
我需要设置一个计时器来定期使 canvas 无效并获得 60fps。
我再次查看了 Microsoft 示例并最终使用以下代码解决了这个问题:
DispatcherTimer timer;
internal void Regions_Invalidated(CanvasVirtualControl sender, CanvasRegionsInvalidatedEventArgs args)
{
// Configure the Mandelbrot effect to position and scale its output.
float baseScale = 0.005f;
float scale = (baseScale * 96 / sender.Dpi) / (helper._modifiers[1] / 1000f);
var controlSize = baseScale * sender.Size.ToVector2() * scale;
Vector2 translate = (baseScale * sender.Size.ToVector2() * new Vector2(-0.5f,-0f));
_effectMandel.Properties["scale"] = scale;
_effectMandel.Properties["translate"] = (Microsoft.Graphics.Canvas.Numerics.Vector2)translate;
#endif
// Draw the effect to whatever regions of the CanvasVirtualControl have been invalidated.
foreach (var region in args.InvalidatedRegions)
{
using (var drawingSession = sender.CreateDrawingSession(region))
{
drawingSession.DrawImage(_effectMandel);
}
}
// start timer for fps
this.timer = new DispatcherTimer();
int fps = 60;
this.timer.Interval = new TimeSpan(0, 0, 0, 0, 100 / fps);
this.timer.Tick += timer_Tick;
this.timer.Start();
}
private void timer_Tick(object sender, object e)
{
this.timer.Stop();
_canvas.Invalidate();
}
希望这对某人有帮助。
我想绘制取自 Win2D-Example-Gallery 的 mandelbrot-set 并稍微调整一下。
起初我有所有代码在 CreateResources
-CanvasAnimatedControl
方法中生成 mandelbrot,但由于性能问题,我继续使用着色器(HLSL 或 PixelShaderEffect
) 和 CanvasVirtualControl
:
public PixelShaderEffect _effectMandel;
CanvasVirtualImageSource _sdrc;
public async Task CreateResources(CanvasVirtualControl sender)
{
_sdrc = new CanvasVirtualImageSource(sender, new Size(_width, _height));
var arr = await FileHelper.ReadAllBytes("Shaders/Mandelbrot.bin");
if (arr != null)
{
_effectMandel = new PixelShaderEffect(arr);
using (CanvasDrawingSession drawingSession = sender.CreateDrawingSession(new Rect(0,0,_width,_height)))
{
drawingSession.DrawImage(_effectMandel);
}
}
}
当我 运行 应用程序时,我在使用部分得到一个 System.Runtime.InteropServices.COMException
并且 'App.g.i.cs' 文件打开告诉我:
我使用的shader代码是这样的:
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
// This shader has no input textures.
// It generates a mandelbrot fractal.
#define D2D_INPUT_COUNT 0
#define D2D_REQUIRES_SCENE_POSITION
#include "d2d1effecthelpers.hlsli"
float scale;
float2 translate;
static const float4 tapOffsetsX = float4(-0.25, 0.25, -0.25, 0.25);
static const float4 tapOffsetsY = float4(-0.25, -0.25, 0.25, 0.25);
static const int iterations = 100;
D2D_PS_ENTRY(main)
{
float2 pos = D2DGetScenePosition().xy;
// Improve visual quality by supersampling inside the pixel shader, evaluating four separate
// versions of the fractal in parallel, each at a slightly different position offset.
// The x, y, z, and w components of these float4s contain the four simultaneous computations.
float4 c_r = (pos.x + tapOffsetsX) * scale + translate.x;
float4 c_i = (pos.y + tapOffsetsY) * scale + translate.y;
float4 value_r = 0;
float4 value_i = 0;
// Evalulate the Mandelbrot fractal.
for (int i = 0; i < iterations; i++)
{
float4 new_r = value_r * value_r - value_i * value_i + c_r;
float4 new_i = value_r * value_i * 2 + c_i;
value_r = new_r;
value_i = new_i;
}
// Adjust our four parallel results to range 0:1.
float4 distanceSquared = value_r * value_r + value_i * value_i;
float4 vectorResult = isfinite(distanceSquared) ? saturate(1 - distanceSquared) : 0;
// Resolve the supersampling to produce a single scalar result.
float result = dot(vectorResult, 0.25);
if (result < 1.0 / 256)
return 0;
else
return float4(result, result, result, 1);
}
如果你知道为什么会这样,请回答。谢谢!
我需要设置一个计时器来定期使 canvas 无效并获得 60fps。 我再次查看了 Microsoft 示例并最终使用以下代码解决了这个问题:
DispatcherTimer timer;
internal void Regions_Invalidated(CanvasVirtualControl sender, CanvasRegionsInvalidatedEventArgs args)
{
// Configure the Mandelbrot effect to position and scale its output.
float baseScale = 0.005f;
float scale = (baseScale * 96 / sender.Dpi) / (helper._modifiers[1] / 1000f);
var controlSize = baseScale * sender.Size.ToVector2() * scale;
Vector2 translate = (baseScale * sender.Size.ToVector2() * new Vector2(-0.5f,-0f));
_effectMandel.Properties["scale"] = scale;
_effectMandel.Properties["translate"] = (Microsoft.Graphics.Canvas.Numerics.Vector2)translate;
#endif
// Draw the effect to whatever regions of the CanvasVirtualControl have been invalidated.
foreach (var region in args.InvalidatedRegions)
{
using (var drawingSession = sender.CreateDrawingSession(region))
{
drawingSession.DrawImage(_effectMandel);
}
}
// start timer for fps
this.timer = new DispatcherTimer();
int fps = 60;
this.timer.Interval = new TimeSpan(0, 0, 0, 0, 100 / fps);
this.timer.Tick += timer_Tick;
this.timer.Start();
}
private void timer_Tick(object sender, object e)
{
this.timer.Stop();
_canvas.Invalidate();
}
希望这对某人有帮助。