[AS3] 東京タワーおじさん2 (ポリゴンごとのzソートで描画)

2009/08/31

こんにちは。きんくまです。
8月末日、関東は見事に台風直撃の状態の中、皆様いかがお過ごしでしょうか。

お正月に見て面白かった、恐竜SFドラマの「プライミーバル」。
第二章が先週始まりまして、見ました。
>> 恐竜SFドラマ プライミーバル|NHK 総合 海外ドラマ

これがまた、恐竜が実写に馴染んですごくよくできていて面白いです。
前回、半分悪役キャラだったリーダーの奥さんがまだ出てきていないんですが、また出てきてひと悶着起こしてくれれば、物語がますます面白くなることでしょう。

これはさっきTwitterにも書いたんですが。
CGといえば、Tron。Tronは国産OSの方じゃなくて1982年の映画の方です。
以前NHKの海外ドキュメンタリーで「VFXの歴史」みたいな番組を見てたときに知りました。

まずはこっちの映像を。

wikiによると「世界で初めて全面的にコンピュータグラフィックスを導入した映画」となっています。

>>トロン (映画)

この翌年1983年にファミコンの登場。
1984年に初代ターミネーター(ラストシーンが模型のコマ撮り)
1985年に初代バック・トゥ・ザ・フューチャー
と考えるとCGで意欲的に取り組んだ作品であることは間違いなしですね。

ただNHKでもやっていましたが、興行的には振るわなかったようです。
まあ今見ると、見た目ショボそうだもんね。
だけど、このときに関わったスタッフが現在のCG・IT界で活躍しているみたいです。
今調べたら、ターンAのシド・ミードやフランスの漫画家メビウスも関わってたみたい。
>> 解説・あらすじ – トロン(1982)

前置きが長くなりました。それで、来年にリメイク版が公開(日本でそこまでいくのか?)されるみたい。
ぜひ音つきでみてくださいな。

 
30年でここまで変わるんですね。シド・ミードとメビウスのイメージしてた世界ってこんなんだったのかな。
————————-

おっと、ASに関係ない話が続きましたね。
前回drawTrianglesでポリゴンを作ったんですが、zバッファーが実装できずに描画が変な風になってました。
それを以下の3Dの基本的なアルゴリズムで修正しました。
1. zバッファ(1pxごとのz値)は無理なので、三角形ポリゴンごとの最大z値を取得
2. zソート
3. 奥のものから順番に描画することで奥行きを表現
という感じです。

実際のデモ

結局のところおじさんとタワーの関係があやしい瞬間がまだありますが、前回よりはよしとしましょう!
 
以下ソースです。

Main2

package
{
  import flash.display.Bitmap;
  import flash.display.BitmapData;
  import flash.display.Graphics;
  import flash.display.MovieClip;
  import flash.display.Sprite;
  import flash.display.TriangleCulling;
  import flash.events.Event;
  import flash.events.MouseEvent;
  import flash.geom.Matrix3D;
  import flash.geom.PerspectiveProjection;
  import flash.geom.Utils3D;
  import flash.geom.Vector3D;
  import flash.text.TextField;
  import flash.utils.getDefinitionByName;
  import fl.controls.Slider;
  import fl.controls.CheckBox;

  public class Main2 extends MovieClip
  {
    public var s1:Slider;
    public var s1_txt:TextField;
    public var cullingChk:CheckBox;

    public var fl:Number = 180;

    public var proj:Matrix3D;
    public var triangles:Array = new Array();
    public var stratBtn:MovieClip;
    public var texture:BitmapData;
    public var canvas:Sprite;

    public var yAxisDeg:Number = 0;

    public function Main2()
    {
      stratBtn.addEventListener(MouseEvent.CLICK, init);
    }

    public function init(e:Event):void
    {
      stratBtn.removeEventListener(MouseEvent.CLICK, init);
      stratBtn.visible = false;

      var TextureC:Class = getDefinitionByName("Texture") as Class;
      texture = new TextureC(0, 0);

      canvas = new Sprite();
      canvas.x = stage.stageWidth / 2;
      canvas.y = stage.stageHeight / 2;
      addChildAt(canvas, 0);

      setTriangles();
      addEventListener(Event.ENTER_FRAME, render);
    }

    private function setTriangles():void
    {

      var tri:Triangle;
      var i:int;
      var mat:Matrix3D = new Matrix3D();
      var tverts:Vector.<Number>;

      //tower
      for (i = 0; i < 4; i++) {
        tverts = new Vector.<Number>();
        tri = new Triangle();
        tri.texture = texture;
        tri.pt1.push(0, -160, 0);
        tri.pt2.push(80, 160, -80);
        tri.pt3.push( -80, 160, -80);
        tri.setVerts();
        mat.appendRotation(90 * i, Vector3D.Y_AXIS); //90度ずつ回転
        mat.transformVectors(tri.verts, tverts);
        tri.verts = tverts;

        tri.uv.push(
          0.1 + 0.2 * i, 0,
          0.2 + 0.2 * i, 1.0,
          0.2 * i, 1.0
        );
        triangles.push(tri);
      }

      //man
      for (i = 0; i < 2; i++) {
        tri = new Triangle();
        tri.texture = texture;
        if (i == 0) {
          tri.pt1.push(-150, 0, 0);
          tri.pt2.push(-70, 0, 0);
          tri.pt3.push( -150, 160, 0);
          tri.uv.push(
            0.8, 0,
            1, 0,
            0.8, 1.0
          );
        }else {
          tri.pt1.push(-70, 0, 0);
          tri.pt2.push(-70, 160, 0);
          tri.pt3.push( -150, 160, 0);
          tri.uv.push(
            1, 0,
            1, 1,
            0.8, 1.0
          );
        }
        tri.setVerts();
        triangles.push(tri);
      }
    }

    private function render(e:Event):void
    {
      var setCulling:String = cullingChk.selected ? TriangleCulling.NEGATIVE : TriangleCulling.NONE;
      fl = s1.value;
      s1_txt.text = "focalLength: " + s1.value;

      var transe:Matrix3D = new Matrix3D();
      var verts:Vector.<Number> = new Vector.<Number>();
      var drawVerts:Vector.<Number> = new Vector.<Number>();
      var tVerts:Vector.<Number> = new Vector.<Number>();
      var uvts:Vector.<Number> = new Vector.<Number>();

      var perse:PerspectiveProjection = new PerspectiveProjection();
      perse.focalLength = fl;
      proj = perse.toMatrix3D();
      transe.appendRotation(yAxisDeg, Vector3D.Y_AXIS);
      transe.appendRotation(30, Vector3D.X_AXIS);
      transe.appendTranslation(0, 0, 1.1 * fl);

      var i:int;
      var tri:Triangle;
      for (i = 0; i < triangles.length; i++) {
        tri = triangles[i];
        transe.transformVectors(tri.verts, tri.tverts);
        tri.setUVT(fl);
        tri.setMaxZ();
      }

      triangles.sortOn("maxZ", Array.DESCENDING | Array.NUMERIC);

      for (i = 0; i < triangles.length; i++) {
        tri = triangles[i];
        verts = verts.concat(tri.tverts);
        uvts = uvts.concat(tri.uvt);
      }
      Utils3D.projectVectors(proj, verts, drawVerts, uvts);

      var g:Graphics = canvas.graphics;
      g.clear();
      g.beginBitmapFill(texture, null, false, true);
      g.drawTriangles(drawVerts, null, uvts, setCulling);
      g.endFill();

      yAxisDeg += 1;
    }
  }

}

Triangle

package
{
  import flash.display.BitmapData;
  public class Triangle
  {
    public var pt1:Vector.<Number>;
    public var pt2:Vector.<Number>;
    public var pt3:Vector.<Number>;
    public var maxZ:Number;
    public var uv:Vector.<Number>;
    public var uvt:Vector.<Number>;
    public var verts:Vector.<Number>;
    public var texture:BitmapData;
    public var tverts:Vector.<Number>;

    public function Triangle()
    {
      pt1 = new Vector.<Number>();
      pt2 = new Vector.<Number>();
      pt3 = new Vector.<Number>();
      uv = new Vector.<Number>();
    }

    public function setVerts():void
    {
      verts = Vector.<Number>(pt1);
      verts = verts.concat(pt2);
      verts = verts.concat(pt3);
      tverts = new Vector.<Number>();
    }

    public function setUVT(fl:Number):void
    {
      uvt = new Vector.<Number>();
      var z1:Number = pt1[2];
      var z2:Number = pt2[2];
      var z3:Number = pt3[2];
      uvt.push(
        uv[0], uv[1], fl / (fl + z1),
        uv[2], uv[3], fl / (fl + z2),
        uv[4], uv[5], fl / (fl + z3)
      );
    }

    public function setMaxZ():void
    {
      var z1:Number = tverts[2];
      var z2:Number = tverts[5];
      var z3:Number = tverts[8];
      maxZ = z1 > z2 ? z1 : z2;
      maxZ = maxZ > z3 ? maxZ : z3;
    }


  }

}

自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

ページトップへ戻る