Three.js实现简单开门动画

5 篇文章 2 订阅
订阅专栏

Three.js实现简单开门动画

先来看一下简单的开门动画实现效果,如下图所示:

可以看得出这个开门动画还是比较简单的,主要关键点有2个地方:

  1. 实现门围绕右门框旋转。
  2. 利用关键帧实现动画。

1.实现门围绕右门框旋转

Three.js中物体的默认旋转中心为物体自身的中心,例如有一扇门(实际上是一个宽为10,高为20,深度为0.5的立方体),如果让它绕Y轴旋转90度,也就是设置rotation.y属性为Math.PI/2,结果如下图所示:

很显然,大多数门不应该这样旋转。那么我们应该怎么做才能让门绕着指定轴旋转呢?这时候我们可以在这个对象外面包一层Object3D对象,让外层物体的旋转中心位置在原本想要旋转的指定位置上,再调整门在外层物体中的相对位置,使门的右边缘在外层物体的中心位置上。

// 创建门
const door = new THREE.BoxBufferGeometry(10, 20, 0.5);
const doorMaterial = new THREE.MeshLambertMaterial({ color: 0xd88c00 });
const doorMesh = new THREE.Mesh(door, doorMaterial);
// 实现门围绕特定轴旋转
const group = new THREE.Group(); // 外层对象
group.position.set(5, 10, 0); // 设置外层对象的中心为原本想要旋转的位置
group.add(doorMesh); // 把'门'添加进外层对象中
doorMesh.position.set(-5, 0, 0); // 调整门在外层对象中的相对位置

Group对象和Object3D对象几乎是相同的,其目的是使得组中对象在语法上的结构更加清晰。

2.利用关键帧实现动画

先给用于关键帧动画的网格模型命名。

group.name = 'door'; // 外层网格模型命名为door

动画将作用于外层对象group上,因为group包含doorMesh对象,所以group旋转时doorMesh也会旋转。

接着需要编辑关键帧,需要用到关键帧轨道 (KeyframeTrack) API。

const times = [0, 3]; // 关键帧时间数组,单位'秒'
const rotationValues = [0, -Math.PI / 2]; // 需要转动的角度
 // 创建关键帧轨道
const rotationTrack = new THREE.KeyframeTrack(
    'door.rotation[y]', // 指定对象中的变形目标为Y轴旋转属性
    times, // 关键帧的时间数组
    rotationValues // 与时间数组中的时间点相关的值组成的数组
);

然后使用 AnimationClip API剪辑动画。

const duration = 3; // 持续时间,单位'秒'
// 动画剪辑
const clip = new THREE.AnimationClip(
    'open', // 此剪辑的名称
    duration, // 如果传入负数,持续时间将会从传入的数组中计算得到
    [rotationTrack] // 一个由关键帧轨道(KeyframeTracks)组成的数组。
);

duration参数决定了动画的播放时间,偏小则编辑的帧动画将不能完全播放,偏大则帧动画播放完后会继续空播放,所以一般设置为关键帧时间数组的最大值。
第三个参数为数组,可以剪辑多个关键帧轨道,意思是可以同时进行多个不同的动画,比如在物体旋转的同时可以改变材质的颜色或者改变几何体的大小等。

最后就是播放编辑好的关键帧数据,需要用到动画混合器 AnimationMixer API。

const mixer = new THREE.AnimationMixer(group); // 动画混合器
const AnimationAction = mixer.clipAction(clip); // 返回所传入的剪辑参数的AnimationAction
AnimationAction.timeScale = 1; // 可以调节播放速度,默认是1。为0时动画暂停。值为负数时动画会反向执行。
AnimationAction.play(); // 开始播放

AnimationMixer需要传入的参数为混合器播放的动画所属的对象,在这里也就是外层对象group
clipAction方法返回所传入的剪辑参数的 AnimationAction,第一个参数可以是动画剪辑(AnimationClip)对象或者动画剪辑的名称,所以这里也可以传入剪辑的名称“open”。

设置完以上所有内容后,你会发现动画还是没有变化,那是因为还有一个很重要的步骤没有做。我们需要在渲染函数中render()调用动画混合器mixerupdate方法,update方法需要传入两帧渲染的间隔时间,需要用到 Clock对象的 getDelta方法。

const clock = new THREE.Clock(); // 创建时钟

在render方法中添加:

mixer.update(clock.getDelta()); // 更新动画

现在我们的动画就已经动了起来。


以下是完整代码:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Three.js实现简单开门动画</title>
    <style>
      * {
        margin: 0;
        padding: 0;
        overflow: hidden;
      }
    </style>
  </head>
  <body>
    <script type="module">
      import * as THREE from 'https://threejs.org/build/three.module.js';
      import Stats from 'https://threejs.org/examples/jsm/libs/stats.module.js';
      import { OrbitControls } from 'https://threejs.org/examples/jsm/controls/OrbitControls.js';

      const stats = new Stats(); // 性能监控器,用来查看Three.js渲染帧率

      // 创建div
      const container = document.createElement('div');
      document.body.appendChild(container);

      // 创建场景
      const scene = new THREE.Scene();

      // 创建时钟
      const clock = new THREE.Clock();

      // 创建相机
      const camera = new THREE.PerspectiveCamera( // 透视投影相机
        40, // 视场,表示能够看到的角度范围
        window.innerWidth / window.innerHeight, // 渲染窗口的长宽比,设置为浏览器窗口的长宽比
        0.1, // 从距离相机多远的位置开始渲染
        2000 // 距离相机多远的位置截止渲染
      );
      camera.position.set(-20, 60, 30); // 设置相机位置

      // 创建渲染器
      const renderer = new THREE.WebGLRenderer({
        antialias: true, // 是否执行抗锯齿
      });
      renderer.setPixelRatio(window.devicePixelRatio); // 设置设备像素比率。通常用于HiDPI设备,以防止输出画布模糊。
      renderer.setSize(window.innerWidth, window.innerHeight); // 设置渲染器大小
      renderer.shadowMap.enabled = true;
      container.appendChild(renderer.domElement);

      // 创建控制器
      const controls = new OrbitControls(camera, renderer.domElement);

      // 创建平面
      const planeGeometry = new THREE.PlaneGeometry(300, 300); // 生成平面几何
      const planeMaterial = new THREE.MeshLambertMaterial({
        // 生成材质
        color: 0xcccccc,
      });
      const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial); // 生成平面网格
      planeMesh.rotation.x = -Math.PI / 2; //绕X轴旋转90度
      scene.add(planeMesh); // 添加到场景中

      // 创建平行光源
      const light = new THREE.DirectionalLight(0xffffff, 1); // 平行光,颜色为白色,强度为1
      light.position.set(-40, 40, 20); // 设置灯源位置
      scene.add(light); // 添加到场景中

      // 创建门框
      const doorFrameSide = new THREE.BoxBufferGeometry(1, 20, 2); // 侧边门框
      const doorFrameTop = new THREE.BoxBufferGeometry(12, 1, 2); // 上门框
      const doorFrameMaterial = new THREE.MeshLambertMaterial({
        color: 0xad4800,
      });
      const doorFrameLeftMesh = new THREE.Mesh(
        doorFrameSide,
        doorFrameMaterial
      );
      const doorFrameTopMesh = new THREE.Mesh(doorFrameTop, doorFrameMaterial);
      const doorFrameRightMesh = doorFrameLeftMesh.clone();
      doorFrameLeftMesh.position.set(-5.5, 10, 0);
      doorFrameRightMesh.position.set(5.5, 10, 0);
      doorFrameTopMesh.position.set(0, 20.5, 0);
      scene.add(doorFrameLeftMesh);
      scene.add(doorFrameRightMesh);
      scene.add(doorFrameTopMesh);

      // 创建门
      const door = new THREE.BoxBufferGeometry(10, 20, 0.5);
      const doorMaterial = new THREE.MeshLambertMaterial({ color: 0xd88c00 });
      const doorMesh = new THREE.Mesh(door, doorMaterial);

      // 实现门围绕特定轴旋转
      const group = new THREE.Group();
      group.position.set(5, 10, 0); // 设置外层对象的中心为原本想要旋转的位置
      group.add(doorMesh);
      group.name = 'door';
      doorMesh.position.set(-5, 0, 0);
      scene.add(group);

      const times = [0, 3]; // 关键帧时间数组
      const rotationValues = [0, -Math.PI / 2];
      const rotationTrack = new THREE.KeyframeTrack(
        'door.rotation[y]',
        times,
        rotationValues
      ); // 关键帧轨道
      const duration = 3; // 持续时间 (单位秒)
      const clip = new THREE.AnimationClip('open', duration, [rotationTrack]); // 动画剪辑

      // 播放编辑好的关键帧数据
      const mixer = new THREE.AnimationMixer(group); // 动画混合器
      const AnimationAction = mixer.clipAction(clip); // 返回所传入的剪辑参数的AnimationAction
      AnimationAction.timeScale = 1; // 可以调节播放速度,默认是1。为0时动画暂停。值为负数时动画会反向执行。
      AnimationAction.play(); // 开始播放

      render();

      function render() {
        requestAnimationFrame(render);
        stats.begin();
        renderer.render(scene, camera);
        mixer.update(clock.getDelta());
        stats.end();
      }
    </script>
  </body>
</html>

vue使用three.js实现盒子上下左右开关门的效果
菜鸟karroy
06-11 2653
效果图: 默认是关闭状态。从每个方向打开后需要关闭后才可以进行其他方向的打开操作。 具体实现的步骤: 1、新建文件 在src中创建views文件夹,在views中创建switch文件夹。在switch中创建components文件夹和index.vue文件,最后在components创建BoxSwitch.vue文件。 2、BoxSwitch.vue文件中 (1)、加载需要的js文件 impor...
使用threesixty.js 设置汽车外观360度旋转 外带两个开门关门的小动画 纯js实现
最新发布
06-12
threesixty.js是一个基于JavaScript的轻量级库,它使得创建交互式的360度产品视图变得简单。以下是关于这个主题的详细知识: 1. **threesixty.js介绍**: threesixty.js 是一个基于HTML5和JavaScript的库,专门...
threejs实现的汽车开关web
08-25
threejs实现的汽车开关门,具体有不懂的私信我,一起研究threejs,还有vr这方面的,也可以一起研究,
three.js 画的3D房间布局,可用Enter件控制开门,关门。
09-20
在支持webgl的浏览器上打开room.html,即可看到效果图。如果加载不出来,打开Chrome快捷方式的属性中设置:右击Chrome浏览器快捷方式, 选择“属性”,在“目标”中加上"--allow-file-access-from-files",注意前面有个空格,重启Chrome浏览器便可。three.js 画的3D房间布局,可用Enter件控制开门,关门。
Threejs实现开门关门动画
左本Web3D
05-09 2296
1,介绍 该示例使用的是 r95版本Three.js库。 主要实现功能:模拟开门关门动画。效果图如下: 2,动画主要说明 1,使用THREE.BoxGeometry创建几何体。 2,引用纹理THREE.TextureLoader进行材质创建THREE.MeshPhongMaterial 3,创建物体THREE.Mesh并引用几何体和材质 4,设置物体绕Y轴旋转实现动画,这里需要注意的是物体旋转是以自身中心进行旋转的,所以这里需要把几何体THREE.BoxGeometry平移自身宽度.
040318_three.js_开关门动画简单实现
chuigoujian9267的博客
04-03 606
<!DOCTYPE html> <html lang="en"> <head> <title>untitled</title> . .0 <meta name="viewport" content="width=de...
three.js简单例子 墙上挖门
06-02
项目要用到web3d 但是webgl学习起来太麻烦,先用three.js库写这点,初期做个记录。 关于框架的基本搭建和js引入,场景相机等的基本添加就不说明了,随便搜一下就一堆说明,重点说下如何在墙壁上挖一个门出来
threejs开关门动画
a7442358的专栏
06-17 1159
threejs开关门动画
vue和three.js版炫酷的登录页
11-23
总之,“vue版炫酷的登录页”利用Vue.js的强大功能处理页面逻辑和数据绑定,同时结合Three.js实现炫酷的3D动画效果,提升登录页的视觉吸引力和用户体验。通过熟练掌握这两个工具的结合使用,开发者可以创建出既实用...
JS点击开门效果
04-02
JS点击开门效果,通过JS点击按钮呈现模拟开门的效果,开门动画采用CSS动画效果。
ThreeJS中文文档
08-09
Three.js中文文档 包含demo
threejs 消防报警 报警精灵 动画
07-01
threejs 消防报警 报警精灵 动画 闪烁报警
html5+canvas开门效果
11-12
html5 canvas开门效果,修复了GOOGLE浏览器中运行不了的BUG,开门可以自己调节速度,和图片切开的位置。相应调节
Html5 Canvas 图片开门效果
11-24
Html5 Canvas drawImage 绘制的图片。实现开门效果。速度又慢变快。
Three.js盖房子 点击开关门
宏斌的博客
01-13 1223
建房子 for (let i = 0; i < 5; i++) { const w = Math.random() * 10 + 4; const h = House(w, w * 2); h.position.set(Math.random() * 100 - 50, 0, Math.random() * 100 - 50); h.rotateY(Math.random()); scene.add(h); } f.
Three开关门
weixin_42358094的博客
08-11 766
如何避免开关门自转中心轴不正确;我们以模型父级场景为中心轴旋转达到正常开关门示例
three.js做一个新闻联播开头动画(一)
05-04 786
整个活儿,用three.js做一个新闻联播开头动画。本文将详细讲述整个制作流程,内附在线演示地址及代码仓库。
js实现开门效果
huningning123的博客
08-29 3662
HTML  class="indexTop"> class=" divleft" id="left"> class=" divright" id="right"> type="button" value="点击登录" class="inputLogin"> Css .indexTop{ width: 60em; height: 40em;
Three.js 模型加载及加载简单动画
jinse29的博客
01-30 3526
简单介绍下Three.js吧,Three.js是基于原生WebGL封装运行的三维引擎,在所有WebGL引擎中,Three.js是国内文资料最多、使用最广泛的三维引擎。因为使用简单,入门比较容易。 Three.js的具体介绍和使用有很多教程,可以根据自己需要搜索。它重要的三个属性:场景(scene),相机(camera),渲染器(renderer),组合构成一个三维画面。
写文章

热门文章

  • 纯Git实现前端项目打包部署 7500
  • ArcGIS JS API实现地图场景视频融合 4392
  • 使用ArcGIS API和Three.js在三维场景中实现动态立体墙效果 3716
  • ArcGIS API在视图中渲染Three.js场景 3272
  • Three.js实现简单开门动画 3020

分类专栏

  • ArcGIS API for JavaScript 11篇
  • ArcGIS API 3篇
  • 前端 8篇
  • canvas 1篇
  • Three.js 5篇

最新评论

  • ArcGIS API在视图中渲染Three.js场景

    人间不值得君莫愁: 我也显示不出来表情包

  • ArcGIS JS API创建自定义图层实现在2D地图中渲染水波纹扩散效果

    茉傷寻: 大佬 你这个地图底色是如何来实现的呀

  • ArcGIS JS API实现水淹模拟功能

    伊利诺伊: 赞一个,很棒

  • 如何部署npm私有仓库以及在项目中如何使用

    CSDN-Ada助手: 推荐 Vue入门 技能树:https://edu.csdn.net/skill/vue?utm_source=AI_act_vue

  • ArcGIS API在视图中渲染Three.js场景

    Chokxtj: 表情包现在好像加了也不行表情包

最新文章

  • 如何部署npm私有仓库以及在项目中如何使用
  • ArcGIS JS API实现小车导航效果
  • 三维场景路径流线效果实现及如何发布npm包
2024年1篇
2023年3篇
2022年4篇
2021年5篇
2020年6篇

目录

目录

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

travelclover

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或 充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

天下网标王合肥放心的网站优化凤岗东莞网站推广优化报价企业网站seo优化服务兰州网站优化营商环境瓷砖网站优化规划深圳网站优化推广河北网站优化排名怎么选网络推广衡阳网站优化联系方式kfc网站优化seo网站优化如何插外链深圳电器网站优化如何十堰外包网站优化多少钱温州网站优化公司山东济宁seo优化网站济南家装行业网站优化推广渠道普陀区谷歌网站优化价格费用长春实力强的服装行业网站优化楚雄网站优化排名网站图片加载很慢怎么优化属于优化网站资产加载手段平顶山网站推广优化怎么选网站竞价优化服务湘潭网站排名优化公司杨浦网站优化选哪家焦作网站优化代理泰安网站整站优化安阳关键词网站优化哪家便宜隆子县网站seo优化排名云浮外贸网站关键词优化工具河南优惠网站优化公司地址香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声卫健委通报少年有偿捐血浆16次猝死汪小菲曝离婚始末何赛飞追着代拍打雅江山火三名扑火人员牺牲系谣言男子被猫抓伤后确诊“猫抓病”周杰伦一审败诉网易中国拥有亿元资产的家庭达13.3万户315晚会后胖东来又人满为患了高校汽车撞人致3死16伤 司机系学生张家界的山上“长”满了韩国人?张立群任西安交通大学校长手机成瘾是影响睡眠质量重要因素网友洛杉矶偶遇贾玲“重生之我在北大当嫡校长”单亲妈妈陷入热恋 14岁儿子报警倪萍分享减重40斤方法杨倩无缘巴黎奥运考生莫言也上北大硕士复试名单了许家印被限制高消费奥巴马现身唐宁街 黑色着装引猜测专访95后高颜值猪保姆男孩8年未见母亲被告知被遗忘七年后宇文玥被薅头发捞上岸郑州一火锅店爆改成麻辣烫店西双版纳热带植物园回应蜉蝣大爆发沉迷短剧的人就像掉进了杀猪盘当地回应沈阳致3死车祸车主疑毒驾开除党籍5年后 原水城县长再被查凯特王妃现身!外出购物视频曝光初中生遭15人围殴自卫刺伤3人判无罪事业单位女子向同事水杯投不明物质男子被流浪猫绊倒 投喂者赔24万外国人感慨凌晨的中国很安全路边卖淀粉肠阿姨主动出示声明书胖东来员工每周单休无小长假王树国卸任西安交大校长 师生送别小米汽车超级工厂正式揭幕黑马情侣提车了妈妈回应孩子在校撞护栏坠楼校方回应护栏损坏小学生课间坠楼房客欠租失踪 房东直发愁专家建议不必谈骨泥色变老人退休金被冒领16年 金额超20万西藏招商引资投资者子女可当地高考特朗普无法缴纳4.54亿美元罚金浙江一高校内汽车冲撞行人 多人受伤

天下网标王 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化