Done is better than perfect

0%

Photoshop图层混合

本文的目的是通过Shader代码实现Photoshop的图层混合模式,图层混合模式是将上图层中的颜色与下层图层中的颜色,通过一个公式计算出最总的颜色。

颜色混合公式

具体的公式如下:

混合模式 公式 说明
透明度 alpha * foregroundCol + bgCol * (1.0 - alpha) 实现Alpha混合
变暗 min(bgCol, foregroundCol) 上下图层中,取最小的颜色值
正片叠底 bgCol * foregroundCol 混合后颜色整体压暗,最常用的混合模式
颜色加深 1 - ((1-bgCol) / foregroundCol) -
线性加深 bgCol + foregroundCol - 1 -
变亮 max(bgCol, foregroundCol) 上下图层中,取最大的颜色值
滤色 1 - (1-bgCol) * (1-foregroundCol) 和正片叠底真好向反,两图层取反后再乘,再取反,也是比较常用的混合模式
颜色减淡 bgCol / (1-foregroundCol) -
线性减淡 bgCol + foregroundCol -
叠加 当bgCol<0.5时, 2(bgColforegroundCol); 当bgCol >= 0.5时, 1-2(1-bgCol)(1-foregroundCol) 当bgCol小于0.5时,使用2倍的正片叠底;当bgColr大于等于0.5时,使用2倍的滤色,使用2倍是为了当bgCol=0.5时不断层.
柔光 当foregroundCol<0.5时, 2bgColforegroundCol+pow(bgCol,2)(1-2foregroundCol); 当foregroundCol >= 0.5时, (2bgCol(1-foregroundCol)+sqrt(bgCol)(2foregroundCol - 1)) -
强光 当foregroundCol<0.5时, bgCol * (2foregroundCol); 当foregroundCol >= 0.5时, 1-((1-bgCol) (1-2*(foregroundCol - 0.5))) -
亮光 当foregroundCol<0.5时, 1-(1-bgCol)/(2foregroundCol); 当foregroundCol >= 0.5时, bgCol/(1-2(foregroundCol-0.5)) -
线性光 当foregroundCol<0.5时, bgCol+2foregroundCol-1; 当foregroundCol >= 0.5时, bgCol+2(foregroundCol-0.5) -
点光 当foregroundCol<0.5时, min(bgCol, 2foregroundCol); 当foregroundCol >= 0.5时, max(bgCol, 2(foregroundCol-0.5)) -
差值 abs(bgCol-foregroundCol) -
排除 0.5-2(bgCol-0.5)(foregroundCol-0.5) -
减去 bgCol-foregroundCol -

Shader代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// https://www.deepskycolors.com/archive/2010/04/21/formulas-for-Photoshop-blending-modes.html
// https://en.wikipedia.org/wiki/Blend_modes#Overlay

// 注意:渲染管线必须是gamma空间
// 注意:渲染管线必须是gamma空间
// 注意:渲染管线必须是gamma空间
Shader "PhotoShopLayerBlend/LayerBlend"
{
Properties
{
_FrontTex ("Top", 2D) = "white" {}
_BackgroudTex ("Bottom", 2D) = "white" {}
_Alpha ("Alpha", Range(0, 1)) = 1
[KeywordEnum(OPACITY, DARKEN,MULTIPLY,COLOR_BURN,LINEAR_BURN, LIGHTEN,SCREEN,COLOR_DODGE,LINEAR_DODGE, OVERLAY,SOFT_LIGHT,HARD_LIGHT,VIVID_LIGHT,LINEAR_LIGHT,PIN_LIGHT, DIFFERENCE,EXCLUSION, SUB)] _BLEND ("Blend", Float) = 0
}
SubShader
{
Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline"}
LOD 100

Pass
{
HLSLPROGRAM

#include "Packages/com.unity.render-pipelines.universal@12.1.7/ShaderLibrary/Core.hlsl"
#include "Packages/com.unity.render-pipelines.core@12.1.7/ShaderLibrary/Color.hlsl"

#pragma vertex vert
#pragma fragment frag

#pragma multi_compile _ _BLEND_OPACITY _BLEND_DARKEN _BLEND_MULTIPLY _BLEND_COLOR_BURN _BLEND_LINEAR_BURN _BLEND_LIGHTEN _BLEND_SCREEN _BLEND_COLOR_DODGE _BLEND_LINEAR_DODGE _BLEND_OVERLAY _BLEND_SOFT_LIGHT _BLEND_HARD_LIGHT _BLEND_VIVID_LIGHT _BLEND_LINEAR_LIGHT _BLEND_PIN_LIGHT _BLEND_DIFFERENCE _BLEND_EXCLUSION _BLEND_SUB

sampler2D _BackgroudTex;
float4 _BackgroudTex_ST;
sampler2D _FrontTex;
float4 _FrontTex_ST;
float _Alpha;

struct Attributes
{
float4 positionOS : POSITION;
float2 texcoord : TEXCOORD0;
};

struct Varyings
{
float4 positionCS : SV_POSITION;
float4 uv : TEXCOORD0;
};

Varyings vert(Attributes input)
{
Varyings o;
o.positionCS = TransformObjectToHClip(input.positionOS.xyz);
o.uv.xy = TRANSFORM_TEX(input.texcoord, _BackgroudTex);
o.uv.zw = TRANSFORM_TEX(input.texcoord, _FrontTex);
return o;
}

half4 frag(Varyings input) : SV_TARGET
{
float3 bgCol = tex2D(_BackgroudTex, input.uv.xy).rgb;
float3 foregroundCol = tex2D(_FrontTex, input.uv.zw).rgb;

float3 rstCol = float3(0, 0, 0);
// 透明度
#if _BLEND_OPACITY
float alpha = (_Alpha);
rstCol = alpha * foregroundCol + bgCol * (1.0 - alpha);

// 变暗组
#elif _BLEND_DARKEN //变暗
rstCol = min(bgCol, foregroundCol);
#elif _BLEND_MULTIPLY //正片叠底
rstCol = bgCol * foregroundCol;
#elif _BLEND_COLOR_BURN //颜色加深
rstCol = 1 - ((1-bgCol) / foregroundCol);
#elif _BLEND_LINEAR_BURN //线性加深
rstCol = bgCol + foregroundCol - 1;

// 变亮组
#elif _BLEND_LIGHTEN //变亮
rstCol = max(bgCol, foregroundCol);
#elif _BLEND_SCREEN //滤色
rstCol = 1 - (1-bgCol) * (1-foregroundCol);
#elif _BLEND_COLOR_DODGE //颜色减淡
rstCol = bgCol / (1-foregroundCol);
#elif _BLEND_LINEAR_DODGE //线性减淡
rstCol = bgCol + foregroundCol;

// 叠加
#elif _BLEND_OVERLAY
float3 s = step(bgCol, float3(0.5, 0.5, 0.5));
rstCol = s * (2*bgCol*foregroundCol) + (1-s) * (1-2*(1-bgCol)*(1-foregroundCol));
// 柔光
#elif _BLEND_SOFT_LIGHT
float3 s = step(foregroundCol, float3(0.5, 0.5, 0.5));
// rstCol = s * (bgCol*(foregroundCol+0.5)) + (1-s) * (1-(1-bgCol)*(1-(foregroundCol-0.5)));
rstCol = s * (2*bgCol*foregroundCol+bgCol*bgCol*(1-2*foregroundCol)) + (1-s) * ((2*bgCol*(1-foregroundCol)+sqrt(bgCol)*(2*foregroundCol - 1)));
// 强光
#elif _BLEND_HARD_LIGHT
float3 s = step(foregroundCol, float3(0.5, 0.5, 0.5));
// rstCol = s * (2*bgCol*foregroundCol) + (1-s) * (1-2*(1-bgCol)*(1-foregroundCol));
rstCol = s * (bgCol * (2*foregroundCol)) + (1-s) * (1-((1-bgCol) * (1-2*(foregroundCol - 0.5))));
// 亮光
#elif _BLEND_VIVID_LIGHT
float3 s = step(foregroundCol, float3(0.5, 0.5, 0.5));
rstCol = s * (1-(1-bgCol)/(2*foregroundCol)) + (1-s) * (bgCol/(1-2*(foregroundCol-0.5)));
// 线性光
#elif _BLEND_LINEAR_LIGHT
float3 s = step(foregroundCol, float3(0.5, 0.5, 0.5));
rstCol = s * (bgCol+2*foregroundCol-1) + (1-s) * (bgCol+2*(foregroundCol-0.5));
// 点光
#elif _BLEND_PIN_LIGHT
float3 s = step(foregroundCol, float3(0.5, 0.5, 0.5));
rstCol = s * (min(bgCol, 2*foregroundCol)) + (1-s) * (max(bgCol, 2*(foregroundCol-0.5)));
// 差值
#elif _BLEND_DIFFERENCE
rstCol = abs(bgCol-foregroundCol);
// 排除
#elif _BLEND_EXCLUSION
rstCol = 0.5-2*(bgCol-0.5)*(foregroundCol-0.5);
// 减去
#elif _BLEND_SUB
rstCol = bgCol-foregroundCol;
#else
rstCol = float3(1, 1, 1);
#endif

return half4(rstCol.rgb, 1);
}
ENDHLSL
}
}
}

注意:要想和Photoshop的效果一样,必须使用gamma空间, Photoshop是在gamma空间下计算的颜色值

参考

https://en.wikipedia.org/wiki/Blend_modes https://www.deepskycolors.com/archive/2010/04/21/formulas-for-Photoshop-blending-modes.html