Rich-Harris/svelte-cubed

Enable use of custom cameras or accessing root

nilskjQL opened this issue · 0 comments

Awesome library!

I have a scene exported from blender (a .gltf file) that has a camera and some animations I would like to use.
Since this library is using context im struggling to extend root to use my own camera. Example: If I copy the logic from PerspectiveCamera to a Custom camera it cannot access the context properly when getting root from setup:
const { root, self } = setup(new PerspectiveCamera());

Errors:

three.module.js:26548 Uncaught TypeError: Cannot read properties of null (reading 'isCamera')
    at WebGLRenderer.render (three.module.js:26548:39)
    at Canvas.svelte? [sm]:94:18
WebGLRenderer.render @ three.module.js:26548

context.js?v=7cfba4c5:17 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'scene')
    at setup (context.js?v=7cfba4c5:17:44)
    at instance (GLTFCamera.svelte:20:25)
    at init (index.mjs:1809:11)
    at new GLTFCamera (GLTFCamera.svelte:45:18)
    at createProxiedComponent (svelte-hooks.js:266:9)
    at new ProxyComponent (proxy.js:239:20)
    at new Proxy<GLTFCamera> (proxy.js:346:11)
    at Array.create_default_slot (index.svelte? [sm]:54:94)
    at create_slot (index.mjs:69:27)
    at create_if_block (Canvas.svelte? [sm]:4:32)

From the source I see that only set_root is exposed, not get_root. Is there a reason for this?

I built a wrapping GLTFModel loader component that loads the scene and exposes its data to its children with slot props:

<script>
	import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
	import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader';
	import { Mesh } from 'svelte-cubed';
	import { onMount } from 'svelte';

	let loader = new GLTFLoader();
	let dracoLoader = new DRACOLoader();
	dracoLoader.setDecoderPath(
		'DECODER_PATH'
	);
	loader.setDRACOLoader(dracoLoader);

	export let url = '';
	let load = loadModel(url);

	async function loadModel(model) {
		try {
			const gltf = await loader.loadAsync(model);
			console.log('loaded', gltf);
			return gltf;
		} catch (e) {
			console.error(e);
		}
	}
</script>

{#await load then model}
	<slot {model} />
{/await}

Using it I can read the scene camera and materials and use it like so:

<GLTFModel url="/model.glb" let:model>
    <Mesh geometry={model.scene.children[1].geometry} position={[0, $height, 0]} />
</GLTFModel>

How can I use the camera inside that model and replace the root camera with it?