Weird Opacity animation behavior after adding Composition Light effect

368 views Asked by At

So I'm currently using Windows composition Apis to create a "fade-in" animation, combining a scale animation and an opacity animation, to my custom control, which worked perfectly fine. However, recently I tried to add some light effect but for some reason the opacity animation doesn't work out anymore.

Here is how it looks enter image description here

As you can see, you are able to see the image during the "fade-in" animation without light effect. But once you add the light effect, you are not able to see it until the "fade-in" animation is done. It must be some mechanics of composition animation but I just used them in a wrong way.

You can reproduce the code here

MainPage.xaml(Use your own image):

<Grid x:Name="rootPanel" Background="LightGray" Loaded="rootPanel_Loaded">
<Image x:Name="panel" Source="Assets/aaa.jpg" Loaded="panel_Loaded" />

MainPage.xaml.cs:

public sealed partial class MainPage : Page
{
private Compositor _compositor;
private const float lightDepth = 300f;
private const int animationDelay = 600;
private const int animationDuration = 70;
private CompositionEffectFactory _effectFactory;
private Random _random = new Random();
private PointLight _pointLight;
private Visual _root;
private ImplicitAnimationCollection _implicitAnimations1st;

public MainPage()
{
    this.InitializeComponent();
    _compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;


    _implicitAnimations1st = _compositor.CreateImplicitAnimationCollection();
    var _firstWaveAnimationGroup = _compositor.CreateAnimationGroup();

    var OpacityAnimation1st = _compositor.CreateScalarKeyFrameAnimation();
    OpacityAnimationSetting(OpacityAnimation1st, (double)0);

    var scaleAnimation1st = _compositor.CreateVector3KeyFrameAnimation();
    ScaleAnimationSetting(scaleAnimation1st, (double)0);

    _firstWaveAnimationGroup.Add(OpacityAnimation1st);
    _firstWaveAnimationGroup.Add(scaleAnimation1st);
    _implicitAnimations1st["Offset"] = _firstWaveAnimationGroup;
}

private void ScaleAnimationSetting(Vector3KeyFrameAnimation animation, double delay)
{
    animation.InsertKeyFrame(0.0f, new Vector3(0.7f, 0.7f, -.5f));
    animation.InsertKeyFrame(1.0f, new Vector3(1, 1, 0), _compositor.CreateLinearEasingFunction());
    animation.Duration = TimeSpan.FromMilliseconds(800);
    animation.DelayTime = TimeSpan.FromMilliseconds(delay);
    animation.DelayBehavior = AnimationDelayBehavior.SetInitialValueAfterDelay;
    animation.Target = "Scale";
}

private void OpacityAnimationSetting(ScalarKeyFrameAnimation animation, double delay)
{
    animation.InsertKeyFrame(0.0f, 0.0f);
    animation.InsertKeyFrame(1.0f, 1.0f, _compositor.CreateLinearEasingFunction());
    animation.Duration = TimeSpan.FromMilliseconds(800);
    animation.DelayTime = TimeSpan.FromMilliseconds(delay);
    animation.DelayBehavior = AnimationDelayBehavior.SetInitialValueAfterDelay;
    animation.Target = "Opacity";
}

private void panel_Loaded(object sender, RoutedEventArgs e)
{
    var visual = ElementCompositionPreview.GetElementVisual(panel);
    visual.Opacity = 0f;
    visual.ImplicitAnimations = _implicitAnimations1st;
    visual.CenterPoint = new Vector3((float)(panel.DesiredSize.Width / 2), (float)(panel.DesiredSize.Height / 2), 0);
    visual.Offset = new Vector3((float)-panel.DesiredSize.Width, (float)-panel.DesiredSize.Height, 0);
}

private void rootPanel_Loaded(object sender, RoutedEventArgs e)
{
    _root = ElementCompositionPreview.GetElementVisual(rootPanel);
    _pointLight = _compositor.CreatePointLight();
    _pointLight.Offset = new Vector3(-2500f, -2500f, 300f);
    _pointLight.Intensity = 1.3f;
    IGraphicsEffect graphicsEffect = new CompositeEffect()
    {
        Mode = CanvasComposite.DestinationIn,
        Sources =
                    {
                        new CompositeEffect()
                        {
                            Mode = CanvasComposite.Add,
                            Sources =
                            {
                                new CompositionEffectSourceParameter("ImageSource"),
                                new SceneLightingEffect()
                                {
                                    AmbientAmount = 0,
                                    DiffuseAmount = .5f,
                                    SpecularAmount = 0,
                                    NormalMapSource = new CompositionEffectSourceParameter("NormalMap"),
                                }
                            }
                        },
                        new CompositionEffectSourceParameter("NormalMap"),
                    }
    };

    _effectFactory = _compositor.CreateEffectFactory(graphicsEffect);

    //Comment Out the rest of the two lines can remove light effect
    _pointLight.CoordinateSpace = _root;
    _pointLight.Targets.Add(_root);

    #region First light animation
    Vector3KeyFrameAnimation lightPositionAnimation;
    lightPositionAnimation = _compositor.CreateVector3KeyFrameAnimation();
    lightPositionAnimation.InsertKeyFrame(.0f, new Vector3(200f, 700f, lightDepth), _compositor.CreateLinearEasingFunction());
    lightPositionAnimation.InsertKeyFrame(1f, new Vector3(200f, 700f, lightDepth), _compositor.CreateLinearEasingFunction());
    lightPositionAnimation.DelayTime = TimeSpan.FromMilliseconds(animationDelay);
    lightPositionAnimation.Duration = TimeSpan.FromSeconds(animationDuration);
    lightPositionAnimation.IterationBehavior = AnimationIterationBehavior.Forever;

    _pointLight.StartAnimation("Offset", lightPositionAnimation);
    #endregion

}
}

How do I be able to fix it?

1

There are 1 answers

0
jason_wun On BEST ANSWER

While waiting some days after posting problem as issue on the github repo of Windows UI, one of the Windows UI developers gave a solution to fix such question.

A quote from this developer:

Items not currently targeted by or being illuminated by the point light when animating will appear black. To illuminate surrounding visuals not targeted by the light in a natural way, use an ambient light in conjunction with other lights.

_ambientLight = _compositor.CreateAmbientLight();

_ambientLight.Targets.Add(_root);

After adding such code in my project, it really fix the problem.