@threlte/extras
<VirtualEnvironment>
<script>
import { Canvas } from '@threlte/core'
import Scene from './Scene.svelte'
import { Checkbox, Pane } from 'svelte-tweakpane-ui'
let debug = $state(true)
</script>
<Pane
title="Virtual Environment"
position="fixed"
>
<Checkbox
bind:value={debug}
label="debug"
/>
</Pane>
<div>
<Canvas>
<Scene {debug} />
</Canvas>
</div>
<style>
div {
background-color: black;
width: 100%;
height: 100%;
}
</style>
<VirtualEnvironment>
allows you to create dynamic environment maps which can
be used to light your scene and adjust reflections on your scene’s objects.
It uses a cube camera to create a cubemap of its contents and applies that
cubemap texture to the scene’s environment. <VirtualEnvironment>
internally
creates a new scene to render the virtual environment into. The contents of
<VirtualEnvironment>
may be mounted and made visible by setting the visible
prop to true
.
Controlling Updates
By default, the cube camera updates and renders to its render target every
frame. The frames
prop is used to control the amount of updates that occur. If
your virtual scene is static, you may only need the cube camera to update once.
You can achieve this by settings frames
to 1
:
<VirtualEnvironment frames={1} />
This will cause the cube camera to update once and then stop its update task. If
you ever need to restart the task, a restart
function is available as a
component export and through the children
snippet.
<script>
let virtualEnvironment = $state()
$effect(() => {
// yourDependencyHere
virtualEnvironment?.restart()
})
</script>
<VirtualEnvironment
frames={1}
bind:this={virtualEnvironment}
/>
<script>
let meshInScene = $state(true)
</script>
<VirtualEnvironment
frames={1}
bind:this={virtualEnvironment}
>
{#snippet children({ restart })}
{#if meshInScene}
<T.Mesh>
<T.PlaneGeometry />
</T.Mesh>
{/if}
{/snippet}
</VirtualEnvironment>
Manual Updates
For cases where you want full control over when the render target is updated,
use the update
function available as a component export and through the
children
snippet.
If you use the update
function, be sure to set frames
to 0
to prevent the internal update
task from starting automatically.
As a Component Export
<script>
let virtualEnvironment = $state()
$effect(() => {
// …
virtualEnvironment?.update()
})
</script>
<VirtualEnvironment
frames={0}
bind:this={virtualEnvironment}
>
<!-- Your scene contents here -->
</VirtualEnvironment>
Through Children Snippet
<VirtualEnvironment frames={0}>
{#snippet children({ update })}
<T.Mesh
oncreate={() => {
update()
}}
>
<T.PlaneGeometry />
</T.Mesh>
{/snippet}
</VirtualEnvironment>
The example below is the same as the one above but it only updates the cube camera’s render target when the light formers are updated instead of every frame.
<script>
import { Canvas } from '@threlte/core'
import Scene from './Scene.svelte'
</script>
<div>
<Canvas>
<Scene />
</Canvas>
</div>
<style>
div {
background-color: black;
width: 100%;
height: 100%;
}
</style>
Mixing Virtual and Real Environments
You can also mix <VirtualEnvironment>
with <Environment>
or
<CubeEnvironment>
to create a mix of “real” and virtual environments.
<VirtualEnvironment>
<Environment
url="…"
isBackground
/>
<T.Mesh>
<T.PlaneGeometry />
</T.Mesh>
</VirtualEnvironment>
<script>
import { Canvas } from '@threlte/core'
import Scene from './Scene.svelte'
import { Checkbox, Pane } from 'svelte-tweakpane-ui'
import { Suspense } from '@threlte/extras'
let debug = $state(true)
let mixEnvironment = $state(true)
</script>
<Pane
title="Virtual Environment"
position="fixed"
>
<Checkbox
bind:value={debug}
label="debug"
/>
<Checkbox
bind:value={mixEnvironment}
label="Mix Environment Map"
/>
</Pane>
<div>
<Canvas>
<Scene
{debug}
{mixEnvironment}
/>
</Canvas>
</div>
<style>
div {
background-color: black;
width: 100%;
height: 100%;
}
</style>