AGALでラスタースクロール

テクスチャ座標を正弦関数を利用してずらす擬似ラスタースクロールをAGALで書いてみました。Phaseに加算している値、Frequency、Amplitudeの値を変更するとスクロール量等の調整ができます。

Get Adobe Flash Player
package
{
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.display.Stage3D;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.display3D.Context3D;
	import flash.display3D.Context3DProgramType;
	import flash.display3D.Context3DRenderMode;
	import flash.display3D.Context3DTextureFormat;
	import flash.display3D.Context3DVertexBufferFormat;
	import flash.display3D.IndexBuffer3D;
	import flash.display3D.Program3D;
	import flash.display3D.VertexBuffer3D;
	import flash.display3D.textures.Texture;
	import flash.events.Event;
	import flash.geom.Matrix3D;
	import flash.geom.Vector3D;
	import flash.utils.getTimer;
	import com.adobe.utils.AGALMiniAssembler;
	import com.adobe.utils.PerspectiveMatrix3D;
	import net.hires.debug.Stats;

	[SWF(width = "480", height = "270", frameRate = "60")]
	public class RasterScroll extends Sprite
	{
		[Embed(source = "RasterScroll.png")]
		private var imageEmbedClass:Class;
		private var context3D:Context3D;
		private var indexBuffer:IndexBuffer3D;
		private var projectionMatrix:PerspectiveMatrix3D = new PerspectiveMatrix3D();
		private var modelMatrix:Matrix3D = new Matrix3D();
		private var viewMatrix:Matrix3D = new Matrix3D();
		private var modelViewProjection:Matrix3D = new Matrix3D();
		private var phase:Number = 0;
		private var period:Number = Math.PI * 2;
		private var data:Vector.<Number>;

		public function RasterScroll()
		{
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.stage3Ds[0].addEventListener(Event.CONTEXT3D_CREATE, context3DCreateHandler);
			stage.stage3Ds[0].requestContext3D(Context3DRenderMode.AUTO);
			addChild(new Stats());
		}

		private function context3DCreateHandler(event:Event):void
		{
			context3D = (event.target as Stage3D).context3D;

			context3D.configureBackBuffer(stage.stageWidth, stage.stageHeight, 4);

			var vertexShader:AGALMiniAssembler = new AGALMiniAssembler();
			vertexShader.assemble(Context3DProgramType.VERTEX,
				"m44 op, va0, vc0 \n" +
				"mov v0, va1"
			);
			var fragmentShader:AGALMiniAssembler = new AGALMiniAssembler();
			fragmentShader.assemble(Context3DProgramType.FRAGMENT,
				"mov ft0, v0 \n" +
				"add ft0.z, ft0.y, fc0.x \n" +	// z = y + Phase
				"mul ft0.z, ft0,z, fc0.y \n" +	// z *= Frequency
				"sin ft0.z, ft0.z \n" +			// z = sin(z)
				"mul ft0.z, ft0.z, fc0.z \n" +	// z *= Amplitude
				"add ft0.x, ft0.x, ft0.z \n" +	// x += z
				"tex ft0, ft0, fs0 <2d,linear> \n" +
				"mov oc, ft0"
			);
			var shaderProgram:Program3D = context3D.createProgram();
			shaderProgram.upload(vertexShader.agalcode, fragmentShader.agalcode);
			context3D.setProgram(shaderProgram);

			var vertexBuffer:VertexBuffer3D = context3D.createVertexBuffer(4, 4);
			vertexBuffer.uploadFromVector(Vector.<Number>([
				-1, -1, 0, 1,	// x, y, u, v
				-1,  1, 0, 0,
				 1,  1, 1, 0,
				 1, -1, 1, 1
			]), 0, 4);
			context3D.setVertexBufferAt(0, vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_2);
			context3D.setVertexBufferAt(1, vertexBuffer, 2, Context3DVertexBufferFormat.FLOAT_2);

			indexBuffer = context3D.createIndexBuffer(6);
			indexBuffer.uploadFromVector(Vector.<uint>([
				0, 1, 2,
				2, 3, 0
			]), 0, 6);

			var bitmapData:BitmapData = new imageEmbedClass().bitmapData;
			var texture:Texture = context3D.createTexture(bitmapData.width, bitmapData.height, Context3DTextureFormat.BGRA, false);
			texture.uploadFromBitmapData(bitmapData);
			context3D.setTextureAt(0, texture);

			projectionMatrix.perspectiveFieldOfViewRH(45 * Math.PI / 180, stage.stageWidth / stage.stageHeight, 1, 10);
			viewMatrix.appendTranslation(0, 0, -4);

			data = new Vector.<Number>(4, true);
			data[0] = phase;	// Phase
			data[1] = 20;		// Frequency
			data[2] = 0.05;		// Amplitude
			data[3] = 0;

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

		private function render(event:Event):void
		{
			data[0] = phase;
			phase += 0.01;
			if (phase >= period) phase -= period;

			modelMatrix.appendRotation(0.5, Vector3D.Y_AXIS);
			modelMatrix.appendRotation(0.5, Vector3D.Z_AXIS);

			modelViewProjection.identity();
			modelViewProjection.append(modelMatrix);
			modelViewProjection.append(viewMatrix);
			modelViewProjection.append(projectionMatrix);
			context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, modelViewProjection, true);
			context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT, 0, data);
			context3D.clear();
			context3D.drawTriangles(indexBuffer);
			context3D.present();
		}
	}
}
[トップページに戻る]