Skip to content

God Rays

Demo code
vue
<script setup lang="ts">
import { Environment, OrbitControls } from '@tresjs/cientos'
import { TresCanvas, useTexture } from '@tresjs/core'
import { TresLeches, useControls } from '@tresjs/leches'
import type { Mesh } from 'three'
import { BackSide, NoToneMapping } from 'three'
import { BlendFunction, KernelSize } from 'postprocessing'
import { EffectComposerPmndrs, GodRaysPmndrs } from '@tresjs/post-processing'
import { ref, watch } from 'vue'
import { gsap } from 'gsap'

import '@tresjs/leches/styles'

const gl = {
  toneMapping: NoToneMapping,
  multisampling: 8,
}

const sphereMeshRef = ref<Mesh | null>(null)

const pbrTexture = await useTexture({
  map: '/lens-distortion/room-map.png',
})

const { blur, kernelSize, resolutionScale, opacity, blendFunction, density, decay, weight, exposure, samples, clampMax } = useControls({
  blendFunction: {
    options: Object.keys(BlendFunction).map(key => ({
      text: key,
      value: BlendFunction[key as keyof typeof BlendFunction],
    })),
    value: BlendFunction.SCREEN,
  },
  kernelSize: {
    options: Object.keys(KernelSize).map(key => ({
      text: key,
      value: KernelSize[key as keyof typeof KernelSize],
    })),
    value: KernelSize.SMALL,
  },
  opacity: { value: 1, step: 0.01, min: 0, max: 1.0 },
  density: { value: 0.96, step: 0.01, min: 0, max: 1.0 },
  decay: { value: 0.93, step: 0.01, min: 0, max: 1.0 },
  weight: { value: 0.4, step: 0.1, min: 0, max: 1.0 },
  exposure: { value: 0.6, step: 0.1, min: 0, max: 1.0 },
  samples: { value: 60, step: 1, min: 15, max: 200 },
  clampMax: { value: 1.0, step: 0.1, max: 1.0 },
  resolutionScale: { value: 0.5, step: 0.1, min: 0.1, max: 1.0 },
  blur: true,
})

const torusMeshes = [
  { rotationY: Math.PI / 2, position: [-10, 2, 0], roughness: 0.1, color: '#82DBC5' },
  { rotationY: Math.PI / 2, position: [0, 2, 0], roughness: 0.3, color: '#505050' },
  { rotationY: Math.PI / 2, position: [10, 2, 0], roughness: 0.65, color: '#FC7BAC' },
]

watch(sphereMeshRef, () => {
  if (!sphereMeshRef.value) { return }

  gsap.to(sphereMeshRef.value.position, {
    x: 20,
    duration: 3,
    repeat: -1,
    yoyo: true,
    ease: 'sine.inOut',
  })
})
</script>

<template>
  <div class="aspect-16/9">
    <TresCanvas
      v-bind="gl"
    >
      <TresPerspectiveCamera
        :position="[0, 5, 35]"
        :look-at="[0, 0, 0]"
      />
      <OrbitControls auto-rotate />

      <TresMesh ref="sphereMeshRef" :position="[-20, 2, 0]">
        <TresSphereGeometry :args="[2, 32, 32]" />
        <TresMeshBasicMaterial color="#FFDDAA" :transparent="true" />
      </TresMesh>

      <template v-for="(mesh) in torusMeshes" :key="`demo-god-rays-${mesh.color}`">
        <TresMesh :rotation-y="mesh.rotationY" :position="mesh.position">
          <TresTorusGeometry :args="[5, 2, 16, 100]" />
          <TresMeshPhysicalMaterial :roughness="mesh.roughness" :color="`${mesh.color}`" />
        </TresMesh>
      </template>

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

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

      <Suspense>
        <EffectComposerPmndrs>
          <GodRaysPmndrs
            :opacity="opacity"
            :lightSource="sphereMeshRef"
            :blendFunction="Number(blendFunction)"
            :density="density"
            :decay="decay"
            :weight="weight"
            :exposure="exposure"
            :samples="samples"
            :clampMax="clampMax"
            :resolutionScale="resolutionScale"
            :kernelSize="kernelSize"
            :blur="blur"
          />
        </EffectComposerPmndrs>
      </Suspense>
    </TresCanvas>
  </div>

  <TresLeches :float="false" />
</template>

The GodRays effect is part of the postprocessing 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.

Usage

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

vue
<script setup lang="ts">
import { OrbitControls } from '@tresjs/cientos'
import { TresCanvas } from '@tresjs/core'
import { NoToneMapping } from 'three'
import { EffectComposerPmndrs, GodRaysPmndrs } from '@tresjs/post-processing'

import '@tresjs/leches/styles'

const gl = {
  clearColor: 'blue',
  toneMapping: NoToneMapping,
  multisampling: 8,
}

const sphereMeshRef = ref(null)

const effectProps = reactive({
  opacity: .8,
  exposure: .8,
  resolutionScale: 0.65
})
</script>

<template>
  <TresCanvas v-bind="gl">
    <TresPerspectiveCamera :position="[0, 5, 20]" />

    <OrbitControls auto-rotate />

    <TresMesh ref="sphereMeshRef" :position="[-10, 8, 0]">
      <TresSphereGeometry :args="[2, 32, 32]" />
      <TresMeshBasicMaterial color="#FFDDAA" :transparent="true" />
    </TresMesh>

    <TresMesh :position="[0, .5, 0]">
      <TresBoxGeometry :args="[2, 2, 2]" />
      <TresMeshBasicMaterial color="white" />
    </TresMesh>

    <Suspense>
      <EffectComposerPmndrs>
        <GodRaysPmndrs :lightSource="sphereMeshRef" v-bind="effectProps" />
      </EffectComposerPmndrs>
    </Suspense>
  </TresCanvas>
</template>

Props

PropDescriptionDefault
blendFunctionDefines how the effect blends with the original scene. See the BlendFunction options.BlendFunction.SCREEN
lightSourceThe light source. Must not write depth and has to be flagged as transparent.
This can be a Mesh or a Points.
undefined
opacityThe opacity of the God Rays.1.0
densityThe density of the light rays.0.96
decayThe decay of the light rays.0.9
kernelSizeThe blur kernel size.
Has no effect if blur props is disabled.
See the KernelSize options.
KernelSize.SMALL
resolutionScaleThe resolution scale.0.5
blurWhether the god rays should be blurred to reduce artifacts.true
resolutionXThe horizontal resolution.Resolution.AUTO_SIZE
resolutionYThe vertical resolution.Resolution.AUTO_SIZE
weightThe weight of the light rays.0.4
exposureA constant attenuation coefficient.0.6
samplesThe number of samples per pixel.60
clampMaxAn upper bound for the saturation of the overall effect.1.0

Further Reading

For more details, see the GodRays documentation