p5.js 实现创意绘板
前言
由p5.js实现创意绘板,我分成了动态创意绘板和静态创意绘板。
静态创意绘板
上图仿照水粉画。
上述图中实现了对于水粉笔的模仿。
可以调节颜色的变化,对rgb直接进行调节,大小形状也可调节,上图展示的是使用正方形笔刷,颜色是根据画布横坐标来表现,可以看出,左边偏玫红,右边偏绿,笔刷的形状会对深浅有影响。交互的时候还挺好玩的,一个动作在整个画布中不局限于一种颜色,实现画布上颜色的渐变。
不足之处可能也是上述原因,位置的限制,不能做到自由区域颜色的选择。
主要原理是一定区域随机性,实现笔刷的绘制,实际绘制是一个一个小圆,就形成了粉状的质感。
实现代码:
function pastel(mx,my,sx,sy,r,g,b,a)
{ for(var i = 0; i < 1000; i++)
{
var ratio = mx/width;
var x = mx + random(-sx, sy);
var y = my + random(-sx, sy); fill(r, ratio * g, b * (1 - ratio), a); //fill(ratio * 255,255 * (1 - ratio) ,0, 30); //fill(ratio *r,g * (1 - ratio) ,b, a); ellipse(x, y, 2, 2); }}if (keyCode === 65){ //A colorMode(RGB,255,255,255,255);
pastel(mouseX,mouseY,sx,sy,r,g,b,30); }
var r=0;
var g=255;
var b=255;
var sx=20;
var sy=20;
function keyPressed()
{ if(keyCode==82)//R { r=r+30; } if(keyCode==71)//G { g=g-30; } if(keyCode==66)//B { b=b-30; } if(keyCode==97)//1 { sx=sx-5; } if(keyCode==98)//2 { sx=sx+5; } if(keyCode==97)//3 { sx=sy-5; } if(keyCode==98)//4 { sx=sy+5; }}
上图模仿马克笔。图中线条的粗细变化,我觉得还挺好看的,从图中可以看出,重涂和轻涂,所展示的轨迹不一样,缓慢重涂,出来的效果跟接近于平常所使用马克笔,是很浓重的一抹;但是轻涂,特别是快速的划过,就可能画出另一种圆形,一个一个的圆,也体现模仿马克笔所采用的原理本质,是由一个一个的圆所叠加构成。
区别于传统马克笔,上图画笔的运用方式,如快速涂抹和缓慢重涂,可以展现不同的图案,展现了多边形,但是细腻方面,笔锋方面可能不太比得上传统马克笔,做不到快速细腻的笔锋也是上图所表现的一个不足之处。
(小学生涂鸦。。。)
图中是为了仿照现实水彩笔。
与传统最大的区别就是不用替换颜色呐(可能在选取颜色的时候不太方便),颜色的展现随机相连(适合懒人,一支笔有多种颜色),除此之外,就是笔刷颜色的透明度的变化,我觉得这是传统水彩笔实现不了的,快慢会导致笔刷颜色变化,相应也会导致不图透明度的变化,体现不一样色彩效果。
笔触细腻的处理也是上述图中一大不足。
上述图对水彩马克笔的模仿,缓慢厚涂和快速浅涂的区别。快涂,会使得的透明度升高,所展现的图案也和慢涂不同,原理是运用了插值变化。
实现代码:
// 彩球的位置var x;var y;// 彩球位置的插值变化速率var lerpPosSpd = 31.0;
// 彩球当前大小s和颜色rgbaf(a:alpha)
var s = 15;var r = 0;var g = 0;var b = 0;var a = 0.1;
// 彩球颜色插值速率
var lerpSpd = 3.0;
// 彩球的目标大小和颜色
var st = 30;var rt = 0;var gt = 0;var bt = 0;var at = 0.1;
// //黑色圈圈 if (keyCode == 77){ //M colorMode(RGB,255,255,255,1); circleColor(); } //彩色圈圈 if (keyCode == 68){ //D colorMode(RGB,1,1,1,1); circleColor(); }var lastTime = -1;
function circleColor()
{
var tNow = millis()/1000; if(lastTime<0) { lastTime=tNow; return; }var dt = tNow-lastTime; var lerpPosT = lerpPosSpd*dt; if(mouseIsPressed) { // 让x的数值向mouseX的数值靠拢, // 靠拢方式为“线性插值”,靠拢程度(快慢)为lerpPosT x = lerp(x,mouseX,lerpPosT); y = lerp(y,mouseY,lerpPosT); drawThing(x,y); }var lerpT = lerpSpd * dt; s = lerp(s,st,lerpT); r = lerp(r,rt,lerpT); g = lerp(g,gt,lerpT); b = lerp(b,bt,lerpT); a = lerp(a,at,lerpT);randomChange(dt);lastTime = tNow;
}
function drawThing(x,y)
{ fill(r,g,b,a); noStroke(); ellipse(x,y,s,s);}var TimeToChange = -1;function randomChange(dt)
{
TimeToChange-= dt;
if(TimeToChange<0) { st = random(10,60); rt = random(0,1); gt = random(0,1); bt = random(0,1); at = random(0.1,0.3); TimeToChange = randomValue(); print("TimeToChange:" + TimeToChange); }}var lamda = 5;function randomValue()
{
var x = 5/lamda;
var cnt = 0;
do
{ x = random(0,5/lamda);
var y = random(0,1);
var prob = exp(-lamda*x); /if(cnt>30) {break; } cnt ++; }while(prob<y) }
动态创意绘板
动态创意绘板,可以选择多种笔刷,有圆形、三角形、长条、五边形、四边形、六角星星(星星真好看),六种笔刷,颜色也可多选,画板也可以多选,有夜间模式与白天模式。刷的笔刷都是会动的(图中使用的是静止截图)。
虽然有仿照传统绘画板,保留了绘画板的一些功能,如必刷的选择、清屏(点击C),橡皮擦(点击E),保存文件(点击S),以及多种颜色的可选性,但是从根本上,笔刷所得到的图形,最后是会动的,点击||使得图像静止。
与传统绘画板最大不同是,画出的图案是实时动态变化的,且笔刷也比较灵活,交互性上,也更有趣活波,相对的笔刷可能不太容易制作。
主要实现代码:
对于按钮和物体都需要创建数组来进行管理。
var objs = [];
var btns = [];
显示图案的结构定义。
//显示图案预定义
function Node(position, givenSize, givenR, givenG, givenB)
{
this.R = givenR;
this.G = givenG;
this.B = givenB; /
/图案位置
this.position = createVector(position.x, position.y);
this.position.x += (random(20) - 10);
this.position.y += (random(20) - 10); //
this.size = createVector(0, 0);
this.sizeScale = 0.5; var randomSize = givenSize / 2 + random(10);
this.baseSize = createVector(randomSize, randomSize); //
this.timepast = 0; this.isPlaying = isPlaying; //
this.rotateAngle = random(2 * PI); //笔刷类型
this.shapeType = brushType;
this.pmouseX = pmouseX;
this.pmouseY = pmouseY;
this.mouseX = mouseX;
this.mouseY = mouseY;
}
//功能按钮
function FuncBtn(X, Y, W, H, CMD)
{
this.x = X;
this.y = Y;
this.w = W;
this.h = H;
this.cmd = CMD;
//命令
}
//鼠标在颜色选框内
FuncBtn.prototype.isMouseInBtn = function(){ if (mouseX >= this.x && mouseX <= this.x + this.w && mouseY >= this.y && mouseY <= this.y + this.h) { return true; } else { return false; }}
点击按钮响应。
FuncBtn.prototype.clickBtn = function() { print("ClickBtn!"); //
if (this.cmd == "sun")
{
bR = 255;
bG = 255;
bB = 255;
this.cmd = "moon";} else if (this.cmd == "moon") { //改变画布的颜色 bR = 0; bG = 0; bB = 0; this.cmd = "sun"; } else if (this.cmd == "pause") { //运动状态停止 isPlaying = false; for (var i = 0; i < objs.length; i++) { objs[i].isPlaying = false; } this.cmd = "play";} else if (this.cmd == "play") { isPlaying = true; for (var i = 0; i < objs.length; i++) { objs[i].isPlaying = true; } this.cmd = "pause";} }
//显示颜色按钮 位置 宽高 颜色
function ColorBtn(X, Y, W, H, givenR, givenG, givenB)
{
this.x = X;
this.y = Y;
this.w = W;
this.h = H;
this.r = givenR;
this.g = givenG;
this.b = givenB;
}
星星笔刷和多边形笔刷。
// draw a regular n-gon with n sides
function ngon(n, x, y, d){ beginShape(); for(var i = 0; i < n; i++) { var angle = TWO_PI / n * i; var px = x + sin(angle) * d / 2; var py = y - cos(angle) * d / 2; vertex(px, py); } endShape(CLOSE);}// draw a regular n-pointed star
function star(n, x, y, d1, d2)
{ beginShape();
for(var i = 0; i < 2 * n; i++)
{
var d = (i % 2 === 1) ? d1 : d2;
var angle = PI / n * i; v
ar px = x + sin(angle) * d / 2;
var py = y - cos(angle) * d / 2;
vertex(px, py);
}
endShape(CLOSE);
}
笔刷功能实现,以CIRCLE和SQUARE为例,使用sin函数和cos函数改变图像显示的中心位置,使得图像可以运动。
Node.prototype.drawing = function(){ noStroke(); if (this.shapeType == "CIRCLE") { translate(this.position.x, this.position.y);
fill(this.size.x * this.R / 10, this.size.x * this.G / 10, this.size.x * this.B / 10, round(sin(this.timepast) * 128)); ellipse(sin(this.timepast) * this.baseSize.x, cos(this.timepast) * this.baseSize.y, this.size.x * 1.25, this.size.y * 1.25); fill(this.size.x * this.R / 10, this.size.x * this.G / 10, this.size.x * this.B / 10, 255); ellipse(sin(this.timepast) * this.baseSize.x, cos(this.timepast) * this.baseSize.y, this.size.x, this.size.y); resetMatrix();}else if(this.shapeType == "SQUARE"){ translate(this.position.x, this.position.y); rotate(this.rotateAngle); fill(this.size.x * this.R / 10, this.size.x * this.G / 10, this.size.x * this.B / 10, round(sin(this.timepast) * 128)); // rectMode(CENTER); rect(sin(this.timepast) * this.baseSize.x, cos(this.timepast) * this.baseSize.y, this.size.x * 1.25, this.size.y * 1.25); fill(this.size.x * this.R / 10, this.size.x * this.G / 10, this.size.x * this.B / 10, 255); // rectMode(CENTER); rect(sin(this.timepast) * this.baseSize.x, cos(this.timepast) * this.baseSize.y, this.size.x,this.size.y); resetMatrix(); }
显示图像的更新。
Node.prototype.update = function()
{ this.size = createVector(this.baseSize.x + sin(this.timepast) * this.baseSize.x * this.sizeScale,
this.baseSize.y + sin(this.timepast) * this.baseSize.y * this.sizeScale);
if (this.isPlaying) { this.timepast += 1 / FPS;
}
}
判断是否处于运动中,便于静止处理。
if(isPlaying)
{
btns.push(new FuncBtn(5, 5 + 30 * 14, 30, 30, "pause")); }
else{
btns.push(new FuncBtn(5, 5 + 30 * 14, 30, 30, "play")); }
btns.push(new FuncBtn(5, 5 + 30 * 15, 30, 30, "timer"));
btns.push(new FuncBtn(5, 5 + 30 * 16, 30, 30, "eraser"));
btns.push(new FuncBtn(5, 5 + 30 * 17, 30, 30, "clear"));
btns.push(new FuncBtn(5, 5 + 30 * 18, 30, 30, "save"));
}
鼠标按下的处理,处于可选择区域后的点击的处理。
if (mouseIsPressed && (mouseX > 40 || isMenuHide))
{
if (brushType == "CIRCLE" || brushType == "LINES" || brushType == "TRIANGLE" ||brushType == "SQUARE"||brushType == "PENTAGON"||brushType == "STAR" ||brushType == "COLORCIRCLE"||brushType == "PASTEL")
{
var position = createVector(mouseX, mouseY); //
objs.push(new Node(position, sqrt(sq(mouseX - pmouseX) + sq(mouseY - pmouseY)), R, G, B)); }
//Eraser
else if (brushType == "ERASER" && objs.length > 0)
{
for (var i = 0; i < objs.length; i++)
{
if (sqrt(sq(objs[i].position.x - mouseX) + sq(objs[i].position.y - mouseY)) <= eraserRange)
{
objs.splice(i, 1);
break;} } } else if (brushType == "TIMER" && objs.length > 0) { for (var i = 0; i < objs.length; i++) { if (sqrt(sq(objs[i].position.x - mouseX) + sq(objs[i].position.y - mouseY)) <= timerRange) { objs[i].timepast += 2 / FPS; objs[i].isPlaying = false; } } } }
图像的显示与更新。
for (var i = 0; i < objs.length; i++)
{
objs[i].drawing();
objs[i].update();
}
参考文献:
http://mc.dfrobot.com.cn/forum.php?mod=viewthread&tid=22951
https://blog.csdn.net/magicbrushlv/article/details/77840565
https://blog.csdn.net/qq_27534999/article/details/79427721
p5.js 实现创意绘板相关推荐
- p5.js 绘制创意自画像(互动媒体技术作业)
p5.js 绘制创意自画像Little Prince(互动媒体技术作业) 作品展示 代码&创意点分析 1.设置工具类以获取坐标点:本次实验最有用的东西就是这个了 2.眼睛跟随鼠标运动: 3.披 ...
- P5.js:改进创意动态绘板
在互动媒体课上接触到p5.js这个东西后,我就一直在质疑它的实用性,p5.js用来画图并不是那么的好用,但其和unity差不多的性质为动态绘图提供了条件(p5.js使用setup()函数初始化,每秒调 ...
- 互动媒体技术——基于p5.js实现动态图形临摹与拓展:炫彩光影的千变万化!
博文索引目录: 1. 引言 2. 临摹结果对比 3. 临摹过程 3.1 准备工作 3.2 原图规律--语言描述 3.3 原图规律--数学与代码描述 3.4 完整代码 4. 创意拓展 4.1 拓展一-- ...
- P5.JS绘制动态图形
P5.JS绘制动态图形 一.平台 第一次使用p5.js进行码绘,此次直接使用P5.JS官网的在线编辑器进行编写,完成后点击file->download即可保存到本地. 在正式绘制之前,我经过小小 ...
- 使用p5.js画一幅创意自画像
使用p5.js画一幅创意自画像 使用p5.js画一幅创意自画像 用编程方式创作一幅介绍自己的图片,因为我很喜欢五月天,所以我的自画像就是展示我去看演唱会的样子,穿着五月天Logo的stayrealT恤 ...
- 码绘:使用p5.js进行简单的作画
使用工具 Visual Studio Code+p5.js 下载地址 Visual Studio Code:https://code.visualstudio.com/Download p5.js:h ...
- 【码绘】p5.js画Q版自画像
[码绘]p5.js画Q版自画像 来自互动媒体作业的实验二,这次没有采用processing,而选择了p5.js,原因是用p5.js的在线编辑实时浏览比较方便. 先看一下最后的成果吧 我的实验过程: 手 ...
- 用p5.js实现的码绘与手绘的比较(动态)
用p5.js实现的码绘与手绘的比较(动态) 上篇:用p5.js实现的码绘与手绘的比较(静态)https://blog.csdn.net/wangyouxu24/article/details/8433 ...
- p5.js之数媒logo(码绘1)
一.开发环境: window10.火狐浏览器63.0.3.vs code1.28.2 二.应用框架: p5.js 三.开发背景: 近日学习p5.js稍有所得,想利用此框架绘出一幅自己的作品,便以学院l ...
- Originality Self-portrait 创意自画像——p5.js
Originality Self-portrait 创意自画像--p5.js 1.对自己的理解--以便自画. 个人性格比较像熊,平时吃饱喝足还是比较温顺的,但是烦心事比较暴躁,看什么东西都会不爽,所以 ...
最新文章
- DWZ基于ajax重复请求的修复
- WSL:WSL(Windows Subsystem for Linux)的简介、安装、使用方法之详细攻略
- 线上分享 | AI产品经理之路——从入门到进阶
- android开发中Switch开关在Dialog中不显示
- beego使用php,介绍beego、nginx性能测试实例
- sql查找一个范围的值_销售需求丨查找问题
- 什么是数字孪生?有哪些关键技术?现在怎么样了?
- 计算机会计技术特点,会计电算化的特点
- 数学建模入门篇(新手必看)
- 18年12月英语六级第二套听力单词
- 平行交通:虚实互动的智能交通管理与控制
- 高级计量经济学及stata应用 陈强 2021年5月1-5日 社会科学 经济学 管理学 金融 医学等各个领域
- 利用阿里云容器镜像服务下载gcr.io镜像
- 【其他】Tensorflow分布式使用简介
- Silverlight 教程第五部分:用 ListBox 和 DataBinding 显示列表数据 (木野狐译)
- vue修改浏览器的标题和图标
- MySQL权限与安全管理之权限表与账户管理
- 使用wildfly部署项目
- Android 常用开源库总结-2020年
- JPA @NamedEntityGraph使用
热门文章
- Loadrunner教程–常用操做流程
- Python爬虫-模拟登入-selenium模块
- 状态监测与故障智能诊断技术在能源动力机械内燃机的应用
- 5款Windows系统下的桌面管理软件
- 安装deb软件包时出现Unknown media type in type **/** 的解决办法
- 同人游戏开发工具巡礼——AVG(ADV)引擎篇
- Day 9 2021.3.10多线程-Lambda表达式-File类
- 社会工程学攻击的三个典例
- 一刀工具箱 - 古诗文查询
- 服务器音频文件缓存,音频文件如何缓存到本地,和播放缓存到本地的音频文件...