package test
{
import com.adobe.utils.AGALMiniAssembler;
import com.adobe.utils.PerspectiveMatrix3D;
import flash.display.Bitmap;
import flash.display.Sprite;
import flash.display.Stage;
import flash.display3D.Context3D;
import flash.display3D.Context3DProgramType;
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.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.events.PressAndTapGestureEvent;
import flash.geom.Matrix;
import flash.geom.Matrix3D;
import flash.geom.Point;
import flash.geom.Vector3D;
import flash.ui.Keyboard;
public class TestAgal extends Sprite
{
[Embed(source="/assets/cloth.jpg")]
private var cloth:Class;
[Embed(source="/assets/skyBox.png")]
private var skyBox:Class;
[Embed(source="/assets/flower.jpg")]
private var flower:Class;
[Embed(source="/assets/trinket_diffuse.jpg")]
private var trinketDiff:Class;
[Embed(source="/assets/trinket_normal.jpg")]
private var trinketNor:Class;
[Embed(source="/assets/trinket_specular.jpg")]
private var trinketSpe:Class;
protected var context3D:Context3D;
protected var program:Program3D;
protected var vertexbuffer:VertexBuffer3D;
protected var indexbuffer:IndexBuffer3D;
private var texture:Texture;
private var texture1:Texture;
private var xR:Boolean = false;
private var yR:Boolean = false;
private var zR:Boolean = false;
private var projectionTransform:PerspectiveMatrix3D;
private var lightPos:Vector3D = new Vector3D(0,0,-10);
private var lightStr:Number = 1;
private var lightStrAdd:Number = -0.01;
private var cameraMatrix:Matrix3D;
private var objMatrix:Matrix3D = new Matrix3D();
private var endMatrix:Matrix3D = new Matrix3D();
private var aspect:Number;
public function TestAgal(context3D:Context3D,stage:Stage)
{
this.context3D = context3D;
stage.addEventListener(Event.ENTER_FRAME, onRender);
stage.addEventListener(KeyboardEvent.KEY_DOWN,onKeyDown)
stage.addEventListener(MouseEvent.MOUSE_DOWN,onMouseDown);
aspect = stage.width/stage.height;
initProjection();
initMolehill();
}
protected function initProjection():void
{
aspect = 4/3;
var zNear:Number = 0.1;
var zFar:Number = 1000;
var fov:Number = 45*Math.PI/180;
cameraMatrix = new Matrix3D();
cameraMatrix.appendTranslation(0,0,-5);
// cameraMatrix.invert();
projectionTransform = new PerspectiveMatrix3D();
projectionTransform.perspectiveFieldOfViewLH(fov, aspect, zNear, zFar);
// projectionTransform.perspectiveFieldOfViewRH(45, aspect, zNear, zFar);
// projectionTransform.prepend(cameraMatrix);
}
protected function initMolehill():void
{
var w:Number = 2;
var h:Number = 3;
var hw:Number = w * .5;
var hh:Number = h * .5;
var vertices:Vector.<Number> = Vector.<Number>([
-hw,-hh,0, 0,1, 0,0,-1,//顶点 UV 法线 3+2+3=8
hw,-hh,0, 1,1, 0,0,-1,
hw,hh, 0, 1,0, 0,0,-1,
-hw,hh,0, 0,0, 0,0,-1
]);
var offset:int = 8;
vertexbuffer = context3D.createVertexBuffer(vertices.length/offset, offset);
vertexbuffer.uploadFromVector(vertices, 0, vertices.length/offset);
var indices:Vector.<uint> = Vector.<uint>([0,1,3,1,2,3]);
indexbuffer = context3D.createIndexBuffer(indices.length);
indexbuffer.uploadFromVector (indices, 0, indices.length);
var vertexShaderAssembler : AGALMiniAssembler = new AGALMiniAssembler();
vertexShaderAssembler.assemble( Context3DProgramType.VERTEX,
"m44 op va0 vc0
"+ //顶点
"mov v1 va1
"+ //UV
"mov v2 va2"//法线
);
var fragmentShaderAssembler : AGALMiniAssembler= new AGALMiniAssembler();
fragmentShaderAssembler.assemble( Context3DProgramType.FRAGMENT,
"tex ft0,v1,fs0<2d,linear,repeat>
" +
"mov ft1 fc0
" +
"mov ft2 v2
" +
"m44 ft2 ft2 fc3
" +
"dp3 ft3.w ft1 ft2
" + //ft3 = cos涩塔
"abs ft3.w ft3.w
" +
"mul ft4 ft0 ft3.wwww
"+
"mul ft4 ft4 fc1.wwww
"+
"dp3 ft6.w fc2 ft2
" +
"abs ft6.w ft6.w
" +
"mul ft7 fc4 ft6.wwww
" +
"add ft0 ft0 ft4
" + // 原始颜色 += 漫反射光照加成颜色
"add ft0 ft0 ft7
" + // 原始颜色 += 高光加成颜色
// "add ft0 ft0 fc1
" + // 叠加一个环境光颜色
"mov oc,ft0"
);
var bitmap:Bitmap = new trinketDiff();
texture = context3D.createTexture(bitmap.width,bitmap.height,Context3DTextureFormat.BGRA,false);
texture.uploadFromBitmapData(bitmap.bitmapData);
var bitmap1:Bitmap = new trinketNor();
texture1 = context3D.createTexture(bitmap1.width,bitmap1.height,Context3DTextureFormat.BGRA,false);
texture1.uploadFromBitmapData(bitmap1.bitmapData);
program = context3D.createProgram();
program.upload( vertexShaderAssembler.agalcode, fragmentShaderAssembler.agalcode);
}
private function culculateNormal(vecVb:Vector.<Number>,vertexNum:int):void
{
var data32PerVertex:int = vecVb.length/vertexNum;
var vertexArr:Array = [];
for (var i:int=0;i<vertexNum;i++){
var x:Number = vecVb[data32PerVertex*i];
var y:Number = vecVb[data32PerVertex*i+1];
var z:Number = vecVb[data32PerVertex*i+2];
vertexArr.push(new Vector3D(x,y,z));
}
var calcNormal:Function = function(p1:Vector3D,p2:Vector3D,p3:Vector3D):Vector3D{
var source2:Vector3D = new Vector3D(p2.x-p1.x,p2.y-p1.y,p2.z-p1.z);
var source1:Vector3D = new Vector3D(p3.x-p1.x,p3.y-p1.y,p3.z-p1.z);
var norV:Vector3D = new Vector3D();
norV.x = source1.y * source2.z - source1.z * source2.y;
norV.y = source1.z * source2.x - source1.x * source2.z;
norV.z = source1.x * source2.y - source1.y * source2.x;
norV.normalize();
return norV;
}
var calcNormalAvg:Function = function(arr:Array,offsetNormal:int):void{
var sideLen:int = arr.length/3;
var sideAvg:Vector3D = new Vector3D();
for (var i:int=0;i<sideLen;i++){
var side:Vector3D = calcNormal(vertexArr[arr[i*3]],vertexArr[arr[i*3+1]],vertexArr[arr[i*3+2]]);
sideAvg=sideAvg.add(side);
}
sideAvg.x = sideAvg.x/sideLen;
sideAvg.y = sideAvg.y/sideLen;
sideAvg.z = sideAvg.z/sideLen;
sideAvg.normalize();
vecVb[offsetNormal] = -sideAvg.x;
vecVb[offsetNormal+1] = -sideAvg.y;
vecVb[offsetNormal+2] = -sideAvg.z;
}
// calcNormalAvg([0,1,3,1,2,3],vertexNum*data32PerVertex)
}
protected function onRender(e:Event):void
{
if ( !context3D ) return;
if(xR) objMatrix.appendRotation(1,Vector3D.X_AXIS);
if(yR) objMatrix.appendRotation(1,Vector3D.Y_AXIS);
if(zR) objMatrix.appendRotation(1,Vector3D.Z_AXIS);
endMatrix.identity();
endMatrix.append(objMatrix);
var viewMatrix:Matrix3D = cameraMatrix.clone();
viewMatrix.invert();
viewMatrix.append(projectionTransform);
endMatrix.append(viewMatrix);
// endMatrix.copyFrom(objMatrix);
// endMatrix.append(projectionTransform);
context3D.setVertexBufferAt (0, vertexbuffer, 0, Context3DVertexBufferFormat.FLOAT_3);//顶点 Va0
context3D.setVertexBufferAt(1, vertexbuffer, 3, Context3DVertexBufferFormat.FLOAT_2);// uv Va1
context3D.setVertexBufferAt(2,vertexbuffer,5,Context3DVertexBufferFormat.FLOAT_3); // 法线 Va2
var light:Vector3D=lightPos.clone(); // 不含平移元素的变换
light.normalize();
context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT,0,Vector.<Number>([light.x,light.y,light.z,0]));
// -- 设置状态机当前的fc1 静态常量:xyz用于 环境光颜色叠加 W用于漫反射光照强度 这里叠加一个红色环境光
var ambientR:Number = 1//lightStr*0.2;
var ambientG:Number = 0//(1-lightStr)*0.2;
var ambientB:Number = 0//(lightStr/2)*0.2;
context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT,1,Vector.<Number>([ambientR,ambientG,ambientB,lightStr]));//lightStr
var halfEyeLightPos:Vector3D = cameraMatrix.position.clone();
halfEyeLightPos=halfEyeLightPos.add(lightPos);
halfEyeLightPos.x/=2;
halfEyeLightPos.y/=2;
halfEyeLightPos.z/=2;
halfEyeLightPos.normalize();
context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT,2,Vector.<Number>([halfEyeLightPos.x,halfEyeLightPos.y,halfEyeLightPos.z,0]));
// -- 设置状态机当前的fc3 静态常量:用于将模型矩阵变换传入
context3D.setProgramConstantsFromMatrix(Context3DProgramType.FRAGMENT,3,objMatrix);
// -- 设置状态机当前的fc4 静态常量:高光颜色
var specularR:Number = 0//lightStr*0.3;
var specularG:Number = 1//lightStr*0.3;
var specularB:Number = 0//lightStr*0.3;
context3D.setProgramConstantsFromVector(Context3DProgramType.FRAGMENT,4,Vector.<Number>([specularR,specularG,specularB,0]));
context3D.setTextureAt(0,texture);
// context3D.setTextureAt(1,texture1);
context3D.setProgram(program);
context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, endMatrix, true);
context3D.clear();
context3D.drawTriangles(indexbuffer);
context3D.present();
}
/**
* 当鼠标移动的时候记录的鼠标点
*/
private var onMouseDownPt:Point = new Point();
/**
* 鼠标移动旋转物体
* 原理无非就是根据每次移动时的像素差距来计算让物体矩阵M在当前的状态下再围绕X和Y旋转(至于围绕Z轴旋转可以自己添加试试)
* @param e
*
*/
private function onMouseDown(e:MouseEvent):void{
onMouseDownPt.x = e.stageX;
onMouseDownPt.y = e.stageY;
stage.addEventListener(MouseEvent.MOUSE_MOVE,onMouseMove);
stage.addEventListener(MouseEvent.MOUSE_UP,onMouseUp);
}
private function onMouseMove(e:MouseEvent):void{
var dx:Number = e.stageX - onMouseDownPt.x;
var dy:Number = e.stageY - onMouseDownPt.y;
var degreesY:Number = -dx/2;
var degreesX:Number = -dy/2;
onMouseDownPt.x = e.stageX;
onMouseDownPt.y = e.stageY;
objMatrix.appendRotation(degreesY,Vector3D.Y_AXIS);
objMatrix.appendRotation(degreesX,Vector3D.X_AXIS);
}
private function onMouseUp(e:MouseEvent):void{
stage.removeEventListener(MouseEvent.MOUSE_MOVE,onMouseMove);
stage.removeEventListener(MouseEvent.MOUSE_UP,onMouseUp);
}
private var moveDis:Number = 0.1;
protected function onKeyDown(event:KeyboardEvent):void
{
switch(event.keyCode)
{
case Keyboard.X:
xR = !xR;
break;
case Keyboard.C:
yR = !yR;
break;
case Keyboard.Z:
zR = !zR;
break;
case Keyboard.R:
objMatrix.identity();
xR = false;
yR = false;
zR = false;
break;
case Keyboard.LEFT:
lightPos.x -= moveDis;
break;
case Keyboard.RIGHT:
lightPos.x += moveDis;
break;
case Keyboard.UP:
lightPos.y += moveDis;
break;
case Keyboard.DOWN:
lightPos.y -= moveDis;
break;
case Keyboard.A:
cameraMatrix.appendTranslation(moveDis,0,0);
break;
case Keyboard.D:
cameraMatrix.appendTranslation(-moveDis,0,0);
break;
case Keyboard.W:
cameraMatrix.appendTranslation(0,-moveDis,0);
break;
case Keyboard.S:
cameraMatrix.appendTranslation(0,moveDis,0);
break;
}
trace("lightPos:"+lightPos);
trace("cameraPos"+cameraMatrix.decompose())
}
/**
* 判断设备丢失
*
*/
private function get isContextDispose():Boolean{
return context3D==null||context3D.driverInfo=="Disposed"||context3D.driverInfo=="";
}
}
}