/
useTexture.tsx
32 lines (27 loc) 路 1.31 KB
/
useTexture.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import { Texture, TextureLoader } from 'three'
import { useLoader, useThree } from '@react-three/fiber'
import { useEffect } from 'react'
export const IsObject = (url: any): url is Record<string, string> =>
url === Object(url) && !Array.isArray(url) && typeof url !== 'function'
export function useTexture<Url extends string[] | string | Record<string, string>>(
input: Url
): Url extends any[] ? Texture[] : Url extends object ? { [key in keyof Url]: Texture } : Texture {
const gl = useThree((state) => state.gl)
const textures = useLoader(TextureLoader, IsObject(input) ? Object.values(input) : (input as any))
// https://github.com/mrdoob/three.js/issues/22696
// Upload the texture to the GPU immediately instead of waiting for the first render
useEffect(() => {
const array = Array.isArray(textures) ? textures : [textures]
array.forEach(gl.initTexture)
}, [gl, textures])
if (IsObject(input)) {
const keys = Object.keys(input)
const keyed = {} as any
keys.forEach((key) => Object.assign(keyed, { [key]: textures[keys.indexOf(key)] }))
return keyed
} else {
return textures as any
}
}
useTexture.preload = (url: string extends any[] ? string[] : string) => useLoader.preload(TextureLoader, url)
useTexture.clear = (input: string | string[]) => useLoader.clear(TextureLoader, input)