灯光与阴影的关系
不论我们是在生活中,还是在threejs中。说到阴影肯定和光是分不开的。
首先说说灯光吧。并不是所有的灯光都会投射阴影。能够投射阴影的灯光只有以下三种:
- 平行光(DirectionalLight)
- 点光源(PointLight)
- 聚光灯(SpotLight)
测试的可以正确接收到阴影的材质
- Phong网格材质(MeshPhongMaterial)
- 物理网格材质(MeshPhysicalMaterial)
- 标准网格材质(MeshStandardMaterial)
- 卡通网格材质(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)
看一下现在的场景效果:
发现在场景中并不会有阴影出现,因为还需要一系列的其他设置:
- 渲染器开启 shadowMap.enabled 阴影渲染
- 接收阴影的对象开启 receiveshadow接受阴影
- 投射阴影的物体开启 castshadow 投射阴影
- 灯光也要开启 castshadow投射阴影
renderer.shadowMap.enabled = true
planeMesh.receiveShadow = true
light.castShadow = true
sphereMesh.castShadow = true
这样我们就有了阴影效果了。
☝ 在网上有很多说threejs
中阴影与材质有关系。其实说的不准确,准确的说是 接收 阴影的对象对材质有要求。而 投射阴影的对象(也就是物体) 对材质是没有要求的。
比如我们把上面的球体改成基础材质
// 球体
const sphereGeometry = new THREE.SphereBufferGeometry(30, 100, 100)
// const sphereMaterial = new THREE.MeshStandardMaterial({
// roughness: 0,
// metalness: 0.5,
// })
const sphereMaterial = new THREE.MeshBasicMaterial()
能看得出这样也会有阴影效果(但是这种材质不会和灯光发生交互,显得不够真实哈哈!)
完整代码:
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)
评论区