ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

three.js 引用外部模型,并使用其绑定的动画

2021-12-15 11:03:21  阅读:244  来源: 互联网

标签:Three name 绑定 three js let renderer new scene


<template>   <div id="container">     <!-- <img src="/models/yunlog.png" alt /> -->     <button @click="dispose('robot')">       模型切换     </button>   </div> </template> <script> import * as Three from "three"; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"; import { DoubleSide, GridHelper, Mesh, MeshBasicMaterial, PlaneBufferGeometry, AnimationMixer, Clock, Raycaster, Vector2 } from 'three';
export default {   data() {     return {       // 场景的宽高获取容器宽高       sceneHeight: null,       sceneWidth: null,
      // 场景, 灯光, 摄像机, 控制器, 渲染器       scene: "",       light: "",       camera: "",       controls: "",       renderer: "",             // 动画       animationMixer: null,       clock: null,       animationClipList: [],       animationActionList: {},
      // 可改变的变量       // 点击触发的动作       clickAction: 'Wave'     };   },
  mounted() {     this.init();     // this.drawPlane();     this.drweSkybox()     this.loadGltf();
    // 监测点击事件     this.clickRender()   },
  methods: {     //初始化three.js相关内容     init() {       const container = document.getElementById("container");       // console.log("三维盒子", container, container.offsetHeight, container.offsetWidth)
      // 创建场景对象       this.scene = new Three.Scene();       this.sceneHeight = container.offsetHeight       this.sceneWidth = container.offsetWidth
      // 创建灯光       this.scene.add(new Three.AmbientLight(0x999889)); //环境光       this.light = new Three.DirectionalLight(0xdfebff, 0.5); //从正上方(不是位置)照射过来的平行光,0.45的强度       this.light.position.set(1, 1, 0);       this.light.position.multiplyScalar(0.5);       this.scene.add(this.light);
      //初始化相机  (视野大小, 长宽比, 近景, 远景)       this.camera = new Three.PerspectiveCamera(70, this.sceneWidth / this.sceneHeight, 0.01, 100)       this.camera.position.set(0, 8, 8);  
      this.renderer = new Three.WebGLRenderer({         alpha: true,         antialias: true       });             //初始化控制器       this.controls = new OrbitControls(this.camera, this.renderer.domElement);       // this.controls.target.set(0, 0, 0);//------------------       // this.controls.minDistance = 3;       // this.controls.maxDistance = 100;       // this.controls.maxPolarAngle = Math.PI / 3;       this.controls.update();
      //渲染       this.renderer.setPixelRatio(window.devicePixelRatio); //为了兼容高清屏幕       this.renderer.setSize(this.sceneWidth, this.sceneHeight);       this.renderer.outputEncoding = Three.sRGBEncoding;
      container.appendChild(this.renderer.domElement);       window.addEventListener("resize", this.onWindowResize, false); //添加窗口监听事件(resize-onresize即窗口或框架被重新调整大小)     },     //窗口监听函数     onWindowResize() {       // 模型比例调整       this.camera.aspect = this.sceneWidth / this.sceneHeight;       this.camera.updateProjectionMatrix();
      this.renderer.setSize(this.sceneWidth, this.sceneHeight);     },
    // 绘制平面     drawPlane() {       const planeBufferGeometry = new PlaneBufferGeometry( 30, 30 );       const plane = new Mesh( planeBufferGeometry, new MeshBasicMaterial({ color: '#000', side: DoubleSide }) )       plane.name = 'plane'       // 平面绕x轴旋转90度(弧度制)       plane.rotation.x = -Math.PI / 2       this.scene.add( plane )
      // 添加网格       this.scene.add(new GridHelper(30, 30))     },
    // 绘制天空盒     drweSkybox() {       let skyBox = new Three.BoxGeometry(100, 100, 100)                                                                       // 创建立方体
      let textureLoader = new Three.TextureLoader       let right = require('../assets/skybox/right.jpg')       let left = require('../assets/skybox/left.jpg')       let top = require('../assets/skybox/top.jpg')       let bottom = require('../assets/skybox/bottom.jpg')       let back = require('../assets/skybox/back.jpg')       let front = require('../assets/skybox/front.jpg')
      let skyBoxMaterialList = [         new Three.MeshBasicMaterial({ map: textureLoader.load(right), side: DoubleSide }),         new Three.MeshBasicMaterial({ map: textureLoader.load(left), side: DoubleSide }),         new Three.MeshBasicMaterial({ map: textureLoader.load(top), side: DoubleSide }),         new Three.MeshBasicMaterial({ map: textureLoader.load(bottom), side: DoubleSide }),         new Three.MeshBasicMaterial({ map: textureLoader.load(front), side: DoubleSide }),         new Three.MeshBasicMaterial({ map: textureLoader.load(back), side: DoubleSide })       ]             let sky = new Three.Mesh(skyBox, skyBoxMaterialList)                                                                          // 创建网格       this.scene.add(sky)     },
    //外部模型加载函数     loadGltf() {       // 加载模型       var loader = new GLTFLoader()       loader.load("static/RobotExpressive.glb", (data) => {         // console.log(data)         let mesh = data.scene;         // mesh.position.set(0, 0, 0);         mesh.name = 'robot'         this.scene.add(mesh); // 将模型引入three
        this.animationClipList = data.animations         this.setAnimation()
        this.render();       });     },
    // 加载动画     setAnimation() {       this.animationMixer = new AnimationMixer(this.scene)       this.clock = new Clock()
      console.log("动画列表", this.animationClipList)     },
    render()  {       requestAnimationFrame(() => { this.render() });             // 调用动画       this.animationMixer.update(this.clock.getDelta())       this.renderer.render(this.scene, this.camera);     },
    // 监测点击事件     clickRender() {       this.renderer.domElement.addEventListener('click', event => {         // 获取屏幕坐标         let { offsetX, offsetY } = event         // 计算画布上的二维坐标         let x = ( offsetX / this.sceneWidth ) * 2 - 1         let y = - ( offsetY / this.sceneHeight ) * 2 + 1         let mousePoint = new Vector2( x, y )
        // 获取点击元素         let raycaster = new Raycaster()         // 按照this.camera摄像头下,mousePoint位置设置raycaster         raycaster.setFromCamera( mousePoint, this.camera )         // 获取点击的元素         let intersect = raycaster.intersectObjects(this.scene.children, true)         // 筛选去除点击的网格元素及平面元素         intersect = intersect.filter( intersect => !(intersect.object instanceof GridHelper) && intersect.object.name != "plane" )
        console.log("点击元素", intersect)         let hasClick = []         // 所有被点击的指定元素及其子元素组成数组,通过数组中有无数据判断是否点击         intersect.forEach((v) => {           let click = this.isClick(v.object, 'robot')           // console.log("比较结果", click)           if( this.isClick(v.object, 'robot') ){             hasClick.push(v)           }         })         // console.log("比较结果", hasClick)
        let action = this.getAnimationAction(this.clickAction)         // 判断元素被点击,并且该点击动作还未触发,触发动作,若已触发动作停止动作         // if( hasClick.length > 0 && action.isRunning () ){         //   action.stop()         // } else if( hasClick.length > 0 ) {         //   action.play()         // }                 action.play()         action.weight = 0         console.log("权重", action.getEffectiveWeight () )         if( hasClick.length > 0 && action.getEffectiveWeight () ){           action.fadeOut(1)         } else if( hasClick.length > 0 ) {           action.fadeIn(1)         }       })     },
    // 判断点击的元素是否是指定元素或其子元素     isClick(object, name) {       if( object.name == name ){         return true       }else if( object.parent ){         return this.isClick(object.parent, name)       }else {         return false       }     },
    // 动画调用方法,当动作已使用混合器生成AnimationAction直接返回储存的AnimationAction,若还未生成,生成一个AnimationAction返回,并储存下次使用     getAnimationAction(name) {       let animationActionList = this.animationActionList       // 检索animationActionList中是否已储存AnimationAction       for( let actionName in animationActionList ) {         if( actionName == name ){           return animationActionList[name]         }       }
      // 若还未储存AnimationAction       let animationClip = this.animationClipList.find(animationClip => animationClip.name == name )       animationActionList[name] = this.animationMixer.clipAction(animationClip)       return animationActionList[name]     },
    // 删除对象     dispose(name) {       // console.log('删除测试', this.scene)       let childrenList = this.scene.children       let group = childrenList.find(v => v.name == name)       group.visible = !group.visible     }   }   }; </script>
<style scoped> #container {   width: 600px;   margin: 0 auto;   height: 400px;   overflow: hidden; } </style>

标签:Three,name,绑定,three,js,let,renderer,new,scene
来源: https://www.cnblogs.com/yan122/p/15691682.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有