前言
接下来的项目实战讲解过程中,有必要多花几个篇幅介绍一下项目中用到的两个库。
"@react-three/drei": "^9.70.3"
,
"@react-three/fiber": "^8.13.0"
此篇仅对入门不久或者新手小白,如果对 threejs
有一定的了解,完全可以跳过,直接看对应的文档。
文档链接: react-three/fiber, react-three/drei
请记住这两个版本号,因为在实战的过程中,不同的版本,api 也会有所不同,具体可以查看对应的版本。
值得一提的是,新手在看文档案例的时候,很容易对文档中的案例代码误解,比如案例的代码给的是这样:
实际上,它的代码是这样用的,具体可以到它的github上进行查看。
若有小伙伴找到官网案例的代码入口,可以在评论区留言~
光源
OK,言归正传,下面,我们介绍常见的几种光源,与本项目中使用到的光源,为了更好的理解,本篇会将工厂类部分效果打开。
基础光源
在three.js中,光源是用于照亮场景中的对象的关键组件之一。它们模拟了现实世界中的光源,包括太阳光、点光源、聚光灯和方向光等。下面是three.js中几种常见的光源类型及其用法:
- AmbientLight(环境光): AmbientLight是一种均匀分布的光源,它不会产生阴影,而是向场景中的所有对象提供一个均匀的亮度。创建AmbientLight的代码如下所示:
const ambientLight = new THREE.AmbientLight(0xffffff, intensity);
scene.add(ambientLight);
- DirectionalLight(方向光): DirectionalLight模拟了来自一个远处的平行光源,例如太阳。它发射的光线是平行的,并且具有方向性,可以产生阴影效果。创建DirectionalLight的代码如下所示:
const directionalLight = new THREE.DirectionalLight(0xffffff, intensity);
directionalLight.position.set(x, y, z);
scene.add(directionalLight);
- PointLight(点光源): PointLight模拟了一个点状的光源,可以从一个点向所有方向发射光线。它可以产生逼真的光照和阴影效果。创建PointLight的代码如下所示:
const pointLight = new THREE.PointLight(0xffffff, intensity, distance, decay);
pointLight.position.set(x, y, z);
scene.add(pointLight);
- SpotLight(聚光灯): SpotLight模拟了一个具有方向性的聚光灯光源,类似于手电筒的效果。它可以发射锥形的光束,可以产生聚焦的光照和阴影效果。创建SpotLight的代码如下所示:
const spotLight = new THREE.SpotLight(0xffffff, intensity, distance, angle, penumbra, decay);
spotLight.position.set(x, y, z);
spotLight.target.position.set(targetX, targetY, targetZ);
scene.add(spotLight);
在上述代码中
intensity
表示光源的强度
distance
表示光源的最大照射距离
decay
表示光照强度的衰减系数
angle
表示聚光灯的锥形角度
penumbra
表示聚光灯的柔化程度
position
表示光源在场景中的位置
target.position
表示聚光灯的照射目标的位置。
以上四种灯光,只有AmbientLight
是无法产生投影,其他三种,均可以产生投影。
介绍完基础的光源后,我们来看,项目中,光源都是如何生效的吧。
实战光
首先,我们先看看项目实际的光源效果。
这里一共用到了三种光,查看BaseScene=>components=>Lights.tsx文件(项目结构,可以查看上篇# 3D数字孪生 – Three.js 项目介绍与基础环境搭建(一))
// 初始化场景灯光
import React, { useRef } from 'react';
import { SpotLight, SpotLightProps } from '@react-three/drei';
function MovingSpot(props: SpotLightProps) {
const light = useRef();
return (
<SpotLight
ref={light}
castShadow
penumbra={2}
distance={6000}
angle={Math.PI * 0.6}
attenuation={5}
anglePower={Math.PI / 2}
intensity={6}
shadow-mapSize={[1024, 1024]}
shadow-camera-near={200}
shadow-camera-far={2000}
{...props}
/>
);
}
const Lights = () => {
return (
<>
{/* 环境光,AmbientLight,影响整个场景的光源 */}
<ambientLight intensity={0.5} />
{/* 模拟远处类似太阳的光源 */}
<directionalLight color={0xffffff} intensity={3} position={[10, 10, 0]} />
<MovingSpot color="#fff" position={[3, 2000, 2]} />
</>
);
};
export { MovingSpot };
export default Lights;
是否会好奇,为什么光源在上面介绍基础光源的时候,需要手动初始化,而在这里,我们却可以像原生组件一样写就行而无需声明呢? 我们看react-three/fiber文档中的解释:
也就是说,在驼峰命名的版本中,我们只需要像写原生的html
元素一样,写threejs
的组件,这个很重要,因为在接下来的实战项目中,到处都是这种写法。
接下来,我们关闭环境光,看看效果:
可以看到,物体有两个面,已经没有了光源,只剩下一个太阳光,与聚光灯。
接下来,我们再将太阳光关闭。
整个场景的亮度变暗,因为只剩下我们的聚光灯啦。
那么,如果我将我们的聚光灯关闭,是否会以为,整个场景失去了所有光源,就全暗了呢?
结局是不是会让你意外,为什么不是整个场景都无光了呢?
答案我们将在下一期揭晓~