# 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; } ``` 效果如下图: ![image-20230627175428242](https://woniumd.oss-cn-hangzhou.aliyuncs.com/web/xuchaobo202306271754287.png) #### 二、进行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场景中定义坐标格出现。后续我们会在坐标格上面放我们的模型进行展示 代码编写完毕后,最终渲染出来的坐标格效果如下: ![image-20230628155733478](https://woniumd.oss-cn-hangzhou.aliyuncs.com/web/xuchaobo202306281557511.png) ##### (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这个函数,页面就可以渲染出对应的效果了 ![image-20230628161312404](https://woniumd.oss-cn-hangzhou.aliyuncs.com/web/xuchaobo202306281613435.png) 说明: 1. 场景的背景色为`0x333333`效果为深灰色。 2. 我们设置的fog线性雾颜色为红色,所以你会发现在背景和网格之间会有一个过渡颜色。 3. 网格的颜色采用的是`0xffffff`效果为灰色。 对应的各种参数,当你在学习的时候都都可以进行调整。一遍调整就能看懂参数和最终渲染的效果差异。 当你把fog的颜色调整为跟背景一样的时候,你会发现画面上就类似产生了迷雾效果,让3D背景更加立体 ``` scene.fog = new THREE.Fog(0x333333, 10, 15); ``` 效果如下: ![image-20230628161707934](https://woniumd.oss-cn-hangzhou.aliyuncs.com/web/xuchaobo202306281617970.png) 你也可以继续设置网格线条的透明度,让网格线不那么抢眼 ``` grid.material.opacity = 0.3; ``` 效果如下: ![image-20230628161827094](https://woniumd.oss-cn-hangzhou.aliyuncs.com/web/xuchaobo202306281618130.png) 是不是整个画面看起来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) } ``` 效果实现如下: ![img](https://woniumd.oss-cn-hangzhou.aliyuncs.com/web/xuchaobo202306291223608.gif) ##### (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上面下载 ![image-20230629142933880](https://woniumd.oss-cn-hangzhou.aliyuncs.com/web/xuchaobo202306291429924.png) ##### (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() ``` 加载的效果如下: ![image-20230629143514305](https://woniumd.oss-cn-hangzhou.aliyuncs.com/web/xuchaobo202306291435348.png) 模型已经加载成功了,但是你会发现他在整个背景中是黑色的。当然模型本身是有材质贴图的,车身默认是红色的。 之所以产生这个效果那是因为我们现在缺少一个非常重要的元素,那就是光照。 你试想一下,一个物体在没有任何光源的情况下,呈现出来的就是黑色的效果。如果你的场景背景也是黑色,那根本看不到效果。 ##### (4)加载光影效果 我们设置光源的时候主要有两个部分 1. 环境光:相当于天空的颜色,物体表面可以反射出对应的颜色。 2. 点光源:相当于开启手电筒,照射到模型表面反射出来的颜色。 设置环境光 ``` /** * (9)添加光影效果 */ //创建环境光 var ambient = new THREE.AmbientLight("blue"); scene.add(ambient); ``` 环境光的颜色为blue,效果如下: ![image-20230629145635074](https://woniumd.oss-cn-hangzhou.aliyuncs.com/web/xuchaobo202306291456119.png) 环境光为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); ``` 效果如下: ![image-20230629145913328](https://woniumd.oss-cn-hangzhou.aliyuncs.com/web/xuchaobo202306291459377.png) 此刻我们基本上完成了模型的渲染,环境光蓝色默认替换为黑色,这样车辆立体感会更强一些 ``` //环境光 var ambient = new THREE.AmbientLight("#000"); ``` 效果如下: ![image-20230629150241875](https://woniumd.oss-cn-hangzhou.aliyuncs.com/web/xuchaobo202306291502925.png) 私聊博主:可以获取更多的文档。qq:550250108