threejs系列:相机与投影 📷

写在最前

three.js 摄像机是用于控制三维场景视角的对象,用于控制相机的位置、方向、视野和其他属性。

PerspectiveCamera 透视投影相机

视锥体

fov:垂直视野角度,fov越小,物体越大,反之亦然。

很好理解,眯起眼睛看物体,物体会整个呈现在视野中,所以就会显得很大。

aspect: 视锥体长宽比,呈现在屏幕的宽高比。

如全屏则使用window的宽高比,如不全屏则使用Canvas(renderer.domElement)的宽高比。

far、near:可观测的最远与最近的距离。

相关

投影

投影是什么?投影是3维物体投射到2D平面的过程。生活中的物体都是3维的,而相机拍出的照片是二维的,这中间必然是受到某种"介质"的影响,而这个"介质"就是算法。

不同算法可以有不同的叫法。

透视投影

近大远小,物体的位置需受与照相机的距离影响。

正交投影

物体位置不受与照相机距离影响。

原理

在WebGL中并没有摄像机的概念,只是通过把场景中的所有物体往相反方向移动的方式来模拟出摄像机。

怎么理解呢,就像是当你坐火车看向窗外时,你会感觉树在往后移动。

相关常用 API

lookAt

Object3D<Event>.lookAt(vector: THREE.Vector3): void

参数为一个3维向量,向量可以代表物体位置,调用方法设置相机朝向。

不要好奇为什么相机可以调用Object3D的方法,因为万物皆是Object3D,后面会将这个基类

getWorldDirection

Camera.getWorldDirection(target: THREE.Vector3): THREE.Vector3

返回当前摄像机所正视的世界空间方向的Vector3对象,俯视时z为负数

updateProjectionMatrix

更新摄像机投影矩阵,当far、near、aspect、fov等修改时需执行,常用于自适应屏幕

setViewOffset

设置相机偏移,用途常用于:多显示器拼接画面

动手实践

  1. 跟随运动

假如我们拥有一个物体随机移动,我们需要镜头始终瞄准物体。

js 复制代码
<template>
    <div ref="dom"></div>
</template>
<script lang="ts" setup>
import * as THREE from "three";
import { Ref, onMounted, ref } from "vue"

let { PerspectiveCamera, WebGLRenderer, Scene } = THREE;
let camera = new PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 1000);
let renderer = new WebGLRenderer();
let scene = new Scene();
let dom = ref(null);
let angle = 0;

let cube = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), new THREE.MeshBasicMaterial({ color: 0x000000 }))
scene.add(cube);
cube.position.y = 1;


let plane = new THREE.Mesh(new THREE.BoxGeometry(70, 70, 0.5), new THREE.MeshBasicMaterial({ color: 0x9D9D9D }))
plane.position.z = 0;
plane.rotation.x = -Math.PI / 2;
scene.add(plane)

camera.position.set(20, 20, -20);
camera.lookAt(cube.position);
renderer.setSize(window.innerWidth, window.innerHeight);

let animate = () => {
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
    angle += 3
    cubeAnimate();

    camera.lookAt(cube.position);
}

let cubeAnimate = () => {
    cube.position.z = Math.sin(Math.PI / 180 * angle) * 3;
    cube.position.x = Math.cos(Math.PI / 180 * angle) * 3;
}

onMounted(() => {
    if (dom.value) {
        dom.value.appendChild(renderer.domElement);
        animate();
    }
})

</script>
  1. 屏幕自适应
js 复制代码
let setSceneAdapt = () => {
    let width = window.innerWidth, height = window.innerHeight;
    camera.aspect = width / height;
    camera.updateProjectionMatrix()
    renderer.setSize(width, height);

    renderer.setPixelRatio(window.devicePixelRatio)
}

window.addEventListener("resize", setSceneAdapt)
相关推荐
胡萝卜术2 小时前
从API调用到手写LRU:力扣146「LRU缓存」的哈希表+双向链表终极进化之路
前端·javascript·面试
科技道人2 小时前
记录 默认置灰/禁用 app ‘Search Engine Selector‘ 的disable按钮
开发语言·前端·javascript
天疆说2 小时前
Zotero Connector 在 Edge 里找不到桌面 Zotero(Linux / Zotero 9.0.6 / Edge 150)
linux·前端·edge
李伟_Li慢慢3 小时前
02-从硬件说起WebGL
前端·three.js
kyriewen4 小时前
看了微软几万人用AI编程的数据——效率涨24%的代价没人提
前端·ai编程·claude
2601_963771374 小时前
How to Scale Your WordPress Store Traffic in 2026
前端·php·plugin
亿元程序员5 小时前
老板说我的3D箭头游戏用来做试玩太普通了,没人想玩,让我变点花样...
前端
李伟_Li慢慢5 小时前
01-threejs架构原理-课程简介
前端·three.js
_瑞7 小时前
深入理解 iOS 渲染原理
前端·ios
IT_陈寒7 小时前
SpringBoot自动配置失灵?你可能忘了这个关键注解
前端·人工智能·后端