👨⚕️ 主页: gis分享者
👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅!
文章目录
- 一、🍀前言
-
- [1.1 ☘️THREE.EffectComposer 后期处理](#1.1 ☘️THREE.EffectComposer 后期处理)
-
- [1.1.1 ☘️代码示例](#1.1.1 ☘️代码示例)
- [1.1.2 ☘️构造函数](#1.1.2 ☘️构造函数)
- [1.1.3 ☘️属性](#1.1.3 ☘️属性)
- [1.1.4 ☘️方法](#1.1.4 ☘️方法)
- [1.2 ☘️THREE.RenderPass](#1.2 ☘️THREE.RenderPass)
-
- [1.2.1 ☘️构造函数](#1.2.1 ☘️构造函数)
- [1.2.2 ☘️属性](#1.2.2 ☘️属性)
- [1.2.3 ☘️方法](#1.2.3 ☘️方法)
- [1.3 ☘️THREE.FilmPass](#1.3 ☘️THREE.FilmPass)
-
- [1.3.1 ☘️构造函数](#1.3.1 ☘️构造函数)
- [1.3.2 ☘️属性](#1.3.2 ☘️属性)
- [1.3.3 ☘️方法](#1.3.3 ☘️方法)
- 二、🍀使用EffectComposer后期处理组合器(采用RenderPass、FilmPass渲染通道)
-
- [1. ☘️实现思路](#1. ☘️实现思路)
- [2. ☘️代码样例](#2. ☘️代码样例)
一、🍀前言
本文详细介绍如何基于threejs在三维场景中使用EffectComposer后期处理组合器(采用RenderPass、FilmPass渲染通道),亲测可用。希望能帮助到您。一起学习,加油!加油!
1.1 ☘️THREE.EffectComposer 后期处理
THREE.EffectComposer 用于在three.js中实现后期处理效果。该类管理了产生最终视觉效果的后期处理过程链。 后期处理过程根据它们添加/插入的顺序来执行,最后一个过程会被自动渲染到屏幕上。
1.1.1 ☘️代码示例
javascript
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
// 初始化 composer
const composer = new EffectComposer(renderer);
// 创建 RenderPass 并添加到 composer
const renderPass = new RenderPass(scene, camera);
composer.addPass(renderPass);
// 添加其他后期处理通道(如模糊)
// composer.addPass(blurPass);
// 在动画循环中渲染
function animate() {
composer.render();
requestAnimationFrame(animate);
}
1.1.2 ☘️构造函数
EffectComposer( renderer : WebGLRenderer, renderTarget : WebGLRenderTarget )
renderer -- 用于渲染场景的渲染器。
renderTarget -- (可选)一个预先配置的渲染目标,内部由 EffectComposer 使用。
1.1.3 ☘️属性
.passes : Array
一个用于表示后期处理过程链(包含顺序)的数组。
javascript
渲染通道:
BloomPass 该通道会使得明亮区域参入较暗的区域。模拟相机照到过多亮光的情形
DotScreenPass 将一层黑点贴到代表原始图片的屏幕上
FilmPass 通过扫描线和失真模拟电视屏幕
MaskPass 在当前图片上贴一层掩膜,后续通道只会影响被贴的区域
RenderPass 该通道在指定的场景和相机的基础上渲染出一个新的场景
SavePass 执行该通道时,它会将当前渲染步骤的结果复制一份,方便后面使用。这个通道实际应用中作用不大;
ShaderPass 使用该通道你可以传入一个自定义的着色器,用来生成高级的、自定义的后期处理通道
TexturePass 该通道可以将效果组合器的当前状态保存为一个纹理,然后可以在其他EffectCoposer对象中将该纹理作为输入参数
.readBuffer : WebGLRenderTarget
内部读缓冲区的引用。过程一般从该缓冲区读取先前的渲染结果。
.renderer : WebGLRenderer
内部渲染器的引用。
.renderToScreen : Boolean
最终过程是否被渲染到屏幕(默认帧缓冲区)。
.writeBuffer : WebGLRenderTarget
内部写缓冲区的引用。过程常将它们的渲染结果写入该缓冲区。
1.1.4 ☘️方法
.addPass ( pass : Pass ) : undefined
pass -- 将被添加到过程链的过程
将传入的过程添加到过程链。
.dispose () : undefined
释放此实例分配的 GPU 相关资源。每当您的应用程序不再使用此实例时调用此方法。
.insertPass ( pass : Pass, index : Integer ) : undefined
pass -- 将被插入到过程链的过程。
index -- 定义过程链中过程应插入的位置。
将传入的过程插入到过程链中所给定的索引处。
.isLastEnabledPass ( passIndex : Integer ) : Boolean
passIndex -- 被用于检查的过程
如果给定索引的过程在过程链中是最后一个启用的过程,则返回true。 由EffectComposer所使用,来决定哪一个过程应当被渲染到屏幕上。
.removePass ( pass : Pass ) : undefined
pass -- 要从传递链中删除的传递。
从传递链中删除给定的传递。
.render ( deltaTime : Float ) : undefined
deltaTime -- 增量时间值。
执行所有启用的后期处理过程,来产生最终的帧,
.reset ( renderTarget : WebGLRenderTarget ) : undefined
renderTarget -- (可选)一个预先配置的渲染目标,内部由 EffectComposer 使用。
重置所有EffectComposer的内部状态。
.setPixelRatio ( pixelRatio : Float ) : undefined
pixelRatio -- 设备像素比
设置设备的像素比。该值通常被用于HiDPI设备,以阻止模糊的输出。 因此,该方法语义类似于WebGLRenderer.setPixelRatio()。
.setSize ( width : Integer, height : Integer ) : undefined
width -- EffectComposer的宽度。
height -- EffectComposer的高度。
考虑设备像素比,重新设置内部渲染缓冲和过程的大小为(width, height)。 因此,该方法语义类似于WebGLRenderer.setSize()。
.swapBuffers () : undefined
交换内部的读/写缓冲。
1.2 ☘️THREE.RenderPass
THREE.RenderPass用于将场景渲染到中间缓冲区,为后续的后期处理效果(如模糊、色调调整等)提供基础。
1.2.1 ☘️构造函数
RenderPass(scene, camera, overrideMaterial, clearColor, clearAlpha)
- scene THREE.Scene 要渲染的 Three.js 场景对象。
- camera THREE.Camera 场景对应的相机(如 PerspectiveCamera)。
- overrideMaterial THREE.Material (可选) 覆盖场景中所有物体的材质(默认 null)。
- clearColor THREE.Color (可选) 渲染前清除画布的颜色(默认不主动清除)。
- clearAlpha number (可选) 清除画布的透明度(默认 0)。
1.2.2 ☘️属性
.enabled:boolean
是否启用此通道(默认 true)。设为 false 可跳过渲染。
.clear:boolean
渲染前是否清除画布(默认 true)。若需叠加多个 RenderPass,可设为 false。
.needsSwap:boolean
是否需要在渲染后交换缓冲区(通常保持默认 false)。
1.2.3 ☘️方法
.setSize(width, height)
调整通道的渲染尺寸(通常由 EffectComposer 自动调用)。
width: 画布宽度(像素)。
height: 画布高度(像素)。
1.3 ☘️THREE.FilmPass
THREE.FilmPass是 Three.js 后期处理模块中的一个特效通道,用于模拟电影胶片效果(如扫描线、颗粒噪声和画面抖动)。适用于复古风格或科幻场景的视觉增强。
1.3.1 ☘️构造函数
FilmPass(
noiseIntensity, // 噪声强度
scanlinesIntensity,// 扫描线强度
scanlinesCount, // 扫描线数量
grayscale // 是否转为灰度
)
1.3.2 ☘️属性
.enabled:boolean
是否启用此通道(默认 true)。设为 false 可临时禁用效果。
.uniforms:object
着色器 uniforms 对象,可直接修改参数(动态调整效果):
javascript
filmPass.uniforms.nIntensity.value = 0.8; // 调整噪声强度
filmPass.uniforms.sIntensity.value = 0.5; // 调整扫描线强度
filmPass.uniforms.sCount.value = 1024; // 调整扫描线密度
filmPass.uniforms.grayscale.value = 1; // 启用灰度(1 是,0 否)
1.3.3 ☘️方法
.setSize(width, height)
调整通道的渲染尺寸(通常由 EffectComposer 自动调用)。
width: 画布宽度(像素)。
height: 画布高度(像素)。
二、🍀使用EffectComposer后期处理组合器(采用RenderPass、FilmPass渲染通道)
1. ☘️实现思路
- 1、初始化renderer渲染器。
- 2、初始化Scene三维场景scene。
- 3、初始化camera相机,定义相机位置 camera.position.set,设置相机方向camera.lookAt。
- 4、创建THREE.AmbientLight环境光源ambi,创建DirectionalLight平行光源spotLight,设置spotLight位置和光强,scene场景加入ambi和spotLight。
- 5、加载几何模型:定义createMesh方法(参数:geom 几何对象),用于生成网格对象。调用createMesh方法创建球体网格对象sphere,scene场景添加sphere。创建THREE.RenderPass渲染通道renderPass,创建THREE.FilmPass特效通道effectFilm,设置effectFilm的属性renderToScreen值为true,创建THREE.EffectComposer后期处理组合器composer,composer添加renderPass和effectFilm。定义controls方法,定义gui控制effectFilm特效通道参数以及参数更新方法。定义render方法,实现sphere的旋转动画,调用composer的渲染方法render。具体代码参考下面代码样例。
- 6、加入gui控制。加入stats监控器,监控帧数信息。
2. ☘️代码样例
html
<!DOCTYPE html>
<html>
<head>
<title>学习threejs,使用EffectComposer后期处理组合器(采用RenderPass、FilmPass渲染通道)</title>
<script type="text/javascript" src="../libs/three.js"></script>
<script type="text/javascript" src="../libs/stats.js"></script>
<script type="text/javascript" src="../libs/dat.gui.js"></script>
<script type="text/javascript" src="../libs/OrbitControls.js"></script>
<script type="text/javascript" src="../libs/postprocessing/ShaderPass.js"></script>
<script type="text/javascript" src="../libs/shaders/CopyShader.js"></script>
<script type="text/javascript" src="../libs/postprocessing/EffectComposer.js"></script>
<script type="text/javascript" src="../libs/postprocessing/MaskPass.js"></script>
<script type="text/javascript" src="../libs/postprocessing/FilmPass.js"></script>
<script type="text/javascript" src="../libs/shaders/FilmShader.js"></script>
<script type="text/javascript" src="../libs/postprocessing/RenderPass.js"></script>
<style>
body {
margin: 0;
overflow: hidden;
}
</style>
</head>
<body>
<div id="Stats-output">
</div>
<!-- Div which will hold the Output -->
<div id="WebGL-output">
</div>
<!-- Js代码块 -->
<script type="text/javascript">
// 初始化
function init() {
var stats = initStats();
// 创建三维场景scene
var scene = new THREE.Scene();
// 创建相机camera
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
// 创建渲染器webGLRenderer,设置颜色、大小和投影
var webGLRenderer = new THREE.WebGLRenderer();
webGLRenderer.setClearColor(new THREE.Color(0x000, 1.0));
webGLRenderer.setSize(window.innerWidth, window.innerHeight);
webGLRenderer.shadowMapEnabled = true;
var sphere = createMesh(new THREE.SphereGeometry(10, 40, 40));
// 添加球网格对象
scene.add(sphere);
// 设置相机位置和方向
camera.position.x = -10;
camera.position.y = 15;
camera.position.z = 25;
camera.lookAt(new THREE.Vector3(0, 0, 0));
var orbitControls = new THREE.OrbitControls(camera);
orbitControls.autoRotate = false;
var clock = new THREE.Clock();
var ambi = new THREE.AmbientLight(0x181818);
scene.add(ambi);
var spotLight = new THREE.DirectionalLight(0xffffff);
spotLight.position.set(550, 100, 550);
spotLight.intensity = 0.6;
scene.add(spotLight);
// 渲染器webGLRenderer绑定到html要素
document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement);
var renderPass = new THREE.RenderPass(scene, camera);
var effectFilm = new THREE.FilmPass(0.8, 0.325, 256, false);
// 若作为最后一个通道,需设置 renderToScreen: true(否则后续通道无法显示)
effectFilm.renderToScreen = true;
var composer = new THREE.EffectComposer(webGLRenderer);
composer.addPass(renderPass);
composer.addPass(effectFilm);
// setup the control gui
var controls = new function () {
this.scanlinesCount = 256;
this.grayscale = false;
this.scanlinesIntensity = 0.3;
this.noiseIntensity = 0.8;
this.updateEffectFilm = function () {
effectFilm.uniforms.grayscale.value = controls.grayscale;
effectFilm.uniforms.nIntensity.value = controls.noiseIntensity;
effectFilm.uniforms.sIntensity.value = controls.scanlinesIntensity;
effectFilm.uniforms.sCount.value = controls.scanlinesCount;
};
};
var gui = new dat.GUI();
gui.add(controls, "scanlinesIntensity", 0, 1).onChange(controls.updateEffectFilm);
gui.add(controls, "noiseIntensity", 0, 3).onChange(controls.updateEffectFilm);
gui.add(controls, "grayscale").onChange(controls.updateEffectFilm);
gui.add(controls, "scanlinesCount", 0, 2048).step(1).onChange(controls.updateEffectFilm);
// call the render function
var step = 0;
render();
function createMesh(geom) {
var planetTexture = THREE.ImageUtils.loadTexture("../assets/textures/planets/Earth.png");
var specularTexture = THREE.ImageUtils.loadTexture("../assets/textures/planets/EarthSpec.png");
var normalTexture = THREE.ImageUtils.loadTexture("../assets/textures/planets/EarthNormal.png");
var planetMaterial = new THREE.MeshPhongMaterial();
planetMaterial.specularMap = specularTexture;
planetMaterial.specular = new THREE.Color(0x4444aa);
planetMaterial.normalMap = normalTexture;
planetMaterial.map = planetTexture;
var mesh = THREE.SceneUtils.createMultiMaterialObject(geom, [planetMaterial]);
return mesh;
}
function render() {
stats.update();
var delta = clock.getDelta();
orbitControls.update(delta);
sphere.rotation.y += 0.002;
requestAnimationFrame(render);
composer.render(delta);
}
function initStats() {
var stats = new Stats();
stats.setMode(0);
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';
document.getElementById("Stats-output").appendChild(stats.domElement);
return stats;
}
}
window.onload = init;
</script>
</body>
</html>
效果如下