@vci/quick-three
Version:
quick three
150 lines (149 loc) • 4.9 kB
JavaScript
import { mergeDeep } from "@vci/helper/src/object";
import { EffectComposer, ShaderPass, UnrealBloomPass } from "three/addons";
import { Layers, MeshBasicMaterial, ShaderMaterial, Vector2 } from "three";
import { uuid } from "@vci/helper/src/string";
import { createTweenModifier } from "../../helper/TweenHelper";
import { QtPlugin } from "../../plugins/QtPlugin";
// 特效|虚幻
function createBloomEffect(option) {
const { qt, name, paramsEffect } = mergeDeep(
{
name: "BloomEffect",
qt: null,
paramsEffect: {
threshold: 0,
strength: 1,
radius: 0.5
}
},
option
);
const gui = qt.gui.guis.postprocessing;
const passBloom = new UnrealBloomPass(new Vector2(qt.elWidth, qt.elHeight));
passBloom.threshold = paramsEffect.threshold;
passBloom.strength = paramsEffect.strength;
passBloom.radius = paramsEffect.radius;
const selection = new Set();
const effect = {
_enabled: true,
add: (...o3s) => {
o3s.forEach(o => {
o.layers.enable(BLOOM_SCENE);
selection.add(o);
});
},
delete: o => {
o.layers.disable(BLOOM_SCENE);
selection.delete(o);
},
clear: () => {
selection.forEach(o => effect.delete(o));
}
};
Object.defineProperty(effect, "enabled", {
get: () => effect._enabled,
set: enabled => {
effect._enabled = enabled;
passMix.enabled = enabled;
}
});
qt.effect[effect.uuid = uuid()] = effect;
delete qt.effect.listeners[QtPlugin.Events.Render];
const materials = {};
const darkMaterial = new MeshBasicMaterial({
color: "black"
// SPECIAL 适配此项目,解决目标发光物体被遮挡导致得问题,默认无下面配置
// transparent: true,
// opacity: 0.1,
// alphaTest: 0.2
});
const BLOOM_SCENE = 24;
const layerBloom = effect.layer = new Layers();
layerBloom.set(BLOOM_SCENE);
function darkenNonBloomed(o3) {
if ((o3.isMesh || o3.isLine) && !layerBloom.test(o3.layers)) {
materials[o3.uuid] = o3.material;
o3.material = darkMaterial;
}
}
function restoreMaterial(o3) {
if (materials[o3.uuid]) {
o3.material = materials[o3.uuid];
delete materials[o3.uuid];
}
}
const { composer, passRender, passOutput, passSMAA } = qt.effect;
composer.removePass(passOutput);
composer.removePass(passSMAA);
composer.addPass(passBloom);
composer.renderToScreen = false;
const passMix = new ShaderPass(new ShaderMaterial({
uniforms: {
tDiffuse: { value: null },
bloomTexture: { value: composer.readBuffer.texture }
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
`,
fragmentShader: `
uniform sampler2D tDiffuse;
uniform sampler2D bloomTexture;
varying vec2 vUv;
void main() {
gl_FragColor = ( texture2D( tDiffuse, vUv ) + texture2D( bloomTexture, vUv ) );
}
`,
defines: {}
}));
const composerEnding = new EffectComposer(qt.renderer);
composerEnding.addPass(passRender);
composerEnding.addPass(passSMAA);
composerEnding.addPass(passMix);
composerEnding.addPass(passOutput);
qt.effect.addEventListener(QtPlugin.Events.Render, function (e) {
if (!effect.enabled) composerEnding.render(e.detail.delta);
else {
this._backgorund = qt.scene.background;
this._fog = qt.scene.fog;
qt.scene.background = null;
qt.scene.fog = null;
// SPECIAL 默认以scene进行处理
// qt.thingSmartWorkshop.object.traverse(darkenNonBloomed);
// qt.thingGround.object.visible = false;
qt.scene.traverse(darkenNonBloomed);
composer.render(e.detail.delta);
qt.scene.traverse(restoreMaterial);
// qt.thingSmartWorkshop.object.traverse(restoreMaterial);
// qt.thingGround.object.visible = true;
qt.scene.background = this._backgorund;
qt.scene.fog = this._fog;
composerEnding.render(e.detail.delta);
qt.renderer.info.reset();
}
});
if (qt.debug) {
const menu = gui.addFolder(name);
menu.close();
menu.add(effect, "enabled").listen();
menu.add(passBloom, "threshold", 0, 2).listen();
menu.add(passBloom, "strength", 0, 3).listen();
menu.add(passBloom, "radius", -1, 1).listen();
}
// 调整强度
effect.modifyIntensity = createTweenModifier(
qt.tw,
{
effect,
keyModifyProperty: "strength",
twKey: `effectBloom.modifyIntensity@${effect.uuid}`
}
);
// 重置强度
effect.resetIntensity = async twOption => await effect.modifyIntensity(effect._intensity, twOption);
return effect;
}
export { createBloomEffect };