Three.js简介: 对WebGL原生API进行二次封装
* 注: 本文未严格按学习路径记笔记,遇到一个记一个,可能很会出现中高级知识在前面,基础知识在后面的情况。
1. 场景与物体的初始化
Scene场景
ProspectiveCamera透视相机(视角范围、宽高比、min视距,max视距) + 相机位置
BoxGeometry物体 + MeshBasicMaterial材质 → Mesh物体 (Cesium中叫 primitive、entity)
WebGLRender渲染器 : 初始化canvas + 场景添加进canvas
// 场景
const scene = new THREE.Scene()
// 相机
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight,0.1, 2000)
camera.position.set(0,0,10)
scene.add(camera)
// 物体
const geometry = new THREE.BoxGeometry(1,1,1)
const material = new THREE.MeshBasicMaterial({ color:'red' })
cosnt mesh = new THREE.Mesh( geometry, material)
scene.add(mesh)
// 渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight)
document.getElementByID('scene').appendChild(renderer.domElement)
// 开始
renderer.render(scene,camera)
2. 控制器 Control
参考地址: three.js API : 【 control 】
作用:可以交互控制场景
OrbitContol轨道控制器为例, 关键代码:
let orbitCtl = new OrbitControl(camera, render.domElement); // 可以用鼠标控制场景
orbitCtl.enableDamping = true // 阻尼控制:拖动场景有真实感
/**
* 每一帧调用一次的钩子函数
*/
funciton repeatRender(time){
// console.log(time)
render.render(scene, camera)
requestAnimationFrame(repeatRender)
}
3. 坐标轴辅助器Axes
* 英语科普:axes是axis的复数形式
const axesHelper = new THREE.AxesHelper( 5 );
scene.add( axesHelper );
图:Axes - 坐标轴
4. Mesh的常用属性
① position 位置信息
② scale 缩放
③ rotation 旋转 (修改旋转角时,是radian弧度制变化范围 0~π ,不是0~360°的角度)
5. 原生动画Animation 及动画三方库GSAP
5.1 用自带time控制动画
mesh.positon.x = time/1000 * 1 // 时间 × 速度 来控制移动距离,因为浏览器传入的time不一定是均匀的,所以建议不要直接 cube.position.x += 0.1 来直接控制位置
funciton repeatRender(time){
mesh.positon.x = time/1000 * 1
render.render(scene, camera)
requestAnimationFrame(repeatRender)
}
repeatRender()
5.2 用 clock 控制时间
/**
* let clock = new Three.Clock()
* let curTime = clock.getElapsedTime() // clock被实例化后经历的总时长
* let delayTime = clock.getDelta() // 最近一次和第二近调用clock的间隔时常
*/
let clock = new Three.Clock()
function mounted(){
let time = clock.getDelta() // 因为每一帧调用一次,所以time在144hz上就是0.007
mesh.positon.x = time * 1
render.render(scene, camera)
requestAnimationFrame(mounted)
}
mounted();
5.3 补帧动画库 GSAP
function mounted(){
let gasp1 = gasp.to(mesh.position,
{
x:5,
duration:5,
repeat:-1 , // -1无限次重复
yoyo: true , // 来回运动
delay: 2 , // 延迟2s
ease:'power1.inout', // 动画轨迹
onStart: ()=>{ alert('start') } , // 开始的钩子函数
onComplete: ()=>{ alert('done') }, // 结束的钩子函数
})
gasp1.pause() // 暂停
render.render(scene, camera)
requestAnimationFrame(mounted)
}
6. 自适应画面大小
function autoResize(){
window.addEventListener('resize',()=>{
camera.aspect = window.innerWidth / window.innerHeight // 宽高比
camera.updateProjectionMaxtrix(); // 投影矩阵
render.resize(window.innerWidth, windiw.innerHeight)
render.setPixelRatio(window.devicePixelRatio) // 像素比
})
}
7. 可视化调试工具 dat.gui
let dat = new dat.GUI()
dat.add(mesh.position, 'x').min(0).max(5).step(0.1).name('x轴').onChange(newval=>{})
图:右侧为封装好的dat.gui库可视化控制台
8. 缓冲区BufferGeometry的使用
作用:自定义顶点,绘制自定义形状 。
API封装好的物体形状类名称都以Geometry结尾,如BoxGeometry, CircleGeometry等
// scene 略
// camera 略
// 物体
const geometry = new THREE.BufferGeometry()
let vertices = new Float32Array([
1,1,1
...,
-1,-1,-1
])
geometry.setAttribute('position',new THREE.BufferAttribute(vertices,3))
const material = new THREE.MeshBasicMaterial({color:'red'})
const mesh = new THREE.Mesh(geometry, material)
// renderer略
9. 贴图纹理Texture
9.1 基本使用
MeshBasicMaterial : 基础材质,不收光照影响
TextureLoader:图片纹理加载
const myTexture = new THREE.TextureLoader().load('./../xx.png')
// 偏移
myTexture.offset.x = 0.5
// 根据中心点0.5,0.5旋转45°
myTexture.center.set(0.5,0.5)
myTexture.rotation = Math.PI / 4
//重复repeat 等省略
const material = new THREE.MeshBasicMaterail({
....
map : myTexture // 贴图
})
9.2 纹理算法 *Filter
纹理算法的意义:一个16*16像素的图片,如果没有算法加持,直接放大后会是一个个的巨型栅格点,加入纹理算法,放大后会成为模糊的图片
常用纹理算法:
① magFilter属性设置放大时候的插值算法,默认线性插值,可选NearestFilter临近插值
② minFilter设置缩小时候的重采样算法
9.3 透明效果 alphaMap
原理:用textureLoader再加载一张黑白图,API会根据灰度值自行判断透明度,纯黑为完全透明,纯白为完全不透明,然后加载到material对象中
const transparentTexture = new THREE.textureLoader.load('alpha.png')
...
const material = new THREE.MeshBasicMaterial({
...
alphaMap:transparentTexture,
transparent:ture // 必须设置透明属性
})
10. 物理渲染 PBR 之 MeshStandardMaterial
原理:模拟真实的光照属性和物体表面属性进行场景渲染,如直射光、散射光、高光、阴影,表面粗超度、金属光泽等。
几个好用的贴图网站:
Quixel Bridge(有虚幻引擎账号可以全部免费使用)
10.1 PBR
光线类型:直接照明 、镜面反射(高光) 、环境光(漫射) 、 漫反射
射入射出的交互:直接照明 → 粗糙表面 → 漫反射 ;直接照明 → 镜面 → 直接高光 ; 环境光(漫射)→ 聚合表面 → 间接高光 ; etc ....
表面属性:法线、镜面、粗糙度、金属度
10.2 MeshStandardMaterial基本使用
使用标准材质,必须添加光照对象,下面以环境光为例:
const mat = new THREE.MeshStandardMaterial({ // 标准材质
......
})
const mesh = new THREE.Mesh(geo,mat)
const light = new THREE.AmbientLight(0xffffff,0.5) // 环境光
scene.add(light)
其他光参考API,需要注意的如:directionalLight直射光需要设置光照的位置、
10.3 位移贴图 displacementMap
相当于cesium的二维面拉成三维体,具有拉伸的作用,也可以理解为:可拉伸贴图
const geo = new THREE.PlaneGeomtery(1,1,300,300) // 必须在后面设置300很多个内部点位数
const material = new THREE.MashStandartMaterial({
displacementMap: new THREE.TextureLoader('xxx.png'),
displacementScale:0.1 // 拉伸比例,默认1
})
10.4 粗糙贴图
roughness和roughMap,使用方法和displacementMap一样
10.5 金属贴图
metalness 和 metalnessMap, 用法同上
10.6 法线贴图
normalness,Normalnessmap,同上
10.7 纹理加载生命周期钩子函数
(1)textureLoader自带的钩子函数,检测单张图的加载进度
以onload为例,还有onProgress,onErro
const texture = new THREE.textureLoader.load('xxx.png')
texture.onload = (event)=>{}
(2)LoadingManger :
let loadingManager = new THREE.loadingManager();
loadingManager.onStart = (url,items,itemsTotal)=>{}
loadingManager.onLoad = ()=>{}
loadingManager.onProgress = (url,items,itemsTotal)=>{}
loadingManager.onError = url=>{}
const textureLoader = new THREE.textureLoader(loadingManager) // 工厂模式
let surfaceTexture = textureLoader.load('xx.png')
let metalMapTexture = textureLoader.load('yy.png')
....
10.8 给Mesh设置环境贴图
MeshStandardMaterial.enMap = new CubeTextureLoader('xxxxx.png')
10.9 统一设置环境贴图、场景贴图(背景图)、HDR、纹理映射
(1)背景图
scene.background = new CubeTextureLoader(...) // 背景图
scene.enviroment = new CubeTextureLoader(...) // 环境图,场景中的物体会统一加上这个环境贴图
(2)HDR
HDR - high dynamic range :夜景模式,拍多张照片,亮的地方取光圈小的,暗的地方光圈大的,组合成一张高亮度夜景图片
DataTextureLoader 继承自 RGBELoader
(3)纹理映射 *Mapping
和地图投影一样的原理。
综合起来的代码
import {RBGELoader} from 'three/examples/jsm/loaders/RGBELoader'
const rgbeloader = new RGBELoader();
rgbeloader.loadAsync('xxx.hdr').then(texture=>{ // 加载HDR背景图
texture.mapping = THREE.xxxxxMapping // 背景图纹理映射
scene.background = texture // 设置背景图
scene.environment = texture // 设置环境图
})
11. 灯光与阴影
11. 1 平行光 DirectionalLight
(1)基本使用
以一个场景有环境光DirectionLight、并有SphereGeometry与PlaneGeometry的场景为例,设置他们的阴影效果
MeshStandardMaterial等支持光照的材质
directionLight.castShadow = true
sphere.castShadow = true
plane.receiveShawdow = true
renderer.shadowMap.enable = true
效果图:
(2)基本属性
directionalLight.shadow.radius // 模糊度
dicectionalLight.shadow.mapSize.set(2048,2048) // 阴影大小
direcitonalLight.target = sphere // 光始终跟随球
(3)阴影相机
作用:根据相机位置设置显示阴影的区域,相当于把相机当作一个可以发射直射光的光源,被相机直射的地方才有阴影,其他地方都是环境光。
directionalLight.shadow.camera.far = 500
directionalLight.shadow.camera.near = 1
directionalLight.shadow.camera.left = 5
// ... 还有right、top、bottom 省略了
11.2 点光源 PointLight
物理意义:类似一个灯泡,向周围发散光线
// 将光源绑定到物体上,看着就像这个物体发出的光
const mesh = new THREE.Mesh(
new THREE.SphereGeometry(1,20,20),
new THREE.MeshStandardMaterial({color:0xf0000})
)
mesh.position.set(2,2,2)
const pointLight = new THREE.pointLight(0ff0000,1)
pointLight.castShadow = true
mesh.add(pointLight)
图:光源绑定物体,让物体发光
11.3 聚光灯 SpotLight
物理意义:类似手电筒,越远范围越大。效果如下:
图:聚光灯光源