Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add clear and preload function to useEnvironment #2079

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions README.md
AaronClaes marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,24 @@ https://pmndrs.github.io/drei

[Documentation has moved here](https://pmndrs.github.io/drei/staging/use-environment)

In order to preload you do this:

```jsx
useEnvironment.preload({ preset: 'city' })
useEnvironment.preload({ files: 'model.hdr' })
useEnvironment.preload({ files: ['px', 'nx', 'py', 'ny', 'pz', 'nz'].map((n) => `${n}.png`) })
```

Keep in mind that preloading [gainmaps](https://github.com/MONOGRID/gainmap-js) is not possible, because their loader requires access to the renderer.

You can also clear your environment map from the cache:

```jsx
useEnvironment.clear({ preset: 'city' })
useEnvironment.clear({ files: 'model.hdr' })
useEnvironment.clear({ files: ['px', 'nx', 'py', 'ny', 'pz', 'nz'].map((n) => `${n}.png`) })
```

#### MatcapTexture / useMatcapTexture

[Documentation has moved here](https://pmndrs.github.io/drei/staging/matcap-texture-use-matcap-texture)
Expand Down
150 changes: 119 additions & 31 deletions src/core/useEnvironment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ export type EnvironmentLoaderProps = {
encoding?: TextureEncoding
}

const defaultFiles = ['/px.png', '/nx.png', '/py.png', '/ny.png', '/pz.png', '/nz.png']

export function useEnvironment({
files = ['/px.png', '/nx.png', '/py.png', '/ny.png', '/pz.png', '/nz.png'],
files = defaultFiles,
path = '',
preset = undefined,
encoding = undefined,
Expand All @@ -35,41 +37,17 @@ export function useEnvironment({
let multiFile: boolean = false

if (preset) {
if (!(preset in presetsObj)) throw new Error('Preset must be one of: ' + Object.keys(presetsObj).join(', '))
validatePreset(preset)
files = presetsObj[preset]
path = CUBEMAP_ROOT
}

const isCubemap = isArray(files) && files.length === 6
const isGainmap = isArray(files) && files.length === 3 && files.some((file) => file.endsWith('json'))
const firstEntry = isArray(files) ? files[0] : files

// Everything else
multiFile = isArray(files)
const extension: string | false | undefined = isCubemap
? 'cube'
: isGainmap
? 'webp'
: firstEntry.startsWith('data:application/exr')
? 'exr'
: firstEntry.startsWith('data:application/hdr')
? 'hdr'
: firstEntry.startsWith('data:image/jpeg')
? 'jpg'
: firstEntry.split('.').pop()?.split('?')?.shift()?.toLowerCase()
loader =
extension === 'cube'
? CubeTextureLoader
: extension === 'hdr'
? RGBELoader
: extension === 'exr'
? EXRLoader
: extension === 'jpg' || extension === 'jpeg'
? (HDRJPGLoader as unknown as typeof Loader)
: extension === 'webp'
? (GainMapLoader as unknown as typeof Loader)
: null

const { extension, isCubemap } = getExtension(files)

loader = getLoader(extension)
if (!loader) throw new Error('useEnvironment: Unrecognized file extension: ' + files)

const gl = useThree((state) => state.gl)
Expand All @@ -79,8 +57,11 @@ export function useEnvironment({
if (extension !== 'webp' && extension !== 'jpg' && extension !== 'jpeg') return

function clearGainmapTexture() {
// @ts-expect-error
useLoader.clear(loader, multiFile ? [files] : files)
useLoader.clear(
// @ts-expect-error
loader,
multiFile ? [files] : files
)
}

gl.domElement.addEventListener('webglcontextlost', clearGainmapTexture, { once: true })
Expand Down Expand Up @@ -115,3 +96,110 @@ export function useEnvironment({

return texture
}

type EnvironmentLoaderPreloadOptions = Omit<EnvironmentLoaderProps, 'encoding'>
const preloadDefaultOptions = {
files: defaultFiles,
path: '',
preset: undefined,
extensions: undefined,
}

useEnvironment.preload = (preloadOptions?: EnvironmentLoaderPreloadOptions) => {
const options = { ...preloadDefaultOptions, ...preloadOptions }
let { files, path = '' } = options
const { preset, extensions } = options

if (preset) {
validatePreset(preset)
files = presetsObj[preset]
path = CUBEMAP_ROOT
}

const { extension } = getExtension(files)

if (extension === 'webp' || extension === 'jpg' || extension === 'jpeg') {
throw new Error('useEnvironment: Preloading gainmaps is not supported')
}

const loader = getLoader(extension)
if (!loader) throw new Error('useEnvironment: Unrecognized file extension: ' + files)

useLoader.preload(
// @ts-expect-error
loader,
isArray(files) ? [files] : files,
(loader) => {
loader.setPath?.(path)
if (extensions) extensions(loader)
}
)
}

type EnvironmentLoaderClearOptions = Pick<EnvironmentLoaderProps, 'files' | 'preset'>
const clearDefaultOptins = {
files: defaultFiles,
preset: undefined,
}

useEnvironment.clear = (clearOptions?: EnvironmentLoaderClearOptions) => {
const options = { ...clearDefaultOptins, ...clearOptions }
let { files } = options
const { preset } = options

if (preset) {
validatePreset(preset)
files = presetsObj[preset]
}

const { extension } = getExtension(files)
const loader = getLoader(extension)
if (!loader) throw new Error('useEnvironment: Unrecognized file extension: ' + files)
useLoader.clear(
// @ts-expect-error
loader,
isArray(files) ? [files] : files
)
}

function validatePreset(preset: string) {
if (!(preset in presetsObj)) throw new Error('Preset must be one of: ' + Object.keys(presetsObj).join(', '))
}

function getExtension(files: string | string[]) {
const isCubemap = isArray(files) && files.length === 6
const isGainmap = isArray(files) && files.length === 3 && files.some((file) => file.endsWith('json'))
const firstEntry = isArray(files) ? files[0] : files

// Everything else
const extension: string | false | undefined = isCubemap
? 'cube'
: isGainmap
? 'webp'
: firstEntry.startsWith('data:application/exr')
? 'exr'
: firstEntry.startsWith('data:application/hdr')
? 'hdr'
: firstEntry.startsWith('data:image/jpeg')
? 'jpg'
: firstEntry.split('.').pop()?.split('?')?.shift()?.toLowerCase()

return { extension, isCubemap, isGainmap }
}

function getLoader(extension: string | undefined) {
const loader: typeof Loader | null =
extension === 'cube'
? CubeTextureLoader
: extension === 'hdr'
? RGBELoader
: extension === 'exr'
? EXRLoader
: extension === 'jpg' || extension === 'jpeg'
? (HDRJPGLoader as unknown as typeof Loader)
: extension === 'webp'
? (GainMapLoader as unknown as typeof Loader)
: null

return loader
}