-
-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add tonemapping effect #148
base: main
Are you sure you want to change the base?
Changes from 6 commits
7aa61a7
dc2caf1
cc7dff8
9176298
810efaf
21cffd9
d175bff
61d3862
2bfe923
97aef51
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
<script setup lang="ts"> | ||
import { ContactShadows, Environment, Levioso, OrbitControls, useGLTF } from '@tresjs/cientos' | ||
import { dispose, TresCanvas } from '@tresjs/core' | ||
import { TresLeches, useControls } from '@tresjs/leches' | ||
import { EffectComposer, ToneMapping } from '@tresjs/post-processing/pmndrs' | ||
import { ToneMappingMode } from 'postprocessing' | ||
import { NoToneMapping } from 'three' | ||
import { onUnmounted, shallowRef } from 'vue' | ||
|
||
import '@tresjs/leches/styles' | ||
|
||
const gl = { | ||
toneMappingExposure: 1, | ||
toneMapping: NoToneMapping, | ||
multisampling: 8, | ||
} | ||
|
||
const modelRef = shallowRef(null) | ||
|
||
const { scene: model } = await useGLTF('https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/realistic-pokeball/scene.gltf', { draco: true }) | ||
|
||
const { toneMappingExposure, mode } = useControls({ | ||
toneMappingExposure: { | ||
value: 1, | ||
min: 0, | ||
max: 10, | ||
step: 1, | ||
}, | ||
mode: { | ||
options: Object.keys(ToneMappingMode).map(key => ({ | ||
text: key, | ||
value: ToneMappingMode[key], | ||
})), | ||
value: ToneMappingMode.AGX, | ||
}, | ||
}) | ||
|
||
onUnmounted(() => { | ||
dispose(model) | ||
}) | ||
</script> | ||
|
||
<template> | ||
<TresLeches style="left: initial;right:10px; top:10px;" /> | ||
|
||
<TresCanvas | ||
v-bind="gl" | ||
:toneMappingExposure="toneMappingExposure.value" | ||
> | ||
<TresPerspectiveCamera | ||
:position="[6.5, 6.5, 6.5]" | ||
:look-at="[0, 1, 0]" | ||
/> | ||
<OrbitControls /> | ||
|
||
<Levioso :speed=".5" :rotation-factor=".5" :float-factor="2" :range="[0, .5]"> | ||
<primitive ref="modelRef" :object="model" :position-y="-.5" :scale=".25" /> | ||
</Levioso> | ||
|
||
<Suspense> | ||
<Environment background :blur=".35" preset="dawn" /> | ||
</Suspense> | ||
|
||
<ContactShadows | ||
:opacity=".5" | ||
:position-y="-3.25" | ||
/> | ||
|
||
<Suspense> | ||
<EffectComposer> | ||
<ToneMapping :mode="Number(mode.value)" /> | ||
</EffectComposer> | ||
</Suspense> | ||
</TresCanvas> | ||
</template> |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion: I suggest calling this file There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. modified at next commit |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
# ToneMapping | ||
|
||
<DocsDemo> | ||
<ToneMappingDemo /> | ||
</DocsDemo> | ||
|
||
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. | ||
|
||
::: info | ||
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 `<ToneMapping>` manually as an effect at the end of the `<EffectComposer>` to fix this. | ||
::: | ||
|
||
## Usage | ||
|
||
The `<ToneMapping>` 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. | ||
|
||
```vue{2,4,7-8,32-36} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion: While I like to have a full example on the page, I think it is better to stay uniform with the other effects and only show the usage. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's a shame that we don't produce slightly advanced demos to present concrete use cases. What do you think @alvarosabu ? |
||
<script setup lang="ts"> | ||
import { EffectComposer, ToneMapping } from '@tresjs/post-processing/pmndrs' | ||
import { onUnmounted, shallowRef } from 'vue' | ||
import { ToneMappingMode } from 'postprocessing' | ||
|
||
const gl = { | ||
toneMappingExposure: 1, | ||
toneMapping: NoToneMapping, | ||
multisampling: 8, | ||
} | ||
|
||
const modelRef = shallowRef(null) | ||
|
||
const { scene: model } = await useGLTF('https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/realistic-pokeball/scene.gltf', { draco: true }) | ||
|
||
onUnmounted(() => { | ||
dispose(modelRef.value) | ||
}) | ||
</script> | ||
|
||
<template> | ||
<TresCanvas | ||
v-bind="gl" | ||
> | ||
<TresPerspectiveCamera | ||
:position="[5, 5, 5]" | ||
:look-at="[0, 0, 0]" | ||
/> | ||
|
||
<primitive ref="modelRef" :object="model" /> | ||
|
||
<Suspense> | ||
<EffectComposer> | ||
<ToneMapping :mode="ToneMappingMode.AGX" /> | ||
</EffectComposer> | ||
</Suspense> | ||
</TresCanvas> | ||
</template> | ||
``` | ||
|
||
## Props | ||
|
||
| Prop | Description | Default | | ||
| ----------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | | ||
| mode | Tone mapping mode used, defined by [`ToneMappingMode`](https://pmndrs.github.io/postprocessing/public/docs/variable/index.html#static-variable-ToneMappingMode). | `ToneMappingMode.AGX` | | ||
| blendFunction | Defines the [`BlendFunction`](https://pmndrs.github.io/postprocessing/public/docs/variable/index.html#static-variable-BlendFunction) used for the effect. | `BlendFunction.SRC` | | ||
| resolution | Resolution of the luminance texture (must be a power of two, e.g., 256, 512, etc.). | `256` | | ||
| averageLuminance | Average luminance value used in adaptive calculations. Only applicable to `ToneMappingMode.REINHARD2` | `1.0` | | ||
| middleGrey | Factor to adjust the balance of grey in luminance calculations. Only applicable to `ToneMappingMode.REINHARD2` | `0.6` | | ||
| minLuminance | Lower luminance limit, used to avoid overexposure effects in dark scenes. Only applicable to `ToneMappingMode.REINHARD2` | `0.01` | | ||
| whitePoint | White point for tone mapping, used to balance luminance values. Only applicable to `ToneMappingMode.REINHARD2` | `4.0` | | ||
|
||
## Further Reading | ||
see [postprocessing docs](https://pmndrs.github.io/postprocessing/public/docs/class/src/effects/ToneMappingEffect.js~ToneMappingEffect.html) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
<script setup lang="ts"> | ||
import { ContactShadows, Environment, OrbitControls } from '@tresjs/cientos' | ||
import { TresCanvas } from '@tresjs/core' | ||
import { TresLeches, useControls } from '@tresjs/leches' | ||
import { EffectComposer, ToneMapping } from '@tresjs/post-processing/pmndrs' | ||
import { BlendFunction, ToneMappingMode } from 'postprocessing' | ||
import { NoToneMapping } from 'three' | ||
|
||
import '@tresjs/leches/styles' | ||
|
||
const gl = { | ||
clearColor: 'white', | ||
toneMapping: NoToneMapping, | ||
multisampling: 8, | ||
} | ||
|
||
const { blendFunction, resolution, mode } = useControls({ | ||
mode: { | ||
options: Object.keys(ToneMappingMode).map(key => ({ | ||
text: key, | ||
value: ToneMappingMode[key], | ||
})), | ||
value: ToneMappingMode.AGX, | ||
}, | ||
resolution: { | ||
value: 256, | ||
options: [ | ||
{ text: '128', value: 128 }, | ||
{ text: '256', value: 256 }, | ||
{ text: '512', value: 512 }, | ||
{ text: '1024', value: 1024 }, | ||
{ text: '2048', value: 2048 }, | ||
], | ||
}, | ||
blendFunction: { | ||
options: Object.keys(BlendFunction).map(key => ({ | ||
text: key, | ||
value: BlendFunction[key], | ||
})), | ||
value: BlendFunction.OVERLAY, | ||
}, | ||
}) | ||
</script> | ||
|
||
<template> | ||
<TresLeches /> | ||
|
||
<TresCanvas | ||
v-bind="gl" | ||
> | ||
<TresPerspectiveCamera | ||
:position="[3, 3, 3]" | ||
:look-at="[0, 0, 0]" | ||
/> | ||
<OrbitControls auto-rotate /> | ||
|
||
<TresMesh> | ||
<TresBoxGeometry /> | ||
<TresMeshPhysicalMaterial color="#FFFFFF" :roughness=".25" :transmission=".85" /> | ||
</TresMesh> | ||
|
||
<Suspense> | ||
<Environment background :blur=".85" preset="dawn" /> | ||
</Suspense> | ||
|
||
<ContactShadows | ||
:opacity=".5" | ||
:position-y="-.5" | ||
/> | ||
|
||
<Suspense> | ||
<EffectComposer> | ||
<ToneMapping :mode="Number(mode.value)" :resolution="Number(resolution.value)" :blendFunction="Number(blendFunction.value)" /> | ||
</EffectComposer> | ||
</Suspense> | ||
</TresCanvas> | ||
</template> |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,79 @@ | ||||||||||||||||||||||||||||
<script lang="ts" setup> | ||||||||||||||||||||||||||||
import { BlendFunction, ToneMappingEffect, ToneMappingMode } from 'postprocessing' | ||||||||||||||||||||||||||||
import { defineExpose, defineProps, watchEffect, withDefaults } from 'vue' | ||||||||||||||||||||||||||||
import { useEffect } from './composables/useEffect' | ||||||||||||||||||||||||||||
import { makePropWatchers } from '../../util/prop' | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
export interface ToneMappingProps { | ||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||
* The tone mapping mode. | ||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||
mode?: ToneMappingMode | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||
* The blend function. | ||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||
blendFunction?: BlendFunction | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||
* The resolution for luminance texture. The resolution of the luminance texture. Must be a power of two. | ||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||
resolution?: number | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||
* The average luminance. Only for `REINHARD2`. | ||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||
averageLuminance?: number | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||
* The middle grey factor. Only for `REINHARD2`. | ||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||
middleGrey?: number | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||
* The minimum luminance. Only for `REINHARD2`. | ||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||
minLuminance?: number | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||
* The white point. Only for `REINHARD2`. | ||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||
whitePoint?: number | ||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
const props = withDefaults( | ||||||||||||||||||||||||||||
defineProps<ToneMappingProps>(), | ||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||
mode: ToneMappingMode.AGX, | ||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion: We set defaults only in very rare cases to minimize maintenance effort when postprocessing changes the internals of their effects. I suggest omitting these. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. modified at next commit |
||||||||||||||||||||||||||||
blendFunction: BlendFunction.SRC, | ||||||||||||||||||||||||||||
resolution: 256, | ||||||||||||||||||||||||||||
averageLuminance: 1.0, | ||||||||||||||||||||||||||||
middleGrey: 0.6, | ||||||||||||||||||||||||||||
minLuminance: 0.01, | ||||||||||||||||||||||||||||
whitePoint: 4.0, | ||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
const { pass, effect } = useEffect(() => new ToneMappingEffect(props), props) | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
defineExpose({ pass, effect }) | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
watchEffect(() => { | ||||||||||||||||||||||||||||
if (!effect.value) { return } | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
effect.value.blendMode.blendFunction = Number(props.blendFunction) | ||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
makePropWatchers( | ||||||||||||||||||||||||||||
[ | ||||||||||||||||||||||||||||
[() => props.mode, 'mode'], | ||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion: You can omit the seperate watcher like so:
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Modified at next commit |
||||||||||||||||||||||||||||
[() => props.resolution, 'resolution'], | ||||||||||||||||||||||||||||
[() => props.averageLuminance, 'averageLuminance'], | ||||||||||||||||||||||||||||
[() => props.middleGrey, 'middleGrey'], | ||||||||||||||||||||||||||||
[() => props.minLuminance, 'minLuminance'], | ||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion: I think this has to be like so:
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Exactly! Small mistake on my part! Modified at next commit |
||||||||||||||||||||||||||||
[() => props.whitePoint, 'whitePoint'], | ||||||||||||||||||||||||||||
], | ||||||||||||||||||||||||||||
effect, | ||||||||||||||||||||||||||||
() => new ToneMappingEffect(), | ||||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||||
</script> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
modified at next commit