Threejs 阴影秘籍,打造震撼 3D 效果

定义

阴影是光线照射到物体上,被物体遮挡后形成的效果。在 Three.js 中,可以通过设置光源的 castShadow 属性来开启阴影效果。

步骤

想要实现阴影效果涉及到以下几个步骤:

  • 光源: 开启光源的 castShadow 属性。
  • 渲染器: 开启渲染器的允许在场景中使用阴影贴图(shadowMapEnabled)属性。
  • 物体: 设置物体的材质是否接收阴影(receiveShadow)属性为 true,表示该物体可以接收阴影。
// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true; // 允许渲染器生成阴影
document.body.appendChild(renderer.domElement);

//创建平行光
const directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set(-5, 5, 0);
directionalLight.castShadow = true; // 开启投影
scene.add(directionalLight);

//创建平面
const plane = new THREE.Mesh(new THREE.PlaneGeometry(10, 10), new THREE.MeshStandardMaterial());
plane.rotation.x = -Math.PI / 2;
plane.receiveShadow = true; // 接收阴影
scene.add(plane);

//创建球体
const sphere = new THREE.Mesh(
  new THREE.SphereGeometry(1, 32, 32),
  new THREE.MeshStandardMaterial({ color: 0xff0000 })
);
sphere.position.set(0, 1, 0);
sphere.castShadow = true; // 开启投影
scene.add(sphere);

在这里插入图片描述

  • mapSize: 阴影贴图的大小,默认值为 512。值越大,阴影越清晰,但计算量也越大。较高的值会以计算时间为代价提供更好的阴影质量。
  • radius: 将此值设置为大于1的值将模糊阴影的边缘。较高的值会在阴影中产生不必要的条带效果 - 更大的mapSize将允许在这些效果变得可见之前使用更高的值。

透视相机

阴影相机(ShadowCamera)是用于生成阴影贴图的相机。在 Three.js 中,光源的 shadowCamera 属性可以用来设置阴影相机的参数。

const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(5, 10, 7.5);
light.castShadow = true;

light.shadow.mapSize.width = 1024; // 阴影贴图的宽度
light.shadow.mapSize.height = 1024; // 阴影贴图的高度
light.shadow.camera.near = 0.5; // 阴影相机最近距离
light.shadow.camera.far = 500; // 阴影相机最远距离
light.shadow.camera.left = -50; // 阴影相机左边界
light.shadow.camera.right = 50; // 阴影相机右边界
light.shadow.camera.top = 50; // 阴影相机上边界
light.shadow.camera.bottom = -50; // 阴影相机下边界

scene.add(light);

在这里插入图片描述

示例

import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
// 创建场景
const scene = new THREE.Scene();

// 创建相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(3, 3, -20);
camera.lookAt(0, 0, 0);

// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true; // 允许渲染器生成阴影
document.body.appendChild(renderer.domElement);

//创建环境光
const ambientLight = new THREE.AmbientLight(0x101010);
scene.add(ambientLight);

//创建平行光
const directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set(-5, 5, 0);
directionalLight.castShadow = true; // 开启投影
scene.add(directionalLight);
//创建平行光辅助
const directionalLightHelper = new THREE.DirectionalLightHelper(directionalLight, 1);
scene.add(directionalLightHelper);

//创建点光源
const pointLight = new THREE.PointLight(0xffffff, 10, 1000);
pointLight.position.set(-5, 3, 0);
pointLight.castShadow = true; // 开启投影
scene.add(pointLight);
//创建点光源辅助
const pointLightHelper = new THREE.PointLightHelper(pointLight, 1);
scene.add(pointLightHelper);

//创建平面
const plane = new THREE.Mesh(new THREE.PlaneGeometry(10, 10), new THREE.MeshStandardMaterial());
plane.rotation.x = -Math.PI / 2;
plane.receiveShadow = true; // 接收阴影
scene.add(plane);

//创建球体
const sphere = new THREE.Mesh(
  new THREE.SphereGeometry(1, 32, 32),
  new THREE.MeshStandardMaterial({ color: 0xff0000 })
);
sphere.position.set(0, 1, 0);
sphere.castShadow = true; // 开启投影
scene.add(sphere);

//创建控制器
const controls = new OrbitControls(camera, renderer.domElement);
// 启用阻尼效果
controls.enableDamping = true;
let angle = 0
function animate() {
  angle += 0.01
  pointLight.position.x = Math.sin(angle) * 3
  pointLight.position.z = Math.cos(angle) * 3
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}

animate();

//监听窗口大小变化
window.addEventListener("resize", () => {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
});

在这里插入图片描述

射线

射线(Raycaster)是三维空间中的一条线,它从一点出发,沿着一个方向无限延伸。射线通常用于检测物体之间的碰撞、光线投射等。

构造器

const raycaster = new THREE.Raycaster(origin, direction, near, far);
  • origin:射线的起点,通常是一个三维向量。
  • direction:射线的方向,通常是一个归一化的三维向量。
  • near:可选参数,表示射线开始的位置,near不能为负值,默认为0。
  • far:可选参数,表示射线结束的位置,far不能小于near,默认为无穷大。

方法

  • set(origin, direction):设置射线的起点和方向。
  • setFromCamera(coords, camera):从屏幕坐标设置射线的起点和方向。
  • intersectObject(object, recursive):检测射线与物体之间的碰撞,返回一个包含碰撞结果的数组。
  • intersectObjects(objects, recursive):检测射线与多个物体之间的碰撞,返回一个包含碰撞结果的数组。
//创建射线
const raycaster = new THREE.Raycaster();
// 设置射线的起点和方向
const origin = new THREE.Vector3(-6, 0, 0);
const direction = new THREE.Vector3(1, 0, 0).normalize(); // 将方向向量标准化
raycaster.set(origin, direction);
const meshs = [sphere1, sphere2, sphere3];

function animate() {
  // 使用raycaster对象与meshs数组中的对象进行相交检测
  const intersects = raycaster.intersectObjects(meshs);
  sphere1.position.y = 4 * Math.sin(Date.now() * 0.001);
  sphere2.position.y = 4 * Math.sin(Date.now() * 0.001 + (2 * Math.PI) / 3);
  sphere3.position.y = 4 * Math.sin(Date.now() * 0.001 + (4 * Math.PI) / 3);
  // 遍历meshs数组中的每个对象
  //由于射线是一瞬间完成的,所以需要将每个对象的材质颜色重置
  for (const mesh of meshs) {
    // 将每个对象的材质颜色设置为白色
    mesh.material.color.set(0xffffff);
  }
  // 遍历相交检测结果数组
  for (const intersectObject of intersects) {
    // 将相交的对象的材质颜色设置为红色
    intersectObject.object.material.color.set(0xff0000);
  }
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
}

在这里插入图片描述
书洞笔记

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值