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

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

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

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

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

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

下面给出完整的代码:

 package
{
import com.adobe.utils.AGALMiniAssembler; import flash.display.Bitmap; import flash.display.Sprite;
import flash.display.Stage3D;
import flash.display3D.Context3D;
import flash.display3D.Context3DProfile;
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.ErrorEvent;
import flash.events.Event;
import flash.geom.Matrix3D;
import flash.geom.Vector3D; [SWF(width=550, height=400, frameRate=60)]
public class Matrix3DTest extends Sprite
{
[Embed(source="img.png")]
private var IMG_CLASS:Class; //3D 场景对象
private var _stage3D:Stage3D;
//3D 上下文渲染对象
private var _context3D:Context3D; //顶点缓冲数据
private var _vertexBuffer:VertexBuffer3D;
//索引缓冲数据
private var _indexBuffer:IndexBuffer3D;
//纹理数据对象
private var _texture:Texture; //着色器对象
private var _program3D:Program3D; //正交矩阵
private var _projectionMatrix:Matrix3D;
//模型矩阵, 通过操作该矩阵来变换纹理的显示
private var _modelViewMatrix:Matrix3D; //旋转度数
private var _rotation:Number = 0; public function Matrix3DTest()
{
addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
} private function addedToStageHandler(event:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler); //3D 场景存在, 一般存在 4 个 3D 场景对象
if(stage.stage3Ds.length > 0)
{
//使用最下层的 3D 场景
_stage3D = stage.stage3Ds[0];
//请求 3D 上下文渲染对象
_stage3D.addEventListener(ErrorEvent.ERROR, stage3DErrorHandler);
_stage3D.addEventListener(Event.CONTEXT3D_CREATE, context3DCreateHandler);
_stage3D.requestContext3D(Context3DRenderMode.AUTO, Context3DProfile.BASELINE);
}
} private function stage3DErrorHandler(event:ErrorEvent):void
{
trace("Context3D对象请求失败:", event.text);
} private function context3DCreateHandler(event:Event):void
{
initContext3D();
initOrthographicProjection(stage.stageWidth, stage.stageHeight);
initBuffer();
initTexture();
transformMatrix();
initProgram(); //每帧进行渲染
addEventListener(Event.ENTER_FRAME, render);
} private function initContext3D():void
{
//获取 3D 渲染对象
_context3D = _stage3D.context3D;
//设置后台缓冲区
_context3D.configureBackBuffer(stage.stageWidth, stage.stageHeight, 2);
} private function initOrthographicProjection(width:Number, height:Number, near:Number = -1.0, far:Number = 1.0):void
{
//创建正交矩阵的实例
_projectionMatrix = new Matrix3D();
//设置正交矩阵数据, 这个公式记死即可
var coords:Vector.<Number> = new <Number>
[
2.0 / width, 0.0, 0.0, 0.0,
0.0, -2.0 / height, 0.0, 0.0,
0.0, 0.0, -2.0 / (far - near), 0.0,
-1.0, 1.0, -(far + near) / (far - near), 1.0
];
_projectionMatrix.copyRawDataFrom(coords);
} private function initBuffer():void
{
//顶点数据, 因为只需要显示一张图片所以这里的顶点数据是可以写死的, 同时可以去掉 z 轴
//的数据, 因为不需要使用到 z 轴, 我们按照下面的规则来排列顶点:
//0 - 1
//| / |
//2 - 3
//有趣的是 uv 的数据和顶点数据其实是一致的, 所以 uv 的数据也可以去除, 不过我们这里
//先留着, Starling 框架中 uv 数据是已经去掉的
var vertexData:Vector.<Number> = Vector.<Number>(
[
// x, y, u, v
0, 0, 0, 0,
1, 0, 1, 0,
0, 1, 0, 1,
1, 1, 1, 1
]); //创建顶点缓冲对象, 参数设定存在几组数据和每组数据的个数
_vertexBuffer = _context3D.createVertexBuffer(vertexData.length / 4, 4);
//上传顶点数据到GPU, 参数设定从第几组数据开始上传和上传多少组数据
_vertexBuffer.uploadFromVector(vertexData, 0, vertexData.length / 4); //索引数据
var indexData:Vector.<uint> = Vector.<uint>(
[
0, 1, 2,
1, 2, 3
]); //创建索引缓冲对象, 每个索引对应顶点数据中的相对应的一组数据,
//每3个索引组成一个会被绘制出来的三角形, 参数指定索引的长度
_indexBuffer = _context3D.createIndexBuffer(indexData.length);
//上传索引数据到GPU, 参数设定从第几个数据开始上传和上传多少个数据
_indexBuffer.uploadFromVector(indexData, 0, indexData.length);
} private function initTexture():void
{
//创建位图
var bitmap:Bitmap = new IMG_CLASS() as Bitmap;
//创建纹理, 注意尺寸必须是 2 的幂数
_texture = _context3D.createTexture(128, 128, Context3DTextureFormat.BGRA, true);
//上传纹理到 GPU, 第二个参数表示该纹理的 mipmap 级别, 级别零是高级全分辨率图像
_texture.uploadFromBitmapData(bitmap.bitmapData, 0);
} private function transformMatrix():void
{
//设置纹理的转换矩阵
_modelViewMatrix = new Matrix3D();
//设置矩阵的位置
_modelViewMatrix.prependTranslation(0, 0, 0);
//设置矩阵的旋转
_modelViewMatrix.prependRotation(0, Vector3D.Z_AXIS);
//设置矩阵的尺寸
_modelViewMatrix.prependScale(128, 128, 1);
//设置纹理的中心点
_modelViewMatrix.prependTranslation(0, 0, 0); //将纹理的转换矩阵和正交矩阵结合就得到了最终需要的上传到 GPU 进行运算的矩阵数据
var mvpMatrix:Matrix3D = new Matrix3D();
mvpMatrix.append(_modelViewMatrix);
mvpMatrix.append(_projectionMatrix);
//将我们的最终矩阵作为常量传递到 GPU 中, 指定其是名称为 vc0 的那个寄存器
_context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, mvpMatrix, true);
} private function initProgram():void
{
//顶点着色器代码, 每个上传的顶点前都会执行一次该代码
var vertexArr:Array =
[
//op 代表位置输出寄存器, 无论对顶点进行多少次的运算最终都要将结果
//赋值给他, 这里和我们的正交矩阵进行相乘的运算
"m44 op, va0, vc0",
//片段着色器需要用的数据要在这里通过 v0 中转一下, 因为片段着色器不
//能直接读取 va0 和 va1 的数据
"mov v0, va1"
]; //片段着色器代码, 每个可以显示的像素都会执行一次该代码
var fragmentArr:Array =
[
//对纹理 fs0 进行取样, 通过 v0 代表的 uv 坐标来获取对应的像素点颜
//色, 将该颜色值存储到 ft0 中
"tex ft0, v0, fs0 <2d,repeat,linear,nomip>",
//oc 代表颜色输出寄存器, 每个顶点的颜色数据都要赋值给他
"mov oc, ft0"
]; //使用 Adobe 自己提供的编译器编译代码为程序可使用的二进制数据
var assembler:AGALMiniAssembler = new AGALMiniAssembler();
_program3D = assembler.assemble2(_context3D, 1, vertexArr.join("\n"), fragmentArr.join("\n")); //----- 这段代码是从 render 里搬过来的, 因为不会进行改动就不放在帧循环中了 ----- //指定着色器代码的 va0 代表的数据段, 表示顶点的 x, y 坐标
_context3D.setVertexBufferAt(0, _vertexBuffer, 0, Context3DVertexBufferFormat.FLOAT_2);
//指定着色器代码的 va1 代表的数据段, 表示顶点的 u, v 数据
_context3D.setVertexBufferAt(1, _vertexBuffer, 2, Context3DVertexBufferFormat.FLOAT_2);
//指定上传的纹理由 fs0 表示
_context3D.setTextureAt(0, _texture);
//指定当前使用的着色器对象
_context3D.setProgram(_program3D);
} private function render(event:Event):void
{
//没有变动的数据就不需要进行重复的上传了
//每帧进行旋转
_rotation += 1;
//重置模型矩阵
_modelViewMatrix.identity();
//移动模型到舞台中心
_modelViewMatrix.prependTranslation(stage.stageWidth / 2, stage.stageHeight / 2, 0);
//应用新的旋转角度
_modelViewMatrix.prependRotation(_rotation, Vector3D.Z_AXIS);
//设置模型大小
_modelViewMatrix.prependScale(128, 128, 1);
//设置模型的注册点为中心, 注意这里使用的是百分比, 不要使用 -64 哦
_modelViewMatrix.prependTranslation(-0.5, -0.5, 0);
//同样需要再次上传我们的矩阵数据用于运算
var mvpMatrix:Matrix3D = new Matrix3D();
mvpMatrix.append(_modelViewMatrix);
mvpMatrix.append(_projectionMatrix);
_context3D.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, mvpMatrix, true); //清除已绘制过的 3D 图像
_context3D.clear();
//通过顶点索引数据绘制所有的三角形
_context3D.drawTriangles(_indexBuffer);
//将后台缓冲的图像显示到屏幕
_context3D.present();
}
}
}

Stage3D学习笔记(六):旋转动画效果的更多相关文章

  1. Stage3D学习笔记(五):通过矩阵操作纹理

    虽然我们上一节已经实现了正交矩阵的显示,但是可以明显的感觉到要调整显示纹理的坐标和尺寸是相当复杂的,需要对每个顶点进行操作,如果还要加上注册点和旋转的话,用上一节的方法来做是会让人发疯的! 所以我们距 ...

  2. iOS学习笔记-自定义过渡动画

    代码地址如下:http://www.demodashi.com/demo/11678.html 这篇笔记翻译自raywenderlick网站的过渡动画的一篇文章,原文用的swift,由于考虑到swif ...

  3. 【Stage3D学习笔记续】山寨Starling(八):核心优化(批处理)的实现

    批处理是使GPU进行高效绘制的一种技术手段,也是整个渲染流程中最核心的技术,到目前为止我们并没有使用到这种技术手段,下面我们看看我们现在的渲染机制. 先想一想我们最开始是怎么向GPU绘制一幅图像的,可 ...

  4. Linux学习笔记(六) 进程管理

    1.进程基础 当输入一个命令时,shell 会同时启动一个进程,这种任务与进程分离的方式是 Linux 系统上重要的概念 每个执行的任务都称为进程,在每个进程启动时,系统都会给它指定一个唯一的 ID, ...

  5. 拒绝IE8-,CSS3 transform rotate旋转动画效果(支持IE9+/chrome/firefox)

    <!DOCTYPE html> <html> <head> <meta charset=" utf-8"> <meta nam ...

  6. java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)

    java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...

  7. Learning ROS for Robotics Programming Second Edition学习笔记(六) indigo xtion pro live

    中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...

  8. Typescript 学习笔记六:接口

    中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...

  9. python3.4学习笔记(六) 常用快捷键使用技巧,持续更新

    python3.4学习笔记(六) 常用快捷键使用技巧,持续更新 安装IDLE后鼠标右键点击*.py 文件,可以看到Edit with IDLE 选择这个可以直接打开编辑器.IDLE默认不能显示行号,使 ...

  10. Go语言学习笔记六: 循环语句

    Go语言学习笔记六: 循环语句 今天学了一个格式化代码的命令:gofmt -w chapter6.go for循环 for循环有3种形式: for init; condition; increment ...

随机推荐

  1. C++中的指针与const

    刚开始接触C++时,指针和const之间的关系有点混乱,现在总结如下: 一.指向const变量的指针 #include<iostream.h> void main() { const in ...

  2. JavaScript DOM高级程序设计 4.3控制事件流和注册事件侦听器--我要坚持到底!

    一.事件流 我们通过下面一个实例,进行说明. <body> <h1>Event Flow</h1> <ul id="nav"> &l ...

  3. eclipse为hibernate.cfg.xml添加自动提示【转】

    在hibernate.cfg.xml头部部分如下: <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate C ...

  4. java中的log中的用法和小结

    Log.logInfo(s.toString());的控制台显示 jog.info的具体用法. import java.io.*; import org.apache.log4j.Logger; im ...

  5. 2013 ACM/ICPC Asia Regional Changsha Online - E

    第一个被板刷的题 取余 依次算在周几 #include <iostream> #include<cstdio> #include<cstring> #include ...

  6. hdu 2955 Robberies

    Robberies Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  7. SharePoint 2013 Pop-Up Dialogs

    转:http://blog.csdn.net/tristan_dong/article/details/19076315 自定义弹出框 一. 项目需求: 自定义弹出框,包括弹出框的内容和样式. 说明: ...

  8. unix network programming(3rd)Vol.1 [第1章]《读书笔记系列》

    文章最开头介绍了 获取时间的C/S 模型的代码, 还用了实现了IPV6的版本 unix 介绍了errno值,以及在多进程/多线程中的问题 多线程中不用全局errno,而是用返回值 处理error 详细 ...

  9. 【译】 AWK教程指南 1前言

    前面的话: 这几天写了一个程序,在同一个目录里生成了很多文件,需要统计其中部分文件的总大小,发现经常用到的ls.du等命令都无济于事,我甚至都想到了最笨的方法,写一个脚本:mkdir一个新目录,把要统 ...

  10. Jquery UI的datepicker插件使用方法

    原文链接;http://www.ido321.com/375.html Jquery UI是一个非常丰富的Jquery插件,并且UI的各部分插件可以独自分离出来使用,这是其他很多Jquery插件没有的 ...