Skip to content

Commit dbc1083

Browse files
init smaa effect source
1 parent 70dbb3b commit dbc1083

File tree

4 files changed

+314
-0
lines changed

4 files changed

+314
-0
lines changed
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
<script setup lang="ts">
2+
import { TresCanvas } from '@tresjs/core'
3+
import { OrbitControls } from '@tresjs/cientos'
4+
import { TresLeches, useControls } from '@tresjs/leches'
5+
import { NoToneMapping } from 'three'
6+
import { BlendFunction, EdgeDetectionMode, PredicationMode, SMAAPreset } from 'postprocessing'
7+
import { ref } from 'vue'
8+
import { EffectComposerPmndrs, SMAAPmndrs } from '@tresjs/post-processing'
9+
import type { PerspectiveCamera } from 'three'
10+
11+
import '@tresjs/leches/styles'
12+
13+
const gl = {
14+
antialias: false,
15+
clearColor: '#2e3440',
16+
toneMapping: NoToneMapping,
17+
}
18+
19+
const wrapperRef = ref<HTMLElement | undefined>(undefined)
20+
const cameraRef = ref<PerspectiveCamera | null>(null)
21+
22+
const { blendFunction, debug, autoRotateSpeed, opacity, preset, wireframe, predicationMode, edgeDetectionMode } = useControls({
23+
blendFunction: {
24+
options: Object.keys(BlendFunction).map(key => ({
25+
text: key,
26+
value: BlendFunction[key as keyof typeof BlendFunction],
27+
})),
28+
value: BlendFunction.NORMAL,
29+
},
30+
debug: {
31+
options: [
32+
{ text: 'Off', value: 0 },
33+
{ text: 'Edges', value: 1 },
34+
{ text: 'Weights', value: 2 },
35+
],
36+
value: 0,
37+
},
38+
wireframe: false,
39+
preset: {
40+
options: Object.keys(SMAAPreset).map(key => ({
41+
text: key,
42+
value: SMAAPreset[key as keyof typeof SMAAPreset],
43+
})),
44+
value: SMAAPreset.MEDIUM,
45+
},
46+
predicationMode: {
47+
options: Object.keys(PredicationMode).map(key => ({
48+
text: key,
49+
value: PredicationMode[key as keyof typeof PredicationMode],
50+
})),
51+
value: PredicationMode.DISABLED,
52+
},
53+
edgeDetectionMode: {
54+
options: Object.keys(EdgeDetectionMode).map(key => ({
55+
text: key,
56+
value: EdgeDetectionMode[key as keyof typeof EdgeDetectionMode],
57+
})),
58+
value: EdgeDetectionMode.COLOR,
59+
},
60+
autoRotateSpeed: {
61+
value: 0.5,
62+
min: 0,
63+
max: 10,
64+
step: 0.1,
65+
},
66+
opacity: {
67+
value: 1,
68+
min: 0,
69+
max: 1,
70+
step: 0.01,
71+
},
72+
})
73+
74+
const onChange = (e: { object: PerspectiveCamera }) => {
75+
if (!cameraRef.value) { return }
76+
77+
cameraRef.value.position.copy(e.object.position)
78+
cameraRef.value.rotation.copy(e.object.rotation)
79+
cameraRef.value.zoom = e.object.zoom
80+
cameraRef.value.quaternion.copy(e.object.quaternion)
81+
}
82+
</script>
83+
84+
<template>
85+
<TresLeches />
86+
87+
<div ref="wrapperRef" class="h-[100%] w-[100%] relative">
88+
<p class="playground-smaa-infos text-xl absolute">Left: No SMAA — Right: SMAA</p>
89+
90+
<TresCanvas
91+
v-bind="gl"
92+
class="playground-smaa-canvas-left"
93+
window-size
94+
>
95+
<TresPerspectiveCamera :position="[0, 2.5, 3.5]" />
96+
<OrbitControls
97+
auto-rotate
98+
:domElement="wrapperRef"
99+
:auto-rotate-speed="autoRotateSpeed"
100+
:target="[0, 0.25, 0]"
101+
@change="onChange"
102+
/>
103+
104+
<TresMesh :position="[0, 0.5, 0]">
105+
<TresBoxGeometry :args="[2, 2, 2]" />
106+
<TresMeshBasicMaterial color="#ffffff" :wireframe="wireframe" />
107+
</TresMesh>
108+
</TresCanvas>
109+
110+
<TresCanvas
111+
v-bind="gl"
112+
class="playground-smaa-canvas-right"
113+
window-size
114+
>
115+
<TresPerspectiveCamera ref="cameraRef" :position="[0, 2.5, 3.5]" />
116+
117+
<TresMesh :position="[0, 0.5, 0]">
118+
<TresBoxGeometry :args="[2, 2, 2]" />
119+
<TresMeshBasicMaterial color="#ffffff" :wireframe="wireframe" />
120+
</TresMesh>
121+
122+
<Suspense>
123+
<EffectComposerPmndrs>
124+
<SMAAPmndrs
125+
:debug="Number(debug)"
126+
:blendFunction="blendFunction"
127+
:opacity="opacity"
128+
:preset="preset"
129+
:predicationMode="predicationMode"
130+
:edgeDetectionMode="edgeDetectionMode"
131+
/>
132+
</EffectComposerPmndrs>
133+
</Suspense>
134+
</TresCanvas>
135+
136+
<div class="playground-smaa-divider"></div>
137+
</div>
138+
</template>
139+
140+
<style scoped>
141+
.playground-smaa-canvas-left {
142+
position: absolute;
143+
inset: 0;
144+
z-index: 1;
145+
clip-path: inset(0 50% 0 0);
146+
-webkit-clip-path: inset(0 50% 0 0);
147+
}
148+
149+
.playground-smaa-canvas-right {
150+
position: absolute;
151+
inset: 0;
152+
z-index: 2;
153+
pointer-events: none;
154+
clip-path: inset(0 0 0 50%);
155+
-webkit-clip-path: inset(0 0 0 50%);
156+
}
157+
158+
.playground-smaa-divider {
159+
position: absolute;
160+
top: 0;
161+
bottom: 0;
162+
left: 50%;
163+
width: 2px;
164+
background: red;
165+
z-index: 3;
166+
pointer-events: none;
167+
}
168+
169+
.playground-smaa-infos {
170+
margin: 0 auto;
171+
width: calc(100% - 2rem);
172+
padding: 1rem;
173+
text-align: center;
174+
color: #fff;
175+
background: rgba(0, 0, 0, 0.65);
176+
z-index: 5;
177+
top: 0;
178+
left: 0;
179+
}
180+
</style>

playground/src/router.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export const postProcessingRoutes = [
5252
makeRoute('Scanline', '📽️', false),
5353
makeRoute('Color Depth', '🔳', false),
5454
makeRoute('Grid', '#️⃣', false),
55+
makeRoute('SMAA', '📐', false),
5556
makeRoute('Shock Wave', '🌊', false),
5657
makeRoute('Brightness Contrast', '🔆', false),
5758
makeRoute('Vignette', '🕶️', false),

src/core/pmndrs/SMAAPmndrs.vue

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
<script lang="ts" setup>
2+
import type { BlendFunction, EdgeDetectionMode, PredicationMode, SMAAPreset } from 'postprocessing'
3+
import { EffectPass, SMAAEffect, TextureEffect } from 'postprocessing'
4+
import { makePropWatchers } from '../../util/prop'
5+
import { useEffectPmndrs } from './composables/useEffectPmndrs'
6+
import { inject, watch } from 'vue'
7+
import { useTresContext } from '@tresjs/core'
8+
import { effectComposerInjectionKey } from './EffectComposerPmndrs.vue'
9+
10+
export interface SMAAPmndrsProps {
11+
blendFunction?: BlendFunction
12+
opacity?: number
13+
preset?: SMAAPreset
14+
edgeDetectionMode?: EdgeDetectionMode
15+
predicationMode?: PredicationMode
16+
debug?: number // 0: normal, 1: edges, 2: weights
17+
}
18+
19+
const props = defineProps<SMAAPmndrsProps>()
20+
21+
const { pass, effect } = useEffectPmndrs(() => new SMAAEffect(props), props)
22+
const { camera } = useTresContext()
23+
const composer = inject(effectComposerInjectionKey)
24+
25+
defineExpose({ pass, effect })
26+
27+
makePropWatchers(
28+
[
29+
[() => Number(props.blendFunction), 'blendMode.blendFunction'],
30+
[() => Number(props.predicationMode), 'edgeDetectionMaterial.predicationMode'],
31+
[() => Number(props.edgeDetectionMode), 'edgeDetectionMaterial.edgeDetectionMode'],
32+
],
33+
effect,
34+
() => new SMAAEffect(),
35+
)
36+
37+
watch(
38+
[effect, () => props.opacity],
39+
() => {
40+
if (!effect.value) { return }
41+
42+
if (props.opacity !== undefined) {
43+
effect.value.blendMode.setOpacity(props.opacity)
44+
}
45+
else {
46+
const plainEffect = new SMAAEffect()
47+
effect.value.blendMode.setOpacity(plainEffect.blendMode.getOpacity())
48+
plainEffect.dispose()
49+
}
50+
},
51+
{ immediate: true },
52+
)
53+
54+
watch(
55+
[effect, () => props.preset],
56+
() => {
57+
if (!effect.value) { return }
58+
effect.value.applyPreset(Number(props.preset))
59+
},
60+
)
61+
62+
let smaaEdgesDebugPass: EffectPass | null = null
63+
let smaaWeightsDebugPass: EffectPass | null = null
64+
65+
const createDebugPass = (type: 'edges' | 'weights') => {
66+
if (!effect.value) { return null }
67+
68+
const texture = type === 'edges' ? effect.value.edgesTexture : effect.value.weightsTexture
69+
const pass = new EffectPass(camera.value, effect.value, new TextureEffect({ texture }))
70+
pass.renderToScreen = false
71+
pass.enabled = false
72+
pass.fullscreenMaterial.encodeOutput = false
73+
74+
return pass
75+
}
76+
77+
const ensureDebugPass = (type: 'edges' | 'weights') => {
78+
if (type === 'edges' && !smaaEdgesDebugPass) {
79+
smaaEdgesDebugPass = createDebugPass('edges')
80+
}
81+
if (type === 'weights' && !smaaWeightsDebugPass) {
82+
smaaWeightsDebugPass = createDebugPass('weights')
83+
}
84+
}
85+
86+
const manageDebugPass = (pass: EffectPass | null, active: boolean) => {
87+
if (!pass || !composer?.value) { return }
88+
89+
pass.enabled = active
90+
pass.renderToScreen = active
91+
92+
if (active && !composer?.value.passes.includes(pass)) {
93+
composer?.value.addPass(pass)
94+
}
95+
else if (!active && composer?.value.passes.includes(pass)) {
96+
composer?.value.removePass(pass)
97+
pass.dispose()
98+
}
99+
}
100+
101+
const updateDebugMode = (mode: number) => {
102+
if (!pass.value) { return }
103+
104+
const mainActive = mode === 0
105+
const edgesActive = mode === 1
106+
const weightsActive = mode === 2
107+
108+
pass.value.enabled = mainActive
109+
pass.value.renderToScreen = mainActive
110+
111+
if (edgesActive) { ensureDebugPass('edges') }
112+
if (weightsActive) { ensureDebugPass('weights') }
113+
114+
manageDebugPass(smaaEdgesDebugPass, edgesActive)
115+
manageDebugPass(smaaWeightsDebugPass, weightsActive)
116+
117+
if (!edgesActive) { smaaEdgesDebugPass = null }
118+
if (!weightsActive) { smaaWeightsDebugPass = null }
119+
}
120+
121+
watch(
122+
() => props.debug,
123+
() => {
124+
if (!pass.value || props.debug === undefined) { return }
125+
126+
updateDebugMode(props.debug)
127+
},
128+
{ immediate: true },
129+
)
130+
</script>

src/core/pmndrs/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import ColorDepthPmndrs, { type ColorDepthPmndrsProps } from './ColorDepthPmndrs
2828
import GridPmndrs, { type GridPmndrsProps } from './GridPmndrs.vue'
2929
import FishEyePmndrs, { type FishEyePmndrsProps } from './FishEyePmndrs.vue'
3030
import BrightnessContrastPmndrs, { type BrightnessContrastPmndrsProps } from './BrightnessContrastPmndrs.vue'
31+
import SMAAPmndrs, { type SMAAPmndrsProps } from './SMAAPmndrs.vue'
3132

3233
export {
3334
BloomPmndrs,
@@ -58,6 +59,7 @@ export {
5859
GridPmndrs,
5960
FishEyePmndrs,
6061
BrightnessContrastPmndrs,
62+
SMAAPmndrs,
6163
BloomPmndrsProps,
6264
DepthOfFieldPmndrsProps,
6365
EffectComposerPmndrsProps,
@@ -85,4 +87,5 @@ export {
8587
GridPmndrsProps,
8688
FishEyePmndrsProps,
8789
BrightnessContrastPmndrsProps,
90+
SMAAPmndrsProps,
8891
}

0 commit comments

Comments
 (0)