Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
65 changes: 65 additions & 0 deletions src/lib/components/objects/GLTF.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<script>
import { onMount } from 'svelte';

import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
import { KTX2Loader } from 'three/examples/jsm/loaders/KTX2Loader';
import { setup } from '../../utils/context.js';
import { transform } from '../../utils/object.js';
import * as defaults from '../../utils/defaults.js';

/** @type {string} */
export let path = null;
/** @type {string} */
export let filename = null;
export let useDraco = false;
export let useKTX2 = false;

export let position = defaults.position;
export let rotation = defaults.rotation;
export let scale = defaults.scale;
export let castShadow = false;
export let receiveShadow = false;
export let frustumCulled = true;
export let renderOrder = 0;

/** @type {Object} */
let gltfScene = null;

const { root, parent, self } = setup(new THREE.Object3D());

$: {
if(gltfScene) {
Copy link

@aewing aewing Nov 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Edit: Maybe worth dispatching an event on load/change as well.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you give an example of what that might look like?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure!
At the top of the file before/after the props are exported, we could create an event dispatcher:

import { createEventDispatcher } from "svelte";
const dispatch = createEventDispatcher();

And then on line 77 where we have successfully loaded (or failed to load) the model, we could dispatch("load", gltf); or dispatch("error", err);, etc...

My thinking was that this could provide a convenient entry point for manipulating the materials in the scene, etc...

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a consumer of the component, that would look something like

<SC.GLTF {...} on:load={swapMyTexture} on:error={swapFallbackScene} />

Copy link

@aewing aewing Nov 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that dispatching on change would provide any value to me, but the implementation would be similar, just within the reactive statement.

gltfScene.traverse( function( node ) {
if ( node.isMesh ) {
node.castShadow = castShadow;
node.receiveShadow = receiveShadow;
node.frustumCulled = frustumCulled;
node.renderOrder = renderOrder;
}
} );
}

transform(self, position, rotation, scale);
root.invalidate();
}

onMount(() => {

const loader = new GLTFLoader()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a benefit to creating the loader for each component instance rather than reusing?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hear what your saying but also just doing a thing and getting it off the ground/running is step # 1

Copy link

@aewing aewing Nov 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And reviewing it and iterating on it is step # 2!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely! I submitted this PR early to get feedback, so I'm excited to get feedback. I looked into the loader and figured out how to share it; i'll push a version with this in a bit. This also shares the KTX and Draco loaders.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah! all good then. looking forward to previewing the deploy when that comes together

.setPath( path )
.setDRACOLoader( useDraco ? new DRACOLoader().setDecoderPath( '/loaders/draco/' ) : null )
.setKTX2Loader( useKTX2 ? new KTX2Loader()
.setTranscoderPath( '/loaders/basis/' )
.detectSupport( root.renderer ) : null )
.load( filename, function ( gltf ) {
gltfScene = gltf.scene;
self.add(gltf.scene);
} );

return () => {};
});
</script>

<slot />
1 change: 1 addition & 0 deletions src/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export { default as Canvas } from './components/Canvas.svelte';
export { default as Bone } from './components/objects/Bone.svelte';
export { default as Group } from './components/objects/Group.svelte';
export { default as Mesh } from './components/objects/Mesh.svelte';
export { default as GLTF } from './components/objects/GLTF.svelte';
export { default as Skeleton } from './components/objects/Skeleton.svelte';
export { default as SkinnedMesh } from './components/objects/SkinnedMesh.svelte';
export { default as Primitive } from './components/objects/Primitive.svelte';
Expand Down
59 changes: 59 additions & 0 deletions src/routes/examples/_content/04-gltf-simple/index.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<script>
import * as THREE from 'three';
import * as SC from 'svelte-cubed';

let cameraX = 0.0;

SC.onFrame((elapsedTime, deltaTime) => {
cameraX = Math.pow(Math.sin(elapsedTime/1000),3)*3;
});
</script>

<SC.Canvas
antialias
environment={new THREE.TextureLoader().load('/textures/kiara_1_dawn.jpeg',
(tex) => {
tex.mapping = THREE.EquirectangularReflectionMapping;
tex.encoding = THREE.sRGBEncoding;
})}
background={new THREE.TextureLoader().load('/textures/kiara_1_dawn.jpeg',
(tex) => {
tex.mapping = THREE.EquirectangularReflectionMapping;
tex.encoding = THREE.sRGBEncoding;
})}
shadows
>

<SC.Group position={[0, -1, 0]}>
<SC.Mesh
geometry={new THREE.PlaneGeometry(50, 50)}
material={new THREE.MeshStandardMaterial({ color: 'burlywood' })}
rotation={[-Math.PI / 2, 0, 0]}
receiveShadow
/>
<SC.Primitive
object={new THREE.GridHelper(50, 50, 'papayawhip', 'papayawhip')}
position={[0, 0.001, 0]}
/>
</SC.Group>

<SC.GLTF path="/gltf/" filename="DamagedHelmet.glb"
position={[0, 0, 0]}
castShadow
receiveShadow />
<SC.GLTF path="/gltf/waterbottle/" filename="WaterBottle.gltf"
position={[3, 0, 0]}
useDraco
castShadow
receiveShadow />
<SC.GLTF path="/gltf/stainedglasslamp-KTX2/" filename="StainedGlassLamp.gltf"
position={[-3, 0, 0]}
useKTX2
castShadow
receiveShadow />

<SC.PerspectiveCamera position={[1, 2, 6]} target={[0, 1, 0]} />
<SC.OrbitControls enableZoom={false} maxPolarAngle={Math.PI * 0.51} />
<SC.AmbientLight intensity={0.6} />
<SC.DirectionalLight intensity={0.6} position={[-2, 3, 2]} shadow={{ mapSize: [2048, 2048] }} />
</SC.Canvas>
3 changes: 3 additions & 0 deletions src/routes/examples/_content/04-gltf-simple/meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"title": "glTF simple"
}
Binary file added static/example-thumbnails/gltf-simple.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading