友情链接:threejs 中文文档
目录
1. threejs文件包下载及目录简介
(1) 文件包下载
npm命令下载
npm install [email protected] --save
(2) 特定版本文件包下载
github链接查看所有版本threejs:https://github.com/mrdoob/three.js/releases
如果你那边gihtub打不开或下载很慢,你可以使用下面提供的网盘资源下载。
网盘链接: https://pan.baidu.com/s/1_Ix8TiOScypNcQe3BIl5vA?pwd=rrks提取码:rrks
2. 引入threejs
(1) vue或react框架环境引入
// 引入three.js
import * as THREE from 'three';
// 引入扩展库OrbitControls.js
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// 引入扩展库GLTFLoader.js
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
(2) html环境
<script type="module">
// 现在浏览器支持ES6语法,自然包括import方式引入js文件
import * as THREE from './build/three.module.js';
</script>
<!-- 具体路径配置,需要根据自己文件目录设置 -->
<script type="importmap">
{
"imports": {
"three": "../../../three.js/build/three.module.js"
}
}
</script>
3. 创建场景
入门Three.js的第一步,就是认识场景Scene、相机Camera、渲染器Renderer三个基本概念。
(1) 三维场景
你可以把三维场景Scene对象理解为虚拟的3D场景,用来表示模拟生活中的真实三维场景,或者说三维世界。
// 创建3D场景对象Scene
const scene = new THREE.Scene();
(2) 几何体
Three.js提供了各种各样的几何体API,用来表示三维物体的几何形状。
(3) 物体外观:材质Material
如果你想定义物体的外观效果,比如颜色,就需要通过材质Material相关的API实现。
threejs不同材质渲染效果不同,下面就以threejs最简单的网格基础材质MeshBasicMaterial 为例给大家实现一个红色材质效果。
//创建一个材质对象Material
const material = new THREE.MeshBasicMaterial({
color: 0xff0000,//0xff0000设置材质颜色为红色
});
(4) 物体:网格模型Mesh
实际生活中有各种各样的物体,在threejs中可以通过网格模型Mesh表示一个虚拟的物体,比如一个箱子、一个鼠标。
// 两个参数分别为几何体geometry、材质material
const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
(5) 模型位置.potion
实际生活中,一个物体往往是有位置的,对于threejs而言也是一样的,你可以通过位置属性.position定义网格模型Mesh在三维场景Scene中的位置。
(6) .add() 方法
在threejs中你创建了一个表示物体的虚拟对象Mesh,需要通过.add()方法,把网格模型mesh添加到三维场景scene中。
scene.add(mesh);
4. 透视投影相机
(1) 创建透视投影相机
// 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);
(2) 相机方法介绍
// .position 设置相机位置
camera.position.set(200, 200, 200);
// .lookAt 设置观察目标位置
camera.lookAt(0, 10, 0);
(3) 透视投影相机参数介绍
PerspectiveCamera( fov, aspect, near, far )
参数 | 含义 | 默认值 |
---|---|---|
fov | 相机视锥体竖直方向视野角度 | 50 |
aspect | 相机视锥体水平方向和竖直方向长度比,一般设置为Canvas画布宽高比width / height | 1 |
near | 相机视锥体近裁截面相对相机距离 | 0.1 |
far | 相机视锥体远裁截面相对相机距离,far-near构成了视锥体高度方向 | 2000 |
5. 渲染器
生活中如果有了景物和相机,那么如果想获得一张照片,就需要你拿着相机,按一下,咔,完成拍照。对于threejs而言,如果完成“咔”这个拍照动作,就需要一个新的对象,也就是WebGL渲染器WebGLRenderer 。
(1) 渲染器基础配置
// 创建渲染器对象
const renderer = new THREE.WebGLRenderer({
antialias:true, // 开启抗锯齿
});
// 设置像素比
renderer.setPixelRatio(window.devicePixelRatio);
// 设置背景颜色
renderer.setClearColor(0x444444, 1);
// 设置three.js渲染区域的尺寸(像素px)
renderer.setSize(800, 500);
// 执行渲染操作
renderer.render(scene, camera);
// 添加到页面元素中
document.body.appendChild(renderer.domElement);
(2) 渲染器重复渲染
threejs可以借助HTML5的API请求动画帧window.requestAnimationFrame实现动画渲染
// 渲染函数
function render() {
renderer.render(scene, camera); //执行渲染操作
requestAnimationFrame(render);//请求再次执行渲染函数render,渲染下一帧
}
render();
6. 相机控件OrbitControls
平时开发调试代码,或者展示模型的时候,可以通过相机控件OrbitControls实现旋转缩放预览效果。
- 旋转:拖动鼠标左键
- 缩放:滚动鼠标中键
- 平移:拖动鼠标右键
(1) 引入OrbitControls文件库
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
(2) 使用OrbitControls
// 设置相机控件轨道控制器OrbitControls
const controls = new OrbitControls(camera, renderer.domElement);
// 如果OrbitControls改变了相机参数,重新调用渲染器渲染三维场景
controls.addEventListener('change', function () {
renderer.render(scene, camera); //执行渲染操作
});//监听鼠标、键盘事件
7. 光源
在threejs中,需要设置光源来照亮我们的场景,常用的光源有点光源PointLight、平行光DirectionalLight、环境光AmbientLight
平行光和环境光的使用
//环境光:没有特定方向,整体改变场景的光照明暗
const ambient = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambient);
// 平行光:有光源位置方向和光源指向方向
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
// 设置光源的方向:通过光源position属性和目标指向对象的position属性计算 directionalLight.position.set(80, 100, 50);
// 方向光指向对象网格模型mesh,可以不设置,默认的位置是0,0,0
directionalLight.target = mesh;
scene.add(directionalLight);
8. gui.js库
gui.js就是一个前端js库,对HTML、CSS和JavaScript进行了封装,学习开发的时候,借助gui.js可以快速创建控制三维场景的UI交互界面
// 引入dat.gui.js的一个类GUI
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
// 实例化一个gui对象
const gui = new GUI();
//改变交互界面style属性
gui.domElement.style.right = '0px';
gui.domElement.style.width = '300px';
//创建一个对象,对象属性的值可以被GUI库创建的交互界面改变
const obj = {
x: 30,
};
// gui增加交互界面,用来改变obj对应属性
gui.add(obj, 'x', 0, 100);
9. gui.js库方法
// .name()方法 改变gui生成交互界面显示的内容
gui.add(ambient, 'intensity', 0, 2.0).name('环境光强度');
// .step()方法 设置交互界面每次改变属性值间隔是多少
gui.add(ambient, 'intensity', 0, 2.0).name('环境光强度').step(0.1);
// .onChange()方法 返回一个监听属性值的函数
const obj = {
x: 30,
};
// 当obj的x属性变化的时候,就把此时obj.x的值value赋值给mesh的x坐标
gui.add(obj, 'x', 0, 180).onChange(function(value){
mesh.position.x = value;
// 你可以写任何你想跟着obj.x同步变化的代码
// 比如mesh.position.y = value;
});
// .addColor()生成颜色值改变的交互界面
const obj = {
color:0x00ffff,
};
// .addColor()生成颜色值改变的交互界面
gui.addColor(obj, 'color').onChange(function(value){
mesh.material.color.set(value);
});
10. gui.js 生成下拉菜单、单选框
// 如果参数3、参数4数据类型为数字,则gui生成拖动条
gui.add(obj, 'x', 0, 180).onChange(function (value) {
mesh.position.x = value;
});
// 如果参数3数据类型为数组,则gui生成下拉菜单
const obj = {
scale: 0,
};
gui.add(obj, 'scale', [-100, 0, 100]).name('y坐标').onChange(function (value) {
mesh.position.y = value;
});
// 如果参数3数据类型为对象,gui也生成下拉菜单
const obj = {
scale: 0,
};
gui.add(obj, 'scale', {
left: -100,
center: 0,
right: 100
}).name('位置选择').onChange(function (value) {
mesh.position.x = value;
});
// 如果参数为布尔类型,则gui生成单选框
const obj = {
bool: false,
};
gui.add(obj, 'bool').name('是否旋转');
11. gui.js 分组
// 当gui交互界面要控制的属性过多的情况下,为了避免混合,需要用到分组管理
// 通过gui对象的.addFolder()方法可以创建一个子菜单
// .close()关闭菜单和.open()展开菜单
const gui = new GUI(); //创建GUI对象
const obj = {
color: 0x00ffff,// 材质颜色
};
// 创建材质子菜单
const matFolder = gui.addFolder('材质');
matFolder.close();
// 材质颜色color
matFolder.addColor(obj, 'color').onChange(function(value){
material.color.set(value);
});
// 材质高光颜色specular
matFolder.addColor(obj, 'specular').onChange(function(value){
material.specular.set(value);
});
// 创建环境光子菜单
const ambientFolder = gui.addFolder('环境光');
// 环境光强度
ambientFolder.add(ambient, 'intensity',0,2);
// 平行光强度
dirFolder.add(directionalLight, 'intensity',0,2);
// 平行光位置
dirFolder.add(directionalLight.position, 'x',-400,400);
dirFolder.add(directionalLight.position, 'y',-400,400);
dirFolder.add(directionalLight.position, 'z',-400,400);
小案例分享
import * as THREE from 'three';
import {
OrbitControls
} from 'three/addons/controls/OrbitControls.js';
import Stats from 'three/addons/libs/stats.module.js';
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
// 创建帧率显示器
const stats = new Stats();
document.body.appendChild(stats.domElement);
// 创建GUI对象
const gui = new GUI();
// 创建三维场景
const scene = new THREE.Scene();
// 创建立方体
const geometry = new THREE.BoxGeometry(100, 100, 100);
// 创建材质对象
const material = new THREE.MeshLambertMaterial({
color: '#008B8B',
transparent: true, //开启透明
opacity: 0.7, //设置透明度
});
// 循环创建多个几何体
for (let i = 0; i < 10; i++) {
for (let j = 0; j < 10; j++) {
const mesh = new THREE.Mesh(geometry, material);
mesh.position.set(i * 200, 0, j * 200);
scene.add(mesh);
}
}
// 创建圆柱体
const CylinderGeometry = new THREE.CylinderGeometry(50, 50, 200, 32);
const MeshBasicMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 });
const cylinder = new THREE.Mesh(CylinderGeometry, MeshBasicMaterial);
cylinder.position.set(-400, 0, -400)
scene.add(cylinder);
// 创建坐标轴
const axesHelper = new THREE.AxesHelper(2000);
scene.add(axesHelper)
// 创建环境光
const ambient = new THREE.AmbientLight('#ffffff', 1.2);
ambient.position.set(80, 120, 70);
scene.add(ambient);
// 创建平行光
const directional = new THREE.DirectionalLight('#ffffff', 2);
directional.position.set(200, 120, 200);
directional.target = cylinder;
scene.add(directional);
gui.add(directional.position, 'x', 0, 2000);
gui.add(directional.position, 'y', 0, 2000);
gui.add(directional.position, 'z', 0, 2000);
// 获取浏览器的宽和高
const width = window.innerWidth;
const height = window.innerHeight;
// 创建透视相机 30:相机角度; width/height:画布宽高比; 1:近裁截面, 3000:远裁截面
const camera = new THREE.PerspectiveCamera(60, width / height, 10, 6000);
camera.position.set(1000, 3000, 3000);
camera.lookAt(1000, 0, 0);
// 创建渲染器
const renderer = new THREE.WebGLRenderer({
antialias: true,
});
// 设置像素比
renderer.setPixelRatio(window.devicePixelRatio);
// 设置背景颜色
renderer.setClearColor(0x444444, 1);
// 定义渲染区域大小
renderer.setSize(width, height);
// 执行渲染
renderer.render(scene, camera);
// 将渲染器绑定到元素上
document.getElementById('map').appendChild(renderer.domElement);
// 循环渲染
function render () {
renderer.render(scene, camera);
//渲染循环中执行stats.update()来刷新时间
stats.update();
// 网格绕y轴增加弧度
cylinder.rotateY(0.005);
// 在下次重绘之前执行render函数
window.requestAnimationFrame(render);
}
render();
// 创建相机轨道控制器
const controls = new OrbitControls(camera, renderer.domElement);
// 创建相机轨道控制器后会重置相机的lookAt()参数
controls.target.set(1000, 0, 0);
controls.update();
window.onresize = function () {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
}
文章中部分素材选取自Threejs中文网:Three.js中文网