Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: Tresjs/post-processing
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: e9bd14aaf27a863ed974de50e4259b558e767d0f
Choose a base ref
..
head repository: Tresjs/post-processing
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: ebbdabe9eee2202fc061cc441abb58107bfd5da3
Choose a head ref
Showing with 2,870 additions and 152 deletions.
  1. +12 −4 docs/.vitepress/config.ts
  2. +63 −0 docs/.vitepress/theme/components/pmdrs/BarrelBlurDemo.vue
  3. +92 −0 docs/.vitepress/theme/components/pmdrs/ColorAverageDemo.vue
  4. +62 −0 docs/.vitepress/theme/components/pmdrs/DotScreenDemo.vue
  5. +68 −0 docs/.vitepress/theme/components/pmdrs/LensDistortionDemo.vue
  6. +61 −0 docs/.vitepress/theme/components/pmdrs/SepiaDemo.vue
  7. +218 −0 docs/.vitepress/theme/components/pmdrs/ShockWaveDemo.vue
  8. +79 −0 docs/.vitepress/theme/components/pmdrs/TiltShiftDemo.vue
  9. +73 −0 docs/.vitepress/theme/components/pmdrs/ToneMappingDemo.vue
  10. +7 −0 docs/components.d.ts
  11. +72 −0 docs/guide/pmndrs/barrel-blur.md
  12. +70 −0 docs/guide/pmndrs/color-average.md
  13. +74 −0 docs/guide/pmndrs/dot-screen.md
  14. +85 −0 docs/guide/pmndrs/lens-distortion.md
  15. +66 −0 docs/guide/pmndrs/sepia.md
  16. +188 −0 docs/guide/pmndrs/shock-wave.md
  17. +89 −0 docs/guide/pmndrs/tilt-shift.md
  18. +71 −0 docs/guide/pmndrs/tone-mapping.md
  19. +1 −1 docs/package.json
  20. BIN docs/public/lens-distortion/room-map.png
  21. BIN docs/public/lens-distortion/room-normal.png
  22. +0 −1 playground/components.d.ts
  23. +1 −1 playground/public/nuxt-stones/package.json
  24. +91 −0 playground/src/pages/postprocessing/barrel-blur.vue
  25. +66 −0 playground/src/pages/postprocessing/color-average.vue
  26. +56 −0 playground/src/pages/postprocessing/dot-screen.vue
  27. +54 −0 playground/src/pages/postprocessing/lens-distortion.vue
  28. +61 −0 playground/src/pages/postprocessing/sepia.vue
  29. +121 −0 playground/src/pages/postprocessing/shock-wave.vue
  30. +90 −0 playground/src/pages/postprocessing/tilt-shift.vue
  31. +77 −0 playground/src/pages/postprocessing/tone-mapping.vue
  32. +8 −0 playground/src/router.ts
  33. +155 −109 pnpm-lock.yaml
  34. +50 −0 src/core/pmndrs/BarrelBlurPmndrs.vue
  35. +14 −6 src/core/pmndrs/{ChromaticAberration.vue → ChromaticAberrationPmndrs.vue}
  36. +48 −0 src/core/pmndrs/ColorAveragePmndrs.vue
  37. +31 −0 src/core/pmndrs/DepthPickingPassPmndrs.vue
  38. +41 −0 src/core/pmndrs/DotScreenPmndrs.vue
  39. +1 −8 src/core/pmndrs/HueSaturationPmndrs.vue
  40. +48 −0 src/core/pmndrs/LensDistortionPmndrs.vue
  41. +3 −3 src/core/pmndrs/NoisePmndrs.vue
  42. +19 −9 src/core/pmndrs/ScanlinePmndrs.vue
  43. +33 −0 src/core/pmndrs/SepiaPmndrs.vue
  44. +72 −0 src/core/pmndrs/ShockWavePmndrs.vue
  45. +80 −0 src/core/pmndrs/TiltShiftPmndrs.vue
  46. +63 −0 src/core/pmndrs/ToneMappingPmndrs.vue
  47. +5 −9 src/core/pmndrs/VignettePmndrs.vue
  48. +100 −0 src/core/pmndrs/custom/barrel-blur/index.ts
  49. +31 −1 src/core/pmndrs/index.ts
16 changes: 12 additions & 4 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
@@ -48,16 +48,24 @@ export default defineConfig({
{
text: 'Pmndrs',
items: [
{ 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: 'Chromatic Aberration', link: '/guide/pmndrs/chromatic-aberration' },
{ text: 'Scanline', link: '/guide/pmndrs/scanline' },
{ text: 'Outline', link: '/guide/pmndrs/outline' },

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

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' },
{ text: 'Shock Wave', link: '/guide/pmndrs/shock-wave' },
{ text: 'Tilt Shift', link: '/guide/pmndrs/tilt-shift' },
{ text: 'Tone Mapping', link: '/guide/pmndrs/tone-mapping' },
{ text: 'Vignette', link: '/guide/pmndrs/vignette' },
{ text: 'Hue & Saturation', link: '/guide/pmndrs/hue-saturation' },
],
},
{
63 changes: 63 additions & 0 deletions docs/.vitepress/theme/components/pmdrs/BarrelBlurDemo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<script setup lang="ts">
import { Environment, OrbitControls, RoundedBox } from '@tresjs/cientos'
import { TresCanvas } from '@tresjs/core'
import { TresLeches, useControls } from '@tresjs/leches'
import { BarrelBlurPmndrs, EffectComposerPmndrs } from '@tresjs/post-processing'
import { BlendFunction } from 'postprocessing'
import { NoToneMapping } from 'three'
import '@tresjs/leches/styles'
const gl = {
clearColor: '#4f4f4f',
toneMapping: NoToneMapping,
multisampling: 8,
}
const { amount, offsetX, offsetY, blendFunction } = useControls({
amount: { value: 0.25, step: 0.001, max: 1 },
offsetX: { value: 0.5, step: 0.01, min: 0, max: 1 },
offsetY: { value: 0.5, step: 0.01, min: 0, max: 1 },
blendFunction: {
options: Object.keys(BlendFunction).map(key => ({
text: key,
value: BlendFunction[key],
})),
value: BlendFunction.OVERLAY,
},
})
</script>

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

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

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

<RoundedBox :args="[2, 2, 2, 2, 0.25]">
<TresMeshPhysicalMaterial
color="white"
:metalness=".9"
:roughness=".5"
:clearcoat="1.0"
:clearcoatRoughness="0.1"
/>
</RoundedBox>

<Suspense>
<EffectComposerPmndrs>
<BarrelBlurPmndrs :amount="amount.value" :offset="[offsetX.value, offsetY.value]" :blendFunction="Number(blendFunction.value)" />
</EffectComposerPmndrs>
</Suspense>
</TresCanvas>
</template>
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>
62 changes: 62 additions & 0 deletions docs/.vitepress/theme/components/pmdrs/DotScreenDemo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<script setup lang="ts">
import { ContactShadows, Environment, OrbitControls, useGLTF } from '@tresjs/cientos'
import { TresCanvas } from '@tresjs/core'
import { TresLeches, useControls } from '@tresjs/leches'
import { DotScreenPmndrs, EffectComposerPmndrs } from '@tresjs/post-processing'
import { BlendFunction } from 'postprocessing'
import { NoToneMapping } from 'three'
import '@tresjs/leches/styles'
const gl = {
clearColor: '#ffffff',
toneMapping: NoToneMapping,
multisampling: 8,
}
const { angle, scale, blendFunction } = useControls({
angle: { value: 1.57, min: -Math.PI, max: Math.PI, step: 0.001 },
scale: { value: 1.25, min: 0.1, max: 2.5, step: 0.01 },
blendFunction: {
options: Object.keys(BlendFunction).map(key => ({
text: key,
value: BlendFunction[key],
})),
value: BlendFunction.NORMAL,
},
})
const { scene } = await useGLTF('https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/suzanne/suzanne.glb', { draco: true })
</script>

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

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

<primitive :scale="2" :rotation-x="Math.PI / -5" :rotation-y="Math.PI" :position-y=".25" :position-z="0.5" :object="scene" />

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

<Suspense>
<Environment preset="modern" />
</Suspense>

<Suspense>
<EffectComposerPmndrs>
<DotScreenPmndrs :blendFunction="Number(blendFunction.value)" :angle="angle.value" :scale="scale.value" />
</EffectComposerPmndrs>
</Suspense>
</TresCanvas>
</template>
68 changes: 68 additions & 0 deletions docs/.vitepress/theme/components/pmdrs/LensDistortionDemo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<script setup lang="ts">
import { Environment, OrbitControls } from '@tresjs/cientos'
import { TresCanvas, useTexture } from '@tresjs/core'
import { TresLeches, useControls } from '@tresjs/leches'
import { EffectComposerPmndrs, LensDistortionPmndrs } from '@tresjs/post-processing'
import { BackSide, NoToneMapping, SRGBColorSpace, Vector2 } from 'three'
import '@tresjs/leches/styles'
const gl = {
toneMapping: NoToneMapping,
multisampling: 8,
}
const { distortion, principalPoint, focalLength, skew } = useControls({
distortion: { value: new Vector2(0.5, 0.5), min: 0, max: 1, step: 0.001 },
principalPoint: { value: new Vector2(0.0, 0.0), min: 0, max: 1, step: 0.001 },
focalLength: { value: new Vector2(0.5, 0.5), min: 0, max: 2, step: 0.001 },
skew: { value: 0, min: -1, max: 1, step: 0.001 },
})
const pbrTexture = await useTexture({
map: '/lens-distortion/room-map.png',
normalMap: '/lens-distortion/room-normal.png',
})
pbrTexture.map.colorSpace = SRGBColorSpace
</script>

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

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

<TresMesh :position="[0, 2, 0]">
<TresBoxGeometry :args="[8, 8, 8]" />
<TresMeshStandardMaterial :side="BackSide" :map="pbrTexture.map" :normal-map="pbrTexture.normalMap" />
</TresMesh>

<TresMesh :position="[0, 0, 0]">
<TresBoxGeometry :args="[1.65, 1.65, 1.65]" />
<TresMeshNormalMaterial />
</TresMesh>

<TresAmbientLight :intensity="2" />

<Suspense>
<Environment background :blur=".25" preset="snow" />
</Suspense>

<Suspense>
<EffectComposerPmndrs>
<LensDistortionPmndrs
:distortion="distortion.value"
:principalPoint="principalPoint.value"
:focalLength="focalLength.value"
:skew="skew.value"
/>
</EffectComposerPmndrs>
</Suspense>
</TresCanvas>
</template>
61 changes: 61 additions & 0 deletions docs/.vitepress/theme/components/pmdrs/SepiaDemo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<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 { EffectComposerPmndrs, SepiaPmndrs } from '@tresjs/post-processing'
import { BlendFunction } from 'postprocessing'
import '@tresjs/leches/styles'
const gl = {
clearColor: '#ffffff',
toneMapping: NoToneMapping,
multisampling: 8,
}
const { intensity, blendFunction } = useControls({
intensity: { value: 1.0, step: 0.1, max: 5.0 },
blendFunction: {
options: Object.keys(BlendFunction).map(key => ({
text: key,
value: BlendFunction[key],
})),
value: BlendFunction.NORMAL,
},
})
</script>

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

<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="black" :roughness=".25" />
</TresMesh>

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

<Suspense>
<Environment background :blur=".5" preset="snow" />
</Suspense>

<Suspense>
<EffectComposerPmndrs>
<SepiaPmndrs :intensity="intensity.value" :blendFunction="Number(blendFunction.value)" />
</EffectComposerPmndrs>
</Suspense>
</TresCanvas>
</template>
218 changes: 218 additions & 0 deletions docs/.vitepress/theme/components/pmdrs/ShockWaveDemo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
<script setup lang="ts">
import { ContactShadows, Environment, OrbitControls } from '@tresjs/cientos'
import { TresCanvas } from '@tresjs/core'
import { TresLeches, useControls } from '@tresjs/leches'
import { NoToneMapping, Shape, Vector3 } from 'three'
import { computed, onUnmounted, reactive, ref, shallowRef } from 'vue'
import { DepthPickingPassPmndrs, EffectComposerPmndrs, ShockWavePmndrs } from '@tresjs/post-processing'
import { useElementBounding, useMouse, useParentElement } from '@vueuse/core'
import { gsap } from 'gsap'
import '@tresjs/leches/styles'
const gl = {
clearColor: '#8D404A',
toneMapping: NoToneMapping,
multisampling: 8,
}
const shockWaveEffectRef = shallowRef(null)
const elCanvasRef = ref(null)
const depthPickingPassRef = ref(null)
const meshHeartRef = ref(null)
const mousePosition = ref(new Vector3())
function createHeartShape(scale: number) {
const shape = new Shape()
const x = 0
const y = 0
shape.moveTo(x, y)
shape.bezierCurveTo(x, y, x - 0.5 * scale, y + 2.5 * scale, x - 2.5 * scale, y + 2.5 * scale)
shape.bezierCurveTo(x - 6.5 * scale, y + 2.5 * scale, x - 6.5 * scale, y - 1.5 * scale, x - 6.5 * scale, y - 1.5 * scale)
shape.bezierCurveTo(x - 6.5 * scale, y - 4.5 * scale, x - 3.5 * scale, y - 7 * scale, x, y - 9.5 * scale)
shape.bezierCurveTo(x + 3.5 * scale, y - 7 * scale, x + 6.5 * scale, y - 4.5 * scale, x + 6.5 * scale, y - 1.5 * scale)
shape.bezierCurveTo(x + 6.5 * scale, y - 1.5 * scale, x + 6.5 * scale, y + 2.5 * scale, x + 2.5 * scale, y + 2.5 * scale)
shape.bezierCurveTo(x + 0.5 * scale, y + 2.5 * scale, x, y, x, y)
return shape
}
const heartShapeFront = createHeartShape(0.35)
const parentEl = useParentElement()
const { x, y } = useMouse({ target: parentEl })
const { width, height, left, top } = useElementBounding(parentEl)
const extrudeSettings = reactive({
depth: 0.1,
bevelEnabled: true,
bevelSegments: 2,
steps: 2,
bevelSize: 0.25,
bevelThickness: 0.25,
})
const materialProps = reactive({
color: '#FF9999',
reflectivity: 0.75,
ior: 1.5,
roughness: 0.75,
clearcoat: 0.01,
clearcoatRoughness: 0.15,
transmission: 0.7,
})
let tl: gsap.core.Timeline
const ctx = gsap.context(() => { })
const { amplitude, waveSize, speed, maxRadius } = useControls({
amplitude: { value: 0.4, step: 0.01, max: 1.0 },
waveSize: { value: 0.5, step: 0.01, max: 1.0 },
speed: { value: 1.5, step: 0.1, max: 10.0 },
maxRadius: { value: 0.2, step: 0.01, max: 2 },
})
const cursorX = computed(() => ((x.value - left.value - width.value) / width.value) * 2.0 + 1.0)
const cursorY = computed(() => -((y.value - top.value - height.value) / height.value) * 2.0 - 1.0)
async function updateMousePosition() {
if (!elCanvasRef.value || !shockWaveEffectRef.value || !depthPickingPassRef.value) { return }
const ndcPosition = new Vector3(cursorX.value, cursorY.value, 0)
// Read depth from depth picking pass
ndcPosition.z = await depthPickingPassRef.value.pass.readDepth(ndcPosition)
ndcPosition.z = ndcPosition.z * 2.0 - 1.0
mousePosition.value.copy(ndcPosition.unproject(elCanvasRef.value.context.camera.value))
}
function triggerShockWave() {
if (!meshHeartRef.value || !shockWaveEffectRef.value) { return }
updateMousePosition()
shockWaveEffectRef.value.effect.explode()
const duration = getActiveDuration()
const durationSeconds = duration / 1000
ctx.add(() => {
tl?.kill()
tl = gsap.timeline()
tl.to(meshHeartRef.value.scale, {
duration: durationSeconds / 9,
x: 0.8,
y: 0.8,
z: 0.8,
ease: 'power2.inOut',
}).to(meshHeartRef.value.scale, {
duration: durationSeconds / 9,
x: 1.2,
y: 1.2,
z: 1.2,
ease: 'power2.inOut',
}).to(meshHeartRef.value.scale, {
duration: durationSeconds / 9,
x: 1,
y: 1,
z: 1,
ease: 'power2.inOut',
})
})
// Fallback for onFinish explode Shock Wave
// setTimeout(() => {
// console.log('Explode effect animation done')
// }, duration)
}
function getActiveDuration() {
// This function retrieves the duration for emitting the shock wave.
// For more details, see: https://github.com/pmndrs/postprocessing/blob/3d3df0576b6d49aec9e763262d5a1ff7429fd91a/src/effects/ShockWaveEffectRef.js#L258-L301
// To reduce the duration of the animation, you can decrease the values of maxRadius and waveSize.
// Note that the speed affects how quickly the shock wave radius increases over time, but not the total duration of the emit explode.
// Retrieve the values dynamically
const radiusMax = maxRadius.value.value
const wave = waveSize.value.value
// Duration formula: 2 * maxRadius + 3 * waveSize
const duration = 2 * radiusMax + 3 * wave
// Convert to milliseconds
return duration * 1000
}
onUnmounted(() => {
ctx.revert()
})
</script>

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

<p class="doc-shock-wave-instructions text-xs font-semibold text-zinc-600">Click on the heart to distribute love</p>

<TresCanvas
ref="elCanvasRef"
v-bind="gl"
>
<TresPerspectiveCamera
:position="[0, 0, 10]"
/>

<OrbitControls make-default auto-rotate />

<TresMesh ref="meshHeartRef" :position-y="2" @click="triggerShockWave">
<TresExtrudeGeometry :args="[heartShapeFront, extrudeSettings]" />
<TresMeshPhysicalMaterial
v-bind="materialProps"
/>
</TresMesh>

<TresDirectionalLight
:position="[5, 5, 7.5]"
:intensity="2"
/>

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

<Suspense>
<Environment preset="night" />
</Suspense>

<Suspense>
<EffectComposerPmndrs>
<DepthPickingPassPmndrs ref="depthPickingPassRef" />
<ShockWavePmndrs ref="shockWaveEffectRef" :position="mousePosition" :amplitude="amplitude.value" :waveSize="waveSize.value" :speed="speed.value" :maxRadius="maxRadius.value" />
</EffectComposerPmndrs>
</Suspense>
</TresCanvas>
</template>

<style scoped>
.doc-shock-wave-instructions {
position: absolute;
bottom: 0;
left: 0;
padding: 0.65rem 0.85rem;
text-align: center;
color: #fff;
z-index: 2;
border-radius: 0px 10px 0px 0px;
background: linear-gradient(90deg, hsla(24, 100%, 83%, 1) 0%, hsla(341, 91%, 68%, 1) 100%);
margin: 0;
}
</style>
79 changes: 79 additions & 0 deletions docs/.vitepress/theme/components/pmdrs/TiltShiftDemo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<script setup lang="ts">
import { Environment, OrbitControls } from '@tresjs/cientos'
import { TresCanvas } from '@tresjs/core'
import { TresLeches, useControls } from '@tresjs/leches'
import { EffectComposerPmndrs, TiltShiftPmndrs } from '@tresjs/post-processing'
import { BlendFunction } from 'postprocessing'
import { NoToneMapping } from 'three'
import '@tresjs/leches/styles'
const gl = {
toneMapping: NoToneMapping,
multisampling: 8,
}
const colors = [
'#FF5733',
'#33FF57',
'#3357FF',
'#FF33A1',
'#33FFF5',
'#FF5733',
'#FF8D33',
]
const { blendFunction, offset, rotation, focusArea, feather } = useControls({
blendFunction: {
options: Object.keys(BlendFunction).map(key => ({
text: key,
value: BlendFunction[key],
})),
value: BlendFunction.NORMAL,
},
offset: { value: 0.0, min: -0.5, max: 0.5, step: 0.01 },
rotation: { value: 0.0, min: -Math.PI, max: Math.PI, step: 0.01 },
focusArea: { value: 0.7, min: 0, max: 1, step: 0.01 },
feather: { value: 0.1, min: 0, max: 1, step: 0.01 },
})
</script>

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

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

<template v-for="index in 50" :key="index">
<TresMesh :position="[(index % 10) * 3 - 13.5, 0, Math.floor(index / 10) * 3 - 7.5]" :scale="[2, Math.random() * 5 + 2, 2]">
<TresBoxGeometry :args="[1, 1, 1]" />
<TresMeshPhysicalMaterial
:color="colors[index % colors.length]"
:roughness="0.35"
:metalness="0.5"
:clearcoat="0.3"
:clearcoatRoughness="0.25"
/>
</TresMesh>
</template>

<Suspense>
<Environment background :blur=".35" preset="snow" />
</Suspense>

<Suspense>
<EffectComposerPmndrs>
<TiltShiftPmndrs
:blendFunction="Number(blendFunction.value)"
:offset="offset.value"
:rotation="rotation.value"
:focusArea="focusArea.value"
:feather="feather.value"
/>
</EffectComposerPmndrs>
</Suspense>

<TresGridHelper :position="[0, -3.5, 0]" :args="[30, 15]" />
</TresCanvas>
</template>
73 changes: 73 additions & 0 deletions docs/.vitepress/theme/components/pmdrs/ToneMappingDemo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<script setup lang="ts">
import { ContactShadows, Environment, OrbitControls, useGLTF } from '@tresjs/cientos'
import { dispose, TresCanvas } from '@tresjs/core'
import { TresLeches, useControls } from '@tresjs/leches'
import { EffectComposerPmndrs, ToneMappingPmndrs } from '@tresjs/post-processing'
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 />

<primitive ref="modelRef" :object="model" :position-y="-.5" :scale=".25" />

<Suspense>
<Environment background :blur=".35" preset="dawn" />
</Suspense>

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

<Suspense>
<EffectComposerPmndrs>
<ToneMappingPmndrs :mode="Number(mode.value)" />
</EffectComposerPmndrs>
</Suspense>
</TresCanvas>
</template>
7 changes: 7 additions & 0 deletions docs/components.d.ts
Original file line number Diff line number Diff line change
@@ -7,24 +7,31 @@ export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
BarrelBlurDemo: typeof import('./.vitepress/theme/components/pmdrs/BarrelBlurDemo.vue')['default']
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']
Ducky: typeof import('./.vitepress/theme/components/Ducky.vue')['default']
GlitchDemo: typeof import('./.vitepress/theme/components/pmdrs/GlitchDemo.vue')['default']
GlitchThreeDemo: typeof import('./.vitepress/theme/components/three/GlitchThreeDemo.vue')['default']
HalftoneThreeDemo: typeof import('./.vitepress/theme/components/three/HalftoneThreeDemo.vue')['default']
HueSaturation: typeof import('./.vitepress/theme/components/pmdrs/HueSaturationDemo.vue')['default']
HueSaturationDemo: typeof import('./.vitepress/theme/components/pmdrs/HueSaturationDemo.vue')['default']
LensDistortionDemo: typeof import('./.vitepress/theme/components/pmdrs/LensDistortionDemo.vue')['default']
LoveVueThreeJS: typeof import('./.vitepress/theme/components/LoveVueThreeJS.vue')['default']
NoiseDemo: typeof import('./.vitepress/theme/components/pmdrs/NoiseDemo.vue')['default']
OutlineDemo: typeof import('./.vitepress/theme/components/pmdrs/OutlineDemo.vue')['default']
PixelationDemo: typeof import('./.vitepress/theme/components/pmdrs/PixelationDemo.vue')['default']
PixelationThreeDemo: typeof import('./.vitepress/theme/components/three/PixelationThreeDemo.vue')['default']
ScanlineDemo: typeof import('./.vitepress/theme/components/pmdrs/ScanlineDemo.vue')['default']
ShockWaveDemo: typeof import('./.vitepress/theme/components/pmdrs/ShockWaveDemo.vue')['default']
SepiaDemo: typeof import('./.vitepress/theme/components/pmdrs/SepiaDemo.vue')['default']
SMAAThreeDemo: typeof import('./.vitepress/theme/components/three/SMAAThreeDemo.vue')['default']
TiltShiftDemo: typeof import('./.vitepress/theme/components/pmdrs/TiltShiftDemo.vue')['default']
ToneMappingDemo: typeof import('./.vitepress/theme/components/pmdrs/ToneMappingDemo.vue')['default']
UnrealBloomThreeDemo: typeof import('./.vitepress/theme/components/three/UnrealBloomThreeDemo.vue')['default']
VignetteDemo: typeof import('./.vitepress/theme/components/pmdrs/VignetteDemo.vue')['default']
72 changes: 72 additions & 0 deletions docs/guide/pmndrs/barrel-blur.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Barrel Blur

<DocsDemo>
<BarrelBlurDemo />
</DocsDemo>

The `Barrel Blur` is a custom effect that applies a barrel distortion with chromatic aberration blur, providing a unique visual effect.

## Usage

The `<BarrelBlurPmndrs>` component is straightforward to use and provides customizable options to fine-tune the barrel blur effect.

```vue{4,12-15,40-44}
<script setup lang="ts">
import { TresCanvas } from '@tresjs/core'
import { Environment, OrbitControls, RoundedBox } from '@tresjs/cientos'
import { EffectComposerPmndrs, BarrelBlurPmndrs } from '@tresjs/post-processing'
const gl = {
clearColor: '#4f4f4f',
toneMapping: NoToneMapping,
multisampling: 8,
}
const effectProps = {
amount: 0.25,
offset: [0.5, 0.5],
}
</script>
<template>
<TresCanvas v-bind="gl">
<TresPerspectiveCamera
:position="[5, 5, 5]"
:look-at="[0, 0, 0]"
/>
<OrbitControls auto-rotate />
<Suspense>
<Environment preset="shangai" />
</Suspense>
<RoundedBox :args="[2, 2, 2, 2, 0.25]">
<TresMeshPhysicalMaterial
color="white"
:metalness=".9"
:roughness=".5"
:clearcoat="1.0"
:clearcoatRoughness="0.1"
/>
</RoundedBox>
<Suspense>
<EffectComposerPmndrs>
<BarrelBlurPmndrs v-bind="effectProps" />
</EffectComposerPmndrs>
</Suspense>
</TresCanvas>
</template>
```

## Props

| Prop | Description | Default |
| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ |
| **amount** | The intensity of the barrel distortion. A value between 0 (no distortion) and 1 (maximum distortion). | `0.1` |
| **offset** | The offset of the barrel distortion center. A `Vector2` value or an array of two numbers where both values are between 0 and 1. | `[0.5, 0.5]` |
| **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` |

## Further Reading

For an example of the barrel blur effect in WebGL, see the [Barrel Blur Effect on Shadertoy](https://www.shadertoy.com/view/lc3BW8).
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)
74 changes: 74 additions & 0 deletions docs/guide/pmndrs/dot-screen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Dot Screen

<DocsDemo>
<DotScreenDemo />
</DocsDemo>

The `DotScreen` effect is part of the [`postprocessing`](https://pmndrs.github.io/postprocessing/public/docs/class/src/effects/DotScreenEffect.js~DotScreenEffect.html) package. It allows you to create a dot screen effect, providing flexibility for artistic effects.

## Usage

The `<DotScreenPmndrs>` component is straightforward to use and provides customizable options to fine-tune the dot screen effect.

```vue{4,13-16,42-46}
<script setup lang="ts">
import { ContactShadows, Environment, OrbitControls, useGLTF } from '@tresjs/cientos'
import { TresCanvas } from '@tresjs/core'
import { DotScreenPmndrs, EffectComposerPmndrs } from '@tresjs/post-processing'
import { NoToneMapping } from 'three'
const gl = {
clearColor: '#ffffff',
toneMapping: NoToneMapping,
multisampling: 8,
}
const effectProps = reactive({
angle: 1.57,
scale: 1.25
})
const { scene } = await useGLTF('https://raw.githubusercontent.com/Tresjs/assets/main/models/gltf/suzanne/suzanne.glb', { draco: true })
</script>
<template>
<TresCanvas
v-bind="gl"
>
<TresPerspectiveCamera
:position="[0, 1, 7.5]"
:look-at="[0, 0, 0]"
/>
<OrbitControls />
<primitive :scale="2" :rotation-x="Math.PI / -5" :rotation-y="Math.PI" :position-y=".25" :position-z="0.5" :object="scene" />
<ContactShadows
:opacity="1"
:position-y="-1.5"
/>
<Suspense>
<Environment preset="modern" />
</Suspense>
<Suspense>
<EffectComposerPmndrs>
<DotScreenPmndrs v-bind="effectProps" />
</EffectComposerPmndrs>
</Suspense>
</TresCanvas>
</template>
```

## Props

| Prop | Description | Default |
| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ |
| **angle** | The angle of the dot pattern *(in radians)*. | `1.57` |
| **scale** | The scale of the dot pattern. | `1.0` |
| **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` |

## Further Reading

For more details, see the [DotScreen documentation](https://pmndrs.github.io/postprocessing/public/docs/class/src/effects/DotScreenEffect.js~DotScreenEffect.html).
85 changes: 85 additions & 0 deletions docs/guide/pmndrs/lens-distortion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Lens Distortion

<DocsDemo>
<LensDistortionDemo />
</DocsDemo>

The `LensDistortion` effect is part of the [`postprocessing`](https://pmndrs.github.io/postprocessing/public/docs/class/src/effects/LensDistortionEffect.js~LensDistortionEffect.html) package. It allows you to apply a lens distortion effect to your scene, providing flexibility for creating realistic camera effects.

## Usage

The `<LensDistortionPmndrs>` component is straightforward to use and provides customizable options to fine-tune the distortion effect of your visuals.

```vue{3,12-17,52-56}
<script setup lang="ts">
import { Vector2 } from 'three'
import { EffectComposerPmndrs, LensDistortionPmndrs } from '@tresjs/post-processing'
import { Environment, OrbitControls } from '@tresjs/cientos'
import { TresCanvas, useTexture } from '@tresjs/core'
const gl = {
toneMapping: NoToneMapping,
multisampling: 8,
}
const effectProps = {
distortion: new Vector2(0.5, 0.5),
principalPoint: new Vector2(0.0, 0.0),
focalLength: new Vector2(0.5, 0.5),
skew: 0,
}
const pbrTexture = await useTexture({
map: '/lens-distortion/room-map.png',
normalMap: '/lens-distortion/room-normal.png',
})
pbrTexture.map.colorSpace = SRGBColorSpace
</script>
<template>
<TresCanvas
v-bind="gl"
>
<TresPerspectiveCamera
:position="[-2, 1, 5]"
/>
<OrbitControls auto-rotate />
<TresMesh :position="[0, 2, 0]">
<TresBoxGeometry :args="[8, 8, 8]" />
<TresMeshStandardMaterial :side="BackSide" :map="pbrTexture.map" :normal-map="pbrTexture.normalMap" />
</TresMesh>
<TresMesh :position="[0, 0, 0]">
<TresBoxGeometry :args="[1.65, 1.65, 1.65]" />
<TresMeshNormalMaterial />
</TresMesh>
<TresAmbientLight :intensity="2" />
<Suspense>
<Environment background :blur=".25" preset="snow" />
</Suspense>
<Suspense>
<EffectComposerPmndrs>
<LensDistortionPmndrs v-bind="effectProps" />
</EffectComposerPmndrs>
</Suspense>
</TresCanvas>
</template>
```

## Props

| Prop | Description | Default |
| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ |
| **distortion** | The distortion effect strength. <br> Accepts `Vector2` or `[number, number]`. | `[0.0, 0.0]` |
| **principalPoint** | The center point. <br> Accepts `Vector2` or `[number, number]`. | `[0.0, 0.0]` |
| **focalLength** | The focal length. <br> Accepts `Vector2` or `[number, number]`. | `[1.0, 1.0]` |
| **skew** | The skew value. | `0` |

## Further Reading

For more details, see the [LensDistortion documentation](https://pmndrs.github.io/postprocessing/public/docs/class/src/effects/LensDistortionEffect.js~LensDistortionEffect.html).
66 changes: 66 additions & 0 deletions docs/guide/pmndrs/sepia.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Sepia

<DocsDemo>
<SepiaDemo />
</DocsDemo>

The `Sepia` effect is part of the [`postprocessing`](https://pmndrs.github.io/postprocessing/public/docs/class/src/effects/SepiaEffect.js~SepiaEffect.html) package. It applies a sepia tone to the scene, giving it a warm, antique appearance. This effect can enhance the visual appeal of your scene by adding a vintage or stylized touch.

## Usage

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

```vue{2,36-40}
<script setup lang="ts">
import { EffectComposerPmndrs, SepiaPmndrs } from '@tresjs/post-processing/pmndrs'
const gl = {
toneMapping: NoToneMapping,
multisampling: 8,
}
</script>
<template>
<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="black" :roughness=".25" />
</TresMesh>
<ContactShadows
:opacity="1"
:position-y="-.5"
/>
<Suspense>
<Environment background :blur=".5" preset="snow" />
</Suspense>
<Suspense>
<EffectComposerPmndrs>
<SepiaPmndrs :intensity="2" />
</EffectComposerPmndrs>
</Suspense>
</TresCanvas>
</template>
```

## Props

| Prop | Description | Default |
| ----------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------- |
| 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` |
| intensity | The intensity of the sepia effect. | `1.0` |

## Further Reading
For more details, see the [Sepia documentation](https://pmndrs.github.io/postprocessing/public/docs/class/src/effects/SepiaEffect.js~SepiaEffect.html)
188 changes: 188 additions & 0 deletions docs/guide/pmndrs/shock-wave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
# Shock Wave

<DocsDemo>
<ShockWaveDemo />
</DocsDemo>

<details>
<summary>Demo code</summary>

<<< @/.vitepress/theme/components/pmdrs/ShockWaveDemo.vue{0}
</details>

The `ShockWave` effect is part of the [`postprocessing`](https://pmndrs.github.io/postprocessing/public/docs/class/src/effects/ShockWaveEffect.js~ShockWaveEffect.html) package. It simulates a shockwave effect originating from a center point, creating a ripple-like distortion in the scene. This effect can add dramatic impact to your scene by simulating explosions or other shockwave phenomena.

## Usage

The `<ShockWavePmndrs>` component is easy to use and provides customizable options to suit different visual styles. There are several possible techniques to achieve this. See [Events](#events) and [DepthPickingPass](#depthpickingpass) for more details.

The main difference between `Events` and `DepthPickingPass` lies in the scope you want. `Events` is more suited for being used on a specific element, while `DepthPickingPass` is intended to be used for an entire scene (depth is calculated globally).

### Events

To determine the position of the shockwave effect, you can use Tres.js events. Tres.js allows you to handle user interactions directly and find the intersection point with objects in the scene. This technique is useful when you need to interact with specific objects based on user input.

You can use various Tres.js events such as `click`, `pointer-enter`, etc., to trigger the shockwave effect. For more details about available events, see the [documentation](https://docs.tresjs.org/api/events.html).

Here is an example of how to use events to trigger the shockwave effect:

```vue{2,3,13-15,17-18,20-21,23-24,26-28,30-36,45,50-58}
<script setup lang="ts">
import { EffectComposerPmndrs, ShockWavePmndrs } from '@tresjs/post-processing'
import { useMouse, useWindowSize } from '@vueuse/core'
import { NoToneMapping, Vector3 } from 'three'
import { computed, ref } from 'vue'
import { TresCanvas } from '@tresjs/core'
const gl = {
toneMapping: NoToneMapping,
multisampling: 8,
}
const effectProps = {
speed: 0.2,
}
const position = ref(new Vector3(0, 0, 0))
const shockWaveEffectRef = ref(null)
const { x, y } = useMouse()
const { width, height } = useWindowSize()
const cursorX = computed(() => (x.value / width.value) * 2.0 - 1.0)
const cursorY = computed(() => -(y.value / height.value) * 2.0 + 1.0)
function updateMousePosition({ point }) {
mousePosition.value.copy(point)
}
function triggerShockWave() {
if (!shockWaveEffectRef.value) { return }
updateMousePosition()
shockWaveEffectRef.value.effect.explode()
}
</script>
<template>
<TresCanvas v-bind="gl">
<TresPerspectiveCamera
:position="[5, 5, 5]"
:look-at="[0, 0, 0]"
/>
<TresMesh @click="triggerShockWave">
<TresBoxGeometry />
<TresMeshStandardMaterial color="#1C1C1E" />
</TresMesh>
<Suspense>
<EffectComposerPmndrs>
<ShockWavePmndrs
ref="shockWaveEffectRef"
:position="position"
v-bind="effectProps"
/>
</EffectComposerPmndrs>
</Suspense>
</TresCanvas>
</template>
```

### DepthPickingPass

The `DepthPickingPassPmndrs` component reads depth information from the scene. This is particularly useful for interacting with 3D objects based on their depth, such as triggering effects at specific points in 3D space.

In the example above, `DepthPickingPassPmndrs` determines the depth of the point where the shockwave effect should originate, allowing accurate interaction with 3D objects.

```vue{2,3,13-15,17-20,22-23,25-26,28-37,39-45,51,58,63-72}
<script setup lang="ts">
import { DepthPickingPassPmndrs, EffectComposerPmndrs, ShockWavePmndrs } from '@tresjs/post-processing'
import { useMouse, useWindowSize } from '@vueuse/core'
import { NoToneMapping, Vector3 } from 'three'
import { computed, ref } from 'vue'
import { TresCanvas } from '@tresjs/core'
const gl = {
toneMapping: NoToneMapping,
multisampling: 8,
}
const effectProps = {
speed: 0.2,
}
const position = ref(new Vector3(0, 0, 0))
const depthPickingPassRef = ref(null)
const shockWaveEffectRef = ref(null)
const elCanvasRef = ref(null)
const { x, y } = useMouse()
const { width, height } = useWindowSize()
const cursorX = computed(() => (x.value / width.value) * 2.0 - 1.0)
const cursorY = computed(() => -(y.value / height.value) * 2.0 + 1.0)
async function updateMousePosition() {
if (!elCanvasRef.value || !depthPickingPassRef.value) { return }
const ndcPosition = new Vector3(cursorX.value, cursorY.value, 0)
ndcPosition.z = await depthPickingPassRef.value.pass.readDepth(ndcPosition)
ndcPosition.z = ndcPosition.z * 2.0 - 1.0
position.value.copy(ndcPosition.unproject(elCanvasRef.value.context.camera.value))
}
function triggerShockWave() {
if (!shockWaveEffectRef.value) { return }
updateMousePosition()
shockWaveEffectRef.value.effect.explode()
}
</script>
<template>
<TresCanvas
v-bind="gl"
ref="elCanvasRef"
>
<TresPerspectiveCamera
:position="[5, 5, 5]"
:look-at="[0, 0, 0]"
/>
<TresMesh @click="triggerShockWave">
<TresBoxGeometry />
<TresMeshStandardMaterial color="#1C1C1E" />
</TresMesh>
<Suspense>
<EffectComposerPmndrs>
<DepthPickingPassPmndrs ref="depthPickingPassRef" />
<ShockWavePmndrs
ref="shockWaveEffectRef"
:position="position"
v-bind="effectProps"
/>
</EffectComposerPmndrs>
</Suspense>
</TresCanvas>
</template>
```

For more details about DepthPickingPass, see the [documentation](https://pmndrs.github.io/postprocessing/public/docs/class/src/passes/DepthPickingPass.js~DepthPickingPass.html).

## Props

| Prop | Description | Default |
| ----------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------- |
| position | The position of the shockwave. | `Vector3(0, 0, 0)` |
| amplitude | The amplitude of the shockwave. | `0.05` |
| waveSize | The wave size of the shockwave. | `0.2` |
| speed | The speed of the shockwave. | `2.0` |
| maxRadius | The max radius of the shockwave. | `1.0` |

## Further Reading
see [postprocessing docs](https://pmndrs.github.io/postprocessing/public/docs/class/src/effects/ShockWaveEffect.js~ShockWaveEffect.html)
89 changes: 89 additions & 0 deletions docs/guide/pmndrs/tilt-shift.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Tilt Shift

<DocsDemo>
<TiltShiftDemo />
</DocsDemo>

The `TiltShift` effect is part of the [`postprocessing`](https://pmndrs.github.io/postprocessing/public/docs/class/src/effects/TiltShiftEffect.js~TiltShiftEffect.html) package. It allows you to create a tilt-shift effect, simulating a shallow depth of field.

## Usage

The `<TiltShiftPmndrs>` component is straightforward to use and provides customizable options to fine-tune the tilt-shift effect.

```vue{3,21-24,49-53}
<script setup lang="ts">
import { Environment, OrbitControls } from '@tresjs/cientos'
import { EffectComposerPmndrs, TiltShiftPmndrs } from '@tresjs/post-processing'
import { NoToneMapping } from 'three'
const colors = [
'#FF5733',
'#33FF57',
'#3357FF',
'#FF33A1',
'#33FFF5',
'#FF5733',
'#FF8D33',
]
const gl = {
toneMapping: NoToneMapping,
multisampling: 8,
}
const effectProps = {
focusArea: 0.7,
feather: 0.1,
}
</script>
<template>
<TresCanvas v-bind="gl">
<TresPerspectiveCamera :position="[0, 4, 8]" />
<OrbitControls auto-rotate />
<template v-for="index in 50" :key="index">
<TresMesh :position="[(index % 10) * 3 - 13.5, 0, Math.floor(index / 10) * 3 - 7.5]" :scale="[2, Math.random() * 5 + 2, 2]">
<TresBoxGeometry :args="[1, 1, 1]" />
<TresMeshPhysicalMaterial
:color="colors[index % colors.length]"
:roughness="0.35"
:metalness="0.5"
:clearcoat="0.3"
:clearcoatRoughness="0.25"
/>
</TresMesh>
</template>
<Suspense>
<Environment background :blur=".35" preset="snow" />
</Suspense>
<Suspense>
<EffectComposerPmndrs>
<TiltShiftPmndrs v-bind="effectProps" />
</EffectComposerPmndrs>
</Suspense>
<TresGridHelper :position="[0, -3.5, 0]" :args="[30, 15]" />
</TresCanvas>
</template>
```

## Props

| Prop | Description | Default |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ |
| **blendFunction** | Defines how the effect blends with the original scene. <br> See the [`BlendFunction`](https://pmndrs.github.io/postprocessing/public/docs/variable/index.html#static-variable-BlendFunction) options. | `BlendFunction.NORMAL` |
| **offset** | The relative offset of the focus area. A positive value shifts the focus area upwards, while a negative value shifts it downwards. <br> Range: `[-0.5, 0.5]`. | `0.0` |
| **rotation** | The rotation of the focus area in radians. A positive rotation turns the focus area clockwise, while a negative rotation turns it counterclockwise. <br> Range: `[-π, π]`. | `0.0` |
| **focusArea** | The relative size of the focus area. A higher value increases the size of the focus area, while a lower value reduces it. <br> Range: `[0, 1]`. | `0.4` |
| **feather** | The softness of the focus area edges. A higher value makes the edges softer, while a lower value makes them sharper. <br> Range: `[0, 1]`. | `0.3` |
| **kernelSize** | The blur kernel size. A larger kernel size produces a more pronounced blur. <br> See the [`KernelSize`](https://pmndrs.github.io/postprocessing/public/docs/variable/index.html#static-variable-KernelSize) options. | `KernelSize.MEDIUM` |
| **resolutionScale** | The resolution scale. A higher value increases the effect's resolution, while a lower value reduces it, affecting quality and performance. <br> Range: `[0.1, 1]`. | `0.5` |
| **resolutionX** | The horizontal resolution. Use `Resolution.AUTO_SIZE` for automatic sizing based on the scene's resolution. | `Resolution.AUTO_SIZE` |
| **resolutionY** | The vertical resolution. Use `Resolution.AUTO_SIZE` for automatic sizing based on the scene's resolution. | `Resolution.AUTO_SIZE` |

## Further Reading

For more details, see the [TiltShift documentation](https://pmndrs.github.io/postprocessing/public/docs/class/src/effects/TiltShiftEffect.js~TiltShiftEffect.html).
71 changes: 71 additions & 0 deletions docs/guide/pmndrs/tone-mapping.md
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 `<ToneMappingPmndrs>` manually as an effect at the end of the `<EffectComposerPmndrs>` to fix this.
:::

## Usage

The `<ToneMappingPmndrs>` 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}
<script setup lang="ts">
import { EffectComposerPmndrs, ToneMappingPmndrs } 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>
<EffectComposerPmndrs>
<ToneMappingPmndrs :mode="ToneMappingMode.AGX" />
</EffectComposerPmndrs>
</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
For more details, see the [Tone Mapping documentation](https://pmndrs.github.io/postprocessing/public/docs/class/src/effects/ToneMappingEffect.js~ToneMappingEffect.html)
2 changes: 1 addition & 1 deletion docs/package.json
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@
},
"devDependencies": {
"@tresjs/leches": "^0.14.0",
"unocss": "^0.65.0",
"unocss": "^0.63.0",
"unplugin-vue-components": "^0.27.4",
"vite-svg-loader": "^5.1.0",
"vitepress": "1.3.4"
Binary file added docs/public/lens-distortion/room-map.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/public/lens-distortion/room-normal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion playground/components.d.ts
Original file line number Diff line number Diff line change
@@ -9,7 +9,6 @@ declare module 'vue' {
export interface GlobalComponents {
BasicScene: typeof import('./src/components/BasicScene.vue')['default']
BlenderCube: typeof import('./src/components/BlenderCube.vue')['default']
copy: typeof import('./src/components/UnrealBloom copy.vue')['default']
Ducky: typeof import('./src/components/Ducky.vue')['default']
EffectListItem: typeof import('./src/components/EffectListItem.vue')['default']
GlitchDemo: typeof import('./src/components/GlitchDemo.vue')['default']
2 changes: 1 addition & 1 deletion playground/public/nuxt-stones/package.json
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@
"gsap": "^3.11.5"
},
"devDependencies": {
"unocss": "^0.65.0",
"unocss": "^0.52.3",
"unplugin-vue-components": "^0.24.1",
"vite-svg-loader": "^4.0.0",
"vitepress": "1.0.0-beta.1"
91 changes: 91 additions & 0 deletions playground/src/pages/postprocessing/barrel-blur.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<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 { BarrelBlurPmndrs, EffectComposerPmndrs } from '@tresjs/post-processing'
import '@tresjs/leches/styles'
const gl = {
clearColor: '#ffffff',
toneMapping: NoToneMapping,
multisampling: 8,
envMapIntensity: 10,
}
const neonColors = [
'#FF00FF', // Magenta
'#00FFFF', // Cyan
'#00FF00', // Lime
'#FFFF00', // Yellow
'#FF0000', // Red
'#FF1493', // Deep Pink
'#7FFF00', // Chartreuse
'#FF4500', // Orange Red
'#8A2BE2', // Blue Violet
'#00FF7F', // Spring Green
'#FFD700', // Gold
'#FF69B4', // Hot Pink
'#ADFF2F', // Green Yellow
'#FF6347', // Tomato
'#40E0D0', // Turquoise
'#EE82EE', // Violet
]
const { blendFunction, amount, offsetX, offsetY } = useControls({
amount: { value: 0.2, step: 0.001, max: 1 },
offsetX: { value: 0.5, step: 0.01, min: 0, max: 1 },
offsetY: { value: 0.5, step: 0.01, min: 0, max: 1 },
blendFunction: {
options: Object.keys(BlendFunction).map(key => ({
text: key,
value: BlendFunction[key as keyof typeof BlendFunction],
})),
value: BlendFunction.OVERLAY,
},
})
</script>

<template>
<TresLeches />

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

<TresAmbientLight :intensity="1" />

<template v-for="(color, index) in neonColors" :key="index">
<TresMesh :position="[index % 4 * 2 - 3, 0, Math.floor(index / 4) * 2 - 3]">
<TresBoxGeometry :args="[2, 2, 2]" />
<TresMeshStandardMaterial :color="color" :roughness=".5" :metalness="1" />
</TresMesh>
</template>

<Suspense>
<Environment :blur=".25" preset="snow" />
</Suspense>

<TresDirectionalLight color="white" />

<ContactShadows
:opacity=".65"
:position-y="-1"
:scale="35"
:blur="1"
/>

<Suspense>
<EffectComposerPmndrs>
<BarrelBlurPmndrs :amount="amount.value" :offset="[offsetX.value, offsetY.value]" :blendFunction="Number(blendFunction.value)" />
</EffectComposerPmndrs>
</Suspense>
</TresCanvas>
</template>
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>
56 changes: 56 additions & 0 deletions playground/src/pages/postprocessing/dot-screen.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<script setup lang="ts">
import { Environment, OrbitControls } from '@tresjs/cientos'
import { TresCanvas } from '@tresjs/core'
import { TresLeches, useControls } from '@tresjs/leches'
import { DotScreenPmndrs, EffectComposerPmndrs } from '@tresjs/post-processing'
import { BlendFunction } from 'postprocessing'
import { NoToneMapping } from 'three'
import '@tresjs/leches/styles'
const gl = {
toneMapping: NoToneMapping,
multisampling: 8,
}
const { angle, scale, blendFunction } = useControls({
angle: { value: 1.57, min: -Math.PI, max: Math.PI, step: 0.001 },
scale: { value: 0.5, min: 0.1, max: 2.5, step: 0.01 },
blendFunction: {
options: Object.keys(BlendFunction).map(key => ({
text: key,
value: BlendFunction[key],
})),
value: BlendFunction.NORMAL,
},
})
</script>

<template>
<TresLeches />

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

<TresMesh :position="[0, 1, 0]">
<TresBoxGeometry :args="[2, 2, 2]" />
<TresMeshPhysicalMaterial color="white" :roughness="1" :transmission="0" />
</TresMesh>

<Suspense>
<Environment background :blur=".1" preset="dawn" />
</Suspense>

<Suspense>
<EffectComposerPmndrs>
<DotScreenPmndrs :blendFunction="Number(blendFunction.value)" :angle="angle.value" :scale="scale.value" />
</EffectComposerPmndrs>
</Suspense>
</TresCanvas>
</template>
54 changes: 54 additions & 0 deletions playground/src/pages/postprocessing/lens-distortion.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<script setup lang="ts">
import { Environment, OrbitControls } from '@tresjs/cientos'
import { TresCanvas } from '@tresjs/core'
import { TresLeches, useControls } from '@tresjs/leches'
import { EffectComposerPmndrs, LensDistortionPmndrs } from '@tresjs/post-processing'
import { NoToneMapping, Vector2 } from 'three'
import '@tresjs/leches/styles'
const gl = {
toneMapping: NoToneMapping,
multisampling: 8,
}
const { distortion, principalPoint, focalLength, skew } = useControls({
distortion: { value: new Vector2(0.5, 0.5), min: -1, max: 1, step: 0.001 },
principalPoint: { value: new Vector2(0.0, 0.0), min: -0.5, max: 0.5, step: 0.001 },
focalLength: { value: new Vector2(0.5, 0.5), min: -1, max: 1, step: 0.001 },
skew: { value: 0, min: -1, max: 1, step: 0.001 },
})
</script>

<template>
<TresLeches />

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

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

<Suspense>
<Environment background :blur=".25" preset="modern" />
</Suspense>

<Suspense>
<EffectComposerPmndrs>
<LensDistortionPmndrs
:distortion="distortion.value"
:principalPoint="principalPoint.value"
:focalLength="focalLength.value"
:skew="skew.value"
/>
</EffectComposerPmndrs>
</Suspense>
</TresCanvas>
</template>
61 changes: 61 additions & 0 deletions playground/src/pages/postprocessing/sepia.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<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 { EffectComposerPmndrs, SepiaPmndrs } from '@tresjs/post-processing'
import '@tresjs/leches/styles'
const gl = {
clearColor: '#ffffff',
toneMapping: NoToneMapping,
multisampling: 8,
}
const { intensity, blendFunction } = useControls({
intensity: { value: 2.0, step: 0.1, max: 5.0 },
blendFunction: {
options: Object.keys(BlendFunction).map(key => ({
text: key,
value: BlendFunction[key],
})),
value: BlendFunction.NORMAL,
},
})
</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="black" :roughness=".25" />
</TresMesh>

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

<Suspense>
<Environment background :blur=".5" preset="snow" />
</Suspense>

<Suspense>
<EffectComposerPmndrs>
<SepiaPmndrs :intensity="intensity.value" :blendFunction="Number(blendFunction.value)" />
</EffectComposerPmndrs>
</Suspense>
</TresCanvas>
</template>
121 changes: 121 additions & 0 deletions playground/src/pages/postprocessing/shock-wave.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<script setup lang="ts">
import { ContactShadows, Environment, OrbitControls } from '@tresjs/cientos'
import { TresCanvas } from '@tresjs/core'
import { TresLeches, useControls } from '@tresjs/leches'
import { NoToneMapping, Vector3 } from 'three'
import { DepthPickingPassPmndrs, EffectComposerPmndrs, ShockWavePmndrs } from '@tresjs/post-processing'
import { useMouse, useWindowSize } from '@vueuse/core'
import { computed, ref } from 'vue'
import '@tresjs/leches/styles'
const gl = {
clearColor: '#ffffff',
toneMapping: NoToneMapping,
multisampling: 8,
envMapIntensity: 10,
}
const { x, y } = useMouse()
const { width, height } = useWindowSize()
const shockWaveEffect = ref(null)
const elCanvas = ref(null)
const effectComposerRef = ref(null)
const depthPickingPassRef = ref(null)
const mousePosition = ref(new Vector3())
const { amplitude, waveSize, speed, maxRadius } = useControls({
amplitude: { value: 0.15, step: 0.001, max: 0.25 },
waveSize: { value: 0.3, step: 0.01, max: 2 },
speed: { value: 1.5, step: 0.01, max: 5 },
maxRadius: { value: 1, step: 0.01, max: 3.0 },
})
const cursorX = computed(() => (x.value / width.value) * 2.0 - 1.0)
const cursorY = computed(() => -(y.value / height.value) * 2.0 + 1.0)
async function updateMousePosition() {
if (!elCanvas.value || !shockWaveEffect.value || !depthPickingPassRef.value) { return }
const ndcPosition = new Vector3(cursorX.value, cursorY.value, 0)
ndcPosition.z = await depthPickingPassRef.value.pass.readDepth(ndcPosition)
ndcPosition.z = ndcPosition.z * 2.0 - 1.0
mousePosition.value.copy(ndcPosition.unproject(elCanvas.value.context.camera.value))
}
function triggerShockWave() {
if (!elCanvas.value || !shockWaveEffect.value) { return }
updateMousePosition()
shockWaveEffect.value.effect.explode()
}
</script>

<template>
<TresLeches />

<p class="playground-shock-wave-instructions text-xl font-semibold text-zinc-600">Click on a cube to emit a shock wave.</p>

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

<TresMesh :position="[0, .5, 5]" @click="triggerShockWave">
<TresBoxGeometry :args="[2, 2, 2]" />
<TresMeshPhysicalMaterial color="#82DBC5" :roughness=".25" />
</TresMesh>

<TresMesh :position="[0, 0, 0]" @click="triggerShockWave">
<TresBoxGeometry :args="[2, 2, 2]" />
<TresMeshPhysicalMaterial color="#82DBC5" :roughness=".25" />
</TresMesh>

<TresMesh :position="[0, .5, -5]" @click="triggerShockWave">
<TresBoxGeometry :args="[2, 2, 2]" />
<TresMeshPhysicalMaterial color="#82DBC5" :roughness=".25" />
</TresMesh>

<ContactShadows
:scale="25"
:opacity="1"
:position-y="-1"
:far="20"
/>

<Suspense>
<Environment background :blur=".2" preset="dawn" />
</Suspense>

<Suspense>
<EffectComposerPmndrs ref="effectComposerRef">
<DepthPickingPassPmndrs ref="depthPickingPassRef" />
<ShockWavePmndrs ref="shockWaveEffect" :position="mousePosition" :amplitude="amplitude.value" :waveSize="waveSize.value" :speed="speed.value" :maxRadius="maxRadius.value" />
</EffectComposerPmndrs>
</Suspense>
</TresCanvas>
</template>

<style scoped>
.playground-shock-wave-instructions {
position: absolute;
top: 0;
left: 0;
right: 0;
margin: 0 auto;
padding: 1rem;
text-align: center;
color: #fff;
background: rgba(0, 0, 0, 0.5);
z-index: 2;
}
</style>
90 changes: 90 additions & 0 deletions playground/src/pages/postprocessing/tilt-shift.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<script setup lang="ts">
import { Environment, OrbitControls } from '@tresjs/cientos'
import { TresCanvas } from '@tresjs/core'
import { TresLeches, useControls } from '@tresjs/leches'
import { EffectComposerPmndrs, TiltShiftPmndrs } from '@tresjs/post-processing'
import { BlendFunction, KernelSize, Resolution } from 'postprocessing'
import { NoToneMapping } from 'three'
import '@tresjs/leches/styles'
const gl = {
toneMapping: NoToneMapping,
multisampling: 8,
}
const { blendFunction, offset, rotation, focusArea, feather, kernelSize, resolutionScale, resolutionX, resolutionY } = useControls({
blendFunction: {
options: Object.keys(BlendFunction).map(key => ({
text: key,
value: BlendFunction[key],
})),
value: BlendFunction.NORMAL,
},
offset: { value: 0.0, min: -0.5, max: 0.5, step: 0.01 },
rotation: { value: 0.0, min: -Math.PI, max: Math.PI, step: 0.01 },
focusArea: { value: 0.4, min: 0, max: 1, step: 0.01 },
feather: { value: 0.3, min: 0, max: 1, step: 0.01 },
kernelSize: {
options: Object.keys(KernelSize).map(key => ({
text: key,
value: KernelSize[key],
})),
value: KernelSize.MEDIUM,
},
resolutionScale: { value: 0.5, min: 0.1, max: 1, step: 0.1 },
resolutionX: { value: Resolution.AUTO_SIZE, min: 0, max: 2048, step: 1 },
resolutionY: { value: Resolution.AUTO_SIZE, min: 0, max: 2048, step: 1 },
})
</script>

<template>
<TresLeches />

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

<TresGridHelper :position="[0, -3, 0]" />

<TresMesh :position="[0, 2, 0]">
<TresBoxGeometry :args="[2, 2, 2]" />
<TresMeshPhysicalMaterial color="#FF5733" :roughness="1" :transmission="0" />
</TresMesh>

<TresMesh :position="[0, 0, 0]">
<TresBoxGeometry :args="[2, 2, 2]" />
<TresMeshPhysicalMaterial color="#33FF57" :roughness="1" :transmission="0" />
</TresMesh>

<TresMesh :position="[0, -2, 0]">
<TresBoxGeometry :args="[2, 2, 2]" />
<TresMeshPhysicalMaterial color="#3357FF" :roughness="1" :transmission="0" />
</TresMesh>

<Suspense>
<Environment background :blur=".25" preset="city" />
</Suspense>

<Suspense>
<EffectComposerPmndrs>
<TiltShiftPmndrs
:blendFunction="Number(blendFunction.value)"
:offset="offset.value"
:rotation="rotation.value"
:focusArea="focusArea.value"
:feather="feather.value"
:kernelSize="Number(kernelSize.value)"
:resolutionScale="resolutionScale.value"
:resolutionX="resolutionX.value"
:resolutionY="resolutionY.value"
/>
</EffectComposerPmndrs>
</Suspense>
</TresCanvas>
</template>
77 changes: 77 additions & 0 deletions playground/src/pages/postprocessing/tone-mapping.vue
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 { BlendFunction, ToneMappingMode } from 'postprocessing'
import { NoToneMapping } from 'three'
import { EffectComposerPmndrs, ToneMappingPmndrs } from '@tresjs/post-processing'
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>
<EffectComposerPmndrs>
<ToneMappingPmndrs :mode="Number(mode.value)" :resolution="Number(resolution.value)" :blendFunction="Number(blendFunction.value)" />
</EffectComposerPmndrs>
</Suspense>
</TresCanvas>
</template>
8 changes: 8 additions & 0 deletions playground/src/router.ts
Original file line number Diff line number Diff line change
@@ -33,15 +33,23 @@ export const threeRoutes = [

export const postProcessingRoutes = [
makeRoute('Outline', '🔲', false),
makeRoute('Tone Mapping', '🎨', false),
makeRoute('Glitch', '📺', false),
makeRoute('Depth of Field', '📷', false),
makeRoute('Hue & Saturation', '📷', false),
makeRoute('Tilt Shift', '🔍', false),
makeRoute('Dot Screen', '🔘', false),
makeRoute('Pixelation', '👾', false),
makeRoute('Bloom', '🌼', false),
makeRoute('Noise', '📟', false),
makeRoute('Chromatic Aberration', '🌈', false),
makeRoute('Color Average', '🎞️', false),
makeRoute('Lens Distortion', '🔍', false),
makeRoute('Sepia', '🌅', false),
makeRoute('Scanline', '📺', false),
makeRoute('Shock Wave', '🌊', false),
makeRoute('Vignette', '🕶️', false),
makeRoute('Barrel blur', '🌀', false),
makeRoute('On-demand', '🔄', false),
]

264 changes: 155 additions & 109 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

50 changes: 50 additions & 0 deletions src/core/pmndrs/BarrelBlurPmndrs.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<script lang="ts" setup>
import type { BlendFunction } from 'postprocessing'
import { Vector2 } from 'three'
import { BarrelBlurEffect } from './custom/barrel-blur/index'
import { makePropWatchers } from '../../util/prop'
import { useEffectPmndrs } from './composables/useEffectPmndrs'
export interface BarrelBlurPmndrsProps {
/**
* The blend function for the effect.
* Determines how this effect blends with other effects.
*/
blendFunction?: BlendFunction
/**
* The intensity of the barrel distortion.
* A value between 0 (no distortion) and 1 (maximum distortion).
*/
amount?: number
/**
* The offset of the barrel distortion center.
* A Vector2 value or an A value or an array of two numbers, with both values ranging from 0 to 1.
* This allows you to change the position of the distortion effect.
*/
offset?: Vector2 | [number, number]
}
const props = defineProps<BarrelBlurPmndrsProps>()
const { pass, effect } = useEffectPmndrs(
() => new BarrelBlurEffect({
...props,
offset: Array.isArray(props.offset) ? new Vector2(...props.offset) : props.offset,
}),
props,
)
defineExpose({ pass, effect })
makePropWatchers(
[
[() => props.blendFunction, 'blendMode.blendFunction'],
[() => props.amount, 'amount'],
[() => props.offset, 'offset'],
],
effect,
() => new BarrelBlurEffect(),
)
</script>
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<script lang="ts" setup>
import type { BlendFunction } from 'postprocessing'
import { ChromaticAberrationEffect } from 'postprocessing'
import { Vector2 } from 'three'
import { makePropWatchers } from '../../util/prop'
import { useEffectPmndrs } from './composables/useEffectPmndrs'
import type { Vector2 } from 'three'
import type { BlendFunction } from 'postprocessing'
export interface ChromaticAberrationPmndrsProps {
/**
@@ -30,13 +30,21 @@ export interface ChromaticAberrationPmndrsProps {
const props = withDefaults(
defineProps<ChromaticAberrationPmndrsProps>(),
{
offset: () => new Vector2(0.01, 0.01),
radialModulation: false,
modulationOffset: 0.15,
radialModulation: undefined,
},
)
const { pass, effect } = useEffectPmndrs(() => new ChromaticAberrationEffect(props), props)
const plainEffect = new ChromaticAberrationEffect()
const { pass, effect } = useEffectPmndrs(() => new ChromaticAberrationEffect({
...props,
// Unfortunately, these defaults must be set this way as the type in postprocessing is not correct.
// The arguments are optional in the actual constructor, but not in the type.
radialModulation: props.radialModulation ?? plainEffect.radialModulation,
modulationOffset: props.modulationOffset ?? plainEffect.modulationOffset,
}), props)
plainEffect.dispose()
defineExpose({ pass, effect })
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

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>
31 changes: 31 additions & 0 deletions src/core/pmndrs/DepthPickingPassPmndrs.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<script lang="ts" setup>
import type { DepthPackingStrategies } from 'three'
import { DepthPickingPass } from 'postprocessing'
import { inject, nextTick, onUnmounted } from 'vue'
import { effectComposerInjectionKey } from './EffectComposerPmndrs.vue'
export interface DepthPickingPassPmndrsProps {
depthPacking?: DepthPackingStrategies
mode?: number
}
const props = defineProps<DepthPickingPassPmndrsProps>()
const composer = inject(effectComposerInjectionKey)
const pass = new DepthPickingPass(props)
const unwatch = watchEffect(() => {
if (!composer?.value) { return }
nextTick(() => unwatch())
composer.value.addPass(pass)
})
onUnmounted(() => {
if (!composer?.value || !pass.value) { return }
composer?.value?.removePass(pass.value)
pass.value.dispose()
})
defineExpose({ pass })
</script>
41 changes: 41 additions & 0 deletions src/core/pmndrs/DotScreenPmndrs.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<script lang="ts" setup>
import type { BlendFunction } from 'postprocessing'
import { DotScreenEffect } from 'postprocessing'
import { makePropWatchers } from '../../util/prop'
import { useEffectPmndrs } from './composables/useEffectPmndrs'
export interface DotScreenPmndrsProps {
/**
* The angle of the dot pattern.
* Default: 1.57
*/
angle?: number
/**
* The scale of the dot pattern.
* Default: 1.0
*/
scale?: number
/**
* The blend function. Defines how the effect blends with the original scene.
*/
blendFunction?: BlendFunction
}
const props = defineProps<DotScreenPmndrsProps>()
const { pass, effect } = useEffectPmndrs(() => new DotScreenEffect(props), props)
defineExpose({ pass, effect })
makePropWatchers(
[
[() => props.blendFunction, 'blendMode.blendFunction'],
[() => props.angle, 'angle'],
[() => props.scale, 'scale'],
],
effect,
() => new DotScreenEffect(),
)
</script>
9 changes: 1 addition & 8 deletions src/core/pmndrs/HueSaturationPmndrs.vue
Original file line number Diff line number Diff line change
@@ -21,16 +21,9 @@ export interface HueSaturationPmndrsProps {
* The blend function. Defines how the effect blends with the original scene.
*/
blendFunction?: BlendFunction
}
const props = withDefaults(
defineProps<HueSaturationPmndrsProps>(),
{
saturation: 0.0,
hue: 0.0,
},
)
const props = defineProps<HueSaturationPmndrsProps>()
const { pass, effect } = useEffectPmndrs(() => new HueSaturationEffect(props), props)
48 changes: 48 additions & 0 deletions src/core/pmndrs/LensDistortionPmndrs.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<script lang="ts" setup>
import { LensDistortionEffect } from 'postprocessing'
import { makePropWatchersUsingAllProps } from '../../util/prop'
import { useEffectPmndrs } from './composables/useEffectPmndrs'
import { Vector2 } from 'three'
export interface LensDistortionPmndrsProps {
/**
* The distortion effect strength.
*/
distortion?: Vector2 | [number, number]
/**
* The center point.
*/
principalPoint?: Vector2 | [number, number]
/**
* The focal length.
*/
focalLength?: Vector2 | [number, number]
/**
* The skew value.
*/
skew?: number
}
const props = defineProps<LensDistortionPmndrsProps>()
const { pass, effect } = useEffectPmndrs(
() => new LensDistortionEffect({
...props,
distortion: props.distortion ? (Array.isArray(props.distortion) ? new Vector2(...props.distortion) : props.distortion) : new Vector2(),
principalPoint: props.principalPoint ? (Array.isArray(props.principalPoint) ? new Vector2(...props.principalPoint) : props.principalPoint) : new Vector2(),
focalLength: props.focalLength ? (Array.isArray(props.focalLength) ? new Vector2(...props.focalLength) : props.focalLength) : new Vector2(),
}),
props,
)
defineExpose({ pass, effect })
makePropWatchersUsingAllProps(
props,
effect,
() => new LensDistortionEffect(),
)
</script>
6 changes: 3 additions & 3 deletions src/core/pmndrs/NoisePmndrs.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script lang="ts">
import { useLoop } from '@tresjs/core'
import { BlendFunction, NoiseEffect } from 'postprocessing'
import type { BlendFunction } from 'postprocessing'
import { NoiseEffect } from 'postprocessing'
import { omit } from '../../util/object'
import { makePropWatchersUsingAllProps } from '../../util/prop'
import { useEffectPmndrs } from './composables/useEffectPmndrs'
@@ -16,8 +17,7 @@ export interface NoisePmndrsProps {

<script lang="ts" setup>
const props = withDefaults(defineProps<NoisePmndrsProps>(), {
premultiply: false,
blendFunction: BlendFunction.SCREEN,
premultiply: undefined,
})
const { pass, effect } = useEffectPmndrs(() => new NoiseEffect(props), props)
28 changes: 19 additions & 9 deletions src/core/pmndrs/ScanlinePmndrs.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script lang="ts" setup>
import { watch } from 'vue'
import type { BlendFunction } from 'postprocessing'
import { ScanlineEffect } from 'postprocessing'
import { makePropWatchers } from '../../util/prop'
@@ -26,14 +27,7 @@ export interface ScanlinePmndrsProps {
opacity?: number
}
const props = withDefaults(
defineProps<ScanlinePmndrsProps>(),
{
density: 1.25,
opacity: 1.0,
scrollSpeed: 0.0,
},
)
const props = defineProps<ScanlinePmndrsProps>()
const { pass, effect } = useEffectPmndrs(() => new ScanlineEffect(props), props)
@@ -42,11 +36,27 @@ defineExpose({ pass, effect })
makePropWatchers(
[
[() => props.blendFunction, 'blendMode.blendFunction'],
[() => props.opacity, 'blendMode.opacity.value'],
[() => props.density, 'density'],
[() => props.scrollSpeed, 'scrollSpeed'],
],
effect,
() => new ScanlineEffect(),
)
watch(
[() => props.opacity],
() => {
if (props.opacity !== undefined) {
effect.value?.blendMode.setOpacity(props.opacity)
}
else {
const plainEffect = new ScanlineEffect()
effect.value?.blendMode.setOpacity(plainEffect.blendMode.getOpacity())
plainEffect.dispose()
}
},
{
immediate: true,
},
)
</script>
33 changes: 33 additions & 0 deletions src/core/pmndrs/SepiaPmndrs.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<script lang="ts" setup>
import type { BlendFunction } from 'postprocessing'
import { SepiaEffect } from 'postprocessing'
import { makePropWatchers } from '../../util/prop'
import { useEffectPmndrs } from './composables/useEffectPmndrs'
export interface SepiaPmndrsProps {
/**
* The blend function.
*/
blendFunction?: BlendFunction
/**
* The intensity of the sepia effect.
*/
intensity?: number
}
const props = defineProps<SepiaPmndrsProps>()
const { pass, effect } = useEffectPmndrs(() => new SepiaEffect(props), props)
defineExpose({ pass, effect })
makePropWatchers(
[
[() => props.blendFunction, 'blendMode.blendFunction'],
[() => props.intensity, 'intensity'],
],
effect,
() => new SepiaEffect(),
)
</script>
72 changes: 72 additions & 0 deletions src/core/pmndrs/ShockWavePmndrs.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<script lang="ts" setup>
import { ShockWaveEffect } from 'postprocessing'
import { Vector3 } from 'three'
import { watch } from 'vue'
import { makePropWatchers } from '../../util/prop'
import { useEffectPmndrs } from './composables/useEffectPmndrs'
import { useTresContext } from '@tresjs/core'
export interface ShockWavePmndrsProps {
/**
* The position of the shockwave.
*/
position?: Vector3 | [number, number, number]
/**
* The amplitude of the shockwave.
*/
amplitude?: number
/**
* The speed of the shockwave.
*/
speed?: number
/**
* The max radius of the shockwave.
*/
maxRadius?: number
/**
* The wave size of the shockwave.
*/
waveSize?: number
}
const props = defineProps<ShockWavePmndrsProps>()
const { camera } = useTresContext()
const { pass, effect } = useEffectPmndrs(
() => new ShockWaveEffect(camera.value, Array.isArray(props.position) ? new Vector3(...props.position) : props.position, props),
props,
)
defineExpose({ pass, effect })
watch(
() => props.position,
(newPosition) => {
if (!effect.value) { return }
if (Array.isArray(newPosition)) {
effect.value.position.set(...newPosition)
}
else if (newPosition instanceof Vector3) {
effect.value.position.copy(newPosition)
}
},
{ immediate: true },
)
makePropWatchers(
[
[() => props.amplitude, 'amplitude'],
[() => props.waveSize, 'waveSize'],
[() => props.maxRadius, 'maxRadius'],
[() => props.speed, 'speed'],
],
effect,
() => new ShockWaveEffect(),
)
</script>
80 changes: 80 additions & 0 deletions src/core/pmndrs/TiltShiftPmndrs.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<script lang="ts" setup>
import type { BlendFunction, KernelSize } from 'postprocessing'
import { TiltShiftEffect } from 'postprocessing'
import { makePropWatchers } from '../../util/prop'
import { useEffectPmndrs } from './composables/useEffectPmndrs'
export interface TiltShiftPmndrsProps {
/**
* The blend function. Defines how the effect blends with the original scene.
*/
blendFunction?: BlendFunction
/**
* The relative offset of the focus area.
* Range: [-0.5, 0.5]
*/
offset?: number
/**
* The rotation of the focus area in radians.
* Range: [-π, π]
*/
rotation?: number
/**
* The relative size of the focus area.
* Range: [0, 1]
*/
focusArea?: number
/**
* The softness of the focus area edges.
* Range: [0, 1]
*/
feather?: number
/**
* The blur kernel size.
*/
kernelSize?: KernelSize
/**
* The resolution scale.
* Range: [0.1, 1]
*/
resolutionScale?: number
/**
* The horizontal resolution.
*/
resolutionX?: number
/**
* The vertical resolution.
*/
resolutionY?: number
}
const props = defineProps<TiltShiftPmndrsProps>()
const { pass, effect } = useEffectPmndrs(() => new TiltShiftEffect(props), props)
defineExpose({ pass, effect })
makePropWatchers(
[
[() => props.blendFunction, 'blendMode.blendFunction'],
[() => props.offset, 'offset'],
[() => props.rotation, 'rotation'],
[() => props.focusArea, 'focusArea'],
[() => props.feather, 'feather'],
[() => props.kernelSize, 'kernelSize'],
[() => props.resolutionScale, 'resolution.scale'],
[() => props.resolutionX, 'resolution.width'],
[() => props.resolutionY, 'resolution.height'],
],
effect,
() => new TiltShiftEffect(),
)
</script>
63 changes: 63 additions & 0 deletions src/core/pmndrs/ToneMappingPmndrs.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<script lang="ts" setup>
import type { BlendFunction, ToneMappingMode } from 'postprocessing'
import { ToneMappingEffect } from 'postprocessing'
import { makePropWatchers } from '../../util/prop'
import { useEffectPmndrs } from './composables/useEffectPmndrs'
export interface ToneMappingPmndrsProps {
/**
* 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 = defineProps<ToneMappingPmndrsProps>()
const { pass, effect } = useEffectPmndrs(() => new ToneMappingEffect(props), props)
defineExpose({ pass, effect })
makePropWatchers(
[
[() => props.mode, 'mode'],
[() => props.blendFunction, 'blendMode.blendFunction'],
[() => props.resolution, 'resolution'],
[() => props.averageLuminance, 'averageLuminance'],
[() => props.middleGrey, 'middleGrey'],
[() => props.minLuminance, 'adaptiveLuminanceMaterial.minLuminance'],
[() => props.whitePoint, 'whitePoint'],
],
effect,
() => new ToneMappingEffect(),
)
</script>
14 changes: 5 additions & 9 deletions src/core/pmndrs/VignettePmndrs.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script lang="ts">
import { BlendFunction, VignetteEffect, VignetteTechnique } from 'postprocessing'
import type { BlendFunction, VignetteTechnique } from 'postprocessing'
import { VignetteEffect } from 'postprocessing'
import { omit } from '../../util/object'
import { makePropWatchersUsingAllProps } from '../../util/prop'
import { useEffectPmndrs } from './composables/useEffectPmndrs'
@@ -10,18 +11,13 @@ export interface VignettePmndrsProps {
*/
technique?: VignetteTechnique
blendFunction?: BlendFunction
offset: number
darkness: number
offset?: number
darkness?: number
}
</script>

<script lang="ts" setup>
const props = withDefaults(defineProps<VignettePmndrsProps>(), {
technique: VignetteTechnique.DEFAULT,
blendFunction: BlendFunction.NORMAL,
offset: 0.5,
darkness: 0.5,
})
const props = defineProps<VignettePmndrsProps>()
const { pass, effect } = useEffectPmndrs(() => new VignetteEffect(props), props)
defineExpose({ pass, effect })
100 changes: 100 additions & 0 deletions src/core/pmndrs/custom/barrel-blur/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { Uniform, Vector2 } from 'three'
import { BlendFunction, Effect } from 'postprocessing'

/**
* BarrelBlurEffect - A custom effect for applying a barrel distortion
* with chromatic aberration blur.
*/

export class BarrelBlurEffect extends Effect {
/**
* Creates a new BarrelBlurEffect instance.
*
* @param {object} [options] - Configuration options for the effect.
* @param {BlendFunction} [options.blendFunction] - Blend mode.
* @param {number} [options.amount] - Intensity of the barrel distortion (0 to 1).
* @param {Vector2} [options.offset] - Offset of the barrel distortion center (0 to 1 for both x and y). This allows you to change the position of the distortion effect.
*
*/
constructor({ blendFunction = BlendFunction.NORMAL, amount = 0.15, offset = new Vector2(0.5, 0.5) } = {}) {
super('BarrelBlurEffect', `
uniform float amount;
uniform vec2 offset;
#define NUM_ITER 16
#define RECIP_NUM_ITER 0.0625
#define GAMMA 1.0
vec3 spectrum_offset(float t) {
float lo = step(t, 0.5);
float hi = 1.0 - lo;
float w = 1.0 - abs(2.0 * t - 1.0);
return pow(vec3(lo, 1.0, hi) * vec3(1.0 - w, w, 1.0 - w), vec3(1.0 / GAMMA));
}
vec2 barrelDistortion(vec2 p, float amt) {
p = p - offset;
float theta = atan(p.y, p.x);
float radius = pow(length(p), 1.0 + 3.0 * amt);
return vec2(cos(theta), sin(theta)) * radius + offset;
}
void mainUv(inout vec2 uv) {
uv = barrelDistortion(uv, amount * 0.5);
}
void mainImage(const in vec4 inputColor, const in vec2 uv, out vec4 outputColor) {
vec3 sumcol = vec3(0.0);
vec3 sumw = vec3(0.0);
for (int i = 0; i < NUM_ITER; ++i) {
float t = float(i) * RECIP_NUM_ITER;
vec3 w = spectrum_offset(t);
vec2 distortedUV = barrelDistortion(uv, amount * t);
sumcol += w * texture(inputBuffer, distortedUV).rgb;
sumw += w;
}
vec3 outcol = pow(sumcol / sumw, vec3(1.0 / GAMMA));
outcol = clamp(outcol, 0.0, 1.0); // Ensures normalized color values
outputColor = vec4(outcol, inputColor.a); // Preserves original alpha
}
`, {
blendFunction,
uniforms: new Map<string, Uniform<number | Vector2>>([
['amount', new Uniform(amount)], // Uniform controlling the intensity of distortion
['offset', new Uniform(offset)], // Uniform controlling the offset of distortion
]),
})
}

/**
* The amount.
*
* @type {number}
*/

get amount() {
return this.uniforms.get('amount')?.value
}

set amount(value) {
this.uniforms.get('amount')!.value = value
}

/**
* The offset.
*
* @type {Vector2}
*/

get offset() {
return this.uniforms.get('offset')?.value
}

set offset(value) {
this.uniforms.get('offset')!.value = value
}
}
32 changes: 31 additions & 1 deletion src/core/pmndrs/index.ts
Original file line number Diff line number Diff line change
@@ -9,9 +9,18 @@ import NoisePmndrs, { type NoisePmndrsProps } from './NoisePmndrs.vue'
import OutlinePmndrs, { type OutlinePmndrsProps } from './OutlinePmndrs.vue'
import PixelationPmndrs, { type PixelationPmndrsProps } from './PixelationPmndrs.vue'
import VignettePmndrs, { type VignettePmndrsProps } from './VignettePmndrs.vue'
import ChromaticAberrationPmndrs, { type ChromaticAberrationPmndrsProps } from './ChromaticAberration.vue'
import BarrelBlurPmndrs, { type BarrelBlurPmndrsProps } from './BarrelBlurPmndrs.vue'
import ToneMappingPmndrs, { type ToneMappingPmndrsProps } from './ToneMappingPmndrs.vue'
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'
import TiltShiftPmndrs, { type TiltShiftPmndrsProps } from './TiltShiftPmndrs.vue'
import DotScreenPmndrs, { type DotScreenPmndrsProps } from './DotScreenPmndrs.vue'
import SepiaPmndrs, { type SepiaPmndrsProps } from './SepiaPmndrs.vue'

export {
BloomPmndrs,
@@ -23,9 +32,21 @@ export {
PixelationPmndrs,
useEffectPmndrs,
VignettePmndrs,
BarrelBlurPmndrs,
HueSaturationPmndrs,
ScanlinePmndrs,
ToneMappingPmndrs,
ChromaticAberrationPmndrs,
HueSaturationPmndrs,
ScanlinePmndrs,
ColorAveragePmndrs,
LensDistortionPmndrs,
ShockWavePmndrs,
DepthPickingPassPmndrs,
TiltShiftPmndrs,
DotScreenPmndrs,
SepiaPmndrs,

BloomPmndrsProps,
DepthOfFieldPmndrsProps,
EffectComposerPmndrsProps,
@@ -34,7 +55,16 @@ export {
OutlinePmndrsProps,
PixelationPmndrsProps,
VignettePmndrsProps,
BarrelBlurPmndrsProps,
ToneMappingPmndrsProps,
ChromaticAberrationPmndrsProps,
HueSaturationPmndrsProps,
ScanlinePmndrsProps,
ColorAveragePmndrsProps,
LensDistortionPmndrsProps,
ShockWavePmndrsProps,
DepthPickingPassPmndrsProps,
TiltShiftPmndrsProps,
DotScreenPmndrsProps,
SepiaPmndrsProps,
}