此篇将threeJs相机的使用做一下记录,简单的封装为vue组件,以备参考。
之后慢慢完善此文。
一、立方相机cubeCamera
cubeCamera,构造一个包含6个PerspectiveCameras(透视摄像机)的立方摄像机,并将其拍摄的场景渲染到一个WebGLCubeRenderTarget上,生成目标纹理(WebGLCubeRenderTarget.texture)。
render target是一个缓存,缓存显卡为正在后台渲染的场景绘制的像素。被用于不同的效果,例如用在一个图像渲染到屏幕上之前先做一些后期处理。
此处,将WebGLCubeRenderTarget.texture作为某个具有envMap属性材质的模型的环境贴图,即此模型反射的环境图案。
CubeCamera.vue
<template>
<div>
<div id="canvasContainer" style="width: 900px; height: 800px"></div>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
let scene, camera, renderer, width, height, controls
onMounted(() => {
init()
})
function init() {
const canvasContainer = document.querySelector('#canvasContainer')
width = canvasContainer.clientWidth
height = canvasContainer.clientHeight
// 1、创建场景
scene = new THREE.Scene()
// 2、创建渲染器
renderer = new THREE.WebGLRenderer()
// renderer.setClearColor('#FFFFFF') // 设置渲染器的背景色
renderer.setClearColor('#88b4e1')
renderer.setSize(width, height) // 设置渲染区域尺寸
canvasContainer.appendChild(renderer.domElement) // 将渲染器创建的canvas元素添加到容器元素
// 3、创建透视相机,用于拍摄主场景
camera = new THREE.PerspectiveCamera(fov, width / height, 0.1, 1000)
camera.position.set(100, 50, 200) // 设置相机位置
camera.lookAt(scene.position) // 设置相机方向(指向的场景对象)
// 4、创建立方相机
cubeCamera() // 为具有镜面反射效果的模型A拍摄反射的图形,然后作为A的环境贴图
// 要先创建renderer, 因为cubeCamera.update(renderer, scene)
// 5、其他
pointLight() // 点灯光
initControls() // 用鼠标控制透视相机的拍摄角度
axisHelper() // 坐标辅助器
animate()
}
// 循环动画渲染
function animate() {
requestAnimationFrame(animate)
renderer.render(scene, camera)
}
// 轨道控制器,使得相机围绕目标进行轨道运动
function initControls() {
controls = new OrbitControls(camera, renderer.domElement)
}
// 辅助三维坐标系
function axisHelper() {
const axis = new THREE.AxesHelper(250)
scene.add(axis)
}
// 创建一个虚拟的球形网格Mesh的辅助对象来模拟点光源PointLight
function pointLight() {
const pointLight = new THREE.PointLight(0xffffff, 1, 1000)
pointLight.position.set(100, 150, 100) //点光源位置
scene.add(pointLight)
// 创建点光源辅助对象模拟点光源
const pointLightHelper = new THREE.PointLightHelper(pointLight, 1)
scene.add(pointLightHelper)
}
let sphere, box
// 创建立方相机
function cubeCamera() {
// 创建cube相机的渲染目标
const cubeRenderTarget = new THREE.WebGLCubeRenderTarget(128, {
format: THREE.RGBAFormat,
generateMipmaps: true,
minFilter: THREE.LinearMipmapLinearFilter
});
// 创建cube相机
const cubeCamera = new THREE.CubeCamera(1, 100000, cubeRenderTarget)
scene.add(cubeCamera)
// 创建具能反射环境的模型
const sphereGeometry = new THREE.SphereGeometry(50)
const sphereMaterial = new THREE.MeshPhongMaterial({
color: 0xff0000,
envMap: cubeRenderTarget.texture
});
sphere = new THREE.Mesh(sphereGeometry, sphereMaterial)
sphere.position.set(80, -50, 0)
scene.add(sphere)
// 创建被反射的模型
const boxGeometry = new THREE.BoxGeometry(20, 20, 20)
const boxMaterial = new THREE.MeshPhongMaterial({
color: 0x00ff00
})
box = new THREE.Mesh(boxGeometry, boxMaterial)
box.position.set(80, 100, 0)
scene.add(box)
// 更新渲染目标对象
sphere.visible = false
cubeCamera.position.copy(sphere.position)
cubeCamera.update(renderer, scene)
// 可以渲染场景了
sphere.visible = true
}
</script>
注意:光源与两个模型的位置关系
效果图:
二、阵列相机
1. ArrayCamera.vue
<template>
<div>
<h1>阵列相机(ArrayCamera)</h1>
<div id="canvasContainer" style="width: 900px; height: 800px"></div>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { usePerspectiveCamera, useArrayCamera } from '@/composables/threejs/camera'
let scene, camera, renderer, width, height, mesh, controls
onMounted(() => {
init()
})
function init() {
const canvasContainer = document.querySelector('#canvasContainer')
width = canvasContainer.clientWidth
height = canvasContainer.clientHeight
// 1、创建场景
scene = new THREE.Scene()
// 2、创建渲染器
renderer = new THREE.WebGLRenderer()
// renderer.setClearColor('#FFFFFF') // 设置渲染器的背景色
renderer.setClearColor('#88b4e1')
renderer.setSize(width, height) // 设置渲染区域尺寸
// 将渲染器创建的canvas元素添加容器元素
canvasContainer.appendChild(renderer.domElement)
// 3、创建相机
camera = arrayCamera()
// 4、其他
pointLight()
initControls()
axisHelper()
boxGeo()
animate()
}
function arrayCamera() {
const camera1 = usePerspectiveCamera(width, height, { x: -100, y: 0, z: 0 }, scene.position)
const camera2 = usePerspectiveCamera(width, height, { x: 100, y: 0, z: 0 }, scene.position)
const camera3 = usePerspectiveCamera(width, height, { x: 0, y: 100, z: 0 }, scene.position)
const cameras = [camera1, camera2, camera3]
const camera = useArrayCamera(cameras, width, height, 2)
return camera
}
// 循环动画渲
function animate() {
requestAnimationFrame(animate)
mesh.rotateY(0.01)
renderer.render(scene, camera)
}
// 轨道控制器,使得相机围绕目标进行轨道运动
function initControls() {
controls = new OrbitControls(camera, renderer.domElement)
}
// 辅助三维坐标系
function axisHelper() {
const axis = new THREE.AxesHelper(250)
scene.add(axis)
}
// 创建一个虚拟的球形网格Mesh的辅助对象来模拟点光源PointLight
function pointLight() {
const pointLight = new THREE.PointLight(0xffffff, 1, 1000)
pointLight.position.set(100, 150, 100) //点光源位置
scene.add(pointLight)
// 创建点光源辅助对象模拟点光源
const pointLightHelper = new THREE.PointLightHelper(pointLight, 1)
scene.add(pointLightHelper)
}
// 创建立方体
// 几何体默认位于场景世界坐标的原点(0, 0, 0)
function boxGeo() {
// const geometry = new THREE.BoxGeometry(50, 100, 20)
// const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 })
// mesh = new THREE.Mesh(geometry, material)
var geometry = new THREE.BoxGeometry(20, 20, 20)
var material = new THREE.MeshLambertMaterial({
color: 0x0000ff
})
mesh = new THREE.Mesh(geometry, material)
// 将物体和灯光添加到场景里
scene.add(mesh)
}
</script>
2. @/composables/threejs/camera.js
import * as THREE from 'three'
// 创建透视相机
function usePerspectiveCamera(width, height, position = { x: 0, y: 0, z: 0 }, lookPos = { x: 0, y: 0, z: 0 }, fov = 75, near = 0.1, far = 1000) {
const camera = new THREE.PerspectiveCamera(fov, width / height, 0.1, 1000)
camera.position.set(position.x, position.y, position.z) // 设置相机位置
camera.lookAt(lookPos.x, lookPos.y, lookPos.z) // 设置相机方向(指向的场景对象)
return camera
}
// 2. 创建摄像机阵列
// 画布的width, height
function useArrayCamera(cameras, width, height, colNum) {
const rowNum = Math.ceil(cameras.length / colNum)
const cameraArrs = []
for(let i = 0; i < rowNum; i++) {
const cameraItem = cameras.slice(i * colNum, (i + 1) * colNum)
cameraArrs.push(cameraItem)
}
for(const [rowIndex, rowCameras] of cameraArrs.entries()) {
for(const [colIndex, camera] of rowCameras.entries()) {
const colWidth = width / colNum
const rowHeight = height / rowNum
const x = colIndex * colWidth
const y = rowIndex * rowHeight
camera.viewport = new THREE.Vector4(x, y, colWidth, rowHeight) // x, y, width, height 根据每行每列相机数决定
camera.updateMatrixWorld() // 更新物体及其后代的全局变换。
}
}
const arrayCamera = new THREE.ArrayCamera(cameras)
return arrayCamera
}
export {
usePerspectiveCamera,
useArrayCamera
}
效果图:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。