Three.js实现分区Bloom辉光效果
·
一、效果展示
辉光效果
二、如何实现
- 1.基于EffectComposer后期渲染器。
- 2.借助UnrealBloomPass渲染通道,实现辉光效果。
- 3.了解three.js中 layers 分层的概念,实现分层渲染。
- 4.单帧两次渲染,分别渲染两个不同的场景,组合成为需要的场景。
三、代码实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<script type="module">
import * as THREE from "./node_modules/three/build/three.module.js";
import { OrbitControls } from "./node_modules/three/examples/jsm/controls/OrbitControls.js";
import { EffectComposer } from "./node_modules/three/examples/jsm/postprocessing/EffectComposer.js";
import { UnrealBloomPass } from "./node_modules/three/examples/jsm/postprocessing/UnrealBloomPass.js";
import { RenderPass } from "./node_modules/three/examples/jsm/postprocessing/RenderPass.js";
let scene, camera, renderer, composer;
const params = {
exposure: 0,
bloomStrength: 1.5,
bloomThreshold: 0,
bloomRadius: 0,
};
const init = () => {
// 场景
scene = new THREE.Scene();
// 相机
camera = new THREE.PerspectiveCamera(
70,
window.innerWidth / window.innerHeight,
1,
100000
);
camera.position.set(50, 50, 50);
camera.position.y = 50;
// 渲染器
renderer = new THREE.WebGLRenderer({
antialias: true,
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 环境光
const light = new THREE.AmbientLight(0xffffff, 0.6);
light.layers.enable(0);
light.layers.enable(1);
scene.add(light);
// 控制器
const controls = new OrbitControls(camera, renderer.domElement);
scene.add(new THREE.AxesHelper(100));
window.onresize = () => {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
};
};
const initComposer = () => {
composer = new EffectComposer(renderer);
const renderScene = new RenderPass(scene, camera);
// 光晕
const bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
1.5,
0.4,
0.85
);
bloomPass.threshold = params.bloomThreshold;
bloomPass.strength = params.bloomStrength;
bloomPass.radius = params.bloomRadius;
composer.addPass(renderScene);
composer.addPass(bloomPass);
};
const main = () => {
const geometry = new THREE.BoxGeometry(20, 20, 10);
// 正常方块
const normalMtl = new THREE.MeshLambertMaterial({ color: 0x00ffff });
const normalBox = new THREE.Mesh(geometry, normalMtl);
normalBox.position.z = -5;
normalBox.layers.set(0);
scene.add(normalBox);
// 发光方块
const bloomMtl = new THREE.MeshLambertMaterial({ color: 0xff5500 });
const bloomBox = new THREE.Mesh(geometry, bloomMtl);
bloomBox.position.z = 5;
bloomBox.layers.set(1);
scene.add(bloomBox);
};
const render = () => {
renderer.autoClear = false;
renderer.clear();
camera.layers.set(1);
composer.render();
renderer.clearDepth(); // 清除深度缓存
camera.layers.set(0);
renderer.render(scene, camera);
requestAnimationFrame(render);
};
init();
initComposer();
main();
render();
</script>
</body>
</html>
四、注意点
UnrealBloomPass
将会影响渲染器的alpha通道,需要修改源码解决。源码地址- 使用layers分层渲染,只有当渲染目标与camera处与同一层时才会渲染
- 在使用分层渲染时,需要注意光源问题,所有场景默认都是在mask(1)层的,失去光源可能丢失渲染效果
- 分层渲染时需要关闭
autoClear(定义渲染器是否在渲染每一帧之前自动清除其输出)
属性,避免渲染效果被清除。 - 此方案会有深度信息丢失问题(单帧渲染两次,清除了Depth信息,同时使用了不同的渲染器),解决方案参考 ShaderPass方案
更多推荐
已为社区贡献10条内容
所有评论(0)