ThreeJS创建关键帧动画

简介: 这篇文章讲解了如何在Three.js中利用关键帧轨道 (`KeyframeTrack`) 创建动画效果,并提供了详细的步骤和代码示例。

之前有说过两种创建动画的形式,一个是很粗的方式,直接在requestAnimationFrame中修改模型的属性,因为threejs本身就会不断刷新画面,利用不断刷新的时候修改模型属性就实现了每次刷新后修改模型的一些属性,另一种方式是用tweenJs,这个使用起来简单,但是缺点要另外引入tweenjs才可以使用,还有一种是threejs自带的动画实现效果,叫关键帧动画,这节补上。

了解关键帧动画之前要了解其中几个重要的概念。

KeyframeTrack 关键帧轨道:

关键帧轨道用来制作一组动画,用来在这组动画中动态修改模型某一个属性的值,最终形成动画,比如可以修改模型的位置,修改模型的材质颜色等,KeyframeTack的入参如下

KeyframeTrack( name : String, times : Array, values : Array, interpolation : Constant )

name - 关键帧轨道(KeyframeTrack)的标识符
times - 关键帧的时间数组, 被内部转化为 Float32Array
values - 与时间数组中的时间点相关的值组成的数组, 被内部转化为 Float32Array
interpolation - 使用的插值类型
同时,threejs提供多种KeyFrameTrack的子类,来展示各种不用的属性值改变,包括:
VectorKeyframeTrack:向量类型的关键帧轨道,ColorKeyframeTrack:反应颜色变化的关键帧轨道
,BooleanKeyframeTrack:布尔类型的关键帧轨道,NumberKeyframeTrack:数字类型的关键帧轨道,QuaternionKeyframeTrack:四元数类型的关键帧轨道,StringKeyframeTrack:字符串类型的关键帧轨道。

AnimationClip 动画剪辑

动画剪辑(AnimationClip)是一个可重用的关键帧轨道集,它用来定义动画,它的入参如下

AnimationClip( name : String, duration : Number, tracks : Array )
name - 此剪辑的名称
duration - 持续时间 (单位秒). 如果传入负数, 持续时间将会从传入的数组中计算得到。
tracks - 一个由关键帧轨道(KeyframeTracks)组成的数组。AnimationClip里面,每个动画属性的数据都存储在一个单独的KeyframeTrack中。

Animation Mixer 动画混合器

动画混合器是用于场景中特定对象的动画的播放器。当场景中的多个对象独立动画时,每个对象都可以使用同一个动画混合器,它的入参如下:AnimationMixer( rootObject : Object3D )
rootObject - 混合器播放的动画所属的对象。

AnimationAction 动画动作

AnimationActions 用来调控制存储在AnimationClips中的动画。通过配置AnimationAction,我们可以决定何时播放、暂停或停止其中一个混合器中的某个AnimationClip, 这个AnimationClip是否需要重复播放以及重复的频率, 是否需要使用淡入淡出或时间缩放,以及一些其他内容。它的入参如下:AnimationAction( mixer : AnimationMixer, clip : AnimationClip, localRoot : Object3D )

mixer - 被此动作控制的 动画混合器
clip - 动画剪辑 保存了此动作当中的动画数据
localRoot - 动作执行的根对象

下面放完整代码,可以直接复制到html中运行,不过记得添加上两个js文件

<!DOCTYPE html>
<html>

<head includeDefault="true">
  <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
  <title>位置移动</title>
  <script src="./ThreeJs/js/three.js"></script>
  <script src="./ThreeJs/js/OrbitControls.js"></script>
</head>

<body>
  <div class="text"></div>
  <div id="container"></div>
  <script>
    var camera, scene, renderer, controls;
    var mixer;
    init();

      // 初始化场景
      function initScene() {
        scene = new THREE.Scene();
        scene.background = new THREE.Color( 0xf0f0f0 );
        scene.fog = new THREE.Fog(scene.background, 3000, 5000);
      }

      // 初始化相机
      function initCamera() {
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);
        camera.position.set(150, 150, 150);
        camera.lookAt(new THREE.Vector3(0, 0, 0));
      }

      // 初始化灯光
      function initLight() {
        var directionalLight = new THREE.DirectionalLight(0xffffff, 0.3); //模拟远处类似太阳的光源
        directionalLight.color.setHSL(0.1, 1, 0.95);
        directionalLight.position.set(0, 200, 0).normalize();
        scene.add(directionalLight);

        var ambient = new THREE.AmbientLight(0xffffff, 1); //AmbientLight,影响整个场景的光源
        ambient.position.set(0, 0, 0);
        scene.add(ambient);
      }
      //创建模型以及实现动画效果
      function initCube(){
        clock = new THREE.Clock();
        cubeGeo = new THREE.BoxBufferGeometry( 50, 50, 50 );
        cubeMaterial = new THREE.MeshLambertMaterial( { color: 0xfeb74c, map: new THREE.TextureLoader().load( './ThreeJs/images/box.png' ) } );
        var mesh = new THREE.Mesh( cubeGeo, cubeMaterial );;
        scene.add( mesh );
        mesh.name = "Box";

        //创建时间轴,并配置第一个动画效果,改变模型位置
        const times = [0, 3, 6]; //时间轴上,设置三个时刻0、3、6秒
        const values = [0, 0, 0, 100, 0, 0, 0, 100, 100];// times中三个不同时间点,物体分别对应values中的三个xyz坐标
        const posKF = new THREE.KeyframeTrack('Box.position', times, values);// 0~3秒,物体从(0,0,0)逐渐移动到(100,0,0),3~6秒逐渐从(100,0,0)移动到(0,0,100)

        //创建第二个动画效果,改变模型角度
        const xAxis = new THREE.Vector3(1,0,0) //三维向量,沿x轴
        const qInitial = new THREE.Quaternion().setFromAxisAngle(xAxis,0)//起点角度
        const qFinal = new THREE.Quaternion().setFromAxisAngle(xAxis,Math.PI)//终点角度
        const rotateValues = [ qInitial.x,qInitial.y,qInitial.z,qInitial.w, qFinal.x,qFinal.y,qFinal.z,qFinal.w,qInitial.x,qInitial.y,qInitial.z,qInitial.w];//设置三个关键帧的角度,
        const rotateKF = new THREE.QuaternionKeyframeTrack('Box.quaternion', times, rotateValues);

        //创建第三个动画效果,设置模型颜色
        const colorValues = [1, 0, 0, 0, 0, 1, 0, 1, 1];// times中三个不同时间点,分别设置三种不同的颜色
        const colorKF = new THREE.KeyframeTrack('Box.material.color', times, colorValues);// 0~3秒,颜色从[1,0,0]到[0,0,1]最后到[0,1,1]

        //将三个动画效果添加到AnimationClip中,名字,持续时间(与时间轴对应),动画组
        const clip = new THREE.AnimationClip("test", 6, [posKF, rotateKF, colorKF]);

        //创建动画混合器
        mixer = new THREE.AnimationMixer(mesh);
        // 剪辑clip作为参数,通过混合器clipAction方法返回一个操作对象AnimationAction
        var AnimationAction = mixer.clipAction(clip);
        //通过操作Action设置播放方式
        AnimationAction.timeScale = 1;//默认1,可以调节播放速度
        // AnimationAction.loop = THREE.LoopOnce; //不循环播放
        AnimationAction.play();//开始播放
      }

      // 初始化渲染器
      function initRenderer() {
        renderer = new THREE.WebGLRenderer({
          antialias: true
        });
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setClearColor(0x4682B4, 1.0);
        document.body.appendChild(renderer.domElement);
      }

      // 初始化轨迹球控件
      function initControls() {
        controls = new THREE.OrbitControls(camera, renderer.domElement);
        controls.enableDamping = true;
        controls.dampingFactor = 0.5;
        // 视角最小距离
        controls.minDistance = 100;
        // 视角最远距离
        controls.maxDistance = 5000;
        // 最大角度
        controls.maxPolarAngle = Math.PI / 2.2;
      }

    //加载初始化
    function init() {
        initScene();
        initCamera();
        initLight();
        initCube();
        initRenderer();
        initControls();
        render();
    }

    function onWindowResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize( window.innerWidth, window.innerHeight );
    }

    function render() {
        renderer.render(scene, camera); //执行渲染操作
        mixer.update(0.0166666666);//这里给动画设置更新速度,因为默认是一秒钟渲染60次,所以这里设置为1/60的值,
        requestAnimationFrame(render); //请求再次执行渲染函数render,渲染下一帧    
     }
    // 更新控件
    function update() {
        controls.update();
    }

  </script>
</body>

</html>

实现效果图:

这里暂不支持视频,关键帧动画视频请见https://blog.csdn.net/qq_26881073/article/details/135284820

相关文章
|
24天前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
16天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。
|
20天前
|
机器学习/深度学习 算法 大数据
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
2024“华为杯”数学建模竞赛,对ABCDEF每个题进行详细的分析,涵盖风电场功率优化、WLAN网络吞吐量、磁性元件损耗建模、地理环境问题、高速公路应急车道启用和X射线脉冲星建模等多领域问题,解析了问题类型、专业和技能的需要。
2577 22
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
|
18天前
|
人工智能 IDE 程序员
期盼已久!通义灵码 AI 程序员开启邀测,全流程开发仅用几分钟
在云栖大会上,阿里云云原生应用平台负责人丁宇宣布,「通义灵码」完成全面升级,并正式发布 AI 程序员。
|
3天前
|
JSON 自然语言处理 数据管理
阿里云百炼产品月刊【2024年9月】
阿里云百炼产品月刊【2024年9月】,涵盖本月产品和功能发布、活动,应用实践等内容,帮助您快速了解阿里云百炼产品的最新动态。
阿里云百炼产品月刊【2024年9月】
|
2天前
|
存储 人工智能 搜索推荐
数据治理,是时候打破刻板印象了
瓴羊智能数据建设与治理产品Datapin全面升级,可演进扩展的数据架构体系为企业数据治理预留发展空间,推出敏捷版用以解决企业数据量不大但需构建数据的场景问题,基于大模型打造的DataAgent更是为企业用好数据资产提供了便利。
163 2
|
20天前
|
机器学习/深度学习 算法 数据可视化
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
2024年中国研究生数学建模竞赛C题聚焦磁性元件磁芯损耗建模。题目背景介绍了电能变换技术的发展与应用,强调磁性元件在功率变换器中的重要性。磁芯损耗受多种因素影响,现有模型难以精确预测。题目要求通过数据分析建立高精度磁芯损耗模型。具体任务包括励磁波形分类、修正斯坦麦茨方程、分析影响因素、构建预测模型及优化设计条件。涉及数据预处理、特征提取、机器学习及优化算法等技术。适合电气、材料、计算机等多个专业学生参与。
1576 16
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
|
22天前
|
编解码 JSON 自然语言处理
通义千问重磅开源Qwen2.5,性能超越Llama
击败Meta,阿里Qwen2.5再登全球开源大模型王座
973 14
|
3天前
|
Linux 虚拟化 开发者
一键将CentOs的yum源更换为国内阿里yum源
一键将CentOs的yum源更换为国内阿里yum源
219 2
|
17天前
|
人工智能 开发框架 Java
重磅发布!AI 驱动的 Java 开发框架:Spring AI Alibaba
随着生成式 AI 的快速发展,基于 AI 开发框架构建 AI 应用的诉求迅速增长,涌现出了包括 LangChain、LlamaIndex 等开发框架,但大部分框架只提供了 Python 语言的实现。但这些开发框架对于国内习惯了 Spring 开发范式的 Java 开发者而言,并非十分友好和丝滑。因此,我们基于 Spring AI 发布并快速演进 Spring AI Alibaba,通过提供一种方便的 API 抽象,帮助 Java 开发者简化 AI 应用的开发。同时,提供了完整的开源配套,包括可观测、网关、消息队列、配置中心等。
734 9