2D 그래픽-왜 스프라이트 시트를 사용합니까?


62

스프라이트 시트에서 스프라이트를 렌더링하는 방법에 대한 많은 예를 보았지만 이것이 2D 게임에서 스프라이트를 처리하는 가장 일반적인 방법 인 이유를 파악하지 못했습니다.

주어진 스프라이트 유형에 대한 각 애니메이션 프레임을 자체 텍스처로 처리하여 만든 몇 가지 데모 응용 프로그램에서 2D 스프라이트 렌더링으로 시작했습니다.이 텍스처 컬렉션은 사전에 저장됩니다. 이것은 애니메이션을 gif / mng 파일로 만든 다음 개별 png로 프레임을 추출하는 경향이 있기 때문에 저에게 효과적이며 워크 플로에 매우 적합합니다.

개별 텍스처가 아닌 단일 시트에서 렌더링 할 때 눈에 띄는 성능 이점이 있습니까? 초당 수백 번의 화면에 수백만 개의 다각형을 그릴 수있는 최신 하드웨어를 사용하면 수십 개의 50x100px 사각형을 처리하는 2D 게임에도 문제가되지 않습니까?

텍스처를 그래픽 메모리에로드하고 XNA에 표시하는 구현 세부 사항은 상당히 추상화 된 것 같습니다. 내가 아는 것은 텍스처가로드 될 때 그래픽 장치에 바인딩 된 다음 게임 루프 동안 텍스처가 일괄 적으로 렌더링된다는 것입니다. 내 선택이 성능에 영향을 미치는지 확실하지 않습니다.

나는 대부분의 2D 게임 개발자들이 그것들을 사용하는 것처럼 보이는 아주 좋은 이유가 있다고 생각합니다. 그 이유를 이해하지 못합니다.


아니요, 50 개의 이상한 스프라이트에는 그다지 중요하지 않습니다. 그러나 잃을 것은 무엇입니까?
공산주의 오리

답변:


69

스프라이트 시트 사용에 대한 강력한 주장은 그래픽 카드에서 사용 가능한 텍스처의 수가 제한 될 수 있다는 것입니다. 따라서 그래픽 라이브러리는 GPU에서 텍스처를 지속적으로 제거하고 텍스처를 다시 할당해야합니다. 큰 텍스처를 한 번만 할당하는 것이 훨씬 효율적입니다.

텍스처 크기는 일반적으로 2의 거듭 제곱입니다. 따라서 50x100px Sprite를 사용하는 경우 64x128px 또는 최악의 경우 128x128px의 텍스처를 할당합니다. 그것은 단지 그래픽 메모리를 낭비하고 있습니다. 모든 스프라이트를 1024x1024px 텍스처로 더 잘 압축하여 20x10 스프라이트를 허용하고 수평 및 수직으로 24 픽셀 만 잃게됩니다. 때로는 크기가 다른 스프라이트도 하나의 거대한 스프라이트 시트로 결합되어 텍스처를 가능한 한 효율적으로 사용합니다.

부록 : 스프라이트 시트를 사용해야하는 매우 중요한 이유는 GPU에 대한 드로우 콜의 양을 줄여 성능에 현저한 영향을 줄 수 있기 때문입니다. 이것은 다른 답변에서 언급되었으며 더 명확하게하기 위해 완전성을 위해 이것을 추가하고 있습니다.


1
고마워, 나는 그 점 중 하나를 고려하지 않았다-당신은 사용 가능한 텍스처의 수에 대한 한계가 대략 무엇인지 알고 있습니까? 그래픽 사양에 언급 된이 통계를 본 적이 없습니다. 한도는 기본적으로 그래픽 RAM의 양과 같은 것입니까?
Columbo

일반적으로 GPU 메모리가 한계입니다. 구형 카드의 텍스처 수에는 제한이 있다고 생각했지만 그 점을 입증하는 참조를 찾을 수없는 것 같습니다.
bummzack

12
수량에 제한이 없더라도 작은 이미지를 많이 이동시키는 버스 트래픽은 한 번 (또는 몇 가지) 큰 전송만큼 효율적이지 않습니다.
Mordachai 2016 년

5
좋은 점이지만 가장 중요한 측면은 드로우 콜 카운트 다운을 유지하여 파이프 라인 정지를 최소화하는 것입니다. GPU는 대규모 소규모 작업보다는 소규모 작업을 선호합니다. 모든 스프라이트를 작은 양의 큰 시트에 넣으면 텍스트 스테이지를 한 번 설정하고 한 번에 많은 스프라이트를 한 번에 그릴 수 있습니다. Spritebatch가이를 수행합니다. 스프라이트 시트가 두 개 이상인 경우 텍스처별로 정렬하도록 스프라이트 배치를 알려주십시오.
Cubed2D

텍스쳐 압축을 추가하면 여유 공간을 아주 작은 양의 오버 헤드로 바꿀 수 있습니다.
Joe Plante

36

사용할 주장은 한 번의 호출로 여러 가지를 렌더링 할 수있는 능력이라고 말할 것입니다. 스프라이트 시트가없는 글꼴 렌더링을 예로 들자면 각 문자를 별도의 텍스처 스왑과 드로우 콜로 렌더링해야합니다. 그것들을 스프라이트 시트에 던져 놓고 단일 드로우 콜 (모서리에 다른 UV를 지정하여 선택되는 글꼴의 차이 문자)으로 전체 문장을 렌더링 할 수 있습니다. 많은 플랫폼에서 물건을 렌더링하는 데 실제로 발생하는 오버 헤드가 너무 많은 API 호출을 수행하는 경우 훨씬 효율적인 렌더링 방법입니다.

공간을 절약하는 데 도움이 될 수도 있지만, 스프라이트 시트에 포장하는 내용이 무엇보다 우선합니다.


2
+1 드로우 콜을 터치합니다. (허용 된 답변에서 보지 못한 것)
Michael Coleman

11

각 드로우 콜에는 일정량의 오버 헤드가 있습니다. 스프라이트 시트를 사용하면 애니메이션의 동일한 프레임을 사용하지 않는 것 (또는 일반적으로 같은 머티리얼에있는 모든 것)을 사용하여 그림을 배치하여 성능을 크게 향상시킬 수 있습니다. 게임에 따라 최신 PC에서는 그다지 중요하지 않지만 iPhone과 관련해서는 분명히 중요합니다.


2
여전히 중요합니다. 그래픽 하드웨어는 대부분의 게임이 그 방향을 따르기 때문에 적은 수의 세부 모델 (예 : 캐릭터)을 위해 수많은 다각형을 밀도록 최적화되었습니다. 결과적으로 단 몇 번의 드로우 콜에서 가능한 한 많은 폴리곤을 밀어야합니다. 도시와 같은 큰 장면을 렌더링하는 게임 엔진은 드로우 콜을 줄이기 위해 여러 텍스처를 하나의 즉시 결합합니다.
jhocking

많은 3D 하드웨어에서 텍스처 u, v 매핑과 비트 블리 팅 작업이 스프라이트 시트에서 이점을 얻는 지 확실히 궁금합니다.
Joe Plante

7

성능 고려 사항 외에도 스프라이트 시트는 아트를 만들 때 편리 할 수 ​​있습니다. 각 문자는 자체 시트에있을 수 있으며 스크롤하면 모든 프레임을 볼 수 있습니다. 모든 프레임에서 일관된 모양을 유지하는 데 도움이됩니다.

또한 AS3으로 코딩하며 각 이미지 파일에는 별도의 포함 명령이 필요합니다. 별도의 리소스 클래스를 사용하는 경우에도 모든 프레임에 대해 24 개의 임베드보다 전체 스프라이트 시트의 단일 임베드를 원합니다.


1
+1. OP는 Flash를 사용하지 않지만 포함 또는로드는 스프라이트 시트에 유리합니다. 또한 웹 서버에서 자산이로드 될 때 (각 "프레임"에 대해 수백 개의 요청보다 하나의 요청이 선호되는 경우) 관련이 있습니다.
bummzack

온라인 게임에 대한 서버 요청을 줄이려고합니다. 우리는이 주요 목표를 달성하기 때문에 이미지를 .swf 또는 스프라이트 시트에 넣는 것이 더 좋은지 여부를 고려했습니다. 결국 스프라이트 시트는 아티스트의 노동 집약도가 낮습니다.
jhocking

7

XNA에서 스프라이트 시트를 사용하는 또 다른 이유는 Xbox360 개발에서 프로젝트에있는 파일 수와 관련하여 배포 /로드 시간이 느리다는 알려진 문제가 있기 때문입니다. 따라서 많은 작은 이미지 파일을 단일 이미지 파일로 결합하면 해당 문제를 해결하는 데 도움이됩니다.


5

메모리 / GPU에 대해서는 언급하지 않겠습니다. 답변이 충분하기 때문입니다.

대신, 작업 할 때나 그 이후에 아트를 정리할 수 있습니다. 보행주기를보기 위해 10 개의 이미지를 넘겨야하는 대신 모든 프레임을 한 번에 볼 수 있습니다. 이것을 배포하려면 10 개 대신 처리 할 파일이 1 개뿐입니다.

그런 다음 characterwalk01에서 characterwalk10, characterattack01에서 characterattack05에 이르기까지 character.png 및 enemy.png를 갖는 것이 구성 측면에서 더 깨끗합니다.


4

그래픽 메모리에는 디스크의 파일 시스템과 같은 확장 메모리 관리 기능 이 없습니다 . oposite가 그 경우입니다 : 간단하고 빠릅니다 .

이러한 간단하고 빠른 메모리 관리 중 하나는 너비 및 / 또는 높이의 절반으로 여러 개의 작은 스프라이트로 절단되는 하나의 거대한 4096x4096 스프라이트를 갖는 것과 같습니다. (유사한 1 차원 메모리 관리 기술이 있지만 이름을 잊어 버렸습니다.) 결국 조각 모음을 수행해야합니다.

런타임시 이러한 메모리 관리를 건너 뛰기 위해 개발자는 컴파일 타임 또는 그래픽의 디싱 프로세스 중에도 하나의 큰 스프라이트를 여러 개의 작은 스프라이트로 자동으로 채 웁니다 .


3

또한 초기화 중에 절약 할 수있는 I / O 작업도 잊지 마십시오. CD 드라이브에서로드하는 경우 각 파일은 추가 I / O 호출이며 검색하는 데 약간의 시간이 걸릴 수 있습니다 (현대 HDD는 파일 당 약 15ms, CD는 50-100ms일까요?). 하나의 파일 만 가져와야하므로 초기화 시간을 많이 절약 할 수 있습니다. 또한 응용 프로그램이 GPU 대기와 같은 다른 작업을 수행하는 경우 OS에서 이러한 I / O 작업을 캐시 할 수 있습니다.


1
다른 한편으로 파일 탐색 문제를 해결하려면 사용자 정의 형식을 사용하여 모든 스프라이트를 단일 파일로 압축 할 수 있습니다. 대부분의 게임이 그렇게합니다.
tigrou

0

더 효율적인 성능 이외에, 나는 그것이 더 쉽다는 것을 안다. 아트를 만들 때 이미지가 항상 경계 안에 있는지 확인하려면 약간의 추가 작업이 필요하지만 현재 처리하고있는 모든 이미지를 훨씬 쉽게 볼 수 있습니다.

제 생각에는 코딩하기가 더 쉽습니다. 단순히 다음과 같은 객체 배열이 있습니다.

sheet = {
    img: (the actual image),
    rects: [
        {x:0, y:0, w:32, h:32},
        {x:32, y:0, w:32, h:32},
        {x:64, y:0, w:32, h:32}
    ]
};

sheets.push(sheet);

그런 다음 각 항목에 대해 sheet와 rect의 두 값을 제공합니다. 시트는 객체 배열의 인덱스이고 rect는 해당 시트의 rects 배열의 인덱스입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.