雪梨小白的“码绘”起步——p5.js实现心形动态图形的绘制

作为一个快乐的程序媛,尤其还是一个快乐的树莓程序媛,当然应该什么都会!所以这学期学院开了很多偏艺术类的课程让我们学习,然后就开始了互动媒体这门课的学习。这一次的作业要利用p5绘制动态图形,我自己还真的是活力满满的选了一个,emmmm……一点都不容易的,是真不把自己当小白,话不多说,就让我在ddl的这一天记录下雪梨小白的成果。(哈,我还是第一次在CSDN上发博客,搓手手)

平台选择以及p5.js库的配置

我是选择了WebStorm作为JavaScript语言的编译器(虽然我们老师课上墙裂推荐了Sublime Text,但我还是毅然决然了用了WebStorm,其实是主要原因是JetBrains公司出的IDE界面真的简洁美观、用户友好到飞起了啊有木有)

在这里插入图片描述
对我来说,配环境导入库这种事情,其实远比让我敲代码难,从我开始做作业到我完成,有一半的时间都折在了百度上搜索“如何在WebStorm中使用p5.js”,真实暴风哭泣,这时候我的愚蠢就显现出来了,后来在同学的帮助下终于解决了这个问题。

Step 1

新建一个Empty Project,在这个项目下,新建一个js文件(我的叫“SketchWork.js”,我们的码绘代码都要写在这里),再新建一个html用于js文件的呈现(就简单的叫index.html了)。
在这里插入图片描述

Step 2

这个时候要打开p5.js的官网啦(p5js.org),依次根据页面信息选择:下载——单一文件——CDN,把下图的链接Copy下来。
在这里插入图片描述

Step 3

向我们的html文件中标签组内加入几行代码,完成对js文件的引用。

<script src="SketchWork.js" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.js" type="text/javascript"></script>

好啦,阶段性胜利,可以进入到正式的绘制阶段了。

动态图形的分析

让我们先来看看,我要临摹的这张图。
在这里插入图片描述
乍一看还挺好看,就是有点麻烦。

图像外观分析

看动态gif图,我有一个很好的办法,用Ps打开gif可以看到每一帧的图像,所以我就把90张图老老实实地看了一遍。
根据我的观察,这个图像外观上是6层正方体以不同数量整齐堆叠的,有前后两层,由两种颜色组成这些正方形。(如图更清晰)
在这里插入图片描述
所以这直接决定了我们选用box()函数来绘制这些小方块。

运动分析

我还真的是十分的相信我自己的能力,关键是,这个可爱的图像,它动就动了,它还是不匀速的运动,它要先加速转起来,然后再减速停下来。而最最重要的是,心形的每一层在转动的时候彼此与彼此的转速也不一样,按照我在Ps里一帧帧切换的观察来看,应该是这样的:
(我计了一下时,每次循环大致是2.5s完成)

层名单词循环内圈数单词循环内转过的角度
1st4 rounds8PI
2nd4 rounds8PI
3rd3 rounds6PI
4th1.5 rounds3PI
5th1 rounds2PI
6th0.5 roundsPI

*除第六层为匀速运动外,其余各层都是匀角加速运动(我自己默认了这一点,因为如果算变速运动,我可能头就要掉了)
这个时候我就想起了我难忘的大学物理(真的是无语凝噎啊,过了这么久居然在码绘中用到了刚体的旋转),按照我的思路,每一层在绕轴旋转的时候,应该是都以这样的运动规律在进行:
在这里插入图片描述前一阶段先做角加速度为正的运动,后一阶段做角加速度为负的减速运动。两个阶段加起来的旋转角度与我们之前观察到的总旋转角度一致。
在这里插入图片描述
依照上述的公式就可以求解出每层的角加速度,并且列出我们的旋转代码啦。

代码实现

终于写完了分析,我一边写还一边在画分析图表,差点哭出声,那么我们就开始实现吧。
首先要先创建一块画布:

function setup() {
    createCanvas(400,400,WEBGL);
}

在p5中的setup()函数中,完成绘制之前的预设。
这里要敲黑板的是,因为我们用的是box()函数,这个函数在js的原有二维画布上是没有办法实现的,一定要在属性中加入WEBGL,要不然就什么都画不出来,还会报错:在这里插入图片描述
然后给画布一个背景颜色(写在draw()函数中):

function draw(){
    background(0);
}

然后在draw中写一个box()函数:
(在程序开头声明一下BoxSize作为盒子的大小)

function draw(){
    background(0);
    box(BoxSize);
}

在这里插入图片描述
画出来了一个小盒子,但它还是白色的,好像视图角度也不太对,让我们来修正一下。
在setup()中做一下颜色预设,把之前的两种颜色设定好,这里使用了color()函数。

function setup() {
    createCanvas(400,400,WEBGL);
    color1=color(252,68,106);
    color2=color(246,36,71);
}

再在draw()里面通过rotateX(),rotateY(),调整到我们需要的视角。
在这里插入图片描述
如我们所愿,只要绘制出了第一个,接下来每一层都可以通过translate()函数,改变位置再绘制,让我们来画一下中间这一层。(要注意的是box()的绘制以画布中央作为起始位置,translate()之后绘制的起始位置会随之改变,我在这里把画中间层的代码封装成了一个函数)

unction draw3rdline(){
    stroke(0);
    strokeWeight(linewidth);
    fill(color1);

    translate(0,0,1/2*gap);
    box(BoxSize);//Center Box

    //the right part
    translate(gap,0,0);
    box(BoxSize);

    translate(gap,0,0);
    box(BoxSize);

    translate(gap,0,0);
    box(BoxSize);

    //backside line
    translate(0,0,-gap);
    box(BoxSize);

    translate(-gap,0,0);
    box(BoxSize);

    translate(-gap,0,0);
    box(BoxSize);

    translate(-gap,0,0);
    box(BoxSize);

    translate(-gap,0,0);
    box(BoxSize);

    translate(-gap,0,0);
    box(BoxSize);

    translate(-gap,0,0);
    box(BoxSize);

    //back to frontside
    translate(0,0,gap);
    box(BoxSize);

    translate(gap,0,0);
    box(BoxSize);

    translate(gap,0,0);
    box(BoxSize);
}

然后就是下面这个样子:
在这里插入图片描述
让我们努努力把别的层也写出来,需要注意的是需要在相邻层切换一下颜色(代码量较多,我就不全部贴上来了)
画完之后的效果图:
在这里插入图片描述
看起来就像成功了一样…
但我们还有最关键的地方需要处理,就是通过我们刚才公式的推导实现不同层之间加速减速旋转的效果,针对不同层设立变量,写出旋转公式,得到变化的旋转角度,这里要说明的是,为了使得各层旋转独立起来,我们把每一次变换绘制放进push(),pop()函数之间,确保每一层做的是独立的旋转运动。

var BoxSize=26;//盒子的大小
var gap=BoxSize+6;//下一个盒子绘制点的间隔
var linewidth=2;//盒子边框线宽
var color1;
var color2;

var t;//变化的时间
var tset;//每次循环的时间

//每一层的角加速度、角速度、角度
var agularvelocity1stmax;//最大角速度
var angularacceleration1st;//角加速度
var theta1st;//角度
var agularvelocity2ndmax;
var angularacceleration2nd;
var theta2nd;
var agularvelocity3rdmax;
var angularacceleration3rd;
var theta3rd;
var agularvelocity4thmax;
var angularacceleration4th;
var theta4th;
var agularvelocity5thmax;
var angularacceleration5th;
var theta5th;

(上面有些变量刚刚忘了贴)

function drawtheheart(){
    tset=2.5;
    t=millis()/1000%(tset+0.1);

    angularacceleration1st=6*PI;
    agularvelocity1stmax=1/2*angularacceleration1st*tset/2;

    angularacceleration2nd=5.12*PI;
    agularvelocity2ndmax=1/2*angularacceleration2nd*tset/2;

    angularacceleration3rd=3.84*PI;
    agularvelocity3rdmax=1/2*angularacceleration3rd*tset/2;

    angularacceleration4th=1.92*PI;
    agularvelocity4thmax=1/2*angularacceleration4th*tset/2;

    angularacceleration5th=1.28*PI;
    agularvelocity5thmax=1/2*angularacceleration5th*tset/2;

    if(t<=1/2*tset)
    {
        theta1st=1/2*angularacceleration1st*t*t;
        theta2nd=1/2*angularacceleration2nd*t*t;
        theta3rd=1/2*angularacceleration3rd*t*t;
        theta4th=1/2*angularacceleration4th*t*t;
        theta5th=1/2*angularacceleration5th*t*t;
    }
    if(t>1/2*tset&&t<tset)
    {
        theta1st=agularvelocity1stmax*(t-1/2*tset)-1/2*angularacceleration1st*(t-1/2*tset)*(t-1/2*tset);
        theta2nd=agularvelocity2ndmax*(t-1/2*tset)-1/2*angularacceleration2nd*(t-1/2*tset)*(t-1/2*tset);
        theta3rd=agularvelocity3rdmax*(t-1/2*tset)-1/2*angularacceleration3rd*(t-1/2*tset)*(t-1/2*tset);
        theta4th=agularvelocity4thmax*(t-1/2*tset)-1/2*angularacceleration4th*(t-1/2*tset)*(t-1/2*tset)+PI*8;
        theta5th=agularvelocity5thmax*(t-1/2*tset)-1/2*angularacceleration5th*(t-1/2*tset)*(t-1/2*tset)+PI*8;
    }

    push();
    rotateY(theta1st);
    draw1stline();
    pop();

    push();
    rotateY(theta2nd);
    draw2ndline();
    pop();

    push();
    rotateY(theta3rd);
    draw3rdline();
    pop();

    push();
    rotateY(theta4th);
    draw4thline();
    pop();

    push();
    rotateY(theta5th);
    draw5thline();
    pop();

    push();
    rotateY(-0.38*PI*t);
    draw6thline();
    pop();

}

写完了之后,我真是感叹,也许自己学得最好的是物理。(嘤~)

    t=millis()/1000%(tset+0.1);

这一句我要强调下,一开始我是没有这个百分号的,利用一个循环去让t归零,但是这样做的结果就是,我的图形只转了一个循环就停下了,我找了很久为什么都没有解决,最后还是小黑狗同学指出%time可以实现循环(cue一下他,非常感激),之后我们就成功实现了让这个可爱的心,不停不停的转下去的效果。效果图如下(小糊~)
在这里插入图片描述

存留的一些问题与新发现

1.又非常愚蠢的在声明全局变量的时候,用函数赋值了。
在这里插入图片描述
以后不敢了,报错的时候搞得我一脸懵,还以为这个函数不让用。

2.其实translate()函数移动的原理我也不是很明白,有些在使用的时候都是看着效果调整的,再有就是旋转物体的旋转轴,我也找的不是很准,最后转起来了之后发现,没有绕着中心轴在转,我又吭哧吭哧用平移函数挪了半天,如果有哪位大佬知道使用详情,可以稍微指点我一下。

3.除此以外,我和另外一位同样选择了这个图像临摹的同学进行了交流,发现,大家的方法真的好不一样啊!!!莫非这就是逻辑的奥秘,他是用改变开始帧的方式,一帧一帧分配的。(总感觉我自己的方法非常笨重,待我之后再和他好好交流下)

拓展图形

在上述图形的基础上,我进行了颜色的变换、图形位置的编排、以及鼠标交互的制作。

鼠标拖拽改变色彩

这次最值得一提的是这个部分,重写了mouseDragged()函数,在鼠标按下左键拖拽时实现了色彩的变化:

function mouseDragged(){
    colorvalue=colorvalue+5;
    color1=color(0,colorvalue,2*colorvalue);
    color2=color(255,255,255);
    if (colorvalue > 255) {
        colorvalue = 0;
    }
}

再有就是进行缩放、平移,把心形们在画面上安排得明明白白,直接上炫酷的效果图咯:
在这里插入图片描述

心得小结

我大概是ddl狂魔,永远都在追逐ddl,这次终于在交报告前的半小时,完成了这篇博客…虽然很紧张很着急,但也确实很有收获,对我这个雪梨小白来说,每一次收获一点什么都是莫大的快乐哇。当然如果有幸这篇超超超冗长的博客能被人看到,发现我制作的还有什么不足或是错误,还希望大佬们帮我指正。

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值