BLEND:ATOMIC NODE :SUBSTANCE DESIGNER.
学习目标
- 学习混合像素的 SD 所有 NODE 和功能的基本知识。
- 理解Blend Node 的像素颜色合成式。
- 把两个不同图片的 RGBA 用 Split 和 Merge 生成新的图片。
- Channel Shuffle 和 Channel Mixer。
本章节了解下 Blend node 的混合方式,并看一下是否可以用 Mask 达到更详细的混合。
Blend Mode 的种类。
- Copy
- Add(Linear Dodge)
- Subtract
- Multiply
- Add Sub
- Max(Lighten)
- Min(Darken)
- Switch
- Divide
- Overay
- Screen
- SoftLight
总共有12种 Mode 。
看下可以直接追加制作的各种 Blend Node 。
因为美术以前主要使用的是PS,所以对 HardLighr , VividLight , PinLight , Difference 等其他 Blend mode 也很有兴趣。
介绍相关公式后,选择其中一个简单跟着制作下吧。
也可以参考后续介绍的 Pixel Processor 来跟着做。
Copy
Copy 是普通的 Linear interpolation 会混合两个信息。


把 Opacity 设成 0.5后来看下两个 Shape 重叠的部分。
重叠的中间部分应该是正确的白色值。

表示鼠标指向点的色彩信息。
V 值是 RGB 值 255 , Float 值正确表示着 1.0。
看下实际颜色。

像这样用蓝色和红色把 Shape 的白色部分填充了。

但是使用 Color 确认 Blend 节点的话,就会显示中间部分减少 50%的原色的蓝色和减少50%的原色的红色各混合一半的颜色。
RGB 加算混合(RGB 加算混合)是利用光的三原色来表现颜色的方式,所以这种结果是正确的。

看下中间粉色部分的值, Value 值是 RGB 127 , Float 值是 0.49803 。
再来详细看下 Color 颜色混合方式。
在公式里 a 是 Blend 的 Background , b 是 Blend 的 Foreground 。
对 Linear Interpolation 的理解。
Linear Interpolation law 以下线性插值法是可以填充两个数字间距的技术。
大部分 API是根据始发点 a、终点 b,以及连接 0和 1 之间的值 t的分段来移动的三种变量为准来提供线性插值。

t = 0 就会回执 a。
t = 1,会返还 。
这个公式的优点是容易理解容易实现,在2D和3D都能使用。
线性插值总是回执连接 a和 b的线的点。
标准 RGB Lerp执行如下。
public static Color LerpRGB (Color a, Color b, float t)
{
return ( a + (b - a) * t).rgba;
}
Code language: PHP (php)
使用 Pixel Processor 再现了以上公式。
Pixel Processor 部分后面有说明用法,到时候再仔细看下。

制作Get Float来获取两个图片的输入和外部变量,再把这个定义成 t 。
把外部变量 t 想成 Blend 节点的 Opacity 吧。
跟普通的 Blend Weight 有点不一样。

用简单的公式制作来验证下 Blend 节点的 Copy 和 Opacity 是不是正确的 Lerp 。
这里的 t 是 Opacity 的变量。
这里不要搞混了, input0 是 blend 的 foreground , input1 是 Background 。

两个方式都是同一个结果。
这就可以知道 Copy 使用了线性插值法的基本颜色插值法。
Add(Linear Dodge)

通常叫做 Linear Dodge 。
把两个值单纯加起来。
float4 LinearDodge (float4 a, float4 b , float t)
{
return (a*t + b).rgba;
}
Code language: JavaScript (javascript)
如上函数。

重叠部分的颜色加起来。

在这里 t 是 Opacity 的变量。

如上函数,简单从 a 减去了 b。
float4 Subtract (float4 a, float4 b , float t)
{
return lerp(a, (a-b), t);
}
Code language: JavaScript (javascript)
和 b 相乘的变量 t 是 opacity 值。


虽然上图看起来有点错误,但这是正常的。
因为使用的是完整的 Blue 和完整的 Red ,所以在 RGB 加算混合方式里 R 通道和 B 通道间是没有关联的,故不减掉任何值。
用其他贴图测试下。

可以看到 Subtract 运作正常。
只是在 Pixel Processor 的 Node 预览里没有单独对 Alpha 通道的管理系统,所以用 Alpha Split 预览了。
Multiply
float4 Multiply (float4 a, float4 b , float t)
{
return lerp(a, (a*b), t);
}
Code language: JavaScript (javascript)


Add Sub
混合两个高度值的结果很独特,在 Opacity 中间值也可以做出不一样的造型。
float4 AddSub (float4 a, float4 b , float t)
{
return lerp(a, (b-1)+(b+a) , t);
}
Code language: JavaScript (javascript)


Max(Lighten)
float4 Lighten (float4 a, float4 b , float t)
{
return max(a, b*t);
}
Code language: JavaScript (javascript)


Min(Darken)
float4 Darken (float4 a, float4 b , float t)
{
return min(a, b * t);
}
Code language: JavaScript (javascript)


Divide
颜色模式和单色模式的内部代码需要根据 Divide 的特性构成。
Color Mode
float4 Divide (float4 a, float4 b , float t)
{
return lerp(a ,(a/b), t);
}
Code language: JavaScript (javascript)
Gray Mode
float Divide (float a, float b , float t)
{
float clampedA = clamp(a , 0.01 , 1)
float clampedB = clamp(b , 0.01 , 1)
return lerp(a ,(a/b), t);
}
Code language: JavaScript (javascript)



Difference
float4 Difference (float4 a, float4 b, float t)
{
return (abs(a - b*t));
}
Code language: JavaScript (javascript)


Overay
float4 Overlay (float4 a, float4 b)
{
float isLessOrEq = step(a, 0.5);
float4 cNew = lerp(2 * b*a, 1 - (1 - 2*(a - 0.5))*(1 - b), isLessOrEq);
cNew.a = 1.0;
return cNew;
}
Code language: JavaScript (javascript)
Screen
float4 Softlight(float4 a , float4 b , float t)
{
Float4 cNew = (b < 0.5) ? (2.0 * a * b + a * a * (1.0 - 2.0 * b)) :
(sqrt(a) * (2.0 * b - 1.0) + 2.0 * a * (1.0 - b));
return (a , cNew , t);
}
Code language: JavaScript (javascript)


其他一些算法…
ColorBurn
float4 ColorBurn (float4 a, float4 b, float t)
{
return (1 - (1 - a) / (b*t));
}
Code language: JavaScript (javascript)
LinearBurn
float4 LinearBurn (float4 a, float4 b, float t)
{
return (a + b*t - 1);
}
Code language: JavaScript (javascript)
HardLight
float4 HardLight (float4 a, float4 b, float t)
{
float4 valueB = b * t;
float isLessOrEq = step(valueB, .5);
float4 cNew = lerp(1 - (1 - a)*(1 - 2*valueB), 2*valueB*a, isLessOrEq);
return cNew;
}
Code language: JavaScript (javascript)
VividLight
float4 VividLight (float4 a, float4 b, float t)
{
float4 valueB = b * t;
float isLessOrEq = step(valueB, .5);
float4 cNew = lerp(1 - (1 - a)/(2*(valueB - .5)), a/(1 - 2*valueB), isGreaterThen);
return cNew;
}
Code language: JavaScript (javascript)
LinearLight
float4 LinearLight (float4 a, float4 b, float t)
{
float4 valueB = b * t;
float isLessOrEq = step(valueB, .5);
float4 cNew = lerp(a + 2*(valueB - .5), a + 2*valueB - 1., isLessOrEq);
return cNew;
}
Code language: JavaScript (javascript)
PinLight
float4 PinLight (float4 a, float4 b, float t)
{
float4 valueB = b * t;
float isLessOrEq = step(b, .5);
float4 cNew = lerp(max(a, 2*(b - .5)), min(cBase, 2*b), isLessOrEq);
return cNew;
}
Code language: JavaScript (javascript)
Exclusion
float4 Exclusion (float4 a, float4 b, float t)
{
return (.5 - 2 * (a - .5) * (b*t - .5));
}
Code language: JavaScript (javascript)