🔥 Three.js 一个项目用到:轨道控制器、动画与GUI交互

Three.js是构建Web3D内容的强大工具库。

我看评论区有小伙伴叫我搞web3,会比web3d有前途,😂,回头我看看web3的相关文档搞搞看,最近公司正好在搞web3d,正好借助掘金这个平台分享一下开发3d的一些踩坑记录。

vitethreejs写的,很简单,一个main.js够用了。先去下vitethreejs。做一个完整的Three.js应用,包含了3D场景的基本元素、交互控制和动画效果。

package.json

main.js 引用如下:

首先看效果

🔥 场景初始化与核心组件

构建Three.js应用首先需要设置三个核心要素:

javascript 复制代码
// 创建三维世界容器
const scene = new THREE.Scene();

// 配置观察视角 - 45度透视相机
const camera = new THREE.PerspectiveCamera(
  45, 
  window.innerWidth/window.innerHeight, 
  0.1, 
  1000
);

// 初始化WebGL渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

🔥 视觉辅助系统

🔥 三维坐标指引器

javascript 复制代码
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);

笛卡尔右手系(右手规则)

标识空间方向:

  • 红色箭头 → X轴(左右)
  • 绿色箭头 → Y轴(上下)
  • 蓝色箭头 → Z轴(前后)

🔥 智能视角控制器

javascript 复制代码
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;  // 启用物理阻尼
controls.dampingFactor = 0.05;  // 设置惯性系数

交互方式:

  • 左键拖动 → 环绕观察
  • 滚轮滑动 → 推拉镜头
  • 右键拖动 → 平移场景

🔥 动态动画引擎

创建弹性球体并设置运动轨迹:

javascript 复制代码
// 绿色球体初始化
const sphere = new THREE.Mesh(
  new THREE.SphereGeometry(1, 32, 32),
  new THREE.MeshBasicMaterial({ color: 0x00ff00 })
);
sphere.position.x = -4;
scene.add(sphere);

// 创建补间动画序列
const moveRight = new TWEEN.Tween(sphere.position)
  .to({ x: 4 }, 1000)
  .easing(TWEEN.Easing.Quadratic.InOut);

const moveLeft = new TWEEN.Tween(sphere.position)
  .to({ x: -4 }, 1000);

// 构建循环动画链
moveRight.chain(moveLeft);
moveLeft.chain(moveRight);
moveRight.start();

动画控制参数:

  • .to() 定义目标状态和持续时间
  • .easing() 设置运动曲线(先加速后减速)
  • .chain() 连接动画片段形成循环

🔥 可视化控制面板

集成lil-gui创建调试界面:

javascript 复制代码
const gui = new GUI();

const controlPanel = {
  暂停动画: () => moveRight.stop(),
  恢复动画: () => moveRight.start(),
  运动速度: 1.0
};

gui.add(controlPanel, '暂停动画');
gui.add(controlPanel, '恢复动画');
gui.add(controlPanel, '运动速度', 0.1, 5.0)
  .onChange(val => {
    moveRight.duration(1000/val);
    moveLeft.duration(1000/val);
  });

🔥 自适应响应机制

确保多设备兼容性:

javascript 复制代码
window.addEventListener("resize", () => {
  renderer.setSize(window.innerWidth, window.innerHeight);
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();  // 重计算透视矩阵
});

🔥 核心渲染循环

驱动整个场景运转的引擎:

javascript 复制代码
function renderScene() {
  controls.update();          // 更新控制器
  TWEEN.update();            // 推进动画
  renderer.render(scene, camera);
  requestAnimationFrame(renderScene);
}
renderScene();

整体代码

main.js

js 复制代码
// 导入threejs
import * as THREE from "three";
// 导入轨道控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
// 导入lil.gui
import { GUI } from "three/examples/jsm/libs/lil-gui.module.min.js";
// 导入hdr加载器
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";
// 导入gltf加载器
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js";
// 导入draco解码器
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader.js";
// 导入tween
import * as TWEEN from "three/examples/jsm/libs/tween.module.js";

// 创建场景
const scene = new THREE.Scene();

// 创建相机
const camera = new THREE.PerspectiveCamera(
  45, // 视角
  window.innerWidth / window.innerHeight, // 宽高比(根据窗口尺寸)
  0.1, // 近平面,近裁剪面(小于此距离的对象不显示)
  1000 // 远平面,远裁剪面(大于此距离的对象不显示)
);

// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 设置相机位置
camera.position.z = 15;
camera.position.y = 2;
camera.position.x = 2;
camera.lookAt(0, 0, 0);

// 添加世界坐标辅助器
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);

// 添加轨道控制器
const controls = new OrbitControls(camera, renderer.domElement);
// 设置带阻尼的惯性
controls.enableDamping = true;
// 设置阻尼系数
controls.dampingFactor = 0.05;
// 设置旋转速度
// controls.autoRotate = true;

// 渲染函数
function animate() {
  controls.update();
  requestAnimationFrame(animate);
  // 渲染
  renderer.render(scene, camera);
  // 更新tween
  TWEEN.update();
}
animate();

// 监听窗口变化
window.addEventListener("resize", () => {
  // 重置渲染器宽高比
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 重置相机宽高比
  camera.aspect = window.innerWidth / window.innerHeight;
  // 更新相机投影矩阵
  camera.updateProjectionMatrix();
});

// 创建GUI
const gui = new GUI();

// 创建1个球
const sphere1 = new THREE.Mesh(
  new THREE.SphereGeometry(1, 32, 32),
  new THREE.MeshBasicMaterial({
    color: 0x00ff00,
  })
);
sphere1.position.x = -4; // 初始位置:x轴-4处
scene.add(sphere1);

const tween = new TWEEN.Tween(sphere1.position);
tween.to({ x: 4 }, 1000);
tween.onUpdate(() => {
  console.log(sphere1.position.x);
});
// 设置缓动函数
tween.easing(TWEEN.Easing.Quadratic.InOut);

let tween2 = new TWEEN.Tween(sphere1.position);
tween2.to({ x: -4 }, 1000);

tween.chain(tween2);
tween2.chain(tween);
// 启动补间动画
tween.start();
tween.onStart(() => {
  console.log("开始");
});
tween.onComplete(() => {
  console.log("结束");
});
tween.onStop(() => {
  console.log("停止");
});
tween.onUpdate(() => {
  console.log("更新");
});
let params = {
  stop: function () {
    tween.stop();
  },
};

这个小球正在执行一个来回往复的水平移动动画:

起点:X轴坐标-4的位置(屏幕左侧)

向右移动:用1秒时间平滑移动到X轴+4的位置(屏幕右侧)

向左返回:再用1秒时间平滑返回起点X轴-4的位置

循环往复:上述过程会无限循环

分别用了:

Three.js:负责3D渲染和场景管理

Tween.js:处理复杂动画和过渡效果

lil-gui:提供调试和控制界面

相关推荐
GIS之路9 小时前
GDAL 实现矢量裁剪
前端·python·信息可视化
是一个Bug9 小时前
后端开发者视角的前端开发面试题清单(50道)
前端
Amumu121389 小时前
React面向组件编程
开发语言·前端·javascript
持续升级打怪中9 小时前
Vue3 中虚拟滚动与分页加载的实现原理与实践
前端·性能优化
GIS之路9 小时前
GDAL 实现矢量合并
前端
hxjhnct9 小时前
React useContext的缺陷
前端·react.js·前端框架
前端 贾公子10 小时前
从入门到实践:前端 Monorepo 工程化实战(4)
前端
菩提小狗10 小时前
Sqlmap双击运行脚本,双击直接打开。
前端·笔记·安全·web安全
前端工作日常10 小时前
我学习到的AG-UI的概念
前端
韩师傅10 小时前
前端开发消亡史:AI也无法掩盖没有设计创造力的真相
前端·人工智能·后端