用 Three.js 实现描边发光效果
简介
描边效果(Outline Effect)是指在物体的轮廓周围添加一条明显的边框线条,使得物体在三维场景中更加突出,易于被辨识。这种效果常常用于高亮显示某些物体、增强可视化效果,或在交互界面中标识选中的物体。
特点
- 突出物体:通过加上轮廓线,使物体在复杂的场景中更加显眼。
- 增强可见性:即使物体的材质或颜色不显眼,描边也能帮助其显现。
- 视觉美感:合适的描边效果可以提升画面的美感,特别是在强调某些元素时。
使用场景
- 交互式场景:当用户点击或选中物体时,常常会添加描边效果来明确表示当前选择。
- 游戏中的高亮:在角色、敌人或物品周围添加描边效果,帮助玩家快速识别目标。
- 3D 建模与可视化:在 3D 建模软件中,给物体加上描边效果,帮助查看模型的细节。
核心 api 介绍
在 Three.js 中,描边效果的核心 API 主要通过 OutlinePass
来实现。OutlinePass
是一个后处理效果,它可以为物体添加描边。下面是该 API 的核心部分以及常用的配置项。
EffectComposer
EffectComposer
是一个非常重要的类,用于执行 后处理(Post-processing)效果。后处理效果是指在渲染场景后,应用一些图像处理效果,例如模糊、色调调整、描边效果等,这些效果通常是在图像渲染完成后再进行的。
基本概念
- 后处理效果:这些效果通常是指在渲染图像后,对图像进行额外的图像处理,以增强视觉效果。
- 渲染顺序:你可以通过
EffectComposer
控制多个效果的顺序。每个后处理效果都会在图像渲染的不同阶段进行操作。 - 渲染目标:
EffectComposer
会将渲染的内容首先绘制到一个 帧缓冲 中,然后再对这个缓冲区中的图像进行处理。
作用
- 组合多个后处理效果:你可以将多个效果(例如描边、模糊等)组合到一起,在最终渲染中应用。
- 控制后处理的顺序:后处理效果按顺序应用,允许你控制每个效果的优先级。
- 实现复杂的图像处理:你可以将简单的渲染分解为多个步骤,每一步都可以应用不同的图像效果,组合起来就能产生复杂的视觉效果。
使用流程
创建 EffectComposer
实例
创建一个 WebGLRenderer
实例,并用它初始化 EffectComposer
。
const renderer = new WebGLRenderer();
// 创建一个 EffectComposer 实例
const composer = new EffectComposer(renderer);
添加渲染通道(Pass)
每个后处理效果都被称为一个 Pass,你可以将多个 Pass 添加到 EffectComposer
中。常见的 Pass 包括 RenderPass
和 OutlinePass
,它们分别用来渲染场景和实现描边效果。
通过 composer.addPass()
将不同的后处理效果添加到 EffectComposer
中。
// 添加 RenderPass,用于渲染场景
composer.addPass(new RenderPass(scene, camera));
// 创建并添加 OutlinePass,用于描边效果
const outlinePass = new OutlinePass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
scene,
camera
);
outlinePass.edgeStrength = 5.0; // 设置描边强度
outlinePass.edgeGlow = 0.5; // 设置描边发光强度
outlinePass.edgeThickness = 3.0; // 设置描边厚度
outlinePass.visibleEdgeColor.set(0xffffff); // 设置可见边缘颜色
outlinePass.hiddenEdgeColor.set(0x000000); // 设置不可见边缘颜色
composer.addPass(outlinePass);
执行渲染
在渲染过程中,EffectComposer
会按顺序执行所有添加的 Pass,并渲染最终的效果。你只需要在渲染循环中调用 composer.render()
即可。
// 使用 EffectComposer 渲染场景,执行所有 Pass
composer.render();
案例
创建基础的场景
首先,我们创建一个基础的 Three.js 场景,包括一个简单的立方体和一些光源。这个场景将作为描边效果的基础。
import * as THREE from "three";
// 场景设置
const canvas = document.getElementById("myCanvas");
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x000000);
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.z = 5;
const renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true,
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
创建三个发光立方体
- 创建颜色和发光强度的配置:
- 通过
colors
数组定义多个颜色及对应的发光强度。 - 每个立方体都根据该配置生成不同的材质。
- 通过
- 几何体和材质的选择:
- 每个立方体使用
THREE.BoxGeometry
(立方体的几何体)来定义形状。 - 使用
THREE.MeshBasicMaterial
来给立方体设置颜色,使其表面有颜色。 - 使用
THREE.MeshStandardMaterial
设置发光效果。emissive
属性设置发光颜色,emissiveIntensity
用来控制发光的强度。
- 每个立方体使用
- 将发光材质应用到立方体的面:
- 通过设置不同的面材质,我们确保只有一个面的材质具有发光效果,其他面保持普通材质。
emissiveMaterial
只应用于立方体的一个面,这样立方体的其他部分保持正常渲染。
- 立方体的位置设置:
- 使用
cube.position.x
和cube.position.z
来将立方体在 3D 空间中进行定位。 - 立方体的位置通过
index
进行偏移,确保它们均匀分布在屏幕中。
- 使用
- 添加到场景:
- 使用
scene.add(cube)
将创建的立方体添加到 Three.js 场景中,使它们能被渲染显示。
- 使用
const cubes = [];
const colors = [
{ color: 0x00ff00, intensity: 1.5 }, // 绿色
{ color: 0x0000ff, intensity: 15 }, // 蓝色,进一步增加发光强度
{ color: 0xffff00, intensity: 2.5 }, // 黄色
];
colors.forEach((colorInfo, index) => {
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({
// 使用 BasicMaterial 确保发光
color: colorInfo.color,
});
const emissiveMaterial = new THREE.MeshStandardMaterial({
color: colorInfo.color,
emissive: colorInfo.color,
emissiveIntensity: colorInfo.intensity,
transparent: true,
opacity: 0.8,
});
const cube = new THREE.Mesh(geometry, [
material,
material,
material,
material,
emissiveMaterial, // 仅使用发光材质作为立方体的一个面
material,
]);
// 将立方体均匀分布在屏幕上,增加间距
const totalCubes = colors.length;
cube.position.x = (index - (totalCubes - 1) / 2) * 5; // 增加间距从 2.5 到 5
cube.position.z = -5;
scene.add(cube);
cubes.push(cube);
});
添加光源
创建白色的环境光以及蓝色的电光源,照射范围为 100
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
const pointLight = new THREE.PointLight(0xffffff, 1, 100);
pointLight.position.set(0, 0, 10);
scene.add(pointLight);
后期处理 - EffectComposer
创建 EffectComposer
来组合多个后期处理效果。 RenderPass
是基本的渲染通道,将场景和相机传入后进行渲染。
const composer = new EffectComposer(renderer);
const renderPass = new RenderPass(scene, camera);
composer.addPass(renderPass);
添加 UnrealBloomPass 实现发光效果
UnrealBloomPass
是 Three.js 中的一个后期处理效果,用于实现类似“虚幻发光”的效果。它通过增强场景中亮度较高的部分,创造出炫光和发光的视觉效果。
UnrealBloomPass
参数:
resolution
:渲染目标的分辨率,通常是浏览器窗口的宽度和高度。strength
:发光的强度,数值越大,发光效果越强烈。radius
:发光的扩展范围,数值越大,发光效果越模糊。threshold
:定义了哪些像素会被视为“发光”。较低的值会使更多的像素被认为是发光的,产生更强的发光效果。
const bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
3.0, // 发光强度
0.4, // 发光范围
0.85 // 发光阈值
);
composer.addPass(bloomPass);
动画循环
最后,我们在动画循环中更新立方体的旋转,并使用 composer.render()
渲染带有后期处理效果的场景。
function animate() {
requestAnimationFrame(animate); // 递归调用确保每一帧都会更新
// 让每个立方体旋转
cubes.forEach((cube, index) => {
cube.rotation.x += 0.01 * (index + 1);
cube.rotation.y += 0.01 * (index + 1);
});
// 渲染带有后期处理效果的场景
composer.render();
}
代码
github
https://github.com/calmound/threejs-demo/tree/main/effect (opens in a new tab)
gitee
https://gitee.com/calmound/threejs-demo/tree/main/effect (opens in a new tab)