@luma.gl/gltf 9.2.6 → 9.3.0-alpha.11
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.
- package/dist/dist.dev.js +4064 -1967
- package/dist/dist.min.js +117 -46
- package/dist/gltf/animations/animations.d.ts +57 -5
- package/dist/gltf/animations/animations.d.ts.map +1 -1
- package/dist/gltf/animations/interpolate.d.ts +6 -3
- package/dist/gltf/animations/interpolate.d.ts.map +1 -1
- package/dist/gltf/animations/interpolate.js +47 -51
- package/dist/gltf/animations/interpolate.js.map +1 -1
- package/dist/gltf/create-gltf-model.d.ts +15 -1
- package/dist/gltf/create-gltf-model.d.ts.map +1 -1
- package/dist/gltf/create-gltf-model.js +168 -43
- package/dist/gltf/create-gltf-model.js.map +1 -1
- package/dist/gltf/create-scenegraph-from-gltf.d.ts +39 -2
- package/dist/gltf/create-scenegraph-from-gltf.d.ts.map +1 -1
- package/dist/gltf/create-scenegraph-from-gltf.js +76 -6
- package/dist/gltf/create-scenegraph-from-gltf.js.map +1 -1
- package/dist/gltf/gltf-animator.d.ts +37 -0
- package/dist/gltf/gltf-animator.d.ts.map +1 -1
- package/dist/gltf/gltf-animator.js +112 -17
- package/dist/gltf/gltf-animator.js.map +1 -1
- package/dist/gltf/gltf-extension-support.d.ts +13 -0
- package/dist/gltf/gltf-extension-support.d.ts.map +1 -0
- package/dist/gltf/gltf-extension-support.js +178 -0
- package/dist/gltf/gltf-extension-support.js.map +1 -0
- package/dist/index.cjs +1806 -298
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/parsers/parse-gltf-animations.d.ts +1 -0
- package/dist/parsers/parse-gltf-animations.d.ts.map +1 -1
- package/dist/parsers/parse-gltf-animations.js +373 -27
- package/dist/parsers/parse-gltf-animations.js.map +1 -1
- package/dist/parsers/parse-gltf-lights.d.ts +5 -0
- package/dist/parsers/parse-gltf-lights.d.ts.map +1 -0
- package/dist/parsers/parse-gltf-lights.js +163 -0
- package/dist/parsers/parse-gltf-lights.js.map +1 -0
- package/dist/parsers/parse-gltf.d.ts +19 -2
- package/dist/parsers/parse-gltf.d.ts.map +1 -1
- package/dist/parsers/parse-gltf.js +120 -67
- package/dist/parsers/parse-gltf.js.map +1 -1
- package/dist/parsers/parse-pbr-material.d.ts +115 -2
- package/dist/parsers/parse-pbr-material.d.ts.map +1 -1
- package/dist/parsers/parse-pbr-material.js +602 -53
- package/dist/parsers/parse-pbr-material.js.map +1 -1
- package/dist/pbr/pbr-environment.d.ts +10 -4
- package/dist/pbr/pbr-environment.d.ts.map +1 -1
- package/dist/pbr/pbr-environment.js +18 -15
- package/dist/pbr/pbr-environment.js.map +1 -1
- package/dist/pbr/pbr-material.d.ts +13 -3
- package/dist/pbr/pbr-material.d.ts.map +1 -1
- package/dist/pbr/texture-transform.d.ts +24 -0
- package/dist/pbr/texture-transform.d.ts.map +1 -0
- package/dist/pbr/texture-transform.js +98 -0
- package/dist/pbr/texture-transform.js.map +1 -0
- package/dist/webgl-to-webgpu/convert-webgl-attribute.d.ts +12 -1
- package/dist/webgl-to-webgpu/convert-webgl-attribute.d.ts.map +1 -1
- package/dist/webgl-to-webgpu/convert-webgl-attribute.js +3 -0
- package/dist/webgl-to-webgpu/convert-webgl-attribute.js.map +1 -1
- package/dist/webgl-to-webgpu/convert-webgl-sampler.d.ts +11 -5
- package/dist/webgl-to-webgpu/convert-webgl-sampler.d.ts.map +1 -1
- package/dist/webgl-to-webgpu/convert-webgl-sampler.js +16 -12
- package/dist/webgl-to-webgpu/convert-webgl-sampler.js.map +1 -1
- package/dist/webgl-to-webgpu/convert-webgl-topology.d.ts +2 -9
- package/dist/webgl-to-webgpu/convert-webgl-topology.d.ts.map +1 -1
- package/dist/webgl-to-webgpu/convert-webgl-topology.js +3 -15
- package/dist/webgl-to-webgpu/convert-webgl-topology.js.map +1 -1
- package/dist/webgl-to-webgpu/gltf-webgl-constants.d.ts +27 -0
- package/dist/webgl-to-webgpu/gltf-webgl-constants.d.ts.map +1 -0
- package/dist/webgl-to-webgpu/gltf-webgl-constants.js +34 -0
- package/dist/webgl-to-webgpu/gltf-webgl-constants.js.map +1 -0
- package/package.json +8 -9
- package/src/gltf/animations/animations.ts +88 -6
- package/src/gltf/animations/interpolate.ts +84 -96
- package/src/gltf/create-gltf-model.ts +233 -48
- package/src/gltf/create-scenegraph-from-gltf.ts +134 -11
- package/src/gltf/gltf-animator.ts +198 -20
- package/src/gltf/gltf-extension-support.ts +226 -0
- package/src/index.ts +11 -2
- package/src/parsers/parse-gltf-animations.ts +533 -32
- package/src/parsers/parse-gltf-lights.ts +218 -0
- package/src/parsers/parse-gltf.ts +189 -96
- package/src/parsers/parse-pbr-material.ts +974 -79
- package/src/pbr/pbr-environment.ts +44 -21
- package/src/pbr/pbr-material.ts +18 -3
- package/src/pbr/texture-transform.ts +263 -0
- package/src/webgl-to-webgpu/convert-webgl-attribute.ts +12 -1
- package/src/webgl-to-webgpu/convert-webgl-sampler.ts +38 -29
- package/src/webgl-to-webgpu/convert-webgl-topology.ts +3 -15
- package/src/webgl-to-webgpu/gltf-webgl-constants.ts +35 -0
- package/dist/utils/deep-copy.d.ts +0 -3
- package/dist/utils/deep-copy.d.ts.map +0 -1
- package/dist/utils/deep-copy.js +0 -21
- package/dist/utils/deep-copy.js.map +0 -1
- package/src/utils/deep-copy.ts +0 -22
|
@@ -2,14 +2,23 @@
|
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
4
|
|
|
5
|
-
import type {Device,
|
|
6
|
-
import {
|
|
5
|
+
import type {Device, SamplerProps, TextureFormat, TypedArray} from '@luma.gl/core';
|
|
6
|
+
import {Texture, log, textureFormatDecoder} from '@luma.gl/core';
|
|
7
|
+
import type {GLTFPostprocessed, GLTFSampler} from '@loaders.gl/gltf';
|
|
7
8
|
|
|
8
|
-
import {log} from '@luma.gl/core';
|
|
9
9
|
import {type ParsedPBRMaterial} from '../pbr/pbr-material';
|
|
10
10
|
import {type PBREnvironment} from '../pbr/pbr-environment';
|
|
11
11
|
import {type PBRMaterialBindings} from '@luma.gl/shadertools';
|
|
12
|
+
import {GLEnum} from '../webgl-to-webgpu/gltf-webgl-constants';
|
|
12
13
|
import {convertSampler} from '../webgl-to-webgpu/convert-webgl-sampler';
|
|
14
|
+
import {
|
|
15
|
+
getTextureTransformSlotDefinition,
|
|
16
|
+
getTextureTransformSlotDefinitions,
|
|
17
|
+
getTextureTransformMatrix,
|
|
18
|
+
resolveTextureCoordinateSet,
|
|
19
|
+
resolveTextureTransform,
|
|
20
|
+
type PBRTextureTransformSlot
|
|
21
|
+
} from '../pbr/texture-transform';
|
|
13
22
|
|
|
14
23
|
// TODO - synchronize the GLTF... types with loaders.gl
|
|
15
24
|
// TODO - remove the glParameters, use only parameters
|
|
@@ -18,6 +27,7 @@ import {convertSampler} from '../webgl-to-webgpu/convert-webgl-sampler';
|
|
|
18
27
|
|
|
19
28
|
type GLTFTexture = {
|
|
20
29
|
id: string;
|
|
30
|
+
index?: number;
|
|
21
31
|
texture: {source: {image: any}; sampler: {parameters: any}};
|
|
22
32
|
uniformName?: string;
|
|
23
33
|
// is this on all textures?
|
|
@@ -35,16 +45,116 @@ type GLTFPBRMetallicRoughness = {
|
|
|
35
45
|
};
|
|
36
46
|
|
|
37
47
|
type GLTFPBRMaterial = {
|
|
48
|
+
extensions?: GLTFMaterialExtensions;
|
|
38
49
|
unlit?: boolean;
|
|
39
50
|
pbrMetallicRoughness?: GLTFPBRMetallicRoughness;
|
|
40
51
|
normalTexture?: GLTFTexture;
|
|
41
52
|
occlusionTexture?: GLTFTexture;
|
|
42
53
|
emissiveTexture?: GLTFTexture;
|
|
43
54
|
emissiveFactor?: [number, number, number];
|
|
44
|
-
alphaMode?: 'MASK' | 'BLEND';
|
|
55
|
+
alphaMode?: 'OPAQUE' | 'MASK' | 'BLEND';
|
|
56
|
+
doubleSided?: boolean;
|
|
45
57
|
alphaCutoff?: number;
|
|
46
58
|
};
|
|
47
59
|
|
|
60
|
+
type GLTFMaterialSpecularExtension = {
|
|
61
|
+
specularFactor?: number;
|
|
62
|
+
specularTexture?: GLTFTexture;
|
|
63
|
+
specularColorFactor?: [number, number, number];
|
|
64
|
+
specularColorTexture?: GLTFTexture;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
type GLTFMaterialIorExtension = {
|
|
68
|
+
ior?: number;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
type GLTFMaterialTransmissionExtension = {
|
|
72
|
+
transmissionFactor?: number;
|
|
73
|
+
transmissionTexture?: GLTFTexture;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
type GLTFMaterialVolumeExtension = {
|
|
77
|
+
thicknessFactor?: number;
|
|
78
|
+
thicknessTexture?: GLTFTexture;
|
|
79
|
+
attenuationDistance?: number;
|
|
80
|
+
attenuationColor?: [number, number, number];
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
type GLTFMaterialClearcoatExtension = {
|
|
84
|
+
clearcoatFactor?: number;
|
|
85
|
+
clearcoatTexture?: GLTFTexture;
|
|
86
|
+
clearcoatRoughnessFactor?: number;
|
|
87
|
+
clearcoatRoughnessTexture?: GLTFTexture;
|
|
88
|
+
clearcoatNormalTexture?: GLTFTexture;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
type GLTFMaterialSheenExtension = {
|
|
92
|
+
sheenColorFactor?: [number, number, number];
|
|
93
|
+
sheenColorTexture?: GLTFTexture;
|
|
94
|
+
sheenRoughnessFactor?: number;
|
|
95
|
+
sheenRoughnessTexture?: GLTFTexture;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
type GLTFMaterialIridescenceExtension = {
|
|
99
|
+
iridescenceFactor?: number;
|
|
100
|
+
iridescenceTexture?: GLTFTexture;
|
|
101
|
+
iridescenceIor?: number;
|
|
102
|
+
iridescenceThicknessMinimum?: number;
|
|
103
|
+
iridescenceThicknessMaximum?: number;
|
|
104
|
+
iridescenceThicknessTexture?: GLTFTexture;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
type GLTFMaterialAnisotropyExtension = {
|
|
108
|
+
anisotropyStrength?: number;
|
|
109
|
+
anisotropyRotation?: number;
|
|
110
|
+
anisotropyTexture?: GLTFTexture;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
type GLTFMaterialEmissiveStrengthExtension = {
|
|
114
|
+
emissiveStrength?: number;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
type GLTFMaterialExtensions = {
|
|
118
|
+
KHR_materials_unlit?: Record<string, never>;
|
|
119
|
+
KHR_materials_specular?: GLTFMaterialSpecularExtension;
|
|
120
|
+
KHR_materials_ior?: GLTFMaterialIorExtension;
|
|
121
|
+
KHR_materials_transmission?: GLTFMaterialTransmissionExtension;
|
|
122
|
+
KHR_materials_volume?: GLTFMaterialVolumeExtension;
|
|
123
|
+
KHR_materials_clearcoat?: GLTFMaterialClearcoatExtension;
|
|
124
|
+
KHR_materials_sheen?: GLTFMaterialSheenExtension;
|
|
125
|
+
KHR_materials_iridescence?: GLTFMaterialIridescenceExtension;
|
|
126
|
+
KHR_materials_anisotropy?: GLTFMaterialAnisotropyExtension;
|
|
127
|
+
KHR_materials_emissive_strength?: GLTFMaterialEmissiveStrengthExtension;
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
type TextureEnabledUniformName =
|
|
131
|
+
| 'baseColorMapEnabled'
|
|
132
|
+
| 'normalMapEnabled'
|
|
133
|
+
| 'emissiveMapEnabled'
|
|
134
|
+
| 'metallicRoughnessMapEnabled'
|
|
135
|
+
| 'occlusionMapEnabled'
|
|
136
|
+
| 'specularColorMapEnabled'
|
|
137
|
+
| 'specularIntensityMapEnabled'
|
|
138
|
+
| 'transmissionMapEnabled'
|
|
139
|
+
| 'clearcoatMapEnabled'
|
|
140
|
+
| 'clearcoatRoughnessMapEnabled'
|
|
141
|
+
| 'sheenColorMapEnabled'
|
|
142
|
+
| 'sheenRoughnessMapEnabled'
|
|
143
|
+
| 'iridescenceMapEnabled'
|
|
144
|
+
| 'anisotropyMapEnabled';
|
|
145
|
+
|
|
146
|
+
type TextureFeatureOptions = {
|
|
147
|
+
define?: string;
|
|
148
|
+
enabledUniformName?: TextureEnabledUniformName;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
type TextureParseOptions = {
|
|
152
|
+
featureOptions?: TextureFeatureOptions;
|
|
153
|
+
gltf?: GLTFPostprocessed;
|
|
154
|
+
attributes?: Record<string, any>;
|
|
155
|
+
textureTransformSlot?: PBRTextureTransformSlot;
|
|
156
|
+
};
|
|
157
|
+
|
|
48
158
|
export type ParsePBRMaterialOptions = {
|
|
49
159
|
/** Debug PBR shader */
|
|
50
160
|
pbrDebug?: boolean;
|
|
@@ -54,6 +164,10 @@ export type ParsePBRMaterialOptions = {
|
|
|
54
164
|
useTangents?: boolean;
|
|
55
165
|
/** provide an image based (texture cube) lighting environment */
|
|
56
166
|
imageBasedLightingEnvironment?: PBREnvironment;
|
|
167
|
+
/** parent post-processed glTF, used to resolve extension texture infos */
|
|
168
|
+
gltf?: GLTFPostprocessed;
|
|
169
|
+
/** run primitive-attribute diagnostics such as missing TEXCOORD_0 / NORMAL */
|
|
170
|
+
validateAttributes?: boolean;
|
|
57
171
|
};
|
|
58
172
|
|
|
59
173
|
/**
|
|
@@ -92,7 +206,8 @@ export function parsePBRMaterial(
|
|
|
92
206
|
imageBasedLightingEnvironment.diffuseEnvSampler.texture;
|
|
93
207
|
parsedMaterial.bindings.pbr_specularEnvSampler =
|
|
94
208
|
imageBasedLightingEnvironment.specularEnvSampler.texture;
|
|
95
|
-
parsedMaterial.bindings.
|
|
209
|
+
parsedMaterial.bindings.pbr_brdfLUT = imageBasedLightingEnvironment.brdfLutTexture.texture;
|
|
210
|
+
parsedMaterial.uniforms.IBLenabled = true;
|
|
96
211
|
parsedMaterial.uniforms.scaleIBLAmbient = [1, 1];
|
|
97
212
|
}
|
|
98
213
|
|
|
@@ -106,111 +221,233 @@ export function parsePBRMaterial(
|
|
|
106
221
|
if (attributes['NORMAL']) parsedMaterial.defines['HAS_NORMALS'] = true;
|
|
107
222
|
if (attributes['TANGENT'] && options?.useTangents) parsedMaterial.defines['HAS_TANGENTS'] = true;
|
|
108
223
|
if (attributes['TEXCOORD_0']) parsedMaterial.defines['HAS_UV'] = true;
|
|
224
|
+
if (attributes['TEXCOORD_1']) parsedMaterial.defines['HAS_UV_1'] = true;
|
|
225
|
+
if (attributes['JOINTS_0'] && attributes['WEIGHTS_0']) parsedMaterial.defines['HAS_SKIN'] = true;
|
|
226
|
+
if (attributes['COLOR_0']) parsedMaterial.defines['HAS_COLORS'] = true;
|
|
109
227
|
|
|
110
228
|
if (options?.imageBasedLightingEnvironment) parsedMaterial.defines['USE_IBL'] = true;
|
|
111
229
|
if (options?.lights) parsedMaterial.defines['USE_LIGHTS'] = true;
|
|
112
230
|
|
|
113
231
|
if (material) {
|
|
114
|
-
|
|
232
|
+
if (options.validateAttributes !== false) {
|
|
233
|
+
warnOnMissingExpectedAttributes(material, attributes);
|
|
234
|
+
}
|
|
235
|
+
parseMaterial(device, material, parsedMaterial, attributes, options.gltf);
|
|
115
236
|
}
|
|
116
237
|
|
|
117
238
|
return parsedMaterial;
|
|
118
239
|
}
|
|
119
240
|
|
|
241
|
+
function warnOnMissingExpectedAttributes(
|
|
242
|
+
material: GLTFPBRMaterial,
|
|
243
|
+
attributes: Record<string, any>
|
|
244
|
+
): void {
|
|
245
|
+
const uvDependentTextureSlots = getUvDependentTextureSlots(material, 0);
|
|
246
|
+
if (uvDependentTextureSlots.length > 0 && !attributes['TEXCOORD_0']) {
|
|
247
|
+
log.warn(
|
|
248
|
+
`glTF material uses ${uvDependentTextureSlots.join(', ')} but primitive is missing TEXCOORD_0; textured shading will sample the default UV coordinates`
|
|
249
|
+
)();
|
|
250
|
+
}
|
|
251
|
+
const uv1DependentTextureSlots = getUvDependentTextureSlots(material, 1);
|
|
252
|
+
if (uv1DependentTextureSlots.length > 0 && !attributes['TEXCOORD_1']) {
|
|
253
|
+
log.warn(
|
|
254
|
+
`glTF material uses ${uv1DependentTextureSlots.join(', ')} with TEXCOORD_1 but primitive is missing TEXCOORD_1; those textures will be skipped`
|
|
255
|
+
)();
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const isUnlitMaterial = Boolean(material.unlit || material.extensions?.KHR_materials_unlit);
|
|
259
|
+
if (isUnlitMaterial || attributes['NORMAL']) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const missingNormalReason = material.normalTexture
|
|
264
|
+
? 'lit PBR shading with normalTexture'
|
|
265
|
+
: 'lit PBR shading';
|
|
266
|
+
log.warn(
|
|
267
|
+
`glTF primitive is missing NORMAL while using ${missingNormalReason}; shading will fall back to geometric normals`
|
|
268
|
+
)();
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function getUvDependentTextureSlots(
|
|
272
|
+
material: GLTFPBRMaterial,
|
|
273
|
+
textureCoordinateSet: number
|
|
274
|
+
): string[] {
|
|
275
|
+
const uvDependentTextureSlots: string[] = [];
|
|
276
|
+
|
|
277
|
+
for (const slotDefinition of getTextureTransformSlotDefinitions()) {
|
|
278
|
+
const textureInfo = getNestedTextureInfo(material, slotDefinition.pathSegments);
|
|
279
|
+
if (!textureInfo) {
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (resolveTextureCoordinateSet(textureInfo) === textureCoordinateSet) {
|
|
284
|
+
uvDependentTextureSlots.push(slotDefinition.displayName);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return uvDependentTextureSlots;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function getNestedTextureInfo(
|
|
292
|
+
material: GLTFPBRMaterial,
|
|
293
|
+
pathSegments: string[]
|
|
294
|
+
): Record<string, any> | null {
|
|
295
|
+
let value: any = material;
|
|
296
|
+
for (const pathSegment of pathSegments) {
|
|
297
|
+
value = value?.[pathSegment];
|
|
298
|
+
if (!value) {
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return value;
|
|
304
|
+
}
|
|
305
|
+
|
|
120
306
|
/** Parse GLTF material record */
|
|
121
307
|
function parseMaterial(
|
|
122
308
|
device: Device,
|
|
123
309
|
material: GLTFPBRMaterial,
|
|
124
|
-
parsedMaterial: ParsedPBRMaterial
|
|
310
|
+
parsedMaterial: ParsedPBRMaterial,
|
|
311
|
+
attributes: Record<string, any>,
|
|
312
|
+
gltf?: GLTFPostprocessed
|
|
125
313
|
): void {
|
|
126
|
-
parsedMaterial.uniforms.unlit = Boolean(
|
|
314
|
+
parsedMaterial.uniforms.unlit = Boolean(
|
|
315
|
+
material.unlit || material.extensions?.KHR_materials_unlit
|
|
316
|
+
);
|
|
127
317
|
|
|
128
318
|
if (material.pbrMetallicRoughness) {
|
|
129
|
-
parsePbrMetallicRoughness(
|
|
130
|
-
}
|
|
131
|
-
if (material.normalTexture) {
|
|
132
|
-
addTexture(
|
|
319
|
+
parsePbrMetallicRoughness(
|
|
133
320
|
device,
|
|
134
|
-
material.
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
321
|
+
material.pbrMetallicRoughness,
|
|
322
|
+
parsedMaterial,
|
|
323
|
+
attributes,
|
|
324
|
+
gltf
|
|
138
325
|
);
|
|
326
|
+
}
|
|
327
|
+
if (material.normalTexture) {
|
|
328
|
+
addTexture(device, material.normalTexture, 'pbr_normalSampler', parsedMaterial, {
|
|
329
|
+
featureOptions: {
|
|
330
|
+
define: 'HAS_NORMALMAP',
|
|
331
|
+
enabledUniformName: 'normalMapEnabled'
|
|
332
|
+
},
|
|
333
|
+
gltf,
|
|
334
|
+
attributes,
|
|
335
|
+
textureTransformSlot: 'normal'
|
|
336
|
+
});
|
|
139
337
|
|
|
140
338
|
const {scale = 1} = material.normalTexture;
|
|
141
339
|
parsedMaterial.uniforms.normalScale = scale;
|
|
142
340
|
}
|
|
143
341
|
if (material.occlusionTexture) {
|
|
144
|
-
addTexture(
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
342
|
+
addTexture(device, material.occlusionTexture, 'pbr_occlusionSampler', parsedMaterial, {
|
|
343
|
+
featureOptions: {
|
|
344
|
+
define: 'HAS_OCCLUSIONMAP',
|
|
345
|
+
enabledUniformName: 'occlusionMapEnabled'
|
|
346
|
+
},
|
|
347
|
+
gltf,
|
|
348
|
+
attributes,
|
|
349
|
+
textureTransformSlot: 'occlusion'
|
|
350
|
+
});
|
|
151
351
|
|
|
152
352
|
const {strength = 1} = material.occlusionTexture;
|
|
153
353
|
parsedMaterial.uniforms.occlusionStrength = strength;
|
|
154
354
|
}
|
|
355
|
+
parsedMaterial.uniforms.emissiveFactor = material.emissiveFactor || [0, 0, 0];
|
|
155
356
|
if (material.emissiveTexture) {
|
|
156
|
-
addTexture(
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
357
|
+
addTexture(device, material.emissiveTexture, 'pbr_emissiveSampler', parsedMaterial, {
|
|
358
|
+
featureOptions: {
|
|
359
|
+
define: 'HAS_EMISSIVEMAP',
|
|
360
|
+
enabledUniformName: 'emissiveMapEnabled'
|
|
361
|
+
},
|
|
362
|
+
gltf,
|
|
363
|
+
attributes,
|
|
364
|
+
textureTransformSlot: 'emissive'
|
|
365
|
+
});
|
|
164
366
|
}
|
|
165
367
|
|
|
166
|
-
|
|
167
|
-
|
|
368
|
+
parseMaterialExtensions(device, material.extensions, parsedMaterial, gltf, attributes);
|
|
369
|
+
|
|
370
|
+
switch (material.alphaMode || 'OPAQUE') {
|
|
371
|
+
case 'OPAQUE':
|
|
372
|
+
break;
|
|
373
|
+
case 'MASK': {
|
|
168
374
|
const {alphaCutoff = 0.5} = material;
|
|
169
375
|
parsedMaterial.defines['ALPHA_CUTOFF'] = true;
|
|
376
|
+
parsedMaterial.uniforms.alphaCutoffEnabled = true;
|
|
170
377
|
parsedMaterial.uniforms.alphaCutoff = alphaCutoff;
|
|
171
378
|
break;
|
|
379
|
+
}
|
|
172
380
|
case 'BLEND':
|
|
173
381
|
log.warn('glTF BLEND alphaMode might not work well because it requires mesh sorting')();
|
|
382
|
+
applyAlphaBlendParameters(parsedMaterial);
|
|
174
383
|
|
|
175
|
-
|
|
176
|
-
|
|
384
|
+
break;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
177
387
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
388
|
+
function applyAlphaBlendParameters(parsedMaterial: ParsedPBRMaterial): void {
|
|
389
|
+
parsedMaterial.parameters.blend = true;
|
|
390
|
+
parsedMaterial.parameters.blendColorOperation = 'add';
|
|
391
|
+
parsedMaterial.parameters.blendColorSrcFactor = 'src-alpha';
|
|
392
|
+
parsedMaterial.parameters.blendColorDstFactor = 'one-minus-src-alpha';
|
|
393
|
+
parsedMaterial.parameters.blendAlphaOperation = 'add';
|
|
394
|
+
parsedMaterial.parameters.blendAlphaSrcFactor = 'one';
|
|
395
|
+
parsedMaterial.parameters.blendAlphaDstFactor = 'one-minus-src-alpha';
|
|
181
396
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
397
|
+
parsedMaterial.glParameters['blend'] = true;
|
|
398
|
+
parsedMaterial.glParameters['blendEquation'] = GLEnum.FUNC_ADD;
|
|
399
|
+
parsedMaterial.glParameters['blendFunc'] = [
|
|
400
|
+
GLEnum.SRC_ALPHA,
|
|
401
|
+
GLEnum.ONE_MINUS_SRC_ALPHA,
|
|
402
|
+
GLEnum.ONE,
|
|
403
|
+
GLEnum.ONE_MINUS_SRC_ALPHA
|
|
404
|
+
];
|
|
405
|
+
}
|
|
185
406
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
];
|
|
407
|
+
function applyTransmissionBlendApproximation(parsedMaterial: ParsedPBRMaterial): void {
|
|
408
|
+
parsedMaterial.parameters.blend = true;
|
|
409
|
+
parsedMaterial.parameters.depthWriteEnabled = false;
|
|
410
|
+
parsedMaterial.parameters.blendColorOperation = 'add';
|
|
411
|
+
parsedMaterial.parameters.blendColorSrcFactor = 'one';
|
|
412
|
+
parsedMaterial.parameters.blendColorDstFactor = 'one-minus-src-alpha';
|
|
413
|
+
parsedMaterial.parameters.blendAlphaOperation = 'add';
|
|
414
|
+
parsedMaterial.parameters.blendAlphaSrcFactor = 'one';
|
|
415
|
+
parsedMaterial.parameters.blendAlphaDstFactor = 'one-minus-src-alpha';
|
|
196
416
|
|
|
197
|
-
|
|
198
|
-
|
|
417
|
+
parsedMaterial.glParameters['blend'] = true;
|
|
418
|
+
parsedMaterial.glParameters['depthMask'] = false;
|
|
419
|
+
parsedMaterial.glParameters['blendEquation'] = GLEnum.FUNC_ADD;
|
|
420
|
+
parsedMaterial.glParameters['blendFunc'] = [
|
|
421
|
+
GLEnum.ONE,
|
|
422
|
+
GLEnum.ONE_MINUS_SRC_ALPHA,
|
|
423
|
+
GLEnum.ONE,
|
|
424
|
+
GLEnum.ONE_MINUS_SRC_ALPHA
|
|
425
|
+
];
|
|
199
426
|
}
|
|
200
427
|
|
|
201
428
|
/** Parse GLTF material sub record */
|
|
202
429
|
function parsePbrMetallicRoughness(
|
|
203
430
|
device: Device,
|
|
204
431
|
pbrMetallicRoughness: GLTFPBRMetallicRoughness,
|
|
205
|
-
parsedMaterial: ParsedPBRMaterial
|
|
432
|
+
parsedMaterial: ParsedPBRMaterial,
|
|
433
|
+
attributes: Record<string, any>,
|
|
434
|
+
gltf?: GLTFPostprocessed
|
|
206
435
|
): void {
|
|
207
436
|
if (pbrMetallicRoughness.baseColorTexture) {
|
|
208
437
|
addTexture(
|
|
209
438
|
device,
|
|
210
439
|
pbrMetallicRoughness.baseColorTexture,
|
|
211
440
|
'pbr_baseColorSampler',
|
|
212
|
-
|
|
213
|
-
|
|
441
|
+
parsedMaterial,
|
|
442
|
+
{
|
|
443
|
+
featureOptions: {
|
|
444
|
+
define: 'HAS_BASECOLORMAP',
|
|
445
|
+
enabledUniformName: 'baseColorMapEnabled'
|
|
446
|
+
},
|
|
447
|
+
gltf,
|
|
448
|
+
attributes,
|
|
449
|
+
textureTransformSlot: 'baseColor'
|
|
450
|
+
}
|
|
214
451
|
);
|
|
215
452
|
}
|
|
216
453
|
parsedMaterial.uniforms.baseColorFactor = pbrMetallicRoughness.baseColorFactor || [1, 1, 1, 1];
|
|
@@ -220,49 +457,700 @@ function parsePbrMetallicRoughness(
|
|
|
220
457
|
device,
|
|
221
458
|
pbrMetallicRoughness.metallicRoughnessTexture,
|
|
222
459
|
'pbr_metallicRoughnessSampler',
|
|
223
|
-
|
|
224
|
-
|
|
460
|
+
parsedMaterial,
|
|
461
|
+
{
|
|
462
|
+
featureOptions: {
|
|
463
|
+
define: 'HAS_METALROUGHNESSMAP',
|
|
464
|
+
enabledUniformName: 'metallicRoughnessMapEnabled'
|
|
465
|
+
},
|
|
466
|
+
gltf,
|
|
467
|
+
attributes,
|
|
468
|
+
textureTransformSlot: 'metallicRoughness'
|
|
469
|
+
}
|
|
225
470
|
);
|
|
226
471
|
}
|
|
227
472
|
const {metallicFactor = 1, roughnessFactor = 1} = pbrMetallicRoughness;
|
|
228
473
|
parsedMaterial.uniforms.metallicRoughnessValues = [metallicFactor, roughnessFactor];
|
|
229
474
|
}
|
|
230
475
|
|
|
476
|
+
function parseMaterialExtensions(
|
|
477
|
+
device: Device,
|
|
478
|
+
extensions: GLTFMaterialExtensions | undefined,
|
|
479
|
+
parsedMaterial: ParsedPBRMaterial,
|
|
480
|
+
gltf?: GLTFPostprocessed,
|
|
481
|
+
attributes: Record<string, any> = {}
|
|
482
|
+
): void {
|
|
483
|
+
if (!extensions) {
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
if (hasMaterialExtensionShading(extensions)) {
|
|
488
|
+
parsedMaterial.defines['USE_MATERIAL_EXTENSIONS'] = true;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
parseSpecularExtension(
|
|
492
|
+
device,
|
|
493
|
+
extensions.KHR_materials_specular,
|
|
494
|
+
parsedMaterial,
|
|
495
|
+
gltf,
|
|
496
|
+
attributes
|
|
497
|
+
);
|
|
498
|
+
parseIorExtension(extensions.KHR_materials_ior, parsedMaterial);
|
|
499
|
+
parseTransmissionExtension(
|
|
500
|
+
device,
|
|
501
|
+
extensions.KHR_materials_transmission,
|
|
502
|
+
parsedMaterial,
|
|
503
|
+
gltf,
|
|
504
|
+
attributes
|
|
505
|
+
);
|
|
506
|
+
parseVolumeExtension(device, extensions.KHR_materials_volume, parsedMaterial, gltf, attributes);
|
|
507
|
+
parseClearcoatExtension(
|
|
508
|
+
device,
|
|
509
|
+
extensions.KHR_materials_clearcoat,
|
|
510
|
+
parsedMaterial,
|
|
511
|
+
gltf,
|
|
512
|
+
attributes
|
|
513
|
+
);
|
|
514
|
+
parseSheenExtension(device, extensions.KHR_materials_sheen, parsedMaterial, gltf, attributes);
|
|
515
|
+
parseIridescenceExtension(
|
|
516
|
+
device,
|
|
517
|
+
extensions.KHR_materials_iridescence,
|
|
518
|
+
parsedMaterial,
|
|
519
|
+
gltf,
|
|
520
|
+
attributes
|
|
521
|
+
);
|
|
522
|
+
parseAnisotropyExtension(
|
|
523
|
+
device,
|
|
524
|
+
extensions.KHR_materials_anisotropy,
|
|
525
|
+
parsedMaterial,
|
|
526
|
+
gltf,
|
|
527
|
+
attributes
|
|
528
|
+
);
|
|
529
|
+
parseEmissiveStrengthExtension(extensions.KHR_materials_emissive_strength, parsedMaterial);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function hasMaterialExtensionShading(extensions: GLTFMaterialExtensions): boolean {
|
|
533
|
+
return Boolean(
|
|
534
|
+
extensions.KHR_materials_specular ||
|
|
535
|
+
extensions.KHR_materials_ior ||
|
|
536
|
+
extensions.KHR_materials_transmission ||
|
|
537
|
+
extensions.KHR_materials_volume ||
|
|
538
|
+
extensions.KHR_materials_clearcoat ||
|
|
539
|
+
extensions.KHR_materials_sheen ||
|
|
540
|
+
extensions.KHR_materials_iridescence ||
|
|
541
|
+
extensions.KHR_materials_anisotropy
|
|
542
|
+
);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
function parseSpecularExtension(
|
|
546
|
+
device: Device,
|
|
547
|
+
extension: GLTFMaterialSpecularExtension | undefined,
|
|
548
|
+
parsedMaterial: ParsedPBRMaterial,
|
|
549
|
+
gltf?: GLTFPostprocessed,
|
|
550
|
+
attributes: Record<string, any> = {}
|
|
551
|
+
): void {
|
|
552
|
+
if (!extension) {
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
if (extension.specularColorFactor) {
|
|
557
|
+
parsedMaterial.uniforms.specularColorFactor = extension.specularColorFactor;
|
|
558
|
+
}
|
|
559
|
+
if (extension.specularFactor !== undefined) {
|
|
560
|
+
parsedMaterial.uniforms.specularIntensityFactor = extension.specularFactor;
|
|
561
|
+
}
|
|
562
|
+
if (extension.specularColorTexture) {
|
|
563
|
+
addTexture(device, extension.specularColorTexture, 'pbr_specularColorSampler', parsedMaterial, {
|
|
564
|
+
featureOptions: {
|
|
565
|
+
define: 'HAS_SPECULARCOLORMAP',
|
|
566
|
+
enabledUniformName: 'specularColorMapEnabled'
|
|
567
|
+
},
|
|
568
|
+
gltf,
|
|
569
|
+
attributes,
|
|
570
|
+
textureTransformSlot: 'specularColor'
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
if (extension.specularTexture) {
|
|
574
|
+
addTexture(device, extension.specularTexture, 'pbr_specularIntensitySampler', parsedMaterial, {
|
|
575
|
+
featureOptions: {
|
|
576
|
+
define: 'HAS_SPECULARINTENSITYMAP',
|
|
577
|
+
enabledUniformName: 'specularIntensityMapEnabled'
|
|
578
|
+
},
|
|
579
|
+
gltf,
|
|
580
|
+
attributes,
|
|
581
|
+
textureTransformSlot: 'specularIntensity'
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
function parseIorExtension(
|
|
587
|
+
extension: GLTFMaterialIorExtension | undefined,
|
|
588
|
+
parsedMaterial: ParsedPBRMaterial
|
|
589
|
+
): void {
|
|
590
|
+
if (extension?.ior !== undefined) {
|
|
591
|
+
parsedMaterial.uniforms.ior = extension.ior;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
function parseTransmissionExtension(
|
|
596
|
+
device: Device,
|
|
597
|
+
extension: GLTFMaterialTransmissionExtension | undefined,
|
|
598
|
+
parsedMaterial: ParsedPBRMaterial,
|
|
599
|
+
gltf?: GLTFPostprocessed,
|
|
600
|
+
attributes: Record<string, any> = {}
|
|
601
|
+
): void {
|
|
602
|
+
if (!extension) {
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
if (extension.transmissionFactor !== undefined) {
|
|
607
|
+
parsedMaterial.uniforms.transmissionFactor = extension.transmissionFactor;
|
|
608
|
+
}
|
|
609
|
+
if (extension.transmissionTexture) {
|
|
610
|
+
addTexture(device, extension.transmissionTexture, 'pbr_transmissionSampler', parsedMaterial, {
|
|
611
|
+
featureOptions: {
|
|
612
|
+
define: 'HAS_TRANSMISSIONMAP',
|
|
613
|
+
enabledUniformName: 'transmissionMapEnabled'
|
|
614
|
+
},
|
|
615
|
+
gltf,
|
|
616
|
+
attributes,
|
|
617
|
+
textureTransformSlot: 'transmission'
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
if ((extension.transmissionFactor ?? 0) > 0 || extension.transmissionTexture) {
|
|
622
|
+
log.warn(
|
|
623
|
+
'KHR_materials_transmission uses a premultiplied-alpha blending approximation and may require mesh sorting'
|
|
624
|
+
)();
|
|
625
|
+
applyTransmissionBlendApproximation(parsedMaterial);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
function parseVolumeExtension(
|
|
630
|
+
device: Device,
|
|
631
|
+
extension: GLTFMaterialVolumeExtension | undefined,
|
|
632
|
+
parsedMaterial: ParsedPBRMaterial,
|
|
633
|
+
gltf?: GLTFPostprocessed,
|
|
634
|
+
attributes: Record<string, any> = {}
|
|
635
|
+
): void {
|
|
636
|
+
if (!extension) {
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
if (extension.thicknessFactor !== undefined) {
|
|
641
|
+
parsedMaterial.uniforms.thicknessFactor = extension.thicknessFactor;
|
|
642
|
+
}
|
|
643
|
+
if (extension.thicknessTexture) {
|
|
644
|
+
addTexture(device, extension.thicknessTexture, 'pbr_thicknessSampler', parsedMaterial, {
|
|
645
|
+
featureOptions: {
|
|
646
|
+
define: 'HAS_THICKNESSMAP'
|
|
647
|
+
},
|
|
648
|
+
gltf,
|
|
649
|
+
attributes,
|
|
650
|
+
textureTransformSlot: 'thickness'
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
if (extension.attenuationDistance !== undefined) {
|
|
654
|
+
parsedMaterial.uniforms.attenuationDistance = extension.attenuationDistance;
|
|
655
|
+
}
|
|
656
|
+
if (extension.attenuationColor) {
|
|
657
|
+
parsedMaterial.uniforms.attenuationColor = extension.attenuationColor;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
function parseClearcoatExtension(
|
|
662
|
+
device: Device,
|
|
663
|
+
extension: GLTFMaterialClearcoatExtension | undefined,
|
|
664
|
+
parsedMaterial: ParsedPBRMaterial,
|
|
665
|
+
gltf?: GLTFPostprocessed,
|
|
666
|
+
attributes: Record<string, any> = {}
|
|
667
|
+
): void {
|
|
668
|
+
if (!extension) {
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
if (extension.clearcoatFactor !== undefined) {
|
|
673
|
+
parsedMaterial.uniforms.clearcoatFactor = extension.clearcoatFactor;
|
|
674
|
+
}
|
|
675
|
+
if (extension.clearcoatRoughnessFactor !== undefined) {
|
|
676
|
+
parsedMaterial.uniforms.clearcoatRoughnessFactor = extension.clearcoatRoughnessFactor;
|
|
677
|
+
}
|
|
678
|
+
if (extension.clearcoatTexture) {
|
|
679
|
+
addTexture(device, extension.clearcoatTexture, 'pbr_clearcoatSampler', parsedMaterial, {
|
|
680
|
+
featureOptions: {
|
|
681
|
+
define: 'HAS_CLEARCOATMAP',
|
|
682
|
+
enabledUniformName: 'clearcoatMapEnabled'
|
|
683
|
+
},
|
|
684
|
+
gltf,
|
|
685
|
+
attributes,
|
|
686
|
+
textureTransformSlot: 'clearcoat'
|
|
687
|
+
});
|
|
688
|
+
}
|
|
689
|
+
if (extension.clearcoatRoughnessTexture) {
|
|
690
|
+
addTexture(
|
|
691
|
+
device,
|
|
692
|
+
extension.clearcoatRoughnessTexture,
|
|
693
|
+
'pbr_clearcoatRoughnessSampler',
|
|
694
|
+
parsedMaterial,
|
|
695
|
+
{
|
|
696
|
+
featureOptions: {
|
|
697
|
+
define: 'HAS_CLEARCOATROUGHNESSMAP',
|
|
698
|
+
enabledUniformName: 'clearcoatRoughnessMapEnabled'
|
|
699
|
+
},
|
|
700
|
+
gltf,
|
|
701
|
+
attributes,
|
|
702
|
+
textureTransformSlot: 'clearcoatRoughness'
|
|
703
|
+
}
|
|
704
|
+
);
|
|
705
|
+
}
|
|
706
|
+
if (extension.clearcoatNormalTexture) {
|
|
707
|
+
addTexture(
|
|
708
|
+
device,
|
|
709
|
+
extension.clearcoatNormalTexture,
|
|
710
|
+
'pbr_clearcoatNormalSampler',
|
|
711
|
+
parsedMaterial,
|
|
712
|
+
{
|
|
713
|
+
featureOptions: {
|
|
714
|
+
define: 'HAS_CLEARCOATNORMALMAP'
|
|
715
|
+
},
|
|
716
|
+
gltf,
|
|
717
|
+
attributes,
|
|
718
|
+
textureTransformSlot: 'clearcoatNormal'
|
|
719
|
+
}
|
|
720
|
+
);
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
function parseSheenExtension(
|
|
725
|
+
device: Device,
|
|
726
|
+
extension: GLTFMaterialSheenExtension | undefined,
|
|
727
|
+
parsedMaterial: ParsedPBRMaterial,
|
|
728
|
+
gltf?: GLTFPostprocessed,
|
|
729
|
+
attributes: Record<string, any> = {}
|
|
730
|
+
): void {
|
|
731
|
+
if (!extension) {
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
if (extension.sheenColorFactor) {
|
|
736
|
+
parsedMaterial.uniforms.sheenColorFactor = extension.sheenColorFactor;
|
|
737
|
+
}
|
|
738
|
+
if (extension.sheenRoughnessFactor !== undefined) {
|
|
739
|
+
parsedMaterial.uniforms.sheenRoughnessFactor = extension.sheenRoughnessFactor;
|
|
740
|
+
}
|
|
741
|
+
if (extension.sheenColorTexture) {
|
|
742
|
+
addTexture(device, extension.sheenColorTexture, 'pbr_sheenColorSampler', parsedMaterial, {
|
|
743
|
+
featureOptions: {
|
|
744
|
+
define: 'HAS_SHEENCOLORMAP',
|
|
745
|
+
enabledUniformName: 'sheenColorMapEnabled'
|
|
746
|
+
},
|
|
747
|
+
gltf,
|
|
748
|
+
attributes,
|
|
749
|
+
textureTransformSlot: 'sheenColor'
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
if (extension.sheenRoughnessTexture) {
|
|
753
|
+
addTexture(
|
|
754
|
+
device,
|
|
755
|
+
extension.sheenRoughnessTexture,
|
|
756
|
+
'pbr_sheenRoughnessSampler',
|
|
757
|
+
parsedMaterial,
|
|
758
|
+
{
|
|
759
|
+
featureOptions: {
|
|
760
|
+
define: 'HAS_SHEENROUGHNESSMAP',
|
|
761
|
+
enabledUniformName: 'sheenRoughnessMapEnabled'
|
|
762
|
+
},
|
|
763
|
+
gltf,
|
|
764
|
+
attributes,
|
|
765
|
+
textureTransformSlot: 'sheenRoughness'
|
|
766
|
+
}
|
|
767
|
+
);
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
function parseIridescenceExtension(
|
|
772
|
+
device: Device,
|
|
773
|
+
extension: GLTFMaterialIridescenceExtension | undefined,
|
|
774
|
+
parsedMaterial: ParsedPBRMaterial,
|
|
775
|
+
gltf?: GLTFPostprocessed,
|
|
776
|
+
attributes: Record<string, any> = {}
|
|
777
|
+
): void {
|
|
778
|
+
if (!extension) {
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
if (extension.iridescenceFactor !== undefined) {
|
|
783
|
+
parsedMaterial.uniforms.iridescenceFactor = extension.iridescenceFactor;
|
|
784
|
+
}
|
|
785
|
+
if (extension.iridescenceIor !== undefined) {
|
|
786
|
+
parsedMaterial.uniforms.iridescenceIor = extension.iridescenceIor;
|
|
787
|
+
}
|
|
788
|
+
if (
|
|
789
|
+
extension.iridescenceThicknessMinimum !== undefined ||
|
|
790
|
+
extension.iridescenceThicknessMaximum !== undefined
|
|
791
|
+
) {
|
|
792
|
+
parsedMaterial.uniforms.iridescenceThicknessRange = [
|
|
793
|
+
extension.iridescenceThicknessMinimum ?? 100,
|
|
794
|
+
extension.iridescenceThicknessMaximum ?? 400
|
|
795
|
+
];
|
|
796
|
+
}
|
|
797
|
+
if (extension.iridescenceTexture) {
|
|
798
|
+
addTexture(device, extension.iridescenceTexture, 'pbr_iridescenceSampler', parsedMaterial, {
|
|
799
|
+
featureOptions: {
|
|
800
|
+
define: 'HAS_IRIDESCENCEMAP',
|
|
801
|
+
enabledUniformName: 'iridescenceMapEnabled'
|
|
802
|
+
},
|
|
803
|
+
gltf,
|
|
804
|
+
attributes,
|
|
805
|
+
textureTransformSlot: 'iridescence'
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
if (extension.iridescenceThicknessTexture) {
|
|
809
|
+
addTexture(
|
|
810
|
+
device,
|
|
811
|
+
extension.iridescenceThicknessTexture,
|
|
812
|
+
'pbr_iridescenceThicknessSampler',
|
|
813
|
+
parsedMaterial,
|
|
814
|
+
{
|
|
815
|
+
featureOptions: {
|
|
816
|
+
define: 'HAS_IRIDESCENCETHICKNESSMAP'
|
|
817
|
+
},
|
|
818
|
+
gltf,
|
|
819
|
+
attributes,
|
|
820
|
+
textureTransformSlot: 'iridescenceThickness'
|
|
821
|
+
}
|
|
822
|
+
);
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
function parseAnisotropyExtension(
|
|
827
|
+
device: Device,
|
|
828
|
+
extension: GLTFMaterialAnisotropyExtension | undefined,
|
|
829
|
+
parsedMaterial: ParsedPBRMaterial,
|
|
830
|
+
gltf?: GLTFPostprocessed,
|
|
831
|
+
attributes: Record<string, any> = {}
|
|
832
|
+
): void {
|
|
833
|
+
if (!extension) {
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
if (extension.anisotropyStrength !== undefined) {
|
|
838
|
+
parsedMaterial.uniforms.anisotropyStrength = extension.anisotropyStrength;
|
|
839
|
+
}
|
|
840
|
+
if (extension.anisotropyRotation !== undefined) {
|
|
841
|
+
parsedMaterial.uniforms.anisotropyRotation = extension.anisotropyRotation;
|
|
842
|
+
}
|
|
843
|
+
if (extension.anisotropyTexture) {
|
|
844
|
+
addTexture(device, extension.anisotropyTexture, 'pbr_anisotropySampler', parsedMaterial, {
|
|
845
|
+
featureOptions: {
|
|
846
|
+
define: 'HAS_ANISOTROPYMAP',
|
|
847
|
+
enabledUniformName: 'anisotropyMapEnabled'
|
|
848
|
+
},
|
|
849
|
+
gltf,
|
|
850
|
+
attributes,
|
|
851
|
+
textureTransformSlot: 'anisotropy'
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
function parseEmissiveStrengthExtension(
|
|
857
|
+
extension: GLTFMaterialEmissiveStrengthExtension | undefined,
|
|
858
|
+
parsedMaterial: ParsedPBRMaterial
|
|
859
|
+
): void {
|
|
860
|
+
if (extension?.emissiveStrength !== undefined) {
|
|
861
|
+
parsedMaterial.uniforms.emissiveStrength = extension.emissiveStrength;
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
|
|
231
865
|
/** Create a texture from a glTF texture/sampler/image combo and add it to bindings */
|
|
232
866
|
function addTexture(
|
|
233
867
|
device: Device,
|
|
234
868
|
gltfTexture: GLTFTexture,
|
|
235
869
|
uniformName: keyof PBRMaterialBindings,
|
|
236
|
-
|
|
237
|
-
|
|
870
|
+
parsedMaterial: ParsedPBRMaterial,
|
|
871
|
+
textureParseOptions: TextureParseOptions = {}
|
|
238
872
|
): void {
|
|
239
|
-
const
|
|
240
|
-
|
|
873
|
+
const {featureOptions = {}, gltf, attributes = {}, textureTransformSlot} = textureParseOptions;
|
|
874
|
+
const {define, enabledUniformName} = featureOptions;
|
|
875
|
+
const textureCoordinateSet = resolveTextureCoordinateSet(gltfTexture as Record<string, any>);
|
|
876
|
+
if (textureCoordinateSet > 1) {
|
|
877
|
+
log.warn(
|
|
878
|
+
`Skipping ${String(uniformName)} because ${textureCoordinateSet} is not supported; only TEXCOORD_0 and TEXCOORD_1 are currently available`
|
|
879
|
+
)();
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
if (textureCoordinateSet === 1 && !attributes['TEXCOORD_1']) {
|
|
883
|
+
log.warn(
|
|
884
|
+
`Skipping ${String(uniformName)} because it requires TEXCOORD_1 but the primitive does not provide TEXCOORD_1`
|
|
885
|
+
)();
|
|
886
|
+
return;
|
|
887
|
+
}
|
|
241
888
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
889
|
+
const resolvedTextureInfo = resolveTextureInfo(gltfTexture, gltf);
|
|
890
|
+
const image = resolvedTextureInfo.texture?.source?.image;
|
|
891
|
+
if (!image) {
|
|
892
|
+
log.warn(`Skipping unresolved glTF texture for ${String(uniformName)}`)();
|
|
893
|
+
return;
|
|
247
894
|
}
|
|
248
895
|
|
|
249
896
|
const gltfSampler = {
|
|
250
897
|
wrapS: 10497, // default REPEAT S (U) wrapping mode.
|
|
251
898
|
wrapT: 10497, // default REPEAT T (V) wrapping mode.
|
|
252
|
-
|
|
253
|
-
|
|
899
|
+
minFilter: 9729, // default LINEAR filtering
|
|
900
|
+
magFilter: 9729, // default LINEAR filtering
|
|
901
|
+
...resolvedTextureInfo?.texture?.sampler
|
|
902
|
+
} as GLTFSampler;
|
|
254
903
|
|
|
255
|
-
const
|
|
256
|
-
id:
|
|
257
|
-
sampler: convertSampler(gltfSampler)
|
|
258
|
-
|
|
259
|
-
|
|
904
|
+
const baseOptions = {
|
|
905
|
+
id: resolvedTextureInfo.uniformName || resolvedTextureInfo.id,
|
|
906
|
+
sampler: convertSampler(gltfSampler)
|
|
907
|
+
};
|
|
908
|
+
|
|
909
|
+
let texture: Texture;
|
|
910
|
+
|
|
911
|
+
if (image.compressed) {
|
|
912
|
+
texture = createCompressedTexture(device, image, baseOptions);
|
|
913
|
+
} else {
|
|
914
|
+
const {width, height} = device.getExternalImageSize(image);
|
|
915
|
+
texture = device.createTexture({
|
|
916
|
+
...baseOptions,
|
|
917
|
+
width,
|
|
918
|
+
height,
|
|
919
|
+
data: image
|
|
920
|
+
});
|
|
921
|
+
}
|
|
260
922
|
|
|
261
923
|
parsedMaterial.bindings[uniformName] = texture;
|
|
262
924
|
if (define) parsedMaterial.defines[define] = true;
|
|
925
|
+
if (enabledUniformName) {
|
|
926
|
+
parsedMaterial.uniforms[enabledUniformName] = true;
|
|
927
|
+
}
|
|
928
|
+
if (textureTransformSlot) {
|
|
929
|
+
const textureTransformSlotDefinition = getTextureTransformSlotDefinition(textureTransformSlot);
|
|
930
|
+
(parsedMaterial.uniforms as Record<string, any>)[textureTransformSlotDefinition.uvSetUniform] =
|
|
931
|
+
textureCoordinateSet;
|
|
932
|
+
(parsedMaterial.uniforms as Record<string, any>)[
|
|
933
|
+
textureTransformSlotDefinition.uvTransformUniform
|
|
934
|
+
] = getTextureTransformMatrix(resolveTextureTransform(gltfTexture as Record<string, any>));
|
|
935
|
+
}
|
|
263
936
|
parsedMaterial.generatedTextures.push(texture);
|
|
264
937
|
}
|
|
265
938
|
|
|
939
|
+
function resolveTextureInfo(gltfTexture: GLTFTexture, gltf?: GLTFPostprocessed): GLTFTexture {
|
|
940
|
+
if (gltfTexture.texture || gltfTexture.index === undefined || !gltf?.textures) {
|
|
941
|
+
return gltfTexture;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
const resolvedTextureEntry = gltf.textures[gltfTexture.index] as
|
|
945
|
+
| Partial<GLTFTexture>
|
|
946
|
+
| GLTFTexture['texture']
|
|
947
|
+
| undefined;
|
|
948
|
+
if (!resolvedTextureEntry) {
|
|
949
|
+
return gltfTexture;
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
if ('texture' in resolvedTextureEntry && resolvedTextureEntry.texture) {
|
|
953
|
+
return {
|
|
954
|
+
...resolvedTextureEntry,
|
|
955
|
+
...gltfTexture,
|
|
956
|
+
texture: resolvedTextureEntry.texture
|
|
957
|
+
} as GLTFTexture;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
if (!('source' in resolvedTextureEntry)) {
|
|
961
|
+
return gltfTexture;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
return {
|
|
965
|
+
...gltfTexture,
|
|
966
|
+
texture: resolvedTextureEntry
|
|
967
|
+
};
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
/** One mip level as produced by loaders.gl compressed texture parsers */
|
|
971
|
+
export type CompressedMipLevel = {
|
|
972
|
+
data: TypedArray;
|
|
973
|
+
width: number;
|
|
974
|
+
height: number;
|
|
975
|
+
textureFormat?: TextureFormat;
|
|
976
|
+
};
|
|
977
|
+
|
|
978
|
+
/**
|
|
979
|
+
* Compressed image from current loaders.gl releases.
|
|
980
|
+
* - `mipmaps` is a boolean (true), NOT an array
|
|
981
|
+
* - `data` is an Array of TextureLevel-like objects
|
|
982
|
+
* - Per-level `textureFormat` is already a luma.gl TextureFormat
|
|
983
|
+
* - Top-level `width`/`height` may be undefined
|
|
984
|
+
*/
|
|
985
|
+
export type CompressedImageDataArray = {
|
|
986
|
+
compressed: true;
|
|
987
|
+
mipmaps?: boolean;
|
|
988
|
+
width?: number;
|
|
989
|
+
height?: number;
|
|
990
|
+
data: CompressedMipLevel[];
|
|
991
|
+
};
|
|
992
|
+
|
|
993
|
+
/**
|
|
994
|
+
* Hypothetical future format where `mipmaps` is an actual array.
|
|
995
|
+
* Kept for forward compatibility.
|
|
996
|
+
*/
|
|
997
|
+
export type CompressedImageMipmapArray = {
|
|
998
|
+
compressed: true;
|
|
999
|
+
width?: number;
|
|
1000
|
+
height?: number;
|
|
1001
|
+
mipmaps: CompressedMipLevel[];
|
|
1002
|
+
};
|
|
1003
|
+
|
|
1004
|
+
/** Union of all known loaders.gl compressed image shapes */
|
|
1005
|
+
export type CompressedImage = CompressedImageDataArray | CompressedImageMipmapArray;
|
|
1006
|
+
|
|
1007
|
+
function createCompressedTextureFallback(
|
|
1008
|
+
device: Device,
|
|
1009
|
+
baseOptions: {id: string; sampler: SamplerProps}
|
|
1010
|
+
): Texture {
|
|
1011
|
+
return device.createTexture({
|
|
1012
|
+
...baseOptions,
|
|
1013
|
+
format: 'rgba8unorm',
|
|
1014
|
+
width: 1,
|
|
1015
|
+
height: 1,
|
|
1016
|
+
mipLevels: 1
|
|
1017
|
+
});
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
function resolveCompressedTextureFormat(level: CompressedMipLevel): TextureFormat | undefined {
|
|
1021
|
+
return level.textureFormat;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
/**
|
|
1025
|
+
* Maximum mip levels that can be filled for a compressed texture.
|
|
1026
|
+
* texStorage2D allocates level i at (baseW >> i) × (baseH >> i).
|
|
1027
|
+
* Compressed formats can't upload data for levels smaller than one block,
|
|
1028
|
+
* so we stop before either dimension drops below the block size.
|
|
1029
|
+
*/
|
|
1030
|
+
function getMaxCompressedMipLevels(
|
|
1031
|
+
baseWidth: number,
|
|
1032
|
+
baseHeight: number,
|
|
1033
|
+
format: TextureFormat
|
|
1034
|
+
): number {
|
|
1035
|
+
const {blockWidth = 1, blockHeight = 1} = textureFormatDecoder.getInfo(format);
|
|
1036
|
+
let count = 1;
|
|
1037
|
+
for (let i = 1; ; i++) {
|
|
1038
|
+
const w = Math.max(1, baseWidth >> i);
|
|
1039
|
+
const h = Math.max(1, baseHeight >> i);
|
|
1040
|
+
if (w < blockWidth || h < blockHeight) break;
|
|
1041
|
+
count++;
|
|
1042
|
+
}
|
|
1043
|
+
return count;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
/**
|
|
1047
|
+
* Create a texture from compressed image data produced by loaders.gl.
|
|
1048
|
+
* Handles current loaders.gl compressed image layouts:
|
|
1049
|
+
*
|
|
1050
|
+
* current: {compressed, mipmaps: true, data: [{data, width, height, textureFormat}, ...]}
|
|
1051
|
+
* forward: {compressed, mipmaps: [{data, width, height, textureFormat}, ...]}
|
|
1052
|
+
*/
|
|
1053
|
+
export function createCompressedTexture(
|
|
1054
|
+
device: Device,
|
|
1055
|
+
image: CompressedImage,
|
|
1056
|
+
baseOptions: {id: string; sampler: SamplerProps}
|
|
1057
|
+
): Texture {
|
|
1058
|
+
// Normalize mip levels from all known loaders.gl formats
|
|
1059
|
+
let levels: CompressedMipLevel[];
|
|
1060
|
+
|
|
1061
|
+
if (Array.isArray((image as any).data) && (image as any).data[0]?.data) {
|
|
1062
|
+
// loaders.gl current format: image.data is Array of mip-level objects
|
|
1063
|
+
levels = (image as CompressedImageDataArray).data;
|
|
1064
|
+
} else if ('mipmaps' in image && Array.isArray((image as CompressedImageMipmapArray).mipmaps)) {
|
|
1065
|
+
// Hypothetical future format: image.mipmaps is an Array
|
|
1066
|
+
levels = (image as CompressedImageMipmapArray).mipmaps;
|
|
1067
|
+
} else {
|
|
1068
|
+
levels = [];
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
if (levels.length === 0 || !levels[0]?.data) {
|
|
1072
|
+
log.warn(
|
|
1073
|
+
'createCompressedTexture: compressed image has no valid mip levels, creating fallback'
|
|
1074
|
+
)();
|
|
1075
|
+
return createCompressedTextureFallback(device, baseOptions);
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
const baseLevel = levels[0];
|
|
1079
|
+
const baseWidth = baseLevel.width ?? (image as any).width ?? 0;
|
|
1080
|
+
const baseHeight = baseLevel.height ?? (image as any).height ?? 0;
|
|
1081
|
+
|
|
1082
|
+
if (baseWidth <= 0 || baseHeight <= 0) {
|
|
1083
|
+
log.warn('createCompressedTexture: base level has invalid dimensions, creating fallback')();
|
|
1084
|
+
return createCompressedTextureFallback(device, baseOptions);
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
const format = resolveCompressedTextureFormat(baseLevel);
|
|
1088
|
+
|
|
1089
|
+
if (!format) {
|
|
1090
|
+
log.warn('createCompressedTexture: compressed image has no textureFormat, creating fallback')();
|
|
1091
|
+
return createCompressedTextureFallback(device, baseOptions);
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
// Validate mip levels: truncate chain at first invalid level.
|
|
1095
|
+
// Levels must be contiguous, so we stop at the first level that has
|
|
1096
|
+
// a format mismatch, missing data, non-positive dimensions, or
|
|
1097
|
+
// dimensions that don't match what texStorage2D will allocate.
|
|
1098
|
+
//
|
|
1099
|
+
// For block-compressed formats (ASTC, BC, ETC2), texStorage2D allocates
|
|
1100
|
+
// mip levels down to 1×1 texels, but compressed data can't be smaller
|
|
1101
|
+
// than one block (e.g. 4×4 for ASTC-4x4). Cap the chain so we never
|
|
1102
|
+
// try to upload data whose block-aligned size exceeds the allocated level.
|
|
1103
|
+
const maxMipLevels = getMaxCompressedMipLevels(baseWidth, baseHeight, format);
|
|
1104
|
+
const levelLimit = Math.min(levels.length, maxMipLevels);
|
|
1105
|
+
|
|
1106
|
+
let validLevelCount = 1;
|
|
1107
|
+
for (let i = 1; i < levelLimit; i++) {
|
|
1108
|
+
const level = levels[i];
|
|
1109
|
+
if (!level.data || level.width <= 0 || level.height <= 0) {
|
|
1110
|
+
log.warn(`createCompressedTexture: mip level ${i} has invalid data/dimensions, truncating`)();
|
|
1111
|
+
break;
|
|
1112
|
+
}
|
|
1113
|
+
const levelFormat = resolveCompressedTextureFormat(level);
|
|
1114
|
+
if (levelFormat && levelFormat !== format) {
|
|
1115
|
+
log.warn(
|
|
1116
|
+
`createCompressedTexture: mip level ${i} format '${levelFormat}' differs from base '${format}', truncating`
|
|
1117
|
+
)();
|
|
1118
|
+
break;
|
|
1119
|
+
}
|
|
1120
|
+
const expectedW = Math.max(1, baseWidth >> i);
|
|
1121
|
+
const expectedH = Math.max(1, baseHeight >> i);
|
|
1122
|
+
if (level.width !== expectedW || level.height !== expectedH) {
|
|
1123
|
+
log.warn(
|
|
1124
|
+
`createCompressedTexture: mip level ${i} dimensions ${level.width}x${level.height} ` +
|
|
1125
|
+
`don't match expected ${expectedW}x${expectedH}, truncating`
|
|
1126
|
+
)();
|
|
1127
|
+
break;
|
|
1128
|
+
}
|
|
1129
|
+
validLevelCount++;
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
const texture = device.createTexture({
|
|
1133
|
+
...baseOptions,
|
|
1134
|
+
format,
|
|
1135
|
+
usage: Texture.TEXTURE | Texture.COPY_DST,
|
|
1136
|
+
width: baseWidth,
|
|
1137
|
+
height: baseHeight,
|
|
1138
|
+
mipLevels: validLevelCount,
|
|
1139
|
+
data: baseLevel.data
|
|
1140
|
+
});
|
|
1141
|
+
|
|
1142
|
+
// Upload additional validated mip levels
|
|
1143
|
+
for (let i = 1; i < validLevelCount; i++) {
|
|
1144
|
+
texture.writeData(levels[i].data, {
|
|
1145
|
+
width: levels[i].width,
|
|
1146
|
+
height: levels[i].height,
|
|
1147
|
+
mipLevel: i
|
|
1148
|
+
});
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
return texture;
|
|
1152
|
+
}
|
|
1153
|
+
|
|
266
1154
|
/*
|
|
267
1155
|
/**
|
|
268
1156
|
* Parses a GLTF material definition into uniforms and parameters for the PBR shader module
|
|
@@ -308,7 +1196,7 @@ export class PBRMaterialParser {
|
|
|
308
1196
|
if (imageBasedLightingEnvironment) {
|
|
309
1197
|
this.bindings.pbr_diffuseEnvSampler = imageBasedLightingEnvironment.getDiffuseEnvSampler();
|
|
310
1198
|
this.bindings.pbr_specularEnvSampler = imageBasedLightingEnvironment.getSpecularEnvSampler();
|
|
311
|
-
this.bindings.
|
|
1199
|
+
this.bindings.pbr_brdfLUT = imageBasedLightingEnvironment.getBrdfTexture();
|
|
312
1200
|
this.uniforms.scaleIBLAmbient = [1, 1];
|
|
313
1201
|
}
|
|
314
1202
|
|
|
@@ -322,6 +1210,7 @@ export class PBRMaterialParser {
|
|
|
322
1210
|
this.defineIfPresent(attributes.NORMAL, 'HAS_NORMALS');
|
|
323
1211
|
this.defineIfPresent(attributes.TANGENT && useTangents, 'HAS_TANGENTS');
|
|
324
1212
|
this.defineIfPresent(attributes.TEXCOORD_0, 'HAS_UV');
|
|
1213
|
+
this.defineIfPresent(attributes.COLOR_0, 'HAS_COLORS');
|
|
325
1214
|
|
|
326
1215
|
this.defineIfPresent(imageBasedLightingEnvironment, 'USE_IBL');
|
|
327
1216
|
this.defineIfPresent(lights, 'USE_LIGHTS');
|
|
@@ -377,8 +1266,13 @@ export class PBRMaterialParser {
|
|
|
377
1266
|
log.warn('BLEND alphaMode might not work well because it requires mesh sorting')();
|
|
378
1267
|
Object.assign(this.parameters, {
|
|
379
1268
|
blend: true,
|
|
380
|
-
blendEquation:
|
|
381
|
-
blendFunc: [
|
|
1269
|
+
blendEquation: GLEnum.FUNC_ADD,
|
|
1270
|
+
blendFunc: [
|
|
1271
|
+
GLEnum.SRC_ALPHA,
|
|
1272
|
+
GLEnum.ONE_MINUS_SRC_ALPHA,
|
|
1273
|
+
GLEnum.ONE,
|
|
1274
|
+
GLEnum.ONE_MINUS_SRC_ALPHA
|
|
1275
|
+
]
|
|
382
1276
|
});
|
|
383
1277
|
}
|
|
384
1278
|
}
|
|
@@ -415,7 +1309,8 @@ export class PBRMaterialParser {
|
|
|
415
1309
|
if (image.compressed) {
|
|
416
1310
|
textureOptions = image;
|
|
417
1311
|
specialTextureParameters = {
|
|
418
|
-
[
|
|
1312
|
+
[GLEnum.TEXTURE_MIN_FILTER]:
|
|
1313
|
+
image.data.length > 1 ? GLEnum.LINEAR_MIPMAP_NEAREST : GLEnum.LINEAR
|
|
419
1314
|
};
|
|
420
1315
|
} else {
|
|
421
1316
|
// Texture2D accepts a promise that returns an image as data (Async Textures)
|
|
@@ -429,7 +1324,7 @@ export class PBRMaterialParser {
|
|
|
429
1324
|
...specialTextureParameters
|
|
430
1325
|
},
|
|
431
1326
|
pixelStore: {
|
|
432
|
-
[
|
|
1327
|
+
[GLEnum.UNPACK_FLIP_Y_WEBGL]: false
|
|
433
1328
|
},
|
|
434
1329
|
...textureOptions
|
|
435
1330
|
});
|