• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

iTowns / itowns / 7743821661

01 Feb 2024 03:41PM UTC coverage: 77.306% (-0.05%) from 77.36%
7743821661

Pull #2124

github

web-flow
Merge 9b8011e0b into 47d0c7cab
Pull Request #2124: Feat/google3d tiles

4108 of 6059 branches covered (0.0%)

Branch coverage included in aggregate %.

53 of 92 new or added lines in 3 files covered. (57.61%)

1 existing line in 1 file now uncovered.

8097 of 9729 relevant lines covered (83.23%)

1940.33 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

67.5
/src/Parser/B3dmParser.js
1
import * as THREE from 'three';
1✔
2
import utf8Decoder from 'Utils/Utf8Decoder';
1✔
3
import C3DTBatchTable from 'Core/3DTiles/C3DTBatchTable';
1✔
4
import Capabilities from 'Core/System/Capabilities';
1✔
5
import { MeshBasicMaterial } from 'three';
6
import disposeThreeMaterial from 'Utils/ThreeUtils';
1✔
7
import shaderUtils from 'Renderer/Shader/ShaderUtils';
1✔
8
import ReferLayerProperties from 'Layer/ReferencingLayerProperties';
1✔
9
import GLTFParser from './GLTFParser';
1,721!
10

11
const matrixChangeUpVectorYtoZInv = (new THREE.Matrix4()).makeRotationX(-Math.PI / 2);
1✔
12
const matrixChangeUpVectorXtoZ = (new THREE.Matrix4()).makeRotationZ(-Math.PI / 2);
1✔
13

14
/**
15
 * 3D Tiles pre-1.0 contain not standardized and specific uniforms that we filter out to avoid shader compilation errors
16
 * This method is passed to scene.traverse and applied to all 3D objects of the loaded gltf.
17
 * @param {THREE.Object3D} obj - 3D object of the gltf hierarchy
18
 */
19
function filterUnsupportedSemantics(obj) {
20
    // see GLTFLoader GLTFShader.prototype.update function
21
    const supported = [
10✔
22
        'MODELVIEW',
23
        'MODELVIEWINVERSETRANSPOSE',
24
        'PROJECTION',
25
        'JOINTMATRIX'];
26

27
    if (obj.gltfShader) {
10!
28
        const names = [];
×
29
        // eslint-disable-next-line guard-for-in
30
        for (const name in obj.gltfShader.boundUniforms) {
×
31
            names.push(name);
×
32
        }
33
        for (const name of names) {
×
34
            const semantic = obj.gltfShader.boundUniforms[name].semantic;
×
35
            if (!supported.includes(semantic)) {
×
36
                delete obj.gltfShader.boundUniforms[name];
×
37
            }
38
        }
39
    }
40
}
41

42
/**
43
 * 3D Tiles pre-1.0 had a gltfUpAxis parameter that defined the up vector of the gltf file that might be different from
44
 * the standard y-up for gltf. Manage the case when this gltfUpAxis is defined (i.e. apply the correct rotation to the
45
 * gltf file to have it z-up in the end).
46
 * @param {THREE.Object3D} gltfScene - the parsed glTF scene
47
 * @param {String} gltfUpAxis - the gltfUpAxis parameter
48
 */
49
function applyDeprecatedGltfUpAxis(gltfScene, gltfUpAxis) {
50
    if (gltfUpAxis === 'Z') {
3!
51
        // If gltf up was already z-up, apply the inverse transform matrix that was applied in the glTFParser
NEW
52
        gltfScene.applyMatrix4(matrixChangeUpVectorYtoZInv);
×
53
    } else if (gltfUpAxis === 'X') {
3!
NEW
54
        gltfScene.applyMatrix4(matrixChangeUpVectorYtoZInv);
×
NEW
55
        gltfScene.applyMatrix4(matrixChangeUpVectorXtoZ);
×
56
    }
57
}
58

59
/**
60
 * @module B3dmParser
61
 */
62

63
export default {
1✔
64
    /** Parse b3dm buffer and extract THREE.Scene and batch table
65
     * @param {ArrayBuffer} buffer - the b3dm buffer.
66
     * @param {Object} options - additional properties.
67
     * @param {string=} [options.gltfUpAxis='Y'] - embedded glTF model up axis.
68
     * @param {string} options.urlBase - the base url of the b3dm file (used to fetch textures for the embedded glTF model).
69
     * @param {boolean=} [options.doNotPatchMaterial=false] - disable patching material with logarithmic depth buffer support.
70
     * @param {float} [options.opacity=1.0] - the b3dm opacity.
71
     * @param {boolean=} [options.frustumCulled=false] - enable frustum culling.
72
     * @param {boolean|Material=} [options.overrideMaterials=false] - override b3dm's embedded glTF materials. If
73
     * true, a threejs [MeshBasicMaterial](https://threejs.org/docs/index.html?q=meshbasic#api/en/materials/MeshBasicMaterial)
74
     * is set up. config.overrideMaterials can also be a threejs [Material](https://threejs.org/docs/index.html?q=material#api/en/materials/Material)
75
     * in which case it will be the material used to override.
76
     * @return {Promise} - a promise that resolves with an object containig a THREE.Scene (gltf) and a batch table (batchTable).
77
     *
78
     */
79
    parse(buffer, options) {
80
        const frustumCulled = options.frustumCulled === undefined || options.frustumCulled === null ? true : !!(options.frustumCulled);
3!
81

82
        if (!buffer) {
3!
83
            throw new Error('No array buffer provided.');
×
84
        }
85

86
        const view = new DataView(buffer, 4);   // starts after magic
3✔
87

88
        let byteOffset = 0;
3✔
89
        const b3dmHeader = {};
3✔
90

91
        // Magic type is unsigned char [4]
92
        const magicNumberByteLength = 4;
3✔
93
        b3dmHeader.magic = utf8Decoder.decode(new Uint8Array(buffer, 0, magicNumberByteLength));
3✔
94
        if (b3dmHeader.magic) {
3!
95
            // Version, byteLength, batchTableJSONByteLength, batchTableBinaryByteLength and batchTable types are uint32
96
            b3dmHeader.version = view.getUint32(byteOffset, true);
3✔
97
            byteOffset += Uint32Array.BYTES_PER_ELEMENT;
3✔
98

99
            b3dmHeader.byteLength = view.getUint32(byteOffset, true);
3✔
100
            byteOffset += Uint32Array.BYTES_PER_ELEMENT;
3✔
101

102
            b3dmHeader.FTJSONLength = view.getUint32(byteOffset, true);
3✔
103
            byteOffset += Uint32Array.BYTES_PER_ELEMENT;
3✔
104

105
            b3dmHeader.FTBinaryLength = view.getUint32(byteOffset, true);
3✔
106
            byteOffset += Uint32Array.BYTES_PER_ELEMENT;
3✔
107

108
            b3dmHeader.BTJSONLength = view.getUint32(byteOffset, true);
3✔
109
            byteOffset += Uint32Array.BYTES_PER_ELEMENT;
3✔
110

111
            b3dmHeader.BTBinaryLength = view.getUint32(byteOffset, true);
3✔
112
            byteOffset += Uint32Array.BYTES_PER_ELEMENT;
3✔
113

114
            const headerByteLength = byteOffset + magicNumberByteLength;
3✔
115
            const promises = [];
3✔
116
            let FTJSON = {};
3✔
117
            const FT_RTC = new THREE.Vector3();
3✔
118
            if (b3dmHeader.FTJSONLength > 0) {
3!
119
                const sizeBegin = headerByteLength;
3✔
120
                const jsonBuffer = buffer.slice(sizeBegin, b3dmHeader.FTJSONLength + sizeBegin);
3✔
121
                const content = utf8Decoder.decode(new Uint8Array(jsonBuffer));
3✔
122
                FTJSON = JSON.parse(content);
3✔
123
                if (FTJSON.RTC_CENTER) {
3!
124
                    FT_RTC.fromArray(FTJSON.RTC_CENTER);
×
125
                } else {
126
                    FT_RTC.set(0, 0, 0);
3✔
127
                }
128
            }
129
            if (b3dmHeader.FTBinaryLength > 0) {
3!
130
                console.warn('3D Tiles feature table binary not supported yet.');
×
131
            }
132

133
            // Parse batch table
134
            if (b3dmHeader.BTJSONLength > 0) {
3✔
135
                // sizeBegin is an index to the beginning of the batch table
136
                const sizeBegin = headerByteLength + b3dmHeader.FTJSONLength +
1✔
137
                    b3dmHeader.FTBinaryLength;
138
                const BTBuffer = buffer.slice(sizeBegin, sizeBegin + b3dmHeader.BTJSONLength +
1✔
139
                    b3dmHeader.BTBinaryLength);
140
                promises.push(Promise.resolve(new C3DTBatchTable(BTBuffer, b3dmHeader.BTJSONLength,
1✔
141
                    b3dmHeader.BTBinaryLength, FTJSON.BATCH_LENGTH, options.registeredExtensions)));
142
            } else {
143
                promises.push(Promise.resolve(new C3DTBatchTable()));
2✔
144
            }
145

146
            const posGltf = headerByteLength +
3✔
147
                b3dmHeader.FTJSONLength + b3dmHeader.FTBinaryLength +
148
                b3dmHeader.BTJSONLength + b3dmHeader.BTBinaryLength;
149

150
            const gltfBuffer = buffer.slice(posGltf);
3✔
151
            const headerView = new DataView(gltfBuffer, 0, 20);
3✔
152

153
            const init_mesh = function f_init(mesh) {
3✔
154
                mesh.frustumCulled = frustumCulled;
10✔
155
                if (mesh.material) {
10✔
156
                    if (options.overrideMaterials) {
5!
NEW
157
                        const oldMat = mesh.material;
×
158
                        // Set up new material
NEW
159
                        if (typeof (options.overrideMaterials) === 'object' &&
×
160
                            options.overrideMaterials.isMaterial) {
NEW
161
                            mesh.material = options.overrideMaterials;
×
162
                        } else {
NEW
163
                            mesh.material = new MeshBasicMaterial();
×
164
                        }
NEW
165
                        disposeThreeMaterial(oldMat);
×
166
                    } else if (Capabilities.isLogDepthBufferSupported()
5!
167
                        && mesh.material.isRawShaderMaterial
168
                        && !options.doNotPatchMaterial) {
NEW
169
                        shaderUtils.patchMaterialForLogDepthSupport(mesh.material);
×
NEW
170
                        console.warn('glTF shader has been patched to add log depth buffer support');
×
171
                    }
172
                    ReferLayerProperties(mesh.material, options.layer);
5✔
173
                }
174
            };
175

176
            promises.push(GLTFParser.parse(gltfBuffer, options).then((gltf) => {
3✔
177
                for (const scene of gltf.scenes) {
3✔
178
                    scene.traverse(filterUnsupportedSemantics);
3✔
179
                }
3✔
180

181
                applyDeprecatedGltfUpAxis(gltf.scene, options.gltfUpAxis);
3✔
182

183
                const shouldBePatchedForLogDepthSupport = Capabilities.isLogDepthBufferSupported() && !options.doNotPatchMaterial;
3✔
184
                if (options.frustumCulling === false || options.overrideMaterials || shouldBePatchedForLogDepthSupport || options.layer) {
3!
185
                    gltf.scene.traverse(init_mesh);
3✔
186
                }
187

188
                // Apply relative center from Feature table.
189
                gltf.scene.position.copy(FT_RTC);
3✔
190

191
                // Apply relative center from gltf json.
192
                const contentArray = new Uint8Array(gltfBuffer, 20, headerView.getUint32(12, true));
3✔
193
                const content = utf8Decoder.decode(new Uint8Array(contentArray));
3✔
194
                const json = JSON.parse(content);
3✔
195
                if (json.extensions && json.extensions.CESIUM_RTC) {
3!
NEW
196
                    gltf.scene.position.fromArray(json.extensions.CESIUM_RTC.center);
×
NEW
197
                    gltf.scene.updateMatrixWorld(true);
×
198
                }
199

200
                return gltf;
3✔
NEW
201
            }).catch((e) => { throw new Error(e); }));
×
202
            return Promise.all(promises).then(values => ({ gltf: values[1], batchTable: values[0] })).catch((e) => { throw new Error(e); });
3✔
203
        } else {
204
            throw new Error('Invalid b3dm file.');
×
205
        }
206
    },
207
};
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc