three.js学习笔记 2.光照和材质

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/...

相关推荐
Mintopia1 小时前
Three.js 在数字孪生中的应用场景教学
前端·javascript·three.js
啊花是条龙3 小时前
使用 Axios 和 AbortController 实现请求控制和取消
react.js·typescript
PyAIGCMaster5 小时前
穷鬼计划:react+tailwindcss+vercel
前端·react.js·前端框架
啵咿傲6 小时前
Next框架学习篇 ✅
react.js·服务端渲染
JiangJiang18 小时前
🚀 React 弹窗还能这样写?手撸一个高质量 Modal 玩起来!
前端·javascript·react.js
t20071819 小时前
4.27 react第一天
前端·react.js·前端框架
溪i20 小时前
react-spring/web + children not defined
前端·spring·react.js
雨夜带刀_20 小时前
vue+three.js贴图-自定义贴图.仿写VANS定制功能(three.js+vue)
three.js
egghead2631620 小时前
trae+react+tailwindcss项目开发
前端·react.js