Skip to content
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: color average #166

Merged
merged 5 commits into from
Jan 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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' },
{ 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'
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
Loading