Three.js教程
入门
实现描边发光效果

用 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 包括 RenderPassOutlinePass,它们分别用来渲染场景和实现描边效果。

通过 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.xcube.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)