【C#】 WPF achieves 3D particle wave effect

MainWindow.xaml

 <Window x:Class="_3dwaveEffect.MainWindow"

        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/blend/2008"

        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

        xmlns:local="clr-namespace:_3dwaveEffect"

        mc:Ignorable="d"

        Title="MainWindow" Height="450" Width="800">

    

    <Grid>

        <Viewport3D Name="World">

            <Viewport3D.Camera>

                <PerspectiveCamera Position="0,50,1000" LookDirection="0,2,-1" UpDirection="0,-1,-1" FieldOfView="10000" NearPlaneDistance="10" FarPlaneDistance="8000"/>

            </Viewport3D.Camera> 

            <Viewport3D.Children>

                <ModelVisual3D>

                    <ModelVisual3D.Content>

                        <Model3DGroup x:Name="WorldModels">

                            <AmbientLight Color="#000" />

                        </Model3DGroup>

                    </ModelVisual3D.Content> 

                </ModelVisual3D>

            </Viewport3D.Children> 

        </Viewport3D>

    </Grid>

</Window>

WindowMain.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace _3dwaveEffect
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    /// 
   
    public partial class MainWindow : Window
    {
        private readonly ParticleSystem _ps;
        private DispatcherTimer _frameTimer;

        public MainWindow()
        {
            InitializeComponent();
            _frameTimer = new DispatcherTimer();
            _frameTimer.Tick += OnFrame;
            _frameTimer.Interval = TimeSpan.FromSeconds(1.0 / 60.0);
            _frameTimer.Start();
            _ps = new ParticleSystem(50, 50, Colors.White, 30);
            WorldModels.Children.Add(_ps.ParticleModel);
            _ps.SpawnParticle(30);
            KeyDown += Window_KeyDown;
            Cursor = Cursors.None;
        }
        private void Window_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Escape)
                Close();
        }
        private void OnFrame(object sender, EventArgs e)
        {
            _ps.Update();
        }
    }
}



using System.Windows.Media.Media3D;

public class Particle
{
    public Point3D Position;//Position
    public double Size;//size
    public int XIndex;//X position identification
    public int YIndex;//Y position identification
}

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using System.Windows.Shapes;

public class ParticleSystem
{
    private readonly List<Particle> _particleList;
    private readonly GeometryModel3D _particleModel;
    private readonly int SEPARATION = 100;
    public ParticleSystem(int amountX, int amountY, Color color, int Size)
    {
        XParticleCount = amountX;
        YParticleCount = amountY;
        _particleList = new List<Particle>();
        _particleModel = new GeometryModel3D { Geometry = new MeshGeometry3D() };
        var e = new Ellipse
        {
            Width = Size,
            Height = Size
        };
        var b = new RadialGradientBrush();
        b.GradientStops.Add(new GradientStop(Color.FromArgb(0xFF, color.R, color.G, color.B), 0.25));
        b.GradientStops.Add(new GradientStop(Color.FromArgb(0x00, color.R, color.G, color.B), 1.0));
        e.Fill = b;
        e.Measure(new System.Windows.Size(Size, Size));
        e.Arrange(new Rect(0, 0, Size, Size));
        Brush brush = null;
        var renderTarget = new RenderTargetBitmap(Size, Size, 96, 96, PixelFormats.Pbgra32);
        renderTarget.Render(e);
        renderTarget.Freeze();
        brush = new ImageBrush(renderTarget);
        var material = new DiffuseMaterial(brush);
        _particleModel.Material = material;
    }
    public int XParticleCount { get; set; }
    public int YParticleCount { get; set; }
    public Model3D ParticleModel => _particleModel;
    private double _count = 0;
    public void Update()
    {

        // Calculate particle position and size
        for (int ix = 0; ix < XParticleCount; ix++)
        {
            for (int iy = 0; iy < YParticleCount; iy++)
            {
                foreach (var p in _particleList)
                {
                    if (p.XIndex == ix && p.YIndex == iy)
                    {
                        p.Position.Z = (Math.Sin((ix + _count) * 0.3) * 100) + (Math.Sin((iy + _count) * 0.5) * 100);
                        p.Size = (Math.Sin((ix + _count) * 0.3) + 1) * 8 + (Math.Sin((iy + _count) * 0.5) + 1) * 8;
                    }
                }
            }
        }
        _count += 0.1;
        UpdateGeometry();
    }
    private void UpdateGeometry()
    {
        var positions = new Point3DCollection();
        var indices = new Int32Collection();
        var texcoords = new PointCollection();
        for (var i = 0; i < _particleList.Count; ++i)
        {
            var positionIndex = i * 4;
            var indexIndex = i * 6;
            var p = _particleList[i];
            var p1 = new Point3D(p.Position.X, p.Position.Y, p.Position.Z);
            var p2 = new Point3D(p.Position.X, p.Position.Y + p.Size, p.Position.Z);
            var p3 = new Point3D(p.Position.X + p.Size, p.Position.Y + p.Size, p.Position.Z);
            var p4 = new Point3D(p.Position.X + p.Size, p.Position.Y, p.Position.Z);
            positions.Add(p1);
            positions.Add(p2);
            positions.Add(p3);
            positions.Add(p4);
            var t1 = new Point(0.0, 0.0);
            var t2 = new Point(0.0, 1.0);
            var t3 = new Point(1.0, 1.0);
            var t4 = new Point(1.0, 0.0);
            texcoords.Add(t1);
            texcoords.Add(t2);
            texcoords.Add(t3);
            texcoords.Add(t4);
            indices.Add(positionIndex);
            indices.Add(positionIndex + 2);
            indices.Add(positionIndex + 1);
            indices.Add(positionIndex);
            indices.Add(positionIndex + 3);
            indices.Add(positionIndex + 2);
        }
        ((MeshGeometry3D)_particleModel.Geometry).Positions = positions;
        ((MeshGeometry3D)_particleModel.Geometry).TriangleIndices = indices;
        ((MeshGeometry3D)_particleModel.Geometry).TextureCoordinates = texcoords;
    }
    public void SpawnParticle(double size)
    {

        // Initialize particle position and size
        for (int ix = 0; ix < XParticleCount; ix++)
        {
            for (int iy = 0; iy < YParticleCount; iy++)
            {
                var p = new Particle
                {
                    Position = new Point3D(ix * SEPARATION - ((XParticleCount * SEPARATION) / 2), iy * SEPARATION - ((YParticleCount * SEPARATION) / 2), 0),
                    Size = size,
                    XIndex = ix,
                    YIndex = iy,
                };
                _particleList.Add(p);
            }
        }
    }
}

No comments:

Pipe and Drape Backdrop Ideas for Weddings: Budget-Friendly Elegance

We get it. You've envisioned the perfect wedding venue, a space overflowing with love, joy, and elegance. But when it comes to backdrops...

Contact Form

Name

Email *

Message *