three.js 关键帧动画

news2024/12/23 18:45:43

效果:

代码:

<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>

 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【架构】API接口安全防护救命的11招

前言 如何保证接口的安全性? 根据多年的工作经验,给大家介绍一下保证接口安全的一些小技巧,希望对你会有所帮助。 1 参数校验 保证接口安全的第一步,也是最重要的一步,需要对接口的请求参数做校验。 如果我们把接口请求参数的校验做好了,真的可以拦截大部分的无效请求…

使用paho.mqtt.embedded-c和openssl实现MQTT的单向认证功能

1、背景 由于项目有需求在一个现有的产品上增加MQTT通信的功能&#xff0c;且出于安全考虑&#xff0c;MQTT要走TLS&#xff0c;采用单向认证的方式。 2、方案选择 由于是在现有的产品上新增功能&#xff0c;那么为了减少总的成本&#xff0c;故选择只动应用软件的来实现需求。…

设置若依Token过期时间

方法一&#xff1a;设置永不过期&#xff0c;有安全隐患&#xff0c;不建议使用 redisCache.setCacheObject(userKey, loginUser); 方法二&#xff1a;修改application.yml

Flutter组件GridView使用介绍

介绍 GridView 是 Flutter 中用于创建网格布局的滚动小部件。它可以创建多列布局&#xff0c;并且每个网格单元可以包含一个小部件。 GridView 提供了几种构造函数来创建不同类型的网格布局&#xff1a; GridView&#xff1a;最通用的构造函数&#xff0c;完全自定义网格布局…

vs报错TypeError: Cannot read property ‘parseComponent‘ of undefined(已解决)

目录 错误分析&#xff1a; 解决方案&#xff1a; 1.卸载 vue-template-compiler&#xff1a; 2.查看项目中已经安装的 Vue 的版本。 3.安装特定版本的 vue-template-compiler&#xff1a; 4.现在重新运行一下&#xff0c;成功&#xff01; 错误分析&#xff1a; 这是因…

练习接口测试第一步骤

最近一段时间学了Python语言&#xff0c;重新学了 Java&#xff0c;js&#xff0c;html语言&#xff0c;CSS&#xff0c;linux&#xff0c;一堆测试工具&#xff1b;唉&#xff5e; 在接触接口测试过程中补了很多课&#xff0c; 终于有点领悟接口测试的根本&#xff1b; 偶是…

在ubuntu上检查内存使用情况的九种方法

在 Ubuntu 中&#xff0c;可以通过 GUI(图形用户界面)和命令行使用多种方法来监视系统的内存使用情况&#xff0c;监视 Ubuntu 服务器上的内存使用情况并不复杂&#xff1b;了解已使用和可用的内存量对于故障排除和优化服务器性能至关重要&#xff0c;因为内存对系统 I/O 速度至…

008-关于FPGA/ZYNQ直接处理图像传感器数据输出的若干笔记(裸板采集思路)

文章目录 前言一、图像传感器厂商二、图像传感器的参数解析三、图像传感器中的全局曝光和卷帘曝光四、处理传感器图像数据流程1.研究当前图像传感器输出格式2.FPGA处理图像数据 总结 前言 最近也是未来需要考虑做的一件事情是&#xff0c;如何通过FPGA/ZYNQ去做显微镜图像观测…

VUE2/3:element ui table表格的显隐列(若依框架)

若依框架自带一个组件&#xff0c;封装了关于表格&#xff0c;展示和隐藏表格列的功能&#xff1b; 使用效果就是这样的&#xff0c;在表格上面&#xff0c;三个框&#xff0c;从左到右分别是隐藏上面搜索&#xff0c;刷新列表&#xff0c;和显隐列的功能&#xff1b; 一、下面…

基于 Spring Boot 支付宝沙箱支付(Java 版本)

基于 Spring Boot 支付宝沙箱支付&#xff08;Java 版本&#xff09; 步骤第一步&#xff1a;使用支付宝账户登录&#xff0c;打开控制台&#xff0c;进入沙箱环境第二步&#xff1a;配置内网穿透账号第三步&#xff1a;引入支付宝 SDK第四步&#xff1a; 配置 SpringBoot第五步…

【elastic search】JAVA操作elastic search

目录 1.环境准备 2.ES JAVA API 3.Spring Boot操作ES 1.环境准备 本文是作者ES系列的第三篇文章&#xff0c;关于ES的核心概念移步&#xff1a; https://bugman.blog.csdn.net/article/details/135342256?spm1001.2014.3001.5502 关于ES的下载安装教程以及基本使用&…

探秘人工智能大会:揭示未来技术发展趋势与学习之道

随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;已经逐渐渗透到我们生活的方方面面。 参加人工智能大会&#xff0c;不仅能够洞察到最前沿的技术动态&#xff0c;还能与业界专家、学者交流思想&#xff0c;共同探讨AI的未来发展。本文将带您探秘人工智能大…

SAP一次查看多张凭证明细SQ03

1、在SAP中通过FB03可以查看所有的凭证清单&#xff0c;但是如果想一次性查看多张凭证的行项目明细&#xff0c;通过SAP的查询功能SQ03来查询 首先&#xff0c;通过SQ03&#xff0c;给用户组&#xff0c;输入“/SAPQUERY/GL”&#xff0c;回车 2、通过SQ02&#xff0c;菜单栏的…

重建传播网络并识别隐藏来源

1.摘要 我们从数据中揭示复杂网络结构和动态的能力&#xff0c;对于理解和控制复杂系统中的集体动态至关重要。尽管在这一领域已有近期进展&#xff0c;但如何从有限的时间序列中重建具有随机动态过程的网络仍然是一个突出问题。在这里&#xff0c;我们开发了一个基于压缩感知的…

大语言模型面试问题

自己在看面经中遇到的一些面试题&#xff0c;结合自己和理解进行了一下整理。 transformer中求和与归一化中“求和”是什么意思&#xff1f; 求和的意思就是残差层求和&#xff0c;原本的等式为y H(x)转化为y x H(x)&#xff0c;这样做的目的是防止网络层数的加深而造成的梯…

k8s动态PV

当发布PVC之后可以生成PV&#xff0c;还可以再共享服务器上直接绑定和使用PV 动态PV需要两个组件&#xff1a; 存储卷插件&#xff0c;k8s本身支持的动态PV创建不包括NFS&#xff0c;需要声明和安装一个外插件 Provisioner&#xff1a;存储分配器。动态创建PV&#xff0c;然后…

互联网加竞赛 基于大数据的社交平台数据爬虫舆情分析可视化系统

文章目录 0 前言1 课题背景2 实现效果**实现功能****可视化统计****web模块界面展示**3 LDA模型 4 情感分析方法**预处理**特征提取特征选择分类器选择实验 5 部分核心代码6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于大数据…

【笔记】Blender4.0建模入门-1、2

Blender入门 ——邵发 1.1 课程介绍 Blender&#xff0c;一款3D建模软件&#xff0c;小乔、免费、全流程 常见的3D建模软件&#xff1a; - 3DsMax/Maya/Blender/Cinema4D/ZBrush...游戏影视 - Proe/Solidworks/Inventor/UG...工业建模 - SketchUp/Rhino/Revit...建筑设计 …

OpenWRT部署web服务并结合内网穿透实现公网远程访问内网网站

文章目录 前言1. 检查uhttpd安装2. 部署web站点3. 安装cpolar内网穿透4. 配置远程访问地址5. 配置固定远程地址 前言 uhttpd 是 OpenWrt/LuCI 开发者从零开始编写的 Web 服务器&#xff0c;目的是成为优秀稳定的、适合嵌入式设备的轻量级任务的 HTTP 服务器&#xff0c;并且和…

《剑指 Offer》专项突破版 - 面试题 8 : 和大于或等于 k 的最短子数组(C++ 实现)- 详解同向双指针(滑动窗口算法)

目录 前言 一、暴力求解 二、同向双指针&#xff08;滑动窗口算法&#xff09; 前言 题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 题目&#xff1a; 输入一个正整数组成的数组和一个正整数 k&#xff0c;请问数组中和大于或等于 k 的连续子数组的最短…