【ShaderToy】水彩画


写在前面



好久没有更新shadertoy系列了,我万万没想到有童鞋还惦记着它。。。之前说过希望可以一周更新一篇,现在看来是不怎么可能了,一个月更新一篇的希望比较大(不要再相信我了。。。)

我把之前实现的这个系列上传到了GitHub(https://github.com/candycat1992/Shadertoy_Lab)上,有兴趣的可以去下载下来。当然,也希望有网友可以一起贡献这个项目。

GitHub上这个项目大部分灵感来源于shadertoy(https://www.shadertoy.com),也有一些是配合博客里的一些文章讲解的,也有一些是在原shadertoy里面的例子扩展而来的。总之,每个lab我都会在README里面给出相关的参考资料。

项目链接:https://github.com/candycat1992/Shadertoy_Lab


好啦,我们来看一下这一篇里面要讲的例子。如同题目所讲,我们的目标是模拟水彩风格的效果。当然,这里实现的只是简化版本后的实现,我们只实现了渲染部分。

参考资料:

[1] https://www.shadertoy.com/view/XdSSWd
[2] Curtis C J, Anderson S E, Seims J E, et al. Computer-generated watercolor[C]// Proceedings of the 24th annual conference on Computer graphics and interactive techniques. ACM Press/Addison-Wesley Publishing Co., 1997.



论文研讨:Computer-Generated Watercolor



这个例子来源于一篇著名的论文,也就是1997年的Computer-Generated Watercolor。年代虽然很久远了,但是这篇论文开启了用计算机模拟水彩画的先河,后面陆陆续续又有很多论文被发表出来,但几乎都可以看到这篇论文的影子。

这篇论文主要可以分为四个部分:

  1. 首先,描述了水彩颜料的物理性质,并从艺术角度给出了一些水彩画的风格特性;
  2. 给出了如何模拟这些特性的方法;
  3. 具体描述了对水彩和颜料(pigment)的物理模拟算法;
  4. 描述了如何渲染这些颜料。

而本文其实只是实现了最后一个部分,在本节后面的内容里,我会简略介绍下论文里其他三个方面的内容。如果读者对这方面研究有兴趣的话,还是强烈建议去阅读原论文。



水彩的物理属性



水彩画(watercolor paint ,也被简称为watercolor)是一种比较常见的艺术风格。一幅水彩画涉及到了两种材质:

  • 水彩纸(watercolor paper)。它并不是由木材制作而成的,而是通过把亚麻布或者棉花捣碎成细小的纤维的来的。这种材质非常容易吸收液体,为了防止颜料迅速蔓延,因此还给这些纸张进行上浆(sizing)。

  • 颜料(pigment)。这是一种固体材质,由很多很小的单独的粒子组成。这些水彩颜料通常由0.05到0.5微米的粉末构成,它们可以渗透水彩纸,但一旦附着在纸上,扩散速度就会下降。

除此之外,水彩画有一些特点,例如:

  • 干笔画(Dry brush)。如果使用较干的画笔画在粗糙的纸上,那么会出现一些不规则的空隙和粗糙的边界效果。

  • 边界颜色较深(Edge darkening)。如果使用较湿的画笔画在较干的纸面上,在纸的浆料和水的表面张力的作用下,颜料不会继续扩散,并在边缘处留下一圈颜色更深的沉淀痕迹。



模拟



在论文中,作者提出使用三个图层来模拟水彩画中颜料的流动:

  • 第一层是shallow-water layer。在这一层中,水和颜料会在纸张表面扩散流动。

  • 第二层是pigment-deposition layer。在这一层中,颜料会沉淀进入和释放出纸张。

  • 第三层是capillary layer。在这一层中,被纸张吸收的水会通过毛细管作用被继续扩散。(这一层仅仅用于模拟水彩画的回流效果。)

在模拟时,作者使用了很多参数来控制模拟效果,例如颜料的扩散速度、画笔压力、纸张的高度、颜料密度、液体饱和度、液体容量等等。

关于纸张的模拟,作者使用了一种简单的模型,即高度场的方法,并使用了Perlin噪声(Ken Perlin. An image synthesizer. In SIGGRAPH ’85 Proceedings, pages 287–296. July 1985.)和Worley的多孔纹理(Steven P. Worley. A cellular texturing basis function. In SIGGRAPH ’96 Proceedings, pages 291–294. 1996.)来生成。这种方法非常常见。



算法



有了上述这些参数之后,就可以进行算法模拟的部分。主循环部分在每个时间步内,会进行四个计算步骤:

  1. 在shallow-water layer移动液体(Move Water)。

  2. 在shallow-water layer移动颜料(Move Pigment)。

  3. 在pigment-deposition layer传递颜料(Transfer Pigment)。这一步会模拟颜料的吸收和释放。

  4. 在capillary layer模拟毛细流动(Simulate Capillary Flow)。这一步会模拟回流现象等。

具体的算法还是要参考论文,本文不涉及这些算法的实现。



渲染



以上的内容只是为了完整性,而与这篇博客相关的只有渲染部分。

当经过上面的算法后,我们可以得到每个区域的颜料厚度。

作者使用了Kubelka-Munk(KM)模型来渲染颜料。在论文中,作者为每个颜料指定了两个系数:吸收系数(absorption coefficients)K和散射系数(scattering coefficients)S。K和S都是三维属性,分别表示颜料吸收和散射的能量。



指定颜料的光学属性



虽然K和S系数通常是经验决定的,但作者允许让用户来指定:通过选择希望的“unit thickness”(单位厚度)的颜料在黑白背景下的外观来决定。具体方法是,给定用户选择的两个RGB颜色 Rw (在白色背景下的颜色)和 Rb (在黑色背景下的颜色),K和S系数可以靠下面的等式来得到:

S=1bcoth1(b2(aRw)(a1)b(1
  • 18
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 19
    评论
要在Android上实现水彩笔绘画,可以使用以下步骤: 1. 创建自定义View类,继承自View或SurfaceView类。 2. 在该类中添加绘图方法,在绘图方法中使用Canvas类和Paint类实现绘制水彩效果的画笔。 3. 在onTouchEvent()方法中监听用户手指触摸事件,根据手指移动的轨迹绘制水彩画笔的效果。 4. 使用Bitmap类在内存中保存绘制的内容,并将其显示在屏幕上。 以下是一个简单的实现示例: ```java public class WaterColorView extends View { private Path mPath; private Paint mPaint; private Bitmap mBitmap; private Canvas mCanvas; public WaterColorView(Context context, AttributeSet attrs) { super(context, attrs); mPath = new Path(); mPaint = new Paint(); mPaint.setColor(Color.BLUE); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(10); mPaint.setAntiAlias(true); mPaint.setDither(true); mPaint.setStrokeJoin(Paint.Join.ROUND); mPaint.setStrokeCap(Paint.Cap.ROUND); mBitmap = Bitmap.createBitmap(1000, 1000, Bitmap.Config.ARGB_8888); mCanvas = new Canvas(mBitmap); } @Override protected void onDraw(Canvas canvas) { canvas.drawBitmap(mBitmap, 0, 0, null); canvas.drawPath(mPath, mPaint); } @Override public boolean onTouchEvent(MotionEvent event) { float x = event.getX(); float y = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mPath.moveTo(x, y); break; case MotionEvent.ACTION_MOVE: mPath.lineTo(x, y); mCanvas.drawPath(mPath, mPaint); invalidate(); break; case MotionEvent.ACTION_UP: mPath.reset(); break; } return true; } } ``` 在这个示例中,我们创建了一个自定义View类,使用mPath和mPaint对象实现绘制水彩画笔的效果,使用mBitmap和mCanvas对象保存和绘制内容。在onTouchEvent()方法中监听用户手指触摸事件,并根据手指移动的轨迹绘制水彩画笔的效果。最后使用onDraw()方法将绘制的内容显示在屏幕上。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值