본문 바로가기

Starling

Starling 과 Image. 그리고 VertexData - 2. stage3D 맛보기


이전 글에서는 stage 의 drawTriangles 를 통해 가볍게 몸을 풀어 보았다.



이번 포스팅은 Starling에서 Image 의 VertexData 를 조작하기에 앞서


그 기반이 되는 stage3D의 렌더링에 대해 조금 알아보고 예제를 만들어 보기로 한다.


예제는 이전글에서 stage 를 통해 한 것을 똑같이 stage3D 로 만들어 보는 것이다.




구구절절 stage3D 가 무엇이니 언제부터 지원했느니 GPU 는 어떻게 작동하느니 하는 것은 쿨하게 생략하자.


Figure 1. The blocks of a fixed function graphics pipeline.

이런거라던지

Figure 2. The blocks of the programmable graphics pipeline.
이런거라던지
Figure 3. Understanding how Stage3D is displayed as the stage behind the Stage.

이런것들은 다 생략.


몰라도 지구는 돌아가는데 이딴거 알게뭐야?

.
.
.
.
.
.


는 아니고 매우 중요하긴 한데 비루한 나 따위가 설명하는 것보다  이곳 에서 제대로 배우는게 나을 것 같다.

카우보이모자 쓴 형이 잘 알려주고 있다.

시리즈물로 되어 있으므로 쭉 읽어나간다면 많은 도움이 될 것이다. 사실 그림과 코드만 봐도 반은 이해할 수 있다.




마음 같아선 번역 포스팅을 해보고 싶지만 그럼 또 언제 끝날지 알수가 없어서...

딱 필요한 정도만 간단하게 짚고 넘어갈 생각이다.

지루하더라도 일단 참고 보도록 하자.






AGAL ( Adobe Graphics Assembly Language )


gpu 가속은 결국 gpu 가 작업하게 되므로 CPU를 위한 코딩용으로 설계던 ActinoScript 와는 다르게


gpu가 잘 알아먹는 언어를 사용해야 하는데 이를 셰이딩언어라고 한다.


OpenGL 과 DirectX 에서 이미 사용되고 있는 셰이딩언어가 있지만


우리의 Adobe 는 그딴 거 필요없이 새로운 셰이딩 언어를 만들어 내었다.



이름하여 Adobe Graphcis Assembly Language.



이름에서 이미 어셈어셈한게 느껴진다.  눈치챘겠지만 이는 어셈블리 언어이고


이 말은 곧 GPU 는 행복한만큼 대다수의 우리는 불행해진다는 의미이다.




심적으로 받아들이긴 힘들긴 하겠지만  stage3D 에서 작업을 하려면 AGAL 을 사용할 수 밖에 없다...


물론 Starling 에서도 당연히 AGAL 은 사용되고 있다.

-----------------------------------------------------------------------------------

-----------------------------------------------------------------------------------

Starling QuadBatch 클래스의 코드 일부.



우리는,

우리가 조금 덜 불행하도록 이 AGAL 을 최소한 외계어보다는 친숙하게 만들 필요가 있다.






쉐이더


그래픽스 파이프라인 에서 프로그래밍 가능한 코드를 쉐이더라 한다.


쉐이더는 cpu 에서 실행되지 않고 그래픽 하드웨어 gpu 에서 실행되는 작은 프로그램으로


크게 정점쉐이더(VertexShader) 와 단편쉐이더(fragementShader) 로 나뉜다.



아래는 정점 쉐이더의 한 예이다.


m44 op, va0, vc0

mov v0, va1



쉐이더의 모든 줄은 하나의 명령으로 opcode 라 불리는 세자리 문자열로 명시 된다.



AGAL 의코드 문법은 아래와 같다.


<opcode> <destination>, <source1>, <sourdce2 or sampler>



이중에서 destination 과 source 는 레지스터라 부른다.


source 는 명령에 사용할 값을 담고, destination 은 그 결과가 저장되는 곳이다. 


자세한 포맷은 이곳 에서 확인 할 수 있다.




stage3D 에서는 쉐이더를 Program3D 라는 클래스로 감싼 후  GPU 에 업로드하게 된다.

upload(vertexProgram:ByteArray, fragmentProgram:ByteArray):void
AGAL(Adobe Graphics Assembly Language) 바이트 코드로 표현된 렌더링 프로그램 쌍을 업로드합니다.


여기서 잠깐. upload 메서드엔 ByteArray 형태의 인자를 요구하고 있는데 어떻게 해야 할까?


여기서 문자열로 이루어진 쉐이더 프로그램을 ByteArray 로 적절하게 바꿔 줄 AGALMiniAssembler 클래스가 필요하다.


AGALMiniAssembler 클래스는 런타임에 포함되어 있지 않으므로 아래의 주소에서 다운 받을 수 있다.


http://www.bytearray.org/wp-content/projects/agalassembler/com.zip 


역시 Tinbault Imbert 형이 짱이다. 



이 글을 보는 여러분은 아마 Starling 을 사용하고 있을 것이고


Starling 프레임워크에는 이미 AGALMiniAssembler 가 포함되어 있다.





기본 흐름



stage3D 에서의 작업은 stage 와 비슷하다.


텍스쳐를 준비하고,


각 정점 데이터를 기술 한다음


정점 데이터를 읽은 순서를 정하고


삼각형을 그린다.


큰 흐름은 똑같다.


단지 조금 더 귀찮을 뿐이다.


바로 코딩 들어가자.






백문이불여일RUN



프로젝트는 이전 포스팅에서 사용한 프로젝트를 그대로 사용하면 된다.


똑같이 DisplayPoint 를 이용해 정점을 조절하고 _model 에서 받아와 화면에 표시한다.


단 View 가 달라진다.




변화된 메인클래스를 보자.



전과 거의 같다. 



다른 점은 딱 하나,


initView 메서드에서 

NativeStageView 가 아니라 NativeStage3DView 를 화면에 표시하고 있다.



NativeStage3DView 클래스는 어떻게 생긴놈인지 살펴보자.


코드가 NativeStageView 보다는 쪼오오오금 길다.



한구문 씩 살펴보자.



초기화


우선 화면에 add 되어  stage 에 대한 접근이 가능해지면 stage3Ds 속성을 통해 stage3D 객체를 구한다.


stage3Ds 에 담겨있는 stage3D객체의 수는 플랫폼에 따라 다르다. 모바일은 하나만 지원한다.


제공되는 stage3D 객체를 구했다면 Context3D 객체를 요청하고 Context3D 객체가 생성이 되면 init 메서드를 실행한다.




텍스쳐


우선 사용할 텍스쳐를 준비하자.



텍스쳐는 직접 생성할 순 없고 context3D 객체를 통해 얻을 수 있다.


텍스쳐를 반환하는 메서드는 기존엔 createTexutre 메서드만 존재 했으나


AIR 3.8 부터 RectangleTexture 를 반환하는 createRectangleTexture 라는 메서드가 추가되었다.



RectangleTexutre 는  Texutre 와는 다르게 폭과 높이가 2의 거듭제곱일 필요가 없고 밉맵을 포함하지 않는다.


텍스쳐로 사용할 이미지의 크기를 2의 제곱으로 맞추는것은 귀찮은 일이다.


여기서는 밉맵을 적용할 일도 없으므로 RectangleTexture 를 사용하였다.


텍스쳐가 준비되면 GPU 에 업로드 한다.




정점


다음으로 할일은 정점 데이터를 정의하는 것이다.


텍스쳐 매핑의 경우 보통 한 정점을 표시하기 위해  ( x, y, z, u, v ) 5개의 속성이 사용된다.


텍스쳐맵핑이 필요없는 단순 도형의 경우 u,v 대신 r,g,b,a 등의 색상 정보가 포함되기도 한다.

( Starling 에서는 z 가 빠지고 u,v,r,g,b,a 가  같이 기술되어 있다. Image 냐 Quad 냐에 따라 선택되어져 사용된다 )



실제 정점 데이터는 화면에 표시된 DiaplayPoint 의 위치정보를 Model 을 통해 얻을 것이다. 

여기서는 빈 Vector 만 만들어놓자.



그 다음은 삼각형을 정의할 인덱스버퍼를 만드는 것이다.



정점을 그려나갈 순서는 이전 예제와 동일하지만 좀 병맛인것이


stage 에서는 Vector.<int> 타입으로 받고

stage3D 에서는 Vector.<uint> 타입으로 받는다.


아 귀찮게.... uint 로 다시 하나 만들어놓자.


현 예제에서 인덱스 순서는 바뀌는 경우가 없으므로 이시점에서 인덱스 버퍼에 담아 GPU에 한번만 올려두면 된다.




쉐이더


이제는 쉐이더를 만들어야 한다.


정점 쉐이더는 아래와 같다.

m44 op, va0, vc0

mov v0, va1


정점 쉐이더는 정점을 액션스크립트에서 받은 행렬을 이용해 변환하고 uv 좌표를 단편쉐이더로 전송한다.



단편쉐이더는 아래와 같다.

tex ft1, v0, fs0 <2d>

mov v0, va1


단편 쉐이더는 보간된 uv 좌표를 가지고 텍스쳐를 표시한다.



이 쉐이더 코드들은 문자열로 이루어져 있으므로 AGALMiniAssembler 를 이용해

program3D 의 upload 메서드에 전달하여 GPU 에 쉐이더를 업로드하도록 하자.





기본 변환행렬



stage3D 에선 기본적으로 화면 중앙이 0,0 원점으로 되어 있고 Y좌표는 반대이며


x , y 값을 -1,1 로 해야 좌측상단을 가르키는 평범한 우리에겐 비범함 좌표체계를 가지고 있다.


우리가 소율이를 위해 준비한 각 정점은 stage 에 포함된 displayPoint 객체의 위치를 받아오고 있기 때문에


이를 stage3D 에서도 그대로 쓸려면 좌표를 적당히 바꿔줘야할 필요가 있다.



_helperMatrix는 ' 좌표를 적당히 바꿔주는' 일을 할 때 필요하다. 그냥 내 입맛대로 만들었다 ㅋ




렌더링



Control 클래스 내부 displayPoint 를 드래그하여 좌표가 바뀌면 update 메서드가 실행된다.




model 에서 얻는 정점의 xy 좌표와 UV 값이 따로 분리되어 있으니


 x, y, z , u , v  형태로 정점을 기술하기 위해 model 에서 얻어온 데이터를 믹스시키자.


z 는 사용하지 않으므로 0으로 고정시켰다. 사실 여기서 z값을 바꿔도 아무런 변화가 없을 것이다.


z를 사용하려면 원근투영 (PerspectiveProjection ) 을 위한 몇가지 작업과 행렬변환과 기타등등이 필요한데

그냥 하지말자.ㅋㅋㅋㅋ 



그다음, 화면을 비우고,


변화된 정점 정보가 담긴 정점버퍼를 업로드하고,


버퍼에 맞게 context3D 를 구성한 뒤,


drawTriangles로 삼각형을 그리고,


present 를 호출해 마무리한다.



그럼 아래와 같은 결과를 얻는다.

                                                      날따라 투♥.swf




힘빠지겠지만 당연히 stage 위에서 했던 것과 같은 결과물이다.


단 이번엔 stage 가 아닌 stage3d 에서 렌더링 되고 있다. 씡난댜.





자 우리는 stage 와 stage3D 에서 "Hello Image" 정도를 해봤다.


텍스쳐를 화면에 보여줄 때 정점 데이터가 어떠한 역할을 하는지만 대충 이해되었으면 목적은 이룬셈이다.


다음 포스팅에선 이와 똑같은 작업을 Starling 을 이용하여 해보도록 하자.




계속...