3. 텍스쳐와 이미지(Textures & Images)

우리는 Image와 Texture 클래스를 여러번 보았습니다. 사실 Starling에서 가장 유용한 클래스 중 하나입니다. 그러나 그것들은 어떻게 사용되며 둘의 차이점은 무엇일까요?

3.1. 텍스쳐

텍스처는 디지털 카메라에 저장된 파일과 같이 이미지를 설명하는 데이터일 뿐입니다. 이 파일 하나로는 아무것도 보여줄 수 없습니다. 결국 0과 1 뿐입니다. 이미지 뷰어로 보거나 프린터로 출력해야 합니다.

텍스처는 GPU 메모리에 직접 로드되므로 렌더링 중에 매우 효율적으로 액세스할 수 있습니다. 일반적으로 임베디드 클래스에서 생성되거나 파일에서 로드됩니다. 다음 파일 형식 중 하나를 선택할 수 있습니다.

PNG
가장 다재다능합니다. 무손실 압축은 넓은 영역의 단색 이미지가 특히 적합합니다. 기본 텍스처 형식으로 권장됩니다.
JPG
손실 인코딩 방식 덕분에 사진 (및 사진 같은) 이미지 용으로 PNG보다 작은 파일을 생성합니다. 그러나 알파 채널이 없기 때문에 제한적입니다. 사진 및 큰 배경 이미지에만 권장됩니다.
ATF
특별히 Stage3D 용으로 만든 형식. ATF 텍스처는 텍스처 메모리가 거의 필요하지 않으며 매우 빠르게 로드됩니다. 그러나 손실 압축은 모든 종류의 이미지에 완벽하게 적합하지 않습니다. 우리는 ATF 텍스처를 이후 장에서 더 자세히 살펴볼 것입니다 (‘ATF Textures, ATF 텍스처‘ 참조).

starling.textures.Texture 클래스는 텍스처를 인스턴스화하는 데 사용되는 많은 팩토리 메소드를 포함합니다. 다음은 그 중 몇 가지입니다 (명확성을 위해 논쟁은 생략합니다).

1
2
3
4
5
6
7
8
9
10
public class Texture
{
    static function fromColor():Texture;
    static function fromBitmap():Texture;
    static function fromBitmapData():Texture;
    static function fromEmbeddedAsset():Texture;
    static function fromCamera():Texture;
    static function fromNetStream():Texture;
    static function fromTexture():Texture;
}

아마도 가장 일반적인 작업은 비트맵에서 텍스처를 만드는 것입니다. 쉽진 않겠지만…​:

1
2
var bitmap:Bitmap = getBitmap();
var texture:Texture = Texture.fromBitmap(bitmap);

또한 임베디드 비트맵에서 텍스처를 만드는 것이 매우 일반적입니다. 그건 똑같은 방법으로 할 수 있어요:

1
2
3
4
5
[Embed(source="mushroom.png")] // (1)
public static const Mushroom:Class;

var bitmap:Bitmap = new Mushroom(); // (2)
var texture:Texture = Texture.fromBitmap(bitmap); // (3)

(1) 비트맵을 임베드하세요.
(2) 비트맵을 인스턴스화 하세요.
(3) 비트맵에서 텍스처를 만듭니다.

그러나, 이를 더 단순화하는 지름길이 있습니다:

1
2
3
4
[Embed(source="mushroom.png")] // (1)
public static const Mushroom:Class;

var texture:Texture = Texture.fromEmbeddedAsset(Mushroom); // (2)

(1) 비트맵을 임베드하세요.
(2) 임베디드 애셋을 저장하는 클래스에서 바로 텍스처를 만듭니다.

전문가의 팁

이것은 코드가 적을뿐만 아니라 메모리도 적게 소요됩니다!

fromEmbeddedAsset 메서드는 문맥상 손실을 막기 위해 씬 배후에 있는 마법을 사용하며 Bitmap 메서드에서 수행할 수 있는 기존의 것보다 더 효율적입니다. 나중에 이 주제로 다시 돌아갈 것이지만 지금은 이것이 임베디드 비트맵에서 텍스처를 생성하는 기본 방법임을 기억하십시오.

Texture 클래스의 또 다른 기능은 숨겨져 있습니다. fromTexture 메서드를 이용하면 다른 텍스처 내의 영역을 가리키는 텍스처를 설정할 수 있습니다.

이 점을 유용하게 만드는 것은 픽셀이 이 과정에서 복사되지 않는다는 사실입니다. 대신 생성된 SubTexture는 상위 텍스처에 대한 참조만 저장합니다. 이것은 매우 효율적입니다!

1
2
3
var texture:Texture = getTexture();
var subTexture:Texture = Texture.fromTexture(
        texture, new Rectangle(10, 10, 41, 47));

곧 TextureAtlas 클래스에 대해 알게될 것입니다. 이것은 기본적으로 이 기능을 중심으로 구축되었습니다.

3.2. 이미지

우리는 아직 두 개의 텍스처를 스크린에 표시하는 방법을 배우지 않았습니다. 가장 쉬운 방법은 Image 클래스 또는 그 사촌 중 하나를 사용하는 것입니다.

클래스 가계도의 일부분을 확대합시다.

mesh classes

  • Mesh는 삼각형의 평면 컬렉션입니다 (GPU는 삼각형 만 그릴 수 있음을 기억하십시오).
  • 쿼드는 사각형을 생성하는 적어도 두 개의 삼각형의 모음입니다.
  • 이미지는 편리한 생성자와 몇 가지 추가 메서드가 있는 쿼드입니다.
  • MovieClip은 시간이 지남에 따라 텍스처를 전환하는 이미지입니다.

이모든 클래스는 텍스처를 처리할 수 있도록 준비되어 있지만 Image 클래스를 사용하는 것이 가장 일반적입니다. 직사각형 텍스처가 가장 보편적이기 때문에 간단합니다. Image 클래스가 가장 편리한 방법입니다.

시연하기 위해 Quad 대 Image로 텍스처를 표시하는 방법을 보여 드리겠습니다:

1
2
3
4
5
6
7
8
var texture:Texture = Texture.fromBitmap(...);

var quad:Quad = new Quad(texture.width, texture.height); // (1)
quad.texture = texture;
addChild(quad);

var image:Image = new Image(texture); // (2)
addChild(image);

(1) 적절한 크기의 쿼드를 만들고 텍스처를 지정하거나 또는:
(2) 표준 생성자로 이미지를 만듭니다.

개인적으로 나는 항상 나에게 더 많은 키 스트로크를 저장하는 접근 방식을 선택했습니다. 그러나 뒤에서 일어나는 일은 두 경우 모두 동일합니다.

Texture-Mapping
그림 10. 텍스처가 쿼드에 매핑됩니다.

3.3. 하나의 텍스쳐, 여러개의 이미지

텍스처가 여러 이미지(메쉬)에 매핑될 수 있다는 점에 유의해야 합니다. 실제로 텍스처가 한 번만 로드된 다음 응용 프로그램의 수명이 다할 때까지 다시 사용하십시오.

1
2
3
4
5
6
7
8
9
10
// 이렇게 하지 마세요!!
var image1:Image = new Image(Texture.fromEmbeddedAsset(Mushroom));
var image2:Image = new Image(Texture.fromEmbeddedAsset(Mushroom));
var image3:Image = new Image(Texture.fromEmbeddedAsset(Mushroom));

// 대신 텍스처를 한 번 만들고 참조를 유지하십시오:
var texture:Texture = Texture.fromEmbeddedAsset(Mushroom));
var image1:Image = new Image(texture);
var image2:Image = new Image(texture);
var image3:Image = new Image(texture);

거의 모든 메모리 사용량은 텍스처에서 나옵니다. 텍스처 메모리를 낭비할 경우 RAM이 빨리 소모됩니다.

3.4. 텍스처 아틀라스 (Texture Atlases)

모든 이전 샘플에서는 각 텍스처를 별도로 로드했습니다. 그러나 실제 응용 프로그램에서는 그렇게 하지 말아야 합니다. 이유가 여기 있습니다.

  • 효율적인 GPU 렌더링을 위해 Starling은 렌더링된 메쉬를 일괄 처리합니다. 그러나 텍스처가 변경될 때마다 일괄 처리는 중단되죠.
  • 상황에 따라 Stage3D에서는 폭과 높이가 2의 배수가 되는 텍스처가 필요합니다. Starling은 이 제한을 숨기지만 그 규칙을 따르지 않으면 더 많은 메모리를 사용하게 됩니다.

텍스처 아틀라스를 사용하면 텍스처 스위치와 2배수의 제한 제한을 피할 수 있습니다. 모든 텍스처는 하나의 큰 “수퍼 텍스처” 내에 있고 Starling은 이 텍스처의 올바른 부분이 표시되도록 합니다.

Texture Atlas
그림 11. 텍스처 아틀라스.

트릭은 Stage3D가 작은 텍스처 대신 이 큰 텍스처를 사용하고 렌더링된 각 쿼드에 그 중 일부만 매핑하는 것입니다. 이렇게 하면 매우 효율적인 메모리 사용으로 이어져 가능한 한 최소한의 공간만 낭비하게 됩니다. (다른 프레임 워크에서는 이 기능을 스프라이트 시트라고 부릅니다.)

“Texture Packer” 팀은 실제로 스프라이트 시트에 대한 멋진 소개 비디오를 만들었습니다. 여기에서 확인: 스프라이트 시트란 무엇인가?

아틀라스 만들기

각 SubTexture의 위치는 이와 같은 XML 파일에 정의됩니다:

1
2
3
4
5
<TextureAtlas imagePath="atlas.png">
 <SubTexture name="moon" x="0" y="0" width="30" height="30"/>;
 <SubTexture name="jupiter" x="30" y="0" width="65" height="78"/>;
 ...
</TextureAtlas>;

보시다시피 XML은 하나의 큰 텍스처를 참조하고 각각 이 해당 텍스처 내의 영역을 가리키는 여러 개의 명명 된 하위 텍스처를 정의합니다. 런타임에 이 하위 텍스처를 이름으로 참조할 수 있으며 마치 독립적인 텍스처인 것처럼 작동합니다.

그런데 어떻게 모든 텍스처를 그러한 아틀라스에 결합합니까? 고맙게도 수동으로 할 필요는 없습니다. 그 일로 당신을 도울 도구가 많이 있습니다. 여기에 두 명의 후보자가 있지만 Google에서 검색하면 많이 나올 것입니다.

  • TexturePacker 제가 즐겨쓰는 것입니다. 어떤 것보다 스프라이트 시트에 대한 많은 제어가 가능합니다. Starling 지원이 뛰어납니다 (ATF 텍스처뿐 아니라 뭐든지?).
  • Shoebox 는 AIR로 제작 된 무료 도구입니다. TexturePacker로 아틀라스를 만들 수있는 옵션은 많지 않지만 비트맵 글꼴 생성이나 스프라이트 추출과 같은 많은 관련 기능이 포함되어 있습니다.
아틀라스 사용하기

좋아요. 여러분에게 텍스쳐 아틀라스가 있습니다. 그런데 어떻게 사용하죠? 텍스처와 XML 데이터를 임베드하는 것으로 시작해 보겠습니다:

1
2
3
4
5
[Embed(source="atlas.xml", mimeType="application/octet-stream")] // (1)
public static const AtlasXml:Class;

[Embed(source="atlas.png")] // (2)
public static const AtlasTexture:Class;

(1) 아틀라스 XML을 임베드하십시오. mimeType을 지정하는 것을 잊지 마십시오.
(2) 아틀라스 텍스처를 삽입합니다.

또는 URL이나 디스크에서 이러한 파일을 로드할 수도 있습니다 (AIR의 경우). Starling의 AssetManager에 대해 자세히 살펴보겠습니다.

사용 가능한 두 객체를 사용하여 새로운 TextureAtlas 인스턴스를 만들고 getTexture() 메서드를 통해 모든 하위 텍스처에 액세스할 수 있습니다. 게임이 초기화되고 끝까지 참조될 아틀라스 개체를 만듭니다.

1
2
3
4
5
6
var texture:Texture = Texture.fromEmbeddedAsset(AtlasTexture); // (1)
var xml:XML = XML(new AtlasXml());
var atlas:TextureAtlas = new TextureAtlas(texture, xml);

var moonTexture:Texture = atlas.getTexture("moon"); // (2)
var moonImage:Image = new Image(moonTexture);

(1) 아틀라스를 만듭니다.
(2) SubTexture를 표시합니다.

매우 간단합니다!

3.5. 텍스처 렌더링

RenderTexture 클래스를 사용하면 텍스처를 동적으로 생성할 수 있습니다. 모든 디스플레이 오브젝트를 칠할 수 있는 캔버스라고 생각하십시오.

렌더링 텍스처를 만든 후에는 drawObject 메서드를 호출하여 객체를 텍스처에 직접 렌더링합니다. 객체는 현재 위치의 텍스처에 그려지며 현재 회전 크기 및 알파 속성을 유지합니다.

1
2
3
4
5
6
7
8
var renderTexture:RenderTexture = new RenderTexture(512, 512); // (1)

var brush:Sprite = getBrush(); // (2)
brush.x = 40;
brush.y = 120;
brush.rotation = 1.41;

renderTexture.draw(brush); // (3)

(1) 지정된 크기(포인트 단위)로 새로운 RenderTexture를 만듭니다. 완전한 투명 픽셀로 초기화됩니다.
(2) 이 샘플에서는 브러시를 묘사한 디스플레이 오브젝트를 참조합니다. 그것을 특정 위치로 옮깁니다.
(3) 브러시 객체는 현재 위치 및 방향 설정으로 텍스처에 그려집니다.

그리기는 그래픽 메모리에서 직접 일어나므로 매우 효율적으로 수행됩니다. 텍스처 위에 오브젝트를 그린 후에는 얼마나 많은 오브젝트를 그려 넣었는지에 관계없이 일반 텍스처와 비슷한 성능을 얻을 수 있습니다:

1
2
var image:Image = new Image(renderTexture);
addChild(image); // (1)

(1) 텍스처는 다른 텍스처와 마찬가지로 사용할 수 있습니다.

한 번에 많은 객체를 그릴 경우 아래와 같이 Bundled draw 메서드를 통해 블록에 도면 호출을 묶는 것이 좋습니다. 이를 통해 Starling은 비용이 많이 드는 작업을 약간 건너 뛸 수있어 프로세스 속도가 상당히 빨라졌습니다:

1
2
3
4
5
6
7
8
renderTexture.drawBundled(function():void // (1)
{
    for (var i:int=0; i<numDrawings; ++i)
    {
        image.rotation = (2 * Math.PI / numDrawings) * i;
        renderTexture.draw(image); // (2)
    }
});

(1) 함수에서 모든 드로우 콜을 캡슐화하여 묶음 도면을 활성화합니다.
(2) 함수 내부에서 이전처럼 ‘draw’를 호출합니다.

렌더 텍스처의 일부를 지우려면 블렌드 모드를 BlendMode.ERASE로 설정하여 “지우개”와 같이 디스플레이 오브젝트를 사용할 수 있습니다.

1
2
brush.blendMode = BlendMode.ERASE;
renderTexture.draw(brush);

깨끗하게 지우려면 clear 메소드를 사용하십시오.

컨텍스트 손실

불행히도 렌더링 텍스처는 하나의 큰 단점을 가지고 있습니다. 렌더링 컨텍스트가 손실되면 모든 내용을 잃게됩니다. ‘Context Loss‘ 는 다음 장에서 자세히 설명합니다. 요컨대 특정 상황에서 Stage3D가 모든 버퍼의 내용을 잃을 수 있음을 의미합니다. (네. 발음만큼 꽤 불쾌합니다.)

따라서, 텍스처의 내용이 계속 유지되는 것이 중요하다면 (즉 눈가림만이 아니라) 몇 가지 조치를 취해야 합니다. 우리는 언급된 장에서 가능한 전략들을 조사할 것입니다 – 제가 이 사실을 여기에서 언급했기 때문에 당신은 덜 놀라게 될 것입니다.

Was this article helpful?

Related Articles