易妖游戏网
您的当前位置:首页Three.js光照与阴影

Three.js光照与阴影

来源:易妖游戏网

阴影 / 平行光

<template>
  <div id="webgl"></div>
</template>

<script setup>
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

const scene = new THREE.Scene();

// 目标:灯光与阴影
// 1、材质要满足能够对光照有反应
// 2、设置渲染器开启阴影的计算 renderer.shadowMap.enabled = true
// 3、设置光照投射阴影 directionalLight.castShadow = true
// 4、设置物体投射阴影 sphere.castShadow = true
// 5、设置物体接收阴影 plane.receiveShadow = true

const sphereGemometry = new THREE.SphereGeometry(1, 20, 20) // 球体
const material = new THREE.MeshStandardMaterial()
const sphere = new THREE.Mesh(sphereGemometry, material)
sphere.castShadow = true
scene.add(sphere)

// 创建平面
const planeGeometry = new THREE.PlaneGeometry(50, 50)
const plane = new THREE.Mesh(planeGeometry, material)
plane.position.set(0, -1, 0)
plane.rotation.x = -Math.PI / 2
// 接收阴影
plane.receiveShadow = true
scene.add(plane)

// 平行光
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.9)
directionalLight.position.set(5, 5, 5)
directionalLight.castShadow = true
scene.add(directionalLight)

const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 0, 10);
// scene.add(camera);

const axesHelper = new THREE.AxesHelper(5); // 长度
scene.add(axesHelper);

// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight); //设置three.js渲染区域的尺寸(像素px)
renderer.shadowMap.enabled = true
document.body.appendChild(renderer.domElement);
renderer.render(scene, camera);

// 相机围绕目标进行轨道运动
const controls = new OrbitControls(camera, renderer.domElement);

function render(time) {
  renderer.render(scene, camera);
  requestAnimationFrame(render);
}
render()
</script>

阴影模糊

// 设置阴影贴图模糊度(分辨率不够会导致显示的不清晰)
directionalLight.shadow.radius = 20
// 设置阴影贴图的分辨率
directionalLight.shadow.mapSize.set(4096, 4096)

设置投影相机

// 设置平行光投影相机的属性(近端和远端决定了阴影的长度)
directionalLight.shadow.camera.near = 0.5
directionalLight.shadow.camera.far = 500
directionalLight.shadow.camera.top = 5
directionalLight.shadow.camera.bottom = -5
directionalLight.shadow.camera.left = -5
directionalLight.shadow.camera.right = 5

const gui = new GUI();
gui.add(directionalLight.shadow.camera,"near").min(0).max(10).step(0.1).onChange(()=>{
  directionalLight.shadow.camera.updateProjectionMatrix() // 更新
})

聚光灯(手电)

// 聚光灯(手电筒)
const spotLight = new THREE.SpotLight(0xffffff, 1);
spotLight.position.set(5, 5, 5)
spotLight.castShadow = true
// 设置阴影贴图模糊度
spotLight.shadow.radius = 20
spotLight.shadow.mapSize.set(4096, 4096)
spotLight.target = sphere //聚光灯的方向是从它的位置到目标位置.默认的目标位置为原点 (0,0,0)。
spotLight.intensity = 2 // 光照强度
spotLight.target = sphere // 聚光灯的方向是从它的位置到目标位置.默认的目标位置为原点 (0,0,0)。
spotLight.angle = Math.PI / 6 // 从聚光灯的位置以弧度表示聚光灯的最大范围。应该不超过 Math.PI/2。默认值为 Math.PI/3。
spotLight.distance = 0 // 光源照射的最大距离。默认值为 0(无限远)
spotLight.penumbra = 0 // 聚光锥的半影衰减百分比。在0和1之间的值。 默认值 — 0.0。
spotLight.decay = 0 // 沿着光照距离的衰减量,值越大减弱效果越明细。默认值为 2
scene.add(spotLight);

const spotLightHelper = new THREE.SpotLightHelper( spotLight );
scene.add( spotLightHelper );

import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
const gui = new GUI();
gui.add(sphere.position, "x").min(-5).max(5).step(0.1)
gui.add(spotLight, "angle").min(0).max(Math.PI / 2).step(0.01)
gui.add(spotLight, "distance").min(0).max(10).step(0.01)
gui.add(spotLight, "penumbra").min(0).max(1).step(0.01)
gui.add(spotLight, "decay").min(0).max(5).step(0.01)

点光源

// 点光源
const pointLight = new THREE.PointLight(0xffffff, 1);
pointLight.position.set(1, 1, 1)
pointLight.castShadow = true
scene.add(pointLight);

const sphereSize = 1;
const pointLightHelper = new THREE.PointLightHelper( pointLight, sphereSize );
scene.add( pointLightHelper );

点光源还可以直接添加在物体上面(实现小球围绕着大球旋转)

<template>
  <div id="webgl"></div>
</template>

<script setup>
import * as THREE from 'three'
//导入轨道控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
// 导入 dat.gui
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';

// 目标:点光源

const gui = new GUI();
//1.创建场景
const scene = new THREE.Scene()

//2.创建相机 角度  宽高比  近端  远端
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000)
// 设置相机位置  x y z 
camera.position.set(0, 0, 10)
// 把相机添加到场景中
scene.add(camera)

const sphereGeometry = new THREE.SphereGeometry(1, 20, 20)
const material = new THREE.MeshStandardMaterial()
const sphere = new THREE.Mesh(sphereGeometry, material)
// 投射阴影
sphere.castShadow = true
scene.add(sphere)


// 创建平面
const planeGeometry = new THREE.PlaneGeometry(50, 50)
const plane = new THREE.Mesh(planeGeometry, material)
plane.position.set(0, -1, 0)
plane.rotation.x = -Math.PI / 2
// 接收阴影
plane.receiveShadow = true
scene.add(plane)

// 红色小球
const smallBall = new THREE.Mesh(
  new THREE.SphereGeometry(0.1, 20, 20),
  new THREE.MeshBasicMaterial({ color: 0xff0000 })
)
smallBall.position.set(2, 2, 2)

// 点光源
const pointLight = new THREE.PointLight(0xff0000, 1);
// pointLight.position.set(2, 2, 2)
pointLight.castShadow = true
// 设置阴影贴图模糊度
pointLight.shadow.radius = 20
// 设置阴影贴图的分辨率
pointLight.shadow.mapSize.set(512, 512);

smallBall.add(pointLight)
scene.add(smallBall);

// 初始化渲染器
const renderer = new THREE.WebGLRenderer()
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight)
// 开启场景中的阴影贴图
renderer.shadowMap.enabled = true
renderer.physicallyCorrectLights = true

// 将webgel渲染的canvas内容添加到body
document.body.appendChild(renderer.domElement)

// 创建轨道控制器
const controls = new OrbitControls(camera, renderer.domElement)
// 设置控制器的阻尼 更真实 惯性
controls.enableDamping = true

// 添加坐标轴辅助器
const axesHelper = new THREE.AxesHelper(5)
scene.add(axesHelper)


// 设置时钟
const clock = new THREE.Clock()


function render () {
  let time = clock.getElapsedTime()
  // 小球围绕着大球旋转
  smallBall.position.x = Math.sin(time) * 3
  smallBall.position.z = Math.cos(time) * 3
  smallBall.position.y = 2 + Math.sin(time * 10) / 2
  controls.update()
  // 使用渲染器,通过相机将场景渲染进来
  renderer.render(scene, camera);
  // 渲染下一帧的时候 调用 render函数
  requestAnimationFrame(render)
}
render()

// 监听画面变化,更新渲染画面
window.addEventListener("resize", () => {
  // 更新摄像头
  camera.aspect = window.innerWidth / window.innerHeight
  // 更新摄像机的投影矩阵
  camera.updateProjectionMatrix()

  // 更新渲染器
  renderer.setSize(window.innerWidth, window.innerHeight)
  // 设置渲染器的像素比
  renderer.setPixelRatio(window.devicePixelRatio)
})

</script>

因篇幅问题不能全部显示,请点此查看更多更全内容