@luma.gl/gltf 9.2.6 → 9.3.0-alpha.10
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 +1362 -313
- package/dist/dist.min.js +98 -46
- package/dist/gltf/animations/animations.d.ts +16 -4
- package/dist/gltf/animations/animations.d.ts.map +1 -1
- package/dist/gltf/animations/interpolate.d.ts +4 -3
- package/dist/gltf/animations/interpolate.d.ts.map +1 -1
- package/dist/gltf/animations/interpolate.js +27 -36
- 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 +154 -48
- 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 +26 -0
- package/dist/gltf/gltf-animator.d.ts.map +1 -1
- package/dist/gltf/gltf-animator.js +22 -19
- package/dist/gltf/gltf-animator.js.map +1 -1
- package/dist/gltf/gltf-extension-support.d.ts +10 -0
- package/dist/gltf/gltf-extension-support.d.ts.map +1 -0
- package/dist/gltf/gltf-extension-support.js +173 -0
- package/dist/gltf/gltf-extension-support.js.map +1 -0
- package/dist/index.cjs +1302 -276
- 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 +73 -28
- 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 +101 -61
- 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 +570 -54
- 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/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 +2 -14
- 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 +17 -5
- package/src/gltf/animations/interpolate.ts +49 -68
- package/src/gltf/create-gltf-model.ts +214 -48
- package/src/gltf/create-scenegraph-from-gltf.ts +134 -11
- package/src/gltf/gltf-animator.ts +34 -25
- package/src/gltf/gltf-extension-support.ts +214 -0
- package/src/index.ts +11 -2
- package/src/parsers/parse-gltf-animations.ts +94 -33
- package/src/parsers/parse-gltf-lights.ts +218 -0
- package/src/parsers/parse-gltf.ts +170 -90
- package/src/parsers/parse-pbr-material.ts +870 -80
- package/src/pbr/pbr-environment.ts +44 -21
- package/src/pbr/pbr-material.ts +18 -3
- 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 +2 -14
- 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
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// luma.gl
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { Texture, log, textureFormatDecoder } from '@luma.gl/core';
|
|
5
|
+
import { GLEnum } from "../webgl-to-webgpu/gltf-webgl-constants.js";
|
|
6
6
|
import { convertSampler } from "../webgl-to-webgpu/convert-webgl-sampler.js";
|
|
7
7
|
/**
|
|
8
8
|
* Parses a GLTF material definition into uniforms and parameters for the PBR shader module
|
|
@@ -32,7 +32,8 @@ export function parsePBRMaterial(device, material, attributes, options) {
|
|
|
32
32
|
imageBasedLightingEnvironment.diffuseEnvSampler.texture;
|
|
33
33
|
parsedMaterial.bindings.pbr_specularEnvSampler =
|
|
34
34
|
imageBasedLightingEnvironment.specularEnvSampler.texture;
|
|
35
|
-
parsedMaterial.bindings.
|
|
35
|
+
parsedMaterial.bindings.pbr_brdfLUT = imageBasedLightingEnvironment.brdfLutTexture.texture;
|
|
36
|
+
parsedMaterial.uniforms.IBLenabled = true;
|
|
36
37
|
parsedMaterial.uniforms.scaleIBLAmbient = [1, 1];
|
|
37
38
|
}
|
|
38
39
|
if (options?.pbrDebug) {
|
|
@@ -47,102 +48,610 @@ export function parsePBRMaterial(device, material, attributes, options) {
|
|
|
47
48
|
parsedMaterial.defines['HAS_TANGENTS'] = true;
|
|
48
49
|
if (attributes['TEXCOORD_0'])
|
|
49
50
|
parsedMaterial.defines['HAS_UV'] = true;
|
|
51
|
+
if (attributes['JOINTS_0'] && attributes['WEIGHTS_0'])
|
|
52
|
+
parsedMaterial.defines['HAS_SKIN'] = true;
|
|
53
|
+
if (attributes['COLOR_0'])
|
|
54
|
+
parsedMaterial.defines['HAS_COLORS'] = true;
|
|
50
55
|
if (options?.imageBasedLightingEnvironment)
|
|
51
56
|
parsedMaterial.defines['USE_IBL'] = true;
|
|
52
57
|
if (options?.lights)
|
|
53
58
|
parsedMaterial.defines['USE_LIGHTS'] = true;
|
|
54
59
|
if (material) {
|
|
55
|
-
|
|
60
|
+
if (options.validateAttributes !== false) {
|
|
61
|
+
warnOnMissingExpectedAttributes(material, attributes);
|
|
62
|
+
}
|
|
63
|
+
parseMaterial(device, material, parsedMaterial, options.gltf);
|
|
56
64
|
}
|
|
57
65
|
return parsedMaterial;
|
|
58
66
|
}
|
|
67
|
+
function warnOnMissingExpectedAttributes(material, attributes) {
|
|
68
|
+
const uvDependentTextureSlots = getUvDependentTextureSlots(material);
|
|
69
|
+
if (uvDependentTextureSlots.length > 0 && !attributes['TEXCOORD_0']) {
|
|
70
|
+
log.warn(`glTF material uses ${uvDependentTextureSlots.join(', ')} but primitive is missing TEXCOORD_0; textured shading will sample the default UV coordinates`)();
|
|
71
|
+
}
|
|
72
|
+
const isUnlitMaterial = Boolean(material.unlit || material.extensions?.KHR_materials_unlit);
|
|
73
|
+
if (isUnlitMaterial || attributes['NORMAL']) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const missingNormalReason = material.normalTexture
|
|
77
|
+
? 'lit PBR shading with normalTexture'
|
|
78
|
+
: 'lit PBR shading';
|
|
79
|
+
log.warn(`glTF primitive is missing NORMAL while using ${missingNormalReason}; shading will fall back to geometric normals`)();
|
|
80
|
+
}
|
|
81
|
+
function getUvDependentTextureSlots(material) {
|
|
82
|
+
const uvDependentTextureSlots = [];
|
|
83
|
+
if (material.pbrMetallicRoughness?.baseColorTexture) {
|
|
84
|
+
uvDependentTextureSlots.push('baseColorTexture');
|
|
85
|
+
}
|
|
86
|
+
if (material.pbrMetallicRoughness?.metallicRoughnessTexture) {
|
|
87
|
+
uvDependentTextureSlots.push('metallicRoughnessTexture');
|
|
88
|
+
}
|
|
89
|
+
if (material.normalTexture) {
|
|
90
|
+
uvDependentTextureSlots.push('normalTexture');
|
|
91
|
+
}
|
|
92
|
+
if (material.occlusionTexture) {
|
|
93
|
+
uvDependentTextureSlots.push('occlusionTexture');
|
|
94
|
+
}
|
|
95
|
+
if (material.emissiveTexture) {
|
|
96
|
+
uvDependentTextureSlots.push('emissiveTexture');
|
|
97
|
+
}
|
|
98
|
+
if (material.extensions?.KHR_materials_specular?.specularTexture) {
|
|
99
|
+
uvDependentTextureSlots.push('KHR_materials_specular.specularTexture');
|
|
100
|
+
}
|
|
101
|
+
if (material.extensions?.KHR_materials_specular?.specularColorTexture) {
|
|
102
|
+
uvDependentTextureSlots.push('KHR_materials_specular.specularColorTexture');
|
|
103
|
+
}
|
|
104
|
+
if (material.extensions?.KHR_materials_transmission?.transmissionTexture) {
|
|
105
|
+
uvDependentTextureSlots.push('KHR_materials_transmission.transmissionTexture');
|
|
106
|
+
}
|
|
107
|
+
if (material.extensions?.KHR_materials_clearcoat?.clearcoatTexture) {
|
|
108
|
+
uvDependentTextureSlots.push('KHR_materials_clearcoat.clearcoatTexture');
|
|
109
|
+
}
|
|
110
|
+
if (material.extensions?.KHR_materials_clearcoat?.clearcoatRoughnessTexture) {
|
|
111
|
+
uvDependentTextureSlots.push('KHR_materials_clearcoat.clearcoatRoughnessTexture');
|
|
112
|
+
}
|
|
113
|
+
if (material.extensions?.KHR_materials_sheen?.sheenColorTexture) {
|
|
114
|
+
uvDependentTextureSlots.push('KHR_materials_sheen.sheenColorTexture');
|
|
115
|
+
}
|
|
116
|
+
if (material.extensions?.KHR_materials_sheen?.sheenRoughnessTexture) {
|
|
117
|
+
uvDependentTextureSlots.push('KHR_materials_sheen.sheenRoughnessTexture');
|
|
118
|
+
}
|
|
119
|
+
if (material.extensions?.KHR_materials_iridescence?.iridescenceTexture) {
|
|
120
|
+
uvDependentTextureSlots.push('KHR_materials_iridescence.iridescenceTexture');
|
|
121
|
+
}
|
|
122
|
+
if (material.extensions?.KHR_materials_anisotropy?.anisotropyTexture) {
|
|
123
|
+
uvDependentTextureSlots.push('KHR_materials_anisotropy.anisotropyTexture');
|
|
124
|
+
}
|
|
125
|
+
return uvDependentTextureSlots;
|
|
126
|
+
}
|
|
59
127
|
/** Parse GLTF material record */
|
|
60
|
-
function parseMaterial(device, material, parsedMaterial) {
|
|
61
|
-
parsedMaterial.uniforms.unlit = Boolean(material.unlit);
|
|
128
|
+
function parseMaterial(device, material, parsedMaterial, gltf) {
|
|
129
|
+
parsedMaterial.uniforms.unlit = Boolean(material.unlit || material.extensions?.KHR_materials_unlit);
|
|
62
130
|
if (material.pbrMetallicRoughness) {
|
|
63
|
-
parsePbrMetallicRoughness(device, material.pbrMetallicRoughness, parsedMaterial);
|
|
131
|
+
parsePbrMetallicRoughness(device, material.pbrMetallicRoughness, parsedMaterial, gltf);
|
|
64
132
|
}
|
|
65
133
|
if (material.normalTexture) {
|
|
66
|
-
addTexture(device, material.normalTexture, 'pbr_normalSampler',
|
|
134
|
+
addTexture(device, material.normalTexture, 'pbr_normalSampler', parsedMaterial, {
|
|
135
|
+
featureOptions: {
|
|
136
|
+
define: 'HAS_NORMALMAP',
|
|
137
|
+
enabledUniformName: 'normalMapEnabled'
|
|
138
|
+
},
|
|
139
|
+
gltf
|
|
140
|
+
});
|
|
67
141
|
const { scale = 1 } = material.normalTexture;
|
|
68
142
|
parsedMaterial.uniforms.normalScale = scale;
|
|
69
143
|
}
|
|
70
144
|
if (material.occlusionTexture) {
|
|
71
|
-
addTexture(device, material.occlusionTexture, 'pbr_occlusionSampler',
|
|
145
|
+
addTexture(device, material.occlusionTexture, 'pbr_occlusionSampler', parsedMaterial, {
|
|
146
|
+
featureOptions: {
|
|
147
|
+
define: 'HAS_OCCLUSIONMAP',
|
|
148
|
+
enabledUniformName: 'occlusionMapEnabled'
|
|
149
|
+
},
|
|
150
|
+
gltf
|
|
151
|
+
});
|
|
72
152
|
const { strength = 1 } = material.occlusionTexture;
|
|
73
153
|
parsedMaterial.uniforms.occlusionStrength = strength;
|
|
74
154
|
}
|
|
155
|
+
parsedMaterial.uniforms.emissiveFactor = material.emissiveFactor || [0, 0, 0];
|
|
75
156
|
if (material.emissiveTexture) {
|
|
76
|
-
addTexture(device, material.emissiveTexture, 'pbr_emissiveSampler',
|
|
77
|
-
|
|
157
|
+
addTexture(device, material.emissiveTexture, 'pbr_emissiveSampler', parsedMaterial, {
|
|
158
|
+
featureOptions: {
|
|
159
|
+
define: 'HAS_EMISSIVEMAP',
|
|
160
|
+
enabledUniformName: 'emissiveMapEnabled'
|
|
161
|
+
},
|
|
162
|
+
gltf
|
|
163
|
+
});
|
|
78
164
|
}
|
|
79
|
-
|
|
80
|
-
|
|
165
|
+
parseMaterialExtensions(device, material.extensions, parsedMaterial, gltf);
|
|
166
|
+
switch (material.alphaMode || 'OPAQUE') {
|
|
167
|
+
case 'OPAQUE':
|
|
168
|
+
break;
|
|
169
|
+
case 'MASK': {
|
|
81
170
|
const { alphaCutoff = 0.5 } = material;
|
|
82
171
|
parsedMaterial.defines['ALPHA_CUTOFF'] = true;
|
|
172
|
+
parsedMaterial.uniforms.alphaCutoffEnabled = true;
|
|
83
173
|
parsedMaterial.uniforms.alphaCutoff = alphaCutoff;
|
|
84
174
|
break;
|
|
175
|
+
}
|
|
85
176
|
case 'BLEND':
|
|
86
177
|
log.warn('glTF BLEND alphaMode might not work well because it requires mesh sorting')();
|
|
87
|
-
|
|
88
|
-
parsedMaterial.parameters.blend = true;
|
|
89
|
-
parsedMaterial.parameters.blendColorOperation = 'add';
|
|
90
|
-
parsedMaterial.parameters.blendColorSrcFactor = 'src-alpha';
|
|
91
|
-
parsedMaterial.parameters.blendColorDstFactor = 'one-minus-src-alpha';
|
|
92
|
-
parsedMaterial.parameters.blendAlphaOperation = 'add';
|
|
93
|
-
parsedMaterial.parameters.blendAlphaSrcFactor = 'one';
|
|
94
|
-
parsedMaterial.parameters.blendAlphaDstFactor = 'one-minus-src-alpha';
|
|
95
|
-
// GL parameters
|
|
96
|
-
// TODO - remove in favor of parameters
|
|
97
|
-
parsedMaterial.glParameters['blend'] = true;
|
|
98
|
-
parsedMaterial.glParameters['blendEquation'] = 32774;
|
|
99
|
-
parsedMaterial.glParameters['blendFunc'] = [
|
|
100
|
-
770,
|
|
101
|
-
771,
|
|
102
|
-
1,
|
|
103
|
-
771
|
|
104
|
-
];
|
|
178
|
+
applyAlphaBlendParameters(parsedMaterial);
|
|
105
179
|
break;
|
|
106
180
|
}
|
|
107
181
|
}
|
|
182
|
+
function applyAlphaBlendParameters(parsedMaterial) {
|
|
183
|
+
parsedMaterial.parameters.blend = true;
|
|
184
|
+
parsedMaterial.parameters.blendColorOperation = 'add';
|
|
185
|
+
parsedMaterial.parameters.blendColorSrcFactor = 'src-alpha';
|
|
186
|
+
parsedMaterial.parameters.blendColorDstFactor = 'one-minus-src-alpha';
|
|
187
|
+
parsedMaterial.parameters.blendAlphaOperation = 'add';
|
|
188
|
+
parsedMaterial.parameters.blendAlphaSrcFactor = 'one';
|
|
189
|
+
parsedMaterial.parameters.blendAlphaDstFactor = 'one-minus-src-alpha';
|
|
190
|
+
parsedMaterial.glParameters['blend'] = true;
|
|
191
|
+
parsedMaterial.glParameters['blendEquation'] = GLEnum.FUNC_ADD;
|
|
192
|
+
parsedMaterial.glParameters['blendFunc'] = [
|
|
193
|
+
GLEnum.SRC_ALPHA,
|
|
194
|
+
GLEnum.ONE_MINUS_SRC_ALPHA,
|
|
195
|
+
GLEnum.ONE,
|
|
196
|
+
GLEnum.ONE_MINUS_SRC_ALPHA
|
|
197
|
+
];
|
|
198
|
+
}
|
|
199
|
+
function applyTransmissionBlendApproximation(parsedMaterial) {
|
|
200
|
+
parsedMaterial.parameters.blend = true;
|
|
201
|
+
parsedMaterial.parameters.depthWriteEnabled = false;
|
|
202
|
+
parsedMaterial.parameters.blendColorOperation = 'add';
|
|
203
|
+
parsedMaterial.parameters.blendColorSrcFactor = 'one';
|
|
204
|
+
parsedMaterial.parameters.blendColorDstFactor = 'one-minus-src-alpha';
|
|
205
|
+
parsedMaterial.parameters.blendAlphaOperation = 'add';
|
|
206
|
+
parsedMaterial.parameters.blendAlphaSrcFactor = 'one';
|
|
207
|
+
parsedMaterial.parameters.blendAlphaDstFactor = 'one-minus-src-alpha';
|
|
208
|
+
parsedMaterial.glParameters['blend'] = true;
|
|
209
|
+
parsedMaterial.glParameters['depthMask'] = false;
|
|
210
|
+
parsedMaterial.glParameters['blendEquation'] = GLEnum.FUNC_ADD;
|
|
211
|
+
parsedMaterial.glParameters['blendFunc'] = [
|
|
212
|
+
GLEnum.ONE,
|
|
213
|
+
GLEnum.ONE_MINUS_SRC_ALPHA,
|
|
214
|
+
GLEnum.ONE,
|
|
215
|
+
GLEnum.ONE_MINUS_SRC_ALPHA
|
|
216
|
+
];
|
|
217
|
+
}
|
|
108
218
|
/** Parse GLTF material sub record */
|
|
109
|
-
function parsePbrMetallicRoughness(device, pbrMetallicRoughness, parsedMaterial) {
|
|
219
|
+
function parsePbrMetallicRoughness(device, pbrMetallicRoughness, parsedMaterial, gltf) {
|
|
110
220
|
if (pbrMetallicRoughness.baseColorTexture) {
|
|
111
|
-
addTexture(device, pbrMetallicRoughness.baseColorTexture, 'pbr_baseColorSampler',
|
|
221
|
+
addTexture(device, pbrMetallicRoughness.baseColorTexture, 'pbr_baseColorSampler', parsedMaterial, {
|
|
222
|
+
featureOptions: {
|
|
223
|
+
define: 'HAS_BASECOLORMAP',
|
|
224
|
+
enabledUniformName: 'baseColorMapEnabled'
|
|
225
|
+
},
|
|
226
|
+
gltf
|
|
227
|
+
});
|
|
112
228
|
}
|
|
113
229
|
parsedMaterial.uniforms.baseColorFactor = pbrMetallicRoughness.baseColorFactor || [1, 1, 1, 1];
|
|
114
230
|
if (pbrMetallicRoughness.metallicRoughnessTexture) {
|
|
115
|
-
addTexture(device, pbrMetallicRoughness.metallicRoughnessTexture, 'pbr_metallicRoughnessSampler',
|
|
231
|
+
addTexture(device, pbrMetallicRoughness.metallicRoughnessTexture, 'pbr_metallicRoughnessSampler', parsedMaterial, {
|
|
232
|
+
featureOptions: {
|
|
233
|
+
define: 'HAS_METALROUGHNESSMAP',
|
|
234
|
+
enabledUniformName: 'metallicRoughnessMapEnabled'
|
|
235
|
+
},
|
|
236
|
+
gltf
|
|
237
|
+
});
|
|
116
238
|
}
|
|
117
239
|
const { metallicFactor = 1, roughnessFactor = 1 } = pbrMetallicRoughness;
|
|
118
240
|
parsedMaterial.uniforms.metallicRoughnessValues = [metallicFactor, roughnessFactor];
|
|
119
241
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
let textureOptions;
|
|
124
|
-
if (image.compressed) {
|
|
125
|
-
textureOptions = image;
|
|
242
|
+
function parseMaterialExtensions(device, extensions, parsedMaterial, gltf) {
|
|
243
|
+
if (!extensions) {
|
|
244
|
+
return;
|
|
126
245
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
246
|
+
if (hasMaterialExtensionShading(extensions)) {
|
|
247
|
+
parsedMaterial.defines['USE_MATERIAL_EXTENSIONS'] = true;
|
|
248
|
+
}
|
|
249
|
+
parseSpecularExtension(device, extensions.KHR_materials_specular, parsedMaterial, gltf);
|
|
250
|
+
parseIorExtension(extensions.KHR_materials_ior, parsedMaterial);
|
|
251
|
+
parseTransmissionExtension(device, extensions.KHR_materials_transmission, parsedMaterial, gltf);
|
|
252
|
+
parseVolumeExtension(device, extensions.KHR_materials_volume, parsedMaterial, gltf);
|
|
253
|
+
parseClearcoatExtension(device, extensions.KHR_materials_clearcoat, parsedMaterial, gltf);
|
|
254
|
+
parseSheenExtension(device, extensions.KHR_materials_sheen, parsedMaterial, gltf);
|
|
255
|
+
parseIridescenceExtension(device, extensions.KHR_materials_iridescence, parsedMaterial, gltf);
|
|
256
|
+
parseAnisotropyExtension(device, extensions.KHR_materials_anisotropy, parsedMaterial, gltf);
|
|
257
|
+
parseEmissiveStrengthExtension(extensions.KHR_materials_emissive_strength, parsedMaterial);
|
|
258
|
+
}
|
|
259
|
+
function hasMaterialExtensionShading(extensions) {
|
|
260
|
+
return Boolean(extensions.KHR_materials_specular ||
|
|
261
|
+
extensions.KHR_materials_ior ||
|
|
262
|
+
extensions.KHR_materials_transmission ||
|
|
263
|
+
extensions.KHR_materials_volume ||
|
|
264
|
+
extensions.KHR_materials_clearcoat ||
|
|
265
|
+
extensions.KHR_materials_sheen ||
|
|
266
|
+
extensions.KHR_materials_iridescence ||
|
|
267
|
+
extensions.KHR_materials_anisotropy);
|
|
268
|
+
}
|
|
269
|
+
function parseSpecularExtension(device, extension, parsedMaterial, gltf) {
|
|
270
|
+
if (!extension) {
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
if (extension.specularColorFactor) {
|
|
274
|
+
parsedMaterial.uniforms.specularColorFactor = extension.specularColorFactor;
|
|
275
|
+
}
|
|
276
|
+
if (extension.specularFactor !== undefined) {
|
|
277
|
+
parsedMaterial.uniforms.specularIntensityFactor = extension.specularFactor;
|
|
278
|
+
}
|
|
279
|
+
if (extension.specularColorTexture) {
|
|
280
|
+
addTexture(device, extension.specularColorTexture, 'pbr_specularColorSampler', parsedMaterial, {
|
|
281
|
+
featureOptions: {
|
|
282
|
+
define: 'HAS_SPECULARCOLORMAP',
|
|
283
|
+
enabledUniformName: 'specularColorMapEnabled'
|
|
284
|
+
},
|
|
285
|
+
gltf
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
if (extension.specularTexture) {
|
|
289
|
+
addTexture(device, extension.specularTexture, 'pbr_specularIntensitySampler', parsedMaterial, {
|
|
290
|
+
featureOptions: {
|
|
291
|
+
define: 'HAS_SPECULARINTENSITYMAP',
|
|
292
|
+
enabledUniformName: 'specularIntensityMapEnabled'
|
|
293
|
+
},
|
|
294
|
+
gltf
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
function parseIorExtension(extension, parsedMaterial) {
|
|
299
|
+
if (extension?.ior !== undefined) {
|
|
300
|
+
parsedMaterial.uniforms.ior = extension.ior;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
function parseTransmissionExtension(device, extension, parsedMaterial, gltf) {
|
|
304
|
+
if (!extension) {
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
if (extension.transmissionFactor !== undefined) {
|
|
308
|
+
parsedMaterial.uniforms.transmissionFactor = extension.transmissionFactor;
|
|
309
|
+
}
|
|
310
|
+
if (extension.transmissionTexture) {
|
|
311
|
+
addTexture(device, extension.transmissionTexture, 'pbr_transmissionSampler', parsedMaterial, {
|
|
312
|
+
featureOptions: {
|
|
313
|
+
define: 'HAS_TRANSMISSIONMAP',
|
|
314
|
+
enabledUniformName: 'transmissionMapEnabled'
|
|
315
|
+
},
|
|
316
|
+
gltf
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
if ((extension.transmissionFactor ?? 0) > 0 || extension.transmissionTexture) {
|
|
320
|
+
log.warn('KHR_materials_transmission uses a premultiplied-alpha blending approximation and may require mesh sorting')();
|
|
321
|
+
applyTransmissionBlendApproximation(parsedMaterial);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
function parseVolumeExtension(device, extension, parsedMaterial, gltf) {
|
|
325
|
+
if (!extension) {
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
if (extension.thicknessFactor !== undefined) {
|
|
329
|
+
parsedMaterial.uniforms.thicknessFactor = extension.thicknessFactor;
|
|
330
|
+
}
|
|
331
|
+
if (extension.thicknessTexture) {
|
|
332
|
+
addTexture(device, extension.thicknessTexture, 'pbr_thicknessSampler', parsedMaterial, {
|
|
333
|
+
featureOptions: {
|
|
334
|
+
define: 'HAS_THICKNESSMAP'
|
|
335
|
+
},
|
|
336
|
+
gltf
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
if (extension.attenuationDistance !== undefined) {
|
|
340
|
+
parsedMaterial.uniforms.attenuationDistance = extension.attenuationDistance;
|
|
341
|
+
}
|
|
342
|
+
if (extension.attenuationColor) {
|
|
343
|
+
parsedMaterial.uniforms.attenuationColor = extension.attenuationColor;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
function parseClearcoatExtension(device, extension, parsedMaterial, gltf) {
|
|
347
|
+
if (!extension) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
if (extension.clearcoatFactor !== undefined) {
|
|
351
|
+
parsedMaterial.uniforms.clearcoatFactor = extension.clearcoatFactor;
|
|
352
|
+
}
|
|
353
|
+
if (extension.clearcoatRoughnessFactor !== undefined) {
|
|
354
|
+
parsedMaterial.uniforms.clearcoatRoughnessFactor = extension.clearcoatRoughnessFactor;
|
|
355
|
+
}
|
|
356
|
+
if (extension.clearcoatTexture) {
|
|
357
|
+
addTexture(device, extension.clearcoatTexture, 'pbr_clearcoatSampler', parsedMaterial, {
|
|
358
|
+
featureOptions: {
|
|
359
|
+
define: 'HAS_CLEARCOATMAP',
|
|
360
|
+
enabledUniformName: 'clearcoatMapEnabled'
|
|
361
|
+
},
|
|
362
|
+
gltf
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
if (extension.clearcoatRoughnessTexture) {
|
|
366
|
+
addTexture(device, extension.clearcoatRoughnessTexture, 'pbr_clearcoatRoughnessSampler', parsedMaterial, {
|
|
367
|
+
featureOptions: {
|
|
368
|
+
define: 'HAS_CLEARCOATROUGHNESSMAP',
|
|
369
|
+
enabledUniformName: 'clearcoatRoughnessMapEnabled'
|
|
370
|
+
},
|
|
371
|
+
gltf
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
if (extension.clearcoatNormalTexture) {
|
|
375
|
+
addTexture(device, extension.clearcoatNormalTexture, 'pbr_clearcoatNormalSampler', parsedMaterial, {
|
|
376
|
+
featureOptions: {
|
|
377
|
+
define: 'HAS_CLEARCOATNORMALMAP'
|
|
378
|
+
},
|
|
379
|
+
gltf
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
function parseSheenExtension(device, extension, parsedMaterial, gltf) {
|
|
384
|
+
if (!extension) {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
if (extension.sheenColorFactor) {
|
|
388
|
+
parsedMaterial.uniforms.sheenColorFactor = extension.sheenColorFactor;
|
|
389
|
+
}
|
|
390
|
+
if (extension.sheenRoughnessFactor !== undefined) {
|
|
391
|
+
parsedMaterial.uniforms.sheenRoughnessFactor = extension.sheenRoughnessFactor;
|
|
392
|
+
}
|
|
393
|
+
if (extension.sheenColorTexture) {
|
|
394
|
+
addTexture(device, extension.sheenColorTexture, 'pbr_sheenColorSampler', parsedMaterial, {
|
|
395
|
+
featureOptions: {
|
|
396
|
+
define: 'HAS_SHEENCOLORMAP',
|
|
397
|
+
enabledUniformName: 'sheenColorMapEnabled'
|
|
398
|
+
},
|
|
399
|
+
gltf
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
if (extension.sheenRoughnessTexture) {
|
|
403
|
+
addTexture(device, extension.sheenRoughnessTexture, 'pbr_sheenRoughnessSampler', parsedMaterial, {
|
|
404
|
+
featureOptions: {
|
|
405
|
+
define: 'HAS_SHEENROUGHNESSMAP',
|
|
406
|
+
enabledUniformName: 'sheenRoughnessMapEnabled'
|
|
407
|
+
},
|
|
408
|
+
gltf
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
function parseIridescenceExtension(device, extension, parsedMaterial, gltf) {
|
|
413
|
+
if (!extension) {
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
if (extension.iridescenceFactor !== undefined) {
|
|
417
|
+
parsedMaterial.uniforms.iridescenceFactor = extension.iridescenceFactor;
|
|
418
|
+
}
|
|
419
|
+
if (extension.iridescenceIor !== undefined) {
|
|
420
|
+
parsedMaterial.uniforms.iridescenceIor = extension.iridescenceIor;
|
|
421
|
+
}
|
|
422
|
+
if (extension.iridescenceThicknessMinimum !== undefined ||
|
|
423
|
+
extension.iridescenceThicknessMaximum !== undefined) {
|
|
424
|
+
parsedMaterial.uniforms.iridescenceThicknessRange = [
|
|
425
|
+
extension.iridescenceThicknessMinimum ?? 100,
|
|
426
|
+
extension.iridescenceThicknessMaximum ?? 400
|
|
427
|
+
];
|
|
428
|
+
}
|
|
429
|
+
if (extension.iridescenceTexture) {
|
|
430
|
+
addTexture(device, extension.iridescenceTexture, 'pbr_iridescenceSampler', parsedMaterial, {
|
|
431
|
+
featureOptions: {
|
|
432
|
+
define: 'HAS_IRIDESCENCEMAP',
|
|
433
|
+
enabledUniformName: 'iridescenceMapEnabled'
|
|
434
|
+
},
|
|
435
|
+
gltf
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
if (extension.iridescenceThicknessTexture) {
|
|
439
|
+
addTexture(device, extension.iridescenceThicknessTexture, 'pbr_iridescenceThicknessSampler', parsedMaterial, {
|
|
440
|
+
featureOptions: {
|
|
441
|
+
define: 'HAS_IRIDESCENCETHICKNESSMAP'
|
|
442
|
+
},
|
|
443
|
+
gltf
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
function parseAnisotropyExtension(device, extension, parsedMaterial, gltf) {
|
|
448
|
+
if (!extension) {
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
if (extension.anisotropyStrength !== undefined) {
|
|
452
|
+
parsedMaterial.uniforms.anisotropyStrength = extension.anisotropyStrength;
|
|
453
|
+
}
|
|
454
|
+
if (extension.anisotropyRotation !== undefined) {
|
|
455
|
+
parsedMaterial.uniforms.anisotropyRotation = extension.anisotropyRotation;
|
|
456
|
+
}
|
|
457
|
+
if (extension.anisotropyTexture) {
|
|
458
|
+
addTexture(device, extension.anisotropyTexture, 'pbr_anisotropySampler', parsedMaterial, {
|
|
459
|
+
featureOptions: {
|
|
460
|
+
define: 'HAS_ANISOTROPYMAP',
|
|
461
|
+
enabledUniformName: 'anisotropyMapEnabled'
|
|
462
|
+
},
|
|
463
|
+
gltf
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
function parseEmissiveStrengthExtension(extension, parsedMaterial) {
|
|
468
|
+
if (extension?.emissiveStrength !== undefined) {
|
|
469
|
+
parsedMaterial.uniforms.emissiveStrength = extension.emissiveStrength;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
/** Create a texture from a glTF texture/sampler/image combo and add it to bindings */
|
|
473
|
+
function addTexture(device, gltfTexture, uniformName, parsedMaterial, textureParseOptions = {}) {
|
|
474
|
+
const { featureOptions = {}, gltf } = textureParseOptions;
|
|
475
|
+
const { define, enabledUniformName } = featureOptions;
|
|
476
|
+
const resolvedTextureInfo = resolveTextureInfo(gltfTexture, gltf);
|
|
477
|
+
const image = resolvedTextureInfo.texture?.source?.image;
|
|
478
|
+
if (!image) {
|
|
479
|
+
log.warn(`Skipping unresolved glTF texture for ${String(uniformName)}`)();
|
|
480
|
+
return;
|
|
130
481
|
}
|
|
131
482
|
const gltfSampler = {
|
|
132
483
|
wrapS: 10497, // default REPEAT S (U) wrapping mode.
|
|
133
484
|
wrapT: 10497, // default REPEAT T (V) wrapping mode.
|
|
134
|
-
|
|
485
|
+
minFilter: 9729, // default LINEAR filtering
|
|
486
|
+
magFilter: 9729, // default LINEAR filtering
|
|
487
|
+
...resolvedTextureInfo?.texture?.sampler
|
|
135
488
|
};
|
|
136
|
-
const
|
|
137
|
-
id:
|
|
138
|
-
sampler: convertSampler(gltfSampler)
|
|
139
|
-
|
|
140
|
-
|
|
489
|
+
const baseOptions = {
|
|
490
|
+
id: resolvedTextureInfo.uniformName || resolvedTextureInfo.id,
|
|
491
|
+
sampler: convertSampler(gltfSampler)
|
|
492
|
+
};
|
|
493
|
+
let texture;
|
|
494
|
+
if (image.compressed) {
|
|
495
|
+
texture = createCompressedTexture(device, image, baseOptions);
|
|
496
|
+
}
|
|
497
|
+
else {
|
|
498
|
+
const { width, height } = device.getExternalImageSize(image);
|
|
499
|
+
texture = device.createTexture({
|
|
500
|
+
...baseOptions,
|
|
501
|
+
width,
|
|
502
|
+
height,
|
|
503
|
+
data: image
|
|
504
|
+
});
|
|
505
|
+
}
|
|
141
506
|
parsedMaterial.bindings[uniformName] = texture;
|
|
142
507
|
if (define)
|
|
143
508
|
parsedMaterial.defines[define] = true;
|
|
509
|
+
if (enabledUniformName) {
|
|
510
|
+
parsedMaterial.uniforms[enabledUniformName] = true;
|
|
511
|
+
}
|
|
144
512
|
parsedMaterial.generatedTextures.push(texture);
|
|
145
513
|
}
|
|
514
|
+
function resolveTextureInfo(gltfTexture, gltf) {
|
|
515
|
+
if (gltfTexture.texture || gltfTexture.index === undefined || !gltf?.textures) {
|
|
516
|
+
return gltfTexture;
|
|
517
|
+
}
|
|
518
|
+
const resolvedTextureEntry = gltf.textures[gltfTexture.index];
|
|
519
|
+
if (!resolvedTextureEntry) {
|
|
520
|
+
return gltfTexture;
|
|
521
|
+
}
|
|
522
|
+
if ('texture' in resolvedTextureEntry && resolvedTextureEntry.texture) {
|
|
523
|
+
return {
|
|
524
|
+
...resolvedTextureEntry,
|
|
525
|
+
...gltfTexture,
|
|
526
|
+
texture: resolvedTextureEntry.texture
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
if (!('source' in resolvedTextureEntry)) {
|
|
530
|
+
return gltfTexture;
|
|
531
|
+
}
|
|
532
|
+
return {
|
|
533
|
+
...gltfTexture,
|
|
534
|
+
texture: resolvedTextureEntry
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
function createCompressedTextureFallback(device, baseOptions) {
|
|
538
|
+
return device.createTexture({
|
|
539
|
+
...baseOptions,
|
|
540
|
+
format: 'rgba8unorm',
|
|
541
|
+
width: 1,
|
|
542
|
+
height: 1,
|
|
543
|
+
mipLevels: 1
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
function resolveCompressedTextureFormat(level) {
|
|
547
|
+
return level.textureFormat;
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Maximum mip levels that can be filled for a compressed texture.
|
|
551
|
+
* texStorage2D allocates level i at (baseW >> i) × (baseH >> i).
|
|
552
|
+
* Compressed formats can't upload data for levels smaller than one block,
|
|
553
|
+
* so we stop before either dimension drops below the block size.
|
|
554
|
+
*/
|
|
555
|
+
function getMaxCompressedMipLevels(baseWidth, baseHeight, format) {
|
|
556
|
+
const { blockWidth = 1, blockHeight = 1 } = textureFormatDecoder.getInfo(format);
|
|
557
|
+
let count = 1;
|
|
558
|
+
for (let i = 1;; i++) {
|
|
559
|
+
const w = Math.max(1, baseWidth >> i);
|
|
560
|
+
const h = Math.max(1, baseHeight >> i);
|
|
561
|
+
if (w < blockWidth || h < blockHeight)
|
|
562
|
+
break;
|
|
563
|
+
count++;
|
|
564
|
+
}
|
|
565
|
+
return count;
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Create a texture from compressed image data produced by loaders.gl.
|
|
569
|
+
* Handles current loaders.gl compressed image layouts:
|
|
570
|
+
*
|
|
571
|
+
* current: {compressed, mipmaps: true, data: [{data, width, height, textureFormat}, ...]}
|
|
572
|
+
* forward: {compressed, mipmaps: [{data, width, height, textureFormat}, ...]}
|
|
573
|
+
*/
|
|
574
|
+
export function createCompressedTexture(device, image, baseOptions) {
|
|
575
|
+
// Normalize mip levels from all known loaders.gl formats
|
|
576
|
+
let levels;
|
|
577
|
+
if (Array.isArray(image.data) && image.data[0]?.data) {
|
|
578
|
+
// loaders.gl current format: image.data is Array of mip-level objects
|
|
579
|
+
levels = image.data;
|
|
580
|
+
}
|
|
581
|
+
else if ('mipmaps' in image && Array.isArray(image.mipmaps)) {
|
|
582
|
+
// Hypothetical future format: image.mipmaps is an Array
|
|
583
|
+
levels = image.mipmaps;
|
|
584
|
+
}
|
|
585
|
+
else {
|
|
586
|
+
levels = [];
|
|
587
|
+
}
|
|
588
|
+
if (levels.length === 0 || !levels[0]?.data) {
|
|
589
|
+
log.warn('createCompressedTexture: compressed image has no valid mip levels, creating fallback')();
|
|
590
|
+
return createCompressedTextureFallback(device, baseOptions);
|
|
591
|
+
}
|
|
592
|
+
const baseLevel = levels[0];
|
|
593
|
+
const baseWidth = baseLevel.width ?? image.width ?? 0;
|
|
594
|
+
const baseHeight = baseLevel.height ?? image.height ?? 0;
|
|
595
|
+
if (baseWidth <= 0 || baseHeight <= 0) {
|
|
596
|
+
log.warn('createCompressedTexture: base level has invalid dimensions, creating fallback')();
|
|
597
|
+
return createCompressedTextureFallback(device, baseOptions);
|
|
598
|
+
}
|
|
599
|
+
const format = resolveCompressedTextureFormat(baseLevel);
|
|
600
|
+
if (!format) {
|
|
601
|
+
log.warn('createCompressedTexture: compressed image has no textureFormat, creating fallback')();
|
|
602
|
+
return createCompressedTextureFallback(device, baseOptions);
|
|
603
|
+
}
|
|
604
|
+
// Validate mip levels: truncate chain at first invalid level.
|
|
605
|
+
// Levels must be contiguous, so we stop at the first level that has
|
|
606
|
+
// a format mismatch, missing data, non-positive dimensions, or
|
|
607
|
+
// dimensions that don't match what texStorage2D will allocate.
|
|
608
|
+
//
|
|
609
|
+
// For block-compressed formats (ASTC, BC, ETC2), texStorage2D allocates
|
|
610
|
+
// mip levels down to 1×1 texels, but compressed data can't be smaller
|
|
611
|
+
// than one block (e.g. 4×4 for ASTC-4x4). Cap the chain so we never
|
|
612
|
+
// try to upload data whose block-aligned size exceeds the allocated level.
|
|
613
|
+
const maxMipLevels = getMaxCompressedMipLevels(baseWidth, baseHeight, format);
|
|
614
|
+
const levelLimit = Math.min(levels.length, maxMipLevels);
|
|
615
|
+
let validLevelCount = 1;
|
|
616
|
+
for (let i = 1; i < levelLimit; i++) {
|
|
617
|
+
const level = levels[i];
|
|
618
|
+
if (!level.data || level.width <= 0 || level.height <= 0) {
|
|
619
|
+
log.warn(`createCompressedTexture: mip level ${i} has invalid data/dimensions, truncating`)();
|
|
620
|
+
break;
|
|
621
|
+
}
|
|
622
|
+
const levelFormat = resolveCompressedTextureFormat(level);
|
|
623
|
+
if (levelFormat && levelFormat !== format) {
|
|
624
|
+
log.warn(`createCompressedTexture: mip level ${i} format '${levelFormat}' differs from base '${format}', truncating`)();
|
|
625
|
+
break;
|
|
626
|
+
}
|
|
627
|
+
const expectedW = Math.max(1, baseWidth >> i);
|
|
628
|
+
const expectedH = Math.max(1, baseHeight >> i);
|
|
629
|
+
if (level.width !== expectedW || level.height !== expectedH) {
|
|
630
|
+
log.warn(`createCompressedTexture: mip level ${i} dimensions ${level.width}x${level.height} ` +
|
|
631
|
+
`don't match expected ${expectedW}x${expectedH}, truncating`)();
|
|
632
|
+
break;
|
|
633
|
+
}
|
|
634
|
+
validLevelCount++;
|
|
635
|
+
}
|
|
636
|
+
const texture = device.createTexture({
|
|
637
|
+
...baseOptions,
|
|
638
|
+
format,
|
|
639
|
+
usage: Texture.TEXTURE | Texture.COPY_DST,
|
|
640
|
+
width: baseWidth,
|
|
641
|
+
height: baseHeight,
|
|
642
|
+
mipLevels: validLevelCount,
|
|
643
|
+
data: baseLevel.data
|
|
644
|
+
});
|
|
645
|
+
// Upload additional validated mip levels
|
|
646
|
+
for (let i = 1; i < validLevelCount; i++) {
|
|
647
|
+
texture.writeData(levels[i].data, {
|
|
648
|
+
width: levels[i].width,
|
|
649
|
+
height: levels[i].height,
|
|
650
|
+
mipLevel: i
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
return texture;
|
|
654
|
+
}
|
|
146
655
|
/*
|
|
147
656
|
/**
|
|
148
657
|
* Parses a GLTF material definition into uniforms and parameters for the PBR shader module
|
|
@@ -188,7 +697,7 @@ export class PBRMaterialParser {
|
|
|
188
697
|
if (imageBasedLightingEnvironment) {
|
|
189
698
|
this.bindings.pbr_diffuseEnvSampler = imageBasedLightingEnvironment.getDiffuseEnvSampler();
|
|
190
699
|
this.bindings.pbr_specularEnvSampler = imageBasedLightingEnvironment.getSpecularEnvSampler();
|
|
191
|
-
this.bindings.
|
|
700
|
+
this.bindings.pbr_brdfLUT = imageBasedLightingEnvironment.getBrdfTexture();
|
|
192
701
|
this.uniforms.scaleIBLAmbient = [1, 1];
|
|
193
702
|
}
|
|
194
703
|
|
|
@@ -202,6 +711,7 @@ export class PBRMaterialParser {
|
|
|
202
711
|
this.defineIfPresent(attributes.NORMAL, 'HAS_NORMALS');
|
|
203
712
|
this.defineIfPresent(attributes.TANGENT && useTangents, 'HAS_TANGENTS');
|
|
204
713
|
this.defineIfPresent(attributes.TEXCOORD_0, 'HAS_UV');
|
|
714
|
+
this.defineIfPresent(attributes.COLOR_0, 'HAS_COLORS');
|
|
205
715
|
|
|
206
716
|
this.defineIfPresent(imageBasedLightingEnvironment, 'USE_IBL');
|
|
207
717
|
this.defineIfPresent(lights, 'USE_LIGHTS');
|
|
@@ -257,8 +767,13 @@ export class PBRMaterialParser {
|
|
|
257
767
|
log.warn('BLEND alphaMode might not work well because it requires mesh sorting')();
|
|
258
768
|
Object.assign(this.parameters, {
|
|
259
769
|
blend: true,
|
|
260
|
-
blendEquation:
|
|
261
|
-
blendFunc: [
|
|
770
|
+
blendEquation: GLEnum.FUNC_ADD,
|
|
771
|
+
blendFunc: [
|
|
772
|
+
GLEnum.SRC_ALPHA,
|
|
773
|
+
GLEnum.ONE_MINUS_SRC_ALPHA,
|
|
774
|
+
GLEnum.ONE,
|
|
775
|
+
GLEnum.ONE_MINUS_SRC_ALPHA
|
|
776
|
+
]
|
|
262
777
|
});
|
|
263
778
|
}
|
|
264
779
|
}
|
|
@@ -295,7 +810,8 @@ export class PBRMaterialParser {
|
|
|
295
810
|
if (image.compressed) {
|
|
296
811
|
textureOptions = image;
|
|
297
812
|
specialTextureParameters = {
|
|
298
|
-
[
|
|
813
|
+
[GLEnum.TEXTURE_MIN_FILTER]:
|
|
814
|
+
image.data.length > 1 ? GLEnum.LINEAR_MIPMAP_NEAREST : GLEnum.LINEAR
|
|
299
815
|
};
|
|
300
816
|
} else {
|
|
301
817
|
// Texture2D accepts a promise that returns an image as data (Async Textures)
|
|
@@ -309,7 +825,7 @@ export class PBRMaterialParser {
|
|
|
309
825
|
...specialTextureParameters
|
|
310
826
|
},
|
|
311
827
|
pixelStore: {
|
|
312
|
-
[
|
|
828
|
+
[GLEnum.UNPACK_FLIP_Y_WEBGL]: false
|
|
313
829
|
},
|
|
314
830
|
...textureOptions
|
|
315
831
|
});
|