目 录CONTENT

文章目录

灯光与阴影的关系和设置

Hello!你好!我是村望~!
2022-08-14 / 0 评论 / 0 点赞 / 173 阅读 / 924 字
温馨提示:
我不想探寻任何东西的意义,我只享受当下思考的快乐~

灯光与阴影的关系

不论我们是在生活中,还是在threejs中。说到阴影肯定和光是分不开的。

首先说说灯光吧。并不是所有的灯光都会投射阴影。能够投射阴影的灯光只有以下三种:

  1. 平行光(DirectionalLight)
  2. 点光源(PointLight)
  3. 聚光灯(SpotLight)

测试的可以正确接收到阴影的材质

  1. Phong网格材质(MeshPhongMaterial)
  2. 物理网格材质(MeshPhysicalMaterial)
  3. 标准网格材质(MeshStandardMaterial)
  4. 卡通网格材质(MeshToonMaterial)

阴影效果实现设置

我们来写一个小demo来看一下threejs的灯光阴影效果:

首先准备一个标准的场景,有物体,有地面,有灯光,物体和地面我们使用的标准网格材质,灯光使用的聚光灯!

import * as THREE from "three"
import {
    OrbitControls
} from "three/examples/jsm/controls/OrbitControls"

// 场景
const scene = new THREE.Scene()

// 相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1000)
camera.position.set(100, 100, 100)

// 渲染器
const renderer = new THREE.WebGLRenderer()
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)

//灯光
const light = new THREE.SpotLight(0xfffff0, 2)
light.position.set(100, 100, 100)

// 球体-标准网格材质
const sphereGeometry = new THREE.SphereBufferGeometry(30, 100, 100)
const sphereMaterial = new THREE.MeshStandardMaterial({
    roughness: 0,
    metalness: 0.5,
})
const sphereMesh = new THREE.Mesh(sphereGeometry, sphereMaterial)

// 平面-标准网格材质
const planeGeometry = new THREE.PlaneBufferGeometry(200.200, 200, 200)
const planeMaterial = new THREE.MeshStandardMaterial({
    side: THREE.DoubleSide,
    roughness: 0,
    metalness: 0.5,
})
const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial)

// 沿着 x 轴 旋转 90度
planeMesh.rotation.x = Math.PI / 2

// 沿着 y 轴 平移自身半径
sphereMesh.position.y = 30

scene.add(camera)
scene.add(light)
scene.add(sphereMesh)
scene.add(planeMesh)

// 控制器
const controls = new OrbitControls(camera, renderer.domElement)
const handleRender = () => {
    controls.update
    renderer.render(scene, camera)
    requestAnimationFrame(handleRender)
}
requestAnimationFrame(handleRender)

看一下现在的场景效果:
1-1660453738747
发现在场景中并不会有阴影出现,因为还需要一系列的其他设置:

  • 渲染器开启 shadowMap.enabled 阴影渲染
  • 接收阴影的对象开启 receiveshadow接受阴影
  • 投射阴影的物体开启 castshadow 投射阴影
  • 灯光也要开启 castshadow投射阴影
renderer.shadowMap.enabled = true
planeMesh.receiveShadow = true
light.castShadow = true
sphereMesh.castShadow = true

1-1660453825613

这样我们就有了阴影效果了。

☝ 在网上有很多说threejs中阴影与材质有关系。其实说的不准确,准确的说是 接收 阴影的对象对材质有要求投射阴影的对象(也就是物体) 对材质是没有要求的。

比如我们把上面的球体改成基础材质

// 球体
const sphereGeometry = new THREE.SphereBufferGeometry(30, 100, 100)
// const sphereMaterial = new THREE.MeshStandardMaterial({
//     roughness: 0,
//     metalness: 0.5,
// })
const sphereMaterial = new THREE.MeshBasicMaterial()

1-1660453928552
能看得出这样也会有阴影效果(但是这种材质不会和灯光发生交互,显得不够真实哈哈!)

完整代码:

import * as THREE from "three"
import {
    OrbitControls
} from "three/examples/jsm/controls/OrbitControls"
// 场景
const scene = new THREE.Scene()
// 相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1000)
camera.position.set(100, 100, 100)

// 渲染器
const renderer = new THREE.WebGLRenderer()
renderer.setSize(window.innerWidth, window.innerHeight)
document.body.appendChild(renderer.domElement)

//灯光
const light = new THREE.SpotLight(0xfffff0, 2)
light.position.set(100, 100, 100)

// 球体
const sphereGeometry = new THREE.SphereBufferGeometry(30, 100, 100)

// 标准网格材质
// const sphereMaterial = new THREE.MeshStandardMaterial({
//     roughness: 0,
//     metalness: 0.5,
// })

//基础材质
const sphereMaterial = new THREE.MeshBasicMaterial()
const sphereMesh = new THREE.Mesh(sphereGeometry, sphereMaterial)

// 平面
const planeGeometry = new THREE.PlaneBufferGeometry(200.200, 200, 200)
const planeMaterial = new THREE.MeshStandardMaterial({
    side: THREE.DoubleSide,
    roughness: 0,
    metalness: 0.5,
})
const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial)

renderer.shadowMap.enabled = true
planeMesh.receiveShadow = true
light.castShadow = true
sphereMesh.castShadow = true
// 沿着 x 轴 旋转 90度
planeMesh.rotation.x = Math.PI / 2

// 沿着 y 轴 平移自身半径
sphereMesh.position.y = 30

scene.add(camera)
scene.add(light)
scene.add(sphereMesh)
scene.add(planeMesh)

const controls = new OrbitControls(camera, renderer.domElement)
const handleRender = () => {
    controls.update
    renderer.render(scene, camera)
    requestAnimationFrame(handleRender)
}
requestAnimationFrame(handleRender)
0

评论区