3️⃣threejs学习笔记(三)
2026-3-12
| 2026-3-17
字数 3288阅读时长 9 分钟
type
Post
status
Published
date
Mar 12, 2026
slug
summary
个人项目上线 灯光 阴影 搭鬼屋demo记录的一些API
tags
Three.js
category
技术学习笔记
icon
password

个人项目上线

使用 vercel 部署: https://vercel.com/
  1. 本地全局安装 npm install vercel -g
  1. 打包项目 npm run build
  1. 配置部署命令:
  1. 执行 vercel login 使用 github 登录 vercel
  1. 执行 npm run deploy 即可:
    1. 在这里插入图片描述

灯光

AmbientLight

环境光源会无差别地作用在物体的各个方向,不会造成阴影等效果
添加光照前:
在这里插入图片描述
添加光照后:
在这里插入图片描述
在这里插入图片描述

DirectionalLight

平行光是从单一方向照射而来的光,默认平行光来源为正上方:(0,1,0)的位置
在这里插入图片描述
在这里插入图片描述
平行光默认照向的位置是原点

HemisphereLight半球光

半球光自带两个方向,分为 skyColorgroudColor ,光的默认位置也是(0,1,0)
在这里插入图片描述
在这里插入图片描述
注意看,半球光在光交界处的颜色是渐变的,即两种光深浅的交融
在这里插入图片描述

PointLight

点光源就是从某个点发出的光,默认从(0,0,0)的位置发出:
在这里插入图片描述
在这里插入图片描述
通过 distance 属性可以配置光照射的距离,默认是0,代表无限远
如果将光移动到某个位置,
设为达不到物体的距离,那么光就不会作用到
范围外的物体,比如将光移动到下面这个位置并且设置光的距离:
在这里插入图片描述
decay 对应的是光的衰减值,通常情况下使用的默认的就行,默认值是2,2已经是 threejs 算出来的最符合物理规律的值了

RectAreaLight

平面光光源,类似生活中摄影棚里的灯:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
代码中设置了在每次修改光源位置、宽高时都让光源重新照向( lookAt )原点,如果不这么设置,光源将保持初次声明的方向不变
注意,这个光源只能作用于 MeshStandardMaterialMeshPhysicalMaterial 两种材质。

SpotLight

聚光灯,照射方式类似手电筒,
在这里插入图片描述
另外,通过
属性,可以配置出灯光在边缘区域的衰减程度:
在这里插入图片描述
另外,聚光灯默认始终看向原点,如果想要改变其照射的方向,使用 lookAt 是无效的,必须通过修改 spotLight.target.position 才能实现:
在这里插入图片描述
在这里插入图片描述

性能问题

灯光是很耗性能的,我们应该使用尽可能少的光源实现,光的性能消耗从高到低排行如下:
T0:SpotLight、RectAreaLight(最耗性能) T1:DirectionalLight 、PointLight T2:AmbientLight 、HemisphereLight(最不耗性能)
所以,当来到性能优化层面时,灯光的实现可以考虑在一开始进行3D建模时就给纹理附加上灯光,而不是使用 threejs 里的光源实现,不过这样的问题是做不到实时的灯光移动,对于需要动态变化的场景可能就略有欠缺
比如
上提供的示例:
在这里插入图片描述
这个场景内的几何体,都是使用原本就有灯光效果的纹理实现的
在这里插入图片描述

阴影

阴影在 threejs 中是被计算成一张阴影贴图来展示的,比如可以看官方给的 expample 示例:
在这里插入图片描述
在这里插入图片描述
画面中存在一个从上往下照射的 directionalLight ,那么经过 threejs 计算后,得到左上角第一张的阴影贴图;
画面中存在一个照向左下角的 spotLight ,这个 spotLight 只照得到环状结几何体,所以左上角第二张阴影贴图只有这个环状结
这就是 threejs 内部处理阴影的原理

阴影的一般实现方式

  1. 几何体网格设置 castShadow = true
  1. 某个需要展示投影的平面 Mesh 设置 receiveShadow = true
  1. 灯光设置 castShadow = true
  1. 渲染器开启阴影 renderer.shadowMap.enabled = true
在这里插入图片描述
在这里插入图片描述
默认情况下,阴影贴图的分辨率为
,可以通过打印灯光的
属性看到(阴影的相关属性存储在
的光源对象里)
在这里插入图片描述
可以通过修改 mapSize 的分辨率来获取更清晰的阴影,比如将 mapSize 设为 2048 * 2048
阴影很显然地变得更高清了
在这里插入图片描述
分辨率越高,意味着GPU的计算性能就会占用得越多,并且基于GPU得渲染原理,分辨率的值应该尽量传 2的指数幂

观察阴影

观察阴影的媒介其实是摄像机,所以在平行光的位置会会存在一台 摄像机 ,通过 directionalLight.shadow.camera 可以访问到,添加一个 CameraHelper 可以看到这个摄像机的位置:
在这里插入图片描述
在这里插入图片描述
所以,既然是正交摄像机,那么就可以设置它的 near、far、left 等,目前默认情况下,摄像机的 near = 0.5far = 500left = -5top = 5right = 5bottom = -5 ,将这些值改为下面的配置:
效果:
在这里插入图片描述
如果把摄像机的far设得更小,那就会发现阴影可能渲染得不完全:
在这里插入图片描述
在这里插入图片描述
所以,如果未来遇到类似的这种阴影被切割或看不到阴影的问题,优先考虑是不是观察阴影的摄像机参数没有设对
不同的光源,使用的摄像机有可能也是不同的,可能是正交摄像机,也可能是透视摄像机

模糊

设置模糊属性要通过 directionalLight.shadow.radius 来设置,值越大代表阴影越模糊,如:
在这里插入图片描述
在这里插入图片描述

阴影贴图算法

通过
设置,可选的值有4个,性能表现依次下降:
在这里插入图片描述
比如降低原本阴影的分辨率:
使用
在这里插入图片描述
使用默认值
在这里插入图片描述
放大:
在这里插入图片描述
使用
在这里插入图片描述
放大:
在这里插入图片描述
使用
在这里插入图片描述

阴影的其他实现方式

场景中如果实时计算的阴影太多,就会造成性能问题,所以还可以使用静态阴影贴图来实现
比如下面这张图是在3D软件中对球几何体模拟光照导出的阴影贴图
在这里插入图片描述
当位置正确时,阴影的效果是很好的
在这里插入图片描述
既然是静态阴影,那么当物体发生移动时,阴影的效果当然就不尽人意了
在这里插入图片描述
这种阴影属于 BakedShadow ,可以理解为定制化的阴影,即3D建模完成后,阴影就已经定型了,不应该去动态的修改它,也不好修改
但如果是一个简单的
阴影,那他修改起来就很方便,比如对于下面这张图:
在这里插入图片描述
想要在几何体下方创建一个 plane 用来放置阴影图,首先创建一个 plane
默认情况下这个创建出来的
是面对我们的:
在这里插入图片描述
通过将其绕X轴逆时针旋转 Π / 2 可以得到朝上的平面
在这里插入图片描述
在这里插入图片描述
将其放到物体下方,也就是底部平面正上方一点点,如:
在这里插入图片描述
在这里插入图片描述
这么做是避免出现渲染的冲突,即不应该把两个平面放在同一层,假如放在同一层,会出现下面的 glitch 效果:
在这里插入图片描述
在这里插入图片描述
最后使用阴影图作为 alpha 贴图即可,对于 alphaMap 而言,贴图里白色的部分会渲染,黑色的部分会被忽略,注意要设置 transparent :true
在这里插入图片描述
在这里插入图片描述
最后把
的红色改为黑色即可:
在这里插入图片描述
那么,假如遇到物体移动的话,我们也可以很轻松的结合这个方式设置动态的阴影了
举个例子,假如物体在空间中沿着Y轴绕圈,阴影要跟着它动,可以这么实现:
在这里插入图片描述
在这里插入图片描述
再比如,如果要让球体弹跳,同时阴影有着明暗程度的变化,用现在的阴影贴图也可以很轻易地实现:
在这里插入图片描述
在这里插入图片描述
阴影的实现方案要根据实际场景来决定,贴图的简单动画相比动态的实时计算性能更好,有时牺牲一些物理上的真实性对用户的感知来说其实并不会有太大的影响

搭鬼屋demo记录的一些API

git@github.com:JohnWicc/threejs-hunted-house.git

生成雾

有线性雾和指数雾 FogExp2 ,区别在于雾的变化是线性变化程度还是指数变化程度,都是越远雾越蒙

setClearColor

可以理解为设置天空颜色,与 scene.background 在设置颜色时效果相同
在这里插入图片描述
在这里插入图片描述

clock类

threejs 内置的时钟,通常用来实现动画的计算,最常用的API是 getElapsedTime ,可以获取此时此刻的秒数
在这里插入图片描述
在这里插入图片描述
 
threeJs学习笔记(三)
  • Three.js
  • threejs学习笔记(二)threejs学习笔记(四)
    Loading...