vue+threejs控制相机:聚焦到某物体

1,126 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第23天,点击查看活动详情


写在前面

本文用vue+threejs控制相机聚焦到某物体。

以下是演示gif:

20221018_112604.gif

代码说明

  1. html和css

创建一个id,用于存放threejs渲染器节点。创建三个按钮:【小狗】、【女孩】、【树】,点击对应的按钮聚焦到对应的物体。

<template>
  <div class="item">
    <div id="THREE49"></div>
    <div class="btn_box">
      <el-button @click="focusDog">小狗</el-button>
      <el-button @click="focusGirl">女孩</el-button>
      <el-button @click="focusTree"></el-button>
    </div>
  </div>
</template>
<style lang="less" scoped>
.btn_box {
  position: absolute;
  top: 10px;
  left: 210px;
}
</style>
  1. 按钮事件

点击按钮之后,通过调整控制器的焦点和相机位置来实现聚焦到某物体。至于如何获取控制器的焦点和相机位置在下面的render()方法中会说到。

    focusDog() {
      this.controls.target.set(-5, 1.8, -10.5); // 控制器的焦点
      this.camera.position.set(-4.8, 2.7, 13.6); // 相机位置
      this.controls.update();
    },
    focusGirl() {
      this.controls.target.set(2.7, 9.7, -10); // 控制器的焦点
      this.camera.position.set(-10.5, 8, 43); // 相机位置
      this.controls.update();
    },
    focusTree() {
      this.controls.target.set(42.4, 29.1, -4.8); // 控制器的焦点
      this.controls.update();
    },
  1. 引入threejs和需要的模块

OrbitControls - 轨道控制器,需要改变它的焦点

GLTFLoader - 引入模型需要的加载器

import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
  1. data()中定义的变量

camera相机,scene场景,gltfLoader模型加载器,renderer场景渲染器,controls轨道控制器,manager模型加载进度管理

  data() {
    return {
      camera: null,
      scene: null,
      gltfLoader: null,
      renderer: null,
      controls: null,

      manager: null,
    };
  },
  1. mounted()方法中调用的函数

每个函数的意义在代码种都有说明

  mounted() {
    this.manager = new THREE.LoadingManager();
    this.gltfLoader = new GLTFLoader(this.manager);
    this.initScene(); // 创建场景
    this.initCamera(); // 创建相机
    this.initLight(); // 创建灯光
    this.initRenderer(); // 创建渲染器
    this.initControls(); //创建轨道控制器
    this.initModel(); // 加载模型

    this.manager.onLoad = () => {
      this.render();
      console.log("Loading complete!");
    };
  },
  1. 创建场景

创建场景并设置背景颜色

    initScene() {
      this.scene = new THREE.Scene();
      this.scene.background = new THREE.Color(0x000000); // 设置场景背景颜色
    },
  1. 创建相机

创建一个透视相机并设置相机的位置

    initCamera() {
      this.camera = new THREE.PerspectiveCamera(
        35,
        (window.innerWidth - 201) / window.innerHeight,
        1,
        600
      ); // 透视相机
      this.camera.position.x = 10.5;
      this.camera.position.y = 32.3; // 设置相机的位置
      this.camera.position.z = 104.3;
      this.scene.add(this.camera); // 将相机添加到场景中
    },
  1. 创建灯光

创建一个平行光和一个环境光

    initLight() {
      const light = new THREE.DirectionalLight(0xffffff); // 平行光
      light.position.set(0.5, 1.0, 0.5).normalize(); // 设置平行光的方向,从(0.5, 1.0, 0.5)->target一般(0, 0, 0)
      this.scene.add(light); // 将灯光添加到场景中

      const ambLight = new THREE.AmbientLight(0xf0f0f0, 0.1); // 环境光
      this.scene.add(ambLight);
    },
  1. 创建渲染器

创建渲染器,并将渲染器节点添加到html中

    initRenderer() {
      this.renderer = new THREE.WebGLRenderer({ antialias: true });
      this.renderer.outputEncoding = THREE.sRGBEncoding;
      this.renderer.setPixelRatio(window.devicePixelRatio);
      this.renderer.setSize(window.innerWidth - 201, window.innerHeight);
      document.getElementById("THREE49").appendChild(this.renderer.domElement);
    },
  1. 创建轨道控制器

创建轨道控制器并设置控制器的焦点

    initControls() {
      this.controls = new OrbitControls(this.camera, this.renderer.domElement);
      this.controls.addEventListener("change", this.render);

      this.controls.target.set(22, 26, -7); // 控制器的焦点
      this.controls.update();
    },
  1. 加载模型

加载【树】、【女孩】、【小狗】模型,并设置模型的缩放,让他们看起来和谐一点,然后将模型添加到场景中

    initModel() {
      this.gltfLoader.load(
        "/models/models/gltf/urban_tree/scene.gltf",
        (gltf) => {
          gltf.scene.scale.set(10, 10, 10);
          gltf.scene.position.set(40, 0, 0);
          this.scene.add(gltf.scene);
        }
      );
      this.gltfLoader.load("/models/models/gltf/shiba/scene.gltf", (gltf) => {
        gltf.scene.scale.set(3, 3, 3);
        gltf.scene.position.set(-5, 3, 1);
        this.scene.add(gltf.scene);
      });
      this.gltfLoader.load("/models/models/gltf/matilda/scene.gltf", (gltf) => {
        gltf.scene.scale.set(0.1, 0.1, 0.1);
        this.scene.add(gltf.scene);
      });
    },
  1. 渲染场景和相机

在每次渲染的时候获取相机位置和获取控制器的焦点,先获取能聚焦物体的最合适的相机位置和控制器的焦点,然后写进按钮事件中,即可实现点击按钮聚焦到某物体。

    render() {
      console.log("this.camera.position", this.camera.position); // 获取相机位置
      console.log("target", this.controls.target); // 获取控制器的焦点
      this.renderer.render(this.scene, this.camera);
    },

写在最后

以上就是所有的代码和说明。