6

我怎样才能模拟像窗户油漆一样的喷雾?我认为它会随机产生分数,你的意见是什么?

4

6 回答 6

5

是的,我会说它在选择点的某个半径内为随机像素着色。一个像素的着色和另一个像素的着色之间也可能存在时间延迟,因为今天的机器速度足够快,可以在您放开鼠标按钮之前为每个可能的像素着色(只要半径很小)。

另外,我认为 Paint 使用的算法可以选择一个像素进行绘制,即使它已经被绘制,因为有时你可能会得到一个内部有几个未绘制像素的绘制圆圈。

于 2010-05-25T17:00:14.197 回答
3

喷漆的图案是半随机的。如果你拿出一罐 Krylon 并在墙上慢慢喷一条线,你最终会得到一条宽实线,该线逐渐淡出到背景中,边缘有渐变。在一个点喷洒十秒钟,你会在中心得到一个大点,颜色完全饱和,与背景呈放射状渐变。

所以 - 你的模拟变量包括:

  • 拿着“喷雾器”(鼠标按钮)的时间
  • “罐头”(鼠标)的运动
  • “罐头”的速度(快速移动形成一条轻快的、不饱和的线。慢速移动形成一条带有渐变的粗、饱和的线)
  • 扩散模式:喷雾是像喷枪一样集中,还是像喷雾罐一样大?
  • 《距离》:“喷子”离“画布”有多远?
于 2010-05-25T17:12:48.963 回答
2

您收到了许多答案,这些答案为您指明了开始处理喷雾效果的用户体验的正确方向。根据您对我的评论的回复,您还需要一种算法来生成半径内的随机点。

有很多方法可以做到这一点,最明显的可能是使用 极坐标选择随机点,然后将极坐标转换为笛卡尔 (x,y) 坐标来渲染像素。这是这种方法的一个简单示例。为了简单起见,我刚刚为每个点绘制了一个简单的 1x1 椭圆。

private Random _rnd = new Random();
private void Form1_MouseDown(object sender, MouseEventArgs e)
{      
  int radius = 15;

  using (Graphics g = this.CreateGraphics())
  {
    for (int i = 0; i < 100; ++i)
    {
      // Select random Polar coordinate
      // where theta is a random angle between 0..2*PI
      // and r is a random value between 0..radius
      double theta = _rnd.NextDouble() * (Math.PI * 2);
      double r = _rnd.NextDouble() * radius;

      // Transform the polar coordinate to cartesian (x,y)
      // and translate the center to the current mouse position
      double x = e.X + Math.Cos(theta) * r;
      double y = e.Y + Math.Sin(theta) * r;

      g.DrawEllipse(Pens.Black, new Rectangle((int)x - 1, (int)y - 1, 1, 1));
    }
  }
}

或者,您可以从适合喷雾圆的矩形中随机选择 x,y 坐标,并使用圆方程 r^2 = x^2 + y^2 测试该点以确定它是否位于圆内,如果是的话随机选择另一个点并再次测试,直到您有一个位于圆圈内的点。这是此方法的快速示例

private Random _rnd = new Random();
private void Form1_MouseDown(object sender, MouseEventArgs e)
{      
  int radius = 15;
  int radius2 = radius * 2;

  using (Graphics g = this.CreateGraphics())
  {
    double x;
    double y;

    for (int i = 0; i < 100; ++i)
    {          
      do 
      {
        // Randomy select x,y so that 
        // x falls between -radius..radius
        // y falls between -radius..radius
        x = (_rnd.NextDouble() * radius2) - radius;
        y = (_rnd.NextDouble() * radius2) - radius;

        // If x^2 + y^2 > r2 the point is outside the circle
        // and a new point needs to be selected
      } while ((x*x + y*y) > (radius * radius));

      // Translate the point so that the center is at the mouse
      // position
      x += e.X;
      y += e.Y;

      g.DrawEllipse(Pens.Black, new Rectangle((int)x - 1, (int)y - 1, 1, 1));
    }
  }
}
于 2010-05-26T21:54:22.457 回答
0

您可以通过对极坐标的一些数量(与所需的强度和扩散相关)进行采样来创建各种强度的喷雾模式。为此,请通过以下方式确定每个样本的随机极坐标 (ρ, θ):

从 N(0, 1) 采样的 ρ:使用正态(高斯)分布表示距喷雾模式精确中心的距离。我不记得 .NET 库中是否有普通的变量生成器。如果没有,您可以从 U(0, 1) 生成器创建一个

从 U(0, π) 采样的 θ:从均匀连续分布中采样角度分量。在不损失性能或通用性的情况下,您可以改为在 U( n π, m π) 上对n < m进行采样,但 U(0, π) 可能适合您的需要。

每个样本的笛卡尔坐标由 (T x + S x ρ cos θ, T y + S y ρ sin θ) 给出,其中 (T x , T y ) 是您要创建的喷雾模式的中心;S x和 S y分别是您希望在 x 和 y 方向上的扩展因子。

于 2010-07-06T02:38:20.860 回答
0

尝试使用计时器

public partial class Form1 : Form
{
    int Radious = 5;
    Random _rnd = new Random();
    Timer T = new Timer();
    int InterVal = 1000;
    MouseEventArgs MEA = null;
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        T.Tick += (O, E) =>
        {
            StartSpray();
        };
        this.MouseDown += (O, E) =>
        {
            MEA = E;
            T.Interval = InterVal;
            T.Start();

         };
        this.MouseUp += (O, E) =>
        {
            T.Stop();
        };
    }
    private void StartSpray()
    {
        Point P = DrawPoint(Radious, MEA.X, MEA.Y);
        // Draw the point on any graphics area you can add the color or anything else
    }
    private Point DrawPoint(int Radious, int StatX, int StartY)
    {
        double theta = _rnd.NextDouble() * (Math.PI * 2);
        double r = _rnd.NextDouble() * Radious;
        Point P = new Point { X = StatX + Convert.ToInt32(Math.Cos(theta) * r), Y = StartY + Convert.ToInt32(Math.Sin(theta) * r) };
        return P;
    }      
}

请修改间隔和半径。

于 2010-07-06T22:51:28.853 回答
-1

我认为很难在 C# 上找到示例。下面我将介绍一种开始您的旅程的方法。在这里,我使用纹理画笔。

private void Button1_Click(System.Object sender, System.EventArgs e)
{
    try
    {
        Bitmap image1 = (Bitmap)Image.FromFile(@"C:\temp\mybrush.bmp", true);

        TextureBrush t = new TextureBrush(image1);
        t.WrapMode = System.Drawing.Drawing2D.WrapMode.Tile;
        Graphics formGraphics = this.CreateGraphics();
        formGraphics.FillEllipse(t, new RectangleF(90.0F, 110.0F, 100, 100));
        formGraphics.Dispose();

    }
    catch (System.IO.FileNotFoundException)
    {
        MessageBox.Show("Image file not found!");
    }

}

正如杰西所说,我认为你应该找到一种算法来传播随机像素。

于 2010-05-25T17:09:43.603 回答