こんにちは。きんくまです。
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;
}
}
}