[WebGL] 流动图片——Flow Map

1,923 阅读5分钟

flowmap.gif

最近我厂在裁员,而我顶着幸运的光环顺利得到了毕业鹅的称谓,在即将离开的两个月中,需求不饱和的情况下(哪里是需求不饱和,是根本没有需求),闲来无事做了些感觉比较好玩的blender工具,其中flowMap是其中之一。

下文描述的颜色值都是webGL中的颜色,也就是[0,1]区间内,请自行对应到ps中的颜色

DEMO

什么是FlowMap

通俗来讲就是一个向量图片,图片中的每个像素对应的颜色代表的是这个位置的向量,也就是纹理在该位置的流动方向。 97bef21f8dc94469a3e7c9e0080d38c6.png 上图是从网上找的标准FlowMap的原理,他是根据颜色中的R&G分量进行提取向量的。

其中R代表的是水平方向上的流向,G代表的是垂直方向上的流向。

怎么才能实现360°向量呢

因为只考虑RG分量,所以正常的颜色取值范围都是[0,1]区间的,如果按照默认的坐标系,也就是下图所示,那么得出来得向量只是第一象限中得向量(也就是只能取得[0°,90°]之间得向量),无法得到[0°,360°],最后导致得结果只能是往右上方向进行流动。

image.png

那么怎么才能实现[0°,360°]得向量呢,只需要把原点坐标移动到中间位置就可以保证能够得到[0°,360°]的所有向量。

image.png

映射到FlowMap中的色值就如下图所示,其中(0.5,0.5,0)为向量场的原点颜色:

image.png

这里面通过FLowMap 提取的向量代码如下:

vec2 flowDir = texture2D(FlowMap, i.uv) * 2.0 - 1.0;

之后就是运用得到的向量进行像素偏移,步骤就不在这里进行详细描述了,搜索flowMap可以看看其他人写的文章。

为什么还要写FlowMap

既然网上已经有一些关于flowMap的文章,那为什么我还要写它呢?我在开头已经说了,我做的是flowMap的工具, 既然是工具,那么这篇文章主要不是介绍怎么利用flowMap来实现流动图片了。

我搜到的关于flowMap工具都是按照上述的想法来生成flowMap的,都是用R&G分量来设置向量的,其中(0.5,0.5)是原点颜色。

这么做有什么不好的地方呢?

1. 不能局部弱化向量

这里不讨论全部弱化向量,全部统一弱化向量只需要得到向量后同一乘上一个系数即可。

什么是弱化向量,就是颜色取值趋近于(0.5,0.5)

搜到的flowMap工具全都是同一方向输出同一颜色。比如实现右上角的向量,flowMap统一输出(1,1,0)的颜色,我想得到(0.75,0.75,0)怎么办,工具说:“抱歉,这个臣妾做不到”

2. 不能对flowMap做后期颜色调整

制作好flowMap图片之后,我想通过PS后期调整flowMap图片的颜色怎么办。同样是不能调整的。

原因在于flowMap的原点颜色是(0.5,0.5,0), 在PS中的任何一步操作都会影响原点颜色的修改,从而使flowMap失效。

有什么办法能解决上述问题呢?

答案:HSV色盘(也就是我做的flowMap插件的思路)

HSV(Hue, Saturation, Value)是根据颜色的直观特性由 A. R. Smith 在 1978 年创建的一种颜色空间, 也称六角锥体模型(Hexcone Model)。

这个模型中颜色的参数分别是色调(H)、饱和度(S)和明度(V)。

image.png

色调H

用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。它们的补色是:黄色为60°,青色为180°,紫色为300°;

饱和度S

饱和度S表示颜色接近光谱色的程度。一种颜色,可以看成是某种光谱色与白色混合的结果。其中光谱色所占的比例愈大,颜色接近光谱色的程度就愈高,颜色的饱和度也就愈高。饱和度高,颜色则深而艳。光谱色的白光成分为0,饱和度达到最高。通常取值范围为0%~100%,值越大,颜色越饱和。

明度V

明度表示颜色明亮的程度,对于光源色,明度值与发光体的光亮度有关;对于物体色,此值和物体的透射比或反射比有关。通常取值范围为0%(黑)到100%(白)。

image.png

如上图所示,Hue本身就是[0°,360°]的范围,可以代表方向,明度Value可以代表向量的大小,我认为flowMap改为HSV色盘模式完全可以结局上述两个问题:

1. 局部弱化向量

可以通过更改Value来输出想要的向量大小,因为HSV相互独立的,修改V分量不影响Hue的输出。

flowmap2.gif

2. 对flowMap做后期颜色调整

flowMap改为HSV后,原点为(0,0,0),黑色在PS中很多操作都不会改变黑色的,所以在生成FlowMap之后可以进行PS后期处理,例如降低局部的向量大小:

flowmap2.gif

RGB 转 HSV

剩下的步骤就是在片元着色器中实现RGBToHSV的转换,转换完成之后就可以根据上述常规的flowMap流程进行渲染即可,转换方法如下:

void rgb_to_hsv(vec4 rgb, out vec4 outcol) {
  float cmax, cmin, h, s, v, cdelta;
  vec3 c;
  cmax = max(rgb[0], max(rgb[1], rgb[2]));
  cmin = min(rgb[0], min(rgb[1], rgb[2]));
  cdelta = cmax - cmin;
  v = cmax;
  if (cmax != 0.0) {
    s = cdelta / cmax;
  } else {
    s = 0.0;
    h = 0.0;
  }
  if (s == 0.0) {
    h = 0.0;
  } else {
    c = (vec3(cmax) - rgb.xyz) / cdelta;
    if (rgb.x == cmax) {
      h = c[2] - c[1];
    } else if (rgb.y == cmax) {
      h = 2.0 + c[0] - c[2];
    } else {
      h = 4.0 + c[1] - c[0];
    }
    h /= 6.0;
    if (h < 0.0) {
      h += 1.0;
    }
  }
  outcol = vec4(h, s, v, rgb.w);
}

flowMap在blender中的实现思路如下,顺着思路编写片元着色器就能实现效果了:

image.png

总结

写这篇文章,主题是想说flowMap可以用HSV去实现,并且效果会更好。

网上有免费的常规的(基于UV映射的颜色)flowMap for Blender插件,大家有兴趣可以体验下。

AdobeSubstance 3D Painter 中也集成了常规的flowMap工具,但软件是收费的,我没怎么研究了。