# 一、Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script type="importmap">
{
"imports": {
"three": "./node_modules/three/build/three.module.js",
"OrbitControls": "./node_modules/three/examples/jsm/controls/OrbitControls.js",
"lil-gui":"./node_modules/three/examples/jsm/libs/lil-gui.module.min.js"
}
}
</script>
</head>
<body>
<canvas id="canvas" style="width: 100%;height: 100%;"></canvas>
<script type="module">
// 引入three.js
import * as THREE from 'three'
//引入orbitControls控制相机
import { OrbitControls } from 'OrbitControls'
//引入gui控制物体或者光源
import {GUI} from 'lil-gui'
const gui = new GUI()
const canvas = document.getElementById('canvas')
//获取canvas显示的宽高
const width = canvas.clientWidth
const height = canvas.clientHeight
//1.创建场景
const scene = new THREE.Scene()
//2.创建物体并添加进场景中。
const geometry = new THREE.BoxGeometry( 200, 200, 1000 ) //创建一个立方体
const material = new THREE.MeshLambertMaterial( { color: 0xffff00 } ) //创建MeshBasicMaterial一种网络基础材质以及颜色
const mesh = new THREE.Mesh(geometry,material)
mesh.position.set(1,10,1) //设置物体的方法
scene.add(mesh)
//3.设置相机。相机有两种,正交投影相机(OrthographicCamera),透视相机(PerspectiveCamera)
//PerspectiveCamera有四个参数分别为fov视角角度,aspet宽高比,near近面,far远面
const camera = new THREE.PerspectiveCamera(120,width/height,0.1,1000)
camera.position.set(100,10,800) //设置视点
camera.lookAt(0,0,0) //设置观察点
camera.up.set(0,1,0) //设置相机的上方向,如果不设置的话默认是y轴。
//4.添加坐标轴
const axesHelper = new THREE.AxesHelper(1500)//参数为坐标轴的长度
scene.add(axesHelper)
// 添加环境光
const ambientLight = new THREE.AmbientLight(0xffffff, 0.1) //给物体一个白色,强度为0.5的环境光
scene.add(ambientLight)
//5.渲染器设置。
const renderer = new THREE.WebGLRenderer({canvas:canvas})
renderer.setSize(width,height) //设置渲染的宽高,与canvas显示的宽高一致。
renderer.render(scene,camera) //将场景和相机放入渲染器
//6.鼠标拖动改变相机方向
const controls = new OrbitControls(camera, renderer.domElement)
controls.addEventListener('change', function () {
renderer.render(scene, camera) //执行渲染操作
})
//7.改变物体
let animateId
const animate =()=>{
renderer.render(scene,camera)
mesh.rotateY(0.01)
animateId = requestAnimationFrame(animate)
}
// setTimeout(()=>{cancelAnimationFrame(animateId)},1000)
animate()
//8.gui控制平行光
// 平行光
//设置平行光的颜色和强度
const directionalLight = new THREE.DirectionalLight(0xffffff, 1)
// 设置光源的方向:通过光源position属性和目标指向对象的position属性计算
directionalLight.position.set(100, 100, 50)
// 方向光指向对象网格模型mesh,可以不设置,默认的位置是0,0,0
directionalLight.target = mesh
// 可视化平行光
const dirLightHelper = new THREE.DirectionalLightHelper(directionalLight, 5)
console.log(directionalLight)
scene.add(directionalLight)
scene.add(dirLightHelper)

gui.add(directionalLight.position, 'x', 0, 1000).onChange(()=>{ renderer.render(scene, camera)})
gui.add(directionalLight.position, 'y', 0, 1000).onChange(()=>{ renderer.render(scene, camera)})
gui.add(directionalLight.position, 'z', 0, 1000).onChange(()=>{ renderer.render(scene, camera)})
</script>
</body>

​ 关于 OrbitControls 的引入问题,参考 Stack Overflow javascript - 尝试导入 OrbitControls.js 时 Three.js 中断 - 堆栈溢出 — javascript - Three.js breaks when trying to import OrbitControls.js - Stack Overflow

# 二、全屏

  1. 全屏的 css 样式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
html,body{
overflow: hidden;
}
body{
border: 0;
margin: 0;

}
#canvas{
position: fixed;
top: 0;
left: 0;
outline: none;
}
  1. 当屏幕发生变化时仍然全屏
1
2
3
4
5
6
7
8
9
10
11
window.addEventListener('resize',()=>{
//1.获取变化后的屏幕大小
let width = window.innerWidth
let height = window.innerHeight
//2. 改变透视相机的角度并更新透视投影矩阵
camera.aspect = width/height
camera.updateProjectionMatrix()
//3.重新渲染
renderer.setSize(width,height)
})//监听屏幕大小变化
renderer.setPixelRatio(window.devicePixelRatio)//不同屏幕有不同像素比,如果不设置这个的话,高像素比的屏幕观看会糊。
  1. 进入推出全屏
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
window.addEventListener('dblclick', () => {
const fullscreenElement = document.fullscreenElement || document.webkitFullscreenElement //兼容safari
//如果全屏则推出,否则进入
if (fullscreenElement) {
if (document.exitFullscreen) {
document.exitFullscreen()
} else {
document.webkitExitFullscreen()
}
} else {
if (canvas.requestFullscreen) {
canvas.requestFullscreen()
} else {
canvas.webkitRequestFullscreen()
}
}
})

# 三、可视化调试

  1. 引入 lil-gui

​ lil-gui 是 threejs 内置的库功能与 dat-gui 类似。如果是在原生的 html,js 中使用,没有用到脚手架搭建的项目。引入前需在 head 标签上加入

1
2
3
4
5
6
7
8
9
<script type="importmap">
{
"imports": {
"three": "./node_modules/three/build/three.module.js",
"OrbitControls": "./node_modules/three/examples/jsm/controls/OrbitControls.js",
"lil-gui":"./node_modules/three/examples/jsm/libs/lil-gui.module.min.js",
}
}
</script>

​ 然后引入

1
2
import {GUI} from 'lil-gui'
const gui = new GUI()

​ GUI 这个类主要有三个方法分别是 add,addcolor,addfolder

  1. add

​ 创建一个滑块

1
2
3
4
5
6
7
8
9
10
gui.add(obj,'attr',min,max,step) //obj为对象也可以是对象的某个属性,attr为属性
gui.add(obj.'attr').min(min).max(max).step(step).name(name) //链式调用的写法

//使用滑块控制物体和平行光。
gui.add(mesh.position,'x',0,100,1).name('meshpositionx')
gui.add(mesh.position,'y',0,100,1).name('meshpositiony')
gui.add(mesh.position,'z',0,100,1).name('meshpositionz')
gui.add(directionalLight.position,'x',0,100,1).name('lightpositionx')
gui.add(directionalLight.position,'y',0,100,1).name('lightpositiony')
gui.add(directionalLight.position,'z',0,100,1).name('lightpositionz')

​ 创建一个下拉框

1
2
gui.add(obj,'attr',['a','b','c'])
gui.add(obj,'attr'.{a:1,b:2,c:3})

​ 创建一个单选框

1
2
3
4
5
 gui.add(obj,'attr')

//改变物体绘制方式以及显示
gui.add(mesh.material,'wireframe') //是否以线的方式绘制
gui.add(mesh,'visible') //物体的显示
  1. addcolor

​ 为了让 gui1 知道是在修改颜色,而不是传入字符串,所以 add 无法改颜色,就有了 addcolor。

1
2
3
4
5
6
const colorobj ={
color:0x00ff00
}
gui.addColor(colorobj,'color').onChange(()=>{
material.color.set(colorobj.color) //因为无法直接修改,需要借助set方法。
})
  1. addFolder

​ 创建文件夹用于收录各个控制面板

1
2
3
4
const folder = gui.addFolder('mposition')
folder.add(mesh.position,'x',0,100,1).name('meshpositionx')
folder.add(mesh.position,'y',0,100,1).name('meshpositiony')
folder.add(mesh.position,'z',0,100,1).name('meshpositionz')