Hello pot with texture.
テクスチャのテストです。
/**
* Copyright ume ( http://wonderfl.net/user/ume )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/mYnB
*/
package {
import net.hires.debug.Stats;
import flash.display.Sprite;
import flash.text.TextField;
import com.adobe.utils.*;
import flash.utils.getTimer;
import flash.events.*;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.display3D.*;
import flash.geom.Matrix3D;
import flash.geom.Vector3D;
import flash.display.Stage;
import flash.display.Stage3D;
import flash.display.Loader;
import flash.net.URLRequest;
import flash.display3D.textures.Texture;
import flash.display.BitmapData;
import flash.display.Bitmap;
[SWF(width="465", height="465", frameRate="60")]
public class HelloPotWithUV extends Sprite{
//3Dコンテクスト
private var context3D:Context3D;
private var program:Program3D;
//頂点・法線・インデックス
private var vertexbuffer:VertexBuffer3D;
private var normalbuffer:VertexBuffer3D;
private var indexBuffer:IndexBuffer3D;
//WVP
private var constMatrix:Matrix3D;
private var modelMatrix:Matrix3D;
private var cameraMatrix:Camera;
private var perspective:PerspectiveMatrix3D;
//もろもろ
private var movieWidth:Number = 465;
private var movieHeight:Number = 465;
private var msg:TextField;
private var canRender:Boolean;
private var objData:OBJParser;
private var picLoader:Loader;
private const PIC_URL:String ="http://ciruelo.jp/assets/teapotuv.png";
private const OBJ_URL:String ="http://ciruelo.jp/assets/teapotUV.obj";
public function HelloPotWithUV() {
//スタッツ等配置
var stats:Stats = new Stats();
stage.addChild(stats);
msg = createTF();
addChild(msg);
//サイズ固定
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
//レンダリングフラグ初期化
canRender = false;
//3D準備
stage.stage3Ds[0].addEventListener( Event.CONTEXT3D_CREATE, onContext );
stage.stage3Ds[0].requestContext3D();
}
//テキストボックス準備
private function createTF():TextField{
var msg:TextField = new TextField();
msg.multiline = true;
msg.width = 150;
msg.height = 100;
msg.border = true;
msg.x = stage.stageWidth - msg.width - 5;
msg.y = stage.stageHeight - msg.height - 5;
msg.text = "Hello";
return msg
}
// コンテキスト準備完了時
private function onContext(e:Event):void{
context3D = stage.stage3Ds[0].context3D;
context3D.configureBackBuffer(stage.stageWidth, stage.stageHeight, 1, true);
addEventListener(Event.ENTER_FRAME, onRender);
//テクスチャ用画像読み込み開始
picLoader = new Loader();
picLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,onCompLoadPic);
picLoader.load(new URLRequest(PIC_URL));
}
//テクスチャ読み込み
private function onCompLoadPic(e:Event):void{
picLoader.scaleX = picLoader.scaleY = 0.5;
picLoader.y = stage.height - picLoader.height;
addChild(picLoader);
//モデルデータ読み込み
try{
objData = new OBJParser(OBJ_URL,0xFFFFFF,1);
}catch(e:Error){
msg.text = "@エラー:" + e.message;
}
objData.compFunc = onComp;
}
//モデル読み込み完了時イベントハンドラメソッド
private function onComp():void{
msg.text = "OBJ読み込み完了";
//頂点情報セット
setBuffer();
msg.text = "頂点セット完了";
//テクスチャセット
setTexture();
msg.text = "テクスチャセット完了";
//プログラムセット
setProgram();
msg.text = "プログラムセット完了";
//マトリクス初期化
constMatrix = new Matrix3D();
modelMatrix = new Matrix3D();
cameraMatrix=new Camera();
cameraMatrix.InitView(new Vector3D(0,5,10), new Vector3D(0,0,0), Vector3D.Y_AXIS);
perspective = new PerspectiveMatrix3D();
perspective.perspectiveFieldOfViewRH(45*Math.PI/180, movieWidth / movieHeight, 0.1, 1000.0);
msg.text = "モデル読み込み完了\nポリゴン数:" + objData.rawIndexBuffer.length/3 + "\n頂点共有してません><;"
this.canRender = true;
//OBJ解放
objData.dispose();
objData = null;
}
//テクスチャ作成&セット
private function setTexture():void{
//テクスチャ用のビットマップを生成
var bmd:BitmapData = Bitmap(picLoader.content).bitmapData;
//テクスチャとして登録・転送
var texture:Texture = context3D.createTexture(bmd.width, bmd.height, Context3DTextureFormat.BGRA, false);
texture.uploadFromBitmapData(bmd);
context3D.setTextureAt(0, texture);
}
//プログラムセット
private function setProgram():void{
//頂点シェーダーを生成 今回は頂点側でライティング計算まで行う
var vertexShaderAssembler : AGALMiniAssembler = new AGALMiniAssembler(true);
vertexShaderAssembler.assemble( Context3DProgramType.VERTEX,
//頂点出力
"m44 vt0, va0, vc0\n" +
"mov op, vt0\n" +
//UV座標を移動
"mov v0, va2\n" +
//ディフューズとアンビエント計算 最適化を考えずに地道に計算中
"m44 vt1, va1, vc4\n" +
"dp3 vt2.x vt1, vc8\n" +
"sat vt2.x, vt2.x\n" +
"add vt2.x, vt2.x, vc11.z\n" +
"mul vt2.xyz, vt2.xxx, vc9.xyz\n" +
"mov vt2.w vc9.w\n" +
"mov v1, vt2\n" +
//スペキュラ計算
"sub vt3, vc10, vt0\n" +
"nrm vt3.xyz, vt3\n" +
"mov vt3.w, vc9.w\n" +
"add vt3.xyz, vt3.xyz, vt1.xyz\n" +
"nrm vt3.xyz, vt3\n" +
"mov vt3.w, vc9.w\n" +
"dp3 vt4.x, vt3, vt1\n" +
"sat vt4.x, vt4.x\n" +
"pow vt4.x, vt4.x, vc11.y\n" +
"mul vt4.x, vt4.x, vc11.w\n" +
"mul vt5.xyz, vt4.xxx, vc12\n" +
"mov vt5.w, vc9.w\n" +
"mov v2, vt5"
);
//フラグメントシェーダー(ピクセルシェーダー)テクスチャと頂点単位のライト色を補完して出力
var fragmentShaderAssembler : AGALMiniAssembler= new AGALMiniAssembler(true);
fragmentShaderAssembler.assemble( Context3DProgramType.FRAGMENT,
"tex ft0, v0, fs0 <2d,linear,nomip>\n" +
"mul ft0, ft0, v1\n" +
"add ft0.xyz, ft0.xyz, v2.xyz\n" +
"mov oc, ft0"
);
//プログラムを生成・セット
program = context3D.createProgram();
program.upload( vertexShaderAssembler.agalcode, fragmentShaderAssembler.agalcode);
context3D.setProgram(program);
}
//頂点等セット
private function setBuffer():void{
//頂点・法線・UV
var vertices:Vector.<Number> = objData.rawVertexBuffer;
var normals:Vector.<Number> = objData.rawNormalBuffer;
//頂点数・法線数・インデックス数を算出
var vertexLength:int = objData.rawVertexBuffer.length/5;
var normalLength:int = objData.rawNormalBuffer.length/3;
var indexLength:int = objData.rawIndexBuffer.length;
// 頂点バッファを作成・アップロード
vertexbuffer = context3D.createVertexBuffer(vertexLength, 5);
vertexbuffer.uploadFromVector(vertices, 0, vertexLength);
// 法線バッファを作成・アップロード
normalbuffer = context3D.createVertexBuffer(normalLength,3);
normalbuffer.uploadFromVector(normals, 0, normalLength);
// UVバッファを作成・アップロード
// インデックスバッファを作成・アップロード
indexBuffer = context3D.createIndexBuffer(indexLength);
indexBuffer.uploadFromVector (objData.rawIndexBuffer, 0, indexLength);
// 頂点・対応する法線、UV座標をレジスタva0・va1・va2にセット
context3D.setVertexBufferAt(0, vertexbuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
context3D.setVertexBufferAt(2, vertexbuffer, 3, Context3DVertexBufferFormat.FLOAT_2);
context3D.setVertexBufferAt(1, normalbuffer, 0, Context3DVertexBufferFormat.FLOAT_3);
}
// レンダリング
private function onRender(e:Event):void{
if ( !context3D ) return;
context3D.clear ( 0.3, 0.3, 0.3, 1 );
//変換マトリクス生成
//モデル回転
modelMatrix.identity()
modelMatrix.appendRotation(getTimer()/10,Vector3D.Y_AXIS);
constMatrix.identity();
constMatrix.append(modelMatrix);
constMatrix.append(cameraMatrix.matrix);
constMatrix.append(perspective);
constMatrix.appendTranslation(0,-2,0);
/* 頂点プログラムで使用する定数 */
//vc0-vc3:WVPマトリクス
context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0,constMatrix, true);
//vc4-vc7:ワールド座標変換用マトリクス
context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 4,modelMatrix, true);
//vc8:ライトの法線
context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 8,Vector.<Number>([0.5773502691896258, 0.5773502691896258, 0.5773502691896258, 1]));
//vc9:ベースカラー いわゆるマテリアルの色 今回はUVなので必要ないのだけど、「1」という値で埋めておいていろいろな所で再利用
context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX,9,Vector.<Number>([1,1,1,1]));
//vc10:カメラ座標 0,5,10固定で
context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX,10,Vector.<Number>([0, 5, 10, 1]));
//vc11:反射係数, power値
context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX,11,Vector.<Number>([1, 30, 0.25, 0.5]));
//vc12:スペキュラ色(白)
context3D.setProgramConstantsFromVector(Context3DProgramType.VERTEX,12,Vector.<Number>([1, 1, 1, 1]));
/* フラグメントプログラムで使用する定数 */
//今回はありませぬ。
//三角ポリゴン描画
context3D.drawTriangles(indexBuffer);
//取り出して画面に反映
context3D.present();
}
}
}
import flash.geom.Matrix3D;
import flash.geom.Vector3D;
/*
なんちゃってカメラ
*/
class Camera {
private var _view:Matrix3D;
public function Camera() {
_view = new Matrix3D();
}
public function InitView( from:Vector3D, at:Vector3D, up:Vector3D ) : void {
var vz:Vector3D = from.subtract( at );
vz.normalize();
var vx:Vector3D = up.crossProduct( vz );
vx.normalize();
var vy:Vector3D = vz.crossProduct( vx );
vy.normalize();
var vtx:Number = vx.dotProduct( from ) * -1;
var vty:Number = vy.dotProduct( from ) * -1;
var vtz:Number = vz.dotProduct( from ) * -1;
_view.identity();
_view.rawData = Vector.<Number>([
vx.x, vy.x, vz.x, 0,
vx.y, vy.y, vz.y, 0,
vx.z, vy.z, vz.z, 0,
vtx, vty, vtz, 1,
]);
}
public function get matrix():Matrix3D {
return _view;
}
}
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.events.Event;
import flash.events.SecurityErrorEvent;
import flash.events.IOErrorEvent;
import flash.system.Security;
/*
とりあえず、.objを読み込んでみて、頂点・法線・インデックス・UVをパースするクラス
*/
class OBJParser{
private const LINE_FEED:String = String.fromCharCode(10);
private const SPACE:String = String.fromCharCode(32);
private const SLASH:String = "/";
private const VERTEX:String = "v";
private const UV:String = "vt";
private const NORMAL:String = "vn";
private const INDEX_DATA:String = "f";
private var _loader:URLLoader;
private var _color:uint;
//4種類の一時的バッファ
private var _vertexTemp:Array;
private var _normalTemp:Array;
private var _indexTemp:Array;
private var _uvTemp:Array;
//3種類のアップロード用バッファ
public var rawIndexBuffer:Vector.<uint> = new Vector.<uint>();
public var rawVertexBuffer:Vector.<Number> = new Vector.<Number>();
public var rawNormalBuffer:Vector.<Number> = new Vector.<Number>();
//スケール
private var _scale:Number;
//読み込み完了後のハンドラ用
public var compFunc:Function;
public function OBJParser(path:String, defaultColor:uint = 0xFFFFFF ,scale:Number = 0.01){
Security.loadPolicyFile("http://ciruelo.jp/assets/crossdomain.xml");
_color = defaultColor;
_scale = scale;
var req:URLRequest = new URLRequest(path);
_loader = new URLLoader(req);
_loader.addEventListener(Event.COMPLETE, _onLoadComp);
_loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR,_onErr);
}
//読み込みエラー
private function _onErr(e:SecurityErrorEvent):void{
var err:Error = e as Error;
throw err;
}
//読み込み完了
private function _onLoadComp(e:Event):void{
// 1行ごと取り出して読み込む
var data:String = String(_loader.data);
this._indexTemp = [];
this._vertexTemp = [];
this._normalTemp = [];
this._uvTemp = [];
var lines:Array = data.split(LINE_FEED);
var loop:int = lines.length;
for (var i:int = 0; i < loop; ++i){
parseLine(lines[i]);
}
//バッファ用データに変換
rawIndexBuffer = new Vector.<uint>();
rawVertexBuffer = new Vector.<Number>();
rawNormalBuffer = new Vector.<Number>();
parseBuffer();
//コールバック実行
compFunc();
}
//バッファ用データに変換
private function parseBuffer():void{
var vIndex:int = 0;
var nIndex:int = 0;
var v:int=3;
var w:int=2;
for(var i:int=0;i<this._indexTemp.length;i++){
//3つインデックスデータを取り出す
var poly1:Array = _indexTemp[i][0];
var poly2:Array = _indexTemp[i][1];
var poly3:Array = _indexTemp[i][2];
rawVertexBuffer.push(
_vertexTemp[poly1[0]*v], _vertexTemp[poly1[0]*v+1], _vertexTemp[poly1[0]*v+2],_uvTemp[poly1[1]*w], _uvTemp[poly1[1]*w+1],
_vertexTemp[poly2[0]*v], _vertexTemp[poly2[0]*v+1], _vertexTemp[poly2[0]*v+2],_uvTemp[poly2[1]*w], _uvTemp[poly2[1]*w+1],
_vertexTemp[poly3[0]*v], _vertexTemp[poly3[0]*v+1], _vertexTemp[poly3[0]*v+2],_uvTemp[poly3[1]*w], _uvTemp[poly3[1]*w+1]
);
rawNormalBuffer.push(
_normalTemp[poly1[2]*v], _normalTemp[poly1[2]*v+1], _normalTemp[poly1[2]*v+2],
_normalTemp[poly2[2]*v], _normalTemp[poly2[2]*v+1], _normalTemp[poly2[2]*v+2],
_normalTemp[poly3[2]*v], _normalTemp[poly3[2]*v+1], _normalTemp[poly3[2]*v+2]
);
//インデックスバッファ作成
rawIndexBuffer.push(i*3, i*3+1, i*3+2);
}
}
//1行ごとの処理
private function parseLine(line:String):void{
// スペースごとに区切る
var words:Array = line.split(SPACE);
if (words.length > 0){
var data:Array = words.slice(1);
}else{
return;
}
var firstWord:String = words[0];
switch (firstWord){
case VERTEX :
parseVertex(data);
break;
case NORMAL :
parseNormal(data);
break;
case INDEX_DATA :
parseIndex(data);
break;
case UV :
parseUV(data);
break;
}
}
//頂点
private function parseVertex(data:Array):void{
var loop:int = 3;
for (var i:uint = 0; i < loop; i++){
var element:String = data[i];
_vertexTemp.push(Number(element)*_scale);
}
}
//法線
private function parseNormal(data:Array):void{
var loop:int = 3;
for (var i:uint = 0; i < loop; i++){
var element:String = data[i];
_normalTemp.push(Number(element));
}
}
//UV
private function parseUV(data:Array):void{
var loop:int = 2;
for (var i:uint = 0; i < loop; i++){
var element:String = data[i];
_uvTemp.push(Number(element));
}
}
//面
private function parseIndex(data:Array):void{
var poly:Array = [];
var loop:int = 3;
for(var i:int=0;i<loop;i++){
var v:Array = [];
var element:Array = data[i].split(SLASH);
for(var j:int=0;j<loop;j++){
//objの番号は、「1」から始まるのでひとつ減算
v.push(Number(element[j])-1)
}
poly.push(v);
}
_indexTemp.push(poly);
}
//データ解放
public function dispose():void{
_vertexTemp = _normalTemp = _indexTemp = _uvTemp = null;
rawVertexBuffer = rawNormalBuffer= null;
rawIndexBuffer = null;
}
}