블로그 이미지
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 07:22

[추가]

아래 방법은 Mono 전용으로IL2CPP에서는 런타임 오류가 난다.

IL2CPP 빌드로 바껴서 현재는 사용 못할 것 같다.

-----------------------------------------------------------------

 

System.Diagnostics.ProcessThreadCollection pt = System.Diagnostics.Process.GetCurrentProcess().Threads;
foreach (System.Diagnostics.ProcessThread p in pt)
{
    p.Dispose();
}
System.Diagnostics.Process.GetCurrentProcess().Kill();

 

[링크] https://chopchops.tistory.com/17

 

[Unity] 게임 재실행시 튕기는 오류

게임을 재시작했을때 게임이 갑자기 꺼지는 기이한 현상 해결 1 ) 게임이 종료될때 모든 Thread가 종료되지 않아서 발생하는 문제라는 의견 -> 게임종료시 모든 스레드 종료 1 2 3 4 5 6 7 8 9 10 11 privat

chopchops.tistory.com

 

[참조1] https://202psj.tistory.com/1341

 

[Unity] 유니티 종료,Quit, Exit 관련

================================= ================================= ================================= 출처: https://hyunity3d.tistory.com/386 using UnityEngine; using System.Collections; public class CsGameManager : MonoBehaviour { // Use this for initia

202psj.tistory.com

[참조2] https://blog.naver.com/captainj/221103098214

 

Application.Quit으로 앱종료시 오류 메시지가 뜰때

종종 유니티에서 Application.Quit() 함수로 앱을 종료하는 경우, 앱은 정상적으로 종료는 되지만 오류 ...

blog.naver.com

 

반응형
Posted by blueasa
, |

Unity 2021.3.32f1

----

 

[추가3] 2024-03-27

Play Asset Delivery v1.9.0(2024-03-27 기준 최신)이 업데이트 됐다.

1.9.0은 최소 Unity 버전이 2017.4로 표기돼있다.(버전별 문제를 해결한건가..?)

 

[추가2]

AssetDelivery 1.7.0으로 iOS 빌드 하면서 ./GooglePlayPlugins/com.google.play.assetdelivery/Samples 폴더 관련 소스에서 에러가 나서 삭제 함.

 

[추가]

aab파일 150mb 초과해서 구글스토어 올리려고 알아보고

아래 [링크]의 내용대로 진행해서  Play Asset Delivery v1.8.2(2023-04-25 기준 최신)를 설치해서 빌드해보니,

빌드는 잘 되지만 실행하면 크래시 나면서 앱이 죽는다.

버전 정보를 보면 Play Asset Delivery v1.8.0 이상부터는 Unity 최소 버전이 2023.1.0 (베타)이다.

(1.8.0이상은 2023.1.0 이상이라고 돼있지만 2022.2.18f1에서 정상동작 하는걸 확인했다.)

 

[참조] https://github.com/google/play-unity-plugins/issues/187

 

Crash at Android 12 · Issue #187 · google/play-unity-plugins

Hello I'm now experiencing crash on android devices with Android 12 only. thread.cc:2372] Throwing new exception 'No interface method getPackStates(Ljava/util/List;)Lcom/google/android/play/core/ta...

github.com

 

크래시 내용을 찾아보니 위[참조]와 같은 내용이 있다.

Firebase와 PAD(Play Asset Delevery)와 호환성 문제가 있는 것 같다.

 

참조 링크의 내용대로면 현재 Play Asset Delivery v1.8.x 버전은 제대로 안되고, Play Asset Delivery v1.7.0을 사용해서 성공했다고 한다.

 

[Github:Play Unity Plugins v1.7.0] https://github.com/google/play-unity-plugins/releases/tag/v1.7.0

 

Release v1.7.0 · google/play-unity-plugins

com.google.play.integrity (v1.0.0) New Features Initial release Unchanged Packages com.google.android.appbundle (v1.7.0) com.google.play.appupdate (v1.7.0) com.google.play.assetdelivery (v1.7.0)...

github.com

[Google Play:Play Asset Delivery] https://developers.google.com/unity/archive?hl=ko#play_asset_delivery

 

Unity용 Google 패키지 다운로드  |  Google Developers

이 페이지는 Cloud Translation API를 통해 번역되었습니다. Switch to English Unity용 Google 패키지 다운로드 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 이 보관 파

developers.google.com

 

위 Play Asset Delivery 링크에서 1.7.0버전 UnityPackage를 다운로드해서 Import하고,

정상 빌드 되는 것을 확인했다.

 

[결론]

Unity 2021 이하 Play Asset Delivery 1.7.0을 사용하고,

Unity 2022 이상은 Play Asset Delivery 1.8.2(2023-05-12 기준 최신)을 사용하자.

(Unity 2021에서도 gradle 4.2.0을 적용하면 Play Asset Delivery 1.8.2 이상을 사용할 수 있다.

  2024-03-27 기준 1.9.0이 나와있으니 1.9.0을 사용하자.)

 

 

--------------------------------------------------------------------------------------------------------------------------------------------

 

[링크] https://devgod.tistory.com/49

 

[Unity] Unity Play Asset Delivery 앱 빌드, Unity 대용량 앱 빌드

2021년 8월부터 Google Play Store에선 obb를 이용한 대용량 앱 업로드가 사라지고, 무조건 Play Asset Delivery(PAD)를 통해 앱을 업로드 해야합니다. 제발 정책좀 그만 변경했으면 좋겠습니다. 먼저 제가 궁

devgod.tistory.com

반응형
Posted by blueasa
, |

Android 13에서 Runtime에 android.permission.POST_NOTIFICATIONS Permission 요청하기.

----

 

1. Android Target API 33으로 셋팅

 

2. AndroidManifest.xml에 POST_NOTIFICATIONS Permission 추가

<manifest ...>
    <application ...>
        ...
    </application>
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
</manifest>

 

3. 권한 요청 원하는 시점에 아래 함수 호출(함수 호출하면 Android 13이상 폰에서는 알림 권한 허용 요청 팝업이 뜸)

void CheckPermission_PostNotifications_Android13()
{
    // 디바이스의 안드로이드 api level 얻기
    // ex) Prints "Android OS API-33" on Android 13.0
    // https://docs.unity3d.com/ScriptReference/SystemInfo-operatingSystem.html
    string androidInfo = SystemInfo.operatingSystem;
    Debug.Log("androidInfo: " + androidInfo);
    
    int apiLevel = int.Parse(androidInfo.Substring(androidInfo.IndexOf("-") + 1, 3), System.Globalization.CultureInfo.InvariantCulture);
    Debug.Log("apiLevel: " + apiLevel);

    // 디바이스의 api level이 33 이상이라면 퍼미션 요청
    if (33 <= apiLevel 
        && !UnityEngine.Android.Permission.HasUserAuthorizedPermission("android.permission.POST_NOTIFICATIONS"))
    {
        UnityEngine.Android.Permission.RequestUserPermission("android.permission.POST_NOTIFICATIONS");
    }
}

 

 

-----------------------------------------------------------------------------------------

[참고]

안드로이드 알림은 api level 26 과 33 에서 변경점이 있다. 내 앱이 대상으로 삼은 Sdk Version 범위에 이 버전이 포함되어 있다면 버전에 따라 분기 처리를 해주는 편이 좋다.
API level 26 (Android 8.0 Oreo) 이상 변경점
API level 33 (Android 13 Tiramisu) 이상 변경점

public void InitializeAndroidLocalPush()
{
	// 디바이스의 안드로이드 api level 얻기
	string androidInfo = SystemInfo.operatingSystem;
	Debug.Log("androidInfo: " + androidInfo);
	apiLevel = int.Parse(androidInfo.Substring(androidInfo.IndexOf("-") + 1, 2));
	Debug.Log("apiLevel: " + apiLevel);

	// 디바이스의 api level이 33 이상이라면 퍼미션 요청
	if (apiLevel >= 33 &&
		!Permission.HasUserAuthorizedPermission("android.permission.POST_NOTIFICATIONS"))
	{
		Permission.RequestUserPermission("android.permission.POST_NOTIFICATIONS");
	}

	// 디바이스의 api level이 26 이상이라면 알림 채널 설정
	if (apiLevel >= 26)
	{
		var channel = new AndroidNotificationChannel()
		{
			Id = CHANNEL_ID,
			Name = "pubSdk",
			Importance = Importance.High,
			Description = "for test",
		};
		AndroidNotificationCenter.RegisterNotificationChannel(channel);
	}
}

api level 얻기 코드 출처

 

 

[참고 내용 출처]

https://velog.io/@maratangsoft/%EC%9C%A0%EB%8B%88%ED%8B%B0-%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%95%B1%EC%97%90%EC%84%9C-FCM-%EC%84%9C%EB%B2%84-%ED%91%B8%EC%8B%9C-%EB%B0%9B%EA%B8%B0

 

유니티 안드로이드 앱에서 FCM 서버 푸시 받기

유니티 모바일 앱 개발시 안드로이드 앱은 Firebase Cloud Messaging(이하 FCM) 서비스, iOS 앱은 Apple Push Notification 서비스를 이용해서 (FCM으로도 가능) 푸시를 수신할 수 있다. 그 중 FCM을 이용한 안드로

velog.io

 

[참고]

https://android-developer.tistory.com/entry/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C13%EC%97%90%EC%84%9C-Notification-%ED%97%88%EA%B0%80-%EB%B0%9B%EA%B8%B0-%EB%B0%A9%EB%B2%95-%EB%B0%8F-%EB%B3%80%EA%B2%BD%EC%A0%90

 

안드로이드13에서 Notification 허가 받기 방법 및 변경점

안드로이드13에서 Notification에 대해 바뀐점 POST_NOTIFICATIONS (Notification Permission) 은 Target SDK API 33 이상부터 추가 가능 Target SDK API 32 이하의 앱이 Android 13 디바이스에 설치되면 Notification Channel을 등록

android-developer.tistory.com

반응형
Posted by blueasa
, |

어쩌다보니 유니티 어필리에이트 참여하게 돼서 가입하고 보니 레퍼럴 링크 개념인 것 같다.

아래 링크들로 구매 or 구독하면 나에게 일정의 수수료를 주는 듯..

 

손해볼 건 없으니 참여했는데.. 내가 내 레퍼럴 링크로 사도 되나..?? 라는 궁금증이 생김.

 

 

Promote Unity Subscription Products:
To promote Unity subscription products, use these links:

Unity Plus:
https://prf.hn/click/camref:1011lvKwd/destination:https://store.unity.com/products/unity-plus

 

Easy 2D, 3D, VR, & AR software for cross-platform development of games and mobile apps. - Unity Store

Have a 2D, 3D, VR, or AR project that needs cross-platform functionality? We can help. Take a look at the easy-to-use Unity Plus real-time dev platform!

store.unity.com

Unity Pro:
https://prf.hn/click/camref:1011lvKwd/destination:https://store.unity.com/products/unity-pro

 

Unity Pro

The complete solutions for professionals to create and operate.

unity.com

Unity Learn Premium:
https://prf.hn/click/camref:1011lvKwd/destination:https://unity.com/learn-premium

 

Unity Learn

Advance your Unity skills with live sessions and over 750 hours of on-demand learning content designed for creators at every skill level.

unity.com

Unity Partner Courses:
https://prf.hn/click/camref:1011lvKwd/destination:https://unity.com/learn/partner-courses

 

Learn

Online and in-person Unity courses and training in 2D, 3D, AR, and VR development.

unity.com

 

 

반응형
Posted by blueasa
, |

성능이 한정된 기기에서 실행되는 애플리케이션의 충돌을 방지하려면 메모리 최적화가 반드시 필요합니다. 여러 기기를 대상으로 출시하려는 경우, 각 플랫폼에서 최고의 성능을 끌어내기 위해 메모리 사용량을 조정해야 할 수도 있습니다.

 
메모리에 영향을 끼치는 요소는 매우 다양하지만, 그 중에서도 에셋을 중심으로 메모리를 효율적으로 관리할 수 있도록 지원하는 Unity 툴과 최적화할 수 있는 방안에 대해 소개합니다.

 
제공: 오지현 에반젤리스트, 2023년 2월

빌트인 프로파일러 모듈로, 애플리케이션이 메모리를 사용하는 위치에 대한 기본 정보를 제공합니다.
 
메모리 프로파일러 모듈은 애플리케이션에 할당된 전체 메모리를 나타내는 카운터를 시각화합니다. 메모리 모듈을 사용하여 로드된 오브젝트의 수와 카테고리 별로 해당 오브젝트가 차지하는 메모리 양과 같은 정보를 볼 수 있습니다.

2. Memory Profiler 1.0 (필수)
 

Unity 애플리케이션 및 Unity 에디터의 메모리 사용량을 검사하는 데 사용할 수 있는 도구로, 어떤 에셋이 메모리를 사용하고 있는지 애플리케이션의 메모리 할당에 대한 정보를 자세하게 확인할 수 있습니다. 특히 Unity 에디터에 메모리 프로파일러 창을 추가하여 메모리 스냅샷을 캡처, 검사 및 비교할 수 있습니다.

Unity 패키지 관리자를 통해 다운로드하고 메모리를 최적화할 수 있습니다.

▶ Memory Profiler 1.0.0 관련 블로그 아티클 보기


3. Unity Addressables
 

Unity Addressables는 복잡한 라이브 콘텐츠를 전달해야 하는 대규모 제작팀의 요구사항을 보다 효과적으로 지원하기 위한 Unity 에디터 및 런타임 에셋 관리 시스템입니다.
 
Unity Addressables을 활용해 불필요한 에셋의 로드를 방지하는 약한 참조를 도입하여 런타임 메모리를 개선할 수 있습니다.

 

 어드레서블 에셋 시스템으로 메모리 최적화하기 블로그 아티클 보기


4. Audio / Sound 설정
[Force to Mono]
오디오의 스테레오 정보를 없애고 Mono로 만드는 만큼 용량이 줄어듭니다. 특히 모바일에서는 스테레오로 설정할 일이 드물어 추천 드립니다.
 
[읽기 방식(Load type)]
사운드가 어떤 성격인지에 따라 로드 타입과 포맷을 설정하는 것을 추천 드립니다.




[권장 압축 형식(Compression Format)]
● Unity는 하드웨어 가속이 아닌 소프트웨어로 오디오 디코딩을 처리하고 있어 안드로이드/iOS 구분 없이 사용할 수 있는 Vorbis 타입을 권장합니다.
● 매우 짧은 클립의 경우 ADPCM 포맷을 권장 드립니다.
 
※ 오디오는 음소거(Mute) 상태여도 메모리에는 존재하고 있어 선택 옵션이 아니라면, 지우는 것을 권장합니다.

5. Mesh

Mesh 데이터 관리를 통해 메모리를 최적화할 수 있습니다.



Read / Write Enabled 옵션은 CPU와 GPU메모리 양측에 존재하여 옵션을 OFF하는 것이 좋습니다.




6. 셰이더 배리언트
하나의 셰이더라도 여러 조건에 따라 수많은 바이너리로 파생되어 빌드 시간, 패키지 사이즈는 물론 메모리까지 영향을 줄 수 있습니다.
 
셰이더 배리언트의 개념부터 이슈 발생 원인, 최적화하는 방법으로 메모리를 최적화해 보세요.



7. TextMesh Pro
시각적 품질을 크게 개선할 뿐만 아니라 텍스트 스타일 지정 및 텍스처링 부문에서 사용자에게 뛰어난 유연성을 선사하는 TextMesh Pro
 
특히 한글은 초성+중성+종성 조합 방식으로 11,000자가 넘는 글자를 텍스트 아틀라스와 텍스처로 제작한다면 메모리가 커질 수 밖에 없습니다. 메모리 최적화를 위해 사용 시 여러 테스트를 통해 제작하는 것을 권장합니다.


8. 메모리에 영향을 주는 텍스처

대부분의 게임에서는 텍스처로 인한 메모리 이슈가 발생합니다.
 
[Baked Lighting]
Lightmap, Light Probe, Reflection Probe와 같은 조명 설정으로도 메모리 문제가 발생할 수 있습니다. 메모리에 영향을 주는 요소로 적절하게 사용하는 것이 좋습니다.
 
● Lightmap은 배경, 건물과 같은 스태틱 오브젝트에 라이트 결과를 미리 적용하여 저장하기 때문에 텍스처 메모리 이슈가 발생할 수 있습니다.
● Reflection Probe는 6면의 큐브로 만들어진 텍스처로, 텍스처 6개가 생성됩니다. 그에 따라 메모리 이슈 발생 가능성이 큽니다.
 
가능한 시각 효과 대비 사이즈를 작게 제작하고, 적절한 압축 형식을 사용하는 것을 권장합니다.

[텍스처 압축]
 

텍스처 에셋의 화질이 높을수록 픽셀당 비트가 더 높으며, 그에 따라 빌드 크기, 로드 시간, 런타임 메모리 사용량이 늘어납니다.

기기에서 지원하지 않는 포맷 사용 시 압축이 풀리기 때문에 기기별 지원하는 텍스처 포맷을 사용하는 것이 좋습니다. 모바일에서는 ASTC 형식을 사용하는 것을 권장합니다. (타겟 디바이스에 따라 상이)



[Mipmap]

Mipmap(밉맵)은 3D 그래픽스에서 텍스처를 적용하는 과정에서 렌더링 속도를 가속화하기 위해 축소한 비트맵 이미지의 집합으로, 카메라로부터의 거리에 따라 달라질 수 있습니다.


Mipmap 사용 시 원래 텍스처보다 33.3333%의 메모리가 증가합니다. 2D 맵에서는 원근법이 필요하지 않기 때문에 Off를 하는 것이 좋습니다.

[Scene Loading]
Scene 전환 시 기존 Scene A 의 데이터가 남아있는 상황에서 추가적으로 Scene B의 데이터를 로드할 경우 순간적으로 메모리에 과부하가 발생할 수 있습니다.



9. 메모리 최적화에 도움이 되는 Unity 가이드

 

[출처]

https://unitysquare.co.kr/growwith/unityblog/webinarView?id=348&utm_source=facebook-page&utm_medium=social&utm_campaign=korea_unitytipsblog-memory

 

Unity Square

성능이 한정된 기기에서 실행되는 애플리케이션의 충돌을 방지하려면 메모리 최적화가 반드시

unitysquare.co.kr

 

 

반응형
Posted by blueasa
, |

Unity 2021.3.22f1

----

 

Unity Editor에서 Memory Profiler를  보다보니 아래와 같이 System.Byte[] 라는게 있는데 204MB라니..

생각보다 용량을 많이 차지한다.

그래서 이래저래 찾아봤는데 나온 내용은 Unity Editor에서 사용하는 건지, 버그인지..

아무튼 별다른 문제는 없는 것 같다..(하단 링크 참조)

 

해당 메모리는 없는걸로 생각하고 봐야 될 듯 하다.

 

[참조] https://teratail.com/questions/339976

 

teratail【テラテイル】|ITエンジニア特化型Q&Aサイト

teratail(テラテイル)はプログラミングに特化したQ&Aサイトです。実現したい機能や作業中に発生したエラーについて質問すると、他のエンジニアから回答を得られます。

teratail.com

 

반응형
Posted by blueasa
, |

Unity 2022.3.10f1

NGUI 2022.08.01

----

[추가2] 2023-10-25

NGUI v2023.07.26에서 아래와 같은 업데이트가 올라왔다.

- FIX: NGUI will now change all imported textures to be uncompressed when creating an atlas, matching how it used to work in older versions of Unity.

이 수정 사항 때문에 NGUI Atlas 압축을 유지해주려던 부분이 작동하지 않고 무조건 Uncompressed로 변경되고 있어서 해당 부분인 아래 소스 부분(NGUIEditorTools.cs : line 538)을 주석 처리 했다.

//-------------------------------------------------
//			  NGUI: Next-Gen UI kit
// Copyright © 2011-2023 Tasharen Entertainment Inc
//-------------------------------------------------

using System.Collections.Generic;
using System.Reflection;
using UnityEditor;
using UnityEngine;

/// <summary>
/// Tools for the editor
/// </summary>

static public class NGUIEditorTools
{
    ...
    static public bool MakeTextureReadable (string path, bool force)
    {
        if (string.IsNullOrEmpty(path)) return false;
        var ti = AssetImporter.GetAtPath(path) as TextureImporter;
        if (ti == null) return false;

        var settings = new TextureImporterSettings();
        ti.ReadTextureSettings(settings);

        if (force || !settings.readable || settings.npotScale != TextureImporterNPOTScale.None || ti.textureCompression != TextureImporterCompression.Uncompressed)
        {
            settings.readable = true;

            if (NGUISettings.trueColorAtlas)
            {
                var platform = ti.GetDefaultPlatformTextureSettings();
                platform.format = TextureImporterFormat.RGBA32;
            }

            settings.npotScale = TextureImporterNPOTScale.None;
            
            #region NGUI Atlas 압축 관련 처리 [blueasa / 2023-10-25]
            /// NGUI v2023.07.26 에서 강제로 Uncompressed 하는 소스가 추가됨.
            /// 이 부분 때문에 아틀라스 압축이 유지되지 않고 풀리는 문제가 있어서 주석 처리 함
            /// trueColorAtlas 셋팅 될 때만 Uncompressed 강제 하도록 함
            if (NGUISettings.trueColorAtlas)
            {
                ti.textureCompression = TextureImporterCompression.Uncompressed;
            }
            #endregion
            
            ti.SetTextureSettings(settings);

#if UNITY_5_6
            AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate | ImportAssetOptions.ForceSynchronousImport);
#else
            ti.SaveAndReimport();
#endif
        }
        return true;
    }
    ...
}

 

----

[추가]

아틀라스 압축을 사용하려면 Atlas Maker의 Truecolor를 끄자.

(켜놓으면 압축상태를 무시하고 무조건 Truecolor로 아틀라스를 묶어낸다.)

Truecolor 체크 해제

----

 

[수정] New Atlas 관련 예외처리 추가(2023-04-12)

 

----

게임 최적화를 위해 Andrio/iOS 둘다 설정에서 Texture compression format을 ASTC로 설정하고 사용하고 있다.

NGUI Atlas도 최적화를 위해 Compression을 High Quality로 사용중인데

여기서 문제가 NGUI의 Atlas를 묶을 때는 Compression이 None(비압축)이 아니면 에러가 발생한다.

 

그래서 Atlas 묶을 때는 Compression을 None으로 풀어서 묶은 다음 원래 Compression인 High Quality로 변경하고 있었는데

불편하기도하고 사용하다 실수가 나오기도 해서 이참에 NGUI Atlas Maker를 수정해서 자동으로 되도록 했다.

 

작동 원리는 아래와 같이 간단하다.

(처음 해보는거라 적용 지점이 어딘지 찾는다고 좀 헤멤)

 

  [작동 원리]

----------------------------------------------------

- Atlas가 압축 된 상태면

  1. Compression 별도로 저장

  2. Compression : None으로 변경

  3. Atlas Make(NGUI 원래 소스)

  4. 별도로 저장했던 Compression을 Atlas에 적용해서 원래 압축 상태로 되돌려 줌

- Atlas가 압축 안된 상태(None)면

  1. 원래 소스만 실행(위에서 3.만 실행)

----------------------------------------------------

 

추가된 소스는 NGUI의 UIAtlasMaker.cs - UpdateTexture() 함수에 두 곳 추가 되었다.

소스 위치를 알기 위해 UpdateTexutre() 함수 전체를 올렸고, blueasa를 찾으면 region 정리해 둔 두 곳이 있다.

 

//-------------------------------------------------
//            NGUI: Next-Gen UI kit
// Copyright © 2011-2020 Tasharen Entertainment Inc
//-------------------------------------------------

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

/// <summary>
/// Atlas maker lets you create atlases from a bunch of small textures. It`s an alternative to using the external Texture Packer.
/// </summary>
public class UIAtlasMaker : EditorWindow
{
	....
    
    /// <summary>
    /// Combine all sprites into a single texture and save it to disk.
    /// </summary>
    
    static public bool UpdateTexture (INGUIAtlas atlas, List<SpriteEntry> sprites)
    {
        // Get the texture for the atlas
        var tex = atlasTexture;
        var oldPath = (tex != null) ? AssetDatabase.GetAssetPath(tex.GetInstanceID()) : "";
        var newPath = NGUIEditorTools.GetSaveableTexturePath(atlas as UnityEngine.Object, atlasTexture);
    
        // Clear the read-only flag in texture file attributes
        if (System.IO.File.Exists(newPath))
        {
            System.IO.FileAttributes newPathAttrs = System.IO.File.GetAttributes(newPath);
            newPathAttrs &= ~System.IO.FileAttributes.ReadOnly;
            System.IO.File.SetAttributes(newPath, newPathAttrs);
        }
    
        bool newTexture = (tex == null || oldPath != newPath);
    
        if (newTexture)
        {
            // Create a new texture for the atlas
            tex = new Texture2D(1, 1, TextureFormat.ARGB32, false);
        }
        else
        {
            // Make the atlas readable so we can save it
            tex = NGUIEditorTools.ImportTexture(oldPath, true, false, false);
        }
    
        #region NGUI Atlas 압축 관련 처리 [blueasa / 2023-04-07]
        /// NGUI Atlas가 압축돼 있으면,
        /// 압축 해제한 다음 Atlas 만든 후 원래 압축으로 돌리도록 함
    
        // TextureImporter 가져오기
        string strPath = AssetDatabase.GetAssetPath(tex);
        TextureImporter tiAtlas = AssetImporter.GetAtPath(strPath) as TextureImporter;
        TextureImporterCompression ticTextureCompression_Original = TextureImporterCompression.Uncompressed;
        bool bTextureCompressed = false;
    
        // New Atlas 관련 예외처리(New Atlas는 로직 타지 않도록 수정)
        if (false == newTexture)
        {
            Debug.LogWarningFormat("[Atlas TextureCompression] {0}", tiAtlas.textureCompression);
    
            if (tiAtlas.textureCompression != TextureImporterCompression.Uncompressed)
            {
                // Atlas Texutre 압축 여부
                bTextureCompressed = true;
                // 압축 설정 백업
                ticTextureCompression_Original = tiAtlas.textureCompression;
                // 압축 설정 변경
                tiAtlas.textureCompression = TextureImporterCompression.Uncompressed;
                // 변경 내용 적용
                AssetDatabase.ImportAsset(strPath);
            }
        }
        #endregion
    
        // Pack the sprites into this texture
        if (PackTextures(tex, sprites))
        {
            var bytes = tex.EncodeToPNG();
            System.IO.File.WriteAllBytes(newPath, bytes);
            bytes = null;
        
            // Load the texture we just saved as a Texture2D
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);
            tex = NGUIEditorTools.ImportTexture(newPath, false, true, !premultipliedAlpha);
        
            // Update the atlas texture
            if (newTexture)
            {
                if (tex == null)
                {
                    Debug.LogError("Failed to load the created atlas saved as " + newPath);
                    EditorUtility.ClearProgressBar();
                }
                else
                {
                    var mat = spriteMaterial;
        
                    if (mat == null)
                    {
                        var matPath = newPath.Replace(".png", ".mat");
                        var shader = Shader.Find(NGUISettings.atlasPMA ? "Unlit/Premultiplied Colored" : "Unlit/Transparent Colored");
                        mat = new Material(shader);
	    
                        // Save the material
                        AssetDatabase.CreateAsset(mat, matPath);
                        AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);
        
                        // Load the material so it`s usable
                        mat = AssetDatabase.LoadAssetAtPath<Material>(matPath);
                        spriteMaterial = mat;
                    }
        
                    mat.mainTexture = tex;
                }
        
                ReleaseSprites(sprites);
        
                AssetDatabase.SaveAssets();
                AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);
            }
        
            #region NGUI Atlas 압축 관련 처리 [blueasa / 2023-04-07]
            if (true == bTextureCompressed)
            {
                // 압축 설정 복원
                tiAtlas.textureCompression = ticTextureCompression_Original;
                // 변경 내용 적용
                AssetDatabase.ImportAsset(strPath);
            }
            #endregion
        
            return true;
        }
        else
        {
            if (!newTexture) NGUIEditorTools.ImportTexture(oldPath, false, true, !premultipliedAlpha);
    
            //Debug.LogError("Operation canceled: The selected sprites can`t fit into the atlas.\n" +
            //	"Keep large sprites outside the atlas (use UITexture), and/or use multiple atlases instead.");
    
            EditorUtility.DisplayDialog("Operation Canceled", "The selected sprites can`t fit into the atlas.\n" +
                    "Keep large sprites outside the atlas (use UITexture), and/or use multiple atlases instead", "OK");
            return false;
        }
    }
    
    ....
}

 

 

반응형
Posted by blueasa
, |

Audio Import 시, 원하는 최적화 관련 설정 자동 셋팅하도록 소스 정리 함.

(AudioCompressionFormat은 심플하게 Vobis / Quality 40으로 통일함.)

 

using System.IO;
using UnityEditor;
using UnityEngine;

public class AssetPostprocessor_Audio : AssetPostprocessor
{
    /*
     * 오디오클립 파일 경로
     * Resources - Sound ┬ BGM - MainBGM
     *                   ├ InGame - SFX
     *                   └ SoundEffect ┬ OutGame
     *                                 ├ UI
     *                                 └ Voice
     * Resources_AssetBundles ┬ sound ┬ sound_effect
     *                        │       ├ sound_main_bgm
     *                        │       ├ sound_sub_bgm
     *                        │       └ sound_voice
     *                        ├ sound_scenario
     *                        └ sound_scenario_StreamingAssets
     */
    void OnPreprocessAudio()
    {
        bool bDefaultSettingChanged = false;
        AudioImporter audioImporter = assetImporter as AudioImporter;
        AudioImporterSampleSettings defaultSampleSettings = audioImporter.defaultSampleSettings;
        AudioImporterSampleSettings iosSampleSettings = audioImporter.GetOverrideSampleSettings("iOS");
        bool biOSSettingChanged = false;

        UnityEditor.SerializedObject serializedObject = new UnityEditor.SerializedObject(audioImporter);
        UnityEditor.SerializedProperty normalize = serializedObject.FindProperty("m_Normalize");

        string strPath = audioImporter.assetPath;
        Debug.LogFormat("[audioImporter.assetPath] {0}", strPath);

        // Folder Name
        if (strPath.StartsWith("Assets/Resources/Sound/BGM"))
        {
            audioImporter.forceToMono = true;
            normalize.boolValue = false;
            audioImporter.loadInBackground = true;
            //audioImporter.ambisonic = false;

            defaultSampleSettings.loadType = AudioClipLoadType.Streaming;
            audioImporter.preloadAudioData = false;
            defaultSampleSettings.compressionFormat = AudioCompressionFormat.Vorbis;
            defaultSampleSettings.quality = 0.4f;   // 40
            defaultSampleSettings.sampleRateSetting = AudioSampleRateSetting.OptimizeSampleRate;

            //iosSampleSettings.loadType = AudioClipLoadType.Streaming;
            //iosSampleSettings.compressionFormat = AudioCompressionFormat.MP3;
            //iosSettingChanged = true;

            bDefaultSettingChanged = true;
        }
        else if (strPath.StartsWith("Assets/Resources/Sound/InGame/SFX"))
        {
            audioImporter.forceToMono = true;
            normalize.boolValue = false;
            audioImporter.loadInBackground = false;
            //audioImporter.ambisonic = false;

            defaultSampleSettings.loadType = AudioClipLoadType.DecompressOnLoad;
            audioImporter.preloadAudioData = true;
            defaultSampleSettings.compressionFormat = AudioCompressionFormat.Vorbis;
            defaultSampleSettings.quality = 0.4f;   // 40
            defaultSampleSettings.sampleRateSetting = AudioSampleRateSetting.OptimizeSampleRate;

            bDefaultSettingChanged = true;
        }
        else if (strPath.StartsWith("Assets/Resources/Sound/SoundEffect/OutGame"))
        {
            audioImporter.forceToMono = true;
            normalize.boolValue = false;
            audioImporter.loadInBackground = false;
            //audioImporter.ambisonic = false;

            defaultSampleSettings.loadType = AudioClipLoadType.DecompressOnLoad;
            audioImporter.preloadAudioData = true;
            defaultSampleSettings.compressionFormat = AudioCompressionFormat.Vorbis;
            defaultSampleSettings.quality = 0.4f;   // 40
            defaultSampleSettings.sampleRateSetting = AudioSampleRateSetting.OptimizeSampleRate;

            bDefaultSettingChanged = true;
        }
        else if (strPath.StartsWith("Assets/Resources/Sound/SoundEffect/UI"))
        {
            audioImporter.forceToMono = true;
            normalize.boolValue = false;
            audioImporter.loadInBackground = false;
            //audioImporter.ambisonic = false;

            defaultSampleSettings.loadType = AudioClipLoadType.DecompressOnLoad;
            audioImporter.preloadAudioData = true;
            defaultSampleSettings.compressionFormat = AudioCompressionFormat.Vorbis;
            defaultSampleSettings.quality = 0.4f;   // 40
            defaultSampleSettings.sampleRateSetting = AudioSampleRateSetting.OptimizeSampleRate;

            bDefaultSettingChanged = true;
        }
        else if (strPath.StartsWith("Assets/Resources/Sound/SoundEffect/Voice"))
        {
            audioImporter.forceToMono = true;
            normalize.boolValue = false;
            audioImporter.loadInBackground = false;
            //audioImporter.ambisonic = false;

            defaultSampleSettings.loadType = AudioClipLoadType.CompressedInMemory;
            audioImporter.preloadAudioData = true;
            defaultSampleSettings.compressionFormat = AudioCompressionFormat.Vorbis;
            defaultSampleSettings.quality = 0.4f;   // 40
            defaultSampleSettings.sampleRateSetting = AudioSampleRateSetting.OptimizeSampleRate;

            bDefaultSettingChanged = true;
        }
        else if (strPath.StartsWith("Assets/Resources_AssetBundles/sound/sound_effect"))
        {
            audioImporter.forceToMono = true;
            normalize.boolValue = false;
            audioImporter.loadInBackground = false;
            //audioImporter.ambisonic = false;

            defaultSampleSettings.loadType = AudioClipLoadType.DecompressOnLoad;
            audioImporter.preloadAudioData = true;
            defaultSampleSettings.compressionFormat = AudioCompressionFormat.Vorbis;
            defaultSampleSettings.quality = 0.4f;   // 40
            defaultSampleSettings.sampleRateSetting = AudioSampleRateSetting.OptimizeSampleRate;

            bDefaultSettingChanged = true;
        }
        else if (strPath.StartsWith("Assets/Resources_AssetBundles/sound/sound_main_bgm"))
        {
            audioImporter.forceToMono = true;
            normalize.boolValue = false;
            audioImporter.loadInBackground = true;
            //audioImporter.ambisonic = false;

            defaultSampleSettings.loadType = AudioClipLoadType.Streaming;
            audioImporter.preloadAudioData = false;
            defaultSampleSettings.compressionFormat = AudioCompressionFormat.Vorbis;
            defaultSampleSettings.quality = 0.4f;   // 40
            defaultSampleSettings.sampleRateSetting = AudioSampleRateSetting.OptimizeSampleRate;

            bDefaultSettingChanged = true;
        }
        else if (strPath.StartsWith("Assets/Resources_AssetBundles/sound/sound_sub_bgm"))
        {
            audioImporter.forceToMono = true;
            normalize.boolValue = false;
            audioImporter.loadInBackground = true;
            //audioImporter.ambisonic = false;

            defaultSampleSettings.loadType = AudioClipLoadType.Streaming;
            audioImporter.preloadAudioData = false;
            defaultSampleSettings.compressionFormat = AudioCompressionFormat.Vorbis;
            defaultSampleSettings.quality = 0.4f;   // 40
            defaultSampleSettings.sampleRateSetting = AudioSampleRateSetting.OptimizeSampleRate;

            bDefaultSettingChanged = true;
        }
        else if (strPath.StartsWith("Assets/Resources_AssetBundles/sound/sound_voice"))
        {
            audioImporter.forceToMono = true;
            normalize.boolValue = false;
            audioImporter.loadInBackground = false;
            //audioImporter.ambisonic = false;

            defaultSampleSettings.loadType = AudioClipLoadType.CompressedInMemory;
            audioImporter.preloadAudioData = true;
            defaultSampleSettings.compressionFormat = AudioCompressionFormat.Vorbis;
            defaultSampleSettings.quality = 0.4f;   // 40
            defaultSampleSettings.sampleRateSetting = AudioSampleRateSetting.OptimizeSampleRate;

            bDefaultSettingChanged = true;
        }
        else if (strPath.StartsWith("Assets/Resources_AssetBundles/sound_scenario"))
        {
            // File Name
            if (strPath.Contains("/bg_"))  // BGM
            {
                audioImporter.forceToMono = true;
                normalize.boolValue = false;
                audioImporter.loadInBackground = true;
                //audioImporter.ambisonic = false;

                defaultSampleSettings.loadType = AudioClipLoadType.Streaming;
                audioImporter.preloadAudioData = false;
                defaultSampleSettings.compressionFormat = AudioCompressionFormat.Vorbis;
                defaultSampleSettings.quality = 0.4f;   // 40
                defaultSampleSettings.sampleRateSetting = AudioSampleRateSetting.OptimizeSampleRate;

                bDefaultSettingChanged = true;
            }
            else if(strPath.Contains("/se_"))  // SFX
            {
                audioImporter.forceToMono = true;
                normalize.boolValue = false;
                audioImporter.loadInBackground = false;
                //audioImporter.ambisonic = false;

                defaultSampleSettings.loadType = AudioClipLoadType.DecompressOnLoad;
                audioImporter.preloadAudioData = true;
                defaultSampleSettings.compressionFormat = AudioCompressionFormat.Vorbis;
                defaultSampleSettings.quality = 0.4f;   // 40
                defaultSampleSettings.sampleRateSetting = AudioSampleRateSetting.OptimizeSampleRate;

                bDefaultSettingChanged = true;
            }
            else    // Etc(SFX?)
            {
                audioImporter.forceToMono = true;
                normalize.boolValue = false;
                audioImporter.loadInBackground = false;
                //audioImporter.ambisonic = false;

                defaultSampleSettings.loadType = AudioClipLoadType.DecompressOnLoad;
                audioImporter.preloadAudioData = true;
                defaultSampleSettings.compressionFormat = AudioCompressionFormat.Vorbis;
                defaultSampleSettings.quality = 0.4f;   // 40
                defaultSampleSettings.sampleRateSetting = AudioSampleRateSetting.OptimizeSampleRate;

                bDefaultSettingChanged = true;
            }
        }
        else if (strPath.StartsWith("Assets/Resources_AssetBundles/sound_scenario_StreamingAssets"))
        {
            // File Name
            if (strPath.Contains("/bg_"))  // BGM(
            {
                audioImporter.forceToMono = true;
                normalize.boolValue = false;
                audioImporter.loadInBackground = true;
                //audioImporter.ambisonic = false;

                defaultSampleSettings.loadType = AudioClipLoadType.Streaming;
                audioImporter.preloadAudioData = false;
                defaultSampleSettings.compressionFormat = AudioCompressionFormat.Vorbis;
                defaultSampleSettings.quality = 0.4f;   // 40
                defaultSampleSettings.sampleRateSetting = AudioSampleRateSetting.OptimizeSampleRate;

                bDefaultSettingChanged = true;
            }
            else if (strPath.Contains("/se_"))  // SFX
            {
                audioImporter.forceToMono = true;
                normalize.boolValue = false;
                audioImporter.loadInBackground = false;
                //audioImporter.ambisonic = false;

                defaultSampleSettings.loadType = AudioClipLoadType.DecompressOnLoad;
                audioImporter.preloadAudioData = true;
                defaultSampleSettings.compressionFormat = AudioCompressionFormat.Vorbis;
                defaultSampleSettings.quality = 0.4f;   // 40
                defaultSampleSettings.sampleRateSetting = AudioSampleRateSetting.OptimizeSampleRate;

                bDefaultSettingChanged = true;
            }
            else    // Etc(SFX?)
            {
                audioImporter.forceToMono = true;
                normalize.boolValue = false;
                audioImporter.loadInBackground = false;
                //audioImporter.ambisonic = false;

                defaultSampleSettings.loadType = AudioClipLoadType.DecompressOnLoad;
                audioImporter.preloadAudioData = true;
                defaultSampleSettings.compressionFormat = AudioCompressionFormat.Vorbis;
                defaultSampleSettings.quality = 0.4f;   // 40
                defaultSampleSettings.sampleRateSetting = AudioSampleRateSetting.OptimizeSampleRate;

                bDefaultSettingChanged = true;
            }
        }

        try
        {
            // 수정됐으면 Save
            if (true == bDefaultSettingChanged)
            {
                audioImporter.defaultSampleSettings = defaultSampleSettings;
                serializedObject.ApplyModifiedProperties();
                if (true == biOSSettingChanged)
                {
                    audioImporter.SetOverrideSampleSettings("iOS", iosSampleSettings);
                }
                audioImporter.SaveAndReimport();

                EditorUtility.SetDirty(audioImporter);

                Debug.LogFormat("[{0}] has been imported to [{1}]\n[Force To Mono] {2}\n[Normalize] {3}\n[Load In Background] {4}\n[Load Type] {5}\n[Compression Format] Default: {6}, iOS: {7}\n[Quality] {8}\n[Sample Rate Setting] {9}",
                                Path.GetFileName(strPath),
                                Path.GetDirectoryName(strPath),
                                audioImporter.forceToMono.ToString(),
                                normalize.boolValue,
                                audioImporter.loadInBackground,
                                defaultSampleSettings.loadType.ToString(),
                                defaultSampleSettings.compressionFormat.ToString(),
                                iosSampleSettings.compressionFormat.ToString(),
                                (defaultSampleSettings.quality * 100f),
                                defaultSampleSettings.sampleRateSetting.ToString()
                                );
            }

            // OnPreprocessAudio() 에서는 Refresh 안함
            //AssetDatabase.Refresh();
        }
        catch (System.Exception e)
        {
            Debug.LogError(e);
        }
    }

    // 파일이 이동한 경우 다시 임포트.
    static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
    {
        try
        {
            foreach (string movedAsset in movedAssets)
            {
                if (movedAsset.StartsWith("Assets/Resources/Sound")
                    || movedAsset.StartsWith("Assets/Resources_AssetBundles/sound")
                    || movedAsset.StartsWith("Assets/Resources_AssetBundles/sound_scenario")
                    || movedAsset.StartsWith("Assets/Resources_AssetBundles/sound_scenario_StreamingAssets")
                    )
                {
                    AssetDatabase.ImportAsset(movedAsset);
                }
            }
        }
        catch (System.Exception e)
        {
            Debug.LogError(e);
        }
    }
}

 

[참조]

https://overworks.github.io/unity/2018/09/22/unity-audio-clip-import-guide.html

https://jwidaegi.blogspot.com/2019/07/unity-sound.html?sc=1680659862098#c4452839809969885205

https://www.jianshu.com/p/b389936ff1ad

https://blog.csdn.net/hururu20120502/article/details/121425411

https://drehzr.tistory.com/1016

 

 

반응형
Posted by blueasa
, |

Today we’ll be talking about the Preload Audio Data option in Unity’s Audio Import Settings and why understanding this small but critical checkbox is important for your game.

So many options… How does Unity choose which audio is loaded to a scene?

Editor’s Note: Compression Formats, Load Type and the Preload Audio Data/Load in Background settings go hand in hand. We recommend reading our blog posts on all three in the following order for a complete overview:

Blog 1: Compression Formats

Blog 2: Load Types

Blog 3: Preload Audio (this post)

Blog 4: Load in Background (coming soon)

This blog post has been made as a supplement to our video tutorial on this same topic.

 
 

Introduction

After figuring out how Unity compresses your audio with the different compression formats, and primes your audio for playing with the different Load Type settings, the next question to answer is: What does the Preload Audio Data option do?

The Unity Documentation provides important information on this subject, but it doesn’t explain exactly when and how audio files are selected to be loaded in an active scene.

 

Preload Audio Data

Here’s Unity’s definition of Preload Audio Data from their manual:

If enabled, the audio clip will be pre-loaded when the scene is loaded. This is on by default to reflect standard Unity behavior where all AudioClips have finished loading when the scene starts playing.

This information is pretty clear already. If you choose this option, you want the audio priming process with the respective Load Types to take place before the scene is activated and becomes playable.

This will result in mission-critical audio files being ready to be played at all times at the expense of making the scene load time a little bit longer.

So far, so good. But there is one question left unanswered:

How does Unity decide which Audio is going to be loaded in which Scene?

 

References

Let’s imagine this situation: you’re developing a large game that has 15 hours of playtime and around 30 scenes. You have something like 1000 SFX and 2000 dialogue files. You would not want every single audio asset marked with Preload Audio Data to be loaded in every scene, would you?

Unfortunately, the documentation doesn’t address this in detail, making the process of deciding whether or not to Preload your audio assets very difficult and full of uncertainty.

Luckily, Unity is a sophisticated engine. After many tests, we concluded that Unity will scan everything in our scene and load all audio files flagged with Preload Audio Data that are referenced in the scene in any way.

Let’s take a step back here because now we have another question to answer:

What is a reference?

Let’s open up Unity and find out.

 

Testing Testing

We’ve imported 10 sound effects, 10 dialogue, and 2 music files into a Unity project. They’re all marked with Preload Audio Data to simulate a larger game. There are also two different scenes to simulate loading and unloading audio in a normal scene transition.

Let’s start with the first scene. We have a GameObject here with an AudioSource that has an AudioClip.

We hope this looks familiar.

This is already a so-called reference and this audio file will be loaded when the scene is loaded. I turned off Play on Awake for this to make sure that the audio is not played. Let’s build this and confirm with the profiler.

Our AudioClip is loaded and ready for action.

Perfect. Even though the AudioClip is not played at all, it is loaded because it has been referenced.

Note that this music file, which has “Streaming” selected as its Load Type, is only 311 bytes in the memory, unlike the 200-ish kilobytes from the last tutorial. That will change if we actually play the sound file.

Let’s now add two scripts we’ve prepared for another GameObject.

These two scripts do nothing but define a public AudioClip variable and a public AudioClip array. Let’s add an AudioClip to that and profile this.

Voilá. We have the second audio clip loaded.

For the sake of this demonstration, I will add another two AudioClips to the array and check the profiler once again.

As you might have guessed, without Preload Audio Data selected, Unity will not load the AudioClip until it is called, even though it is referenced in the scene. We’ll be going more in-depth on this in our next tutorial.

So, a reference is as simple as that. As long as you have a reference of any kind to an AudioClip, be it directly in the AudioSource, as a variable in a script, or even in a ScriptableObject, it will be loaded when the scene is loaded if you have checked Preload Audio Data.

 

Scene Transitions

Now: what happens if we change to another scene? Will the audio data we loaded in this scene be automatically unloaded?

Let’s go to the second scene. We’ll keep one AudioClip constant across both scenes but change the rest. Now we can build and profile this once again.

And then we’ll transition to the next scene.

We see here that all but one of our AudioClips from the first scene are already unloaded from the memory, leaving only the one that is used again in the second scene.

The unloading process took place as the scene was changed; this is a normal routine that Unity does in the background called GarbageCollection.

 

Final Words

Let’s summarize what we’ve learned:

  • Selecting Preload Audio Data means the scene will not start until all sounds with this setting are loaded into memory. This is most important for audio content that is needed right away in the scene, such as footsteps, UI, or anything synced to visual content that plays immediately upon the scene’s activation.
  • Unity determines which files to load in a scene by searching for references. If an audio file is referenced unnecessarily, for example, an AudioClip in an AudioSource that you ended up not using but didn’t delete from the scene, it will be loaded as well, even if the entire GameObject is deactivated. In that respect, it’s important to keep your scenes clear of unused references.
 

That’s it! We hope this tutorial has helped you to understand the Preload Audio Data option in Unity’s Import Settings and why this information is important for your game.

If you want to learn more about how audio functions in Unity, be sure to check out our other tutorials (linked below). If you have a question, leave it in the comments or contact us directly through our website:

 

 

[출처] https://medium.com/@made-indrayana/preload-audio-data-how-unity-decides-which-audio-assets-to-load-to-a-scene-a440a654e7e2

 

Preload Audio Data & How Unity Decides Which Audio Assets to Load to a Scene

Today we’ll be talking about the Preload Audio Data option in Unity’s Audio Import Settings and why it’s important for your game.

medium.com

 

반응형
Posted by blueasa
, |

Force To Mono

Unity 측에서 음원을 모노로 변환하여 용량을 줄여주는 설정
모바일이라고 ON하고 싶다.

인스펙터상이라면 이 설정을 ON으로 하면 Normalize옵션 설정을 선택할 수 있게 된다.
이것은 음량을 평균화해 주는 기능입니다만, 음소재측에서 음량 조정되고 있는 케이스도 있어, 「작은 소리로 하고 싶었는데 어쨌든 음량 오르지 않았어?」같은 것이 됩니다
.

그래서, 모노럴 설정은 ON으로 하면서, 노멀라이즈는 OFF로 해 두고 싶은 기분이 되네요.

 

가져오기 설정을 자동화하고 싶습니다.

수동으로 하는 것은 힘들어지므로,
AudioImporter 를 스크립트로부터 괴롭히고 어떻게든 하고 싶다.

그러나 AudioImpoter에는 forceToMono매개 변수가 있지만
Normalize관련 매개 변수가 노출되지 않았습니다.

 

결과

아래와 같이 해 주면, 해당의 파라미터를 취득해 재기입할 수 있었습니다.

 

var audioImporter = assetImporter as AudioImporter;
var serializedObject = new UnityEditor.SerializedObject(audioImporter);
var normalize = serializedObject.FindProperty("m_Normalize");
normalize.boolValue = false;

serializedObject.ApplyModifiedProperties();

audioImporter.SaveAndReimport();
UnityEditor.EditorUtility.SetDirty(audioImporter);
UnityEditor.AssetDatabase.Refresh();

 

https://answers.unity.com/questions/1016473/how-to-disable-normalize-in-audioimporter.html
https://docs.unity3d.com/ScriptReference/EditorUtility.SetDirty.html

 

 

[출처] https://qiita.com/mrhdms/items/85bd2e524a9c76e1273c

 

AudioImporter で Force to mono は有効にしつつ、Normalize だけ無効にする - Qiita

Force to mono Unity側で音源をモノラルに変換して、容量を削減してくれる設定 モバイルだとONにしたい。 インスペクタ上だと、この設定をONにすると、 Normalize というオプション設定が選択でき

qiita.com

 

[참조] https://www.jianshu.com/p/b389936ff1ad

 

Unity插件-音频参数优化

需求:需要对音频做出修改,压缩音频质量,检测是否设置为Mono与Normalize, 超过10秒LoadType设为Streaming. 思路:遍历所有的音频文件,拿到所有的...

www.jianshu.com

 

반응형
Posted by blueasa
, |