«

»

9月 04

Stage3D テクスチャマッピング

このエントリーを含むはてなブックマークはてなブックマーク - Stage3D テクスチャマッピング Googleブックマークに追加 このエントリをつぶやくこのWebページのtweets

今回はテクスチャマッピングに挑戦

画像を一枚のPlane上に張り付けたもの

デモ

立方体に貼り付け、さらにフォンシェーディングしたもの

デモ

参考書

一つ目のソース

package 
{
	import com.adobe.utils.AGALMiniAssembler;
	import com.adobe.utils.PerspectiveMatrix3D;
	
	import flash.display.*;
	import flash.display3D.*;
	import flash.display3D.textures.Texture;
	import flash.events.Event;
	import flash.geom.*;
	
	[SWF(width="500", height="500", frameRate="60")]
	public class Stage3D_08 extends Sprite
	{
		private const WIDTH:Number = 500;
		private const HEIGHT:Number = 500;
		
		private var stage3D:Stage3D;
		private var context3D:Context3D;
		
		//テクスチャに使う画像
		[Embed(source="texture.jpg")]
		private var Img:Class;
		
		// 頂点シェーダ
		private const VERTEX_SHADER:String =
			"m44 op, va0, vc0 \n" +		
			"mov v0, va1 \n";			//ピクセルシェーダへ
		
		// ピクセルシェーダ
		private const FRAGMENT_SHADER:String =
			//テクスチャ情報の処理
			"tex oc, v0, fs0<2d, linear>";	//色情報の取得  v2:uv座標, fs0:画像データ
		
		public function Stage3D_08()
		{
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			
			stage3D = this.stage.stage3Ds[0];
			
			stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContext3DCreate);
			stage3D.requestContext3D(Context3DRenderMode.AUTO);
		}
		
		private function onContext3DCreate(event:Event):void
		{
			context3D = Stage3D(event.target).context3D;
			
			context3D.enableErrorChecking = true;
			context3D.configureBackBuffer(WIDTH, HEIGHT, 2, false);
			
			// 頂点シェーダをコンパイル;
			var vertexAssembly:AGALMiniAssembler = new AGALMiniAssembler();
			vertexAssembly.assemble(Context3DProgramType.VERTEX, VERTEX_SHADER);
			// ピクセルシェーダをコンパイル;
			var fragmentAssembly:AGALMiniAssembler = new AGALMiniAssembler();
			fragmentAssembly.assemble(Context3DProgramType.FRAGMENT, FRAGMENT_SHADER);
			
			var programPair:Program3D;
			// Program3Dのインスタンスを取得
			programPair = context3D.createProgram();
			// 頂点シェーダとピクセルシェーダのコードをGPUにアップロード
			programPair.upload(vertexAssembly.agalcode, fragmentAssembly.agalcode);
			// 使用するシェーダのペアを指定;
			context3D.setProgram(programPair);
			
			//頂点情報
			var vertexData:Vector.<Number> = Vector.<Number>([
				-0.5,  0.5, 0, 0, 0,  // x, y, z, u, v のフォーマット
				 0.5,  0.5, 0, 1, 0,
				-0.5, -0.5, 0, 0, 1,
				 0.5, -0.5, 0, 1, 1 
			]);
			
			var vertices:VertexBuffer3D;
			// 5個(頂点座標(x,y,z)、uv座標(u,v))の値を持つ頂点用の頂点バッファを作成
			vertices = context3D.createVertexBuffer(4, 5);
			// 頂点データをアップロード
			vertices.uploadFromVector(vertexData, 0, 4);
			
			// 最初の属性は座標の情報:Float型の数値が3つ これを属性レジスタ0に入れる
			context3D.setVertexBufferAt(0, vertices, 0, Context3DVertexBufferFormat.FLOAT_3);
			// uv情報 Float型が2つ これを属性レジスタ1に入れる
			context3D.setVertexBufferAt(1, vertices, 3, Context3DVertexBufferFormat.FLOAT_2);
			
			//使用する頂点のインデックス
			var indexData:Vector.<uint> = Vector.<uint>([
				0, 1, 2,
				1, 2, 3
			]);
			
			//インデックスバッファを作成
			var indices:IndexBuffer3D = context3D.createIndexBuffer(6);
			//インデックス情報をアップロード
			indices.uploadFromVector(indexData, 0, 6);
			
			var texture:Texture = context3D.createTexture(512, 512, Context3DTextureFormat.BGRA, false);
			texture.uploadFromBitmapData((new Img() as Bitmap).bitmapData);
			//fs0に設定
			context3D.setTextureAt(0, texture);
			
			//レジスタに登録
			context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, new Matrix3D());
			
			// drawTriangles()を呼ぶ前に必ずバッファをクリア;
			context3D.clear(0, 0, 0);
			// 3角形を全て描画する;
			context3D.drawTriangles(indices, 0, -1);
			//ビューポートに表示;
			context3D.present();
		}
	}
}

二つ目のソース

package 
{
	import com.adobe.utils.AGALMiniAssembler;
	import com.adobe.utils.PerspectiveMatrix3D;
	
	import flash.display.*;
	import flash.display3D.*;
	import flash.display3D.textures.Texture;
	import flash.events.Event;
	import flash.geom.*;
	
	[SWF(width="500", height="500", frameRate="60")]
	public class Stage3D_07 extends Sprite
	{
		private const WIDTH:Number = 500;
		private const HEIGHT:Number = 500;
		
		private var stage3D:Stage3D;
		private var context3D:Context3D;
		
		private var loop_count:int = 0;
		
		//テクスチャに使う画像
		[Embed(source="texture2.jpg")]
		private var Img:Class;
		
		//モデル、ビュー、プロジェクション変換行列
		private var model:Matrix3D, view:Matrix3D, projection:PerspectiveMatrix3D;
		//法線ベクトル変換行列
		private var normal:Matrix3D;
		
		//頂点インデックスバッファー
		private var indices:IndexBuffer3D;
		
		// 頂点シェーダ
		private const VERTEX_SHADER:String =
			"m44 vt0, va0, vc0 \n" +		//vt0 = 頂点 * モデルビュー
			"m44 op, vt0, vc4 \n" +			//出力 = vt0*プロジェクション
			//法線ベクトルN ⇒ vt1
			"mov vt1, va2 \n" +
			"m33 vt1.xyz, vt1, vc8 \n" +	//Nの座標変換
			//ピクセルシェーダへ
			"mov v0, vt0 \n" +
			"mov v1, vt1 \n" +
			"mov v2, va1 \n";
		
		// ピクセルシェーダ
		private const FRAGMENT_SHADER:String =
			"mov ft0, v0 \n" +
			"mov ft1, v1 \n" +
			"nrm ft1.xyz, ft1 \n" +
			
			//光源ベクトルL ⇒ ft2  L=(光源座標-頂点座標)
			"sub ft2, fc23, ft0 \n" +	
			
			"nrm ft2.xyz, ft2 \n" +			
			
			//視線ベクトルV ⇒ ft0
			"nrm ft0.xyz, ft0 \n" +			//視線ベクトルVを求める
			
			//環境光 ⇒ ft3  環境光成分=光の強さ x反射率   xは各成分同士の掛け算
			"mov ft3, fc16 \n" +
			"mul ft3, ft3, fc20 \n" +		  
			
			//拡散光 ⇒ ft4    拡散光成分=光の強さ x反射率*(N・L)
			"mov ft4, fc17 \n" +
			"mul ft4, ft4, fc21 \n" +		//ft4 = (光の強さ ) x (反射率)
			"dp3 ft5, ft1, ft2 \n" +		//ft5 = N・L 内積
			"sat ft5, ft5 \n" +				//ft5を0~1に収める
			"mul ft4, ft4, ft5 \n" +		//ft4 = ft4*ft5(スカラ)
			"add ft4, ft4, ft3 \n" +
			
			//テクスチャ情報の処理
			"tex ft3, v2, fs0<2d, linear> \n" +	//色情報の取得  v2:uv座標, fs0:画像データ
			"mul ft4, ft4, ft3 \n" +
			
			//鏡面光 ⇒ ft5	鏡面光成分=光の強さ x反射率*(H・N)^n
			"sub ft5, ft2, ft0 \n" +		//光源ベクトルと視線ベクトルの中間ベクトルを求める  H = L-V
			"nrm ft5.xyz, ft5 \n" +			//Hを正規化
			"dp3 ft5, ft5, ft1 \n" +		//内積 H・N
			"sat ft5, ft5 \n" +				//0~1に収める
			"pow ft5.x, ft5, fc19 \n" +		//強度=(H・N)^n
			"mul ft5, ft5.x, fc18 \n" +		//光の強さを掛け合わせる
			"mul ft5, ft5, fc22 \n" +		//反射率を掛け合わせる
			
			"add ft3, ft3, ft4 \n" +		//求めた光成分を足し合わせる
			"add ft3, ft4, ft5 \n" +
			"mov oc, ft3";
		
		public function Stage3D_07()
		{
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			
			stage3D = this.stage.stage3Ds[0];
			
			stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContext3DCreate);
			stage3D.requestContext3D(Context3DRenderMode.AUTO);
		}
		
		private function onContext3DCreate(event:Event):void
		{
			context3D = Stage3D(event.target).context3D;
			
			context3D.enableErrorChecking = true;
			context3D.configureBackBuffer(WIDTH, HEIGHT, 2, false);
			context3D.setCulling(Context3DTriangleFace.BACK);
			
			// 頂点シェーダをコンパイル;
			var vertexAssembly:AGALMiniAssembler = new AGALMiniAssembler();
			vertexAssembly.assemble(Context3DProgramType.VERTEX, VERTEX_SHADER);
			// ピクセルシェーダをコンパイル;
			var fragmentAssembly:AGALMiniAssembler = new AGALMiniAssembler();
			fragmentAssembly.assemble(Context3DProgramType.FRAGMENT, FRAGMENT_SHADER);
			
			var programPair:Program3D;
			// Program3Dのインスタンスを取得
			programPair = context3D.createProgram();
			// 頂点シェーダとピクセルシェーダのコードをGPUにアップロード
			programPair.upload(vertexAssembly.agalcode, fragmentAssembly.agalcode);
			// 使用するシェーダのペアを指定;
			context3D.setProgram(programPair);
			
			//立方体の頂点データを作成
			var cube:CubeVertex = new CubeVertex(100, 100, 100);
			
			var vertices:VertexBuffer3D;
			// 10個(頂点座標(x,y,z)、uv座標(u,v), 法線ベクトル(x,y,z))の値を持つ頂点用の頂点バッファを作成
			vertices = context3D.createVertexBuffer(CubeVertex.VERTEX_N, 8);
			// 頂点データをアップロード
			vertices.uploadFromVector(cube.vertex, 0, CubeVertex.VERTEX_N);
			
			// 最初の属性は座標の情報:Float型の数値が3つ これを属性レジスタ0に入れる
			context3D.setVertexBufferAt(0, vertices, 0, Context3DVertexBufferFormat.FLOAT_3);
			// uv情報 Float型が2つ これを属性レジスタ1に入れる
			context3D.setVertexBufferAt(1, vertices, 3, Context3DVertexBufferFormat.FLOAT_2);
			// 法線ベクトル情報 Float型が3つ これを属性レジスタ2に入れる
			context3D.setVertexBufferAt(2, vertices, 5, Context3DVertexBufferFormat.FLOAT_3);
			
			//インデックスバッファを作成
			indices = context3D.createIndexBuffer(CubeVertex.INDEX_N);
			//インデックス情報をアップロード
			indices.uploadFromVector(cube.index, 0, CubeVertex.INDEX_N);
			
			var texture:Texture = context3D.createTexture(256, 256, Context3DTextureFormat.BGRA, false);
			texture.uploadFromBitmapData((new Img() as Bitmap).bitmapData);
			//fs0に設定
			context3D.setTextureAt(0, texture);
			
			//法線ベクトル変換行列の初期化
			normal = new Matrix3D();
			
			//モデル変換行列の初期化
			model = new Matrix3D();
			
			//ビュー変換行列の設定
			view = new Matrix3D();
			view.appendTranslation(0, 0, -500);
			view.pointAt(new Vector3D(0,0,0), Vector3D.Z_AXIS, Vector3D.Y_AXIS);
			view.invert();
			
			//プロジェクション変換行列の設定
			projection = new PerspectiveMatrix3D();
			projection.perspectiveFieldOfViewLH(Math.PI/4, WIDTH/HEIGHT, 10, 1000);
			//レジスタに登録
			context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 4, projection, true);
			
			//光の情報を設定したベクトル
			//反射に関するもの
			var M:Vector.<Number> = Vector.<Number>([
				1.0, 1.0, 1.0, 1.0, //環境光反射
				1.0, 1.0, 1.0, 1.0, //拡散光反射
				1.0, 1.0, 1.0, 1.0, //鏡面光反射
				80,  80,  80,  1.0  //光沢度
			]);
			
			//強さに関するもの
			var I:Vector.<Number> = Vector.<Number>([
				0.2, 0.2, 0.2, 0.2, //環境光の強さ
				1.0, 1.0, 1.0, 1.0, //拡散光の強さ
				1.0, 1.0, 1.0, 1.0, //鏡面光の強さ
				0,   0, -500.0, 1.0  //光源の位置 
			]);
			
			//レジスタに登録
			context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 16, M);
			context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 20, I);
			
			addEventListener(Event.ENTER_FRAME, onEnterFrame);
		}
		
		private function onEnterFrame(e:Event):void{
			//モデル変換行列の設定
			model.identity();
			model.appendRotation(loop_count*1, Vector3D.X_AXIS);
			model.appendRotation(loop_count*1.2, Vector3D.Y_AXIS);
			model.appendTranslation(100*Math.cos(loop_count/100), 100*Math.sin(loop_count/100), 0);
			model.append(view);
			context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, model, true);
			
			//法線ベクトル変換行列の設定
			normal.copyFrom(model);
			normal.invert();
			normal.transpose();
			context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 8, normal, true);
			
			// drawTriangles()を呼ぶ前に必ずバッファをクリア;
			context3D.clear(0, 0, 0);
			// 3角形を全て描画する;
			context3D.drawTriangles(indices, 0, -1);
			//ビューポートに表示;
			context3D.present();
			
			loop_count++;
		}
	}
}

CubeVertexクラス

package
{
	public class CubeVertex
	{
		public var vertex:Vector.<Number>;
		public var index:Vector.<uint>;
		public static const VERTEX_N:int = 24;
		public static const INDEX_N:int = 36;
		
		public function CubeVertex(width:Number, height:Number, depth:Number)
		{
			var w:Number = width/2, h:Number = height/2, d:Number = depth/2;
			//立方体の頂点データ
			vertex =	Vector.<Number>([
				-w,-h, d,  1,1,  0,0,1,
				-w, h, d,  1,0,  0,0,1,  
				w, h, d,   0,0,  0,0,1,   
				w,-h, d,   0,1,  0,0,1, 
				
				-w,-h,-d,  0,0,  0,-1,0,   
				w,-h,-d,   1,0,  0,-1,0, 
				w,-h, d,   1,1,  0,-1,0,  
				-w,-h, d,  0,1,  0,-1,0, 
				
				-w,-h,-d,  0,1,  0,0,-1,  
				w,-h,-d,   1,1,  0,0,-1,  
				w, h,-d,   1,0,  0,0,-1,	
				-w, h,-d,  0,0,  0,0,-1, 
				
				-w, h, d,  0,0,  0,1,0,   
				w, h, d,   1,0,  0,1,0,  
				w, h,-d,   1,1,  0,1,0,  
				-w, h,-d,  0,1,  0,1,0,
				
				-w, h, d,  0,0, -1,0,0,  
				-w, h,-d,  1,0, -1,0,0, 
				-w,-h,-d,  1,1, -1,0,0,  
				-w,-h, d,  0,1, -1,0,0, 
				
				w, h,-d,   0,0,  1,0,0,   
				w, h, d,   1,0,  1,0,0,  
				w,-h, d,   1,1,  1,0,0,  
				w,-h,-d,   0,1,  1,0,0 
			]);
			
			index = Vector.<uint>([ 
				2, 1, 0,  3, 2, 0, 
				4, 5, 7,  7, 5, 6, 
				8,11, 9,  9,11,10, 
				12,13,15, 13,14,15, 
				16,17,19, 17,18,19, 
				20,21,23, 21,22,23  
			]);
		}
	}
}

コメントを残す

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

次の HTMLタグおよび属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>