Skip to content

Commit fba8b58

Browse files
feat: FXAA (#197)
* feat: add and init playground + doc fxaa * fix: doc and code adapation * modify doc, examples
1 parent 70dbb3b commit fba8b58

File tree

8 files changed

+502
-0
lines changed

8 files changed

+502
-0
lines changed

docs/.vitepress/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export default defineConfig({
6161
{ text: 'Hue & Saturation', link: '/guide/pmndrs/hue-saturation' },
6262
{ text: 'Lens Distortion', link: '/guide/pmndrs/lens-distortion' },
6363
{ text: 'Grid', link: '/guide/pmndrs/grid' },
64+
{ text: 'FXAA', link: '/guide/pmndrs/fxaa' },
6465
{ text: 'Kuwahara', link: '/guide/pmndrs/kuwahara' },
6566
{ text: 'Color Average', link: '/guide/pmndrs/color-average' },
6667
{ text: 'Depth of Field', link: '/guide/pmndrs/depth-of-field' },
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
<script setup lang="ts">
2+
import { 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 { EffectComposerPmndrs, FXAAPmndrs } from '@tresjs/post-processing'
8+
import type { PerspectiveCamera } from 'three'
9+
import { ref } from 'vue'
10+
11+
import '@tresjs/leches/styles'
12+
13+
const gl = {
14+
antialias: false,
15+
clearColor: '#2e3440',
16+
toneMapping: NoToneMapping,
17+
}
18+
19+
const { autoRotateSpeed, blendFunction, wireframe, boxColor, opacity, samples, minEdgeThreshold, maxEdgeThreshold, subpixelQuality } = useControls({
20+
blendFunction: {
21+
options: Object.keys(BlendFunction).map(key => ({
22+
text: key,
23+
value: BlendFunction[key as keyof typeof BlendFunction],
24+
})),
25+
value: BlendFunction.SRC,
26+
},
27+
samples: {
28+
value: 12,
29+
min: 0,
30+
max: 32,
31+
step: 1,
32+
},
33+
minEdgeThreshold: {
34+
value: 0.0312,
35+
min: 0,
36+
max: 1,
37+
step: 0.001,
38+
},
39+
maxEdgeThreshold: {
40+
value: 0.125,
41+
min: 0,
42+
max: 1,
43+
step: 0.001,
44+
},
45+
subpixelQuality: {
46+
value: 0.75,
47+
min: 0,
48+
max: 1,
49+
step: 0.01,
50+
},
51+
autoRotateSpeed: {
52+
value: 1,
53+
min: 0,
54+
max: 10,
55+
step: 0.1,
56+
},
57+
boxColor: '#ffffff',
58+
wireframe: false,
59+
opacity: {
60+
value: 1,
61+
min: 0,
62+
max: 1,
63+
step: 0.01,
64+
},
65+
})
66+
67+
const wrapperRef = ref<HTMLElement | undefined>(undefined)
68+
const cameraRef = ref<PerspectiveCamera | null>(null)
69+
70+
const onChange = (e: { object: PerspectiveCamera }) => {
71+
if (!cameraRef.value) { return }
72+
73+
cameraRef.value.position.copy(e.object.position)
74+
cameraRef.value.rotation.copy(e.object.rotation)
75+
cameraRef.value.zoom = e.object.zoom
76+
cameraRef.value.quaternion.copy(e.object.quaternion)
77+
}
78+
</script>
79+
80+
<template>
81+
<div ref="wrapperRef" class="aspect-16/9 relative h-full">
82+
<TresCanvas
83+
v-bind="gl"
84+
class="doc-fxaa-canvas-left"
85+
>
86+
<TresPerspectiveCamera :position="[0, 2, 3.5]" />
87+
<OrbitControls :domElement="wrapperRef" auto-rotate :auto-rotate-speed="autoRotateSpeed" :target="[0, 0.25, 0]" @change="onChange" />
88+
89+
<TresMesh :position="[0, .5, 0]">
90+
<TresBoxGeometry :args="[2, 2, 2]" />
91+
<TresMeshBasicMaterial :color="boxColor" :wireframe="wireframe" />
92+
</TresMesh>
93+
</TresCanvas>
94+
95+
<div class="doc-fxaa-divider"></div>
96+
97+
<TresCanvas
98+
v-bind="gl"
99+
class="doc-fxaa-canvas-right"
100+
>
101+
<TresPerspectiveCamera ref="cameraRef" :position="[0, 2, 3.5]" />
102+
103+
<TresMesh :position="[0, .5, 0]">
104+
<TresBoxGeometry :args="[2, 2, 2]" />
105+
<TresMeshBasicMaterial :color="boxColor" :wireframe="wireframe" />
106+
</TresMesh>
107+
108+
<Suspense>
109+
<EffectComposerPmndrs>
110+
<FXAAPmndrs
111+
:blendFunction="Number(blendFunction)"
112+
:opacity="opacity"
113+
:samples="samples"
114+
:maxEdgeThreshold="maxEdgeThreshold"
115+
:minEdgeThreshold="minEdgeThreshold"
116+
:subpixelQuality="subpixelQuality"
117+
/>
118+
</EffectComposerPmndrs>
119+
</Suspense>
120+
</TresCanvas>
121+
122+
<p class="doc-fxaa-info doc-fxaa-info-left text-xs font-semibold">⬅️ No FXAA</p>
123+
<p class="doc-fxaa-info doc-fxaa-info-right text-xs font-semibold">With FXAA ➡️</p>
124+
</div>
125+
126+
<TresLeches :float="false" />
127+
</template>
128+
129+
<style scoped>
130+
.doc-fxaa-canvas-left {
131+
position: absolute !important;
132+
inset: 0;
133+
z-index: 1;
134+
clip-path: inset(0 50% 0 0);
135+
-webkit-clip-path: inset(0 50% 0 0);
136+
}
137+
138+
.doc-fxaa-canvas-right {
139+
position: absolute !important;
140+
inset: 0;
141+
z-index: 2;
142+
pointer-events: none;
143+
clip-path: inset(0 0 0 50%);
144+
-webkit-clip-path: inset(0 0 0 50%);
145+
}
146+
147+
.doc-fxaa-divider {
148+
position: absolute;
149+
top: 0;
150+
bottom: 0;
151+
left: 50%;
152+
width: 2px;
153+
background: red;
154+
z-index: 3;
155+
pointer-events: none;
156+
}
157+
158+
.doc-fxaa-info {
159+
position: absolute;
160+
bottom: 0;
161+
padding: 0.45rem 0.75rem;
162+
margin: 0;
163+
text-align: center;
164+
color: #fff;
165+
z-index: 2;
166+
background: linear-gradient(90deg, #7a95b1 0%, #517284 100%);
167+
}
168+
169+
.doc-fxaa-info-left {
170+
left: 0;
171+
border-radius: 0px 10px 0px 0px;
172+
}
173+
174+
.doc-fxaa-info-right {
175+
right: 0;
176+
border-radius: 10px 0px 0px 0px;
177+
}
178+
</style>

docs/components.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ declare module 'vue' {
2121
DotScreenDemo: typeof import('./.vitepress/theme/components/pmdrs/DotScreenDemo.vue')['default']
2222
Ducky: typeof import('./.vitepress/theme/components/Ducky.vue')['default']
2323
FishEyeDemo: typeof import('./.vitepress/theme/components/pmdrs/FishEyeDemo.vue')['default']
24+
FXAADemo: typeof import('./.vitepress/theme/components/pmdrs/FXAADemo.vue')['default']
2425
GlitchDemo: typeof import('./.vitepress/theme/components/pmdrs/GlitchDemo.vue')['default']
2526
GlitchThreeDemo: typeof import('./.vitepress/theme/components/three/GlitchThreeDemo.vue')['default']
2627
GodRaysDemo: typeof import('./.vitepress/theme/components/pmdrs/GodRaysDemo.vue')['default']

docs/guide/pmndrs/fxaa.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# FXAA
2+
3+
<DocsDemoGUI>
4+
<FXAADemo />
5+
</DocsDemoGUI>
6+
7+
<details>
8+
<summary>Demo code</summary>
9+
10+
<<< @/.vitepress/theme/components/pmdrs/FXAADemo.vue{0}
11+
</details>
12+
13+
The `FXAAEffect` effect is part of the [`postprocessing`](https://pmndrs.github.io/postprocessing/public/docs/class/src/effects/FXAAEffect.js~FXAAEffect.html) package.
14+
FXAA offers a performance-optimized anti-aliasing solution that smooths jagged edges while maintaining excellent performance. However, its quality may be modest at times, occasionally resulting in a slightly blurred appearance.
15+
16+
<a href="https://x.com/Miamiamia0103/status/1490355292487487494" target="_blank" class="flex flex-col gap-[7.5px] items-center justify-center">
17+
<img src="https://pbs.twimg.com/media/FK7MziPWUAYdHfu?format=jpg&name=large" alt="@Miamiamia0103 illustration" class="w-4/5">
18+
<span class="text-xs">
19+
Illustration credit @Miamiamia0103
20+
</span>
21+
</a>
22+
23+
## Usage
24+
25+
The `<FXAAPmndrs>` component is easy to use and provides customizable options to suit different visual styles.
26+
27+
:::info
28+
When using the `<EffectComposerPmndrs>` pipeline, enabling native antialiasing with the [`antialias`](https://docs.tresjs.org/api/tres-canvas.html#props) props on `<TresCanvas>` is unnecessary.
29+
:::
30+
31+
```vue{2,12-14,23-27}
32+
<script setup lang="ts">
33+
import { EffectComposerPmndrs, FXAAPmndrs } from '@tresjs/post-processing/pmndrs'
34+
35+
const gl = {
36+
toneMapping: NoToneMapping,
37+
antialias: false,
38+
}
39+
// It is not required to add `antialias: false` for
40+
// the <TresCanvas> context, as it is automatically
41+
// disabled when using `<EffectComposerPmndrs>`.
42+
43+
const effectProps = {
44+
samples: 24
45+
}
46+
</script>
47+
48+
<template>
49+
<TresCanvas v-bind="gl">
50+
<TresPerspectiveCamera />
51+
52+
<!-- Your scene -->
53+
54+
<Suspense>
55+
<EffectComposerPmndrs>
56+
<FXAAPmndrs v-bind="effectProps" />
57+
</EffectComposerPmndrs>
58+
</Suspense>
59+
</TresCanvas>
60+
</template>
61+
```
62+
63+
## Props
64+
65+
| Prop | Description | Default |
66+
| ------------- | ------------------------------------------------------------------- | --------------------------- |
67+
| 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.SRC` |
68+
| opacity | The opacity of the effect. | `1` |
69+
| samples | The maximum amount of edge detection samples. | `12` |
70+
| minEdgeThreshold | The minimum edge detection threshold. <br> Range: `[0.0, 1.0]`. | `0.0312` |
71+
| maxEdgeThreshold | The maximum edge detection threshold. <br> Range: `[0.0, 1.0]`. | `0.125` |
72+
| subpixelQuality | The subpixel blend quality. Range: `[0.0, 1.0]`. | `0.75` |
73+
74+
## Further Reading
75+
For more details, see the [FXAAEffect documentation](https://pmndrs.github.io/postprocessing/public/docs/class/src/effects/FXAAEffect.js~FXAAEffect.html)

0 commit comments

Comments
 (0)