Skip to content

Commit c09851c

Browse files
feat: color depth (#186)
* migrate to new tresleches, change devDependencies package.json file * add todo next commit * lint * try floa false leches * refactor: improve BarrelBlurDemo component layout and styling * leches floatg * merge * add effect * lint: fix log --------- Co-authored-by: alvarosabu <alvaro.saburido@gmail.com> Co-authored-by: Tino Koch <>
1 parent 212312e commit c09851c

File tree

8 files changed

+299
-0
lines changed

8 files changed

+299
-0
lines changed

docs/.vitepress/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export default defineConfig({
5252
{ text: 'Fish Eye', link: '/guide/pmndrs/fish-eye' },
5353
{ text: 'Bloom', link: '/guide/pmndrs/bloom' },
5454
{ text: 'Chromatic Aberration', link: '/guide/pmndrs/chromatic-aberration' },
55+
{ text: 'Color Depth', link: '/guide/pmndrs/color-depth' },
5556
{ text: 'Linocut', link: '/guide/pmndrs/linocut' },
5657
{ text: 'Sepia', link: '/guide/pmndrs/sepia' },
5758
{ text: 'Brightness Contrast', link: '/guide/pmndrs/brightness-contrast' },
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<script setup lang="ts">
2+
import { Environment, OrbitControls } from '@tresjs/cientos'
3+
import { TresCanvas } from '@tresjs/core'
4+
import { TresLeches, useControls } from '@tresjs/leches'
5+
import type { Vector3 } from 'three'
6+
import { NoToneMapping } from 'three'
7+
import { BlendFunction } from 'postprocessing'
8+
import { ColorDepthPmndrs, EffectComposerPmndrs } from '@tresjs/post-processing'
9+
import { onUnmounted, toRaw, useTemplateRef, watch } from 'vue'
10+
import { gsap } from 'gsap'
11+
12+
import '@tresjs/leches/styles'
13+
14+
const gl = {
15+
clearColor: '#ffffff',
16+
toneMapping: NoToneMapping,
17+
multisampling: 8,
18+
}
19+
20+
const ctx = gsap.context(() => {})
21+
22+
const meshsArray = useTemplateRef('meshRefs')
23+
24+
const { blendFunction, bits, opacity } = useControls({
25+
blendFunction: {
26+
options: Object.keys(BlendFunction).map(key => ({
27+
text: key,
28+
value: BlendFunction[key as keyof typeof BlendFunction],
29+
})),
30+
value: BlendFunction.NORMAL,
31+
},
32+
bits: { value: 8, step: 1, min: 1, max: 16 },
33+
opacity: { value: 1, step: 0.1, min: 0, max: 1 },
34+
})
35+
36+
const meshes: { position: [number, number, number], color: string }[] = [
37+
{ position: [0, 0.5, 0], color: 'white' },
38+
{ position: [0, 0.5, -2], color: 'red' },
39+
{ position: [0, 0.5, 2], color: 'yellow' },
40+
{ position: [-2, 0.5, 0], color: 'blue' },
41+
{ position: [2, 0.5, 0], color: 'purple' },
42+
]
43+
44+
watch(meshsArray, () => {
45+
ctx.add(() => {
46+
meshsArray.value?.forEach((el) => {
47+
const position = toRaw(el.position) as Vector3
48+
49+
if (position) {
50+
gsap.to(position as Vector3, {
51+
x: position.x === 0 ? '+=0' : position.x < 0 ? '-=3' : '+=3',
52+
z: position.z === 0 ? '+=0' : position.z < 0 ? '-=3' : '+=3',
53+
repeat: -1,
54+
yoyo: true,
55+
})
56+
}
57+
})
58+
})
59+
})
60+
61+
onUnmounted(() => {
62+
ctx.revert()
63+
})
64+
</script>
65+
66+
<template>
67+
<div class="aspect-16/9">
68+
<TresCanvas
69+
v-bind="gl"
70+
>
71+
<TresPerspectiveCamera :position="[8, 5, 5]" />
72+
<OrbitControls auto-rotate />
73+
74+
<TresMesh
75+
v-for="(mesh, index) in meshes"
76+
:key="`color-depth-demo-box-${index}`"
77+
ref="meshRefs"
78+
:position="mesh.position"
79+
>
80+
<TresBoxGeometry :args="[2, 2, 2]" />
81+
<TresMeshPhysicalMaterial :color="mesh.color" :roughness="0.25" />
82+
</TresMesh>
83+
84+
<Suspense>
85+
<Environment background preset="umbrellas" />
86+
</Suspense>
87+
88+
<Suspense>
89+
<EffectComposerPmndrs>
90+
<ColorDepthPmndrs :blendFunction="Number(blendFunction)" :bits="bits" :opacity="opacity" />
91+
</EffectComposerPmndrs>
92+
</Suspense>
93+
</TresCanvas>
94+
</div>
95+
<TresLeches :float="false" />
96+
</template>

docs/components.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ declare module 'vue' {
1313
BrightnessContrastDemo: typeof import('./.vitepress/theme/components/pmdrs/BrightnessContrastDemo.vue')['default']
1414
ChromaticAberrationDemo: typeof import('./.vitepress/theme/components/pmdrs/ChromaticAberrationDemo.vue')['default']
1515
ColorAverageDemo: typeof import('./.vitepress/theme/components/pmdrs/ColorAverageDemo.vue')['default']
16+
ColorDepthDemo: typeof import('./.vitepress/theme/components/pmdrs/ColorDepthDemo.vue')['default']
1617
copy: typeof import('./.vitepress/theme/components/DocsDemoGUI.vue')['default']
1718
DepthOfFieldDemo: typeof import('./.vitepress/theme/components/pmdrs/DepthOfFieldDemo.vue')['default']
1819
DocsDemo: typeof import('./.vitepress/theme/components/DocsDemo.vue')['default']

docs/guide/pmndrs/color-depth.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Color Depth
2+
3+
<DocsDemoGUI>
4+
<ColorDepthDemo />
5+
</DocsDemoGUI>
6+
7+
<details>
8+
<summary>Demo code</summary>
9+
10+
<<< @/.vitepress/theme/components/pmdrs/ColorDepthDemo.vue{0}
11+
</details>
12+
13+
The `ColorDepthEffect` effect is part of the [`postprocessing`](https://pmndrs.github.io/postprocessing/public/docs/class/src/effects/ColorDepthEffect.js~ColorDepthEffect.html) package.
14+
It renders a ColorDepth that can be scaled or adjusted to achieve a variety of visual effects.
15+
16+
## Usage
17+
18+
The `<ColorDepthPmndrs>` component is easy to use and provides customizable options to suit different visual styles.
19+
20+
```vue{2,9-13,25-29}
21+
<script setup lang="ts">
22+
import { EffectComposerPmndrs, ColorDepthPmndrs } from '@tresjs/post-processing/pmndrs'
23+
24+
const gl = {
25+
toneMapping: NoToneMapping,
26+
multisampling: 8,
27+
}
28+
29+
const effectProps = {
30+
blendFunction: BlendFunction.NORMAL,
31+
bits: 8,
32+
opacity: 0.75,
33+
}
34+
</script>
35+
36+
<template>
37+
<TresCanvas v-bind="gl">
38+
<TresPerspectiveCamera />
39+
40+
<TresMesh :position="[0, .5, 0]">
41+
<TresBoxGeometry :args="[2, 2, 2]" />
42+
<TresMeshNormalMaterial />
43+
</TresMesh>
44+
45+
<Suspense>
46+
<EffectComposerPmndrs>
47+
<ColorDepthPmndrs v-bind="effectProps" />
48+
</EffectComposerPmndrs>
49+
</Suspense>
50+
</TresCanvas>
51+
</template>
52+
```
53+
54+
## Props
55+
56+
| Prop | Description | Default |
57+
| ------------- | ------------------------------------------------------------------- | --------------------------- |
58+
| 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.NORMAL` |
59+
| bits | The color bit depth. The color bit depth represents the virtual color bits. Each channel uses a quarter of the total, except alpha. | `16` |
60+
| opacity | The opacity of the effect. | `1` |
61+
62+
## Further Reading
63+
For more details, see the [ColorDepthEffect documentation](https://pmndrs.github.io/postprocessing/public/docs/class/src/effects/ColorDepthEffect.js~ColorDepthEffect.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 { Environment, 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 { ColorDepthPmndrs, 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 { blendFunction, bits, opacity } = useControls({
18+
blendFunction: {
19+
options: Object.keys(BlendFunction).map(key => ({
20+
text: key,
21+
value: BlendFunction[key as keyof typeof BlendFunction],
22+
})),
23+
value: BlendFunction.NORMAL,
24+
},
25+
bits: { value: 8, step: 1, min: 1, max: 32 },
26+
opacity: { value: 1, step: 0.1, min: 0, max: 1 },
27+
})
28+
29+
const meshes: { position: [number, number, number], color: string }[] = [
30+
{ position: [0, 0.5, 0], color: 'white' },
31+
{ position: [0, 0.5, -10], color: 'red' },
32+
{ position: [0, 0.5, 10], color: 'yellow' },
33+
{ position: [-10, 0.5, 0], color: 'blue' },
34+
{ position: [10, 0.5, 0], color: 'purple' },
35+
]
36+
</script>
37+
38+
<template>
39+
<TresLeches />
40+
41+
<TresCanvas
42+
v-bind="gl"
43+
>
44+
<TresPerspectiveCamera :position="[17.5, 7.5, 5]" />
45+
<OrbitControls auto-rotate />
46+
47+
<TresMesh
48+
v-for="(mesh, index) in meshes"
49+
:key="index"
50+
:position="mesh.position"
51+
>
52+
<TresBoxGeometry :args="[2, 2, 2]" />
53+
<TresMeshPhysicalMaterial :color="mesh.color" :roughness="0.25" />
54+
</TresMesh>
55+
56+
<Suspense>
57+
<Environment background preset="umbrellas" />
58+
</Suspense>
59+
60+
<Suspense>
61+
<EffectComposerPmndrs>
62+
<ColorDepthPmndrs :blendFunction="Number(blendFunction)" :bits="bits" :opacity="opacity" />
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
@@ -49,6 +49,7 @@ export const postProcessingRoutes = [
4949
makeRoute('Lens Distortion', '🌐', false),
5050
makeRoute('Sepia', '🌅', false),
5151
makeRoute('Scanline', '📽️', false),
52+
makeRoute('Color Depth', '🔳', false),
5253
makeRoute('Grid', '#️⃣', false),
5354
makeRoute('Shock Wave', '🌊', false),
5455
makeRoute('Brightness Contrast', '🔆', false),

src/core/pmndrs/ColorDepthPmndrs.vue

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<script lang="ts" setup>
2+
import type { BlendFunction } from 'postprocessing'
3+
import { ColorDepthEffect } from 'postprocessing'
4+
import { makePropWatcher } from '../../util/prop'
5+
import { useEffectPmndrs } from './composables/useEffectPmndrs'
6+
import { watch } from 'vue'
7+
8+
export interface ColorDepthPmndrsProps {
9+
/**
10+
* The blend function.
11+
*/
12+
blendFunction?: BlendFunction
13+
14+
/**
15+
* The color bit depth.
16+
*/
17+
bits?: number
18+
19+
/**
20+
* The opacity of the effect.
21+
*/
22+
opacity?: number
23+
}
24+
25+
const props = defineProps<ColorDepthPmndrsProps>()
26+
27+
const { pass, effect } = useEffectPmndrs(() => new ColorDepthEffect(props), props)
28+
29+
defineExpose({ pass, effect })
30+
31+
makePropWatcher(
32+
() => props.blendFunction,
33+
effect,
34+
'blendMode.blendFunction',
35+
() => new ColorDepthEffect(),
36+
)
37+
watch(
38+
[effect, () => props.bits],
39+
() => {
40+
if (!effect.value) { return }
41+
42+
if (props.bits !== undefined) {
43+
effect.value?.setBitDepth(props.bits)
44+
}
45+
else {
46+
const plainEffect = new ColorDepthEffect()
47+
effect.value?.setBitDepth(plainEffect.getBitDepth())
48+
plainEffect.dispose()
49+
}
50+
},
51+
)
52+
53+
watch(
54+
[effect, () => props.opacity],
55+
() => {
56+
if (!effect.value) { return }
57+
58+
if (props.opacity !== undefined) {
59+
effect.value?.blendMode.setOpacity(props.opacity)
60+
}
61+
else {
62+
const plainEffect = new ColorDepthEffect()
63+
effect.value?.blendMode.setOpacity(plainEffect.blendMode.getOpacity())
64+
plainEffect.dispose()
65+
}
66+
},
67+
)
68+
</script>

src/core/pmndrs/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import DotScreenPmndrs, { type DotScreenPmndrsProps } from './DotScreenPmndrs.vu
2323
import SepiaPmndrs, { type SepiaPmndrsProps } from './SepiaPmndrs.vue'
2424
import LinocutPmndrs, { type LinocutPmndrsProps } from './LinocutPmndrs.vue'
2525
import DepthPickingPassPmndrs, { type DepthPickingPassPmndrsProps } from './DepthPickingPassPmndrs.vue'
26+
import ColorDepthPmndrs, { type ColorDepthPmndrsProps } from './ColorDepthPmndrs.vue'
2627
import GridPmndrs, { type GridPmndrsProps } from './GridPmndrs.vue'
2728
import FishEyePmndrs, { type FishEyePmndrsProps } from './FishEyePmndrs.vue'
2829
import BrightnessContrastPmndrs, { type BrightnessContrastPmndrsProps } from './BrightnessContrastPmndrs.vue'
@@ -51,6 +52,7 @@ export {
5152
SepiaPmndrs,
5253
LinocutPmndrs,
5354
DepthPickingPassPmndrs,
55+
ColorDepthPmndrs,
5456
GridPmndrs,
5557
FishEyePmndrs,
5658
BrightnessContrastPmndrs,
@@ -76,6 +78,7 @@ export {
7678
SepiaPmndrsProps,
7779
LinocutPmndrsProps,
7880
DepthPickingPassPmndrsProps,
81+
ColorDepthPmndrsProps,
7982
GridPmndrsProps,
8083
FishEyePmndrsProps,
8184
BrightnessContrastPmndrsProps,

0 commit comments

Comments
 (0)