Avalonia: Shadow effect

Created on 1 Jun 2019  Â·  13Comments  Â·  Source: AvaloniaUI/Avalonia

Hello, unfortunately I have not found an answer to this question anywhere, and only Pull Request which has been closed, how can I create DropShadow on an item?

This is a very important part in almost any design.

To example as here

image

enhancement question

Most helpful comment

I think we can add drop-shadow effect support for simple visuals like rectangles, paths, text and images. That would be a sufficient building block for most of the UI elements. After all, browsers only support box-shadow and text-shadow.

All 13 comments

Basically we need a proper layer system implementation that understands concepts of nesting, bounds and z-order.

We can implement simple box-shadow effect that doesn't require any layers though. Something that works like box-shadow in CSS.

The difference between WPF and Browsers:

WPF's DropShadowEffect:

<Border Margin="10" BorderBrush="Black" BorderThickness="1">
    <Border.Effect>
        <DropShadowEffect/>
    </Border.Effect>
    <StackPanel Orientation="Vertical" Margin="5">
        <Label Content="Staying within borders"/>
        <Button Content="Do It"/>
    </StackPanel>
</Border>

Produces a proper shadow for all elements:
изображение

CSS box-shadow:

<div style="background:transparent; box-shadow: red 10px 5px 5px; padding: 5px">
    <p>Staying within borders</p>
    <button>Do it!</button>
</div>

Produces a shadow for the bounding rectangle (round corners are supported) of the div:
изображение

We can implement box-shadow quite easily while WPF-like shadow would be troublesome.

Isn't it possible to use a RenderTargetBitmap in combination with a CustomDrawOperation to apply a shader on all drawing calls when a control is rendered to that bitmap? That is somehow like Avalonia's layering but without the scene graph.

You will lose hit testing because the scene graph is responsible for that.

I think that might break when layers actually come into play. Also, such shadows should be supported by DeferredRenderer itself for invalidation purposes.

I think we can add drop-shadow effect support for simple visuals like rectangles, paths, text and images. That would be a sufficient building block for most of the UI elements. After all, browsers only support box-shadow and text-shadow.

      <Path Fill="OrangeRed" Canvas.Left="180" Canvas.Top="250">
        <Path.ImageFilter>
            <DropShadowImageFilter Offset="10,20" Blur="5,15"  Color="Green"/>
        </Path.ImageFilter>  
        <Path.Data>
          <PathGeometry>
            <PathFigure StartPoint="0,0" IsClosed="True">
              <QuadraticBezierSegment Point1="50,0" Point2="50,-50" />
              <QuadraticBezierSegment Point1="100,-50" Point2="100,0" />
              <LineSegment Point="50,0" />
              <LineSegment Point="50,50" />
            </PathFigure>
          </PathGeometry>
        </Path.Data>
      </Path>

изображение

How do you add this to the DrawingContext? Is it possible to add PushImageFilter(Image Filter filter) and PopImageFilter() that way it is possible to add these in custom scenarios for specific drawing operations.

Push/Pop won't properly without using layers at least internally, also, combining them would be troublesome. As I've suggested, for now I'm adding image filters for primitive drawing operations

Direct2D effects only work on I2D1Bitmap so you always need a surface to draw on before you can apply an effect. If we were wrapping drawing calls with a RenderTargetBitmap we could easily apply effects in the way Direct2D works. This kind of works like a layer I guess. The render pipeline needs to redirect all drawing calls to that wrapping RenderTargetBitmap and after the root node is rendered the effect is applied and the result is transferred to the main surface. So without effect layers this will not be supported by Direct2D. Skia could easily adapt this approach.

We are considering to drop Direct2D completely

image-filter

          <Style Selector="Image">
              <Style.Animations>
                  <Animation Duration="0:0:2"
                             IterationCount="Infinite"
                             FillMode="None"
                             PlaybackDirection="AlternateReverse"
                             Easing="SineEaseInOut">
                      <KeyFrame Cue="0%">
                          <Setter Property="DropShadowImageFilter.Offset" Value="0,0"/>
                          <Setter Property="DropShadowImageFilter.Blur" Value="5,5"/>
                          <Setter Property="DropShadowImageFilter.Color" Value="Green"/>
                      </KeyFrame>
                      <KeyFrame Cue="100%">
                          <Setter Property="DropShadowImageFilter.Offset" Value="40,60"/>
                          <Setter Property="DropShadowImageFilter.Blur" Value="20,30"/>
                          <Setter Property="DropShadowImageFilter.Color" Value="Blue"/>
                      </KeyFrame>
                  </Animation>
              </Style.Animations>
          </Style>
Was this page helpful?
0 / 5 - 0 ratings

Related issues

RUSshy picture RUSshy  Â·  4Comments

grokys picture grokys  Â·  4Comments

ZZerker picture ZZerker  Â·  4Comments

SeleDreams picture SeleDreams  Â·  4Comments

maxkatz6 picture maxkatz6  Â·  3Comments