自由に変形できるスプライトのこと。自由に指定した4頂点を用いて違和感なくスプライトを表現する手法。Free Form Deformation(自由変形)の略。Spineなんかのアニメツールで生成されるスプライトにはこの機能が必要。4頂点を2枚の三角形で表現する分にはどんな絵もだせそうであるが、実際には1枚目の写真のようにテクスチャの接合部分で絵が歪む。そもそも歪んだポリゴンとはどういうものなのか?2枚の三角形で構成できるものなのか?
4頂点に対して割り当てた2枚の三角形の接合部分で折れている。2枚の三角形だとコレが限界。テクスチャの歪みがひどい。
4分割。分割数を増やすと滑らかになってテクスチャの歪みが減った。
9分割 だいぶなめらかになってる。テクスチャの歪みも、かなりわかりにくくなった。
16分割 9分割よりは綺麗に見えるけどあまり違いがなくなってきた。
256分割 ここまで細かくしても16分割とは大差がない感じ。ポリゴンの無駄かな。
1枚の四角形を複数の三角形に分けて構成したメッシュにすることでテクスチャの歪みを抑制するスプライト表示。自由な4頂点にも対応しようと思うと2枚の三角形ではねじれに限界がでてくるので分割数を増やさないと上記の通りテクスチャが崩れてしまう。3Dで表現される揺らめくハタなんかの作られ方に近い。
無理だった。四角形の板の法線方向から4頂点がぴったり一致する角度を割り出すことができそうで色々挑戦してみたけれども、ぴったり一致させる為の元の板のカタチ、回転角度を逆算するのが難しい。よしんばそれらが逆算できたとしてもカメラの視野角が変わることで奥ゆきにより長さが変わってしまうことから、視野角の異なるタイトル間ではデータを共有できないとか、このレンダリングの時のみ視野角を固定するとかアニメデータのくせに汎用性がなくなってレンダリングが面倒といった非現実的な要素からこれ以上追いかけるのをやめた。
すごくベタに書くとこんな感じ。
{ gxPoint pos[4]; Sint32 div = divNum+1; if( div < 2 ) div = 2; if( div > 16 ) div = 16; for( Sint32 ii=0; ii<4; ii++ ) { pos[ii].x = pXY[ii].x; pos[ii].y = pXY[ii].y; pos[ii].x *= fx; pos[ii].y *= fy; gxUtil::RotationPoint( &pos[ii] , fRot ); } Sint32 max = div*div; gxPoint* pMat = new gxPoint[max]; gxPoint* pTx = new gxPoint[max]; //四辺の分割座標を確定 for( Sint32 ii=0;ii<div;ii++ ) { pMat[ ii ].x = pos[0].x + 1.0f * ii * ( pos[1].x - pos[0].x ) /( div-1 ); pMat[ ii ].y = pos[0].y + 1.0f * ii * ( pos[1].y - pos[0].y ) /( div-1 ); pMat[ (div-1)*div+ii ].x = pos[3].x + 1.0f * ii * ( pos[2].x - pos[3].x ) /( div-1 ); pMat[ (div-1)*div+ii ].y = pos[3].y + 1.0f * ii * ( pos[2].y - pos[3].y ) /( div-1 ); pMat[ ii*div ].x = pos[0].x + 1.0f * ii * ( pos[3].x - pos[0].x ) /( div -1 ); pMat[ ii*div ].y = pos[0].y + 1.0f * ii * ( pos[3].y - pos[0].y ) /( div -1 ); pMat[ ii*div+(div-1) ].x = pos[1].x + 1.0f * ii * ( pos[2].x - pos[1].x ) /( div -1 ); pMat[ ii*div+(div-1) ].y = pos[1].y + 1.0f * ii * ( pos[2].y - pos[1].y ) /( div -1 ); } //中の補完座標を策定 for( Sint32 ii=1;ii<div-1;ii++ ) { for( Sint32 xx=1;xx<div-1;xx++ ) { Float32 x1 = pMat[ ii*div+0 ].x; Float32 y1 = pMat[ ii*div+0 ].y; Float32 x2 = pMat[ ii*div+(div-1) ].x; Float32 y2 = pMat[ ii*div+(div-1) ].y; pMat[ ii*div+xx ].x = x1 + xx * (x2-x1)/(div-1); pMat[ ii*div+xx ].y = y1 + xx * (y2-y1)/(div-1); } } for( Sint32 yy=0;yy<div;yy++) { for( Sint32 xx=0;xx<div;xx++) { pTx[ yy*div + xx ].x = u + 1.0f * xx * w / (div-1); pTx[ yy*div + xx ].y = v + 1.0f * yy * h / (div-1); } } for( Sint32 yy=0;yy<div-1;yy++) { for( Sint32 xx=0;xx<div-1;xx++) { Sint32 p1,p2,p3,p4; p1 = yy*div + xx; p2 = yy*div + xx+1; p3 = yy*div + xx+1+div; p4 = (yy+1)*div + xx; gxLib::PutTriangle( pMat[ p1 ].x+x , pMat[ p1 ].y+y , pTx[p1].x , pTx[p1].y, pMat[ p2 ].x+x , pMat[ p2 ].y+y , pTx[p2].x , pTx[p2].y, pMat[ p4 ].x+x , pMat[ p4 ].y+y , pTx[p4].x , pTx[p4].y, 0, prio ,ATR_DFLT , ARGB_DFLT ); gxLib::PutTriangle( pMat[ p2 ].x+x , pMat[ p2 ].y+y , pTx[p2].x , pTx[p2].y, pMat[ p4 ].x+x , pMat[ p4 ].y+y , pTx[p4].x , pTx[p4].y, pMat[ p3 ].x+x , pMat[ p3 ].y+y , pTx[p3].x , pTx[p3].y, 0, prio ,ATR_DFLT , ARGB_DFLT ); } } SAFE_DELETES( pMat ); SAFE_DELETES( pTx ); return 0; }