three.js 关键帧动画

2024-01-10 15:24:12

效果:

代码:

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

?

文章来源:https://blog.csdn.net/yinge0508/article/details/135498488
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。