经历了十多篇的渲染器以及闲聊js: 实现一个关键的,最小化的,非场景图类型的精灵系统(上)和闲聊js: 实现一个关键的,最小化的,非场景图类型的精灵系统(下),我们已经有了一个可以演示动画,数学,碰撞检测的小类库。今天是第一篇!
先看gif吧:
- 并行动画:物体一边放大,一边绕x轴(pitch,上下转)旋转,一边朝前方平移
- 达到要求的位置后,紧接着绕y轴(yaw,左右转)旋转一定角度
- 上述过程中,物体的表面显示绕z轴(roll,滚转)旋转的精灵和网格背景
本篇目的:
通过一个css 3D 动画 + BLFRender2D协同作战的Demo,来了解
- 什么是动画(Animation)
- 属性动画(Property Animation)
- 动画按时间发生的顺序进行分类
- css3对动画的支持
- css3和BLFRender2D的对接
- css3中 transition vs animation
- 什么是动画:
按照opengl红宝书对动画的定义是: 重绘(repaint)+交换(swapBuffer)
我个人来扩展一下对动画的定义是: 重复的【更新(update) + 重绘(repaint) + 交换(swapBuffer)】
也就是我们BLFEngine2D中的run所做的事情
run(msec) {
//更新
this.updateAll(msec);
//重绘
this.renderAll();
//重复
//调用requestAnimationFrame
requestAnimationFrame((msec) => { this.run(msec) });
}
update中,我们更新我们的位置,角度,缩放,颜色,alpha,.......一切可以变化的属性(例如ios/android中的属性动画)
repaint中进行绘图渲染,将渲染结果写入到后备缓冲区中
swapBuffer是指渲染后,提交显存显示
这一步在浏览器中你看不到,因为浏览器(目前只要是绘图库,都是双缓存,最大的好处是避免闪烁)帮你做了这部操作。实际从底层来看,就是经典的双缓存bitblt【闲聊js:创建一个演示用的渲染库4(渲染表面,像素格式,光栅化,位块传输,图形与图像)】操作。如果是全屏独占模式(玩游戏都知道吧,我也不解释了),则仅仅是双显存缓冲区的指针交换,让前缓冲变为后缓存,后缓冲变为前缓冲,交替显示,速度超快(显示的同时,另外一个在渲染,玩过dx/gl的同学应该很了解这个机制)
- 属性动画:
在我们的的精灵系统中,对精灵中的某个或某些属性进行更新和重绘。
在css3/ios/android中都有属性动画概念,不了解的话,可以自己google/baidu一下
- 动画从时间来看,可以分为连续动画和并行动画两种类型:顺序动画(SequentialAnimation) / 并行动画(ParallelAnimation)
顺序动画(SequentialAnimation): 表达的动作(Action)语义是:
先...然后...最终....(很显然需前一个动作完成后,发出通知:我完成了,谁来继续下面的事情呢?)并行动画(ParallelAnimation): 表的的动作(Action)语义是:
一边.....一边....(例如:物体一边扩大,一边旋转,一边平移)
- css3中对动画的支持:
- 2d 仿射变换【闲聊js:创建一个演示用的渲染库10(坐标轴绘制、空间变换及总结与展望)】
http://www.w3school.com.cn/css3/css3_2dtransform.asp - 3d 仿射变换
http://www.w3school.com.cn/css3/css3_3dtransform.asp - 过渡
http://www.w3school.com.cn/css3/css3_transition.asp - 动画
http://www.w3school.com.cn/css3/css3_animation.asp
关于css3方面的内容,请自行参考上述文档。本篇不做详解
- css3和BLFRender2D的对接(css3代码来自与apple公司的flipcard demo,修改后用于我的demo)
- 为了减少对jquery的依赖,对Html Element元素进行扩展,定义最小化的css class类似操作(http://api.jquery.com/category/attributes/)
这些操作比较通用,就定义在BLFES6Lib.js中吧!
//为了防止和jquery名字发生冲突,增加name后缀
//例如jquery中是addClass,这里就变成了addClassName
Element.prototype.hasClassName = function (a) {
return new RegExp("(?:^|\\s+)" + a + "(?:\\s+|$)").test(this.className);
};
Element.prototype.addClassName = function (a) {
if (!this.hasClassName(a)) {
this.className = [this.className, a].join(" ");
}
};
Element.prototype.removeClassName = function (b) {
if (this.hasClassName(b)) {
var a = this.className;
this.className = a.replace(new RegExp("(?:^|\\s+)" + b + "(?:\\s+|$)", "g"), " ");
}
};
Element.prototype.toggleClassName = function (a) {
this[this.hasClassName(a) ? "removeClassName" : "addClassName"](a);
};
//上面代码都很简单,下面这个是加强版的函数
Element.prototype.changeClassName = function(remove,add) {
if(this.hasClassName(remove))
this.removeClassName(remove);
if(add)
this.addClassName(add);
}
- 需求描述:
- 并行动画:物体一边放大,一边绕x轴(pitch,上下转)旋转,一边朝前方平移
- 达到要求的位置后,紧接着绕y轴(yaw,左右转)旋转一定角度
- 上述过程中,物体的表面显示绕z轴(roll,滚转)旋转的精灵和网格背景
- yaw/pitch/roll【欧拉角】来源于飞行器的姿态描述,在3D中用于描述物体的朝向,先暂时了解一下吧。其实很多基础知识,专业术语要了解,然后才能更精确的google/baidu,否则范围太广,搜索不到
- css3动画:
.container {
width: 600px;
height: 400x;
margin: 0 auto 40px;
border: 2px solid red;
perspective: 1200px;
/* 设置3D投影矩阵*/
}
@keyframes myTransform {
from {
transform: translate3d(0px, 0px, -5000px) rotateX(-720deg);
/*从-720度*/
}
to {
transform: translate3d(0px, 0px, 0px) rotateX(720deg);
/*到720度*/
}
}
@keyframes myYrotate {
from {
transform: rotateY(0deg);
}
to {
transform: rotateY(720deg);
}
}
/*并行动画*/
.animation {
width: 100%;
height: 100%;
transform-style: preserve-3d;
/*使用3d变换*/
animation: myTransform 5s;
}
/*顺序动画第二步*/
.animation1 {
width: 100%;
height: 100%;
transform-style: preserve-3d;
/*使用3d变换*/
animation: myYrotate 5s;
}
- html层次树及css3使用如下:
<body>
<h1>随风而行之青衫磊落险峰行 BLFRender2D + CSSAnimation3D Demo</h1>
<section class="container">
<canvas id="myCanvas" class="animation" width="600" height="400">
你的浏览器还不支持哦
</canvas>
</section>
</body>
- js控制代码:
var init = function() {
let animationDiv = document.getElementById("myCanvas");
//初始化时候,canvas上的动画使用的是上下旋转及向前平移(典型的并行动画),一旦完成后
//触发webkitAnimationEnd事件
//对webkitAnimationEnd事件进行处理,切换css为左右旋转,很典型的顺序动画
//当完成一个动画序列后,浏览器会发送一个完成事件
//我们对该事件进行处理就可以了animationDiv.addEventListener("webkitAnimationEnd", function() {
animationDiv.changeClassName("animation", "animation1");
}, false);
};
//挂接init事件处理函数
window.addEventListener('DOMContentLoaded', init, false);
let canvas = document.getElementById("myCanvas");
let context = canvas.getContext('2d');
let engine = new BLFEngine2D(context);
let spr2 = new BLFDemoSprite(true);
spr2.y = 200;
spr2.rotateSpeed = -1; //逆时针
engine.sprMgr.addSprite(new BLFGridSprite("background"));
engine.sprMgr.addSprite(spr2);
engine.run(); //run的是BLFSprite精灵系统的动画
可能看不到效果,我也不知道为什么,也懒得花时间解决了
大家可以到我的github上下载代码
如果感觉不错,给我的github加颗小星星,鼓励鼓励我!
对了,在使用css3中的animation/transition中遇到一些问题,然后查了一些资料结合实践,总结一下一起分享吧:
- transition简单易用,但是有如下几个缺点:
- 没法自动运行(init中),只能靠事件触发(例如click)
- 无法循环运行,只能一次结束
- 只能设置开始,结束状态,无中间任意多的过度状态设置
- 只能animate一个属性,例如设置了移动就不能旋转
综上所述,transition全部的缺点就是animation的优点!