11 Animation动画
这些天有些忙,导致一个多星期没有更新文章,群里的小伙伴也天天催我更。为了表示歉意,我决定在现在的基础上面增加一节Three.js
核心类的相关介绍,来让让小伙伴们能更清楚的了解相关的基础内容。下面我们开始这一节的内容,动画。
动画一般可以定义两种:一种是变形动画,另一种是骨骼动画。下面,我们先介绍一下变形动画。
变形动画
变形动画的实现就是通过修改当前模型的顶点位置来实现动画。就比如,一个动画需要变动十次才可以实现,那么我们就需要为当前模型的每一个顶点定义每一次所在的位置,Three.js
通过每一次修改实现最后的一个动画的整个流程。
为了更好的理解变形动画,我们创建了一个案例,查看地址为:点击这里
这个案例是为了让我们更好的了解变形动画的实现以及使用。在右上角,我们能发现两个可切换的拖拽条,这两个拖拽条对应的是两个变形目标数组,拖拽范围是0-1,就是当前的变形目标对本体的影响程度。我们进行拖拽就可以发现,界面中的立方体也会跟随着变动,影响当前的立方体。接下来我讲解一下,当前案例是如何实现的:
- 首先,在我们创建模型的几何体时,给几何体
morphTargets
赋值了两个变形目标,morphTargets
是一个数组,这意味着我们可以增加很多的变形目标,在给morphTargets
添加的数组,我们需要自己定义一个名称和相关的顶点,这个顶点数据必须和默认的模型的顶点数据保持一致,设置完后,我们需要调用geometry
的computeMorphNormals()
来更新:
var cubeGeometry = new THREE.BoxGeometry(4, 4, 4);// 创建两个影响立方体的变形目标
var cubeTarget1 = new THREE.BoxGeometry(2, 10, 2);
var cubeTarget2 = new THREE.BoxGeometry(8, 2, 8);// 将两个geometry的顶点放入到立方体的morphTargets里面
cubeGeometry.morphTargets[0] = {name: 'target1', vertices: cubeTarget1.vertices};
cubeGeometry.morphTargets[1] = {name: 'target2', vertices: cubeTarget2.vertices};
cubeGeometry.computeMorphNormals();
- 然后,当前模型使用的材质必须设置可以使用变形目标变形:
var cubeMaterial = new THREE.MeshLambertMaterial({morphTargets: true, color: 0x00ffff});
- 当我们创建好网格模型添加到场景内后,可以在
mesh
对象上面找到morphTargetInfluences
这一个配置项,这里面也是一个数组,是和geometry
的morphTargets
相对应的,主要就是用于设置当前的变形目标对本体的影响度,默认值为0-1,0为不影响本体,1为完全影响本体:
gui = {influence1:0.01,influence2:0.01,update : function () {cube.morphTargetInfluences[0] = gui.influence1;cube.morphTargetInfluences[1] = gui.influence2;}
};
通过上面我们手动实现了一个变形动画,就会发现,其实变形动画是一直在修改变形目标对本体的影响尺度。我们可以通过这个原理实现一些变形动画。
当前案例代码查看地址:点击这里
骨骼动画
骨骼动画是需要生成一个与模型相关的骨架,骨架中的骨骼也会存在对应关系,模型的每一个需要动画的顶点需要设置影响它的骨骼以及骨骼影响顶点的程度。骨骼动画和变形动画相比会比较复杂一些,但是它又有更多的灵活性。我们可以想象一下人体的骨骼,如果使用变形动画,需要把所有的每一次的变动都存一个顶点数组,而骨骼动画,只需要设置骨骼的相关信息,就可以实现更多的动画。下面我们看一下骨骼动画的简单案例:点击这里
这是一个官方提供的案例,我经过一些简单的修改,也将当前一个柱形图形的骨骼显示的出来,这个实现比较复杂,我们需要做的就是先理解它是怎么实现的:
- 首先, 我们创建了一个圆柱几何体,然后通过圆柱的几何体每一个顶点的y轴坐标来设置需要绑定的骨骼的下标和影响的程度:
//遍历几何体所有的顶点
for (var i = 0; i < geometry.vertices.length; i++) {//根据顶点的位置计算出骨骼影响下标和权重var vertex = geometry.vertices[i];var y = (vertex.y + sizing.halfHeight);var skinIndex = Math.floor(y / sizing.segmentHeight);var skinWeight = (y % sizing.segmentHeight) / sizing.segmentHeight;geometry.skinIndices.push(new THREE.Vector4(skinIndex, skinIndex + 1, 0, 0));geometry.skinWeights.push(new THREE.Vector4(1 - skinWeight, skinWeight, 0, 0));}
几何体的skinIndices
属性和skinWeights
属性就是来设置相关的绑定下标和权重(骨骼影响程度)。
- 相应的,我们需要设置一组相关的骨骼,骨骼具有嵌套关系,这样才能实现一个骨架,由于圆柱体比较简单,我们就创建一条骨骼垂直嵌套的骨骼:
bones = [];var prevBone = new THREE.Bone();
bones.push(prevBone);
prevBone.position.y = -sizing.halfHeight;for (var i = 0; i < sizing.segmentCount; i++) {var bone = new THREE.Bone();bone.position.y = sizing.segmentHeight;bones.push(bone); //添加到骨骼数组prevBone.add(bone); //上一个骨骼定义为父级prevBone = bone;}
- 创建纹理时,我们还需要设置当前纹理需要受到骨骼的影响,将材质的
skinning
属性设置为true
:
var lineMaterial = new THREE.MeshBasicMaterial({skinning: true,wireframe: true
});
- 最后,我们需要创建骨骼材质,并将模型绑定骨骼:
mesh = new THREE.SkinnedMesh(geometry, [material, lineMaterial]);
var skeleton = new THREE.Skeleton(bones); //创建骨架
mesh.add(bones[0]); //将骨骼添加到模型里面
mesh.bind(skeleton); //模型绑定骨架
这样,我们就实现了使用Three.js
创建一个简单的骨骼动画。使用dat.gui
我们能够修改每一个骨骼的poisition
、rotation
和scale
并查看对当前模型的影响。案例的源码地址:点击这里
两种动画的区别
变形动画主要用于精度要求高的动画,比如人物的面部表情。优点是动画表达会很到位,缺点就是扩展性不强,只能执行设置好的相关动画。
骨骼动画主要用于那种精度要求低,而且需要丰富多样的动画,就比如人物的走动,攻击防御等动画,我们可以通过一套骨骼,修改相应骨骼的位置的信息直接实现相应的效果。确定是没有变形动画的精度高,但是可以实现多种多样的效果。
总结:我们可以根据项目的需求来设置不同的动画,就比如一个人物模型,说话我们使用变形动画去实现,而肢体动作使用骨骼动画去实现。
导入模型动画
在Three.js
的动画系统中,你可以为模型的各种属性设置动画:骨骼动画,变形动画,材质的相关属性(颜色,透明度, 是否可见)。动画属性可以设置淡入淡出效果以及各种扭曲特效。也可以单独的改变一个对象或者多个对象上的动画的影响程度和动画时间。
为了实现这些,Three.js
动画系统在2015年修改为了一个类似于Unity
和虚幻引擎4的架构。接下来我们了解一下这套动画系统的主要组件以及它们时如何协同工作。
动画片段(Animation Clips)
在我们成功导入模型以后,如果模型拥有相关的动画属性,会在返回的模型数据中产生一个名为animations
的数组,数组的每一个子项都是一个AnimationClips
对象。
每一个单独AnimationClips
对象通常保存的都是模型的一个动画的数据,假如,如果模型网格是一个人物角色,第一个AnimationClips
对象有可能保存的是人物走动的动画,第二个AnimationClips
对象用于跳跃,第三个用于攻击动画等等。
关键帧轨迹(Keyframe Tracks)
在AnimationClips
对象内部,一般会有四个属性:
- name:当前的动画的一个名称
- uuid:一个不会重复的uuid
- duration:当前动画一个循环所需要的时间
- tracks:轨迹当前动画每一次切换动作所需要的数据
假设当前的动画是骨骼动画,在关键帧轨迹中存储的数据是在每一帧骨骼随着时间变动的数据(位置,旋转和缩放等)。
如果当前动画是一个变形动画,在关键帧轨迹中将会把顶点数据的变动存储在其中(比如实现人脸的笑以及哭等动作)。
动画混合器(Animation Mixer)
在动画片段中存储的数据仅仅构成了动画实现的基础,实际的播放权力在动画混合器的手中。你可以想象动画混合器其实不仅仅只是作为动画的播放器,它还可以同时控制几个动画,混合它们或者合并它们。
动画播放器(Animation Actions)
这个英文我更乐意将它翻译成动画播放器,因为我们最终需要将数据生成一个动画播放器来操作当前的动画执行,暂停或者停止,是否使用淡入淡出效果或者将动画加快或减慢。
动画对象组(Animation Object Groups)
如果你希望一组模型对象共享当前的动画,我们可以使用动画对象组来实现。
通过导入模型显示动画
变形动画
我们首先查看一个官方的模型案例,这个案例效果是一匹马奔跑的动画,我们也可以通过下面地址查看:点击这里
接下来我们看一下这匹马是如何实现的:
- 在模型加载成功以后,我们首先将模型创建出来,并将材质的
morphTargets
设置为ture,可以使用变形动画:
mesh = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({vertexColors: THREE.FaceColors,morphTargets: true
}));
mesh.castShadow = true;
mesh.scale.set(0.1, 0.1, 0.1);
scene.add(mesh);
- 然后我们创建了一个针对于该模型的混合器:
mixer = new THREE.AnimationMixer(mesh);
- 接着使用变形目标数据创建一个动画片段:
var clip = THREE.AnimationClip.CreateFromMorphTargetSequence('gallop', geometry.morphTargets, 30);
- 使用混合器和动画片段创建一个动画播放器来播放:
var action = mixer.clipAction(clip); //创建动画播放器
action.setDuration(1); //设置当前动画一秒为一个周期
action.play(); //设置当前动画播放
- 最后,我们还需要在重新绘制循环中更新混合器,进行动作更新:
function render() {control.update();var time = clock.getDelta();//由于模型导入是异步的,所以我们再模型没有加载完之前是获取不到混合器的if (mixer) {mixer.update(time);}renderer.render(scene, camera);
}
骨骼动画
骨骼动画模型我们使用的是gltf
格式,这个模型是在Sketchfab
网站下载,案例是一个小姐姐跳舞的一个片段,查看地址:点击这里
gltf
格式的模型导入进来以后,我们可以直接通过animations
数组创建播放器:
mixer = new THREE.AnimationMixer(obj); //通过当前模型创建混合器
action = mixer.clipAction(gltf.animations[0]); //通过动画数据创建播放器
直接调用播放器的播放事件让动画播放:
action.play();
最后,我们还是需要在循环渲染中更新混合器,并将每一帧渲染的间隔时间传入
function render() {control.update();var time = clock.getDelta();if (mixer) {mixer.update(time);}renderer.render(scene, camera);
}
11 Animation动画相关推荐
- CSS3 Animation动画的十二原则
[本文系外部转贴,原文地址:https://cssanimation.rocks/principles/] 编者注:鉴于KM不能插入iframe直接演示效果,只能给链接跳转页面看代码了:(Animat ...
- 第100天:CSS3中animation动画详解
CSS3属性中有关于制作动画的三个属性:Transform,Transition,Animation: 一.Animation定义动画 CSS3的Animation是由"keyframes& ...
- animation停留_这些Animation动画技巧与细节你知道么
引言- 在 web 应用中,前端同学在实现动画效果时往往常用的几种方案: css3 transition / animation - 实现过渡动画 setInterval / setTimeout - ...
- core Animation动画
在iOS中,图形可分为以下几个层次:越上层,封装程度越高,动画实现越简洁越简单,但是自由度越低:反之亦然.本文着重介绍Core Animation层的基本动画实现方案.在iOS中,展示动画可以类比于显 ...
- 用css的animation动画属性来实现一个H5场景动态电子邀请函
接触css的animation 也有一段时间,经常在朋友圈会看到一些很漂亮的电子邀请函,刚开始以为是视频,后来发现原来是用css的animation来实现的.经过分析,其实是利用css的animati ...
- css 右上角 翻开动画_CSS3 transition动画、transform变换、animation动画
一.CSS3 transition动画 transition可以实现动态效果,实际上是一定时间之内,一组css属性变换到另一组属性的动画展示过程. 属性参数: 1.transition-propert ...
- 超级强大的SVG SMIL animation动画详解
超级强大的SVG SMIL animation动画详解 本文摘自超级强大的SVG SMIL animation动画详解_Zoomla!逐浪CMS官网 (z01.com),网站看上去有年头了,担心哪天会 ...
- [转]超级强大的SVG SMIL animation动画详解
超级强大的SVG SMIL animation动画详解 本文花费精力惊人,具有先驱前瞻性,转载规则以及申明见文末,当心予以追究. 本文地址:http://www.zhangxinxu.com/word ...
- SVG animation动画
一:简介 由于Web是一个动态的媒介,SVG有支持实时动画能力.SVG的内容可以使用下面的方式添加动画: 1.使用SVG动画元素SVG文档片段可以描述基于时间对文档元素的修改.通过各种各样的动画元素, ...
最新文章
- LeetCode刷题记录10——434. Number of Segments in a String(easy)
- docker 挂载目录_完美解决:Docker部署SpringBoot项目后图片无法访问和上传,3招搞定!...
- 公众号python训练营真的假的_python中的这些坑,早看早避免。
- 重新理解@Resource注解
- RocketMQ源码解析-事务消息的二阶段提交
- Android系统(74)--- 从零实现灵活且可高度定制的Android图片选择架构
- C语言中用链表构建栈讲解,C语言数据结构之使用链表模拟栈的实例
- 8.最大滑动窗口问题
- 【雨林木风】装机人员常用软件工具盘Y6.5
- 携程实时大数据平台实践分享
- 打造你的微信自动回复智障机器人
- 有家谱和没家谱,后人的差距真的很大!家谱用怎么样的形式完成传承
- 一款不错的Android环形进度条
- v-model 自带绑定的number 、lazy 、debounce属性
- dataframe排序 pd.rank()
- Allegro学习笔记
- 深度丨一文读懂智能制造的主线——智能生产(工厂/车间数字化)
- 线程池有哪些状态?状态是如何转换的?
- java学习第109天,p665-676(05/07),12集干的漂亮
- 使用Java 编写将阿拉伯数字转为中文数字的代码