前言

由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 实现创意绘板相关推荐

  1. p5.js 绘制创意自画像(互动媒体技术作业)

    p5.js 绘制创意自画像Little Prince(互动媒体技术作业) 作品展示 代码&创意点分析 1.设置工具类以获取坐标点:本次实验最有用的东西就是这个了 2.眼睛跟随鼠标运动: 3.披 ...

  2. P5.js:改进创意动态绘板

    在互动媒体课上接触到p5.js这个东西后,我就一直在质疑它的实用性,p5.js用来画图并不是那么的好用,但其和unity差不多的性质为动态绘图提供了条件(p5.js使用setup()函数初始化,每秒调 ...

  3. 互动媒体技术——基于p5.js实现动态图形临摹与拓展:炫彩光影的千变万化!

    博文索引目录: 1. 引言 2. 临摹结果对比 3. 临摹过程 3.1 准备工作 3.2 原图规律--语言描述 3.3 原图规律--数学与代码描述 3.4 完整代码 4. 创意拓展 4.1 拓展一-- ...

  4. P5.JS绘制动态图形

    P5.JS绘制动态图形 一.平台 第一次使用p5.js进行码绘,此次直接使用P5.JS官网的在线编辑器进行编写,完成后点击file->download即可保存到本地. 在正式绘制之前,我经过小小 ...

  5. 使用p5.js画一幅创意自画像

    使用p5.js画一幅创意自画像 使用p5.js画一幅创意自画像 用编程方式创作一幅介绍自己的图片,因为我很喜欢五月天,所以我的自画像就是展示我去看演唱会的样子,穿着五月天Logo的stayrealT恤 ...

  6. 码绘:使用p5.js进行简单的作画

    使用工具 Visual Studio Code+p5.js 下载地址 Visual Studio Code:https://code.visualstudio.com/Download p5.js:h ...

  7. 【码绘】p5.js画Q版自画像

    [码绘]p5.js画Q版自画像 来自互动媒体作业的实验二,这次没有采用processing,而选择了p5.js,原因是用p5.js的在线编辑实时浏览比较方便. 先看一下最后的成果吧 我的实验过程: 手 ...

  8. 用p5.js实现的码绘与手绘的比较(动态)

    用p5.js实现的码绘与手绘的比较(动态) 上篇:用p5.js实现的码绘与手绘的比较(静态)https://blog.csdn.net/wangyouxu24/article/details/8433 ...

  9. p5.js之数媒logo(码绘1)

    一.开发环境: window10.火狐浏览器63.0.3.vs code1.28.2 二.应用框架: p5.js 三.开发背景: 近日学习p5.js稍有所得,想利用此框架绘出一幅自己的作品,便以学院l ...

  10. Originality Self-portrait 创意自画像——p5.js

    Originality Self-portrait 创意自画像--p5.js 1.对自己的理解--以便自画. 个人性格比较像熊,平时吃饱喝足还是比较温顺的,但是烦心事比较暴躁,看什么东西都会不爽,所以 ...

最新文章

  1. DWZ基于ajax重复请求的修复
  2. WSL:WSL(Windows Subsystem for Linux)的简介、安装、使用方法之详细攻略
  3. 线上分享 | AI产品经理之路——从入门到进阶
  4. android开发中Switch开关在Dialog中不显示
  5. beego使用php,介绍beego、nginx性能测试实例
  6. sql查找一个范围的值_销售需求丨查找问题
  7. 什么是数字孪生?有哪些关键技术?现在怎么样了?
  8. 计算机会计技术特点,会计电算化的特点
  9. 数学建模入门篇(新手必看)
  10. 18年12月英语六级第二套听力单词
  11. 平行交通:虚实互动的智能交通管理与控制
  12. 高级计量经济学及stata应用 陈强 2021年5月1-5日 社会科学 经济学 管理学 金融 医学等各个领域
  13. 利用阿里云容器镜像服务下载gcr.io镜像
  14. 【其他】Tensorflow分布式使用简介
  15. Silverlight 教程第五部分:用 ListBox 和 DataBinding 显示列表数据 (木野狐译)
  16. vue修改浏览器的标题和图标
  17. MySQL权限与安全管理之权限表与账户管理
  18. 使用wildfly部署项目
  19. Android 常用开源库总结-2020年
  20. JPA @NamedEntityGraph使用

热门文章

  1. Loadrunner教程–常用操做流程
  2. Python爬虫-模拟登入-selenium模块
  3. 状态监测与故障智能诊断技术在能源动力机械内燃机的应用
  4. 5款Windows系统下的桌面管理软件
  5. 安装deb软件包时出现Unknown media type in type **/** 的解决办法
  6. 同人游戏开发工具巡礼——AVG(ADV)引擎篇
  7. Day 9 2021.3.10多线程-Lambda表达式-File类
  8. 社会工程学攻击的三个典例
  9. 一刀工具箱 - 古诗文查询
  10. 服务器音频文件缓存,音频文件如何缓存到本地,和播放缓存到本地的音频文件...