var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // dist/index.js var dist_exports = {}; __export(dist_exports, { GLTFAnimator: () => GLTFAnimator, createScenegraphsFromGLTF: () => createScenegraphsFromGLTF, loadPBREnvironment: () => loadPBREnvironment, parsePBRMaterial: () => parsePBRMaterial }); module.exports = __toCommonJS(dist_exports); // dist/pbr/parse-pbr-material.js var import_core = require("@luma.gl/core"); var GLEnum; (function(GLEnum3) { GLEnum3[GLEnum3["FUNC_ADD"] = 32774] = "FUNC_ADD"; GLEnum3[GLEnum3["ONE"] = 1] = "ONE"; GLEnum3[GLEnum3["SRC_ALPHA"] = 770] = "SRC_ALPHA"; GLEnum3[GLEnum3["ONE_MINUS_SRC_ALPHA"] = 771] = "ONE_MINUS_SRC_ALPHA"; GLEnum3[GLEnum3["TEXTURE_MIN_FILTER"] = 10241] = "TEXTURE_MIN_FILTER"; GLEnum3[GLEnum3["LINEAR"] = 9729] = "LINEAR"; GLEnum3[GLEnum3["LINEAR_MIPMAP_NEAREST"] = 9985] = "LINEAR_MIPMAP_NEAREST"; GLEnum3[GLEnum3["UNPACK_FLIP_Y_WEBGL"] = 37440] = "UNPACK_FLIP_Y_WEBGL"; })(GLEnum || (GLEnum = {})); function parsePBRMaterial(device, material, attributes, options) { const parsedMaterial = { defines: { // TODO: Use EXT_sRGB if available (Standard in WebGL 2.0) MANUAL_SRGB: 1, SRGB_FAST_APPROXIMATION: 1 }, bindings: {}, uniforms: { // TODO: find better values? u_Camera: [0, 0, 0], // Model should override u_MetallicRoughnessValues: [1, 1] // Default is 1 and 1 }, parameters: {}, glParameters: {}, generatedTextures: [] }; parsedMaterial.defines.USE_TEX_LOD = 1; const { imageBasedLightingEnvironment } = options; if (imageBasedLightingEnvironment) { parsedMaterial.bindings.u_DiffuseEnvSampler = imageBasedLightingEnvironment.diffuseEnvSampler; parsedMaterial.bindings.u_SpecularEnvSampler = imageBasedLightingEnvironment.specularEnvSampler; parsedMaterial.bindings.u_brdfLUT = imageBasedLightingEnvironment.brdfLutTexture; parsedMaterial.uniforms.u_ScaleIBLAmbient = [1, 1]; } if (options == null ? void 0 : options.pbrDebug) { parsedMaterial.defines.PBR_DEBUG = 1; parsedMaterial.uniforms.u_ScaleDiffBaseMR = [0, 0, 0, 0]; parsedMaterial.uniforms.u_ScaleFGDSpec = [0, 0, 0, 0]; } if (attributes.NORMAL) parsedMaterial.defines.HAS_NORMALS = 1; if (attributes.TANGENT && (options == null ? void 0 : options.useTangents)) parsedMaterial.defines.HAS_TANGENTS = 1; if (attributes.TEXCOORD_0) parsedMaterial.defines.HAS_UV = 1; if (options == null ? void 0 : options.imageBasedLightingEnvironment) parsedMaterial.defines.USE_IBL = 1; if (options == null ? void 0 : options.lights) parsedMaterial.defines.USE_LIGHTS = 1; if (material) { parseMaterial(device, material, parsedMaterial); } return parsedMaterial; } function parseMaterial(device, material, parsedMaterial) { parsedMaterial.uniforms.pbr_uUnlit = Boolean(material.unlit); if (material.pbrMetallicRoughness) { parsePbrMetallicRoughness(device, material.pbrMetallicRoughness, parsedMaterial); } if (material.normalTexture) { addTexture(device, material.normalTexture, "u_NormalSampler", "HAS_NORMALMAP", parsedMaterial); const { scale = 1 } = material.normalTexture; parsedMaterial.uniforms.u_NormalScale = scale; } if (material.occlusionTexture) { addTexture(device, material.occlusionTexture, "u_OcclusionSampler", "HAS_OCCLUSIONMAP", parsedMaterial); const { strength = 1 } = material.occlusionTexture; parsedMaterial.uniforms.u_OcclusionStrength = strength; } if (material.emissiveTexture) { addTexture(device, material.emissiveTexture, "u_EmissiveSampler", "HAS_EMISSIVEMAP", parsedMaterial); parsedMaterial.uniforms.u_EmissiveFactor = material.emissiveFactor || [0, 0, 0]; } switch (material.alphaMode) { case "MASK": const { alphaCutoff = 0.5 } = material; parsedMaterial.defines.ALPHA_CUTOFF = 1; parsedMaterial.uniforms.u_AlphaCutoff = alphaCutoff; break; case "BLEND": import_core.log.warn("glTF BLEND alphaMode might not work well because it requires mesh sorting")(); parsedMaterial.parameters.blendColorOperation = "add"; parsedMaterial.parameters.blendColorSrcFactor = "src-alpha"; parsedMaterial.parameters.blendColorDstFactor = "one-minus-src-alpha"; parsedMaterial.parameters.blendAlphaOperation = "add"; parsedMaterial.parameters.blendAlphaSrcFactor = "one"; parsedMaterial.parameters.blendAlphaDstFactor = "one-minus-src-alpha"; parsedMaterial.glParameters.blend = true; parsedMaterial.glParameters.blendEquation = GLEnum.FUNC_ADD; parsedMaterial.glParameters.blendFunc = [ GLEnum.SRC_ALPHA, GLEnum.ONE_MINUS_SRC_ALPHA, GLEnum.ONE, GLEnum.ONE_MINUS_SRC_ALPHA ]; break; } } function parsePbrMetallicRoughness(device, pbrMetallicRoughness, parsedMaterial) { if (pbrMetallicRoughness.baseColorTexture) { addTexture(device, pbrMetallicRoughness.baseColorTexture, "u_BaseColorSampler", "HAS_BASECOLORMAP", parsedMaterial); } parsedMaterial.uniforms.u_BaseColorFactor = pbrMetallicRoughness.baseColorFactor || [1, 1, 1, 1]; if (pbrMetallicRoughness.metallicRoughnessTexture) { addTexture(device, pbrMetallicRoughness.metallicRoughnessTexture, "u_MetallicRoughnessSampler", "HAS_METALROUGHNESSMAP", parsedMaterial); } const { metallicFactor = 1, roughnessFactor = 1 } = pbrMetallicRoughness; parsedMaterial.uniforms.u_MetallicRoughnessValues = [metallicFactor, roughnessFactor]; } function addTexture(device, gltfTexture, uniformName, define = null, parsedMaterial) { var _a, _b; const parameters = ((_b = (_a = gltfTexture == null ? void 0 : gltfTexture.texture) == null ? void 0 : _a.sampler) == null ? void 0 : _b.parameters) || {}; const image = gltfTexture.texture.source.image; let textureOptions; let specialTextureParameters = {}; if (image.compressed) { textureOptions = image; specialTextureParameters = { [GLEnum.TEXTURE_MIN_FILTER]: image.data.length > 1 ? GLEnum.LINEAR_MIPMAP_NEAREST : GLEnum.LINEAR }; } else { textureOptions = { data: image }; } const texture = device.createTexture({ id: gltfTexture.uniformName || gltfTexture.id, parameters: { ...parameters, ...specialTextureParameters }, pixelStore: { [GLEnum.UNPACK_FLIP_Y_WEBGL]: false }, ...textureOptions }); parsedMaterial.bindings[uniformName] = texture; if (define) parsedMaterial.defines[define] = 1; parsedMaterial.generatedTextures.push(texture); } // dist/pbr/pbr-environment.js var import_textures = require("@loaders.gl/textures"); function loadPBREnvironment(device, props) { const brdfLutTexture = device.createTexture({ id: "brdfLUT", sampler: { wrapS: "clamp-to-edge", wrapT: "clamp-to-edge", minFilter: "linear", maxFilter: "linear" }, // Texture accepts a promise that returns an image as data (Async Textures) data: (0, import_textures.loadImageTexture)(props.brdfLutUrl) }); const diffuseEnvSampler = makeCube(device, { id: "DiffuseEnvSampler", getTextureForFace: (dir) => (0, import_textures.loadImageTexture)(props.getTexUrl("diffuse", dir, 0)), sampler: { wrapS: "clamp-to-edge", wrapT: "clamp-to-edge", minFilter: "linear", maxFilter: "linear" } }); const specularEnvSampler = makeCube(device, { id: "SpecularEnvSampler", getTextureForFace: (dir) => { const imageArray = []; for (let lod = 0; lod <= props.specularMipLevels - 1; lod++) { imageArray.push((0, import_textures.loadImageTexture)(props.getTexUrl("specular", dir, lod))); } return imageArray; }, sampler: { wrapS: "clamp-to-edge", wrapT: "clamp-to-edge", minFilter: "linear", // [GL.TEXTURE_MIN_FILTER]: GL.LINEAR_MIPMAP_LINEAR, maxFilter: "linear" } }); return { brdfLutTexture, diffuseEnvSampler, specularEnvSampler }; } var FACES = [0, 1, 2, 3, 4, 5]; function makeCube(device, { id, getTextureForFace, sampler }) { const data = {}; FACES.forEach((face) => { data[String(face)] = getTextureForFace(face); }); return device.createTexture({ id, dimension: "cube", mipmaps: false, sampler, data }); } // dist/gltf/gltf-instantiator.js var import_engine2 = require("@luma.gl/engine"); var import_core5 = require("@math.gl/core"); // dist/gltf/gltf-animator.js var import_core2 = require("@luma.gl/core"); var import_core3 = require("@math.gl/core"); var ATTRIBUTE_TYPE_TO_COMPONENTS = { SCALAR: 1, VEC2: 2, VEC3: 3, VEC4: 4, MAT2: 4, MAT3: 9, MAT4: 16 }; var ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY = { 5120: Int8Array, 5121: Uint8Array, 5122: Int16Array, 5123: Uint16Array, 5125: Uint32Array, 5126: Float32Array }; var GLTFAnimation = class { name; startTime = 0; playing = true; speed = 1; channels = []; constructor(props) { Object.assign(this, props); } animate(timeMs) { if (!this.playing) { return; } const absTime = timeMs / 1e3; const time = (absTime - this.startTime) * this.speed; this.channels.forEach(({ sampler, target, path }) => { interpolate(time, sampler, target, path); applyTranslationRotationScale(target, target._node); }); } }; var GLTFAnimator = class { animations; constructor(gltf) { this.animations = gltf.animations.map((animation, index) => { const name = animation.name || `Animation-${index}`; const samplers = animation.samplers.map(({ input, interpolation = "LINEAR", output }) => ({ input: accessorToJsArray(gltf.accessors[input]), interpolation, output: accessorToJsArray(gltf.accessors[output]) })); const channels = animation.channels.map(({ sampler, target }) => ({ sampler: samplers[sampler], target: gltf.nodes[target.node], path: target.path })); return new GLTFAnimation({ name, channels }); }); } /** @deprecated Use .setTime(). Will be removed (deck.gl is using this) */ animate(time) { this.setTime(time); } setTime(time) { this.animations.forEach((animation) => animation.animate(time)); } getAnimations() { return this.animations; } }; function accessorToJsArray(accessor) { if (!accessor._animation) { const ArrayType = ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY[accessor.componentType]; const components = ATTRIBUTE_TYPE_TO_COMPONENTS[accessor.type]; const length = components * accessor.count; const { buffer, byteOffset } = accessor.bufferView.data; const array = new ArrayType(buffer, byteOffset + (accessor.byteOffset || 0), length); if (components === 1) { accessor._animation = Array.from(array); } else { const slicedArray = []; for (let i = 0; i < array.length; i += components) { slicedArray.push(Array.from(array.slice(i, i + components))); } accessor._animation = slicedArray; } } return accessor._animation; } var helperMatrix = new import_core3.Matrix4(); function applyTranslationRotationScale(gltfNode, node) { node.matrix.identity(); if (gltfNode.translation) { node.matrix.translate(gltfNode.translation); } if (gltfNode.rotation) { const rotationMatrix = helperMatrix.fromQuaternion(gltfNode.rotation); node.matrix.multiplyRight(rotationMatrix); } if (gltfNode.scale) { node.matrix.scale(gltfNode.scale); } } var quaternion = new import_core3.Quaternion(); function linearInterpolate(target, path, start, stop, ratio) { if (path === "rotation") { quaternion.slerp({ start, target: stop, ratio }); for (let i = 0; i < quaternion.length; i++) { target[path][i] = quaternion[i]; } } else { for (let i = 0; i < start.length; i++) { target[path][i] = ratio * stop[i] + (1 - ratio) * start[i]; } } } function cubicsplineInterpolate(target, path, { p0, outTangent0, inTangent1, p1, tDiff, ratio: t }) { for (let i = 0; i < target[path].length; i++) { const m0 = outTangent0[i] * tDiff; const m1 = inTangent1[i] * tDiff; target[path][i] = (2 * Math.pow(t, 3) - 3 * Math.pow(t, 2) + 1) * p0[i] + (Math.pow(t, 3) - 2 * Math.pow(t, 2) + t) * m0 + (-2 * Math.pow(t, 3) + 3 * Math.pow(t, 2)) * p1[i] + (Math.pow(t, 3) - Math.pow(t, 2)) * m1; } } function stepInterpolate(target, path, value) { for (let i = 0; i < value.length; i++) { target[path][i] = value[i]; } } function interpolate(time, { input, interpolation, output }, target, path) { const maxTime = input[input.length - 1]; const animationTime = time % maxTime; const nextIndex = input.findIndex((t) => t >= animationTime); const previousIndex = Math.max(0, nextIndex - 1); if (!Array.isArray(target[path])) { switch (path) { case "translation": target[path] = [0, 0, 0]; break; case "rotation": target[path] = [0, 0, 0, 1]; break; case "scale": target[path] = [1, 1, 1]; break; default: import_core2.log.warn(`Bad animation path ${path}`)(); } } (0, import_core2.assert)(target[path].length === output[previousIndex].length); const previousTime = input[previousIndex]; const nextTime = input[nextIndex]; switch (interpolation) { case "STEP": stepInterpolate(target, path, output[previousIndex]); break; case "LINEAR": if (nextTime > previousTime) { const ratio = (animationTime - previousTime) / (nextTime - previousTime); linearInterpolate(target, path, output[previousIndex], output[nextIndex], ratio); } break; case "CUBICSPLINE": if (nextTime > previousTime) { const ratio = (animationTime - previousTime) / (nextTime - previousTime); const tDiff = nextTime - previousTime; const p0 = output[3 * previousIndex + 1]; const outTangent0 = output[3 * previousIndex + 2]; const inTangent1 = output[3 * nextIndex + 0]; const p1 = output[3 * nextIndex + 1]; cubicsplineInterpolate(target, path, { p0, outTangent0, inTangent1, p1, tDiff, ratio }); } break; default: import_core2.log.warn(`Interpolation ${interpolation} not supported`)(); break; } } // dist/gltf/create-gltf-model.js var import_core4 = require("@luma.gl/core"); var import_shadertools = require("@luma.gl/shadertools"); var import_engine = require("@luma.gl/engine"); var vs = ` #pragma vscode_glsllint_stage: vert #if (__VERSION__ < 300) #define _attr attribute #else #define _attr in #endif // _attr vec4 POSITION; _attr vec4 positions; #ifdef HAS_NORMALS // _attr vec4 NORMAL; _attr vec4 normals; #endif #ifdef HAS_TANGENTS _attr vec4 TANGENT; #endif #ifdef HAS_UV // _attr vec2 TEXCOORD_0; _attr vec2 texCoords; #endif void main(void) { vec4 _NORMAL = vec4(0.); vec4 _TANGENT = vec4(0.); vec2 _TEXCOORD_0 = vec2(0.); #ifdef HAS_NORMALS _NORMAL = normals; #endif #ifdef HAS_TANGENTS _TANGENT = TANGENT; #endif #ifdef HAS_UV _TEXCOORD_0 = texCoords; #endif pbr_setPositionNormalTangentUV(positions, _NORMAL, _TANGENT, _TEXCOORD_0); gl_Position = u_MVPMatrix * positions; } `; var fs = ` #pragma vscode_glsllint_stage: frag #if (__VERSION__ < 300) #define fragmentColor gl_FragColor #else out vec4 fragmentColor; #endif void main(void) { vec3 pos = pbr_vPosition; fragmentColor = pbr_filterColor(vec4(1.0)); } `; function createGLTFModel(device, options) { const { id, geometry, material, vertexCount, materialOptions, modelOptions } = options; const parsedMaterial = parsePBRMaterial(device, material, geometry.attributes, materialOptions); import_core4.log.info(4, "createGLTFModel defines: ", parsedMaterial.defines)(); const managedResources = []; const parameters = { depthWriteEnabled: true, depthCompare: "less", depthFormat: "depth24plus", cullMode: "back" }; const modelProps = { id, geometry, topology: geometry.topology, vertexCount, modules: [import_shadertools.pbr], vs: addVersionToShader(device, vs), fs: addVersionToShader(device, fs), ...modelOptions, bindings: { ...parsedMaterial.bindings, ...modelOptions.bindings }, defines: { ...parsedMaterial.defines, ...modelOptions.defines }, parameters: { ...parameters, ...parsedMaterial.parameters, ...modelOptions.parameters }, uniforms: { ...parsedMaterial.uniforms, ...modelOptions.uniforms } }; const model = new import_engine.Model(device, modelProps); return new import_engine.ModelNode({ managedResources, model }); } function addVersionToShader(device, source) { return `#version 300 es ${source}`; } // dist/gltf/gltf-instantiator.js var DEFAULT_OPTIONS = { modelOptions: {}, pbrDebug: false, imageBasedLightingEnvironment: null, lights: true, useTangents: false }; var GLTFInstantiator = class { device; options; gltf; constructor(device, options = {}) { this.device = device; this.options = { ...DEFAULT_OPTIONS, ...options }; } instantiate(gltf) { this.gltf = gltf; const scenes = (gltf.scenes || []).map((scene) => this.createScene(scene)); return scenes; } createAnimator() { if (Array.isArray(this.gltf.animations)) { return new GLTFAnimator(this.gltf); } return null; } createScene(gltfScene) { const gltfNodes = gltfScene.nodes || []; const nodes = gltfNodes.map((node) => this.createNode(node)); const scene = new import_engine2.GroupNode({ id: gltfScene.name || gltfScene.id, children: nodes }); return scene; } createNode(gltfNode) { if (!gltfNode._node) { const gltfChildren = gltfNode.children || []; const children = gltfChildren.map((child) => this.createNode(child)); if (gltfNode.mesh) { children.push(this.createMesh(gltfNode.mesh)); } const node = new import_engine2.GroupNode({ id: gltfNode.name || gltfNode.id, children }); if (gltfNode.matrix) { node.setMatrix(gltfNode.matrix); } else { node.matrix.identity(); if (gltfNode.translation) { node.matrix.translate(gltfNode.translation); } if (gltfNode.rotation) { const rotationMatrix = new import_core5.Matrix4().fromQuaternion(gltfNode.rotation); node.matrix.multiplyRight(rotationMatrix); } if (gltfNode.scale) { node.matrix.scale(gltfNode.scale); } } gltfNode._node = node; } return gltfNode._node; } createMesh(gltfMesh) { if (!gltfMesh._mesh) { const gltfPrimitives = gltfMesh.primitives || []; const primitives = gltfPrimitives.map((gltfPrimitive, i) => this.createPrimitive(gltfPrimitive, i, gltfMesh)); const mesh = new import_engine2.GroupNode({ id: gltfMesh.name || gltfMesh.id, children: primitives }); gltfMesh._mesh = mesh; } return gltfMesh._mesh; } createPrimitive(gltfPrimitive, i, gltfMesh) { const id = gltfPrimitive.name || `${gltfMesh.name || gltfMesh.id}-primitive-${i}`; const topology = convertGLDrawModeToTopology(gltfPrimitive.mode || 4); const vertexCount = gltfPrimitive.indices ? gltfPrimitive.indices.count : this.getVertexCount(gltfPrimitive.attributes); const modelNode = createGLTFModel(this.device, { id, geometry: this.createGeometry(id, gltfPrimitive, topology), material: gltfPrimitive.material, materialOptions: this.options, modelOptions: this.options.modelOptions, vertexCount }); modelNode.bounds = [ gltfPrimitive.attributes.POSITION.min, gltfPrimitive.attributes.POSITION.max ]; return modelNode; } getVertexCount(attributes) { throw new Error("getVertexCount not implemented"); } createGeometry(id, gltfPrimitive, topology) { const attributes = {}; for (const [attributeName, attribute] of Object.entries(gltfPrimitive.attributes)) { const { components, size, value } = attribute; attributes[attributeName] = { size: size ?? components, value }; } return new import_engine2.Geometry({ id, topology, indices: gltfPrimitive.indices.value, attributes }); } createBuffer(attribute, usage) { if (!attribute.bufferView) { attribute.bufferView = {}; } const { bufferView } = attribute; if (!bufferView.lumaBuffers) { bufferView.lumaBuffers = {}; } if (!bufferView.lumaBuffers[usage]) { bufferView.lumaBuffers[usage] = this.device.createBuffer({ id: `from-${bufferView.id}`, // Draco decoded files have attribute.value data: bufferView.data || attribute.value }); } return bufferView.lumaBuffers[usage]; } // TODO - create sampler in WebGL2 createSampler(gltfSampler) { return gltfSampler; } // Helper methods (move to GLTFLoader.resolve...?) needsPOT() { return false; } }; var GLEnum2; (function(GLEnum3) { GLEnum3[GLEnum3["POINTS"] = 0] = "POINTS"; GLEnum3[GLEnum3["LINES"] = 1] = "LINES"; GLEnum3[GLEnum3["LINE_LOOP"] = 2] = "LINE_LOOP"; GLEnum3[GLEnum3["LINE_STRIP"] = 3] = "LINE_STRIP"; GLEnum3[GLEnum3["TRIANGLES"] = 4] = "TRIANGLES"; GLEnum3[GLEnum3["TRIANGLE_STRIP"] = 5] = "TRIANGLE_STRIP"; GLEnum3[GLEnum3["TRIANGLE_FAN"] = 6] = "TRIANGLE_FAN"; })(GLEnum2 || (GLEnum2 = {})); function convertGLDrawModeToTopology(drawMode) { switch (drawMode) { case GLEnum2.POINTS: return "point-list"; case GLEnum2.LINES: return "line-list"; case GLEnum2.LINE_STRIP: return "line-strip"; case GLEnum2.LINE_LOOP: return "line-loop-webgl"; case GLEnum2.TRIANGLES: return "triangle-list"; case GLEnum2.TRIANGLE_STRIP: return "triangle-strip"; case GLEnum2.TRIANGLE_FAN: return "triangle-fan-webgl"; default: throw new Error(drawMode); } } // dist/gltf/create-gltf-objects.js function createScenegraphsFromGLTF(device, gltf, options) { const instantiator = new GLTFInstantiator(device, options); const scenes = instantiator.instantiate(gltf); const animator = instantiator.createAnimator(); return { scenes, animator }; } //# sourceMappingURL=index.cjs.map