Skip to content

Commit db77fc6

Browse files
damienmontastierTinoooo
andauthoredJan 10, 2025··
feat: add tonemapping effect (#148)
* add tonemapping effect * change tonemapping doc required mode * fix little bit documentation * revert copy issue outline * improve doc and demo * fix <suspense> doc * fix V2 update and modify code about reviews * update doc * delete import * update code, props * delete playground-nuxt --------- Co-authored-by: Tino Koch <17991193+Tinoooo@users.noreply.github.com>
1 parent a0e957c commit db77fc6

File tree

8 files changed

+289
-1
lines changed

8 files changed

+289
-1
lines changed
 

‎docs/.vitepress/config.ts

+1
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: 'Tone Mapping', link: '/guide/pmndrs/tone-mapping' },
5657
{ text: 'Chromatic Aberration', link: '/guide/pmndrs/chromatic-aberration' },
5758
{ text: 'Sepia', link: '/guide/pmndrs/sepia' },
5859
{ text: 'Scanline', link: '/guide/pmndrs/scanline' },
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<script setup lang="ts">
2+
import { ContactShadows, Environment, OrbitControls, useGLTF } from '@tresjs/cientos'
3+
import { dispose, TresCanvas } from '@tresjs/core'
4+
import { TresLeches, useControls } from '@tresjs/leches'
5+
import { EffectComposerPmndrs, ToneMappingPmndrs } from '@tresjs/post-processing'
6+
import { ToneMappingMode } from 'postprocessing'
7+
import { NoToneMapping } from 'three'
8+
import { onUnmounted, shallowRef } from 'vue'
9+
10+
import '@tresjs/leches/styles'
11+
12+
const gl = {
13+
toneMappingExposure: 1,
14+
toneMapping: NoToneMapping,
15+
multisampling: 8,
16+
}
17+
18+
const modelRef = shallowRef(null)
19+
20+
const { scene: model } = await useGLTF('https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/realistic-pokeball/scene.gltf', { draco: true })
21+
22+
const { toneMappingExposure, mode } = useControls({
23+
toneMappingExposure: {
24+
value: 1,
25+
min: 0,
26+
max: 10,
27+
step: 1,
28+
},
29+
mode: {
30+
options: Object.keys(ToneMappingMode).map(key => ({
31+
text: key,
32+
value: ToneMappingMode[key],
33+
})),
34+
value: ToneMappingMode.AGX,
35+
},
36+
})
37+
38+
onUnmounted(() => {
39+
dispose(model)
40+
})
41+
</script>
42+
43+
<template>
44+
<TresLeches style="left: initial;right:10px; top:10px;" />
45+
46+
<TresCanvas
47+
v-bind="gl"
48+
:toneMappingExposure="toneMappingExposure.value"
49+
>
50+
<TresPerspectiveCamera
51+
:position="[6.5, 6.5, 6.5]"
52+
:look-at="[0, 1, 0]"
53+
/>
54+
<OrbitControls />
55+
56+
<primitive ref="modelRef" :object="model" :position-y="-.5" :scale=".25" />
57+
58+
<Suspense>
59+
<Environment background :blur=".35" preset="dawn" />
60+
</Suspense>
61+
62+
<ContactShadows
63+
:opacity=".5"
64+
:position-y="-3.25"
65+
/>
66+
67+
<Suspense>
68+
<EffectComposerPmndrs>
69+
<ToneMappingPmndrs :mode="Number(mode.value)" />
70+
</EffectComposerPmndrs>
71+
</Suspense>
72+
</TresCanvas>
73+
</template>

‎docs/guide/pmndrs/tone-mapping.md

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# ToneMapping
2+
3+
<DocsDemo>
4+
<ToneMappingDemo />
5+
</DocsDemo>
6+
7+
The `ToneMapping` effect from the [`postprocessing`](https://pmndrs.github.io/postprocessing/public/docs/class/src/effects/ToneMappingEffect.js~ToneMappingEffect.html) package provides an abstraction for various tone mapping algorithms to improve the visual rendering of HDR (high dynamic range) content. Tone mapping is used to map high-range brightness values to a range that is displayable on standard screens. This effect contributes significantly to the visual quality of your scene by controlling luminance and color balance.
8+
9+
::: info
10+
If the colors in your scene look incorrect after adding the EffectComposer, it might be because tone mapping is deactivated by default, which is normal behavior. Add `<ToneMappingPmndrs>` manually as an effect at the end of the `<EffectComposerPmndrs>` to fix this.
11+
:::
12+
13+
## Usage
14+
15+
The `<ToneMappingPmndrs>` component is easy to set up and comes with multiple tone mapping modes to suit different visual requirements. Below is an example of how to use it in a Vue application.
16+
17+
```vue{2,4,7-8,32-36}
18+
<script setup lang="ts">
19+
import { EffectComposerPmndrs, ToneMappingPmndrs } from '@tresjs/post-processing/pmndrs'
20+
import { onUnmounted, shallowRef } from 'vue'
21+
import { ToneMappingMode } from 'postprocessing'
22+
23+
const gl = {
24+
toneMappingExposure: 1,
25+
toneMapping: NoToneMapping,
26+
multisampling: 8,
27+
}
28+
29+
const modelRef = shallowRef(null)
30+
31+
const { scene: model } = await useGLTF('https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/realistic-pokeball/scene.gltf', { draco: true })
32+
33+
onUnmounted(() => {
34+
dispose(modelRef.value)
35+
})
36+
</script>
37+
38+
<template>
39+
<TresCanvas
40+
v-bind="gl"
41+
>
42+
<TresPerspectiveCamera
43+
:position="[5, 5, 5]"
44+
:look-at="[0, 0, 0]"
45+
/>
46+
47+
<primitive ref="modelRef" :object="model" />
48+
49+
<Suspense>
50+
<EffectComposerPmndrs>
51+
<ToneMappingPmndrs :mode="ToneMappingMode.AGX" />
52+
</EffectComposerPmndrs>
53+
</Suspense>
54+
</TresCanvas>
55+
</template>
56+
```
57+
58+
## Props
59+
60+
| Prop | Description | Default |
61+
| ----------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
62+
| mode | Tone mapping mode used, defined by [`ToneMappingMode`](https://pmndrs.github.io/postprocessing/public/docs/variable/index.html#static-variable-ToneMappingMode). | `ToneMappingMode.AGX` |
63+
| blendFunction | Defines the [`BlendFunction`](https://pmndrs.github.io/postprocessing/public/docs/variable/index.html#static-variable-BlendFunction) used for the effect. | `BlendFunction.SRC` |
64+
| resolution | Resolution of the luminance texture (must be a power of two, e.g., 256, 512, etc.). | `256` |
65+
| averageLuminance | Average luminance value used in adaptive calculations. Only applicable to `ToneMappingMode.REINHARD2` | `1.0` |
66+
| middleGrey | Factor to adjust the balance of grey in luminance calculations. Only applicable to `ToneMappingMode.REINHARD2` | `0.6` |
67+
| minLuminance | Lower luminance limit, used to avoid overexposure effects in dark scenes. Only applicable to `ToneMappingMode.REINHARD2` | `0.01` |
68+
| whitePoint | White point for tone mapping, used to balance luminance values. Only applicable to `ToneMappingMode.REINHARD2` | `4.0` |
69+
70+
## Further Reading
71+
For more details, see the [Tone Mapping documentation](https://pmndrs.github.io/postprocessing/public/docs/class/src/effects/ToneMappingEffect.js~ToneMappingEffect.html)

‎playground/components.d.ts

-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ declare module 'vue' {
99
export interface GlobalComponents {
1010
BasicScene: typeof import('./src/components/BasicScene.vue')['default']
1111
BlenderCube: typeof import('./src/components/BlenderCube.vue')['default']
12-
copy: typeof import('./src/components/UnrealBloom copy.vue')['default']
1312
Ducky: typeof import('./src/components/Ducky.vue')['default']
1413
EffectListItem: typeof import('./src/components/EffectListItem.vue')['default']
1514
GlitchDemo: typeof import('./src/components/GlitchDemo.vue')['default']
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
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 { BlendFunction, ToneMappingMode } from 'postprocessing'
6+
import { NoToneMapping } from 'three'
7+
import { EffectComposerPmndrs, ToneMappingPmndrs } from '@tresjs/post-processing'
8+
9+
import '@tresjs/leches/styles'
10+
11+
const gl = {
12+
clearColor: 'white',
13+
toneMapping: NoToneMapping,
14+
multisampling: 8,
15+
}
16+
17+
const { blendFunction, resolution, mode } = useControls({
18+
mode: {
19+
options: Object.keys(ToneMappingMode).map(key => ({
20+
text: key,
21+
value: ToneMappingMode[key],
22+
})),
23+
value: ToneMappingMode.AGX,
24+
},
25+
resolution: {
26+
value: 256,
27+
options: [
28+
{ text: '128', value: 128 },
29+
{ text: '256', value: 256 },
30+
{ text: '512', value: 512 },
31+
{ text: '1024', value: 1024 },
32+
{ text: '2048', value: 2048 },
33+
],
34+
},
35+
blendFunction: {
36+
options: Object.keys(BlendFunction).map(key => ({
37+
text: key,
38+
value: BlendFunction[key],
39+
})),
40+
value: BlendFunction.OVERLAY,
41+
},
42+
})
43+
</script>
44+
45+
<template>
46+
<TresLeches />
47+
48+
<TresCanvas
49+
v-bind="gl"
50+
>
51+
<TresPerspectiveCamera
52+
:position="[3, 3, 3]"
53+
:look-at="[0, 0, 0]"
54+
/>
55+
<OrbitControls auto-rotate />
56+
57+
<TresMesh>
58+
<TresBoxGeometry />
59+
<TresMeshPhysicalMaterial color="#FFFFFF" :roughness=".25" :transmission=".85" />
60+
</TresMesh>
61+
62+
<Suspense>
63+
<Environment background :blur=".85" preset="dawn" />
64+
</Suspense>
65+
66+
<ContactShadows
67+
:opacity=".5"
68+
:position-y="-.5"
69+
/>
70+
71+
<Suspense>
72+
<EffectComposerPmndrs>
73+
<ToneMappingPmndrs :mode="Number(mode.value)" :resolution="Number(resolution.value)" :blendFunction="Number(blendFunction.value)" />
74+
</EffectComposerPmndrs>
75+
</Suspense>
76+
</TresCanvas>
77+
</template>

‎playground/src/router.ts

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ export const threeRoutes = [
3333

3434
export const postProcessingRoutes = [
3535
makeRoute('Outline', '🔲', false),
36+
makeRoute('Tone Mapping', '🎨', false),
3637
makeRoute('Glitch', '📺', false),
3738
makeRoute('Depth of Field', '📷', false),
3839
makeRoute('Hue & Saturation', '📷', false),

‎src/core/pmndrs/ToneMappingPmndrs.vue

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<script lang="ts" setup>
2+
import type { BlendFunction, ToneMappingMode } from 'postprocessing'
3+
import { ToneMappingEffect } from 'postprocessing'
4+
import { makePropWatchers } from '../../util/prop'
5+
import { useEffectPmndrs } from './composables/useEffectPmndrs'
6+
7+
export interface ToneMappingPmndrsProps {
8+
/**
9+
* The tone mapping mode.
10+
*/
11+
mode?: ToneMappingMode
12+
13+
/**
14+
* The blend function.
15+
*/
16+
blendFunction?: BlendFunction
17+
18+
/**
19+
* The resolution for luminance texture. The resolution of the luminance texture. Must be a power of two.
20+
*/
21+
resolution?: number
22+
23+
/**
24+
* The average luminance. Only for `REINHARD2`.
25+
*/
26+
averageLuminance?: number
27+
28+
/**
29+
* The middle grey factor. Only for `REINHARD2`.
30+
*/
31+
middleGrey?: number
32+
33+
/**
34+
* The minimum luminance. Only for `REINHARD2`.
35+
*/
36+
minLuminance?: number
37+
38+
/**
39+
* The white point. Only for `REINHARD2`.
40+
*/
41+
whitePoint?: number
42+
}
43+
44+
const props = defineProps<ToneMappingPmndrsProps>()
45+
46+
const { pass, effect } = useEffectPmndrs(() => new ToneMappingEffect(props), props)
47+
48+
defineExpose({ pass, effect })
49+
50+
makePropWatchers(
51+
[
52+
[() => props.mode, 'mode'],
53+
[() => props.blendFunction, 'blendMode.blendFunction'],
54+
[() => props.resolution, 'resolution'],
55+
[() => props.averageLuminance, 'averageLuminance'],
56+
[() => props.middleGrey, 'middleGrey'],
57+
[() => props.minLuminance, 'adaptiveLuminanceMaterial.minLuminance'],
58+
[() => props.whitePoint, 'whitePoint'],
59+
],
60+
effect,
61+
() => new ToneMappingEffect(),
62+
)
63+
</script>

‎src/core/pmndrs/index.ts

+3
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 ToneMappingPmndrs, { type ToneMappingPmndrsProps } from './ToneMappingPmndrs.vue'
1213
import ChromaticAberrationPmndrs, { type ChromaticAberrationPmndrsProps } from './ChromaticAberrationPmndrs.vue'
1314
import HueSaturationPmndrs, { type HueSaturationPmndrsProps } from './HueSaturationPmndrs.vue'
1415
import ScanlinePmndrs, { type ScanlinePmndrsProps } from './ScanlinePmndrs.vue'
@@ -25,6 +26,7 @@ export {
2526
PixelationPmndrs,
2627
useEffectPmndrs,
2728
VignettePmndrs,
29+
ToneMappingPmndrs,
2830
ChromaticAberrationPmndrs,
2931
HueSaturationPmndrs,
3032
ScanlinePmndrs,
@@ -39,6 +41,7 @@ export {
3941
OutlinePmndrsProps,
4042
PixelationPmndrsProps,
4143
VignettePmndrsProps,
44+
ToneMappingPmndrsProps,
4245
ChromaticAberrationPmndrsProps,
4346
HueSaturationPmndrsProps,
4447
ScanlinePmndrsProps,

0 commit comments

Comments
 (0)
Please sign in to comment.