Object/Texture Loaders
Rigo-m opened this issue · 3 comments
Is this already implemented and not documented or is the implementation lacking/won't be implemented by design?
https://threejs.org/docs/#examples/en/loaders/OBJLoader
Another good name for the issue would be: how do I load an external .obj file via Svelte Cubed API?
I put together a simple working example in a project I'm working on. I converted my .obj
file to a .js
file, wrapped everything in a template literal, and exported it. To avoid having to do that, there's room to potentially sweeten this up with a custom vite plugin that imports .obj
files.
<script lang="ts">
import * as THREE from 'three';
import * as SC from 'svelte-cubed';
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader';
import obj from '$lib/components/models/Lowpoly_tree_sample.js';
</script>
<SC.Canvas antialias background={new THREE.Color('papayawhip')} shadows>
<SC.Primitive object={new OBJLoader().parse(obj)} />
<SC.PerspectiveCamera position={[50, 50, 50]} />
<SC.OrbitControls enableZoom={true} 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>
Using SvelteKit, I hypothesize performance may be improved here by parsing the .obj
file contents during prerendering (in the load function of <script context="module">
) and passing both a BufferGeometry
and Material
through the props. I attempted that without success but I'm pretty green to three.js, so someone more knowledgeable may know how to extract those from the Object3D
that new OBJLoader().parse(obj)
returns.
I just created that vite plugin I mentioned above so you don't have to convert your the .obj
files https://github.com/tonyketcham/unplugin-obj
Using that, you just have to do
import obj from '$lib/components/models/Lowpoly_tree_sample.obj';
Alternatively (and probably more performantly albeit more verbose) you can place your .obj
/.mtl
files within your static
folder and do something like:
<script lang="ts">
import * as THREE from 'three';
import * as SC from 'svelte-cubed';
import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader';
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader';
import { assets } from '$app/paths';
import { browser } from '$app/env';
let mesh: THREE.Mesh;
const mtlSrc = `${assets}/Lowpoly_tree_sample.mtl`;
const mtlLoader = new MTLLoader();
const objLoader = new OBJLoader();
if (browser) {
// Load the object and material resources
mtlLoader.load(mtlSrc, (mtl) => {
const objSrc = `${assets}/Lowpoly_tree_sample.obj`;
mtl.preload();
objLoader.setMaterials(mtl);
objLoader.load(objSrc, (event) => {
mesh = event.children[0] as THREE.Mesh;
console.log(mesh);
return mesh;
});
});
}
async function loadMesh(mesh) {
return new Promise((resolve: (value: THREE.Mesh) => any) => {
if (mesh) {
resolve(mesh);
}
});
}
// Wait for the mesh to load before adding it to the scene
$: meshPromise = loadMesh(mesh);
</script>
<SC.Canvas antialias background={new THREE.Color('papayawhip')} shadows>
{#await meshPromise then mesh}
<SC.Mesh geometry={mesh.geometry} material={mesh.material} />
{/await}
<SC.PerspectiveCamera position={[50, 50, 50]} />
<SC.OrbitControls enableZoom={true} 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>