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

카테고리

분류 전체보기 (2795)
Unity3D (852)
Programming (478)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (185)
협업 (61)
3DS Max (3)
Game (12)
Utility (68)
Etc (98)
Link (32)
Portfolio (19)
Subject (90)
iOS,OSX (55)
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

[링크] https://blog.naver.com/kki7540/221538021815

 

에요 예요 이에요 이예요 완벽하게 정리해보자!!

뭐가 맞고 뭐가 틀린지 간단하게 보실 분들은 중간에 쓴 내용은 무시하시고 자, 최종적으로 다 정리를 해보...

blog.naver.com

 

반응형
Posted by blueasa
, |

오늘 저는 다음 정보와 함께 "Command CodeSign failed with a nonzero exit code" 오류를 받았습니다 .

ID 서명: "내 ID"
/usr/bin/codesign --force --sign xxxxxxxx --timestamp=none /path/to/derived/data...
xxxxxxxx: ID를 찾을 수 없음 0이 아닌
종료 코드로 인해 명령 CodeSign이 실패함

이 오류가 발생하는 데는 몇 가지 이유가 있을 수 있습니다. 방금 나에게 일어난 일을 공유하겠습니다.

#문제의 원인

키체인 액세스 앱 에서 키체인을 망칠 때 이 문제가 발생합니다 . 새 인증서를 만들고 이전 인증서를 삭제하려고 했습니다. 그리고 Xcode가 삭제된 것을 사용하려고 시도한 것 같습니다.

 

#해결책

내 솔루션은 Xcode 문제가 발생했을 때 항상 수행하는 작업인 Clean Build Folder입니다.

  1. 옵션 키 또는 ⌘ - CMD + ⇧ - SHIFT⌥ + - option + K 를 누른 상태에서 메뉴 제품 > 빌드 폴더 정리를 클릭합니다 .
  2. Xcode를 닫습니다. 이것은 저에게 매우 중요한 단계입니다. 닫아야 작동합니다.
  3. 앱을 다시 열면 키체인에 액세스하라는 대화 상자가 표시될 수 있습니다. 액세스 권한을 부여하면 문제가 해결됩니다.

 

----

Today I got the "Command CodeSign failed with a nonzero exit code" error with the following information.

Signing Identity: "My identity"
/usr/bin/codesign --force --sign xxxxxxxx --timestamp=none /path/to/derived/data...
xxxxxxxx: no identity found
Command CodeSign failed with a nonzero exit code

There might be several reasons that cause this error. I will share one that just happened to me.

#Cause of the problem

I got this problem when I mess up with keychains in the Keychain Access app. I created a new certificate and tried to delete an old one. And I think Xcode was attempting to use the deleted one.

 

#Solution

My solution is what we always do when we got an Xcode problem, Clean Build Folder.

  1. Click menu Product > Clean Build Folder while holding down option key or ⌘ - CMD + ⇧ - SHIFT + ⌥ - option + K.
  2. Close the Xcode. This is a very important step for me. I need to close it to work.
  3. Reopen the app, and you might see the dialog asking to access the keychain. Grant the access, and the problem should go away.

 

 

[출처] https://sarunw.com/posts/how-to-fix-command-codesign-failed/

 

How to fix "no identity found - Command CodeSign failed with a nonzero exit code" error in Xcode | Sarunw

There might be several reasons that cause this error. I will share one that just happened to me.

sarunw.com

[참조] https://intrepidgeeks.com/tutorial/error-handling-ios-development-error-command-codesign-failed-with-nonzero-exit

 

[오류 처리] iOS 개발 오류, command codesign failed with a nonzero exit code

문제. Xcode 실행 코드, error입니다. 아래와 같습니다.command codesign failed with a nonzero exit code 해결하다 1. 클렌징, command+shift+k 2. 컴퓨터를 재부팅하고 다시 실행

intrepidgeeks.com

 

반응형
Posted by blueasa
, |

Mac Chrome에서 다른 사이트는 정상인데,

항상 접속하던 https://appcenter.ms 에 접속하려니 아래와 같은 오류가 뜬다.

'주의 요함'을 눌러보니 아래와 같이 '인증서가 올바르지 않음' 이라고 뜨는게 보인다.

인증서 문제인 듯..

문제를 해결하기 위해  아래 에러 문구로 이리저리 뒤져보고 여러가지를 시도해 봤지만 제대로 되지 않았다.

 

[검색어]

연결이 비공개로 설정되어 있지 않습니다.

NET::ERR_CERT_AUTHORITY_INVALID

 

검색하던 중 아래 링크의 사이트를 보게 됐는데,

인증서를 받아서 Mac의 '키 체인'에 추가한다음 '항상 신뢰'를 해주라고 돼있다.

 

[링크] https://www.ibm.com/docs/ko/tncm-p/1.4.2?topic=setup-not-able-accept-certificate-chrome-browser-mac 

 

Mac의 크롬 브라우저에서 인증서를 받을 수 없음

이 문제는 Mac의 크롬 브라우저에서만 확인할 수 있다. 증상Dashboard Application Services Hub에서 Telco Network Cloud Manager - Performance 대시보드 를 보려면 Chrome 브라우저가 인증서를 승인하지 않습니다. 이

www.ibm.com

인증서를 신뢰하지 못해서 생기는 문제니 인증서를 신뢰하게 만들면 될 것 같아서 시도 해 봄.

 

1. 오류 나는 사이트 접속(내 경우는 https://appcenter.ms)

2. 크롬 주소창 - '주의 요함' - '인증서가 올바르지 않음' Click

3. '인증서 뷰어' - '세부정보' - '내보내기(X)' Click 해서 해당 사이트 인증서 저장

4. 다운 받은 인증서 Double-Click 해서 '키 체인'에 추가.

5. '키 체인'에 추가된 인증서 다시 Double-Click 해서 설정 열기

6. '이 인증서 사용 시'가 '시스템 초기 설정 사용' → '항상 신뢰'로 변경

7. '항상 신뢰'로 변경하면 아래 보듯이 '이 인증서는 이 계정에 대해 신뢰된 것으로 표시됩니다' 라고 뜬다.

8. 좌측 상단 x를 누르면 변경하려면 로그인 암호 넣으라고 나오는데 입력하고 종료.

9. Chrome을 완전 종료 후, 다시 켜서 해당 사이트를 들어가보면 아래와 같이 정상적으로 뜨고,

   주소창 자물쇠를 눌러보면 '이 연결은 안전합니다' 라고 뜬다.

 

반응형
Posted by blueasa
, |

[링크] https://cjh94.tistory.com/3

 

[ios]codesign이 변경하려고 합니다. 허용하려면 관리자 이름 및 암호를 입력하십시오.

새로운 프로젝트와 키체인을 받아서 작업 완료 후에 TestFlight에 올리려고 하니 발생했던 상황 빌드 파일마다 암호를 요청하고 보통 이런 경우 해결 방법은 비밀번호를 누르고. 허용이 아닌 항상

cjh94.tistory.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
, |