Three.js 笔记

Three.js简介: 对WebGL原生API进行二次封装

 * 注:  本文未严格按学习路径记笔记,遇到一个记一个,可能很会出现中高级知识在前面,基础知识在后面的情况。

1. 场景与物体的初始化

参考地址: three.js AP 【 start 】

      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 );

7cede7e96d0744779f4ee167ca9e76e5.png

 图: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

Three.js运用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

教程地址:dat.gui

let dat = new dat.GUI()
dat.add(mesh.position, 'x').min(0).max(5).step(0.1).name('x轴').onChange(newval=>{})

b99a3e2a5bf842b89b3e8215061df4c8.png

 图:右侧为封装好的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(有虚幻引擎账号可以全部免费使用)

Poliigon(部分可以免费)

3D TEXTURES (部分可以免费)

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设置环境贴图

0aa8cb8527414b9589e789d6ae73e178.png

      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

物理意义:类似手电筒,越远范围越大。效果如下:

 图:聚光灯光源

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值