three项目创建
three+vue3
首先创建vue3的项目:npm create vite@latest
然后通过命令行下载three依赖:
npm install three@0.157.0 -S
注:最好指定版本号,以防止api的不适用
基本使用
在需要用到的组件中按需引入three的对象。
// 引入three.js
import * as THREE from 'three';
我们在实际项目中,光一个THREE对象还是不够的,因此还需要引入其他的对象来辅助我们进行编写。
注意:在老版本时辅助方法路径是three/examples,新版本更换为:three/addons
// 引入扩展库OrbitControls.js
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// 引入扩展库GLTFLoader.js
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
创建3D场景
想创建一个最基本的3D场景,其实只需要四个因素就可以了。
场景、相机、渲染器、元素。当我们拥有这四个因素后,就可以在页面中创建出一个简单的3D场景
// 引入three.js
import * as THREE from 'three';
// 创建3D场景对象Scene
const scene = new THREE.Scene();
//创建一个长方体几何对象Geometry
const geometry = new THREE.BoxGeometry(100, 100, 100);
//创建一个材质对象Material
const material = new THREE.MeshBasicMaterial({
color: 0xff0000,//0xff0000设置材质颜色为红色
});
// 网格模型对象Mesh,用户将几何图和材质合并以方便在场景中展示
const mesh = new THREE.Mesh(geometry, material);
mesh.position.set(0,10,0);
scene.add(mesh);
let width = 500;
let height = 400;
// 实例化一个透视投影相机对象
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
// 设置相机在Three.js三维坐标系中的位置
camera.position.set(200, 200, 200);
//相机观察目标指向Threejs 3D空间中某个位置
camera.lookAt(0, 0, 0); //坐标原点
scene.add(camera)
// 创建渲染器对象
const renderer = new THREE.WebGLRenderer();
//设置three.js渲染区域的尺寸(像素px)
renderer.setSize(width, height);
renderer.render(scene, camera); //执行渲染操作
// 此时一个简单的3D场景就创建完成了,我们现在只需要将它放在页面元素中就好
document.body.appendChild(renderer.domElment)
下面就来详细介绍下每个API的用法
场景
// 创建3D场景对象Scene
const scene = new THREE.Scene();
这没啥说的,创建一个场景,就好似创建一个舞台。我们可以让各种各样的元素如:人、花草等上去表演。
元素
几何体
在THREE中有好多中定义几何体的API,我们可以直接调用它们来实现绘制。
//BoxGeometry:长方体
const geometry = new THREE.BoxGeometry(100, 100, 100);
// SphereGeometry:球体
const geometry = new THREE.SphereGeometry(50);
// CylinderGeometry:圆柱
const geometry = new THREE.CylinderGeometry(50,50,100);
// PlaneGeometry:矩形平面
const geometry = new THREE.PlaneGeometry(100,50);
// CircleGeometry:圆形平面
const geometry = new THREE.CircleGeometry(50);
更多几何体可以参考官网
材质
有了上面的API调用后,我们现在拥有了一个自定义的几何体图形。但是他的形状可能不如意。所以现在需要使用材质API来为我们定义的材质添砖加瓦。
现在使用一个最基本的材质为矩形盒子添加颜色
//创建一个材质对象Material
const material = new THREE.MeshBasicMaterial({
color: 0xff0000,//0xff0000设置材质颜色为红色
});
对了,在threejs中模式的几何体设置是正面可见,后面学习了相机控件后,我们会发现自己渲染的几何体只能看到正面,拖动到反面就看不到物体了,此时需要在材质中改变一个参数即可。
// THREE.DoubleSide 双面可见
// THREE.FrontSide 正面可见
// THREE.BackSide 背面可见
new THREE.MeshBasicMaterial({
side: THREE.FrontSide, //默认只有正面可见
});
一开始使用的高级材质有漫反射材质MeshLambertMaterial和高光材质MeshPhongMaterial。
漫反射材质:就是当光源照射到几何体身上时,光不会有固定的反射角将光源反射出去,而是想四方周围反射。
高光材质:就是当光源照射到几何体身上时,光会根据照射的角度来确定一个固定的反射角,由反射角反射出去。高光的地方更加明显,渲染出来的几何体更加逼真。
网络模型
好了,现在几何体和材质都有了,这时需要具体的对象来将他们整合在一起,这里使用网格模型来表示一个虚拟的物体。在最后为这个网格模型位置,将这个网格模型放在我们的相机设置的可视范围内就可以了。
// 网格模型对象Mesh,用户将几何图和材质合并以方便在场景中展示
const mesh = new THREE.Mesh(geometry, material);
mesh.position.set(0,10,0);
scene.add(mesh);
相机
PerspectiveCamera:透视投影相机
在three.js中提供了两个相机,分别是PerspectiveCamera透视投影相机、OrthographicCamera正投影相机。透视投影相机的本质就是模拟人眼观察周围环境的规律。
在使用时,需要new THREE.PerspectiveCamera()
实例化一个对象,其中PerspectiveCamera类有四个参数。分别是fov, aspect, near, far。相机分别用这四个参数构成一个四棱台,也称为视锥体。只有在视锥体内的元素才能被渲染出来。
- fov:相机视锥体竖直方向视野角度,一般角度越大,看的面越广。
- aspect:相机视锥体水平方向和竖直方向长度比,一般设置为Canvas画布宽高比width / height
- near:相机视锥体近裁截面相对相机距离
- far:相机视锥体远裁截面相对相机距离,far-near构成了视锥体高度方向
position
camera.position.set(200, 200, 200)
:使用代码来控制场景中相机的位置,相机的位置决定了看到物体的角度和大小。就好像人站在远处看高楼,感觉也不怎么高,但是在楼底下就看出楼是非常高了。
lookAt
camera.lookAt(0, 0, 0)
这行代码表示往哪个位置拍照,就像人体一样,光有确定位置还不行,就好像你像看正前方的公园,但是在背过身去看背面的高楼,那肯定是看不到你想看的公园的。
注意:如果项目中有使用到相机控件,那个相机控件在初始化时会重置lookAt的值,因此光在这里更改还不行,还要修改相机控件的target值。(下面会说)
渲染器
通过WebGL渲染器WebGLRenderer可以实例化一个WebGL渲染器对象。然后使用setSize(width, height)
的方式来设置渲染面的大小,最后通过渲染方法.render()
来实现场景的渲染。
不过此时光有渲染器还不行,还需要添加到dom中。使用渲染器的.domElement
属性将canvas元素添加到body中,具体使用代码如下:
// 创建渲染器对象
const renderer = new THREE.WebGLRenderer();
//设置three.js渲染区域的尺寸(像素px)
renderer.setSize(width, height);
renderer.render(scene, camera); //执行渲染操作
// 此时一个简单的3D场景就创建完成了,我们现在只需要将它放在页面元素中就好
document.body.appendChild(renderer.domElment)
通过以上操作可以将场景中的物体都展示到界面上,但是默认情况下,WebGL为了保持性能,会关闭抗锯齿功能。此时我们渲染出来的几何体多多少少会出现点锯齿,很不美观。此时初始化渲染器是设置一个参数即可。
const renderer = new THREE.WebGLRenderer({
antialias:true, // 默认是false
});
// 或 renderer.antialias = true,
如果在canvas画布上输出时有模糊的问题,可能是你的设备像素比和three默认的像素比不同,导致计算出现覆盖模糊了。这是需要设置下你的像素比。
// 不同硬件设备的屏幕的设备像素比window.devicePixelRatio值可能不同
// window.devicePixelRatio这是window自带的方法参数,不用管直接用即可
renderer.setPixelRatio(window.devicePixelRatio);
有时需要渲染出来的背景颜色是自定义的,那么:
renderer.setClearColor(0x444444, 1); //设置背景颜色
光源
在生活中,如果没有光,我们周围就会一片漆黑,这时什么都看不到。所以THREE中使用Light类来模拟光照。就是模拟光照Light
对网格模型Mesh
表面的影响。
但是在上面的案例中,我们没有添加光源,但是依然可以看到有物体被渲染出来了,是因为我们使用的材质不同,有些材质是不受光源的影响。但是有些材质为了渲染的更逼真、更贴合实际生活,是需要光源的加入的。
在THREE中主要的光源有:
- 点光源:PointLight
- 环境光:AmbientLight
- 平行光源:DirectionalLight
- 聚光源:SpotLight(用得不多)
下面以点光源为例:
//点光源:两个参数分别表示光源颜色和光照强度
// 参数1:0xffffff是纯白光,表示光源颜色
// 参数2:1.0,表示光照强度,可以根据需要调整
const pointLight = new THREE.PointLight(0xffffff, 1.0);
如果你不想再初始化时定义他的光照强度,可以动态在js中定义
pointLight.intensity = 1.0;//光照强度
在生活中光线会随着距离的增加而逐渐减少,我们这里可以设置衰减的程度。
// 设置光源不随距离衰减
pointLight.decay = 0.0;
//或者设置光源随距离衰减
pointLight.decay = 0.1;
定义点光源的位置并添加到场景中
//点光源位置,点光源放在x轴上
pointLight.position.set(400, 0, 0);
//点光源添加到场景中
scene.add(pointLight);
相机控件
在threejs中的相机控件有很多,主要是用来对场景中的元素进行移动缩放等操作的。使其更有3D立体感。
这里使用轨道控制器OrbitControls相机控件。
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
实例化一个new OrbitControls相机控件时,需要两个参数,一个是需要控制的相机,一个是需要控制的canvas元素。使用的具体方式如下:
// 设置相机控件轨道控制器OrbitControls
const controls = new OrbitControls(camera, renderer.domElement);
controls.target(0,0,0)
// 如果OrbitControls改变了相机参数,重新调用渲染器change事件
controls.addEventListener('change', function () {
// 注意:如果这里不执行重新渲染操作,系统会只改变参数,而不渲染场景
renderer.render(scene, camera);
console.log('camera.position',camera.position);
});
controls.target(0,0,0)
这是指控件的焦点围绕哪个对象进行旋转,因此如果想更改camear.lookAt的属性时,记住一点要设置控件的此target属性,反正自定义的lookAt属性不生效。
其实相机控件OrbitControls的本质就是改变相机的位置,视角等参数,通过观看角度的不同,来达到我们视线观察物体的不同。
辅助线
辅助线主要的作用是在开发中帮助我们确定物体位置的工具。
坐标转辅助线
使用THREE.AxesHelper(x,y,z)来初始化坐标线。分别又三个参数来改变他们的xyz轴的长度。
// AxesHelper:辅助观察的坐标系
const axesHelper = new THREE.AxesHelper(150);
scene.add(axesHelper);
此时,在屏幕上会出现三条线段,分别是红绿蓝三种颜色的线,分别对应xyz轴,
网格辅助线
const axeshelper = new THREE.GridHelper(100);
scene.add(axeshelper)
完结语
这是本人的学习笔记,如果有哪里理解或笔记不正确的地方,请各位朋友多多指教,如果有不懂或技术上的难题也可以私信我,咱们一块研究,共同进步嘛。