案例展示
创建一个透视相机,表单实时修改相机参数(FOV、位置、近/远裁面)。
<template>
<div style="position: relative">
<div id="TO"></div>
<el-form id="formCamera" label-width="80px">
<el-form-item label="视角FOV:">
<div style="display: flex; align-items: center; width: 100%">
<el-slider
v-model="fov"
:min="10"
:max="120"
:step="1"
style="flex: 1; margin-right: 5px" />
<span class="pos-value">{{ fov }}°</span>
</div>
</el-form-item>
<el-form-item label="位置X:">
<div style="display: flex; align-items: center; width: 100%">
<el-slider
v-model="posX"
:min="-400"
:max="400"
:step="1"
style="flex: 1; margin-right: 5px" />
<span class="pos-value">{{ posX }}</span>
</div>
</el-form-item>
<el-form-item label="位置Y:">
<div style="display: flex; align-items: center; width: 100%">
<el-slider
v-model="posY"
:min="0"
:max="400"
:step="1"
style="flex: 1; margin-right: 5px" />
<span class="pos-value">{{ posY }}</span>
</div>
</el-form-item>
<el-form-item label="位置Z:">
<div style="display: flex; align-items: center; width: 100%">
<el-slider
v-model="posZ"
:min="-400"
:max="600"
:step="1"
style="flex: 1; margin-right: 5px" />
<span class="pos-value">{{ posZ }}</span>
</div>
</el-form-item>
<el-form-item label="近裁面:">
<div style="display: flex; align-items: center; width: 100%">
<el-slider
v-model="near"
:min="0.1"
:max="50"
:step="0.1"
style="flex: 1; margin-right: 5px" />
<span class="pos-value">{{ near }}</span>
</div>
</el-form-item>
<el-form-item label="远裁面:">
<div style="display: flex; align-items: center; width: 100%">
<el-slider
v-model="far"
:min="100"
:max="10000"
:step="100"
style="flex: 1; margin-right: 5px" />
<span class="pos-value">{{ far }}</span>
</div>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="applyCamera()" size="small">应用</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { ElForm, ElFormItem, ElSlider, ElButton } from 'element-plus'
let TO = null
// 相机可调参数
const fov = ref(45)
const posX = ref(0)
const posY = ref(50)
const posZ = ref(200)
const near = ref(0.1)
const far = ref(5000)
onMounted(() => {
// 初始化场景:创建一个透视相机,关闭轨道控制
TO = new ThingOrigin('cameraScene', document.getElementById('TO'), {
scene: {
background: {
type: 'color',
color: { alpha: 1, color: '#fefefe' }
}
},
camera: {
position: { x: posX.value, y: posY.value, z: posZ.value }
},
controls: {
orbit: { active: false }
},
lights: [
{ name: 'ambient', type: 'AmbientLight', color: '#ffffff', intensity: 0.7, visible: true },
{
name: 'dir',
type: 'DirectionalLight',
color: '#ffffff',
intensity: 0.6,
visible: true,
position: { x: 10, y: 20, z: 10 }
}
],
helper: {
axes: { active: true },
grid: { active: true, size: 400, divisions: 20 }
}
})
// 放置几个方块作为相机观察对象,便于看出 FOV / 位置 / 裁面变化
const cubes = [
{ x: -60, z: 0, color: '#36CFC9' },
{ x: 0, z: -60, color: '#FFC53D' },
{ x: 60, z: 0, color: '#F759AB' },
{ x: 0, z: 60, color: '#5CDBD3' }
]
cubes.forEach((c) => {
const cube = TO.model.initCube({
position: { x: c.x, y: 10, z: c.z },
material: { color: c.color }
})
TO.scene.add(cube)
})
// 首次应用一次,确保相机参数与表单一致
applyCamera()
})
// 应用相机参数到透视相机
function applyCamera() {
const cam = TO.camera.PerspectiveCamera || TO.camera.camera
cam.fov = fov.value
cam.near = near.value
cam.far = far.value
cam.position.set(posX.value, posY.value, posZ.value)
cam.lookAt(0, 0, 0)
cam.updateProjectionMatrix()
}
</script>
<style scoped>
#TO {
width: 100%;
height: 400px;
position: relative;
}
#formCamera {
position: absolute;
top: 10px;
right: 10px;
min-width: 280px;
box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.1);
z-index: 1000;
background: rgba(0, 0, 0, 0.6);
color: #fff;
padding: 12px 16px;
border-radius: 4px;
font-size: 12px;
}
.pos-value {
min-width: 50px;
text-align: right;
font-size: 12px;
color: #fff;
}
#formCamera :deep(.el-form-item__label) {
color: #fff;
font-size: 12px;
}
</style>API 介绍
相机配置(建景参数)
建景时通过 camera 配置创建相机:
js
new ThingOrigin('scene', container, {
camera: {
position: { x: 0, y: 50, z: 200 }, // 相机位置
lookAt: { x: 0, y: 0, z: 0 } // 相机朝向(默认 0,0,0)
// perspective: { fov: 45, near: 0.1, far: 5000 } // 透视参数,可覆盖
}
})| 参数名 | 说明 | 类型 | 必填 | 默认值 |
|---|---|---|---|---|
position | 相机位置 | { x, y, z } | 否 | { x:0, y:2, z:20 } |
lookAt | 相机朝向 | { x, y, z } | 否 | { x:0, y:0, z:0 } |
perspective.fov | 视野角度(度) | number | 否 | 45 |
perspective.near | 近裁面距离 | number | 否 | 0.1 |
perspective.far | 远裁面距离 | number | 否 | 5000 |
运行时修改相机
引擎默认相机为 PerspectiveCamera,可通过 TO.camera.PerspectiveCamera(或 TO.camera.camera)拿到实例,直 接改属性后调用 updateProjectionMatrix() 生效:
js
const cam = TO.camera.PerspectiveCamera
cam.fov = 60
cam.near = 1
cam.far = 8000
cam.position.set(0, 50, 200)
cam.lookAt(0, 0, 0)
cam.updateProjectionMatrix()修改
fov/near/far后必须调用updateProjectionMatrix()重新计算投影矩阵,否则画面不会更新。若启用 了 OrbitControls,其每帧update()会按内部球坐标覆盖相机位置;本案例关闭了轨道控制,相机完全由表单参数控制 。