Skip to content

Commit eafe305

Browse files
feat: god rays (#187)
* migrate to new tresleches, change devDependencies package.json file * add todo next commit * lint * try floa false leches * refactor: improve BarrelBlurDemo component layout and styling * leches floatg * add effect godrays playground * add doc god-rays * review: fix --------- Co-authored-by: alvarosabu <[email protected]> Co-authored-by: Tino Koch <>
1 parent cf4aad2 commit eafe305

File tree

8 files changed

+444
-0
lines changed

8 files changed

+444
-0
lines changed

docs/.vitepress/config.ts

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export default defineConfig({
5555
{ text: 'Color Depth', link: '/guide/pmndrs/color-depth' },
5656
{ text: 'Linocut', link: '/guide/pmndrs/linocut' },
5757
{ text: 'Sepia', link: '/guide/pmndrs/sepia' },
58+
{ text: 'God Rays', link: '/guide/pmndrs/god-rays' },
5859
{ text: 'Brightness Contrast', link: '/guide/pmndrs/brightness-contrast' },
5960
{ text: 'Vignette', link: '/guide/pmndrs/vignette' },
6061
{ text: 'Hue & Saturation', link: '/guide/pmndrs/hue-saturation' },
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
<script setup lang="ts">
2+
import { Environment, OrbitControls } from '@tresjs/cientos'
3+
import { TresCanvas, useTexture } from '@tresjs/core'
4+
import { TresLeches, useControls } from '@tresjs/leches'
5+
import type { Mesh } from 'three'
6+
import { BackSide, NoToneMapping } from 'three'
7+
import { BlendFunction, KernelSize } from 'postprocessing'
8+
import { EffectComposerPmndrs, GodRaysPmndrs } from '@tresjs/post-processing'
9+
import { ref, watch } from 'vue'
10+
import { gsap } from 'gsap'
11+
12+
import '@tresjs/leches/styles'
13+
14+
const gl = {
15+
toneMapping: NoToneMapping,
16+
multisampling: 8,
17+
}
18+
19+
const sphereMeshRef = ref<Mesh | null>(null)
20+
21+
const pbrTexture = await useTexture({
22+
map: '/lens-distortion/room-map.png',
23+
})
24+
25+
const { blur, kernelSize, resolutionScale, opacity, blendFunction, density, decay, weight, exposure, samples, clampMax } = useControls({
26+
blendFunction: {
27+
options: Object.keys(BlendFunction).map(key => ({
28+
text: key,
29+
value: BlendFunction[key as keyof typeof BlendFunction],
30+
})),
31+
value: BlendFunction.SCREEN,
32+
},
33+
kernelSize: {
34+
options: Object.keys(KernelSize).map(key => ({
35+
text: key,
36+
value: KernelSize[key as keyof typeof KernelSize],
37+
})),
38+
value: KernelSize.SMALL,
39+
},
40+
opacity: { value: 1, step: 0.01, min: 0, max: 1.0 },
41+
density: { value: 0.96, step: 0.01, min: 0, max: 1.0 },
42+
decay: { value: 0.93, step: 0.01, min: 0, max: 1.0 },
43+
weight: { value: 0.4, step: 0.1, min: 0, max: 1.0 },
44+
exposure: { value: 0.6, step: 0.1, min: 0, max: 1.0 },
45+
samples: { value: 60, step: 1, min: 15, max: 200 },
46+
clampMax: { value: 1.0, step: 0.1, max: 1.0 },
47+
resolutionScale: { value: 0.5, step: 0.1, min: 0.1, max: 1.0 },
48+
blur: true,
49+
})
50+
51+
const torusMeshes = [
52+
{ rotationY: Math.PI / 2, position: [-10, 2, 0], roughness: 0.1, color: '#82DBC5' },
53+
{ rotationY: Math.PI / 2, position: [0, 2, 0], roughness: 0.3, color: '#505050' },
54+
{ rotationY: Math.PI / 2, position: [10, 2, 0], roughness: 0.65, color: '#FC7BAC' },
55+
]
56+
57+
watch(sphereMeshRef, () => {
58+
if (!sphereMeshRef.value) { return }
59+
60+
gsap.to(sphereMeshRef.value.position, {
61+
x: 20,
62+
duration: 3,
63+
repeat: -1,
64+
yoyo: true,
65+
ease: 'sine.inOut',
66+
})
67+
})
68+
</script>
69+
70+
<template>
71+
<div class="aspect-16/9">
72+
<TresCanvas
73+
v-bind="gl"
74+
>
75+
<TresPerspectiveCamera
76+
:position="[0, 5, 35]"
77+
:look-at="[0, 0, 0]"
78+
/>
79+
<OrbitControls auto-rotate />
80+
81+
<TresMesh ref="sphereMeshRef" :position="[-20, 2, 0]">
82+
<TresSphereGeometry :args="[2, 32, 32]" />
83+
<TresMeshBasicMaterial color="#FFDDAA" :transparent="true" />
84+
</TresMesh>
85+
86+
<template v-for="(mesh) in torusMeshes" :key="`demo-god-rays-${mesh.color}`">
87+
<TresMesh :rotation-y="mesh.rotationY" :position="mesh.position">
88+
<TresTorusGeometry :args="[5, 2, 16, 100]" />
89+
<TresMeshPhysicalMaterial :roughness="mesh.roughness" :color="`${mesh.color}`" />
90+
</TresMesh>
91+
</template>
92+
93+
<TresMesh :position="[0, 2, 0]">
94+
<TresBoxGeometry :args="[50, 50, 50]" />
95+
<TresMeshStandardMaterial :side="BackSide" :map="pbrTexture.map" />
96+
</TresMesh>
97+
98+
<Suspense>
99+
<Environment preset="shangai" />
100+
</Suspense>
101+
102+
<Suspense>
103+
<EffectComposerPmndrs>
104+
<GodRaysPmndrs
105+
:opacity="opacity"
106+
:lightSource="sphereMeshRef"
107+
:blendFunction="Number(blendFunction)"
108+
:density="density"
109+
:decay="decay"
110+
:weight="weight"
111+
:exposure="exposure"
112+
:samples="samples"
113+
:clampMax="clampMax"
114+
:resolutionScale="resolutionScale"
115+
:kernelSize="kernelSize"
116+
:blur="blur"
117+
/>
118+
</EffectComposerPmndrs>
119+
</Suspense>
120+
</TresCanvas>
121+
</div>
122+
123+
<TresLeches :float="false" />
124+
</template>

docs/components.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ declare module 'vue' {
2323
FishEyeDemo: typeof import('./.vitepress/theme/components/pmdrs/FishEyeDemo.vue')['default']
2424
GlitchDemo: typeof import('./.vitepress/theme/components/pmdrs/GlitchDemo.vue')['default']
2525
GlitchThreeDemo: typeof import('./.vitepress/theme/components/three/GlitchThreeDemo.vue')['default']
26+
GodRaysDemo: typeof import('./.vitepress/theme/components/pmdrs/GodRaysDemo.vue')['default']
2627
GridDemo: typeof import('./.vitepress/theme/components/pmdrs/GridDemo.vue')['default']
2728
HalftoneThreeDemo: typeof import('./.vitepress/theme/components/three/HalftoneThreeDemo.vue')['default']
2829
HueSaturation: typeof import('./.vitepress/theme/components/pmdrs/HueSaturationDemo.vue')['default']

docs/guide/pmndrs/god-rays.md

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# God Rays
2+
3+
<DocsDemoGUI>
4+
<GodRaysDemo />
5+
</DocsDemoGUI>
6+
7+
<details>
8+
<summary>Demo code</summary>
9+
10+
<<< @/.vitepress/theme/components/pmdrs/GodRaysDemo.vue{0}
11+
</details>
12+
13+
The `GodRays` effect is part of the [`postprocessing`](https://pmndrs.github.io/postprocessing/public/docs/class/src/effects/GodRaysEffect.js~GodRaysEffect.html) package. It simulates the appearance of light rays shining through objects, creating a volumetric lighting effect. This effect can enhance the visual appeal of your scene by adding a dramatic and realistic lighting effect.
14+
15+
## Usage
16+
17+
The `<GodRaysPmndrs>` component is easy to use and provides customizable options to suit different visual styles.
18+
19+
```vue{5,17-21,40-44}
20+
<script setup lang="ts">
21+
import { OrbitControls } from '@tresjs/cientos'
22+
import { TresCanvas } from '@tresjs/core'
23+
import { NoToneMapping } from 'three'
24+
import { EffectComposerPmndrs, GodRaysPmndrs } from '@tresjs/post-processing'
25+
26+
import '@tresjs/leches/styles'
27+
28+
const gl = {
29+
clearColor: 'blue',
30+
toneMapping: NoToneMapping,
31+
multisampling: 8,
32+
}
33+
34+
const sphereMeshRef = ref(null)
35+
36+
const effectProps = reactive({
37+
opacity: .8,
38+
exposure: .8,
39+
resolutionScale: 0.65
40+
})
41+
</script>
42+
43+
<template>
44+
<TresCanvas v-bind="gl">
45+
<TresPerspectiveCamera :position="[0, 5, 20]" />
46+
47+
<OrbitControls auto-rotate />
48+
49+
<TresMesh ref="sphereMeshRef" :position="[-10, 8, 0]">
50+
<TresSphereGeometry :args="[2, 32, 32]" />
51+
<TresMeshBasicMaterial color="#FFDDAA" :transparent="true" />
52+
</TresMesh>
53+
54+
<TresMesh :position="[0, .5, 0]">
55+
<TresBoxGeometry :args="[2, 2, 2]" />
56+
<TresMeshBasicMaterial color="white" />
57+
</TresMesh>
58+
59+
<Suspense>
60+
<EffectComposerPmndrs>
61+
<GodRaysPmndrs :lightSource="sphereMeshRef" v-bind="effectProps" />
62+
</EffectComposerPmndrs>
63+
</Suspense>
64+
</TresCanvas>
65+
</template>
66+
```
67+
68+
## Props
69+
70+
| Prop | Description | Default |
71+
| ----------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------- |
72+
| 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.SCREEN` |
73+
| lightSource | The light source. Must not write depth and has to be flagged as transparent. <br> This can be a [`Mesh`](https://threejs.org/docs/index.html#api/en/objects/Mesh) or a [`Points`](https://threejs.org/docs/#api/en/objects/Points). | `undefined` |
74+
| opacity | The opacity of the God Rays. | `1.0` |
75+
| density | The density of the light rays. | `0.96` |
76+
| decay | The decay of the light rays. | `0.9` |
77+
| kernelSize | The blur kernel size. <br> Has no effect if `blur` props is disabled. <br> See the [`KernelSize`](https://pmndrs.github.io/postprocessing/public/docs/variable/index.html#static-variable-KernelSize) options. | `KernelSize.SMALL` |
78+
| resolutionScale | The resolution scale. | `0.5` |
79+
| blur | Whether the god rays should be blurred to reduce artifacts. | `true` |
80+
| resolutionX | The horizontal resolution. | `Resolution.AUTO_SIZE` |
81+
| resolutionY | The vertical resolution. | `Resolution.AUTO_SIZE` |
82+
| weight | The weight of the light rays. | `0.4` |
83+
| exposure | A constant attenuation coefficient. | `0.6` |
84+
| samples | The number of samples per pixel. | `60` |
85+
| clampMax | An upper bound for the saturation of the overall effect. | `1.0` |
86+
87+
## Further Reading
88+
For more details, see the [GodRays documentation](https://pmndrs.github.io/postprocessing/public/docs/class/src/effects/GodRaysEffect.js~GodRaysEffect.html)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
<script setup lang="ts">
2+
import { OrbitControls } from '@tresjs/cientos'
3+
import { TresCanvas } from '@tresjs/core'
4+
import { TresLeches, useControls } from '@tresjs/leches'
5+
import { NoToneMapping } from 'three'
6+
import { BlendFunction, KernelSize, Resolution } from 'postprocessing'
7+
import { EffectComposerPmndrs, GodRaysPmndrs } from '@tresjs/post-processing'
8+
9+
import '@tresjs/leches/styles'
10+
11+
const gl = {
12+
clearColor: 'blue',
13+
toneMapping: NoToneMapping,
14+
multisampling: 8,
15+
}
16+
17+
const boxMeshRef = ref(null)
18+
const sphereMeshRef = ref(null)
19+
20+
const { blur, kernelSize, resolutionX, resolutionY, resolutionScale, opacity, blendFunction, density, decay, weight, exposure, samples, clampMax } = useControls({
21+
blendFunction: {
22+
options: Object.keys(BlendFunction).map(key => ({
23+
text: key,
24+
value: BlendFunction[key as keyof typeof BlendFunction],
25+
})),
26+
value: BlendFunction.SCREEN,
27+
},
28+
kernelSize: {
29+
options: Object.keys(KernelSize).map(key => ({
30+
text: key,
31+
value: KernelSize[key as keyof typeof KernelSize],
32+
})),
33+
value: KernelSize.SMALL,
34+
},
35+
resolutionX: {
36+
options: [Resolution.AUTO_SIZE, 240, 360, 480, 720, 1080],
37+
value: Resolution.AUTO_SIZE,
38+
},
39+
resolutionY: {
40+
options: [Resolution.AUTO_SIZE, 240, 360, 480, 720, 1080],
41+
value: Resolution.AUTO_SIZE,
42+
},
43+
opacity: { value: 1, step: 0.01, min: 0, max: 1.0 },
44+
density: { value: 0.96, step: 0.01, min: 0, max: 1.0 },
45+
decay: { value: 0.93, step: 0.01, min: 0, max: 1.0 },
46+
weight: { value: 0.4, step: 0.1, min: 0, max: 1.0 },
47+
exposure: { value: 0.6, step: 0.1, min: 0, max: 1.0 },
48+
samples: { value: 60, step: 1, min: 15, max: 200 },
49+
clampMax: { value: 1.0, step: 0.1, max: 1.0 },
50+
resolutionScale: { value: 0.5, step: 0.1, min: 0.1, max: 1.0 },
51+
blur: true,
52+
})
53+
</script>
54+
55+
<template>
56+
<TresLeches />
57+
58+
<TresCanvas
59+
v-bind="gl"
60+
>
61+
<TresPerspectiveCamera
62+
:position="[0, 5, 20]"
63+
:look-at="[0, 0, 0]"
64+
/>
65+
<OrbitControls auto-rotate />
66+
67+
<TresMesh ref="sphereMeshRef" :position="[-10, 8, 0]">
68+
<TresSphereGeometry :args="[2, 32, 32]" />
69+
<TresMeshBasicMaterial color="#FFDDAA" />
70+
</TresMesh>
71+
72+
<TresMesh ref="boxMeshRef" :position="[0, .5, 0]">
73+
<TresBoxGeometry :args="[2, 2, 2]" />
74+
<TresMeshBasicMaterial color="white" />
75+
</TresMesh>
76+
77+
<Suspense>
78+
<EffectComposerPmndrs>
79+
<GodRaysPmndrs
80+
:opacity="opacity"
81+
:lightSource="sphereMeshRef"
82+
:blendFunction="Number(blendFunction)"
83+
:density="density"
84+
:decay="decay"
85+
:weight="weight"
86+
:exposure="exposure"
87+
:samples="samples"
88+
:clampMax="clampMax"
89+
:resolutionScale="resolutionScale"
90+
:resolutionX="Number(resolutionX)"
91+
:resolutionY="Number(resolutionY)"
92+
:kernelSize="kernelSize"
93+
:blur="blur"
94+
/>
95+
</EffectComposerPmndrs>
96+
</Suspense>
97+
</TresCanvas>
98+
</template>

playground/src/router.ts

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ export const postProcessingRoutes = [
4848
makeRoute('Color Average', '🎞️', false),
4949
makeRoute('Lens Distortion', '🌐', false),
5050
makeRoute('Sepia', '🌅', false),
51+
makeRoute('God Rays', '🌞', false),
5152
makeRoute('Scanline', '📽️', false),
5253
makeRoute('Color Depth', '🔳', false),
5354
makeRoute('Grid', '#️⃣', false),

0 commit comments

Comments
 (0)