# three3D最详细案列实战
**Repository Path**: weixinper/threejsDemoProduct
## Basic Information
- **Project Name**: three3D最详细案列实战
- **Description**: threejs案列驱动学习,包含了最全的案列实战步骤。
跟着案列你可以快速的入门,在配合threejs官网文档。
学习效率提升非常快
学习开发文档的,请私信博主
- **Primary Language**: JavaScript
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 10
- **Created**: 2023-09-14
- **Last Updated**: 2023-09-14
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# three3D最详细案列实战
#### 介绍
threejs案列驱动学习,包含了最全的案列实战步骤。
跟着案列你可以快速的入门,在配合threejs官网文档。
学习效率提升非常快
#### 软件架构
纯web项目。只需要下载threejs依赖。
后续继续更新vue、react版本
#### 部分文档参考
### 课程内容
#### 一、环境的搭建
##### (1)搭建项目
threejs的每个版本都有一些差异,在api和threejs项目文件夹下面,本案列使用的版本
```
npm i three@0.153.0
```
项目的目录结构如下:
```
03-fulldemo
└───css
│───main.css
│
└───draco
│───gltf——存放Google Draco解码器插件
│
└───models——存放模型
│───ferrari.glb——模型文件,可以是glb也可以是gltf格式
│───ferrari_ao.png——模型贴图,这个图片是阴影效果
│
└───textures——纹理材质
│───venice_sunset_1k.hdr——将其用作场景的环境映射或者用来创建基于物理的材质
│
```
##### (2)代码基础结构搭建
创建对应的html文件并引入相应的环境
```
three.js webgl - materials - car
Body
Details
Glass
```
在css/main.css文件中我们的代码如下
```
body {
margin: 0;
background-color: #000;
color: #fff;
font-family: Monospace;
font-size: 13px;
line-height: 24px;
overscroll-behavior: none;
}
a {
color: #ff0;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
button {
cursor: pointer;
text-transform: uppercase;
}
#info {
position: absolute;
top: 0px;
width: 100%;
padding: 10px;
box-sizing: border-box;
text-align: center;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
pointer-events: none;
z-index: 1; /* TODO Solve this in HTML */
}
a, button, input, select {
pointer-events: auto;
}
.lil-gui {
z-index: 2 !important; /* TODO Solve this in HTML */
}
@media all and ( max-width: 640px ) {
.lil-gui.root {
right: auto;
top: auto;
max-height: 50%;
max-width: 80%;
bottom: 0;
left: 0;
}
}
#overlay {
position: absolute;
font-size: 16px;
z-index: 2;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
background: rgba(0,0,0,0.7);
}
#overlay button {
background: transparent;
border: 0;
border: 1px solid rgb(255, 255, 255);
border-radius: 4px;
color: #ffffff;
padding: 12px 18px;
text-transform: uppercase;
cursor: pointer;
}
#notSupported {
width: 50%;
margin: auto;
background-color: #f00;
margin-top: 20px;
padding: 10px;
}
```
效果如下图:

#### 二、进行3D场景的渲染
##### (1)进行初始化函数设计
在项目中我们添加一个carInit函数进行动画的初始化
```
...省略之前代码
//下面的代码就是JS渲染逻辑代码
let scene, renderer, grid, camera;
function initCar(){
//里面就开始进行3D场景的搭建
}
//执行初始化函数
initCar()
```
上面的函数设计用于执行我们所有3d业务代码。
##### (2)创建场景
```
/**
* (1)获取要渲染的容器
*/
const container = document.getElementById('container');
/**
* (2)创建场景对象Scene
*/
//创建一个场景对象,用来模拟3d世界
scene = new THREE.Scene();
//设置一个场景的背景颜色
scene.background = new THREE.Color(0x333333);
//这个类中的参数定义了线性雾。也就是说,雾的密度是随着距离线性增大的
scene.fog = new THREE.Fog("red", 10, 15);
```
background:这个属性用于设置我们场景的背景颜色,`0x333333`默认采用深灰来作为我们初始颜色
fog:定义了线性雾,类似于在背景指定位置设置雾化的效果,让背景看起来更加模糊,凸显空旷效果。
##### (3)坐标格辅助对象
```
/**
* (3)坐标格辅助对象. 坐标格实际上是2维线数组.
*/
//创建网格对象,参数1:大小,参数2:网格细分次数,参数3:网格中线颜色,参数4:网格线条颜色
grid = new THREE.GridHelper(40, 40, 0xffffff, 0xffffff);
//网格透明度
grid.material.opacity = 1;
grid.material.depthWrite = false;
grid.material.transparent = true;
scene.add(grid);
```
坐标格辅助对象GridHelper可以在3D场景中定义坐标格出现。后续我们会在坐标格上面放我们的模型进行展示
代码编写完毕后,最终渲染出来的坐标格效果如下:

##### (4) 创建相机对象
```
/**
* (4)创建透视相机
* 参数一:摄像机视锥体垂直视野角度
* 参数二:摄像机视锥体长宽比
* 参数三:摄像机视锥体近端面
* 参数四:摄像机视锥体远端面
*/
camera = new THREE.PerspectiveCamera(40, window.innerWidth / window.innerHeight, 0.3, 100);
camera.position.set(0, 1.4, - 4.5);
```
任何一个3D渲染效果都需要相机来成像
这一投影模式被用来模拟人眼所看到的景象,它是3D场景的渲染中使用得最普遍的投影模式
透视相机最大的特点就是满足近大远小的效果。
##### (5)创建一个渲染器
```
/**
* (5)创建一个渲染器
*/
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer = new THREE.WebGLRenderer({ antialias: true });
//设置设备像素比。通常用于避免HiDPI设备上绘图模糊
renderer.setPixelRatio(window.devicePixelRatio);
//设置渲染出来的画布范围
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(renderer.domElement);
renderer.render(scene, camera);
```
有了场景、相机、坐标格辅助,我们想要让画面能够呈现出来,那就得有渲染器。
相当于你拍照需要将画面呈现到交卷上面。
其中`renderer.render(scene, camera);` 这段代码就是在进行渲染器的渲染。
如果render在指定频率内不断被调用,那就意味着可以不断拍照,不断渲染。可以实现动态切换效果
##### (6)效果渲染
当执行完上面的代码后,你需要确保调用了carInit这个函数,页面就可以渲染出对应的效果了

说明:
1. 场景的背景色为`0x333333`效果为深灰色。
2. 我们设置的fog线性雾颜色为红色,所以你会发现在背景和网格之间会有一个过渡颜色。
3. 网格的颜色采用的是`0xffffff`效果为灰色。
对应的各种参数,当你在学习的时候都都可以进行调整。一遍调整就能看懂参数和最终渲染的效果差异。
当你把fog的颜色调整为跟背景一样的时候,你会发现画面上就类似产生了迷雾效果,让3D背景更加立体
```
scene.fog = new THREE.Fog(0x333333, 10, 15);
```
效果如下:

你也可以继续设置网格线条的透明度,让网格线不那么抢眼
```
grid.material.opacity = 0.3;
```
效果如下:

是不是整个画面看起来3D立体效果会更强一些,背景看起来更深邃一些。
#### 三、加载外部模型进行渲染
##### (1)添加轨道控制器
threejs官方给我们提供了一个类,OrbitControls(轨道控制器)可以使得相机围绕目标进行轨道运动。
换句话说,引入了OrbitControls后,我们可以操作鼠标来控制页面上动态效果。
比如:鼠标滚动、鼠标点击、鼠标左右滑动效果。
代码如下:
```
...省略了 【(5)创建一个渲染器】
/**
* (6)开启OrbitControls控件,可以支持鼠标操作图像
*/
controls = new OrbitControls(camera, container);
//你能够将相机向外移动多少(仅适用于PerspectiveCamera),其默认值为Infinity
controls.maxDistance = 9;
//你能够垂直旋转的角度的上限,范围是0到Math.PI,其默认值为Math.PI
controls.maxPolarAngle = THREE.MathUtils.degToRad(90);
controls.target.set(0, 0.5, 0);
controls.update();
```
加入上面代码后,我们还要继续优化代码
在carInit函数后面在添加一个render函数,用于执行渲染
```
function initCar(){
/**
* (5)创建一个渲染器
*/
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(renderer.domElement);
//注释掉这句话
//renderer.render(scene, camera);
//调用一次render函数进行渲染
render()
}
function render(){
renderer.render(scene, camera);
requestAnimationFrame(render)
}
```
效果实现如下:

##### (2)加载汽车模型
既然要加载外部模型,那我们肯定需要通过模型软件来设计对应的模型。本案列不讲解如何设计模型,我使用threejs官方提供的模型来进行展示。
我们常用的模型格式如下:
1. OBJ (Wavefront OBJ):
OBJ 是一种常见的纯文本模型格式,支持存储模型的几何信息(顶点、面)和材质信息(纹理坐标、法线等)。可以通过OBJLoader来加载和解析OBJ格式的模型。
2. FBX (Autodesk FBX):
FBX 是由Autodesk开发的一种常用的二进制模型格式,支持存储模型的几何信息、材质、动画等。可以通过FBXLoader来加载和解析FBX格式的模型。
3. GLTF (GL Transmission Format):
GLTF 是一种基于JSON的开放标准,用于存储和传输三维模型和场景。GLTF格式支持几何信息、材质、骨骼动画、节点层次结构等,并且通常具有较小的文件大小。可以通过GLTFLoader来加载和解析GLTF格式的模型。
4. STL (Stereolithography):
STL 是一种常用的三维打印文件格式,用于存储模型的几何信息。STL 文件通常包含三角形面片的列表,用于定义模型的外观。可以通过STLLoader来加载和解析STL格式的模型。
5. GLB:
GLB是GL Transmission Format(gltf)的二进制版本,GLB格式将模型的几何信息、材质、骨骼动画、节点层次结构等存储在单个二进制文件中,通常具有较小的文件大小和更高的加载性能.
本案列采用glb格式来加载外部模型。
因为案列中使用glb模型数据采用了Draco来进行压缩,所以我们需要引入DRACOLoader来解析我们的模型
(1)引入DRACOLoader加载模型
```
/**
* (7)汽车模型相关的内容
* DRACOLoader 主要用于解析使用 Draco 压缩的 GLB 模型,而不是所有的 GLB 模型都使用了 Draco 压缩
*/
const dracoLoader = new DRACOLoader();
//配置加载器的位置,这个需要提前下载到项目中
dracoLoader.setDecoderPath('./draco/gltf/');
const loader = new GLTFLoader();
//设置GLTFLoader加载器使用DRACO来解析我们的模型数据
loader.setDRACOLoader(dracoLoader);
```
> 并不是所有的模型都需要Draco来进行加载,取决于你的模型在设计导出的时候是否用了Draco来进行压缩。
`./draco/gltf/`目录下面的文件如下:代码可以从gitee上面下载

##### (3)加载glb模型数据
当你已经创建了`const loader = new GLTFLoader();这个类实例后,我们就可以加载模型了
```
/**
* (8)加载glb模型
*/
loader.load('./models/gltf/ferrari.glb', function (gltf) {
//获取到模型的数据
const carModel = gltf.scene.children[0];
//将模型添加到3D场景中
scene.add(carModel);
});
render()
```
加载的效果如下:

模型已经加载成功了,但是你会发现他在整个背景中是黑色的。当然模型本身是有材质贴图的,车身默认是红色的。
之所以产生这个效果那是因为我们现在缺少一个非常重要的元素,那就是光照。
你试想一下,一个物体在没有任何光源的情况下,呈现出来的就是黑色的效果。如果你的场景背景也是黑色,那根本看不到效果。
##### (4)加载光影效果
我们设置光源的时候主要有两个部分
1. 环境光:相当于天空的颜色,物体表面可以反射出对应的颜色。
2. 点光源:相当于开启手电筒,照射到模型表面反射出来的颜色。
设置环境光
```
/**
* (9)添加光影效果
*/
//创建环境光
var ambient = new THREE.AmbientLight("blue");
scene.add(ambient);
```
环境光的颜色为blue,效果如下:

环境光为blue的情况下,模型表面反射出来的颜色就是蓝色,一般金属材质和玻璃材质反射的效果更佳明显。所以轮毂和车辆挡风玻璃效果会更强烈一些。
设置点光源
```
/**
* (9)添加光影效果
*/
//创建环境光
var ambient = new THREE.AmbientLight("blue");
scene.add(ambient);
//创建点光源
var point = new THREE.PointLight("#fff");
//设置点光源位置
point.position.set(0, 300, 0);
//点光源添加到场景中
scene.add(point);
```
效果如下:

此刻我们基本上完成了模型的渲染,环境光蓝色默认替换为黑色,这样车辆立体感会更强一些
```
//环境光
var ambient = new THREE.AmbientLight("#000");
```
效果如下:

私聊博主:可以获取更多的文档。qq:550250108