@babylonjs/loaders 9.8.0 → 9.9.1
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/SPLAT/splatFileLoader.js +11 -3
- package/SPLAT/splatFileLoader.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_materials_diffuse_transmission.js +4 -0
- package/glTF/2.0/Extensions/KHR_materials_diffuse_transmission.js.map +1 -1
- package/glTF/2.0/Extensions/KHR_materials_transmission.js +3 -331
- package/glTF/2.0/Extensions/KHR_materials_transmission.js.map +1 -1
- package/glTF/2.0/Extensions/MSFT_minecraftMesh.js +2 -1
- package/glTF/2.0/Extensions/MSFT_minecraftMesh.js.map +1 -1
- package/glTF/2.0/Extensions/index.d.ts +1 -0
- package/glTF/2.0/Extensions/index.js +1 -0
- package/glTF/2.0/Extensions/index.js.map +1 -1
- package/glTF/2.0/Extensions/transmissionHelper.d.ts +157 -0
- package/glTF/2.0/Extensions/transmissionHelper.js +373 -0
- package/glTF/2.0/Extensions/transmissionHelper.js.map +1 -0
- package/glTF/2.0/glTFLoader.d.ts +24 -4
- package/glTF/2.0/glTFLoader.js +98 -32
- package/glTF/2.0/glTFLoader.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { type Nullable } from "@babylonjs/core/types.js";
|
|
2
|
+
import { type Material } from "@babylonjs/core/Materials/material.js";
|
|
3
|
+
import { type Scene } from "@babylonjs/core/scene.js";
|
|
4
|
+
import { type Texture } from "@babylonjs/core/Materials/Textures/texture.js";
|
|
5
|
+
import { Observable } from "@babylonjs/core/Misc/observable.js";
|
|
6
|
+
import { type Color4 } from "@babylonjs/core/Maths/math.color.js";
|
|
7
|
+
import { type IMaterialLoadingAdapter } from "../materialLoadingAdapter.js";
|
|
8
|
+
import { type GLTFLoader } from "../glTFLoader.js";
|
|
9
|
+
/**
|
|
10
|
+
* Describes a material class and its corresponding loading adapter.
|
|
11
|
+
* Passed to TransmissionHelper so it can classify and interact with materials
|
|
12
|
+
* independently of any specific loader instance.
|
|
13
|
+
*/
|
|
14
|
+
export interface ITransmissionHelperMaterialImpl {
|
|
15
|
+
/** The material class constructor */
|
|
16
|
+
materialClass: typeof Material;
|
|
17
|
+
/** The adapter class constructor */
|
|
18
|
+
adapterClass: new (material: Material) => IMaterialLoadingAdapter;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* @internal
|
|
22
|
+
*/
|
|
23
|
+
export interface ITransmissionHelperHolder {
|
|
24
|
+
/** The transmission helper instance, if created on the scene */
|
|
25
|
+
_transmissionHelper: TransmissionHelper | undefined;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Options for the TransmissionHelper.
|
|
29
|
+
*/
|
|
30
|
+
export interface ITransmissionHelperOptions {
|
|
31
|
+
/**
|
|
32
|
+
* The size of the render buffers (default: 1024)
|
|
33
|
+
*/
|
|
34
|
+
renderSize: number;
|
|
35
|
+
/**
|
|
36
|
+
* The number of samples to use when generating the render target texture for opaque meshes (default: 4)
|
|
37
|
+
*/
|
|
38
|
+
samples: number;
|
|
39
|
+
/**
|
|
40
|
+
* Scale to apply when selecting the LOD level to sample the refraction texture (default: 1)
|
|
41
|
+
*/
|
|
42
|
+
lodGenerationScale: number;
|
|
43
|
+
/**
|
|
44
|
+
* Offset to apply when selecting the LOD level to sample the refraction texture (default: -4)
|
|
45
|
+
*/
|
|
46
|
+
lodGenerationOffset: number;
|
|
47
|
+
/**
|
|
48
|
+
* Type of the refraction render target texture (default: TEXTURETYPE_HALF_FLOAT)
|
|
49
|
+
*/
|
|
50
|
+
renderTargetTextureType: number;
|
|
51
|
+
/**
|
|
52
|
+
* Defines if the mipmaps for the refraction render target texture must be generated (default: true)
|
|
53
|
+
*/
|
|
54
|
+
generateMipmaps: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Clear color of the opaque texture. If not provided, use the scene clear color (which will be converted to linear space).
|
|
57
|
+
* If provided, should be in linear space
|
|
58
|
+
*/
|
|
59
|
+
clearColor?: Color4;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* A class to handle setting up the rendering of opaque objects to be shown through transmissive objects.
|
|
63
|
+
* @internal
|
|
64
|
+
*/
|
|
65
|
+
export declare class TransmissionHelper {
|
|
66
|
+
/**
|
|
67
|
+
* Creates the default options for the helper.
|
|
68
|
+
* @returns the default options
|
|
69
|
+
*/
|
|
70
|
+
private static _GetDefaultOptions;
|
|
71
|
+
private readonly _scene;
|
|
72
|
+
private _options;
|
|
73
|
+
private _opaqueRenderTarget;
|
|
74
|
+
private _opaqueMeshesCache;
|
|
75
|
+
private _transparentMeshesCache;
|
|
76
|
+
private _materialObservers;
|
|
77
|
+
private readonly _materialImpls;
|
|
78
|
+
private readonly _adapterCache;
|
|
79
|
+
/**
|
|
80
|
+
* This observable will be notified with any error during the creation of the environment,
|
|
81
|
+
* mainly texture creation errors.
|
|
82
|
+
*/
|
|
83
|
+
onErrorObservable: Observable<{
|
|
84
|
+
message?: string;
|
|
85
|
+
exception?: any;
|
|
86
|
+
}>;
|
|
87
|
+
private _translucentMaterialIndices;
|
|
88
|
+
private _opaqueOnlySubMeshes;
|
|
89
|
+
private _savedSubMeshes;
|
|
90
|
+
/**
|
|
91
|
+
* constructor
|
|
92
|
+
* @param options Defines the options we want to customize the helper
|
|
93
|
+
* @param scene The scene to add the material to
|
|
94
|
+
*/
|
|
95
|
+
constructor(options: Partial<ITransmissionHelperOptions>, scene: Scene);
|
|
96
|
+
/**
|
|
97
|
+
* Registers a material implementation with the helper so it can classify and create
|
|
98
|
+
* adapters for materials of that type. Safe to call multiple times with the same
|
|
99
|
+
* implementation — duplicates are ignored.
|
|
100
|
+
* @param impl The material implementation to register
|
|
101
|
+
*/
|
|
102
|
+
addMaterialImpl(impl: ITransmissionHelperMaterialImpl): void;
|
|
103
|
+
/**
|
|
104
|
+
* Updates the helper options.
|
|
105
|
+
* @param options the options to update
|
|
106
|
+
*/
|
|
107
|
+
updateOptions(options: Partial<ITransmissionHelperOptions>): void;
|
|
108
|
+
/**
|
|
109
|
+
* @returns the opaque render target texture or null if not available.
|
|
110
|
+
*/
|
|
111
|
+
getOpaqueTarget(): Nullable<Texture>;
|
|
112
|
+
private _getOrCreateAdapter;
|
|
113
|
+
/**
|
|
114
|
+
* Classify a mesh's materials as transparent, opaque, or mixed.
|
|
115
|
+
* Sets the refraction background texture on any translucent materials found.
|
|
116
|
+
* For mixed MultiMaterial meshes, populates _translucentMaterialIndices so
|
|
117
|
+
* their translucent submeshes can be excluded from the opaque render target.
|
|
118
|
+
* @param mesh - The mesh to classify
|
|
119
|
+
* @returns 'transparent' if all materials are translucent, 'opaque' if none are, 'mixed' if both
|
|
120
|
+
*/
|
|
121
|
+
private _classifyMeshMaterials;
|
|
122
|
+
/**
|
|
123
|
+
* Rebuild the cached opaque-only submesh array for a mixed mesh.
|
|
124
|
+
* Called when classification changes so the per-frame swap is allocation-free.
|
|
125
|
+
* @param mesh - The mesh to rebuild for
|
|
126
|
+
* @param translucentIndices - Set of materialIndex values that are translucent
|
|
127
|
+
*/
|
|
128
|
+
private _rebuildOpaqueOnlySubMeshes;
|
|
129
|
+
private _addMesh;
|
|
130
|
+
private _removeMesh;
|
|
131
|
+
private _parseScene;
|
|
132
|
+
private _onMeshMaterialChanged;
|
|
133
|
+
/**
|
|
134
|
+
* @internal
|
|
135
|
+
* Check if the opaque render target has not been disposed and can still be used.
|
|
136
|
+
* @returns
|
|
137
|
+
*/
|
|
138
|
+
_isRenderTargetValid(): boolean;
|
|
139
|
+
/**
|
|
140
|
+
* @internal
|
|
141
|
+
* Setup the render targets according to the specified options.
|
|
142
|
+
*/
|
|
143
|
+
_setupRenderTargets(): void;
|
|
144
|
+
/**
|
|
145
|
+
* Dispose all the elements created by the Helper.
|
|
146
|
+
*/
|
|
147
|
+
dispose(): void;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Ensures a TransmissionHelper exists on the scene and has all of the loader's material
|
|
151
|
+
* implementations registered with it. Creates the helper if one does not yet exist on the
|
|
152
|
+
* scene, and recreates its render target if it has been disposed. Does nothing when the
|
|
153
|
+
* loader's parent has `dontUseTransmissionHelper` set.
|
|
154
|
+
* @param loader The glTF loader whose material implementations should be registered
|
|
155
|
+
* @param babylonMaterial A material belonging to the scene where the helper should live
|
|
156
|
+
*/
|
|
157
|
+
export declare function ensureTransmissionHelper(loader: GLTFLoader, babylonMaterial: Material): void;
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
import { MultiMaterial } from "@babylonjs/core/Materials/multiMaterial.js";
|
|
2
|
+
import { RenderTargetTexture } from "@babylonjs/core/Materials/Textures/renderTargetTexture.js";
|
|
3
|
+
import { Observable } from "@babylonjs/core/Misc/observable.js";
|
|
4
|
+
import { Constants } from "@babylonjs/core/Engines/constants.js";
|
|
5
|
+
import { Tools } from "@babylonjs/core/Misc/tools.js";
|
|
6
|
+
/**
|
|
7
|
+
* A class to handle setting up the rendering of opaque objects to be shown through transmissive objects.
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
export class TransmissionHelper {
|
|
11
|
+
/**
|
|
12
|
+
* Creates the default options for the helper.
|
|
13
|
+
* @returns the default options
|
|
14
|
+
*/
|
|
15
|
+
static _GetDefaultOptions() {
|
|
16
|
+
return {
|
|
17
|
+
renderSize: 1024,
|
|
18
|
+
samples: 4,
|
|
19
|
+
lodGenerationScale: 1,
|
|
20
|
+
lodGenerationOffset: -4,
|
|
21
|
+
renderTargetTextureType: Constants.TEXTURETYPE_HALF_FLOAT,
|
|
22
|
+
generateMipmaps: true,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* constructor
|
|
27
|
+
* @param options Defines the options we want to customize the helper
|
|
28
|
+
* @param scene The scene to add the material to
|
|
29
|
+
*/
|
|
30
|
+
constructor(options, scene) {
|
|
31
|
+
this._opaqueRenderTarget = null;
|
|
32
|
+
this._opaqueMeshesCache = [];
|
|
33
|
+
this._transparentMeshesCache = [];
|
|
34
|
+
this._materialObservers = {};
|
|
35
|
+
// Material implementations registered by loaders. Each entry maps a material class
|
|
36
|
+
// to its adapter class so the helper can classify and interact with materials
|
|
37
|
+
// independently of whichever loader originally created them.
|
|
38
|
+
this._materialImpls = [];
|
|
39
|
+
this._adapterCache = new WeakMap();
|
|
40
|
+
// For MultiMaterial meshes with mixed opaque/translucent sub-materials:
|
|
41
|
+
// maps mesh → set of materialIndex values that are translucent.
|
|
42
|
+
this._translucentMaterialIndices = new Map();
|
|
43
|
+
// Precomputed opaque-only submesh arrays for mixed meshes, swapped in
|
|
44
|
+
// during the opaque RT render to avoid per-frame allocations.
|
|
45
|
+
this._opaqueOnlySubMeshes = new Map();
|
|
46
|
+
this._savedSubMeshes = new Map();
|
|
47
|
+
this._options = {
|
|
48
|
+
...TransmissionHelper._GetDefaultOptions(),
|
|
49
|
+
...options,
|
|
50
|
+
};
|
|
51
|
+
this._scene = scene;
|
|
52
|
+
this._scene._transmissionHelper = this;
|
|
53
|
+
this.onErrorObservable = new Observable();
|
|
54
|
+
this._scene.onDisposeObservable.addOnce(() => {
|
|
55
|
+
this.dispose();
|
|
56
|
+
});
|
|
57
|
+
this._parseScene();
|
|
58
|
+
this._setupRenderTargets();
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Registers a material implementation with the helper so it can classify and create
|
|
62
|
+
* adapters for materials of that type. Safe to call multiple times with the same
|
|
63
|
+
* implementation — duplicates are ignored.
|
|
64
|
+
* @param impl The material implementation to register
|
|
65
|
+
*/
|
|
66
|
+
addMaterialImpl(impl) {
|
|
67
|
+
if (!this._materialImpls.some((i) => i.materialClass === impl.materialClass)) {
|
|
68
|
+
this._materialImpls.push(impl);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Updates the helper options.
|
|
73
|
+
* @param options the options to update
|
|
74
|
+
*/
|
|
75
|
+
updateOptions(options) {
|
|
76
|
+
// First check if any options are actually being changed. If not, exit.
|
|
77
|
+
const newValues = Object.keys(options).filter((key) => this._options[key] !== options[key]);
|
|
78
|
+
if (!newValues.length) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const newOptions = {
|
|
82
|
+
...this._options,
|
|
83
|
+
...options,
|
|
84
|
+
};
|
|
85
|
+
const oldOptions = this._options;
|
|
86
|
+
this._options = newOptions;
|
|
87
|
+
// If size changes, recreate everything
|
|
88
|
+
if (newOptions.renderSize !== oldOptions.renderSize ||
|
|
89
|
+
newOptions.renderTargetTextureType !== oldOptions.renderTargetTextureType ||
|
|
90
|
+
newOptions.generateMipmaps !== oldOptions.generateMipmaps ||
|
|
91
|
+
!this._opaqueRenderTarget) {
|
|
92
|
+
this._setupRenderTargets();
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
this._opaqueRenderTarget.samples = newOptions.samples;
|
|
96
|
+
this._opaqueRenderTarget.lodGenerationScale = newOptions.lodGenerationScale;
|
|
97
|
+
this._opaqueRenderTarget.lodGenerationOffset = newOptions.lodGenerationOffset;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* @returns the opaque render target texture or null if not available.
|
|
102
|
+
*/
|
|
103
|
+
getOpaqueTarget() {
|
|
104
|
+
return this._opaqueRenderTarget;
|
|
105
|
+
}
|
|
106
|
+
_getOrCreateAdapter(material) {
|
|
107
|
+
let adapter = this._adapterCache.get(material);
|
|
108
|
+
if (!adapter) {
|
|
109
|
+
for (const impl of this._materialImpls) {
|
|
110
|
+
if (material instanceof impl.materialClass) {
|
|
111
|
+
adapter = new impl.adapterClass(material);
|
|
112
|
+
this._adapterCache.set(material, adapter);
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return adapter;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Classify a mesh's materials as transparent, opaque, or mixed.
|
|
121
|
+
* Sets the refraction background texture on any translucent materials found.
|
|
122
|
+
* For mixed MultiMaterial meshes, populates _translucentMaterialIndices so
|
|
123
|
+
* their translucent submeshes can be excluded from the opaque render target.
|
|
124
|
+
* @param mesh - The mesh to classify
|
|
125
|
+
* @returns 'transparent' if all materials are translucent, 'opaque' if none are, 'mixed' if both
|
|
126
|
+
*/
|
|
127
|
+
_classifyMeshMaterials(mesh) {
|
|
128
|
+
const material = mesh.material;
|
|
129
|
+
if (!material) {
|
|
130
|
+
return "opaque";
|
|
131
|
+
}
|
|
132
|
+
// Single material case
|
|
133
|
+
if (!(material instanceof MultiMaterial)) {
|
|
134
|
+
const adapter = this._getOrCreateAdapter(material);
|
|
135
|
+
if (!adapter) {
|
|
136
|
+
return "opaque";
|
|
137
|
+
}
|
|
138
|
+
if (adapter.isTranslucent()) {
|
|
139
|
+
adapter.refractionBackgroundTexture = this._opaqueRenderTarget;
|
|
140
|
+
return "transparent";
|
|
141
|
+
}
|
|
142
|
+
return "opaque";
|
|
143
|
+
}
|
|
144
|
+
// MultiMaterial case: check each sub-material individually
|
|
145
|
+
let hasTranslucent = false;
|
|
146
|
+
let hasOpaque = false;
|
|
147
|
+
const translucentIndices = new Set();
|
|
148
|
+
for (let i = 0; i < material.subMaterials.length; i++) {
|
|
149
|
+
const subMat = material.subMaterials[i];
|
|
150
|
+
if (!subMat) {
|
|
151
|
+
hasOpaque = true;
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
const adapter = this._getOrCreateAdapter(subMat);
|
|
155
|
+
if (adapter) {
|
|
156
|
+
if (adapter.isTranslucent()) {
|
|
157
|
+
adapter.refractionBackgroundTexture = this._opaqueRenderTarget;
|
|
158
|
+
hasTranslucent = true;
|
|
159
|
+
translucentIndices.add(i);
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
hasOpaque = true;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
hasOpaque = true;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (hasTranslucent && hasOpaque) {
|
|
170
|
+
this._translucentMaterialIndices.set(mesh, translucentIndices);
|
|
171
|
+
this._rebuildOpaqueOnlySubMeshes(mesh, translucentIndices);
|
|
172
|
+
return "mixed";
|
|
173
|
+
}
|
|
174
|
+
this._translucentMaterialIndices.delete(mesh);
|
|
175
|
+
this._opaqueOnlySubMeshes.delete(mesh);
|
|
176
|
+
return hasTranslucent ? "transparent" : "opaque";
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Rebuild the cached opaque-only submesh array for a mixed mesh.
|
|
180
|
+
* Called when classification changes so the per-frame swap is allocation-free.
|
|
181
|
+
* @param mesh - The mesh to rebuild for
|
|
182
|
+
* @param translucentIndices - Set of materialIndex values that are translucent
|
|
183
|
+
*/
|
|
184
|
+
_rebuildOpaqueOnlySubMeshes(mesh, translucentIndices) {
|
|
185
|
+
if (mesh.subMeshes) {
|
|
186
|
+
this._opaqueOnlySubMeshes.set(mesh, mesh.subMeshes.filter((sm) => !translucentIndices.has(sm.materialIndex)));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
_addMesh(mesh) {
|
|
190
|
+
this._materialObservers[mesh.uniqueId] = mesh.onMaterialChangedObservable.add(this._onMeshMaterialChanged.bind(this));
|
|
191
|
+
// we need to defer the processing because _addMesh may be called as part as an instance mesh creation, in which case some
|
|
192
|
+
// internal properties are not setup yet, like _sourceMesh (needed when doing mesh.material below)
|
|
193
|
+
Tools.SetImmediate(() => {
|
|
194
|
+
if (mesh.material) {
|
|
195
|
+
const classification = this._classifyMeshMaterials(mesh);
|
|
196
|
+
if (classification === "transparent") {
|
|
197
|
+
if (this._transparentMeshesCache.indexOf(mesh) === -1) {
|
|
198
|
+
this._transparentMeshesCache.push(mesh);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
// Both 'opaque' and 'mixed' go in the opaque cache.
|
|
203
|
+
// For 'mixed', the translucent submeshes are temporarily
|
|
204
|
+
// excluded during the opaque render target render.
|
|
205
|
+
if (this._opaqueMeshesCache.indexOf(mesh) === -1) {
|
|
206
|
+
this._opaqueMeshesCache.push(mesh);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
_removeMesh(mesh) {
|
|
213
|
+
mesh.onMaterialChangedObservable.remove(this._materialObservers[mesh.uniqueId]);
|
|
214
|
+
delete this._materialObservers[mesh.uniqueId];
|
|
215
|
+
let idx = this._transparentMeshesCache.indexOf(mesh);
|
|
216
|
+
if (idx !== -1) {
|
|
217
|
+
this._transparentMeshesCache.splice(idx, 1);
|
|
218
|
+
}
|
|
219
|
+
idx = this._opaqueMeshesCache.indexOf(mesh);
|
|
220
|
+
if (idx !== -1) {
|
|
221
|
+
this._opaqueMeshesCache.splice(idx, 1);
|
|
222
|
+
}
|
|
223
|
+
this._translucentMaterialIndices.delete(mesh);
|
|
224
|
+
this._opaqueOnlySubMeshes.delete(mesh);
|
|
225
|
+
}
|
|
226
|
+
_parseScene() {
|
|
227
|
+
this._scene.meshes.forEach(this._addMesh.bind(this));
|
|
228
|
+
// Listen for when a mesh is added to the scene and add it to our cache lists.
|
|
229
|
+
this._scene.onNewMeshAddedObservable.add(this._addMesh.bind(this));
|
|
230
|
+
// Listen for when a mesh is removed from to the scene and remove it from our cache lists.
|
|
231
|
+
this._scene.onMeshRemovedObservable.add(this._removeMesh.bind(this));
|
|
232
|
+
}
|
|
233
|
+
// When one of the meshes in the scene has its material changed, make sure that it's in the correct cache list.
|
|
234
|
+
_onMeshMaterialChanged(mesh) {
|
|
235
|
+
const transparentIdx = this._transparentMeshesCache.indexOf(mesh);
|
|
236
|
+
const opaqueIdx = this._opaqueMeshesCache.indexOf(mesh);
|
|
237
|
+
const classification = this._classifyMeshMaterials(mesh);
|
|
238
|
+
if (classification === "transparent") {
|
|
239
|
+
// Fully translucent: move to transparent cache
|
|
240
|
+
if (opaqueIdx !== -1) {
|
|
241
|
+
this._opaqueMeshesCache.splice(opaqueIdx, 1);
|
|
242
|
+
this._transparentMeshesCache.push(mesh);
|
|
243
|
+
}
|
|
244
|
+
else if (transparentIdx === -1) {
|
|
245
|
+
this._transparentMeshesCache.push(mesh);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
// Opaque or mixed: move to opaque cache (mixed meshes have their
|
|
250
|
+
// translucent submeshes excluded during opaque RT render)
|
|
251
|
+
if (transparentIdx !== -1) {
|
|
252
|
+
this._transparentMeshesCache.splice(transparentIdx, 1);
|
|
253
|
+
this._opaqueMeshesCache.push(mesh);
|
|
254
|
+
}
|
|
255
|
+
else if (opaqueIdx === -1) {
|
|
256
|
+
this._opaqueMeshesCache.push(mesh);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* @internal
|
|
262
|
+
* Check if the opaque render target has not been disposed and can still be used.
|
|
263
|
+
* @returns
|
|
264
|
+
*/
|
|
265
|
+
_isRenderTargetValid() {
|
|
266
|
+
return this._opaqueRenderTarget?.getInternalTexture() !== null;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* @internal
|
|
270
|
+
* Setup the render targets according to the specified options.
|
|
271
|
+
*/
|
|
272
|
+
_setupRenderTargets() {
|
|
273
|
+
if (this._opaqueRenderTarget) {
|
|
274
|
+
this._opaqueRenderTarget.dispose();
|
|
275
|
+
}
|
|
276
|
+
this._opaqueRenderTarget = new RenderTargetTexture("opaqueSceneTexture", this._options.renderSize, this._scene, this._options.generateMipmaps, undefined, this._options.renderTargetTextureType);
|
|
277
|
+
this._opaqueRenderTarget.ignoreCameraViewport = true;
|
|
278
|
+
this._opaqueRenderTarget.renderList = this._opaqueMeshesCache;
|
|
279
|
+
this._opaqueRenderTarget.clearColor = this._options.clearColor?.clone() ?? this._scene.clearColor.clone();
|
|
280
|
+
this._opaqueRenderTarget.clearColor.a = 0.0;
|
|
281
|
+
this._opaqueRenderTarget.gammaSpace = false;
|
|
282
|
+
this._opaqueRenderTarget.lodGenerationScale = this._options.lodGenerationScale;
|
|
283
|
+
this._opaqueRenderTarget.lodGenerationOffset = this._options.lodGenerationOffset;
|
|
284
|
+
this._opaqueRenderTarget.samples = this._options.samples;
|
|
285
|
+
this._opaqueRenderTarget.renderSprites = true;
|
|
286
|
+
this._opaqueRenderTarget.renderParticles = true;
|
|
287
|
+
this._opaqueRenderTarget.disableImageProcessing = true;
|
|
288
|
+
let saveSceneEnvIntensity;
|
|
289
|
+
this._opaqueRenderTarget.onBeforeBindObservable.add((opaqueRenderTarget) => {
|
|
290
|
+
saveSceneEnvIntensity = this._scene.environmentIntensity;
|
|
291
|
+
this._scene.environmentIntensity = 1.0;
|
|
292
|
+
if (!this._options.clearColor) {
|
|
293
|
+
this._scene.clearColor.toLinearSpaceToRef(opaqueRenderTarget.clearColor, this._scene.getEngine().useExactSrgbConversions);
|
|
294
|
+
}
|
|
295
|
+
else {
|
|
296
|
+
opaqueRenderTarget.clearColor.copyFrom(this._options.clearColor);
|
|
297
|
+
}
|
|
298
|
+
opaqueRenderTarget.clearColor.a = 0.0;
|
|
299
|
+
// For mixed MultiMaterial meshes, swap in the precomputed opaque-only
|
|
300
|
+
// submesh array so translucent submeshes don't render into the opaque texture.
|
|
301
|
+
const tlEntries = this._opaqueOnlySubMeshes.entries();
|
|
302
|
+
for (let tlEntry = tlEntries.next(); !tlEntry.done; tlEntry = tlEntries.next()) {
|
|
303
|
+
const mesh = tlEntry.value[0];
|
|
304
|
+
const opaqueOnly = tlEntry.value[1];
|
|
305
|
+
if (mesh.subMeshes) {
|
|
306
|
+
this._savedSubMeshes.set(mesh, mesh.subMeshes);
|
|
307
|
+
mesh.subMeshes = opaqueOnly;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
this._opaqueRenderTarget.onAfterUnbindObservable.add(() => {
|
|
312
|
+
this._scene.environmentIntensity = saveSceneEnvIntensity;
|
|
313
|
+
// Restore the full submesh list after the opaque RT render
|
|
314
|
+
const savedEntries = this._savedSubMeshes.entries();
|
|
315
|
+
for (let savedEntry = savedEntries.next(); !savedEntry.done; savedEntry = savedEntries.next()) {
|
|
316
|
+
savedEntry.value[0].subMeshes = savedEntry.value[1];
|
|
317
|
+
}
|
|
318
|
+
this._savedSubMeshes.clear();
|
|
319
|
+
});
|
|
320
|
+
// Update refraction textures on transparent and mixed meshes
|
|
321
|
+
for (const mesh of this._transparentMeshesCache) {
|
|
322
|
+
if (mesh.material) {
|
|
323
|
+
this._classifyMeshMaterials(mesh);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
const mixedEntries = this._translucentMaterialIndices.entries();
|
|
327
|
+
for (let mixedEntry = mixedEntries.next(); !mixedEntry.done; mixedEntry = mixedEntries.next()) {
|
|
328
|
+
const mesh = mixedEntry.value[0];
|
|
329
|
+
if (mesh.material) {
|
|
330
|
+
this._classifyMeshMaterials(mesh);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Dispose all the elements created by the Helper.
|
|
336
|
+
*/
|
|
337
|
+
dispose() {
|
|
338
|
+
this._scene._transmissionHelper = undefined;
|
|
339
|
+
if (this._opaqueRenderTarget) {
|
|
340
|
+
this._opaqueRenderTarget.dispose();
|
|
341
|
+
this._opaqueRenderTarget = null;
|
|
342
|
+
}
|
|
343
|
+
this._transparentMeshesCache = [];
|
|
344
|
+
this._opaqueMeshesCache = [];
|
|
345
|
+
this._translucentMaterialIndices.clear();
|
|
346
|
+
this._opaqueOnlySubMeshes.clear();
|
|
347
|
+
this._savedSubMeshes.clear();
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Ensures a TransmissionHelper exists on the scene and has all of the loader's material
|
|
352
|
+
* implementations registered with it. Creates the helper if one does not yet exist on the
|
|
353
|
+
* scene, and recreates its render target if it has been disposed. Does nothing when the
|
|
354
|
+
* loader's parent has `dontUseTransmissionHelper` set.
|
|
355
|
+
* @param loader The glTF loader whose material implementations should be registered
|
|
356
|
+
* @param babylonMaterial A material belonging to the scene where the helper should live
|
|
357
|
+
*/
|
|
358
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
359
|
+
export function ensureTransmissionHelper(loader, babylonMaterial) {
|
|
360
|
+
if (loader.parent.dontUseTransmissionHelper) {
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
const scene = babylonMaterial.getScene();
|
|
364
|
+
const existingHelper = scene._transmissionHelper;
|
|
365
|
+
const helper = existingHelper ?? new TransmissionHelper({}, babylonMaterial.getScene());
|
|
366
|
+
for (const impl of Array.from(loader._pbrMaterialImpls.values())) {
|
|
367
|
+
helper.addMaterialImpl(impl);
|
|
368
|
+
}
|
|
369
|
+
if (existingHelper && !existingHelper._isRenderTargetValid()) {
|
|
370
|
+
existingHelper._setupRenderTargets();
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
//# sourceMappingURL=transmissionHelper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transmissionHelper.js","sourceRoot":"","sources":["../../../../../../dev/loaders/src/glTF/2.0/Extensions/transmissionHelper.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Nullable } from \"core/types\";\nimport { type Material } from \"core/Materials/material\";\nimport { MultiMaterial } from \"core/Materials/multiMaterial\";\nimport { type Scene } from \"core/scene\";\nimport { type AbstractMesh } from \"core/Meshes/abstractMesh\";\nimport { type SubMesh } from \"core/Meshes/subMesh\";\nimport { type Texture } from \"core/Materials/Textures/texture\";\nimport { RenderTargetTexture } from \"core/Materials/Textures/renderTargetTexture\";\nimport { type Observer, Observable } from \"core/Misc/observable\";\nimport { Constants } from \"core/Engines/constants\";\nimport { Tools } from \"core/Misc/tools\";\nimport { type Color4 } from \"core/Maths/math.color\";\nimport { type IMaterialLoadingAdapter } from \"../materialLoadingAdapter\";\nimport { type GLTFLoader } from \"../glTFLoader\";\n\n/**\n * Describes a material class and its corresponding loading adapter.\n * Passed to TransmissionHelper so it can classify and interact with materials\n * independently of any specific loader instance.\n */\nexport interface ITransmissionHelperMaterialImpl {\n /** The material class constructor */\n materialClass: typeof Material;\n /** The adapter class constructor */\n adapterClass: new (material: Material) => IMaterialLoadingAdapter;\n}\n\n/**\n * @internal\n */\nexport interface ITransmissionHelperHolder {\n /** The transmission helper instance, if created on the scene */\n _transmissionHelper: TransmissionHelper | undefined;\n}\n\n/**\n * Options for the TransmissionHelper.\n */\nexport interface ITransmissionHelperOptions {\n /**\n * The size of the render buffers (default: 1024)\n */\n renderSize: number;\n\n /**\n * The number of samples to use when generating the render target texture for opaque meshes (default: 4)\n */\n samples: number;\n\n /**\n * Scale to apply when selecting the LOD level to sample the refraction texture (default: 1)\n */\n lodGenerationScale: number;\n\n /**\n * Offset to apply when selecting the LOD level to sample the refraction texture (default: -4)\n */\n lodGenerationOffset: number;\n\n /**\n * Type of the refraction render target texture (default: TEXTURETYPE_HALF_FLOAT)\n */\n renderTargetTextureType: number;\n\n /**\n * Defines if the mipmaps for the refraction render target texture must be generated (default: true)\n */\n generateMipmaps: boolean;\n\n /**\n * Clear color of the opaque texture. If not provided, use the scene clear color (which will be converted to linear space).\n * If provided, should be in linear space\n */\n clearColor?: Color4;\n}\n\n/**\n * A class to handle setting up the rendering of opaque objects to be shown through transmissive objects.\n * @internal\n */\nexport class TransmissionHelper {\n /**\n * Creates the default options for the helper.\n * @returns the default options\n */\n private static _GetDefaultOptions(): ITransmissionHelperOptions {\n return {\n renderSize: 1024,\n samples: 4,\n lodGenerationScale: 1,\n lodGenerationOffset: -4,\n renderTargetTextureType: Constants.TEXTURETYPE_HALF_FLOAT,\n generateMipmaps: true,\n };\n }\n\n private readonly _scene: Scene & ITransmissionHelperHolder;\n\n private _options: ITransmissionHelperOptions;\n\n private _opaqueRenderTarget: Nullable<RenderTargetTexture> = null;\n private _opaqueMeshesCache: AbstractMesh[] = [];\n private _transparentMeshesCache: AbstractMesh[] = [];\n private _materialObservers: { [id: string]: Nullable<Observer<AbstractMesh>> } = {};\n\n // Material implementations registered by loaders. Each entry maps a material class\n // to its adapter class so the helper can classify and interact with materials\n // independently of whichever loader originally created them.\n private readonly _materialImpls: ITransmissionHelperMaterialImpl[] = [];\n private readonly _adapterCache: WeakMap<Material, IMaterialLoadingAdapter> = new WeakMap();\n\n /**\n * This observable will be notified with any error during the creation of the environment,\n * mainly texture creation errors.\n */\n public onErrorObservable: Observable<{ message?: string; exception?: any }>;\n\n // For MultiMaterial meshes with mixed opaque/translucent sub-materials:\n // maps mesh → set of materialIndex values that are translucent.\n private _translucentMaterialIndices: Map<AbstractMesh, Set<number>> = new Map();\n // Precomputed opaque-only submesh arrays for mixed meshes, swapped in\n // during the opaque RT render to avoid per-frame allocations.\n private _opaqueOnlySubMeshes: Map<AbstractMesh, SubMesh[]> = new Map();\n private _savedSubMeshes: Map<AbstractMesh, SubMesh[]> = new Map();\n\n /**\n * constructor\n * @param options Defines the options we want to customize the helper\n * @param scene The scene to add the material to\n */\n constructor(options: Partial<ITransmissionHelperOptions>, scene: Scene) {\n this._options = {\n ...TransmissionHelper._GetDefaultOptions(),\n ...options,\n };\n this._scene = scene as any;\n this._scene._transmissionHelper = this;\n\n this.onErrorObservable = new Observable();\n this._scene.onDisposeObservable.addOnce(() => {\n this.dispose();\n });\n\n this._parseScene();\n this._setupRenderTargets();\n }\n\n /**\n * Registers a material implementation with the helper so it can classify and create\n * adapters for materials of that type. Safe to call multiple times with the same\n * implementation — duplicates are ignored.\n * @param impl The material implementation to register\n */\n public addMaterialImpl(impl: ITransmissionHelperMaterialImpl): void {\n if (!this._materialImpls.some((i) => i.materialClass === impl.materialClass)) {\n this._materialImpls.push(impl);\n }\n }\n\n /**\n * Updates the helper options.\n * @param options the options to update\n */\n public updateOptions(options: Partial<ITransmissionHelperOptions>) {\n // First check if any options are actually being changed. If not, exit.\n const newValues = Object.keys(options).filter((key: string) => (this._options as any)[key] !== (options as any)[key]);\n if (!newValues.length) {\n return;\n }\n\n const newOptions = {\n ...this._options,\n ...options,\n };\n\n const oldOptions = this._options;\n this._options = newOptions;\n\n // If size changes, recreate everything\n if (\n newOptions.renderSize !== oldOptions.renderSize ||\n newOptions.renderTargetTextureType !== oldOptions.renderTargetTextureType ||\n newOptions.generateMipmaps !== oldOptions.generateMipmaps ||\n !this._opaqueRenderTarget\n ) {\n this._setupRenderTargets();\n } else {\n this._opaqueRenderTarget.samples = newOptions.samples;\n this._opaqueRenderTarget.lodGenerationScale = newOptions.lodGenerationScale;\n this._opaqueRenderTarget.lodGenerationOffset = newOptions.lodGenerationOffset;\n }\n }\n\n /**\n * @returns the opaque render target texture or null if not available.\n */\n public getOpaqueTarget(): Nullable<Texture> {\n return this._opaqueRenderTarget;\n }\n\n private _getOrCreateAdapter(material: Material): IMaterialLoadingAdapter | undefined {\n let adapter = this._adapterCache.get(material);\n if (!adapter) {\n for (const impl of this._materialImpls) {\n if (material instanceof impl.materialClass) {\n adapter = new impl.adapterClass(material);\n this._adapterCache.set(material, adapter);\n break;\n }\n }\n }\n return adapter;\n }\n\n /**\n * Classify a mesh's materials as transparent, opaque, or mixed.\n * Sets the refraction background texture on any translucent materials found.\n * For mixed MultiMaterial meshes, populates _translucentMaterialIndices so\n * their translucent submeshes can be excluded from the opaque render target.\n * @param mesh - The mesh to classify\n * @returns 'transparent' if all materials are translucent, 'opaque' if none are, 'mixed' if both\n */\n private _classifyMeshMaterials(mesh: AbstractMesh): \"transparent\" | \"opaque\" | \"mixed\" {\n const material = mesh.material;\n if (!material) {\n return \"opaque\";\n }\n\n // Single material case\n if (!(material instanceof MultiMaterial)) {\n const adapter = this._getOrCreateAdapter(material);\n if (!adapter) {\n return \"opaque\";\n }\n if (adapter.isTranslucent()) {\n adapter.refractionBackgroundTexture = this._opaqueRenderTarget;\n return \"transparent\";\n }\n return \"opaque\";\n }\n\n // MultiMaterial case: check each sub-material individually\n let hasTranslucent = false;\n let hasOpaque = false;\n const translucentIndices = new Set<number>();\n\n for (let i = 0; i < material.subMaterials.length; i++) {\n const subMat = material.subMaterials[i];\n if (!subMat) {\n hasOpaque = true;\n continue;\n }\n const adapter = this._getOrCreateAdapter(subMat);\n if (adapter) {\n if (adapter.isTranslucent()) {\n adapter.refractionBackgroundTexture = this._opaqueRenderTarget;\n hasTranslucent = true;\n translucentIndices.add(i);\n } else {\n hasOpaque = true;\n }\n } else {\n hasOpaque = true;\n }\n }\n\n if (hasTranslucent && hasOpaque) {\n this._translucentMaterialIndices.set(mesh, translucentIndices);\n this._rebuildOpaqueOnlySubMeshes(mesh, translucentIndices);\n return \"mixed\";\n }\n this._translucentMaterialIndices.delete(mesh);\n this._opaqueOnlySubMeshes.delete(mesh);\n return hasTranslucent ? \"transparent\" : \"opaque\";\n }\n\n /**\n * Rebuild the cached opaque-only submesh array for a mixed mesh.\n * Called when classification changes so the per-frame swap is allocation-free.\n * @param mesh - The mesh to rebuild for\n * @param translucentIndices - Set of materialIndex values that are translucent\n */\n private _rebuildOpaqueOnlySubMeshes(mesh: AbstractMesh, translucentIndices: Set<number>): void {\n if (mesh.subMeshes) {\n this._opaqueOnlySubMeshes.set(\n mesh,\n mesh.subMeshes.filter((sm: SubMesh) => !translucentIndices.has(sm.materialIndex))\n );\n }\n }\n\n private _addMesh(mesh: AbstractMesh): void {\n this._materialObservers[mesh.uniqueId] = mesh.onMaterialChangedObservable.add(this._onMeshMaterialChanged.bind(this));\n\n // we need to defer the processing because _addMesh may be called as part as an instance mesh creation, in which case some\n // internal properties are not setup yet, like _sourceMesh (needed when doing mesh.material below)\n Tools.SetImmediate(() => {\n if (mesh.material) {\n const classification = this._classifyMeshMaterials(mesh);\n if (classification === \"transparent\") {\n if (this._transparentMeshesCache.indexOf(mesh) === -1) {\n this._transparentMeshesCache.push(mesh);\n }\n } else {\n // Both 'opaque' and 'mixed' go in the opaque cache.\n // For 'mixed', the translucent submeshes are temporarily\n // excluded during the opaque render target render.\n if (this._opaqueMeshesCache.indexOf(mesh) === -1) {\n this._opaqueMeshesCache.push(mesh);\n }\n }\n }\n });\n }\n\n private _removeMesh(mesh: AbstractMesh): void {\n mesh.onMaterialChangedObservable.remove(this._materialObservers[mesh.uniqueId]);\n delete this._materialObservers[mesh.uniqueId];\n let idx = this._transparentMeshesCache.indexOf(mesh);\n if (idx !== -1) {\n this._transparentMeshesCache.splice(idx, 1);\n }\n idx = this._opaqueMeshesCache.indexOf(mesh);\n if (idx !== -1) {\n this._opaqueMeshesCache.splice(idx, 1);\n }\n this._translucentMaterialIndices.delete(mesh);\n this._opaqueOnlySubMeshes.delete(mesh);\n }\n\n private _parseScene(): void {\n this._scene.meshes.forEach(this._addMesh.bind(this));\n // Listen for when a mesh is added to the scene and add it to our cache lists.\n this._scene.onNewMeshAddedObservable.add(this._addMesh.bind(this));\n // Listen for when a mesh is removed from to the scene and remove it from our cache lists.\n this._scene.onMeshRemovedObservable.add(this._removeMesh.bind(this));\n }\n\n // When one of the meshes in the scene has its material changed, make sure that it's in the correct cache list.\n private _onMeshMaterialChanged(mesh: AbstractMesh) {\n const transparentIdx = this._transparentMeshesCache.indexOf(mesh);\n const opaqueIdx = this._opaqueMeshesCache.indexOf(mesh);\n\n const classification = this._classifyMeshMaterials(mesh);\n\n if (classification === \"transparent\") {\n // Fully translucent: move to transparent cache\n if (opaqueIdx !== -1) {\n this._opaqueMeshesCache.splice(opaqueIdx, 1);\n this._transparentMeshesCache.push(mesh);\n } else if (transparentIdx === -1) {\n this._transparentMeshesCache.push(mesh);\n }\n } else {\n // Opaque or mixed: move to opaque cache (mixed meshes have their\n // translucent submeshes excluded during opaque RT render)\n if (transparentIdx !== -1) {\n this._transparentMeshesCache.splice(transparentIdx, 1);\n this._opaqueMeshesCache.push(mesh);\n } else if (opaqueIdx === -1) {\n this._opaqueMeshesCache.push(mesh);\n }\n }\n }\n\n /**\n * @internal\n * Check if the opaque render target has not been disposed and can still be used.\n * @returns\n */\n public _isRenderTargetValid() {\n return this._opaqueRenderTarget?.getInternalTexture() !== null;\n }\n\n /**\n * @internal\n * Setup the render targets according to the specified options.\n */\n public _setupRenderTargets(): void {\n if (this._opaqueRenderTarget) {\n this._opaqueRenderTarget.dispose();\n }\n this._opaqueRenderTarget = new RenderTargetTexture(\n \"opaqueSceneTexture\",\n this._options.renderSize,\n this._scene,\n this._options.generateMipmaps,\n undefined,\n this._options.renderTargetTextureType\n );\n this._opaqueRenderTarget.ignoreCameraViewport = true;\n this._opaqueRenderTarget.renderList = this._opaqueMeshesCache;\n this._opaqueRenderTarget.clearColor = this._options.clearColor?.clone() ?? this._scene.clearColor.clone();\n this._opaqueRenderTarget.clearColor.a = 0.0;\n this._opaqueRenderTarget.gammaSpace = false;\n this._opaqueRenderTarget.lodGenerationScale = this._options.lodGenerationScale;\n this._opaqueRenderTarget.lodGenerationOffset = this._options.lodGenerationOffset;\n this._opaqueRenderTarget.samples = this._options.samples;\n this._opaqueRenderTarget.renderSprites = true;\n this._opaqueRenderTarget.renderParticles = true;\n this._opaqueRenderTarget.disableImageProcessing = true;\n\n let saveSceneEnvIntensity: number;\n this._opaqueRenderTarget.onBeforeBindObservable.add((opaqueRenderTarget) => {\n saveSceneEnvIntensity = this._scene.environmentIntensity;\n this._scene.environmentIntensity = 1.0;\n if (!this._options.clearColor) {\n this._scene.clearColor.toLinearSpaceToRef(opaqueRenderTarget.clearColor, this._scene.getEngine().useExactSrgbConversions);\n } else {\n opaqueRenderTarget.clearColor.copyFrom(this._options.clearColor);\n }\n opaqueRenderTarget.clearColor.a = 0.0;\n\n // For mixed MultiMaterial meshes, swap in the precomputed opaque-only\n // submesh array so translucent submeshes don't render into the opaque texture.\n const tlEntries = this._opaqueOnlySubMeshes.entries();\n for (let tlEntry = tlEntries.next(); !tlEntry.done; tlEntry = tlEntries.next()) {\n const mesh = tlEntry.value[0];\n const opaqueOnly = tlEntry.value[1];\n if (mesh.subMeshes) {\n this._savedSubMeshes.set(mesh, mesh.subMeshes);\n mesh.subMeshes = opaqueOnly;\n }\n }\n });\n this._opaqueRenderTarget.onAfterUnbindObservable.add(() => {\n this._scene.environmentIntensity = saveSceneEnvIntensity;\n\n // Restore the full submesh list after the opaque RT render\n const savedEntries = this._savedSubMeshes.entries();\n for (let savedEntry = savedEntries.next(); !savedEntry.done; savedEntry = savedEntries.next()) {\n savedEntry.value[0].subMeshes = savedEntry.value[1];\n }\n this._savedSubMeshes.clear();\n });\n\n // Update refraction textures on transparent and mixed meshes\n for (const mesh of this._transparentMeshesCache) {\n if (mesh.material) {\n this._classifyMeshMaterials(mesh);\n }\n }\n const mixedEntries = this._translucentMaterialIndices.entries();\n for (let mixedEntry = mixedEntries.next(); !mixedEntry.done; mixedEntry = mixedEntries.next()) {\n const mesh = mixedEntry.value[0];\n if (mesh.material) {\n this._classifyMeshMaterials(mesh);\n }\n }\n }\n\n /**\n * Dispose all the elements created by the Helper.\n */\n public dispose(): void {\n this._scene._transmissionHelper = undefined;\n if (this._opaqueRenderTarget) {\n this._opaqueRenderTarget.dispose();\n this._opaqueRenderTarget = null;\n }\n this._transparentMeshesCache = [];\n this._opaqueMeshesCache = [];\n this._translucentMaterialIndices.clear();\n this._opaqueOnlySubMeshes.clear();\n this._savedSubMeshes.clear();\n }\n}\n\n/**\n * Ensures a TransmissionHelper exists on the scene and has all of the loader's material\n * implementations registered with it. Creates the helper if one does not yet exist on the\n * scene, and recreates its render target if it has been disposed. Does nothing when the\n * loader's parent has `dontUseTransmissionHelper` set.\n * @param loader The glTF loader whose material implementations should be registered\n * @param babylonMaterial A material belonging to the scene where the helper should live\n */\n// eslint-disable-next-line @typescript-eslint/naming-convention\nexport function ensureTransmissionHelper(loader: GLTFLoader, babylonMaterial: Material): void {\n if (loader.parent.dontUseTransmissionHelper) {\n return;\n }\n const scene = babylonMaterial.getScene() as unknown as ITransmissionHelperHolder;\n const existingHelper = scene._transmissionHelper;\n const helper = existingHelper ?? new TransmissionHelper({}, babylonMaterial.getScene());\n for (const impl of Array.from(loader._pbrMaterialImpls.values())) {\n helper.addMaterialImpl(impl);\n }\n if (existingHelper && !existingHelper._isRenderTargetValid()) {\n existingHelper._setupRenderTargets();\n }\n}\n"]}
|
package/glTF/2.0/glTFLoader.d.ts
CHANGED
|
@@ -97,12 +97,17 @@ export declare class GLTFLoader implements IGLTFLoader {
|
|
|
97
97
|
private readonly _postSceneLoadActions;
|
|
98
98
|
private readonly _materialAdapterCache;
|
|
99
99
|
private readonly _materialAdapters;
|
|
100
|
-
/** @internal */
|
|
101
|
-
_pbrMaterialImpl: Nullable<Readonly<PBRMaterialImplementation>> | false;
|
|
102
100
|
/**
|
|
103
|
-
*
|
|
101
|
+
* Loaded PBR material implementations, keyed by their identifier (e.g. "pbr", "openpbr").
|
|
102
|
+
* Only populated after the load has started and only for the types actually needed by the asset.
|
|
103
|
+
* Empty when PBR materials are disabled (skipMaterials).
|
|
104
|
+
* @internal
|
|
105
|
+
*/
|
|
106
|
+
readonly _pbrMaterialImpls: Map<string, Readonly<PBRMaterialImplementation>>;
|
|
107
|
+
/**
|
|
108
|
+
* Test if the given material is an instance of any PBR material type known to this loader.
|
|
104
109
|
* @param material The material to test
|
|
105
|
-
* @returns true if the material
|
|
110
|
+
* @returns true if the material matches one of the loaded PBR implementations
|
|
106
111
|
*/
|
|
107
112
|
isMatchingMaterialType(material: Nullable<Material>): boolean;
|
|
108
113
|
/**
|
|
@@ -297,6 +302,21 @@ export declare class GLTFLoader implements IGLTFLoader {
|
|
|
297
302
|
* @internal
|
|
298
303
|
*/
|
|
299
304
|
_loadMaterialAsync(context: string, material: IMaterial, babylonMesh: Nullable<Mesh>, babylonDrawMode: number, assign?: (babylonMaterial: Material) => void): Promise<Material>;
|
|
305
|
+
/**
|
|
306
|
+
* Selects the appropriate PBR material implementation for a given glTF material.
|
|
307
|
+
* Uses OpenPBR when the material carries a "KHR_materials_openpbr" extension or when
|
|
308
|
+
* the loader-level `useOpenPBR` flag is set; falls back to standard PBR otherwise.
|
|
309
|
+
* @param material The glTF material
|
|
310
|
+
* @returns The matching loaded implementation
|
|
311
|
+
*/
|
|
312
|
+
private _selectImplForGltfMaterial;
|
|
313
|
+
/**
|
|
314
|
+
* Returns the default PBR material implementation used when there is no per-material
|
|
315
|
+
* selection context (e.g. when creating the built-in default material for primitives
|
|
316
|
+
* that have no glTF material assigned). Prefers OpenPBR when `useOpenPBR` is set.
|
|
317
|
+
* @returns The default loaded implementation
|
|
318
|
+
*/
|
|
319
|
+
private _getDefaultImpl;
|
|
300
320
|
private _createDefaultMaterial;
|
|
301
321
|
/**
|
|
302
322
|
* Creates a Babylon material from a glTF material.
|