【发布时间】:2011-06-27 17:20:53
【问题描述】:
我正在编写的 WPF 应用程序中有一些奇怪的行为。当我在相机位置上运行动画时(PerspectiveCamera.PositionProperty 上的 Point3DAnimation),我在应用程序中得到了非常糟糕的闪烁伪影。对于某些帧,3D 渲染的对象似乎消失了,并允许窗口的背景显示出来。
我在下面编写了一个非常简单的示例应用程序来演示我机器上的问题。要使用它,只需编译它并使用向上和向下箭头键来放大和缩小。这个问题在我的机器上很容易重复:每次我尝试放大或缩小时,对象都会在动画期间闪烁,然后在动画完成后再次变为“实心”。
我正在运行 Windows 7 32 位并使用 NVIDIA GeForce 8600GT。以下是一些有趣的细节:
1) 似乎与硬件有关。我在 WPF 论坛上发了一个帖子,一位用户回复说一切对他来说都很好。我已经请了几个朋友尝试一下,其中一位报告的闪烁与我遇到的完全相同,另一位则说一切正常。
2) 通过 NVIDIA 控制面板强制垂直同步和启用三重缓冲并不能解决问题。
3) 降低动画所需的 FPS 会显着改善问题。在所需的低帧速率(例如 5FPS)下,闪烁消失了……但是动画看起来很糟糕。我在下面提供的示例应用程序仅显示了映射到四边形的单个图像,因此我认为这不应该是处理能力的问题!
4) 问题似乎与可见窗口之外的多边形顶点直接相关。如果我在程序中将 closeDist 值设置为 4(这样即使“放大”对象仍然完全适合窗口),则 没有闪烁。但是,当我增加 closeDist 时,一旦达到“放大”状态的顶点超出窗口的值,就会发生闪烁。随着我增加 closeDist,闪烁似乎逐渐更糟。值为 9.8(就在相机的 NearPlaneDistance 完全切断对象之前),闪烁最严重。
事不宜迟,下面是示例代码!
MainWindow.xaml:
<Window x:Class="WPFFlickerTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
KeyDown="Window_KeyDown">
<Grid>
<Viewport3D Name="Viewport">
<Viewport3D.Camera>
<PerspectiveCamera LookDirection="0,0,1" FieldOfView="70" x:Name="viewportCam" />
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<AmbientLight />
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</Grid>
</Window>
MainWindow.xaml.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Media.Media3D;
using System.Windows.Media.Animation;
namespace WPFFlickerTest
{
public partial class MainWindow : Window
{
// time the camera animation takes to complete
private const double animTime = 0.25;
// path to an image to use (assuming it's 1920x1200 or 1.6 aspect ratio)
private const string imagePath = "C:/Windows/Web/Wallpaper/Windows/img0.jpg";
// far and close camera distances
private const double closeDist = 8, farDist = 10;
// chosen to align with aspect ratio of the image
private const double halfW = 4.8, halfH = 3;
public MainWindow()
{
InitializeComponent();
Model3DGroup modelGroup = new Model3DGroup();
// set up the mesh
MeshGeometry3D mesh = new MeshGeometry3D();
mesh.Positions.Add(new Point3D(-halfW, halfH, farDist));
mesh.Positions.Add(new Point3D(halfW, halfH, farDist));
mesh.Positions.Add(new Point3D(halfW, -halfH, farDist));
mesh.Positions.Add(new Point3D(-halfW, -halfH, farDist));
// set up triangle indices
mesh.TriangleIndices = (Int32Collection)new Int32CollectionConverter().ConvertFromString(
"0,1,2 2,3,0");
// set up texture coords
mesh.TextureCoordinates = (PointCollection)new PointCollectionConverter().ConvertFromString(
"1,0 0,0 0,1 1,1");
// set up the brush
ImageBrush brush = new ImageBrush(new BitmapImage(new Uri(imagePath, UriKind.Relative)));
// create a geometry model based on the mesh and give it a material based on an image
GeometryModel3D geom = new GeometryModel3D(mesh, new DiffuseMaterial(brush));
// add the object
modelGroup.Children.Add(geom);
// we should have filled in our objects now
// so we'll just add them to the viewport
ModelVisual3D modelVisual = new ModelVisual3D();
modelVisual.Content = modelGroup;
Viewport.Children.Add(modelVisual);
}
// react to keypresses
private void Window_KeyDown(object sender, KeyEventArgs e)
{
switch (e.Key)
{
// move the camera to the centre
case Key.Down: AnimateTo(new Point3D(0, 0, 0)); break;
// move the camera to the currently targeted image
case Key.Up: AnimateTo(new Point3D(0, 0, closeDist)); break;
}
}
// animate to a given position
void AnimateTo(Point3D position)
{
Point3DAnimation camPosAnim = new Point3DAnimation(position, TimeSpan.FromSeconds(animTime));
viewportCam.BeginAnimation(PerspectiveCamera.PositionProperty, camPosAnim);
}
}
}
【问题讨论】:
-
试一试,我觉得它看起来不错......所以你的预感确实与硬件相关听起来很准确。我在笔记本电脑上...没什么特别的...运行 .NET 3.5 SP1;你更新你的 DirectX/Direct3D 了吗?
-
@Aaron 很好的建议。我尝试获取最新的 DirectX 运行时,但被告知我已经有了更新或等效的版本。 dxdiag 显示我正在运行 DirectX 11。我注意到另一个有趣的花絮,我将在下面发布。
-
@Aaron 有趣。我可能会尝试降级以查看是否可以解决问题。我刚刚添加了“有趣的细节 #4”。它似乎与超出窗口边界的多边形顶点有关。也许要让问题在您的机器上显示出来,请尝试将 closeDist 值更改为 9.8 以增加缩放因子以查看是否有任何闪烁。感谢您的帮助!
-
@aardvarkk 我在 closeDist = 8, farDist = 10 运行它,我注意到动画中的过渡,但无论如何我都不会认为它们不好;所以我很确定事情的动画效果仍然很好
-
@Aaron 看来你已经幸免于难了!在我的机器上效果非常很明显。感谢您调查它。我会看看我能不能抓住更多有趣的花絮……
标签: wpf animation 3d flicker perspectivecamera