Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
File size: 3,535 Bytes
ac7030c |
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 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
import React, { useEffect, useRef } from "react"
import * as SPLAT from "gsplat"
type GsplatStatus =
| "idle"
| "loading"
| "loaded"
| "failed"
export function Gsplat({
url,
width,
height,
className = "" }: {
url: string
width?: number
height?: number
className?: string
}) {
const canvasRef = useRef<HTMLCanvasElement>(null)
const sceneRef = useRef<SPLAT.Scene>()
const cameraRef = useRef<SPLAT.Camera>()
const controlsRef = useRef<SPLAT.OrbitControls>()
const rendererRef = useRef<SPLAT.WebGLRenderer>()
const frameIdRef = useRef<number>(0)
const statusRef = useRef<GsplatStatus>("idle")
function animate() {
const renderer = rendererRef.current
const scene = sceneRef.current
const camera = cameraRef.current
const controls = controlsRef.current
if (!scene || !renderer || !camera || !controls) { return }
controls.update()
renderer.render(scene, camera)
frameIdRef.current = requestAnimationFrame(animate)
}
async function loadScene() {
const canvas = canvasRef.current
if (!canvas) { return }
const status = statusRef.current
if (!status || status === "loaded" || status === "loading" || status === "failed") {
console.log(`Gsplat: a scene is already loading or loaded: skipping..`)
return
}
statusRef.current = "loading"
try {
const renderer = rendererRef.current = new SPLAT.WebGLRenderer(canvas)
let fileUrl = url.trim()
let fileExt = fileUrl.toLowerCase().split(".").pop() || "splat"
const isVideo = fileExt === "splatv"
if (isVideo) {
console.log("Gsplat: loading video splat..")
renderer.addProgram(new SPLAT.VideoRenderProgram(renderer))
const scene = sceneRef.current = new SPLAT.Scene()
const camera = cameraRef.current = new SPLAT.Camera()
const controls = controlsRef.current = new SPLAT.OrbitControls(camera, renderer.canvas)
await SPLAT.SplatvLoader.LoadAsync(url, scene, camera, (progress) => {
console.log(`${Math.round(progress * 100)}%`)
})
controls.setCameraTarget(camera.position.add(camera.forward.multiply(5)))
} else {
console.log("Gsplat: loading static splat..")
const scene = sceneRef.current = new SPLAT.Scene()
const camera = cameraRef.current = new SPLAT.Camera()
const controls = controlsRef.current = new SPLAT.OrbitControls(camera, renderer.canvas)
await SPLAT.Loader.LoadAsync(url, scene, (progress) => {
console.log(`${Math.round(progress * 100)}%`)
})
}
console.log("Gsplat: finished loading! rendering..")
statusRef.current = "loaded"
} catch (err) {
console.error(`Gsplat: failed to load the content`)
statusRef.current = "failed"
return
}
animate()
};
useEffect(() => {
if (!canvasRef.current) { return }
loadScene()
return () => { cancelAnimationFrame(frameIdRef?.current || 0) }
}, [])
// responsive width and height
useEffect(() => {
const canvas = canvasRef.current
const renderer = rendererRef.current
if (!canvas || !renderer) { return }
// renderer.setSize(canvas.clientWidth, canvas.clientHeight)
renderer.setSize(
width || canvas.clientWidth,
height || canvas.clientHeight
)
}, [width, height])
return (
<div style={{ width, height }} className={className}>
<canvas ref={canvasRef} style={{ width, height}}></canvas>
</div>
);
}
|