WPF中3D表面上的图像缩放质量问题

4
我有一个使用WPF 3D图形创建的图像查看器。在那里,图像质量真的很差,所以我开始研究这个问题,创建了一个简单的应用程序,在窗口的顶部使用2D图形显示图像,在底部使用3D图形显示相同的图像。我注意到,与2D图像相比,3D表面上的图像看起来要差得多。3D表面上的颜色饱和度较低,没有清晰的边界。请注意,我将线性位图缩放模式应用于根网格。另一个奇怪的事情是,当我将位图缩放模式更改为“Fant”或“NearestNeighbor”时,它会影响2D图形,但3D表面上的图像仍然保持不变!我在代码中使用高度=466像素,宽度=490像素的图像进行示例。我在代码中对其进行了一些缩小(包括2D和3D实现),以查看缩放质量的降低。代码如下:
<Window x:Class="Scaling3DSample.Window2"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="340">
        <Grid x:Name="backgroundGrid">
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />
            </Grid.RowDefinitions>
        </Grid>
</Window>

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using System.Windows.Shapes;
    namespace Scaling3DSample
    {
        public partial class Window2 : Window
        {
            private static double _distanceFromCamera = 0.62618;

            public Window2()
            {
                InitializeComponent();
                RenderOptions.SetBitmapScalingMode(backgroundGrid, BitmapScalingMode.Linear);
                Create2DGraphics();
                // THE SAME IMAGE ON 3D SURFACE LOOKS MUCH WORSE
                Create3DGraphics();
            }

            private void Create2DGraphics()
            {
                Rectangle exampleRectangle = new Rectangle();
                Grid.SetRow(exampleRectangle, 0);

                exampleRectangle.Width = 335;
                exampleRectangle.Height = 317;
                exampleRectangle.Fill = GetBrush();
                backgroundGrid.Children.Add(exampleRectangle);
            }

            private void Create3DGraphics()
            {
                Viewport3D mainViewPort3D = new Viewport3D();
                Grid.SetRow(mainViewPort3D, 1);

                mainViewPort3D.Camera = new PerspectiveCamera { LookDirection = new Vector3D(-1, 0, 0), UpDirection = new Vector3D(0, 0, 1), FieldOfView = 77.0942 };
                mainViewPort3D.Children.Add(new ModelVisual3D { Content = new AmbientLight() });

                MeshGeometry3D geometry3D = new MeshGeometry3D();

                Point3D topLeft = new Point3D(-_distanceFromCamera, 0.5, -0.5);
                Point3D bottomRight = new Point3D(-_distanceFromCamera, -0.5, 0.5);

                geometry3D.Positions.Add(bottomRight);
                geometry3D.Positions.Add(new Point3D(-_distanceFromCamera, topLeft.Y, bottomRight.Z));
                geometry3D.Positions.Add(new Point3D(-_distanceFromCamera, bottomRight.Y, topLeft.Z));
                geometry3D.Positions.Add(topLeft);

                geometry3D.TriangleIndices.Add(1);
                geometry3D.TriangleIndices.Add(0);
                geometry3D.TriangleIndices.Add(2);

                geometry3D.TriangleIndices.Add(2);
                geometry3D.TriangleIndices.Add(3);
                geometry3D.TriangleIndices.Add(1);

                geometry3D.TextureCoordinates.Add(new Point(0, 0));
                geometry3D.TextureCoordinates.Add(new Point(1, 0));
                geometry3D.TextureCoordinates.Add(new Point(0, 1));
                geometry3D.TextureCoordinates.Add(new Point(1, 1));

                Material material = new DiffuseMaterial(GetBrush());

                ModelVisual3D modelForGeometry = new ModelVisual3D { Content = new GeometryModel3D(geometry3D, material) };
                mainViewPort3D.Children.Add(modelForGeometry);
                backgroundGrid.Children.Add(mainViewPort3D);
            }

            private ImageBrush GetBrush()
            {
            // put any other image URI here, image Height = 466px, Width = 490px
                ImageBrush brush = new ImageBrush(new BitmapImage(new Uri("lion.jpg", UriKind.Relative)));
                brush.Stretch = Stretch.Fill;
                return brush;
            }
        }
    }

非常感谢您提供的所有帮助!


有一点不同-但不要忘记,在渲染3D图形时涉及到更多的变换,包括影像、几何和透视变换的视觉效果。 - ChrisF
@ChrisF,感谢您的评论。当我使用这段代码来显示高清晰度照片时,差异更加显著。特别是当我缩小图像时。 - Semen Shekhovtsov
2个回答

1
只是猜测:您没有定义任何光源或法线。有时这会导致比您预期的更暗的图像。

嗨@Erno,实际上我正在使用环境光。 codemainViewPort3D.Children.Add(new ModelVisual3D { Content = new AmbientLight() });code. - Semen Shekhovtsov

1

还有一些其他的变量需要考虑。

你的显卡设置可能会强制降低插值模式,尽管WPF请求更好的外观。WPF的3D在Tier 2硬件上进行硬件加速,因此请检查您的驱动程序控制软件。WPF可能无法请求更好的效果!

也可以尝试在应用程序和显卡设置中启用抗锯齿功能。


嗨,@djdanlib,感谢您的回复。我该如何更改我的显卡的插值模式?我认为在所有客户端机器上配置视频卡可能会很困难,是否有更改WPF而不是图形卡的插值模式的选项?感谢您的帮助。 - Semen Shekhovtsov
在WPF中似乎无法关闭抗锯齿(它总是开启的)在社交MSDN上的讨论 - Semen Shekhovtsov
1
这将是在显卡软件中进行的每台机器设置(对于每个制造商而言不同),通常需要用户进行设置。我从未见过它默认强制降到最低设置,只有当有人手动调整以获得更多FPS时才会这样做。如果您没有调整GFX设置,则可能不会这样做。那个BitmapScalingMode调用看起来像是您为WPF应用程序设置它的方式。嘿,值得一试!我找到了一个论坛帖子,可能会帮助您:http://forums.silverlight.net/forums/p/82277/223689.aspx - djdanlib
谢谢,我会尝试应用自定义像素着色器,并告诉你结果。 - Semen Shekhovtsov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接