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

카테고리

분류 전체보기 (2738)
Unity3D (817)
Script (91)
Extensions (14)
Effect (3)
NGUI (77)
UGUI (8)
Physics (2)
Shader (36)
Math (1)
Design Pattern (2)
Xml (1)
Tips (200)
Link (22)
World (1)
AssetBundle (25)
Mecanim (2)
Plugins (70)
Trouble Shooting (68)
Encrypt (7)
LightMap (4)
Shadow (4)
Editor (8)
Crash Report (3)
Utility (9)
UnityVS (2)
Facebook SDK (2)
iTween (3)
Font (11)
Ad (14)
Photon (2)
IAP (1)
Google (8)
Android (45)
iOS (41)
Programming (475)
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
05-07 02:43

출처: http://beatup.springnote.com/pages/3277191


BPM : beat per min 의 준말.  즉 분당 비트수로써 1분당 1/4박자의 갯수이다.

- 1분당 BPM별 비트 갯수

 BPM1/4 박자1/8박자 1/16박자 1/32박자 
 60 BPM 60 개 120 개 240 개 480 개
 100 BPM 100 개 200 개 400 개 800 개
 130 BPM 130 개 260 개 520 개 1040 개
 155 BPM 155 개 310 개 620 개 1240 개


즉, 우리가 만들 게임은 1/32박자 (이하 32비트) 게임이므로
155bpm시 1분당 최대 1240개의 노트가 들어간다.



이제 노트 하나당 간격을 알아보도록 하자.

60bpm에서 4비트는 1초마다 1비트가 올라가므로 최대 60개가 나온다.
그럼 1/8박자는 0.5초마다, 16박자는 0.25초마다, 32박자는 0.125초마다 1비트가 오른다.

130bpm의 32비트는 최대 1040개이므로 비트 하나당 간격을 알아보자.
소수점자리까지 사용하므로 총 8자리까지 쓰고 이하는 반올림을 기준으로 한다.

130 / 60 = 2.16666667
0.125 / 2.1666 = 0.05769230

 


노트는 0.05869230초마다 나오며 이 값이 맞는지 최대 비트인 1040개와 계산을 해보자

 0.05769230 * 1040 = 59.999992


얼추 60이 맞는것을 알수 있다.
더 낮은 자리까지 계산을 하면 정확해지며 이게 정확하지 않다면 음악이 재생시간이
길어질수록 비트는 조금씩 밀리거나 당겨지는 현상이 있을수가 있으므로 주의하기 바란다.


이 문제를 해결하려면 10초마다 실행하는 타이머를 주어 다음 10초간의 비트의 위치를
부분적으로 계산하면 될듯싶다.

60bpm시 부분 계산 방식

 플레이시간읽는 비트 
 0:00 0 - 80 
 0:10 80 - 160
 0:20 160 - 240
 0:30 240 - 320
 0:40 320 - 400
 0:50 400 - 480



화살표(노트) 이동 속도의 구현
60bpm은 매우 느린 속도이다.
120bpm은 60bpm의 2배의 속도이다.
180bpm은 60bpm의 3배의 속도이다. 

 bpm 픽셀당이동속도 
 1 bpm 1 초
 60 bpm 0.00166667 초
 120 bpm 0.00083333 초
 180 bpm 0.00055556 초


픽셀은 구현이 어떤식으로 되는지 모르기에 예를 든것이다.
구현 방법에 따라 적절히 하도록 바람.




 



여기까지 bpm 계산 방법을 알아 보았다.
이제 배속의 구현을 알아보도록 하자.

먼저 bpm 공식에 의거하여 노트는 기본적인 이동속도를 가진다.
이것은 1배속이 된다.

60 bpm이 0.00166667 초에 1픽셀을 이동하는데
만약 2배속일경우엔 0.00083333 초에 1픽셀을 이동한다.

그러나 배속은 비트에 대해 절대 영향을 끼치지 않으며 단순히 이동속도만을 제어한다.



[출처] http://smilejsu.tistory.com/380

반응형
Posted by blueasa
, |

유니티 재팬의 keijiro 님이 공개한 텍스쳐 압축 플러그인입니다. 
내용으로 보아서 픽셀당 12bits정도의 메모리를 확보할수 있다고 합니다.

사용자 삽입 이미지

압축을 원하는 이미지 파일 이름 확장자 이전에 CP를 붙이면 ChromaPackProcessor에서 자동적으로 아래와 같이 Alpha8 이미지로 바꾸어주는 것을 볼수있습니다.

사용자 삽입 이미지

사용자 삽입 이미지

실제 바이너리를 프로파일링해본건 아니지만 샘플 이미지 기준 
원본 텍스쳐 : 256 256 ARGB 32 bit = 256.0KB
압축된 텍스쳐 : 384 256 Alpha 8 = 96.0KB

그리고 크게 눈에 띄지는 않지만 아래의 이미지를 보시면 머리카락 부분에 계단지는 현상이 나타나기도 합니다. (상 : 오리지날 텍스쳐 하 : ChromaPack이 적용된 텍스쳐)

사용자 삽입 이미지

사실 크게 눈에 띄지않고 용량 대비 좋은 퀄리티를 내는 건 사실이기 때문에 true color 텍스쳐를 적용하길 원하시는 분들은 한번쯤 적용해봐도 괜찮은 플러그인인것같습니다.

Git hub : https://github.com/keijiro/ChromaPack




[출처] http://lancekun.com/tc/196

반응형
Posted by blueasa
, |

손실 텍스처 압축 플러그인



* 이미지의 1픽셀당 12비트 메모리 절약

* 기존 유니티 16bit rgba 비해 절반 가량 절약

* ChromaPack 전용 쉐이더 사용


https://github.com/keijiro/ChromaPack


결론

용량 대비 품질이 좋음

텍스쳐 크기 변화에 따른 UV 문제는 없음

전용쉐이더를 써야하는 불편함

품질 손실을 감안 한다면 ETC2 4bits / ETC2 8bits 선택은 여전히 유효

품질 때문에 RGBA16bit/RGB 24bit 를 사용해야한다면 Chromapack 유효

(간혹, 알파 빗금이 1픽셀 보이는 문제가 있음. 쉐이더에서 좌표 수정해서 사용하심)



[출처]

http://3dmesh.tistory.com/entry/%EC%9C%A0%EB%8B%88%ED%8B%B0-ChromaPack-%ED%85%8D%EC%8A%A4%EC%B2%98-%EC%95%95%EC%B6%95

반응형
Posted by blueasa
, |



디더링 방식의 변화로 16비트 이미지 변화 비교


 * 스크립트를 적용하여 디더링 방식을 바꾸는 형태

 * 적용하기 쉬움

 * 모든 이미지가 위처럼 좋아지는 것은 아님 (점박이 노이즈 압박;;)

 * 그라데이션 표현을 살리고 싶을 때 좋을 듯

 * 귀찮더라도 Chromapack 사용한다면 패스~ (용량과 품질이 chromapack 압도)


https://github.com/keijiro/unity-dither4444



[출처]

http://3dmesh.tistory.com/entry/%EA%B0%9C%EC%84%A0%EB%90%9C-%EB%94%94%EB%8D%94%EB%A7%81-%EB%B0%A9%EC%8B%9D-%EC%86%8C%EA%B0%9C-16%EB%B9%84%ED%8A%B8-%ED%85%8D%EC%8A%A4%EC%B3%90-dither4444

반응형
Posted by blueasa
, |

Unity Job Process

Unity3D/Tips / 2016. 6. 27. 23:38

Window > Lighting > Lightmaps > Uncheck Auto.



[출처] http://answers.unity3d.com/questions/945639/a-unity-job-process-is-taking-up-95-of-my-physical.html

반응형
Posted by blueasa
, |

Edit -> Project Settings -> Player 들어가서 


Resolution and Presentation 에서 

Display Resolution dialog 에서 

[Disabled] = 실행시 설정창 비활성화 
[Enabled] = 실행시 설정창 활성화 
[Hidden By Default] = 평소에는 비활성화 Shift 누르면서 프로그램 실행시키면 설정창 활성화 입니다. 

참고 
http://openwiki.kr/unity/class-playersettings




반응형
Posted by blueasa
, |

Android 나 PC 의 유니티에서 WWW 를 통해 파일을 받을 경우 IOS 는 해당 컨텐츠 헤더에 있는 값으로 자동으로 캐싱을 진행해 준다.

너무나 완벽한 OS 라서 문제가 생긴다..


아래 두가지 경우의 파일이 있다.



< Cache-Control 이 설정되어 있는 경우 >



< Cache-Control 이 없는 경우 >



Cache-Control 이 있는경우 IOS 에서는 해당 파일 캐싱을 진짜로 구현해 준다. ( 원래 이게 당연한 거지만.. )

따라서 저 만료 날자가 되기 전에 다시 같은 주소로 요청을 하면 새로 받아오지 않고 이전 캐싱된 데이터를 준다.


이 경우 가장 간단하게 해결하는 방법은 주소뒤에 의미없는 값을 추가하여 캐싱되지 않는 것처럼 꾸미는 것이다.

WWW( "http://www.naver.com/file.json?t=213948712" );

그러나 이 경우 클라이언트나 CDN 등에 쓸데없는 캐싱이 생길 수 있으며, 깔끔하지 않다.


가능한 Request 에서 요청 헤더에 다음과 같이 캐싱을 하지 않겠다고 추가하는것이 좋다.

WWWForm form = new WWWForm();

form.AddField( "Cache-Control", "no-cache" );




출처 : http://flystone.tistory.com/195

반응형
Posted by blueasa
, |

유니티 5.3.1 f1 로 버전업 했더니, NGUI 에서 범상치 않은 워닝을 내뱉었다.


1
2
3
Assets/NGUI/Examples/Scripts/Other/LoadLevelOnClick.cs(15,37): 
warning CS0618: `UnityEngine.Application.LoadLevel(string)' is obsolete: 
`Use SceneManager.LoadScene'

cs



Application.LoadLevel 로 씬 이동 하던 것을 SceneManager.LoadScene 으로 사용하란다.


그래서 유니티의 바람대로 SceneManager.LoadScene 으로 고쳐썼더니 네임스페이스가 없다고 한다....


검색해보니 UnityEngine.SceneManagement 라는 네임 스페이스가 추가된 듯.. 



1
using UnityEngine.SceneManagement;
cs


위와 같이 네임스페이스를 추가하니 정상적으로 작동한다.




알고보니 유니티 5.3에서 멀티 씬 편집(Multi-Scene Editing) 을 지원한다고 한다.


아래와 같이 프로젝트 뷰 에서 오른쪽 클릭을 한 후, Open Scene Additive 를 클릭하면...



▼ 이렇게 하이라키 뷰에 여러 씬이 열린다.





또한 SceneManager 추가되었고, 덕분에 자주쓰는 메소드들도 거의 다 구식이 되어버렸다.


변경점은 다음과 같다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// old
Application.LoadLevel(0);                                       // 로드. 
Application.LoadLevel("SceneName");
AsyncOperation ao = Application.LoadLevelAsync(0);              // 로드. (비동기)
AsyncOperation ao = Application.LoadLevelAsync("SceneName");
Application.LoadLevelAdditive(0);                               // 씬 병합 추가. 
Application.LoadLevelAdditive("SceneName");
Application.LoadLevelAdditiveAsync(0);                          // 씬 병합 추가. (비동기)
Application.LoadLevelAdditiveAsync("SceneName");
Application.UnloadLevel(0);                                     // 언로드. 
Application.UnloadLevel("SceneName");
Application.levelCount;                                // BuildSetting 에 등록 된 씬 개수. 
Application.loadedLevel;                                        // 현재 씬 인덱스. 
Application.loadedLevelName;                                    // 현재 씬 이름. 
 
// 5.3
SceneManager.LoadScene(0);                                      // 로드. 
SceneManager.LoadScene("SceneName");
AsyncOperation ao = SceneManager.LoadSceneAsync(0);             // 로드. (비동기)
AsyncOperation ao = SceneManager.LoadSceneAsync("SceneName");
SceneManager.LoadScene(0, LoadSceneMode.Additive);              // 씬 병합 추가. 
SceneManager.LoadScene("SceneName", LoadSceneMode.Additive);
SceneManager.LoadSceneAsync(0, LoadSceneMode.Additive);         // 씬 병합 추가. (비동기)
SceneManager.LoadSceneAsync("SceneName", LoadSceneMode.Additive);
SceneManager.UnloadScene(0);                                    // 언로드. 
SceneManager.UnloadScene("SceneName");
SceneManager.sceneCount;                                        // 현재 로드 된 씬 개수. 
SceneManager.sceneCountInBuildSettings;                // BuildSetting 에 등록 된 씬 개수. 
SceneManager.GetActiveScene().buildIndex;                       // 현재 씬 인덱스. 
SceneManager.GetActiveScene().name;                             // 현재 씬 이름. 
 
// 씬 정보 조회. 
Scene activeScene = SceneManager.GetActiveScene();
Scene scene1 = SceneManager.GetSceneAt(0);
Scene scene2 = SceneManager.GetSceneByName("SceneName");
Scene scene3 = SceneManager.GetSceneByPath("Assets/SceneName.unity");
Scene[] loadedScenes = SceneManager.GetAllScenes();
 
// Scene 구조체. 
int buildIndex;
string name;
string path;
bool isLoaded;
bool isDirty;       // 씬을 변경(수정)했는지 여부. 
int rootCount;      // 씬의 Root에 있는 GameObject 개수. 
bool IsValid();     // 유효한 씬인지 여부. 
 
// 기타. 
Scene scene = gameObject.scene;                 // 게임오브젝트가 속해있는 씬을 가져오기. 
GameObject go = new GameObject("New Object");   // 게임오브젝트를 생성하면 현재 씬에 추가 됨. 
SceneManager.MoveGameObjectToScene(go, scene);      // 게임오브젝트를 다른 씬으로 이동. 
SceneManager.MergeScenes(sourceScene, destinationScene);    // 씬을 병합. 
 
// SceneManager.Get~() 으로 가져올 수 있는 것은 로드가 끝난 씬만 가능. 
Scene scene = SceneManager.GetSceneByName("SceneName");
bool isValid = scene.IsValid();     // false 가 리턴 됨.
cs



정리하다보니 꽤 많네;;;


아, 그리고 DontDestroyOnLoad 메소드 비스므리 한 것은 아예 없었는데,


Tips 를 참조해 보면, DontDestroyOnLoad 의 사용은 피하는 것이 좋고, Manager 씬을 만들어서 병합하는 것이 좋다고 한다.


앞으로 개발 시 참고해야 할 사항인 것 같다.



PS. Unity 5.3 에서는 과금 플러그인을 이용할 필요가 없을 수도 있겠다.


Unity Service Tab 에서 여러가지를(Unity Ads, Analytics, Cloud Build, In-App Purchasing, Multiplayer) 지원함..






출처 : http://worksp.tistory.com/10

반응형
Posted by blueasa
, |

[파일]


Albatross-Programming-Unity-Unity로 다수의 인원이 개발할 때 알아두면 좋은 9가지.pdf


반응형
Posted by blueasa
, |

Unity에서 장치의 고유한 식별 번호를 얻고 싶은데...

아이폰으로는 테스트를 못해 봤습니다만... 잘 되지 않을까 싶네요.

안드로이드에서 장치의 식별자로 쓸만한 것이 3개 있는데

  1. Settings.Secure 의 ANDROID_ID
  2. WiFi의 MAC 주소
  3. 전화 모듈의 식별자

입니다.
아래 코드에서는 위 순서대로 가져오기를 시도해서 잘 가져오는 것을 반환하게 했습니다.

당연히... 별다른 이상한 오류 상황이 아니면 ANDROID_ID를 가져 오겠지요?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
public string GetDeviceID ()
{
    if (Application.platform == RuntimePlatform.Android)
    {
        try
        {
            using (AndroidJavaObject activity = new AndroidJavaClass ("com.unity3d.player.UnityPlayer").GetStatic<AndroidJavaObject> ("currentActivity"))
            {
                // ANDROID_ID
                try
                {
                    using (AndroidJavaObject resolver = activity.Call<AndroidJavaObject> ("getContentResolver"))
                    {
                        using (AndroidJavaObject settingsSecure = new AndroidJavaObject ("android.provider.Settings.Secure"))
                        {
                            string deviceID = settingsSecure.CallStatic<string> ("getString", resolver, settingsSecure.GetStatic<string> ("ANDROID_ID"));
                            if (!string.IsNullOrEmpty (deviceID))
                            {
                                return deviceID;
                            }
                        }
                    }
                }
                catch (System.Exception)
                {
                }
 
                // WiFi MAC
                try
                {
                    using (AndroidJavaObject wifiManager = activity.Call<AndroidJavaObject> ("getSystemService", activity.GetStatic<string>("WIFI_SERVICE")))
                    {
                        string macAddr = wifiManager.Call<AndroidJavaObject> ("getConnectionInfo").Call<string> ("getMacAddress");
                        if (!string.IsNullOrEmpty (macAddr))
                        {
                            return macAddr;
                        }
                    }
                }
                catch (System.Exception)
                {
                }
                 
                // IMEI/MEID code
                try
                {
                    using (AndroidJavaObject telephonyManager = activity.Call<AndroidJavaObject> ("getSystemService", activity.GetStatic<string>("TELEPHONY_SERVICE")))
                    {
                        string imeiCode = telephonyManager.Call<string> ("getDeviceId");
                        if (!string.IsNullOrEmpty (imeiCode))
                        {
                            return imeiCode;
                        }
                    }
                }
                catch (System.Exception)
                {
                }
 
            }
        }
        catch (System.Exception)
        {
        }
    }
    else
    {
        // 이 방법은 안드로이드에서는 안된다. - Unity 4.3.4f1
        try
        {
            var nics = NetworkInterface.GetAllNetworkInterfaces ();
            if (nics.Length > 0)
            {
                return nics[0].GetPhysicalAddress ().ToString ();
            }
        }
        catch (System.Exception)
        {
        }
    }
    return "";
}

WiFi MAC 주소를 가져오려면 ACCESS_WIFI_STATE 권한이 필요합니다.

IMEI code 를 가져오려면 READ_PHONE_STATE 권한이 필요합니다.

그럼 이 권한은 어떻게 설정할까요?
만약 프로젝트 경로 아래에
Assets/Plugins/Android/AndroidManifest.xml 파일이 있다면 해당 파일을 수정하시면 됩니다.
이 파일이 없으시다면
(Unity 설치 경로)/Editor/Data/PlaybackEngines 폴더 밑에 있는
androidplayer 또는 androiddevelopmentplayer 폴더에 있는 파일을 복사해서 사용하시면 됩니다.

아래 내용을 추가하시면 되겠죠?

1
2
3
4
5
6
7
8
<uses-permission
    android:name="android.permission.READ_PHONE_STATE"
    >
</uses-permission>
<uses-permission
    android:name="android.permission.ACCESS_WIFI_STATE"
    >
</uses-permission>



출처 : http://bspfp.pe.kr/536

반응형
Posted by blueasa
, |