threejs教程-透视相机

161 阅读3分钟

简介

本系列教程需要具备threejs的基础入门知识,了场景、几何体、相机等基础概念。

学习本教程之前,建议学习笔者的【场景及坐标轴】的基础知识。

使用前置知识,可以很快的开发一个3D页面。

其核心代码如下:

<template>
  <div class="wrap" ref="threeContainer"></div>
</template>

<script setup>
import * as THREE from "three";
import { onMounted, ref } from "vue";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
// import { CubeTextureLoader } from "three/examples/jsm/loaders/CubeTextureLoader.js";

const threeContainer = ref(null);

// 1、创建3D场景对象Scene
const scene = new THREE.Scene();
// 添加背景颜色
scene.background = new THREE.CubeTextureLoader().setPath("/sky/").load(["posx.jpg", "negx.jpg", "posy.jpg", "negy.jpg", "posz.jpg", "negz.jpg"]);

// 添加网格地面
const gridHelper = new THREE.GridHelper(200, 10);
scene.add(gridHelper);

// 添加三维坐标轴
const axesHelper = new THREE.AxesHelper(80);
axesHelper.position.y = 20;
scene.add(axesHelper);

// 2、创建几何体Geometry模型
const geometry = new THREE.BoxGeometry(20, 20, 20);

const material = new THREE.MeshBasicMaterial({
  color: "blue",
});
const mesh = new THREE.Mesh(geometry, material);
// 设置模型mesh的xyz坐标
mesh.position.set(0, 40, 0);
scene.add(mesh);

// 3、使用虚拟相机观察模型
const camera = new THREE.PerspectiveCamera();
camera.position.set(0, 50, 200);
camera.lookAt(0, 0, 20); //坐标原点

// 4、渲染3D场景到DOM上
const width = 800; //宽度
const height = 500; //高度
const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)
renderer.setAnimationLoop(animation);
// 创建轨道控制器
const controls = new OrbitControls(camera, renderer.domElement);
// 添加阻尼
controls.enableDamping = true;
controls.dampingFactor = 0.01;
// 开启自动旋转
controls.autoRotate = true;
// 设置自动旋转速度
controls.autoRotateSpeed = 5;

function animation() {
  mesh.rotation.x += 0.05;
  mesh.rotation.y += 0.05;
  controls.update();
  renderer.render(scene, camera);
}

onMounted(() => {
  threeContainer.value.appendChild(renderer.domElement);
});
</script>

<style scoped></style>

透视相机

在Three.js中,透视相机(PerspectiveCamera)是用来模拟人眼所看到的景象,它是3D场景的渲染中使用得最普遍的投影模式。

我们创建项目的时候,采用的就是透视相机

// 3、使用虚拟相机观察模型
const camera = new THREE.PerspectiveCamera();
camera.position.set(0, 50, 200);
camera.lookAt(0, 0, 20); //坐标原点

要想深入了解透视相机的使用方法,我们需要先学习一些基本的3D知识

PerspectiveCamera简介

语法结构:PerspectiveCamera( fov : Number, aspect : Number, near : Number, far : Number )

参数含义默认值
fov相机视锥体竖直方向视野角度50
aspect相机视锥体水平方向和竖直方向长度比,一般设置为Canvas画布宽高比width / height1
near相机视锥体近裁截面相对相机距离0.1
far相机视锥体远裁截面相对相机距离,far-near构成了视锥体高度方向2000

透视投影相机的四个参数fov, aspect, near, far构成一个四棱台3D空间,被称为视锥体,只有视锥体之内的物体,才会渲染出来,视锥体范围之外的物体不会显示在Canvas画布上。

使用官方编辑器学习透视相机

要想深入学习透视相机,我们可以借助官方提供的编辑器。

编辑器在线地址:threejs.org/editor/

创建物体和透视相机

透视相机的移动与旋转

透视相机与普通相机的视角切换

透视相机的参数调整

不同参数对透视相机位置的影响

代码示例

首先,我们关闭场景的自动旋转,方便观察。

PerspectiveCamera增加初始参数

// 3、使用虚拟相机观察模型
const camera = new THREE.PerspectiveCamera(
  75, 
  window.innerWidth / window.innerHeight, 
  0.1, 
  1000
);

视野角度fov对视角的影响

<template>
  <div class="wrap" ref="threeContainer"></div>
  <button @click="changeCameraAdd">+</button>
  <button>相机fov</button>
  <button @click="changeCameraDe">-</button>
</template>

updateProjectionMatrix()方法来更新投影矩阵,以确保场景在新的fov参数下正确渲染

截面near、far对视角的影响

近远截面及fov构成视椎体,当远近界面位置不恰当时,物体可能位于视椎体之外,渲染不出来。

<template>
  <div class="wrap" ref="threeContainer"></div>
  <button @click="changeCameraAdd">+</button>
  <button>相机fov</button>
  <button @click="changeCameraDe">-</button>
  <button @click="nearAdd">+</button>
  <button>近界面near</button>
  <button @click="nearDe">-</button>
</template>
function nearAdd() {
  camera.near += 10;
  camera.updateProjectionMatrix();
}
function nearDe() {
  camera.near -= 10;
  camera.updateProjectionMatrix();
}

相机位置对视角的影响

<template>
  <div class="wrap" ref="threeContainer"></div>
  <button @click="changeCameraAdd">+</button>
  <button>相机fov</button>
  <button @click="changeCameraDe">-</button>
  <button @click="cameraYAdd">Y轴+</button>
  <button>相机位置</button>
  <button @click="cameraXdd">Z轴+</button>
</template>
function cameraYAdd() {
  camera.position.x += 10;
  controls.update();
}
function cameraXdd() {
  camera.position.z += 10;
  controls.update();
}

物体位置对视角的影响

<template>
  <div class="wrap" ref="threeContainer"></div>
  <button @click="meshAdd">Y轴+</button>
  <button>物体位置</button>
  <button @click="meshDe">Y轴-</button>
</template>
function meshAdd() {
  mesh.position.y += 10;
}
function meshDe() {
  mesh.position.y -= 10;
}