非常喜欢星星,非常喜欢特别美特别棒的东西,所以我的自画像是一只一直在追逐光明的兔子。
希望自己永远好奇,永远追逐,赤诚得与在世界上的每一天相恋。
也希望可以有星星点点,在追逐的路上与我相伴。

一追再追

兔子

静态图像

兔子的身子组成部分是头、身体、左耳、右耳、前腿、后退与尾巴,每个部分都是一条bezier曲线。
本来深受平时个人用AI画图的习惯影响,准备所有的图形都用圆来绘制。这里实名感谢yc小天使安利的bezier tool,让我放弃了这个危险的想法。事实证明,当使兔子动起来时,bezier曲线只要移动对应的端点与控制点就可以了,而用圆,即便可以在静态时绘制地好,动态时还是很难控制的。(其实是因为不能像AI中修改锚点)

由于想要天真随意的手绘风格,所以采用的方法是将兔子的代码封装在一个类中,创建多个对象,同时绘制。给每个顶点与控制点都添加一个较小的噪声,就可以使四条线条比较随意地重叠交叉。

绘制方法以身体为例,首先使用bezier tool获得满意的曲线,输出顶点信息:

beginShape();
vertex(633,406);
bezierVertex(521,552,478,382,352,456);
bezierVertex(125,692,697,746,673,458);
endShape();

由于获得的顶点学习是在固定位置的,而我们希望能够动态调整兔子的绘制位置,所以添加x与y到每一个顶点位置坐标中去,实现对位置信息动态修改。

同时,因为希望每一次绘制时的线条都是不同的,而且线条比较连贯顺畅,所以使用了噪声,也添加到每个顶点的位置坐标中。
为了代码的简洁性【大雾,将噪声封装起来。
nosie()函数每次返回一个0-1之间的柏林噪声,与偏移量offset相乘,得到顶点的偏移距离。
由于每绘制一个顶点都会使 i 自增,为了防止长时间运行使浮点数 i 超出取值范围,每次判断,当 i 等于2的23次时,将i重新置零。

  float change(){if(i == 2 << 23){i = 0;}return noise(i++) * offset;}
beginShape();float x = xR;float y = yR;vertex(633 + x + change(),406 + y + change());bezierVertex(521 + x + change() + xOffset * 0.5,510 + y + change() + yOffset * 0.8,478 + x + change() + xOffset * 0.8,382 + y + change() + yOffset * 0.8,352 + x + change() + xOffset,456 + y + change() + yOffset);bezierVertex(125 + x + change() + xOffset * 0.8,692 + y + change() + yOffset * 0.8,707 + x + change() + xOffset * 0.3,746 + y + change() + yOffset * 0.3,673 + x + change(),458 + y + change());endShape();

像这样依次绘制可以获得兔子的静态图像。
但是这张图上耳朵并没有画上去

动态图像

那么下一步就是使兔子动起来。

由于听了yc小天使的话,使用的是bezier曲线,所以要动起来只需要动态改变顶点与控制点的坐标即可。

但是要调整到满意的效果还是非常非常非常非常令人绝望的

还是以身体为例,由于兔子在奔跑时,身体会随着奔跑动作拉伸或收缩,所以对最右边的那个点及其控制点添加一个随时间变化的偏移量。

在每次绘制兔子时,都将记录绘制次数的updateCount增加一。
每绘制10次,使其动作变化一次,将变化次数记为runCount。

    updateCount++;runCount = updateCount % 10;

我们希望每个动作的周期中动作变化10次,因此将runCount乘上36,每增加10次,回到起点。

    float xOffset = 50 - cos(PI - radians(36 * runCount)) * 50;float yOffset = sin(PI - radians(36 * runCount)) * 10 - 10;

将偏移量乘上相对的值,添加在身体后的点及其控制点上。
更新后代码如下:

  void drawBody(){beginShape();float x = xR;float y = yR;float xOffset = 50 - cos(PI - radians(36 * runCount)) * 50;float yOffset = sin(PI - radians(36 * runCount)) * 10 - 10;vertex(633 + x + change(),406 + y + change());bezierVertex(521 + x + change() + xOffset * 0.5,510 + y + change() + yOffset * 0.8,478 + x + change() + xOffset * 0.8,382 + y + change() + yOffset * 0.8,352 + x + change() + xOffset,456 + y + change() + yOffset);bezierVertex(125 + x + change() + xOffset * 0.8,692 + y + change() + yOffset * 0.8,707 + x + change() + xOffset * 0.3,746 + y + change() + yOffset * 0.3,673 + x + change(),458 + y + change());endShape();}

同时,由于奔跑时前腿及后退也要前后摆动,此处使用旋转的方法绘制。
以后腿为例:
首先,后腿需要随着身体的伸缩前后移动,所以后腿也需要加上与之前相同的身体部分的偏离量。

    float xOffset = 20 - cos(PI - radians(36 * runCount)) * 50;float yOffset = sin(PI - radians(36 * runCount)) * 20 - 70;

其次,后腿自身也应该绕某一点转动。
先使用translate函数将画布平移至轴心,再对画布进行旋转,最后用相对的坐标画图。(此处的坐标相当于局部坐标,图形学忘记了,也第一次用popMatrix、pushMatrix的我debug了大半节课
旋转角度的选择,由于想要有个速度由快到慢再到快的变化过程,所以同样使用了三角函数。

    float xStart = 339 + x + change();float yStart = 471 + y + change();float rotation = 1 - abs(sin(radians(18 * runCount)));pushMatrix();translate(xStart + 10, yStart + 80);rotate(-backDeg * rotation);beginShape();...endShape();popMatrix();
void drawBackLeg(){float xOffset = 20 - cos(PI - radians(36 * runCount)) * 50;float yOffset = sin(PI - radians(36 * runCount)) * 20 - 70;float x = xR + 20 + xOffset + cos(PI - radians(36 * runCount)) * 100;float y = yR + yOffset + sin(PI - radians(36 * runCount)) * 30;float xStart = 339 + x + change();float yStart = 471 + y + change();float rotation = 1 - abs(sin(radians(18 * runCount)));pushMatrix();translate(xStart + 10, yStart + 80);rotate(-backDeg * rotation);beginShape();vertex(0, 0);bezierVertex(300 + x + change() - xStart - rotation * 20,466 + y + change() - yStart- rotation * 50,267 + x + change() - xStart - rotation * 20,502 + y + change() - yStart - rotation * 20,221 + x + change() - xStart - rotation * 30,541 + y + change() - yStart - rotation * 40);bezierVertex(175 + x + change() - xStart,548 + y + change() - yStart,104 + x + change() - xStart,556 + y + change() - yStart,104 + x + change() - xStart + rotation * 20 + 10,577 + y + change() - yStart);bezierVertex(121 + x + change() - xStart,593 + y + change() - yStart,173 + x + change() - xStart,569 + y + change() - yStart - rotation * 10,250 + x + change() - xStart - rotation * 80,576 + y + change() - yStart - rotation * 10);bezierVertex(288 + x + change() - xStart - rotation * 50,596 + y + change() - yStart - rotation * 30,340 + x + change() - xStart - rotation * 120,600 + y + change() - yStart - rotation * 30,360 + x + change() - xStart - rotation * 120,583 + y + change() - yStart - rotation * 20);endShape();popMatrix();}

像这样依次绘制可以获得兔子的动态图像
这一张是死机前唯一的一张遗照

光源

光源是用pixel逐点计算得到(总觉得这样性能不太好,但好像确实是使用最频繁的方法之一

首先获得屏幕上的所有像素

  loadPixels();

然后计算每个像素与光源位置的距离,并用2000 / distance得到一个值作为该点光照强度的依据。

distance = dist(i, j, lightPos.y, lightPos.x);distance = 2000 / distance;

如果直接将2000 / distance的值赋给该像素,若光源在兔子之后绘制,则会将兔子的图形完全抹去,形成两个图像交替闪烁的结果。
解决方法是判断2000 / distance是否小于1,当小于1时,由于本身作为参数传入color也是黑色,所以直接跳过不绘制,还可以提高性能。

若光源在兔子之前绘制,则兔子的线条上就没有光照(处女座…)
因此此处解决方法为首先绘制兔子等,再绘制光源。
在绘制光源时,先获取本身的颜色,再将光照的颜色添加,可以获得物体被光照后的效果。

      if(distance > 1){c = pixels[i * width + j];pixels[i * width + j] = color(distance + red(c), distance + green(c), blue(c), 200);}

最后将添加光照后的图片updatePixel

  updatePixels();

完整代码如下:

void drawLight(PVector lightPos){loadPixels();float distance;int c;for(int i = 0; i < height; i++){for(int j = 0; j < width; j++){distance = dist(i, j, lightPos.y, lightPos.x);distance = 2000 / distance;if(distance > 1){c = pixels[i * width + j];pixels[i * width + j] = color(distance + red(c), distance + green(c), blue(c), 200);}}}updatePixels();
}

星星

封装了一个星星的类,每次同时创建30个对象。

对于每一个星星,初始化时随机赋位置值(x\y)、星星半径®、星星向内收缩(size)的程度,创建时随机星星每次旋转角度,即旋转速度(rotateSpeed)

  for(int i = 0; i < 30; i++){star[i] = new Star(1100, 200, random(20) + 5, random(0.3) + 0.4);}
  Star(float tempX, float tempY, float tempR, float tempSize){xOriginal = tempX;yOriginal = tempY;r = tempR;size = tempSize;rotateSpeed = random(60);init();}

在每颗星星刚刚在起点重新生成时,都实时动态随机其x轴速度(xSpeed),y轴速度(ySpeed)。
因为想要实现星星向上喷涌而出再随风飘落的效果,因此再随机每颗星星初始受到向上的力时上升的最大高度(yHeight)。
同时,因为想要星星受到风的作用后向兔子身上飘落的效果,所以在随机x轴速度时,使用了random(60) - 40,使其向负方向的概率较大,向负方向的速度较大。

  void init(){x = xOriginal;y = yOriginal;xSpeed = random(60) - 40;ySpeed = random(30);yHeight = random(500);isReached = 0;deg = 0;force = 0;}

每次更新星星时,按情况分两种:星星刚刚生成,正在飞向最高点,以及星星已经到达最高点,正在下落。

飞向最高点的过程中,由于受到重力作用,速度会逐渐减小,因此将目前y坐标值与最高点y坐标之差作为飞行速度的依据。

到达最高点后,同样由于受到重力作用,速度会逐渐增大,因此同样目前y坐标值与最高点y坐标之差作为飞行速度的依据。

当星星飞出屏幕时,重新调用init函数,使其在光源处随机重新生成。

  void update(){checkMouse();if(isReached == 0){x += (y + yHeight - yOriginal) / yHeight * xSpeed;y -= (y + yHeight - yOriginal) / yHeight * ySpeed + force;if(y < yOriginal - yHeight * 0.5){isReached = 1;y += ySpeed;}drawStar();}else{x += (y + yHeight - yOriginal) / yHeight * xSpeed;y += (y + yHeight - yOriginal) / yHeight * ySpeed - force;if((y < 0) || (y > height) || (x < 0) || (x > width)){init();}else{drawStar();}}}

星星的绘制

  void drawStar(){deg += rotateSpeed;noStroke();fill(#ffda2b);beginShape();for(int i = 0; i < 360; i += 72){vertex(x + r * cos(radians(i + deg)), y + r * sin(radians(i + deg)));vertex(x + r * cos(radians(i + deg + 36)) * size, y + r * sin(radians(i + deg + 36)) * size);vertex(x + r * cos(radians(i + deg + 72)), y + r * sin(radians(i + deg + 72)));}endShape();}
}

交互

实现了鼠标接触到星星,星星受到向上的力弹起的效果。

每次更新星星时,判断鼠标是否接触到星星。如果接触到,就添加一个力。同时每次更新时,对有力作用的星星都将其作用力减小部分。
绘制时,将力添加到y坐标上。

  void checkMouse(){if(force > 0){force -= 4;}if(dist(x, y, mouseX, mouseY) < r * 1.5){force += 40;}}

后记

第一次快要写完时,刚刚和yc说觉得自己可以做完,合上电脑换了教室,再打开电脑就已经死机了。强制关机后打开processing,看着只剩下几十行画曲线的代码,愣 住 了!
然后才发现processing运行后居然不会自动保存。
重新写代码,重新调参数,生无可恋。

【processing】追相关推荐

  1. 追源索骥:透过源码看懂Flink核心框架的执行流程

    https://www.cnblogs.com/bethunebtj/p/9168274.html 追源索骥:透过源码看懂Flink核心框架的执行流程 前言 1.从 Hello,World WordC ...

  2. 斯坦福大学NLP公开课CS224n上映啦!华人助教陪你追剧

    一只小狐狸带你解锁NLP/DL/ML秘籍 作者:小鹿鹿鹿,QvQ,夕小瑶 CS224n: Natural Language Processing with Deep Learning Stanford ...

  3. 追源索骥:透过源码看懂Flink核心框架的执行流程--来自GitHub

    追源索骥:透过源码看懂Flink核心框架的执行流程 联系qq2499496272可进行删除,需要文件版本的私聊!!~ 文章目录 追源索骥:透过源码看懂Flink核心框架的执行流程 前言 1.从 ~~H ...

  4. Processing 模拟池塘生态系统

    Processing 模拟生态系统 博文简介 生物知识 生态系统 实现内容 效果展示 操作说明 相关类 技术讲解 遗传 自治智能体 群集行为 个体行为 问题与思考 参考 其他作品推荐 布料模拟 融入动 ...

  5. Processing互动编程开发实践之动态文字打乱功能(别嫌长,代码多,图片多)

    这篇文章有什么价值? 简单介绍Processing编程 提供一份基于鼠标响应的动画的Processing代码 重头戏:描述动态文字打乱功能实现的重要细节,并将源码公开 1.什么是Processing编 ...

  6. Processing 案例 | 用粒子系统谱写冰与火之歌

    文章目录 引言 FireBrush 分析作品 大概流程 父类:Particle 子类:Fire 子类:Smoke IceAndFire 更多拓展 Frozen Brush 愤怒的小鸟 小结 引言 前不 ...

  7. 基于《代码本色》的processing学习与拓展

    目录 1. 第0章 引言 2. 第1章 向量 3. 第2章 力 4. 第3章 振荡 5. 第4章 粒子系统 1. 第0章 引言 <代码本色>在这一章节的主要内容是模拟随机游走. 讲了利用r ...

  8. 优秀的 Verilog/FPGA开源项目介绍(二十八)- DSP(Digital Signal Processing)

    优秀的 Verilog/FPGA开源项目介绍(二十八)- DSP(Digital Signal Processing) 介绍 FPGA在数字信号处理领域一直有着比通用CPU得天独厚的优势,所以一直都受 ...

  9. 手机GPU光追新解:详谈Imagination刚发布的DXT架构

    最近Imagination Technologies发布新一代IMG DXT架构GPU IP--这次发布的DXT产品主要是面向手机设备的.如果你对Imagination的GPU IP熟的话,应该知道2 ...

  10. Deep Learning in Natural Language Processing中文连载(三)

    第二章 对话语言理解中的深度学习 Gokhan Tur, Asli Celikyilmaz, 何晓东,Dilek Hakkani-Tür 以及邓力 摘要  人工智能的最新进展导致对话助手的可用性增加, ...

最新文章

  1. 崇阳计算机技校,湖北省崇阳县龙翔技工学校
  2. 在linux环境下启动es,linux上Elasticsearch 安装配置、网页访问
  3. 用于磁盘I / O性能SQL Server监视工具
  4. 使用XML及XSL生成简单HTML
  5. 单链表java实现及相关操作(版本1)
  6. 【ML】特征归一化、为什么归一化、归一化的方法、归一化方法选择依据
  7. 若依ruoyi框架整合magic-api增删改查Demo
  8. java找不到符号或方法,java 找不到符号解决方法
  9. 压缩文件下载后无法打开问题解决方法
  10. 360极速浏览器取消默认迅雷下载的正确方法
  11. Matlab【路径规划】—— 无人机药品配送路线最优化
  12. jquery 中 $(document).ready() 与window.onload 的区别
  13. java 实现word转pdf
  14. 为什么使用React作为云平台的前端框架(PPT)
  15. p2psearcher 2013 绿色版下载
  16. 网上学什么副业赚钱?分享多个赚钱的副业,总有一个适合你
  17. 【密码学基础】混淆电路(Garbled Circuit)
  18. CPU mask机制变化
  19. Pr:文本面板之转录文本
  20. 在Google Daydream上用VR观看Youtobe视频吧!

热门文章

  1. CSS拓展选择器 组合选择器 后代选择器 交集选择器 伪类选择器
  2. hdu 5208 Where is Bob
  3. signature=eccf62e7a0495066ee494ebfc791f8cc,测试帖,勿进
  4. OpenCv阈值化处理cv2.threshold()函数
  5. 【Unity3d】存档与读档
  6. html video ajax,利用AJAX开源项目 在网页里播放视频实现方法
  7. latex formula
  8. paip 破解网站手机验证码
  9. 迅速提高社群用户活跃度,需要怎么做?
  10. Guava源码解析五:Splitter源码解析