Mat*_*att 5 wpf directx-11 managed-directx sharpdx
我试图在WPF应用程序中通过SharpDX使用DirectX11在窗口中平滑地滚动一些图像.
一点背景:
图像是信号返回,随时间变化,从文件加载并作为纹理数组加载到D3D中,图像本身呈现为一系列纹理四边形(一系列相邻的矩形,在很长的水平线上) ).设置视口,使左右边缘表示时间偏移,并且信号显示在这些时间之间的时间段内.DirectX实现非常简单; 四个顶点生成一次,一个非常小的每帧缓冲区包含一个简单的2D世界视图变换,根据当前可见范围/缩放等更新缩放和平移.据我所知,D3D实现不是我遇到的问题的一部分 - 它确实是一个非常简单的设置,并且似乎渲染非常快(应该如此),虽然我确实有一些更好的东西(根据需要从磁盘传输纹理),但我有禁用所有这些并运行非常简单(小)纹理,而我尝试解决我遇到的问题..
问题:
当可见时间范围被动画化时,图像的滚动不平滑.图像在很多时候"抖动",坦率地看起来很糟糕(当它不抖动时,它看起来很棒).
设置:
DirectX渲染到D3DImage,在幕后进行一些工作以使DX11工作 - 此代码取自https://sharpdxwpf.codeplex.com/
有多个D3DImages(最多总共4个),排列在一个网格中(我已经测试了两个,两个都包含相同时间段的信号并一起动画).
这些D3DImages由DrawingVisual(由自定义FrameworkElement托管)绘制,它们被用作ImageBrush的源.frameworkelement对象根据需要触发渲染,绘图视觉处理D3D渲染调用并绘制一个矩形以使用D3DImage画笔填充控件.
使用WPF DoubleAnimation动画时间范围值.当前显示的视觉效果通过INotifyPropertyChanged绑定到此值,并在每次更改时触发渲染(通过InvalidateVisual).
DrawingVisual呈现代码,由"位置"值(可见时间范围的开始)的更改触发:
// update scene per-frame buffer first, with world-view transform
using (DrawingContext dc = RenderOpen()
{
_scene.Renderer.Render(_draw_args);
_image.Invalidate();
dc.DrawRectangle(_brush, null, new Rect(viewer.RenderSize));
}
Run Code Online (Sandbox Code Playgroud)
我尝试过的:
我已经尝试过很多东西(并经过大量搜索)来尝试确定问题是由于抖动渲染请求计时,还是问题是否进一步进入渲染过程.
(不用说,这是非常"测试"代码):
Stopwatch rsw;
long last_time = 0;
void play()
{
rsw = new Stopwatch();
last_time = 0;
rsw.Start();
CompositionTarget.Rendering += rendering;
}
void rendering(object sender, EventArgs e)
{
double update_distance = rsw.ElapsedMilliseconds - last_time;
Position += 10 * update_distance;
last_time = rsw.ElapsedMilliseconds;
}
Run Code Online (Sandbox Code Playgroud)
结果 - 比简单的双动画更糟糕.
原始尝试以及变体1和2都尝试更新单个值,然后触发相关方的呈现.出于兴趣,我记录了渲染请求到达绘图视觉时之间的时间差异 - 尽管DisptacherTimer实际上给出了最一致的结果(WPF动画和CompositionTarget都丢弃了奇数帧),DisptacherTimer也给出了最震撼的动画.
更新图像,但不会使视觉无效.更新ImageBrush的源会更新显示的图像,而无需重新渲染DrawingVisual.这种方法产生了非常紧张的结果.
CompositionTarget.Rendering在框架元素本身.这产生了最好的结果,但仍然不完美.抖动会发生,然后消散,只会再次返回.在这种方法中,保存DV的框架元素连接到CompositionTarget.Rendering,并且视觉查询当前位置,该位置是独立动画的.我几乎可以忍受这种方法.
尝试等待D3D场景渲染,然后使图像无效(无可识别的改进):
_scene.Renderer.Render(_draw_args);
_scene.Renderer.Device.ImmediateContext.End(Q);
while(!(_ scene.Renderer.Device.ImmediateContext.IsDataAvailable(q)))Thread.Yield();
_image.Invalidate();
观察:
编辑
我尽可能地回过头来试图找出问题,而这个问题似乎是WPF更新和呈现D3DImage的方式的基础.
我修改了SharpDX Samples解决方案中的WPFHost示例,以便在屏幕上显示所显示的简单三角形.此示例托管在DX10ImageSource中,该源由CompositionTarget.Rendering上的DPFCanvas呈现.
这个例子不可能更简单,并且在WPF中渲染D3DImage时可以获得"接近金属".一个三角形,在屏幕上翻译一个由渲染之间的时差计算出来的值.口吃仍然存在,来来往往,好像某种同步问题.它令我感到困惑,但基本上使得SharpDX在WPF中无法用于任何类型的平滑动画,这是非常令人失望的.
如果有人有兴趣重现这个问题,可以在这里找到SharpDX样本:https://github.com/sharpdx/SharpDX-Samples
我对WPFHost示例进行了以下简单更改:
void IScene.Render()
{
...
EffectMatrixVariable wv = this.SimpleEffect.GetVariableBySemantic("WorldView").AsMatrix();
wv.SetMatrix(this.WorldViewMatrix);
...
}
void IScene.Update(TimeSpan sceneTime)
{
float x = (float)sceneTime.Milliseconds * 0.001f - 0.5f;
WorldViewMatrix = Matrix.Translation(x, 0, 0);
}
Run Code Online (Sandbox Code Playgroud)
并在着色器Simple.fx中:
float4x4 WorldViewTransform : WorldView;
PS_IN VS( VS_IN input )
{
PS_IN output = (PS_IN)0;
output.pos = mul(input.pos, WorldViewTransform);
output.col = input.col * Overlay;
return output;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
887 次 |
| 最近记录: |