🚗 Three.js 实战全解析:打造 SU7 展示 + 人物控制 + HDR 场景 + 碰撞检测

🚗 Three.js 实战全解析:打造 SU7 展示 + 人物控制 + HDR 场景 + 碰撞检测

car-cq6.pages.dev/

用 Three.js 做一个能开车、能走人、能撞墙,还能跳跃的酷炫 3D 展示场景。本文基于 项目源码 和真实模型资源,进行逐行讲解,适合学习 Three.js 实践开发。

📦 模型 & 贴图资源

贴图目录结构如下:

arduino 复制代码
public/textures/
├── brick_pavement_02_diff_1k.jpg
├── brick_pavement_02_disp_1k.png
├── concrete_pavement_diff_1k.jpg
├── concrete_pavement_disp_1k.png
├── sky.hdr

🧱 项目结构

arduino 复制代码
car/
├── public/
│   ├── models/
│   │   ├── su7-xiaomini.glb
│   │   └── person/Character.glb
│   └── textures/
├── src/
│   ├── main.js        // 主场景逻辑
│   └── person.js      // 人物模块
├── index.html
├── vite.config.js

🚀 快速启动

bash 复制代码
git clone https://github.com/yunshengya/car
cd car
npm install
npm run dev

浏览器打开 http://localhost:5173 即可进入场景。


🎮 操作说明

汽车控制

键位 说明
W / S 前进 / 后退
A / D 左转 / 右转
Q / E 车体倾斜
Shift 加速
Space 跳跃
R 重置位置

人物控制

键位 说明
↑ / ↓ 前进/后退
← / → 左右旋转
0(键盘) 跳跃

✨ 主逻辑详解(main.js)

✅ 初始化场景、相机、渲染器

dart 复制代码
const scene = new THREE.Scene(); // 创建场景对象
scene.background = new THREE.Color(0x111111); // 设置背景颜色为深灰

const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000); // 设置相机参数:视角、宽高比、近远裁剪面
camera.position.set(0, 5, 8); // 相机位置设置在空中,稍微偏后

const renderer = new THREE.WebGLRenderer({ antialias: true }); // 创建 WebGL 渲染器并开启抗锯齿
renderer.setSize(window.innerWidth, window.innerHeight); // 设置渲染器尺寸
javascript 复制代码
document.body.appendChild(renderer.domElement); // 将渲染画布挂载到页面中

🌅 加载 HDR 贴图用于环境光照和背景

arduino 复制代码
const rgbeLoader = new RGBELoader(); // 创建 HDR 加载器
const pmremGenerator = new THREE.PMREMGenerator(renderer); // 用于从 HDR 创建环境贴图
ini 复制代码
rgbeLoader.load(`${baseUrl}textures/sky.hdr`, (hdrTexture) => {
  const envMap = pmremGenerator.fromEquirectangular(hdrTexture).texture; // 生成环境贴图
  scene.environment = envMap;  // 用作物体反射
  scene.background = envMap;   // 设置背景图为 HDR 图
});

🧱 加载地面贴图

ini 复制代码
const asphaltDiffuse = textureLoader.load('/textures/brick_pavement_02_disp_1k.png');
const asphaltNormal = textureLoader.load('/textures/brick_pavement_02_diff_1k.jpg');

设置贴图重复效果:

ini 复制代码
asphaltDiffuse.wrapS = asphaltDiffuse.wrapT = THREE.RepeatWrapping;
asphaltNormal.wrapS = asphaltNormal.wrapT = THREE.RepeatWrapping;
asphaltDiffuse.repeat.set(20, 20);
asphaltNormal.repeat.set(20, 20);

创建地面:

php 复制代码
const plane = new THREE.Mesh(
  new THREE.PlaneGeometry(50, 50),
  new THREE.MeshStandardMaterial({
    map: asphaltDiffuse,
    normalMap: asphaltNormal,
    metalness: 0.2,
    roughness: 0.8
  })
);
plane.rotation.x = -Math.PI / 2; // 平面朝上
scene.add(plane);

💡 添加环境光与方向光

csharp 复制代码
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5); // 环境光,提供整体亮度
const directionalLight = new THREE.DirectionalLight(0xffffff, 1); // 平行光,类似太阳
scene.add(ambientLight);
scene.add(directionalLight);

🚧 创建场景边界墙体 + 贴图 + 碰撞

ini 复制代码
const wallDiffuse = textureLoader.load(`${baseUrl}textures/concrete_pavement_diff_1k.jpg`);
const wallDisplace = textureLoader.load(`${baseUrl}textures/concrete_pavement_disp_1k.png`);
php 复制代码
const wallMaterial = new THREE.MeshStandardMaterial({
  map: wallDiffuse,
  displacementMap: wallDisplace,
  displacementScale: 0.15,
  metalness: 0.2,
  roughness: 0.8
});

创建四面墙:

ini 复制代码
function createWall (x, y, z, w, h, d) {
  const geometry = new THREE.BoxGeometry(w, h, d, 64, 64, 1);
  const wall = new THREE.Mesh(geometry, wallMaterial);
  wall.position.set(x, y, z);
  scene.add(wall);
  obstacles.push(new THREE.Box3().setFromObject(wall));
}

👦 人物控制模块(person.js)讲解重点

kotlin 复制代码
export class People {
  constructor(scene, baseUrl) {
    this.scene = scene;
    this.baseUrl = baseUrl;
    this.model = null; // 人物模型引用

控制状态与按键监听

kotlin 复制代码
    this.keys = {
      ArrowUp: false,
      ArrowDown: false,
      ArrowLeft: false,
      ArrowRight: false,
      Digit0: false, // 跳跃
    };
    this.initListeners();

模型加载

kotlin 复制代码
    const loader = new GLTFLoader();
    loader.load(`${this.baseUrl}models/person/Character.glb`, gltf => {
      this.model = gltf.scene;
      this.model.position.set(5, 0, 0);
      this.model.scale.set(0.5, 0.5, 0.5);
      this.scene.add(this.model);
    });

跳跃逻辑: 用正弦模拟自然跳跃

arduino 复制代码
this.model.position.y = Math.sin(p * Math.PI) * this.jumpHeight;

旋转移动:

kotlin 复制代码
if (this.keys.ArrowLeft) {
  this.model.rotation.y += this.rotationSpeed;
}
if (this.keys.ArrowRight) {
  this.model.rotation.y -= this.rotationSpeed;
}

✅ GitHub 项目地址

github.com/yunshengya/...


下一步你可以:

  • 添加第一人称视角相机跟随人物
  • 给人物增加动画融合(走路、跳跃)
  • 加载更多模型进行场景装饰

愿你在 Three.js 的路上越玩越溜!🚀

相关推荐
阿怼丶6 小时前
🚶‍♂️基于 Three.js 的自定义角色漫游系统实战:支持碰撞检测与动画控制
前端·three.js
Mintopia8 小时前
Three.js 3D 柱状图制作指南:从像素到立体的魔法之旅
前端·javascript·three.js
Mintopia1 天前
Three.js 顶点与颜色点的装配艺术:从像素到彩虹的底层之旅
前端·javascript·three.js
爱看书的小沐2 天前
【小沐杂货铺】基于Three.JS绘制汽车展示Car(WebGL、vue、react、autoshow、提供全部源代码)
汽车·vue3·react·webgl·three.js·opengl·autoshow
Mintopia2 天前
Three.js 中三角形到四边形的顶点变换:一场几何的华丽变身
前端·javascript·three.js
Mintopia3 天前
Three.js 中的噪声与图形变换:一场数字世界的舞蹈
前端·javascript·three.js
中国黄金Gold4 天前
Three.js OrbitControls:实现鼠标左键直接平移场景
three.js
三年三月4 天前
021-顶点法线与反射原理
javascript·three.js
Mintopia4 天前
Three.js 中正切函数在相机视野里的那些事儿
前端·javascript·three.js