Unity NativeArry를 사용하여 ASTC 로드
18419 단어 Unity
ASTC가 GPU에 대응하는 증가 관계로 ASTC 포맷은 이동 중 가장 먼저 필수적인 단계입니다.
또 네이티브 아레이는 유니티 2018년 이후에도 다양한 저등급 API를 추가해 독자 처리에서도 활용이 용이해졌다.
이번에는 AB화하지 않고 NativeArry를 통해 ASTC 포맷을 로드하는 방법을 소개하고자 합니다.
NativeArry를 사용하여 ASTC를 로드하는 이점
Texture2D.LoadImage
하지 않아도 불러올 수 있지만 메모리를 모두 관리구역으로 전개해야 하기 때문에 메모리 부하가 높다사전 조사
이번에는 AB가 아니기 때문에 Unity의 ASTC 인코딩에 의존하지 않고 스스로 ASTC 인코딩을 진행한다.
다행히 ARM이 공식 인코더를 공개해 이번에 사용했다.
이번에 사용한 ASTC 인코더
https://github.com/ARM-software/astc-encoder
./astcenc -c sample.png sample.astc 6x6 -medium
이렇게 하면 쉽게 인코딩할 수 있다.Unity가 필요하지 않기 때문에ci 도구로도 쉽게 가져올 수 있습니다.또 인코딩 데이터의 전개 위치는 Native Aray이지만 GPU에 올리려면 사용해야 한다
Texture2D.LoadRawTextureData
.그러나 이것
Texture2D.LoadRawTextureData
은 Texture2D.LoadImage
과 달리 형식과 이미지의 사이즈를 명확하게 지정해야 한다.다만, 여기에 이미지 메타데이터를 단독으로 제공하는 것은 터무니없는 것이기 때문에 ASTC 포맷에 포함된 메타데이터에서 ASTC의 블록 사이즈와 이미지 사이즈를 얻을 수 있습니다.
ASTC 형식 읽기
ASTC의 격식은 다음과 같은 것으로 조사됐다.
메모리 바이트
저장 정보
0~3 byte
마술 번호
0x5CA1AB13
4 bytex의 블록 크기입니다.(6x6)의 경우
0x6
5 bytey의 블록 사이즈.(6x6)의 경우
0x6
6 bytez의 블록 크기입니다.2D 이미지에서 항상
0x1
7~9 byte이미지의 x 크기입니다.(1920x1080)면
0x000780
10~12 byte이미지의 y 크기입니다.(1920x1080)면
0x000438
13~15 byte이미지의 z 크기입니다.만약 2D 그림이라면, 여기는 항상
0x000001
따라서 1920×1080 이미지의 블록 사이즈 6x6로 ASTC로 인코딩하면 머리는 다음과 같다(바이트 순서는 소단 바이트 순서
13ABA15C 06060180 07003804 00010000
z에 대한 정보는 잘 모르겠지만 기본적으로 1이니까 너무 신경 쓰지 마세요.이 메타 정보
Texture2D.LoadRawTextureData
로 로드이루어지다
using System;
using System.IO;
using System.Linq;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.IO.LowLevel.Unsafe;
using UnityEngine;
using UnityEngine.UI;
public unsafe class AsyncLoader : MonoBehaviour
{
const int AstcBlockInfoSize = 3;
const int AstcFullHeaderSize = 16;
static readonly byte[] AstcHeaderMagicNumber = { 0x5C, 0xA1, 0xAB, 0x13 };
NativeArray<ReadCommand> commands;
ReadHandle readHandle;
Action callback;
void Start()
{
// astcファイルを生成した際のコマンド
// ./astcenc -c sample.png sample.astc 6x6 -medium
var filePath = Path.Combine(Application.dataPath, "StreamingAssets/Sign_Okay.astc");
var fileSize = new FileInfo(filePath).Length;
commands = new NativeArray<ReadCommand>(1, Allocator.Persistent)
{
[0] = new ReadCommand
{
Offset = 0,
Size = fileSize,
Buffer = (byte*)UnsafeUtility.Malloc(fileSize, UnsafeUtility.AlignOf<byte>(), Allocator.Persistent),
},
};
readHandle = AsyncReadManager.Read(filePath, (ReadCommand*)commands.GetUnsafePtr(), 1);
callback = () =>
{
var buffer = (byte*)commands[0].Buffer;
if (!IsValid(buffer))
{
Dispose();
throw new NotSupportedException("ASTCファイル内のヘッダが正しくありません");
}
var (width, height) = GetTexSize(buffer);
buffer += AstcFullHeaderSize;
var textureDataSize = fileSize - AstcFullHeaderSize;
var tex = new Texture2D(width, height, TextureFormat.ASTC_6x6, false);
tex.LoadRawTextureData((IntPtr)buffer, (int)textureDataSize);
tex.Apply();
GetComponent<RawImage>().texture = tex;
Dispose();
};
}
void Update()
{
if (readHandle.IsValid() && readHandle.Status == ReadStatus.Complete)
{
callback?.Invoke();
callback = null;
}
}
void OnDestroy()
{
Dispose();
}
static bool IsValid(byte* buffer)
{
var isAstc = true;
var magicNumber = BitConverter.IsLittleEndian ? AstcHeaderMagicNumber.Reverse() : AstcHeaderMagicNumber;
foreach (var b in magicNumber)
{
isAstc &= *buffer == b;
if (!isAstc)
{
return false;
}
buffer++;
}
return true;
}
static (int Width, int Height) GetTexSize(byte* buffer)
{
buffer += AstcHeaderMagicNumber.Length + AstcBlockInfoSize;
if (BitConverter.IsLittleEndian)
{
var width = *buffer++ | *buffer++ << 8 | *buffer++ << 16;
var height = *buffer++ | *buffer++ << 8 | *buffer << 16;
return (width, height);
}
else
{
var width = *buffer++ << 16 | *buffer++ << 8 | *buffer++;
var height = *buffer++ << 16 | *buffer++ << 8 | *buffer;
return (width, height);
}
}
void Dispose()
{
readHandle.Dispose();
UnsafeUtility.Free(commands[0].Buffer, Allocator.Persistent);
commands.Dispose();
}
}
이번에는 부실 공사ASTC_6x6
형식의 하드웨어 코드입니다.물론 메타 정보를 사용하여 블록 크기를 얻어 형식을 동적으로 지정할 수도 있다.
결실
실장점
실장점 2 시.
Native Arry의 해방을 잊지 마세요.
NativrAray의 모든 실복을 사용했다고 할 수 있지만 해방을 잊지 마세요.
해방을 잊으면 붕괴가 누설된다.
LoadRawTextureData
ASTC 머리의 메타 정보가 필요 없음이곳은 적당한 곳
LoadRawTextureData
입니다. ASTC의 헤드 정보는 필요 없으니 헤드의 16자 바이트 부분을 제외하고LoadRawTextureData
에 맡겨주세요.헤더를 제거하지 않고 상대방에게 직접 건네주는 경우 헤더 정보도 주체로 해석되고 이 부분은 소음을 나타낸다.
주의 사항
PC에 ASTC가 지원되지 않는 GPU가 많습니다.
따라서 Unity는 Standalone 환경에서 ASTC도 CPU 디코딩을 하기 때문에 PC에 사용하지 않는 장점과 성능 측정에 주의하십시오.
최후
저는 개인적으로 의존하지 않고 2D 무늬에 이 방법을 사용하는 것이 효과가 있기 때문에 추천합니다.
대응 터미널이 ASTC 대응 터미널로 한정된 것은 단점이지만, 상당히 오래된 터미널만 지원하지 않으면 ASTC에 대응할 수 있기 때문에 새 프로젝트에서 가져오면 문제가 된다.
그리고 Native Arry가 이런 저수준 API를 제공해 주셔서 정말 기쁩니다.
DOTS도 최근에 애니메이션 대응을 해서 드디어 현장에서 사용할 수 있게 되었습니다. 그래서 메모리 레이아웃을 잘 고려하고 싶습니다!
참고 자료
Reference
이 문제에 관하여(Unity NativeArry를 사용하여 ASTC 로드), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/hzn/items/5762cd8d3b0ed1f205f9텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)