引入three.js
1.script标签引入
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Three.js中文网:http://www.webgl3d.cn/</title>
<!-- 引入three.js -->
<script src="./build/three.js"></script>
</head>
<body>
<script>
// 浏览器控制台测试,是否引入成功
console.log(THREE.Scene);
</script>
</body>
</html>
2.import方式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Three.js中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<script type="module">
// ES6写法import引入
import * as THREE from './build/three.module.js';
// 浏览器控制台测试,是否引入成功
console.log(THREE.Scene);
</script>
</body>
</html>
3.模拟npm安装的写法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Three.js中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<!-- type="importmap"功能:.html文件中也能和nodejs开发环境中一样方式,引入npm安装的js库 -->
<script type="importmap">
{
"imports": {
"three": "../../../three.js/build/three.module.js"
}
}
</script>
<script type="module">
// 引入three.js库:借助<script type="importmap">,和nodejs开发环境中写法一样
import * as THREE from 'three';
// 浏览器控制台测试,是否引入成功
console.log(THREE.Scene);
</script>
</body>
</html>
4.扩展库—模拟npm安装的写法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Three.js中文网:http://www.webgl3d.cn/</title>
</head>
<body>
<!-- type="importmap"功能:.html文件中也能和nodejs开发环境中一样方式,引入npm安装的js库 -->
<script type="importmap">
{
"imports": {
"three": "../../../three.js/build/three.module.js",
"three/addons/": "../../../three.js/examples/jsm/"
}
}
</script>
<script type="module">
// 引入three.js库:借助<script type="importmap">,和nodejs开发环境中写法一样
import * as THREE from 'three';
// 浏览器控制台测试,是否引入成功
console.log(THREE.Scene);
// 引入扩展库OrbitControls.js
import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
// 引入扩展库GLTFLoader.js
import {GLTFLoader} from 'three/addons/loaders/GLTFLoader.js';
console.log(OrbitControls);
console.log(GLTFLoader);
</script>
</body>
</html>
第一个3D案例—创建3D场景
入门Three.js的第一步,就是认识场景Scene、相机Camera、渲染器Renderer三个基本概念。这样我们就能透过摄像机渲染出场景
三维场景Scene
构造器
你可以把三维场景Scene (opens new window)对象理解为虚拟的3D场景,用来表示模拟生活中的真实三维场景,或者说三维世界。
// 创建3D场景对象Scene
const scene = new THREE.Scene();
物体形状:几何体Geometry
Three.js提供了各种各样的几何体API,用来表示三维物体的几何形状。
文档搜索关键词geometry
你可以看到threejs提供各种几何体相关API,例如立方缓冲几何体(BoxGeometry
)。
BoxGeometry 是四边形的原始几何类,它通常使用构造函数所提供的 “width”、“height”、“depth” 参数来创建立方体或者不规则四边形。每个几何体内部传参都不一样这里只是列举。具体参考官方文档
//创建一个长方体几何对象Geometry
const geometry = new THREE.BoxGeometry(100, 100, 100);
物体外观:材质Material
如果你想定义物体的外观效果,比如颜色,就需要通过材质Material
相关的API实现。
threejs不同材质渲染效果不同,下面就以threejs最简单的网格基础材质MeshBasicMaterial (opens new window)为例实现一个红色材质效果。
//创建一个材质对象Material
const material = new THREE.MeshBasicMaterial({
color: 0xff0000,//0xff0000设置材质颜色为红色
});
物体:网格模型Mesh
实际生活中有各种各样的物体,在threejs中可以通过网格模型Mesh (opens new window)表示一个虚拟的物体,比如一个箱子、一个鼠标。
// 两个参数分别为几何体geometry、材质material
const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
模型位置.position
实际生活中,一个物体往往是有位置的,对于threejs而言也是一样的,你可以通过位置属性.position
定义网格模型Mesh
在三维场景Scene
中的位置。
const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
//设置网格模型在三维空间中的位置坐标,默认是坐标原点
mesh.position.set(0,10,0);
.add()
方法
在threejs中你创建了一个表示物体的虚拟对象Mesh,需要通过.add()
方法,把网格模型mesh
添加到三维场景scene
中。
scene.add(mesh); //网格模型添加到场景中
第一个3D案例—透视投影相机
Threejs如果想把三维场景Scene
渲染到web网页上,还需要定义一个虚拟相机Camera
,就像你生活中想获得一张照片,需要一台用来拍照的相机。
透视投影相机PerspectiveCamera
Threejs提供了正投影相机OrthographicCamera (opens new window)和透视投影相机PerspectiveCamera (opens new window)。本节课先给大家比较常用的透视投影相机PerspectiveCamera
。
透视投影相机PerspectiveCamera
本质上就是在模拟人眼观察这个世界的规律。
相机位置.position
生活中用相机拍照,你相机位置不同,拍照结果也不同,threejs中虚拟相机同样如此。比如有一间房子,你拿着相机站在房间里面,看到的是房间内部,站在房子外面看到的是房子外面效果。相机对象Camera
具有位置属性.position
,通过位置属性.position
可以设置相机的位置。
//相机在Three.js三维坐标系中的位置
// 根据需要设置相机位置具体值
camera.position.set(200, 200, 200);
相机观察目标.lookAt()
你用相机拍照你需要控制相机的拍照目标,具体说相机镜头对准哪个物体或说哪个坐标。对于threejs相机而言,就是设置.lookAt()
方法的参数,指定一个3D坐标。
//相机观察目标指向Threejs 3D空间中某个位置
camera.lookAt(0, 0, 0); //坐标原点
camera.lookAt(0, 10, 0); //y轴上位置10
camera.lookAt(mesh.position);//指向mesh对应的位置
判断相机相对三维场景中长方体位置
你可以把三维场景中长方体mesh
想象为一个房间,然后根据相机位置和长方体位置尺寸对比,判断两者相对位置。你可以发现设置相机坐标(200, 200, 200),位于长方体外面一处位置。
// 长方体尺寸100, 100, 100
const geometry = new THREE.BoxGeometry( 100, 100, 100 );
const mesh = new THREE.Mesh(geometry,material);
// 网格模型位置xyz坐标:0,10,0
mesh.position.set(0,10,0);
// 相机位置xyz坐标:200, 200, 200
camera.position.set(200, 200, 200);
定义相机渲染输出的画布尺寸
你生活中相机拍照的照片是有大小的,对于threejs而言一样,需要定义相机在网页上输出的Canvas画布(照片)尺寸,大小可以根据需要定义,这里先随机定义一个尺寸。
Canvas画布:课程中会把threejs虚拟相机渲染三维场景在浏览器网页上呈现的结果称为Canvas画布。
// 定义相机输出画布的尺寸(单位:像素px)
const width = 800; //宽度
const height = 500; //高度
透视投影相机PerspectiveCamera
:视锥体
透视投影相机的四个参数fov, aspect, near, far
构成一个四棱台3D空间,被称为视锥体,只有视锥体之内的物体,才会渲染出来,视锥体范围之外的物体不会显示在Canvas画布上。
// width和height用来设置Three.js输出的Canvas画布尺寸(像素px)
const width = 800; //宽度
const height = 500; //高度
// 30:视场角度, width / height:Canvas画布宽高比, 1:近裁截面, 3000:远裁截面
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
PerspectiveCamera
参数介绍:
PerspectiveCamera( fov, aspect, near, far )
参数 | 含义 | 默认值 |
---|---|---|
fov | 相机视锥体竖直方向视野角度 | 50 |
aspect | 相机视锥体水平方向和竖直方向长度比,一般设置为Canvas画布宽高比width / height | 1 |
near | 相机视锥体近裁截面相对相机距离 | 0.1 |
far | 相机视锥体远裁截面相对相机距离,far-near构成了视锥体高度方向 | 20 |
第一个3D案例—渲染器
生活中如果有了景物和相机,那么如果想获得一张照片,就需要你拿着相机,按一下,咔,完成拍照。对于threejs而言,如果完成“咔”这个拍照动作,就需要一个新的对象,也就是WebGL渲染器WebGLRenderer (opens new window)。
渲染器WebGLRenderer
通过WebGL渲染器WebGLRenderer (opens new window)可以实例化一个WebGL渲染器对象。
// 创建渲染器对象
const renderer = new THREE.WebGLRenderer();
设置Canvas画布尺寸.setSize()
// 定义threejs输出画布的尺寸(单位:像素px)
const width = 800; //宽度
const height = 500; //高度
renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)
渲染器渲染方法.render()
渲染器WebGLRenderer
执行渲染方法.render()
就可以生成一个Canvas画布(照片),并把三维场景Scene呈现在canvas画布上面,你可以把.render()
理解为相机的拍照动作“咔”。
renderer.render(scene, camera); //执行渲染操作
渲染器Canvas画布属性.domElement
渲染器WebGLRenderer
通过属性.domElement
可以获得渲染方法.render()
生成的Canvas画布,.domElement
本质上就是一个HTML元素:Canvas画布。
document.body.appendChild(renderer.domElement);
Canvas画布插入到任意HTML元素中
<div id="webgl" style="margin-top: 200px;margin-left: 100px;"></div>
document.getElementById('webgl').appendChild(renderer.domElement);
代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Threejs中文网:www.webgl3d.cn</title>
</head>
<body>
<!-- type="importmap"功能:.html文件中也能和nodejs开发环境中一样方式,引入npm安装的js库 -->
<script type="importmap">
{
"imports": {
"three": "../../../three.js/build/three.module.js"
}
}
</script>
<script src="./index.js" type="module">
</script>
</body>
</html>
// 引入three.js
import * as THREE from 'three';
/**
* 创建3D场景对象Scene
*/
const scene = new THREE.Scene();
/**
* 创建网格模型
*/
//创建一个长方体几何对象Geometry
const geometry = new THREE.BoxGeometry(50, 50, 50);
//材质对象Material
const material = new THREE.MeshBasicMaterial({
color: 0x0000ff, //设置材质颜色
});
const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
//设置网格模型在三维空间中的位置坐标,默认是坐标原点
mesh.position.set(50,50,50);
scene.add(mesh); //网格模型添加到场景中
// width和height用来设置Three.js输出的Canvas画布尺寸(像素px)
const width = 800; //宽度
const height = 500; //高度
/**
* 透视投影相机设置
*/
// 30:视场角度, width / height:Canvas画布宽高比, 1:近裁截面, 3000:远裁截面
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
camera.position.set(200, 200, 200); //相机在Three.js三维坐标系中的位置
camera.lookAt(0, 0, 0); //相机观察目标指向Three.js坐标系原点
/**
* 创建渲染器对象
*/
const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)
renderer.render(scene, camera); //执行渲染操作
//three.js执行渲染命令会输出一个canvas画布,也就是一个HTML元素,你可以插入到web页面中
document.body.appendChild(renderer.domElement);
效果
三维坐标系-加强三维空间认识
辅助观察坐标系
THREE.AxesHelper()
的参数表示坐标系坐标轴线段尺寸大小,你可以根据需要改变尺寸。
// AxesHelper:辅助观察的坐标系
const axesHelper = new THREE.AxesHelper(150);
scene.add(axesHelper);
材质半透明设置
设置材质半透明,这样可以看到坐标系的坐标原点。
const material = new THREE.MeshBasicMaterial({
color: 0x0000ff, //设置材质颜色
transparent:true,//开启透明
opacity:0.5,//设置透明度
});
AxesHelper
的xyz轴
three.js坐标轴颜色红R、绿G、蓝B分别对应坐标系的x、y、z轴,对于three.js的3D坐标系默认y轴朝上
设置模型在坐标系中的位置或尺寸
通过模型的位置、尺寸设置,加深3D坐标系的概念。
测试:设置长方体xyz不同方向尺寸
// 设置几何体长宽高,也就是x、y、z三个方向的尺寸
//对比三个参数分别对应xyz轴哪个方向
new THREE.BoxGeometry(100, 60, 20);
测试:改变位置
// 设置模型mesh的xyz坐标
mesh.position.set(100,0,0);
改变相机参数——预览新的渲染效果
相机放在x轴负半轴,目标观察点是坐标原点,这样相当于相机的视线是沿着x轴正方向,只能看到长方体的一个矩形平面。
camera.position.set(-1000, 0, 0);
camera.lookAt(0, 0, 0);
// 相机视线沿着x轴负半轴,mesh位于相机后面,自然看不到
camera.position.set(-1000, 0, 0);
camera.lookAt(-2000, 0, 0);
相机far偏小,mesh位于far之外,物体不会显示在画布上。
// const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
// 你可以进行下面测试,改变相机参数,把mesh放在视锥体之外,看看是否显示
// 3000改为300,使mesh位于far之外,mesh不在视锥体内,被剪裁掉
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 300);
光源对物体表面影响
实际生活中物体表面的明暗效果是会受到光照的影响,比如晚上不开灯,你就看不到物体,灯光比较暗,物体也比较暗。在threejs中,咱们用网格模型Mesh
模拟生活中物体,所以threejs中模拟光照Light
对物体表面的影响,就是模拟光照Light
对网格模型Mesh
表面的影响。
受光照影响材质
threejs提供的网格材质,有的受光照影响,有的不受光照影响。
基础网格材质MeshBasicMaterial (opens new window)不会受到光照影响。
//MeshBasicMaterial不受光照影响
const material = new THREE.MeshBasicMaterial();
漫反射网格材质MeshLambertMaterial (opens new window)会受到光照影响,该材质也可以称为Lambert网格材质,音译为兰伯特网格材质。
一个立方体长方体使用MeshLambertMaterial材质,不同面和光线夹角不同,立方体不同面就会呈现出来不同的明暗效果。
//MeshLambertMaterial受光照影响
const material = new THREE.MeshLambertMaterial();
光源简介
Three.js提供了多种模拟生活中光源的API,文档搜索关键词light就可以看到(Light – three.js docs (threejs.org))。
点光源
点光源PointLight (opens new window)可以类比为一个发光点,就像生活中一个灯泡以灯泡为中心向四周发射光线。
//点光源:两个参数分别表示光源颜色和光照强度
// 参数1:0xffffff是纯白光,表示光源颜色
// 参数2:1.0,表示光照强度,可以根据需要调整
const pointLight = new THREE.PointLight(0xffffff, 1.0);
除了通过THREE.PointLight
的参数2设置光照强度,你可以可以直接访问光照强度属性.intensity
设置。
pointLight.intensity = 1.0;//光照强度
光源衰减
实际生活中点光源,比如比如一个灯泡,随机距离的改变,光线会衰减,越来越弱,光源衰减属性.decay
默认值是2.0,如果你不希望衰减可以设置为0.0
。
pointLight.decay = 0.0;//设置光源不随距离衰减
【扩展提醒】:如果使用默认衰减2.0
,不同版本可能有差异,对于部分threejs新版本,有时候你可能看不到光源效果,这时候可以把光照强度加强试试看,如果你的版本不影响,就不用加强光照强度(根据版本情况灵活对应)。
// 你可以对比不同光照强度明暗差异(传播同样距离)
pointLight.intensity = 10000.0;//光照强度
pointLight.intensity = 50000.0;//光照强度
光源位置
把点光源想象为一个电灯泡,你在3D空间中,放的位置不同,模型的渲染效果就不一样。
注意光源位置尺寸大小:如果你希望光源照在模型的外表面,那你就需要把光源放在模型的外面。
//点光源位置
pointLight.position.set(400, 0, 0);//点光源放在x轴上
#光源添加到场景
光源和网格模型Mesh对应一样是三维场景的一部分,自然需要添加到三维场景中才能起作用。
scene.add(pointLight); //点光源添加到场景中
设置好上面所有代码,用浏览器查看渲染效果。
#改变光源位置,观察网格模型表面的明暗变化。
pointLight.position.set(400, 200, 300);
相机控件OrbitControls
开发调试代码,或者展示模型的时候,可以通过相机控件OrbitControls实现旋转缩放预览效果
OrbitControls使用
引入扩展库OrbitControls.js
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
注意:如果你在原生.html文件中,使用上面引入方式
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
,注意通过<script type="importmap">
配置。
<script type="importmap">
{
"imports": {
"three": "../../../three.js/build/three.module.js",
"three/addons/": "../../../three.js/examples/jsm/"
}
}
</script>
使用OrbitControls
// 设置相机控件轨道控制器OrbitControls
const controls = new OrbitControls(camera, renderer.domElement);
// 如果OrbitControls改变了相机参数,重新调用渲染器渲染三维场景
controls.addEventListener('change', function () {
renderer.render(scene, camera); //执行渲染操作
});//监听鼠标、键盘事件
OrbitControls本质
OrbitControls本质上就是改变相机的参数,比如相机的位置属性,改变相机位置也可以改变相机拍照场景中模型的角度,实现模型的360度旋转预览效果,改变透视投影相机距离模型的距离,就可以改变相机能看到的视野范围。
controls.addEventListener('change', function () {
// 浏览器控制台查看相机位置变化
console.log('camera.position',camera.position);
});