代码之家  ›  专栏  ›  技术社区  ›  Joachim Kerschbaumer

在屏幕外位图上应用像素着色器

  •  4
  • Joachim Kerschbaumer  · 技术社区  · 16 年前

    我目前正在尝试使用.NET3.5SP1中引入的像素着色器来提高图像处理性能。一切都要快得多,但直到我刚刚对wpf表单中的某些元素应用了效果,这是我实际上想要避免的。

    有没有一种方法可以将这样的像素着色器应用于图像源而不必显示它?

    2 回复  |  直到 16 年前
        1
  •  4
  •   Suma    16 年前

    看到你还没有从C专家那里得到任何答案,我会尝试从C++ DirectX开发者的角度来解决这个问题,希望如果我的答案没有用,至少它会指引你正确的方向。我对C#知之甚少,对如何支持像素着色器一无所知,因此我完全错了,我在这里写的东西根本不适用。在这种情况下,请根据需要自由评论或否决投票

    准备(完成一次)

    • 使用CreateRenderTarget创建渲染目标
    • 使用SetRenderTarget设置渲染目标曲面

    渲染(多次完成)

    • 根据需要更新输入资源(纹理、缓冲区)
    • 提供
    • 通过GetRenderTarget将渲染目标的内容复制到屏幕外曲面
    • 锁定屏幕外表面并在CPU上读取其内容
        2
  •  2
  •   H B    11 年前

    我刚刚在这里创建了这篇文章,展示了如何在WPF中实现这一点。 http://www.codeproject.com/Articles/642151/Pixel-shaders-in-a-background-thread-in-WPF

    相关代码复制如下。它来自一个具有一些存储变量的类

    • 来源:图像来源
    • DpiX,DpiY:包含源Dpi的双精度
    • viewbox:WPF viewbox控件
    • WPF_DPI_X,WPF_DPI_Y:常数加倍,值为96.0

    1.图像img嵌入到一个可视框中(也在屏幕外)

    //prepare images
    img = new Image();
    img.Stretch = Stretch.None;
    viewbox = new Viewbox();
    viewbox.Stretch = Stretch.None;
    viewbox.Child = img; //control to render
    

    2.img和viewbox的大小已调整到正确的比例,并且在viewbox上调用了一些布局功能。这将使控件在应用着色器的情况下渲染。

    /// <summary>
    /// Loads the image and viewbox for off-screen rendering.
    /// </summary>
    public void LoadImage(double width, double height)
    {
        img.BeginInit();
        img.Width = width;
        img.Height = height;
        img.Source = Source;
        img.EndInit();
    
        viewbox.Measure(new Size(img.Width, img.Height));
        viewbox.Arrange(new Rect(0, 0, img.Width, img.Height));
        viewbox.UpdateLayout();
    } 
    

    3.要获取图像内容,请提供“截图”,如果您愿意:

    void SaveUsingEncoder(BitmapEncoder encoder, Stream stream)
    {
        RenderTargetBitmap bitmap = new RenderTargetBitmap((int)(img.Width * DpiX / WPF_DPI_X), (int)(img.Height * DpiY / WPF_DPI_Y), DpiX, DpiY, PixelFormats.Pbgra32);
        bitmap.Render(viewbox);
    
        BitmapFrame frame = BitmapFrame.Create(bitmap);
        encoder.Frames.Add(frame);
        encoder.Save(stream);
    } 
    

    另外,如果你想在一个单独的线程中运行它,你需要用

    thread.SetApartmentState(ApartmentState.STA);