three.js 关键帧动画

效果:

代码:

<template>
  <div>
    <el-container>
      <el-main>
        <div class="box-card-left">
          <div id="threejs" style="border: 1px solid red"></div>

          <div class="box-right">
            <el-button type="primary" @click="start">循环播放</el-button>
            <el-button type="primary" @click="start_once">播放一次</el-button>
            <el-button type="primary" @click="start_clamp"
              >保持播放结束效果</el-button
            >
            <el-button type="primary" @click="stop">结束动画</el-button>
            <el-button type="primary" @click="pausedFn">暂停</el-button>
            <el-button type="primary" @click="time_scale"
              >2倍速循环播放</el-button
            >
            <el-button type="primary" @click="time_duration"
              >控制动画播放特定时间开始(2秒)</el-button
            >
            <div style="margin-top: 20px;"></div>
            <el-progress
              :percentage="percentage"
              :format="format"
            ></el-progress>
            <el-button-group>
              <el-button icon="el-icon-minus" @click="decrease"
                >播放速度</el-button
              >
              <el-button icon="el-icon-plus" @click="increase"
                >播放速度</el-button
              >
            </el-button-group>
            <el-slider v-model="value1" @change="change"></el-slider>
            动画播放(拖动任意时间状态)
          </div>
        </div>
      </el-main>
    </el-container>
  </div>
</template>
<script>
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
// 效果制作器
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js";
// 渲染通道
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass.js";
// 发光描边OutlinePass
import { OutlinePass } from "three/examples/jsm/postprocessing/OutlinePass.js";
import {
  CSS2DObject,
  CSS2DRenderer,
} from "three/examples/jsm/renderers/CSS2DRenderer.js";

export default {
  data() {
    return {
      value1: 0,
      percentage: 20,
      name: "",
      scene: null,
      camera: null,
      renderer: null,
      effectComposer: null,
      mesh: null,
      geometry: null,
      group: null,
      material: null,
      texture: null,
      position: null,
      outlinePass: null,
      clock: null,
      mixer: null,
      clip_action: null,
      request_animation_frame: null,
      canvasWidth: 1000,
      canvasHeight: 800,
      color: [],
      meshArr: [],
    };
  },
  created() {},
  mounted() {
    this.name = this.$route.query.name;
    this.init();
  },
  methods: {
    goBack() {
      this.$router.go(-1);
    },
    // 动画播放(拖动任意时间状态)
    change(e) {
      console.log("e:", e);
      this.clip_action.paused = true;
      this.clip_action.clampWhenFinished = true;
      this.clip_action.time = 0.1 * e;
    },
    format(percentage) {
      return percentage / 10 + "倍";
    },
    increase() {
      this.percentage += 10;
      if (this.percentage > 100) {
        this.percentage = 100;
      }
      this.clip_action.timeScale = this.percentage / 10;
    },
    decrease() {
      this.percentage -= 10;
      if (this.percentage < 0) {
        this.percentage = 0;
      }
      this.clip_action.timeScale = this.percentage / 10;
    },
    init() {
      //  创建场景对象
      this.scene = new this.$three.Scene();
      // 创建立方几何体对象
      this.geometry = new this.$three.BoxGeometry(60, 50, 90);
      // 创建材质对象
      this.material = new this.$three.MeshBasicMaterial({
        color: 0xaabbdd,
      });
      // 创建网格对象
      this.mesh = new this.$three.Mesh(this.geometry, this.material);
      this.scene.add(this.mesh);

      this.clock = new this.$three.Clock();
      this.animation();

      // 调用play方法
      // clip_action.play();
      // 创建相机对象
      this.camera = new this.$three.PerspectiveCamera(60, 1, 0.01, 2000);
      this.camera.position.set(300, 300, 300);
      this.camera.lookAt(0, 0, 0);
      // 创建网格辅助对象
      const axesHelper = new this.$three.AxesHelper(100);
      this.scene.add(axesHelper);
      const gridHelper = new this.$three.GridHelper(
        300,
        20,
        0xffaaaa,
        0xaabbcc
      );
      this.scene.add(gridHelper);
      // 创建渲染器对象
      this.renderer = new this.$three.WebGLRenderer();
      this.renderer.setSize(1000, 800);
      this.renderer.render(this.scene, this.camera);
      window.document
        .getElementById("threejs")
        .appendChild(this.renderer.domElement);
      const controls = new OrbitControls(this.camera, this.renderer.domElement);
      controls.addEventListener("change", () => {
        this.renderer.render(this.scene, this.camera);
      });
    },
    // 创建关键帧的方法
    animation() {
      // 给模型定义name
      this.mesh.name = "Box";
      // 定义时间范围
      const time = [0, 3, 6, 8, 10]; // 对应时间轴上的0,3,6秒
      // 定义0,3,6秒对应的坐标值
      const values = [0, 0, 0, 100, 0, 0, 0, 0, 100, 0, 100, 0, 0, 0, 0];
      // 创建关键帧 KeyframeTrack(params: String, timeRange: Array, valueRange: Array)
      // params 模型的属性,timeRange: 时间范围,valueRange: 值范围
      const position_kf = new this.$three.KeyframeTrack(
        "Box.position",
        time,
        values
      );
      // 设置在2-6秒内颜色变化,颜色三个数一组表示 rgb格式的
      /**
       * .setRGB ( r, g, b ) this
          r — 红色通道值在1和0之间。
          g — 绿色通道值在1和0之间。
          b — 蓝色通道值在1和0之间。

          设置颜色的RGB值。
       */
      const color_kf = new this.$three.KeyframeTrack(
        "Box.material.color",
        [2, 6],
        [1, 0.2, 0.3, 0.1, 0.8, 0.3]
      );
      // 创建关键帧动画对象  AnimationClip(name:String, time:Number, value: Array)
      const clip = new this.$three.AnimationClip("clip_name", 10, [
        position_kf,
        color_kf,
      ]);
      // 创建动画播放器
      this.mixer = new this.$three.AnimationMixer(this.mesh);
      this.clip_action = this.mixer.clipAction(clip);
    },
    renderFun() {
      this.renderer.render(this.scene, this.camera);
      const frameT = this.clock.getDelta();
      // 更新播放器相关的时间(如果不更新,则没有动画效果)
      if (this.mixer) {
        this.mixer.update(frameT);
      }
      this.request_animation_frame = window.requestAnimationFrame(
        this.renderFun
      );
    },
    start() {
      this.clip_action.loop = this.$three.LoopRepeat;
      this.clip_action.paused = false;
      // play() 控制动画播放,默认循环播放
      this.clip_action.play();
      this.renderFun();
    },
    start_once() {
      this.clip_action.loop = this.$three.LoopOnce;
      // play() 控制动画播放,默认循环播放
      this.clip_action.play();
      this.renderFun();
    },
    start_clamp() {
      // 物体状态停留在动画结束的时候
      this.clip_action.clampWhenFinished = true;
      this.clip_action.loop = this.$three.LoopOnce;
      // play() 控制动画播放,默认循环播放
      this.clip_action.play();
      this.renderFun();
    },
    stop() {
      // play() 控制动画播放,默认循环播放
      this.clip_action.stop();
      // // 物体状态停留在动画结束的时候
      this.clip_action.clampWhenFinished = true;
      // this.renderFun();
    },
    pausedFn() {
      console.log(this.clip_action.paused);
      if (this.clip_action.paused) {
        this.clip_action.paused = false;
      } else {
        this.clip_action.paused = true;
      }
      this.renderFun();
    },
    time_scale() {
      this.clip_action.timeScale = 2;
      this.clip_action.play();
      this.renderFun();
    },
    time_duration() {
      // 控制动画播放特定时间段;需要设置为非循环模式、同时设置动画播放完定留在结束状态,
      // 设置为非循环模式
      this.clip_action.loop = this.$three.LoopOnce;
      this.clip_action.clampWhenFinished = true;
      this.clip_action.time = 2; // 动画开始时间
      // this.clip_action.duration = 2; // 动画结束时间
      this.clip_action.play();
      this.renderFun();
    },
  },
};
</script>
//
<style lang="less" scoped>
.box-card-left {
  display: flex;
  align-items: flex-start;
  flex-direction: row;

  width: 100%;

  .box-right {
    img {
      width: 500px;
      user-select: none;
    }
  }
}
</style>

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/311461.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

二维激光雷达

目录 前言 1 单线激光雷达 激光器 接收器 信号处理单元 旋转机构 2 单线激光雷达原理 2.1 三角测距法 1、直射式 2、斜射式 2.2 TOF飞行时间测距法 总结 前言 开始干活啦&#xff0c;单线激光雷达&#xff0c;三维知道原理&#xff0c;但不研究了&#xff0c;问就是买不起。 1 …

【JaveWeb教程】(19) MySQL数据库开发之 MySQL数据库操作-DML 详细代码示例讲解

目录 3. 数据库操作-DML3.1 增加(insert)3.2 修改(update)3.3 删除(delete)3.4 总结 3. 数据库操作-DML DML英文全称是Data Manipulation Language(数据操作语言)&#xff0c;用来对数据库中表的数据记录进行增、删、改操作。 添加数据&#xff08;INSERT&#xff09;修改数据…

mybatis-flex与springBoot整合

mybatis-flex基本使用 1.测试sql2.导入坐标3.框架搭建1.pojo层2.mapper层3.service层4.controller层5.启动类6.配置类7.EmpMapper.xml 4.启动测试 本片文章在springBoot3&#xff0c;jdk21下测试通过 注意官方网站为&#xff1a;https://mybatis-flex.com/ 请点击&#xff1a;直…

【C++】C++11中的常见语法(上)

C11 一、C11简介二、统一的列表初始化1.&#xff5b;&#xff5d;初始化2. std::initializer_list 三、声明1. auto2. decltype3. nullptr 四、右值引用和移动语义1. 左值引用和右值引用2. 左值引用与右值引用比较3. 右值引用使用场景和意义4. 右值引用引用左值及其一些更深入的…

如何使用Postman创建Mock Server?

这篇文章将教会大家如何利用 Postman&#xff0c;通过 Mock 的方式测试我们的 API。 什么是 Mock Mock 是一项特殊的测试技巧&#xff0c;可以在没有依赖项的情况下进行单元测试。通常情况下&#xff0c;Mock 与其他方法的主要区别就是&#xff0c;用于取代代码依赖项的模拟对…

Vue3 + TS + Element-Plus —— 项目系统中封装表格+搜索表单 十分钟写五个UI不在是问题

前期回顾 纯前端 —— 200行JS代码、实现导出Excel、支持DIY样式&#xff0c;纵横合并-CSDN博客https://blog.csdn.net/m0_57904695/article/details/135537511?spm1001.2014.3001.5501 目录 一、&#x1f6e0;️ newTable.vue 封装Table 二、&#x1f6a9; newForm.vue …

【数据库】视图索引执行计划多表查询笔试题

文章目录 一、视图1.1 概念1.2 视图与数据表的区别1.3 优点1.4 语法1.5 实例 二、索引2.1 什么是索引2.2.为什么要使用索引2.3 优缺点2.4 何时不使用索引2.5 索引何时失效2.6 索引分类2.6.1.普通索引2.6.2.唯一索引2.6.3.主键索引2.6.4.组合索引2.6.5.全文索引 三、执行计划3.1…

性能测试中TPS上不去的几种原因浅析

昨晚在某个测试群看到有人问了一个问题&#xff1a;压力测试中TPS一直上不去&#xff0c;是什么原因&#xff1f;稍微整理了下思路&#xff0c;列举性的简略回答了他的问题。 这篇博客&#xff0c;就具体说说在实际压力测试中&#xff0c;为什么有时候TPS上不去的原因。如有遗…

一包多语言——使用FontForge合并字体

大家好&#xff0c;我是阿赵。   比较多游戏做了一个游戏包里面包含了多种语言&#xff0c;可以游戏内切换。这里分享一个合并多种语言字体的方法。 一、遇到的问题 假设我们游戏需要同时显示简体中文、泰文、老挝文三种语言。 解决方案有多种&#xff1a; 1、准备多种字体 …

【清华社机器之心】视频生成前沿研究与应用特别活动

在视频生成即将迎来技术和应用大爆发之际&#xff0c;为了帮助企业和广大从业者掌握技术前沿&#xff0c;把握时代机遇&#xff0c;机器之心AI论坛就将国内的视频生成技术力量齐聚一堂&#xff0c;共同分享国内顶尖力量的技术突破和应用实践。 论坛将于2024.01.20在北京举办&am…

FineBI实战项目一(18):每小时上架商品个数分析开发

点击新建组件&#xff0c;创建每小时上架商品个数组件。 选择线图&#xff0c;拖拽cnt&#xff08;总数&#xff09;到纵轴&#xff0c;拖拽hourStr到横轴。 修改横轴和纵轴的文字。 调节连线样式。 添加组件到仪表板。

ride导入常用的库

1、打开程序 安装ride成功后&#xff0c;直接在cmd中打开&#xff0c;过程中可以捕获到日志记录 输入&#xff1a;ride.py 2、新建测试套件 右键文件夹&#xff0c;选择--》new Suite 3、导入 Library 导入成功的是黑色&#xff0c;失败的是红色&#xff0c;可以再cmd中查看…

Jenkins基础篇--添加节点

节点介绍 Jenkins 拥有分布式构建(在 Jenkins 的配置中叫做节点)&#xff0c;分布式构建能够让同一套代码在不同的环境(如&#xff1a;Windows 和 Linux 系统)中编译、测试等。 Jenkins 运行的主机在逻辑上是 master 节点&#xff0c;下图是主节点和从节点的关系。 添加节点 …

Pytorch常用的函数(六)常见的归一化总结(BatchNorm/LayerNorm/InsNorm/GroupNorm)

Pytorch常用的函数(六)常见的归一化总结(BatchNorm/LayerNorm/InsNorm/GroupNorm) 常见的归一化操作有&#xff1a;批量归一化&#xff08;Batch Normalization&#xff09;、层归一化&#xff08;Layer Normalization&#xff09;、实例归一化&#xff08;Instance Normaliza…

WindowsServer安装mysql最新版

安装 下载相应mysql安装包&#xff1a; MySQL :: Download MySQL Installer 选择不登陆下载 双击运行下载好的mysql-installer-community-*.*.*.msi 进入类型选择页面&#xff0c;本人需要mysql云服务就选择了server only server only&#xff08;服务器&#xff09;&#x…

第8章-第2节-Java中流的简单介绍

1、什么是流 我们可以先想象水流是怎样的&#xff1f;溪水不断流动&#xff0c;最终融入大海&#xff1b;我们今天的学习IO其实如同水流一样&#xff0c;当我们读取文件信息或者写入信息时&#xff0c;如同水流一样&#xff0c;不断读取或者写入&#xff0c;直到业务流程结束。…

【AI视野·今日CV 计算机视觉论文速览 第286期】Tue, 9 Jan 2024

AI视野今日CS.CV 计算机视觉论文速览 Tue, 9 Jan 2024 Totally 121 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computer Vision Papers Dr$^2$Net: Dynamic Reversible Dual-Residual Networks for Memory-Efficient Finetuning Authors Chen Zhao, Shuming Li…

Vercel配置自定义域名

首先你需要有一个域名 1.点击部署的项目设置 2.找到Domains 3.输入自己的域名 点击添加之后按要求去域名服务商添加解析即可 4.显示下面内容就设置完成了&#xff0c;

vscode配置Todo Tree插件

一、在VSCode中安装插件Todo Tree ​​​​ 二、按下快捷键ctrlshiftP&#xff0c;输入setting.jspn 选择相应的配置范围&#xff0c;我们选择的是用户配置 Open User Settings(JSON)&#xff0c;将以下代码插入其中。 {//todo-tree 标签配置从这里开始 标签兼容大小写字母(…

The Sandbox 线下联动|「友邦嘉年华」地主专享门票免费放送

我们很高兴与票务合作伙伴 0xMoongate 合作&#xff0c; 为各位地主们准备了免费的“友邦嘉年华”门票&#xff01; “友邦嘉年华”介绍&#xff1a; The Sandbox 是香港最大户外盛事之一“友邦嘉年华”的荣誉合作伙伴&#xff01; 我们将这份兴奋延伸到现实世界&#xff0c…