【问题标题】:Can't render pixel shader to RenderTargetBitmap! Please help!无法将像素着色器渲染到 RenderTargetBitmap!请帮忙!
【发布时间】:2014-01-29 00:49:56
【问题描述】:

我编写了一个非常简单的 WPF 应用程序来测试将具有关联像素着色器的控件渲染到 RenderTargetBitmap 的能力。然后我将位图写入文件(jpeg)。控件被渲染到位图上,但是像素着色器效果不应用于控件。

代码和 XAML 如下:

namespace TestPixelShader
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void OnSaveSnapshot(object sender, RoutedEventArgs e)
        {
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.DefaultExt = "jpg";

            if ((bool)dlg.ShowDialog() == true)
            {
                String fileName = dlg.FileName;

                int Height = (int)CanvasControl.ActualHeight;
                int Width = (int)CanvasControl.ActualWidth;

                RenderTargetBitmap bmp = new RenderTargetBitmap(
                    Width, Height, 96, 96, PixelFormats.Pbgra32);
                bmp.Render(CanvasControl);

                string Extension = System.IO.Path.GetExtension(fileName).ToLower();

                BitmapEncoder encoder;
                if (Extension == ".gif")
                    encoder = new GifBitmapEncoder();
                else if (Extension == ".png")
                    encoder = new PngBitmapEncoder();
                else if (Extension == ".jpg")
                    encoder = new JpegBitmapEncoder();
                else
                    return;

                encoder.Frames.Add(BitmapFrame.Create(bmp));
                using (Stream stm = File.Create(fileName))
                {
                    encoder.Save(stm);
                }
            }
        }
    }
}

XAML:

<Window x:Class="TestPixelShader.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:TestPixelShader"
    Height="400"
    Width="300"
    Title="Test Pixel Shader">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Canvas Grid.Column="0" x:Name="CanvasControl" Margin="5"
                HorizontalAlignment="Stretch"
                VerticalAlignment="Stretch" >
            <Canvas.Effect>
                <local:TestPixelShaderEffect />
            </Canvas.Effect>
            <Canvas.Background>
                <ImageBrush ImageSource="/TestPixelShader;component/Images/DSCF0225.JPG" />
            </Canvas.Background>
        </Canvas>
        <Button x:Name="SaveSnapshotButton" Grid.Row="1" Click="OnSaveSnapshot" Height="40"
                Content="Take Snapshot" Margin="5"/>
    </Grid>
</Window>

【问题讨论】:

  • 你能清理一下代码示例吗?
  • 不,我不认为这是所引用问题的重复。我正在尝试渲染到 RTB,但是我使用的是 PS 3.0,并且 Kris 表示 3.0 没有软件回退,因此将被忽略。这似乎是我问题的根源。我需要使用 3.0,因为 2.0 没有足够的能力。还有其他建议吗?

标签: wpf pixel-shader rendertargetbitmap


【解决方案1】:

您的目标是哪个 Pixel Shader 版本?

我尝试了您的代码,它为 PS 2.0 着色器正确保存了图像。 RenderTargetBitmap 使用软件渲染器,而 PS 3.0 没有软件回退,因此如果您使用 PS 3.0 着色器,它将被忽略。

【讨论】:

  • 这很令人失望,我需要 PS 3.0 的一些功能,但还需要能够将屏幕外渲染的 WPF 控件的快照保存到文件中。我认为 RenderTargetBitmap 是我最大的希望。有什么建议么?我想我可以以某种方式使用 DirectX,但我仍然需要将 WPF 控件呈现在屏幕外。这非常令人沮丧!感谢您的帮助!
  • 如果您不需要在屏幕外进行,那么屏幕截图可能是最简单的,但似乎使用 D3D 或自己在软件中进行是您最好的选择。我对 D3D 没有太多经验,但您可以使用 Slim Dx 或“Windows API 代码包”通过托管代码访问它。您的着色器有多复杂,是否可以将其拆分为多个 PS 2.0 着色器?
【解决方案2】:
 public class SnapshotHelper
{
    public static BitmapSource Capture(Rect absoluteControlRect)
    {
        using (var screenBmp = new System.Drawing.Bitmap(
            (int)absoluteControlRect.Width,
            (int)absoluteControlRect.Height,
            PixelFormat.Format32bppArgb))
        {
            using (var bmpGraphics = System.Drawing.Graphics.FromImage(screenBmp))
            {
                bmpGraphics.CopyFromScreen((int)absoluteControlRect.Left, (int)absoluteControlRect.Top, 0, 0, screenBmp.Size);
                return System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                    screenBmp.GetHbitmap(),
                    IntPtr.Zero,
                    Int32Rect.Empty,
                    BitmapSizeOptions.FromEmptyOptions());
            }
        }
    }

    public static Rect GetAbsoltutePlacement(FrameworkElement visual)
    {
        Point absolutePos = visual.PointToScreen(new Point(0, 0));
        return new Rect(absolutePos.X, absolutePos.Y, visual.ActualWidth, visual.ActualHeight);
    }

}

用法:

var rect = SnapshotHelper.GetAbsoltutePlacement(yourControl);
var image = SnapshotHelper.Capture(rect);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-10
    • 1970-01-01
    • 1970-01-01
    • 2019-06-06
    • 2015-12-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多