locked
custom ShaderEffect: strange WPF behaviour RRS feed

  • Question

  • I noticed a strange behaviour of WPF when it comes to shader effects.
    I applied a custom ShaderEffect (blur) to a Canvas. The shader processes the actual mouse position and draws it viewable.

    Normally the effect works fine.
    But if you set the Canvas.LeftProperty of an added child of the Canvas via Canvas.SetLeft() and place the child outside the Canvas (where its out of sight), it seems that the effect uses the size of the logical bounding box of the Canvas, which includes all children (the lesser width and height properties of the Canvas get ignored).

    When i apply the effect just to the Window (which has the Canvas as Content), it works perfect.

    I've tried to use the following methods and properties of the Canvas:
    Arrange(), Clip, ClipToBounds, MinWidth, MaxWidth, RenderSize. Without success :(
    Saturday, February 6, 2010 9:00 PM

Answers

  • What you could do is use the RenderTargetBitmap.

    RenderTargetBitmap target = new RenderTargetBitmap(500, 500, 96, 96, PixelFormats.Pbgra32);
    target.Render(YourVisual);

    ...

    m_image.Source = target;
    m_image.Effect = YourEffect;

    You can set the size of the render target matching some final image size that you want and render whatever WPF visual objects you want to it (the canvas).  The only really crappy part is that you'll need to manage the rendering yourself.

    One thing you might try before trying this is to have clip to bounds turned on, and host one canvas inside another canvas, and apply your effect to the outer most canvas.  That will likely fix your problem.
    Nick
    • Proposed as answer by Nick Darnell Sunday, February 7, 2010 2:48 PM
    • Marked as answer by Tim Li Tuesday, February 9, 2010 3:23 AM
    Sunday, February 7, 2010 5:37 AM

All replies

  • We are lazy... Could you post a ready to run example of this?


    Kenneth
    Saturday, February 6, 2010 9:37 PM
  • No problem. Something like this...

    public partial class Window1 : Window
    {
    Canvas canvas;
    
    public Window1()
    {
    InitializeComponent();
    
    canvas = new Canvas();
    canvas.Width = 800;
    canvas.Height = 600;
    canvas.Background = Brushes.White;
    canvas.Effect = new ZoomBlurEffect();	//my custom effect
    
    this.Content = canvas;
    this.Width = canvas.Width;
    this.Height = canvas.Height;
    this.Show();
    
    // Add a Rectangle Element
    myRect = new Rectangle();
    myRect.Fill = Brushes.SkyBlue;
    myRect.Width = 50;
    myRect.Height = 50;
    Canvas.SetLeft(myRect, 1000);	//place it outside of the Canvas
    Canvas.SetTop(myRect, 100);
    canvas.Children.Add(myRect);

    I verified the problem. I wrote a simple shader, which draws a black box around the mouse position.
    So if i place an UIElement outside the canvas size, this black box gets stretched. WPF works internally with a bounding box.
    Bad for me :\
    Saturday, February 6, 2010 10:14 PM
  • So problem solved?
    Kenneth
    Saturday, February 6, 2010 10:24 PM
  • No, still without any solution.
    I need the effect applied just to the visible canvas size i defined (width and height).
    Saturday, February 6, 2010 10:27 PM
  • What you could do is use the RenderTargetBitmap.

    RenderTargetBitmap target = new RenderTargetBitmap(500, 500, 96, 96, PixelFormats.Pbgra32);
    target.Render(YourVisual);

    ...

    m_image.Source = target;
    m_image.Effect = YourEffect;

    You can set the size of the render target matching some final image size that you want and render whatever WPF visual objects you want to it (the canvas).  The only really crappy part is that you'll need to manage the rendering yourself.

    One thing you might try before trying this is to have clip to bounds turned on, and host one canvas inside another canvas, and apply your effect to the outer most canvas.  That will likely fix your problem.
    Nick
    • Proposed as answer by Nick Darnell Sunday, February 7, 2010 2:48 PM
    • Marked as answer by Tim Li Tuesday, February 9, 2010 3:23 AM
    Sunday, February 7, 2010 5:37 AM
  • @Nick Darnell
    your second suggestion worked for me. thank you very much.
    a strange thing anyway.
    Sunday, February 7, 2010 12:01 PM
  • I just got an easier solution, use the "VisualTreeHelper.GetContentBounds(Visual)" method, which give you the Rect used by ShaderEffect. So you can translate the uv vector. 

    Hope this works for you too.


    • Edited by Robird Thursday, July 30, 2015 10:37 AM
    Thursday, July 30, 2015 10:37 AM