普通视图

发现新文章,点击刷新页面。
昨天 — 2025年6月9日首页

Three.js 光影魔法:如何单独点亮你的3D模型

2025年6月9日 18:21

在 Three.js 的世界里,光与材质的交相互动创造了我们所见的视觉效果。一个常见的场景是:你已经精心布置了全局的环境光和方向光,整个场景看起来很和谐,但你发现其中某个特定的模型显得有些暗淡。你希望单独把它调亮,又不想影响场景中的其他物体。

这可能是一个需要强调的主角模型、一个交互式 UI 元素,或者一个需要模拟发光效果的物体。

这篇文章将带你深入了解如何实现这一目标,从最直接的方法到其背后的核心渲染原理,让你彻底掌握控制物体亮度的“魔法”。

我们的基础场景

在开始之前,让我们先搭建一个简单的基础场景作为参照。这个场景包含两个完全相同的立方体和两种基本光源:环境光(AmbientLight)和方向光(DirectionalLight)。

import * as THREE from 'three';

// 场景、相机、渲染器等基础设置...
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x111111);
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 2, 5);
const renderer = new THREE.WebGLRenderer({ antialias: true });
// ...

// 1. 全局光照
const ambientLight = new THREE.AmbientLight(0x404040, 1.0); // 提供基础环境亮度
scene.add(ambientLight);

const directionalLight = new THREE.DirectionalLight(0xffffff, 1.2); // 模拟太阳光
directionalLight.position.set(3, 5, 4);
scene.add(directionalLight);

// 2. 两个对比物体
const geometry = new THREE.BoxGeometry(1, 1, 1);

// 物体A:标准蓝色立方体
const standardMaterial = new THREE.MeshStandardMaterial({ color: 0x0077ff });
const standardCube = new THREE.Mesh(geometry, standardMaterial);
standardCube.position.x = -1.5;
scene.add(standardCube);

// 物体B:我们希望调亮的目标
const targetMaterial = new THREE.MeshStandardMaterial({ color: 0x0077ff });
const targetCube = new THREE.Mesh(geometry, targetMaterial);
targetCube.position.x = 1.5;
scene.add(targetCube);

// 渲染循环...

在这个场景中,两个蓝色立方体看起来一模一样,它们的亮度完全由全局光照决定。现在,我们的任务是让右侧的 targetCube 单独变亮。

核心武器:material.emissive 自发光属性

要单独控制一个物体的亮度,最直接、最高效的方法就是利用材质的 自发光(Emissive) 属性。

你可以把它想象成给物体内部装了一个灯泡。这个“灯泡”发出的光会直接叠加到物体最终的颜色上,并且它不受场景中任何光源的影响

MeshStandardMaterialMeshBasicMaterial 等多种材质都支持以下两个关键属性:

  • material.emissive: 一个 THREE.Color 对象,定义了物体自身发出的光的颜色
  • material.emissiveIntensity: 一个浮点数,定义了自发光的强度,默认为 1.0

实践:点亮我们的目标

现在,我们来修改 targetMaterial

// ...接上文...

// 物体B:我们希望调亮的目标
const targetMaterial = new THREE.MeshStandardMaterial({
    color: 0x0077ff, // 物体本身的基础颜色依然是蓝色
    emissive: 0xffffff, // 关键!设置一个白色的自发光
    emissiveIntensity: 0.6 // 控制自发光的强度,可以随意调整
});

const targetCube = new THREE.Mesh(geometry, targetMaterial);
targetCube.position.x = 1.5;
scene.add(targetCube);

效果立竿见 victimes! 右侧的立方体在保持其蓝色色调的同时,整体亮度得到了显著提升。即使你关闭所有场景光源,它依然会显示为一个有亮度的形状。

深入剖析:自发光颜色如何选择?

一个常见的问题是:emissive 的颜色应该怎么设置?设置成红色会怎么样?

1. 白色自发光 (0xffffff):纯粹的亮度提升

当你只想让物体变亮而不改变其原有色调时,应该使用白色自发光。

  • 原理:白色 (rgb(1,1,1)) 包含了所有颜色通道。当它与物体的基础色叠加时,会等比例地提升基础色的R、G、B分量,效果就是纯粹的亮度增加。
  • 比喻:就像用一个白色手电筒去照一个有色的物体,物体只会变亮,不会变色。

2. 彩色自发光 (如 0xff0000):创造发光体与色彩混合

当你希望物体本身发出某种特定颜色的光(如霓虹灯、岩浆),或者想创造特殊的艺术效果时,可以使用彩色自发光。

  • 原理:彩色自发光会与物体的基础色发生颜色混合
  • 比喻:用一个红色手电筒去照一个蓝色物体,物体最终会呈现出紫色的色调,因为蓝色表面反射的光与手电筒发出的红光混合了。

原理揭秘:为何光照是乘法,自发光是加法?

你可能会好奇,最终的颜色是如何计算出来的。一个简化的模型可以帮助我们理解:

最终颜色 = (基础颜色 * 场景光照) + (自发光颜色 * 自发光强度)

这里的 乘法加法 是关键,它们分别代表了两种完全不同的物理过程。

光照的本质:调制(Modulation),因此是乘法

一个不发光的物体,它的颜色来自于它对入射光线的反射吸收。材质的 color 属性定义了它对不同颜色光的“反射率”。

  • 过程:入射光颜色 * 材质反射率 = 反射光颜色
  • 示例
    • 白光 (1,1,1) 照射到红色材质 (1,0,0) 上。
    • 反射光 = (1,1,1) * (1,0,0) = (1*1, 1*0, 1*0) = (1,0,0),结果是红色。
    • 材质的颜色像一个滤光片,调制了入射光,所以这是一个乘法过程。

自发光的本质:叠加(Addition),因此是加法

自发光是物体自身产生的能量,它与外部光线无关。它的贡献是直接叠加在物体反射的光之上的。

  • 过程:物体反射的光 + 物体自身发出的光 = 最终看到的光
  • 示例:黑暗房间里,一张桌子反射了微弱的月光,同时桌上的手机屏幕自身在发光。你眼中看到的手机屏幕亮度,就是月光反射的亮度与屏幕自发光亮度的总和。这是一个纯粹的叠加过程,所以是加法。

理解了这一点,你就掌握了控制 Three.js 中颜色与亮度的核心逻辑。

其他方案与对比

除了 emissive,还有一些其他方法可以影响单个物体的亮度,它们适用于不同的场景。

方法 原理 优点 缺点 适用场景
自发光 (Emissive) 材质自身发光,与光源无关 最直接、简单、常用,效果可控 可能看起来有点“假”,像霓虹灯,缺乏阴影细节 UI元素、发光体、魔法效果,或简单粗暴地提亮某个模型
调整基础色 (Color) 改变材质对光的反射率,调成更亮的颜色 简单,符合物理直觉 完全依赖现有光照,亮度上限受光源限制 当你只想让一个物体在同样光照下显得比其他物体更“白”或更“亮”时
调整PBR属性 改变 roughness (粗糙度) 和 metalness (金属度) 物理效果真实,能创造出质感差异 效果比较微妙,更侧重于质感而非单纯的亮度 调整金属、塑料、玻璃等不同材质的视觉表现,低粗糙度会产生更亮的高光
专用光源 + 图层 添加一个只影响特定物体的光源(如PointLight 效果真实,有光影和方向感 设置复杂,增加性能开销 精确的光照控制,如台灯只照亮书本,或给主角添加“天使光”

总结

要在 Three.js 中单独调亮一个模型,使用 material.emissive 是最推荐的首选方案

  • 若要保持原色仅提升亮度,请设置 emissive: 0xffffff (白色),并用 emissiveIntensity 精确调节。
  • 若要创造自发光物体或混合色彩,请将 emissive 设置为目标颜色。

理解“光照是乘法,自发光是加法”这一核心原理,将帮助你更自由地创造出丰富而逼真的三维视觉效果。现在,去施展你的光影魔法吧!

❌
❌