WPF で雪を降らせてみた


Let it snow.

 

<Window x:Class=”SnowFall.Window1″ Background=”Black” Title=”SnowFall” Width=”400″ Height=”300″ xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation” xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml” xmlns:d=”http://schemas.microsoft.com/expression/interactivedesigner/2006″ xmlns:c=”http://schemas.openxmlformats.org/markup-compatibility/2006″ c:Ignorable=”d” Loaded=”Window_Loaded”>
    <Grid>
        <Viewport3D x:Name=”ZAM3DViewport3D” ClipToBounds=”true” >
            <Viewport3D.Effect>
                <BlurEffect Radius=”10″></BlurEffect>
            </Viewport3D.Effect>
            <Viewport3D.Camera>
                <PerspectiveCamera x:Name=”Target_CameraOR6″ FarPlaneDistance=”100″ LookDirection=”0,2,-1″ UpDirection=”0,1,0″ NearPlaneDistance=”0.1″ Position=”0,-5,5″ FieldOfView=”50″ />
            </Viewport3D.Camera>

            <ModelVisual3D>
                <ModelVisual3D.Content>
                    <Model3DGroup x:Name=”Scene” >
                        <AmbientLight Color=”#7777FF” />
                        <DirectionalLight Color=”#FFFFFF” Direction=”-0.612372,-0.5,-0.612372″ />
                        <DirectionalLight Color=”#FFFFFF” Direction=”0.612372,-0.5,-0.612372″ />
                        <Model3DGroup x:Name=”Model3DG” />
                    </Model3DGroup>
                </ModelVisual3D.Content>
            </ModelVisual3D>
        </Viewport3D>
    </Grid>
</Window>

C# Code

using System;
using System.Windows;
using System.Windows.Media.Media3D;
using System.Windows.Media.Animation;
using System.Windows.Media;
using System.Windows.Markup;

namespace SnowFall
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>

    public partial class Window1 : System.Windows.Window
    {
        private const int maxSnow = 1000;

        public Window1()
        {
            InitializeComponent();
        }

        Snow[] snow = new Snow[maxSnow];

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            CreateSnow();
        }

        private void CreateSnow()
        {
            for (int i = 0; i < maxSnow; i++)
            {
                snow[i] = SnowFactory.CreateSnowBall(Colors.White, 0.2);

                this.Model3DG.Children.Add(snow[i].snowBall);

                snow[i].BeginAnimation();
            }
        }
    }

    public class Snow
    {
        public GeometryModel3D snowBall = new GeometryModel3D();

        public DoubleAnimationUsingKeyFrames daukf = new DoubleAnimationUsingKeyFrames();

        public Snow()
        {
            snowBall.Geometry = GetBall();
            snowBall.Transform = GetTransform(0.1);
            snowBall.Material = new DiffuseMaterial(new SolidColorBrush(Colors.White));

            daukf = CreateAnimation();
        }

        public Snow(Color col, double size)
        {
            snowBall.Geometry = GetBall();
            snowBall.Transform = GetTransform(size);
            snowBall.Material = new DiffuseMaterial(new SolidColorBrush(col));

            daukf = CreateAnimation();
        }

        public void BeginAnimation()
        {
            t2.BeginAnimation(TranslateTransform3D.OffsetYProperty, daukf);
        }

        public TranslateTransform3D t2 { get; set; }

        private Transform3DGroup GetTransform(double size)
        {
            Transform3DGroup t3dg = new Transform3DGroup();
            ScaleTransform3D s01 = new ScaleTransform3D(size, size, size);
            RotateTransform3D r01 = new RotateTransform3D();
            TranslateTransform3D t1 = new TranslateTransform3D(GetRnd(50) -25, 25, GetRnd(50) – 25);
            t2 = new TranslateTransform3D(0, 0, 0);

            t3dg.Children.Add(t1);
            t3dg.Children.Add(s01);
            t3dg.Children.Add(r01);
            t3dg.Children.Add(t2);

            return t3dg;
        }

        private static MeshGeometry3D GetBall()
        {
            MeshGeometry3D ball = new MeshGeometry3D();
            ball.TriangleIndices = new Int32Collection { 0, 1, 2, 3, 0, 2,…..240, 226 };
            ball.Normals = new Vector3DCollection { new Vector3D(0.18024, 0.980785, 0.0746578), …., new Vector3D(0, -1, 0) };
            ball.Positions = new Point3DCollection { new Point3D(0.09012, 0.490393, 0.0373289), … new Point3D(0, -0.5, 0) };
            return ball;
        }

        LinearDoubleKeyFrame ldkf1 = new LinearDoubleKeyFrame();
        LinearDoubleKeyFrame ldkf2 = new LinearDoubleKeyFrame();

        private DoubleAnimationUsingKeyFrames CreateAnimation()
        {
            ldkf1.KeyTime = KeyTime.FromTimeSpan(new TimeSpan(0, 0, 0));
            ldkf1.Value = 20;

            ldkf2.KeyTime = KeyTime.FromTimeSpan(new TimeSpan(0, 0, 5));
            ldkf2.Value = -10;

            daukf.KeyFrames.Add(ldkf1);
            daukf.KeyFrames.Add(ldkf2);
            daukf.BeginTime = new TimeSpan(0, 0, 0, 0, (int)GetRnd(5000));
            daukf.Duration = new TimeSpan(0, 0, 0, 5);
            daukf.RepeatBehavior = RepeatBehavior.Forever;

            return daukf;
        }

        Random rnd = new Random();
        double GetRnd(double range)
        {
            return (rnd.NextDouble() * range);
        }
    }

    public class SnowFactory
    {
        public static Snow CreateSnowBall()
        {
            Snow snow = new Snow();
            return snow;
        }

        public static Snow CreateSnowBall(Color col, double size)
        {
            Snow snow = new Snow(col, size);
            return snow;
        }
    }
}

広告

1件のフィードバック to “WPF で雪を降らせてみた”

  1. 木下 英俊 Says:

    こんにちは。WPFでの3D表示関連を勉強中でこちらにたどり着きました。記載内容に従ってVSで実際に作ってみて、おかげさまで大分内容がわかってきた気がします。ありがとうございました。
    ところでソース中で一点気になったのでコメントさせていただきます。せっかく1000個の雪を乱数で生成していますが、上記ソースのままだと Random() が同じシードで生成される場合が多数発生してしまい、結果として複数の雪が同じ座標で生成されてしまっているようです。
    一例ですが、雪の数を例えば maxSnow = 10 にすると画面上には3個程度しか出てきませんでした。そこで私は以下のように乱数生成部を static へ修正することで意図通りに動作することを確認しました。

    private static Random _rnd = new Random();
    private static double GetRnd(double range)
    {
    return (_rnd.NextDouble() * range);
    }

    こうすることで Random _rnd が一回しか生成されませんのでちゃんと散らばることを確認しました。

    以上、ご参考まで。

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中


%d人のブロガーが「いいね」をつけました。