How to apply a drop shadow effect when drawing to a DrawingContext in WPF?
Asked Answered
D

2

8

I'm drawing into a DrawingContext, and I'd like to apply a drop shadow effect to part of the drawing. At the moment I create the relevant parts in a DrawingGroup and apply a BitmapEffect, but this has no effect:

var layer = new DrawingGroup();
using (var lcontext = layer.Open())
{
    // draw stuff in lcontext
}
layer.BitmapEffect = new DropShadowBitmapEffect { Color = Colors.Black, ShadowDepth = 3, Opacity = 0.5 };
context.DrawDrawing(layer);

This draws everything inside the layer correctly, but without the drop shadow effect.

What am I doing wrong / how else might I apply a drop shadow to a bunch of primitives in a DrawingContext?

Destruction answered 28/12, 2011 at 12:9 Comment(0)
G
3

BitmapEffect is an old property (they used CPU-rendered effects) from pre .NET 3.5. The property has no effect in 4.0.

In 4.0 you should use Effect property, which uses Pixel Shaders.

DrawingGroup however doesn't appear to have an effect property - it sounds like you might need to set the effect on the parent UI element instead.

Gambia answered 28/12, 2011 at 15:44 Comment(3)
Hmm... I don't have a parent UI element; this DrawingGroup is rendered directly into a RenderTargetBitmap. Odd how I have to use UI elements for pure rendering, eh?...Destruction
I don't think it's odd - when creating a bitmap in memory, it hasn't been sent to the GPU, and so the GPU doesn't get to run the pixel shaders. The old BitmapEffects didn't use pixel shaders, they ran on the CPU, which is why they worked in this case. BitmapEffects were too slow most of the time though, which is why they are obsoleted.Gambia
In this situation you can probably use the drawing group to fill a Rectangle, and render the Rectangle to RenderTargetBitmap (don't forget to size the element first) - that should (I think) invoke the GPU to call your shader.Gambia
J
-2

If you're running on .NET Framework 3.5 SP1 or higher, you should use UIElement.Effect or Visual.VisualEffect (this one is protected so you would need to derive from it) instead, with an instance of System.Windows.Media.Effects.DropShadowEffect.

Jenninejennings answered 7/3, 2012 at 10:45 Comment(10)
A DrawingGroup is neither a Visual nor a UIElement, so where do I apply that effect?Destruction
@romkyns - yes, because a DrawingGroup is a hierarchy/tree concept, not a "visual" concept. What do you put in your group? You must have something "visual" that will serve as the base for the drop shadow.Jenninejennings
I draw stuff like images and primitives into my DrawingGroup (using code I quoted in the question). I then render it using DrawDrawing. I’d like to do the same, but have everything inside the DrawingGroup to cast a shadow.Destruction
@romkyns - well, the Drawing classes hierarchy is probably not the good horse to ride when you want to use builtin (fast) drop down shadows. You'll have to use the Visual/UIElement classes hierarchy. WPF is mostly a composition engine where you build your UI hierarchy (probably using a holding Canvas) and let the system do the rendering job.Jenninejennings
DrawingContext is a perfectly capable replacement for the GDI APIs, in my experience. There just doesn’t seem to be a ready-made drop-shadow effect, which is understandable. Would you like to update or remove your answer? As it stands, it’s inapplicable/misleading.Destruction
let me give u my angle - i've inherited SomeControl from FrameworkElement, and overriden OnRender. UIElement.Effect is just not good enough- it puts the effect on the entire element, whereas the depricated PushEffect could put the effect only on a few drawingContext.DrawXXX lines, allowing me not to put the effect on the entire element at once. WPF4 => less control than WPF3?Marmite
@romkyns - I will certainly not remove my answer. I spent some time trying to help, I will not spent points to remove it.Jenninejennings
@SimonMourier I appreciate your efforts to help. FWIW, I don’t think it costs anything to delete an answer.Destruction
@EladKatz Did you figure out a solution to this problem. I want to have shadows on individual items I draw using drawingContext.DrawXYZResourceful
@Resourceful nope. i came to think that this is impossible with WPF4.Marmite

© 2022 - 2024 — McMap. All rights reserved.