Skip to content

Commit 8fc0321

Browse files
feat: add chromatic aberration effect (#149)
* add chromatic aberration * add chromatic aberration * improve doc and demo * fix <suspense> doc * revert outlineDemo deleted by mistake * update for package v2 --------- Co-authored-by: Alvaro Saburido <[email protected]>
1 parent f5a699f commit 8fc0321

File tree

8 files changed

+284
-0
lines changed

8 files changed

+284
-0
lines changed

docs/.vitepress/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export default defineConfig({
5353
{ text: 'Glitch', link: '/guide/pmndrs/glitch' },
5454
{ text: 'Noise', link: '/guide/pmndrs/noise' },
5555
{ text: 'Outline', link: '/guide/pmndrs/outline' },
56+
{ text: 'Chromatic Aberration', link: '/guide/pmndrs/chromatic-aberration' },
5657
{ text: 'Scanline', link: '/guide/pmndrs/scanline' },
5758
{ text: 'Pixelation', link: '/guide/pmndrs/pixelation' },
5859
{ text: 'Vignette', link: '/guide/pmndrs/vignette' },
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
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, Vector2 } from 'three'
6+
import { shallowRef, watchEffect } from 'vue'
7+
import { ChromaticAberrationPmndrs, 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+
}
16+
17+
const chromaticAberrationRef = shallowRef(null)
18+
19+
const { offsetX, offsetY, radialModulation, modulationOffset } = useControls({
20+
offsetX: { value: 0.070, step: 0.001, max: 0.5 },
21+
offsetY: { value: 0.070, step: 0.001, max: 0.5 },
22+
radialModulation: true,
23+
modulationOffset: { value: 0, step: 0.01 },
24+
})
25+
26+
watchEffect(() => {
27+
modulationOffset.value.visible = radialModulation.value.value
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+
<template
44+
v-for="i in 4"
45+
:key="i"
46+
>
47+
<TresMesh
48+
:position="[((i - 1) - (4 - 1) / 2) * 1.5, 0, 0]"
49+
>
50+
<TresBoxGeometry
51+
:width="4"
52+
:height="4"
53+
:depth="4"
54+
/>
55+
<TresMeshStandardMaterial color="#1C1C1E" />
56+
</TresMesh>
57+
</template>
58+
59+
<TresAmbientLight color="#ffffff" />
60+
61+
<TresDirectionalLight />
62+
63+
<ContactShadows
64+
:opacity="1"
65+
:position-y="-.5"
66+
:scale="20"
67+
:blur=".85"
68+
/>
69+
70+
<Suspense>
71+
<EffectComposerPmndrs>
72+
<ChromaticAberrationPmndrs ref="chromaticAberrationRef" :offset="new Vector2(offsetX.value, offsetY.value)" :radial-modulation="radialModulation.value" :modulation-offset="modulationOffset.value" />
73+
</EffectComposerPmndrs>
74+
</Suspense>
75+
76+
<Suspense>
77+
<Environment :intensity="2" :blur="0" preset="snow" />
78+
</Suspense>
79+
</TresCanvas>
80+
</template>

docs/components.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ declare module 'vue' {
99
export interface GlobalComponents {
1010
BlenderCube: typeof import('./.vitepress/theme/components/BlenderCube.vue')['default']
1111
BloomDemo: typeof import('./.vitepress/theme/components/pmdrs/BloomDemo.vue')['default']
12+
ChromaticAberrationDemo: typeof import('./.vitepress/theme/components/pmdrs/ChromaticAberrationDemo.vue')['default']
1213
DepthOfFieldDemo: typeof import('./.vitepress/theme/components/pmdrs/DepthOfFieldDemo.vue')['default']
1314
DocsDemo: typeof import('./.vitepress/theme/components/DocsDemo.vue')['default']
1415
Ducky: typeof import('./.vitepress/theme/components/Ducky.vue')['default']
@@ -24,6 +25,7 @@ declare module 'vue' {
2425
PixelationThreeDemo: typeof import('./.vitepress/theme/components/three/PixelationThreeDemo.vue')['default']
2526
ScanlineDemo: typeof import('./.vitepress/theme/components/pmdrs/ScanlineDemo.vue')['default']
2627
SMAAThreeDemo: typeof import('./.vitepress/theme/components/three/SMAAThreeDemo.vue')['default']
28+
ToneMappingDemo: typeof import('./.vitepress/theme/components/pmdrs/ToneMappingDemo.vue')['default']
2729
UnrealBloomThreeDemo: typeof import('./.vitepress/theme/components/three/UnrealBloomThreeDemo.vue')['default']
2830
VignetteDemo: typeof import('./.vitepress/theme/components/pmdrs/VignetteDemo.vue')['default']
2931
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Chromatic Aberration
2+
3+
<DocsDemo>
4+
<ChromaticAberrationDemo />
5+
</DocsDemo>
6+
7+
The `ChromaticAberration` effect is part of the [`postprocessing`](https://pmndrs.github.io/postprocessing/public/docs/class/src/effects/ChromaticAberrationEffect.js~ChromaticAberrationEffect.html) package. It simulates the dispersion of light as it passes through a lens, creating subtle or dramatic color fringing effects at the edges of objects. This effect can enhance the visual appeal of your scene by adding a realistic lens effect or a stylized touch.
8+
9+
## Usage
10+
11+
The `<ChromaticAberrationPmndrs>` component is easy to use and provides customizable options to suit different visual styles.
12+
13+
```vue{2,38-46}
14+
<script setup lang="ts">
15+
import { EffectComposerPmndrs, ChromaticAberrationPmndrs } from '@tresjs/post-processing/pmndrs'
16+
import { Vector2 } from 'three'
17+
18+
const gl = {
19+
toneMapping: NoToneMapping,
20+
multisampling: 8,
21+
}
22+
23+
const offset = new Vector2(0.07, 0.07)
24+
</script>
25+
26+
<template>
27+
<TresCanvas
28+
v-bind="gl"
29+
>
30+
<TresPerspectiveCamera
31+
:position="[5, 5, 5]"
32+
:look-at="[0, 0, 0]"
33+
/>
34+
35+
<template
36+
v-for="i in 4"
37+
:key="i"
38+
>
39+
<TresMesh
40+
:position="[((i - 1) - (4 - 1) / 2) * 1.5, 0, 0]"
41+
>
42+
<TresBoxGeometry
43+
:width="4"
44+
:height="4"
45+
:depth="4"
46+
/>
47+
<TresMeshStandardMaterial color="#1C1C1E" />
48+
</TresMesh>
49+
</template>
50+
51+
<Suspense>
52+
<EffectComposerPmndrs>
53+
<ChromaticAberrationPmndrs
54+
:offset
55+
radial-modulation
56+
:modulation-offset="0"
57+
/>
58+
</EffectComposerPmndrs>
59+
</Suspense>
60+
</TresCanvas>
61+
</template>
62+
```
63+
64+
## Props
65+
66+
| Prop | Description | Default |
67+
| ----------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------- |
68+
| blendFunction | Defines the [`BlendFunction`](https://pmndrs.github.io/postprocessing/public/docs/variable/index.html#static-variable-BlendFunction) used for the effect. | `BlendFunction.SRC` |
69+
| offset | The color offset vector determining the intensity and direction of chromatic aberration. | `Vector2(0.01, 0.01)` |
70+
| radialModulation | Enables radial modulation to vary the effect intensity based on distance from the center. | `false` |
71+
| modulationOffset | Specifies the modulation offset when `radialModulation` is **enabled**. | `0.15` |
72+
73+
::: info
74+
The `modulationOffset` property is functional only when `radialModulation` is enabled.
75+
:::
76+
77+
## Further Reading
78+
see [postprocessing docs](https://pmndrs.github.io/postprocessing/public/docs/class/src/effects/ToneMappingEffect.js~ToneMappingEffect.html)
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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, Vector2 } from 'three'
6+
import { watchEffect } from 'vue'
7+
import { BlendFunction } from 'postprocessing'
8+
import { ChromaticAberrationPmndrs, EffectComposerPmndrs } from '@tresjs/post-processing'
9+
10+
import '@tresjs/leches/styles'
11+
12+
const gl = {
13+
clearColor: '#ffffff',
14+
toneMapping: NoToneMapping,
15+
multisampling: 8,
16+
envMapIntensity: 10,
17+
}
18+
19+
const { offsetX, offsetY, radialModulation, modulationOffset, blendFunction } = useControls({
20+
offsetX: { value: 0.085, step: 0.001, max: 0.5 },
21+
offsetY: { value: 0.0, step: 0.001, max: 0.5 },
22+
radialModulation: false,
23+
modulationOffset: { value: 0, step: 0.01 },
24+
blendFunction: {
25+
options: Object.keys(BlendFunction).map(key => ({
26+
text: key,
27+
value: BlendFunction[key],
28+
})),
29+
value: BlendFunction.SRC,
30+
},
31+
})
32+
33+
watchEffect(() => {
34+
modulationOffset.value.visible = radialModulation.value.value
35+
})
36+
</script>
37+
38+
<template>
39+
<TresLeches />
40+
41+
<TresCanvas
42+
v-bind="gl"
43+
>
44+
<TresPerspectiveCamera
45+
:position="[5, 5, 5]"
46+
:look-at="[0, 0, 0]"
47+
/>
48+
<OrbitControls auto-rotate />
49+
50+
<TresMesh :position="[0, .5, 0]">
51+
<TresBoxGeometry :args="[2, 2, 2]" />
52+
<TresMeshPhysicalMaterial color="#82DBC5" :roughness=".25" />
53+
</TresMesh>
54+
55+
<ContactShadows
56+
:opacity="1"
57+
:position-y="-.5"
58+
/>
59+
60+
<Suspense>
61+
<EffectComposerPmndrs>
62+
<ChromaticAberrationPmndrs :offset="new Vector2(offsetX.value, offsetY.value)" :radial-modulation="radialModulation.value" :modulation-offset="modulationOffset.value" :blendFunction="Number(blendFunction.value)" />
63+
</EffectComposerPmndrs>
64+
</Suspense>
65+
</TresCanvas>
66+
</template>

playground/src/router.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export const postProcessingRoutes = [
3939
makeRoute('Pixelation', '👾', false),
4040
makeRoute('Bloom', '🌼', false),
4141
makeRoute('Noise', '📟', false),
42+
makeRoute('Chromatic Aberration', '🌈', false),
4243
makeRoute('Scanline', '📺', false),
4344
makeRoute('Vignette', '🕶️', false),
4445
makeRoute('On-demand', '🔄', false),
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<script lang="ts" setup>
2+
import type { BlendFunction } from 'postprocessing'
3+
import { ChromaticAberrationEffect } from 'postprocessing'
4+
import { Vector2 } from 'three'
5+
import { makePropWatchers } from '../../util/prop'
6+
import { useEffectPmndrs } from './composables/useEffectPmndrs'
7+
8+
export interface ChromaticAberrationPmndrsProps {
9+
/**
10+
* The blend function.
11+
*/
12+
blendFunction?: BlendFunction
13+
14+
/**
15+
* The color offset.
16+
*/
17+
offset?: Vector2
18+
19+
/**
20+
* Whether the effect should be modulated with a radial gradient.
21+
*/
22+
radialModulation?: boolean
23+
24+
/**
25+
* The modulation offset, applicable if radial modulation is enabled.
26+
*/
27+
modulationOffset?: number
28+
}
29+
30+
const props = withDefaults(
31+
defineProps<ChromaticAberrationPmndrsProps>(),
32+
{
33+
offset: () => new Vector2(0.01, 0.01),
34+
radialModulation: false,
35+
modulationOffset: 0.15,
36+
},
37+
)
38+
39+
const { pass, effect } = useEffectPmndrs(() => new ChromaticAberrationEffect(props), props)
40+
41+
defineExpose({ pass, effect })
42+
43+
makePropWatchers(
44+
[
45+
[() => props.blendFunction, 'blendMode.blendFunction'],
46+
[() => props.offset, 'offset'],
47+
[() => props.radialModulation, 'radialModulation'],
48+
[() => props.modulationOffset, 'modulationOffset'],
49+
],
50+
effect,
51+
() => new ChromaticAberrationEffect(),
52+
)
53+
</script>

src/core/pmndrs/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import NoisePmndrs, { type NoisePmndrsProps } from './NoisePmndrs.vue'
99
import OutlinePmndrs, { type OutlinePmndrsProps } from './OutlinePmndrs.vue'
1010
import PixelationPmndrs, { type PixelationPmndrsProps } from './PixelationPmndrs.vue'
1111
import VignettePmndrs, { type VignettePmndrsProps } from './VignettePmndrs.vue'
12+
import ChromaticAberrationPmndrs, { type ChromaticAberrationPmndrsProps } from './ChromaticAberration.vue'
1213
import HueSaturationPmndrs, { type HueSaturationPmndrsProps } from './HueSaturationPmndrs.vue'
1314
import ScanlinePmndrs, { type ScanlinePmndrsProps } from './ScanlinePmndrs.vue'
1415

@@ -22,6 +23,7 @@ export {
2223
PixelationPmndrs,
2324
useEffectPmndrs,
2425
VignettePmndrs,
26+
ChromaticAberrationPmndrs,
2527
HueSaturationPmndrs,
2628
ScanlinePmndrs,
2729
BloomPmndrsProps,
@@ -32,6 +34,7 @@ export {
3234
OutlinePmndrsProps,
3335
PixelationPmndrsProps,
3436
VignettePmndrsProps,
37+
ChromaticAberrationPmndrsProps,
3538
HueSaturationPmndrsProps,
3639
ScanlinePmndrsProps,
3740
}

0 commit comments

Comments
 (0)