UNPKG

threepipe

Version:

A 3D viewer framework built on top of three.js in TypeScript with a focus on quality rendering, modularity and extensibility.

309 lines 17.1 kB
var _a; import { ThreeSerialization } from '../../utils/serialization'; import { DoubleSide } from 'three'; export class GLTFMaterialExtrasExtension { } _a = GLTFMaterialExtrasExtension; GLTFMaterialExtrasExtension.WebGiMaterialExtrasExtension = 'WEBGI_material_extras'; /** * for physical material * Also {@link Export} * @param loadConfigResources */ GLTFMaterialExtrasExtension.Import = (loadConfigResources) => (_) => ({ name: '__' + _a.WebGiMaterialExtrasExtension, // __ is prefix so that the extension is added to userdata, and we can process later in afterRoot afterRoot: async (result) => { const scenes = result.scenes || (result.scene ? [result.scene] : []); for (const s of scenes) { const resExt = s.userData?.gltfExtensions?.[_a.WebGiMaterialExtrasExtension]; // Note: see exporter for details of material extra resources in scene. const resources = resExt?.resources ? await loadConfigResources(resExt.resources) : {}; s.traverse((obj) => { const o = obj?.material; if (!o?.isMaterial) return; const ext = o.userData?.gltfExtensions?.[_a.WebGiMaterialExtrasExtension]; if (!ext) return; // extras from MaterialLoader.js if (ext.emissiveIntensity !== undefined) o.emissiveIntensity = ext.emissiveIntensity; // kept for old versions, this is not saved in extras because of KHR_materials_emissive_strength // bumpMap, displacementMap, lightMap, alphaMap moved to separate extensions // if (material.shininess !== undefined) dat.shininess = material.shininess if (ext.fog !== undefined) o.fog = ext.fog; if (ext.flatShading !== undefined) o.flatShading = ext.flatShading; if (ext.blending !== undefined) o.blending = ext.blending; // if (ext.combine !== undefined) o.combine = ext.combine if (ext.side !== undefined) o.side = ext.side; if (ext.shadowSide !== undefined) o.shadowSide = ext.shadowSide; if (ext.depthFunc !== undefined) o.depthFunc = ext.depthFunc; if (ext.depthTest !== undefined) o.depthTest = ext.depthTest; if (ext.depthWrite !== undefined) o.depthWrite = ext.depthWrite; if (ext.colorWrite !== undefined) o.colorWrite = ext.colorWrite; if (ext.vertexColors !== undefined) o.vertexColors = ext.vertexColors; // this is override, it is also set in GLTFLoader if geometry has vertex colors, todo: check how to do this in a better way if (ext.alphaTest !== undefined) o.alphaTest = ext.alphaTest; // if (ext.transparent !== undefined) o.transparent = ext.transparent // this is set by GLTFLoader based on alpha mode if (ext.envMapIntensity !== undefined) o.envMapIntensity = ext.envMapIntensity; // for when separateEnvMapIntensity is true // if (ext.envMapSlotKey !== undefined) o.envMapSlotKey = ext.envMapSlotKey // in userdata // if (ext.stencilWrite !== undefined) o.stencilWrite = ext.stencilWrite // if (ext.stencilWriteMask !== undefined) o.stencilWriteMask = ext.stencilWriteMask // if (ext.stencilFunc !== undefined) o.stencilFunc = ext.stencilFunc // if (ext.stencilRef !== undefined) o.stencilRef = ext.stencilRef // if (ext.stencilFuncMask !== undefined) o.stencilFuncMask = ext.stencilFuncMask // if (ext.stencilFail !== undefined) o.stencilFail = ext.stencilFail // if (ext.stencilZFail !== undefined) o.stencilZFail = ext.stencilZFail // if (ext.stencilZPass !== undefined) o.stencilZPass = ext.stencilZPass if (ext.wireframe !== undefined) o.wireframe = ext.wireframe; if (ext.wireframeLinewidth !== undefined) o.wireframeLinewidth = ext.wireframeLinewidth; if (ext.wireframeLinecap !== undefined) o.wireframeLinecap = ext.wireframeLinecap; if (ext.wireframeLinejoin !== undefined) o.wireframeLinejoin = ext.wireframeLinejoin; if (ext.rotation !== undefined) o.rotation = ext.rotation; // if (ext.linewidth !== 1) o.linewidth = ext.linewidth // if (ext.dashSize !== undefined) o.dashSize = ext.dashSize // if (ext.gapSize !== undefined) o.gapSize = ext.gapSize // if (ext.scale !== undefined) o.scale = ext.scale if (ext.polygonOffset !== undefined) o.polygonOffset = ext.polygonOffset; if (ext.polygonOffsetFactor !== undefined) o.polygonOffsetFactor = ext.polygonOffsetFactor; if (ext.polygonOffsetUnits !== undefined) o.polygonOffsetUnits = ext.polygonOffsetUnits; if (ext.dithering !== undefined) o.dithering = ext.dithering; if (ext.alphaToCoverage !== undefined) o.alphaToCoverage = ext.alphaToCoverage; if (ext.premultipliedAlpha !== undefined) o.premultipliedAlpha = ext.premultipliedAlpha; // if (ext.visible !== undefined) o.visible = ext.visible if (ext.toneMapped !== undefined) o.toneMapped = ext.toneMapped; // we are ignoring the normalScale set from the GLTFLoader, because it is not correct in some cases. // todo: check if this is still the case if (ext.normalScale !== undefined && o.normalScale !== undefined) { if (Array.isArray(ext.normalScale)) o.normalScale.fromArray(ext.normalScale); else if (typeof ext.normalScale === 'number') o.normalScale.set(ext.normalScale, ext.normalScale); else console.warn('normalScale is not an array or number', ext.normalScale); } if (ext.reflectivity !== undefined) o.reflectivity = ext.reflectivity; // this is not present in the extras exporter because KHR_materials_ior, todo: kept for backward compatibility, remove ? // if (ext.refractionRatio !== undefined) o.refractionRatio = ext.refractionRatio // todo forceSinglePass // todo: make extension for these like GLTFMaterialsBumpMapExtension // if ( ext.gradientMap !== undefined ) o.gradientMap = getTexture( json.gradientMap ); Object.entries(ext).forEach(([key, value]) => { if (key.startsWith('_')) return; if (value && value.resource && typeof value.resource === 'string') { o[key] = ThreeSerialization.Deserialize(value, o[key], resources); } }); delete o.userData.gltfExtensions[_a.WebGiMaterialExtrasExtension]; }); // todo: check for resources that are not used and dispose them? see todo in ThreeViewer.fromJSON if (resExt) delete s.userData.gltfExtensions[_a.WebGiMaterialExtrasExtension]; } }, }); /** * Also see {@link Import} * @param w * @constructor */ GLTFMaterialExtrasExtension.Export = (w) => ({ writeMaterial(material, matDef) { if (!material?.isMaterial) return; if (!matDef.extensions) matDef.extensions = {}; const dat = {}; // non-default stuff from MaterialLoader.js // hardcode fix for: emissive components are limited to stay within the 0 - 1 range to accommodate glTF spec. see threejs: #21849 and #22000. // not needed anymore. // if (material.emissiveIntensity !== undefined && material.emissive?.isColor) { // const emissive = material.emissive.clone().multiplyScalar(material.emissiveIntensity) // const maxEmissiveComponent = Math.max(emissive.r, emissive.g, emissive.b) // if (maxEmissiveComponent > 1) { // dat.emissiveIntensity = maxEmissiveComponent // } // } // bumpMap, lightMap, alphaMap moved to separate extensions // if (material.shininess !== undefined) dat.shininess = material.shininess if (material.fog !== undefined) dat.fog = material.fog; if (material.flatShading !== undefined) dat.flatShading = material.flatShading; if (material.blending !== undefined) dat.blending = material.blending; // if (material.combine !== undefined) dat.combine = material.combine if (material.side !== undefined && material.side !== DoubleSide) dat.side = material.side; // DoubleSide handled in GLTF if (material.shadowSide !== undefined) dat.shadowSide = material.shadowSide; if (material.depthFunc !== undefined) dat.depthFunc = material.depthFunc; if (material.depthTest !== undefined) dat.depthTest = material.depthTest; if (material.depthWrite !== undefined) dat.depthWrite = material.depthWrite; if (material.colorWrite !== undefined) dat.colorWrite = material.colorWrite; if (material.vertexColors !== undefined) dat.vertexColors = material.vertexColors; // this is override, it is also set in GLTFLoader if geometry has vertex colors, todo: check how to do this in a better way if (material.alphaTest !== undefined) dat.alphaTest = material.alphaTest; if (material.envMapIntensity !== undefined) dat.envMapIntensity = material.envMapIntensity; // for when separateEnvMapIntensity is true // if (material.envMapSlotKey !== undefined) dat.envMapSlotKey = material.envMapSlotKey // in userData // if (material.stencilWrite !== undefined) dat.stencilWrite = material.stencilWrite // if (material.stencilWriteMask !== undefined) dat.stencilWriteMask = material.stencilWriteMask // if (material.stencilFunc !== undefined) dat.stencilFunc = material.stencilFunc // if (material.stencilRef !== undefined) dat.stencilRef = material.stencilRef // if (material.stencilFuncMask !== undefined) dat.stencilFuncMask = material.stencilFuncMask // if (material.stencilFail !== undefined) dat.stencilFail = material.stencilFail // if (material.stencilZFail !== undefined) dat.stencilZFail = material.stencilZFail // if (material.stencilZPass !== undefined) dat.stencilZPass = material.stencilZPass if (material.wireframe !== undefined) dat.wireframe = material.wireframe; if (material.wireframeLinewidth !== undefined) dat.wireframeLinewidth = material.wireframeLinewidth; if (material.wireframeLinecap !== undefined) dat.wireframeLinecap = material.wireframeLinecap; if (material.wireframeLinejoin !== undefined) dat.wireframeLinejoin = material.wireframeLinejoin; if (material.rotation !== undefined) dat.rotation = material.rotation; // if (material.linewidth !== 1) dat.linewidth = material.linewidth // if (material.dashSize !== undefined) dat.dashSize = material.dashSize // if (material.gapSize !== undefined) dat.gapSize = material.gapSize // if (material.scale !== undefined) dat.scale = material.scale if (material.polygonOffset !== undefined) dat.polygonOffset = material.polygonOffset; if (material.polygonOffsetFactor !== undefined) dat.polygonOffsetFactor = material.polygonOffsetFactor; if (material.polygonOffsetUnits !== undefined) dat.polygonOffsetUnits = material.polygonOffsetUnits; if (material.dithering !== undefined) dat.dithering = material.dithering; if (material.alphaToCoverage !== undefined) dat.alphaToCoverage = material.alphaToCoverage; if (material.premultipliedAlpha !== undefined) dat.premultipliedAlpha = material.premultipliedAlpha; // if (material.visible !== undefined) dat.visible = material.visible if (material.toneMapped !== undefined) dat.toneMapped = material.toneMapped; // ignoring data from the GLTFExporter. if (material.normalScale !== undefined) dat.normalScale = [material.normalScale.x, material.normalScale.y]; // if (material.reflectivity !== undefined) dat.reflectivity = material.reflectivity // see KHR_materials_ior, and comments in parser. // if (material.refractionRatio !== undefined) dat.refractionRatio = material.refractionRatio // todo: make extension for this like GLTFMaterialsBumpMapExtension // if ( material.gradientMap !== undefined ) dat.gradientMap = getTexture( json.gradientMap ); const resources = this.materialExternalResources[material.uuid]; if (resources) { Object.entries(resources).forEach(([k, v]) => { if (k.startsWith('_')) return; let setFlag = false; if (v?.userData && v.userData.embedUrlImagePreviews === undefined) { // check ThreeSerialization texture serialization and GLTFWriter2.processTexture v.userData.embedUrlImagePreviews = w.options.exporterOptions?.embedUrlImagePreviews; setFlag = true; } dat[k] = ThreeSerialization.Serialize(v, this.serializedMeta); if (v?.userData && setFlag) delete v.userData.embedUrlImagePreviews; }); } if (Object.keys(dat).length > 0) { matDef.extensions[_a.WebGiMaterialExtrasExtension] = dat; w.extensionsUsed[_a.WebGiMaterialExtrasExtension] = true; } }, materialExternalResources: {}, serializedMeta: { images: {}, textures: {}, }, beforeParse(input) { this.materialExternalResources = {}; // externalImagesInExtras: this is required because gltf-transform doesnt support external images in glb // see https://github.com/donmccurdy/glTF-Transform/discussions/644 if (!w.options.externalImagesInExtras) return; const materials = []; (Array.isArray(input) ? input : [input]).forEach(obj => { obj?.traverse((o) => { if (o && o.material?.isMaterial) materials.push(o.material); }); }); materials.forEach(material => { if (material) { if (!this.materialExternalResources[material.uuid]) this.materialExternalResources[material.uuid] = {}; this.materialExternalResources[material.uuid].__materialRef = material; Object.entries(material).forEach(([k, v]) => { if (k.startsWith('_')) return; if (!v) return; if (!v.isTexture) return; if (v.userData.rootPath && (v.userData.rootPath.startsWith('http') || v.userData.rootPath.startsWith('data:'))) { material[k] = null; this.materialExternalResources[material.uuid][k] = v; } }); } }); }, afterParse(_) { const vals = Object.values(this.materialExternalResources); if (vals.length < 1) return; vals.forEach((resources) => { const mat = resources.__materialRef; if (!mat) return; Object.entries(resources).forEach(([k, v]) => { if (k.startsWith('_')) return; if (!v) return; mat[k] = v; }); delete this.materialExternalResources[mat.uuid]; }); const scene = w.json.scenes[w.json.scene || 0]; if (!scene.extensions) scene.extensions = {}; scene.extensions[_a.WebGiMaterialExtrasExtension] = { resources: this.serializedMeta, }; w.extensionsUsed[_a.WebGiMaterialExtrasExtension] = true; // console.log(w) }, }); // see GLTFDracoExportPlugin GLTFMaterialExtrasExtension.Textures = undefined; //# sourceMappingURL=GLTFMaterialExtrasExtension.js.map