vue3结合three.js实现3D带有交互的动画

这篇具有很好参考价值的文章主要介绍了vue3结合three.js实现3D带有交互的动画。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

three.js引入
npm install three
安装轨道控件插件:
npm install three-orbit-controls
安装渲染器插件:
npm i --save three-css2drender
vue文件中引用:
import * as Three from 'three'
在页面中创建场景
//创建一个三维场景
const scene = new THREE.Scene();
创建一个透视相机
//创建一个透视相机,窗口宽度,窗口高度
const width = window.innerWidth,
  height = 400;
const camera = new THREE.PerspectiveCamera(38, width / height, 0.25, 100);
//设置相机位置
camera.position.set(-5, 3, 10);
//设置相机方向
camera.lookAt(new THREE.Vector3(0, 2, 0));
初始化渲染器
// 初始化渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setClearAlpha(0);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, height);
renderer.outputEncoding = THREE.sRGBEncoding;
container.appendChild(renderer.domElement);

window.addEventListener("resize", onWindowResize);
初始动画混合器
// 创建动画混个器
let mixer = new THREE.AnimationMixer(scene);
// 创建时钟对象 该对象用于跟踪时间
let clock = new THREE.Clock();

动画混合器是用于场景中特定对象的动画的播放器。当场景中的多个对象独立动画时,每个对象都可以使用同一个动画混合器。

参数:rootObject 混合器播放的动画所属的对象。就是包含动画模型的场景对象。
常用参数和属性:
.time 全局的混合器时间。
.clipAction(AnimationClip) 返回所传入的剪辑参数的AnimationAction对象。AnimationAction用来调度存储在AnimationClip中的动画。
AnimationClip 动画剪辑,是一个可重用的关键帧轨道集,它代表动画。
.getRoot() 返回混合器的根对象。
.update() 推进混合器时间并更新动画。在渲染函数中调用更新动画。文章来源地址https://www.toymoban.com/news/detail-767151.html

创建光源,用于视觉可见
const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444);
hemiLight.position.set(0, 20, 0);
 scene.add(hemiLight);

 const dirLight = new THREE.DirectionalLight(0xffffff);
 dirLight.position.set(0, 20, 10);
 scene.add(dirLight);
创建加载glb文件模型
const loader = new GLTFLoader();
loader.load(
   "RobotExpressive.glb",
   function (gltf) {
     // 存储模型含有动画集合
     model = gltf.scene;
     scene.add(model);
     createGUI(model, gltf.animations);
   },
   undefined,
   function (e) {
     console.error(e);
   }
 );

最后加上动画循环渲染

const animate = () => {
const dt = clock.getDelta();
	if (mixer) mixer.update(dt);
	 requestAnimationFrame(animate);
	 renderer.render(scene, camera);
	 stats.update();
};

完整代码

<template>
   <div id="my-three"></div>
</template>
<script>
import {
  defineComponent,
  getCurrentInstance,
  onMounted,
  onUnmounted,
  computed,
  reactive,
  toRefs,
} from "vue";

import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import Stats from "three/examples/jsm/libs/stats.module.js";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";

export default defineComponent({
  name: "index",
  setup() {
    const ctx = getCurrentInstance();
    let state = reactive({
      currentIndex:0,
    });
    //创建一个三维场景
    const scene = new THREE.Scene();
    //创建一个透视相机,窗口宽度,窗口高度
    const width = window.innerWidth,
      height = 400;
    const camera = new THREE.PerspectiveCamera(38, width / height, 0.25, 100);
    //设置相机位置
    camera.position.set(-5, 3, 10);
    //设置相机方向
    camera.lookAt(new THREE.Vector3(0, 2, 0));

    const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
    let mixer = new THREE.AnimationMixer(scene);
    let stats = new Stats();
    let clock = new THREE.Clock();
    let actions = {},
      activeAction,
      previousAction;
    // 默认动画
    const api = {state:'Walking'}
    //控制器
    // const Controls = new OrbitControls(camera, renderer.domElement);
    onMounted(() => {
      onLoad();
    });
    const onLoad = () => {
      let model, container;
      container = document.getElementById("my-three");

      // scene.background = new THREE.Color(0xe0e0e0);
      scene.fog = new THREE.Fog(0xe0e0e0, 20, 100);

      // lights

      const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444);
      hemiLight.position.set(0, 20, 0);
      scene.add(hemiLight);

      const dirLight = new THREE.DirectionalLight(0xffffff);
      dirLight.position.set(0, 20, 10);
      scene.add(dirLight);

      // model
      const loader = new GLTFLoader();
      loader.load(
        "RobotExpressive.glb",
        function (gltf) {
          // 存储模型含有动画集合
          model = gltf.scene;
          scene.add(model);
          createGUI(model, gltf.animations);
        },
        undefined,
        function (e) {
          console.error(e);
        }
      );

      renderer.setClearAlpha(0);
      renderer.setPixelRatio(window.devicePixelRatio);
      renderer.setSize(window.innerWidth, height);
      renderer.outputEncoding = THREE.sRGBEncoding;
      container.appendChild(renderer.domElement);

      window.addEventListener("resize", onWindowResize);
      container.appendChild(stats.dom);
      animate();

      // 点击动画
      renderer.domElement.addEventListener("click", (event) => {
        const { offsetX, offsetY } = event;
        const x = (offsetX / window.innerWidth) * 2 - 1;
        const y = -(offsetY / window.innerHeight) * 2 + 1;
        const mousePoint = new THREE.Vector2(x, y);

        const raycaster = new THREE.Raycaster();
        raycaster.setFromCamera(mousePoint, camera);
        const instersects = raycaster.intersectObjects(scene.children);

        instersects.forEach((item) => {
          console.log(item.object.name);
          if (
            item.object.name == "Head_2" ||
            item.object.name == "Head_3" ||
            item.object.name == "Head_4"
          ) {
            // console.log(instersects);
            // action.stop();
            const states = [
              "Idle",
              "Dance",
              "Death",
              "Sitting",
              "Standing",
              "Jump",
              "Yes",
              "No",
              "Wave",
              "Punch",
              "ThumbsUp",
            ];
            if(state.currentIndex<states.length - 1){
              state.currentIndex = state.currentIndex+1
            }else{
              state.currentIndex  = 0
            }
            fadeToAction(states[state.currentIndex], 0.2);
            mixer.addEventListener("finished", restoreState);
          }
        });
      });
    };
    const createGUI = (model, animations) => {
      const states = [
        "Idle",
        "Walking",
        "Running",
        "Dance",
        "Death",
        "Sitting",
        "Standing",
      ];
      const emotes = ["Jump", "Yes", "No", "Wave", "Punch", "ThumbsUp"];
      for (let i = 0; i < animations.length; i++) {
        const clip = animations[i];
        const action = mixer.clipAction(clip);
        actions[clip.name] = action;
        if (emotes.indexOf(clip.name) >= 0 || states.indexOf(clip.name) >= 4) {
          action.clampWhenFinished = true;
          action.loop = THREE.LoopOnce;
        }
      }
      activeAction = actions["Walking"];
      activeAction.play();
    };
    const fadeToAction = (name, duration) => {
      previousAction = activeAction;
      activeAction = actions[name];

      if (previousAction !== activeAction) {
        previousAction.fadeOut(duration);
      }

      activeAction
        .reset()
        .setEffectiveTimeScale(1)
        .setEffectiveWeight(1)
        .fadeIn(duration)
        .play();
    };
    const restoreState = () => {
      mixer.removeEventListener("finished", restoreState);

      fadeToAction(api.state, 0.2);
    };

    const animate = () => {
      const dt = clock.getDelta();

      if (mixer) mixer.update(dt);

      requestAnimationFrame(animate);

      renderer.render(scene, camera);

      stats.update();
    };
    const onWindowResize = () => {
      camera.aspect = window.innerWidth / height;
      camera.updateProjectionMatrix();

      renderer.setSize(window.innerWidth, height);
    };
    onUnmounted(() => {
      scene.traverse((e) => {
        if (e.BufferGeometry) e.BufferGeometry.dispose();
        if (e.material) {
          if (Array.isArray(e.material)) {
            e.material.forEach((m) => {
              m.dispose();
            });
          } else {
            e.material.dispose();
          }
        }
        if (e.isMesh) {
          e.remove();
        }
      });
      scene.remove();
      renderer.dispose();
      renderer.content = null;
      window.removeEventListener("resize", onWindowResize, false);
    });

    return {
      ...toRefs(state),
      onLoad,
      createGUI,
    };
  },
});
</script>
<style lang="less">
@import "./index.less";
</style>

到了这里,关于vue3结合three.js实现3D带有交互的动画的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • vue2+three.js实现类似VR、3D全景效果

    vue2+three.js实现类似VR、3D全景效果

    效果图: 俩图标是我自己加的前进后退按钮,也是百度了好久,再加上GPT的帮助,才给搞出来。因为需求急,都不看官方文档,百度到一个能跑的demo之后改吧改吧,就先用着了。 下面是代码: 这里 代码有很多用不到的地方和需要优化的地方,我是来不及改了,就先这样吧

    2024年02月15日
    浏览(33)
  • vue2+three.js+blender(实现3d 模型引入并可点击效果)

    vue2+three.js+blender(实现3d 模型引入并可点击效果)

    2023.9.13今天我学习了如何把3d建模里面的模型引入到vue中,并可以实现拖动,点击的效果: 首先安装: npm install three 相关代码如下:  如果没有图片可以去 Three.js--》建模软件如何加载外部3D模型?_threejs加载3d模型_亦世凡华、的博客-CSDN博客

    2024年02月03日
    浏览(41)
  • VUE使用Three.js实现模型,点击交互,相机旋转视角跟随移动(Threejs中使用Tweenjs,含demo源码)

    VUE使用Three.js实现模型,点击交互,相机旋转视角跟随移动(Threejs中使用Tweenjs,含demo源码)

    目录 一、Three.js是什么? 二、VUE简单使用Three.js步骤 1.npm安装 2.template模板 3.引入库 4.定义全局变量 5.初始化场景 6.初始化相机 7.初始化灯光 8.初始化渲染器 9.创建模型(这里我搭建的模型是一个简单双面货架模型) 10.根据浏览器窗口自适应 11.初始化函数,页面加载完成时调用

    2024年02月03日
    浏览(42)
  • 【案例】3D地球(vue+three.js)

    【案例】3D地球(vue+three.js)

    需要下载插件 有人找不到合适的地球平面图的话,可直接地球平面图

    2024年02月06日
    浏览(9)
  • vue3项目中使用three.js

    vue3项目中使用three.js

    在vue3项目中,通过three.js使用了一段短小但完整的代码实现了实际的三维效果图。 Three.js是一个轻量级,跨平台的Javascript库,可以在浏览器上结合HTML5的canvas,SVG或者WebGL,创建和展示3D模型和动画。 Three.js允许我们在不依赖任何浏览器插件的情况下,创建一个GPU加速的3D动画场

    2024年01月23日
    浏览(13)
  • TransformControls 是 Three.js 中的一个类,用于在网页中进行 3D 场景中物体的交互式操作。

    TransformControls 是 Three.js 中的一个类,用于在网页中进行 3D 场景中物体的交互式操作。

    demo案例 TransformControls 是 Three.js 中的一个类,用于在网页中进行 3D 场景中物体的交互式操作。让我们来详细讲解它的输入参数、输出、属性和方法: 输入参数: TransformControls 构造函数通常接受两个参数: camera (THREE.Camera):用于渲染场景的摄像机。这个参数是必需的。

    2024年04月15日
    浏览(41)
  • Vue+Three.js建造3D小房子

    Vue+Three.js建造3D小房子

    前言 一、Three.js简介 二、开发步骤 1.安装Three.js 2.创建容器 3.创建模型 总结 3D模型给人一种更真实的感受,带来极致的视觉体验。本文介绍Vue结合Three.js开发3D小房子,接触过OpenGL的小伙伴看起来会更轻松一点。 Three.js,一个WebGL引擎,基于JavaScript,可直接运行GPU驱动游戏与

    2024年02月07日
    浏览(11)
  • Three.js--》实现3d字体模型展示

    Three.js--》实现3d字体模型展示

    目录 项目搭建 初始化three.js基础代码 设置环境纹理 加载字体模型 今天简单实现一个three.js的小Demo,加强自己对three知识的掌握与学习,只有在项目中才能灵活将所学知识运用起来,话不多说直接开始。 项目搭建 本案例还是借助框架书写three项目,借用vite构建工具搭建vue项

    2024年02月07日
    浏览(42)
  • Three.js--》实现3d踢球模型展示

    Three.js--》实现3d踢球模型展示

    目录 项目搭建 初始化three.js基础代码 设置环境纹理加载模型 使用Cannon-es实现物理世界 今天简单实现一个three.js的小Demo,加强自己对three知识的掌握与学习,只有在项目中才能灵活将所学知识运用起来,话不多说直接开始。 项目搭建 本案例还是借助框架书写three项目,借用

    2024年02月11日
    浏览(35)
  • Three.js--》实现3d地球模型展示

    Three.js--》实现3d地球模型展示

    目录 项目搭建 实现网页简单布局 初始化three.js基础代码 创建环境背景 加载地球模型 实现光柱效果 添加月球模型 今天简单实现一个three.js的小Demo,加强自己对three知识的掌握与学习,只有在项目中才能灵活将所学知识运用起来,话不多说直接开始。 项目搭建 本案例还是借

    2024年02月08日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包