テンセグリティ

tensegrity
>> demo
(※要FlashPlayer10 マウス操作で回転を制御できます)

引き続きVector3D/Matrix3Dを使う練習。
今回はTensegrity – Wikipedia を作ってみます。
圧縮する力と引っ張る力がちょうど釣り合って安定した構造体を形成するそうです。
参考:テンセグリティの作り方 How to make a Tensegrity
   テンセグリティ(Tensegrity)
また、CiNiiでもテンセグリティに関する論文(主に日本建築学会)を何本も見つけることができます。
( CiNii 検索条件: フリーワード “テンセグリティ” すべてを含む )

一応、ストローと輪ゴムで作ることはできたんですが、見た目が貧相すぎたので後日改めて作り直します。。
とりあえずここではFlashでテンセグリティを工作。これなら不器用な僕でもキレイに作れます。

graphics.drawPath() では直接Z軸方向に線を引くことができないようなので、
透明なキャンバスを圧縮材2本1組に対して1枚用意し、正面からテンセグリティを見て二次元で線を引きます。
それを角度を変えて空間に差し込んでいき、後から引張材を引っかけていくイメージです。
これは圧縮材を2本平行に並べていくタイプなので、点より面で考えた方がコードも短く済みそうです。

Papervision3Dを使わなくてもテンセグリティくらいなら割と簡単に作れることがわかりました。
ただ、これをシミュレーションさせるには何か物理エンジンを使わないと大変かも。
参考:YouTube – PhysXでテンセグリティのシミュレーション

・ソースコード
(入り組んだ物体や面が交差するような場合にはZソートが使えないので重なりが変になっています;)
[as]
package {
import __AS3__.vec.Vector;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Matrix3D;
import flash.geom.Vector3D;

[SWF(width = “400”, height = “400”, backgroundColor = “#ffffff”, frameRate = “60”)]

public class Test3D extends Sprite {
private var container:Sprite;
private var tensegrity:Tensegrity;
private var size:int = Tensegrity.SIZE/2;
private var nX:Number;
private var nY:Number;

public function Test3D():void {
container = new Sprite();
tensegrity = new Tensegrity();
nX = container.x = (this.stage.stageWidth/2) – size;
nY = container.y = (this.stage.stageHeight/2) – size;
container.z = 0;
stage.addChild(container);
container.addChild(tensegrity);
container.addEventListener(Event.ENTER_FRAME, rotate);
}
private function rotate(e:Event):void {
var rotX:Number = (mouseY – size – nY)*0.1;
var rotY:Number = (mouseX – size – nX)*0.1;
var mat:Matrix3D = container.transform.matrix3D;
mat.appendTranslation(-nX – size, -nY – size, 0);
mat.appendRotation(rotX, Vector3D.X_AXIS);
mat.appendRotation(-rotY, Vector3D.Y_AXIS);
mat.appendTranslation(nX + size, nY + size, 0);
container.transform.matrix3D = mat;
}
}
}

// 6パート・プッシュ・プル テンセグリティ
import __AS3__.vec.Vector;
import flash.display.Shape;
import flash.display.Sprite;
import flash.geom.Matrix3D;
import flash.geom.Vector3D;

class Tensegrity extends Sprite {
public static const SIZE:int = 240; // 縦横サイズ
private var compression:Vector.; // 圧縮材
private var tension:Vector.; // 引張材
private var commands:Vector.; // moveTo, lineTo の指定
private var data:Vector.; // 座標データ

public function Tensegrity():void {
compression = new Vector.(3, true);
tension = new Vector.(12, true);
commands = Vector.([1, 2, 1, 2]); // moveTo -> lineTo -> moveTo -> lineTo
setCompression();
setTension();
}
private function setCompression():void {
var color:Vector. = Vector.([0xff7fbf, 0x7fffbf, 0x7fbfff]);
data = Vector.([SIZE/3, 0, SIZE/3, SIZE, SIZE/3*2, 0, SIZE/3*2, SIZE]);

for(var i:int=0; i<3; i++) { compression[i] = new Sprite(); compression[i].z = 0; with(compression[i].graphics) { lineStyle(5, color[i]); drawPath(commands, data); lineStyle(5, color[i]); drawCircle(SIZE/3, 0, 3); drawCircle(SIZE/3*2, 0, 3); drawCircle(SIZE/3, SIZE, 3); drawCircle(SIZE/3*2, SIZE, 3); } addChild(compression[i]); } compression[1].transform.matrix3D.appendRotation(90, Vector3D.X_AXIS); compression[1].transform.matrix3D.appendRotation(90, Vector3D.Z_AXIS); compression[1].transform.matrix3D.appendTranslation(SIZE/2, 0, -SIZE/2); compression[2].transform.matrix3D.appendRotation(90, Vector3D.Y_AXIS); compression[2].transform.matrix3D.appendRotation(90, Vector3D.Z_AXIS); compression[2].transform.matrix3D.appendTranslation(SIZE, SIZE/2, SIZE/2); } private function setTension():void { var len:Number = Math.sqrt(5/18*SIZE*SIZE); // SIZE/3*SIZE/3 + SIZE/6*SIZE/6 var angle:Number = Math.atan(1/3)*180/Math.PI; // (SIZE/6)/(SIZE/2) var k:int = 0; for(var i:int=0; i<12; i++) { tension[i] = new Shape(); tension[i].z = 0; tension[i].graphics.lineStyle(0, 0xdddddd); } for(var i:int=0; i<3; i++) { k = i << 2; data = Vector.([SIZE/3, 0, 0, len, SIZE/3*2, 0, SIZE, len]);
tension[k].graphics.drawPath(commands, data);
tension[k].transform.matrix3D.appendRotation(angle, Vector3D.X_AXIS);
tension[k+1].graphics.drawPath(commands, data);
tension[k+1].transform.matrix3D.appendRotation(-angle, Vector3D.X_AXIS);
data = Vector.([SIZE/3, SIZE, 0, SIZE – len, SIZE/3*2, SIZE, SIZE, SIZE – len]);
tension[k+2].graphics.drawPath(commands, data);
rotationAtOrigin(tension[k+2], SIZE, angle, Vector3D.X_AXIS);
tension[k+3].graphics.drawPath(commands, data);
rotationAtOrigin(tension[k+3], SIZE, -angle, Vector3D.X_AXIS);
for(var j:int=k; j<=k+3; j++) compression[i].addChild(tension[j]); } } private function rotationAtOrigin(object:Shape, size:int, angle:Number, axis:Vector3D):void { var mat:Matrix3D = object.transform.matrix3D; mat.appendTranslation(-size, -size, 0); mat.appendRotation(angle, axis); mat.appendTranslation(size, size, 0); object.transform.matrix3D = mat; } } [/as]

あわせて読む:

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です