さて。Mesh及びGeometryのイメージが掴めてきたところでAlterrnativa3D 8で頂点制御をしてみよう。
まずはattributesのおさらい(推測)。
3Dは複数の頂点で表される。各頂点はxyz座標以外にもuv座標など複数の情報を持ち、これらの情報の種類は多岐にわたるが、プログラム上(描画上)毎回使用するものではないものもある。
頂点についてはGPUで計算するため、その情報はGPU側のVRAM上に記憶させなくてはならないが、使用しない情報まで各頂点に持たせておくのはVRAMがもったいないので、頂点に持たせる情報の種類を取捨選択できるようにし、プログラム組む側が柔軟に選べるようにした。
これがvertex bufferという配列で、1つの頂点について何種類の情報を持たせるのかが選べる。
また、頂点の番号を結ぶ順番でポリゴンの定義をするのがindex bufferだ。この際、index bufferの中身は2byteで表されるらしい。よってこれを超えると頂点を指定できなくなるため、1つのbufferの頂点の最大数は65536だとか。
vertex bufferには1つの頂点につき任意の情報が任意の順番で与えられる。そこでattributesという、頂点のもつ情報の種類を識別するものが必要になってくる。
VertexAttributesクラスにはこの情報の種類の定義(uint)が入ったstatic constが書かれている。
たとえばxyz座標情報であるVertexAttributes.POSITION=1、
テクスチャのuv座標情報であるVertexAttributes.TEXCOORDS[0]=8だ。
POSITIONという種類の情報なので、xでもyでもzでもこのVertexAttributes.POSITIONを使用する。
また、これらのattributesには指定された次元があり、その数だけまとめて記録しなくてはいけないようだ。
指定された次元はVertexAttributesのstaticメソッドgetAttributesStride()で得ることができる。
getAttributesStride(VertexAttributes.POSITION)=3、
getAttributesStride(VertexAttributes.TEXCOORDS[0])=2だ。
これらのattributesは好きな順番で与えられるが、指定された次元は隣同士でなくてはならない。
attributes=[1,1,1,8,8]
attributes=[8,8,1,1,1]
は許されるが、
attributes=[1,8,1,1,8]
のようにすることはできない。
このように指定したattributes配列の順番にvertex bufferに頂点ごとの情報が入る。
attributes=[1,1,1,8,8]だった場合はvertex buffer=[x0,y0,z0,u0,v0,x1,y1,z1,u1,v1,...]といった具合だ。
つまりvertex bufferの長さは頂点数*attributes数となる。
Planeのコードをもう一度見ると、
var attributes:Array = new Array();
attributes[0] = VertexAttributes.POSITION;
attributes[1] = VertexAttributes.POSITION;
attributes[2] = VertexAttributes.POSITION;
attributes[3] = VertexAttributes.TEXCOORDS[0];
attributes[4] = VertexAttributes.TEXCOORDS[0];
var geometry:Geometry = new Geometry();
geometry.addVertexStream(attributes);
となっている。これは、attributes=[1,1,1,8,8]とし、このattributes配列をGeometry.addVertexStream()に与えることでgeometryの持つattributesを指定している。
そしてそれぞれのVectorを作った後、
geometry.setAttributeValues(VertexAttributes.POSITION, vertices);
geometry.setAttributeValues(VertexAttributes.TEXCOORDS[0], uvt);
でvertex bufferにそれぞれのattributesに対応する頂点情報をセットすることができるわけだ(この段階ではまだVRAMにアップロードはされていない)。
vertex bufferがなんなのか掴めてきたところで、Geometryクラスのメンバをざっと全部見てみよう。
プロパティ
indices : Vector...index bufferに入れる配列
isUploaded : Boolean...Context3Dにアップロードされたかどうか
numTriangles : int...ポリゴン数
numVertexStreams : int...vertex streamの数
numVertices : int...頂点数
簡単だね。vertex streamだけちょっとよくわからないけれど。
メソッド
Geometry(numVertices:int = 0)
コンストラクタ。
addVertexStream(attributes:Array):int
attributes配列を引数にvertex streamを追加する。
dispose():void
Context3Dからgeometryリソースの解放をする。
findVertexStreamByAttribute(attribute:uint):int
attributes識別番号からattributesが所属するvertex stream番号を調べる。
getAttributeOffset(attribute:uint):int
attributes識別番号からattributesがvertex bufferの何番目の情報なのか(次元が2以上の場合は何番目の情報から始まるのか)教えてくれる。
getAttributeValues(attribute:uint):Vector
attributes識別番号からvertex buffer内のattributesの情報をVectorで返す。
getVertexStreamAttributes(index:int):Array
vertex stream番号からそのvertex streamのattributes配列を返す。
hasAttribute(attribute:uint):Boolean
attributes識別番号からvertex buffer内にそのattributesがあるかどうかを返す。
setAttributeValues(attribute:uint, values:Vector):void
attributes識別番号からvertex bufferにattributesの情報をVectorで渡してセットする。
updateIndexBufferInContextFromByteArray(data:ByteArray, byteArrayOffset:int, startOffset:int, count:int):void
updateIndexBufferInContextFromVector(data:Vector, startOffset:int, count:int):void
index bufferの値をアップデートする。どちらもまずデータを渡し、 ByteArrayの場合はByteArrayのどこからアップロードするかを指定。そのあとはどちらもindex bufferの何番目から頂点(もしくは単にindex bufferの長さいくつぶんかも)いくつぶんアップデートするかを指定する。
updateVertexBufferInContextFromByteArray(index:int, data:ByteArray, byteArrayOffset:int, startVertex:int, numVertices:int):void
updateVertexBufferInContextFromVector(index:int, data:Vector, startVertex:int, numVertices:int):void
vertex bufferの値をアップデートする。indexはvertex stream番号。データを渡し、ByteArrayではどこからアップロードするか、そのあとはどちらもどちらもvertex bufferの何番目から頂点いくつぶんアップデートするかを指定する。
upload(context3D:Context3D):void
Context3DにGeometryの情報をアップロードする。
なんか前回めんどくさそうで放置してたけどぜんぶ読めちゃった。
多分に推測入ってるけどだいたいあってると思う。
クラスの説明を読んでみると
Resource, which stores geometry data of object. All data is stored per vertex. It can be useful to split parameters on several vertexBuffer's for independent upload in GPU. (vertexBuffer can be updated only entirely) For this feature, groups of parameters can be stored in different streams, from which will be generated vertexBuffers for upload in GPU.
vertex bufferはまとめてしか転送出来ないが、複数のattributesをまとめたvertex streamをいくつか作ることができ、これらは独立してGPUに転送できる(転送後は全ストリーム1つのvertex bufferに統合されるのかな?)。
このことによってGPUへの転送量を減らすことができるかもしれないってことか。
uv座標ってふつう変わるもんじゃないよね。ということは毎ステップかわる可能性の高いPOSITIONとストリーム分けたほうがよいのかな?
さて、ここまでわかったらさくっと頂点制御行っちゃおう。
と思ったけどコードもあるし記事分けるわ。
Author:9ballsyn
ActionScriptについて
最近はMolehill