查看原文
其他

[源代码]- Test 96 变换动画

2016-04-15 Wenzy InsLab

这里分享一个变换算法。原理简单,效果有趣。你可以绘制任何内容,然后对图形进行形态转换。


实现原理

包含两个部分
1.运动算法
2.关联坐标点

运动算法

有尝试用程序写过运动效果的想必非常熟悉这个写法。

(Processing 代码)


PVector A,B;


void setup(){

  size(500,500);

  A = new PVector(width/2,height/2);

}


void draw(){

  background(0);

  B = new PVector(mouseX,mouseY);

  A.x = A.x + (B.x - A.x) * 0.05;

  A.y = A.y + (B.y - A.y) * 0.05;

  fill(255);

  ellipse(A.x,A.y,10,10);

}

点A往点B的方向不断累加,并按比例地不断逼近点 B,则可实现由快至慢的运动效果。你也可以用其他的运动算法来决定点 A 的运动形式。匀速,变速,直线运动,曲线运动。

关联坐标点

一般用数组或是vector来记录点坐标,所以可以将两个不同的绘画轨迹分成两组来保存。外面再加一个 for 循环做遍历,就可以将上面的运动效果,应用到每一个点上。但问题在于,每组点的数据量,往往是不一致的。画面的内容越多,点的坐标数就越多。因此无法完全一一对应。

这里有一个巧妙的解决方法。

(关键代码)


  if(pic1.length < pic2.length){

            int addNum = pic2.length - pic1.length;

            for(int i = 0;i < addNum;i++){

                pic1 = (PVector [])append(pic1,pic1[int(random(pic1.length-1))]);

               

            }

        }

  if(pic1.length > pic2.length){

            int addNum = pic1.length - pic2.length;

            for(int i = 0;i < addNum;i++){

               pic2 = (PVector [])append(pic2,pic2[int(random(pic2.length-1))]);

            }

  }


只要在点的数量相对少的一边,通过随机的方式,补充点坐标,就可以使两边的点一一对应起来。这种做法不会破坏点数较少一边的造型,相当于某些点有了重叠的分身。它会在运动的过程中,分裂成若干个点。又或是若干个点,汇聚成一个点。

Processing完整代码:


PVector []pic1;

PVector []pic2;

int curPic;

boolean running;


void setup(){

  size(500,500);

  pic1 = new PVector[0];

  pic2 = new PVector[0];

  curPic = 1;

}


void draw(){

  background(0);

  

  if(curPic == 1){

    for(int i = 0;i < pic1.length;i++){

      noStroke();

      fill(255);

      ellipse(pic1[i].x,pic1[i].y,5,5);

    }

  }

  if(curPic == 2){

    for(int i = 0;i < pic2.length;i++){

      noStroke();

      fill(255);

      ellipse(pic2[i].x,pic2[i].y,5,5);

    }

  }

  

    if(running && pic1.length!= 0 && pic2.length!= 0){

        for(int i = 0;i < pic2.length;i++){

            pic2[i].x += (pic1[i].x - pic2[i].x) * 0.05;

            pic2[i].y += (pic1[i].y - pic2[i].y) * 0.05;

        }

    }

}


void keyPressed(){

  if(key == '1'){

    curPic = 1;

  }

  if(key == '2'){

    curPic = 2; 

  }

  if(key == 'r'){

        if(pic1.length < pic2.length){

            int addNum = pic2.length - pic1.length;

            for(int i = 0;i < addNum;i++){

                pic1 = (PVector [])append(pic1,pic1[int(random(pic1.length-1))]);

               

            }

        }

        if(pic1.length > pic2.length){

            int addNum = pic1.length - pic2.length;

            for(int i = 0;i < addNum;i++){

               pic2 = (PVector [])append(pic2,pic2[int(random(pic2.length-1))]);

            }

        }

        running = true;

    }

}


void mouseDragged(){

  if(curPic == 1){

    pic1 = (PVector [])append(pic1,new PVector(mouseX,mouseY));

  }

  if(curPic == 2){

    pic2 = (PVector [])append(pic2,new PVector(mouseX,mouseY));

  }

  if(curPic == 'r'){

    running = true; 

  }

}

上面的代码可以完整地体现变化的过程。

  • 数字键 1 ,2 切换画布

  • 数字键 1 对应绘制图形1

  • 数字键 2 对应绘制图形2

  • ‘r’键:开始变换动画,将图形 2 变成图形 1.

为了让代码结构更清晰,做了一定程度的简化。以上的转换过程是不可逆的,如果你希望可以自由来回切换,则需要创建一个数组 temp 来作为中间变量,以保存变换之前的点坐标。

其它形式

这种变换可以有多种变式。

除了二维的点,三维的点同样可以采取同样的方式来进行变换。


你只要导入模型,获取模型的顶点数据。

图片的转换也是同理,由于图片尺寸本身是规整的,前后像素点的数量亦一致,所以只需建立点与点之间的对应关系。


这里将前后两张图片进行了明度排序,图片A最亮的像素点,对应用图片B最亮的像素点,由亮到暗往下排序。由于这个变换过程并不改变原始图片像素的颜色,所以前后图片灰度像素的层次分布越相似,最终还原的效果偏差会越少。

坐标点也可以替换成图片素材,可以依此制作一个围棋棋形变化的动画。



因为是用棋子去表现,如果某些棋子是凭空出现,会显得比较奇怪。所以在排列设计棋形的时候,就刻意用数量相同的棋子(数量都是51)。

END

 “阅读原文” 可获取 OF 源码


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存