现在的位置: 首页 > 综合 > 正文

Flash Stage3D Molehill 学习笔记(2)

2012年02月03日 ⁄ 综合 ⁄ 共 7575字 ⁄ 字号 评论关闭

  前面已经学习了“常见的3D显像术语”与“常见的3D编码术语”。今天所要探讨的是Molehill。

什么是Molehill:

  Molehill是Adobe官方预计推出的一套底层3D渲染引擎,该引擎能够调用GPU,借助GPU强大的浮点运算能力实现开创新的Flash3D技术。

  2010年10月,Adobe在MAX大会中公布了关于Flash Player的新项目,名为Molehill的新API集可以让开发者借助GPU大幅提升Flash的3D渲染能力。
目前现有的Flash Player 10.1可以在30Hz下渲染几千个非Z缓冲三角形,使用Molehill和图形芯片则可以在60Hz左右的高分辨率显示器中全屏渲染近百万的Z缓冲三角形。这些新的3D API还将同时支持Flash Player和Adobe AIR,为用户提供全新的3D体验。
  Adboe介绍称,Molehill是新推出的支持GPU硬件加速底层API的总称,支持Z缓冲、模版色缓冲、碎片和顶点着色、立方体纹理等特性。借助这些3D API,开发者可以在任何情况下调用GPU,如果出现GPU不兼容的情况则会调用CPU作为图形渲染处理器。
Flash Player10中现有的3D API将可以继续使用,Molehill主要面向高级开发人员用来构建复杂的3D模型,开发者可以按照实际需要选择使用这两种API。Adobe表示他们将会为不同的平台提供这些新的开发工具,在Windows系统中将会依赖于DirectX 9,在Mac和Linux下则依赖于OpenGL 1.3,未来还将会借助OpenGL ES 2.0支持Android和Linux Mobile等移动平台。
 
Molehill的结构:
  对Flash而言,舞台就是画到屏幕上的东西,而各式各样的可视元素(位图、矢量图、文本、UI组件)被附加到了舞台上。同样,基于Molehill的Flash动画也被附加到了一个名为Stage3D的特殊对象上。你的舞台可以拥有一个以上的Stage3D,而每个Stage3D都有一个Context3D对象。Context3D就是引擎,它就是Molehill对象。
 
Stage      
  这是常规的Flash舞台,任何将会显示在屏幕上的东西都要放在这里。
Stage3D   
  是出于Flash和GUP之间的对象,不像诸如Sprite这样的常规Flash2D显示对象,Stage3D是不会出现在显示列表中的。这就意味着你不能在Stage3D对象上进行addChild()方法。Stage3D对象位于所以常规Flash内容的后面,它总是位于舞台的最底层。
Context3D  
  stage3D对象包含了一个Context3D,就像Bitmap 对象包含 BitmapData一样。当你处理Bitmap的时候。花的大部分时间其实是在处理BitmapData.同理,在Molehill中你也很少会直接用到Stage3D.取而代之的,你将使用Context3D进行工作。你可以把Context3D当做“3D引擎”,它是所有3D数据的对象。当你想把顶点数据作为顶点数据上传到显卡时候,你会把一个数字数组送入Context3D.
VertexBuffer3D
  3D顶点缓冲。3D世界中的模型由成千上万个顶点组成的。每个顶点定义了一个网格“定角”的X,Y,Z坐标。而VertexBuffer3D就是一个用于这些坐标的数组。在初始化3D世界的时候。我们需要将VertexBuffer3D对象交给Context3D,以此来把这庞大的数据数组送给Molehill.接下来Context3D会把这些数据直接上传到你的显存中,以备渲染时使用。
IndexBuffer3D
  3D索引缓冲 FLash终归还是需要知道每一块是从什么地方开始又到什么地方结束的,而索引缓冲就是用来告诉Flash哪部分数据是属于哪个顶点的。
Program3D
  3D着色器 顶点着色器和片段着色器被上传到显卡,这样一来它们就能在GPU中运行了。着色器使用一种类似于汇编语言的特殊语言进行编译,它们将告诉GPU如何去绘制上传好的网格模型。
 
  在初始化期间,所有的缓冲和编译好的着色器都将送人显卡,这个过程只有一次,一旦完成,Flash就可以反复的绘制这些模型到新的位置上了。
 
说了这么多理论我们开始动手来写一个简单的demo 来帮助消化下这些知识:
 
 

package
{
 import com.adobe.utils.AGALMiniAssembler;
 import com.adobe.utils.PerspectiveMatrix3D;
 
 import flash.display.Bitmap;
 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.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.Matrix;
 import flash.geom.Matrix3D;
 import flash.geom.Vector3D;
 
 [SWF(width=1024,height=590)]
 public class lesson1 extends Sprite
 {
  [Embed(source = "assset/bricks_a_spec.jpg")]
  private var myTextureBitmap:Class;
  
  /**
   * 舞台的宽度
   */  
  public const stageW:int = 1024;
  /**
   * 舞台的高度
   */  
  public const stageH:int = 590;
  /**
   * 纹理大小
   */  
  public const textureSize:int = 512;
  /**
   * 3D图形窗口
   */  
  private var context3D:Context3D;
  /**
   *定义着色器
   */  
  private var shaderProgram:Program3D;
  /**
   * 定义一个顶点缓冲
   */  
  private var vertexBuffer:VertexBuffer3D;
  /**
   * 定义一个索引缓冲
   */  
  private var indexBuffer:IndexBuffer3D;
  /**
   * 定义网格的顶点数据
   */  
  private var meshVertexData:Vector.<Number>;
  /**
   * 定义网格的索引数据
   */  
  private var meshIndexData:Vector.<uint>;
  
  /**
   * 影响模型位置和相机的角度的矩阵
   */  
  private var projectionMatrix3D:PerspectiveMatrix3D = new PerspectiveMatrix3D();
  /**
   * 定义一个模型的矩阵
   */  
  private var modelMatrix:Matrix3D = new Matrix3D;
  
  /**
   * 定义一个视图的矩阵
   */  
  private var viewMatrix:Matrix3D = new Matrix3D;
  
  /**
   * 定义一个投影
   */  
  private var modelViewProjection:Matrix3D = new Matrix3D;
  /**
   * 用于动画的帧计数器
   */  
  private var t:Number = 0;
  /**
   * 创建纹理
   */  
  private var myTextureData:Bitmap = new myTextureBitmap();
    
  private var myTexture:Texture;
  
  public function lesson1()
  {
   this.stage ? addEventListener(Event.ADDED_TO_STAGE,init) : init();
  }
  
  private function init(event:Event = null):void
  {
   hasEventListener(Event.ADDED_TO_STAGE) && removeEventListener(Event.ADDED_TO_STAGE,init);
   stage.scaleMode = StageScaleMode.NO_SCALE;
   stage.align = StageAlign.TOP_LEFT;
   stage.stage3Ds[0].addEventListener(Event.CONTEXT3D_CREATE,onContext3DCreate);
   stage.stage3Ds[0].requestContext3D();
  }
  
  private function onContext3DCreate(event:Event):void
  {
   removeEventListener(Event.CONTEXT3D_CREATE,onContext3DCreate);
   var stage3D:Stage3D = event.target as Stage3D;
   context3D = stage3D.context3D;
   if(!context3D)
   {
    return;
   }
   context3D.enableErrorChecking = true;
   initData();
  }
  
  private function initData():void
  {
   //定义一个正方形的顶点信息
   meshVertexData = Vector.<Number>([
    -1, -1, 1, 0, 0, 0, 0, 1,
    1, -1, 1, 1, 0, 0, 0, 1,
    1, 1, 1, 1, 1, 0, 0, 1,
    -1, 1, 1, 0, 1, 0, 0, 1
   ]);
   // 定义一个正方形的索引
   meshIndexData = Vector.<uint>
   ([
    0,1,2, 0,2,3
   ]);
   
   // 3D缓冲区的像素尺寸
   context3D.configureBackBuffer(stageW,stageH,0,true);
   //创建一个顶点着色器
   var vertexShader:AGALMiniAssembler = new AGALMiniAssembler();
   vertexShader.assemble
   (
    Context3DProgramType.VERTEX,
    // 创建一个4X4矩阵乘以相机角度
    "m44 op, va0, vc\n"+
    //告诉片段着色器X,Y,Z的值
    "mov v0, va0\n"+
    //告诉片段着色器u,v的值
    "mov v1, va1\n"
   );
   // 创建一个片段着色器
   var pixelShader:AGALMiniAssembler = new AGALMiniAssembler();
   pixelShader.assemble
   (
    Context3DProgramType.FRAGMENT,
    "tex ft0, v1, fs0 <2d,repeat,miplinear>\n"+
    // 结果输出
    "mov oc, ft0\n"
   );
   
   shaderProgram = context3D.createProgram();
   //上传网格索引
   shaderProgram.upload(vertexShader.agalcode,pixelShader.agalcode);
   indexBuffer = context3D.createIndexBuffer(meshIndexData.length);
   indexBuffer.uploadFromVector(meshIndexData,0,meshIndexData.length);
   // 上传网格顶点数据
   // 因为包含X,Y,Z,U,V,nX,nY,nZ 所以每个顶点各占8个数组元素
   vertexBuffer = context3D.createVertexBuffer(meshVertexData.length/8,8);
   vertexBuffer.uploadFromVector(meshVertexData,0,meshVertexData.length / 8);
   //产生MIP映射
   myTexture = context3D.createTexture(textureSize,textureSize,Context3DTextureFormat.BGRA,false);
   var ws:int = myTextureData.bitmapData.width;
   var hs:int = myTextureData.bitmapData.height;
   var level:int = 0;
   var transform:Matrix = new Matrix();
   var tmp:BitmapData = new BitmapData(ws,hs,true,0x00000000);
   while(ws >=1 && hs >=1)
   {
    tmp.draw(myTextureData.bitmapData,transform,null,null,null,true);
    myTexture.uploadFromBitmapData(tmp,level);
    transform.scale(0.5,0.5);
    level++;
    ws >>=1;
    hs >>=1;
    if(hs && ws)
    {
     tmp.dispose();
     tmp = new BitmapData(ws,hs,true,0x00000000);
    }
   }
   tmp.dispose();
   // 创建透视矩阵
   projectionMatrix3D.identity();
   // 设置45度视角,1024 / 590 长宽比,0,1的近裁剪面,100的远裁剪面
   projectionMatrix3D.perspectiveFieldOfViewRH(45,stageW / stageH,0.01,100);
   // 创建一个定义相机位置的矩阵
   viewMatrix.identity();
   // 为了看到Mesh,把相机往后移;
   viewMatrix.appendTranslation(0,0,-4);
   
   // 准备就绪 开始渲染
   addEventListener(Event.ENTER_FRAME,onRendering);
  }
  
  protected function onRendering(event:Event):void
  {
   context3D.clear(0,0,0);
   context3D.setProgram(shaderProgram);
   // 创建变换矩阵
   modelMatrix.identity();
   modelMatrix.appendRotation(t*0.6,Vector3D.X_AXIS);
   modelMatrix.appendRotation(t*0.7,Vector3D.Y_AXIS);
   modelMatrix.appendRotation(t*0.8,Vector3D.Z_AXIS);
   modelMatrix.appendTranslation(0,0,0);

   t+=2.0;
   
   //重置矩阵
   modelViewProjection.identity();
   modelViewProjection.append(modelMatrix);
   modelViewProjection.append(viewMatrix);
   modelViewProjection.append(projectionMatrix3D);
   
   //把矩阵传给着色器
   context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX,0,modelViewProjection,true);
   // 着色器处理顶点数据
   context3D.setVertexBufferAt(0,vertexBuffer,0,Context3DVertexBufferFormat.FLOAT_3);
   // 着色器处理纹理
   context3D.setVertexBufferAt(1,vertexBuffer,3,Context3DVertexBufferFormat.FLOAT_3);
   context3D.setTextureAt(0,myTexture);
   context3D.drawTriangles(indexBuffer,0,meshIndexData.length / 3);
   context3D.present();
  }
 }
}

抱歉!评论已关闭.