2018년 1월 20일 토요일

IOS11 Private api - exist specific application

- (BOOL)existAppContainer: (NSString*)bundleID
{
    if ([[UIDevice currentDevice].systemVersion floatValue] >= 11.0)
    {
        NSBundle *container = [NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/MobileContainerManager.framework"];
        if ([container load])
        {
            Class appContainer = NSClassFromString(@"MCMAppContainer");
            id test = [appContainer performSelector:@selector(containerWithIdentifier:error:) withObject:bundleID withObject:nil];
            NSLog(@"%@",test);
            
            if (test)
            {
                return YES;
            }
        }
    }
    
    return NO;

}

IOS Private api - detect airplane mode

- (BOOL) isAirplainMode
{
    NSBundle *bundle = [NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/AppSupport.framework"];
    BOOL success = [bundle load];
    BOOL airplain = NO;
    
    if(YES == success)
    {
        Class RadiosPreferences = NSClassFromString(@"RadiosPreferences");
        id radioPreferences = [[RadiosPreferences alloc] init];
        
        SEL selector = NSSelectorFromString(@"airplaneMode");
        if(YES == [radioPreferences respondsToSelector:selector])
        {
            airplain = [[radioPreferences valueForKey:@"airplaneMode"] boolValue];
        }
    }

    return airplain;

}

2018년 1월 8일 월요일

CommandBuffer를 사용한 Post Effect효과 처리

CommandBuffer를 사용하여 Gray Post Effect 효과를 적용해보는 Simple code...

일단 보여지는 결과는...

실행전
실행후

CommmandBuffer를 이용한 C#예제 소스

using UnityEngine;
using System.Collections;
using UnityEngine.Rendering;

public class TestCommandBuffer : MonoBehaviour
{
    // 작성해둔 Post Effect Shader를 연결합니다.(Inspect에서 연결)
    [SerializeField] 
    Shader shader; 

    void Start()
    {
        if (shader == null) 
        {
            return; 
        }

        var camera = Camera.main;
        if (camera == null) 
        {
            return; 
        }

        Material material = new Material(this.shader); // Shader Matrial 

        CommandBuffer commandBuffer = new CommandBuffer();

        // 적당한 이름의 TemporaryRT를 작성(임시적인 RenderTexture를 생성)
        int temp = Shader.PropertyToID("_Temp");
        commandBuffer.GetTemporaryRT(temp, -1, -1, 0, FilterMode.Bilinear);

        // 포스트 이펙트 처리
        // Blit : 첫번째 인자의 RenderTexture를 두번째 인자의 RenderTexture로 전달
        //        세번쨰 인자에 메터리얼이 지정되면 해당 메터리얼을 적용
        commandBuffer.Blit(BuiltinRenderTextureType.CurrentActive, temp);
        commandBuffer.Blit(temp, BuiltinRenderTextureType.CurrentActive, material);

        // TemporaryRT을 해제
        commandBuffer.ReleaseTemporaryRT(temp);

        // 카메라에 CommandBuffer 추가
        camera.AddCommandBuffer(CameraEvent.AfterEverything, commandBuffer);

        // RemoveCommandBuffer를 사용해서 CommandBuffer해제 처리
        //camera.RemoveCommandBuffer(CameraEvent.AfterEverything, commandBuffer);
    }
}



임의 객체를 생성해서 위 소스를 Add Component하고선
인스펙터에서 아래 Gray Shader 를 연결하고 실해하면 씬에 보여지는 내용이 Gray로 그려집니다.

Shader "Test/GrayImageEffectShader"
{
    Properties
    {
        _MainTex ("Texture"2D) = "white" {}
        _EffectAmount ("Effect Amount"Range (01)) = 1.0            // add
    }
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }
            
            sampler2D _MainTex;
            float4 _MainTex_ST;         // add
            fixed _EffectAmount;        // add

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
                col.rgb = lerp(col.rgbdot(col.rgbfloat3(0.30.590.11)), _EffectAmount);
                return col;
            }
            ENDCG
        }
    }
}




2017년 12월 20일 수요일

Zenject 의 Inject Binding 방식들 몇가지 메모


// string타입값이 필요할때  생성된 string 인스턴스 "Hello World!" 할당하도록 합니다.
// 적용 대상의 타입은 Greeter로 한정
Container.Bind<string>().FromInstance("Hello World!")
    .When(context => context.ObjectType == typeof(Greeter));

// AsTransient모든 객체 요청이 있을때마다 재활용 없이 인스턴스를 생성하도록 합니다. 
// Inject어트리뷰트에 적용된 아이디가 다음과 같은 경우 > [Inject(Id = "Transient")]
Container.Bind<Dummy>().WithId("Transient").AsTransient();

// AsCached를 사용하는 경우 적용 대상의 타입/조건에 따라 캐쉬된 인스턴스가 사용됩니다.
// When조건이나 WithID조건 있으면 동일한 조건상에서는 같은 인스턴스가 사용됩니다.
// Inject어트리뷰트에 적용된 아이디가 다음과 같은 경우 > [Inject(Id = "Cached")]
Container.Bind<Dummy>().WithId("Cached").AsCached();

// AsSingle는 항상 한개의 인스턴스만 사용합니다.
// AsCached처럼 When조건이나 WithID조건에 따라 다른 인스턴스를 생성하지 않습니다. 싱클톤 패턴에 적합
// Inject어트리뷰트에 적용된 아이디가 다음과 같은 경우 > [Inject(Id = "Single")]
Container.Bind<Dummy>().WithId("Single").AsSingle();


// WithID의 전달 값은 string타입이 일반적이지만 enum을 사용할 수도 있습니다.

/* enum AsScope
   {
      Transient,
      Cached,
      Single,
   }*/
  
Container.Bind<Dummy>().WithId(AsScope.Transient).AsSingle();


// Greeter클래스가 인젝션될  있도록 컨테이너에 바인딩해놓습니다.
// 싱글인스턴스로(AsSingle), 필요할 때가 아닌 즉시 생성(NonLazy)
Container.Bind<Greeter>().AsSingle().NonLazy();

// 초기화 함수가 필요한경우 IInitializable인터페이스를 사용하여 바인딩합니다.
// 값을 인젝션하는 순서는 생성자 > 인젝션 필드 > IInitializable.Initialize 함수순입니다.
Container.Bind<IInitializable>().To<GreeterInit>().AsSingle().NonLazy();

// 앱이 닫힐 때나 장면이 전환될때  객체가 파괴될   정리할 외부 리소스가 존재할 경우 IDisposable를 바인딩 해줄  있다.
Container.Bind<IDisposable>().To<GreeterInit>().AsSingle().NonLazy();


// IWeapon인터페이스에 대한 객체가 필요할때 Weapon클래스 인스턴스를 할당하도록 합니다.
// 적용 대상의 타입은 Player로 한정합니다.
Container.Bind<IWeapon>()
    .To<Weapon>()
    .AsCached()
    .When(context => context.ObjectType == typeof(Player));

// Zenject내에 제공되는 Factory기능을 이용하여 DI형태의 팩토리를 만들  있습니다.
// cubePrefab 프리팹을 기반으로 Cube.Factory클래스를 사용하여 Cube를 생성하도록 합니다.
Container.BindFactory<Cube, Cube.Factory>().FromComponentInNewPrefab(cubePrefab);


// ITickable를 사용하는 InstancingManager클래스에 매프레임 마다 Tick함수를 호출해 주도록 합니다.
// MonoBehaviour의 Update함수 대응
Container.Bind<ITickable>().To<InstancingManager>().AsSingle();

// MonoBehaviour의 FixedUpdate함수 대응
Container.Bind<IFixedTickable>().To<InstancingManager>().AsSingle();

// MonoBehaviour의 LateUpdate함수 대응
Container.Bind<ILateTickable>().To<InstancingManager>().AsSingle();

Container.Bind<InstancingManager>().AsSingle();

2017년 12월 18일 월요일

Mac OS에서 Unity 프로젝트 멀티로 띄우기(Automator활용)


맥에서 유니티 프로그램을 여러개 실행하는 방법

터미널에서 “open –na Unity.app” 명령어 실행



매번 터미널 열기 귀찮으니 Automator를 이용해서 App를 만들고 Dock에 넣어버리자.

Automator 실행 > 새로운 도큐먼트 > 응용프로그램 선택



왼쪽 리스트에서 “쉘 스크립트 실행” 항목 찾아 오른쪽으로 Drag&Drop!

스크립트 내용에 “open –na Unity.app” 입력


파일 > 저장 > 파일명을 정하고(예: UnityMulti.app) 응용프로그램 폴더에 저장
Dock에 넣어두고 편하게 사용하자..

2017년 12월 9일 토요일

Customize Unity (C#)Script Templates


C# 스크립트를 만들면 Unity Editor는 아래 소스 코드를 생성합니다.
(파일명이 클래스의 이름으로 사용됩니다.)


using UnityEngine;
using System.Collections;

public class MyCustomScript : MonoBehaviour {

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    }
}


스크립트 템플릿을 변경하려면 아래 경로에 저장된 스크립트 템플릿 파일을 수정해야 합니다.

Windows: C:\Program Files\Unity\Editor\Data\Resources\ScriptTemplates
Mac /Applications/Unity/Unity.app/Contents/Resources/ScriptTemplates


해당 경로에는 아래와 같은 여러개의 템플릿 파일들이 있습니다.

81-C# Script-NewBehaviourScript.cs.txt
83-Shader__Standard Surface Shader-NewSurfaceShader.shader.txt
83-Testing__EditMode Test C# Script-NewEditModeTest.cs.txt
83-Testing__PlayMode Test C# Script-NewPlayModeTest.cs.txt
84-Shader__Unlit Shader-NewUnlitShader.shader.txt
85-Shader__Image Effect Shader-NewImageEffectShader.shader.txt
86-C# Script-NewStateMachineBehaviourScript.cs.txt
86-C# Script-NewSubStateMachineBehaviourScript.cs.txt
87-Playables__Playable Behaviour C# Script-NewPlayableBehaviour.cs.txt
88-Playables__Playable Asset C# Script -NewPlayableAsset.cs.txt
90-Shader__Compute Shader-NewComputeShader.compute.txt


각각의 사용 용도는 아마 파일명에서 대충 유추할 수 있지 않을까 싶습니다.. ^^;

새로 생성되는 C#스크립트 템플릿을 가지고 싶다면 "81-C# Script-NewBehaviourScript.cs.txt" 파일을 편집하면 됩니다.
(일반 편집기로는 권한문제로 저장이 안될 수 있습니다.)

sudo nano "/Applications/Unity/Unity.app/Contents/Resources/ScriptTemplates/81-C# Script-NewBehaviourScript.cs.txt"




템플릿 파일의 기본 형태는 아래와 같이 되어 있을 겁니다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class #SCRIPTNAME# : MonoBehaviour {

    // Use this for initialization
    void Start () {
        #NOTRIM#
    }

    // Update is called once per frame
    void Update () {
        #NOTRIM#
    }
}


위 소스에서 #SCRIPTNAME#는 파일명을 클래스 명으로 대체하는 부분입니다. 그대로 두는편이 좋겠지요.

#NOTRIM# .. no trim? 정확한 역할이 뭔지 모르겠습니다만~ 아마 공백을 유지하기 위함이 아닐까 생각해봅니다.


아래는 C# 템플릿의 모양을 바꿔본 예제입니다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/**
 * @brief #SCRIPTNAME# Class
 */
public class #SCRIPTNAME# : MonoBehaviour 
{
    #region Public Fields
    #endregion

    #region Unity Methods
    // Use this for initialization
    void Start () 
    {
        #NOTRIM#
    }

    // Update is called once per frame
    void Update () 
    {
        #NOTRIM#
    }
    #endregion

    #region Private Methods
    #endregion
}



템플릿 파일을 수정/저장한 뒤 Unity Editor를 다시 실행하고 새로운 C# 파일을 생성하면 아래와 같이 생성된 소스를 확인할 수 있습니다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/**
 * @brief Test3 Class
 */
public class Test3 : MonoBehaviour 
{
    #region Public Fields
    #endregion

    #region Unity Methods
    // Use this for initialization
    void Start () 
    {

    }

    // Update is called once per frame
    void Update () 
    {

    }
    #endregion

    #region Private Methods
    #endregion
}



* 인식 오류 문제를 위해 원본 템플릿 파일은 백업해 두는것이 좋겠습니다.
* Unity가 업데이트 될 때 수정한 템플릿이 덮어씌어질 수 있겠습니다. 수정한 파일도 백업할 필요가 있겠지요.