我本是写react的,公司让我换赛道搞web3D

当你在会议室里争论需求时,
智慧工厂的数字孪生正同步着每一条产线的脉搏;
当你对着平面图想象空间时,
智慧小区的三维模型已在虚拟世界精准复刻每一扇窗的采光。
当你在CAD里调整参数时,

数字孪生城市的交通流正实时映射每辆车的轨迹;

当你等待客户确认方案时,

机械臂的3D仿真已预演了十万次零误差的运动路径;
当你用二维图纸解释传动原理时,

可交互的3D引擎正让客户'拆解'每一个齿轮;

当你担心售后维修难描述时,

AR里的动态指引已覆盖所有故障点;
当你用PS拼贴效果图时,

VR漫游的业主正'推开'你设计的每一扇门;

当你纠结墙面材质时,

光影引擎已算出了午后3点最温柔的折射角度;

从前端到Web3D,
不是换条赛道,
而是打开新维度。

韩老师说过:再牛的程序员都是从小白开始,既然开始了,就全心投入学好技术。

🔴 工具

所有的api都可以通过threejs官网的document,切成中文,去搜:

🔴 平面

⭕️ Scene 场景

场景能够让你在什么地方、摆放什么东西来交给three.js来渲染,这是你放置物体、灯光和摄像机的地方。

js 复制代码
import * as THREE from "three";

// console.log(THREE);

// 目标:了解three.js最基本的内容

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

⭕️ camera 相机

示例:threejs.org/examples/?q...

js 复制代码
import * as THREE from "three";

// console.log(THREE);

// 目标:了解three.js最基本的内容

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

// 2、创建相机
const camera = new THREE.PerspectiveCamera(
  75, // 相机的角度
  window.innerWidth / window.innerHeight, // 相机的宽高比
  0.1, // 相机的近截面
  1000 // 相机的远截面
);

// 设置相机位置
camera.position.set(0, 0, 10); // 相机位置 (X轴坐标, Y轴坐标, Z轴坐标)
scene.add(camera); // 相机添加到场景中

⭕️ 物体 cube

js 复制代码
import * as THREE from "three";

// console.log(THREE);

// 目标:了解three.js最基本的内容

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

// 2、创建相机
const camera = new THREE.PerspectiveCamera(
  75, // 相机的角度
  window.innerWidth / window.innerHeight, // 相机的宽高比
  0.1, // 相机的近截面
  1000 // 相机的远截面
);

// 设置相机位置
camera.position.set(0, 0, 10); // 相机位置 (X轴坐标, Y轴坐标, Z轴坐标)
scene.add(camera); // 相机添加到场景中

// 添加物体
// 创建几何体
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1); // 创建立方体的几何体 (长, 宽, 高)
const cubeMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 }); // MeshBasicMaterial 基础网格材质 ({ color: 0xffff00 }) 颜色
// 根据几何体和材质创建物体
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial); // 创建立方体的物体 (几何体, 材质)
// 将几何体添加到场景中
scene.add(cube); // 物体添加到场景中

⭕️ 渲染 render

js 复制代码
// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight); // 设置渲染的尺寸大小 (窗口宽度, 窗口高度)
// console.log(renderer);
// 将webgl渲染的canvas内容添加到body
document.body.appendChild(renderer.domElement); // 将webgl渲染的canvas内容添加到body

// 使用渲染器,通过相机将场景渲染进来
renderer.render(scene, camera); // 使用渲染器,通过相机将场景渲染进来 (场景, 相机)

⭕️ 效果

效果是平面的:

到这里,还不是3d的,如果要加3d,要加一下控制器。

🔴 3d

⭕️ 控制器

添加轨道。像卫星☄围绕地球🌏,环绕查看的视角:

js 复制代码
// 导入轨道控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";

// 目标:使用控制器查看3d物体

// // 使用渲染器,通过相机将场景渲染进来
// renderer.render(scene, camera);

// 创建轨道控制器
const controls = new OrbitControls(camera, renderer.domElement); // 创建轨道控制器 (相机, 渲染器dom元素)
controls.enableDamping = true; // 设置控制器阻尼,让控制器更有真实效果。

function render() {
  renderer.render(scene, camera); // 浏览器每渲染一帧,就重新渲染一次
  //   渲染下一帧的时候就会调用render函数
  requestAnimationFrame(render); // 浏览器渲染下一帧的时候就会执行render函数,执行完会再次调用render函数,形成循环,每秒60次
}

render();

⭕️ 加坐标轴辅助器

js 复制代码
// 添加坐标轴辅助器
const axesHelper = new THREE.AxesHelper(5); // 坐标轴(size轴的大小)
scene.add(axesHelper);

⭕️ 设置物体移动

js 复制代码
// 设置相机位置
camera.position.set(0, 0, 10);
scene.add(camera);
js 复制代码
cube.position.x = 3;
js 复制代码
// 往返移动
function render() {
  cube.position.x += 0.01;
  if (cube.position.x > 5) {
    cube.position.x = 0;
  }
  renderer.render(scene, camera);
  //   渲染下一帧的时候就会调用render函数
  requestAnimationFrame(render);
}

render();

⭕️ 缩放

js 复制代码
cube.scale.set(3, 2, 1); // xyz, x3倍, y2倍

单独设置

js 复制代码
cube.position.x = 3;

⭕️ 旋转

js 复制代码
cube.rotation.set(Math.PI / 4, 0, 0, "XZY"); // x轴旋转45度

单独设置

js 复制代码
cube.rotation.x = Math.PI / 4;

⭕️ requestAnimationFrame

js 复制代码
function render(time) {
  //   console.log(time);
  //   cube.position.x += 0.01;
  //   cube.rotation.x += 0.01;
  
  // time 是一个不断递增的数字,代表当前的时间
  let t = (time / 1000) % 5; // 为什么求余数,物体移动的距离就是t,物体移动的距离是0-5,所以求余数
  cube.position.x = t * 1; // 0-5秒,物体移动0-5距离
  
  //   if (cube.position.x > 5) {
  //     cube.position.x = 0;
  //   }
  renderer.render(scene, camera);
  //   渲染下一帧的时候就会调用render函数
  requestAnimationFrame(render);
}

render();

⭕️ Clock 跟踪事件处理动画

js 复制代码
// 设置时钟
const clock = new THREE.Clock();
function render() {
  // 获取时钟运行的总时长
  let time = clock.getElapsedTime();
  console.log("时钟运行总时长:", time);
  //   let deltaTime = clock.getDelta();
  //     console.log("两次获取时间的间隔时间:", deltaTime);
  let t = time % 5;
  cube.position.x = t * 1;

  renderer.render(scene, camera);
  //   渲染下一帧的时候就会调用render函数
  requestAnimationFrame(render);
}

render();

大概是8毫秒一次渲染时间.

⭕️ 不用算 用 Gsap动画库

gsap.com/

js 复制代码
// 导入动画库
import gsap from "gsap";

// 设置动画
var animate1 = gsap.to(cube.position, {
  x: 5,
  duration: 5,
  ease: "power1.inOut", // 动画属性
  //   设置重复的次数,无限次循环-1
  repeat: -1,
  //   往返运动
  yoyo: true,
  //   delay,延迟2秒运动
  delay: 2,
  onComplete: () => {
    console.log("动画完成");
  },
  onStart: () => {
    console.log("动画开始");
  },
});
gsap.to(cube.rotation, { x: 2 * Math.PI, duration: 5, ease: "power1.inOut" });

// 双击停止和恢复运动
window.addEventListener("dblclick", () => {
  //   console.log(animate1);
  if (animate1.isActive()) {
    //   暂停
    animate1.pause();
  } else {
    //   恢复
    animate1.resume();
  }
});

function render() {
  renderer.render(scene, camera);
  //   渲染下一帧的时候就会调用render函数
  requestAnimationFrame(render);
}

render();

⭕️ 根据尺寸变化 实现自适应

js 复制代码
// 监听画面变化,更新渲染画面
window.addEventListener("resize", () => {
  //   console.log("画面变化了");
  // 更新摄像头
  camera.aspect = window.innerWidth / window.innerHeight;
  //   更新摄像机的投影矩阵
  camera.updateProjectionMatrix();

  //   更新渲染器
  renderer.setSize(window.innerWidth, window.innerHeight);
  //   设置渲染器的像素比
  renderer.setPixelRatio(window.devicePixelRatio);
});

⭕️ 用js控制画布 全屏 和 退出全屏

js 复制代码
window.addEventListener("dblclick", () => {
  const fullScreenElement = document.fullscreenElement;
  if (!fullScreenElement) {
    //   双击控制屏幕进入全屏,退出全屏
    // 让画布对象全屏
    renderer.domElement.requestFullscreen();
  } else {
    //   退出全屏,使用document对象
    document.exitFullscreen();
  }
  //   console.log(fullScreenElement);
});

⭕️ 应用 图形 用户界面 更改变量

js 复制代码
// 导入dat.gui
import * as dat from "dat.gui";

const gui = new dat.GUI();
gui
  .add(cube.position, "x")
  .min(0)
  .max(5)
  .step(0.01)
  .name("移动x轴")
  .onChange((value) => {
    console.log("值被修改:", value);
  })
  .onFinishChange((value) => {
    console.log("完全停下来:", value);
  });
js 复制代码
//   修改物体的颜色
const params = {
  color: "#ffff00",
  fn: () => {
    //   让立方体运动起来
    gsap.to(cube.position, { x: 5, duration: 2, yoyo: true, repeat: -1 });
  },
};
gui.addColor(params, "color").onChange((value) => {
  console.log("值被修改:", value);
  cube.material.color.set(value);
});
// 设置选项框
gui.add(cube, "visible").name("是否显示");

var folder = gui.addFolder("设置立方体");
folder.add(cube.material, "wireframe");
// 设置按钮点击触发某个事件
folder.add(params, "fn").name("立方体运动");

🔴 结语

前端的世界,
不该只有Vue和React------
还有WebGPU里等待你征服的星辰大海。"

"当WebGL成为下一代前端的基础设施,愿你是最早站在三维坐标系里的那个人。"

相关推荐
定栓24 分钟前
Webpack迁到Vite第一节:模块系统迁移:require → import
运维·前端·webpack
小熊在忙fpga33 分钟前
N32G430芯片的flash表示
前端·javascript·html
Data analyse45639 分钟前
App埋点版本兼容的字段迁移校验
大数据·运维·服务器·前端·数据库·数据分析
todoitbo1 小时前
本来只想给内网开个口子,Natapp 却多给了一道防护
前端·javascript·vue.js·内网穿透·网络防护·natapp
会灭火的程序员1 小时前
SuperMap AgentX Server智能体接入WEB应用技术文档
前端·supermap·agentx·agentx server
CRMEB1 小时前
商品 SKU 设计,从简单规格到多规格踩过什么
java·前端·数据库·开源
Chloe.Zz1 小时前
一篇入门Agent
开发语言·前端·javascript
java1234_小锋1 小时前
【技术专题】HTML5 网页技术 - HTML5 表格标签
前端·html·html5
雪芽蓝域zzs1 小时前
JS 项目转 TS 项目(Vue3 + 若依这类后台项目)完整改造清单
前端·vue.js