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 小时前
基于HTML的悬窗可拖动记事本
前端·css·html
祝余呀2 小时前
html初学者第一天
前端·html
耶啵奶膘5 小时前
uniapp+firstUI——上传视频组件fui-upload-video
前端·javascript·uni-app
视频砖家5 小时前
移动端Html5播放器按钮变小的问题解决方法
前端·javascript·viewport功能
lyj1689976 小时前
vue-i18n+vscode+vue 多语言使用
前端·vue.js·vscode
小白变怪兽7 小时前
一、react18+项目初始化(vite)
前端·react.js
ai小鬼头7 小时前
AIStarter如何快速部署Stable Diffusion?**新手也能轻松上手的AI绘图
前端·后端·github
墨菲安全8 小时前
NPM组件 betsson 等窃取主机敏感信息
前端·npm·node.js·软件供应链安全·主机信息窃取·npm组件投毒
GISer_Jing8 小时前
Monorepo+Pnpm+Turborepo
前端·javascript·ecmascript
天涯学馆8 小时前
前端开发也能用 WebAssembly?这些场景超实用!
前端·javascript·面试