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

카테고리

분류 전체보기 (2737)
Unity3D (817)
Programming (474)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (228)
협업 (58)
3DS Max (3)
Game (12)
Utility (136)
Etc (96)
Link (32)
Portfolio (19)
Subject (90)
iOS,OSX (53)
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
04-27 00:02

Android에서는 빌드해서 실행 잘 되는데,

iOS 빌드는 다 되고 실행하는 데 통신이 안돼서 Xcode 로그를 보니 아래와 같은 에러 로그가 보인다 있다.

iOS에서 이제는 https를 강제하기 때문에 http URL로 통신하려고 하면 Runtime에 Error를 뱉는다.

 

2020-12-28 20:02:53.378574+0900 project[46312:8363659] 
You are using download over http. 
Currently Unity adds NSAllowsArbitraryLoads to Info.plist to simplify transition, 
but it will be removed soon. Please consider updating to https.

2020-12-28 20:02:53.380318+0900 project[46312:8363628] 
App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. 
Temporary exceptions can be configured via your app's Info.plist file.

2020-12-28 20:02:53.380351+0900 project[46312:8363628] 
Cannot start load of Task <9D5615C0-5B46-4144-9851-1EB6BFDEAF4A>.
<0> since it does not conform to ATS policy

 

[결론]

iOS는 https URL을 강제한다.

URL은 항상 https를 준비하고 사용하자.

 

반응형
Posted by blueasa
, |

[링크] sesang-story.tistory.com/725

 

애드센스 Google sellers.json 해결방법

애드센스 홈페이지에 들어가시면 뜬금없이 이런 문구가 떠있을 겁니다. 혹시 애드센스 수익에 문제가?? 이 문구를 보고 처음에 이게 뭔가 했어요. 먼저 자세히 알아보기에 들어가 어떤 내용인지

sesang-story.tistory.com

 

반응형
Posted by blueasa
, |

에러메시지

응용 프로그램을 위한 유효한 ‘aps-environment’ 인타이틀먼트 문자열을 찾을 수 없습니다.

 

 

해결

Signing & Capabilities > Capability 추가 버튼 클릭 > Push Notifications 을 추가한다



출처: https://ghj1001020.tistory.com/796?category=718567 [혁준 블로그]

 

iOS 응용 프로그램을 위한 유효한 ‘aps-environment’ 인타이틀먼트 문자열을 찾을 수 없습니다.

에러메시지 응용 프로그램을 위한 유효한 ‘aps-environment’ 인타이틀먼트 문자열을 찾을 수 없습니다. 해결 Signing & Capabilities > Capability 추가 버튼 클릭 > Push Notifications 을 추가한다

ghj1001020.tistory.com

 

 

반응형
Posted by blueasa
, |

이번에는 HTTP 서버에 데이터 요청을 보내고 데이터를 얻어오기, 혹은 데이터를 보내는 방법입니다.


목차

1. WWW 클래스로 구현(권장하지 않습니다.)

2-1. Get 방식

2-2. Post 방식

2. UnityWebRequest 클래스로 구현(권장)

2-1. Get 방식

2-2. Post 방식

3. 요약 및 정리


1. WWW 클래스로 구현

1-1 GET 방식

아래는 제가 작성한 간단한 GET 방식의 코드입니다.

GET 방식 테스트를 위해 이곳을 이용하겠습니다.

https://developers.neople.co.kr/contents/apiDocs

 

Neople Developers

## 참고 사항 >- 타임라인 코드 다중 입력 시 콤마(,)를 이용해서 구분 처리   ex) /timeline?code=101,102,103 - startDate, endDate 요청 변수 사용 예시   ex) /timeline?startDate=20180901T0000&endDate=20180930T2359           /timeline?startDate=2018-09-01 00:00&endDate=2018-09-30 23:59   ※ 기간 검색

developers.neople.co.kr

 

APIKey는 로그인을 하시고 발급받으시면 보입니다.

응답 요청은 코루틴을 이용해서 보내도록 하겠습니다.

코루틴을 이용하는 이유는 응답을 보내고 오는 시간이 걸리기 때문입니다.

다른 곳에서 작성하시면 응답이 오기 전에 처리하게 되어 오류가 출력됩니다.

위에 코드는 예시 코드입니다.

홈페이지에서 발급받은 apikey를 저기에 입력하시면 됩니다.

url을 보시면 servers? apikey=하고 요청을 보내게 되는데

헤더 부분에 정보를 넣어서 보내는 곳이 저곳입니다.

코드에 주석을 넣었으니 읽으면서 확인해보세요.

코드를 실행해보시면 이렇게 응답이 옵니다.

1-2 POST 방식

위에는 POST 방식입니다.

POST 방식은 따로 동작을 처리해야 하기 때문에 개인적으로 만든 서버를 이용하여 설명하겠습니다.(저건 사설 ip 주소이기 때문에 똑같이 적으셔도 동작 안 합니다.)

(테스트해보고 싶으신 분들은 따로 서버를 만드셔서 실험해보세요)

POST 방식은? apikey= 이런 게 없습니다.

필드명에 apikey를 넣고 데이터를 넣으시면 됩니다.

필요한 내용은 주석 처리했습니다.

서버에서 로그인 정보가 맞으면 응답을 보냅니다.


2. unitywebrequest 클래스

이제 www 클래스는 Unity에서 사용을 권장하지 않습니다.

사용하시면 주의로 unitywebrequest를 사용하라고 나올 텐데요.

이것을 사용하는 방법을 알려드리겠습니다.

UnityEngine.Networking을 추가해줍니다.

2-1 GET 방식

아래는 WWW 클래스를 UnityWebRequest 클래스 방식으로 수정한 것입니다.

수정한 부분은 빨간 줄로 밑줄을 쳤습니다.

2-2 POST 방식

수정한 부분은 밑줄 쳤습니다.


3. 요약 및 정리

정리 : 통신방식에는 GET과 POST가 있다.

GET은 쉬우나 보안 취약, 용량 제한

POST는 어려우나 보안에 좋고, 용량 제한이 없다.

WWW 클래스는 이제 사용하지 않는다.

UnityWepRequest를 사용하자.(설명은 WWW 클래스에 적어놓았다.)

 

 

[출처] mungto.tistory.com/190

 

www 클래스, UnityWebRequest 클래스 사용하기(HTTP 서버에 데이터 가져오기, 보내기 등)

이번에는 HTTP 서버에 데이터 요청을 보내고 데이터를 얻어오기, 혹은 데이터를 보내는 방법입니다. 목차 1. WWW 클래스로 구현(권장하지 않습니다.) 2-1. Get 방식 2-2. Post 방식 2. UnityWebRequest 클래스

mungto.tistory.com

 

[참조] docs.unity3d.com/ScriptReference/Networking.UnityWebRequest.Post.html

반응형
Posted by blueasa
, |

[출처] www.raywenderlich.com/9671886-new-unity-input-system-getting-started

 

New Unity Input System: Getting Started

In this Unity Input System tutorial, you’ll learn how to convert player input in your existing projects from the old Input Manager to the new Input System.

www.raywenderlich.com

 

In this Unity Input System tutorial, you’ll learn how to convert player input in your existing projects from the old Input Manager to the new Input System.

 

Version

  • C# 7.3, Unity 2020.1, Unity

Handling input is a pillar of creating a successful game. Input devices help player characters perform actions inside the game such as walking, jumping and climbing.

Recently, many new platforms have come out, introducing more Unity input devices. These include touch screens, VR controllers and gamepads from different game consoles. If you want your game to support different platforms, you need to write code to handle the logic for different devices. The more platforms you support, the more complex your code will be.

Luckily, there’s a new Unity Input System that helps developers deal with this situation, making input-related code easier to manage.

In this tutorial, you’ll learn:

  • The features of the new Input System.
  • How the new system works.
  • How to migrate apps to the new Input System from the old Input Manager.

The materials for this tutorial were built in Unity version 2020.1. You can get this version of Unity from the Unity website or install it with the Unity Hub.

Note: Although this tutorial is for beginners, you’ll need to have some basic knowledge of Unity development and how to work with Unity Editor to complete it. If you’re new to Unity development, check out our tutorial on Getting Started In Unity.

Getting Started

First, download the starter project for this tutorial using the Download Materials button at the top or bottom of this page. Unzip its contents and open NewUnityInputSystem-Starter in Unity.

After the project loads, you’ll see the RW folder in the Project Window:

Take a look at the organization of the folder:

  • Fonts: Fonts used in the scene.
  • Materials: Materials for the scene.
  • Models: 3D meshes for the player character and game environments.
  • Prefabs: Pre-built components composed of Scripts and Models.
  • Scenes: The game scene.
  • Scripts: Scripts with game logic.
  • Settings: The settings file, which is where you’ll put the input settings.
  • Shaders: Shaders for special effects like the player’s shadow.
  • Textures: The graphics used by Materials and UIs.

The starter project is a simple platformer game. You control the player character by moving around and jumping to collect coins.

The game is ready to play. Open GameScene from the Scenes folder and click Play to try the game for yourself!

Currently, the Move and Jump controls use the old Unity Input Manager. You’ll learn how to use the new Input System to replace the old system later in the tutorial.

What’s New in the Unity Input System

Before diving into the code, take a look at the new Input System’s features.

Simpler Action and Binding Architecture

The old input system checked input from different devices every frame to determine whether players took an action.

The following code, which supports both gamepads and keyboards, is an example of the old way of doing things:

bool isGamepad = Input.GetAxis("Gamepad Fire") != 0f; if (isGamepad) { return Input.GetAxis("Gamepad Fire") >= triggerAxisThreshold; } else { return Input.GetButton("Fire"); }

The code uses if-else branching to handle support for different devices and their associated actions.

The new Input System separates device input from code actions. That means you only have to handle the actions the players trigger. You don’t need to know which device the player is using or which button they’re clicking.

An input event in the new system is called an action, while the mapping between an action and an input device is a binding.

Gathering Information With the Input Debug Tool

The Input System provides you with a new tool called Input Debugger. Open it by selecting Window ▸ Analysis ▸ Input Debugger from the menu.

The Input Debugger helps developers by gathering the following information in one place:

The state of the Input System, including:

  • Device: Information about the connected devices.
  • Layout: Which controls those devices provide.
  • Setting: The configuration of the input system.

It also provides real-time information about a specific device. Open this by double-clicking the device from the device list in the Input Debugger window.

Here’s a demo of the Input Debugger in action:

Feel free to keep the Input Debugger open while you work through the tutorial.

Support for Multiple Devices and Platforms

With the increased flexibility from the Input System’s new architecture, Unity can support many different input devices, including:

  • Keyboard
  • Mouse
  • Pen
  • TouchScreen
  • Sensor
  • Joystick
  • GamePad

Note: The Input System also supports devices that implement the USB HID specification. For more details, check out Unity’s Supported Devices Documentation.

Understanding the New Input System

The new Input System has four building blocks that funnel events from player devices to your game code:

  • Input Action Assets: A settings file that contains the properties of the actions and their associated bindings.
  • Actions: Actions define the logical meanings of the input. You can find that information in the Input Action Assets.
  • Bindings: Bindings describe the connection between an action and the input device controls. You’ll find this information in the Input Action Assets, too.
  • PlayerInput: PlayerInput is a script that manages and links action events to the corresponding code logic.

Sometimes it’s easier to understand a new workflow if you can visualize it, so take a look at the image below:

Break this down into its simplest steps:

  • First, the Unity Engine collects information from the connected devices and sends corresponding events, like a button click, to the Input System.
  • The Input System then translates those events into actions, based on the action and binding information stored in the Input Action Assets.
  • It then passes the actions to the PlayerInput script, which invokes the corresponding methods.

Now that you know a little more about how the Input System works, you’ll use it to control the game character in the coming sections.

Installing the New Input System

The first thing you’ll do is install the new Input System package. The standard Unity installation doesn’t include it.

Open Window ▸ Package Manager in the menu bar. Make sure that you select Unity Registry in the Packages dropdown, if you haven’t already.

Find Input System on the list. Select it and click Install.

Creating an Input Action Asset

Once you’ve installed the Input System package, you’ll create an Input Action Asset to store the settings for your actions and bindings.

Open the Project window and select Settings from RW. Right-click, select Create ▸ Input Actions and rename it to MyControl.

Setting up the Action Editor

Double-click MyControl in Settings to open the Action Editor, which helps you manipulate actions and control bindings.

Since this is a new window, take a look at the sections:

  1. Action Maps: Groups of actions that occur in the game. You can group actions for different purposes, like player, gameplay or UI.
  2. Actions: The list of actions and bindings associated with the selected Action Map. In this panel, you create, modify or delete actions and bindings.
  3. Properties: Edit the action or binding properties in this panel, such the type of action and the controls you associated with the binding.
  4. Save Assets: This is a very important function: You must click Save Asset after making any changes to the Input Action Asset. If you forget to save, the setting won’t work. Thus, you won’t see the expected result and may think there’s a bug in the code.

    You can switch on Auto Save to prevent the problem, but it’s quite slow.

Now you’re ready to create your first action, the Jump action.

Creating a Jump Action

First, open the Action Editor and click the + icon in the ActionMap to create a new Action Map. Rename it from the default, New Action Map, to Player.

Then, in the Action panel, double-click New Action and rename it to a meaningful name: Jump.

Finally, you need to add a binding to the Jump action. You’ll bind the Spacebar and Left Mouse Button to this action by following these steps:

  1. Select the Jump action, click the + icon and select Add Binding.
  2. Click the new binding item, <No binding>.
  3. Click the Path field in the Binding properties panel.
  4. Type Spacebar Keyboard and select Space [Keyboard] to create the binding for the Spacebar.
  5. Repeat steps 1–3 to create another binding for the Left Mouse Button.
  6. Type Left Button in the Path field and select Left Button [Mouse] to create the binding.

Congratulations, you’ve now associated the Jump action with the Spacebar on the keyboard and the left button on the mouse.

Now to hook up those actions with your code!

Implementing the Jump Logic

First of all, you need to remove the old input logic from the project. Open Player.cs and navigate to the Update() method.

void Update() { UpdateAnimation(); if (!jumping && Input.GetKeyDown(KeyCode.Space)) { HandleJump(); } }

As you can see, the current code triggers the animation updates, then it checks if the player has pressed the space bar in order to start a jump.

Now that the Jump action and its control bindings are ready, the next thing to do is link the action to the code.

Linking the Jump Action to the Code

Start by deleting the code in Update to remove the implementation of the old Input Manager so you can add Jump logic using the new Input System. Update will now only control the animations.

void Update() { UpdateAnimation(); }

Save the script and go back to the editor. Select the Player object in the Hierarchy and add a PlayerInput component from the Inspector.

Next, you’ll drag MyControl to PlayerInput’s Actions. Make sure to set the Default Map to Player.

Finally, open Player.cs and add a new method called OnJump() with the following code:

public void OnJump() { HandleJump(); }

You’ve associated this method with the Jump action by using this pattern to name it: public void On[Action Name Goes Here]().

For example, the Jump action invokes OnJump(), while the Attack action invokes OnAttack().

Click Save Asset in the Action Editor and run the game. Now you can use the SpaceBar or the left mouse button to make the player character jump. It’s really that easy!

Creating the Move Action

You’ve learned how to use the Input System to create a Jump action. Next up is the Move action! Move is similar to Jump, but it has a few key differences.

For example, the Jump action is a simple trigger event, while the Move action is an event that carries values: the movement direction, which comes from user input.

Again, you need to create the action and its binding. Start by going to Action Editor (double click MyControl if you lost the window) and click the + icon in the Actions panel to create a new action. Rename it to Move.

Next, open the Action properties panel, change Action Type to Value and Control Type to Vector 2.

Finally, remove <No Binding> by right-clicking and selecting Delete.

Now, you need to create the Move action’s bindings.

First, you’ll click the + icon in the header of the Move action. Then, select Add 2D Vector Composite, which will create four binding items corresponding to the up, down, left and right directions.

Now, you’ll set the path of each binding as follows:

  • Up: Up Arrow [Keyboard]
  • Down: Down Arrow [Keyboard]
  • Left: Left Arrow [Keyboard]
  • Right: Right Arrow [Keyboard]

Don’t forget to save the asset in the Action Editor!

Implementing the Move Logic

Before adding new movement logic, you need to remove the implementation of the old Unity input.

Open Player.cs and go to FixedUpdate():

private void FixedUpdate() { // 1 float speedX = Input.GetAxisRaw("Horizontal"); // Left, Right float speedY = Input.GetAxisRaw("Vertical"); // Back, Forward moveVec = new Vector3(speedX, 0, speedY); if (jumping == false) { // 2 UpdateWhenGrounded(); } else { // 3 UpdateWhenJumping(); } }

Note that FixedUpdate() is called in every fixed frame-rate frame.

Now, break this down:

  1. Input.GetAxisRaw returns the value of Axis. Input.GetAxisRaw("Horizontal") gives the value of the X-Axis, while Input.GetAxisRaw("Vertical") gives the value of Y-Axis.

    These two values define the movement vector moveVec, which you use to control the direction of the player movement.

  2. The logic of the player character’s behavior while it’s on the ground.
  3. The logic of the player character’s behavior while it’s jumping.

Now, delete all the code prior to the if statement to remove the old input logic. Add the following code above the class definition:

using UnityEngine.InputSystem;

This allows you to access values from the new Input System.

Then, add OnMove(), which the Move action invokes.

public void OnMove(InputValue input) { Vector2 inputVec = input.Get<Vector2>(); moveVec = new Vector3(inputVec.x, 0, inputVec.y); }

When a player presses the Up, Down, Left or Right keys, it passes a Move action to this method, along with the values. Here’s how the key presses affect the values:

  • Up: (0, 1)
  • Down: (0, -1)
  • Left: (-1, 0)
  • Right: (1, 0)
  • No Key: (0, 0)
  • Up and Left: (1, -1)

InputValue is a new type you may not know. This class has a Get\() method that you can use to access its values. In this instance, you want the 2D Vector Composite you set in the binding to calculate the movement vector.

Click Play to test the logic.

Handling Actions

The new Input System provides four ways to handle action events.

In this tutorial, you used the SendMessages approach. You can change this option in the Behavior field in the PlayerInput component.

SendMessage and BroadcastMessage are the simplest ways to handle actions. When you use these two options, the system invokes the method with a name matching the name of the action.

For example, in this tutorial, the Jump action invokes OnJump() and the Move action invokes OnMove().

BroadcastMessage is similar to SendMessage, except it can invoke the methods on any child GameObject. These two options are easy to use because you don’t need to configure anything to use them.

Using Invoke Unity Events

When using Invoke Unity Events, you configure the action much as you’d configure a button click in Unity UI.

This approach is more flexible, letting you use different methods in different objects. Those GameObjects don’t even need to have the PlayerInput component.

Using Invoke C# Events

This approach is as flexible as Invoke Unity Events. You can define the methods you want to use instead of using methods with a specific name. However, if you use this approach, you need to write code to control which methods to invoke.

Here is a sample of how this looks:

private void Awake() { animator = GetComponentInChildren<Animator>(); rigidbody = GetComponent<Rigidbody>(); // 1 GetComponent<PlayerInput>().onActionTriggered += HandleAction; } private void HandleAction(InputAction.CallbackContext context) { // 2 if(context.action.name == "Jump") { HandleJump(); } }

Here’s what this code does:

  1. Gets the PlayerInput component and registers the method to onActionTriggered.
  2. Controls which method to call for different actions.

Using the Update Cycle of the New Input System

In the old Unity Input Manager, you checked the input in every frame using Update(). In the new Input System, you may wonder when actions are being sent, and if they’re sent before every Update().

The new Input System uses a different update cycle that’s independent of MonoBehaviour‘s lifecycle. You can read more about it in Unity’s Execution Order documentation.

The system offers three Update Modes to control the update cycle. You can configure them in Project Settings ▸ Input System Package ▸ Update Mode.

Take a look at each of these nodes:

  • Dynamic Update: Processes events at irregular intervals determined by the current frame rate. This is the default setting.
  • Fixed Update: Processes events at fixed-length intervals. Time.fixedDeltaTime determines the length of the interval.
  • Manually: Events aren’t processed automatically; you process them when you call InputSystem.Update(). If you want a check similar to the old system, you can call InputSystem.Update() in Update().

These new options, as part of the new Input System, give you a lot more control over input, whilst also making it easier to support multiple input devices :]

Where to Go from Here?

Download the completed project using the Download Materials button at the top or bottom of this tutorial.

In this Unity Input tutorial, you’ve learned:

  • The basic layout of the new Input System.
  • How to use actions and bindings.
  • How to handle different kinds of player input efficiently.

To test your skill, try to add a Pause action to the game!

To learn more about the new Input System, you can read the Unity Input System manual.

I hope you have enjoyed this tutorial! If you have any questions or comments, please join the forum discussion below.

반응형
Posted by blueasa
, |

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

[정리]

1. 아이폰 완전 종료 후, 재실행

1.1. Unpair Device 권장(Xcode - Window > Devices and Simulators > 해당 디바이스에서 우클릭 > Unpari Device)

2. 아이폰 케이블 연결해서 '신뢰' 체크

3. Xcode 다시 켜서 Devices and Simulators에 들어가서 에러 없는지 확인

4. 없으면 OK

 


Follow this: https://developer.apple.com/forums/thread/650077

Also make sure to shut down your iPhone, start it back up. 
Then I would also suggest unpairing the device from Xcode (Window > Devices Simulator....). 
And then Clean build folder, and quit and restart xcode again!

 

 

[출처] www.reddit.com/r/swift/comments/jtbcqa/iphone_not_available_please_reconnect_the_device/

 

iPhone Not Available. Please reconnect the device / Xcode 12.2 iOS 14.2

When I try to run my Xcode with my iPhone X I get this: iPhone Not Available. Please reconnect the device I've looked through and tried the...

www.reddit.com

 

반응형
Posted by blueasa
, |

[결론]

GoogleMobileAds iOS SDK 7.68 이상은 Firebase 7.x 이상에서 지원합니다.

Firebase 업데이트 하세요


Unity: 2019.4.8f1

AdMob v5.4.0

Firebase v6.16.1 (Messaging & Analytics)

Target minimum iOS Version 12.0

Problem

I can't build the project. XCode error:

../Libraries/Plugins/iOS/GADUAdLoader.h:5:9: 'GoogleMobileAds/GoogleMobileAds.h' file not found

When I trying to update pods terminal throw the next error:

[!] CocoaPods could not find compatible versions for pod "GoogleAppMeasurement":
  In Podfile:
    Firebase/Analytics (= 6.32.2) was resolved to 6.32.2, which depends on
      Firebase/Core (= 6.32.2) was resolved to 6.32.2, which depends on
        FirebaseAnalytics (= 6.8.2) was resolved to 6.8.2, which depends on
          GoogleAppMeasurement (= 6.8.2)

    Google-Mobile-Ads-SDK (~> 7.68) was resolved to 7.68.0, which depends on
      GoogleAppMeasurement (~> 7.0)

Attempts

  1. Add 'pod 'GoogleAppMeasurement', '7.0'' to Podfile.

Result

CocoaPods could not find compatible versions for pod "GoogleAppMeasurement":
  In Podfile:
    Firebase/Analytics (= 6.32.2) was resolved to 6.32.2, which depends on
      Firebase/Core (= 6.32.2) was resolved to 6.32.2, which depends on
        FirebaseAnalytics (= 6.8.2) was resolved to 6.8.2, which depends on
          GoogleAppMeasurement (= 6.8.2)

    Google-Mobile-Ads-SDK (~> 7.68) was resolved to 7.68.0, which depends on
      GoogleAppMeasurement (~> 7.0)

    GoogleAppMeasurement (= 7.0)
  1. Uninstall and install cocoapods

Result

Same error

Project Podfile

source 'https://github.com/CocoaPods/Specs.git'
source 'https://github.com/CocoaPods/Specs'
platform :ios, '12.0'

target 'UnityFramework' do
  pod 'Firebase/Analytics', '6.32.2'
  pod 'Firebase/Core', '6.32.2'
  pod 'Firebase/Messaging', '6.32.2'
  pod 'Google-Mobile-Ads-SDK', '~> 7.68'
end

 

How can I resolve this problem?

 

 

[Answer]

Google-Mobile-Ads-SDK version 7.68 is only compatible with Firebase 7.x. If you want to use Firebase 6.x, you need to use 7.67 or earlier.

 

 

[출처] stackoverflow.com/questions/64850730/unity-firebase-admob-conflict-googleappmeasurement

 

Unity Firebase + AdMob conflict (GoogleAppMeasurement)

Unity: 2019.4.8f1 AdMob v5.4.0 Firebase v6.16.1 (Messaging & Analytics) Target minimum iOS Version 12.0 Problem I can't build the project. XCode error: ../Libraries/Plugins/iOS/GADUAdLoader.h:5...

stackoverflow.com

 

반응형
Posted by blueasa
, |

많은 사람들이 pod install 을 코코아팟 프로젝트를 처음 세팅할 때 딱 한 번 쓰고 pod update 는 그 이후에 사용된다고 생각합니다. 그러나 전혀 그렇지 않습니다! 😝

 

이번 포스팅에서 pod install  pod update 를 정확히 알아보도록 하겠습니다.

pod install

  pod을 프로젝트에 세팅하기 위하여 맨 처음에 사용됩니다. 하지만 Podfile의 pod을 추가, 수정, 삭제할 때에도 사용됩니다.

 

pod install 명령어를 실행하면 새로운 pod을 다운받고 설치합니다. 그리고 각 pod 마다 설치된 버전을 Podfile.lock 에 기록해 놓습니다. Podfile.lock은 설치된 pod들의 버전을 계속 추적하여 기록해놓고 유지시키는 역할을 합니다.

 

pod install 을 실행하면,

Podfile.lock에 리스트된 팟들에 대해선 지정된 버전만 다운받습니다. 새로운 버전이 존재하는지 체크하지 않는 것이죠!

Podfile.lock에 리스트되지 않은 팟들은 Podfile에 명시된 버전 조건으로 검색하여 다운로드 받습니다. (ex. pod 'MyPod', '~>1.2')

Podfile.lock 예시

PODS: - Alamofire (4.8.2) - Crashlytics (3.13.2) . . . PODFILE CHECKSUM: 567f647c0698abc31d48952ce58077we758abse2

Podfile.lock에는 CHECKSUM이 부여됩니다. Podfile.lock의 유일성을 보증하는 해쉬값인 셈이죠. 만약 버전에 변경이 생기면 CHECKSUM 또한 변하게 됩니다.

pod update

  pod update {팟이름} 을 실행시키면, 코코아팟은 해당 팟의 업데이트된 버전이 있는지 검색합니다. Podfile.lock을 참조하지 않죠. 이 명령어는 팟을 최신 버전으로 업데이트 시켜주는 것입니다. (단, Podfile의 버전 조건과 일치해야 합니다.) 단순하게 pod update 만 실행시키면 코코아팟은 모든 팟에 대해 가능한 최신 버전으로 업데이트를 실행합니다.

pod outdated

  pod outdated 를 실행하면, 코코아팟은 Podfile.lock에 리스트된 것보다 새로운 버전을 가진 모든 팟을 나열합니다. 이 팟들에 대해 pod update {팟이름} 을 실행한다면 업데이트가 될 것이라는 것을 의미합니다. (역시나 Podfile의 버전 조건과 부합하는 한!)

pod repo update

  /Users/{사용자이름}/.cocoapods/repos 에 있는 모든 podspec 파일을 업데이트 합니다. podspec 파일에는 해당 pod 의 주소 등 중요한 정보들이 담겨있습니다.

 

spec.source = { :git => 'https://github.com/Alamofire/Alamofire.git', :tag => 'v3.1.1' }

 

~/.cocoapods/repos 에는 모든 pod에 대해 가능한 버전들의 podspec 파일들이 모여있습니다. pod repo update 를 실행하게 되면 최신 podspec 파일들로 업데이트되게 되는 것입니다. 추가한 라이브러리에 대한 podspec 이 업데이트되지 않아 오류가 날 경우 이 명령어를 통하여 해결할 수 있습니다.

Podfile.lock을 커밋하세요!

  동료와 같이 협업하고 있다면! 꼭 Podfile.lock을 공유해야 합니다. pod 버전을 모두가 동일하게 쓰도록 유지시키는 역할을 하는 것이죠. 그리고 Podfile이 수정될 일이 생긴다면 pod install 명령어를 통해 의존성을 관리하면 됩니다. 만약 동료들과 같은 CHECKSUM을 얻는데에 실패했다면 간단하게 rm -rf Pods && pod install 을 실행하면 됩니다. 😎

참조

https://guides.cocoapods.org/using/pod-install-vs-update.html

 

 

[출처] onelife2live.tistory.com/30

 

[Cocoapods] pod install? pod update? 제대로 알고 쓰자

많은 사람들이 pod install 을 코코아팟 프로젝트를 처음 세팅할 때 딱 한 번 쓰고 pod update 는 그 이후에 사용된다고 생각합니다. 그러나 전혀 그렇지 않습니다! 😝 이번 포스팅에서 pod install 과 pod

onelife2live.tistory.com

 

반응형
Posted by blueasa
, |