Helper
这是一个来自于@react-three/drei的实用工具 可以方便的使用three.js的helper对象 为光线网格等增加辅助线
js
<mesh>
{/** 不同的type对应的args类型不同 */}
<Helper type={BoxHelper} args={['red']}></Helper>
<boxGeometry></boxGeometry>
<meshPhysicalMaterial />
</mesh>

阴影
阴影需要四处设置
- 启用阴影
<Canvas shadows>
- 光照启用阴影
<directionalLight castShadow />
- 物体允许投影
<mesh castShadow>
- 接收投影
<mesh receiveShadow>
js
const Page: FC = () => {
return (
<Canvas shadows>
<Axes />
<OrbitControls />
<ambientLight></ambientLight>
<directionalLight castShadow position={[2, 2, 2]}>
</directionalLight>
<mesh castShadow>
<boxGeometry></boxGeometry>
<meshPhysicalMaterial color={'red'} />
</mesh>
<mesh receiveShadow position={[0, -1, 0]} rotation={[-Math.PI / 2, 0, 0]}>
<planeGeometry args={[10, 10]} />
<meshStandardMaterial />
</mesh>
</Canvas>
)
}
还可以通过这种方式设置阴影属性
js
<directionalLight
castShadow
shadow-mapSize-width={1024}
shadow-mapSize-height={1024}
></directionalLight>
虽然没有类型提示 但是shadow-mapSize-width
会被自动映射到shadow.mapSize.width
属性上 shadow的其余属性同理
width和height是阴影贴图的分辨率
阴影相机
生成阴影的原理是使用一个额外的"阴影相机"判断哪里需要阴影 没有被拍摄的阴影不会显示
不同光源类型的阴影相机类型不同 可以通过shadow-camera-*
进行设置
光照
环境光
简单光照 没有阴影 没有反射 可以简单理解成物体自发光 也不需要helper
js
const Page: FC = () => {
return (
<Canvas shadows>
<Axes />
<OrbitControls />
<ambientLight></ambientLight>
<mesh castShadow>
<boxGeometry></boxGeometry>
<meshPhysicalMaterial color={'red'} />
</mesh>
<mesh receiveShadow position={[0, -1, 0]} rotation={[-Math.PI / 2, 0, 0]}>
<planeGeometry args={[10, 10]} />
<meshStandardMaterial />
</mesh>
</Canvas>
)
}

方向光
平行光束 具有阴影 模拟太阳光
在环境光的示例中添加以下光照
js
<directionalLight position={[2, 2, 2]}>
<Helper type={DirectionalLightHelper} args={[0.5, 'red']}></Helper>
</directionalLight>
红色正方形以及连接它和原点的线段就是Heler绘制的辅助线
需要注意的是 这只表示光的方向 方向光的来源是无限远 可以看到 即使物体和光照的方向向量不在同一侧 也会被相应的光照照亮
阴影相机
方向光的阴影相机是正交投影相机 可以配置shadow-camera-left
shadow-camera-right
shadow-camera-top
shadow-camera-bottom
控制其大小
点光源
从一个点向四周发射光 具有阴影 在环境光的示例中添加以下光照
js
<pointLight
castShadow
position={[1, 1, 1]}
intensity={10}
decay={0}
distance={10}
>
<Helper type={PointLightHelper} args={[1, 'red']}></Helper>
</pointLight>
decay
配置光源的衰减速度 默认2
distance
配置其最远距离 超出的衰减为0
阴影相机
点光源的阴影相机是六个方向的透视相机 可以配置shadow-camera-near
shadow-camera-far
控制其最近距离和最远距离
聚光灯
模拟聚光灯 具有阴影 范围是一个锥形
js
<spotLight
castShadow
intensity={10}
decay={0}
position={[1, 1, 1]}
distance={4}
angle={(45 / 180) * Math.PI}
penumbra={0}
>
<Helper type={SpotLightHelper} args={['red']}></Helper>
</spotLight>
decay
光的衰减速率
distance
照射范围
angle
光锥的顶角
penumbra
阴影边缘柔软程度
还可以设置target指定照射对象
js
const Page: FC = () => {
const [target, setTarget] = useState<Object3D>()
return (
<Canvas className='translate-y-10' shadows>
<Axes />
<OrbitControls />
<ambientLight></ambientLight>
<spotLight
castShadow
intensity={10}
decay={0}
position={[1, 1, 1]}
distance={4}
angle={(45 / 180) * Math.PI}
penumbra={0}
target={target}
>
<Helper type={SpotLightHelper} args={['red']}></Helper>
</spotLight>
<mesh
ref={(el) => {
if (el && el !== target) {
setTarget(el)
}
}}
castShadow
position={[3, 3, 3]}
>
<boxGeometry></boxGeometry>
<meshPhysicalMaterial color={'red'} />
</mesh>
<mesh receiveShadow position={[0, -1, 0]} rotation={[-Math.PI / 2, 0, 0]}>
<planeGeometry args={[10, 10]} />
<meshStandardMaterial />
</mesh>
</Canvas>
)
}
也可以直接使用光源的lookAt函数 让其指向一个空间中的一个点
阴影相机
一个透视相机 辅助线与其视锥相同
矩形光
用于模拟广告牌、窗户等 不支持阴影
去除环境光加入矩形光
js
'use client'
import { FC, RefObject, useRef } from 'react'
import { Helper, OrbitControls } from '@react-three/drei'
import { Canvas, useFrame } from '@react-three/fiber'
import { Mesh, RectAreaLight } from 'three'
import { RectAreaLightHelper } from 'three/addons/helpers/RectAreaLightHelper.js'
import { Axes } from '@/components/Axes'
const Page: FC = () => {
const meshRef = useRef<Mesh>(null)
return (
<Canvas shadows>
<Axes />
<OrbitControls />
<RectLight meshRef={meshRef}></RectLight>
<mesh castShadow ref={meshRef}>
<boxGeometry></boxGeometry>
<meshPhysicalMaterial color={'red'} />
</mesh>
<mesh receiveShadow position={[0, -1, 0]} rotation={[-Math.PI / 2, 0, 0]}>
<planeGeometry args={[10, 10]} />
<meshStandardMaterial />
</mesh>
</Canvas>
)
}
export default Page
const RectLight: FC<{ meshRef: RefObject<Mesh> }> = (props) => {
const lightRef = useRef<RectAreaLight>(null)
useFrame(() => {
if (props.meshRef.current && lightRef.current) {
lightRef.current.lookAt(
props.meshRef.current.getWorldPosition(new Vector3()),
)
}
})
return (
<rectAreaLight
position={[1, 1, 1]}
width={1}
height={2}
intensity={10}
ref={lightRef}
>
<Helper type={RectAreaLightHelper} args={['red']}></Helper>
</rectAreaLight>
)
}
width和height用于设置矩形宽高
lookAt控制指向 接受一个世界坐标
getWorldPosition用于获取一个mesh的世界坐标 其参数是 useFrame是每帧的动作 这个hook需要在Canvas
下的子组件中使用

半球光
天空和地面光的结合,不支持阴影
js
<hemisphereLight position={[0, 2, 0]} color={'blue'} groundColor={'red'}>
<Helper type={HemisphereLightHelper} args={[1, 'black']}></Helper>
</hemisphereLight>
color表示天空光 groundColor表示地面光
材质
材质决定了物体表面与光的交互方式 这里仅以属性最为丰富的MeshPhysicalMaterial
为例
-
color 物体表面的基础颜色
-
transparent 是否启用透明度通道。
-
opacity 控制材质的整体透明度,需要配合transparent属性使用。
-
side 渲染哪一面:正面、背面或双面。
-
emissive 材质自身发光颜色。
-
emissiveIntensity 控制自发光颜色的亮度。
-
roughness
控制表面的粗糙程度,决定反射是否清晰。粗糙度值越高,表面的反射越模糊,呈现磨砂效果;值越低,表面反射越清晰,类似镜面反射。通常用于表现不平滑、磨砂或者有纹理的表面,如石头、木材等。适用于金属和非金属材质。数值范围:0(完全光滑)到 1(非常粗糙)。
-
metalness
控制材质表面是否具有金属感。金属度为 0 时,材质表现为非金属,金属度为 1 时,材质表现为完全金属。金属表面具有高反射率,其反射的颜色是材质的本身颜色,而非环境光。数值范围:0(完全非金属)到 1(完全金属)。金属度影响光泽度和反射强度,适用于各种金属和表面材质。适用场景包括金属、塑料和其他材料的表现。
-
reflectivity 表面反射的强度。值越高,反射效果越强,适合表现镜面等反射强烈的材质。
-
ior 为非金属材质所设置的折射率
-
transmission
很薄的透明或者半透明的塑料、玻璃材质即便在几乎完全透明的情况下仍旧会保留反射的光线,透光性属性用于这种类型的材质。当透光率不为0的时候, opacity透明度应设置为1.
-
thickness
控制透明材质的体积厚度,用于模拟玻璃或类似材质的体积效果。较高的厚度值可以产生更强的折射效果,并影响材质的透明度表现。通常用于创建玻璃、液体等透光材质。
-
clearcoat
有些类似于车漆,碳纤,被水打湿的表面的材质需要在面上再增加一个透明的,具有一定反光特性的面。而且这个面说不定有一定的起伏与粗糙度。
-
clearcoatRoughness
控制清漆层的粗糙度。清漆层的粗糙度影响清漆表面的反射模糊度,粗糙度越高,反射越模糊,越低时反射越清晰。此属性主要影响涂层表面的光泽感与反射质量。适用场景:高光泽涂层、汽车漆、油漆表面。数值范围:0(完全光滑)到 1(非常粗糙)。
-
sheen
可用于表示布料和织物材料,用于模拟丝绸、绒面、织物等柔软表面随角度变化的柔和高光。会在基本反射之外添加角度相关的次表面光泽。
-
sheenColor 光泽层颜色
-
sheenRoughness
控制布料光泽的模糊程度。值越小,光泽越清晰;越大则越模糊,表现更柔和。用于加强丝绸、绒面等材质的真实感。
测试和学习
fanethedivine.github.io/test-three/...
