3D描画してみたくなったのでちょっとお勉強。

Javaで3D表示しよう! がすごく参考になる。

どうやって3Dを2次元に描画するのかと思ったら、

それでは、このモデルを描画してみましょう。描画は、モデルをz座標軸の正の方向から原点へ向かう方向から見ているものとします(右図)。こうすることで、頂点のz座標値を扱う必要がなくなるから簡単です♪ 単に頂点のx座標値とy座標値だけを扱ってモデルを描くことができます。

Javaで3D表示しよう! - Step1 いちばん簡単な表示方法

目からウロコ。z軸を無視。

これらのページを参考にして、Flex 2 SDK でコンパイルできる形でサンプルを作ってみた。

回転する3Dオブジェクト Flash

ソースコード

メインクラス ThreeD.as


package {
 
  import flash.display.*;
  import flash.events.*;
  import flash.text.*;
  import flash.utils.*;
  
  public class ThreeD extends Sprite {
 
    private var shape:Shape;
    private var face:Array = new Array();
    private var m_Scale:Number = 100;
    private var Center_x:Number = 100;
    private var Center_y:Number = 100;
 
    private var angle:Number = 5;
 
    public function ThreeD() {
 
      // 描画されるキャンバス
      shape = new Shape();
      addChild(shape);
 
      // 描画する3Dモデル
      var vertex:Array = new Array();
      vertex[0] = new Vertex(-1, 0, 0);
      vertex[1] = new Vertex( 0, 0, 1);
      vertex[2] = new Vertex( 0, 1, 0);
      vertex[3] = new Vertex( 1, 0, 0);
      vertex[4] = new Vertex( 0,-1, 0);
      vertex[5] = new Vertex( 0, 0,-1);
      face[0] = new Face( vertex[1], vertex[4], vertex[2]);
      face[1] = new Face( vertex[1], vertex[0], vertex[4]);
      face[2] = new Face( vertex[1], vertex[2], vertex[0]);
      face[3] = new Face( vertex[3], vertex[2], vertex[4]);
      face[4] = new Face( vertex[0], vertex[5], vertex[4]);
      face[5] = new Face( vertex[4], vertex[5], vertex[3]);
      face[6] = new Face( vertex[3], vertex[5], vertex[2]);
      face[7] = new Face( vertex[2], vertex[5], vertex[0]);
 
      // 3Dモデルを描画
      drawModel();
 
      // 定期的に3Dモデルを回転して描画
      var timer:Timer=new Timer(200,0);
      timer.addEventListener(TimerEvent.TIMER, ontick);
      timer.start();
    }
 
    private function ontick(evt:TimerEvent):void {
      rotate(angle, angle/2, 0);
      drawModel();
    }
 
    private function drawModel():void {
 
      // 前の描画を消去
      shape.graphics.clear();
 
      // 3Dモデルを描画
      for(var i:int=0; i < face.length; i++) {
        var x0:Number =  face[i].vertex[0].x * m_Scale + Center_x;
        var x1:Number =  face[i].vertex[1].x * m_Scale + Center_x;
        var x2:Number =  face[i].vertex[2].x * m_Scale + Center_x;
        var y0:Number = -face[i].vertex[0].y * m_Scale + Center_y;
        var y1:Number = -face[i].vertex[1].y * m_Scale + Center_y;
        var y2:Number = -face[i].vertex[2].y * m_Scale + Center_y;
 
        // 奥行き(Z軸)
        var depth:Number = 3 - (face[i].vertex[0].z + face[i].vertex[1].z + face[i].vertex[2].z);
        // 描画ペンの太さ
        var penWidth:Number = depth;
        // アルファ値(0~1を指定) しかしこのプログラムでは意味がないような...
        var penAlpha:Number = depth / 3;
 
        shape.graphics.lineStyle(penWidth, 0xff0000, penAlpha);
        shape.graphics.moveTo(x0, y0);
        shape.graphics.lineTo(x1, y1);
        shape.graphics.lineTo(x2, y2);
        shape.graphics.lineTo(x0, y0);
      }
    }
 
    // ActionScript の Math.sin とか Math.cos には
    // 角度(°)ではなくラジアンが必要
    private static function toRadians(degree:Number):Number{
      return degree / 180.0 * Math.PI;
    }
 
    // 3Dモデルを回転
    private function rotate(x:Number,y:Number,z:Number):void{
      for(var i:int=0; i<face.length; i++) {
        face[i].rotate(toRadians(x), toRadians(y), toRadians(z));
      }
    }
 
  }
 
}

3頂点による面 Face.as


package {
 
  // 3頂点による面
  public class Face {
 
    public var vertex:Array = new Array();
 
    public function Face(v0:Vertex, v1:Vertex, v2:Vertex){
      // 頂点オブジェクトを共有されないように
      // オブジェクトをコピーしておく
      this.vertex[0] = v0.copy();
      this.vertex[1] = v1.copy();
      this.vertex[2] = v2.copy();
    }
 
    public function rotate(x:Number, y:Number, z:Number):void{
      for(var i:int=0; i<vertex.length; i++) {
        vertex[i].rotate(x,y,z);
      }
    }
  }
 
}

頂点クラス Vertex.as


package {
 
  // 頂点クラス
  public class Vertex {
 
    public var x:Number;
    public var y:Number;
    public var z:Number;
 
    public function Vertex(x:Number, y:Number, z:Number) {
      this.x = x;
      this.y = y;
      this.z = z;
    }
 
    public function copy():Vertex {
      return new Vertex(x,y,z);
    }
 
    public function rotate(x:Number,y:Number,z:Number):void {
      rotatex(x);
      rotatey(y);
    }
 
    // X軸を中心に回転
    public function rotatey(angle:Number):void {
 
      var sin:Number = Math.sin(angle);
      var cos:Number = Math.cos(angle);
 
      var tx:Number = x * cos - z * sin;
      var tz:Number = x * sin + z * cos;
 
      x = tx;
      z = tz;
    }
 
    // X軸を中心に回転
    public function rotatex(angle:Number):void {
 
      var sin:Number = Math.sin(angle);
      var cos:Number = Math.cos(angle);
 
      var ty:Number =  y * cos + z * sin;
      var tz:Number = -y * sin + z * cos;
 
      y = ty;
      z = tz;
    }
  }

}

コンパイル

mxmlc -default-size 240 240 -default-frame-rate 30 -default-background-color 0xFFFFFF ThreeD.as

tags: zlashdot Flash Flash Flex

Posted by NI-Lab. (@nilab)