jjzjj

Photoshop图层混合模式公式(Unity,CG实现)

fairen 2023-05-17 原文

本文主要目的来自于在unity符合美术在ps里面的演示效果。

两个图层叠加到一起的效果,废话不多说直接看效果:

图片资源在文章末尾

完整代码也在末尾

目录

目录

Multiply 正片叠底

 Screen 滤色

 Color Dodge 颜色减淡

 Color Burn 颜色加深

Linear Dodge 线形减淡

Linear Burn 线形加深

Overlay 叠加

 Hard Light 强光

Soft Light 柔光

亮光 vivid light

Linear Light 线形光

Pin Light 点光

Hard Mix 实色混合

Difference 差值

Excusion 排除

Hue 色相

HSV那几个模式异常说明:

完整代码:

测试效果图片资源:


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
        }
    }
}

测试效果图片资源:

 

有关Photoshop图层混合模式公式(Unity,CG实现)的更多相关文章

  1. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  4. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  5. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  6. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

    给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

  7. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  8. Unity 热更新技术 | (三) Lua语言基本介绍及下载安装 - 2

    ?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------

  9. FOHEART H1数据手套驱动Optitrack光学动捕双手运动(Unity3D) - 2

    本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01  客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02  数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit

  10. unity---接入Admob - 2

    目录1.AdmobSDK下载地址2.将下载好的unityPackagesdk导入到unity里​编辑 3.解析依赖到项目中

随机推荐