three vue3 ts 练手 人物动画 骨骼动画

<template><div><div class="main" ref="box"></div></div>
</template>

安装three插件 需要装ts版本

npm i -s -d @types/three

安装dat.gui调试插件

 npm i --save-dev @types/dat.gui

将里面的文件地址 换成你的文件地址
并且保存在 public下
文件可以在https://www.mixamo.com/#/下载

<script lang="ts">
import {WebGLRenderer, //渲染器Scene, //场景AxesHelper, //坐标轴PerspectiveCamera, //相机Plane, //平面PlaneHelper, //平面辅助Vector3, //3维向量DirectionalLight, //平行光 太阳光DirectionalLightHelper, //平行光辅助Color, //颜色 three格式化PlaneGeometry, //矩形MeshStandardMaterial, //材质MeshPhongMaterial, //材质DoubleSide, //渲染两个面FrontSide, //只渲染正面BackSide, //只渲染背面Mesh, //组合AnimationMixer, //动画的播放器Clock, //时间插件SkeletonHelper, //骨骼辅助
} from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"; //镜头控制
import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader"; //加载文件loader
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; //加载文件loaderimport { defineComponent, ref, onMounted, reactive } from "vue";
import * as dat from "dat.gui"; //调试插件
import Stats from "three/examples/jsm/libs/stats.module.js"; //性能监控插件
export default defineComponent({setup() {//提前创建好调试插件const gioData = new dat.GUI(); //测试插件const floorFaces: dat.GUI = gioData.addFolder("地板配置"); //测试插件新增组const Folder: dat.GUI = gioData.addFolder("平行光控制"); // //测试插件组const box = ref<HTMLElement | null>(null); //ref获取domconst scence: Scene = new Scene(); //场景const camera = new PerspectiveCamera( //新建相机45, //摄像机视锥体垂直视野角度window.innerWidth / window.innerHeight, //摄像机视锥体长宽比0.1, //摄像机视锥体近端面10000 //摄像机视锥体远端面);const clock = new Clock(); //时钟 动画用const stats = Stats(); //性能监控var rander: WebGLRenderer; //渲染器var xAxis: Object3D<Event> | AxesHelper; //坐标轴var directionalLight: DirectionalLight; //平行光var lightHelper: DirectionalLightHelper; //平行光辅助var mesh: AnimationMixer; //人物var plan: Mesh; //地板//定义接口 gui用interface guiType {[e: string]: any;sunColor: "#ffffff";floorFaces: "正面";routerFaces: 0;randerColor: "#eeeeee";}//定义接口 动作数组用interface actionsType {[e: string]: { action: any; play: boolean };}//定义插件控制的值const gui: guiType = reactive({sunColor: "#ffffff",floorFaces: "正面",routerFaces: 0,randerColor: "#eeeeee",action: "停止",speed: 0.5,xAxis: true,lightHelper: false,planeHelper: false,skeletonHelper: true,});// 渲染器方法function randerFun() {rander = new WebGLRenderer({ antialias: true }); //新建渲染器 antialias 否执行抗锯齿rander.setClearColor(new Color(gui.randerColor), 1); //更改渲染器颜色为默认rander.shadowMap.enabled = true; //开启阴影贴图 没用上//场景颜色gioData //测试插件.addColor(gui, "randerColor") //添加监听 gui里的randerColor.name("场景颜色") //名字为场景颜色.onChange((e) => {//更改以后的回调rander.setClearColor(new Color(e), 1); //更改场景颜色});}randerFun();//新建场景function scenceFun() {scence.name = "场景"; //场景名字camera.name = "相机"; //相机名字camera.position.set(-10, 40, 100); //相机位置new OrbitControls(camera, rander.domElement); //相机控制插件 实现拖拽渲染}scenceFun();//坐标轴     红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.function xAxisFun() {xAxis = new AxesHelper(29); //长度29的坐标轴xAxis.name = "坐标轴"; //坐标轴名字scence.add(xAxis); //添加实例gioData.add(gui, "xAxis") //添加监听.name("显示坐标轴") //名字.onChange((e) => {//更改后的回调xAxis.visible = e; //隐藏或显示});}xAxisFun();//平行光function directionalLightFun() {directionalLight = new DirectionalLight(new Color(gui.sunColor)); //添加一个平行光 初始化颜色directionalLight.name = "太阳光"; //名字directionalLight.position.set(-10, 20, 20); //更改位置directionalLight.castShadow = true; //开启阴影directionalLight.shadow.camera.near = 0; //产生阴影的最近距离directionalLight.shadow.camera.far = 200; //产生阴影的最远距离directionalLight.shadow.camera.left = -50; //产生阴影距离位置的最左边位置directionalLight.shadow.camera.right = 50; //最右边directionalLight.shadow.camera.top = 50; //最上边directionalLight.shadow.camera.bottom = -50; //最下面scence.add(directionalLight); //添加实例Folder.addColor(gui, "sunColor") //添加方法 数据controls 根据传入数据不同渲染不同.name("颜色") //更改名字.onChange((e) => {directionalLight.color = new Color(e);}); //操作后的回调 更改颜色}directionalLightFun();//平行光辅助function lightHelperFun() {lightHelper = new DirectionalLightHelper(directionalLight, 10); //添加辅助线 辅助实例directionalLight 大小lightHelper.name = "平行光辅助"; //名字lightHelper.visible = gui.lightHelper; //是否显示scence.add(lightHelper); //添加实例Folder.add(gui, "lightHelper") //添加监听 在folder组内.name("平行光辅助") //名字.onChange((e) => {lightHelper.visible = e; //显示/隐藏});}lightHelperFun();//平面 这个玩意是用来计算交点的 所以... 未使用const plane = new Plane();plane.normal = new Vector3(0, 1, 0);plane.constant = 0; //距离中心点的位置//平面辅助const planeHelper = new PlaneHelper(plane, 555);planeHelper.name = "平面辅助";planeHelper.visible = false;scence.add(planeHelper);//地板 正方形function planFun() {// 地板// var planSty: any;// var planeGeometry: any;const planSty: any = new PlaneGeometry(100, 100, 10, 1); //添加矩形// 更改材质const planeGeometry = new MeshPhongMaterial({color: 0xcccccc,side: BackSide, //单双面fog: true, //是否受雾影响});// 合称plan = new Mesh(planSty, planeGeometry);plan.name = "地板"; //名字plan.rotation.x = Math.PI / 2; //旋转// plan.position.y = 0.1;plan.receiveShadow = true; //阴影floorFaces.add(gui, "floorFaces", ["正面", "背面", "两面"]).name("显示哪个面").onChange((e) => {if (e == "正面") {planSty.side = FrontSide; //正面渲染} else if (e == "背面") {planSty.side = BackSide; //背面渲染} else if (e == "两面") {planSty.side = DoubleSide; //两面渲染}});floorFaces.add(gui, "routerFaces", -1, 1) //添加监听 最小值 最大值 拖动.name("旋转角度").step(0.1).onChange((e) => {plan.rotation.x = Math.PI * e;});floorFaces.add(gui, "planeHelper").name("平面辅助").onChange((e) => {planeHelper.visible = e;});scence.add(plan);}planFun();// 加载动画async function flash() {const fbx = new FBXLoader(); //加载器let actionOption = gioData.addFolder("动作控制"); //测试插件let actions: actionsType = reactive({}); //空对象//使用这个fbx里的人物await new Promise<void>((resolve, reject) => {//新建一个promise对象try {//捕获错误fbx.load("文件地址", (gltf) => {//加载器load以后加载fbx文件 gltf为文件gltf.scale.x = 0.1; //x大小 可以压缩gltf.scale.y = 0.1;gltf.scale.z = 0.1;let skeletonHelper = new SkeletonHelper(gltf); //骨骼辅助skeletonHelper.name = "骨骼辅助";scence.add(skeletonHelper); //添加实例actionOption //添加监听.add(gui, "skeletonHelper").name("骨骼辅助").onChange((e) => {skeletonHelper.visible = e;});gltf.name = "角色";scence.add(gltf); //添加实例mesh = new AnimationMixer(gltf); //新建动画混合器 绑定模型//动画中循环for (let i of gltf.animations) {//如果不是空动画if (i.duration && i.tracks.length) {actions[i.name] = { action: i, play: false }; //添加到动作对象中}}//对各个部位开启阴影//遍历gltf中所有对象gltf.traverse((e: any) => {if (e.isMesh) {//是骨骼则开启效果e.castShadow = true; //阴影投射e.receiveShadow = true; //接受阴影}});resolve();});} catch (error) {console.error("加载glb文件错误", error);reject(error);}});//使用glb中的动画await new Promise<void>((resolve, reject) => {try {new GLTFLoader().load("文件地址", (gltf) => {for (let i of gltf.animations) {//在自带的动画中循环if (i.duration && i.tracks.length) {//不为空let action = mesh.clipAction(i); //绑定动画到人物 混合器actions[i.name] = { action: i, play: false }; //添加到动作数组action.setEffectiveTimeScale(gui.speed); //设置时间比例action.setEffectiveWeight(0); //设置权重resolve();}}});} catch (error) {console.error("加载glb文件错误", error);reject(error);}});let accc: any; //用于替换当前动作的变量actionOption //监听.add(gui, "speed", 0.1, 1).name("动作速度").onChange((e) => {accc?.setEffectiveTimeScale(e); //调整当前动画的时间比例});// 动作控制actionOption.add(gui, "action", ["停止", ...Object.keys(actions)]) //所有的下标 中选择 ...ags.name("展示动作").onChange((e) => {//如果是停止if (e == "停止") {accc.fadeOut(3); //3s内缓出accc = null; //当前动画为空return;}actions[e].play = true; //讲播放状态更改为true 播放状态暂时无用let ac = mesh.clipAction(actions[e].action); //绑定动画ac.enabled = true; //是否禁用ac.setEffectiveTimeScale(gui.speed); //设置时间比例ac.setEffectiveWeight(1); //设置权重ac.play(); //开启播放if (!accc) {//如果为空 但是新增了动画ac.fadeIn(3); //缓动} else {accc.crossFadeTo(ac, 3); //狗则正常切换过度}accc = ac; //保存当前动作});}flash();//生命周期 页面加载完onMounted(() => {rander.setSize(window.innerWidth, window.innerHeight); //更改渲染大小box.value?.append(rander.domElement); //box渲染完成则添加box.value?.appendChild(stats.dom); //box渲染完成则添加性能监控//aim定时执行 动画function aim() {stats.update(); //刷新性能监控mesh?.update(clock.getDelta()); //如果mesh存在 则刷新 传入时间rander.render(scence, camera); //更新试图requestAnimationFrame(aim); //定时器 到时间调用自己}aim();});//使画布动态大小window.onresize = () => {camera.aspect = window.innerWidth / window.innerHeight; //更改比例camera.updateProjectionMatrix(); //更新摄像机投影矩阵rander.setSize(window.innerWidth, window.innerHeight); //更改场景大小};return {box,};},
});
</script>
<style>
* {padding: 0;margin: 0;
}
</style>
<style lang="less" scoped>
.main {height: 100%;width: 100%;
}
</style>

vue3 ts three 动画 骨骼动画 人物动画 模型动画相关推荐

  1. Unity(三十七):3D模型动画、脚本控制模型骨骼IK动画

    效果(左侧模型动画,右侧模型IK控制) 模型动画下载及导入 推荐模型动画下载链接地址 https://actorcore.reallusion.com/ Unity导入教程参见以下链接地址(需要科学上 ...

  2. 从零开始学习3D可视化之模型动画

    获取模型动画 播放模型动画 停止播放模型动画 在搭建3D可视化场景的过程中,我发现很多模型都有内置动画,很多模型在制作阶段就内置了动画,如果模型有内置动画,可以在 ThingJS 中利用 API 调用 ...

  3. Vue3+ts——动画Loading以及引入本地随机背景效果

    Vue3+ts--随机生成背景图片 我这里是采用loading为例子制作的随机背景效果(底部附上代码和成品效果展示) 这里需要注意一下,数组的格式必须要用下面这种格式创建对象 new URL(&quo ...

  4. 动画骨骼【Visual C++】游戏开发五十二 浅墨DirectX教程二十 骨骼动画来袭(一)...

    间时紧张,先记一笔,后续优化与完善. 本系列文章由zhmxy555(毛星云)编写,载转请注明出处. 文章链接: http://blog.csdn.net/zhmxy555/article/detail ...

  5. UE4 回合游戏项目 20- 添加人物被攻击的动画

    在上一节(UE4 回合游戏项目 19- 添加血量UI)基础上继续添加人物被攻击时播放被攻击动画的功能. 效果:(当玩家被攻击时,播放相应的受到伤害的动画) 步骤: 1.打开"1lantu&q ...

  6. 将其他人物模型动画导入Carla使用

    事先准备: 从UE4官方商店下载人物模型和动画 . 打开人物骨架 单击MCO_Mocap_Basics--Character--UE4_Mannequin_Skeleton 单击重定向管理器 单击新增 ...

  7. VUE3+ThreeJs加载飞机模型且播放模型动画

    介绍 Three.js 是一个 3D JavaScript 库,我们经常使用它加载各种不同格式的模型.示例中的直升机模型出处飞机航空器模型-3D模型库-CG模型网-第1页 免费3d模型下载的网站 免费 ...

  8. Unity动画系统-给人物添加动画

    导入人物模型,模型是不会动的,因为没有添加动画 首先给模型添加Animator组件 有的模型上自带组件,是因为我们给他设置成了人形动画,如果是普通动画就需要自己添加.添加好组件以后,我们发现上面缺少了 ...

  9. 前端使用css3实现人物卡片介绍动画

    前端使用css3实现人物卡片介绍动画,鼠标移入后图片缩小现实出人物简介文字,鼠标移出再恢复. <!doctype html> <html lang="zh-CN" ...

  10. 计算机二维动画实验原理,浅析计算机二维动画制作

    摘 要:最初的二维动画在制作上需要大量的人力还有较长的时间,相对的就是财力的消耗,在修改上也极度不便.计算机动画技术的发展提高了二维动画的制作效率,然而效率的提高却也让二维动画的质量变得不如以前.不过 ...

最新文章

  1. java maven 开发环境_Maven 搭建开发环境
  2. html+css 百度首页练习
  3. Live Writer测试
  4. 服务器负载信息失败,网络故障分析案例:负载均衡系统造成网络业务访问失败...
  5. 电脑教程从入门到精通_HALCON机器视觉软件零基础入门学习到精通实用教学视频教程...
  6. Windows Phone 7开发一月谈(3)
  7. mysql事务、视图
  8. Java基础复习——访问权限
  9. Flutter 《从0到1构建大前端应用》-所有知识点架构
  10. php 匹配标签内的文本内容 preg_match_all strip_tags
  11. 学生系统优化——字符限定
  12. DRF实战1 - 环境搭建
  13. 找茬游戏html5源码,大家来找茬游戏以JS实现
  14. jetbrains intellij idea从2021.2.3版本开始需要用户登录之后才能使用,2021.2.2版本以及之前的版本不用登录
  15. c语言 遍历搜索文件夹(获取文件夹中所有内容)
  16. 关于本科期间参加人工智能方向竞赛的建议
  17. Done、Doing、ToDo
  18. 博途PLC和CODESYS平台下FB编程应用(如何实例化多个FB)
  19. 5-2 学习打卡(11.7)
  20. 大工计算机学院实验室,计算机教学实验室

热门文章

  1. c# 调用浏览器打开页面
  2. linux解压 tar命令
  3. mysql设备采集数据_怎么将PLC设备数据采集到SQL数据库
  4. APP-Android:APK
  5. 变频器供电高频电子变压器电源电压检测
  6. RS232,RS485简介,以及DB9接口上引脚对应关系
  7. GP数据库(Greenplum)单机版安装
  8. 真正彻底卸载ie8的某些加载项
  9. 使用wunderlist进行TODO管理
  10. 苹果id无法登陆_苹果手机无法连接到app store怎么办