Three.js中文网:http://www.webgl3d.cn/
一、简介
开启 Web 3D 之门:WebGL与Three.js简介 | Threejs指南
二、three.js下载
Three.js -- JavaScript 3D Library

mrdoob/three.js: JavaScript 3D Library.
three.js: JavaScript 3D Library. - Gitee.com

文档


案例


三、开发和学习环境,引入threejs库
除了three.js核心库以外,在threejs文件包中examples/jsm目录下,扩展库很多


// 引入扩展库OrbitControls.js
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.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
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(0, 10, 0);
//网格模型添加到场景中
scene.add(mesh);
console.log('三维场景',scene);
<!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>

透视投影相机
如果想把三维场景Scene渲染到web网页上,还需要定义一个虚拟相机
// 创建一个透视投影相机对象
// width和height用来设置渲染后,输出的画布宽高度。
const width = 800; //宽度
const height = 500; //高度
/**
* 透视投影相机设置,相机对象Camera具有位置属性.position,通过位置属性.position可以设置相机的位置。
*/
// 30:视场角度, width / height:Canvas画布宽高比, 1:近裁截面, 3000:远裁截面
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
camera.position.set(292, 223, 185); //相机在Three.js三维坐标系中的位置
// camera.lookAt(0, 1, 0); //y轴上一点
// camera.lookAt(mesh.position);//指向网络模型mesh
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);

<div id="webgl" style="margin-top: 200px;margin-left: 100px;"></div>
// 将渲染器的DOM元素添加到页面中id为'webgl'的元素内
document.getElementById('webgl').appendChild(renderer.domElement);

五、Threejs三维坐标系
javascript
/**
* 创建网格模型
*/
//创建一个长方体几何对象Geometry
const geometry = new THREE.BoxGeometry(50, 50, 50);
//材质对象Material
const material = new THREE.MeshBasicMaterial({
color: 0xffffff, //设置材质颜色
transparent: true, //开启透明
opacity: 0.5, //设置透明度
});
const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
//设置网格模型在三维空间中的位置坐标,默认是坐标原点
// mesh.position.set(0,10,0);
scene.add(mesh); //网格模型添加到场景中
// AxesHelper:辅助观察的坐标系
const axesHelper = new THREE.AxesHelper(100);
scene.add(axesHelper);


六、光源对物体表面影响





七、相机控件轨道控制器OrbitControls
index.html
html
<script type="importmap">
{
"imports": {
"three": "../../../three.js/build/three.module.js",
"three/addons/": "../../../three.js/examples/jsm/"
}
}
</script>
javascript
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
// 设置相机控件轨道控制器OrbitControls
const controls = new OrbitControls(camera, renderer.domElement);
// 如果OrbitControls改变了相机参数,重新调用渲染器渲染三维场景
controls.addEventListener("change", function () {
renderer.render(scene, camera); //执行渲染操作
// 浏览器控制台查看相机位置变化
console.log("camera.position", camera.position);
}); //监听鼠标、键盘事件

控制台

八、平行光与环境光
可视化点光源
javascript
/**
* 光源设置
*/
// //点光源
const pointLight = new THREE.PointLight(0xffffff, 1.0);
// //点光源位置
pointLight.position.set(400, 200, 300);
pointLight.decay = 0.0; //不随着距离的改变而衰减,默认衰减2.0
scene.add(pointLight); //点光源添加到场景中
//可视化点光源
const pointLightHelper = new THREE.PointLightHelper(pointLight, 5, 0xff0000);
scene.add(pointLightHelper);

环境光
javascript
//环境光:没有特定方向,整体改变场景的光照明暗
const ambient = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambient);

平行光
javascript
// 平行光
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
// 设置光源的方向:通过光源position属性和目标指向对象的position属性计算
directionalLight.position.set(100, 60, 50);
// 方向光指向对象网格模型mesh,可以不设置,默认的位置是0,0,0
directionalLight.target = mesh;
scene.add(directionalLight);
// DirectionalLightHelper:可视化平行光
const dirLightHelper = new THREE.DirectionalLightHelper(directionalLight, 5,0xff0000);
scene.add(dirLightHelper);

九、动画渲染循环
请求动画帧
javascript
<script>
// requestAnimationFrame实现周期性循环执行
// requestAnimationFrame默认每秒钟执行60次,但不一定能做到,要看代码的性能
let i = 0;
function render() {
i+=1;
console.log('执行次数'+i);
requestAnimationFrame(render);//请求再次执行函数render
}
render();
</script>

渲染循环
javascript
/**
* 创建渲染器对象
*/
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);
// 渲染循环
function render() {
renderer.render(scene, camera); //执行渲染操作
mesh.rotateY(0.01);//每次绕y轴旋转0.01弧度
requestAnimationFrame(render);//请求再次执行渲染函数render,渲染下一帧
}

计算两帧时间间隔
javascript
// 渲染循环
const clock = new THREE.Clock();
function render() {
const spt = clock.getDelta()*1000;//毫秒
console.log('两帧渲染时间间隔(毫秒)',spt);
console.log('帧率FPS',1000/spt);
renderer.render(scene, camera); //执行渲染操作
mesh.rotateY(0.01);//每次绕y轴旋转0.01弧度
requestAnimationFrame(render);//请求再次执行渲染函数render,渲染下一帧
}
render();

渲染循环+OrbitControls相机控件
javascript
// 渲染循环
function render() {
renderer.render(scene, camera); //执行渲染操作
mesh.rotateY(0.01); //每次绕y轴旋转0.01弧度
requestAnimationFrame(render); //请求再次执行渲染函数render,渲染下一帧
}
render();
// 设置相机控件轨道控制器OrbitControls
const controls = new OrbitControls(camera, renderer.domElement);
// // 如果OrbitControls改变了相机参数,重新调用渲染器渲染三维场景
// controls.addEventListener('change', function () {
// renderer.render(scene, camera); //执行渲染操作
// }); //监听鼠标、键盘事件

十、Canvas画布布局和全屏
插入到body元素中

插入到任意div元素中

全屏
javascript
// width和height用来设置Three.js输出的Canvas画布尺寸(像素px)
// const width = 800; //宽度
// const height = 500; //高度
// width和height用来设置Three.js输出的Canvas画布尺寸(像素px)
const width = window.innerWidth; //窗口文档显示区的宽度作为画布宽度
const height = window.innerHeight; //窗口文档显示区的高度作为画布高度
javascript
<style>
body{
overflow: hidden;/* 隐藏滚动条 */
margin: 0px;
}
</style>

canvas画布宽高度动态变化
javascript
// onresize 事件会在窗口被调整大小时发生
window.onresize = function () {
// 重置渲染器输出画布canvas尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
// 全屏情况下:设置观察范围长宽比aspect为窗口宽高比
camera.aspect = window.innerWidth / window.innerHeight;
// 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix
// 但是不会每渲染一帧,就通过相机的属性计算投影矩阵(节约计算资源)
// 如果相机的一些属性发生了变化,需要执行updateProjectionMatrix ()方法更新相机的投影矩阵
camera.updateProjectionMatrix();
};

十一、stats查看threejs渲染帧率
javascript
//引入性能监视器stats.js,显示帧率
import Stats from "three/addons/libs/stats.module.js";
//创建stats对象
const stats = new Stats();
//Stats.domElement:web页面上输出计算结果,一个div元素
document.body.appendChild(stats.domElement);

创建大量物体,测试性能
javascript
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
//引入性能监视器stats.js,显示帧率
import Stats from "three/addons/libs/stats.module.js";
//创建stats对象
const stats = new Stats();
//Stats.domElement:web页面上输出计算结果,一个div元素
document.body.appendChild(stats.domElement);
// 三维场景
const scene = new THREE.Scene();
// 随机创建大量的模型,测试渲染性能
const num = 1000; //控制长方体模型数量,你可以一直增加或减少看看帧率变化,电脑性能不同结果不同
for (let i = 0; i < num; i++) {
const geometry = new THREE.BoxGeometry(5, 5, 5);
const material = new THREE.MeshLambertMaterial({
color: 0xffffff,
});
const mesh = new THREE.Mesh(geometry, material);
// 随机生成长方体xyz坐标
const x = (Math.random() - 0.5) * 200;
const y = (Math.random() - 0.5) * 200;
const z = (Math.random() - 0.5) * 200;
mesh.position.set(x, y, z);
scene.add(mesh); // 模型对象插入场景中
}
//辅助观察的坐标系
const axesHelper = new THREE.AxesHelper(100);
scene.add(axesHelper);
//光源设置
const pointLight = new THREE.PointLight(0xffffff, 1.0);
pointLight.decay = 0;
pointLight.position.set(400, 200, 300);
scene.add(pointLight);
const ambient = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambient);
//渲染器和相机
const width = window.innerWidth;
const height = window.innerHeight;
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
camera.position.set(292, 223, 185);
camera.lookAt(0, 0, 0);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height);
document.body.appendChild(renderer.domElement);
// 渲染循环
function render() {
stats.update(); //渲染循环中执行stats.update()来刷新时间
renderer.render(scene, camera);
requestAnimationFrame(render);
}
render();
const controls = new OrbitControls(camera, renderer.domElement);
// 画布跟随窗口变化
window.onresize = function () {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
};

javascript
//创建stats对象
const stats = new Stats();
//stats.setMode(0); //默认模式
stats.setMode(1);
//Stats.domElement:web页面上输出计算结果,一个div元素
document.body.appendChild(stats.domElement);
(0: fps, 1: ms, 2: mb)

十二、阵列立方体和相机适配体验
立方体阵列一排
javascript
const geometry = new THREE.BoxGeometry(100, 100, 100);
const material = new THREE.MeshLambertMaterial({
color: 0xffffff,
transparent: true,
opacity: 0.5,
});
// 沿着x轴等间距创建一系列网格模型
for (let i = 0; i < 10; i++) {
// 所有模型对象共享同一个几何体或材质
const mesh = new THREE.Mesh(geometry, material);
// 沿着x轴分布
mesh.position.set(i * 200, 0, 0);
scene.add(mesh); //网格模型添加到场景中
}

立方体行列阵列
javascript
const geometry = new THREE.BoxGeometry(100, 100, 100);
const material = new THREE.MeshLambertMaterial({
color: 0xffffff,
transparent: true,
opacity: 0.5,
});
for (let i = 0; i < 10; i++) {
for (let j = 0; j < 10; j++) {
const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
// 在XOZ平面上分布
mesh.position.set(i * 200, 0, j * 200);
scene.add(mesh); //网格模型添加到场景中
}
}

调整相机参数
立方体阵列为基础
javascript
/**
* 透视投影相机设置
*/
// 30:视场角度, width / height:Canvas画布宽高比, 1:近裁截面, 3000:远裁截面
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 8000);
camera.position.set(292, 223, 185); //相机在Three.js三维坐标系中的位置
// 1. 相机位置拉远,可以看到更大的观察范围
//camera.position.set(800, 800, 800);
// 2. 超出视锥体远裁界面的范围的会被剪裁掉,不渲染 可以调整far参数适配
//camera.position.set(2000, 2000, 2000);
camera.lookAt(0, 0, 0); //相机观察目标指向Three.js坐标系原点
// 3. 改变相机观察目标点
// camera.lookAt(1000, 0, 1000);
// 4. 一个物体:体验透视投影相机远小近大的投影规律
// 5. 视野角度fov越大,观察范围越大



相机控件影响lookAt值,camera.lookAt(0, 0, 0); camera.lookAt(1000, 0, 1000);


javascript
/**
* 透视投影相机设置
*/
// 30:视场角度, width / height:Canvas画布宽高比, 1:近裁截面, 3000:远裁截面
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 8000);
// camera.position.set(292, 223, 185); //相机在Three.js三维坐标系中的位置
// 1. 相机位置拉远,可以看到更大的观察范围
// camera.position.set(800, 800, 800);
// 2. 超出视锥体远裁界面的范围的会被剪裁掉,不渲染 可以调整far参数适配
camera.position.set(2000, 2000, 2000);
camera.lookAt(0, 0, 0); //相机观察目标指向Three.js坐标系原点
// 3. 改变相机观察目标点
// camera.lookAt(1000, 0, 1000);
// 4. 一个物体:体验透视投影相机远小近大的投影规律
// 5. 视野角度fov越大,观察范围越大
const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height);
document.body.appendChild(renderer.domElement);
// 渲染循环
function render() {
renderer.render(scene, camera);
requestAnimationFrame(render);
}
render();
const controls = new OrbitControls(camera, renderer.domElement);
// 相机控件.target属性在OrbitControls.js内部表示相机目标观察点,默认0,0,0
console.log("controls.target", controls.target);
controls.target.set(0, 0, 0);
// controls.target.set(1000, 0, 1000);
controls.update(); //update()函数内会执行camera.lookAt(controls.targe)


十三、Threejs常见简单几何体简介
javascript
//BoxGeometry:长方体
const geometry = new THREE.BoxGeometry(200, 100, 100);

javascript
// SphereGeometry:球体
const geometry = new THREE.SphereGeometry(50);

javascript
// CylinderGeometry:圆柱
const geometry = new THREE.CylinderGeometry(50,50,100);


javascript
// PlaneGeometry:矩形平面
const geometry = new THREE.PlaneGeometry(100,50);

javascript
// CircleGeometry:圆形平面
const geometry = new THREE.CircleGeometry(50);

十四、高光网格材质MeshPhongMaterial
javascript
// 创建网格模型
//BoxGeometry:长方体
// const geometry = new THREE.BoxGeometry(100, 100, 100);
// SphereGeometry:球体
const geometry = new THREE.SphereGeometry(50);
// MeshBasicMaterial不受光照影响
// const material = new THREE.MeshBasicMaterial({
// color: 0xff0000,
// });
// 漫反射,没有镜面反射效果,不会产生局部高光效果
// const material = new THREE.MeshLambertMaterial({
// color: 0xff0000,
// });
// 模拟镜面反射,产生一个高光效果
const material = new THREE.MeshPhongMaterial({
color: 0xff0000,
shininess: 20, //高光部分的亮度,默认30
specular: 0x444444, //高光部分的颜色
});
漫反射,没有镜面反射效果,不会产生局部高光效果(左


十五、WebGL渲染器设置(锯齿模糊、背景颜色)
渲染器锯齿属性.antialias
javascript
// WebGL渲染器设置
const renderer = new THREE.WebGLRenderer({
antialias: true, //开启优化锯齿
});
设备像素比window.devicePixelRatio
javascript
// 不同硬件设备的屏幕的设备像素比window.devicePixelRatio值可能不同
console.log("查看当前屏幕设备像素比", window.devicePixelRatio);
2560*1440

1920*1080

设置设备像素比.setPixelRatio()
javascript
// 获取你屏幕对应的设备像素比.devicePixelRatio告诉threejs,以免渲染模糊问题
renderer.setPixelRatio(window.devicePixelRatio);
设置背景颜色.setClearColor()
javascript
renderer.setClearColor(0x0a3e1e, 0.8); //设置背景颜色

十六.gui.js库(可视化改变三维场景)
gui基本语法
javascript
// 从threejs扩展库引入gui.js
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
//创建一个GUI对象,你可以看到浏览器右上角多了一个交互界面,GUI本质上就是一个前端js库。
const gui = new GUI();
//改变交互界面style属性
gui.domElement.style.right = '0px';
gui.domElement.style.width = '300px';
//创建一个对象,对象属性的值可以被GUI库创建的交互界面改变
const obj = {
x: 30,
y: 60,
z: 300,
};
// gui界面上增加交互界面,改变obj对应属性
gui.add(obj, 'x', 0, 100);
gui.add(obj, 'y', 0, 50);
gui.add(obj, 'z', 0, 60);
// 可以不停地打印obj的值,这样通过gui界面拖动改变obj对象属性的的时候,便于观察obj的变化
setInterval(function () {
console.log('x', obj.x);
// console.log('y',obj.y);
// console.log('z',obj.z);
}, 10)
style属性

对象属性

改变obj对应属性


gui改变光照参数
javascript
// 光照强度属性.intensity
console.log("ambient.intensity", ambient.intensity);
// 通过GUI改变mesh.position对象的xyz属性
gui.add(ambient, "intensity", 0, 2.0);

gui改变threejs模型位置
javascript
// 浏览器控制可以知道mesh.position是一个具有x、y、z属性的对象
// mesh.position是一个具有x、y、z属性表示模型的xyz坐标
console.log('mesh.position',mesh.position);
// 通过GUI改变mesh.position对象的xyz属性
gui.add(mesh.position, 'x', 0, 180);
gui.add(mesh.position, 'y', 0, 180);
gui.add(mesh.position, 'z', 0, 180);

十七、gui.js库(颜色、命名、步长、事件)
颜色
javascript
// .addColor()生成颜色值改变的交互界面
gui.addColor(obj, 'color').onChange(function(value){
// console.log('obj.color',obj.color);
mesh.material.color.set(value);
});

命名
javascript
// 光照强度属性.intensity
console.log('ambient.intensity',ambient.intensity);
// 通过GUI改变mesh.position对象的xyz属性
gui.add(ambient, 'intensity', 0, 2.0).name('环境光强度');
gui.add(directionalLight, 'intensity', 0, 2.0).name('平行光强度');

步长
javascript
gui.add(ambient, "intensity", 0, 2.0).name("环境光强度").step(0.1);

事件
javascript
// 当obj的x属性变化的时候,就把此时obj.x的值value赋值给mesh的x坐标
gui.add(obj, "x", 0, 180).onChange(function (value) {
// console.log('obj.x',obj.x);
mesh.position.x = value;
});
对比
// 通过GUI改变mesh.position对象的xyz属性
gui.add(mesh.position, 'x', 0, 180);

十八、gui.js库(下拉菜单、单选框)
javascript
// 1. 参数3、参数4数据类型:数字(拖动条)
gui.add(obj, 'x', 0, 180).onChange(function (value) {
mesh.position.x = value;
});
// 2. 参数3数据类型:数组(下拉菜单)
gui.add(obj, 'scale', [-100, 0, 100]).name('y坐标').onChange(function (value) {
mesh.position.y = value;
});
// 3. 参数3数据类型:对象(下拉菜单)
gui.add(obj, 'scale', {
left: -100,
center: 0,
right: 100
// 左: -100,//可以用中文
// 中: 0,
// 右: 100
}).name('位置选择').onChange(function (value) {
mesh.position.x = value;
});
// 3. 参数3数据类型:布尔值(单选框)
gui.add(obj, 'bool').name('是否旋转');

javascript
// 渲染循环
function render() {
// 当gui界面设置obj.bool为true,mesh执行旋转动画
if (obj.bool) mesh.rotateY(0.01);
renderer.render(scene, camera);
requestAnimationFrame(render);
}

十九、gui.js库(分组)
javascript
const gui = new GUI(); //创建GUI对象
//创建一个对象,对象属性的值可以被GUI库创建的交互界面改变
const obj = {
color: 0x00ffff,// 材质颜色
specular: 0x111111,// 材质高光颜色
};
// 材质颜色color
gui.addColor(obj, 'color').onChange(function(value){
material.color.set(value);
});
// 材质高光颜色specular
gui.addColor(obj, 'specular').onChange(function(value){
material.specular.set(value);
});
// 环境光强度
gui.add(ambient, 'intensity',0,2);
// 平行光强度
gui.add(directionalLight, 'intensity',0,2);
// 平行光位置
gui.add(directionalLight.position, 'x',-400,400);
gui.add(directionalLight.position, 'y',-400,400);
gui.add(directionalLight.position, 'z',-400,400);
.addFolder()分组

材质子菜单

环境光子菜单
javascript
// 环境光子菜单
const ambientFolder = gui.addFolder("环境光");
// 环境光强度
ambientFolder.add(ambient, "intensity", 0, 2).name("环境强度");
平行光子菜单
javascript
// 平行光子菜单
const dirFolder = gui.addFolder("平行光");
// 平行光强度
dirFolder.add(directionalLight, "intensity", 0, 2).name("平行光强度");
// 平行光位置
dirFolder.add(directionalLight.position, "x", -400, 400);
dirFolder.add(directionalLight.position, "y", -400, 400);
dirFolder.add(directionalLight.position, "z", -400, 400);
总
javascript
const gui = new GUI(); //创建GUI对象
//创建一个对象,对象属性的值可以被GUI库创建的交互界面改变
const obj = {
color: 0xafafaf, // 材质颜色
specular: 0xffffff, // 材质高光颜色
};
// 创建材质子菜单
const matFolder = gui.addFolder("材质");
// 材质颜色color
matFolder
.addColor(obj, "color")
.name("材质颜色")
.onChange(function (value) {
material.color.set(value);
});
// 材质高光颜色specular
matFolder
.addColor(obj, "specular")
.name("高光颜色")
.onChange(function (value) {
material.specular.set(value);
});
// 环境光子菜单
const ambientFolder = gui.addFolder("环境光");
// 环境光强度
ambientFolder.add(ambient, "intensity", 0, 2).name("环境颜色");
// 平行光子菜单
const dirFolder = gui.addFolder("平行光");
// 平行光强度
dirFolder.add(directionalLight, "intensity", 0, 2).name("平行光强度");
// 平行光位置
dirFolder.add(directionalLight.position, "x", -400, 400);
dirFolder.add(directionalLight.position, "y", -400, 400);
dirFolder.add(directionalLight.position, "z", -400, 400);

二十、threejs语法总结
javascript
// 引入three.js
import * as THREE from "three";
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
/**
* 创建3D场景对象Scene
*/
const scene = new THREE.Scene();
// 创建网格模型
const geometry = new THREE.PlaneGeometry(100, 50);
// // new实例化类THREE.MeshLambertMaterial,创建一个材质对象
// const material = new THREE.MeshLambertMaterial();
// // 可以看到材质对象的属性color、side、opacity、transparent...
// // 通过属性可以看到threejs默认的属性值
// console.log('查看材质对象',material);
// // 查看材质默认属性值
// console.log('material.color',material.color);
// console.log('material.side',material.side);
// console.log('material.transparent',material.transparent);
// console.log('material.opacity',material.opacity);
const material = new THREE.MeshLambertMaterial({
// 通过选项参数设置材质属性
color: 0xffffff,
side: THREE.DoubleSide,
transparent: true,
opacity: 0.5,
});
// 访问对象属性改变属性的值
material.transparent = false;
material.opacity = 1.0;
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
console.log("模型位置属性", mesh.position);
mesh.position.x = 50; //访问属性改变位置x坐标
mesh.translateX(50); //执行方法改变位置属性
//辅助观察的坐标系
const axesHelper = new THREE.AxesHelper(100);
scene.add(axesHelper);
//光源设置
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(400, 200, 300);
scene.add(directionalLight);
const ambient = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambient);
console.log("directionalLight", ambient.intensity);
directionalLight.intensity = 0.1; //改变光源强度
//相机
const width = window.innerWidth;
const height = window.innerHeight;
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
camera.position.set(292, 223, 185);
camera.lookAt(0, 0, 0);
// WebGL渲染器设置
const renderer = new THREE.WebGLRenderer({
antialias: true, //开启优化锯齿
});
renderer.setPixelRatio(window.devicePixelRatio); //防止输出模糊
renderer.setSize(width, height);
document.body.appendChild(renderer.domElement);
// 设置相机控件轨道控制器OrbitControls
const controls = new OrbitControls(camera, renderer.domElement);
// 渲染循环
function render() {
renderer.render(scene, camera);
requestAnimationFrame(render);
}
render();
// 画布跟随窗口变化
window.onresize = function () {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
};
二十一、【选修】Vue + Threejs 开发环境( 可跳过 )
javascript
npm create vite@latest

javascript
# 安装 Three.js 核心库
npm install three

清理工程
src\App.vue
javascript
<script setup>
</script>
<template>
</template>
<style scoped>
</style>
src\style.css
javascript
body{
margin: 0;
}
新建index.js
导入
javascript
import * as THREE from "three";
// 三维场景
const scene = new THREE.Scene();
// 模型对象
const geometry = new THREE.BoxGeometry(50, 50, 50);
const material = new THREE.MeshBasicMaterial({
color: 0xffffff,
transparent: true,
opacity: 0.8,
});
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
// AxesHelper:辅助观察的坐标系
const axesHelper = new THREE.AxesHelper(250);
scene.add(axesHelper);
const width = window.innerWidth; //宽度
const height = window.innerHeight; //高度
// 相机
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
camera.position.set(292, 223, 185);
camera.lookAt(0, 0, 0);
// WebGL渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height);
renderer.render(scene, camera);
//three.js执行渲染命令会输出一个canvas画布(HTML元素),你可以插入到web页面中
document.body.appendChild(renderer.domElement);
引入到vue的main.js文件中
javascript
// main.js文件
import './index.js'// 执行threejs代码

引入相机控件

javascript
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
javascript
// 设置相机控件轨道控制器OrbitControls
const controls = new OrbitControls(camera, renderer.domElement);
// 如果OrbitControls改变了相机参数,重新调用渲染器渲染三维场景
controls.addEventListener("change", function () {
renderer.render(scene, camera); //执行渲染操作
}); //监听鼠标、键盘事件
