Bitmapdata로 Blitting를 구현하기
웹을 돌아다니다보면 visualist라고 부르는 사람들의 플래시 작품을 보게됩니다. 상당히 현란하고 부드러운 애니메이션 보면 이게 과연 플래시 성능으로 가능하단 말이야? 라는 생각까지 들곤하죠. 대부분 이러한 전시(?) 전용 플래시가 높은 성능을 낼 수 있는 이유는 뭘까요? 여러 가지 자신 만의 노하우를 사용했겠지만 다음과 같은 공통점이 있습니다.
- Interaction이 없거나 단순한 이벤트만 처리한다.
- Bitmapdata를 사용한다.
반대로 생각해 봅시다. 다른 플래시 어플은 왜 느릴까요? 의외로 답은 당연한 곳에 있습니다.
- DisplayObject 모델을 사용하여 복잡한 객체구조로 표현한다.
- event 모델을 이용하여 복잡하게 이벤트를 전파한다.
여러 가지 다른 이유도 있을 수 있지만, 사실 다른 이유보다는 위의 두 가지가 Direct2D로 작동하는 설치형 어플같은 FPS를 낼 수 없게 만듭니다.
as3가 제안하는 Display 모델과 Event 모델은 사실 플래시플레이어가 감당하기엔 너무 무거운 객체구조라는 겁니다. 이는 마치 광범위한 핫스왑이 잡히기 전인 자바 1.2x. 1.3x 시대의 swing과 같은 느낌입니다.
그러면 visualist 들의 작품과 같이 부드러운 FPS를 갖게 하면서도 기존 플래시 어플이 처리 해주던 모든 Event와 Display의 다양한 기능을 사용하려면 어떻게 해야할까요?
API 수준의 화면 객체 구조를 사용하는 것은 여러가지 그래픽 통합 기능도 있지만, 화면 내의 특정 객체를 식별하기 위한 베이스를 제공하기 위함입니다. 따라서 이러한 개별 객체를 식별할 수 있는 가상의 디스플레이층을 만들어내면 단 한 장의 Bitmapdata에 모든 그래픽 요소를 그릴 수 있습니다. 따라서 그리는 과정은 아래와 같이 요약됩니다.
- 캔버스로 사용할 한 장의 BitmapData를 준비한다.
- 자식이 될 element 클래스는 인스턴스 별로 자신만의 고유한 BitmapData와 x, y 등의 화면객체로서 속성을 갖는다.
- EnterFrame에서 캔버스를 완전히 지우고 자식들을 순서대로 차근차근 위치에 맞춰 draw 또는 copyPixels 를 통해 그려간다.
여튼 그리는거야 BitmapData에 차근 차근 draw를 하거나 copyPixels를 해가면 순서대로 잘 그려집니다만, Event는 어떻게 처리할까요? 저는 이 부분을 다음과 같이 해결했습니다.
- 캔버스와 같은 사이즈로 Bitmapdata을 한 장 더 준비한다.
- 자식 element들은 자신만의 고유한 색상을 갖는다.
- 캔버스에 자신을 그릴 때 다른 BitmapData에 자신의 색으로 동일한 위치에 같은 모양을 그린다.
- 위의 과정을 통해 DepthMap 이 생성된다.
- 마우스 이벤트를 stage나 Sprite수준에서 받은 후 mouseX, mouseY의 위치를 이용하여 depthMap.getPixel32( x, y ) 를 하면 특정 색이 얻어진다.
- 그 색이 어떤 element의 색인지를 조사하여 누가 이벤트를 받은 건지 구분해낸다.
따라서 내부적으로는 BitmapData를 두 장을 유지하게 됩니다. 이제 실제 샘플을 보겠습니다. 왼쪽이 캔버스고 오른쪽은 DepthMap 입니다. 원래 어플에서는 보이지 않지만 이해를 위해 일부러 노출했습니다. 미키마우스를 클릭해보세요.
결론
추상 디스플레이를 구축한 뒤, 매번 지우고 다시 그리게 하는 게 API의 Display 모델보다 느릴 것 같지만 훨씬 빠릅니다. 실제 플래시의 대부분의 리소스는 화면처리가 잡아먹고 있습니다. 이러한 화면처리를 최소화하고 데이터 로직으로 돌릴 수록 더욱 기민한 어플리케이션이 됩니다. BitmapData를 캔버스로 쓰는 방법은 어찌보면 거의 모든 OS에서 그래픽을 표현하는 기본적인 방법입니다. 또한 플8시절부터 제한적인 성능 내에서 게임을 구현하기 위해 자주 사용하던 방법입니다.
이 BitmapCanvas(가칭)모델을 사용하면 일단 Stage에 단한개의 Bitmap객체만 등록되고, stage에서는 딱하나씩 이벤트 리스너를 종류별로 등록합니다. 또한 각 리스너는 $e.stopImmediatePropagation(); 를 지정할 수 있고 더욱 강력한 것은 Stage.mouseChildren = false; 를 할 수 있다는 점입니다. 따라서 위에서 언급했던 성능의 한계(Display모델, Event모델)를 뛰어넘게 됩니다.
최근 웹게임이 뜨고 있고 설치형 캐쥬얼 미니게임이 유행하는 요즘. 일반적인 Display객체로는 도저히 부드러운 느낌의 애니메이션이 나오지 않습니다. 높아진 소비자의 눈을 맞추기 위해 정말 어쩔 수 없이 Bitmap Canvas모델로 이동하는 군요 ^^; 위의 플랫폼으로 구현된 애니메이션은 아래와 같은 느낌입니다.
관련된 글:
디스플레이의 최적화 ^-^와 뎁스 맵… 정말 생각지도 않은 걸 매번 내놓으시니
신나기도하고 의욕에 차기도 하고 좋습니다 ㅋ ~ 좋은 정보 감사합니다 ~
fps가 높을때 깜빡인다고 해야하나 웨이브가 지는데..고민중.
이미 처리하셨는데도 불구하고 그러는지는 잘모르겠지만…
더블 버퍼링, 스왑체인 개념으로 여러개의 BitmapData 캔버스를 사용해 Bitmap에 바꿔 끼워주는 형식은 어떨런지요?
더블버퍼링은 사실 아무 상관없습니다 ^^
다른 플랫폼의 경우 bitmapData.lock()이란 메서드가 없기 때문에 더블버퍼링을 쓴다라고도 할 수 있습니다. 플래시는 자체적으로 비트맵의 업데이트를 화면에 표시하지 않고 최종상태만 내보내는 능력이 있기 때문에 깜빡임은 그런곳에서 오는게 아니라 스테이지의 렌더링 주기때문에 오게됩니다.
몇가지 렌더동기화 기법들이 존재하긴 하는데 역시 답은 fps를 적당한 수준에서 처리해야겠죠.
참고로 다른 언어의 버퍼링 기법이나 스왑을 사용하면 더욱 느려집니다 ^^ 각 플랫폼별 특성이 존재하기 때문에 일반론적으로만 접근할 수가 없는게 아쉬운 점이죠.
d이거야 말로 누가 어떠한 구조로 알고리즘을 만드느냐에 따라 성능차이가 퐉나겠네요…
진정.. 프로그래밍의 맛을 느낄수 있겠습니다 !!!!
그..그렇게까지야. 다른 언어에서는 당연한 것들을 구현했을뿐입니다 ^^;
대박 포스팅 감사합니다.
노땅 소리 듣는 늦은 나이에 욕구 충전 시켜주시네요.
이 포스트는 당장 따라해봐야겠습니다.
많이 배워갑니다.
감사합니다~~~
ㅎㅎ 큰 칭찬에 감사드립니다.
그렇지 않아도 이 부분에 대한 공부를 시작했습니다. 저한테 정말 적절한 시기에 너무 좋은 글을 올려주셨네요. 요즘 게임부분으로 눈을 돌리기 시작했는데 큰 도움이 됩니다.
이 모듈의 이름은 CScanvas 입니다만, 실제 사용은 CSdoc를 이용해서 사용하도록 변경되었습니다.
CSdoc.ADD( ‘캔버스명’, 자식들..)
이런식으로 CSdoc의 첫번째 인자가 doc가 아닌 문자열이 오면 생성해둔 캔버스를 인식해서 전부 캔버스 모드로 작동하는 식으로..ddo에서 익스프레션까지 수정한 초대형 작업이었습니다 ^^;
예전에 Visual C++이나 Quick Basic 로 개발할때 이런개념을 몇번 사용한 적이 있는데… Flash를 하면서 거의 생각을 안하게 되더군요. ㅎㅎ
요즘 픽피쉬, 팝캡, 한게임의 팩군 등 캐쥬얼 설치형 미니게임들이 너무 퀄리티가 좋아요.
대응하려면 display모델로 작성된 프레임레이트로 대적하기 힘들더라구요.
가끔씩 오면서 눈팅만 했었는데, 들를때마다 감동을 받습니다.
깊이 있는 내용으로 이해하기 쉽도록 포스팅하시는 것을 보면서 매번 감사하게 됩니다.^^
시간 가는 줄 모르고 읽게 됩니다.
가끔씩 리뷰한 책도 많은 도움이 되는거 같습니다.
앞으로도 좋은 글 계속 볼수 있으면 좋겠다는 작은 바램이 생깁니다 ^^
개인적으로 2D 이미지를 몰핑시켜 남여 얼굴을 합성하는 것을 제작 중인데, 흐름은 알겠는데 실 코딩 들어가니 막히는게 꽤 되네요. 혹시 실례가 않된다면 참고할 만한 서적이 없을까요? 염치 불구하고 여쩌봅니다 ^^;;
헛 이미지 프로세싱 분야에서 까다롭기로 유명한 몰핑이군요 ^^;
몰핑의 기초이론은 역시 영상처리 분야의 형태학적 처리 카테고리 입니다. 영상처리 책 대부분이 openCV를 다루거나 단순 필터링에 치중하는 편이라 형태학적 처리를 전문적으로 다루는 책은 희귀한 편입니다.
이제 처음 들어가시는 수준이시니 영상처리 관련 서적을 서점에서 보시고 형태학적 처리에 대해 다룬 섹션을 비교해보시고 고르세요 ^^
짚히는 책이 없는건 아니지만 추천해드리기는 좀 애매한 부분이네요 ^^
답변 감사합니다. ^^
한번 이런식으로 처리를 해보면 어떨까 생각은 하고 시도는 안해보고 있었는데ㅋ 덕분에 좋은걸 알아가네요. (클릭처리에 관해서도 명쾌한 답변을 쓰셔서 윈도우즈용 게임을-요즘 윈도우즈API 연습을 하고 있습니다ㅋ-제작할 때에도 도움이 많이 될듯 합니다.)
유용한글 많이 보고 갑니다.
감사합니다. 원래 귀찮은 것만이 유일한 사바세계의 문제점이죠 ^^