UNPKG

@needle-tools/engine

Version:

Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.

115 lines 4.54 kB
import { Loader, TextureLoader } from "three"; import { ObjectUtils } from "../engine_create_objects.js"; import { MODULES } from "../engine_modules.js"; // #region Utils export var MaterialX; (function (MaterialX) { /** * Utility function to load a MaterialX material from a URL. This can be used in your own code to load MaterialX materials outside of the glTF loading process. The URL should point to a MaterialX XML file. */ async function loadFromUrl(urlOrXML, opts) { if (!urlOrXML) throw new Error("URL or XML string is required to load a MaterialX material"); // Ensure the MaterialX module is loaded const module = await MODULES.MaterialX.load(); // Check if the input is an XML string or a URL // And fetch the XML content if it's a URL const isXmlString = urlOrXML.trimStart().startsWith("<"); const xml = isXmlString ? urlOrXML : await fetch(urlOrXML).then(r => r.text()).catch(console.error); if (!xml) { console.warn("Failed to load MaterialX file from url", urlOrXML); return null; } // For relative texture paths we might need to detect the base directory of the material file. // We can only do this if we have a URL (not an XML string) and if the URL is not a data URL. In that case we can use the URL to determine the base path for textures. // This can be used by the loader callback to resolve texture paths relative to the material file. let dir = undefined; if (opts?.url || !isXmlString) { const parts = (opts?.url || urlOrXML).split('/'); parts.pop(); dir = parts.join('/'); } const textureLoader = new TextureLoader(); return module.Experimental_API.createMaterialXMaterial(xml, opts?.materialNameOrIndex ?? 0, { getTexture: async (url) => { if (!url.startsWith("http") && !url.startsWith("data:") && !url.startsWith("blob:") && !url.startsWith("file:")) { if (dir) { url = dir + "/" + url; } } return textureLoader.loadAsync(url).catch(e => { console.warn(`Failed to load texture for MaterialX material ${url}`, e); }); } }, { cacheKey: urlOrXML, }); } MaterialX.loadFromUrl = loadFromUrl; })(MaterialX || (MaterialX = {})); // #region Loader export class MaterialXLoader extends Loader { loadAsync(url, onProgress) { return new Promise((resolve, reject) => { this.load(url, resolve, onProgress, reject); }); } load(url, onLoad, onProgress, onError) { onProgress?.({ type: "progress", loaded: 0, total: 0 }); MaterialX.loadFromUrl(url, {}).then(mat => { if (mat) { onLoad(this.onLoaded(mat)); } else { onError?.(new Error("Failed to load MaterialX material from url: " + url)); } }); } onLoaded(mat) { const shaderball = ObjectUtils.createPrimitive("ShaderBall", { material: mat }); return shaderball; } } // #region GLTF Extension export class NEEDLE_materialx { context; loader; url; parser; get name() { return "materialx-loading-helper"; } constructor(context, loader, url, parser) { this.context = context; this.loader = loader; this.url = url; this.parser = parser; } mtlxLoader; async beforeRoot() { const mtlxExtension = this.parser.json.extensions?.["NEEDLE_materials_mtlx"]; if (mtlxExtension) { const module = await MODULES.MaterialX.load(); try { this.mtlxLoader = new module.MaterialXLoader(this.parser, { cacheKey: `${this.url}:materialx`, parameters: { precision: this.context.renderer?.capabilities.precision, } }, { getFrame: () => this.context.time.frame, getTime: () => this.context.time.time, }); } catch (error) { console.error(error); } } } loadMaterial(index) { if (this.mtlxLoader) return this.mtlxLoader.loadMaterial(index); return null; } } //# sourceMappingURL=NEEDLE_materialx.js.map