UNPKG

@vci/quick-three

Version:

quick three

148 lines 4.69 kB
import { mergeDeep, uuid } from "@vci/helper"; import { EffectComposer, ShaderPass, UnrealBloomPass } from "three/addons"; import { Layers, MeshBasicMaterial, ShaderMaterial, Vector2 } from "three"; 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 };