添加合成光效果后奇怪的不透明度动画行为
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);
在我的项目中添加了这样的代码后,确实解决了问题。
所以我目前正在使用 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);
在我的项目中添加了这样的代码后,确实解决了问题。