前言
Threejs 可以实现特别多炫酷的 3D 效果,作为当下极度内卷的前端时代的前端 er,需要不断的提升自己,但是苦于 Three 的高质量资料较少,学起来有几分困难。
从去年最开始写 Threejs 专栏开始,就想写一个汽车展示平台,一直没能够很完善的实现,这次在 AI 的协助下,写一个 su7 和保时捷的展示&对比平台,咱们就来较个真,看看到底咋好看?
通过本文,你能学到:
- 打造一个 SU7 和 保时捷的 3D 展示平台
- 初始化 Three 项目的必备要素
- Three 开发常用辅助手段
- 如何下载、加载和预览模型
- 如何实现颜色、贴膜的替换
- 实现动画效果
- 学习如何使用 MarsCode 和豆包进行辅助编程
观看本文前,推荐先阅读:Threejs 从入门到实战专栏,建立起对 Three 的基本概念
准备工作
在实现一个 3D 展示平台之前,首先需要一些准备工作
获取模型
这里比较推荐 sketchfab,从里面下载一下,su7 的模型比较多, porsche_taycan 模型相对少一些,而且还不够精美
模型有很多种格式,本文选用 GLTF 格式,根据扩展名可以分为两种
- gltf: gltf 格式文件没有被压缩,会附带额外的 bin 数据文件,在文本编辑器中容易阅读,方便进行调试。
- glb: 所有数据都包含在二进制文件中,文件小,推荐使用,本文选用
创建项目
建议使用 vue 或者 react 进行实现,避免引入 Threejs 有一堆莫名其妙的问题。
// 创建项目
npm create vite@latest
// 安装依赖
npm i
// 安装three.js
npm i --save-dev three
// 启动项目
npm run dev
搭建 Three 项目
搭建一个基础的 Three 演示代码,Threejs 中存在核心三要素
- scene:渲染物体的场景
- camera:相机,决定场景中哪些部分能看到
- renderer:渲染器,将场景渲染到画布 canvas 上
这部分可以参考官方的案例 Creating a scene,也可以直接使用 MarsCode 生成一份。
输入:在本仓库的基础上,使用 vue 写一个 threejs 演示代码。由于当前为 vue 仓库,输入指令限定一下范围,避免生成原生 javascript 代码
<template>
<div id="container"></div>
</template>
<script>
import * as THREE from "three";
export default {
name: "ThreejsDemo",
mounted() {
this.initThreejs();
},
methods: {
initThreejs() {
const width = window.innerWidth;
const height = window.innerHeight;
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height);
document.getElementById("container").appendChild(renderer.domElement);
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({
color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
camera.position.z = 5;
const animate = () => {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
};
animate();
},
},
};
</script>
<style>
#container {
width: 100%;
height: 100%;
}
</style>
重新运行程序,就可以实现一个转动的绿色正方体。另外,我比较习惯将 scene、renderer、camera 等变量定义为全局变量,方便后续使用,这里按需使用。
在 Threejs 开发中,在开发的过程中,官方提供的某些辅助功能,非常方便,这里也添加一下,简单的建议还是使用 MarsCode 直接生成就好。
输入:添加轨道控制器 control 和辅助线和窗口自适应
import {
OrbitControls } from "three/examples/jsm/controls/OrbitControls";
initThree() {
// 创建坐标辅助线
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);
// 创建轨道控制器
controls = new OrbitControls(camera, renderer.domElement);
// 窗口自适应
window.addEventListener("resize", () => {
const width = window.innerWidth / 2;
const height = window.innerHeight;
camera.aspect = width / height;
camera.updateProjectionMatrix();
renderer.setSize(width, height);
});
}
- 轨道控制器:允许用户通过鼠标操作来控制相机,实现围绕场景中的目标物体进行旋转、缩放和平移。通俗来讲就是一个可以控制相机的工具。
- 坐标辅助线:可以创建一个坐标系,注意轴的颜色,黄色代表 X 轴,绿色代表 Y 轴,蓝色代表 Z 轴,不小心就被坑了,将 Z 轴和 Y 轴混淆
- 窗口自适应
有可能还有一些更深层次的辅助需求,比如想看相机的位置,那可以启用相机位置指示器
// 创建相机位置指示器
cameraHelper = new THREE.CameraHelper(camera);
scene.add(cameraHelper);
据我体验,只是在页面中多了一个灰色的坐标系,交叉点是相机指向的方向,目前没有感觉出什么用。
想获取相机的位置,因为在后续操作中,可以根据相机的位置进行一些复杂交互。
输入:能不能渲染出相机的位置,并可视化渲染的区域。
此次 MarsCode 没有给出满意的结果啊,反复问了几次都没有成功,依旧推荐 CameraHelper,遇到这种情形,不要头铁,换一种描述来做:
输入:尝试通过一个物体来模拟相机的位置
MarsCode 生成的代码如下:
camera.position.z = 5;
const markerGeometry = new THREE.SphereGeometry(0.1, 16, 16);
const markerMaterial = new THREE.MeshBasicMaterial({
color: 0xff0000 });
marker =