mirror of
https://github.com/troisjs/trois.git
synced 2024-11-24 04:12:02 +08:00
vanruesc/postprocessing wip
This commit is contained in:
parent
1c4acdc1e3
commit
786555ea5c
80
src/components/postprocessing/vanruesc/Effect.ts
Normal file
80
src/components/postprocessing/vanruesc/Effect.ts
Normal file
@ -0,0 +1,80 @@
|
||||
import { defineComponent, inject, onUnmounted, PropType } from 'vue'
|
||||
import { LoadingManager } from 'three'
|
||||
// @ts-ignore
|
||||
import * as PP from 'postprocessing'
|
||||
// import { RendererInterface } from '../../../build/trois'
|
||||
import { RendererInterface } from '../../../export'
|
||||
import { EffectPassInjectionKey } from './EffectPass'
|
||||
|
||||
type EffectTypes = 'bloom' | 'dof' | 'smaa'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
type: { type: String as PropType<EffectTypes>, required: true },
|
||||
options: { type: Object, default: () => ({}) },
|
||||
},
|
||||
setup(props) {
|
||||
const effectPass = inject(EffectPassInjectionKey)
|
||||
if (!effectPass) {
|
||||
console.error('EffectPass not found')
|
||||
return
|
||||
}
|
||||
|
||||
let effect: undefined | PP.Effect // not useful
|
||||
const effectIndex = effectPass.getEffectIndex()
|
||||
// console.log(effectIndex)
|
||||
|
||||
const initEffect = (params: any = undefined) => {
|
||||
effect = createEffect(effectPass.composer.renderer, props.type, props.options, params)
|
||||
if (!effect) {
|
||||
console.error('Invalid effect type')
|
||||
return
|
||||
}
|
||||
effectPass.addEffect(effect, effectIndex)
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
if (effect) {
|
||||
effectPass.removeEffect(effect)
|
||||
effect.dispose()
|
||||
}
|
||||
})
|
||||
|
||||
if (props.type === 'smaa') {
|
||||
const smaaImageLoader = new PP.SMAAImageLoader(new LoadingManager())
|
||||
smaaImageLoader.load(([search, area]: [HTMLImageElement, HTMLImageElement]) => {
|
||||
initEffect({ smaaSearch: search, smaaArea: area })
|
||||
})
|
||||
} else {
|
||||
initEffect()
|
||||
}
|
||||
},
|
||||
render() { return [] },
|
||||
})
|
||||
|
||||
function createEffect(
|
||||
renderer: RendererInterface,
|
||||
type: string,
|
||||
options: Record<string, any>,
|
||||
assets: any = undefined
|
||||
): PP.Effect {
|
||||
let effect
|
||||
switch (type) {
|
||||
case 'bloom' :
|
||||
effect = new PP.BloomEffect(options)
|
||||
break
|
||||
case 'dof' :
|
||||
effect = new PP.DepthEffect(renderer, options)
|
||||
break
|
||||
case 'smaa' :
|
||||
effect = createSmaaEffect(options, assets)
|
||||
break
|
||||
}
|
||||
return effect
|
||||
}
|
||||
|
||||
function createSmaaEffect(options: Record<string, any>, assets: any): PP.Pass {
|
||||
const { smaaSearch, smaaArea } = assets
|
||||
// TODO : options
|
||||
return new PP.SMAAEffect(smaaSearch, smaaArea)
|
||||
}
|
49
src/components/postprocessing/vanruesc/EffectComposer.ts
Normal file
49
src/components/postprocessing/vanruesc/EffectComposer.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import { defineComponent, inject, InjectionKey, onUnmounted, provide } from 'vue'
|
||||
import { Clock } from 'three'
|
||||
// @ts-ignore
|
||||
import * as PP from 'postprocessing'
|
||||
// import { RendererInjectionKey, RendererInterface } from '../../../build/trois'
|
||||
import { RendererInjectionKey, RendererInterface } from '../../../export'
|
||||
|
||||
export interface EffectComposerInterface {
|
||||
renderer: RendererInterface
|
||||
composer: PP.EffectComposer
|
||||
getPassIndex: {(): number}
|
||||
}
|
||||
|
||||
export const ComposerInjectionKey: InjectionKey<EffectComposerInterface> = Symbol('Composer')
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
const renderer = inject(RendererInjectionKey)
|
||||
if (!renderer) {
|
||||
console.error('Renderer not found')
|
||||
return
|
||||
}
|
||||
|
||||
const composer = new PP.EffectComposer(renderer.renderer)
|
||||
const clock = new Clock()
|
||||
const render = () => { composer.render(clock.getDelta()) }
|
||||
const setSize = () => { composer.setSize(renderer.size.width, renderer.size.height) }
|
||||
|
||||
let passIndex = 0
|
||||
const getPassIndex = () => { return passIndex++ }
|
||||
|
||||
renderer.onInit(() => {
|
||||
renderer.renderer.autoClear = false
|
||||
renderer.renderFn = render
|
||||
setSize()
|
||||
renderer.onResize(setSize)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
renderer.offResize(setSize)
|
||||
composer.dispose()
|
||||
})
|
||||
|
||||
provide(ComposerInjectionKey, { renderer, composer, getPassIndex })
|
||||
},
|
||||
render() {
|
||||
return this.$slots.default ? this.$slots.default() : []
|
||||
},
|
||||
})
|
75
src/components/postprocessing/vanruesc/EffectPass.ts
Normal file
75
src/components/postprocessing/vanruesc/EffectPass.ts
Normal file
@ -0,0 +1,75 @@
|
||||
import { defineComponent, inject, InjectionKey, onUnmounted, provide } from 'vue'
|
||||
// @ts-ignore
|
||||
import * as PP from 'postprocessing'
|
||||
import { ComposerInjectionKey, EffectComposerInterface } from './EffectComposer'
|
||||
|
||||
export interface EffectPassInterface {
|
||||
composer: EffectComposerInterface
|
||||
effectPass: PP.EffectPass
|
||||
effects: Array<PP.Effect>
|
||||
getEffectIndex: {(): number}
|
||||
addEffect: {(effect: PP.Effect, index: number): number}
|
||||
removeEffect: {(effect: PP.Effect): number}
|
||||
}
|
||||
|
||||
export const EffectPassInjectionKey: InjectionKey<EffectPassInterface> = Symbol('Composer')
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
// needsSwap: { type: Boolean, default: false },
|
||||
renderToScreen: { type: Boolean, default: false },
|
||||
},
|
||||
setup() {
|
||||
const composer = inject(ComposerInjectionKey)
|
||||
if (!composer) {
|
||||
console.error('Composer not found')
|
||||
return {}
|
||||
}
|
||||
|
||||
const passIndex = composer.getPassIndex()
|
||||
let effectPass: PP.EffectPass
|
||||
|
||||
const effects: Array<PP.Effect> = []
|
||||
let effectIndex = 0
|
||||
const getEffectIndex = () => { return effectIndex++ }
|
||||
|
||||
const refreshEffectPass = () => {
|
||||
// we have to recreate EffectPass (modifying effectPass.effects don't work)
|
||||
if (effectPass) {
|
||||
composer.composer.removePass(effectPass)
|
||||
effectPass.dispose()
|
||||
}
|
||||
effectPass = new PP.EffectPass(composer.renderer.camera, ...effects)
|
||||
composer.composer.addPass(effectPass, passIndex)
|
||||
}
|
||||
|
||||
const addEffect = (effect: PP.Effect, index: number) => {
|
||||
effects.splice(index, 1, effect)
|
||||
refreshEffectPass()
|
||||
}
|
||||
|
||||
const removeEffect = (effect: PP.Effect) => {
|
||||
const index = effects.indexOf(effect)
|
||||
if (index >= 0) {
|
||||
effects.splice(index, 1)
|
||||
refreshEffectPass()
|
||||
}
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
if (effectPass) {
|
||||
composer.composer.removePass(effectPass)
|
||||
effectPass.dispose()
|
||||
}
|
||||
})
|
||||
|
||||
provide(EffectPassInjectionKey, {
|
||||
composer,
|
||||
effectPass,
|
||||
effects,
|
||||
getEffectIndex,
|
||||
addEffect, removeEffect,
|
||||
})
|
||||
},
|
||||
render() { return this.$slots.default ? this.$slots.default() : [] },
|
||||
})
|
61
src/components/postprocessing/vanruesc/Pass.ts
Normal file
61
src/components/postprocessing/vanruesc/Pass.ts
Normal file
@ -0,0 +1,61 @@
|
||||
import { defineComponent, inject, onUnmounted, PropType } from 'vue'
|
||||
// @ts-ignore
|
||||
import * as PP from 'postprocessing'
|
||||
import { ComposerInjectionKey } from './EffectComposer'
|
||||
// import { RendererInterface } from '../../../build/trois'
|
||||
import { RendererInterface } from '../../../export'
|
||||
|
||||
type PassTypes = 'render'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
type: { type: String as PropType<PassTypes>, required: true },
|
||||
options: { type: Object, default: () => ({}) },
|
||||
// needsSwap: { type: Boolean, default: false },
|
||||
renderToScreen: { type: Boolean, default: false },
|
||||
},
|
||||
setup(props) {
|
||||
const composer = inject(ComposerInjectionKey)
|
||||
if (!composer || !composer.renderer) {
|
||||
console.error('Composer/Renderer not found')
|
||||
return {}
|
||||
}
|
||||
|
||||
let pass: undefined | PP.Pass
|
||||
const passIndex = composer.getPassIndex()
|
||||
|
||||
const initPass = (params: any = undefined) => {
|
||||
pass = createPass(composer.renderer, props.type, props.options)
|
||||
if (!pass) {
|
||||
console.error('Invalid pass type')
|
||||
return
|
||||
}
|
||||
pass.renderToScreen = props.renderToScreen
|
||||
composer.composer.addPass(pass, passIndex)
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
if (pass) {
|
||||
composer.composer.removePass(pass)
|
||||
pass.dispose()
|
||||
}
|
||||
})
|
||||
|
||||
initPass()
|
||||
},
|
||||
render() { return [] },
|
||||
})
|
||||
|
||||
function createPass(
|
||||
renderer: RendererInterface,
|
||||
type: string,
|
||||
options: Record<string, any>
|
||||
): PP.Pass {
|
||||
let pass
|
||||
switch (type) {
|
||||
case 'render' :
|
||||
pass = new PP.RenderPass(renderer.scene, renderer.camera)
|
||||
break
|
||||
}
|
||||
return pass
|
||||
}
|
4
src/components/postprocessing/vanruesc/index.ts
Normal file
4
src/components/postprocessing/vanruesc/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export { default as EffectComposer } from './EffectComposer'
|
||||
export { default as Pass } from './Pass'
|
||||
export { default as EffectPass } from './EffectPass'
|
||||
export { default as Effect } from './Effect'
|
Loading…
Reference in New Issue
Block a user