何に困ったか
HelixToolkitは、WPFで簡単に3D表現ができる素晴らしいライブラリなのですが、MeshElement3DのFillプロパティに対して、Storyboardでアニメーション指定することができないみたいで、ハマりました。
コードビハインドからBrushの指定はできることは確認済みでした。
やりたいことは単純で、MeshElement3D派生オブジェクトの上にマウスがオーバーしたら色を変えるというだけです。
回避策
初めは、コードの書き方が悪いのだろうと考えて、いじくりまして見たのですが解決せず。
パフォーマンスなどに問題が起きるため積極的に使って欲しくないのだろうという結論に達しました。
ホントは、マテリアルで出来るのかも知れませんが、単色指定できる誘惑には勝てずBehaviorを使って回避する方法をひねり出しました。
public class MeshElement3DFillBehavior : Behavior<MeshElement3D>
{
private MeshElement3D hostControl;
protected sealed override void OnAttached()
{
base.OnAttached();
this.hostControl = (MeshElement3D)this.AssociatedObject;
}
protected sealed override void OnDetaching()
{
base.OnDetaching();
}
public static readonly DependencyProperty SolidColorFillProperty = DependencyProperty.Register("SolidColorFill", typeof(Color), typeof(MeshElement3DFillBehavior), new UIPropertyMetadata(Colors.White, OnSolidColorFill));
public Color SolidColorFill
{
get { return (Color)this.GetValue(SolidColorFillProperty); }
set { this.SetValue(SolidColorFillProperty, value); }
}
private static void OnSolidColorFill(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
{
MeshElement3DFillBehavior mine = (MeshElement3DFillBehavior)depObj;
mine.hostControl.Fill = new SolidColorBrush(mine.SolidColorFill);
}
}
<helix:BoxVisual3D>
<i:Interaction.Behaviors>
<local:MeshElement3DFillBehavior />
</i:Interaction.Behaviors>
</helix:BoxVisual3D>
Storyboardのターゲットとして、MeshElement3DFillBehavior.SolidColorFillを使用すれば、ColorAnimationUsingKeyFramesが使用できるようになります。
private void MouseHoverAnimation(MeshElement3DFillBehavior target, bool leave = false)
{
Color startColor = Color.FromArgb(0x40, 0xFF, 0xFF, 0xFF);
Color endColor = Color.FromArgb(0x60, 0xFF, 0xFF, 0xFF);
if (leave)
{
startColor = Color.FromArgb(0x60, 0xFF, 0xFF, 0xFF);
endColor = Color.FromArgb(0x40, 0xFF, 0xFF, 0xFF);
}
ColorAnimationUsingKeyFrames animation = new ColorAnimationUsingKeyFrames();
animation.Duration = new Duration(TimeSpan.FromSeconds(0.2));
EasingColorKeyFrame startAnimation = new EasingColorKeyFrame(startColor, KeyTime.FromPercent(0));
EasingColorKeyFrame endAnimation = new EasingColorKeyFrame(endColor, KeyTime.FromPercent(1.0));
animation.KeyFrames.Add(startAnimation);
animation.KeyFrames.Add(endAnimation);
target.BeginAnimation(MeshElement3DFillBehavior.SolidColorFillProperty, animation);
}
追記:マテリアルを指定する方法
Fillプロパティを使ってアニメーションさせるために、ビヘイビアまで作って頑張ってみたのですが、マテリアルを使った方法の方が遥かに簡単でした。
下記のようにSolidColorBrushを露出してやれば、Storyboardで簡単にアニメーションさせる事ができました。
<Window x:Class="HelixToolkitTestSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:helix="clr-namespace:HelixToolkit.Wpf;assembly=HelixToolkit.Wpf"
Title="MainWindow"
Width="800"
Height="600"
Background="Black">
<Window.Resources>
<Storyboard x:Key="ColorAnime">
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(SolidColorBrush.Color)" Storyboard.TargetName="colorBrush">
<EasingColorKeyFrame KeyTime="0:0:0" Value="White"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(SolidColorBrush.Color)" Storyboard.TargetName="colorBrush">
<EasingColorKeyFrame KeyTime="0:0:2" Value="#20FFFFFF"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{StaticResource ColorAnime}"/>
</EventTrigger>
</Window.Triggers>
<Grid>
<helix:HelixViewport3D x:Name="viewport3d"
ShowCameraInfo="True"
ShowViewCube="True">
<!-- カメラ -->
<helix:HelixViewport3D.DefaultCamera>
<PerspectiveCamera FieldOfView="45"
LookDirection="0.0,0.0,-122.334"
NearPlaneDistance="0.125"
Position="0.966,0.831,68.597"
UpDirection="0.0,1.0,0.0" />
</helix:HelixViewport3D.DefaultCamera>
<!-- 光源 -->
<helix:SunLight />
<helix:RectangleVisual3D Width="30" Length="40">
<helix:RectangleVisual3D.Material>
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<SolidColorBrush x:Name="colorBrush" Color="White"/>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
</helix:RectangleVisual3D.Material>
</helix:RectangleVisual3D>
</helix:HelixViewport3D>
</Grid>
</Window>