WPF мерцает во время анимации в Viewport3D - PullRequest
4 голосов
/ 15 февраля 2011

У меня странное поведение в приложении WPF, которое я пишу.Когда я запускаю анимацию в положении камеры (Point3DAnimation в PerspectiveCamera.PositionProperty), я получаю очень плохие мерцающие артефакты внутри приложения.3D-рендеринг объекта, кажется, исчезает для определенных кадров и позволяет фону окна просвечивать.

Я написал очень простой пример приложения ниже, чтобы продемонстрировать проблему на моем компьютере.Чтобы использовать его, просто скомпилируйте его и используйте клавиши со стрелками вверх и вниз для увеличения и уменьшения масштаба.Проблема очень повторяется на моей машине: каждый раз, когда я пытаюсь увеличить или уменьшить масштаб, объект мерцает во время анимации и затем снова становится «твердым» после завершения анимации.

Я работаю под управлением Windows 732-битная и с использованием NVIDIA GeForce 8600GT.Вот несколько интересных деталей:

1) Похоже, это связано с аппаратным обеспечением.Я разместил сообщение на форумах WPF, и один пользователь ответил, что все выглядит хорошо для него.Я попросил нескольких друзей попробовать его, и один из них сообщил о том же мерцании, с которым я столкнулся, а другой сказал, что все выглядит хорошо.

2) Принудительная вертикальная синхронизация и включение тройной буферизации через панель управления NVIDIA нене решить проблему.

3) Уменьшение требуемого FPS анимации значительно улучшает проблему.При низкой требуемой частоте кадров (скажем, 5 кадров в секунду) мерцание исчезает ... но тогда анимация выглядит ужасно.Пример приложения, который я предоставляю ниже, показывает только одно изображение, отображенное на четырехугольник, поэтому я не думаю, что это должно быть связано с вычислительной мощностью!

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);
    }
  }
}

Ответы [ 5 ]

2 голосов
/ 07 июля 2016

Это старый старый вопрос, но, поскольку я боролся с точно такой же проблемой и, наконец, нашел рабочее решение, я подумал, что примечание здесь может стоить:

Как уже упоминал Абрам, NearPlaneDistance была для меня решением, но я совсем не установил для него маленькое значение. На самом деле, мне пришлось пройти весь путь до 25. В модели, которую я рисую, все велико. 1 единица равна 1 миллиметру, и никакие плоскости не отводятся ближе, чем на 10 единиц друг от друга. Поскольку я продолжал увеличивать NearPlaneDistance все выше и выше, разрывы становились все меньше и меньше, пока в 25 не все работает отлично.

Итак, если кто-то еще борется с этим, поэкспериментируйте с NearPlaneDistance.

1 голос
/ 04 января 2012

Я знаю, что это старый вопрос, но я столкнулся с этой ошибкой на работе и около 10 часов находился у стены, прежде чем наконец нашел решение. Я надеюсь, что это поможет кому-то еще -

Вам необходимо вручную установить высоту / ширину Viewport3d. Он не должен быть жестко запрограммирован (вы можете связать его, жестко закодировать, поместить область просмотра в сетку и т. Д.). По моему опыту, размер области просмотра должен быть МЕНЬШЕ, чем размер окна.

Рабочее допущение здесь заключается в том, что WPF испытывает некоторые затруднения при определении того, находится ли изображение в области просмотра в пределах видимого окна.

В любом случае, HTH

1 голос
/ 23 февраля 2011

Я столкнулся с подобной проблемой, используя PerspectiveCamera с динамическим позиционированием камеры. Кажется, что камера «запутывается» в том, показывать или нет объект (или его части), когда он находится слишком близко к камере, и часть какого-либо объекта - даже объекта на «заднем плане» - частично скрыта. ..

Попробуйте установить для параметра "NearPlaneDistance" для вашей PerspectiveCamera низкое, но ненулевое значение, например 0,001.

0 голосов
/ 24 августа 2011

Я собираюсь пометить это как решенное, хотя фактического решения не найдено.Пока модели находились в пределах области экрана и не выходили за ее пределы, мерцания не происходило.Извините!

0 голосов
/ 15 февраля 2011

Ваша анимация запускается событием KeyDown - если пользователь удерживает клавишу нажатой, вы можете перегружать ваше приложение вызовами BeginAnimation.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...