本文主要目的来自于在unity符合美术在ps里面的演示效果。
两个图层叠加到一起的效果,废话不多说直接看效果:
图片资源在文章末尾
完整代码也在末尾
目录
目录
Multiply 正片叠底
公式:
Ans = A * B;
half4 finalRGBA = half4(colorA.xyz * colorB.xyz,1);
效果对比:
核心代码:
half4 finalRGBA = half4(1 - (1 - colorA.xyz) * (1 -colorB.xyz),1);
Screen 滤色
公式:
Ans = 1 - (1 - colorA ) * (1 - colorB);
效果对比:
核心代码:
half4 finalRGBA = half4(1 - (1 - colorA.xyz) * (1 -colorB.xyz),1);
Color Dodge 颜色减淡
公式:
ans=colorA / ( 1 - colorB);
效果对比:(unity存在些许过曝的情况)
核心代码:
finalRGBA = half4(colorA.xyz * (rcp(1 - colorB.xyz)),1);
Color Burn 颜色加深
公式:
ans=1 - (1 - colorA)/ colorB;
效果对比:
核心代码:
finalRGBA = half4(1- rcp(colorB.xyz) * (1 - colorA.xyz),1);
Linear Dodge 线形减淡
公式:
Ans = colorA + colorB;
效果对比:
核心代码:
finalRGBA = half4(colorB.xyz + colorA.xyz,1);
Linear Burn 线形加深
公式:
Ans = colorA + colorB - 1 ;
效果对比:
核心代码:
finalRGBA = half4(colorB.xyz + colorA.xyz - 1,1);
Overlay 叠加
公式:
colorB<=0.5 : Ans=2*colorA*colorB
colorB>0.5: Ans=1 - 2 * (1-colorA) * ( 1 - colorB)
效果对比:
核心代码:
half3 c1 = colorA.xyz * colorB.xyz * 2 *OA ;
half3 c2 = (1 - 2 * (1 - colorA.xyz) *(1 - colorB.xyz)) * (1 - OA);
finalRGBA = half4(c1+ c2,1);
Hard Light 强光
公式:
colorA <= 0.5: Ans = 2 * colorA * colorB
colorA > 0.5 : Ans = 1 - 2 * (1 - colorA) * (1 - colorB)
效果对比:
核心代码:
half3 OB = step(colorB.xyz,0.5);
half3 c1 = colorA.xyz * colorB.xyz * 2 *OB ;
half3 c2 = (1 - 2 * (1 - colorA.xyz) *(1 - colorB.xyz)) * (1 - OB);
Soft Light 柔光
公式:
colorA <= 0.5 : Ans = ( 2 * A - 1 ) * ( B - B * B ) + B;
colorA > 0.5 : Ans = ( 2 * A - 1 ) * ( sqrt ( B ) - B ) + B;
效果对比:
核心代码:
half3 OB = step(colorB.xyz,0.5);
half3 c1 = ((2 * colorB - 1) * (colorA - colorA * colorA) + colorA) * OB ;
half3 c2 = ((2 * colorB - 1) * (sqrt(colorA)- colorA) + colorA) * (1 - OB);
亮光 vivid light
效果与ps中存在部分差异,但目前没找到原因,盲猜是因为自己没有模拟出图层上下级关系。
公式:
colorB <= 0.5 : Ans = colorA - (1 - colorA) * ( 1 - 2 * colorB) / (2 * colorB);
colorB > 0.5 : Ans = colorA + colorA * (2 * colorB - 1)/(2 * (1 - colorB));
效果对比:
上下层级不同的情况下(unity没有层级)
核心代码:
float3 c1 = colorB - (1 - colorB) * (1 - 2 * colorA) / (2 * colorA);
float3 c2 = colorB + colorB * (2 * colorA - 1) / (2 * (1 - colorA));
float3 OB = step(colorA.xyz,0.5);
c1 *= OB;
c2 *= (1 - OB);
finalRGBA = float4(c1+ c2,1);
Linear Light 线形光
公式:
Ans = colorB + 2 * colorA - 1;
效果对比:
核心代码:
finalRGBA = float4(colorA + 2 * colorB) - 1;
Pin Light 点光
公式:
colorB < 2 * colorA - 1 : Ans = 2 * colorA - 1;
2 * A - 1 < B < 2 * A : Ans = colorB;
colorB > 2 * colorA : Ans = 2 * colorA;
效果展示:
核心代码:
half3 OB = step(colorA,2 *colorB - 1);
half3 c1 = (2 * colorB - 1) * OB;
half3 OB1 = (1 - OB) * step(colorA , 2 * colorB);
half3 c2 = colorA * OB1;
half3 OB2 = 1 - step(colorA ,2 * colorB);
half3 c3 = 2 * colorB * OB2;
finalRGBA = half4(c1 + c2 + c3,1);
Hard Mix 实色混合
公式:
colorA < 1 - colorB : Ans = 0;
colorA > 1 - colorB : Ans = 1;
效果展示:
核心代码:
half3 OA = step(colorB, 1 - colorA);
half3 c1 = 0 * OA;
half3 OA1 = step(1 - colorA,colorB);
half3 c2 = 1 * OA1;
finalRGBA = half4(c1 + c2,1);
Difference 差值
公式:
Ans=|colorA-colorB|
效果展示:
核心代码:
finalRGBA = half4(abs(colorB.xyz - colorA.xyz),1);
Excusion 排除
公式:
Ans=colorA+colorB-(colorA×colorB) * 2
效果展示:
核心代码:
finalRGBA = half4(colorB + colorA - 2 * colorB * colorA);
Hue 色相
公式:
Ans( HSV) =HB SA VA
(HSV空间下) Ans = (colorB.x,colorA.y,colorB.z);
该效果再HSV空间下进行计算(后续需要转化为RGB)
效果展示:
核心代码:
float3 c1 = float3(colorBHSV.x,colorAHSV.yz);
c1 = HSV2RGB(c1);
finalRGBA = half4(c1,1);
HSV那几个模式异常说明:
- 这几个模式按照公式去计算并不能正常的得到目标结果所以,复刻不出来但是不是很懂怎么回事经测试转颜色空间并无差别且计算并无问题,具体的的混合算法来源也无差别出自官方文档维基百科等都是显示该结果,或为还有部分转化过程,待查证。
- 饱和度混合模式保留底层的亮度和色调,同时采用顶层的色度。
- 颜色混合模式保留底层的亮度,同时采用顶层的色调和色度。
- 亮度混合模式保留底层的色调和色度,同时采用顶层的亮度。、
颜色混合未完待续。
完整代码:
Shader "Unlit/TestPs"
{
Properties
{
_MainTexA ("TextureA", 2D) = "white" {}
_MainTexB ("TextureB", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
float3 RGB2HSV(float3 c)
{
float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
float4 p = lerp(float4(c.bg, K.wz), float4(c.gb, K.xy), step(c.b, c.g));
float4 q = lerp(float4(p.xyw, c.r), float4(c.r, p.yzx), step(p.x, c.r));
float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
// Official HSV to RGB conversion
float3 HSV2RGB( float3 c ){
float3 rgb = clamp( abs(fmod(c.x*6.0+float3(0.0,4.0,2.0),6)-3.0)-1.0, 0, 1);
rgb = rgb*rgb*(3.0-2.0*rgb);
return c.z * lerp( float3(1,1,1), rgb, c.y);
}
sampler2D _MainTexA;
float4 _MainTexA_ST;
sampler2D _MainTexB;
float4 _MainTexB_ST;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv.xy = TRANSFORM_TEX(v.uv.xy, _MainTexA);
o.uv.zw = TRANSFORM_TEX(v.uv.xy, _MainTexB);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
half4 frag (v2f i) : SV_Target
{
float4 colorA = tex2D(_MainTexA, i.uv.xy);
float colorALum = Luminance(colorA.xyz);
float4 colorB = tex2D(_MainTexB, i.uv.zw);
float3 colorAHSV = RGB2HSV(colorA.xyz);
float3 colorBHSV = RGB2HSV(colorB.xyz);
float colorBLum = Luminance(colorA.xyz);
float4 finalRGBA = 0;
// opacity 正片叠底
finalRGBA = float4(colorA.xyz * colorB.xyz,1);
// Screen 滤色
// finalRGBA = float4(1 - (1 - colorA.xyz) * (1 -colorB.xyz),1);
// Color Dodge 颜色减淡
// finalRGBA = float4(colorA.xyz * (rcp(1 - colorB.xyz)),1);
// Color Burn 颜色加深
// finalRGBA = float4(1- rcp(colorB.xyz) * (1 - colorA.xyz),1);
// Linear Dodge 线形减淡
// finalRGBA = float4(colorB.xyz + colorA.xyz,1);
// Linear Burn 线形加深
// finalRGBA = float4(colorB.xyz + colorA.xyz - 1,1);
// overlay 叠加
// float3 OA = step(colorA.xyz,0.5);
// float3 c1 = colorA.xyz * colorB.xyz * 2 *OA ;
// float3 c2 = (1 - 2 * (1 - colorA.xyz) *(1 - colorB.xyz)) * (1 - OA);
// finalRGBA = float4(c1+ c2,1);
// hard light 强光
// float3 OB = step(colorB.xyz,0.5);
// float3 c1 = colorA.xyz * colorB.xyz * 2 *OB ;
// float3 c2 = (1 - 2 * (1 - colorA.xyz) *(1 - colorB.xyz)) * (1 - OB);
// soft light 柔光
// float3 OB = step(colorB.xyz,0.5);
// float3 c1 = ((2 * colorB - 1) * (colorA - colorA * colorA) + colorA) * OB ;
// float3 c2 = ((2 * colorB - 1) * (sqrt(colorA)- colorA) + colorA) * (1 - OB);
// vivid light 亮光///
// float3 c1 = colorB - (1 - colorB) * (1 - 2 * colorA) / (2 * colorA);
// float3 c2 = colorB + colorB * (2 * colorA - 1) / (2 * (1 - colorA));
// float3 OB = step(colorA.xyz,0.5);
// c1 *= OB;
// c2 *= (1 - OB);
// finalRGBA = float4(c1+ c2,1);
// linear Light 线性光
// finalRGBA = float4(colorA + 2 * colorB) - 1;
// 点光(存在等于符号问题)
// B<2*A-1: C=2*A-1
// 2*A-1<B<2*A: C=B
// B>2*A: C=2*A
// float3 OB = step(colorA,2 *colorB - 1);
// float3 c1 = (2 * colorB - 1) * OB;
// float3 OB1 = (1 - OB) * step(colorA , 2 * colorB);
// float3 c2 = colorA * OB1;
// float3 OB2 = 1 - step(colorA ,2 * colorB);
// float3 c3 = 2 * colorB * OB2;
// finalRGBA = float4(c1 + c2 + c3,1);
// 混合实色
// float3 OA = step(colorB, 1 - colorA);
// float3 c1 = 0 * OA;
// float3 OA1 = step(1 - colorA,colorB);
// float3 c2 = 1 * OA1;
// finalRGBA = float4(c1 + c2,1);
// 差值
// finalRGBA = float4(abs(colorB.xyz - colorA.xyz),1);
// Excusion 排除
// finalRGBA = float4(colorB + colorA - 2 * colorB * colorA);
// hue 色相
// float3 c1 = float3(colorBHSV.x,colorAHSV.yz);
// c1 = HSV2RGB(c1);
// finalRGBA = half4(c1,1);
return finalRGBA;
}
ENDCG
}
}
}
测试效果图片资源: