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 3 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
1 change: 1 addition & 0 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export default defineConfig({
{ text: 'Noise', link: '/guide/pmndrs/noise' },
{ text: 'Outline', link: '/guide/pmndrs/outline' },
{ text: 'Chromatic Aberration', link: '/guide/pmndrs/chromatic-aberration' },
{ text: 'Color Average', link: '/guide/pmndrs/color-average' },
{ text: 'Scanline', link: '/guide/pmndrs/scanline' },
{ text: 'Pixelation', link: '/guide/pmndrs/pixelation' },
{ text: 'Vignette', link: '/guide/pmndrs/vignette' },
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 @@ -10,6 +10,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']
Ducky: typeof import('./.vitepress/theme/components/Ducky.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 @@ -40,6 +40,7 @@ export const postProcessingRoutes = [
makeRoute('Bloom', '🌼', false),
makeRoute('Noise', '📟', false),
makeRoute('Chromatic Aberration', '🌈', false),
makeRoute('Color Average', '🎞️', false),
makeRoute('Scanline', '📺', false),
makeRoute('Vignette', '🕶️', false),
makeRoute('On-demand', '🔄', false),
Expand Down
57 changes: 57 additions & 0 deletions src/core/pmndrs/ColorAveragePmndrs.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<script lang="ts" setup>
import type { BlendFunction } from 'postprocessing'
import { ColorAverageEffect } from 'postprocessing'
import { 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 = withDefaults(
defineProps<ColorAveragePmndrsProps>(),
{
opacity: 1,
Tinoooo marked this conversation as resolved.
Show resolved Hide resolved
},
)

const { pass, effect } = useEffectPmndrs(() => new ColorAverageEffect(props.blendFunction), props)

defineExpose({ pass, effect })

makePropWatchers(
Tinoooo marked this conversation as resolved.
Show resolved Hide resolved
[
[() => props.blendFunction, 'blendMode.blendFunction'],
],
effect,
() => 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()
}
},
{
immediate: true,
Tinoooo marked this conversation as resolved.
Show resolved Hide resolved
},
)
</script>
4 changes: 4 additions & 0 deletions src/core/pmndrs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import VignettePmndrs, { type VignettePmndrsProps } from './VignettePmndrs.vue'
import ChromaticAberrationPmndrs, { type ChromaticAberrationPmndrsProps } from './ChromaticAberration.vue'
import HueSaturationPmndrs, { type HueSaturationPmndrsProps } from './HueSaturationPmndrs.vue'
import ScanlinePmndrs, { type ScanlinePmndrsProps } from './ScanlinePmndrs.vue'
import ColorAveragePmndrs, { type ColorAveragePmndrsProps } from './ColorAveragePmndrs.vue'

export {
BloomPmndrs,
Expand All @@ -26,6 +27,8 @@ export {
ChromaticAberrationPmndrs,
HueSaturationPmndrs,
ScanlinePmndrs,
ColorAveragePmndrs,

BloomPmndrsProps,
DepthOfFieldPmndrsProps,
EffectComposerPmndrsProps,
Expand All @@ -37,4 +40,5 @@ export {
ChromaticAberrationPmndrsProps,
HueSaturationPmndrsProps,
ScanlinePmndrsProps,
ColorAveragePmndrsProps,
}
Loading