three.js的基础和使用
1.threejs引入three.js
- 项目开发引入threejs,比如vue或react脚手架引入threejs。
比如你采用的是Vue + threejs或React + threejs技术栈,这很简单,threejs就是一个js库,直接通过npm命令行安装就行
npm安装特定版本three.js(注意使用哪个版本,查文档就查对应版本)
| |
| npm install three@0.148.0 --save |
复制
- npm安装后,引入three.js
执行import * as THREE from 'three'
;,ES6语法引入three.js核心。
| |
| import * as THREE from 'three'; |
复制
- npm安装后,如何引入three.js其他扩展库
除了three.js核心库以外,在threejs文件包中examples/jsm目录下,你还可以看到各种不同功能的扩展库。
一般来说,你项目用到那个扩展库,就引入那个,用不到就不需要引入
| |
| import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; |
| |
| import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; |
| |
| |
| |
| import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'; |
复制
二,基础知识
1、右手坐标系
three.js中使用的都是右手坐标系,即图示右手大拇指指向x轴正向,食指指向y轴正向,中指指向z轴正向,这样的一个三维坐标系。具体来说,x,y坐标用于控制浏览器平面,如果不改变z坐标则物体只在浏览器平面上运动,因此z坐标控制的就是远近

2、整个程序解构

程序整个运行过程就是:场景 —— 相机 —— 渲染器
three.js核心组成
1、场景(secne)
| |
| |
| |
| const scene = new THREE.Scene(); |
复制
2、相机(camera)
- 创建透视相机,也称投影相机(PerspectiveCamera)-- 用来模拟人眼所看到的景象
| |
| |
| |
| const camera = new THREE.PerspectiveCamera( |
| 75, |
| window.innerWidth / window.innerHeight, |
| 0.1, |
| 1000 |
| ); |
| |
| camera.position.set(0, 0, 10); |
| scene.add(camera); |
复制
| const camera = new THREE.PerspectiveCamera( |
| fov : Number, |
| aspect : Number, |
| near : Number, |
| far : Number |
| ) |
| fov — 摄像机视锥体垂直视野角度 (相机的拍摄视角大小) |
| aspect — 摄像机视锥体长宽比 (相机拍摄区域的长宽比) |
| near — 摄像机视锥体近端面 (相机拍摄范围近端距离) |
| far — 摄像机视锥体远端面 (相机拍摄范围远端距离) |
| 常用:const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); |
| 效果:相机拍摄的画面具有近大远小的特性,距离相机近的物体显示的大,距离相机远的物体显示的小。 |
| |
复制
在 Three 中是没有「长度单位」这个概念的,它的数值都是根据比例计算得出,因此这里提到的 0.1 或 1000 都没有具体的含义,而是一种相对长度

可以看到,通过配置透视相机的相关参数,最终被渲染到屏幕上的,是在 near
到 far
之间,根据 fov 的值和物体远近
确定渲染高度,再通过 aspect
值来确定渲染宽度的。

如图中所示,透视投影相机一共有4个参数:fov(视场,一个角度值), Horizonta Field of View(横向视场),Vertical Field of View(纵向视场),Near plane(近面), Far plane(远面);由这几个因素,构成一个六面体的封闭空间,在这个空间内的一切物体可见。在设置参数时,需满足:
横向视场 / 纵向视场 = 浏览器窗口的宽/浏览器窗口的高。
渲染器(render)
有了场景和相机,我们还需要渲染器把对应的场景用对应的相机可见渲染出来,因此渲染器需要传入场景和相机参数。
| |
| |
| |
| const renderer = new THREE.WebGL1Renderer(); |
| |
| |
| renderer.setSize(window.innerWidth, window.innerHeight); |
| |
| |
| |
| |
| |
| document.body.appendChild(renderer.domElement); |
| |
| |
| renderer.render(scene, camera); |
复制
| const renderer = new THREE.WebGLRenderer(); |
| document.body.appendChild( renderer.domElement ); |
| 实例化一个渲染器,然后将它的dom元素插入到body中,即插入了一个canvas。 |
| |
| |
| 也可以将其插入到其他元素中,比如html中有一个<div id='canvas'></div>,就可以写成 |
| document.getElementById('canvas').appendChild( renderer.domElement );这样场景就在这个div中加载了。 |
| |
| |
| 注意:设置渲染器的大小,常用的为renderer.setSize( window.innerWidth, window.innerHeight );,如果不设就是默认大小 |
复制
物体对象-- 包含 几何体(Geometry)、材质(Material)、网格对象(Mesh)
Three 提供了多种类型的几何体,可以分为二维网格和三维网格。二维网格顾名思义只有两个维度,可以通过这种几何体创建简单的二维平面;三维网格允许你定义三维物体;在 Three 中定义一个几何体十分简单,只需要选择需要的几何体并传入相应参数创建即可。常用几何体如下
三维:

材质(Material)
| const basicMaterial = new THREE.MeshBasicMaterial({ color: 0x666666 }); |
| const lambertMaterial = new THREE.MeshLambertMaterial({ color: 0x666666 }); |
| const phongMaterial = new THREE.MeshPhongMaterial({ color: 0x666666 }); |
| const wireMaterial = new THREE.MeshBasicMaterial({ wireframe: true, color: 0x666666 }); |
复制
网格对象(Mesh)
需要将几何体和材质添加到场景中,还需要依赖 Mesh。Mesh 是用来定义材质和几何体之间是如何粘合的。
或者说 3d物体由点->线->面组成,mesh网格就是由大量的面组成的网格图,再加上材质就创建成物体,新建几何体和材质后,就可以将该物体对象添加到场景中了。
创建网格对象可以应用一个或多个材质和几何体。
网格 = 几何体 + 材质
创建几何体相同材质不同的网格对象
| const cube = new THREE.Mesh(cubeGeometry, basicMaterial); |
| const cubePhong = new THREE.Mesh(cubeGeometry, phongMaterial); |
复制
scene.add(cube, cubePhong);
创建材质相同几何体不同的网格对象:
| const cube = new THREE.Mesh(cubeGeometry, basicMaterial); |
| const sphere = new THREE.Mesh(sphereGeometry, basicMaterial); |
| scene.add(cube, sphere); |
复制
创建拥有多个材质几何体的网格对象:
| const phongMaterial = new THREE.MeshPhongMaterial({ color: 0x666666 }); |
| const cubeMeshPhong = new THREE.Mesh(cubeGeometry, cubePhongMaterial); |
| const cubeMeshWire = new THREE.Mesh(cubeGeometry, wireMaterial); |
| |
| cubeMeshPhong.add(cubeMeshWire); |
| scene.add(cubeMeshPhong); |
复制
有了场景、相机和渲染器,再加上物体,我们已经可以看到初步的效果了。但3D世界里,静止的物体多无趣啊。于是我们尝试加入动画效果.。
5、帧循环,游戏循环
| |
| function render() { |
| |
| cube.position.x += 0.01; |
| if (cube.position.x > 7) { |
| cube.position.x = 0; |
| } |
| |
| cube.rotateX(0.01); |
| |
| |
| renderer.render(scene, camera); |
| requestAnimationFrame(render); |
| } |
| render(); |
复制
灯光
| 1、灯光用来为场景添加光源,照明物体,虽然部分材质(如MeshBasicMaterial)不会受到灯光的影响,无需添加灯光也能看见,但是这种材质的物体没有质感,也没有明暗变化;如果想让物体更接近真实场景的物体,就需要可以被灯光影响的材质,如MeshLamberMaterial,如果不添加光源就无法看到物体。 |
| 2、灯光分为点光源,线光源,面光源等,可依据实际场景进行选择,正如真实场景的光源情况,three.js允许添加多个灯光从而对真实场景进行模拟。 |
| 添加灯光方法: |
| const light = new THREE.AmbientLight( 0x404040 ); |
| scene.add( light ); |
复制

辅助线
| |
| const axisHelper = new THREE.AxisHelper(7); |
| scene.add(axisHelper); |
| |
| |
| const grid = new THREE.GridHelper(1000, 1000, 0xff0000, 0xff0000); |
| scene.add(grid); |
复制
轨道控制器查看物体(鼠标控制)
| |
| import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"; |
| |
| |
| |
| |
| |
| const controls = new OrbitControls(camera, renderer.domElement); |
| controls.autoRotate = true; |
| controls.autoRotateSpeed = 3; |
| |
| controls.enableDamping = true; |
复制
设置控制器阻尼,必须在动画循环render()中调用controls.update()()
| |
| function render() { |
| |
| cube.position.x += 0.01; |
| if (cube.position.x > 7) { |
| cube.position.x = 0; |
| } |
| |
| cube.rotateX(0.01); |
| |
| |
| renderer.render(scene, camera); |
| |
| controls.update(); |
| |
| requestAnimationFrame(render); |
| } |
| render(); |
复制
拓展
| |
| window.addEventListener("resize", () => { |
| |
| |
| camera.aspect = window.innerWidth / window.innerHeight; |
| |
| camera.updateProjectionMatrix(); |
| |
| renderer.setSize(window.innerWidth, window.innerHeight); |
| |
| renderer.setPixelRatio(window.devicePixelRatio); |
| }); |
复制
- 在学习环境中实现
示例:通过script标签和CDN来引入three.min.js,实现一个旋转的球:
| <!DOCTYPE html> |
| <html lang="en"> |
| |
| <head> |
| <meta charset="UTF-8"> |
| <title>My First three.js app2</title> |
| <style> |
| * { |
| margin: 0; |
| padding: 0; |
| } |
| </style> |
| <script src='https://cdn.bootcss.com/three.js/91/three.min.js'></script> |
| </head> |
| |
| <body> |
| <script> |
| |
| const scene = new THREE.Scene(); |
| |
| const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000); |
| |
| const renderer = new THREE.WebGLRenderer(); |
| |
| renderer.setSize(window.innerWidth, window.innerHeight); |
| |
| document.body.appendChild(renderer.domElement); |
| |
| const geometry = new THREE.SphereGeometry(3, 30, 30); |
| |
| const material = new THREE.MeshBasicMaterial({ color: 0xB3DD, wireframe: true }); |
| |
| const ball = new THREE.Mesh(geometry, material); |
| |
| scene.add(ball); |
| |
| camera.position.z = 8; |
| function render() { |
| |
| requestAnimationFrame(render); |
| |
| ball.rotation.y += 0.005; |
| renderer.render(scene, camera); |
| } |
| render(); |
| </script> |
| </body> |
| |
| </html> |
| |
复制
效果如下:
