본 글은 회사 업무 중에 서버에서 불러오는 Texture2D (JPG, PNG)등의 용량이 너무 커서 램 관리가 필요한 모바일 환경에서 강제 종료되는 현상을 방지하기 위해 구현하게 된 기능입니다.
필요한 기능
서버에서 불러오는 이미지를 런타임 환경에서 불러오는 과정과 동시에 텍스처 압축을 진행하여서 메모리 과부하를 막는 기능이 필요합니다.
유니티 프로젝트 안에 있는 텍스처의 경우 따로 여러 플랫폼에 원하는 형식으로 저장할 수 있는 기능이 제공되고 있으나 서버에서 바로 불러올 경우 위 기능을 사용하지 못하는 형식입니다.
구현한 기능
PNG or JPG -> GPU 랜더링이 필요하지 않는 이미지 파일들을 더 낮은 용량인 RGBA32로 변환 후 DXT5로 압축 진행
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Experimental.Rendering;
public class textureCompress : MonoBehaviour
{
// Start is called before the first frame update
public RawImage oldRaw; // 테스트 확인을 위한 RawImage
public RawImage newRaw;
public Texture2D oldTex; // 테스트 확인을 위해 셋팅하는 이미지
public Texture2D newTex;
void Start()
{
oldRaw.texture = oldTex;
newTex = ResizeTexture(oldTex);
newRaw.texture = newTex;
}
// 이미지 리사이징 함수
public Texture2D ResizeTexture(Texture2D oldTexture)
{
Texture2D copy = DuplicateTexture(oldTexture); // 읽기 가능하도록 설정
Color[] oldColor = copy.GetPixels(); // 읽기 가능한 파일의 픽셀값 저장
copy.Resize(oldTexture.width, oldTexture.height, TextureFormat.RGBA32, false);
// RGBA32로 변환 (사이즈 유지)
copy.SetPixels(oldColor); // 이전에 저장해둔 픽셀값 적용 (안할경우 이미지 단색)
copy.Compress(true); // 추가로 압축 진행 (DXT5로 적용됨 확인)
copy.Apply(); // 저장
return copy;
}
// Texture2D를 RenderTexture에 넣은 다음 이미지를 새로 읽어서 사용
// 이 방식으로 진행해야 오류 없이 이미지 읽기(readable) 가능
public Texture2D DuplicateTexture(Texture source)
{
RenderTexture renderTex = RenderTexture.GetTemporary(
source.width,
source.height,
0,
RenderTextureFormat.Default,
RenderTextureReadWrite.Linear);
Graphics.Blit(source, renderTex);
RenderTexture previous = RenderTexture.active;
RenderTexture.active = renderTex;
Texture2D readableTexture = new Texture2D(source.width, source.height);
readableTexture.ReadPixels(new Rect(0, 0, renderTex.width, renderTex.height), 0, 0);
readableTexture.Apply();
RenderTexture.active = previous;
RenderTexture.ReleaseTemporary(renderTex);
return readableTexture;
}
}
위 코드를 빈 게임오브젝트 생성 후 적용 한 다음에 확인을 위한 Canvas와 RawImage 2개를 설치합니다.
높은 해상도를 가진 이미지 적용 후 실행
보여지는 이미지는 압축 전이나 후를 구분하기 어려울 수준이지만 차지하는 용량의 차이를 볼수 있다.
32.0MB 에서 압축 후 -> 8.0MB로 줄었다.
픽셀 수는 동일하게 2048 * 4096으로 해상도는 동일한 것을 확인할 수 있다.
위 방식으로 불러오는 이미지에 적용하면 로직이 완성되는 부분이다.
이미지 한 두장에서는 차이가 적을수도 있으나 서버에서 이미지를 불러오는 경우엔 보통 많은 이미지를 불러오는 경우로 생각합니다. 위 로직을 잘 사용하셔서 조금 더 최적화된 이미지를 사용했으면 좋겠습니다.
출처
테스트 이미지 -> eberhard grossgasteiger 님의 사진, 출처: Pexels
로직 -> https://stackoverflow.com/questions/44733841/how-to-make-texture2d-readable-via-script