@needle-tools/engine 4.6.2 → 4.7.0-next.2756168

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/dist/needle-engine.bundle-C2wJAuPf.min.js +1604 -0
  2. package/dist/{needle-engine.bundle-DGcStTA7.js → needle-engine.bundle-S0N_qbSh.js} +8713 -8443
  3. package/dist/{needle-engine.bundle-DmYMLdWP.umd.cjs → needle-engine.bundle-lLDHlwZU.umd.cjs} +213 -184
  4. package/dist/needle-engine.js +2 -2
  5. package/dist/needle-engine.min.js +1 -1
  6. package/dist/needle-engine.umd.cjs +1 -1
  7. package/lib/engine/engine_context.js +3 -2
  8. package/lib/engine/engine_context.js.map +1 -1
  9. package/lib/engine-components/export/usdz/ThreeUSDZExporter.d.ts +5 -3
  10. package/lib/engine-components/export/usdz/ThreeUSDZExporter.js +124 -117
  11. package/lib/engine-components/export/usdz/ThreeUSDZExporter.js.map +1 -1
  12. package/lib/engine-components/export/usdz/extensions/NodeMaterialConverter.d.ts +10 -0
  13. package/lib/engine-components/export/usdz/extensions/NodeMaterialConverter.js +452 -0
  14. package/lib/engine-components/export/usdz/extensions/NodeMaterialConverter.js.map +1 -0
  15. package/lib/engine-components/postprocessing/Effects/BloomEffect.js +0 -3
  16. package/lib/engine-components/postprocessing/Effects/BloomEffect.js.map +1 -1
  17. package/lib/engine-components/postprocessing/PostProcessingHandler.js +43 -11
  18. package/lib/engine-components/postprocessing/PostProcessingHandler.js.map +1 -1
  19. package/lib/engine-components/postprocessing/utils.d.ts +1 -0
  20. package/lib/engine-components/postprocessing/utils.js.map +1 -1
  21. package/package.json +2 -2
  22. package/plugins/vite/alias.js +48 -38
  23. package/src/engine/engine_context.ts +3 -2
  24. package/src/engine-components/export/usdz/ThreeUSDZExporter.ts +155 -142
  25. package/src/engine-components/export/usdz/extensions/NodeMaterialConverter.ts +532 -0
  26. package/src/engine-components/postprocessing/Effects/BloomEffect.ts +0 -2
  27. package/src/engine-components/postprocessing/PostProcessingHandler.ts +50 -12
  28. package/src/engine-components/postprocessing/utils.ts +1 -0
  29. package/dist/needle-engine.bundle-D0XWaCQs.min.js +0 -1575
@@ -32,7 +32,8 @@ import {
32
32
  Vector3,
33
33
  Vector4,
34
34
  WebGLRenderer,
35
- WebGLRenderTarget} from 'three';
35
+ WebGLRenderTarget
36
+ } from 'three';
36
37
  import * as fflate from 'three/examples/jsm/libs/fflate.module.js';
37
38
 
38
39
  import { VERSION } from "../../../engine/engine_constants.js";
@@ -42,6 +43,9 @@ import { BehaviorExtension } from '../../api.js';
42
43
  import type { IUSDExporterExtension } from './Extension.js';
43
44
  import type { AnimationExtension } from './extensions/Animation.js';
44
45
  import type { PhysicsExtension } from './extensions/behavior/PhysicsExtension.js';
46
+ import {buildNodeMaterial} from './extensions/NodeMaterialConverter.js';
47
+
48
+ type MeshPhysicalNodeMaterial = import("three/src/materials/nodes/MeshPhysicalNodeMaterial.js").default;
45
49
 
46
50
  function makeNameSafe( str ) {
47
51
  // Remove characters that are not allowed in USD ASCII identifiers
@@ -148,7 +152,7 @@ class USDObject {
148
152
  get isDynamic() { return this._isDynamic; }
149
153
  private set isDynamic( value ) { this._isDynamic = value; }
150
154
  geometry: BufferGeometry | null;
151
- material: MeshStandardMaterial | MeshBasicMaterial | Material | null;
155
+ material: MeshStandardMaterial | MeshBasicMaterial | Material | MeshPhysicalNodeMaterial | null;
152
156
  camera: PerspectiveCamera | OrthographicCamera | null;
153
157
  parent: USDObject | null;
154
158
  skinnedMesh: SkinnedMesh | null;
@@ -180,7 +184,7 @@ class USDObject {
180
184
  return empty;
181
185
  }
182
186
 
183
- constructor( id, name, transform: USDObjectTransform | null = null, mesh: BufferGeometry | null = null, material: MeshStandardMaterial | MeshBasicMaterial | Material | null = null, camera: PerspectiveCamera | OrthographicCamera | null = null, skinnedMesh: SkinnedMesh | null = null, animations: AnimationClip[] | null = null ) {
187
+ constructor( id, name, transform: USDObjectTransform | null = null, mesh: BufferGeometry | null = null, material: MeshStandardMaterial | MeshBasicMaterial | MeshPhysicalNodeMaterial | Material | null = null, camera: PerspectiveCamera | OrthographicCamera | null = null, skinnedMesh: SkinnedMesh | null = null, animations: AnimationClip[] | null = null ) {
184
188
 
185
189
  this.uuid = id;
186
190
  this.name = makeNameSafe( name );
@@ -847,14 +851,16 @@ function traverse( object: Object3D, parentModel: USDObject, context: USDZExport
847
851
  }
848
852
 
849
853
  if ( (object instanceof Mesh || object instanceof SkinnedMesh) &&
850
- material &&
854
+ material && typeof material === 'object' &&
851
855
  (material instanceof MeshStandardMaterial ||
852
- material instanceof MeshBasicMaterial ||
856
+ material instanceof MeshBasicMaterial ||
857
+ // material instanceof MeshPhysicalNodeMaterial ||
858
+ (material as any).isMeshPhysicalNodeMaterial ||
853
859
  (material instanceof Material && material.type === "MeshLineMaterial"))) {
854
860
 
855
861
  const name = getObjectId( object );
856
862
  const skinnedMeshObject = object instanceof SkinnedMesh ? object : null;
857
- model = new USDObject( object.uuid, name, transform, geometry, material, undefined, skinnedMeshObject, object.animations );
863
+ model = new USDObject( object.uuid, name, transform, geometry, material as any, undefined, skinnedMeshObject, object.animations );
858
864
 
859
865
  } else if ( object instanceof PerspectiveCamera || object instanceof OrthographicCamera ) {
860
866
 
@@ -1966,6 +1972,137 @@ ${array.join( '' )}
1966
1972
  /** Slot of the exported texture. Some slots (e.g. normal, opacity) require additional processing. */
1967
1973
  declare type MapType = 'diffuse' | 'normal' | 'occlusion' | 'opacity' | 'roughness' | 'emissive' | 'metallic' | 'transmission';
1968
1974
 
1975
+ function texName(tex: Texture) {
1976
+ // If we have a source, we only want to use the source's id, not the texture's id
1977
+ // to avoid exporting the same underlying data multiple times.
1978
+ return makeNameSafe(tex.name) + '_' + (tex.source?.id ?? tex.id);
1979
+ }
1980
+
1981
+ function buildTexture( texture: Texture, mapType: MapType, quickLookCompatible: boolean, textures: TextureMap, material, usedUVChannels, color: Color | undefined = undefined, opacity: number | undefined = undefined ) {
1982
+
1983
+ const name = texName(texture);
1984
+ // File names need to be unique; so when we're baking color and/or opacity into a texture we need to keep track of that.
1985
+ // TODO This currently results in textures potentially being exported multiple times that are actually identical!
1986
+ // const colorHex = color ? color.getHexString() : undefined;
1987
+ // const colorId = ( color && colorHex != 'ffffff' ? '_' + color.getHexString() : '' );
1988
+ const id = name + ( opacity !== undefined && opacity !== 1.0 ? '_' + opacity : '' );
1989
+
1990
+ // Seems neither QuickLook nor usdview support scale/bias on .a values, so we need to bake opacity multipliers into
1991
+ // the texture. This is not ideal.
1992
+ const opacityIsAppliedToTextureAndNotAsScale = quickLookCompatible && opacity !== undefined && opacity !== 1.0;
1993
+ const scaleToApply = opacityIsAppliedToTextureAndNotAsScale ? new Vector4(1, 1, 1, opacity) : undefined;
1994
+
1995
+ // Treat undefined opacity as 1
1996
+ if (opacity === undefined)
1997
+ opacity = 1.0;
1998
+
1999
+ // When we're baking opacity into the texture, we shouldn't apply it as scale as well – so we set it to 1.
2000
+ if (opacityIsAppliedToTextureAndNotAsScale)
2001
+ opacity = 1.0;
2002
+
2003
+ // sanitize scaleToApply.w === 0 - this isn't working right now, seems the PNG can't be read back properly.
2004
+ if (scaleToApply && scaleToApply.w <= 0.05) scaleToApply.w = 0.05;
2005
+
2006
+ textures[ id ] = { texture, scale: scaleToApply };
2007
+
2008
+ const uv = texture.channel > 0 ? 'st' + texture.channel : 'st';
2009
+ usedUVChannels.add(texture.channel);
2010
+
2011
+ const isRGBA = formatsWithAlphaChannel.includes( texture.format );
2012
+
2013
+ const WRAPPINGS = {
2014
+ 1000: 'repeat', // RepeatWrapping
2015
+ 1001: 'clamp', // ClampToEdgeWrapping
2016
+ 1002: 'mirror' // MirroredRepeatWrapping
2017
+ };
2018
+
2019
+ const repeat = texture.repeat.clone();
2020
+ const offset = texture.offset.clone();
2021
+ const rotation = texture.rotation;
2022
+
2023
+ // rotation is around the wrong point. after rotation we need to shift offset again so that we're rotating around the right spot
2024
+ const xRotationOffset = Math.sin(rotation);
2025
+ const yRotationOffset = Math.cos(rotation);
2026
+
2027
+ // texture coordinates start in the opposite corner, need to correct
2028
+ offset.y = 1 - offset.y - repeat.y;
2029
+
2030
+ // turns out QuickLook is buggy and interprets texture repeat inverted.
2031
+ // Apple Feedback: FB10036297 and FB11442287
2032
+ if ( quickLookCompatible ) {
2033
+
2034
+ // This is NOT correct yet in QuickLook, but comes close for a range of models.
2035
+ // It becomes more incorrect the bigger the offset is
2036
+
2037
+ // sanitize repeat values to avoid NaNs
2038
+ if (repeat.x === 0) repeat.x = 0.0001;
2039
+ if (repeat.y === 0) repeat.y = 0.0001;
2040
+
2041
+ offset.x = offset.x / repeat.x;
2042
+ offset.y = offset.y / repeat.y;
2043
+
2044
+ offset.x += xRotationOffset / repeat.x;
2045
+ offset.y += yRotationOffset - 1;
2046
+ }
2047
+
2048
+ else {
2049
+
2050
+ // results match glTF results exactly. verified correct in usdview.
2051
+ offset.x += xRotationOffset * repeat.x;
2052
+ offset.y += (1 - yRotationOffset) * repeat.y;
2053
+
2054
+ }
2055
+
2056
+ const materialName = getMaterialName(material);
2057
+
2058
+ const needsTextureTransform = ( repeat.x != 1 || repeat.y != 1 || offset.x != 0 || offset.y != 0 || rotation != 0 );
2059
+ const textureTransformInput = `${materialRoot}/${materialName}/${'uvReader_' + uv}.outputs:result>`; const textureTransformOutput = `${materialRoot}/${materialName}/Transform2d_${mapType}.outputs:result>`;
2060
+ const needsTextureScale = mapType !== 'normal' && (color && (color.r !== 1 || color.g !== 1 || color.b !== 1 || opacity !== 1)) || false;
2061
+
2062
+ const needsNormalScaleAndBias = mapType === 'normal';
2063
+ const normalScale = material instanceof MeshStandardMaterial ? (material.normalScale ? material.normalScale.x * 2 : 2) : 2;
2064
+ const normalScaleValueString = normalScale.toFixed( PRECISION );
2065
+ const normalBiasString = (-1 * (normalScale / 2)).toFixed( PRECISION );
2066
+ const normalBiasZString = (1 - normalScale).toFixed( PRECISION );
2067
+
2068
+ return `
2069
+ ${needsTextureTransform ? `def Shader "Transform2d_${mapType}" (
2070
+ sdrMetadata = {
2071
+ string role = "math"
2072
+ }
2073
+ )
2074
+ {
2075
+ uniform token info:id = "UsdTransform2d"
2076
+ float2 inputs:in.connect = ${textureTransformInput}
2077
+ float2 inputs:scale = ${buildVector2( repeat )}
2078
+ float2 inputs:translation = ${buildVector2( offset )}
2079
+ float inputs:rotation = ${(rotation / Math.PI * 180).toFixed( PRECISION )}
2080
+ float2 outputs:result
2081
+ }
2082
+ ` : '' }
2083
+ def Shader "${name}_${mapType}"
2084
+ {
2085
+ uniform token info:id = "UsdUVTexture"
2086
+ asset inputs:file = @textures/${id}.${isRGBA ? 'png' : 'jpg'}@
2087
+ token inputs:sourceColorSpace = "${ texture.colorSpace === 'srgb' ? 'sRGB' : 'raw' }"
2088
+ float2 inputs:st.connect = ${needsTextureTransform ? textureTransformOutput : textureTransformInput}
2089
+ ${needsTextureScale ? `
2090
+ float4 inputs:scale = (${color ? color.r + ', ' + color.g + ', ' + color.b : '1, 1, 1'}, ${opacity})
2091
+ ` : `` }
2092
+ ${needsNormalScaleAndBias ? `
2093
+ float4 inputs:scale = (${normalScaleValueString}, ${normalScaleValueString}, ${normalScaleValueString}, 1)
2094
+ float4 inputs:bias = (${normalBiasString}, ${normalBiasString}, ${normalBiasZString}, 0)
2095
+ ` : `` }
2096
+ token inputs:wrapS = "${ WRAPPINGS[ texture.wrapS ] }"
2097
+ token inputs:wrapT = "${ WRAPPINGS[ texture.wrapT ] }"
2098
+ float outputs:r
2099
+ float outputs:g
2100
+ float outputs:b
2101
+ float3 outputs:rgb
2102
+ ${material.transparent || material.alphaTest > 0.0 ? 'float outputs:a' : ''}
2103
+ }`;
2104
+ }
2105
+
1969
2106
  function buildMaterial( material: MeshBasicMaterial, textures: TextureMap, quickLookCompatible = false ) {
1970
2107
 
1971
2108
  const materialName = getMaterialName(material);
@@ -2008,133 +2145,8 @@ function buildMaterial( material: MeshBasicMaterial, textures: TextureMap, quick
2008
2145
  const samplers: Array<string> = [];
2009
2146
  const usedUVChannels: Set<number> = new Set();
2010
2147
 
2011
- function texName(tex: Texture) {
2012
- // If we have a source, we only want to use the source's id, not the texture's id
2013
- // to avoid exporting the same underlying data multiple times.
2014
- return makeNameSafe(tex.name) + '_' + (tex.source?.id ?? tex.id);
2015
- }
2016
-
2017
- function buildTexture( texture: Texture, mapType: MapType, color: Color | undefined = undefined, opacity: number | undefined = undefined ) {
2018
-
2019
- const name = texName(texture);
2020
- // File names need to be unique; so when we're baking color and/or opacity into a texture we need to keep track of that.
2021
- // TODO This currently results in textures potentially being exported multiple times that are actually identical!
2022
- // const colorHex = color ? color.getHexString() : undefined;
2023
- // const colorId = ( color && colorHex != 'ffffff' ? '_' + color.getHexString() : '' );
2024
- const id = name + ( opacity !== undefined && opacity !== 1.0 ? '_' + opacity : '' );
2025
-
2026
- // Seems neither QuickLook nor usdview support scale/bias on .a values, so we need to bake opacity multipliers into
2027
- // the texture. This is not ideal.
2028
- const opacityIsAppliedToTextureAndNotAsScale = quickLookCompatible && opacity !== undefined && opacity !== 1.0;
2029
- const scaleToApply = opacityIsAppliedToTextureAndNotAsScale ? new Vector4(1, 1, 1, opacity) : undefined;
2030
-
2031
- // Treat undefined opacity as 1
2032
- if (opacity === undefined)
2033
- opacity = 1.0;
2034
-
2035
- // When we're baking opacity into the texture, we shouldn't apply it as scale as well – so we set it to 1.
2036
- if (opacityIsAppliedToTextureAndNotAsScale)
2037
- opacity = 1.0;
2038
-
2039
- // sanitize scaleToApply.w === 0 - this isn't working right now, seems the PNG can't be read back properly.
2040
- if (scaleToApply && scaleToApply.w <= 0.05) scaleToApply.w = 0.05;
2041
-
2042
- textures[ id ] = { texture, scale: scaleToApply };
2043
-
2044
- const uv = texture.channel > 0 ? 'st' + texture.channel : 'st';
2045
- usedUVChannels.add(texture.channel);
2046
-
2047
- const isRGBA = formatsWithAlphaChannel.includes( texture.format );
2048
-
2049
- const WRAPPINGS = {
2050
- 1000: 'repeat', // RepeatWrapping
2051
- 1001: 'clamp', // ClampToEdgeWrapping
2052
- 1002: 'mirror' // MirroredRepeatWrapping
2053
- };
2054
-
2055
- const repeat = texture.repeat.clone();
2056
- const offset = texture.offset.clone();
2057
- const rotation = texture.rotation;
2058
-
2059
- // rotation is around the wrong point. after rotation we need to shift offset again so that we're rotating around the right spot
2060
- const xRotationOffset = Math.sin(rotation);
2061
- const yRotationOffset = Math.cos(rotation);
2062
-
2063
- // texture coordinates start in the opposite corner, need to correct
2064
- offset.y = 1 - offset.y - repeat.y;
2065
-
2066
- // turns out QuickLook is buggy and interprets texture repeat inverted.
2067
- // Apple Feedback: FB10036297 and FB11442287
2068
- if ( quickLookCompatible ) {
2069
-
2070
- // This is NOT correct yet in QuickLook, but comes close for a range of models.
2071
- // It becomes more incorrect the bigger the offset is
2072
-
2073
- // sanitize repeat values to avoid NaNs
2074
- if (repeat.x === 0) repeat.x = 0.0001;
2075
- if (repeat.y === 0) repeat.y = 0.0001;
2076
-
2077
- offset.x = offset.x / repeat.x;
2078
- offset.y = offset.y / repeat.y;
2079
-
2080
- offset.x += xRotationOffset / repeat.x;
2081
- offset.y += yRotationOffset - 1;
2082
- }
2083
-
2084
- else {
2085
-
2086
- // results match glTF results exactly. verified correct in usdview.
2087
- offset.x += xRotationOffset * repeat.x;
2088
- offset.y += (1 - yRotationOffset) * repeat.y;
2089
-
2090
- }
2091
-
2092
- const needsTextureTransform = ( repeat.x != 1 || repeat.y != 1 || offset.x != 0 || offset.y != 0 || rotation != 0 );
2093
- const textureTransformInput = `${materialRoot}/${materialName}/${'uvReader_' + uv}.outputs:result>`; const textureTransformOutput = `${materialRoot}/${materialName}/Transform2d_${mapType}.outputs:result>`;
2094
- const needsTextureScale = mapType !== 'normal' && (color && (color.r !== 1 || color.g !== 1 || color.b !== 1 || opacity !== 1)) || false;
2095
-
2096
- const needsNormalScaleAndBias = mapType === 'normal';
2097
- const normalScale = material instanceof MeshStandardMaterial ? (material.normalScale ? material.normalScale.x * 2 : 2) : 2;
2098
- const normalScaleValueString = normalScale.toFixed( PRECISION );
2099
- const normalBiasString = (-1 * (normalScale / 2)).toFixed( PRECISION );
2100
- const normalBiasZString = (1 - normalScale).toFixed( PRECISION );
2101
-
2102
- return `
2103
- ${needsTextureTransform ? `def Shader "Transform2d_${mapType}" (
2104
- sdrMetadata = {
2105
- string role = "math"
2106
- }
2107
- )
2108
- {
2109
- uniform token info:id = "UsdTransform2d"
2110
- float2 inputs:in.connect = ${textureTransformInput}
2111
- float2 inputs:scale = ${buildVector2( repeat )}
2112
- float2 inputs:translation = ${buildVector2( offset )}
2113
- float inputs:rotation = ${(rotation / Math.PI * 180).toFixed( PRECISION )}
2114
- float2 outputs:result
2115
- }
2116
- ` : '' }
2117
- def Shader "${name}_${mapType}"
2118
- {
2119
- uniform token info:id = "UsdUVTexture"
2120
- asset inputs:file = @textures/${id}.${isRGBA ? 'png' : 'jpg'}@
2121
- token inputs:sourceColorSpace = "${ texture.colorSpace === 'srgb' ? 'sRGB' : 'raw' }"
2122
- float2 inputs:st.connect = ${needsTextureTransform ? textureTransformOutput : textureTransformInput}
2123
- ${needsTextureScale ? `
2124
- float4 inputs:scale = (${color ? color.r + ', ' + color.g + ', ' + color.b : '1, 1, 1'}, ${opacity})
2125
- ` : `` }
2126
- ${needsNormalScaleAndBias ? `
2127
- float4 inputs:scale = (${normalScaleValueString}, ${normalScaleValueString}, ${normalScaleValueString}, 1)
2128
- float4 inputs:bias = (${normalBiasString}, ${normalBiasString}, ${normalBiasZString}, 0)
2129
- ` : `` }
2130
- token inputs:wrapS = "${ WRAPPINGS[ texture.wrapS ] }"
2131
- token inputs:wrapT = "${ WRAPPINGS[ texture.wrapT ] }"
2132
- float outputs:r
2133
- float outputs:g
2134
- float outputs:b
2135
- float3 outputs:rgb
2136
- ${material.transparent || material.alphaTest > 0.0 ? 'float outputs:a' : ''}
2137
- }`;
2148
+ if ((material as any).isMeshPhysicalNodeMaterial === true) {
2149
+ return buildNodeMaterial(material as unknown as MeshPhysicalNodeMaterial, materialName, textures);
2138
2150
  }
2139
2151
 
2140
2152
  let effectiveOpacity = ( material.transparent || material.alphaTest ) ? material.opacity : 1;
@@ -2175,7 +2187,7 @@ function buildMaterial( material: MeshBasicMaterial, textures: TextureMap, quick
2175
2187
 
2176
2188
  }
2177
2189
 
2178
- samplers.push( buildTexture( material.map, 'diffuse', material.color, effectiveOpacity ) );
2190
+ samplers.push( buildTexture( material.map, 'diffuse', quickLookCompatible, textures, material, usedUVChannels, material.color, effectiveOpacity ) );
2179
2191
 
2180
2192
  } else {
2181
2193
 
@@ -2200,7 +2212,7 @@ function buildMaterial( material: MeshBasicMaterial, textures: TextureMap, quick
2200
2212
 
2201
2213
  inputs.push( `${pad}float inputs:occlusion.connect = ${materialRoot}/${materialName}/${texName(material.aoMap)}_occlusion.outputs:r>` );
2202
2214
 
2203
- samplers.push( buildTexture( material.aoMap, 'occlusion' ) );
2215
+ samplers.push( buildTexture( material.aoMap, 'occlusion', quickLookCompatible, textures, material, usedUVChannels ) );
2204
2216
 
2205
2217
  }
2206
2218
 
@@ -2212,7 +2224,7 @@ function buildMaterial( material: MeshBasicMaterial, textures: TextureMap, quick
2212
2224
  haveConnectedOpacity = true;
2213
2225
  haveConnectedOpacityThreshold = true;
2214
2226
 
2215
- samplers.push( buildTexture( material.alphaMap, 'opacity', new Color( 1, 1, 1 ), effectiveOpacity ) );
2227
+ samplers.push( buildTexture( material.alphaMap, 'opacity', quickLookCompatible, textures, material, usedUVChannels, new Color( 1, 1, 1 ), effectiveOpacity ) );
2216
2228
 
2217
2229
  } else { // opacity will always be connected if we have a map
2218
2230
 
@@ -2243,7 +2255,7 @@ function buildMaterial( material: MeshBasicMaterial, textures: TextureMap, quick
2243
2255
  inputs.push( `${pad}color3f inputs:emissiveColor.connect = ${materialRoot}/${materialName}/${texName(material.emissiveMap)}_emissive.outputs:rgb>` );
2244
2256
  const color = material.emissive.clone();
2245
2257
  color.multiplyScalar( material.emissiveIntensity );
2246
- samplers.push( buildTexture( material.emissiveMap, 'emissive', color ) );
2258
+ samplers.push( buildTexture( material.emissiveMap, 'emissive', quickLookCompatible, textures, material, usedUVChannels, color ) );
2247
2259
 
2248
2260
  } else if ( material.emissive?.getHex() > 0 ) {
2249
2261
 
@@ -2262,7 +2274,7 @@ function buildMaterial( material: MeshBasicMaterial, textures: TextureMap, quick
2262
2274
 
2263
2275
  inputs.push( `${pad}normal3f inputs:normal.connect = ${materialRoot}/${materialName}/${texName(material.normalMap)}_normal.outputs:rgb>` );
2264
2276
 
2265
- samplers.push( buildTexture( material.normalMap, 'normal' ) );
2277
+ samplers.push( buildTexture( material.normalMap, 'normal', quickLookCompatible, textures, material, usedUVChannels ) );
2266
2278
 
2267
2279
  }
2268
2280
 
@@ -2270,7 +2282,7 @@ function buildMaterial( material: MeshBasicMaterial, textures: TextureMap, quick
2270
2282
 
2271
2283
  inputs.push( `${pad}float inputs:roughness.connect = ${materialRoot}/${materialName}/${texName(material.roughnessMap)}_roughness.outputs:g>` );
2272
2284
 
2273
- samplers.push( buildTexture( material.roughnessMap, 'roughness' ) );
2285
+ samplers.push( buildTexture( material.roughnessMap, 'roughness', quickLookCompatible, textures, material, usedUVChannels ) );
2274
2286
 
2275
2287
  } else {
2276
2288
 
@@ -2282,7 +2294,7 @@ function buildMaterial( material: MeshBasicMaterial, textures: TextureMap, quick
2282
2294
 
2283
2295
  inputs.push( `${pad}float inputs:metallic.connect = ${materialRoot}/${materialName}/${texName(material.metalnessMap)}_metallic.outputs:b>` );
2284
2296
 
2285
- samplers.push( buildTexture( material.metalnessMap, 'metallic' ) );
2297
+ samplers.push( buildTexture( material.metalnessMap, 'metallic', quickLookCompatible, textures, material, usedUVChannels ) );
2286
2298
 
2287
2299
  } else {
2288
2300
 
@@ -2302,7 +2314,7 @@ function buildMaterial( material: MeshBasicMaterial, textures: TextureMap, quick
2302
2314
 
2303
2315
  inputs.push( `${pad}float inputs:opacity.connect = ${materialRoot}/${materialName}/${texName(material.transmissionMap)}_transmission.outputs:r>` );
2304
2316
 
2305
- samplers.push( buildTexture( material.transmissionMap, 'transmission' ) );
2317
+ samplers.push( buildTexture( material.transmissionMap, 'transmission', quickLookCompatible, textures, material, usedUVChannels ) );
2306
2318
  }
2307
2319
 
2308
2320
  }
@@ -2399,12 +2411,13 @@ export {
2399
2411
  buildMatrix,
2400
2412
  decompressGpuTexture,
2401
2413
  findStructuralNodesInBoneHierarchy,
2414
+ formatsWithAlphaChannel,
2402
2415
  getBoneName,
2403
2416
  getMaterialName as getMaterialNameForUSD,
2404
2417
  getPathToSkeleton,
2405
2418
  imageToCanvas,
2406
2419
  imageToCanvasUnpremultiplied,
2407
- makeNameSafe as makeNameSafeForUSD,
2420
+ makeNameSafe as makeNameSafeForUSD,
2408
2421
  USDDocument,
2409
2422
  fn as usdNumberFormatting,
2410
2423
  USDObject,