Skip to content

Commit

Permalink
feat: color average (#166)
Browse files Browse the repository at this point in the history
* init color average

* add color average component, doc, demo

* final doc

* fix code for reviews

---------

Co-authored-by: Tino Koch <[email protected]>
  • Loading branch information
damienmontastier and Tinoooo authored Jan 12, 2025
1 parent 78b0bb7 commit 03f4986
Show file tree
Hide file tree
Showing 8 changed files with 283 additions and 1 deletion.
3 changes: 2 additions & 1 deletion docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,14 @@ export default defineConfig({
{ text: 'Barrel blur', link: '/guide/pmndrs/barrel-blur' },
{ text: 'Bloom', link: '/guide/pmndrs/bloom' },
{ text: 'Chromatic Aberration', link: '/guide/pmndrs/chromatic-aberration' },
{ text: 'Color Average', link: '/guide/pmndrs/color-average' },
{ text: 'Depth of Field', link: '/guide/pmndrs/depth-of-field' },
{ text: 'Dot Screen', link: '/guide/pmndrs/dot-screen' },
{ text: 'Glitch', link: '/guide/pmndrs/glitch' },
{ text: 'Hue & Saturation', link: '/guide/pmndrs/hue-saturation' },
{ text: 'Lens Distortion', link: '/guide/pmndrs/lens-distortion' },
{ text: 'Noise', link: '/guide/pmndrs/noise' },
{ text: 'Outline', link: '/guide/pmndrs/outline' },
{ text: 'Outline', link: '/guide/pmndrs/outline' },

Check failure on line 61 in docs/.vitepress/config.ts

View workflow job for this annotation

GitHub Actions / Lint (20)

Trailing spaces not allowed
{ text: 'Pixelation', link: '/guide/pmndrs/pixelation' },
{ text: 'Scanline', link: '/guide/pmndrs/scanline' },
{ text: 'Sepia', link: '/guide/pmndrs/sepia' },
Expand Down
92 changes: 92 additions & 0 deletions docs/.vitepress/theme/components/pmdrs/ColorAverageDemo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<script setup lang="ts">
import { Environment, OrbitControls } from '@tresjs/cientos'
import { TresCanvas } from '@tresjs/core'
import { TresLeches, useControls } from '@tresjs/leches'
import type { Mesh } from 'three'
import { NoToneMapping } from 'three'
import { BlendFunction } from 'postprocessing'
import { ColorAveragePmndrs, EffectComposerPmndrs } from '@tresjs/post-processing'
import { gsap } from 'gsap'
import { onUnmounted, ref, watch } from 'vue'
import '@tresjs/leches/styles'
const gl = {
clearColor: '#ffffff',
toneMapping: NoToneMapping,
multisampling: 8,
envMapIntensity: 10,
}
const ctx = gsap.context(() => {})
const meshRef = ref<Mesh | null>(null)
const { blendFunction, opacity } = useControls({
blendFunction: {
options: Object.keys(BlendFunction).map(key => ({
text: key,
value: BlendFunction[key],
})),
value: BlendFunction.NORMAL,
},
opacity: {
value: 1,
min: 0,
max: 1,
},
})
function onUpdateTimeline(e) {
const progress = 1 - e.progress()
opacity.value.value = progress
}
watch(meshRef, () => {
if (!meshRef.value) { return }
ctx.add(() => {
gsap.timeline({
repeat: -1,
yoyo: true,
onUpdate() {
onUpdateTimeline(this)
},
})
.to(meshRef.value.position, { y: -3.5, duration: 2 })
})
})
onUnmounted(() => {
ctx.revert()
})
</script>

<template>
<TresLeches style="left: initial;right:10px; top:10px;" />

<TresCanvas
v-bind="gl"
>
<TresPerspectiveCamera
:position="[5, 2, 15]"
:look-at="[0, 0, 0]"
/>
<OrbitControls auto-rotate />

<TresMesh ref="meshRef" :position="[0, 3.5, 0]">
<TresBoxGeometry :args="[2, 2, 2]" />
<TresMeshPhysicalMaterial color="#8B0000" :roughness=".25" />
</TresMesh>

<Suspense>
<Environment background preset="shangai" />
</Suspense>

<Suspense>
<EffectComposerPmndrs>
<ColorAveragePmndrs :blendFunction="Number(blendFunction.value)" :opacity="opacity.value" />
</EffectComposerPmndrs>
</Suspense>
</TresCanvas>
</template>
1 change: 1 addition & 0 deletions docs/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ declare module 'vue' {
BlenderCube: typeof import('./.vitepress/theme/components/BlenderCube.vue')['default']
BloomDemo: typeof import('./.vitepress/theme/components/pmdrs/BloomDemo.vue')['default']
ChromaticAberrationDemo: typeof import('./.vitepress/theme/components/pmdrs/ChromaticAberrationDemo.vue')['default']
ColorAverageDemo: typeof import('./.vitepress/theme/components/pmdrs/ColorAverageDemo.vue')['default']
DepthOfFieldDemo: typeof import('./.vitepress/theme/components/pmdrs/DepthOfFieldDemo.vue')['default']
DocsDemo: typeof import('./.vitepress/theme/components/DocsDemo.vue')['default']
DotScreenDemo: typeof import('./.vitepress/theme/components/pmdrs/DotScreenDemo.vue')['default']
Expand Down
70 changes: 70 additions & 0 deletions docs/guide/pmndrs/color-average.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Color Average

<DocsDemo>
<ColorAverageDemo />
</DocsDemo>

The `ColorAverage` effect is part of the [`postprocessing`](https://pmndrs.github.io/postprocessing/public/docs/class/src/effects/ColorAverageEffect.js~ColorAverageEffect.html) package. It averages the colors of the scene, creating a unique visual effect. This effect can be used to achieve a variety of artistic styles.

## Usage

The `<ColorAveragePmndrs>` component is easy to use and provides customizable options to suit different visual styles.

```vue{6,15-18,40-44}
<script setup lang="ts">
import { Environment, OrbitControls } from '@tresjs/cientos'
import { TresCanvas } from '@tresjs/core'
import { NoToneMapping } from 'three'
import { BlendFunction } from 'postprocessing'
import { ColorAveragePmndrs, EffectComposerPmndrs } from '@tresjs/post-processing'
const gl = {
clearColor: '#ffffff',
toneMapping: NoToneMapping,
multisampling: 8,
envMapIntensity: 10,
}
const effectProps = reactive({
blendFunction: BlendFunction.NORMAL,
opacity: 0.5
})
</script>
<template>
<TresCanvas
v-bind="gl"
>
<TresPerspectiveCamera
:position="[5, 2, 15]"
:look-at="[0, 0, 0]"
/>
<OrbitControls auto-rotate />
<TresMesh :position="[0, 3.5, 0]">
<TresBoxGeometry :args="[2, 2, 2]" />
<TresMeshPhysicalMaterial color="#8B0000" :roughness=".25" />
</TresMesh>
<Suspense>
<Environment background preset="shangai" />
</Suspense>
<Suspense>
<EffectComposerPmndrs>
<ColorAveragePmndrs v-bind="effectProps" />
</EffectComposerPmndrs>
</Suspense>
</TresCanvas>
</template>
```

## Props

| Prop | Description | Default |
| ----------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------- |
| blendFunction | Defines the [`BlendFunction`](https://pmndrs.github.io/postprocessing/public/docs/variable/index.html#static-variable-BlendFunction) used for the effect. | `BlendFunction.NORMAL` |
| opacity | Sets the opacity of the color average effect. | `1` |

## Further Reading
For more details, see the [ColorAverage documentation](https://pmndrs.github.io/postprocessing/public/docs/class/src/effects/ColorAverageEffect.js~ColorAverageEffect.html)
66 changes: 66 additions & 0 deletions playground/src/pages/postprocessing/color-average.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<script setup lang="ts">
import { ContactShadows, Environment, OrbitControls } from '@tresjs/cientos'
import { TresCanvas } from '@tresjs/core'
import { TresLeches, useControls } from '@tresjs/leches'
import { NoToneMapping } from 'three'
import { BlendFunction } from 'postprocessing'
import { ColorAveragePmndrs, EffectComposerPmndrs } from '@tresjs/post-processing'
import '@tresjs/leches/styles'
const gl = {
clearColor: '#ffffff',
toneMapping: NoToneMapping,
multisampling: 8,
envMapIntensity: 10,
}
const { blendFunction, opacity } = useControls({
blendFunction: {
options: Object.keys(BlendFunction).map(key => ({
text: key,
value: BlendFunction[key],
})),
value: BlendFunction.NORMAL,
},
opacity: {
value: 1,
min: 0,
max: 1,
},
})
</script>

<template>
<TresLeches />

<TresCanvas
v-bind="gl"
>
<TresPerspectiveCamera
:position="[5, 5, 5]"
:look-at="[0, 0, 0]"
/>
<OrbitControls auto-rotate />

<TresMesh :position="[0, .5, 0]">
<TresBoxGeometry :args="[2, 2, 2]" />
<TresMeshPhysicalMaterial color="#8B0000" :roughness=".25" />
</TresMesh>

<ContactShadows
:opacity="1"
:position-y="-.5"
/>

<Suspense>
<Environment background preset="snow" />
</Suspense>

<Suspense>
<EffectComposerPmndrs>
<ColorAveragePmndrs :blendFunction="Number(blendFunction.value)" :opacity="opacity.value" />
</EffectComposerPmndrs>
</Suspense>
</TresCanvas>
</template>
1 change: 1 addition & 0 deletions playground/src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export const postProcessingRoutes = [
makeRoute('Bloom', '🌼', false),
makeRoute('Noise', '📟', false),
makeRoute('Chromatic Aberration', '🌈', false),
makeRoute('Color Average', '🎞️', false),
makeRoute('Lens Distortion', '🔍', false),
makeRoute('Sepia', '🌅', false),
makeRoute('Scanline', '📺', false),
Expand Down
48 changes: 48 additions & 0 deletions src/core/pmndrs/ColorAveragePmndrs.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<script lang="ts" setup>
import type { BlendFunction } from 'postprocessing'
import { ColorAverageEffect } from 'postprocessing'
import { makePropWatcher, makePropWatchers } from '../../util/prop'

Check failure on line 4 in src/core/pmndrs/ColorAveragePmndrs.vue

View workflow job for this annotation

GitHub Actions / Lint (20)

'makePropWatchers' is defined but never used
import { useEffectPmndrs } from './composables/useEffectPmndrs'
import { watch } from 'vue'
export interface ColorAveragePmndrsProps {
/**
* The blend function.
*/
blendFunction?: BlendFunction
/**
* The opacity of the color Average.
*/
opacity?: number
}
const props = defineProps<ColorAveragePmndrsProps>()
const { pass, effect } = useEffectPmndrs(() => new ColorAverageEffect(props.blendFunction), props)
defineExpose({ pass, effect })
makePropWatcher(
() => props.blendFunction,
effect,
'blendMode.blendFunction',
() => new ColorAverageEffect(),
)
watch(
[effect, () => props.opacity],
() => {
if (!effect.value) { return }
if (props.opacity !== undefined) {
effect.value?.blendMode.setOpacity(props.opacity)
}
else {
const plainEffect = new ColorAverageEffect()
effect.value?.blendMode.setOpacity(plainEffect.blendMode.getOpacity())
plainEffect.dispose()
}
},
)
</script>
3 changes: 3 additions & 0 deletions src/core/pmndrs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import ToneMappingPmndrs, { type ToneMappingPmndrsProps } from './ToneMappingPmn
import ChromaticAberrationPmndrs, { type ChromaticAberrationPmndrsProps } from './ChromaticAberrationPmndrs.vue'
import HueSaturationPmndrs, { type HueSaturationPmndrsProps } from './HueSaturationPmndrs.vue'
import ScanlinePmndrs, { type ScanlinePmndrsProps } from './ScanlinePmndrs.vue'
import ColorAveragePmndrs, { type ColorAveragePmndrsProps } from './ColorAveragePmndrs.vue'
import LensDistortionPmndrs, { type LensDistortionPmndrsProps } from './LensDistortionPmndrs.vue'
import ShockWavePmndrs, { type ShockWavePmndrsProps } from './ShockWavePmndrs.vue'
import DepthPickingPassPmndrs, { type DepthPickingPassPmndrsProps } from './DepthPickingPassPmndrs.vue'
Expand All @@ -38,6 +39,7 @@ export {
ChromaticAberrationPmndrs,
HueSaturationPmndrs,
ScanlinePmndrs,
ColorAveragePmndrs,
LensDistortionPmndrs,
ShockWavePmndrs,
DepthPickingPassPmndrs,
Expand All @@ -58,6 +60,7 @@ export {
ChromaticAberrationPmndrsProps,
HueSaturationPmndrsProps,
ScanlinePmndrsProps,
ColorAveragePmndrsProps,
LensDistortionPmndrsProps,
ShockWavePmndrsProps,
DepthPickingPassPmndrsProps,
Expand Down

0 comments on commit 03f4986

Please sign in to comment.