블로그 이미지
Every unexpected event is a path to learning for you.

카테고리

분류 전체보기 (2731)
Unity3D (814)
Programming (474)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (228)
협업 (57)
3DS Max (3)
Game (12)
Utility (136)
Etc (96)
Link (32)
Portfolio (19)
Subject (90)
iOS,OSX (51)
Android (14)
Linux (5)
잉여 프로젝트 (2)
게임이야기 (3)
Memories (20)
Interest (38)
Thinking (38)
한글 (30)
PaperCraft (5)
Animation (408)
Wallpaper (2)
재테크 (18)
Exercise (3)
나만의 맛집 (3)
냥이 (10)
육아 (16)
Total
Today
Yesterday
03-29 00:00

'2020/12/14'에 해당되는 글 2건

  1. 2020.12.14 SKAdNetwork IDs 리스트 XcodePostProssor 2
  2. 2020.12.14 [펌] Photoshop Blend Modes Without Backbuffer Copy

SKAdNetwork IDs 추가 할 게 많아서 내가 사용하는 광고 플랫폼에서 제공하는 리스트 모두 모아서 추가 함

※ 중복되는 SDAdNetwork ID는 주석처리 함

 

[사용하는 광고 플랫폼] Admob(미디에이션), FAN, UnityAds, Vungle

 

namespace blueasa
{
    public class XcodeSettingsPostProcessor
    {

        [PostProcessBuild(444)]
        public static void OnPostprocessBuild(BuildTarget buildTarget, string pathToBuiltProject)
        {

            /// Stop processing if targe is NOT iOS
            if (buildTarget != BuildTarget.iOS)
                return;

            /// Initialize PbxProject
            var projectPath = pathToBuiltProject + "/Unity-iPhone.xcodeproj/project.pbxproj";
            PBXProject pbxProject = new PBXProject();
            pbxProject.ReadFromFile(projectPath);
            string targetGuid = pbxProject.TargetGuidByName("Unity-iPhone");

            var plistPath = System.IO.Path.Combine(pathToBuiltProject, "Info.plist");
            var plist = new PlistDocument();
            plist.ReadFromFile(plistPath);

            /// Add string setting
            // SKAdNetwork IDs integration(for iOS14+)
            // https://blueasa.tistory.com/2482
            var arraySKAdNetworkItems = plist.root.CreateArray("SKAdNetworkItems");
            // for Admob(Google)
            // https://developers.google.com/admob/ios/ios14#skadnetwork
            var dictSKAdNetworkIdentifier_Admob = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_Admob.SetString("SKAdNetworkIdentifier", "cstr6suwn9.skadnetwork"); // Admob
            // for FAN
            // https://developers.facebook.com/docs/audience-network/guides/SKAdNetwork
            var dictSKAdNetworkIdentifier_FAN_1 = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_FAN_1.SetString("SKAdNetworkIdentifier", "v9wttpbfk9.skadnetwork"); // FAN 1
            var dictSKAdNetworkIdentifier_FAN_2 = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_FAN_2.SetString("SKAdNetworkIdentifier", "n38lu8286q.skadnetwork"); // FAN 2
            // for UnityAds
            // https://unityads.unity3d.com/help/ios/skadnetwork-ids?fbclid=IwAR3T6BWG6-SIdWipZaB-PEtUQhg1DAnU_kQ22iiSv4Z5Q6nItq2edtpIIkM
            // https://skan.mz.unity3d.com/v2/partner/skadnetworks.plist.xml?_ga=2.140049011.1591405619.1607905486-1813266944.1603773122
            var dictSKAdNetworkIdentifier_Unity_1 = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_Unity_1.SetString("SKAdNetworkIdentifier", "4DZT52R2T5.skadnetwork"); // Unity Technologies 1
            var dictSKAdNetworkIdentifier_Unity_2 = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_Unity_2.SetString("SKAdNetworkIdentifier", "bvpn9ufa9b.skadnetwork"); // Unity Technologies 2
            var dictSKAdNetworkIdentifier_Mintegral = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_Mintegral.SetString("SKAdNetworkIdentifier", "KBD757YWX3.skadnetwork"); // Mintegral
            var dictSKAdNetworkIdentifier_CriteoSA = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_CriteoSA.SetString("SKAdNetworkIdentifier", "9RD848Q2BZ.skadnetwork"); // Criteo SA (Manage.com)
            var dictSKAdNetworkIdentifier_mkhoj = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_mkhoj.SetString("SKAdNetworkIdentifier", "WZMMZ9FP6W.skadnetwork"); // mkhoj Solutions Private Limited
            var dictSKAdNetworkIdentifier_Snap = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_Snap.SetString("SKAdNetworkIdentifier", "424M5254LK.skadnetwork"); // Snap Inc.
            var dictSKAdNetworkIdentifier_Cheetah = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_Cheetah.SetString("SKAdNetworkIdentifier", "24t9a8vw3c.skadnetwork"); // Cheetah Medialink
            var dictSKAdNetworkIdentifier_Appier = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_Appier.SetString("SKAdNetworkIdentifier", "v72qych5uu.skadnetwork"); // Appier Inc.
            var dictSKAdNetworkIdentifier_Liftoff = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_Liftoff.SetString("SKAdNetworkIdentifier", "7UG5ZH24HU.skadnetwork"); // Liftoff Mobile, Inc.
            var dictSKAdNetworkIdentifier_Beeswax = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_Beeswax.SetString("SKAdNetworkIdentifier", "c6k4g5qg8m.skadnetwork"); // Beeswax
            var dictSKAdNetworkIdentifier_Adikteev = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_Adikteev.SetString("SKAdNetworkIdentifier", "ydx93a7ass.skadnetwork"); // Adikteev SA
            var dictSKAdNetworkIdentifier_Realtime = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_Realtime.SetString("SKAdNetworkIdentifier", "4468km3ulz.skadnetwork"); // Realtime Technologies GmbH
            var dictSKAdNetworkIdentifier_Remerge = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_Remerge.SetString("SKAdNetworkIdentifier", "2U9PT9HC89.skadnetwork"); // Remerge GmbH
            var dictSKAdNetworkIdentifier_CriteoCorp = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_CriteoCorp.SetString("SKAdNetworkIdentifier", "hs6bdukanm.skadnetwork"); // Criteo Corp
            var dictSKAdNetworkIdentifier_Aarki = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_Aarki.SetString("SKAdNetworkIdentifier", "4FZDC2EVR5.skadnetwork"); // Aarki, Inc.
            //var dictSKAdNetworkIdentifier_Google = arraySKAdNetworkItems.AddDict();
            //dictSKAdNetworkIdentifier_Google.SetString("SKAdNetworkIdentifier", "cstr6suwn9.skadnetwork"); // Google LLC(Admob)
            var dictSKAdNetworkIdentifier_YouAppi = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_YouAppi.SetString("SKAdNetworkIdentifier", "3RD42EKR43.skadnetwork"); // YouAppi Inc
            var dictSKAdNetworkIdentifier_LifeStreet = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_LifeStreet.SetString("SKAdNetworkIdentifier", "t38b2kh725.skadnetwork"); // LifeStreet Corporation
            var dictSKAdNetworkIdentifier_SPOTAD = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_SPOTAD.SetString("SKAdNetworkIdentifier", "f73kdq92p3.skadnetwork"); // SPOTAD LTD
            var dictSKAdNetworkIdentifier_BYTEMOD_Global = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_BYTEMOD_Global.SetString("SKAdNetworkIdentifier", "22mmun2rn5.skadnetwork"); // BYTEMOD PTE. LTD-global
            var dictSKAdNetworkIdentifier_DATASEAT = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_DATASEAT.SetString("SKAdNetworkIdentifier", "M8DBW4SV7C.skadnetwork"); // DATASEAT LTD
            var dictSKAdNetworkIdentifier_Kidoz = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_Kidoz.SetString("SKAdNetworkIdentifier", "v79kvwwj4g.skadnetwork"); // Kidoz Ltd.
            var dictSKAdNetworkIdentifier_Sabio = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_Sabio.SetString("SKAdNetworkIdentifier", "GLQZH8VGBY.skadnetwork"); // Sabio Mobile Inc.
            var dictSKAdNetworkIdentifier_Moloco = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_Moloco.SetString("SKAdNetworkIdentifier", "9T245VHMPL.skadnetwork"); // Moloco, Inc
            var dictSKAdNetworkIdentifier_Bidmachine = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_Bidmachine.SetString("SKAdNetworkIdentifier", "wg4vff78zm.skadnetwork"); // Bidmachine
            var dictSKAdNetworkIdentifier_BYTEMOD_CN = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_BYTEMOD_CN.SetString("SKAdNetworkIdentifier", "238da6jt44.skadnetwork"); // BYTEMOD PTE. LTD-CN
            var dictSKAdNetworkIdentifier_Apptimus = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_Apptimus.SetString("SKAdNetworkIdentifier", "lr83yxwka7.skadnetwork"); // Apptimus LTD
            var dictSKAdNetworkIdentifier_Centro = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_Centro.SetString("SKAdNetworkIdentifier", "3sh42y64q3.skadnetwork"); // Centro Inc.
            var dictSKAdNetworkIdentifier_UNICORN = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_UNICORN.SetString("SKAdNetworkIdentifier", "578prtvx9j.skadnetwork"); // UNICORN Inc.
            var dictSKAdNetworkIdentifier_REVX = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_REVX.SetString("SKAdNetworkIdentifier", "5a6flpkh64.skadnetwork"); // REVX TECHNOLOGY PRIVATE LIMITED
            var dictSKAdNetworkIdentifier_RTBHouse = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_RTBHouse.SetString("SKAdNetworkIdentifier", "8s468mfl3y.skadnetwork"); // RTBHouse Pte LTD
            var dictSKAdNetworkIdentifier_CrossInstall = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_CrossInstall.SetString("SKAdNetworkIdentifier", "prcb7njmu6.skadnetwork"); // CrossInstall
            var dictSKAdNetworkIdentifier_Maiden = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_Maiden.SetString("SKAdNetworkIdentifier", "zmvfpc5aq8.skadnetwork"); // Maiden Marketing Pvt Ltd.
            var dictSKAdNetworkIdentifier_AdColony = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_AdColony.SetString("SKAdNetworkIdentifier", "4PFYVQ9L8R.skadnetwork"); // AdColony, Inc.
            var dictSKAdNetworkIdentifier_Spyke = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_Spyke.SetString("SKAdNetworkIdentifier", "44n7hlldy6.skadnetwork"); // Spyke Media GmbH
            var dictSKAdNetworkIdentifier_LoopMe = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_LoopMe.SetString("SKAdNetworkIdentifier", "5lm9lj6jb7.skadnetwork"); // LoopMe Ltd
            var dictSKAdNetworkIdentifier_Smadex = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_Smadex.SetString("SKAdNetworkIdentifier", "ppxm28t8ap.skadnetwork"); // Smadex SL
            var dictSKAdNetworkIdentifier_ADTIMING = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_ADTIMING.SetString("SKAdNetworkIdentifier", "488r3q3dtq.skadnetwork"); // ADTIMING TECHNOLOGY PTE. LTD.
            var dictSKAdNetworkIdentifier_Jampp = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_Jampp.SetString("SKAdNetworkIdentifier", "YCLNXRL5PM.skadnetwork"); // Jampp LTD
            var dictSKAdNetworkIdentifier_PubNative = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_PubNative.SetString("SKAdNetworkIdentifier", "TL55SBB4FM.skadnetwork"); // PubNative GMBH
            var dictSKAdNetworkIdentifier_Chartboost = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_Chartboost.SetString("SKAdNetworkIdentifier", "F38H382JLK.skadnetwork"); // Chartboost, Inc.
            var dictSKAdNetworkIdentifier_ScaleMonk = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_ScaleMonk.SetString("SKAdNetworkIdentifier", "av6w8kgt66.skadnetwork"); // ScaleMonk Inc.
            var dictSKAdNetworkIdentifier_Persona = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_Persona.SetString("SKAdNetworkIdentifier", "44jx6755aq.skadnetwork"); // Persona.ly LTD
            var dictSKAdNetworkIdentifier_Triapodi = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_Triapodi.SetString("SKAdNetworkIdentifier", "mlmmfzh3r3.skadnetwork"); // Triapodi Ltd.
            // for Vungle
            // https://support.vungle.com/hc/en-us/articles/360002925791-Integrate-Vungle-SDK-for-iOS#3-add-the-%E2%80%9C-objc%E2%80%9D-linker-flag-0-9
            // https://vungle.com/skadnetworkids.xml
            var dictSKAdNetworkIdentifier_Vungle = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_Vungle.SetString("SKAdNetworkIdentifier", "GTA9LK7P23.skadnetwork"); // Vungle
            //var dictSKAdNetworkIdentifier_Adikteev = arraySKAdNetworkItems.AddDict();
            //dictSKAdNetworkIdentifier_Adikteev.SetString("SKAdNetworkIdentifier", "ydx93a7ass.skadnetwork"); // Adikteev  
            //var dictSKAdNetworkIdentifier_Aarki = arraySKAdNetworkItems.AddDict();
            //dictSKAdNetworkIdentifier_Aarki.SetString("SKAdNetworkIdentifier", "4FZDC2EVR5.skadnetwork"); // Aarki
            //var dictSKAdNetworkIdentifier_AdColony = arraySKAdNetworkItems.AddDict();
            //dictSKAdNetworkIdentifier_AdColony.SetString("SKAdNetworkIdentifier", "4PFYVQ9L8R.skadnetwork"); // AdColony
            //var dictSKAdNetworkIdentifier_Appier = arraySKAdNetworkItems.AddDict();
            //dictSKAdNetworkIdentifier_Appier.SetString("SKAdNetworkIdentifier", "v72qych5uu.skadnetwork"); // Appier
            //var dictSKAdNetworkIdentifier_Appreciate = arraySKAdNetworkItems.AddDict();
            //dictSKAdNetworkIdentifier_Appreciate.SetString("SKAdNetworkIdentifier", "mlmmfzh3r3.skadnetwork"); // Appreciate
            //var dictSKAdNetworkIdentifier_Beeswax = arraySKAdNetworkItems.AddDict();
            //dictSKAdNetworkIdentifier_Beeswax.SetString("SKAdNetworkIdentifier", "c6k4g5qg8m.skadnetwork"); // Beeswax
            //var dictSKAdNetworkIdentifier_Jampp = arraySKAdNetworkItems.AddDict();
            //dictSKAdNetworkIdentifier_Jampp.SetString("SKAdNetworkIdentifier", "YCLNXRL5PM.skadnetwork"); // Jampp
            //var dictSKAdNetworkIdentifier_LoopMe = arraySKAdNetworkItems.AddDict();
            //dictSKAdNetworkIdentifier_LoopMe.SetString("SKAdNetworkIdentifier", "5lm9lj6jb7.skadnetwork"); // LoopMe
            var dictSKAdNetworkIdentifier_MyTarget = arraySKAdNetworkItems.AddDict();
            dictSKAdNetworkIdentifier_MyTarget.SetString("SKAdNetworkIdentifier", "n9x2a789qt.skadnetwork"); // MyTarget
            //var dictSKAdNetworkIdentifier_Pubnative = arraySKAdNetworkItems.AddDict();
            //dictSKAdNetworkIdentifier_Pubnative.SetString("SKAdNetworkIdentifier", "TL55SBB4FM.skadnetwork"); // Pubnative
            //var dictSKAdNetworkIdentifier_Remerge = arraySKAdNetworkItems.AddDict();
            //dictSKAdNetworkIdentifier_Remerge.SetString("SKAdNetworkIdentifier", "2U9PT9HC89.skadnetwork"); // Remerge
            //var dictSKAdNetworkIdentifier_RTBHouse = arraySKAdNetworkItems.AddDict();
            //dictSKAdNetworkIdentifier_RTBHouse.SetString("SKAdNetworkIdentifier", "8s468mfl3y.skadnetwork"); // RTB House
            //var dictSKAdNetworkIdentifier_Sabio = arraySKAdNetworkItems.AddDict();
            //dictSKAdNetworkIdentifier_Sabio.SetString("SKAdNetworkIdentifier", "GLQZH8VGBY.skadnetwork"); // Sabio
            //var dictSKAdNetworkIdentifier_Webeye = arraySKAdNetworkItems.AddDict();
            //dictSKAdNetworkIdentifier_Webeye.SetString("SKAdNetworkIdentifier", "22mmun2rn5.skadnetwork"); // Webeye
            //var dictSKAdNetworkIdentifier_YouAppi = arraySKAdNetworkItems.AddDict();
            //dictSKAdNetworkIdentifier_YouAppi.SetString("SKAdNetworkIdentifier", "3RD42EKR43.skadnetwork"); // YouAppi
            
            /// Apply editing settings to Info.plist
            plist.WriteToFile(plistPath);

        }
    }
}

 

[SKAdNetwork IDs 참조]

[Admob] developers.google.com/admob/ios/ios14#skadnetwork

[Unity] unityads.unity3d.com/help/ios/skadnetwork-ids?fbclid=IwAR3T6BWG6-SIdWipZaB-PEtUQhg1DAnU_kQ22iiSv4Z5Q6nItq2edtpIIkM

[Unity.xml] skan.mz.unity3d.com/v2/partner/skadnetworks.plist.xml?_ga=2.140049011.1591405619.1607905486-1813266944.1603773122

[Vungle] support.vungle.com/hc/en-us/articles/360002925791-Integrate-Vungle-SDK-for-iOS#3-add-the-%E2%80%9C-objc%E2%80%9D-linker-flag-0-9

[Vungle.xml] vungle.com/skadnetworkids.xml

[AppsFlyer 제공 리스트] docs.google.com/spreadsheets/d/e/2PACX-1vSqwIBW3FzbrXKqluDQ2hEec7zcvVrxQ02ivWsHnGQTvLMeFmHHjGz1R5TVy6_cqAIVh0pAy4Yud7Qx/pubhtml

 

[참조] blueasa.tistory.com/2482

반응형
Posted by blueasa
, |

[링크] www.elopezr.com/photoshop-blend-modes-in-unity/

 

Photoshop Blend Modes Without Backbuffer Copy

[latexpage] For the past couple of weeks, I have been trying to replicate the Photoshop blend modes in Unity. It is no easy task; despite the advances of modern graphics hardware, the blend unit st…

www.elopezr.com

Photoshop Blend Modes Without Backbuffer Copy

 BY ADMINOCTOBER 7, 2016GRAPHICS, UNITY

For the past couple of weeks, I have been trying to replicate the Photoshop blend modes in Unity. It is no easy task; despite the advances of modern graphics hardware, the blend unit still resists being programmable and will probably remain fixed for some time. Some OpenGL ES extensions implement this functionality, but most hardware and APIs don’t. So what options do we have?

1) Backbuffer copy

A common approach is to copy the entire backbuffer before doing the blending. This is what Unity does. After that it’s trivial to implement any blending you want in shader code. The obvious problem with this approach is that you need to do a full backbuffer copy before you do the blending operation. There are certainly some possible optimizations like only copying what you need to a smaller texture of some sort, but it gets complicated once you have many objects using blend modes. You can also do just a single backbuffer copy and re-use it, but then you can’t stack different blended objects on top of each other. In Unity, this is done via a GrabPass. It is the approach used by the Blend Modes plugin.

2) Leveraging the Blend Unit

Modern GPUs have a little unit at the end of the graphics pipeline called the Output Merger. It’s the hardware responsible for getting the output of a pixel shader and blending it with the backbuffer. It’s not programmable, as to do so has quite a lot of complications (you can read about it here) so current GPUs don’t have one.

The blend mode formulas were obtained here and here. Use it as reference to compare it with what I provide. There are many other sources. One thing I’ve noticed is that provided formulas often neglect to mention that Photoshop actually uses modified formulas and clamps quantities in a different manner, especially when dealing with alpha. Gimp does the same. This is my experience recreating the Photoshop blend modes exclusively using a combination of blend unit and shaders. The first few blend modes are simple, but as we progress we’ll have to resort to more and more tricks to get what we want.

Two caveats before we start. First off, Photoshop blend modes do their blending in sRGB space, which means if you do them in linear space they will look wrong. Generally this isn’t a problem, but due to the amount of trickery we’ll be doing for these blend modes, many of the values need to go beyond the 0 – 1 range, which means we need an HDR buffer to do the calculations. Unity can do this by setting the camera to be HDR in the camera settings, and also setting Gamma for the color space in the Player Settings. This is clearly undesirable if you do your lighting calculations in linear space. In a custom engine you would probably be able to set this up in a different manner (to allow for linear lighting).

If you want to try the code out while you read ahead, download it here.

 

[File]

BlendModesNoBackbuffer.zip
0.00MB

 

A) Darken

Formula min(SrcColor, DstColor)
Shader Output color.rgb = lerp(float3(1, 1, 1), color.rgb, color.a);
Blend Unit Min(SrcColor · One, DstColor · One)

Darken

As alpha approaches 0, we need to tend the minimum value to DstColor, by forcing SrcColor to be the maximum possible color float3(1, 1, 1)

 

B) Multiply

Formula SrcColor · DstColor
Shader Output color.rgb = color.rgb * color.a;
Blend Unit SrcColor · DstColor + DstColor · OneMinusSrcAlpha

Multiply

 

C) Color Burn

Formula 1 – (1 – DstColor) / SrcColor
Shader Output color.rgb = 1.0 - (1.0 / max(0.001, color.rgb * color.a + 1.0 - color.a)); // max to avoid infinity
Blend Unit SrcColor · One + DstColor · OneMinusSrcColor

Color Burn

 

D) Linear Burn

Formula SrcColor + DstColor – 1
Shader Output color.rgb = (color.rgb - 1.0) * color.a;
Blend Unit SrcColor · One + DstColor · One

Linear Burn

 

E) Lighten

Formula Max(SrcColor, DstColor)
Shader Output color.rgb = lerp(float3(0, 0, 0), color.rgb, color.a);
Blend Unit Max(SrcColor · One, DstColor · One)

Lighten

 

F) Screen

Formula 1 – (1 – DstColor) · (1 – SrcColor) = Src + Dst – Src · Dst
Shader Output color.rgb = color.rgb * color.a;
Blend Unit SrcColor · One + DstColor · OneMinusSrcColor

Screen

 

G) Color Dodge

Formula DstColor / (1 – SrcColor)
Shader Output color.rgb = 1.0 / max(0.01, (1.0 - color.rgb * color.a));
Blend Unit SrcColor · DstColor + DstColor · Zero

Color Dodge

You can see discrepancies between the Photoshop and the Unity version in the alpha blending, especially at the edges.

 

H) Linear Dodge

Formula SrcColor + DstColor
Shader Output color.rgb = color.rgb;
Blend Unit SrcColor · SrcAlpha + DstColor · One

Linear Dodge

This one also exhibits color “bleeding” at the edges. To be honest I prefer the one to the right just because it looks more “alive” than the other one. Same goes for Color Dodge. However this limits the 1-to-1 mapping to Photoshop/Gimp.

All of the previous blend modes have simple formulas and one way or another they can be implemented via a few instructions and the correct blending mode. However, some blend modes have conditional behavior or complex expressions (complex relative to the blend unit) that need a bit of re-thinking. Most of the blend modes that follow needed a two-pass approach (using the Pass syntax in your shader). Two-pass shaders in Unity have a limitation in that the two passes aren’t guaranteed to render one after the other for a given material. These blend modes rely on the previous pass, so you’ll get weird artifacts. If you have two overlapping sprites (as in a 2D game, such as our use case) the sorting will be undefined. The workaround around this is to move the Order in Layer property to force them to sort properly.

 

I) Overlay

Formula 1 – (1 – 2 · (DstColor – 0.5)) · (1 – SrcColor), if DstColor > 0.5
2 · DstColor · SrcColor, if DstColor <= 0.5
Shader Pass 1 color.rgb *= color.a;
float3 A = (4.0 * color.rgb - 1.0) / (2.0 - 4.0 * color.rgb);
float3 B = (1.0 * color.a) / ((2.0 - 4.0 * color.rgb) * max(0.001, color.a));
color.rgb = A + B;
Blend Pass 1 SrcColor · DstColor + DstColor · DstColor
Shader Pass 2 color.rgb = (2.0 - 4.0 * color.rgb * color.a) max(0.001, color.a);
Blend Pass 2 SrcColor · DstColor + DstColor · Zero

Overlay

How I ended up with Overlay requires an explanation. We take the original formula and approximate via a linear blend:

We simplify as much as we can and end up with this

The only way I found to get DstColor · DstColor is to isolate the term and do it in two passes, therefore we extract the same factor in both sides:

However this formula doesn’t take alpha into account. We still need to linearly interpolate this big formula with alpha, where an alpha of 0 should return Dst. Therefore

If we include the last term into the original formula, we can still do it in 2 passes. We need to be careful to clamp the alpha value with max(0.001, a) because we’re now potentially dividing by 0. The final formula is

 

J) Soft Light

Formula 1 – (1 – DstColor) · (1 – (SrcColor – 0.5)), if SrcColor > 0.5
DstColor · (SrcColor + 0.5), if SrcColor <= 0.5
Shader Pass 1

float3 A = 2.0 * color.rgb * color.a / (1.0 - 2.0 * color.rgb * color.a);
float3 B = (1.0 - color.a) / ((1.0 - 2.0 * color.rgb * color.a) * max(0.001, color.a));
color.rgb = A + B;

Blend Pass 1 SrcColor · DstColor + SrcColor · DstColor
Shader Pass 2 color.rgb = (1.0 - 2.0 * color.rgb * color.a) * max(0.001, color.a);
Blend Pass 2 SrcColor · DstColor + SrcColor * Zero

Soft Light

For the Soft Light we apply a very similar reasoning to Overlay, which in the end leads us to Pegtop’s formula. Both are different from Photoshop’s version in that they don’t have discontinuities. This one also has a darker fringe when alpha blending.

 

K) Hard Light

Formula 1 – (1 – DstColor) · (1 – 2 · (SrcColor – 0.5)), if SrcColor> 0.5
DstColor · (2 · SrcColor), if SrcColor <= 0.5
Shader Pass 1

float3 A (2.0 * color.rgb * color.rgb - color.rgb) * color.a;

float3 B max(0.001, (4.0 * color.rgb - 4.0 * color.rgb * color.rgb) * color.a + 1.0 - color.a);

color.rgb = A B;

Blend Pass 1 SrcColor · One + DstColor · One
Shader Pass 2 color.rgb = max(0.001, (4.0 * color.rgb - 4.0 * color.rgb * color.rgb) * color.a + 1.0 - color.a);
Blend Pass 2 SrcColor · DstColor + SrcColor * Zero

Hard Light

Hard Light has a very delicate hack that allows it to work and blend with alpha. In the first pass we divide by some magic number, only to multiply it back in the second pass! That’s because when alpha is 0 it needs to result in DstColor, but it was resulting in black.

 

L) Vivid Light

Formula 1 – (1 – DstColor) / (2 · (SrcColor – 0.5)), if SrcColor > 0.5
DstColor / (1 – 2 · SrcColor), if SrcColor <= 0.5
Shader Pass 1

color.rgb *= color.a;

color.rgb = color.rgb &gt;0.5 ? 1.0 / max(0.0001, 2.0 - 2.0 * color.rgb) : 1.0);

Blend Pass 1 SrcColor · DstColor + SrcColor · Zero
Shader Pass 2 color.rgb = color.rgb &lt; 0.5 ? (color.a - color.a / max(0.0001, 2.0 * color.rgb)) : 0.0;
Blend Pass 2 SrcColor · One + SrcColor · OneMinusSrcColor

Vivid Light

 

M) Linear Light

Formula DstColor + 2 · (SrcColor – 0.5), if SrcColor > 0.5
DstColor + 2 · SrcColor – 1, if SrcColor <= 0.5
Shader Output color.rgb = (2 * color.rgb - 1.0) * color.a;
Blend Unit  SrcColor · One + DstColor · One

Linear Light

[29/04/2019] Roman in the comments below reports that he couldn’t get Linear Light to work using the proposed method and found an alternative. His reasoning is that the output color becomes negative which gets clamped. I’m not sure what changed in Unity between when I did it and now but perhaps it relied on having an RGBA16F render target which may have changed since then to some other HDR format such as RG11B10F or RGB10A2 which do not support negative values. His alternative becomes (using RevSub as the blend op):

Formula DstColor + 2 · (SrcColor – 0.5), if SrcColor > 0.5
DstColor + 2 · SrcColor – 1, if SrcColor <= 0.5
Shader Output color.rgb = -(2 * color.rgb - 1.0) * color.a;
Blend Unit DstColor · One – SrcColor · One

 

 

 
반응형
Posted by blueasa
, |