Skip to content

案例展示

创建一个透视相机,表单实时修改相机参数(FOV、位置、近/远裁面)。

视角FOV:
45°
位置X:
0
位置Y:
50
位置Z:
200
近裁面:
0.1
远裁面:
5000
<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视野角度(度)number45
perspective.near近裁面距离number0.1
perspective.far远裁面距离number5000

运行时修改相机

引擎默认相机为 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() 会按内部球坐标覆盖相机位置;本案例关闭了轨道控制,相机完全由表单参数控制 。