Skip to content

feat: HBAO + SSGI + TRAA + MotionBlur #211

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Binary file added .storybook/public/porsche.glb
Binary file not shown.
2 changes: 1 addition & 1 deletion .storybook/stories/Autofocus.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { EffectComposer, Autofocus } from '../../src'

// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
const meta = {
title: 'Effect/Autofocus',
title: 'Effects/Autofocus',
component: Autofocus,
decorators: [
(Story) => (
Expand Down
57 changes: 57 additions & 0 deletions .storybook/stories/SSGI.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import * as React from 'react'
import type { Meta, StoryObj } from '@storybook/react'
import { EffectComposer, SSGI as SSGIImpl } from '../../src'
import { Canvas } from '@react-three/fiber'
import { Environment, useGLTF, OrbitControls } from '@react-three/drei'

const meta = {
title: 'Effects/SSGI',
component: SSGIImpl,
parameters: {
layout: 'fullscreen',
},
} satisfies Meta<typeof SSGIImpl>
export default meta

function Model() {
const gltf = useGLTF('/porsche.glb')
return <primitive object={gltf.scene} />
}

type Story = StoryObj<typeof meta>

export const SSGI: Story = {
render: (args) => (
<Canvas gl={{ antialias: false }} camera={{ fov: 35, position: [5, 3, 5] }}>
<OrbitControls />
<Environment preset="city" />
<EffectComposer>
<SSGIImpl {...args} />
</EffectComposer>
<Model />
<directionalLight position={[217, 43, 76]} />
</Canvas>
),
args: {
distance: 10,
thickness: 10,
autoThickness: false,
maxRoughness: 1,
blend: 0.9,
denoiseIterations: 1,
denoiseKernel: 2,
denoiseDiffuse: 10,
denoiseSpecular: 10,
depthPhi: 2,
normalPhi: 50,
roughnessPhi: 1,
envBlur: 0.5,
importanceSampling: true,
directLightMultiplier: 1,
steps: 20,
refineSteps: 5,
spp: 1,
resolutionScale: 1,
missedRays: false,
},
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"maath": "^0.5.3",
"n8ao": "^1.2.1",
"postprocessing": "^6.30.2",
"realism-effects": "^1.1.2",
"screen-space-reflections": "2.5.0",
"three-stdlib": "^2.21.10"
},
Expand Down
154 changes: 154 additions & 0 deletions src/effects/SSGI.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import * as THREE from 'three'
import { useMemo, useEffect, forwardRef } from 'react'
import { useThree } from '@react-three/fiber'
import { Pass, EffectPass } from 'postprocessing'
// @ts-ignore
import { VelocityDepthNormalPass, SSGIEffect, TRAAEffect } from 'realism-effects'

export interface SSGIOptions {
distance: number
thickness: number
autoThickness: boolean
maxRoughness: number
blend: number
denoiseIterations: number
denoiseKernel: number
denoiseDiffuse: number
denoiseSpecular: number
depthPhi: number
normalPhi: number
roughnessPhi: number
envBlur: number
importanceSampling: boolean
directLightMultiplier: number
steps: number
refineSteps: number
spp: number
resolutionScale: number
missedRays: boolean
}

class SSGIPass extends Pass {
readonly velocityDepthNormalPass: VelocityDepthNormalPass
readonly ssgiPass: EffectPass
readonly traaPass: EffectPass

constructor(scene: THREE.Scene, camera: THREE.Camera, options: SSGIOptions = {} as SSGIOptions) {
super('SSGIPass', scene, camera)

this.velocityDepthNormalPass = new VelocityDepthNormalPass(scene, camera)
this.ssgiPass = new EffectPass(camera, new SSGIEffect(scene, camera, this.velocityDepthNormalPass, options))
this.traaPass = new EffectPass(camera, new TRAAEffect(scene, camera, this.velocityDepthNormalPass))
}

initialize(renderer: THREE.WebGLRenderer, alpha: boolean, frameBufferType: number) {
this.velocityDepthNormalPass.initialize(renderer, alpha, frameBufferType)
this.ssgiPass.initialize(renderer, alpha, frameBufferType)
this.traaPass.initialize(renderer, alpha, frameBufferType)
}

setSize(width: number, height: number): void {
this.velocityDepthNormalPass.setSize(width, height)
this.ssgiPass.setSize(width, height)
this.traaPass.setSize(width, height)
}

render(
renderer: THREE.WebGLRenderer,
inputBuffer: THREE.WebGLRenderTarget | null,
outputBuffer: THREE.WebGLRenderTarget | null,
deltaTime?: number,
stencilTest?: boolean
): void {
this.velocityDepthNormalPass.render(renderer, outputBuffer, inputBuffer, deltaTime, stencilTest)
this.ssgiPass.render(renderer, outputBuffer, inputBuffer, deltaTime, stencilTest)
this.traaPass.renderToScreen = this.renderToScreen
this.traaPass.render(renderer, inputBuffer, outputBuffer, deltaTime, stencilTest)
}
}

export interface SSGIProps extends SSGIOptions {}

export const SSGI = forwardRef<SSGIPass, SSGIOptions>(function SSGI(
{
distance = 10,
thickness = 10,
autoThickness = false,
maxRoughness = 1,
blend = 0.9,
denoiseIterations = 1,
denoiseKernel = 2,
denoiseDiffuse = 10,
denoiseSpecular = 10,
depthPhi = 2,
normalPhi = 50,
roughnessPhi = 1,
envBlur = 0.5,
importanceSampling = true,
directLightMultiplier = 1,
steps = 20,
refineSteps = 5,
spp = 1,
resolutionScale = 1,
missedRays = false,
...props
},
ref
) {
const { scene, camera } = useThree()
const effect = useMemo(
() =>
new SSGIPass(scene, camera, {
distance,
thickness,
autoThickness,
maxRoughness,
blend,
denoiseIterations,
denoiseKernel,
denoiseDiffuse,
denoiseSpecular,
depthPhi,
normalPhi,
roughnessPhi,
envBlur,
importanceSampling,
directLightMultiplier,
steps,
refineSteps,
spp,
resolutionScale,
missedRays,
}),
[
scene,
camera,
distance,
thickness,
autoThickness,
maxRoughness,
blend,
denoiseIterations,
denoiseKernel,
denoiseDiffuse,
denoiseSpecular,
depthPhi,
normalPhi,
roughnessPhi,
envBlur,
importanceSampling,
directLightMultiplier,
steps,
refineSteps,
spp,
resolutionScale,
missedRays,
]
)

useEffect(() => {
return () => effect.dispose()
}, [effect])

return <primitive {...props} ref={ref} object={effect} />
})
1 change: 1 addition & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export * from './effects/ScanlineEffect'
export * from './effects/SelectiveBloom'
export * from './effects/Sepia'
export * from './effects/SSAO'
export * from './effects/SSGI'
export * from './effects/N8AO'
export * from './effects/SMAA'
export * from './effects/Texture'
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8947,6 +8947,11 @@ readdirp@~3.6.0:
dependencies:
picomatch "^2.2.1"

realism-effects@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/realism-effects/-/realism-effects-1.1.2.tgz#14b844b45267b1afe661ad9b31251a63b0429fdd"
integrity sha512-dHI++mxZNYJ/k8UO+TUE/PHiNiZcUSkrNlSEwVT48c4d4PHjSz9sjdkH2QlzbmOaI4wYJEmcc9VzI6BZNgpx1A==

recast@^0.21.0:
version "0.21.5"
resolved "https://registry.yarnpkg.com/recast/-/recast-0.21.5.tgz#e8cd22bb51bcd6130e54f87955d33a2b2e57b495"
Expand Down