Three.js Theatrejs教程
2026/6/27 23:34:45 网站建设 项目流程

Theatrejs ·Theatre.js· ▶ 在线运行案例

  • 案例合集:三维可视化功能案例(threehub.cn)
  • 开源仓库github地址:https://github.com/z2586300277/three-cesium-examples
  • 400个案例代码:网盘链接

你将学到什么

  • OrbitControls 相机轨道交互
  • requestAnimationFrame渲染循环与resize自适应

效果说明

本案例演示Theatrejs效果:基于 WebGL 实现「Theatrejs」可视化效果,附完整可运行源码;核心用到 OrbitControls。建议先打开文首在线案例查看动态画面,再对照下方源码逐步理解。

核心概念

  • Scene / Camera / WebGLRenderer构成最小渲染闭环;大场景可开logarithmicDepthBuffer缓解 Z-fighting。
  • OrbitControls提供轨道旋转/缩放;开启enableDamping后需在 animate 中controls.update()
  • 阅读下方完整源码时,建议从init/load/animate三条主线入手,再深入 shader 与工具函数。

实现步骤

  • 搭建灯光与环境(如有)
  • requestAnimationFrame 循环 update + render
  • 代码要点

    import * as THREE from 'three'

    import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js' import theatrecore from '@theatre/core' import theatrestudio from '@theatre/studio'

    const core = theatrecore.default || theatrecore const studio = theatrestudio.default || theatrestudio const { getProject, types } = core

    const box = document.getElementById('box')

    const scene = new THREE.Scene()

    const camera = new THREE.PerspectiveCamera(75, box.clientWidth / box.clientHeight, 0.1, 100000)

    camera.position.set(30, 25, 30)

    const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true, logarithmicDepthBuffer: true })

    renderer.setSize(box.clientWidth, box.clientHeight)

    renderer.shadowMap.enabled = true

    box.appendChild(renderer.domElement)

    new OrbitControls(camera, renderer.domElement)

    // 灯光 const ambientLight = new THREE.AmbientLight(0xffffff, 0.5)

    const directionalLight = new THREE.DirectionalLight(0xffffff, 1)

    directionalLight.position.set(20, 40, 20)

    directionalLight.castShadow = true

    scene.add(ambientLight, directionalLight)

    // 地面 const ground = new THREE.Mesh( new THREE.PlaneGeometry(80, 80), new THREE.MeshStandardMaterial({ color: 0x333333 }) )

    ground.rotation.x = -Math.PI / 2

    ground.receiveShadow = true

    scene.add(ground, new THREE.GridHelper(80, 16, 0x555555, 0x444444))

    /===================== 创建动画物体 =====================/

    // 1. 立方体 const cube = new THREE.Mesh( new THREE.BoxGeometry(4, 4, 4), new THREE.MeshStandardMaterial({ color: 0x049ef4 }) )

    cube.position.set(-12, 2, 0)

    cube.castShadow = true

    scene.add(cube)

    // 2. 球体 const sphere = new THREE.Mesh( new THREE.SphereGeometry(2.5, 32, 32), new THREE.MeshStandardMaterial({ color: 0xe91e63 }) )

    sphere.position.set(0, 2.5, 0)

    sphere.castShadow = true

    scene.add(sphere)

    // 3. 圆环 const torus = new THREE.Mesh( new THREE.TorusGeometry(2.5, 0.8, 16, 50), new THREE.MeshStandardMaterial({ color: 0x4caf50 }) )

    torus.position.set(12, 3, 0)

    torus.castShadow = true

    scene.add(torus)

    /===================== Theatre.js 初始化 =====================/

    // 初始化 Studio UI(编辑器面板) studio.initialize()

    // 自定义 Studio 面板样式 —— 通过 CSS 覆盖 #theatrejs-studio-root const studioStyle = document.createElement('style') studioStyle.textContent =/Studio 面板根容器/ #theatrejs-studio-root { opacity: 0.92; /面板透明度/ /transform: scale(0.9); /整体缩放 */ /top: 0 !important; /移到顶部 */ /bottom: auto !important; /取消底部定位 */ }document.head.appendChild(studioStyle)

    // 创建项目 —— 一个项目对应一个动画场景 const project = getProject('ThreeJS Tutorial')

    // 创建 Sheet —— 一个 Sheet 是一条独立的时间轴 const sheet = project.sheet('Animation Sheet')

    /===================== 为物体创建 Theatre.js 对象 =====================/

    // ---- 立方体动画对象 ---- const cubeObj = sheet.object('Cube', { // 位置 (使用 types.compound 组合为一组) position: types.compound({ x: types.number(cube.position.x, { range: [-30, 30] }), y: types.number(cube.position.y, { range: [0, 30] }), z: types.number(cube.position.z, { range: [-30, 30] }) }), // 旋转 rotation: types.compound({ x: types.number(0, { range: [-Math.PI, Math.PI] }), y: types.number(0, { range: [-Math.PI, Math.PI] }), z: types.number(0, { range: [-Math.PI, Math.PI] }) }), // 缩放 (统一缩放) scale: types.number(1, { range: [0.1, 3] }), // 颜色 (使用 Theatre.js 的 rgba 类型) color: types.rgba({ r: 0.016, g: 0.624, b: 0.957, a: 1 }) })

    // 监听值变化并同步到 Three.js 物体 cubeObj.onValuesChange((values) => { const { position, rotation, scale, color } = values cube.position.set(position.x, position.y, position.z) cube.rotation.set(rotation.x, rotation.y, rotation.z) cube.scale.setScalar(scale) cube.material.color.setRGB(color.r, color.g, color.b) cube.material.opacity = color.a })

    // ---- 球体动画对象 ---- const sphereObj = sheet.object('Sphere', { position: types.compound({ x: types.number(sphere.position.x, { range: [-30, 30] }), y: types.number(sphere.position.y, { range: [0, 30] }), z: types.number(sphere.position.z, { range: [-30, 30] }) }), scale: types.number(1, { range: [0.1, 3] }), color: types.rgba({ r: 0.914, g: 0.118, b: 0.388, a: 1 }) })

    sphereObj.onValuesChange((values) => { const { position, scale, color } = values sphere.position.set(position.x, position.y, position.z) sphere.scale.setScalar(scale) sphere.material.color.setRGB(color.r, color.g, color.b) })

    // ---- 圆环动画对象 ---- const torusObj = sheet.object('Torus', { position: types.compound({ x: types.number(torus.position.x, { range: [-30, 30] }), y: types.number(torus.position.y, { range: [0, 30] }), z: types.number(torus.position.z, { range: [-30, 30] }) }), rotation: types.compound({ x: types.number(0, { range: [-Math.PI2, Math.PI2] }), y: types.number(0, { range: [-Math.PI2, Math.PI2] }) }), scale: types.number(1, { range: [0.1, 3] }), color: types.rgba({ r: 0.298, g: 0.686, b: 0.314, a: 1 }) })

    torusObj.onValuesChange((values) => { const { position, rotation, scale, color } = values torus.position.set(position.x, position.y, position.z) torus.rotation.set(rotation.x, rotation.y, 0) torus.scale.setScalar(scale) torus.material.color.setRGB(color.r, color.g, color.b) })

    /===================== 灯光也可以用 Theatre.js 控制 =====================/

    const lightObj = sheet.object('Light', { position: types.compound({ x: types.number(20, { range: [-50, 50] }), y: types.number(40, { range: [0, 80] }), z: types.number(20, { range: [-50, 50] }) }), intensity: types.number(1, { range: [0, 3] }) })

    lightObj.onValuesChange((values) => { directionalLight.position.set(values.position.x, values.position.y, values.position.z) directionalLight.intensity = values.intensity })

    /===================== 播放控制按钮 =====================/

    const btnContainer = document.createElement('div')

    Object.assign(btnContainer.style, { position: 'fixed', bottom: '120px', left: '50%', transform: 'translateX(-50%)', display: 'flex', gap: '10px', zIndex: '9999' })

    const createBtn = (text, onClick) => { const btn = document.createElement('button') btn.textContent = text Object.assign(btn.style, { padding: '8px 18px', border: 'none', borderRadius: '6px', cursor: 'pointer', background: '#049ef4', color: '#fff', fontSize: '14px', fontWeight: 'bold' }) btn.addEventListener('click', onClick) btnContainer.appendChild(btn) return btn }

    // 播放动画 (从头到第 6 秒, 无限循环) createBtn('▶ 播放', () => { sheet.sequence.play({ iterationCount: Infinity, range: [0, 6] }) })

    // 暂停 createBtn('⏸ 暂停', () => { sheet.sequence.pause() })

    // 跳转到指定时间 createBtn('⏩ 跳到 3s', () => { sheet.sequence.position = 3 })

    // 单次播放 createBtn('▶ 单次播放', () => { sheet.sequence.play({ iterationCount: 1, range: [0, 6] }) })

    box.appendChild(btnContainer)

    /===================== 使用说明 =====================/

    const info = document.createElement('div')

    Object.assign(info.style, { position: 'fixed', bottom: '10px', left: '10px', zIndex: '0', background: 'rgba(0,0,0,0.75)', color: '#fff', padding: '16px 20px', borderRadius: '10px', fontSize: '13px', lineHeight: '1.8', maxWidth: '340px', pointerEvents: 'none' })

    info.innerHTML =

    🎬 Theatre.js 教程
    核心概念:
    Project— 一个动画场景项目
    Sheet— 一条独立时间轴
    Object— 可动画化的属性组
    Sequence— 时间轴上的动画序列

    使用步骤:
    1. 点击底部面板中的物体名称
    2. 右键属性 → "Sequence" 添加到时间轴
    3. 在时间轴上添加关键帧
    4. 拖动关键帧调整数值和时间
    5. 点击播放按钮预览动画

    box.appendChild(info)

    /===================== 渲染循环 =====================/

    animate()

    function animate() {

    requestAnimationFrame(animate)

    renderer.render(scene, camera)

    }

    window.onresize = () => {

    renderer.setSize(box.clientWidth, box.clientHeight)

    camera.aspect = box.clientWidth / box.clientHeight

    camera.updateProjectionMatrix()

    }

    完整源码:GitHub

    小结

    • 本文提供Theatrejs完整 Three.js 源码与在线 Demo,建议先运行案例再改 uniform/参数做二次实验
    • 更多 Three.js 实战案例见 three-cesium-examples 合集 与 GitHub 开源仓库

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询