AGALの勉強 その8 | Photoshop CC Tutorials
今回はフラットシェーディングをやってみました。

アセンブラでフラットシェーディングを記述してみましたが
レジスタに格納される計算結果の値が見れないのでエラーの連続でした。
本当に高級言語のありがたみが身にしみてよくわかりました。(;^_^ A

◆【できあがりはこちらをクリック】(要:FlashPlayer11、ビデオカード等GPU搭載PC)
$ピック社長のブログ

このデモを作成するにあたってcivetさんのプログラムを参考にさせていただきました。

■ civetさんのデモサイト
http://wonderfl.net/c/jJzk

プログラムは下記のようになります。
Main.as
/**
* Copyright civet ( http://wonderfl.net/user/civet )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/jJzk
*/
package
{
import flash.display.*;
import flash.display3D.*;
import net.hires.debug.Stats;

[SWF(width="400", height="400", frameRate="60")]

public class Main extends Sprite
{
private var _holder:*;

public function Main()
{
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;

var detection:FlatShading = new FlatShading(stage);
detection.callback = onCreate;
addChild(new Stats());
}

private function onCreate(stage3D:Stage3D):void
{
_holder = new Context3DExample(stage, stage3D);
}
}
}

import flash.display.Stage;
import flash.display.Stage3D;
import flash.display3D.Context3D;
import flash.display3D.Context3DRenderMode;
import flash.events.ErrorEvent;
import flash.events.Event;
import flash.system.Capabilities;
import flash.system.System;
import flash.text.TextField;
import flash.text.TextFormat;

class FlatShading
{
private var output:TextField;

public function FlatShading(stage:Stage)
{
var stage3DAvailable:Boolean = stage.hasOwnProperty("stage3Ds");

if(stage3DAvailable) {
var stage3D:Stage3D = stage.stage3Ds[0];
stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContext3DCreate);
stage3D.addEventListener(ErrorEvent.ERROR, onStage3DError);
stage3D.requestContext3D(Context3DRenderMode.AUTO);
}
}

private function onStage3DError(event:ErrorEvent):void
{
output.appendText("Context3D available: false" + "\n");
}

private function onContext3DCreate(event:Event):void
{
var stage3D:Stage3D = event.currentTarget as Stage3D;
var context3D:Context3D = stage3D.context3D;
var isHardwareAccelerated:Boolean = context3D.driverInfo.toLowerCase().indexOf("software") == -1;

if(callback != null) callback(stage3D);
}

public var callback:Function;
}

import com.adobe.utils.AGALMiniAssembler;

import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.display.Stage;
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.Context3DTriangleFace;
import flash.display3D.Context3DVertexBufferFormat;
import flash.display3D.IndexBuffer3D;
import flash.display3D.Program3D;
import flash.display3D.VertexBuffer3D;
import flash.events.ErrorEvent;
import flash.events.Event;
import flash.geom.Matrix3D;
import flash.geom.Vector3D;

class Context3DExample
{
public var viewWidth:Number = 400;
public var viewHeight:Number = 400;
public var zNear:Number = 1;
public var zFar:Number = 500;
public var fov:Number = 45;

private var stage:Stage;
private var stage3D:Stage3D;
private var renderContext:Context3D;
private var indexList:IndexBuffer3D;
private var vertexes:VertexBuffer3D;

private var projection:PerspectiveMatrix3D = new PerspectiveMatrix3D();
private var model:Matrix3D = new Matrix3D();
private var view:Matrix3D = new Matrix3D();
private var finalTransform:Matrix3D = new Matrix3D();

//For rotating the cube
private const pivot:Vector3D = new Vector3D();

private const VERTEX_SHADER:String =
"m44 vt0, va0, vc0 \n" + // vertex * localMatrix
"m44 vt1, vt0, vc4 \n" + // vertex * viewMatrix
"m44 vt2, vt1, vc8 \n" + // vertex * projMatrix
"m44 vt3, va2, vc0 \n" + // vt3 = normal * localMatrix
"mov vt4.x, vc12.x \n" + // 光源ベクトルをvt4へ格納する
"mov vt4.y, vc12.y \n" + //
"mov vt4.z, vc12.z \n" + //
"mov vt4.w, vc12.w \n" + //
"dp3 vt5, vt3, vt4 \n" + // 内積 normal * lightD
"mov op, vt2 \n" + // vertex
"mul vt6, va1 vt5 \n" + //
"mov v0, vt6 \n"; // color

private const FRAGMENT_SHADER:String =
"mov oc, v0"; //Set the output color to the value interpolated from the three triangle vertices

private var vertexAssembly:AGALMiniAssembler = new AGALMiniAssembler();
private var fragmentAssembly:AGALMiniAssembler = new AGALMiniAssembler();
private var programPair:Program3D;

public function Context3DExample(stage:Stage, stage3D:Stage3D)
{
this.stage = stage;
this.stage3D = stage3D;
this.viewWidth = stage.stageWidth;
this.viewHeight = stage.stageHeight;

//Compile shaders
vertexAssembly.assemble( Context3DProgramType.VERTEX, VERTEX_SHADER );
fragmentAssembly.assemble( Context3DProgramType.FRAGMENT, FRAGMENT_SHADER );

contextCreated();
}

//Note, context3DCreate event can happen at any time, such as when the hardware resources are taken by another process
private function contextCreated( event:Event=null ):void
{
renderContext = stage3D.context3D;
setupScene();
}

private function setupScene():void
{
createCube();
renderContext.enableErrorChecking = true; //Can slow rendering - only turn on when developing/testing
renderContext.configureBackBuffer( viewWidth, viewHeight, 2, true );
renderContext.setCulling( Context3DTriangleFace.BACK );

//Create vertex index list for the triangles forming a cube
indexList = renderContext.createIndexBuffer( _triangles.length );
indexList.uploadFromVector( _triangles, 0, _triangles.length );

//Create vertexes - cube faces do not share vertexes
const dataPerVertex:int = 9;
vertexes = renderContext.createVertexBuffer( _vertexData.length / dataPerVertex, dataPerVertex );
vertexes.uploadFromVector( _vertexData, 0, _vertexData.length / dataPerVertex );

//Identify vertex data inputs for vertex program
renderContext.setVertexBufferAt( 0, vertexes, 0, Context3DVertexBufferFormat.FLOAT_3 ); //va0 is position
renderContext.setVertexBufferAt( 1, vertexes, 3, Context3DVertexBufferFormat.FLOAT_3 ); //va1 is color
renderContext.setVertexBufferAt( 2, vertexes, 6, Context3DVertexBufferFormat.FLOAT_3 ); //va2 is normal

//Upload programs to render context
programPair = renderContext.createProgram();
programPair.upload( vertexAssembly.agalcode, fragmentAssembly.agalcode );
renderContext.setProgram( programPair );

//Set up 3D transforms
projection.perspectiveFieldOfViewRH( fov, viewWidth/viewHeight, zNear, zFar );
view.appendTranslation( 0, 0, -3.0 ); //Move view back
model.appendTranslation( 0, 0, 0 ); //center cube on origin
stage.addEventListener( Event.ENTER_FRAME, render );
}

private function render( event:Event ):void
{
//Rotate model on each frame
model.appendRotation( .5, Vector3D.Z_AXIS, pivot );
model.appendRotation( -(.5), Vector3D.Y_AXIS, pivot );
model.appendRotation( -(.5), Vector3D.X_AXIS, pivot );

//Pass the final transform to the vertex shader as program constant, vc0
renderContext.setProgramConstantsFromMatrix( Context3DProgramType.VERTEX, 0, model, true ); // vc0
renderContext.setProgramConstantsFromMatrix( Context3DProgramType.VERTEX, 4, view, true ); // vc4
renderContext.setProgramConstantsFromMatrix( Context3DProgramType.VERTEX, 8, projection, true ); // vc8
renderContext.setProgramConstantsFromVector( Context3DProgramType.VERTEX, 12, Vector.([0, 0, -(-1), 0]), 1); // vc12

//Clear is required before drawTriangles on each frame
renderContext.clear( 0,0,0,1 );

//Draw the triangles that make up the cube
renderContext.drawTriangles( indexList, 0, _triangles.length / 3);

//Show the frame
renderContext.present();
}

private function contextCreationError( error:ErrorEvent ):void
{
trace( error.errorID + ": " + error.text );
}

private var _vertexData:Vector.;
private var _triangles:Vector.;

private function createCube():void
{
var index:int = 0;
var r:Number, g:Number, b:Number;
_vertexData = new Vector.();
_triangles = new Vector.();

//////////////////////////////////////
// 前面
r = 1; g = 1; b = 0;
var vec_00:Vector3D = new Vector3D( 0.5, -0.5, -0.5);
var vec_01:Vector3D = new Vector3D( -0.5, -0.5, -0.5);
var vec_02:Vector3D = new Vector3D( -0.5, 0.5, -0.5);
var vec_03:Vector3D = new Vector3D( 0.5, 0.5, -0.5);

// ポリゴンの法線を求める
var normal:Vector3D;
var vA:Vector3D = vec_00.subtract(vec_02);
var vB:Vector3D = vec_01.subtract(vec_02);
normal = vA.crossProduct(vB);
normal.normalize();

// ポリゴンを作成する
_vertexData.push(vec_00.x, vec_00.y, -(vec_00.z));
_vertexData.push(r, g, b);
_vertexData.push(normal.x, normal.y, -(normal.z));
_triangles.push(index++);

_vertexData.push(vec_01.x, vec_01.y, -(vec_01.z));
_vertexData.push(r, g, b);
_vertexData.push(normal.x, normal.y, -(normal.z));
_triangles.push(index++);

_vertexData.push(vec_02.x, vec_02.y, -(vec_02.z));
_vertexData.push(r, g, b);
_vertexData.push(normal.x, normal.y, -(normal.z));
_triangles.push(index++);

// ポリゴンの法線を求める
var normal_02:Vector3D;
var vA_02:Vector3D = vec_00.subtract(vec_03);
var vB_02:Vector3D = vec_02.subtract(vec_03);

normal_02 = vA.crossProduct(vB);
normal_02.normalize();

// ポリゴンを作成する
_vertexData.push(vec_00.x, vec_00.y, -(vec_00.z));
_vertexData.push(r, g, b);
_vertexData.push(normal_02.x, normal_02.y, -(normal_02.z));
_triangles.push(index++);

_vertexData.push(vec_02.x, vec_02.y, -(vec_02.z));
_vertexData.push(r, g, b);
_vertexData.push(normal_02.x, normal_02.y, -(normal_02.z));
_triangles.push(index++);

_vertexData.push(vec_03.x, vec_03.y, -(vec_03.z));
_vertexData.push(r, g, b);
_vertexData.push(normal_02.x, normal_02.y, -(normal_02.z));
_triangles.push(index++);

//////////////////////////////////////
// 右側面
r = 1; g = 1; b = 0;
vec_00 = new Vector3D( 0.5, -0.5, 0.5);
vec_01 = new Vector3D( 0.5, -0.5, -0.5);
vec_02 = new Vector3D( 0.5, 0.5, -0.5);
vec_03 = new Vector3D( 0.5, 0.5, 0.5);

// ポリゴンの法線を求める
vA = vec_00.subtract(vec_02);
vB = vec_01.subtract(vec_02);
normal = vA.crossProduct(vB);
normal.normalize();

// ポリゴンを作成する
_vertexData.push(vec_00.x, vec_00.y, -(vec_00.z));
_vertexData.push(r, g, b);
_vertexData.push(normal.x, normal.y, (normal.z));
_triangles.push(index++);

_vertexData.push(vec_01.x, vec_01.y, -(vec_01.z));
_vertexData.push(r, g, b);
_vertexData.push(normal.x, normal.y, (normal.z));
_triangles.push(index++);

_vertexData.push(vec_02.x, vec_02.y, -(vec_02.z));
_vertexData.push(r, g, b);
_vertexData.push(normal.x, normal.y, (normal.z));
_triangles.push(index++);

vA_02 = vec_00.subtract(vec_03);
vB_02 = vec_02.subtract(vec_03);

normal_02 = vA.crossProduct(vB);
normal_02.normalize();

// ポリゴンを作成する
_vertexData.push(vec_00.x, vec_00.y, -(vec_00.z));
_vertexData.push(r, g, b);
_vertexData.push(normal_02.x, normal_02.y, (normal_02.z));
_triangles.push(index++);

_vertexData.push(vec_02.x, vec_02.y, -(vec_02.z));
_vertexData.push(r, g, b);
_vertexData.push(normal_02.x, normal_02.y, (normal_02.z));
_triangles.push(index++);

_vertexData.push(vec_03.x, vec_03.y, -(vec_03.z));
_vertexData.push(r, g, b);
_vertexData.push(normal_02.x, normal_02.y, (normal_02.z));
_triangles.push(index++);

//////////////////////////////////////
// 左側面
r = 1; g = 1; b = 0;
vec_00 = new Vector3D( -0.5, -0.5, -0.5);
vec_01 = new Vector3D( -0.5, -0.5, 0.5);
vec_02 = new Vector3D( -0.5, 0.5, 0.5);
vec_03 = new Vector3D( -0.5, 0.5, -0.5);

// ポリゴンの法線を求める
vA = vec_00.subtract(vec_02);
vB = vec_01.subtract(vec_02);
normal = vA.crossProduct(vB);
normal.normalize();

// ポリゴンを作成する
_vertexData.push(vec_00.x, vec_00.y, -(vec_00.z));
_vertexData.push(r, g, b);
_vertexData.push(normal.x, normal.y, (normal.z));
_triangles.push(index++);

_vertexData.push(vec_01.x, vec_01.y, -(vec_01.z));
_vertexData.push(r, g, b);
_vertexData.push(normal.x, normal.y, (normal.z));
_triangles.push(index++);

_vertexData.push(vec_02.x, vec_02.y, -(vec_02.z));
_vertexData.push(r, g, b);
_vertexData.push(normal.x, normal.y, (normal.z));
_triangles.push(index++);

// ポリゴンの法線を求める
vA_02 = vec_00.subtract(vec_03);
vB_02 = vec_02.subtract(vec_03);

normal_02 = vA.crossProduct(vB);
normal_02.normalize();

// ポリゴンを作成する
_vertexData.push(vec_00.x, vec_00.y, -(vec_00.z));
_vertexData.push(r, g, b);
_vertexData.push(normal_02.x, normal_02.y, (normal_02.z));
_triangles.push(index++);

_vertexData.push(vec_02.x, vec_02.y, -(vec_02.z));
_vertexData.push(r, g, b);
_vertexData.push(normal_02.x, normal_02.y, (normal_02.z));
_triangles.push(index++);

_vertexData.push(vec_03.x, vec_03.y, -(vec_03.z));
_vertexData.push(r, g, b);
_vertexData.push(normal_02.x, normal_02.y, (normal_02.z));
_triangles.push(index++);

//////////////////////////////////////
// 背面
r = 1; g = 1; b = 0;
vec_00 = new Vector3D( -0.5, -0.5, 0.5);
vec_01 = new Vector3D( 0.5, -0.5, 0.5);
vec_02 = new Vector3D( 0.5, 0.5, 0.5);
vec_03 = new Vector3D( -0.5, 0.5, 0.5);

// ポリゴンの法線を求める
vA = vec_00.subtract(vec_02);
vB = vec_01.subtract(vec_02);
normal = vA.crossProduct(vB);
normal.normalize();

// ポリゴンを作成する
_vertexData.push(vec_00.x, vec_00.y, -(vec_00.z));
_vertexData.push(r, g, b);
_vertexData.push(normal.x, normal.y, -(normal.z));
_triangles.push(index++);

_vertexData.push(vec_01.x, vec_01.y, -(vec_01.z));
_vertexData.push(r, g, b);
_vertexData.push(normal.x, normal.y, -(normal.z));
_triangles.push(index++);

_vertexData.push(vec_02.x, vec_02.y, -(vec_02.z));
_vertexData.push(r, g, b);
_vertexData.push(normal.x, normal.y, -(normal.z));
_triangles.push(index++);

// ポリゴンの法線を求める
vA_02 = vec_00.subtract(vec_03);
vB_02 = vec_02.subtract(vec_03);

normal_02 = vA.crossProduct(vB);
normal_02.normalize();

// ポリゴンを作成する
_vertexData.push(vec_00.x, vec_00.y, -(vec_00.z));
_vertexData.push(r, g, b);
_vertexData.push(normal_02.x, normal_02.y, -(normal_02.z));
_triangles.push(index++);

_vertexData.push(vec_02.x, vec_02.y, -(vec_02.z));
_vertexData.push(r, g, b);
_vertexData.push(normal_02.x, normal_02.y, -(normal_02.z));
_triangles.push(index++);

_vertexData.push(vec_03.x, vec_03.y, -(vec_03.z));
_vertexData.push(r, g, b);
_vertexData.push(normal_02.x, normal_02.y, -(normal_02.z));
_triangles.push(index++);

//////////////////////////////////////
// 上面
r = 1; g = 1; b = 0;
vec_00 = new Vector3D( 0.5, 0.5, -0.5);
vec_01 = new Vector3D( -0.5, 0.5, -0.5);
vec_02 = new Vector3D( -0.5, 0.5, 0.5);
vec_03 = new Vector3D( 0.5, 0.5, 0.5);

// ポリゴンの法線を求める
vA = vec_00.subtract(vec_02);
vB = vec_01.subtract(vec_02);
normal = vA.crossProduct(vB);
normal.normalize();

// ポリゴンを作成する
_vertexData.push(vec_00.x, vec_00.y, -(vec_00.z));
_vertexData.push(r, g, b);
_vertexData.push(normal.x, normal.y, -(normal.z));
_triangles.push(index++);

_vertexData.push(vec_01.x, vec_01.y, -(vec_01.z));
_vertexData.push(r, g, b);
_vertexData.push(normal.x, normal.y, -(normal.z));
_triangles.push(index++);

_vertexData.push(vec_02.x, vec_02.y, -(vec_02.z));
_vertexData.push(r, g, b);
_vertexData.push(normal.x, normal.y, -(normal.z));
_triangles.push(index++);

// ポリゴンの法線を求める
vA_02 = vec_00.subtract(vec_03);
vB_02 = vec_02.subtract(vec_03);

normal_02 = vA.crossProduct(vB);
normal_02.normalize();

// ポリゴンを作成する
_vertexData.push(vec_00.x, vec_00.y, -(vec_00.z));
_vertexData.push(r, g, b);
_vertexData.push(normal_02.x, normal_02.y, -(normal_02.z));
_triangles.push(index++);

_vertexData.push(vec_02.x, vec_02.y, -(vec_02.z));
_vertexData.push(r, g, b);
_vertexData.push(normal_02.x, normal_02.y, -(normal_02.z));
_triangles.push(index++);

_vertexData.push(vec_03.x, vec_03.y, -(vec_03.z));
_vertexData.push(r, g, b);
_vertexData.push(normal_02.x, normal_02.y, -(normal_02.z));
_triangles.push(index++);

//////////////////////////////////////
// 下面
r = 1; g = 1; b = 0;
vec_00 = new Vector3D( -0.5, -0.5, 0.5);
vec_01 = new Vector3D( -0.5, -0.5, -0.5);
vec_02 = new Vector3D( 0.5, -0.5, -0.5);
vec_03 = new Vector3D( 0.5, -0.5, 0.5);

// ポリゴンの法線を求める
vA = vec_00.subtract(vec_02);
vB = vec_01.subtract(vec_02);
normal = vA.crossProduct(vB);
normal.normalize();

// ポリゴンを作成する
_vertexData.push(vec_00.x, vec_00.y, -(vec_00.z));
_vertexData.push(r, g, b);
_vertexData.push(normal.x, normal.y, -(normal.z));
_triangles.push(index++);

_vertexData.push(vec_01.x, vec_01.y, -(vec_01.z));
_vertexData.push(r, g, b);
_vertexData.push(normal.x, normal.y, -(normal.z));
_triangles.push(index++);

_vertexData.push(vec_02.x, vec_02.y, -(vec_02.z));
_vertexData.push(r, g, b);
_vertexData.push(normal.x, normal.y, -(normal.z));
_triangles.push(index++);

// ポリゴンの法線を求める
vA_02 = vec_00.subtract(vec_03);
vB_02 = vec_02.subtract(vec_03);

normal_02 = vA.crossProduct(vB);
normal_02.normalize();

// ポリゴンを作成する
_vertexData.push(vec_00.x, vec_00.y, -(vec_00.z));
_vertexData.push(r, g, b);
_vertexData.push(normal_02.x, normal_02.y, -(normal_02.z));
_triangles.push(index++);

_vertexData.push(vec_02.x, vec_02.y, -(vec_02.z));
_vertexData.push(r, g, b);
_vertexData.push(normal_02.x, normal_02.y, -(normal_02.z));
_triangles.push(index++);

_vertexData.push(vec_03.x, vec_03.y, -(vec_03.z));
_vertexData.push(r, g, b);
_vertexData.push(normal_02.x, normal_02.y, -(normal_02.z));
_triangles.push(index++);
}

}