跳转至

画风:九种手笔,以及画它们用的工具包

画风是做出一种笔触的方式,它远不止一套调色板。同一只狐狸,交给一个拿蜡笔的孩子、一位拼贴艺术家和一位版画家来画,形状、边缘和光线都会变,连笔触落下的顺序也会变。给一幅画重新上色,你得到的只是同一幅画换了九套衣服。下面每一张样张都是 engine/src/canvas-core/ 里一个能运行的模块:用它的画风画画之前先打开它,因为头部注释就是配方,代码就是证明。

任意渲染其中一个:node tools/still.mjs koi --out out/koi.png。整张总览页:node tools/still.mjs styleGallery。

这九种

# 画风 模块 造就它的笔触
1 铅笔水彩 ranunculus.ts 淡彩永远填不满它的轮廓,形体朝一个光源塑造,石墨线画在颜料之上
2 马克笔漫画 koi.ts 平涂的赛璐璐填色带一道硬阴影边,一条粗重的轮廓线,在背光的一侧变粗
3 圆珠笔速写 pocketWatch.ts 一支圆珠笔,线宽几乎恒定;明暗只来自排线落在哪里(单向、交叉、第三个方向),再加上用力的一笔停下时留下的墨团
4 蜡笔 balloon.ts 来回涂抹的填色跳过纸面的凹谷,暗面上再叠一支更深的蜡笔,用一支白蜡笔把高光压亮,一条粗轮廓描了两遍
5 墨线淡彩 wren.ts 先上湿淡彩,漫过线条,沿每个形状的底边沉积,带回花(backrun);然后上弹性笔尖,下压处粗、提笔处细如发丝,光线吃掉边缘的地方轮廓留着开口
6 黑板粉笔 moonPhases.ts 用粉笔侧面擦出的薄涂,受光的月缘反复画两遍,每一笔都被黑板的颗粒打断、两侧落着粉尘,还有旧课残留的痕迹
7 剪纸拼贴 fox.ts 一条画出来的线都没有:撕开的纸片带着白色的纤维毛边,剪刀剪的纸片边缘利落,每一片都带着柔和的影子从下面那片上翘起
8 孔版印刷(Risograph) lighthouse.ts 每个滚筒一层,各自透过自己的套印偏移做正片叠底;其他每一种颜色都是叠印出来的;明暗是每种油墨角度下的一层半调网屏;白色就是纸的本色
9 单线雕刻 mellan.ts 一条不间断的螺旋线,宽度随一个程序化的明暗场变化:整幅画就是一笔

另外两种手笔在完整示例影片里(example/):一种氰版蓝图(直线笔、draftTooth + blueMottle 瓦片、inkGroup 光晕、倾斜哥特体字),以及一个绘本铅笔 + 水彩角色(storybook.ts)。print.ts 是同一个角色的孔版印刷版。

怎么挑

先按用途挑,再看外观。同一个想法放进每一种画风,读起来都不一样。

作品是 首选
温暖、有人情味,一个带笑容的品牌 铅笔水彩、蜡笔、剪纸
严肃的主题、一份报告、一篇创始人文章 圆珠笔、墨线淡彩、雕刻
讲解片、原理说明、信息图 黑板粉笔、蓝图、带制图标注的圆珠笔
热闹的、社交媒体、一次发布 马克笔漫画、孔版印刷
海报、封面、一张人们会留着的图 雕刻、孔版印刷、剪纸

一个品牌挑一种手笔,并一直用下去:之后的每一张主视觉、插图和卡片都用同一种笔触,正是这一点让一组作品看起来像一个体系。

你自己的画风

从最接近的样张出发,改笔触,绝不只改颜色:

  1. 用物理的说法讲清媒介。 什么东西接触纸面,有多湿,怎么提起,纸面又怎么回应。在写任何代码之前把它写成头部注释,就像上面那九种一样。
  2. 给用笔的手笔设一个 Medium:{ nib, taper, pressure, retrace, wobble, rough }。对比 PENCIL、BIRO_M(pocketWatch)、CRAYON_M(balloon)、INK_M(wren)、CHALK_M(moonPhases)、LITHO(riso)。圆珠笔几乎没有收锋;弹性笔尖的压力变化很大。
  3. 决定笔触的顺序。 先淡彩后线条(墨线淡彩),先线条后淡彩(铅笔水彩),一版接一版(孔版印刷),一片接一片(拼贴)。顺序就是画风的一半。
  4. 挑纸:用哪些瓦片,多大的不透明度,最后叠上去。
  5. 用它渲染一张最难题材的静帧,在把这种画风用到任何别的地方之前,对照 realism-and-craft.md 里的手艺对照表批评它。

工具包

一切都是几何,再加几层合成。没有滤镜,没有素材文件。

core.ts 是绘图表面和形状辅助函数。

  • new Gfx(ctx, env, frame, medium),绘图表面。frame 驱动运动中的线条抖动;静帧传 0。
  • g.group("paint" | "ink" | "plain", fn, { blend, alpha, off, textures, blur }):在一个图层上绘制,给它加一次纹理,只合成被画到的部分。paint 会柔化并加颗粒,ink 得到铅笔纸纹,plain 用于剪纸或印刷类媒介。
  • g.pen(pts, { w, color, seed, closed, wobble, boil, taper, opacity, retrace, progress }):一道带收锋、按压力塑形的笔画。progress < 1 只画一部分,沿中心线截断,观众看到一条线正在被画出来,靠的就是这个。
  • g.form(pts, color, shade, { light, hi }):朝一个光源着色的体块,可选高光。
  • g.wash(pts, color, { alpha, dx, dy, shrink, rim }):漏出轮廓的水彩,颜料积在边缘。
  • g.fill、g.hatch、g.glow、g.paper(tile, opacity)、g.vignette、g.inkGroup(带光晕的线条)。
  • 形状:oval、softBox、arc、line(a, b, bow)、tube(centre, r0, r1)、poly、turn、sample(把折线平滑化)、jitter、displace(噪声位移后的几何)、halftone。
  • 随机性:rng(seed)、fractal(seed, x, y, fx, fy, octaves)。
  • 瓦片:paper、coldpress、pencilTooth、washGran、risoSpeck、risoMottle、draftTooth、blueMottle。

gallery.ts 存放各样张共用的具象辅助函数:body(ctrl, halfWidth)(一根带宽度剖面的脊线,用于鱼、鸟、四肢)、profile(knots)、ink(g, centre, color, opts)(一条在背光一侧变粗的轮廓带)、blob(一个有机的闭合形状)、hatchRuns(裁切到形状之内的排线)、fillShape、clipped、inside、mix、resample。

riso.ts 负责版画:INK 颜色、drum(g, offset, fn)、screen(...)(由一个明暗函数驱动的半调网屏)、REG 偏移、cut(手工裁切的边缘)、plateMarks、across(横跨一个形状的 0..1 渐变)。

字母用笔画画出来,所以从不加载任何字体。

  • drafting.ts:letter(g, text, x, y, { cap, color, seed, w, progress }),单线倾斜哥特体大写字母,也就是工程图上的那种字。用于标签、标注、说明文字、信息图里的数字。progress 把它一笔一笔写出来。
  • lettering.ts:尖头笔书写体,宽度取决于每一段往下走了多少。它只拼写一个专门绘制好的词(横幅上那个);换一个新词,就意味着用同样的方式为它绘制中心线。