# threejs搭建前端3D项目 **Repository Path**: wenxiaod/vueThree ## Basic Information - **Project Name**: threejs搭建前端3D项目 - **Description**: 使用threejs搭建前端3D数字化系统,开发语言VUE,3D渲染引擎threejs。刚入手学习,持续更新,未完待续... - **Primary Language**: JavaScript - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 134 - **Forks**: 46 - **Created**: 2021-03-19 - **Last Updated**: 2024-11-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: Threejs ## README # 使用threejs搭建前端3D页面 ## 一 项目 ### 1.安装依赖 ``` npm install ``` ### 2.启动 ``` npm run serve ``` ### 3.打包 ``` npm run build ``` ### 4.当前效果图 ①.基本模型 ![当前效果图](./src/assets/three.gif) ②.外部模型(obj、mtl) 【疑似侵权,不便展示】 ③.自己制作模型(obj、mtl) ![自己制作模型(obj、mtl)](./src/assets/ztpage.png) ## 二 初始化函数 ```javascript Init(){ /*** 创建场景对象Scene*/ var scene = new THREE.Scene(); /*** 创建网格模型*/ // var geometry = new THREE.SphereGeometry(60, 40, 40); //创建一个球体几何对象 var geometry = new THREE.BoxGeometry(100, 100, 100); //创建一个立方体几何对象Geometry var material = new THREE.MeshLambertMaterial({color: 0x0000ff}); //材质对象Material var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh scene.add(mesh); //网格模型添加到场景中 /*** 光源设置*/ //点光源 var point = new THREE.PointLight(0xffffff); point.position.set(400, 200, 300); //点光源位置 scene.add(point); //点光源添加到场景中 //环境光 var ambient = new THREE.AmbientLight(0x444444); scene.add(ambient); /*** 相机设置*/ let container = document.getElementById("container"); var width = 1920; //窗口宽度 var height = 1080; //窗口高度 var k = width / height; //窗口宽高比 var s = 200; //三维场景显示范围控制系数,系数越大,显示的范围越大 //创建相机对象 var camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000); camera.position.set(200, 300, 200); //设置相机位置 camera.lookAt(scene.position); //设置相机方向(指向的场景对象) /*** 创建渲染器对象*/ var renderer = new THREE.WebGLRenderer(); renderer.setSize(width, height);//设置渲染区域尺寸 renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色 container.appendChild(renderer.domElement); //body元素中插入canvas对象 //执行渲染操作 指定场景、相机作为参数 renderer.render(scene, camera); } ``` ## 三 函数 ```javascript /*** 创建一个立方体*/ var geometry = new THREE.BoxGeometry(100, 100, 100); /*** 创建一个球体*/ var geometry = new THREE.SphereGeometry(60, 40, 40); /*** 3D模型的材质(颜色)16进制RGB三原色*/ var material=new THREE.MeshLambertMaterial({color:0x0000ff}); /*** 点光源对象,参数0xffffff定义的是光照强度(颜色深浅)*/ var point=new THREE.PointLight(0xffffff); /*** 创建了一个正射投影相机对象*/ var camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000); camera.position.set(200, 300, 200); //设置相机位置(X、Y、Z轴) ``` ![threejs结构](./src/assets/threejs.png) ## 四 3D模型旋转 将渲染函数: ```javascript //执行渲染操作 指定场景、相机作为参数 renderer.render(scene, camera); ``` 替换为: ```javascript //自定义渲染 function render() { renderer.render(scene,camera);//执行渲染操作 mesh.rotateY(0.01);//每次绕y轴旋转0.01弧度 }; //间隔20ms周期性调用函数fun,20ms也就是刷新频率是50FPS(1s/20ms),每秒渲染50次 setInterval(function () {render();},20) ``` 即可实现3D模型绕Y轴开始旋转。 * 备注:一般调用渲染方法.render()进行渲染的渲染频率控制在每秒30~60次,人的视觉效果都很正常,也可以兼顾渲染性能,延时过高很感觉明显的卡顿。 * requestAnimationFrame(render);//请求再次执行渲染函数render 可以代替setInterval()定时器,默认定时频率约为60FPS,如下: ```javascript //自定义渲染 function render() { renderer.render(scene,camera);//执行渲染操作 mesh.rotateY(0.01);//每次绕y轴旋转0.01弧度 requestAnimationFrame(render);//请求再次执行渲染函数render }; render(); ``` ## 五 鼠标操作3D模型 * 鼠标操作需要引入:three.js众多控件之一OrbitControls.js;这里引入有些小问题,我选择以下方式引入: ①在引入THREE的地方引入该插件 ```javascript import * as THREE from 'three'; import "three/examples/js/controls/OrbitControls" ``` ②注意我使用的是原生引入的方式,控制台存在:THREE is not defined 问题,在three/examples/js/controls/OrbitControls.js定义即可。以下用到的加载外部模型控件方法类似。需要在node_modules文件里找到对应路径的OrbitControls文件,加入import * as THREE from 'three'; ![引入控件](./src/assets/threejs02.png) ③在初始化函数中创建控件对象:(添加在render()后面即可) * 缩放:滚动—鼠标中键 * 旋转:拖动—鼠标左键 * 平移:拖动—鼠标右键 ```javascript // 鼠标操作3D模型 var controls = new THREE.OrbitControls(camera,renderer.domElement);//创建控件对象 ``` ## 六 设置材料效果 | 材质类型 | 功能 | | :-----| :---- | | MeshBasicMaterial | 基础网格材质,不受光照影响的材质 | | MeshLambertMaterial | Lambert网格材质,与光照有反应,漫反射 | | MeshPhongMaterial | 高光Phong材质,与光照有反应 | | MeshStandardMaterial | PBR物理材质,相比较高光Phong材质可以更好的模拟金属、玻璃等效果 | ### 1.材料透明度 添加opacity和transparent属性,opacity的值是0~1之间,transparent表示是否开启透明度效果, 默认是false表示透明度设置不起作用,值设置为true,网格模型就会呈现透明的效果,使用下面的代码替换原来的球体网格模型的材质 ```javascript var material=new THREE.MeshLambertMaterial({color:0xff0000,opacity:0.2,transparent:true});//材质对象 ``` ### 2.材料高光 属性specular表示球体网格模型的高光颜色,改颜色的RGB值会与光照颜色的RGB分量相乘, shininess属性可以理解为光照强度的系数。 ```javascript var material = new THREE.MeshPhongMaterial({color:0x0000ff,specular:0x4488ee,shininess:12});//材质对象 ``` ## 七.加载外部模型(obj、mtl) 加载外部模型需要引入两个控件: ```javascript // 引入obj模型加载库OBJLoader.js import "three/examples/js/loaders/OBJLoader.js" //引入obj模型材质加载库MTLLoader.js import "three/examples/js/loaders/MTLLoader.js" ``` 静态模型文件存放位置:public/static/model/,在Init()初始化函数中加入如下代码: ```javascript /** * OBJ和材质文件mtl加载 */ var OBJLoader = new THREE.OBJLoader();//obj加载器 var MTLLoader = new THREE.MTLLoader();//材质文件加载器 MTLLoader.load('static/model/pipeline.mtl', function(materials) { // 返回一个包含材质的对象MaterialCreator //console.log(materials); //obj的模型会和MaterialCreator包含的材质对应起来 OBJLoader.setMaterials(materials); OBJLoader.load('static/model/pipeline.obj', function(obj) { scene.add(obj);//返回的组对象插入场景中 //obj.scale.set(10, 10, 10); //放大obj组对象 obj.position.set(-100,175,200); //模型位置 }) }) //加载另一个模型 MTLLoader.load('static/model/axle.mtl', function(materials) { // 返回一个包含材质的对象MaterialCreator //console.log(materials); //obj的模型会和MaterialCreator包含的材质对应起来 OBJLoader.setMaterials(materials); OBJLoader.load('static/model/axle.obj', function(obj) { scene.add(obj);//返回的组对象插入场景中 obj.position.set(-100,175,200); //模型位置 }) }) ``` * 注意:模型加载后需要调用render()才能显示出来; * 加载慢:目前使用obj、mtl文件进行加载,会存在加载速度非常慢的问题,解决思路: ①.将文件转换为json文件进行加载。(gltf-pipeline与Draco方式效果好) ②.大文件模型进行拆分,分段加载。 ③.将文件转换为二进制问价进行加载。 ## 八.自己制作3D模型 * 下载3D模型编辑软件:SketchUp(我这里使用的是 SketchUp 2019)。 * 在SketchUp创建3D项目并制作一个3D模型。 * 导出3D模型为obj文件(同时会自动导出mtl材质文件在同一个目录)。 * 在页面中加载该文件。 ![制作3D模型](./src/assets/zt.png) ## 九.持续更新中...