Member 11436310 Ответов: 2

Влияние капли воды на wpf


Привет,
Я пытаюсь разработать программное обеспечение, в котором я могу использовать функциональность мультитач и, соответственно, волны могут генерироваться из этой точки. Я попробовал программное обеспечение Shazzam для того же самого, но эффект не соответствует моему требованию.

Вот что я пытаюсь сделать
Multi Touch Water Wall - YouTube[^]
и
Мультитач Аквариум на CeBIT 09 - YouTube[^]

Пожалуйста, скажите мне, как лучше всего это сделать. Когда я погуглил, то не получил ни одного полезного материала.
спасибо заранее

Что я уже пробовал:

Я попробовал программное обеспечение shazzam и использовал эффект, созданный им в WPF.

2 Ответов

Рейтинг:
1

Member 14793525

1 Новый проект WPF

Ссылка Добавить проект:
Система.Рисование
Система.Окна.Формы
WindowsFormsIntegration

Файл MainWindow.язык XAML:

<Window x:Class="WpfwaterEffectTest.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:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
        xmlns:local="clr-namespace:WpfwaterEffectTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="768" Width="1024" ResizeMode="NoResize" WindowStyle="None" WindowStartupLocation="CenterScreen">
    <Canvas Name="mainCanv">

    </Canvas>
</Window>


Файл MainWindow.язык XAML.в CS:
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms;
using System.Windows.Forms.Integration;
using System.Windows.Threading;

namespace WpfwaterEffectTest
{
    public partial class MainWindow : Window
    {
        private Bitmap _bmp;
        private short[,,] _waves;
        private int _waveWidth;
        private int _waveHeight;
        private int _activeBuffer = 0;
        private bool _weHaveWaves;
        private int _bmpHeight, _bmpWidth;
        private byte[] _bmpBytes;
        private BitmapData _bmpBitmapData;
        private int _scale;

        System.Windows.Forms.PictureBox pbViewport = null;
        DispatcherTimer waterTime = new DispatcherTimer(DispatcherPriority.Render);

        public MainWindow()
        {
            InitializeComponent();

            pbViewport = new PictureBox();
            this.pbViewport.Image = System.Drawing.Image.FromFile("About2.jpg");
            this.pbViewport.Top = 0;
            this.pbViewport.Left = 0;
            this.pbViewport.Height = 360;
            this.pbViewport.Width = 203;
            this.pbViewport.SizeMode = PictureBoxSizeMode.AutoSize;
            this.pbViewport.Paint += new PaintEventHandler(this.WaterEffectControl_Paint);
            this.pbViewport.MouseMove += new System.Windows.Forms.MouseEventHandler(this.WaterEffectControl_MouseMove);
            waterTime.Tick += new EventHandler(effectTimer_Tick);
            WindowsFormsHost wfh = new WindowsFormsHost();
            wfh.Child = pbViewport;
            wfh.Width = 203;
            wfh.Height = 360;
            wfh.Opacity = 0.9;
            mainCanv.Children.Add(wfh);
            Canvas.SetZIndex(wfh, 1);

            this.Width = this.pbViewport.Width;
            this.Height = this.pbViewport.Height;

            this.ImageBitmapNew = (Bitmap)(this.pbViewport.Image);

            waterTime.Interval = TimeSpan.FromMilliseconds(50);

            waterTime.Start();

        }

        private void effectTimer_Tick(object sender, System.EventArgs e)
        {
            if (_weHaveWaves)
            {
                this.pbViewport.Invalidate();

                ProcessWaves();
            }
        }

        private void ProcessWaves()
        {
            int newBuffer = (_activeBuffer == 0) ? 1 : 0;
            bool wavesFound = false;

            for (int x = 1; x < _waveWidth - 1; x++)
            {
                for (int y = 1; y < _waveHeight - 1; y++)
                {
                    _waves[x, y, newBuffer] = (short)(
                                            ((_waves[x - 1, y - 1, _activeBuffer] +
                                            _waves[x, y - 1, _activeBuffer] +
                                            _waves[x + 1, y - 1, _activeBuffer] +
                                            _waves[x - 1, y, _activeBuffer] +
                                            _waves[x + 1, y, _activeBuffer] +
                                            _waves[x - 1, y + 1, _activeBuffer] +
                                            _waves[x, y + 1, _activeBuffer] +
                                            _waves[x + 1, y + 1, _activeBuffer]) >> 2) - _waves[x, y, newBuffer]);

                    //damping
                    if (_waves[x, y, newBuffer] != 0)
                    {
                        _waves[x, y, newBuffer] -= (short)(_waves[x, y, newBuffer] >> 4);
                        wavesFound = true;
                    }
                }
            }

            _weHaveWaves = wavesFound;
            _activeBuffer = newBuffer;
        }

        /// <summary>
        /// This function is used to start a wave by simulating a round drop
        /// </summary>
        /// <param name="x">x position of the drop</param>
        /// <param name="y">y position of the drop</param>
        /// <param name="height">Height position of the drop</param>
        private void PutDrop(int x, int y, short height)
        {
            _weHaveWaves = true;
            int radius = 20;
            double dist;

            for (int i = -radius; i <= radius; i++)
            {
                for (int j = -radius; j <= radius; j++)
                {
                    if (((x + i >= 0) && (x + i < _waveWidth - 1)) && ((y + j >= 0) && (y + j < _waveHeight - 1)))
                    {
                        dist = Math.Sqrt(i * i + j * j);
                        if (dist < radius)
                            _waves[x + i, y + j, _activeBuffer] = (short)(Math.Cos(dist * Math.PI / radius) * height);
                    }
                }
            }
        }

        /// <summary>
        /// The MouseMove handler.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void WaterEffectControl_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left && _bmp != null)
            {
                int realX = (int)((e.X / (double)this.pbViewport.ClientRectangle.Width) * _waveWidth);
                int realY = (int)((e.Y / (double)this.pbViewport.ClientRectangle.Height) * _waveHeight);
                PutDrop(realX, realY, 200);
            }
        }

        #region Properties

        /// <summary>
        /// Our background image
        /// </summary>
        public Bitmap ImageBitmapNew
        {
            get { return _bmp; }
            set
            {
                if (_bmp != null)
                {
                    _bmp.Dispose();
                }
                _bmp = value;
                if (value != null)
                {
                    _bmpHeight = _bmp.Height;
                    _bmpWidth = _bmp.Width;

                    _waveWidth = _bmpWidth >> _scale;
                    _waveHeight = _bmpHeight >> _scale;
                    _waves = new Int16[_waveWidth, _waveHeight, 2];

                    _bmpBytes = new Byte[_bmpWidth * _bmpHeight * 4];
                    _bmpBitmapData = _bmp.LockBits(new Rectangle(0, 0, _bmpWidth, _bmpHeight), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
                    Marshal.Copy(_bmpBitmapData.Scan0, _bmpBytes, 0, _bmpWidth * _bmpHeight * 4);
                    _bmp.UnlockBits(_bmpBitmapData);
                }
            }
        }

        /// <summary>
        /// The scale of the wave matrix compared to the size of the image.
        /// Use it for large images to reduce processor load.
        ///
        /// 0 : wave resolution is the same than image resolution
        /// 1 : wave resolution is half the image resolution
        /// ...and so on
        /// </summary>
        public int Scale
        {
            get { return _scale; }
            set { _scale = value; }
        }

        #endregion Properties

        /// <summary>
        /// Paint handler
        ///
        /// Calculates the final effect-image out of
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void WaterEffectControl_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
        {
            if (_bmp != null)
            {
                using (Bitmap tmp = (Bitmap)_bmp.Clone())
                {
                    int xOffset, yOffset;
                    byte alpha;

                    if (_weHaveWaves)
                    {
                        BitmapData tmpData = tmp.LockBits(new Rectangle(0, 0, _bmpWidth, _bmpHeight), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);

                        byte[] tmpBytes = new Byte[_bmpWidth * _bmpHeight * 4];

                        Marshal.Copy(tmpData.Scan0, tmpBytes, 0, _bmpWidth * _bmpHeight * 4);

                        for (int x = 1; x < _bmpWidth - 1; x++)
                        {
                            for (int y = 1; y < _bmpHeight - 1; y++)
                            {
                                int waveX = (int)x >> _scale;
                                int waveY = (int)y >> _scale;

                                //check bounds
                                if (waveX <= 0) waveX = 1;
                                if (waveY <= 0) waveY = 1;
                                if (waveX >= _waveWidth - 1) waveX = _waveWidth - 2;
                                if (waveY >= _waveHeight - 1) waveY = _waveHeight - 2;

                                //this gives us the effect of water breaking the light
                                xOffset = (_waves[waveX - 1, waveY, _activeBuffer] - _waves[waveX + 1, waveY, _activeBuffer]) >> 3;
       


Richard Deeming

WPF имеет богатую графическую систему. Приклеивание оконных форм PictureBox в окне WPF просто потому, что вы знаете, как писать графический код только с помощью элементов управления Windows Forms, это ужасная идея. Помимо всего прочего, представление будет действительно отстойным.

Рейтинг:
0