添加合成光效果后奇怪的不透明度动画行为

Weird Opacity animation behavior after adding Composition Light effect

所以我目前正在使用 Windows 合成 Apis 创建一个 "fade-in" 动画,将缩放动画和不透明度动画组合到我的自定义控件中,效果非常好。但是,最近我尝试添加一些光效,但由于某些原因,不透明动画不再起作用了。

这是它的样子

如您所见,您可以在 "fade-in" 动画期间看到没有光效的图像。但是一旦你添加了灯光效果,你就无法看到它,直到 "fade-in" 动画完成。一定是合成动画的一些机制,只是我用错了。

您可以在此处重现代码

MainPage.xaml(使用你自己的图片):

<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

}
}

我该如何修复它?

在 Windows UI 的 github 回购上发布问题后等待几天,其中一位 Windows UI 开发人员给出了一个解决此类问题的解决方案。

此开发者的引述:

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);

在我的项目中添加了这样的代码后,确实解决了问题。