Skip to content

Commit 84cc46a

Browse files
feat: add barrel blur effect (#159)
* add effect barrel-blur * add custom effect barrel * update to V2 package * update code * add docs and fix code * lint * fix doc and code * fix doc and code * update props and constructor * fix lint issue and doc --------- Co-authored-by: Tino Koch <17991193+Tinoooo@users.noreply.github.com>
1 parent db77fc6 commit 84cc46a

File tree

9 files changed

+384
-0
lines changed

9 files changed

+384
-0
lines changed

docs/.vitepress/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export default defineConfig({
5959
{ text: 'Scanline', link: '/guide/pmndrs/scanline' },
6060
{ text: 'Pixelation', link: '/guide/pmndrs/pixelation' },
6161
{ text: 'Vignette', link: '/guide/pmndrs/vignette' },
62+
{ text: 'Barrel blur', link: '/guide/pmndrs/barrel-blur' },
6263
{ text: 'Hue & Saturation', link: '/guide/pmndrs/hue-saturation' },
6364
{ text: 'Dot Screen', link: '/guide/pmndrs/dot-screen' },
6465
],
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<script setup lang="ts">
2+
import { Environment, OrbitControls, RoundedBox } from '@tresjs/cientos'
3+
import { TresCanvas } from '@tresjs/core'
4+
import { TresLeches, useControls } from '@tresjs/leches'
5+
import { BarrelBlurPmndrs, EffectComposerPmndrs } from '@tresjs/post-processing'
6+
import { BlendFunction } from 'postprocessing'
7+
import { NoToneMapping } from 'three'
8+
9+
import '@tresjs/leches/styles'
10+
11+
const gl = {
12+
clearColor: '#4f4f4f',
13+
toneMapping: NoToneMapping,
14+
multisampling: 8,
15+
}
16+
17+
const { amount, offsetX, offsetY, blendFunction } = useControls({
18+
amount: { value: 0.25, step: 0.001, max: 1 },
19+
offsetX: { value: 0.5, step: 0.01, min: 0, max: 1 },
20+
offsetY: { value: 0.5, step: 0.01, min: 0, max: 1 },
21+
blendFunction: {
22+
options: Object.keys(BlendFunction).map(key => ({
23+
text: key,
24+
value: BlendFunction[key],
25+
})),
26+
value: BlendFunction.OVERLAY,
27+
},
28+
})
29+
</script>
30+
31+
<template>
32+
<TresLeches style="left: initial;right:10px; top:10px;" />
33+
34+
<TresCanvas
35+
v-bind="gl"
36+
>
37+
<TresPerspectiveCamera
38+
:position="[5, 5, 5]"
39+
:look-at="[0, 0, 0]"
40+
/>
41+
<OrbitControls auto-rotate />
42+
43+
<Suspense>
44+
<Environment preset="shangai" />
45+
</Suspense>
46+
47+
<RoundedBox :args="[2, 2, 2, 2, 0.25]">
48+
<TresMeshPhysicalMaterial
49+
color="white"
50+
:metalness=".9"
51+
:roughness=".5"
52+
:clearcoat="1.0"
53+
:clearcoatRoughness="0.1"
54+
/>
55+
</RoundedBox>
56+
57+
<Suspense>
58+
<EffectComposerPmndrs>
59+
<BarrelBlurPmndrs :amount="amount.value" :offset="[offsetX.value, offsetY.value]" :blendFunction="Number(blendFunction.value)" />
60+
</EffectComposerPmndrs>
61+
</Suspense>
62+
</TresCanvas>
63+
</template>

docs/components.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export {}
77
/* prettier-ignore */
88
declare module 'vue' {
99
export interface GlobalComponents {
10+
BarrelBlurDemo: typeof import('./.vitepress/theme/components/pmdrs/BarrelBlurDemo.vue')['default']
1011
BlenderCube: typeof import('./.vitepress/theme/components/BlenderCube.vue')['default']
1112
BloomDemo: typeof import('./.vitepress/theme/components/pmdrs/BloomDemo.vue')['default']
1213
ChromaticAberrationDemo: typeof import('./.vitepress/theme/components/pmdrs/ChromaticAberrationDemo.vue')['default']

docs/guide/pmndrs/barrel-blur.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Barrel Blur
2+
3+
<DocsDemo>
4+
<BarrelBlurDemo />
5+
</DocsDemo>
6+
7+
The `Barrel Blur` is a custom effect that applies a barrel distortion with chromatic aberration blur, providing a unique visual effect.
8+
9+
## Usage
10+
11+
The `<BarrelBlurPmndrs>` component is straightforward to use and provides customizable options to fine-tune the barrel blur effect.
12+
13+
```vue{4,12-15,40-44}
14+
<script setup lang="ts">
15+
import { TresCanvas } from '@tresjs/core'
16+
import { Environment, OrbitControls, RoundedBox } from '@tresjs/cientos'
17+
import { EffectComposerPmndrs, BarrelBlurPmndrs } from '@tresjs/post-processing'
18+
19+
const gl = {
20+
clearColor: '#4f4f4f',
21+
toneMapping: NoToneMapping,
22+
multisampling: 8,
23+
}
24+
25+
const effectProps = {
26+
amount: 0.25,
27+
offset: [0.5, 0.5],
28+
}
29+
</script>
30+
31+
<template>
32+
<TresCanvas v-bind="gl">
33+
<TresPerspectiveCamera
34+
:position="[5, 5, 5]"
35+
:look-at="[0, 0, 0]"
36+
/>
37+
<OrbitControls auto-rotate />
38+
39+
<Suspense>
40+
<Environment preset="shangai" />
41+
</Suspense>
42+
43+
<RoundedBox :args="[2, 2, 2, 2, 0.25]">
44+
<TresMeshPhysicalMaterial
45+
color="white"
46+
:metalness=".9"
47+
:roughness=".5"
48+
:clearcoat="1.0"
49+
:clearcoatRoughness="0.1"
50+
/>
51+
</RoundedBox>
52+
53+
<Suspense>
54+
<EffectComposerPmndrs>
55+
<BarrelBlurPmndrs v-bind="effectProps" />
56+
</EffectComposerPmndrs>
57+
</Suspense>
58+
</TresCanvas>
59+
</template>
60+
```
61+
62+
## Props
63+
64+
| Prop | Description | Default |
65+
| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ |
66+
| **amount** | The intensity of the barrel distortion. A value between 0 (no distortion) and 1 (maximum distortion). | `0.1` |
67+
| **offset** | The offset of the barrel distortion center. A `Vector2` value or an array of two numbers where both values are between 0 and 1. | `[0.5, 0.5]` |
68+
| **blendFunction** | Defines how the effect blends with the original scene. See the [`BlendFunction`](https://pmndrs.github.io/postprocessing/public/docs/variable/index.html#static-variable-BlendFunction) options. | `BlendFunction.NORMAL` |
69+
70+
## Further Reading
71+
72+
For an example of the barrel blur effect in WebGL, see the [Barrel Blur Effect on Shadertoy](https://www.shadertoy.com/view/lc3BW8).
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<script setup lang="ts">
2+
import { ContactShadows, Environment, OrbitControls } from '@tresjs/cientos'
3+
import { TresCanvas } from '@tresjs/core'
4+
import { TresLeches, useControls } from '@tresjs/leches'
5+
import { NoToneMapping } from 'three'
6+
import { BlendFunction } from 'postprocessing'
7+
import { BarrelBlurPmndrs, EffectComposerPmndrs } from '@tresjs/post-processing'
8+
9+
import '@tresjs/leches/styles'
10+
11+
const gl = {
12+
clearColor: '#ffffff',
13+
toneMapping: NoToneMapping,
14+
multisampling: 8,
15+
envMapIntensity: 10,
16+
}
17+
18+
const neonColors = [
19+
'#FF00FF', // Magenta
20+
'#00FFFF', // Cyan
21+
'#00FF00', // Lime
22+
'#FFFF00', // Yellow
23+
'#FF0000', // Red
24+
'#FF1493', // Deep Pink
25+
'#7FFF00', // Chartreuse
26+
'#FF4500', // Orange Red
27+
'#8A2BE2', // Blue Violet
28+
'#00FF7F', // Spring Green
29+
'#FFD700', // Gold
30+
'#FF69B4', // Hot Pink
31+
'#ADFF2F', // Green Yellow
32+
'#FF6347', // Tomato
33+
'#40E0D0', // Turquoise
34+
'#EE82EE', // Violet
35+
]
36+
37+
const { blendFunction, amount, offsetX, offsetY } = useControls({
38+
amount: { value: 0.2, step: 0.001, max: 1 },
39+
offsetX: { value: 0.5, step: 0.01, min: 0, max: 1 },
40+
offsetY: { value: 0.5, step: 0.01, min: 0, max: 1 },
41+
blendFunction: {
42+
options: Object.keys(BlendFunction).map(key => ({
43+
text: key,
44+
value: BlendFunction[key as keyof typeof BlendFunction],
45+
})),
46+
value: BlendFunction.OVERLAY,
47+
},
48+
})
49+
</script>
50+
51+
<template>
52+
<TresLeches />
53+
54+
<TresCanvas
55+
v-bind="gl"
56+
>
57+
<TresPerspectiveCamera
58+
:position="[0, 6.5, 6.5]"
59+
:look-at="[0, 0, 0]"
60+
/>
61+
<OrbitControls auto-rotate />
62+
63+
<TresAmbientLight :intensity="1" />
64+
65+
<template v-for="(color, index) in neonColors" :key="index">
66+
<TresMesh :position="[index % 4 * 2 - 3, 0, Math.floor(index / 4) * 2 - 3]">
67+
<TresBoxGeometry :args="[2, 2, 2]" />
68+
<TresMeshStandardMaterial :color="color" :roughness=".5" :metalness="1" />
69+
</TresMesh>
70+
</template>
71+
72+
<Suspense>
73+
<Environment :blur=".25" preset="snow" />
74+
</Suspense>
75+
76+
<TresDirectionalLight color="white" />
77+
78+
<ContactShadows
79+
:opacity=".65"
80+
:position-y="-1"
81+
:scale="35"
82+
:blur="1"
83+
/>
84+
85+
<Suspense>
86+
<EffectComposerPmndrs>
87+
<BarrelBlurPmndrs :amount="amount.value" :offset="[offsetX.value, offsetY.value]" :blendFunction="Number(blendFunction.value)" />
88+
</EffectComposerPmndrs>
89+
</Suspense>
90+
</TresCanvas>
91+
</template>

playground/src/router.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export const postProcessingRoutes = [
4545
makeRoute('Sepia', '🌅', false),
4646
makeRoute('Scanline', '📺', false),
4747
makeRoute('Vignette', '🕶️', false),
48+
makeRoute('Barrel blur', '🌀', false),
4849
makeRoute('On-demand', '🔄', false),
4950
]
5051

src/core/pmndrs/BarrelBlurPmndrs.vue

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<script lang="ts" setup>
2+
import type { BlendFunction } from 'postprocessing'
3+
import { Vector2 } from 'three'
4+
import { BarrelBlurEffect } from './custom/barrel-blur/index'
5+
import { makePropWatchers } from '../../util/prop'
6+
import { useEffectPmndrs } from './composables/useEffectPmndrs'
7+
8+
export interface BarrelBlurPmndrsProps {
9+
/**
10+
* The blend function for the effect.
11+
* Determines how this effect blends with other effects.
12+
*/
13+
blendFunction?: BlendFunction
14+
15+
/**
16+
* The intensity of the barrel distortion.
17+
* A value between 0 (no distortion) and 1 (maximum distortion).
18+
*/
19+
amount?: number
20+
21+
/**
22+
* The offset of the barrel distortion center.
23+
* A Vector2 value or an A value or an array of two numbers, with both values ranging from 0 to 1.
24+
* This allows you to change the position of the distortion effect.
25+
*/
26+
offset?: Vector2 | [number, number]
27+
}
28+
29+
const props = defineProps<BarrelBlurPmndrsProps>()
30+
31+
const { pass, effect } = useEffectPmndrs(
32+
() => new BarrelBlurEffect({
33+
...props,
34+
offset: Array.isArray(props.offset) ? new Vector2(...props.offset) : props.offset,
35+
}),
36+
props,
37+
)
38+
39+
defineExpose({ pass, effect })
40+
41+
makePropWatchers(
42+
[
43+
[() => props.blendFunction, 'blendMode.blendFunction'],
44+
[() => props.amount, 'amount'],
45+
[() => props.offset, 'offset'],
46+
],
47+
effect,
48+
() => new BarrelBlurEffect(),
49+
)
50+
</script>

0 commit comments

Comments
 (0)