본문 바로가기

Starling

Starling 화면을 비트맵에 찍을려면?


Bitmap 객체나 BitmapData 객체를 Starling에 표시하는 방법은 쉽다.


Texture.fromBitmap() , Texture.fromBitmapData() 메서드를 통해 텍스쳐에 전달하여 표시하면 끝.



하지만 반대로 Starling의 현재 화면을 Bitmap 객체로 만들려면 어떻게 해야 하는가?


만약 어플리케이션 내에서 화면을 캡쳐하여 이미지 파일로 저장해야 하는 경우가 생긴다면


이문제를 해결해야 한다.


분명 이러한 상황에 대한 질문이 있을 법한데 검색을 해도 만족할 만한 해답을 찾지 못했다.



어쨌든,


아래는 기존의 stage 에서 만들어진 UI 와 starling 을 이용하여 다수의 이미지를 트윈 시키고 있는 예제이다.



으아아아



목표는 특정 순간의 화면을 Bitmap으로 캡쳐하는 것이다.


stage를 통째로 draw 하면 어떨까?



(는 실패했습니다)



Starling의 표시객체들은 stage가 아닌 stage3D 에 그려지므로 당연한 결과


이 말은 Starling의 화면을 BitmapData 로 만드는 것은 곧,


 stage3D에서 렌더링 될것들을 BitmapData로 만드는것과 같다는 것.



stage3D에 그려지는 내용은 context3D 에 좌우되며


context3D 에는 아래와 같은 메서드가 존재한다.



비트맵에 현재 렌더링 버퍼를 그립니다.




좋아 딱 이거야. 이거면 뭐 더이상 생각할 필요 없이 고민해결. 게임 셋이지!




(그는 좋은 오류였습니다)




버퍼를 지워야 한다는 말이 뭐지?


레퍼런스를 보자.



drawToBitmapData

() 메서드  

public function drawToBitmapData(destination:BitmapData):void

언어 버전:  ActionScript 3.0
런타임 버전:  Flash Player 11, AIR 3

비트맵에 현재 렌더링 버퍼를 그립니다.

백 렌더링 버퍼의 현재 내용이 BitmapData 객체에 복사됩니다. 이 작업은 최대 1초가 걸리는 매우 느린 작업이므로 사용에 주의합니다. 이 함수는 스테이지에 표시되는 전면 렌더링 버퍼가 아니라 그려지는 버퍼를 복사합니다. 스테이지에 표시되는 렌더링된 이미지를 캡처하려면 present()를 호출하기 직전에 drawToBitmapData()를 호출합니다.

이미지는 그려질 때 비트맵에 맞게 크기가 조절되지 않습니다. 대신에 내용이 대상 비트맵의 크기로 클리핑됩니다.



주의깊게 봐야할 점은 전면 렌더링 버퍼가 아니라 그려지는 버퍼를 BitmapData 에 복사한다는 것이다. 


만약 스테이지에 렌더링 된 이미지를 캡처하려면 prenset()를 호출하기 직전에 drawToBitmapData() 호출.


레퍼런스의 예제코드를 보면 아래와 같은 부분이 있다.



    //Clear required before first drawTriangles() call
            renderContext.clear( .3,.3,.3 );
            
            
            //Draw the 2 triangles
            renderContext.drawTriangles( indexList, 0, 2 );
            
            var renderedBitmapData:BitmapData = new BitmapData( viewWidth, viewHeight, true );
            renderContext.drawToBitmapData( renderedBitmapData );
            
            renderContext.present();



버퍼를 지우고 > context.clear()


호출 > drawToBitampData()


바로 뒤에 > present();




이젠  알았다. 별거 아니군. 해보자.


(?????????)



실패라기보다는 draw 하는 것은 성공했지만 막상 아무것도 그려지지 않았다.


clear 호출로 인해 초기화된 검정화면만이 보일뿐이다.



ㅠㅠ.....


확실친 않지만 원인을 예상하자면


매프레임마다 화면에 표시될 정보를 GPU 에 upload, 그리고 실제 렌더링하게되는데


예제코드에선


1.일단 버퍼를 지운 뒤 직접 코드로 표시될 정보를 업로드한 뒤

2.stage3d에 렌더링하는 대신에 버퍼의 내용물을 BitmapData을 채우는데 사용

3.새로운 렌더링 주기를 시작하여 이후 부턴 다시 stage3D에 렌더링


를 하고 있지만 Starling 을 통한 렌더링 작업엔 직접적으로 우리가 개입하여


업로드 <-> 렌더링 사이를 끊지 못하기 때문에 clear 호출 시 Starling 화면까지 모두 지워져 버리는게 아닌가..


하는 소설을 써본다.




Starling 은 오픈소스이기 때문에 코드를 만지작 거리며 해결 할 수 있겠지만


혹시 다른 방법이 있지 않을까 이리저리 해보던 중 꼼수를 발견했다.




미리 말해두지만 이것은 정상적인 해결 방법이 아니다.


사실 정상적으로는 어떻게 하는지 모르겠음ㅠㅜ



context에서 clear()를 호출했을때,


Starling에서 렌더링된 것이 제거되는 영역은 Starling 객체의 viewPort에 따라 변한다.


즉 clear 메서드 호출 직전 viewPort 를 실제보다 적게 조절하면 줄어든 영역만 clear가 되며


그 여분의 공간은 아직 지워지지 않고 있다..


물론 바로 다음 프레임이 되어 새로운 렌더링이 시작되면


Starling 은 줄어든 vewPort 만큼 크기가 조절되며 다시 여분의 공간은 텅 비게 되지만


중요한것은 그 순간만큼은 지워지지 않았다는 것이다.  그리고 우린 그 순간을 draw 하면 된다.


(context의 configureBackBuffer() 메서드로는 이러한 결과가 나타나지 않았다.

분명 같은 context 인데... 처리되는 순서에 의해 이런 결과가 나오는게 아닌가 싶다)



아래는 viewPort 를 100 x 100 으로 변경한 뒤 clear를 호출한 결과이다.


(UI 아래로 100x100 의 부분만 지워져 있다)



이젠 뭐 누워서 껌먹기지.


마지막으로 주의해야 할 점은 2가지이다.


viewPort의 최소 영역은 32 *32 이다.


이런건 뭐 상황에 맞게 starling 컨테이너 자체의 크기나 컨테이너 혹은 내용물의 위치를 조절해서 해결할 수 있다.


또다른 한가지는 drawToBitmapData 메서드의 제한 중 하나인 아래의 문제.


이미지는 그려질 때 비트맵에 맞게 크기가 조절되지 않습니다.

대신에 내용이 대상 비트맵의 크기로 클리핑됩니다.


만약 Bitmap 결과물의 사이즈가 조절되야 할 경우 어쩔수 없이


Starling의 화면을 원본사이즈의 BitmapData에 draw한 후


결과물이 될 Bitmap의 BitmapData 에 Matrix 를 활용해 다시 draw 해야한다.




아래는 최종 결과물.


화면찍기 버튼을 누르면 화면을 캡쳐한 후 50% 크기의 jpg 파일로 저장한다.







숨막히는 반전,크롬의 함정

완벽하다고 생각했는데 블로그에 올리고 나니 크롬브라우저에선 stage3d가 draw 되지 않음 ㅋㅋㅋ


익스, 파폭, 오페라 브라우저와 데스크탑에선 제대로 되는데 크롬은 왜 그런지 모르겠다.


꼼수의 한계일 수도 있고 


아니면 크롬에 내장된 플레이어문제이거나 브라우저의 gpu 지원에 따른 차이점때문인가?


글고 이거 왜 wmode를 direct로 해놨는데 포스팅글을 수정하고 나면 다시 transparent 로 변하는거지;;??



어ㅣ;ㅏ머아ㅣㅓㅏ어아ㅓ라아ㅏ아 제대로된 방법 좀 누가 가르쳐줬음 좋겠다.. 


일단 사용된 코드는 아래에






PS.

content uses capabilities that require a license.  이 문구는 뭐지?