簡體   English   中英

WPF在Viewport3D中的動畫期間閃爍

[英]WPF flickering during animation in Viewport3D

我在寫作的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);
    }
  }
}

這是一個古老的問題,但由於我遇到了完全相同的問題並最終找到了一個有效的解決方案,我認為這里的注釋可能是值得的:

正如亞伯蘭已經提到的,NearPlaneDistance對我來說是解決方案,但我根本沒有把它設置為小值。 事實上,對我來說,我必須一直到25歲。在我畫的模型中,一切都很大。 1個單位是1毫米,並且沒有平面彼此拉近10個單位。 隨着我不斷增加NearPlaneDistance越來越高,撕裂越來越少,直到25歲時一切都很好。

因此,如果其他人正在努力解決這個問題,請嘗試使用NearPlaneDistance。

我使用帶有動態相機定位的PerspectiveCamera遇到了類似的問題。 當相機太靠近相機並且任何物體的一部分 - 甚至是“背景”中的物體 - 被部分遮擋時,相機似乎對於是否顯示物體(或部分物體)感到“困惑”。 ..

嘗試將PerspectiveCamera的“NearPlaneDistance”設置為較低但非零的值,例如0.001。

我知道這是一個較老的問題,但我在工作中碰到了這個錯誤,並且在我終於找到解決方案之前已經在牆上撞了大約10個小時。 我希望這有助於其他人 -

您需要手動設置Viewport3d的高度/寬度。 它不必是硬編碼的(您可以綁定它,硬編碼,將視口放在網格中等)。 根據我的經驗,視口的大小必須小於窗口大小。

這里的工作假設是WPF在判斷視口中的圖像是否在可視窗口內時遇到一些麻煩。

無論如何,HTH

您的動畫由KeyDown事件觸發 - 如果用戶按住該鍵,您可能會使用BeginAnimation調用壓倒您的應用程序。

即使找不到實際的解決方案,我也會將其標記為已解決。 只要模型保持在屏幕區域內並且沒有延伸過屏幕,就不會發生閃爍。 抱歉!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM