鸿蒙开发-想给3D场景加滤镜?PostProcess后处理效果详解
本文介绍了3D场景中常用的后处理效果及其实现方法。后处理是在渲染完成后对画面"加滤镜"的技术,包括色调映射、泛光、边缘暗角和色晕等效果。色调映射负责将HDR颜色映射到LDR显示范围,ArkGraphics 3D提供ACES、ACES_2020和FILMIC三种算法。泛光效果通过模糊高亮区域产生光晕,需设置硬/软阈值控制触发范围。边缘暗角使画面四周变暗以突出中心主体,可调整覆盖区域和作用强度。这些效
给 3D 场景加滤镜:色调映射、泛光、暗角这些后处理怎么玩
你有没有注意到,很多游戏和 3D 应用的画面看起来特别"电影感"——高光处有柔和的光晕,画面边缘有暗暗的暗角,整体色调温暖或者冷峻?这些效果不是模型本身的材质做出来的,而是渲染完成后在画面上"加了一层滤镜",专业术语叫"后处理(Post Process)"。
这篇文章就来聊聊 ArkGraphics 3D 的后处理系统,包括色调映射、泛光(Bloom)、边缘暗角和色晕这几种效果。
后处理是什么?
打个比方:你用相机拍了一张照片,这是"原始画面"。然后你用修图软件给它加了滤镜——调了色调、加了光晕、加了暗角。这个"加滤镜"的过程就是后处理。
下面的流程图展示了后处理在 3D 渲染管线中的位置和处理流程:
在 3D 渲染中,后处理是最后一步。引擎先把 3D 场景渲染到一张内部的"图片"上,然后对这张图片应用各种效果,最后才显示到屏幕上。所以后处理不会改变场景中的物体本身,只改变最终呈现的画面。
后处理设置是通过相机(Camera)的 postProcess 属性来配置的。也就是说,不同相机可以有不同的后处理效果——这在做分屏或者画中画时很有用。
PostProcessSettings:后处理设置的容器
PostProcessSettings 是一个配置对象,它包含了所有后处理效果的设置:
import { ToneMappingType, ToneMappingSettings, BloomSettings, PostProcessSettings } from '@kit.ArkGraphics3D';
它有四个可选属性:
- toneMapping:色调映射设置
- bloom(API 18+):泛光设置
- vignette(API 22+):边缘暗角设置
- colorFringe(API 22+):色晕设置
你只需要设置你想要的效果,不需要全部配置。没设置的效果不会生效。
色调映射(Tone Mapping)
色调映射是最基础也最重要的后处理效果。它的作用是把 HDR(高动态范围)的颜色值映射到 LDR(低动态范围),让画面在普通屏幕上看起来正常。
简单说就是:3D 渲染出来的颜色值可能超过 1.0(比如很亮的光源),但屏幕只能显示 0 到 1 的范围。色调映射就是把那些"超亮"的颜色压缩到屏幕能显示的范围内,同时尽量保留画面的层次感。
色调映射类型
ArkGraphics 3D 提供了三种色调映射算法:
- ACES(0):基于 Academy Color Encoding System 标准,追求电影级色彩还原。如果你想要好莱坞电影那种质感,选这个
- ACES_2020(1):基于 ACES 2020 标准,色域更广,色彩精度更高。适合对色彩要求严格的 HDR 渲染场景
- FILMIC(2):模拟胶片曝光响应曲线,高光过渡柔和自然。适合追求写实风格和电影质感的一般 3D 场景
ToneMappingSettings
色调映射设置有两个属性:
- type:色调映射类型,就是上面三种之一
- exposure:曝光度,大于 0 的数。值越大画面越亮,值越小画面越暗。就像相机的曝光补偿
来看一个实际的例子:
import { Scene, SceneResourceFactory, SceneNodeParameters, Camera, CameraParameters,
RenderingPipelineType, PostProcessSettings, ToneMappingType } from '@kit.ArkGraphics3D';
function setupToneMapping(): void {
Scene.load($rawfile("gltf/DamagedHelmet/glTF/DamagedHelmet.glb"))
.then(async (result: Scene) => {
if (!result.root) {
return;
}
let sceneFactory: SceneResourceFactory = result.getResourceFactory();
let nodeParameter: SceneNodeParameters = { name: "camera1" };
let camParameter: CameraParameters = { renderingPipeline: RenderingPipelineType.FORWARD };
// 创建相机
let camera: Camera = await sceneFactory.createCamera(nodeParameter, camParameter);
camera.enabled = true;
// 配置后处理:使用FILMIC色调映射,曝光度1.5
camera.postProcess = {
toneMapping: {
type: ToneMappingType.FILMIC,
exposure: 1.5
}
};
});
}
这段代码创建了一个使用 FORWARD 渲染管线的相机,然后给它配置了 FILMIC 色调映射,曝光度设为 1.5(比默认亮一点)。
注意 renderingPipeline 设为了 RenderingPipelineType.FORWARD。这是因为如果用默认的 FORWARD_LIGHTWEIGHT 管线,某些后处理效果会受限——轻量级管线只能在着色器中实现逐像素效果,不支持泛光等复杂效果。
泛光(Bloom)
泛光就是那种"发光物体周围有一圈光晕"的效果。想象一下夜晚看路灯,灯光周围会有一层柔和的光晕扩散开来——这就是泛光。
在 3D 渲染中,泛光效果的实现原理是:找出画面中亮度超过某个阈值的区域,把它们模糊处理后叠加回原画面上。
BloomSettings
泛光设置有四个属性:
- thresholdHard:硬阈值,亮度超过这个值的像素一定会产生泛光效果。默认值 1.0
- thresholdSoft:软阈值,亮度在硬阈值和软阈值之间的像素会产生部分泛光效果。默认值 2.0
- scaleFactor:缩放因子,控制泛光的强度。默认值 1.0
- scatter:扩散量,控制光晕的扩散范围。默认值 1.0
硬阈值和软阈值之间的关系是这样的:低于硬阈值的像素不产生泛光,高于软阈值的像素完全产生泛光,两者之间的像素部分产生泛光。这种渐变过渡让泛光效果看起来更自然。
import { Scene, SceneResourceFactory, SceneNodeParameters, Camera, CameraParameters,
RenderingPipelineType, PostProcessSettings, ToneMappingType } from '@kit.ArkGraphics3D';
function setupBloom(): void {
Scene.load($rawfile("gltf/DamagedHelmet/glTF/DamagedHelmet.glb"))
.then(async (result: Scene) => {
if (!result.root) {
return;
}
let sceneFactory: SceneResourceFactory = result.getResourceFactory();
let nodeParameter: SceneNodeParameters = { name: "camera1" };
let camParameter: CameraParameters = { renderingPipeline: RenderingPipelineType.FORWARD };
let camera: Camera = await sceneFactory.createCamera(nodeParameter, camParameter);
camera.enabled = true;
// 配置后处理:色调映射 + 泛光
camera.postProcess = {
toneMapping: {
type: ToneMappingType.FILMIC,
exposure: 1.0
},
bloom: {
thresholdHard: 0.8,
thresholdSoft: 1.5,
scaleFactor: 1.2,
scatter: 0.8
}
};
});
}
这段代码同时配置了色调映射和泛光。泛光的硬阈值设为 0.8(比较容易触发泛光),软阈值 1.5,缩放因子 1.2(比默认强一点),扩散量 0.8(比默认收拢一点)。
需要注意的是,泛光效果只能在 FORWARD 渲染管线下使用,FORWARD_LIGHTWEIGHT 不支持。
边缘暗角(Vignette)
暗角就是画面边缘变暗的效果。很多摄影师和电影人都喜欢用暗角来引导观众的视线——因为人眼自然会被亮的区域吸引,暗角会让画面中央的主体更突出。
VignetteSettings
暗角设置有两个属性:
- roundness:暗角的覆盖区域大小,范围 [0, 1]。0 表示覆盖区域收缩到最小,1 表示覆盖整个画面。默认值约 0.707(sqrt(0.5))
- intensity:作用强度,范围 [0, 1]。0 表示没有暗角效果,1 表示最大暗角强度。默认值 0.4
import { Scene, SceneResourceFactory, SceneNodeParameters, Camera, CameraParameters,
RenderingPipelineType, ToneMappingType } from '@kit.ArkGraphics3D';
function setupVignette(): void {
Scene.load($rawfile("gltf/DamagedHelmet/glTF/DamagedHelmet.glb"))
.then(async (result: Scene) => {
if (!result.root) {
return;
}
let sceneFactory: SceneResourceFactory = result.getResourceFactory();
let nodeParameter: SceneNodeParameters = { name: "camera1" };
let camParameter: CameraParameters = { renderingPipeline: RenderingPipelineType.FORWARD };
let camera: Camera = await sceneFactory.createCamera(nodeParameter, camParameter);
camera.enabled = true;
// 配置后处理:色调映射 + 暗角
camera.postProcess = {
toneMapping: {
type: ToneMappingType.FILMIC,
exposure: 1.0
},
vignette: {
roundness: 0.8,
intensity: 0.5
}
};
});
}
这里把暗角的 roundness 设为 0.8(覆盖区域比较大),intensity 设为 0.5(中等强度)。
色晕(Color Fringe)
色晕效果模拟的是光学镜头的色差现象——画面边缘的物体边缘会出现红、绿、蓝三色的偏移。这种效果在摄影中通常是要避免的,但在 3D 渲染中,适当加一点色晕可以让画面看起来更有"镜头感"。
ColorFringeSettings
色晕设置只有一个属性:
- intensity:作用强度,范围 [0, 1]。默认值 0.2
import { Scene, SceneResourceFactory, SceneNodeParameters, Camera, CameraParameters,
RenderingPipelineType, ToneMappingType } from '@kit.ArkGraphics3D';
function setupColorFringe(): void {
Scene.load($rawfile("gltf/DamagedHelmet/glTF/DamagedHelmet.glb"))
.then(async (result: Scene) => {
if (!result.root) {
return;
}
let sceneFactory: SceneResourceFactory = result.getResourceFactory();
let nodeParameter: SceneNodeParameters = { name: "camera1" };
let camParameter: CameraParameters = { renderingPipeline: RenderingPipelineType.FORWARD };
let camera: Camera = await sceneFactory.createCamera(nodeParameter, camParameter);
camera.enabled = true;
// 配置后处理:色调映射 + 色晕
camera.postProcess = {
toneMapping: {
type: ToneMappingType.FILMIC,
exposure: 1.0
},
colorFringe: {
intensity: 0.3
}
};
});
}
色晕效果同样只能在 FORWARD 管线下使用。
把所有效果组合在一起
实际项目中,你通常会同时使用多种后处理效果来达到理想的画面风格。比如做一个虚拟展厅,你可能想要:温暖的色调 + 轻微的泛光 + 柔和的暗角。
import { Scene, SceneResourceFactory, SceneNodeParameters, Camera, CameraParameters,
RenderingPipelineType, ToneMappingType } from '@kit.ArkGraphics3D';
function setupFullPostProcess(): void {
Scene.load($rawfile("gltf/DamagedHelmet/glTF/DamagedHelmet.glb"))
.then(async (result: Scene) => {
if (!result.root) {
return;
}
let sceneFactory: SceneResourceFactory = result.getResourceFactory();
let nodeParameter: SceneNodeParameters = { name: "camera1" };
let camParameter: CameraParameters = { renderingPipeline: RenderingPipelineType.FORWARD };
let camera: Camera = await sceneFactory.createCamera(nodeParameter, camParameter);
camera.enabled = true;
// 组合所有后处理效果
camera.postProcess = {
toneMapping: {
type: ToneMappingType.FILMIC,
exposure: 1.2
},
bloom: {
thresholdHard: 1.0,
thresholdSoft: 2.0,
scaleFactor: 1.0,
scatter: 1.0
},
vignette: {
roundness: 0.707,
intensity: 0.4
},
colorFringe: {
intensity: 0.2
}
};
});
}
这段代码用了所有默认值来组合四种效果。你可以根据实际需求调整每个参数。
渲染管线的选择
下面的流程图展示了如何根据需求选择渲染管线:
前面反复提到,泛光和色晕只能在 FORWARD 管线下使用。这里总结一下两种管线的区别:
FORWARD_LIGHTWEIGHT(轻量级前向渲染):
- 直接渲染到后缓冲区
- 只能在着色器中实现逐像素效果
- 不支持泛光、色晕等复杂后处理
- 性能更好,适合简单场景
FORWARD(高质量前向渲染):
- 支持所有后处理效果
- 性能开销更大
- 适合需要电影级画面的场景
选择哪种管线取决于你的需求。如果只是展示一个简单的 3D 模型,不需要花哨的效果,用轻量级管线就好。如果要做虚拟展厅、产品展示这种对画面要求高的场景,就用高质量管线。
管线类型在创建相机时通过 CameraParameters 指定:
import { CameraParameters, RenderingPipelineType } from '@kit.ArkGraphics3D';
let camParameter: CameraParameters = {
renderingPipeline: RenderingPipelineType.FORWARD
};
也可以在创建相机时不指定,使用默认的轻量级管线,之后再通过相机的 renderingPipeline 属性修改。
渲染配置
除了后处理,还有一些全局的渲染配置可以通过 RenderConfiguration 来设置:
- shadowResolution:全局阴影贴图分辨率(Vec2 类型,单位像素)。默认是 1024x1024。值越大阴影越精细,但性能开销也越大
import { Scene } from '@kit.ArkGraphics3D';
function configureShadow(): void {
Scene.load($rawfile("gltf/DamagedHelmet/glTF/DamagedHelmet.glb"))
.then(async (result: Scene) => {
if (!result) {
return;
}
// 提高阴影分辨率
result.renderConfiguration.shadowResolution = { x: 2048, y: 2048 };
});
}
MSAA 抗锯齿
相机还支持 MSAA(多重采样抗锯齿),通过 msaa 属性控制。开启后可以让物体的边缘更平滑,但会增加性能开销。
import { SceneNodeParameters, Camera, SceneResourceFactory, Scene, CameraParameters } from '@kit.ArkGraphics3D';
function enableMSAA(): void {
Scene.load($rawfile("gltf/DamagedHelmet/glTF/DamagedHelmet.glb"))
.then(async (result: Scene) => {
let sceneFactory: SceneResourceFactory = result.getResourceFactory();
let nodeParameter: SceneNodeParameters = { name: "camera1" };
let camParameter: CameraParameters = { msaa: true };
let camera: Camera = await sceneFactory.createCamera(nodeParameter, camParameter);
camera.enabled = true;
});
}
MSAA 也可以在创建后通过 camera.msaa = true 来开启。
小结
后处理是 3D 渲染的最后一道工序,能显著提升画面质感:
- 色调映射:把 HDR 颜色映射到屏幕能显示的范围,三种算法各有风格
- 泛光:高亮区域的柔和光晕,增加画面的"发光感"
- 边缘暗角:画面边缘变暗,引导视线聚焦中央
- 色晕:模拟镜头色差,增加"镜头感"
所有后处理都通过相机的 postProcess 属性配置。泛光和色晕需要 FORWARD 渲染管线,轻量级管线不支持。
到这里,ArkGraphics 3D 的五个核心模块我们都过了一遍:场景管理、节点操作、材质与资源、数据类型、后处理效果。把这些串起来,你就能在 HarmonyOS 上搭建出一个完整的 3D 应用了。
更多推荐




所有评论(0)