• Stage3D学习笔记(六):旋转动画效果


    我们这节在上一篇代码的基础上再进一步,让显示的纹理进行旋转。

    实现旋转,只需要每帧修改_modelViewMatrix的旋转角度即可,我们需要一个变量来记录旋转:

    1 //旋转度数
    2 private var _rotation:Number = 0;

    每帧修改后的数据需要重新提交到GPU,而已经提交的数据不改动则不需要重新进行提交,所以我们修改一下render方法即可:

     1 private function render(event:Event):void
     2 {
     3     //没有变动的数据就不需要进行重复的上传了
     4     //每帧进行旋转
     5     _rotation += 1;
     6     //重置模型矩阵
     7     _modelViewMatrix.identity();
     8     //移动模型到舞台中心
     9     _modelViewMatrix.prependTranslation(stage.stageWidth / 2, stage.stageHeight / 2, 0);
    10     //应用新的旋转角度
    11     _modelViewMatrix.prependRotation(_rotation, Vector3D.Z_AXIS);
    12     //设置模型大小
    13     _modelViewMatrix.prependScale(128, 128, 1);
    14     //设置模型的注册点为中心, 注意这里使用的是百分比, 不要使用 -64 哦
    15     _modelViewMatrix.prependTranslation(-0.5, -0.5, 0);
    16     //同样需要再次上传我们的矩阵数据用于运算
    17     var mvpMatrix:Matrix3D = new Matrix3D();
    18     mvpMatrix.append(_modelViewMatrix);
    19     mvpMatrix.append(_projectionMatrix);
    20     _context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, mvpMatrix, true);
    21 //省略
    22 }

    对于上传后的数据的销毁,Texture、VertexBuffer3D、IndexBuffer3D和Program3D都有名为dispose的方法,我们如果向GPU上传了数据,调用该方法会清除上传到GPU的数据。

    下面给出完整的代码:

      1 package
      2 {
      3     import com.adobe.utils.AGALMiniAssembler;
      4     
      5     import flash.display.Bitmap;
      6     
      7     import flash.display.Sprite;
      8     import flash.display.Stage3D;
      9     import flash.display3D.Context3D;
     10     import flash.display3D.Context3DProfile;
     11     import flash.display3D.Context3DProgramType;
     12     import flash.display3D.Context3DRenderMode;
     13     import flash.display3D.Context3DTextureFormat;
     14     import flash.display3D.Context3DVertexBufferFormat;
     15     import flash.display3D.IndexBuffer3D;
     16     import flash.display3D.Program3D;
     17     import flash.display3D.VertexBuffer3D;
     18     import flash.display3D.textures.Texture;
     19     import flash.events.ErrorEvent;
     20     import flash.events.Event;
     21     import flash.geom.Matrix3D;
     22     import flash.geom.Vector3D;
     23     
     24     [SWF(width=550, height=400, frameRate=60)]
     25     public class Matrix3DTest extends Sprite
     26     {
     27         [Embed(source="img.png")]
     28         private var IMG_CLASS:Class;
     29         
     30         //3D 场景对象
     31         private var _stage3D:Stage3D;
     32         //3D 上下文渲染对象
     33         private var _context3D:Context3D;
     34         
     35         //顶点缓冲数据
     36         private var _vertexBuffer:VertexBuffer3D;
     37         //索引缓冲数据
     38         private var _indexBuffer:IndexBuffer3D;
     39         //纹理数据对象
     40         private var _texture:Texture;
     41         
     42         //着色器对象
     43         private var _program3D:Program3D;
     44         
     45         //正交矩阵
     46         private var _projectionMatrix:Matrix3D;
     47         //模型矩阵, 通过操作该矩阵来变换纹理的显示
     48         private var _modelViewMatrix:Matrix3D;
     49         
     50         //旋转度数
     51         private var _rotation:Number = 0;
     52         
     53         public function Matrix3DTest()
     54         {
     55             addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
     56         }
     57         
     58         private function addedToStageHandler(event:Event):void
     59         {
     60             removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
     61             
     62             //3D 场景存在, 一般存在 4 个 3D 场景对象
     63             if(stage.stage3Ds.length > 0)
     64             {
     65                 //使用最下层的 3D 场景
     66                 _stage3D = stage.stage3Ds[0];
     67                 //请求 3D 上下文渲染对象
     68                 _stage3D.addEventListener(ErrorEvent.ERROR, stage3DErrorHandler);
     69                 _stage3D.addEventListener(Event.CONTEXT3D_CREATE, context3DCreateHandler);
     70                 _stage3D.requestContext3D(Context3DRenderMode.AUTO, Context3DProfile.BASELINE);
     71             }
     72         }
     73         
     74         private function stage3DErrorHandler(event:ErrorEvent):void
     75         {
     76             trace("Context3D对象请求失败:", event.text);
     77         }
     78         
     79         private function context3DCreateHandler(event:Event):void
     80         {
     81             initContext3D();
     82             initOrthographicProjection(stage.stageWidth, stage.stageHeight);
     83             initBuffer();
     84             initTexture();
     85             transformMatrix();
     86             initProgram();
     87             
     88             //每帧进行渲染
     89             addEventListener(Event.ENTER_FRAME, render);
     90         }
     91         
     92         private function initContext3D():void
     93         {
     94             //获取 3D 渲染对象
     95             _context3D = _stage3D.context3D;
     96             //设置后台缓冲区
     97             _context3D.configureBackBuffer(stage.stageWidth, stage.stageHeight, 2);
     98         }
     99         
    100         private function initOrthographicProjection(Number, height:Number, near:Number = -1.0, far:Number = 1.0):void
    101         {
    102             //创建正交矩阵的实例
    103             _projectionMatrix = new Matrix3D();
    104             //设置正交矩阵数据, 这个公式记死即可
    105             var coords:Vector.<Number> = new <Number>
    106                     [
    107                         2.0 / width, 0.0, 0.0, 0.0,
    108                         0.0, -2.0 / height, 0.0, 0.0,
    109                         0.0, 0.0, -2.0 / (far - near), 0.0,
    110                         -1.0, 1.0, -(far + near) / (far - near), 1.0
    111                     ];
    112             _projectionMatrix.copyRawDataFrom(coords);
    113         }
    114         
    115         private function initBuffer():void
    116         {
    117             //顶点数据, 因为只需要显示一张图片所以这里的顶点数据是可以写死的, 同时可以去掉 z 轴
    118             //的数据, 因为不需要使用到 z 轴, 我们按照下面的规则来排列顶点:
    119             //0 - 1
    120             //| / |
    121             //2 - 3
    122             //有趣的是 uv 的数据和顶点数据其实是一致的, 所以 uv 的数据也可以去除, 不过我们这里
    123             //先留着, Starling 框架中 uv 数据是已经去掉的
    124             var vertexData:Vector.<Number> = Vector.<Number>(
    125                     [
    126                     //  x, y, u, v
    127                         0, 0, 0, 0,
    128                         1, 0, 1, 0,
    129                         0, 1, 0, 1,
    130                         1, 1, 1, 1
    131                     ]);
    132             
    133             //创建顶点缓冲对象, 参数设定存在几组数据和每组数据的个数
    134             _vertexBuffer = _context3D.createVertexBuffer(vertexData.length / 4, 4);
    135             //上传顶点数据到GPU, 参数设定从第几组数据开始上传和上传多少组数据
    136             _vertexBuffer.uploadFromVector(vertexData, 0, vertexData.length / 4);
    137             
    138             //索引数据
    139             var indexData:Vector.<uint> = Vector.<uint>(
    140                     [
    141                         0, 1, 2,
    142                         1, 2, 3
    143                     ]);
    144             
    145             //创建索引缓冲对象, 每个索引对应顶点数据中的相对应的一组数据, 
    146             //每3个索引组成一个会被绘制出来的三角形, 参数指定索引的长度
    147             _indexBuffer = _context3D.createIndexBuffer(indexData.length);
    148             //上传索引数据到GPU, 参数设定从第几个数据开始上传和上传多少个数据
    149             _indexBuffer.uploadFromVector(indexData, 0, indexData.length);
    150         }
    151         
    152         private function initTexture():void
    153         {
    154             //创建位图
    155             var bitmap:Bitmap = new IMG_CLASS() as Bitmap;
    156             //创建纹理, 注意尺寸必须是 2 的幂数
    157             _texture = _context3D.createTexture(128, 128, Context3DTextureFormat.BGRA, true);
    158             //上传纹理到 GPU, 第二个参数表示该纹理的 mipmap 级别, 级别零是高级全分辨率图像
    159             _texture.uploadFromBitmapData(bitmap.bitmapData, 0);
    160         }
    161         
    162         private function transformMatrix():void
    163         {
    164             //设置纹理的转换矩阵
    165             _modelViewMatrix = new Matrix3D();
    166             //设置矩阵的位置
    167             _modelViewMatrix.prependTranslation(0, 0, 0);
    168             //设置矩阵的旋转
    169             _modelViewMatrix.prependRotation(0, Vector3D.Z_AXIS);
    170             //设置矩阵的尺寸
    171             _modelViewMatrix.prependScale(128, 128, 1);
    172             //设置纹理的中心点
    173             _modelViewMatrix.prependTranslation(0, 0, 0);
    174             
    175             //将纹理的转换矩阵和正交矩阵结合就得到了最终需要的上传到 GPU 进行运算的矩阵数据
    176             var mvpMatrix:Matrix3D = new Matrix3D();
    177             mvpMatrix.append(_modelViewMatrix);
    178             mvpMatrix.append(_projectionMatrix);
    179             //将我们的最终矩阵作为常量传递到 GPU 中, 指定其是名称为 vc0 的那个寄存器
    180             _context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, mvpMatrix, true);
    181         }
    182         
    183         private function initProgram():void
    184         {
    185             //顶点着色器代码, 每个上传的顶点前都会执行一次该代码
    186             var vertexArr:Array =
    187                     [
    188                         //op 代表位置输出寄存器, 无论对顶点进行多少次的运算最终都要将结果
    189                         //赋值给他, 这里和我们的正交矩阵进行相乘的运算
    190                         "m44 op, va0, vc0",
    191                         //片段着色器需要用的数据要在这里通过 v0 中转一下, 因为片段着色器不
    192                         //能直接读取 va0 和 va1 的数据
    193                         "mov v0, va1"
    194                     ];
    195             
    196             //片段着色器代码, 每个可以显示的像素都会执行一次该代码
    197             var fragmentArr:Array =
    198                     [
    199                         //对纹理 fs0 进行取样, 通过 v0 代表的 uv 坐标来获取对应的像素点颜
    200                         //色, 将该颜色值存储到 ft0 中
    201                         "tex ft0, v0, fs0 <2d,repeat,linear,nomip>",
    202                         //oc 代表颜色输出寄存器, 每个顶点的颜色数据都要赋值给他
    203                         "mov oc, ft0"
    204                     ];
    205             
    206             //使用 Adobe 自己提供的编译器编译代码为程序可使用的二进制数据
    207             var assembler:AGALMiniAssembler = new AGALMiniAssembler();
    208             _program3D = assembler.assemble2(_context3D, 1, vertexArr.join("
    "), fragmentArr.join("
    "));
    209             
    210             //----- 这段代码是从 render 里搬过来的, 因为不会进行改动就不放在帧循环中了 -----
    211             
    212             //指定着色器代码的 va0 代表的数据段, 表示顶点的 x, y 坐标
    213             _context3D.setVertexBufferAt(0, _vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_2);
    214             //指定着色器代码的 va1 代表的数据段, 表示顶点的 u, v 数据
    215             _context3D.setVertexBufferAt(1, _vertexBuffer, 2, Context3DVertexBufferFormat.FLOAT_2);
    216             //指定上传的纹理由 fs0 表示
    217             _context3D.setTextureAt(0, _texture);
    218             //指定当前使用的着色器对象
    219             _context3D.setProgram(_program3D);
    220         }
    221         
    222         private function render(event:Event):void
    223         {
    224             //没有变动的数据就不需要进行重复的上传了
    225             //每帧进行旋转
    226             _rotation += 1;
    227             //重置模型矩阵
    228             _modelViewMatrix.identity();
    229             //移动模型到舞台中心
    230             _modelViewMatrix.prependTranslation(stage.stageWidth / 2, stage.stageHeight / 2, 0);
    231             //应用新的旋转角度
    232             _modelViewMatrix.prependRotation(_rotation, Vector3D.Z_AXIS);
    233             //设置模型大小
    234             _modelViewMatrix.prependScale(128, 128, 1);
    235             //设置模型的注册点为中心, 注意这里使用的是百分比, 不要使用 -64 哦
    236             _modelViewMatrix.prependTranslation(-0.5, -0.5, 0);
    237             //同样需要再次上传我们的矩阵数据用于运算
    238             var mvpMatrix:Matrix3D = new Matrix3D();
    239             mvpMatrix.append(_modelViewMatrix);
    240             mvpMatrix.append(_projectionMatrix);
    241             _context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, mvpMatrix, true);
    242             
    243             //清除已绘制过的 3D 图像
    244             _context3D.clear();
    245             //通过顶点索引数据绘制所有的三角形
    246             _context3D.drawTriangles(_indexBuffer);
    247             //将后台缓冲的图像显示到屏幕
    248             _context3D.present();
    249         }
    250     }
    251 }
  • 相关阅读:
    模板方法模式
    外观模式
    《那些年啊,那些事——一个程序员的奋斗史》——128 (终章)
    《那些年啊,那些事——一个程序员的奋斗史》——127
    《那些年啊,那些事——一个程序员的奋斗史》——127
    分布式系统开发里必须要解决的3个技术问题
    《那些年啊,那些事——一个程序员的奋斗史》——128 (终章)
    列举几种系统调用
    linux core文件设置
    《那些年啊,那些事——一个程序员的奋斗史》——127
  • 原文地址:https://www.cnblogs.com/hammerc/p/4076490.html
Copyright © 2020-2023  润新知