『 Papervision3Dでオブジェクトの原点をずらして変形する 』
2009 年 3 月 31 日
普通、Papervision3Dがデフォルトで用意している3Dオブジェクトは中心点がオブジェクトの中心にあるので、拡大縮小を掛けると上下左右前後同じように広がっていきます。
今回Planeを拡大させる際にx軸の負の方向には拡大せずに、x軸の正の方向へのみ伸びていく表現(上図の感じ)が必要だったのでメモ。要はオブジェクトの左端から中心点までの距離を変えずに、もう片方だけがウニョっと伸びていく表現がしたかったのです。
scaleXプロパティを使わずにやる必要があったので、かなり強引に実装しました。以後、直感的に読める(書ける)ようにx軸の負の方向を左側、x軸の正の方向を右側とします。
手順1.平行移動

3Dオブジェクト(object3dとする)の一番左側の頂点のx座標が0となるように、頂点全体を右側へ平行移動します。
移動幅をoffsetとすると
var offset:Number = beforeWidth / 2;
で表せます。オブジェクトの頂点情報はobject3d.geometry.vertices配列にVertex3Dクラスとして格納してあるので、for eachループで引っ張ってきます。
for each (var v:Vertex3D in object3d.geometry.vertices) {
v.x += offset;
}
手順2.拡大縮小

いよいよ拡大縮小処理。全頂点のx座標を一律倍します。ウニョ。
頂点のx座標に適用する倍率をscaleとすると
var scale:Number = afterWidth / beforeWidth;
で表せます。先ほどと同じようにして頂点の座標をいじります。
for each (var v:Vertex3D in object3d.geometry.vertices) {
v.x *= scale;
}
0には何を掛けても0なので、一番左側の座標は変わりません。これで、オブジェクトの左側の座標を原点から変えずに拡大縮小を実現できました。
手順3.平行移動再び

このままではオブジェクトの左端の座標がoffsetだけ右にずれてしまっているので、左端が変形前のx座標に揃うように全体を移動してあげます。これは手順1の逆操作をすればよいので
for each (var v:Vertex3D in object3d.geometry.vertices) {
v.x -= offset;
}
これで、変形前と変形後で左側の座標と中心点を変えずに、オブジェクトを変形させることができました。
コードをまとめると、とてもシンプル。
var offset:Number = beforeWidth / 2;
var scale:Number = afterWidth / beforeWidth;
for each (var v:Vertex3D in object3d.geometry.vertices) {
v.x = (v.x + offset) * scale - offset;
}
他にもいくつかやり方がありそうです。先に拡大縮小して、後で位置を合わせたり。紹介した方法は手順が多めですが、マトリクスを用いた代表的な変形方法とよく似ているし、分かりやすいので僕は好きです。
補足
マテリアルによっては、オブジェクトのサイズを変えると、テクスチャのクリッピング範囲も変更しないとうまく表示されない場合があるかも。特に、MovieMaterialなどをしている場合は注意。
object3d.material.rect = new Rectangle(0, 0, afterWidth, afterHeight);
のようにrectプロパティ(MovieClipのどの範囲をテクスチャとして使用するか)を適宜変更することで正しいアスペクト比でテクスチャが表示されるようになります。
なお、Vertex3Dにはextraというプロパティがあって、ユーザが自由に使えるようになっています。
ウニョウニョ何回も伸ばしたり戻したりしたい場合は、変形前後の頂点座標を最初に計算だけしておいて、各頂点のextraに突っ込んでおくと良いです。
var offset:Number = beforeWidth / 2;
var scale:Number = afterWidth / beforeWidth;
for each (var v:Vertex3D in object3d.geometry.vertices) {
v.extra = {
x0 : v.x, //変形前
x1 : (v.x + offset) * scale - offset //変形後
};
}
変形させるときは
for each (var v:Vertex3D in object3d.geometry.vertices) {
v.x = v.extra.x1;
}
戻すときは
for each (var v:Vertex3D in object3d.geometry.vertices) {
v.x = v.extra.x0;
}
こういった感じで。
いじょです!(o’c_,`人)・:*:・
6月 1st, 2009 at 2:42 PM
[...] 構造自体は普通にDisplayObject3Dの入れ子。回転座標系のためにalumicanさんの『 Papervision3Dでオブジェクトの原点をずらして変形する 』というエントリーを参考にさせていただきました。 [...]