diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index cd0ca280ec4..00000000000 --- a/.eslintignore +++ /dev/null @@ -1,23 +0,0 @@ -Apps/HelloWorld.html -Apps/Sandcastle/ThirdParty/** -Build/** -Documentation/** -Source/** -Specs/jasmine/** -ThirdParty/** -Tools/** -Apps/Sandcastle/jsHintOptions.js -Apps/Sandcastle/gallery/gallery-index.js -index.html -index.release.html - - -# packages/engine -packages/engine/Build/** -packages/engine/Source/Scene/GltfPipeline/** -packages/engine/Source/Shaders/** -packages/engine/Source/ThirdParty/** - -# packages/widgets -packages/widgets/Build/** -packages/widgets/Source/ThirdParty/** \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 1468218cac6..00000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": [ - "cesium/node" - ] -} diff --git a/.github/actions/check-for-CLA/.gitignore b/.github/actions/check-for-CLA/.gitignore new file mode 100644 index 00000000000..25c8fdbaba6 --- /dev/null +++ b/.github/actions/check-for-CLA/.gitignore @@ -0,0 +1,2 @@ +node_modules +package-lock.json \ No newline at end of file diff --git a/.github/actions/check-for-CLA/index.js b/.github/actions/check-for-CLA/index.js index e1ee29e17d2..56ece7b8e03 100644 --- a/.github/actions/check-for-CLA/index.js +++ b/.github/actions/check-for-CLA/index.js @@ -2,6 +2,8 @@ import { Octokit } from "@octokit/core"; import { google } from "googleapis"; import Handlebars from "handlebars"; import fs from "fs-extra"; +import { dirname, join } from "path"; +import { fileURLToPath } from "url"; const PULL_REQUST_INFO = { id: process.env.PULL_REQUEST_ID, @@ -20,30 +22,26 @@ const GOOGLE_SHEETS_INFO = { const CONTRIBUTORS_URL = "https://github.com/CesiumGS/cesium/blob/main/CONTRIBUTORS.md"; -const main = async () => { - let hasSignedCLA; - let errorFoundOnCLACheck; +const getGoogleSheetsApiClient = async () => { + const googleConfigFilePath = "GoogleConfig.json"; + fs.writeFileSync(googleConfigFilePath, GOOGLE_SHEETS_INFO.APIKeys); - try { - hasSignedCLA = await checkIfUserHasSignedAnyCLA(); - } catch (error) { - errorFoundOnCLACheck = error.toString(); - } + const auth = new google.auth.GoogleAuth({ + keyFile: googleConfigFilePath, + scopes: ["https://www.googleapis.com/auth/spreadsheets"], + }); + const googleAuthClient = await auth.getClient(); - const response = await postCommentOnPullRequest( - hasSignedCLA, - errorFoundOnCLACheck - ); + return google.sheets({ version: "v4", auth: googleAuthClient }); }; -const checkIfUserHasSignedAnyCLA = async () => { - let foundIndividualCLA = await checkIfIndividualCLAFound(); - if (foundIndividualCLA) { - return true; - } +const getValuesFromGoogleSheet = async (sheetId, cellRanges) => { + const googleSheetsApi = await getGoogleSheetsApiClient(); - let foundCorporateCLA = await checkIfCorporateCLAFound(); - return foundCorporateCLA; + return googleSheetsApi.spreadsheets.values.get({ + spreadsheetId: sheetId, + range: cellRanges, + }); }; const checkIfIndividualCLAFound = async () => { @@ -95,26 +93,34 @@ const checkIfCorporateCLAFound = async () => { return false; }; -const getValuesFromGoogleSheet = async (sheetId, cellRanges) => { - const googleSheetsApi = await getGoogleSheetsApiClient(); +const checkIfUserHasSignedAnyCLA = async () => { + const foundIndividualCLA = await checkIfIndividualCLAFound(); + if (foundIndividualCLA) { + return true; + } - return googleSheetsApi.spreadsheets.values.get({ - spreadsheetId: sheetId, - range: cellRanges, - }); + const foundCorporateCLA = await checkIfCorporateCLAFound(); + return foundCorporateCLA; }; -const getGoogleSheetsApiClient = async () => { - const googleConfigFilePath = "GoogleConfig.json"; - fs.writeFileSync(googleConfigFilePath, GOOGLE_SHEETS_INFO.APIKeys); +const getCommentBody = (hasSignedCLA, errorFoundOnCLACheck) => { + const commentTemplate = fs.readFileSync( + join( + dirname(fileURLToPath(import.meta.url)), + "templates/pullRequestComment.hbs" + ), + "utf-8" + ); - const auth = new google.auth.GoogleAuth({ - keyFile: googleConfigFilePath, - scopes: ["https://www.googleapis.com/auth/spreadsheets"], + const getCommentFromTemplate = Handlebars.compile(commentTemplate); + const commentBody = getCommentFromTemplate({ + errorCla: errorFoundOnCLACheck, + hasCla: hasSignedCLA, + username: PULL_REQUST_INFO.username, + contributorsUrl: CONTRIBUTORS_URL, }); - const googleAuthClient = await auth.getClient(); - return google.sheets({ version: "v4", auth: googleAuthClient }); + return commentBody; }; const postCommentOnPullRequest = async (hasSignedCLA, errorFoundOnCLACheck) => { @@ -136,21 +142,17 @@ const postCommentOnPullRequest = async (hasSignedCLA, errorFoundOnCLACheck) => { ); }; -const getCommentBody = (hasSignedCLA, errorFoundOnCLACheck) => { - const commentTemplate = fs.readFileSync( - "./.github/actions/check-for-CLA/templates/pullRequestComment.hbs", - "utf-8" - ); +const main = async () => { + let hasSignedCLA; + let errorFoundOnCLACheck; - const getCommentFromTemplate = Handlebars.compile(commentTemplate); - const commentBody = getCommentFromTemplate({ - errorCla: errorFoundOnCLACheck, - hasCla: hasSignedCLA, - username: PULL_REQUST_INFO.username, - contributorsUrl: CONTRIBUTORS_URL, - }); + try { + hasSignedCLA = await checkIfUserHasSignedAnyCLA(); + } catch (error) { + errorFoundOnCLACheck = error.toString(); + } - return commentBody; + await postCommentOnPullRequest(hasSignedCLA, errorFoundOnCLACheck); }; main(); diff --git a/.github/actions/check-for-CLA/package.json b/.github/actions/check-for-CLA/package.json new file mode 100644 index 00000000000..d04d9c10a6d --- /dev/null +++ b/.github/actions/check-for-CLA/package.json @@ -0,0 +1,21 @@ +{ + "name": "@cesium/check-for-cla", + "version": "0.1.0", + "main": "index.js", + "dependencies": { + "@octokit/core": "^6.1.2", + "fs-extra": "^11.2.0", + "googleapis": "^137.1.0", + "handlebars": "^4.7.8" + }, + "type": "module", + "repository": { + "type": "git", + "url": "git+https://github.com/CesiumGS/cesium.git" + }, + "license": "Apache-2.0", + "author": { + "name": "Cesium GS, Inc.", + "url": "https://cesium.com" + } +} diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index 79a23b3a1a2..60ffd52516e 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -16,9 +16,11 @@ jobs: with: node-version: '20' - name: install npm packages - run: npm install googleapis @octokit/core handlebars fs-extra + working-directory: ./.github/actions/check-for-CLA + run: npm install - name: run script - run: node .github/actions/check-for-CLA/index.js + working-directory: ./.github/actions/check-for-CLA + run: node index.js env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PULL_REQUEST_ID: ${{ github.event.number }} diff --git a/.slackbot.yml b/.slackbot.yml index d7ef941fcb8..a5496634288 100644 --- a/.slackbot.yml +++ b/.slackbot.yml @@ -1,11 +1,11 @@ releaseSchedule: - jjspace, 4/1/2024 - - jjhembd, 5/1/2024 - - ggetz, 6/1/2024 + - ggetz, 5/1/2024 + - jjhembd, 6/1/2024 - jjspace, 7/1/2024 - - jjhembd, 8/1/2024 - - ggetz, 9/1/2024 + - ggetz, 8/1/2024 + - jjhembd, 9/1/2024 - jjspace, 10/1/2024 - - jjhembd, 11/1/2024 - - ggetz, 12/1/2024 + - ggetz, 11/1/2024 + - jjhembd, 12/1/2024 diff --git a/Apps/.eslintrc.json b/Apps/.eslintrc.json deleted file mode 100644 index e646ee82716..00000000000 --- a/Apps/.eslintrc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "../packages/.eslintrc.json" -} diff --git a/Apps/Sandcastle/.eslintrc.json b/Apps/Sandcastle/.eslintrc.json deleted file mode 100644 index daf23f0bdcd..00000000000 --- a/Apps/Sandcastle/.eslintrc.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "extends": "../.eslintrc.json", - "env": { - "amd": true - }, - "globals": { - "JSON": true, - "require": true, - "console": true, - "Sandcastle": true, - "Cesium": true - }, - "parserOptions": { - "sourceType": "script" - }, - "rules": { - "no-alert": ["off"], - "no-unused-vars": ["off"] - }, - "overrides": [ - { - "files": [ - "load-cesium-es6.js" - ], - "parserOptions": { - "sourceType": "module" - } - } - ] -} diff --git a/Apps/Sandcastle/gallery/Japan Buildings.html b/Apps/Sandcastle/gallery/Japan Buildings.html new file mode 100644 index 00000000000..5534dd276bd --- /dev/null +++ b/Apps/Sandcastle/gallery/Japan Buildings.html @@ -0,0 +1,284 @@ + + + + + + + + + Cesium Demo + + + + + + +
+

Loading...

+
+ + + diff --git a/Apps/Sandcastle/gallery/Japan Buildings.jpg b/Apps/Sandcastle/gallery/Japan Buildings.jpg new file mode 100644 index 00000000000..03c36b17051 Binary files /dev/null and b/Apps/Sandcastle/gallery/Japan Buildings.jpg differ diff --git a/Apps/Sandcastle/gallery/Picking.html b/Apps/Sandcastle/gallery/Picking.html index d6404489b64..157c973b607 100644 --- a/Apps/Sandcastle/gallery/Picking.html +++ b/Apps/Sandcastle/gallery/Picking.html @@ -229,12 +229,7 @@ const scene = viewer.scene; if (scene.mode !== Cesium.SceneMode.MORPHING) { - const pickedObject = scene.pick(movement.endPosition); - if ( - scene.pickPositionSupported && - Cesium.defined(pickedObject) && - pickedObject.id === modelEntity - ) { + if (scene.pickPositionSupported) { const cartesian = viewer.scene.pickPosition( movement.endPosition ); diff --git a/Apps/Sandcastle/gallery/glTF PBR Extensions.html b/Apps/Sandcastle/gallery/glTF PBR Extensions.html new file mode 100644 index 00000000000..279a457fbec --- /dev/null +++ b/Apps/Sandcastle/gallery/glTF PBR Extensions.html @@ -0,0 +1,257 @@ + + + + + + + + + Cesium Demo + + + + + +
+

Loading...

+
+
+
+
+ + + diff --git a/Apps/Sandcastle/gallery/glTF PBR Extensions.jpg b/Apps/Sandcastle/gallery/glTF PBR Extensions.jpg new file mode 100644 index 00000000000..9731d8900f7 Binary files /dev/null and b/Apps/Sandcastle/gallery/glTF PBR Extensions.jpg differ diff --git a/Apps/TimelineDemo/.eslintrc.json b/Apps/TimelineDemo/.eslintrc.json deleted file mode 100644 index 237b3b29d43..00000000000 --- a/Apps/TimelineDemo/.eslintrc.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../.eslintrc.json", - "env": { - "amd": true - }, - "parserOptions": { - "sourceType": "script" - } -} diff --git a/Apps/TimelineDemo/TimelineDemo.js b/Apps/TimelineDemo/TimelineDemo.js index f03d16c34db..5f865c99146 100644 --- a/Apps/TimelineDemo/TimelineDemo.js +++ b/Apps/TimelineDemo/TimelineDemo.js @@ -1,6 +1,5 @@ define(["dijit/dijit", "dojo"], function (dijit, dojo) { "use strict"; - /* global Cesium */ const defined = Cesium.defined; const Clock = Cesium.Clock; diff --git a/CHANGES.md b/CHANGES.md index a67804972ef..fb7f6fec3f0 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,26 @@ # Change Log -### 1.117 +### 1.118 - 2024-06-03 + +#### @cesium/engine + +###### Additions :tada: + +- Added support for glTF models with the [KHR_materials_specular extension](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_specular). [#11970](https://github.com/CesiumGS/cesium/pull/11970) +- Added support for glTF models with the [KHR_materials_anisotropy extension](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_anisotropy/README.md). [#11988](https://github.com/CesiumGS/cesium/pull/11988) +- Added support for glTF models with the [KHR_materials_clearcoat extension](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_clearcoat/README.md). [#12006](https://github.com/CesiumGS/cesium/pull/12006) + +#### Fixes :wrench: + +- Fixed a bug where `scene.pickPosition` returned incorrect results against the globe when `depthTestAgainstTerrain` is `false`. [#4368](https://github.com/CesiumGS/cesium/issues/4368) +- Fixed a bug where `TaskProcessor` worker loading would check the worker module ID rather than the absolute URL when determining if it is cross-origin. [#11833](https://github.com/CesiumGS/cesium/pull/11833) +- Fixed a bug where cross-origin workers would error when loaded with the CommonJS `importScripts` shim instead of an ESM `import`. [#11833](https://github.com/CesiumGS/cesium/pull/11833) +- Fixed an error in the specular reflection calculations for image-based lighting from supplied environment maps. [#12008](https://github.com/CesiumGS/cesium/issues/12008) +- Fixed a normalization error in image-based lighting. [#11994](https://github.com/CesiumGS/cesium/issues/11994) +- Fixes a bug where `sampleTerrain` did not respect the `rejectOnTileFail` flag for failed requests other than the first. [#11998](https://github.com/CesiumGS/cesium/pull/11998) +- Corrected the Typescript types for `Billboard.id` and `Label.id` to be `any` [#11973](https://github.com/CesiumGS/cesium/issues/11973) + +### 1.117 - 2024-05-01 #### @cesium/engine @@ -13,6 +33,7 @@ - Fixed a bug where a data source was not automatically rendered after is was added in request render mode. [#11934](https://github.com/CesiumGS/cesium/pull/11934) - Fixes Typescript definition for `Event.raiseEvent`. [#10498](https://github.com/CesiumGS/cesium/issues/10498) +- Fixed a bug that Label position height may not be correctly updated when its HeightReference is relative. [#11929](https://github.com/CesiumGS/cesium/pull/11929) #### @cesium/widgets diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index dc24c6df14f..7d30e590794 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -130,6 +130,8 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to Cesiu - [Andrew McDowell](https://github.com/madole) - [Tony Luk](https://github.com/impactblue573) - [Daniel Cooper](https://github.com/moodragon46) + - [Harry Morris](https://github.com/harrythemorris) + - [Jesse Gibbs](https://github.com/jesseyay) - [GeoFS](https://www.geo-fs.com) - [Xavier Tassin](https://github.com/xtassin/) - [Esri](https://www.esri.com) diff --git a/Documentation/Contributors/ReleaseGuide/README.md b/Documentation/Contributors/ReleaseGuide/README.md index c1746f4acd9..825757b331f 100644 --- a/Documentation/Contributors/ReleaseGuide/README.md +++ b/Documentation/Contributors/ReleaseGuide/README.md @@ -61,4 +61,4 @@ There is no release manager; instead, our community shares the responsibility. A 30. Check out the `cesium.com` branch. Merge the new release tag into the `cesium.com` branch `git merge origin `. CI will deploy the hosted release, Sandcastle, and the updated doc when you push the branch up. 31. After the `cesium.com` branch is live on cesium.com, comment in the `#comms-chat` slack channel to notify comms that the release is done so they can add these highlights and publish the monthly blog post - Note, it may take a little while for the new version of CesiumJS to be live on cesium.com (~30 minutes after the branch builds). You can check the version of Cesium in [sandcastle](https://sandcastle.cesium.com/) by looking at the tab above the cesium pane. -32. Continue to the [Cesium Analytics release](https://github.com/CesiumGS/cesium-analytics/blob/main/Documentation/Contributors/AnalyticsReleaseGuide/README.md) +32. Continue to the [Cesium Analytics release](https://github.com/CesiumGS/cesium-analytics/tree/main/Documentation/ReleaseGuide) diff --git a/Specs/.eslintrc.json b/Specs/.eslintrc.json deleted file mode 100644 index 926cc63cb4a..00000000000 --- a/Specs/.eslintrc.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "extends": "../packages/.eslintrc.json", - "env": { - "jasmine": true - }, - "rules": { - "no-self-assign": "off" - }, - "overrides": [ - { - "files": [ - "karma.conf.cjs", - "test.cjs" - ], - "parserOptions": { - "sourceType": "script" - } - } - ] -} diff --git a/Specs/Data/Models/glTF-2.0/BoxAnisotropy/README.md b/Specs/Data/Models/glTF-2.0/BoxAnisotropy/README.md new file mode 100644 index 00000000000..0dc1fd980c9 --- /dev/null +++ b/Specs/Data/Models/glTF-2.0/BoxAnisotropy/README.md @@ -0,0 +1,11 @@ +# Box Anisotropy + +## Screenshot + +![screenshot](screenshot/screenshot.png) + +## License Information + +Developed by Cesium for testing the KHR_materials_anisotropy extension. Please follow the [Cesium Trademark Terms and Conditions](https://github.com/AnalyticalGraphicsInc/cesium/wiki/CesiumTrademark.pdf). + +This model is licensed under a [Creative Commons Attribution 4.0 International License](http://creativecommons.org/licenses/by/4.0/). diff --git a/Specs/Data/Models/glTF-2.0/BoxAnisotropy/glTF/BoxAnisotropy.bin b/Specs/Data/Models/glTF-2.0/BoxAnisotropy/glTF/BoxAnisotropy.bin new file mode 100644 index 00000000000..d2a73551f94 Binary files /dev/null and b/Specs/Data/Models/glTF-2.0/BoxAnisotropy/glTF/BoxAnisotropy.bin differ diff --git a/Specs/Data/Models/glTF-2.0/BoxAnisotropy/glTF/BoxAnisotropy.gltf b/Specs/Data/Models/glTF-2.0/BoxAnisotropy/glTF/BoxAnisotropy.gltf new file mode 100644 index 00000000000..19db9c8eef1 --- /dev/null +++ b/Specs/Data/Models/glTF-2.0/BoxAnisotropy/glTF/BoxAnisotropy.gltf @@ -0,0 +1,201 @@ +{ + "asset": { + "generator": "COLLADA2GLTF", + "version": "2.0" + }, + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ], + "nodes": [ + { + "children": [ + 1 + ], + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + -1.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + { + "mesh": 0 + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 2, + "TEXCOORD_0": 3 + }, + "indices": 0, + "mode": 4, + "material": 0 + } + ], + "name": "Mesh" + } + ], + "accessors": [ + { + "bufferView": 0, + "byteOffset": 0, + "componentType": 5123, + "count": 36, + "max": [ + 23 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 1, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 1.0, + 1.0, + 1.0 + ], + "min": [ + -1.0, + -1.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 288, + "componentType": 5126, + "count": 24, + "max": [ + 0.5, + 0.5, + 0.5 + ], + "min": [ + -0.5, + -0.5, + -0.5 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 6.0, + 1.0 + ], + "min": [ + 0.0, + 0.0 + ], + "type": "VEC2" + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 0 + }, + "metallicFactor": 0.0 + }, + "normalTexture": { + "index": 0 + }, + "name": "Texture", + "extensions": { + "KHR_materials_anisotropy": { + "anisotropyStrength": 0.5, + "anisotropyRotation": 0.349065850398866, + "anisotropyTexture": { + "index": 0 + } + } + } + } + ], + "textures": [ + { + "sampler": 0, + "source": 0 + } + ], + "images": [ + { + "uri": "CesiumLogoFlat.png" + } + ], + "samplers": [ + { + "magFilter": 9729, + "minFilter": 9986, + "wrapS": 10497, + "wrapT": 10497 + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteOffset": 768, + "byteLength": 72, + "target": 34963 + }, + { + "buffer": 0, + "byteOffset": 0, + "byteLength": 576, + "byteStride": 12, + "target": 34962 + }, + { + "buffer": 0, + "byteOffset": 576, + "byteLength": 192, + "byteStride": 8, + "target": 34962 + } + ], + "buffers": [ + { + "byteLength": 840, + "uri": "BoxAnisotropy.bin" + } + ], + "extensionsRequired": [ + "KHR_draco_mesh_compression", + "KHR_materials_anisotropy" + ], + "extensionsUsed": [ + "KHR_draco_mesh_compression", + "KHR_materials_anisotropy" + ] +} diff --git a/Specs/Data/Models/glTF-2.0/BoxAnisotropy/glTF/CesiumLogoFlat.png b/Specs/Data/Models/glTF-2.0/BoxAnisotropy/glTF/CesiumLogoFlat.png new file mode 100644 index 00000000000..8159c4c4afd Binary files /dev/null and b/Specs/Data/Models/glTF-2.0/BoxAnisotropy/glTF/CesiumLogoFlat.png differ diff --git a/Specs/Data/Models/glTF-2.0/BoxClearcoat/README.md b/Specs/Data/Models/glTF-2.0/BoxClearcoat/README.md new file mode 100644 index 00000000000..4f5fb2f7cc3 --- /dev/null +++ b/Specs/Data/Models/glTF-2.0/BoxClearcoat/README.md @@ -0,0 +1,11 @@ +# Box Clearcoat + +## Screenshot + +![screenshot](screenshot/screenshot.png) + +## License Information + +Developed by Cesium for testing the KHR_materials_clearcoat extension. Please follow the [Cesium Trademark Terms and Conditions](https://github.com/AnalyticalGraphicsInc/cesium/wiki/CesiumTrademark.pdf). + +This model is licensed under a [Creative Commons Attribution 4.0 International License](http://creativecommons.org/licenses/by/4.0/). diff --git a/Specs/Data/Models/glTF-2.0/BoxClearcoat/glTF/BoxClearcoat.bin b/Specs/Data/Models/glTF-2.0/BoxClearcoat/glTF/BoxClearcoat.bin new file mode 100644 index 00000000000..d2a73551f94 Binary files /dev/null and b/Specs/Data/Models/glTF-2.0/BoxClearcoat/glTF/BoxClearcoat.bin differ diff --git a/Specs/Data/Models/glTF-2.0/BoxClearcoat/glTF/BoxClearcoat.gltf b/Specs/Data/Models/glTF-2.0/BoxClearcoat/glTF/BoxClearcoat.gltf new file mode 100644 index 00000000000..ccea6548bc7 --- /dev/null +++ b/Specs/Data/Models/glTF-2.0/BoxClearcoat/glTF/BoxClearcoat.gltf @@ -0,0 +1,204 @@ +{ + "asset": { + "generator": "COLLADA2GLTF", + "version": "2.0" + }, + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ], + "nodes": [ + { + "children": [ + 1 + ], + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + -1.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + { + "mesh": 0 + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 2, + "TEXCOORD_0": 3 + }, + "indices": 0, + "mode": 4, + "material": 0 + } + ], + "name": "Mesh" + } + ], + "accessors": [ + { + "bufferView": 0, + "byteOffset": 0, + "componentType": 5123, + "count": 36, + "max": [ + 23 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 1, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 1.0, + 1.0, + 1.0 + ], + "min": [ + -1.0, + -1.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 288, + "componentType": 5126, + "count": 24, + "max": [ + 0.5, + 0.5, + 0.5 + ], + "min": [ + -0.5, + -0.5, + -0.5 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 6.0, + 1.0 + ], + "min": [ + 0.0, + 0.0 + ], + "type": "VEC2" + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 0 + }, + "metallicFactor": 0.0 + }, + "name": "Texture", + "extensions": { + "KHR_materials_clearcoat": { + "clearcoatFactor": 0.5, + "clearcoatRoughnessFactor": 0.2, + "clearcoatTexture": { + "index": 0 + }, + "clearcoatRoughnessTexture": { + "index": 0 + }, + "clearcoatNormalTexture": { + "index": 0 + } + } + } + } + ], + "textures": [ + { + "sampler": 0, + "source": 0 + } + ], + "images": [ + { + "uri": "CesiumLogoFlat.png" + } + ], + "samplers": [ + { + "magFilter": 9729, + "minFilter": 9986, + "wrapS": 10497, + "wrapT": 10497 + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteOffset": 768, + "byteLength": 72, + "target": 34963 + }, + { + "buffer": 0, + "byteOffset": 0, + "byteLength": 576, + "byteStride": 12, + "target": 34962 + }, + { + "buffer": 0, + "byteOffset": 576, + "byteLength": 192, + "byteStride": 8, + "target": 34962 + } + ], + "buffers": [ + { + "byteLength": 840, + "uri": "BoxClearcoat.bin" + } + ], + "extensionsRequired": [ + "KHR_draco_mesh_compression", + "KHR_materials_clearcoat" + ], + "extensionsUsed": [ + "KHR_draco_mesh_compression", + "KHR_materials_clearcoat" + ] +} diff --git a/Specs/Data/Models/glTF-2.0/BoxClearcoat/glTF/CesiumLogoFlat.png b/Specs/Data/Models/glTF-2.0/BoxClearcoat/glTF/CesiumLogoFlat.png new file mode 100644 index 00000000000..8159c4c4afd Binary files /dev/null and b/Specs/Data/Models/glTF-2.0/BoxClearcoat/glTF/CesiumLogoFlat.png differ diff --git a/Specs/Data/Models/glTF-2.0/BoxSpecular/README.md b/Specs/Data/Models/glTF-2.0/BoxSpecular/README.md new file mode 100644 index 00000000000..31272183511 --- /dev/null +++ b/Specs/Data/Models/glTF-2.0/BoxSpecular/README.md @@ -0,0 +1,11 @@ +# Box Specular + +## Screenshot + +![screenshot](screenshot/screenshot.png) + +## License Information + +Developed by Cesium for testing the KHR_materials_specular extension. Please follow the [Cesium Trademark Terms and Conditions](https://github.com/AnalyticalGraphicsInc/cesium/wiki/CesiumTrademark.pdf). + +This model is licensed under a [Creative Commons Attribution 4.0 International License](http://creativecommons.org/licenses/by/4.0/). diff --git a/Specs/Data/Models/glTF-2.0/BoxSpecular/glTF/BoxSpecular.bin b/Specs/Data/Models/glTF-2.0/BoxSpecular/glTF/BoxSpecular.bin new file mode 100644 index 00000000000..d2a73551f94 Binary files /dev/null and b/Specs/Data/Models/glTF-2.0/BoxSpecular/glTF/BoxSpecular.bin differ diff --git a/Specs/Data/Models/glTF-2.0/BoxSpecular/glTF/BoxSpecular.gltf b/Specs/Data/Models/glTF-2.0/BoxSpecular/glTF/BoxSpecular.gltf new file mode 100644 index 00000000000..6d4459df349 --- /dev/null +++ b/Specs/Data/Models/glTF-2.0/BoxSpecular/glTF/BoxSpecular.gltf @@ -0,0 +1,205 @@ +{ + "asset": { + "generator": "COLLADA2GLTF", + "version": "2.0" + }, + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ], + "nodes": [ + { + "children": [ + 1 + ], + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + -1.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + { + "mesh": 0 + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 2, + "TEXCOORD_0": 3 + }, + "indices": 0, + "mode": 4, + "material": 0 + } + ], + "name": "Mesh" + } + ], + "accessors": [ + { + "bufferView": 0, + "byteOffset": 0, + "componentType": 5123, + "count": 36, + "max": [ + 23 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 1, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 1.0, + 1.0, + 1.0 + ], + "min": [ + -1.0, + -1.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 288, + "componentType": 5126, + "count": 24, + "max": [ + 0.5, + 0.5, + 0.5 + ], + "min": [ + -0.5, + -0.5, + -0.5 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 6.0, + 1.0 + ], + "min": [ + 0.0, + 0.0 + ], + "type": "VEC2" + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 0 + }, + "metallicFactor": 0.0 + }, + "name": "Texture", + "extensions": { + "KHR_materials_specular": { + "specularFactor": 0.7, + "specularColorFactor": [ + 50, + 0, + 0 + ], + "specularTexture": { + "index": 0 + }, + "specularColorTexture": { + "index": 0 + } + } + } + } + ], + "textures": [ + { + "sampler": 0, + "source": 0 + } + ], + "images": [ + { + "uri": "CesiumLogoFlat.png" + } + ], + "samplers": [ + { + "magFilter": 9729, + "minFilter": 9986, + "wrapS": 10497, + "wrapT": 10497 + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteOffset": 768, + "byteLength": 72, + "target": 34963 + }, + { + "buffer": 0, + "byteOffset": 0, + "byteLength": 576, + "byteStride": 12, + "target": 34962 + }, + { + "buffer": 0, + "byteOffset": 576, + "byteLength": 192, + "byteStride": 8, + "target": 34962 + } + ], + "buffers": [ + { + "byteLength": 840, + "uri": "BoxSpecular.bin" + } + ], + "extensionsRequired": [ + "KHR_draco_mesh_compression", + "KHR_materials_specular" + ], + "extensionsUsed": [ + "KHR_draco_mesh_compression", + "KHR_materials_specular" + ] +} diff --git a/Specs/Data/Models/glTF-2.0/BoxSpecular/glTF/CesiumLogoFlat.png b/Specs/Data/Models/glTF-2.0/BoxSpecular/glTF/CesiumLogoFlat.png new file mode 100644 index 00000000000..8159c4c4afd Binary files /dev/null and b/Specs/Data/Models/glTF-2.0/BoxSpecular/glTF/CesiumLogoFlat.png differ diff --git a/Specs/TestWorkers/.eslintrc.json b/Specs/TestWorkers/.eslintrc.json deleted file mode 100644 index cfa5954c554..00000000000 --- a/Specs/TestWorkers/.eslintrc.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": "cesium/browser", - "plugins": [ - "es" - ] -} \ No newline at end of file diff --git a/Specs/e2e/.eslintrc.json b/Specs/e2e/.eslintrc.json deleted file mode 100644 index 01ed4242fa7..00000000000 --- a/Specs/e2e/.eslintrc.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "root": true, - "extends": "cesium", - "globals": { - "Cesium": true - }, - "env": { - "browser": true, - "node": true - }, - "plugins": [ - "html", - "es" - ], - "rules": { - "no-unused-vars": "off" - }, - "parserOptions": { - "sourceType": "module" - }, - "overrides": [ - { - "files": [ - "playwright.config.js" - ] - } - ] -} diff --git a/Specs/karma.conf.cjs b/Specs/karma.conf.cjs index d368206fef3..86a6933f189 100644 --- a/Specs/karma.conf.cjs +++ b/Specs/karma.conf.cjs @@ -1,4 +1,3 @@ -/*eslint-env node*/ "use strict"; module.exports = function (config) { diff --git a/Specs/test.cjs b/Specs/test.cjs index f248664a0c0..e0daa674665 100644 --- a/Specs/test.cjs +++ b/Specs/test.cjs @@ -1,4 +1,3 @@ -/*eslint-env node*/ "use strict"; const assert = require("node:assert"); diff --git a/ThirdParty.json b/ThirdParty.json index 1927d5d6d17..9a581405204 100644 --- a/ThirdParty.json +++ b/ThirdParty.json @@ -4,7 +4,7 @@ "license": [ "MIT" ], - "version": "23.1.1", + "version": "23.1.2", "url": "https://www.npmjs.com/package/@tweenjs/tween.js" }, { @@ -12,7 +12,7 @@ "license": [ "BSD-3-Clause" ], - "version": "2.7.43", + "version": "2.7.45", "url": "https://www.npmjs.com/package/@zip.js/zip.js" }, { @@ -44,7 +44,7 @@ "license": [ "Apache-2.0" ], - "version": "3.1.2", + "version": "3.1.5", "url": "https://www.npmjs.com/package/dompurify", "notes": "dompurify is available as both MPL-2.0 OR Apache-2.0" }, @@ -158,7 +158,7 @@ "license": [ "BSD-3-Clause" ], - "version": "7.2.6", + "version": "7.3.0", "url": "https://www.npmjs.com/package/protobufjs" }, { diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 00000000000..c8ec3d9bd70 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,106 @@ +import globals from "globals"; +import html from "eslint-plugin-html"; +import configCesium from "eslint-config-cesium"; + +export default [ + { + ignores: [ + "**/Build/", + "Documentation/**/*", + "Source/*", + "**/ThirdParty/", + "Tools/**/*", + "index.html", + "index.release.html", + "Apps/HelloWorld.html", + "Apps/Sandcastle/jsHintOptions.js", + "Apps/Sandcastle/gallery/gallery-index.js", + "packages/engine/Source/Scene/GltfPipeline/**/*", + "packages/engine/Source/Shaders/**/*", + "Specs/jasmine/*", + "**/*/SpecList.js", + ], + }, + { + ...configCesium.configs.recommended, + languageOptions: { + sourceType: "module", + }, + }, + { + files: ["**/*.cjs"], + ...configCesium.configs.node, + }, + { + files: [".github/**/*.js", "scripts/**/*.js", "gulpfile.js", "server.js"], + ...configCesium.configs.node, + languageOptions: { + ...configCesium.configs.node.languageOptions, + sourceType: "module", + }, + }, + { + files: ["packages/**/*.js", "Apps/**/*.js", "Specs/**/*.js", "**/*.html"], + ...configCesium.configs.browser, + plugins: { html }, + rules: { + ...configCesium.configs.browser.rules, + "no-unused-vars": [ + "error", + { vars: "all", args: "none", caughtErrors: "none" }, + ], + }, + }, + { + files: ["Apps/Sandcastle/**/*", "Apps/TimelineDemo/**/*"], + languageOptions: { + sourceType: "script", + globals: { + ...globals.amd, + JSON: true, + console: true, + Sandcastle: true, + Cesium: true, + }, + }, + rules: { + "no-alert": ["off"], + "no-unused-vars": ["off"], + }, + }, + { + files: ["Apps/Sandcastle/load-cesium-es6.js"], + languageOptions: { + sourceType: "module", + }, + }, + { + files: ["Specs/**/*", "packages/**/Specs/**/*"], + languageOptions: { + globals: { + ...globals.jasmine, + }, + }, + rules: { + "no-self-assign": "off", + }, + }, + { + files: ["Specs/e2e/**/*"], + languageOptions: { + globals: { + ...globals.node, + Cesium: true, + }, + }, + rules: { + "no-unused-vars": "off", + }, + }, + { + files: [".github/**/*"], + rules: { + "n/no-missing-import": "off", + }, + }, +]; diff --git a/gulpfile.js b/gulpfile.js index bcf50248450..aea39dcfca2 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,10 +1,10 @@ -/*eslint-env node*/ import { writeFileSync, copyFileSync, readFileSync, existsSync } from "fs"; import { readFile, writeFile } from "fs/promises"; import { join, basename, resolve, dirname } from "path"; import { exec, execSync } from "child_process"; import fetch from "node-fetch"; import { createRequire } from "module"; +import { finished } from "stream/promises"; import gulp from "gulp"; import gulpTap from "gulp-tap"; @@ -15,8 +15,6 @@ import { globby } from "globby"; import open from "open"; import { rimraf } from "rimraf"; import { mkdirp } from "mkdirp"; -import mergeStream from "merge-stream"; -import streamToPromise from "stream-to-promise"; import karma from "karma"; import yargs from "yargs"; import typeScript from "typescript"; @@ -143,7 +141,7 @@ export async function build() { } export default build; -export const buildWatch = gulp.series(build, async function () { +export const buildWatch = gulp.series(build, async function buildWatch() { const minify = argv.minify ? argv.minify : false; const removePragmas = argv.pragmas ? argv.pragmas : false; const sourcemap = argv.sourcemap ? argv.sourcemap : true; @@ -331,7 +329,7 @@ async function clocSource() { cmdLine = "npx cloc" + " --quiet --progress-rate=0" + - " Specs/ packages/engine/Specs packages/widget/Specs --exclude-dir=Data --not-match-f=SpecList.js --not-match-f=.eslintrc.json"; + " Specs/ packages/engine/Specs packages/widget/Specs --exclude-dir=Data --not-match-f=SpecList.js --not-match-f=eslint.config.js"; exec(cmdLine, function (error, stdout, stderr) { if (error) { console.log(stderr); @@ -382,13 +380,14 @@ export async function prepare() { ]); const stream = gulp.src(files).pipe(gulp.dest("Specs/jasmine")); - return streamToPromise(stream); + await finished(stream); + return stream; } export const cloc = gulp.series(clean, clocSource); //Builds the documentation -export function buildDocs() { +export async function buildDocs() { const generatePrivateDocumentation = argv.private ? "--private" : ""; execSync( @@ -403,10 +402,11 @@ export function buildDocs() { ); const stream = gulp - .src("Documentation/Images/**") + .src(["Documentation/Images/**"], { encoding: false }) .pipe(gulp.dest("Build/Documentation/Images")); - return streamToPromise(stream); + await finished(stream); + return stream; } export async function buildDocsWatch() { @@ -429,7 +429,7 @@ function combineForSandcastle() { export const websiteRelease = gulp.series( buildEngine, buildWidgets, - function () { + function websiteReleaseBuild() { return buildCesium({ development: false, minify: false, @@ -452,7 +452,7 @@ export const buildRelease = gulp.series( buildEngine, buildWidgets, // Generate Build/CesiumUnminified - function () { + function buildCesiumForNode() { return buildCesium({ minify: false, removePragmas: false, @@ -461,7 +461,7 @@ export const buildRelease = gulp.series( }); }, // Generate Build/Cesium - function () { + function buildMinifiedCesiumForNode() { return buildCesium({ development: false, minify: true, @@ -477,6 +477,41 @@ export const release = gulp.series( gulp.parallel(buildTs, buildDocs) ); +export const postversion = async function () { + const workspace = argv.workspace; + if (!workspace) { + return; + } + const directory = workspace.replaceAll(`@${scope}/`, ``); + const workspacePackageJson = require(`./packages/${directory}/package.json`); + const version = workspacePackageJson.version; + + // Iterate through all package JSONs that may depend on the updated package and + // update the version of the updated workspace. + const packageJsons = await globby([ + "./package.json", + "./packages/*/package.json", + ]); + const promises = packageJsons.map(async (packageJsonPath) => { + // Ensure that we don't check the updated workspace itself. + if (basename(dirname(packageJsonPath)) === directory) { + return; + } + // Ensure that we only update workspaces where the dependency to the updated workspace already exists. + const packageJson = require(packageJsonPath); + if (!Object.hasOwn(packageJson.dependencies, workspace)) { + console.log( + `Skipping update for ${workspace} as it is not a dependency.` + ); + return; + } + // Update the version for the updated workspace. + packageJson.dependencies[workspace] = `^${version}`; + await writeFile(packageJsonPath, JSON.stringify(packageJson, undefined, 2)); + }); + return Promise.all(promises); +}; + /** * Removes scripts from package.json files to ensure that * they still work when run from within the ZIP file. @@ -529,49 +564,16 @@ async function pruneScriptsForZip(packageJsonPath) { // Write to a temporary package.json file. const noPreparePackageJson = join( dirname(packageJsonPath), - "Build/package.noprepare.json" + "package.noprepare.json" ); await writeFile(noPreparePackageJson, JSON.stringify(contentsJson, null, 2)); - return gulp.src(noPreparePackageJson).pipe(gulpRename(packageJsonPath)); -} - -export const postversion = async function () { - const workspace = argv.workspace; - if (!workspace) { - return; - } - const directory = workspace.replaceAll(`@${scope}/`, ``); - const workspacePackageJson = require(`./packages/${directory}/package.json`); - const version = workspacePackageJson.version; - - // Iterate through all package JSONs that may depend on the updated package and - // update the version of the updated workspace. - const packageJsons = await globby([ - "./package.json", - "./packages/*/package.json", - ]); - const promises = packageJsons.map(async (packageJsonPath) => { - // Ensure that we don't check the updated workspace itself. - if (basename(dirname(packageJsonPath)) === directory) { - return; - } - // Ensure that we only update workspaces where the dependency to the updated workspace already exists. - const packageJson = require(packageJsonPath); - if (!Object.hasOwn(packageJson.dependencies, workspace)) { - console.log( - `Skipping update for ${workspace} as it is not a dependency.` - ); - return; - } - // Update the version for the updated workspace. - packageJson.dependencies[workspace] = `^${version}`; - await writeFile(packageJsonPath, JSON.stringify(packageJson, undefined, 2)); + return gulp.src(noPreparePackageJson, { + base: ".", }); - return Promise.all(promises); -}; +} -export const makeZip = gulp.series(release, async function () { +export const makeZip = gulp.series(release, async function createZipFile() { //For now we regenerate the JS glsl to force it to be unminified in the release zip //See https://github.com/CesiumGS/cesium/pull/3106#discussion_r42793558 for discussion. await glslToJavaScript(false, "Build/minifyShaders.state", "engine"); @@ -584,101 +586,106 @@ export const makeZip = gulp.series(release, async function () { "packages/widgets/package.json" ); - const builtSrc = gulp.src( - [ - "Build/Cesium/**", - "Build/CesiumUnminified/**", - "Build/Documentation/**", - "Build/Specs/**", - "!Build/Specs/e2e/**", - "!Build/InlineWorkers.js", - "Build/package.json", - "packages/engine/Build/**", - "packages/widgets/Build/**", - "!packages/engine/Build/Specs/**", - "!packages/widgets/Build/Specs/**", - "!packages/engine/Build/minifyShaders.state", - "!packages/engine/Build/package.noprepare.json", - "!packages/widgets/Build/package.noprepare.json", - ], - { - base: ".", - } - ); - - const staticSrc = gulp.src( - [ - "Apps/**", - "Apps/**/.eslintrc.json", - "Apps/Sandcastle/.jshintrc", - "!Apps/Sandcastle/gallery/development/**", - "packages/engine/index.js", - "packages/engine/index.d.ts", - "packages/engine/LICENSE.md", - "packages/engine/README.md", - "packages/engine/Source/**", - "!packages/engine/.gitignore", - "packages/widgets/index.js", - "packages/widgets/index.d.ts", - "packages/widgets/LICENSE.md", - "packages/widgets/README.md", - "packages/widgets/Source/**", - "!packages/widgets/.gitignore", - "Source/**", - "Source/**/.eslintrc.json", - "Specs/**", - "!Specs/e2e/*-snapshots/**", - "Specs/**/.eslintrc.json", - "ThirdParty/**", - "favicon.ico", - ".eslintignore", - ".eslintrc.json", - ".prettierignore", - "scripts/**", - "gulpfile.js", - "server.js", - "index.cjs", - "LICENSE.md", - "CHANGES.md", - "README.md", - "web.config", - ], - { - base: ".", - } - ); - - const indexSrc = gulp + const src = gulp .src("index.release.html") - .pipe(gulpRename("index.html")); - - return streamToPromise( - mergeStream( - packageJsonSrc, - enginePackageJsonSrc, - widgetsPackageJsonSrc, - builtSrc, - staticSrc, - indexSrc + .pipe( + gulpRename((file) => { + if (file.basename === "index.release") { + file.basename = "index"; + } + }) ) - .pipe( - gulpTap(function (file) { - // Work around an issue with gulp-zip where archives generated on Windows do - // not properly have their directory executable mode set. - // see https://github.com/sindresorhus/gulp-zip/issues/64#issuecomment-205324031 - if (file.isDirectory()) { - file.stat.mode = parseInt("40777", 8); - } - }) + .pipe(enginePackageJsonSrc) + .pipe(widgetsPackageJsonSrc) + .pipe(packageJsonSrc) + .pipe( + gulpRename((file) => { + if (file.basename === "package.noprepare") { + file.basename = "package"; + } + }) + ) + .pipe( + gulp.src( + [ + "Build/Cesium/**", + "Build/CesiumUnminified/**", + "Build/Documentation/**", + "Build/Specs/**", + "Build/package.json", + "packages/engine/Build/**", + "packages/widgets/Build/**", + "!Build/Specs/e2e/**", + "!Build/InlineWorkers.js", + "!packages/engine/Build/Specs/**", + "!packages/widgets/Build/Specs/**", + "!packages/engine/Build/minifyShaders.state", + ], + { + encoding: false, + base: ".", + } + ) + ) + .pipe( + gulp.src( + [ + "Apps/**", + "Apps/Sandcastle/.jshintrc", + "packages/engine/index.js", + "packages/engine/index.d.ts", + "packages/engine/LICENSE.md", + "packages/engine/README.md", + "packages/engine/Source/**", + "packages/widgets/index.js", + "packages/widgets/index.d.ts", + "packages/widgets/LICENSE.md", + "packages/widgets/README.md", + "packages/widgets/Source/**", + "Source/**", + "Specs/**", + "ThirdParty/**", + "scripts/**", + "favicon.ico", + ".prettierignore", + "eslint.config.js", + "gulpfile.js", + "server.js", + "index.cjs", + "LICENSE.md", + "CHANGES.md", + "README.md", + "web.config", + "!**/*.gitignore", + "!Specs/e2e/*-snapshots/**", + "!Apps/Sandcastle/gallery/development/**", + ], + { + encoding: false, + base: ".", + } ) - .pipe(gulpZip(`Cesium-${version}.zip`)) - .pipe(gulp.dest(".")) - .on("finish", function () { - rimraf.sync("./Build/package.noprepare.json"); - rimraf.sync("./packages/engine/Build/package.noprepare.json"); - rimraf.sync("./packages/widgets/Build/package.noprepare.json"); + ) + .pipe( + gulpTap(function (file) { + // Work around an issue with gulp-zip where archives generated on Windows do + // not properly have their directory executable mode set. + // see https://github.com/sindresorhus/gulp-zip/issues/64#issuecomment-205324031 + if (file.isDirectory()) { + file.stat.mode = parseInt("40777", 8); + } }) - ); + ) + .pipe(gulpZip(`Cesium-${version}.zip`)) + .pipe(gulp.dest(".")); + + await finished(src); + + rimraf.sync("./package.noprepare.json"); + rimraf.sync("./packages/engine/package.noprepare.json"); + rimraf.sync("./packages/widgets/package.noprepare.json"); + + return src; }); export async function deploySetVersion() { @@ -1596,14 +1603,19 @@ export async function buildThirdParty() { return writeFile("ThirdParty.json", JSON.stringify(licenseJson, null, 2)); } -function buildSandcastle() { +async function buildSandcastle() { const streams = []; - let appStream = gulp.src([ - "Apps/Sandcastle/**", - "!Apps/Sandcastle/load-cesium-es6.js", - "!Apps/Sandcastle/images/**", - "!Apps/Sandcastle/gallery/**.jpg", - ]); + let appStream = gulp.src( + [ + "Apps/Sandcastle/**", + "!Apps/Sandcastle/load-cesium-es6.js", + "!Apps/Sandcastle/images/**", + "!Apps/Sandcastle/gallery/**.jpg", + ], + { + encoding: false, + } + ); if (isProduction) { // Remove swap out ESM modules for the IIFE build @@ -1667,6 +1679,7 @@ function buildSandcastle() { { base: "Apps/Sandcastle", buffer: false, + encoding: false, } ); if (isProduction) { @@ -1702,7 +1715,7 @@ function buildSandcastle() { .pipe(gulp.dest("Build/Sandcastle")); streams.push(standaloneStream); - return streamToPromise(mergeStream(...streams)); + return Promise.all(streams.map((s) => finished(s))); } async function buildCesiumViewer() { @@ -1750,30 +1763,37 @@ async function buildCesiumViewer() { path: cesiumViewerOutputDirectory, }); - const stream = mergeStream( - gulp.src([ - "Apps/CesiumViewer/**", - "!Apps/CesiumViewer/Images", - "!Apps/CesiumViewer/**/*.js", - "!Apps/CesiumViewer/**/*.css", - ]), - - gulp.src( + const stream = gulp + .src( [ - "Build/Cesium/Assets/**", - "Build/Cesium/Workers/**", - "Build/Cesium/ThirdParty/**", - "Build/Cesium/Widgets/**", - "!Build/Cesium/Widgets/**/*.css", + "Apps/CesiumViewer/**", + "!Apps/CesiumViewer/Images", + "!Apps/CesiumViewer/**/*.js", + "!Apps/CesiumViewer/**/*.css", ], { - base: "Build/Cesium", - nodir: true, + encoding: false, } - ), - - gulp.src(["web.config"]) - ); + ) + .pipe( + gulp.src( + [ + "Build/Cesium/Assets/**", + "Build/Cesium/Workers/**", + "Build/Cesium/ThirdParty/**", + "Build/Cesium/Widgets/**", + "!Build/Cesium/Widgets/**/*.css", + ], + { + base: "Build/Cesium", + nodir: true, + encoding: false, + } + ) + ) + .pipe(gulp.src(["web.config"])) + .pipe(gulp.dest(cesiumViewerOutputDirectory)); - return streamToPromise(stream.pipe(gulp.dest(cesiumViewerOutputDirectory))); + await finished(stream); + return stream; } diff --git a/package.json b/package.json index 26287446b08..3d6857aa857 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cesium", - "version": "1.117.0", + "version": "1.118.0", "description": "CesiumJS is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.", "homepage": "http://cesium.com/cesiumjs/", "license": "Apache-2.0", @@ -50,24 +50,23 @@ "./Specs/**/*" ], "dependencies": { - "@cesium/engine": "^9.1.0", + "@cesium/engine": "^9.2.0", "@cesium/widgets": "^6.1.0" }, "devDependencies": { "@playwright/test": "^1.41.1", "chokidar": "^3.5.3", - "cloc": "^2.8.0", + "cloc": "^2.0.0-cloc", "compression": "^1.7.4", - "esbuild": "^0.20.0", - "eslint": "^8.56.0", - "eslint-config-cesium": "^10.0.1", - "eslint-plugin-es": "^4.1.0", - "eslint-plugin-html": "^8.0.0", - "eslint-plugin-node": "^11.1.0", + "esbuild": "^0.21.4", + "eslint": "^9.1.1", + "eslint-config-cesium": "^11.0.1", + "eslint-plugin-html": "^8.1.1", "express": "^4.17.1", + "globals": "^15.1.0", "globby": "^14.0.0", "glsl-strip-comments": "^1.0.0", - "gulp": "^4.0.2", + "gulp": "^5.0.0", "gulp-clean-css": "^4.3.0", "gulp-insert": "^0.5.0", "gulp-rename": "^2.0.0", @@ -90,7 +89,7 @@ "karma-safari-launcher": "^1.0.0", "karma-sourcemap-loader": "^0.4.0", "karma-spec-reporter": "^0.0.36", - "markdownlint-cli": "^0.39.0", + "markdownlint-cli": "^0.41.0", "merge-stream": "^2.0.0", "mkdirp": "^3.0.1", "node-fetch": "^3.2.10", @@ -99,14 +98,13 @@ "prismjs": "^1.28.0", "request": "^2.79.0", "rimraf": "^5.0.0", - "sinon": "^17.0.0", - "stream-to-promise": "^3.0.0", + "sinon": "^18.0.0", "tsd-jsdoc": "^2.5.0", "typescript": "^5.3.2", "yargs": "^17.0.1" }, "scripts": { - "prepare": "gulp prepare && husky install && playwright install --with-deps", + "prepare": "gulp prepare && husky && playwright install --with-deps", "start": "node server.js", "start-public": "node server.js --public", "build": "gulp build", @@ -120,7 +118,7 @@ "coverage": "gulp coverage", "build-docs": "gulp buildDocs", "build-docs-watch": "gulp buildDocsWatch", - "eslint": "eslint \"./**/*.js\" \"./**/*.cjs\" \"./**/*.html\" --cache --quiet", + "eslint": "eslint \"./**/*.*js\" \"./**/*.html\" --cache --quiet", "make-zip": "gulp makeZip", "markdownlint": "markdownlint \"**/*.md\"", "release": "gulp release", @@ -144,7 +142,7 @@ "prettier-check": "prettier --check --no-config \"**/*\"" }, "engines": { - "node": ">=14.0.0" + "node": ">=18.18.0" }, "lint-staged": { "*.{js,cjs,mjs,css,html}": [ @@ -160,4 +158,4 @@ "packages/engine", "packages/widgets" ] -} \ No newline at end of file +} diff --git a/packages/.eslintrc.json b/packages/.eslintrc.json deleted file mode 100644 index 09c9b3fe948..00000000000 --- a/packages/.eslintrc.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "root": true, - "extends": [ - "cesium/browser" - ], - "plugins": [ - "html", - "es" - ], - "rules": { - "no-unused-vars": ["error", {"vars": "all", "args": "none"}] - } -} diff --git a/packages/engine/Source/Core/Ion.js b/packages/engine/Source/Core/Ion.js index d4602709895..8c747f60790 100644 --- a/packages/engine/Source/Core/Ion.js +++ b/packages/engine/Source/Core/Ion.js @@ -8,7 +8,7 @@ let defaultTokenCredit; const cesiumWebsiteToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI3ODZkMDQzOS03ZGJjLTQzZWUtYjlmYy04ZmM5Y2UwNzNhMmYiLCJpZCI6MjU5LCJpYXQiOjE2MzgyMDYwMDB9.cK1hsaFBgz0l2dG9Ry5vBFHWp-HF2lwjLC0tcK8Z8tY"; const defaultAccessToken = - "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJkYzAzYzE4NS0yZmJiLTQ5NzUtOWJlYS0zNjdkMzc2ODBmZDgiLCJpZCI6MjU5LCJpYXQiOjE3MTQ1NzE1MDN9.tIhlyfC7MHSWrQmoAqkvQdXMbg3igaC2HIbQp1HKCVM"; + "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI0YjhlOGM0Yy0xNzcwLTQwNWEtODk4Yy0xMGJkODg4MTA5ZGEiLCJpZCI6MjU5LCJpYXQiOjE3MTc0MzM4NjB9.VwBpSnRTNdg_G6uvU-JNsRNcSOCDMKW_j3Nl5E7wfwg"; /** * Default settings for accessing the Cesium ion API. * diff --git a/packages/engine/Source/Core/Math.js b/packages/engine/Source/Core/Math.js index a8f5e57d681..59ae199d8dc 100644 --- a/packages/engine/Source/Core/Math.js +++ b/packages/engine/Source/Core/Math.js @@ -205,7 +205,6 @@ CesiumMath.FOUR_GIGABYTES = 4 * 1024 * 1024 * 1024; * @param {number} value The value to return the sign of. * @returns {number} The sign of value. */ -// eslint-disable-next-line es/no-math-sign CesiumMath.sign = defaultValue(Math.sign, function sign(value) { value = +value; // coerce to number if (value === 0 || value !== value) { @@ -292,7 +291,6 @@ CesiumMath.normalize = function (value, rangeMinimum, rangeMaximum) { * @param {number} value The number whose hyperbolic sine is to be returned. * @returns {number} The hyperbolic sine of value. */ -// eslint-disable-next-line es/no-math-sinh CesiumMath.sinh = defaultValue(Math.sinh, function sinh(value) { return (Math.exp(value) - Math.exp(-value)) / 2.0; }); @@ -317,7 +315,6 @@ CesiumMath.sinh = defaultValue(Math.sinh, function sinh(value) { * @param {number} value The number whose hyperbolic cosine is to be returned. * @returns {number} The hyperbolic cosine of value. */ -// eslint-disable-next-line es/no-math-cosh CesiumMath.cosh = defaultValue(Math.cosh, function cosh(value) { return (Math.exp(value) + Math.exp(-value)) / 2.0; }); @@ -1034,7 +1031,6 @@ CesiumMath.logBase = function (number, base) { * @param {number} [number] The number. * @returns {number} The result. */ -// eslint-disable-next-line es/no-math-cbrt CesiumMath.cbrt = defaultValue(Math.cbrt, function cbrt(number) { const result = Math.pow(Math.abs(number), 1.0 / 3.0); return number < 0.0 ? -result : result; @@ -1047,7 +1043,6 @@ CesiumMath.cbrt = defaultValue(Math.cbrt, function cbrt(number) { * @param {number} number The number. * @returns {number} The result. */ -// eslint-disable-next-line es/no-math-log2 CesiumMath.log2 = defaultValue(Math.log2, function log2(number) { return Math.log(number) * Math.LOG2E; }); diff --git a/packages/engine/Source/Core/TaskProcessor.js b/packages/engine/Source/Core/TaskProcessor.js index b69011c6817..9eca8d863e1 100644 --- a/packages/engine/Source/Core/TaskProcessor.js +++ b/packages/engine/Source/Core/TaskProcessor.js @@ -81,18 +81,34 @@ function urlFromScript(script) { function createWorker(url) { const uri = new Uri(url); const isUri = uri.scheme().length !== 0 && uri.fragment().length === 0; + const moduleID = url.replace(/\.js$/, ""); const options = {}; let workerPath; + let crossOriginUrl; + + // If we are provided a fully resolved URL, check it is cross-origin + // Or if provided a module ID, check the full absolute URL instead. if (isCrossOriginUrl(url)) { + crossOriginUrl = url; + } else if (!isUri) { + const moduleAbsoluteUrl = buildModuleUrl( + `${TaskProcessor._workerModulePrefix}/${moduleID}.js` + ); + + if (isCrossOriginUrl(moduleAbsoluteUrl)) { + crossOriginUrl = moduleAbsoluteUrl; + } + } + + if (crossOriginUrl) { // To load cross-origin, create a shim worker from a blob URL - const script = `importScripts("${url}");`; + const script = `import "${crossOriginUrl}";`; workerPath = urlFromScript(script); + options.type = "module"; return new Worker(workerPath, options); } - const moduleID = url.replace(/\.js$/, ""); - /* global CESIUM_WORKERS */ if (!isUri && typeof CESIUM_WORKERS !== "undefined") { // If the workers are embedded, create a shim worker from the embedded script data diff --git a/packages/engine/Source/Core/sampleTerrain.js b/packages/engine/Source/Core/sampleTerrain.js index f2804b431e2..cd2f2dee82f 100644 --- a/packages/engine/Source/Core/sampleTerrain.js +++ b/packages/engine/Source/Core/sampleTerrain.js @@ -20,7 +20,7 @@ import defined from "./defined.js"; * @param {TerrainProvider} terrainProvider The terrain provider from which to query heights. * @param {number} level The terrain level-of-detail from which to query terrain heights. * @param {Cartographic[]} positions The positions to update with terrain heights. - * @param {boolean} [rejectOnTileFail=false] If true, for a failed terrain tile request the promise will be rejected. If false, returned heights will be undefined. + * @param {boolean} [rejectOnTileFail=false] If true, for any failed terrain tile requests, the promise will be rejected. If false, returned heights will be undefined. * @returns {Promise} A promise that resolves to the provided list of positions when terrain the query has completed. * * @see sampleTerrainMostDetailed @@ -139,12 +139,12 @@ function drainTileRequestQueue(tileRequests, results, rejectOnTileFail) { rejectOnTileFail ); if (success) { - return drainTileRequestQueue(tileRequests, results); + return drainTileRequestQueue(tileRequests, results, rejectOnTileFail); } // wait a small fixed amount of time first, before retrying the same request again return delay(100).then(() => { - return drainTileRequestQueue(tileRequests, results); + return drainTileRequestQueue(tileRequests, results, rejectOnTileFail); }); } diff --git a/packages/engine/Source/Scene/ArcGisMapService.js b/packages/engine/Source/Scene/ArcGisMapService.js index 648b8c04227..50029ecb120 100644 --- a/packages/engine/Source/Scene/ArcGisMapService.js +++ b/packages/engine/Source/Scene/ArcGisMapService.js @@ -8,7 +8,7 @@ const cesiumWebsiteToken = let defaultTokenCredit; const defaultAccessToken = - "AAPK809db8a668914f14bf886dcf16d4dc82Hm5SsO4xOJY2n4-V_ypQyxlGKJRQugNnPIslyTLkk5-HHQl9BRpgdNXaKNGe7oxx"; + "AAPKe5e6f1571ad74096bfacbdf289c5cdb687BUrehhWYnNo9tN4coC66_qhHDNruh3ygZV90buspkWdOqZUq6tb0kCb_dms9Ir"; /** * Default options for accessing the ArcGIS image tile service. * diff --git a/packages/engine/Source/Scene/Billboard.js b/packages/engine/Source/Scene/Billboard.js index bb1153d040b..f7c0264ae1f 100644 --- a/packages/engine/Source/Scene/Billboard.js +++ b/packages/engine/Source/Scene/Billboard.js @@ -28,7 +28,7 @@ import VerticalOrigin from "./VerticalOrigin.js"; * Initialization options for the first param of Billboard constructor * * @property {Cartesian3} position The cartesian position of the billboard. - * @property {string} [id] A user-defined object to return when the billboard is picked with {@link Scene#pick}. + * @property {*} [id] A user-defined object to return when the billboard is picked with {@link Scene#pick}. * @property {boolean} [show=true] Determines if this billboard will be shown. * @property {string | HTMLCanvasElement} [image] A loaded HTMLImageElement, ImageData, or a url to an image to use for the billboard. * @property {number} [scale=1.0] A number specifying the uniform scale that is multiplied with the billboard's image size in pixels. @@ -892,7 +892,7 @@ Object.defineProperties(Billboard.prototype, { /** * Gets or sets the user-defined object returned when the billboard is picked. * @memberof Billboard.prototype - * @type {object} + * @type {*} */ id: { get: function () { diff --git a/packages/engine/Source/Scene/GltfLoader.js b/packages/engine/Source/Scene/GltfLoader.js index 68989c3fe5c..18f825a6ae4 100644 --- a/packages/engine/Source/Scene/GltfLoader.js +++ b/packages/engine/Source/Scene/GltfLoader.js @@ -30,29 +30,34 @@ import ResourceLoader from "./ResourceLoader.js"; import SupportedImageFormats from "./SupportedImageFormats.js"; import VertexAttributeSemantic from "./VertexAttributeSemantic.js"; -const Attribute = ModelComponents.Attribute; -const Indices = ModelComponents.Indices; -const FeatureIdAttribute = ModelComponents.FeatureIdAttribute; -const FeatureIdTexture = ModelComponents.FeatureIdTexture; -const FeatureIdImplicitRange = ModelComponents.FeatureIdImplicitRange; -const MorphTarget = ModelComponents.MorphTarget; -const Primitive = ModelComponents.Primitive; -const Instances = ModelComponents.Instances; -const Skin = ModelComponents.Skin; -const Node = ModelComponents.Node; -const AnimatedPropertyType = ModelComponents.AnimatedPropertyType; -const AnimationSampler = ModelComponents.AnimationSampler; -const AnimationTarget = ModelComponents.AnimationTarget; -const AnimationChannel = ModelComponents.AnimationChannel; -const Animation = ModelComponents.Animation; -const ArticulationStage = ModelComponents.ArticulationStage; -const Articulation = ModelComponents.Articulation; -const Asset = ModelComponents.Asset; -const Scene = ModelComponents.Scene; -const Components = ModelComponents.Components; -const MetallicRoughness = ModelComponents.MetallicRoughness; -const SpecularGlossiness = ModelComponents.SpecularGlossiness; -const Material = ModelComponents.Material; +const { + Attribute, + Indices, + FeatureIdAttribute, + FeatureIdTexture, + FeatureIdImplicitRange, + MorphTarget, + Primitive, + Instances, + Skin, + Node, + AnimatedPropertyType, + AnimationSampler, + AnimationTarget, + AnimationChannel, + Animation, + ArticulationStage, + Articulation, + Asset, + Scene, + Components, + MetallicRoughness, + SpecularGlossiness, + Specular, + Anisotropy, + Clearcoat, + Material, +} = ModelComponents; /** * States of the glTF loading process. These states also apply to @@ -188,42 +193,28 @@ const GltfLoaderState = { */ function GltfLoader(options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - const gltfResource = options.gltfResource; - let baseResource = options.baseResource; - const typedArray = options.typedArray; - const releaseGltfJson = defaultValue(options.releaseGltfJson, false); - const asynchronous = defaultValue(options.asynchronous, true); - const incrementallyLoadTextures = defaultValue( - options.incrementallyLoadTextures, - true - ); - const upAxis = defaultValue(options.upAxis, Axis.Y); - const forwardAxis = defaultValue(options.forwardAxis, Axis.Z); - const loadAttributesAsTypedArray = defaultValue( - options.loadAttributesAsTypedArray, - false - ); - const loadAttributesFor2D = defaultValue(options.loadAttributesFor2D, false); - const enablePick = defaultValue(options.enablePick); - const loadIndicesForWireframe = defaultValue( - options.loadIndicesForWireframe, - false - ); - const loadPrimitiveOutline = defaultValue(options.loadPrimitiveOutline, true); - const loadForClassification = defaultValue( - options.loadForClassification, - false - ); - const renameBatchIdSemantic = defaultValue( - options.renameBatchIdSemantic, - false - ); + const { + gltfResource, + typedArray, + releaseGltfJson = false, + asynchronous = true, + incrementallyLoadTextures = true, + upAxis = Axis.Y, + forwardAxis = Axis.Z, + loadAttributesAsTypedArray = false, + loadAttributesFor2D = false, + enablePick = false, + loadIndicesForWireframe = false, + loadPrimitiveOutline = true, + loadForClassification = false, + renameBatchIdSemantic = false, + } = options; //>>includeStart('debug', pragmas.debug); Check.typeOf.object("options.gltfResource", gltfResource); //>>includeEnd('debug'); - baseResource = defined(baseResource) ? baseResource : gltfResource.clone(); + const { baseResource = gltfResource.clone() } = options; this._gltfJson = options.gltfJson; this._gltfResource = gltfResource; @@ -273,6 +264,8 @@ function GltfLoader(options) { this._resourcesLoaded = false; this._texturesLoaded = false; + this._supportedImageFormats = undefined; + // In some cases where geometry post-processing is needed (like generating // outlines) new attributes are added that may have GPU resources attached. // The GltfLoader will own the resources and store them here. @@ -408,20 +401,17 @@ async function loadResources(loader, frameState) { await FeatureDetection.supportsWebP.initialize(); } - const supportedImageFormats = new SupportedImageFormats({ + loader._supportedImageFormats = new SupportedImageFormats({ webp: FeatureDetection.supportsWebP(), basis: frameState.context.supportsBasis, }); - // Parse the glTF which populates the loaders arrays. Loading promises will be created, and will - // resolve once the loaders are ready (i.e. all external resources - // have been fetched and all GPU resources have been created). Loaders that - // create GPU resources need to be processed every frame until they become + // Loaders that create GPU resources need to be processed every frame until they become // ready since the JobScheduler is not able to execute all jobs in a single - // frame. Any promise failures are collected, and will be handled synchronously in process(). Also note that it's fine to call process before a loader is ready - // to process or after it has failed; nothing will happen. - const gltf = loader.gltfJson; - const promise = parse(loader, gltf, supportedImageFormats, frameState); + // frame. Any promise failures are collected, and will be handled synchronously in process(). + // Also note that it's fine to call process before a loader is ready to process or + // after it has failed; nothing will happen. + const promise = parse(loader, frameState); // All resource loaders have been created, so we can begin processing loader._state = GltfLoaderState.PROCESSING; @@ -460,11 +450,9 @@ function handleError(gltfLoader, error) { } function processLoaders(loader, frameState) { - let i; let ready = true; const geometryLoaders = loader._geometryLoaders; - const geometryLoadersLength = geometryLoaders.length; - for (i = 0; i < geometryLoadersLength; ++i) { + for (let i = 0; i < geometryLoaders.length; ++i) { const geometryReady = geometryLoaders[i].process(frameState); if (geometryReady && defined(loader._geometryCallbacks[i])) { loader._geometryCallbacks[i](); @@ -493,8 +481,7 @@ function postProcessGeometry(loader, context) { // Apply post-processing steps on geometry such as // updating attributes for rendering outlines. const loadPlans = loader._primitiveLoadPlans; - const length = loadPlans.length; - for (let i = 0; i < length; i++) { + for (let i = 0; i < loadPlans.length; i++) { const loadPlan = loadPlans[i]; loadPlan.postProcess(context); @@ -520,8 +507,7 @@ function gatherPostProcessBuffers(loader, primitiveLoadPlan) { // to do post-processing, all the attributes are loaded as typed arrays // so if a buffer exists, it was newly generated const attributes = primitive.attributes; - const length = attributes.length; - for (let i = 0; i < length; i++) { + for (let i = 0; i < attributes.length; i++) { const attribute = attributes[i]; if (defined(attribute.buffer)) { buffers.push(attribute.buffer); @@ -583,11 +569,9 @@ GltfLoader.prototype._processTextures = function (frameState) { return false; } - let i; let ready = true; const textureLoaders = this._textureLoaders; - const textureLoadersLength = textureLoaders.length; - for (i = 0; i < textureLoadersLength; ++i) { + for (let i = 0; i < textureLoaders.length; ++i) { const textureReady = textureLoaders[i].process(frameState); if (textureReady && defined(this._textureCallbacks[i])) { this._textureCallbacks[i](); @@ -676,7 +660,6 @@ GltfLoader.prototype.process = function (frameState) { function getVertexBufferLoader( loader, - gltf, accessorId, semantic, draco, @@ -684,6 +667,7 @@ function getVertexBufferLoader( loadTypedArray, frameState ) { + const gltf = loader.gltfJson; const accessor = gltf.accessors[accessorId]; const bufferViewId = accessor.bufferView; @@ -706,7 +690,6 @@ function getVertexBufferLoader( function getIndexBufferLoader( loader, - gltf, accessorId, draco, loadBuffer, @@ -714,7 +697,7 @@ function getIndexBufferLoader( frameState ) { const indexBufferLoader = ResourceCache.getIndexBufferLoader({ - gltf: gltf, + gltf: loader.gltfJson, accessorId: accessorId, gltfResource: loader._gltfResource, baseResource: loader._baseResource, @@ -728,9 +711,9 @@ function getIndexBufferLoader( return indexBufferLoader; } -function getBufferViewLoader(loader, gltf, bufferViewId) { +function getBufferViewLoader(loader, bufferViewId) { const bufferViewLoader = ResourceCache.getBufferViewLoader({ - gltf: gltf, + gltf: loader.gltfJson, bufferViewId: bufferViewId, gltfResource: loader._gltfResource, baseResource: loader._baseResource, @@ -828,35 +811,37 @@ function loadAccessorValues(accessor, typedArray, values, useQuaternion) { async function loadAccessorBufferView( loader, bufferViewLoader, - gltf, accessor, useQuaternion, values ) { + // Save a link to the gltfJson, which is removed after bufferViewLoader.load() + const { gltfJson } = loader; + await bufferViewLoader.load(); if (loader.isDestroyed()) { return; } - const bufferViewTypedArray = bufferViewLoader.typedArray; - const typedArray = getPackedTypedArray(gltf, accessor, bufferViewTypedArray); + const typedArray = getPackedTypedArray( + gltfJson, + accessor, + bufferViewLoader.typedArray + ); useQuaternion = defaultValue(useQuaternion, false); loadAccessorValues(accessor, typedArray, values, useQuaternion); } -function loadAccessor(loader, gltf, accessorId, useQuaternion) { - const accessor = gltf.accessors[accessorId]; - const accessorCount = accessor.count; - const values = new Array(accessorCount); +function loadAccessor(loader, accessor, useQuaternion) { + const values = new Array(accessor.count); const bufferViewId = accessor.bufferView; if (defined(bufferViewId)) { - const bufferViewLoader = getBufferViewLoader(loader, gltf, bufferViewId); + const bufferViewLoader = getBufferViewLoader(loader, bufferViewId); const promise = loadAccessorBufferView( loader, bufferViewLoader, - gltf, accessor, useQuaternion, values @@ -1145,7 +1130,6 @@ function finalizeAttribute( function loadAttribute( loader, - gltf, accessorId, semanticInfo, draco, @@ -1153,6 +1137,7 @@ function loadAttribute( loadTypedArray, frameState ) { + const gltf = loader.gltfJson; const accessor = gltf.accessors[accessorId]; const bufferViewId = accessor.bufferView; @@ -1179,7 +1164,6 @@ function loadAttribute( const vertexBufferLoader = getVertexBufferLoader( loader, - gltf, accessorId, gltfSemantic, draco, @@ -1224,7 +1208,6 @@ function loadAttribute( function loadVertexAttribute( loader, - gltf, accessorId, semanticInfo, draco, @@ -1271,7 +1254,6 @@ function loadVertexAttribute( const attribute = loadAttribute( loader, - gltf, accessorId, semanticInfo, draco, @@ -1289,17 +1271,17 @@ function loadVertexAttribute( function loadInstancedAttribute( loader, - gltf, accessorId, attributes, gltfSemantic, frameState ) { + const accessors = loader.gltfJson.accessors; const hasRotation = defined(attributes.ROTATION); const hasTranslationMinMax = defined(attributes.TRANSLATION) && - defined(gltf.accessors[attributes.TRANSLATION].min) && - defined(gltf.accessors[attributes.TRANSLATION].max); + defined(accessors[attributes.TRANSLATION].min) && + defined(accessors[attributes.TRANSLATION].max); const semanticInfo = getSemanticInfo( loader, @@ -1344,7 +1326,6 @@ function loadInstancedAttribute( // Don't pass in draco object since instanced attributes can't be draco compressed return loadAttribute( loader, - gltf, accessorId, semanticInfo, undefined, @@ -1356,14 +1337,13 @@ function loadInstancedAttribute( function loadIndices( loader, - gltf, accessorId, draco, hasFeatureIds, needsPostProcessing, frameState ) { - const accessor = gltf.accessors[accessorId]; + const accessor = loader.gltfJson.accessors[accessorId]; const bufferViewId = accessor.bufferView; if (!defined(draco) && !defined(bufferViewId)) { @@ -1400,7 +1380,6 @@ function loadIndices( const indexBufferLoader = getIndexBufferLoader( loader, - gltf, accessorId, draco, loadBuffer, @@ -1428,18 +1407,12 @@ function loadIndices( return indicesPlan; } -function loadTexture( - loader, - gltf, - textureInfo, - supportedImageFormats, - frameState, - samplerOverride -) { +function loadTexture(loader, textureInfo, frameState, samplerOverride) { + const gltf = loader.gltfJson; const imageId = GltfLoaderUtil.getImageIdFromTexture({ gltf: gltf, textureId: textureInfo.index, - supportedImageFormats: supportedImageFormats, + supportedImageFormats: loader._supportedImageFormats, }); if (!defined(imageId)) { @@ -1451,7 +1424,7 @@ function loadTexture( textureInfo: textureInfo, gltfResource: loader._gltfResource, baseResource: loader._baseResource, - supportedImageFormats: supportedImageFormats, + supportedImageFormats: loader._supportedImageFormats, frameState: frameState, asynchronous: loader._asynchronous, }); @@ -1491,13 +1464,177 @@ function loadTexture( return textureReader; } -function loadMaterial( - loader, - gltf, - gltfMaterial, - supportedImageFormats, - frameState -) { +/** + * Load textures and parse factors for the KHR_materials_pbrSpecularGlossiness extension + * @param {GltfLoader} loader + * @param {object} specularGlossinessInfo The contents of the KHR_materials_pbrSpecularGlossiness extension in the parsed glTF JSON + * @param {FrameState} frameState + * @returns {ModelComponents.SpecularGlossiness} + * @private + */ +function loadSpecularGlossiness(loader, specularGlossinessInfo, frameState) { + const { + diffuseTexture, + specularGlossinessTexture, + diffuseFactor, + specularFactor, + glossinessFactor, + } = specularGlossinessInfo; + + const specularGlossiness = new SpecularGlossiness(); + if (defined(diffuseTexture)) { + specularGlossiness.diffuseTexture = loadTexture( + loader, + diffuseTexture, + frameState + ); + } + if (defined(specularGlossinessTexture)) { + specularGlossiness.specularGlossinessTexture = loadTexture( + loader, + specularGlossinessTexture, + frameState + ); + } + specularGlossiness.diffuseFactor = fromArray(Cartesian4, diffuseFactor); + specularGlossiness.specularFactor = fromArray(Cartesian3, specularFactor); + specularGlossiness.glossinessFactor = glossinessFactor; + + return specularGlossiness; +} + +/** + * Load textures and parse factors for a metallic-roughness PBR model in a glTF material + * @param {GltfLoader} loader + * @param {object} metallicRoughnessInfo The contents of a pbrMetallicRoughness property in the parsed glTF JSON + * @param {FrameState} frameState + * @returns {ModelComponents.MetallicRoughness} + * @private + */ +function loadMetallicRoughness(loader, metallicRoughnessInfo, frameState) { + const { + baseColorTexture, + metallicRoughnessTexture, + baseColorFactor, + metallicFactor, + roughnessFactor, + } = metallicRoughnessInfo; + + const metallicRoughness = new MetallicRoughness(); + if (defined(baseColorTexture)) { + metallicRoughness.baseColorTexture = loadTexture( + loader, + baseColorTexture, + frameState + ); + } + if (defined(metallicRoughnessTexture)) { + metallicRoughness.metallicRoughnessTexture = loadTexture( + loader, + metallicRoughnessTexture, + frameState + ); + } + metallicRoughness.baseColorFactor = fromArray(Cartesian4, baseColorFactor); + metallicRoughness.metallicFactor = metallicFactor; + metallicRoughness.roughnessFactor = roughnessFactor; + + return metallicRoughness; +} + +function loadSpecular(loader, specularInfo, frameState) { + const { + specularFactor, + specularTexture, + specularColorFactor, + specularColorTexture, + } = specularInfo; + + const specular = new Specular(); + if (defined(specularTexture)) { + specular.specularTexture = loadTexture(loader, specularTexture, frameState); + } + if (defined(specularColorTexture)) { + specular.specularColorTexture = loadTexture( + loader, + specularColorTexture, + frameState + ); + } + specular.specularFactor = specularFactor; + specular.specularColorFactor = fromArray(Cartesian3, specularColorFactor); + + return specular; +} + +function loadAnisotropy(loader, anisotropyInfo, frameState) { + const { + anisotropyStrength = Anisotropy.DEFAULT_ANISOTROPY_STRENGTH, + anisotropyRotation = Anisotropy.DEFAULT_ANISOTROPY_ROTATION, + anisotropyTexture, + } = anisotropyInfo; + + const anisotropy = new Anisotropy(); + if (defined(anisotropyTexture)) { + anisotropy.anisotropyTexture = loadTexture( + loader, + anisotropyTexture, + frameState + ); + } + anisotropy.anisotropyStrength = anisotropyStrength; + anisotropy.anisotropyRotation = anisotropyRotation; + + return anisotropy; +} + +function loadClearcoat(loader, clearcoatInfo, frameState) { + const { + clearcoatFactor = Clearcoat.DEFAULT_CLEARCOAT_FACTOR, + clearcoatTexture, + clearcoatRoughnessFactor = Clearcoat.DEFAULT_CLEARCOAT_ROUGHNESS_FACTOR, + clearcoatRoughnessTexture, + clearcoatNormalTexture, + } = clearcoatInfo; + + const clearcoat = new Clearcoat(); + if (defined(clearcoatTexture)) { + clearcoat.clearcoatTexture = loadTexture( + loader, + clearcoatTexture, + frameState + ); + } + if (defined(clearcoatRoughnessTexture)) { + clearcoat.clearcoatRoughnessTexture = loadTexture( + loader, + clearcoatRoughnessTexture, + frameState + ); + } + if (defined(clearcoatNormalTexture)) { + clearcoat.clearcoatNormalTexture = loadTexture( + loader, + clearcoatNormalTexture, + frameState + ); + } + clearcoat.clearcoatFactor = clearcoatFactor; + clearcoat.clearcoatRoughnessFactor = clearcoatRoughnessFactor; + + return clearcoat; +} + +/** + * Load textures and parse factors and flags for a glTF material + * + * @param {GltfLoader} loader + * @param {object} gltfMaterial An entry from the .materials array in the glTF JSON + * @param {FrameState} frameState + * @returns {ModelComponents.Material} + * @private + */ +function loadMaterial(loader, gltfMaterial, frameState) { const material = new Material(); const extensions = defaultValue( @@ -1505,82 +1642,43 @@ function loadMaterial( defaultValue.EMPTY_OBJECT ); const pbrSpecularGlossiness = extensions.KHR_materials_pbrSpecularGlossiness; + const pbrSpecular = extensions.KHR_materials_specular; + const pbrAnisotropy = extensions.KHR_materials_anisotropy; + const pbrClearcoat = extensions.KHR_materials_clearcoat; const pbrMetallicRoughness = gltfMaterial.pbrMetallicRoughness; material.unlit = defined(extensions.KHR_materials_unlit); if (defined(pbrSpecularGlossiness)) { - const specularGlossiness = new SpecularGlossiness(); - material.specularGlossiness = specularGlossiness; - - if (defined(pbrSpecularGlossiness.diffuseTexture)) { - specularGlossiness.diffuseTexture = loadTexture( + material.specularGlossiness = loadSpecularGlossiness( + loader, + pbrSpecularGlossiness, + frameState + ); + } else { + if (defined(pbrMetallicRoughness)) { + material.metallicRoughness = loadMetallicRoughness( loader, - gltf, - pbrSpecularGlossiness.diffuseTexture, - supportedImageFormats, + pbrMetallicRoughness, frameState ); } - if (defined(pbrSpecularGlossiness.specularGlossinessTexture)) { - if (defined(pbrSpecularGlossiness.specularGlossinessTexture)) { - specularGlossiness.specularGlossinessTexture = loadTexture( - loader, - gltf, - pbrSpecularGlossiness.specularGlossinessTexture, - supportedImageFormats, - frameState - ); - } + if (defined(pbrSpecular) && !material.unlit) { + material.specular = loadSpecular(loader, pbrSpecular, frameState); } - specularGlossiness.diffuseFactor = fromArray( - Cartesian4, - pbrSpecularGlossiness.diffuseFactor - ); - specularGlossiness.specularFactor = fromArray( - Cartesian3, - pbrSpecularGlossiness.specularFactor - ); - specularGlossiness.glossinessFactor = - pbrSpecularGlossiness.glossinessFactor; - material.pbrSpecularGlossiness = pbrSpecularGlossiness; - } else if (defined(pbrMetallicRoughness)) { - const metallicRoughness = new MetallicRoughness(); - - if (defined(pbrMetallicRoughness.baseColorTexture)) { - metallicRoughness.baseColorTexture = loadTexture( - loader, - gltf, - pbrMetallicRoughness.baseColorTexture, - supportedImageFormats, - frameState - ); + if (defined(pbrAnisotropy) && !material.unlit) { + material.anisotropy = loadAnisotropy(loader, pbrAnisotropy, frameState); } - if (defined(pbrMetallicRoughness.metallicRoughnessTexture)) { - metallicRoughness.metallicRoughnessTexture = loadTexture( - loader, - gltf, - pbrMetallicRoughness.metallicRoughnessTexture, - supportedImageFormats, - frameState - ); + if (defined(pbrClearcoat) && !material.unlit) { + material.clearcoat = loadClearcoat(loader, pbrClearcoat, frameState); } - metallicRoughness.baseColorFactor = fromArray( - Cartesian4, - pbrMetallicRoughness.baseColorFactor - ); - metallicRoughness.metallicFactor = pbrMetallicRoughness.metallicFactor; - metallicRoughness.roughnessFactor = pbrMetallicRoughness.roughnessFactor; - material.metallicRoughness = metallicRoughness; } // Top level textures if (defined(gltfMaterial.emissiveTexture)) { material.emissiveTexture = loadTexture( loader, - gltf, gltfMaterial.emissiveTexture, - supportedImageFormats, frameState ); } @@ -1588,18 +1686,14 @@ function loadMaterial( if (defined(gltfMaterial.normalTexture) && !loader._loadForClassification) { material.normalTexture = loadTexture( loader, - gltf, gltfMaterial.normalTexture, - supportedImageFormats, frameState ); } if (defined(gltfMaterial.occlusionTexture)) { material.occlusionTexture = loadTexture( loader, - gltf, gltfMaterial.occlusionTexture, - supportedImageFormats, frameState ); } @@ -1679,9 +1773,7 @@ function loadFeatureIdImplicitRangeLegacy( // for EXT_mesh_features function loadFeatureIdTexture( loader, - gltf, gltfFeatureIdTexture, - supportedImageFormats, frameState, positionalLabel ) { @@ -1696,9 +1788,7 @@ function loadFeatureIdTexture( const textureInfo = gltfFeatureIdTexture.texture; featureIdTexture.textureReader = loadTexture( loader, - gltf, textureInfo, - supportedImageFormats, frameState, Sampler.NEAREST // Feature ID textures require nearest sampling ); @@ -1720,10 +1810,8 @@ function loadFeatureIdTexture( // for backwards compatibility with EXT_feature_metadata function loadFeatureIdTextureLegacy( loader, - gltf, gltfFeatureIdTexture, featureTableId, - supportedImageFormats, frameState, featureCount, positionalLabel @@ -1735,9 +1823,7 @@ function loadFeatureIdTextureLegacy( featureIdTexture.propertyTableId = featureTableId; featureIdTexture.textureReader = loadTexture( loader, - gltf, textureInfo, - supportedImageFormats, frameState, Sampler.NEAREST // Feature ID textures require nearest sampling ); @@ -1750,7 +1836,6 @@ function loadFeatureIdTextureLegacy( function loadMorphTarget( loader, - gltf, target, needsPostProcessing, primitiveLoadPlan, @@ -1763,44 +1848,46 @@ function loadMorphTarget( const hasInstances = false; for (const semantic in target) { - if (target.hasOwnProperty(semantic)) { - const accessorId = target[semantic]; + if (!target.hasOwnProperty(semantic)) { + continue; + } + const accessorId = target[semantic]; - const semanticInfo = getSemanticInfo( - loader, - VertexAttributeSemantic, - semantic - ); + const semanticInfo = getSemanticInfo( + loader, + VertexAttributeSemantic, + semantic + ); - const attributePlan = loadVertexAttribute( - loader, - gltf, - accessorId, - semanticInfo, - draco, - hasInstances, - needsPostProcessing, - frameState - ); - morphTarget.attributes.push(attributePlan.attribute); + const attributePlan = loadVertexAttribute( + loader, + accessorId, + semanticInfo, + draco, + hasInstances, + needsPostProcessing, + frameState + ); + morphTarget.attributes.push(attributePlan.attribute); - // The load plan doesn't need to distinguish morph target attributes from - // regular attributes - primitiveLoadPlan.attributePlans.push(attributePlan); - } + // The load plan doesn't need to distinguish morph target attributes from + // regular attributes + primitiveLoadPlan.attributePlans.push(attributePlan); } return morphTarget; } -function loadPrimitive( - loader, - gltf, - gltfPrimitive, - hasInstances, - supportedImageFormats, - frameState -) { +/** + * Load resources associated with a mesh primitive for a glTF node + * @param {GltfLoader} loader + * @param {object} gltfPrimitive One of the primitives in a mesh + * @param {boolean} hasInstances True if the node using this mesh has instances + * @param {FrameState} frameState + * @returns {ModelComponents.Primitive} + * @private + */ +function loadPrimitive(loader, gltfPrimitive, hasInstances, frameState) { const primitive = new Primitive(); const primitivePlan = new PrimitiveLoadPlan(primitive); loader._primitiveLoadPlans.push(primitivePlan); @@ -1809,9 +1896,7 @@ function loadPrimitive( if (defined(materialId)) { primitive.material = loadMaterial( loader, - gltf, - gltf.materials[materialId], - supportedImageFormats, + loader.gltfJson.materials[materialId], frameState ); } @@ -1828,7 +1913,6 @@ function loadPrimitive( primitivePlan.needsOutlines = true; primitivePlan.outlineIndices = loadPrimitiveOutline( loader, - gltf, outlineExtension, primitivePlan ); @@ -1841,52 +1925,47 @@ function loadPrimitive( const attributes = gltfPrimitive.attributes; if (defined(attributes)) { for (const semantic in attributes) { - if (attributes.hasOwnProperty(semantic)) { - const accessorId = attributes[semantic]; - const semanticInfo = getSemanticInfo( - loader, - VertexAttributeSemantic, - semantic - ); + if (!attributes.hasOwnProperty(semantic)) { + continue; + } + const accessorId = attributes[semantic]; + const semanticInfo = getSemanticInfo( + loader, + VertexAttributeSemantic, + semantic + ); - const modelSemantic = semanticInfo.modelSemantic; - if ( - loadForClassification && - !isClassificationAttribute(modelSemantic) - ) { - continue; - } + const modelSemantic = semanticInfo.modelSemantic; + if (loadForClassification && !isClassificationAttribute(modelSemantic)) { + continue; + } - if (modelSemantic === VertexAttributeSemantic.FEATURE_ID) { - hasFeatureIds = true; - } + if (modelSemantic === VertexAttributeSemantic.FEATURE_ID) { + hasFeatureIds = true; + } - const attributePlan = loadVertexAttribute( - loader, - gltf, - accessorId, - semanticInfo, - draco, - hasInstances, - needsPostProcessing, - frameState - ); + const attributePlan = loadVertexAttribute( + loader, + accessorId, + semanticInfo, + draco, + hasInstances, + needsPostProcessing, + frameState + ); - primitivePlan.attributePlans.push(attributePlan); - primitive.attributes.push(attributePlan.attribute); - } + primitivePlan.attributePlans.push(attributePlan); + primitive.attributes.push(attributePlan.attribute); } } const targets = gltfPrimitive.targets; // Morph targets are disabled for classification models. if (defined(targets) && !loadForClassification) { - const targetsLength = targets.length; - for (let i = 0; i < targetsLength; ++i) { + for (let i = 0; i < targets.length; ++i) { primitive.morphTargets.push( loadMorphTarget( loader, - gltf, targets[i], needsPostProcessing, primitivePlan, @@ -1900,7 +1979,6 @@ function loadPrimitive( if (defined(indices)) { const indicesPlan = loadIndices( loader, - gltf, indices, draco, hasFeatureIds, @@ -1925,21 +2003,12 @@ function loadPrimitive( // Load feature Ids if (defined(meshFeatures)) { - loadPrimitiveFeatures( - loader, - gltf, - primitive, - meshFeatures, - supportedImageFormats, - frameState - ); + loadPrimitiveFeatures(loader, primitive, meshFeatures, frameState); } else if (hasFeatureMetadataLegacy) { loadPrimitiveFeaturesLegacy( loader, - gltf, primitive, featureMetadataLegacy, - supportedImageFormats, frameState ); } @@ -1962,19 +2031,18 @@ function loadPrimitive( return primitive; } -function loadPrimitiveOutline(loader, gltf, outlineExtension) { +function loadPrimitiveOutline(loader, outlineExtension) { const accessorId = outlineExtension.indices; + const accessor = loader.gltfJson.accessors[accessorId]; const useQuaternion = false; - return loadAccessor(loader, gltf, accessorId, useQuaternion); + return loadAccessor(loader, accessor, useQuaternion); } // For EXT_mesh_features function loadPrimitiveFeatures( loader, - gltf, primitive, meshFeaturesExtension, - supportedImageFormats, frameState ) { let featureIdsArray; @@ -1995,9 +2063,7 @@ function loadPrimitiveFeatures( if (defined(featureIds.texture)) { featureIdComponent = loadFeatureIdTexture( loader, - gltf, featureIds, - supportedImageFormats, frameState, label ); @@ -2016,22 +2082,19 @@ function loadPrimitiveFeatures( // For EXT_feature_metadata function loadPrimitiveFeaturesLegacy( loader, - gltf, primitive, metadataExtension, - supportedImageFormats, frameState ) { // For looking up the featureCount for each set of feature IDs - const featureTables = gltf.extensions.EXT_feature_metadata.featureTables; + const { featureTables } = loader.gltfJson.extensions.EXT_feature_metadata; let nextFeatureIdIndex = 0; // Feature ID Attributes const featureIdAttributes = metadataExtension.featureIdAttributes; if (defined(featureIdAttributes)) { - const featureIdAttributesLength = featureIdAttributes.length; - for (let i = 0; i < featureIdAttributesLength; ++i) { + for (let i = 0; i < featureIdAttributes.length; ++i) { const featureIdAttribute = featureIdAttributes[i]; const featureTableId = featureIdAttribute.featureTable; const propertyTableId = loader._sortedPropertyTableIds.indexOf( @@ -2064,8 +2127,7 @@ function loadPrimitiveFeaturesLegacy( // Feature ID Textures const featureIdTextures = metadataExtension.featureIdTextures; if (defined(featureIdTextures)) { - const featureIdTexturesLength = featureIdTextures.length; - for (let i = 0; i < featureIdTexturesLength; ++i) { + for (let i = 0; i < featureIdTextures.length; ++i) { const featureIdTexture = featureIdTextures[i]; const featureTableId = featureIdTexture.featureTable; const propertyTableId = loader._sortedPropertyTableIds.indexOf( @@ -2077,10 +2139,8 @@ function loadPrimitiveFeaturesLegacy( const featureIdComponent = loadFeatureIdTextureLegacy( loader, - gltf, featureIdTexture, propertyTableId, - supportedImageFormats, frameState, featureCount, featureIdLabel @@ -2124,26 +2184,26 @@ function loadPrimitiveMetadataLegacy(loader, primitive, metadataExtension) { } } -function loadInstances(loader, gltf, nodeExtensions, frameState) { +function loadInstances(loader, nodeExtensions, frameState) { const instancingExtension = nodeExtensions.EXT_mesh_gpu_instancing; const instances = new Instances(); const attributes = instancingExtension.attributes; if (defined(attributes)) { for (const semantic in attributes) { - if (attributes.hasOwnProperty(semantic)) { - const accessorId = attributes[semantic]; - instances.attributes.push( - loadInstancedAttribute( - loader, - gltf, - accessorId, - attributes, - semantic, - frameState - ) - ); + if (!attributes.hasOwnProperty(semantic)) { + continue; } + const accessorId = attributes[semantic]; + instances.attributes.push( + loadInstancedAttribute( + loader, + accessorId, + attributes, + semantic, + frameState + ) + ); } } @@ -2158,7 +2218,7 @@ function loadInstances(loader, gltf, nodeExtensions, frameState) { loadInstanceFeatures(instances, instanceFeatures); } else if (defined(featureMetadataLegacy)) { loadInstanceFeaturesLegacy( - gltf, + loader.gltfJson, instances, featureMetadataLegacy, loader._sortedPropertyTableIds @@ -2202,8 +2262,7 @@ function loadInstanceFeaturesLegacy( const featureIdAttributes = metadataExtension.featureIdAttributes; if (defined(featureIdAttributes)) { - const featureIdAttributesLength = featureIdAttributes.length; - for (let i = 0; i < featureIdAttributesLength; ++i) { + for (let i = 0; i < featureIdAttributes.length; ++i) { const featureIdAttribute = featureIdAttributes[i]; const featureTableId = featureIdAttribute.featureTable; const propertyTableId = sortedPropertyTableIds.indexOf(featureTableId); @@ -2231,7 +2290,15 @@ function loadInstanceFeaturesLegacy( } } -function loadNode(loader, gltf, gltfNode, supportedImageFormats, frameState) { +/** + * Load resources associated with one node from a glTF JSON + * @param {GltfLoader} loader + * @param {object} gltfNode An entry from the .nodes array in the glTF JSON + * @param {FrameState} frameState + * @returns {ModelComponents.Node} + * @private + */ +function loadNode(loader, gltfNode, frameState) { const node = new Node(); node.name = gltfNode.name; @@ -2254,7 +2321,7 @@ function loadNode(loader, gltf, gltfNode, supportedImageFormats, frameState) { "Models with the EXT_mesh_gpu_instancing extension cannot be used for classification." ); } - node.instances = loadInstances(loader, gltf, nodeExtensions, frameState); + node.instances = loadInstances(loader, nodeExtensions, frameState); } if (defined(articulationsExtension)) { @@ -2263,17 +2330,14 @@ function loadNode(loader, gltf, gltfNode, supportedImageFormats, frameState) { const meshId = gltfNode.mesh; if (defined(meshId)) { - const mesh = gltf.meshes[meshId]; + const mesh = loader.gltfJson.meshes[meshId]; const primitives = mesh.primitives; - const primitivesLength = primitives.length; - for (let i = 0; i < primitivesLength; ++i) { + for (let i = 0; i < primitives.length; ++i) { node.primitives.push( loadPrimitive( loader, - gltf, primitives[i], defined(node.instances), - supportedImageFormats, frameState ) ); @@ -2283,120 +2347,105 @@ function loadNode(loader, gltf, gltfNode, supportedImageFormats, frameState) { // by the mesh. If both are undefined, it will default to an array of zero weights. const morphWeights = defaultValue(gltfNode.weights, mesh.weights); const targets = node.primitives[0].morphTargets; - const targetsLength = targets.length; // Since meshes are not stored as separate components, the mesh weights will still // be stored at the node level. node.morphWeights = defined(morphWeights) ? morphWeights.slice() - : new Array(targetsLength).fill(0.0); + : new Array(targets.length).fill(0.0); } return node; } -function loadNodes(loader, gltf, supportedImageFormats, frameState) { - if (!defined(gltf.nodes)) { +/** + * Load resources associated with the nodes in a glTF JSON + * @param {GltfLoader} loader + * @param {FrameState} frameState + * @returns {ModelComponents.Node[]} + * @private + */ +function loadNodes(loader, frameState) { + const nodeJsons = loader.gltfJson.nodes; + if (!defined(nodeJsons)) { return []; } - let i; - let j; - - const nodesLength = gltf.nodes.length; - const nodes = new Array(nodesLength); - for (i = 0; i < nodesLength; ++i) { - const node = loadNode( - loader, - gltf, - gltf.nodes[i], - supportedImageFormats, - frameState - ); + const loadedNodes = nodeJsons.map(function (nodeJson, i) { + const node = loadNode(loader, nodeJson, frameState); node.index = i; - nodes[i] = node; - } + return node; + }); - for (i = 0; i < nodesLength; ++i) { - const childrenNodeIds = gltf.nodes[i].children; + for (let i = 0; i < loadedNodes.length; ++i) { + const childrenNodeIds = nodeJsons[i].children; if (defined(childrenNodeIds)) { - const childrenLength = childrenNodeIds.length; - for (j = 0; j < childrenLength; ++j) { - nodes[i].children.push(nodes[childrenNodeIds[j]]); + for (let j = 0; j < childrenNodeIds.length; ++j) { + loadedNodes[i].children.push(loadedNodes[childrenNodeIds[j]]); } } } - return nodes; + return loadedNodes; } -function loadSkin(loader, gltf, gltfSkin, nodes) { +function loadSkin(loader, gltfSkin, nodes) { const skin = new Skin(); const jointIds = gltfSkin.joints; - const jointsLength = jointIds.length; - const joints = new Array(jointsLength); - for (let i = 0; i < jointsLength; ++i) { - joints[i] = nodes[jointIds[i]]; - } - skin.joints = joints; + skin.joints = jointIds.map((jointId) => nodes[jointId]); const inverseBindMatricesAccessorId = gltfSkin.inverseBindMatrices; if (defined(inverseBindMatricesAccessorId)) { - skin.inverseBindMatrices = loadAccessor( - loader, - gltf, - inverseBindMatricesAccessorId - ); + const accessor = loader.gltfJson.accessors[inverseBindMatricesAccessorId]; + skin.inverseBindMatrices = loadAccessor(loader, accessor); } else { - skin.inverseBindMatrices = new Array(jointsLength).fill(Matrix4.IDENTITY); + skin.inverseBindMatrices = new Array(jointIds.length).fill( + Matrix4.IDENTITY + ); } return skin; } -function loadSkins(loader, gltf, nodes) { - const gltfSkins = gltf.skins; +function loadSkins(loader, nodes) { + const skinJsons = loader.gltfJson.skins; // Skins are disabled for classification models. - if (loader._loadForClassification || !defined(gltfSkins)) { + if (loader._loadForClassification || !defined(skinJsons)) { return []; } - const skinsLength = gltf.skins.length; - const skins = new Array(skinsLength); - for (let i = 0; i < skinsLength; ++i) { - const skin = loadSkin(loader, gltf, gltf.skins[i], nodes); + const loadedSkins = skinJsons.map(function (skinJson, i) { + const skin = loadSkin(loader, skinJson, nodes); skin.index = i; - skins[i] = skin; - } + return skin; + }); - const nodesLength = nodes.length; - for (let i = 0; i < nodesLength; ++i) { - const skinId = gltf.nodes[i].skin; + const nodeJsons = loader.gltfJson.nodes; + for (let i = 0; i < nodes.length; ++i) { + const skinId = nodeJsons[i].skin; if (defined(skinId)) { - nodes[i].skin = skins[skinId]; + nodes[i].skin = loadedSkins[skinId]; } } - return skins; + return loadedSkins; } async function loadStructuralMetadata( loader, - gltf, extension, extensionLegacy, - supportedImageFormats, frameState ) { const structuralMetadataLoader = new GltfStructuralMetadataLoader({ - gltf: gltf, + gltf: loader.gltfJson, extension: extension, extensionLegacy: extensionLegacy, gltfResource: loader._gltfResource, baseResource: loader._baseResource, - supportedImageFormats: supportedImageFormats, + supportedImageFormats: loader._supportedImageFormats, frameState: frameState, asynchronous: loader._asynchronous, }); @@ -2404,11 +2453,12 @@ async function loadStructuralMetadata( return structuralMetadataLoader.load(); } -function loadAnimationSampler(loader, gltf, gltfSampler) { +function loadAnimationSampler(loader, gltfSampler) { const animationSampler = new AnimationSampler(); + const accessors = loader.gltfJson.accessors; - const inputAccessorId = gltfSampler.input; - animationSampler.input = loadAccessor(loader, gltf, inputAccessorId); + const inputAccessor = accessors[gltfSampler.input]; + animationSampler.input = loadAccessor(loader, inputAccessor); const gltfInterpolation = gltfSampler.interpolation; animationSampler.interpolation = defaultValue( @@ -2416,8 +2466,8 @@ function loadAnimationSampler(loader, gltf, gltfSampler) { InterpolationType.LINEAR ); - const outputAccessorId = gltfSampler.output; - animationSampler.output = loadAccessor(loader, gltf, outputAccessorId, true); + const outputAccessor = accessors[gltfSampler.output]; + animationSampler.output = loadAccessor(loader, outputAccessor, true); return animationSampler; } @@ -2450,29 +2500,19 @@ function loadAnimationChannel(gltfChannel, samplers, nodes) { return animationChannel; } -function loadAnimation(loader, gltf, gltfAnimation, nodes) { - let i; - +function loadAnimation(loader, animationJson, nodes) { const animation = new Animation(); - animation.name = gltfAnimation.name; + animation.name = animationJson.name; - const gltfSamplers = gltfAnimation.samplers; - const samplersLength = gltfSamplers.length; - - const samplers = new Array(samplersLength); - for (i = 0; i < samplersLength; i++) { - const sampler = loadAnimationSampler(loader, gltf, gltfSamplers[i]); + const samplers = animationJson.samplers.map(function (samplerJson, i) { + const sampler = loadAnimationSampler(loader, samplerJson); sampler.index = i; - samplers[i] = sampler; - } - - const gltfChannels = gltfAnimation.channels; - const channelsLength = gltfChannels.length; + return sampler; + }); - const channels = new Array(channelsLength); - for (i = 0; i < channelsLength; i++) { - channels[i] = loadAnimationChannel(gltfChannels[i], samplers, nodes); - } + const channels = animationJson.channels.map(function (channelJson) { + return loadAnimationChannel(channelJson, samplers, nodes); + }); animation.samplers = samplers; animation.channels = channels; @@ -2480,21 +2520,19 @@ function loadAnimation(loader, gltf, gltfAnimation, nodes) { return animation; } -function loadAnimations(loader, gltf, nodes) { - const gltfAnimations = gltf.animations; +function loadAnimations(loader, nodes) { + const animationJsons = loader.gltfJson.animations; // Animations are disabled for classification models. - if (loader._loadForClassification || !defined(gltfAnimations)) { + if (loader._loadForClassification || !defined(animationJsons)) { return []; } - const animationsLength = gltf.animations.length; - const animations = new Array(animationsLength); - for (let i = 0; i < animationsLength; ++i) { - const animation = loadAnimation(loader, gltf, gltf.animations[i], nodes); + const animations = animationJsons.map(function (animationJson, i) { + const animation = loadAnimation(loader, animationJson, nodes); animation.index = i; - animations[i] = animation; - } + return animation; + }); return animations; } @@ -2513,45 +2551,20 @@ function loadArticulationStage(gltfStage) { return stage; } -function loadArticulation(gltfArticulation) { +function loadArticulation(articulationJson) { const articulation = new Articulation(); - articulation.name = gltfArticulation.name; - - const gltfStages = gltfArticulation.stages; - const gltfStagesLength = gltfStages.length; - - const stages = new Array(gltfStagesLength); - for (let i = 0; i < gltfStagesLength; i++) { - const stage = loadArticulationStage(gltfStages[i]); - stages[i] = stage; - } - - articulation.stages = stages; - + articulation.name = articulationJson.name; + articulation.stages = articulationJson.stages.map(loadArticulationStage); return articulation; } function loadArticulations(gltf) { const extensions = defaultValue(gltf.extensions, defaultValue.EMPTY_OBJECT); - const articulationsExtension = extensions.AGI_articulations; - - if (!defined(articulationsExtension)) { + const articulationJsons = extensions.AGI_articulations?.articulations; + if (!defined(articulationJsons)) { return []; } - - const gltfArticulations = articulationsExtension.articulations; - if (!defined(gltfArticulations)) { - return []; - } - - const gltfArticulationsLength = gltfArticulations.length; - const articulations = new Array(gltfArticulationsLength); - for (let i = 0; i < gltfArticulationsLength; i++) { - const articulation = loadArticulation(gltfArticulations[i]); - articulations[i] = articulation; - } - - return articulations; + return articulationJsons.map(loadArticulation); } function getSceneNodeIds(gltf) { @@ -2575,7 +2588,23 @@ function loadScene(gltf, nodes) { const scratchCenter = new Cartesian3(); -function parse(loader, gltf, supportedImageFormats, frameState) { +/** + * Parse the glTF which populates the loaders arrays. Loading promises will be created, and will + * resolve once the loaders are ready (i.e. all external resources + * have been fetched and all GPU resources have been created). Loaders that + * create GPU resources need to be processed every frame until they become + * ready since the JobScheduler is not able to execute all jobs in a single + * frame. Any promise failures are collected, and will be handled synchronously in process(). + * Also note that it's fine to call process before a loader is ready to process or + * after it has failed; nothing will happen. + * + * @param {GltfLoader} loader + * @param {FrameState} frameState + * @returns {Promise} A Promise that resolves when all loaders are ready + * @private + */ +function parse(loader, frameState) { + const gltf = loader.gltfJson; const extensions = defaultValue(gltf.extensions, defaultValue.EMPTY_OBJECT); const structuralMetadataExtension = extensions.EXT_structural_metadata; const featureMetadataExtensionLegacy = extensions.EXT_feature_metadata; @@ -2598,9 +2627,9 @@ function parse(loader, gltf, supportedImageFormats, frameState) { loader._sortedFeatureTextureIds = Object.keys(allFeatureTextureIds).sort(); } - const nodes = loadNodes(loader, gltf, supportedImageFormats, frameState); - const skins = loadSkins(loader, gltf, nodes); - const animations = loadAnimations(loader, gltf, nodes); + const nodes = loadNodes(loader, frameState); + const skins = loadSkins(loader, nodes); + const animations = loadAnimations(loader, nodes); const articulations = loadArticulations(gltf); const scene = loadScene(gltf, nodes); @@ -2645,10 +2674,8 @@ function parse(loader, gltf, supportedImageFormats, frameState) { ) { const promise = loadStructuralMetadata( loader, - gltf, structuralMetadataExtension, featureMetadataExtensionLegacy, - supportedImageFormats, frameState ); loader._loaderPromises.push(promise); @@ -2669,8 +2696,7 @@ function parse(loader, gltf, supportedImageFormats, frameState) { function unloadTextures(loader) { const textureLoaders = loader._textureLoaders; - const textureLoadersLength = textureLoaders.length; - for (let i = 0; i < textureLoadersLength; ++i) { + for (let i = 0; i < textureLoaders.length; ++i) { textureLoaders[i] = !textureLoaders[i].isDestroyed() && ResourceCache.unload(textureLoaders[i]); @@ -2680,8 +2706,7 @@ function unloadTextures(loader) { function unloadBufferViewLoaders(loader) { const bufferViewLoaders = loader._bufferViewLoaders; - const bufferViewLoadersLength = bufferViewLoaders.length; - for (let i = 0; i < bufferViewLoadersLength; ++i) { + for (let i = 0; i < bufferViewLoaders.length; ++i) { bufferViewLoaders[i] = !bufferViewLoaders[i].isDestroyed() && ResourceCache.unload(bufferViewLoaders[i]); @@ -2691,8 +2716,7 @@ function unloadBufferViewLoaders(loader) { function unloadGeometry(loader) { const geometryLoaders = loader._geometryLoaders; - const geometryLoadersLength = geometryLoaders.length; - for (let i = 0; i < geometryLoadersLength; ++i) { + for (let i = 0; i < geometryLoaders.length; ++i) { geometryLoaders[i] = !geometryLoaders[i].isDestroyed() && ResourceCache.unload(geometryLoaders[i]); @@ -2702,8 +2726,7 @@ function unloadGeometry(loader) { function unloadGeneratedAttributes(loader) { const buffers = loader._postProcessBuffers; - const length = buffers.length; - for (let i = 0; i < length; i++) { + for (let i = 0; i < buffers.length; i++) { const buffer = buffers[i]; if (!buffer.isDestroyed()) { buffer.destroy(); diff --git a/packages/engine/Source/Scene/GltfLoaderUtil.js b/packages/engine/Source/Scene/GltfLoaderUtil.js index ac24f378a55..76f0a5c3b17 100644 --- a/packages/engine/Source/Scene/GltfLoaderUtil.js +++ b/packages/engine/Source/Scene/GltfLoaderUtil.js @@ -35,9 +35,7 @@ const GltfLoaderUtil = {}; */ GltfLoaderUtil.getImageIdFromTexture = function (options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - const gltf = options.gltf; - const textureId = options.textureId; - const supportedImageFormats = options.supportedImageFormats; + const { gltf, textureId, supportedImageFormats } = options; //>>includeStart('debug', pragmas.debug); Check.typeOf.object("options.gltf", gltf); @@ -73,12 +71,7 @@ GltfLoaderUtil.getImageIdFromTexture = function (options) { */ GltfLoaderUtil.createSampler = function (options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - const gltf = options.gltf; - const textureInfo = options.textureInfo; - const compressedTextureNoMipmap = defaultValue( - options.compressedTextureNoMipmap, - false - ); + const { gltf, textureInfo, compressedTextureNoMipmap = false } = options; //>>includeStart('debug', pragmas.debug); Check.typeOf.object("options.gltf", gltf); @@ -140,9 +133,7 @@ const defaultScale = new Cartesian2(1.0, 1.0); */ GltfLoaderUtil.createModelTextureReader = function (options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - const textureInfo = options.textureInfo; - const channels = options.channels; - const texture = options.texture; + const { textureInfo, channels, texture } = options; //>>includeStart('debug', pragmas.debug); Check.typeOf.object("options.textureInfo", textureInfo); diff --git a/packages/engine/Source/Scene/GltfPipeline/forEachTextureInMaterial.js b/packages/engine/Source/Scene/GltfPipeline/forEachTextureInMaterial.js index 047d4883de1..09ef6ceb2d0 100644 --- a/packages/engine/Source/Scene/GltfPipeline/forEachTextureInMaterial.js +++ b/packages/engine/Source/Scene/GltfPipeline/forEachTextureInMaterial.js @@ -33,10 +33,11 @@ function forEachTextureInMaterial(material, handler) { } } - if (defined(material.extensions)) { + const { extensions } = material; + if (defined(extensions)) { // Spec gloss extension const pbrSpecularGlossiness = - material.extensions.KHR_materials_pbrSpecularGlossiness; + extensions.KHR_materials_pbrSpecularGlossiness; if (defined(pbrSpecularGlossiness)) { if (defined(pbrSpecularGlossiness.diffuseTexture)) { const textureInfo = pbrSpecularGlossiness.diffuseTexture; @@ -54,13 +55,28 @@ function forEachTextureInMaterial(material, handler) { } } + // Specular extension + const specular = extensions.KHR_materials_specular; + if (defined(specular)) { + const { specularTexture, specularColorTexture } = specular; + if (defined(specularTexture)) { + const value = handler(specularTexture.index, specularTexture); + if (defined(value)) { + return value; + } + } + if (defined(specularColorTexture)) { + const value = handler(specularColorTexture.index, specularColorTexture); + if (defined(value)) { + return value; + } + } + } + // Materials common extension (may be present in models converted from glTF 1.0) - const materialsCommon = material.extensions.KHR_materials_common; + const materialsCommon = extensions.KHR_materials_common; if (defined(materialsCommon) && defined(materialsCommon.values)) { - const diffuse = materialsCommon.values.diffuse; - const ambient = materialsCommon.values.ambient; - const emission = materialsCommon.values.emission; - const specular = materialsCommon.values.specular; + const { diffuse, ambient, emission, specular } = materialsCommon.values; if (defined(diffuse) && defined(diffuse.index)) { const value = handler(diffuse.index, diffuse); if (defined(value)) { diff --git a/packages/engine/Source/Scene/GltfStructuralMetadataLoader.js b/packages/engine/Source/Scene/GltfStructuralMetadataLoader.js index 7bd6129a086..b8b2d0b0b45 100644 --- a/packages/engine/Source/Scene/GltfStructuralMetadataLoader.js +++ b/packages/engine/Source/Scene/GltfStructuralMetadataLoader.js @@ -34,15 +34,17 @@ import ResourceLoaderState from "./ResourceLoaderState.js"; */ function GltfStructuralMetadataLoader(options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - const gltf = options.gltf; - const extension = options.extension; - const extensionLegacy = options.extensionLegacy; - const gltfResource = options.gltfResource; - const baseResource = options.baseResource; - const supportedImageFormats = options.supportedImageFormats; - const frameState = options.frameState; - const cacheKey = options.cacheKey; - const asynchronous = defaultValue(options.asynchronous, true); + const { + gltf, + extension, + extensionLegacy, + gltfResource, + baseResource, + supportedImageFormats, + frameState, + cacheKey, + asynchronous = true, + } = options; //>>includeStart('debug', pragmas.debug); Check.typeOf.object("options.gltf", gltf); diff --git a/packages/engine/Source/Scene/Label.js b/packages/engine/Source/Scene/Label.js index 7949cef4d80..bc10b50510f 100644 --- a/packages/engine/Source/Scene/Label.js +++ b/packages/engine/Source/Scene/Label.js @@ -91,7 +91,7 @@ function parseFont(label) { * Initialization options for the Label constructor * * @property {Cartesian3} position The cartesian position of the label. - * @property {string} [id] A user-defined object to return when the label is picked with {@link Scene#pick}. + * @property {*} [id] A user-defined object to return when the label is picked with {@link Scene#pick}. * @property {boolean} [show=true] Determines if this label will be shown. * @property {string} [text] A string specifying the text of the label. * @property {string} [font='30px sans-serif'] A string specifying the font used to draw this label. Fonts are specified using the same syntax as the CSS 'font' property. diff --git a/packages/engine/Source/Scene/Model/AlphaPipelineStage.js b/packages/engine/Source/Scene/Model/AlphaPipelineStage.js index 1cb1f3f1cc4..2f1d542f6d6 100644 --- a/packages/engine/Source/Scene/Model/AlphaPipelineStage.js +++ b/packages/engine/Source/Scene/Model/AlphaPipelineStage.js @@ -7,7 +7,7 @@ import Pass from "../../Renderer/Pass.js"; /** * A pipeline stage for configuring the alpha options for handling translucency. * - * @namespace MaterialPipelineStage + * @namespace AlphaPipelineStage * * @private */ diff --git a/packages/engine/Source/Scene/Model/GeometryPipelineStage.js b/packages/engine/Source/Scene/Model/GeometryPipelineStage.js index ca753b6a01e..28b769a07c9 100644 --- a/packages/engine/Source/Scene/Model/GeometryPipelineStage.js +++ b/packages/engine/Source/Scene/Model/GeometryPipelineStage.js @@ -63,8 +63,7 @@ GeometryPipelineStage.process = function ( primitive, frameState ) { - const shaderBuilder = renderResources.shaderBuilder; - const model = renderResources.model; + const { shaderBuilder, model } = renderResources; // These structs are similar, though the fragment shader version has a couple // additional fields. @@ -125,8 +124,7 @@ GeometryPipelineStage.process = function ( ); // .pnts point clouds store sRGB color rather than linear color - const modelType = model.type; - if (modelType === ModelType.TILE_PNTS) { + if (model.type === ModelType.TILE_PNTS) { shaderBuilder.addDefine( "HAS_SRGB_COLOR", undefined, @@ -246,8 +244,7 @@ function processAttribute( } function addSemanticDefine(shaderBuilder, attribute) { - const semantic = attribute.semantic; - const setIndex = attribute.setIndex; + const { semantic, setIndex } = attribute; switch (semantic) { case VertexAttributeSemantic.NORMAL: shaderBuilder.addDefine("HAS_NORMALS"); @@ -272,19 +269,11 @@ function addAttributeToRenderResources( attributeIndex, modifyFor2D ) { - const quantization = attribute.quantization; - let type; - let componentDatatype; - if (defined(quantization)) { - type = quantization.type; - componentDatatype = quantization.componentDatatype; - } else { - type = attribute.type; - componentDatatype = attribute.componentDatatype; - } + const { quantization, semantic, setIndex } = attribute; + const { type, componentDatatype } = defined(quantization) + ? quantization + : attribute; - const semantic = attribute.semantic; - const setIndex = attribute.setIndex; if ( semantic === VertexAttributeSemantic.FEATURE_ID && setIndex >= renderResources.featureIdVertexAttributeSetIndex @@ -337,18 +326,10 @@ function addMatrixAttributeToRenderResources( attributeIndex, columnCount ) { - const quantization = attribute.quantization; - let type; - let componentDatatype; - if (defined(quantization)) { - type = quantization.type; - componentDatatype = quantization.componentDatatype; - } else { - type = attribute.type; - componentDatatype = attribute.componentDatatype; - } - - const normalized = attribute.normalized; + const { quantization, normalized } = attribute; + const { type, componentDatatype } = defined(quantization) + ? quantization + : attribute; // componentCount is either 4, 9 or 16 const componentCount = AttributeType.getNumberOfComponents(type); @@ -435,7 +416,7 @@ function addAttributeDeclaration(shaderBuilder, attributeInfo, modifyFor2D) { function updateAttributesStruct(shaderBuilder, attributeInfo, use2D) { const vsStructId = GeometryPipelineStage.STRUCT_ID_PROCESSED_ATTRIBUTES_VS; const fsStructId = GeometryPipelineStage.STRUCT_ID_PROCESSED_ATTRIBUTES_FS; - const variableName = attributeInfo.variableName; + const { variableName, glslType } = attributeInfo; if (variableName === "tangentMC") { // The w component of the tangent is only used for computing the bitangent, @@ -451,16 +432,8 @@ function updateAttributesStruct(shaderBuilder, attributeInfo, use2D) { shaderBuilder.addStructField(vsStructId, "vec3", "normalMC"); shaderBuilder.addStructField(fsStructId, "vec3", "normalEC"); } else { - shaderBuilder.addStructField( - vsStructId, - attributeInfo.glslType, - variableName - ); - shaderBuilder.addStructField( - fsStructId, - attributeInfo.glslType, - variableName - ); + shaderBuilder.addStructField(vsStructId, glslType, variableName); + shaderBuilder.addStructField(fsStructId, glslType, variableName); } if (variableName === "positionMC" && use2D) { @@ -501,8 +474,7 @@ function updateInitializeAttributesFunction( } function updateSetDynamicVaryingsFunction(shaderBuilder, attributeInfo) { - const semantic = attributeInfo.attribute.semantic; - const setIndex = attributeInfo.attribute.setIndex; + const { semantic, setIndex } = attributeInfo.attribute; if (defined(semantic) && !defined(setIndex)) { // positions, normals, and tangents are handled statically in // GeometryStageVS diff --git a/packages/engine/Source/Scene/Model/ImageBasedLightingPipelineStage.js b/packages/engine/Source/Scene/Model/ImageBasedLightingPipelineStage.js index 48ebcf81ff4..d347e141100 100644 --- a/packages/engine/Source/Scene/Model/ImageBasedLightingPipelineStage.js +++ b/packages/engine/Source/Scene/Model/ImageBasedLightingPipelineStage.js @@ -8,6 +8,13 @@ const ImageBasedLightingPipelineStage = { name: "ImageBasedLightingPipelineStage", // Helps with debugging }; +/** + * Add shader code, uniforms, and defines related to image based lighting + * @param {ModelRenderResources} renderResources + * @param {Model} model + * @param {FrameState} frameState + * @private + */ ImageBasedLightingPipelineStage.process = function ( renderResources, model, diff --git a/packages/engine/Source/Scene/Model/LightingPipelineStage.js b/packages/engine/Source/Scene/Model/LightingPipelineStage.js index 6ed8f4aad1a..a2f466484ee 100644 --- a/packages/engine/Source/Scene/Model/LightingPipelineStage.js +++ b/packages/engine/Source/Scene/Model/LightingPipelineStage.js @@ -28,9 +28,7 @@ const LightingPipelineStage = { * @private */ LightingPipelineStage.process = function (renderResources, primitive) { - const model = renderResources.model; - const lightingOptions = renderResources.lightingOptions; - const shaderBuilder = renderResources.shaderBuilder; + const { model, lightingOptions, shaderBuilder } = renderResources; if (defined(model.lightColor)) { shaderBuilder.addDefine( @@ -53,7 +51,7 @@ LightingPipelineStage.process = function (renderResources, primitive) { // The lighting model is always set by the material. However, custom shaders // can override this. - const lightingModel = lightingOptions.lightingModel; + const { lightingModel } = lightingOptions; if (lightingModel === LightingModel.PBR) { shaderBuilder.addDefine( diff --git a/packages/engine/Source/Scene/Model/MaterialPipelineStage.js b/packages/engine/Source/Scene/Model/MaterialPipelineStage.js index 0d2f200d53b..99f630f990d 100644 --- a/packages/engine/Source/Scene/Model/MaterialPipelineStage.js +++ b/packages/engine/Source/Scene/Model/MaterialPipelineStage.js @@ -12,15 +12,20 @@ import VertexAttributeSemantic from "../VertexAttributeSemantic.js"; import LightingModel from "./LightingModel.js"; import ModelUtility from "./ModelUtility.js"; -const Material = ModelComponents.Material; -const MetallicRoughness = ModelComponents.MetallicRoughness; -const SpecularGlossiness = ModelComponents.SpecularGlossiness; +const { + Material, + MetallicRoughness, + SpecularGlossiness, + Specular, + Clearcoat, +} = ModelComponents; /** * The material pipeline stage processes textures and other uniforms needed * to render a primitive. This handles the following material types: * @@ -59,20 +64,19 @@ MaterialPipelineStage.process = function ( // gltf-pipeline automatically creates a default material so this will always // be defined. const material = primitive.material; - const model = renderResources.model; + const { model, uniformMap, shaderBuilder } = renderResources; // Classification models only use position and feature ID attributes, // so textures should be disabled to avoid compile errors. const hasClassification = defined(model.classificationType); const disableTextures = hasClassification; - const uniformMap = renderResources.uniformMap; - const shaderBuilder = renderResources.shaderBuilder; - // When textures are loaded incrementally, fall back to a default 1x1 texture - const defaultTexture = frameState.context.defaultTexture; - const defaultNormalTexture = frameState.context.defaultNormalTexture; - const defaultEmissiveTexture = frameState.context.defaultEmissiveTexture; + const { + defaultTexture, + defaultNormalTexture, + defaultEmissiveTexture, + } = frameState.context; processMaterialUniforms( material, @@ -86,15 +90,51 @@ MaterialPipelineStage.process = function ( if (defined(material.specularGlossiness)) { processSpecularGlossinessUniforms( - material, + material.specularGlossiness, uniformMap, shaderBuilder, defaultTexture, disableTextures ); } else { + if ( + defined(material.specular) && + ModelUtility.supportedExtensions.KHR_materials_specular + ) { + processSpecularUniforms( + material.specular, + uniformMap, + shaderBuilder, + defaultTexture, + disableTextures + ); + } + if ( + defined(material.anisotropy) && + ModelUtility.supportedExtensions.KHR_materials_anisotropy + ) { + processAnisotropyUniforms( + material.anisotropy, + uniformMap, + shaderBuilder, + defaultTexture, + disableTextures + ); + } + if ( + defined(material.clearcoat) && + ModelUtility.supportedExtensions.KHR_materials_clearcoat + ) { + processClearcoatUniforms( + material.clearcoat, + uniformMap, + shaderBuilder, + defaultTexture, + disableTextures + ); + } processMetallicRoughnessUniforms( - material, + material.metallicRoughness, uniformMap, shaderBuilder, defaultTexture, @@ -245,7 +285,13 @@ function processMaterialUniforms( defaultEmissiveTexture, disableTextures ) { - const emissiveFactor = material.emissiveFactor; + const { + emissiveFactor, + emissiveTexture, + normalTexture, + occlusionTexture, + } = material; + if ( defined(emissiveFactor) && !Cartesian3.equals(emissiveFactor, Material.DEFAULT_EMISSIVE_FACTOR) @@ -264,7 +310,6 @@ function processMaterialUniforms( ShaderDestination.FRAGMENT ); - const emissiveTexture = material.emissiveTexture; if (defined(emissiveTexture) && !disableTextures) { processTexture( shaderBuilder, @@ -277,7 +322,6 @@ function processMaterialUniforms( } } - const normalTexture = material.normalTexture; if (defined(normalTexture) && !disableTextures) { processTexture( shaderBuilder, @@ -289,7 +333,6 @@ function processMaterialUniforms( ); } - const occlusionTexture = material.occlusionTexture; if (defined(occlusionTexture) && !disableTextures) { processTexture( shaderBuilder, @@ -302,21 +345,37 @@ function processMaterialUniforms( } } +/** + * Add uniforms and defines for the KHR_materials_pbrSpecularGlossiness extension + * + * @param {ModelComponents.SpecularGlossiness} specularGlossiness + * @param {Object} uniformMap The uniform map to modify. + * @param {ShaderBuilder} shaderBuilder + * @param {Texture} defaultTexture + * @param {boolean} disableTextures + * @private + */ function processSpecularGlossinessUniforms( - material, + specularGlossiness, uniformMap, shaderBuilder, defaultTexture, disableTextures ) { - const specularGlossiness = material.specularGlossiness; + const { + diffuseTexture, + diffuseFactor, + specularGlossinessTexture, + specularFactor, + glossinessFactor, + } = specularGlossiness; + shaderBuilder.addDefine( "USE_SPECULAR_GLOSSINESS", undefined, ShaderDestination.FRAGMENT ); - const diffuseTexture = specularGlossiness.diffuseTexture; if (defined(diffuseTexture) && !disableTextures) { processTexture( shaderBuilder, @@ -328,7 +387,6 @@ function processSpecularGlossinessUniforms( ); } - const diffuseFactor = specularGlossiness.diffuseFactor; if ( defined(diffuseFactor) && !Cartesian4.equals(diffuseFactor, SpecularGlossiness.DEFAULT_DIFFUSE_FACTOR) @@ -348,8 +406,6 @@ function processSpecularGlossinessUniforms( ); } - const specularGlossinessTexture = - specularGlossiness.specularGlossinessTexture; if (defined(specularGlossinessTexture) && !disableTextures) { processTexture( shaderBuilder, @@ -361,7 +417,6 @@ function processSpecularGlossinessUniforms( ); } - const specularFactor = specularGlossiness.specularFactor; if ( defined(specularFactor) && !Cartesian3.equals( @@ -371,20 +426,19 @@ function processSpecularGlossinessUniforms( ) { shaderBuilder.addUniform( "vec3", - "u_specularFactor", + "u_legacySpecularFactor", ShaderDestination.FRAGMENT ); - uniformMap.u_specularFactor = function () { + uniformMap.u_legacySpecularFactor = function () { return specularGlossiness.specularFactor; }; shaderBuilder.addDefine( - "HAS_SPECULAR_FACTOR", + "HAS_LEGACY_SPECULAR_FACTOR", undefined, ShaderDestination.FRAGMENT ); } - const glossinessFactor = specularGlossiness.glossinessFactor; if ( defined(glossinessFactor) && glossinessFactor !== SpecularGlossiness.DEFAULT_GLOSSINESS_FACTOR @@ -405,14 +459,277 @@ function processSpecularGlossinessUniforms( } } +/** + * Add uniforms and defines for the KHR_materials_specular extension + * + * @param {ModelComponents.Specular} specular + * @param {Object} uniformMap The uniform map to modify. + * @param {ShaderBuilder} shaderBuilder + * @param {Texture} defaultTexture + * @param {boolean} disableTextures + * @private + */ +function processSpecularUniforms( + specular, + uniformMap, + shaderBuilder, + defaultTexture, + disableTextures +) { + const { + specularTexture, + specularFactor, + specularColorTexture, + specularColorFactor, + } = specular; + + shaderBuilder.addDefine( + "USE_SPECULAR", + undefined, + ShaderDestination.FRAGMENT + ); + + if (defined(specularTexture) && !disableTextures) { + processTexture( + shaderBuilder, + uniformMap, + specularTexture, + "u_specularTexture", + "SPECULAR", + defaultTexture + ); + } + + if ( + defined(specularFactor) && + specularFactor !== Specular.DEFAULT_SPECULAR_FACTOR + ) { + shaderBuilder.addUniform( + "float", + "u_specularFactor", + ShaderDestination.FRAGMENT + ); + uniformMap.u_specularFactor = function () { + return specular.specularFactor; + }; + shaderBuilder.addDefine( + "HAS_SPECULAR_FACTOR", + undefined, + ShaderDestination.FRAGMENT + ); + } + + if (defined(specularColorTexture) && !disableTextures) { + processTexture( + shaderBuilder, + uniformMap, + specularColorTexture, + "u_specularColorTexture", + "SPECULAR_COLOR", + defaultTexture + ); + } + + if ( + defined(specularColorFactor) && + !Cartesian3.equals( + specularColorFactor, + Specular.DEFAULT_SPECULAR_COLOR_FACTOR + ) + ) { + shaderBuilder.addUniform( + "vec3", + "u_specularColorFactor", + ShaderDestination.FRAGMENT + ); + uniformMap.u_specularColorFactor = function () { + return specular.specularColorFactor; + }; + shaderBuilder.addDefine( + "HAS_SPECULAR_COLOR_FACTOR", + undefined, + ShaderDestination.FRAGMENT + ); + } +} + +const scratchAnisotropy = new Cartesian3(); + +/** + * Add uniforms and defines for the KHR_materials_anisotropy extension + * + * @param {ModelComponents.Anisotropy} anisotropy + * @param {Object} uniformMap The uniform map to modify. + * @param {ShaderBuilder} shaderBuilder + * @param {Texture} defaultTexture + * @param {boolean} disableTextures + * @private + */ +function processAnisotropyUniforms( + anisotropy, + uniformMap, + shaderBuilder, + defaultTexture, + disableTextures +) { + const { + anisotropyStrength, + anisotropyRotation, + anisotropyTexture, + } = anisotropy; + + shaderBuilder.addDefine( + "USE_ANISOTROPY", + undefined, + ShaderDestination.FRAGMENT + ); + + if (defined(anisotropyTexture) && !disableTextures) { + processTexture( + shaderBuilder, + uniformMap, + anisotropyTexture, + "u_anisotropyTexture", + "ANISOTROPY", + defaultTexture + ); + } + + // Pre-compute cos and sin of rotation, since they are the same for all fragments. + // Combine with strength as one vec3 uniform. + const cosRotation = Math.cos(anisotropyRotation); + const sinRotation = Math.sin(anisotropyRotation); + shaderBuilder.addUniform("vec3", "u_anisotropy", ShaderDestination.FRAGMENT); + uniformMap.u_anisotropy = function () { + return Cartesian3.fromElements( + cosRotation, + sinRotation, + anisotropyStrength, + scratchAnisotropy + ); + }; +} + +/** + * Add uniforms and defines for the KHR_materials_clearcoat extension + * + * @param {ModelComponents.Clearcoat} clearcoat + * @param {Object} uniformMap The uniform map to modify. + * @param {ShaderBuilder} shaderBuilder + * @param {Texture} defaultTexture + * @param {boolean} disableTextures + * @private + */ +function processClearcoatUniforms( + clearcoat, + uniformMap, + shaderBuilder, + defaultTexture, + disableTextures +) { + const { + clearcoatFactor, + clearcoatTexture, + clearcoatRoughnessFactor, + clearcoatRoughnessTexture, + clearcoatNormalTexture, + } = clearcoat; + + shaderBuilder.addDefine( + "USE_CLEARCOAT", + undefined, + ShaderDestination.FRAGMENT + ); + + if ( + defined(clearcoatFactor) && + clearcoatFactor !== Clearcoat.DEFAULT_CLEARCOAT_FACTOR + ) { + shaderBuilder.addUniform( + "float", + "u_clearcoatFactor", + ShaderDestination.FRAGMENT + ); + uniformMap.u_clearcoatFactor = function () { + return clearcoat.clearcoatFactor; + }; + shaderBuilder.addDefine( + "HAS_CLEARCOAT_FACTOR", + undefined, + ShaderDestination.FRAGMENT + ); + } + + if (defined(clearcoatTexture) && !disableTextures) { + processTexture( + shaderBuilder, + uniformMap, + clearcoatTexture, + "u_clearcoatTexture", + "CLEARCOAT", + defaultTexture + ); + } + + if ( + defined(clearcoatRoughnessFactor) && + clearcoatFactor !== Clearcoat.DEFAULT_CLEARCOAT_ROUGHNESS_FACTOR + ) { + shaderBuilder.addUniform( + "float", + "u_clearcoatRoughnessFactor", + ShaderDestination.FRAGMENT + ); + uniformMap.u_clearcoatRoughnessFactor = function () { + return clearcoat.clearcoatRoughnessFactor; + }; + shaderBuilder.addDefine( + "HAS_CLEARCOAT_ROUGHNESS_FACTOR", + undefined, + ShaderDestination.FRAGMENT + ); + } + + if (defined(clearcoatRoughnessTexture) && !disableTextures) { + processTexture( + shaderBuilder, + uniformMap, + clearcoatRoughnessTexture, + "u_clearcoatRoughnessTexture", + "CLEARCOAT_ROUGHNESS", + defaultTexture + ); + } + + if (defined(clearcoatNormalTexture) && !disableTextures) { + processTexture( + shaderBuilder, + uniformMap, + clearcoatNormalTexture, + "u_clearcoatNormalTexture", + "CLEARCOAT_NORMAL", + defaultTexture + ); + } +} + +/** + * Add uniforms and defines for the PBR metallic roughness model + * + * @param {ModelComponents.MetallicRoughness} metallicRoughness + * @param {Object} uniformMap The uniform map to modify. + * @param {ShaderBuilder} shaderBuilder + * @param {Texture} defaultTexture + * @param {boolean} disableTextures + * @private + */ function processMetallicRoughnessUniforms( - material, + metallicRoughness, uniformMap, shaderBuilder, defaultTexture, disableTextures ) { - const metallicRoughness = material.metallicRoughness; shaderBuilder.addDefine( "USE_METALLIC_ROUGHNESS", undefined, diff --git a/packages/engine/Source/Scene/Model/Model.js b/packages/engine/Source/Scene/Model/Model.js index 5cc4449ef31..32b66a70650 100644 --- a/packages/engine/Source/Scene/Model/Model.js +++ b/packages/engine/Source/Scene/Model/Model.js @@ -2250,6 +2250,10 @@ function updatePickIds(model) { } } +// Matrix3 is a row-major constructor. +// The same constructor in GLSL will produce the transpose of this. +const yUpToZUp = new Matrix3(-1, 0, 0, 0, 0, 1, 0, -1, 0); + function updateReferenceMatrices(model, frameState) { const modelMatrix = defined(model._clampedModelMatrix) ? model._clampedModelMatrix @@ -2267,15 +2271,16 @@ function updateReferenceMatrices(model, frameState) { referenceMatrix, iblReferenceFrameMatrix4 ); - iblReferenceFrameMatrix3 = Matrix4.getMatrix3( + iblReferenceFrameMatrix3 = Matrix4.getRotation( iblReferenceFrameMatrix4, iblReferenceFrameMatrix3 ); - iblReferenceFrameMatrix3 = Matrix3.getRotation( + iblReferenceFrameMatrix3 = Matrix3.transpose( iblReferenceFrameMatrix3, iblReferenceFrameMatrix3 ); - model._iblReferenceFrameMatrix = Matrix3.transpose( + model._iblReferenceFrameMatrix = Matrix3.multiply( + yUpToZUp, iblReferenceFrameMatrix3, model._iblReferenceFrameMatrix ); diff --git a/packages/engine/Source/Scene/Model/ModelUtility.js b/packages/engine/Source/Scene/Model/ModelUtility.js index 877be6bdb24..3e24e068b6c 100644 --- a/packages/engine/Source/Scene/Model/ModelUtility.js +++ b/packages/engine/Source/Scene/Model/ModelUtility.js @@ -357,6 +357,9 @@ ModelUtility.supportedExtensions = { KHR_techniques_webgl: true, KHR_materials_common: true, KHR_materials_pbrSpecularGlossiness: true, + KHR_materials_specular: true, + KHR_materials_anisotropy: true, + KHR_materials_clearcoat: true, KHR_materials_unlit: true, KHR_mesh_quantization: true, KHR_texture_basisu: true, diff --git a/packages/engine/Source/Scene/Model/VerticalExaggerationPipelineStage.js b/packages/engine/Source/Scene/Model/VerticalExaggerationPipelineStage.js index 2a0a059e312..19f26b1001d 100644 --- a/packages/engine/Source/Scene/Model/VerticalExaggerationPipelineStage.js +++ b/packages/engine/Source/Scene/Model/VerticalExaggerationPipelineStage.js @@ -3,11 +3,9 @@ import ShaderDestination from "../../Renderer/ShaderDestination.js"; import VerticalExaggerationStageVS from "../../Shaders/Model/VerticalExaggerationStageVS.js"; /** - * The custom shader pipeline stage takes GLSL callbacks from the - * {@link CustomShader} and inserts them into the overall shader code for the - * {@link Model}. The input to the callback is a struct with many - * properties that depend on the attributes of the primitive. This shader code - * is automatically generated by this stage. + * The vertical exaggeration pipeline stage transforms the vertex + * positions based on the values of {@link Scene#verticalExaggeration} and + * {@link Scene#verticalExaggerationRelativeHeight} * * @namespace VerticalExaggerationPipelineStage * @@ -20,7 +18,7 @@ const VerticalExaggerationPipelineStage = { const scratchExaggerationUniform = new Cartesian2(); /** - * Add vertical exaggeration to a shader + * Add defines and uniforms for vertical exaggeration calculations in the vertex shader * * @param {PrimitiveRenderResources} renderResources The render resources for the primitive * @param {ModelComponents.Primitive} primitive The primitive to be rendered diff --git a/packages/engine/Source/Scene/ModelComponents.js b/packages/engine/Source/Scene/ModelComponents.js index 4cbb1e2fec1..c8179203807 100644 --- a/packages/engine/Source/Scene/ModelComponents.js +++ b/packages/engine/Source/Scene/ModelComponents.js @@ -1337,10 +1337,151 @@ SpecularGlossiness.DEFAULT_SPECULAR_FACTOR = Cartesian3.ONE; */ SpecularGlossiness.DEFAULT_GLOSSINESS_FACTOR = 1.0; +function Specular() { + /** + * The specular factor. + * + * @type {number} + * @default 1.0 + * @private + */ + this.specularFactor = Specular.DEFAULT_SPECULAR_FACTOR; + + /** + * The specular texture reader. + * + * @type {ModelComponents.TextureReader} + * @private + */ + this.specularTexture = undefined; + + /** + * The specular color factor. + * + * @type {Cartesian3} + * @default new Cartesian3(1.0, 1.0, 1.0) + * @private + */ + this.specularColorFactor = Cartesian3.clone( + Specular.DEFAULT_SPECULAR_COLOR_FACTOR + ); + + /** + * The specular color texture reader. + * + * @type {ModelComponents.TextureReader} + * @private + */ + this.specularColorTexture = undefined; +} + +/** + * @private + */ +Specular.DEFAULT_SPECULAR_FACTOR = 1.0; + +/** + * @private + */ +Specular.DEFAULT_SPECULAR_COLOR_FACTOR = Cartesian3.ONE; + +function Anisotropy() { + /** + * The anisotropy strength. + * + * @type {number} + * @default 0.0 + * @private + */ + this.anisotropyStrength = Anisotropy.DEFAULT_ANISOTROPY_STRENGTH; + + /** + * The rotation of the anisotropy in tangent, bitangent space, + * measured in radians counter-clockwise from the tangent. + * + * @type {number} + * @default 0.0 + * @private + */ + this.anisotropyRotation = Anisotropy.DEFAULT_ANISOTROPY_ROTATION; + + /** + * The anisotropy texture reader. + * + * @type {ModelComponents.TextureReader} + * @private + */ + this.anisotropyTexture = undefined; +} + +/** + * @private + */ +Anisotropy.DEFAULT_ANISOTROPY_STRENGTH = 0.0; + +/** + * @private + */ +Anisotropy.DEFAULT_ANISOTROPY_ROTATION = 0.0; + +function Clearcoat() { + /** + * The clearcoat layer intensity. + * + * @type {number} + * @default 0.0 + * @private + */ + this.clearcoatFactor = Clearcoat.DEFAULT_CLEARCOAT_FACTOR; + + /** + * The clearcoat layer intensity texture reader. + * + * @type {ModelComponents.TextureReader} + * @private + */ + this.clearcoatTexture = undefined; + + /** + * The clearcoat layer roughness. + * + * @type {number} + * @default 0.0 + * @private + */ + this.clearcoatRoughnessFactor = Clearcoat.DEFAULT_CLEARCOAT_ROUGHNESS_FACTOR; + + /** + * The clearcoat layer roughness texture. + * + * @type {ModelComponents.TextureReader} + * @private + */ + this.clearcoatRoughnessTexture = undefined; + + /** + * The clearcoat normal map texture. + * + * @type {ModelComponents.TextureReader} + * @private + */ + this.clearcoatNormalTexture = undefined; +} + +/** + * @private + */ +Clearcoat.DEFAULT_CLEARCOAT_FACTOR = 0.0; + +/** + * @private + */ +Clearcoat.DEFAULT_CLEARCOAT_ROUGHNESS_FACTOR = 0.0; + /** * The material appearance of a primitive. * - * @alias ModelComponent.Material + * @alias ModelComponents.Material * @constructor * * @private @@ -1362,6 +1503,30 @@ function Material() { */ this.specularGlossiness = undefined; + /** + * Material properties for the PBR specular shading model. + * + * @type {ModelComponents.Specular} + * @private + */ + this.specular = undefined; + + /** + * Material properties for the PBR anisotropy shading model. + * + * @type {ModelComponents.Anisotropy} + * @private + */ + this.anisotropy = undefined; + + /** + * Material properties for the PBR clearcoat shading model. + * + * @type {ModelComponents.Clearcoat} + * @private + */ + this.clearcoat = undefined; + /** * The emissive texture reader. * @@ -1461,6 +1626,9 @@ ModelComponents.Components = Components; ModelComponents.TextureReader = TextureReader; ModelComponents.MetallicRoughness = MetallicRoughness; ModelComponents.SpecularGlossiness = SpecularGlossiness; +ModelComponents.Specular = Specular; +ModelComponents.Anisotropy = Anisotropy; +ModelComponents.Clearcoat = Clearcoat; ModelComponents.Material = Material; export default ModelComponents; diff --git a/packages/engine/Source/Scene/PickDepth.js b/packages/engine/Source/Scene/PickDepth.js index 19b24625262..f350e0a8a76 100644 --- a/packages/engine/Source/Scene/PickDepth.js +++ b/packages/engine/Source/Scene/PickDepth.js @@ -30,22 +30,30 @@ function updateFramebuffers(pickDepth, context, depthTexture) { function updateCopyCommands(pickDepth, context, depthTexture) { if (!defined(pickDepth._copyDepthCommand)) { - const fs = - "uniform highp sampler2D u_texture;\n" + - "in vec2 v_textureCoordinates;\n" + - "void main()\n" + - "{\n" + - " out_FragColor = czm_packDepth(texture(u_texture, v_textureCoordinates).r);\n" + - "}\n"; - pickDepth._copyDepthCommand = context.createViewportQuadCommand(fs, { - renderState: RenderState.fromCache(), - uniformMap: { - u_texture: function () { - return pickDepth._textureToCopy; + pickDepth._copyDepthCommand = context.createViewportQuadCommand( + `uniform highp sampler2D colorTexture; + +in vec2 v_textureCoordinates; + +void main() +{ + vec4 globeDepthPacked = texture(czm_globeDepthTexture, v_textureCoordinates); + float globeDepth = czm_unpackDepth(globeDepthPacked); + float depth = texture(colorTexture, v_textureCoordinates).r; + out_FragColor = czm_branchFreeTernary(globeDepth <= 0.0 || globeDepth >= 1.0 || depth < globeDepth && depth > 0.0 && depth < 1.0, + czm_packDepth(depth), globeDepthPacked); +} +`, + { + renderState: RenderState.fromCache(), + uniformMap: { + colorTexture: function () { + return pickDepth._textureToCopy; + }, }, - }, - owner: pickDepth, - }); + owner: pickDepth, + } + ); } pickDepth._textureToCopy = depthTexture; diff --git a/packages/engine/Source/Scene/ResourceCache.js b/packages/engine/Source/Scene/ResourceCache.js index 086033589d1..e29571cfb99 100644 --- a/packages/engine/Source/Scene/ResourceCache.js +++ b/packages/engine/Source/Scene/ResourceCache.js @@ -146,8 +146,7 @@ ResourceCache.unload = function (resourceLoader) { */ ResourceCache.getSchemaLoader = function (options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - const schema = options.schema; - const resource = options.resource; + const { schema, resource } = options; //>>includeStart('debug', pragmas.debug); if (defined(schema) === defined(resource)) { @@ -189,9 +188,7 @@ ResourceCache.getSchemaLoader = function (options) { */ ResourceCache.getEmbeddedBufferLoader = function (options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - const parentResource = options.parentResource; - const bufferId = options.bufferId; - const typedArray = options.typedArray; + const { parentResource, bufferId, typedArray } = options; //>>includeStart('debug', pragmas.debug); Check.typeOf.object("options.parentResource", parentResource); @@ -231,7 +228,7 @@ ResourceCache.getEmbeddedBufferLoader = function (options) { */ ResourceCache.getExternalBufferLoader = function (options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - const resource = options.resource; + const { resource } = options; //>>includeStart('debug', pragmas.debug); Check.typeOf.object("options.resource", resource); @@ -268,10 +265,7 @@ ResourceCache.getExternalBufferLoader = function (options) { */ ResourceCache.getGltfJsonLoader = function (options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - const gltfResource = options.gltfResource; - const baseResource = options.baseResource; - const typedArray = options.typedArray; - const gltfJson = options.gltfJson; + const { gltfResource, baseResource, typedArray, gltfJson } = options; //>>includeStart('debug', pragmas.debug); Check.typeOf.object("options.gltfResource", gltfResource); @@ -313,10 +307,7 @@ ResourceCache.getGltfJsonLoader = function (options) { */ ResourceCache.getBufferViewLoader = function (options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - const gltf = options.gltf; - const bufferViewId = options.bufferViewId; - const gltfResource = options.gltfResource; - const baseResource = options.baseResource; + const { gltf, bufferViewId, gltfResource, baseResource } = options; //>>includeStart('debug', pragmas.debug); Check.typeOf.object("options.gltf", gltf); @@ -363,10 +354,7 @@ ResourceCache.getBufferViewLoader = function (options) { */ ResourceCache.getDracoLoader = function (options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - const gltf = options.gltf; - const draco = options.draco; - const gltfResource = options.gltfResource; - const baseResource = options.baseResource; + const { gltf, draco, gltfResource, baseResource } = options; //>>includeStart('debug', pragmas.debug); Check.typeOf.object("options.gltf", gltf); @@ -424,18 +412,20 @@ ResourceCache.getDracoLoader = function (options) { */ ResourceCache.getVertexBufferLoader = function (options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - const gltf = options.gltf; - const gltfResource = options.gltfResource; - const baseResource = options.baseResource; - const frameState = options.frameState; - const bufferViewId = options.bufferViewId; - const draco = options.draco; - const attributeSemantic = options.attributeSemantic; - const accessorId = options.accessorId; - const asynchronous = defaultValue(options.asynchronous, true); - const dequantize = defaultValue(options.dequantize, false); - const loadBuffer = defaultValue(options.loadBuffer, false); - const loadTypedArray = defaultValue(options.loadTypedArray, false); + const { + gltf, + gltfResource, + baseResource, + frameState, + bufferViewId, + draco, + attributeSemantic, + accessorId, + asynchronous = true, + dequantize = false, + loadBuffer = false, + loadTypedArray = false, + } = options; //>>includeStart('debug', pragmas.debug); Check.typeOf.object("options.gltf", gltf); @@ -541,15 +531,17 @@ function hasDracoCompression(draco, semantic) { */ ResourceCache.getIndexBufferLoader = function (options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - const gltf = options.gltf; - const accessorId = options.accessorId; - const gltfResource = options.gltfResource; - const baseResource = options.baseResource; - const frameState = options.frameState; - const draco = options.draco; - const asynchronous = defaultValue(options.asynchronous, true); - const loadBuffer = defaultValue(options.loadBuffer, false); - const loadTypedArray = defaultValue(options.loadTypedArray, false); + const { + gltf, + accessorId, + gltfResource, + baseResource, + frameState, + draco, + asynchronous = true, + loadBuffer = false, + loadTypedArray = false, + } = options; //>>includeStart('debug', pragmas.debug); Check.typeOf.object("options.gltf", gltf); @@ -610,10 +602,7 @@ ResourceCache.getIndexBufferLoader = function (options) { */ ResourceCache.getImageLoader = function (options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - const gltf = options.gltf; - const imageId = options.imageId; - const gltfResource = options.gltfResource; - const baseResource = options.baseResource; + const { gltf, imageId, gltfResource, baseResource } = options; //>>includeStart('debug', pragmas.debug); Check.typeOf.object("options.gltf", gltf); @@ -663,13 +652,15 @@ ResourceCache.getImageLoader = function (options) { */ ResourceCache.getTextureLoader = function (options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - const gltf = options.gltf; - const textureInfo = options.textureInfo; - const gltfResource = options.gltfResource; - const baseResource = options.baseResource; - const supportedImageFormats = options.supportedImageFormats; - const frameState = options.frameState; - const asynchronous = defaultValue(options.asynchronous, true); + const { + gltf, + textureInfo, + gltfResource, + baseResource, + supportedImageFormats, + frameState, + asynchronous = true, + } = options; //>>includeStart('debug', pragmas.debug); Check.typeOf.object("options.gltf", gltf); diff --git a/packages/engine/Source/Scene/ResourceCacheKey.js b/packages/engine/Source/Scene/ResourceCacheKey.js index 71d983242d5..6763461cebc 100644 --- a/packages/engine/Source/Scene/ResourceCacheKey.js +++ b/packages/engine/Source/Scene/ResourceCacheKey.js @@ -20,8 +20,7 @@ function getExternalResourceCacheKey(resource) { } function getBufferViewCacheKey(bufferView) { - let byteOffset = bufferView.byteOffset; - let byteLength = bufferView.byteLength; + let { byteOffset, byteLength } = bufferView; if (hasExtension(bufferView, "EXT_meshopt_compression")) { const meshopt = bufferView.extensions.EXT_meshopt_compression; @@ -34,16 +33,10 @@ function getBufferViewCacheKey(bufferView) { function getAccessorCacheKey(accessor, bufferView) { const byteOffset = bufferView.byteOffset + accessor.byteOffset; - const componentType = accessor.componentType; - const type = accessor.type; - const count = accessor.count; + const { componentType, type, count } = accessor; return `${byteOffset}-${componentType}-${type}-${count}`; } -function getExternalBufferCacheKey(resource) { - return getExternalResourceCacheKey(resource); -} - function getEmbeddedBufferCacheKey(parentResource, bufferId) { const parentCacheKey = getExternalResourceCacheKey(parentResource); return `${parentCacheKey}-buffer-id-${bufferId}`; @@ -54,7 +47,7 @@ function getBufferCacheKey(buffer, bufferId, gltfResource, baseResource) { const resource = baseResource.getDerivedResource({ url: buffer.uri, }); - return getExternalBufferCacheKey(resource); + return getExternalResourceCacheKey(resource); } return getEmbeddedBufferCacheKey(gltfResource, bufferId); @@ -128,8 +121,7 @@ function getSamplerCacheKey(gltf, textureInfo) { * @private */ ResourceCacheKey.getSchemaCacheKey = function (options) { - const schema = options.schema; - const resource = options.resource; + const { schema, resource } = options; //>>includeStart('debug', pragmas.debug); if (defined(schema) === defined(resource)) { @@ -157,13 +149,13 @@ ResourceCacheKey.getSchemaCacheKey = function (options) { */ ResourceCacheKey.getExternalBufferCacheKey = function (options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - const resource = options.resource; + const { resource } = options; //>>includeStart('debug', pragmas.debug); Check.typeOf.object("options.resource", resource); //>>includeEnd('debug'); - return `external-buffer:${getExternalBufferCacheKey(resource)}`; + return `external-buffer:${getExternalResourceCacheKey(resource)}`; }; /** @@ -178,8 +170,7 @@ ResourceCacheKey.getExternalBufferCacheKey = function (options) { */ ResourceCacheKey.getEmbeddedBufferCacheKey = function (options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - const parentResource = options.parentResource; - const bufferId = options.bufferId; + const { parentResource, bufferId } = options; //>>includeStart('debug', pragmas.debug); Check.typeOf.object("options.parentResource", parentResource); @@ -203,7 +194,7 @@ ResourceCacheKey.getEmbeddedBufferCacheKey = function (options) { */ ResourceCacheKey.getGltfCacheKey = function (options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - const gltfResource = options.gltfResource; + const { gltfResource } = options; //>>includeStart('debug', pragmas.debug); Check.typeOf.object("options.gltfResource", gltfResource); @@ -226,10 +217,7 @@ ResourceCacheKey.getGltfCacheKey = function (options) { */ ResourceCacheKey.getBufferViewCacheKey = function (options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - const gltf = options.gltf; - const bufferViewId = options.bufferViewId; - const gltfResource = options.gltfResource; - const baseResource = options.baseResource; + const { gltf, bufferViewId, gltfResource, baseResource } = options; //>>includeStart('debug', pragmas.debug); Check.typeOf.object("options.gltf", gltf); @@ -272,10 +260,7 @@ ResourceCacheKey.getBufferViewCacheKey = function (options) { */ ResourceCacheKey.getDracoCacheKey = function (options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - const gltf = options.gltf; - const draco = options.draco; - const gltfResource = options.gltfResource; - const baseResource = options.baseResource; + const { gltf, draco, gltfResource, baseResource } = options; //>>includeStart('debug', pragmas.debug); Check.typeOf.object("options.gltf", gltf); @@ -309,16 +294,18 @@ ResourceCacheKey.getDracoCacheKey = function (options) { */ ResourceCacheKey.getVertexBufferCacheKey = function (options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - const gltf = options.gltf; - const gltfResource = options.gltfResource; - const baseResource = options.baseResource; - const frameState = options.frameState; - const bufferViewId = options.bufferViewId; - const draco = options.draco; - const attributeSemantic = options.attributeSemantic; - const dequantize = defaultValue(options.dequantize, false); - const loadBuffer = defaultValue(options.loadBuffer, false); - const loadTypedArray = defaultValue(options.loadTypedArray, false); + const { + gltf, + gltfResource, + baseResource, + frameState, + bufferViewId, + draco, + attributeSemantic, + dequantize = false, + loadBuffer = false, + loadTypedArray = false, + } = options; //>>includeStart('debug', pragmas.debug); Check.typeOf.object("options.gltf", gltf); @@ -420,14 +407,16 @@ function hasDracoCompression(draco, semantic) { */ ResourceCacheKey.getIndexBufferCacheKey = function (options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - const gltf = options.gltf; - const accessorId = options.accessorId; - const gltfResource = options.gltfResource; - const baseResource = options.baseResource; - const frameState = options.frameState; - const draco = options.draco; - const loadBuffer = defaultValue(options.loadBuffer, false); - const loadTypedArray = defaultValue(options.loadTypedArray, false); + const { + gltf, + accessorId, + gltfResource, + baseResource, + frameState, + draco, + loadBuffer = false, + loadTypedArray = false, + } = options; //>>includeStart('debug', pragmas.debug); Check.typeOf.object("options.gltf", gltf); @@ -495,10 +484,7 @@ ResourceCacheKey.getIndexBufferCacheKey = function (options) { */ ResourceCacheKey.getImageCacheKey = function (options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - const gltf = options.gltf; - const imageId = options.imageId; - const gltfResource = options.gltfResource; - const baseResource = options.baseResource; + const { gltf, imageId, gltfResource, baseResource } = options; //>>includeStart('debug', pragmas.debug); Check.typeOf.object("options.gltf", gltf); @@ -533,12 +519,14 @@ ResourceCacheKey.getImageCacheKey = function (options) { */ ResourceCacheKey.getTextureCacheKey = function (options) { options = defaultValue(options, defaultValue.EMPTY_OBJECT); - const gltf = options.gltf; - const textureInfo = options.textureInfo; - const gltfResource = options.gltfResource; - const baseResource = options.baseResource; - const supportedImageFormats = options.supportedImageFormats; - const frameState = options.frameState; + const { + gltf, + textureInfo, + gltfResource, + baseResource, + supportedImageFormats, + frameState, + } = options; //>>includeStart('debug', pragmas.debug); Check.typeOf.object("options.gltf", gltf); diff --git a/packages/engine/Source/Shaders/Builtin/Functions/defaultPbrMaterial.glsl b/packages/engine/Source/Shaders/Builtin/Functions/defaultPbrMaterial.glsl deleted file mode 100644 index b60e8e2b5a3..00000000000 --- a/packages/engine/Source/Shaders/Builtin/Functions/defaultPbrMaterial.glsl +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Get default parameters for physically based rendering. These defaults - * describe a rough dielectric (non-metal) surface (e.g. rough plastic). - * - * @return {czm_pbrParameters} Default parameters for {@link czm_pbrLighting} - */ -czm_pbrParameters czm_defaultPbrMaterial() -{ - czm_pbrParameters results; - results.diffuseColor = vec3(1.0); - results.roughness = 1.0; - - const vec3 REFLECTANCE_DIELECTRIC = vec3(0.04); - results.f0 = REFLECTANCE_DIELECTRIC; - return results; -} diff --git a/packages/engine/Source/Shaders/Builtin/Functions/maximumComponent.glsl b/packages/engine/Source/Shaders/Builtin/Functions/maximumComponent.glsl new file mode 100644 index 00000000000..40f51216d7d --- /dev/null +++ b/packages/engine/Source/Shaders/Builtin/Functions/maximumComponent.glsl @@ -0,0 +1,21 @@ +/** + * Find the maximum component of a vector. + * + * @name czm_maximumComponent + * @glslFunction + * + * @param {vec2|vec3|vec4} v The input vector. + * @returns {float} The value of the largest component. + */ +float czm_maximumComponent(vec2 v) +{ + return max(v.x, v.y); +} +float czm_maximumComponent(vec3 v) +{ + return max(max(v.x, v.y), v.z); +} +float czm_maximumComponent(vec4 v) +{ + return max(max(max(v.x, v.y), v.z), v.w); +} diff --git a/packages/engine/Source/Shaders/Builtin/Functions/pbrLighting.glsl b/packages/engine/Source/Shaders/Builtin/Functions/pbrLighting.glsl index 22a0abff0a0..ad8b7a809a7 100644 --- a/packages/engine/Source/Shaders/Builtin/Functions/pbrLighting.glsl +++ b/packages/engine/Source/Shaders/Builtin/Functions/pbrLighting.glsl @@ -5,9 +5,42 @@ vec3 lambertianDiffuse(vec3 diffuseColor) vec3 fresnelSchlick2(vec3 f0, vec3 f90, float VdotH) { - return f0 + (f90 - f0) * pow(clamp(1.0 - VdotH, 0.0, 1.0), 5.0); + float versine = 1.0 - VdotH; + // pow(versine, 5.0) is slow. See https://stackoverflow.com/a/68793086/10082269 + float versineSquared = versine * versine; + return f0 + (f90 - f0) * versineSquared * versineSquared * versine; } +#ifdef USE_ANISOTROPY +/** + * @param {float} roughness Material roughness (along the anisotropy bitangent) + * @param {float} tangentialRoughness Anisotropic roughness (along the anisotropy tangent) + * @param {vec3} lightDirection The direction from the fragment to the light source, transformed to tangent-bitangent-normal coordinates + * @param {vec3} viewDirection The direction from the fragment to the camera, transformed to tangent-bitangent-normal coordinates + */ +float smithVisibilityGGX_anisotropic(float roughness, float tangentialRoughness, vec3 lightDirection, vec3 viewDirection) +{ + vec3 roughnessScale = vec3(tangentialRoughness, roughness, 1.0); + float GGXV = lightDirection.z * length(roughnessScale * viewDirection); + float GGXL = viewDirection.z * length(roughnessScale * lightDirection); + float v = 0.5 / (GGXV + GGXL); + return clamp(v, 0.0, 1.0); +} + +/** + * @param {float} roughness Material roughness (along the anisotropy bitangent) + * @param {float} tangentialRoughness Anisotropic roughness (along the anisotropy tangent) + * @param {vec3} halfwayDirection The unit vector halfway between light and view directions, transformed to tangent-bitangent-normal coordinates + */ +float GGX_anisotropic(float roughness, float tangentialRoughness, vec3 halfwayDirection) +{ + float roughnessSquared = roughness * tangentialRoughness; + vec3 f = halfwayDirection * vec3(roughness, tangentialRoughness, roughnessSquared); + float w2 = roughnessSquared / dot(f, f); + return roughnessSquared * w2 * w2 / czm_pi; +} +#endif + float smithVisibilityG1(float NdotV, float roughness) { // this is the k value for direct lighting. @@ -16,14 +49,34 @@ float smithVisibilityG1(float NdotV, float roughness) return NdotV / (NdotV * (1.0 - k) + k); } +/** + * Estimate the geometric self-shadowing of the microfacets in a surface, + * using the Schlick GGX approximation of a Smith visibility function. + * + * @param {float} roughness The roughness of the material. + * @param {float} NdotL The cosine of the angle between the surface normal and the direction to the light source. + * @param {float} NdotV The cosine of the angle between the surface normal and the direction to the camera. + */ float smithVisibilityGGX(float roughness, float NdotL, float NdotV) { + // Avoid divide-by-zero errors + NdotL = clamp(NdotL, 0.001, 1.0); + NdotV += 0.001; return ( smithVisibilityG1(NdotL, roughness) * smithVisibilityG1(NdotV, roughness) - ); + ) / (4.0 * NdotL * NdotV); } +/** + * Estimate the fraction of the microfacets in a surface that are aligned with + * the halfway vector, which is aligned halfway between the directions from + * the fragment to the camera and from the fragment to the light source. + * + * @param {float} roughness The roughness of the material. + * @param {float} NdotH The cosine of the angle between the surface normal and the halfway vector. + * @return {float} The fraction of microfacets aligned to the halfway vector. + */ float GGX(float roughness, float NdotH) { float roughnessSquared = roughness * roughness; @@ -31,69 +84,80 @@ float GGX(float roughness, float NdotH) return roughnessSquared / (czm_pi * f * f); } +/** + * Compute the strength of the specular reflection due to direct lighting. + * + * @param {vec3} normal The surface normal. + * @param {vec3} lightDirection The unit vector pointing from the fragment to the light source. + * @param {vec3} viewDirection The unit vector pointing from the fragment to the camera. + * @param {vec3} halfwayDirection The unit vector pointing from the fragment to halfway between the light source and the camera. + * @param {float} roughness The roughness of the material. + * @return {float} The strength of the specular reflection. + */ +float computeDirectSpecularStrength(vec3 normal, vec3 lightDirection, vec3 viewDirection, vec3 halfwayDirection, float roughness) +{ + float NdotL = dot(normal, lightDirection); + float NdotV = abs(dot(normal, viewDirection)); + float G = smithVisibilityGGX(roughness, NdotL, NdotV); + float NdotH = clamp(dot(normal, halfwayDirection), 0.0, 1.0); + float D = GGX(roughness, NdotH); + return G * D; +} + /** * Compute the diffuse and specular contributions using physically based * rendering. This function only handles direct lighting. *

* This function only handles the lighting calculations. Metallic/roughness - * and specular/glossy must be handled separately. See {@czm_pbrMetallicRoughnessMaterial}, {@czm_pbrSpecularGlossinessMaterial} and {@czm_defaultPbrMaterial} + * and specular/glossy must be handled separately. See {@MaterialStageFS} *

* - * @name czm_pbrlighting + * @name czm_pbrLighting * @glslFunction * - * @param {vec3} positionEC The position of the fragment in eye coordinates + * @param {vec3} viewDirectionEC Unit vector pointing from the fragment to the eye position * @param {vec3} normalEC The surface normal in eye coordinates * @param {vec3} lightDirectionEC Unit vector pointing to the light source in eye coordinates. - * @param {vec3} lightColorHdr radiance of the light source. This is a HDR value. - * @param {czm_pbrParameters} The computed PBR parameters. + * @param {czm_modelMaterial} The material properties. * @return {vec3} The computed HDR color - * - * @example - * czm_pbrParameters pbrParameters = czm_pbrMetallicRoughnessMaterial( - * baseColor, - * metallic, - * roughness - * ); - * vec3 color = czm_pbrlighting( - * positionEC, - * normalEC, - * lightDirectionEC, - * lightColorHdr, - * pbrParameters); */ -vec3 czm_pbrLighting( - vec3 positionEC, - vec3 normalEC, - vec3 lightDirectionEC, - vec3 lightColorHdr, - czm_pbrParameters pbrParameters -) +vec3 czm_pbrLighting(vec3 viewDirectionEC, vec3 normalEC, vec3 lightDirectionEC, czm_modelMaterial material) { - vec3 v = -normalize(positionEC); - vec3 l = normalize(lightDirectionEC); - vec3 h = normalize(v + l); - vec3 n = normalEC; - float NdotL = clamp(dot(n, l), 0.001, 1.0); - float NdotV = abs(dot(n, v)) + 0.001; - float NdotH = clamp(dot(n, h), 0.0, 1.0); - float LdotH = clamp(dot(l, h), 0.0, 1.0); - float VdotH = clamp(dot(v, h), 0.0, 1.0); + vec3 halfwayDirectionEC = normalize(viewDirectionEC + lightDirectionEC); + float VdotH = clamp(dot(viewDirectionEC, halfwayDirectionEC), 0.0, 1.0); + float NdotL = clamp(dot(normalEC, lightDirectionEC), 0.001, 1.0); - vec3 f0 = pbrParameters.f0; - float reflectance = max(max(f0.r, f0.g), f0.b); + vec3 f0 = material.specular; + float reflectance = czm_maximumComponent(f0); + // Typical dielectrics will have reflectance 0.04, so f90 will be 1.0. + // In this case, at grazing angle, all incident energy is reflected. vec3 f90 = vec3(clamp(reflectance * 25.0, 0.0, 1.0)); vec3 F = fresnelSchlick2(f0, f90, VdotH); - float alpha = pbrParameters.roughness; - float G = smithVisibilityGGX(alpha, NdotL, NdotV); - float D = GGX(alpha, NdotH); - vec3 specularContribution = F * G * D / (4.0 * NdotL * NdotV); + #if defined(USE_SPECULAR) + F *= material.specularWeight; + #endif + + float alpha = material.roughness; + #ifdef USE_ANISOTROPY + mat3 tbn = mat3(material.anisotropicT, material.anisotropicB, normalEC); + vec3 lightDirection = lightDirectionEC * tbn; + vec3 viewDirection = viewDirectionEC * tbn; + vec3 halfwayDirection = halfwayDirectionEC * tbn; + float anisotropyStrength = material.anisotropyStrength; + float tangentialRoughness = mix(alpha, 1.0, anisotropyStrength * anisotropyStrength); + float G = smithVisibilityGGX_anisotropic(alpha, tangentialRoughness, lightDirection, viewDirection); + float D = GGX_anisotropic(alpha, tangentialRoughness, halfwayDirection); + vec3 specularContribution = F * G * D; + #else + float specularStrength = computeDirectSpecularStrength(normalEC, lightDirectionEC, viewDirectionEC, halfwayDirectionEC, alpha); + vec3 specularContribution = F * specularStrength; + #endif - vec3 diffuseColor = pbrParameters.diffuseColor; + vec3 diffuseColor = material.diffuse; // F here represents the specular contribution vec3 diffuseContribution = (1.0 - F) * lambertianDiffuse(diffuseColor); // Lo = (diffuse + specular) * Li * NdotL - return (diffuseContribution + specularContribution) * NdotL * lightColorHdr; + return (diffuseContribution + specularContribution) * NdotL; } diff --git a/packages/engine/Source/Shaders/Builtin/Functions/pbrMetallicRoughnessMaterial.glsl b/packages/engine/Source/Shaders/Builtin/Functions/pbrMetallicRoughnessMaterial.glsl deleted file mode 100644 index 4ae262e867c..00000000000 --- a/packages/engine/Source/Shaders/Builtin/Functions/pbrMetallicRoughnessMaterial.glsl +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Compute parameters for physically based rendering using the - * metallic/roughness workflow. All inputs are linear; sRGB texture values must - * be decoded beforehand - * - * @name czm_pbrMetallicRoughnessMaterial - * @glslFunction - * - * @param {vec3} baseColor For dielectrics, this is the base color. For metals, this is the f0 value (reflectance at normal incidence) - * @param {float} metallic 0.0 indicates dielectric. 1.0 indicates metal. Values in between are allowed (e.g. to model rust or dirt); - * @param {float} roughness A value between 0.0 and 1.0 - * @return {czm_pbrParameters} parameters to pass into {@link czm_pbrLighting} - */ -czm_pbrParameters czm_pbrMetallicRoughnessMaterial( - vec3 baseColor, - float metallic, - float roughness -) -{ - czm_pbrParameters results; - - // roughness is authored as perceptual roughness - // square it to get material roughness - roughness = clamp(roughness, 0.0, 1.0); - results.roughness = roughness * roughness; - - // dielectrics use f0 = 0.04, metals use albedo as f0 - metallic = clamp(metallic, 0.0, 1.0); - const vec3 REFLECTANCE_DIELECTRIC = vec3(0.04); - vec3 f0 = mix(REFLECTANCE_DIELECTRIC, baseColor, metallic); - results.f0 = f0; - - // diffuse only applies to dielectrics. - results.diffuseColor = baseColor * (1.0 - f0) * (1.0 - metallic); - - return results; -} diff --git a/packages/engine/Source/Shaders/Builtin/Functions/pbrSpecularGlossinessMaterial.glsl b/packages/engine/Source/Shaders/Builtin/Functions/pbrSpecularGlossinessMaterial.glsl deleted file mode 100644 index 01dc7a5102a..00000000000 --- a/packages/engine/Source/Shaders/Builtin/Functions/pbrSpecularGlossinessMaterial.glsl +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Compute parameters for physically based rendering using the - * specular/glossy workflow. All inputs are linear; sRGB texture values must - * be decoded beforehand - * - * @name czm_pbrSpecularGlossinessMaterial - * @glslFunction - * - * @param {vec3} diffuse The diffuse color for dielectrics (non-metals) - * @param {vec3} specular The reflectance at normal incidence (f0) - * @param {float} glossiness A number from 0.0 to 1.0 indicating how smooth the surface is. - * @return {czm_pbrParameters} parameters to pass into {@link czm_pbrLighting} - */ -czm_pbrParameters czm_pbrSpecularGlossinessMaterial( - vec3 diffuse, - vec3 specular, - float glossiness -) -{ - czm_pbrParameters results; - - // glossiness is the opposite of roughness, but easier for artists to use. - float roughness = 1.0 - glossiness; - results.roughness = roughness * roughness; - - results.diffuseColor = diffuse * (1.0 - max(max(specular.r, specular.g), specular.b)); - results.f0 = specular; - - return results; -} diff --git a/packages/engine/Source/Shaders/Builtin/Structs/modelMaterial.glsl b/packages/engine/Source/Shaders/Builtin/Structs/modelMaterial.glsl index ff21e666cd2..3802a9a9a06 100644 --- a/packages/engine/Source/Shaders/Builtin/Structs/modelMaterial.glsl +++ b/packages/engine/Source/Shaders/Builtin/Structs/modelMaterial.glsl @@ -26,4 +26,18 @@ struct czm_modelMaterial { vec3 normalEC; float occlusion; vec3 emissive; +#ifdef USE_SPECULAR + float specularWeight; +#endif +#ifdef USE_ANISOTROPY + vec3 anisotropicT; + vec3 anisotropicB; + float anisotropyStrength; +#endif +#ifdef USE_CLEARCOAT + float clearcoatFactor; + float clearcoatRoughness; + vec3 clearcoatNormal; + // Add clearcoatF0 when KHR_materials_ior is implemented +#endif }; diff --git a/packages/engine/Source/Shaders/Builtin/Structs/pbrParameters.glsl b/packages/engine/Source/Shaders/Builtin/Structs/pbrParameters.glsl deleted file mode 100644 index e1d33418d83..00000000000 --- a/packages/engine/Source/Shaders/Builtin/Structs/pbrParameters.glsl +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Parameters for {@link czm_pbrLighting} - * - * @name czm_material - * @glslStruct - * - * @property {vec3} diffuseColor the diffuse color of the material for the lambert term of the rendering equation - * @property {float} roughness a value from 0.0 to 1.0 that indicates how rough the surface of the material is. - * @property {vec3} f0 The reflectance of the material at normal incidence - */ -struct czm_pbrParameters -{ - vec3 diffuseColor; - float roughness; - vec3 f0; -}; diff --git a/packages/engine/Source/Shaders/GlobeFS.glsl b/packages/engine/Source/Shaders/GlobeFS.glsl index 11072943caf..74ad34d886e 100644 --- a/packages/engine/Source/Shaders/GlobeFS.glsl +++ b/packages/engine/Source/Shaders/GlobeFS.glsl @@ -207,7 +207,7 @@ vec4 sampleAndBlend( #ifdef APPLY_COLOR_TO_ALPHA vec3 colorDiff = abs(color.rgb - colorToAlpha.rgb); - colorDiff.r = max(max(colorDiff.r, colorDiff.g), colorDiff.b); + colorDiff.r = czm_maximumComponent(colorDiff); alpha = czm_branchFreeTernary(colorDiff.r < colorToAlpha.a, 0.0, alpha); #endif diff --git a/packages/engine/Source/Shaders/Model/ImageBasedLightingStageFS.glsl b/packages/engine/Source/Shaders/Model/ImageBasedLightingStageFS.glsl index 22fda5197e4..e94ffd0a0dc 100644 --- a/packages/engine/Source/Shaders/Model/ImageBasedLightingStageFS.glsl +++ b/packages/engine/Source/Shaders/Model/ImageBasedLightingStageFS.glsl @@ -1,165 +1,243 @@ -vec3 proceduralIBL( - vec3 positionEC, - vec3 normalEC, - vec3 lightDirectionEC, - vec3 lightColorHdr, - czm_pbrParameters pbrParameters -) { - vec3 v = -positionEC; - vec3 positionWC = vec3(czm_inverseView * vec4(positionEC, 1.0)); - vec3 vWC = -normalize(positionWC); - vec3 l = normalize(lightDirectionEC); - vec3 n = normalEC; - vec3 r = normalize(czm_inverseViewRotation * normalize(reflect(v, n))); +/** + * Compute some metrics for a procedural sky lighting model + * + * @param {vec3} positionWC The position of the fragment in world coordinates. + * @param {vec3} reflectionWC A unit vector in the direction of the reflection, in world coordinates. + * @return {vec3} The dot products of the horizon and reflection directions with the nadir, and an atmosphere boundary distance. + */ +vec3 getProceduralSkyMetrics(vec3 positionWC, vec3 reflectionWC) +{ + // Figure out if the reflection vector hits the ellipsoid + float horizonDotNadir = 1.0 - min(1.0, czm_ellipsoidRadii.x / length(positionWC)); + float reflectionDotNadir = dot(reflectionWC, normalize(positionWC)); + float atmosphereHeight = 0.05; + float smoothstepHeight = smoothstep(0.0, atmosphereHeight, horizonDotNadir); + return vec3(horizonDotNadir, reflectionDotNadir, smoothstepHeight); +} - float NdotL = clamp(dot(n, l), 0.001, 1.0); - float NdotV = abs(dot(n, v)) + 0.001; +/** + * Compute the diffuse irradiance for a procedural sky lighting model + * + * @param {vec3} skyMetrics The dot products of the horizon and reflection directions with the nadir, and an atmosphere boundary distance. + * @return {vec3} The computed diffuse irradiance + */ +vec3 getProceduralDiffuseIrradiance(vec3 skyMetrics) +{ + vec3 blueSkyDiffuseColor = vec3(0.7, 0.85, 0.9); + float diffuseIrradianceFromEarth = (1.0 - skyMetrics.x) * (skyMetrics.y * 0.25 + 0.75) * skyMetrics.z; + float diffuseIrradianceFromSky = (1.0 - skyMetrics.z) * (1.0 - (skyMetrics.y * 0.25 + 0.25)); + return blueSkyDiffuseColor * clamp(diffuseIrradianceFromEarth + diffuseIrradianceFromSky, 0.0, 1.0); +} - // Figure out if the reflection vector hits the ellipsoid - float vertexRadius = length(positionWC); - float horizonDotNadir = 1.0 - min(1.0, czm_ellipsoidRadii.x / vertexRadius); - float reflectionDotNadir = dot(r, normalize(positionWC)); +/** + * Compute the specular irradiance for a procedural sky lighting model + * + * @param {vec3} skyMetrics The dot products of the horizon and reflection directions with the nadir, and an atmosphere boundary distance. + * @return {vec3} The computed specular irradiance + */ +vec3 getProceduralSpecularIrradiance(vec3 reflectionWC, vec3 skyMetrics, float roughness) +{ // Flipping the X vector is a cheap way to get the inverse of czm_temeToPseudoFixed, since that's a rotation about Z. - r.x = -r.x; - r = -normalize(czm_temeToPseudoFixed * r); - r.x = -r.x; - - vec3 diffuseColor = pbrParameters.diffuseColor; - float roughness = pbrParameters.roughness; - vec3 specularColor = pbrParameters.f0; + reflectionWC.x = -reflectionWC.x; + reflectionWC = -normalize(czm_temeToPseudoFixed * reflectionWC); + reflectionWC.x = -reflectionWC.x; float inverseRoughness = 1.04 - roughness; inverseRoughness *= inverseRoughness; - vec3 sceneSkyBox = czm_textureCube(czm_environmentMap, r).rgb * inverseRoughness; + vec3 sceneSkyBox = czm_textureCube(czm_environmentMap, reflectionWC).rgb * inverseRoughness; - float atmosphereHeight = 0.05; - float blendRegionSize = 0.1 * ((1.0 - inverseRoughness) * 8.0 + 1.1 - horizonDotNadir); - float blendRegionOffset = roughness * -1.0; - float farAboveHorizon = clamp(horizonDotNadir - blendRegionSize * 0.5 + blendRegionOffset, 1.0e-10 - blendRegionSize, 0.99999); - float aroundHorizon = clamp(horizonDotNadir + blendRegionSize * 0.5, 1.0e-10 - blendRegionSize, 0.99999); - float farBelowHorizon = clamp(horizonDotNadir + blendRegionSize * 1.5, 1.0e-10 - blendRegionSize, 0.99999); - float smoothstepHeight = smoothstep(0.0, atmosphereHeight, horizonDotNadir); - vec3 belowHorizonColor = mix(vec3(0.1, 0.15, 0.25), vec3(0.4, 0.7, 0.9), smoothstepHeight); + // Compute colors at different angles relative to the horizon + vec3 belowHorizonColor = mix(vec3(0.1, 0.15, 0.25), vec3(0.4, 0.7, 0.9), skyMetrics.z); vec3 nadirColor = belowHorizonColor * 0.5; vec3 aboveHorizonColor = mix(vec3(0.9, 1.0, 1.2), belowHorizonColor, roughness * 0.5); - vec3 blueSkyColor = mix(vec3(0.18, 0.26, 0.48), aboveHorizonColor, reflectionDotNadir * inverseRoughness * 0.5 + 0.75); - vec3 zenithColor = mix(blueSkyColor, sceneSkyBox, smoothstepHeight); - vec3 blueSkyDiffuseColor = vec3(0.7, 0.85, 0.9); - float diffuseIrradianceFromEarth = (1.0 - horizonDotNadir) * (reflectionDotNadir * 0.25 + 0.75) * smoothstepHeight; - float diffuseIrradianceFromSky = (1.0 - smoothstepHeight) * (1.0 - (reflectionDotNadir * 0.25 + 0.25)); - vec3 diffuseIrradiance = blueSkyDiffuseColor * clamp(diffuseIrradianceFromEarth + diffuseIrradianceFromSky, 0.0, 1.0); - float notDistantRough = (1.0 - horizonDotNadir * roughness * 0.8); - vec3 specularIrradiance = mix(zenithColor, aboveHorizonColor, smoothstep(farAboveHorizon, aroundHorizon, reflectionDotNadir) * notDistantRough); - specularIrradiance = mix(specularIrradiance, belowHorizonColor, smoothstep(aroundHorizon, farBelowHorizon, reflectionDotNadir) * inverseRoughness); - specularIrradiance = mix(specularIrradiance, nadirColor, smoothstep(farBelowHorizon, 1.0, reflectionDotNadir) * inverseRoughness); - - // Luminance model from page 40 of http://silviojemma.com/public/papers/lighting/spherical-harmonic-lighting.pdf - #ifdef USE_SUN_LUMINANCE - // Angle between sun and zenith - float LdotZenith = clamp(dot(normalize(czm_inverseViewRotation * l), vWC), 0.001, 1.0); + vec3 blueSkyColor = mix(vec3(0.18, 0.26, 0.48), aboveHorizonColor, skyMetrics.y * inverseRoughness * 0.5 + 0.75); + vec3 zenithColor = mix(blueSkyColor, sceneSkyBox, skyMetrics.z); + + // Compute blend zones + float blendRegionSize = 0.1 * ((1.0 - inverseRoughness) * 8.0 + 1.1 - skyMetrics.x); + float blendRegionOffset = roughness * -1.0; + float farAboveHorizon = clamp(skyMetrics.x - blendRegionSize * 0.5 + blendRegionOffset, 1.0e-10 - blendRegionSize, 0.99999); + float aroundHorizon = clamp(skyMetrics.x + blendRegionSize * 0.5, 1.0e-10 - blendRegionSize, 0.99999); + float farBelowHorizon = clamp(skyMetrics.x + blendRegionSize * 1.5, 1.0e-10 - blendRegionSize, 0.99999); + + // Blend colors + float notDistantRough = (1.0 - skyMetrics.x * roughness * 0.8); + vec3 specularIrradiance = mix(zenithColor, aboveHorizonColor, smoothstep(farAboveHorizon, aroundHorizon, skyMetrics.y) * notDistantRough); + specularIrradiance = mix(specularIrradiance, belowHorizonColor, smoothstep(aroundHorizon, farBelowHorizon, skyMetrics.y) * inverseRoughness); + specularIrradiance = mix(specularIrradiance, nadirColor, smoothstep(farBelowHorizon, 1.0, skyMetrics.y) * inverseRoughness); + + return specularIrradiance; +} + +#ifdef USE_SUN_LUMINANCE +float clampedDot(vec3 x, vec3 y) +{ + return clamp(dot(x, y), 0.001, 1.0); +} +/** + * Sun luminance following the "CIE Clear Sky Model" + * See page 40 of https://3dvar.com/Green2003Spherical.pdf + * + * @param {vec3} positionWC The position of the fragment in world coordinates. + * @param {vec3} normalEC The surface normal in eye coordinates. + * @param {vec3} lightDirectionEC Unit vector pointing to the light source in eye coordinates. + * @return {float} The computed sun luminance. + */ +float getSunLuminance(vec3 positionWC, vec3 normalEC, vec3 lightDirectionEC) +{ + vec3 normalWC = normalize(czm_inverseViewRotation * normalEC); + vec3 lightDirectionWC = normalize(czm_inverseViewRotation * lightDirectionEC); + vec3 vWC = -normalize(positionWC); + + // Angle between sun and zenith. + float LdotZenith = clampedDot(lightDirectionWC, vWC); float S = acos(LdotZenith); // Angle between zenith and current pixel - float NdotZenith = clamp(dot(normalize(czm_inverseViewRotation * n), vWC), 0.001, 1.0); + float NdotZenith = clampedDot(normalWC, vWC); // Angle between sun and current pixel + float NdotL = clampedDot(normalEC, lightDirectionEC); float gamma = acos(NdotL); - float numerator = ((0.91 + 10.0 * exp(-3.0 * gamma) + 0.45 * pow(NdotL, 2.0)) * (1.0 - exp(-0.32 / NdotZenith))); - float denominator = (0.91 + 10.0 * exp(-3.0 * S) + 0.45 * pow(LdotZenith,2.0)) * (1.0 - exp(-0.32)); - float luminance = model_luminanceAtZenith * (numerator / denominator); - #endif + float numerator = ((0.91 + 10.0 * exp(-3.0 * gamma) + 0.45 * NdotL * NdotL) * (1.0 - exp(-0.32 / NdotZenith))); + float denominator = (0.91 + 10.0 * exp(-3.0 * S) + 0.45 * LdotZenith * LdotZenith) * (1.0 - exp(-0.32)); + return model_luminanceAtZenith * (numerator / denominator); +} +#endif + +/** + * Compute the light contribution from a procedural sky model + * + * @param {vec3} positionEC The position of the fragment in eye coordinates. + * @param {vec3} normalEC The surface normal in eye coordinates. + * @param {vec3} lightDirectionEC Unit vector pointing to the light source in eye coordinates. + * @param {czm_modelMaterial} The material properties. + * @return {vec3} The computed HDR color + */ + vec3 proceduralIBL( + vec3 positionEC, + vec3 normalEC, + vec3 lightDirectionEC, + czm_modelMaterial material +) { + vec3 viewDirectionEC = -normalize(positionEC); + vec3 positionWC = vec3(czm_inverseView * vec4(positionEC, 1.0)); + vec3 reflectionWC = normalize(czm_inverseViewRotation * normalize(reflect(viewDirectionEC, normalEC))); + vec3 skyMetrics = getProceduralSkyMetrics(positionWC, reflectionWC); + + float roughness = material.roughness; + vec3 f0 = material.specular; + + vec3 specularIrradiance = getProceduralSpecularIrradiance(reflectionWC, skyMetrics, roughness); + float NdotV = abs(dot(normalEC, viewDirectionEC)) + 0.001; vec2 brdfLut = texture(czm_brdfLut, vec2(NdotV, roughness)).rg; - vec3 iblColor = (diffuseIrradiance * diffuseColor * model_iblFactor.x) + (specularIrradiance * czm_srgbToLinear(specularColor * brdfLut.x + brdfLut.y) * model_iblFactor.y); - float maximumComponent = max(max(lightColorHdr.x, lightColorHdr.y), lightColorHdr.z); - vec3 lightColor = lightColorHdr / max(maximumComponent, 1.0); - iblColor *= lightColor; + vec3 specularColor = czm_srgbToLinear(f0 * brdfLut.x + brdfLut.y); + vec3 specularContribution = specularIrradiance * specularColor * model_iblFactor.y; + #ifdef USE_SPECULAR + specularContribution *= material.specularWeight; + #endif + + vec3 diffuseIrradiance = getProceduralDiffuseIrradiance(skyMetrics); + vec3 diffuseColor = material.diffuse; + vec3 diffuseContribution = diffuseIrradiance * diffuseColor * model_iblFactor.x; - #ifdef USE_SUN_LUMINANCE - iblColor *= luminance; + vec3 iblColor = specularContribution + diffuseContribution; + + #ifdef USE_SUN_LUMINANCE + iblColor *= getSunLuminance(positionWC, normalEC, lightDirectionEC); #endif return iblColor; } +#ifdef DIFFUSE_IBL +vec3 computeDiffuseIBL(vec3 cubeDir) +{ + #ifdef CUSTOM_SPHERICAL_HARMONICS + return czm_sphericalHarmonics(cubeDir, model_sphericalHarmonicCoefficients); + #else + return czm_sphericalHarmonics(cubeDir, czm_sphericalHarmonicCoefficients); + #endif +} +#endif + +#ifdef SPECULAR_IBL +vec3 sampleSpecularEnvironment(vec3 cubeDir, float roughness) +{ + #ifdef CUSTOM_SPECULAR_IBL + float maxLod = model_specularEnvironmentMapsMaximumLOD; + float lod = roughness * maxLod; + return czm_sampleOctahedralProjection(model_specularEnvironmentMaps, model_specularEnvironmentMapsSize, cubeDir, lod, maxLod); + #else + float maxLod = czm_specularEnvironmentMapsMaximumLOD; + float lod = roughness * maxLod; + return czm_sampleOctahedralProjection(czm_specularEnvironmentMaps, czm_specularEnvironmentMapSize, cubeDir, lod, maxLod); + #endif +} +vec3 computeSpecularIBL(vec3 cubeDir, float NdotV, float VdotH, vec3 f0, float roughness) +{ + float reflectance = czm_maximumComponent(f0); + vec3 f90 = vec3(clamp(reflectance * 25.0, 0.0, 1.0)); + vec3 F = fresnelSchlick2(f0, f90, VdotH); + + vec2 brdfLut = texture(czm_brdfLut, vec2(NdotV, roughness)).rg; + vec3 specularSample = sampleSpecularEnvironment(cubeDir, roughness); + + return specularSample * (F * brdfLut.x + brdfLut.y); +} +#endif + #if defined(DIFFUSE_IBL) || defined(SPECULAR_IBL) +/** + * Compute the light contributions from environment maps and spherical harmonic coefficients + * + * @param {vec3} viewDirectionEC Unit vector pointing from the fragment to the eye position + * @param {vec3} normalEC The surface normal in eye coordinates + * @param {vec3} lightDirectionEC Unit vector pointing to the light source in eye coordinates. + * @param {czm_modelMaterial} The material properties. + * @return {vec3} The computed HDR color + */ vec3 textureIBL( - vec3 positionEC, + vec3 viewDirectionEC, vec3 normalEC, vec3 lightDirectionEC, - czm_pbrParameters pbrParameters + czm_modelMaterial material ) { - vec3 diffuseColor = pbrParameters.diffuseColor; - float roughness = pbrParameters.roughness; - vec3 specularColor = pbrParameters.f0; - - vec3 v = -positionEC; - vec3 n = normalEC; - vec3 l = normalize(lightDirectionEC); - vec3 h = normalize(v + l); - - float NdotV = abs(dot(n, v)) + 0.001; - float VdotH = clamp(dot(v, h), 0.0, 1.0); - - const mat3 yUpToZUp = mat3( - -1.0, 0.0, 0.0, - 0.0, 0.0, -1.0, - 0.0, 1.0, 0.0 - ); - vec3 cubeDir = normalize(yUpToZUp * model_iblReferenceFrameMatrix * normalize(reflect(-v, n))); - - #ifdef DIFFUSE_IBL - #ifdef CUSTOM_SPHERICAL_HARMONICS - vec3 diffuseIrradiance = czm_sphericalHarmonics(cubeDir, model_sphericalHarmonicCoefficients); - #else - vec3 diffuseIrradiance = czm_sphericalHarmonics(cubeDir, czm_sphericalHarmonicCoefficients); - #endif - #else - vec3 diffuseIrradiance = vec3(0.0); - #endif + // Find the direction in which to sample the environment map + vec3 cubeDir = normalize(model_iblReferenceFrameMatrix * normalize(reflect(-viewDirectionEC, normalEC))); + + #ifdef DIFFUSE_IBL + vec3 diffuseContribution = computeDiffuseIBL(cubeDir) * material.diffuse; + #else + vec3 diffuseContribution = vec3(0.0); + #endif + + float roughness = material.roughness; + + #ifdef USE_ANISOTROPY + // Update environment map sampling direction to account for anisotropic distortion of specular reflection + vec3 anisotropyDirection = material.anisotropicB; + vec3 anisotropicTangent = cross(anisotropyDirection, viewDirectionEC); + vec3 anisotropicNormal = cross(anisotropicTangent, anisotropyDirection); + float bendFactor = 1.0 - material.anisotropyStrength * (1.0 - roughness); + float bendFactorPow4 = bendFactor * bendFactor * bendFactor * bendFactor; + vec3 bentNormal = normalize(mix(anisotropicNormal, normalEC, bendFactorPow4)); + cubeDir = normalize(model_iblReferenceFrameMatrix * normalize(reflect(-viewDirectionEC, bentNormal))); + #endif #ifdef SPECULAR_IBL - vec3 r0 = specularColor.rgb; - float reflectance = max(max(r0.r, r0.g), r0.b); - vec3 r90 = vec3(clamp(reflectance * 25.0, 0.0, 1.0)); - vec3 F = fresnelSchlick2(r0, r90, VdotH); - - vec2 brdfLut = texture(czm_brdfLut, vec2(NdotV, roughness)).rg; - #ifdef CUSTOM_SPECULAR_IBL - vec3 specularIBL = czm_sampleOctahedralProjection(model_specularEnvironmentMaps, model_specularEnvironmentMapsSize, cubeDir, roughness * model_specularEnvironmentMapsMaximumLOD, model_specularEnvironmentMapsMaximumLOD); - #else - vec3 specularIBL = czm_sampleOctahedralProjection(czm_specularEnvironmentMaps, czm_specularEnvironmentMapSize, cubeDir, roughness * czm_specularEnvironmentMapsMaximumLOD, czm_specularEnvironmentMapsMaximumLOD); - #endif - specularIBL *= F * brdfLut.x + brdfLut.y; - #else - vec3 specularIBL = vec3(0.0); + float NdotV = abs(dot(normalEC, viewDirectionEC)) + 0.001; + vec3 halfwayDirectionEC = normalize(viewDirectionEC + lightDirectionEC); + float VdotH = clamp(dot(viewDirectionEC, halfwayDirectionEC), 0.0, 1.0); + vec3 f0 = material.specular; + vec3 specularContribution = computeSpecularIBL(cubeDir, NdotV, VdotH, f0, roughness); + #else + vec3 specularContribution = vec3(0.0); + #endif + + #ifdef USE_SPECULAR + specularContribution *= material.specularWeight; #endif - return diffuseColor * diffuseIrradiance + specularColor * specularIBL; + return diffuseContribution + specularContribution; } #endif - -vec3 imageBasedLightingStage( - vec3 positionEC, - vec3 normalEC, - vec3 lightDirectionEC, - vec3 lightColorHdr, - czm_pbrParameters pbrParameters -) { - #if defined(DIFFUSE_IBL) || defined(SPECULAR_IBL) - // Environment maps were provided, use them for IBL - return textureIBL( - positionEC, - normalEC, - lightDirectionEC, - pbrParameters - ); - #else - // Use the procedural IBL if there are no environment maps - return proceduralIBL( - positionEC, - normalEC, - lightDirectionEC, - lightColorHdr, - pbrParameters - ); - #endif -} \ No newline at end of file diff --git a/packages/engine/Source/Shaders/Model/LightingStageFS.glsl b/packages/engine/Source/Shaders/Model/LightingStageFS.glsl index 77965e25f69..2b04c170871 100644 --- a/packages/engine/Source/Shaders/Model/LightingStageFS.glsl +++ b/packages/engine/Source/Shaders/Model/LightingStageFS.glsl @@ -1,72 +1,137 @@ -#ifdef LIGHTING_PBR -vec3 computePbrLighting(czm_modelMaterial inputMaterial, ProcessedAttributes attributes) +#ifdef USE_IBL_LIGHTING +vec3 computeIBL(vec3 position, vec3 normal, vec3 lightDirection, vec3 lightColorHdr, czm_modelMaterial material) { - czm_pbrParameters pbrParameters; - pbrParameters.diffuseColor = inputMaterial.diffuse; - pbrParameters.f0 = inputMaterial.specular; - pbrParameters.roughness = inputMaterial.roughness; - - #ifdef USE_CUSTOM_LIGHT_COLOR - vec3 lightColorHdr = model_lightColorHdr; + #if defined(DIFFUSE_IBL) || defined(SPECULAR_IBL) + // Environment maps were provided, use them for IBL + vec3 viewDirection = -normalize(position); + vec3 iblColor = textureIBL(viewDirection, normal, lightDirection, material); #else - vec3 lightColorHdr = czm_lightColorHdr; + // Use procedural IBL if there are no environment maps + vec3 imageBasedLighting = proceduralIBL(position, normal, lightDirection, material); + float maximumComponent = czm_maximumComponent(lightColorHdr); + vec3 clampedLightColor = lightColorHdr / max(maximumComponent, 1.0); + vec3 iblColor = clampedLightColor * imageBasedLighting; #endif + return iblColor * material.occlusion; +} +#endif + +#ifdef USE_CLEARCOAT +vec3 addClearcoatReflection(vec3 baseLayerColor, vec3 position, vec3 lightDirection, vec3 lightColorHdr, czm_modelMaterial material) +{ + vec3 viewDirection = -normalize(position); + vec3 halfwayDirection = normalize(viewDirection + lightDirection); + vec3 normal = material.clearcoatNormal; + float NdotL = clamp(dot(normal, lightDirection), 0.001, 1.0); + + // clearcoatF0 = vec3(pow((ior - 1.0) / (ior + 1.0), 2.0)), but without KHR_materials_ior, ior is a constant 1.5. + vec3 f0 = vec3(0.04); + vec3 f90 = vec3(1.0); + // Note: clearcoat Fresnel computed with dot(n, v) instead of dot(v, h). + // This is to make it energy conserving with a simple layering function. + float NdotV = clamp(dot(normal, viewDirection), 0.0, 1.0); + vec3 F = fresnelSchlick2(f0, f90, NdotV); - vec3 color = inputMaterial.diffuse; - #ifdef HAS_NORMALS - color = czm_pbrLighting( - attributes.positionEC, - inputMaterial.normalEC, - czm_lightDirectionEC, - lightColorHdr, - pbrParameters - ); - - #ifdef USE_IBL_LIGHTING - color += imageBasedLightingStage( - attributes.positionEC, - inputMaterial.normalEC, - czm_lightDirectionEC, - lightColorHdr, - pbrParameters - ); + // compute specular reflection from direct lighting + float roughness = material.clearcoatRoughness; + float directStrength = computeDirectSpecularStrength(normal, lightDirection, viewDirection, halfwayDirection, roughness); + vec3 directReflection = F * directStrength * NdotL; + vec3 color = lightColorHdr * directReflection; + + #ifdef SPECULAR_IBL + // Find the direction in which to sample the environment map + vec3 cubeDir = normalize(model_iblReferenceFrameMatrix * normalize(reflect(-viewDirection, normal))); + vec3 iblColor = computeSpecularIBL(cubeDir, NdotV, NdotV, f0, roughness); + color += iblColor * material.occlusion; + #elif defined(USE_IBL_LIGHTING) + vec3 positionWC = vec3(czm_inverseView * vec4(position, 1.0)); + vec3 reflectionWC = normalize(czm_inverseViewRotation * normalize(reflect(viewDirection, normal))); + vec3 skyMetrics = getProceduralSkyMetrics(positionWC, reflectionWC); + + vec3 specularIrradiance = getProceduralSpecularIrradiance(reflectionWC, skyMetrics, roughness); + vec2 brdfLut = texture(czm_brdfLut, vec2(NdotV, roughness)).rg; + vec3 specularColor = czm_srgbToLinear(f0 * brdfLut.x + brdfLut.y); + vec3 iblColor = specularIrradiance * specularColor * model_iblFactor.y; + #ifdef USE_SUN_LUMINANCE + iblColor *= getSunLuminance(positionWC, normal, lightDirection); #endif + float maximumComponent = czm_maximumComponent(lightColorHdr); + vec3 clampedLightColor = lightColorHdr / max(maximumComponent, 1.0); + color += clampedLightColor* iblColor * material.occlusion; + #endif + + float clearcoatFactor = material.clearcoatFactor; + vec3 clearcoatColor = color * clearcoatFactor; + + // Dim base layer based on transmission loss through clearcoat + return baseLayerColor * (1.0 - clearcoatFactor * F) + clearcoatColor; +} +#endif + +#if defined(LIGHTING_PBR) && defined(HAS_NORMALS) +vec3 computePbrLighting(in czm_modelMaterial material, in vec3 position) +{ + #ifdef USE_CUSTOM_LIGHT_COLOR + vec3 lightColorHdr = model_lightColorHdr; + #else + vec3 lightColorHdr = czm_lightColorHdr; #endif - color *= inputMaterial.occlusion; - color += inputMaterial.emissive; + vec3 viewDirection = -normalize(position); + vec3 normal = material.normalEC; + vec3 lightDirection = normalize(czm_lightDirectionEC); + + vec3 directLighting = czm_pbrLighting(viewDirection, normal, lightDirection, material); + vec3 directColor = lightColorHdr * directLighting; - // In HDR mode, the frame buffer is in linear color space. The - // post-processing stages (see PostProcessStageCollection) will handle - // tonemapping. However, if HDR is not enabled, we must tonemap else large - // values may be clamped to 1.0 - #ifndef HDR - color = czm_acesTonemapping(color); - #endif + // Accumulate colors from base layer + vec3 color = directColor + material.emissive; + #ifdef USE_IBL_LIGHTING + color += computeIBL(position, normal, lightDirection, lightColorHdr, material); + #endif + + #ifdef USE_CLEARCOAT + color = addClearcoatReflection(color, position, lightDirection, lightColorHdr, material); + #endif return color; } #endif +/** + * Compute the material color under the current lighting conditions. + * All other material properties are passed through so further stages + * have access to them. + * + * @param {czm_modelMaterial} material The material properties from {@MaterialStageFS} + * @param {ProcessedAttributes} attributes + */ void lightingStage(inout czm_modelMaterial material, ProcessedAttributes attributes) { - // Even though the lighting will only set the diffuse color, - // pass all other properties so further stages have access to them. - vec3 color = vec3(0.0); - #ifdef LIGHTING_PBR - color = computePbrLighting(material, attributes); + #ifdef HAS_NORMALS + vec3 color = computePbrLighting(material, attributes.positionEC); + #else + vec3 color = material.diffuse * material.occlusion + material.emissive; + #endif + // In HDR mode, the frame buffer is in linear color space. The + // post-processing stages (see PostProcessStageCollection) will handle + // tonemapping. However, if HDR is not enabled, we must tonemap else large + // values may be clamped to 1.0 + #ifndef HDR + color = czm_acesTonemapping(color); + #endif #else // unlit - color = material.diffuse; + vec3 color = material.diffuse; #endif #ifdef HAS_POINT_CLOUD_COLOR_STYLE - // The colors resulting from point cloud styles are adjusted differently. - color = czm_gammaCorrect(color); + // The colors resulting from point cloud styles are adjusted differently. + color = czm_gammaCorrect(color); #elif !defined(HDR) - // If HDR is not enabled, the frame buffer stores sRGB colors rather than - // linear colors so the linear value must be converted. - color = czm_linearToSrgb(color); + // If HDR is not enabled, the frame buffer stores sRGB colors rather than + // linear colors so the linear value must be converted. + color = czm_linearToSrgb(color); #endif material.diffuse = color; diff --git a/packages/engine/Source/Shaders/Model/MaterialStageFS.glsl b/packages/engine/Source/Shaders/Model/MaterialStageFS.glsl index 784c9274b97..b4326757bd3 100644 --- a/packages/engine/Source/Shaders/Model/MaterialStageFS.glsl +++ b/packages/engine/Source/Shaders/Model/MaterialStageFS.glsl @@ -16,211 +16,473 @@ vec2 computeTextureTransform(vec2 texCoord, mat3 textureTransform) return vec2(textureTransform * vec3(texCoord, 1.0)); } -#ifdef HAS_NORMALS -vec3 computeNormal(ProcessedAttributes attributes) +#ifdef HAS_NORMAL_TEXTURE +vec2 getNormalTexCoords() { - // Geometry normal. This is already normalized - vec3 ng = attributes.normalEC; + vec2 texCoord = TEXCOORD_NORMAL; + #ifdef HAS_NORMAL_TEXTURE_TRANSFORM + texCoord = vec2(u_normalTextureTransform * vec3(texCoord, 1.0)); + #endif + return texCoord; +} +#endif - vec3 normal = ng; - #if defined(HAS_NORMAL_TEXTURE) && !defined(HAS_WIREFRAME) - vec2 normalTexCoords = TEXCOORD_NORMAL; - #ifdef HAS_NORMAL_TEXTURE_TRANSFORM - normalTexCoords = computeTextureTransform(normalTexCoords, u_normalTextureTransform); - #endif +#if defined(HAS_NORMAL_TEXTURE) || defined(HAS_CLEARCOAT_NORMAL_TEXTURE) +vec3 computeTangent(in vec3 position, in vec2 normalTexCoords) +{ + vec2 tex_dx = dFdx(normalTexCoords); + vec2 tex_dy = dFdy(normalTexCoords); + float determinant = tex_dx.x * tex_dy.y - tex_dy.x * tex_dx.y; + vec3 tangent = tex_dy.t * dFdx(position) - tex_dx.t * dFdy(position); + return tangent / determinant; +} +#endif - // If HAS_BITANGENTS is set, then HAS_TANGENTS is also set - #ifdef HAS_BITANGENTS - vec3 t = attributes.tangentEC; - vec3 b = attributes.bitangentEC; - mat3 tbn = mat3(t, b, ng); - vec3 n = texture(u_normalTexture, normalTexCoords).rgb; - normal = normalize(tbn * (2.0 * n - 1.0)); - #elif (__VERSION__ == 300 || defined(GL_OES_standard_derivatives)) - // If derivatives are available (not IE 10), compute tangents - vec3 positionEC = attributes.positionEC; - vec3 pos_dx = dFdx(positionEC); - vec3 pos_dy = dFdy(positionEC); - vec3 tex_dx = dFdx(vec3(normalTexCoords,0.0)); - vec3 tex_dy = dFdy(vec3(normalTexCoords,0.0)); - vec3 t = (tex_dy.t * pos_dx - tex_dx.t * pos_dy) / (tex_dx.s * tex_dy.t - tex_dy.s * tex_dx.t); - t = normalize(t - ng * dot(ng, t)); - vec3 b = normalize(cross(ng, t)); - mat3 tbn = mat3(t, b, ng); - vec3 n = texture(u_normalTexture, normalTexCoords).rgb; - normal = normalize(tbn * (2.0 * n - 1.0)); - #endif +#ifdef USE_ANISOTROPY +struct NormalInfo { + vec3 tangent; + vec3 bitangent; + vec3 normal; + vec3 geometryNormal; +}; + +NormalInfo getNormalInfo(ProcessedAttributes attributes) +{ + vec3 geometryNormal = attributes.normalEC; + #ifdef HAS_NORMAL_TEXTURE + vec2 normalTexCoords = getNormalTexCoords(); + #endif + + #ifdef HAS_BITANGENTS + vec3 tangent = attributes.tangentEC; + vec3 bitangent = attributes.bitangentEC; + #else // Assume HAS_NORMAL_TEXTURE + vec3 tangent = computeTangent(attributes.positionEC, normalTexCoords); + tangent = normalize(tangent - geometryNormal * dot(geometryNormal, tangent)); + vec3 bitangent = normalize(cross(geometryNormal, tangent)); + #endif + + #ifdef HAS_NORMAL_TEXTURE + mat3 tbn = mat3(tangent, bitangent, geometryNormal); + vec3 normalSample = texture(u_normalTexture, normalTexCoords).rgb; + vec3 normal = normalize(tbn * (2.0 * normalSample - 1.0)); + #else + vec3 normal = geometryNormal; #endif #ifdef HAS_DOUBLE_SIDED_MATERIAL - if (czm_backFacing()) { - normal = -normal; - } + if (czm_backFacing()) { + tangent *= -1.0; + bitangent *= -1.0; + normal *= -1.0; + geometryNormal *= -1.0; + } #endif - return normal; + NormalInfo normalInfo; + normalInfo.tangent = tangent; + normalInfo.bitangent = bitangent; + normalInfo.normal = normal; + normalInfo.geometryNormal = geometryNormal; + + return normalInfo; } #endif -void materialStage(inout czm_modelMaterial material, ProcessedAttributes attributes, SelectedFeature feature) +#if defined(HAS_NORMAL_TEXTURE) && !defined(HAS_WIREFRAME) +vec3 getNormalFromTexture(ProcessedAttributes attributes, vec3 geometryNormal) { - #ifdef HAS_NORMALS - material.normalEC = computeNormal(attributes); + vec2 normalTexCoords = getNormalTexCoords(); + + // If HAS_BITANGENTS is set, then HAS_TANGENTS is also set + #ifdef HAS_BITANGENTS + vec3 t = attributes.tangentEC; + vec3 b = attributes.bitangentEC; + #else + vec3 t = computeTangent(attributes.positionEC, normalTexCoords); + t = normalize(t - geometryNormal * dot(geometryNormal, t)); + vec3 b = normalize(cross(geometryNormal, t)); #endif - vec4 baseColorWithAlpha = vec4(1.0); - // Regardless of whether we use PBR, set a base color - #ifdef HAS_BASE_COLOR_TEXTURE - vec2 baseColorTexCoords = TEXCOORD_BASE_COLOR; + mat3 tbn = mat3(t, b, geometryNormal); + vec3 n = texture(u_normalTexture, normalTexCoords).rgb; + vec3 textureNormal = normalize(tbn * (2.0 * n - 1.0)); - #ifdef HAS_BASE_COLOR_TEXTURE_TRANSFORM - baseColorTexCoords = computeTextureTransform(baseColorTexCoords, u_baseColorTextureTransform); - #endif + return textureNormal; +} +#endif - baseColorWithAlpha = czm_srgbToLinear(texture(u_baseColorTexture, baseColorTexCoords)); +#ifdef HAS_CLEARCOAT_NORMAL_TEXTURE +vec3 getClearcoatNormalFromTexture(ProcessedAttributes attributes, vec3 geometryNormal) +{ + vec2 normalTexCoords = TEXCOORD_CLEARCOAT_NORMAL; + #ifdef HAS_CLEARCOAT_NORMAL_TEXTURE_TRANSFORM + normalTexCoords = vec2(u_clearcoatNormalTextureTransform * vec3(normalTexCoords, 1.0)); + #endif - #ifdef HAS_BASE_COLOR_FACTOR - baseColorWithAlpha *= u_baseColorFactor; - #endif - #elif defined(HAS_BASE_COLOR_FACTOR) - baseColorWithAlpha = u_baseColorFactor; + // If HAS_BITANGENTS is set, then HAS_TANGENTS is also set + #ifdef HAS_BITANGENTS + vec3 t = attributes.tangentEC; + vec3 b = attributes.bitangentEC; + #else + vec3 t = computeTangent(attributes.positionEC, normalTexCoords); + t = normalize(t - geometryNormal * dot(geometryNormal, t)); + vec3 b = normalize(cross(geometryNormal, t)); #endif - #ifdef HAS_POINT_CLOUD_COLOR_STYLE - baseColorWithAlpha = v_pointCloudColor; - #elif defined(HAS_COLOR_0) - vec4 color = attributes.color_0; - // .pnts files store colors in the sRGB color space - #ifdef HAS_SRGB_COLOR - color = czm_srgbToLinear(color); - #endif - baseColorWithAlpha *= color; + mat3 tbn = mat3(t, b, geometryNormal); + vec3 n = texture(u_clearcoatNormalTexture, normalTexCoords).rgb; + vec3 textureNormal = normalize(tbn * (2.0 * n - 1.0)); + + return textureNormal; +} +#endif + +#ifdef HAS_NORMALS +vec3 computeNormal(ProcessedAttributes attributes) +{ + // Geometry normal. This is already normalized + vec3 normal = attributes.normalEC; + + #if defined(HAS_NORMAL_TEXTURE) && !defined(HAS_WIREFRAME) + normal = getNormalFromTexture(attributes, normal); #endif - material.diffuse = baseColorWithAlpha.rgb; - material.alpha = baseColorWithAlpha.a; + #ifdef HAS_DOUBLE_SIDED_MATERIAL + if (czm_backFacing()) { + normal = -normal; + } + #endif - #ifdef USE_CPU_STYLING - material.diffuse = blend(material.diffuse, feature.color.rgb, model_colorBlend); + return normal; +} +#endif + +#ifdef HAS_BASE_COLOR_TEXTURE +vec4 getBaseColorFromTexture() +{ + vec2 baseColorTexCoords = TEXCOORD_BASE_COLOR; + #ifdef HAS_BASE_COLOR_TEXTURE_TRANSFORM + baseColorTexCoords = computeTextureTransform(baseColorTexCoords, u_baseColorTextureTransform); #endif - #ifdef HAS_OCCLUSION_TEXTURE - vec2 occlusionTexCoords = TEXCOORD_OCCLUSION; - #ifdef HAS_OCCLUSION_TEXTURE_TRANSFORM - occlusionTexCoords = computeTextureTransform(occlusionTexCoords, u_occlusionTextureTransform); - #endif - material.occlusion = texture(u_occlusionTexture, occlusionTexCoords).r; + vec4 baseColorWithAlpha = czm_srgbToLinear(texture(u_baseColorTexture, baseColorTexCoords)); + + #ifdef HAS_BASE_COLOR_FACTOR + baseColorWithAlpha *= u_baseColorFactor; #endif - #ifdef HAS_EMISSIVE_TEXTURE + return baseColorWithAlpha; +} +#endif + +#ifdef HAS_EMISSIVE_TEXTURE +vec3 getEmissiveFromTexture() +{ vec2 emissiveTexCoords = TEXCOORD_EMISSIVE; - #ifdef HAS_EMISSIVE_TEXTURE_TRANSFORM + #ifdef HAS_EMISSIVE_TEXTURE_TRANSFORM emissiveTexCoords = computeTextureTransform(emissiveTexCoords, u_emissiveTextureTransform); - #endif + #endif vec3 emissive = czm_srgbToLinear(texture(u_emissiveTexture, emissiveTexCoords).rgb); - #ifdef HAS_EMISSIVE_FACTOR + #ifdef HAS_EMISSIVE_FACTOR emissive *= u_emissiveFactor; - #endif - material.emissive = emissive; - #elif defined(HAS_EMISSIVE_FACTOR) - material.emissive = u_emissiveFactor; #endif - #if defined(LIGHTING_PBR) && defined(USE_SPECULAR_GLOSSINESS) - #ifdef HAS_SPECULAR_GLOSSINESS_TEXTURE + return emissive; +} +#endif + +#if defined(LIGHTING_PBR) && defined(USE_SPECULAR_GLOSSINESS) +void setSpecularGlossiness(inout czm_modelMaterial material) +{ + #ifdef HAS_SPECULAR_GLOSSINESS_TEXTURE vec2 specularGlossinessTexCoords = TEXCOORD_SPECULAR_GLOSSINESS; - #ifdef HAS_SPECULAR_GLOSSINESS_TEXTURE_TRANSFORM - specularGlossinessTexCoords = computeTextureTransform(specularGlossinessTexCoords, u_specularGlossinessTextureTransform); - #endif + #ifdef HAS_SPECULAR_GLOSSINESS_TEXTURE_TRANSFORM + specularGlossinessTexCoords = computeTextureTransform(specularGlossinessTexCoords, u_specularGlossinessTextureTransform); + #endif vec4 specularGlossiness = czm_srgbToLinear(texture(u_specularGlossinessTexture, specularGlossinessTexCoords)); vec3 specular = specularGlossiness.rgb; float glossiness = specularGlossiness.a; - #ifdef HAS_SPECULAR_FACTOR - specular *= u_specularFactor; - #endif + #ifdef HAS_LEGACY_SPECULAR_FACTOR + specular *= u_legacySpecularFactor; + #endif - #ifdef HAS_GLOSSINESS_FACTOR + #ifdef HAS_GLOSSINESS_FACTOR glossiness *= u_glossinessFactor; - #endif + #endif + #else + #ifdef HAS_LEGACY_SPECULAR_FACTOR + vec3 specular = clamp(u_legacySpecularFactor, vec3(0.0), vec3(1.0)); #else - #ifdef HAS_SPECULAR_FACTOR - vec3 specular = clamp(u_specularFactor, vec3(0.0), vec3(1.0)); - #else vec3 specular = vec3(1.0); - #endif + #endif - #ifdef HAS_GLOSSINESS_FACTOR + #ifdef HAS_GLOSSINESS_FACTOR float glossiness = clamp(u_glossinessFactor, 0.0, 1.0); - #else + #else float glossiness = 1.0; - #endif #endif + #endif - #ifdef HAS_DIFFUSE_TEXTURE + #ifdef HAS_DIFFUSE_TEXTURE vec2 diffuseTexCoords = TEXCOORD_DIFFUSE; - #ifdef HAS_DIFFUSE_TEXTURE_TRANSFORM + #ifdef HAS_DIFFUSE_TEXTURE_TRANSFORM diffuseTexCoords = computeTextureTransform(diffuseTexCoords, u_diffuseTextureTransform); - #endif + #endif vec4 diffuse = czm_srgbToLinear(texture(u_diffuseTexture, diffuseTexCoords)); - #ifdef HAS_DIFFUSE_FACTOR + #ifdef HAS_DIFFUSE_FACTOR diffuse *= u_diffuseFactor; - #endif - #elif defined(HAS_DIFFUSE_FACTOR) + #endif + #elif defined(HAS_DIFFUSE_FACTOR) vec4 diffuse = clamp(u_diffuseFactor, vec4(0.0), vec4(1.0)); - #else + #else vec4 diffuse = vec4(1.0); - #endif - czm_pbrParameters parameters = czm_pbrSpecularGlossinessMaterial( - diffuse.rgb, - specular, - glossiness - ); - material.diffuse = parameters.diffuseColor; + #endif + + material.diffuse = diffuse.rgb * (1.0 - czm_maximumComponent(specular)); // the specular glossiness extension's alpha overrides anything set // by the base material. material.alpha = diffuse.a; - material.specular = parameters.f0; - material.roughness = parameters.roughness; - #elif defined(LIGHTING_PBR) - #ifdef HAS_METALLIC_ROUGHNESS_TEXTURE + + material.specular = specular; + + // glossiness is the opposite of roughness, but easier for artists to use. + float roughness = 1.0 - glossiness; + material.roughness = roughness * roughness; +} +#elif defined(LIGHTING_PBR) +float setMetallicRoughness(inout czm_modelMaterial material) +{ + #ifdef HAS_METALLIC_ROUGHNESS_TEXTURE vec2 metallicRoughnessTexCoords = TEXCOORD_METALLIC_ROUGHNESS; - #ifdef HAS_METALLIC_ROUGHNESS_TEXTURE_TRANSFORM + #ifdef HAS_METALLIC_ROUGHNESS_TEXTURE_TRANSFORM metallicRoughnessTexCoords = computeTextureTransform(metallicRoughnessTexCoords, u_metallicRoughnessTextureTransform); - #endif + #endif vec3 metallicRoughness = texture(u_metallicRoughnessTexture, metallicRoughnessTexCoords).rgb; float metalness = clamp(metallicRoughness.b, 0.0, 1.0); float roughness = clamp(metallicRoughness.g, 0.04, 1.0); - #ifdef HAS_METALLIC_FACTOR - metalness *= u_metallicFactor; - #endif + #ifdef HAS_METALLIC_FACTOR + metalness = clamp(metalness * u_metallicFactor, 0.0, 1.0); + #endif - #ifdef HAS_ROUGHNESS_FACTOR - roughness *= u_roughnessFactor; - #endif - #else - #ifdef HAS_METALLIC_FACTOR + #ifdef HAS_ROUGHNESS_FACTOR + roughness = clamp(roughness * u_roughnessFactor, 0.0, 1.0); + #endif + #else + #ifdef HAS_METALLIC_FACTOR float metalness = clamp(u_metallicFactor, 0.0, 1.0); - #else + #else float metalness = 1.0; - #endif + #endif - #ifdef HAS_ROUGHNESS_FACTOR + #ifdef HAS_ROUGHNESS_FACTOR float roughness = clamp(u_roughnessFactor, 0.04, 1.0); - #else + #else float roughness = 1.0; - #endif - #endif - czm_pbrParameters parameters = czm_pbrMetallicRoughnessMaterial( - material.diffuse, - metalness, - roughness - ); - material.diffuse = parameters.diffuseColor; - material.specular = parameters.f0; - material.roughness = parameters.roughness; + #endif + #endif + + // dielectrics use f0 = 0.04, metals use albedo as f0 + const vec3 REFLECTANCE_DIELECTRIC = vec3(0.04); + vec3 f0 = mix(REFLECTANCE_DIELECTRIC, material.diffuse, metalness); + + material.specular = f0; + + // diffuse only applies to dielectrics. + material.diffuse = material.diffuse * (1.0 - f0) * (1.0 - metalness); + + // roughness is authored as perceptual roughness + // square it to get material roughness + material.roughness = roughness * roughness; + + return metalness; +} +#ifdef USE_SPECULAR +void setSpecular(inout czm_modelMaterial material, in float metalness) +{ + #ifdef HAS_SPECULAR_TEXTURE + vec2 specularTexCoords = TEXCOORD_SPECULAR; + #ifdef HAS_SPECULAR_TEXTURE_TRANSFORM + specularTexCoords = computeTextureTransform(specularTexCoords, u_specularTextureTransform); + #endif + float specularWeight = texture(u_specularTexture, specularTexCoords).a; + #ifdef HAS_SPECULAR_FACTOR + specularWeight *= u_specularFactor; + #endif + #else + #ifdef HAS_SPECULAR_FACTOR + float specularWeight = u_specularFactor; + #else + float specularWeight = 1.0; + #endif + #endif + + #ifdef HAS_SPECULAR_COLOR_TEXTURE + vec2 specularColorTexCoords = TEXCOORD_SPECULAR_COLOR; + #ifdef HAS_SPECULAR_COLOR_TEXTURE_TRANSFORM + specularColorTexCoords = computeTextureTransform(specularColorTexCoords, u_specularColorTextureTransform); + #endif + vec3 specularColorSample = texture(u_specularColorTexture, specularColorTexCoords).rgb; + vec3 specularColorFactor = czm_srgbToLinear(specularColorSample); + #ifdef HAS_SPECULAR_COLOR_FACTOR + specularColorFactor *= u_specularColorFactor; + #endif + #else + #ifdef HAS_SPECULAR_COLOR_FACTOR + vec3 specularColorFactor = u_specularColorFactor; + #else + vec3 specularColorFactor = vec3(1.0); + #endif + #endif + material.specularWeight = specularWeight; + vec3 f0 = material.specular; + vec3 dielectricSpecularF0 = min(f0 * specularColorFactor, vec3(1.0)); + material.specular = mix(dielectricSpecularF0, material.diffuse, metalness); +} +#endif +#ifdef USE_ANISOTROPY +void setAnisotropy(inout czm_modelMaterial material, in NormalInfo normalInfo) +{ + mat2 rotation = mat2(u_anisotropy.xy, -u_anisotropy.y, u_anisotropy.x); + float anisotropyStrength = u_anisotropy.z; + + vec2 direction = vec2(1.0, 0.0); + #ifdef HAS_ANISOTROPY_TEXTURE + vec2 anisotropyTexCoords = TEXCOORD_ANISOTROPY; + #ifdef HAS_ANISOTROPY_TEXTURE_TRANSFORM + anisotropyTexCoords = computeTextureTransform(anisotropyTexCoords, u_anisotropyTextureTransform); + #endif + vec3 anisotropySample = texture(u_anisotropyTexture, anisotropyTexCoords).rgb; + direction = anisotropySample.rg * 2.0 - vec2(1.0); + anisotropyStrength *= anisotropySample.b; + #endif + + direction = rotation * direction; + mat3 tbn = mat3(normalInfo.tangent, normalInfo.bitangent, normalInfo.normal); + vec3 anisotropicT = tbn * normalize(vec3(direction, 0.0)); + vec3 anisotropicB = cross(normalInfo.geometryNormal, anisotropicT); + + material.anisotropicT = anisotropicT; + material.anisotropicB = anisotropicB; + material.anisotropyStrength = anisotropyStrength; +} +#endif +#ifdef USE_CLEARCOAT +void setClearcoat(inout czm_modelMaterial material, in ProcessedAttributes attributes) +{ + #ifdef HAS_CLEARCOAT_TEXTURE + vec2 clearcoatTexCoords = TEXCOORD_CLEARCOAT; + #ifdef HAS_CLEARCOAT_TEXTURE_TRANSFORM + clearcoatTexCoords = computeTextureTransform(clearcoatTexCoords, u_clearcoatTextureTransform); + #endif + float clearcoatFactor = texture(u_clearcoatTexture, clearcoatTexCoords).r; + #ifdef HAS_CLEARCOAT_FACTOR + clearcoatFactor *= u_clearcoatFactor; + #endif + #else + #ifdef HAS_CLEARCOAT_FACTOR + float clearcoatFactor = u_clearcoatFactor; + #else + // PERFORMANCE_IDEA: this case should turn the whole extension off + float clearcoatFactor = 0.0; + #endif + #endif + + #ifdef HAS_CLEARCOAT_ROUGHNESS_TEXTURE + vec2 clearcoatRoughnessTexCoords = TEXCOORD_CLEARCOAT_ROUGHNESS; + #ifdef HAS_CLEARCOAT_ROUGHNESS_TEXTURE_TRANSFORM + clearcoatRoughnessTexCoords = computeTextureTransform(clearcoatRoughnessTexCoords, u_clearcoatRoughnessTextureTransform); + #endif + float clearcoatRoughness = texture(u_clearcoatRoughnessTexture, clearcoatRoughnessTexCoords).g; + #ifdef HAS_CLEARCOAT_ROUGHNESS_FACTOR + clearcoatRoughness *= u_clearcoatRoughnessFactor; + #endif + #else + #ifdef HAS_CLEARCOAT_ROUGHNESS_FACTOR + float clearcoatRoughness = u_clearcoatRoughnessFactor; + #else + float clearcoatRoughness = 0.0; + #endif + #endif + + material.clearcoatFactor = clearcoatFactor; + // roughness is authored as perceptual roughness + // square it to get material roughness + material.clearcoatRoughness = clearcoatRoughness * clearcoatRoughness; + #ifdef HAS_CLEARCOAT_NORMAL_TEXTURE + material.clearcoatNormal = getClearcoatNormalFromTexture(attributes, attributes.normalEC); + #else + material.clearcoatNormal = attributes.normalEC; + #endif +} +#endif +#endif + +void materialStage(inout czm_modelMaterial material, ProcessedAttributes attributes, SelectedFeature feature) +{ + #ifdef USE_ANISOTROPY + NormalInfo normalInfo = getNormalInfo(attributes); + material.normalEC = normalInfo.normal; + #elif defined(HAS_NORMALS) + material.normalEC = computeNormal(attributes); + #endif + + vec4 baseColorWithAlpha = vec4(1.0); + // Regardless of whether we use PBR, set a base color + #ifdef HAS_BASE_COLOR_TEXTURE + baseColorWithAlpha = getBaseColorFromTexture(); + #elif defined(HAS_BASE_COLOR_FACTOR) + baseColorWithAlpha = u_baseColorFactor; + #endif + + #ifdef HAS_POINT_CLOUD_COLOR_STYLE + baseColorWithAlpha = v_pointCloudColor; + #elif defined(HAS_COLOR_0) + vec4 color = attributes.color_0; + // .pnts files store colors in the sRGB color space + #ifdef HAS_SRGB_COLOR + color = czm_srgbToLinear(color); + #endif + baseColorWithAlpha *= color; + #endif + + material.diffuse = baseColorWithAlpha.rgb; + material.alpha = baseColorWithAlpha.a; + + #ifdef USE_CPU_STYLING + material.diffuse = blend(material.diffuse, feature.color.rgb, model_colorBlend); + #endif + + #ifdef HAS_OCCLUSION_TEXTURE + vec2 occlusionTexCoords = TEXCOORD_OCCLUSION; + #ifdef HAS_OCCLUSION_TEXTURE_TRANSFORM + occlusionTexCoords = computeTextureTransform(occlusionTexCoords, u_occlusionTextureTransform); + #endif + material.occlusion = texture(u_occlusionTexture, occlusionTexCoords).r; + #endif + + #ifdef HAS_EMISSIVE_TEXTURE + material.emissive = getEmissiveFromTexture(); + #elif defined(HAS_EMISSIVE_FACTOR) + material.emissive = u_emissiveFactor; + #endif + + #if defined(LIGHTING_PBR) && defined(USE_SPECULAR_GLOSSINESS) + setSpecularGlossiness(material); + #elif defined(LIGHTING_PBR) + float metalness = setMetallicRoughness(material); + #ifdef USE_SPECULAR + setSpecular(material, metalness); + #endif + #ifdef USE_ANISOTROPY + setAnisotropy(material, normalInfo); + #endif + #ifdef USE_CLEARCOAT + setClearcoat(material, attributes); + #endif #endif } diff --git a/packages/engine/Specs/.eslintrc.json b/packages/engine/Specs/.eslintrc.json deleted file mode 100644 index 5b6725648bf..00000000000 --- a/packages/engine/Specs/.eslintrc.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../.eslintrc.json", - "env": { - "jasmine": true - }, - "rules": { - "no-self-assign": "off", - "no-duplicate-imports": "off" - } -} \ No newline at end of file diff --git a/packages/engine/Specs/Core/Cartesian3Spec.js b/packages/engine/Specs/Core/Cartesian3Spec.js index 73e89bcf3e5..463be5cfc4b 100644 --- a/packages/engine/Specs/Core/Cartesian3Spec.js +++ b/packages/engine/Specs/Core/Cartesian3Spec.js @@ -1,6 +1,10 @@ -import { Cartesian3, Cartographic, Ellipsoid } from "../../index.js"; +import { + Cartesian3, + Cartographic, + Ellipsoid, + Math as CesiumMath, +} from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; import createPackableArraySpecs from "../../../../Specs/createPackableArraySpecs.js"; import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; diff --git a/packages/engine/Specs/Core/Cartesian4Spec.js b/packages/engine/Specs/Core/Cartesian4Spec.js index 478ec96fdf3..b9146991493 100644 --- a/packages/engine/Specs/Core/Cartesian4Spec.js +++ b/packages/engine/Specs/Core/Cartesian4Spec.js @@ -1,6 +1,5 @@ -import { Cartesian4, Color } from "../../index.js"; +import { Cartesian4, Color, Math as CesiumMath } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; import createPackableArraySpecs from "../../../../Specs/createPackableArraySpecs.js"; import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; diff --git a/packages/engine/Specs/Core/CartographicSpec.js b/packages/engine/Specs/Core/CartographicSpec.js index 9aaf8bc8a03..98cabba7053 100644 --- a/packages/engine/Specs/Core/CartographicSpec.js +++ b/packages/engine/Specs/Core/CartographicSpec.js @@ -1,6 +1,9 @@ -import { Cartesian3, Cartographic, Ellipsoid } from "../../index.js"; - -import { Math as CesiumMath } from "../../index.js"; +import { + Cartesian3, + Cartographic, + Ellipsoid, + Math as CesiumMath, +} from "../../index.js"; describe("Core/Cartographic", function () { const surfaceCartesian = new Cartesian3( diff --git a/packages/engine/Specs/Core/CatmullRomSplineSpec.js b/packages/engine/Specs/Core/CatmullRomSplineSpec.js index 8db028f94cb..4dd08e164df 100644 --- a/packages/engine/Specs/Core/CatmullRomSplineSpec.js +++ b/packages/engine/Specs/Core/CatmullRomSplineSpec.js @@ -1,6 +1,9 @@ -import { Cartesian3, CatmullRomSpline, HermiteSpline } from "../../index.js"; - -import { Math as CesiumMath } from "../../index.js"; +import { + Cartesian3, + CatmullRomSpline, + HermiteSpline, + Math as CesiumMath, +} from "../../index.js"; describe("Core/CatmullRomSpline", function () { let points; diff --git a/packages/engine/Specs/Core/CircleGeometrySpec.js b/packages/engine/Specs/Core/CircleGeometrySpec.js index dee09cac9f5..78cc3929c4d 100644 --- a/packages/engine/Specs/Core/CircleGeometrySpec.js +++ b/packages/engine/Specs/Core/CircleGeometrySpec.js @@ -2,11 +2,10 @@ import { Cartesian3, CircleGeometry, Ellipsoid, + Math as CesiumMath, VertexFormat, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; describe("Core/CircleGeometry", function () { diff --git a/packages/engine/Specs/Core/ColorSpec.js b/packages/engine/Specs/Core/ColorSpec.js index 11cb942a722..96ab7d12417 100644 --- a/packages/engine/Specs/Core/ColorSpec.js +++ b/packages/engine/Specs/Core/ColorSpec.js @@ -1,6 +1,5 @@ -import { Cartesian4, Color } from "../../index.js"; +import { Cartesian4, Color, Math as CesiumMath } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; describe("Core/Color", function () { diff --git a/packages/engine/Specs/Core/CoplanarPolygonGeometrySpec.js b/packages/engine/Specs/Core/CoplanarPolygonGeometrySpec.js index 820b4b33b8a..11e767ab508 100644 --- a/packages/engine/Specs/Core/CoplanarPolygonGeometrySpec.js +++ b/packages/engine/Specs/Core/CoplanarPolygonGeometrySpec.js @@ -2,12 +2,11 @@ import { Cartesian3, Cartesian2, CoplanarPolygonGeometry, + Math as CesiumMath, Ellipsoid, VertexFormat, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; describe("Core/CoplanarPolygonGeometry", function () { diff --git a/packages/engine/Specs/Core/CorridorGeometrySpec.js b/packages/engine/Specs/Core/CorridorGeometrySpec.js index f11f558cd7f..c8d4c6efd2d 100644 --- a/packages/engine/Specs/Core/CorridorGeometrySpec.js +++ b/packages/engine/Specs/Core/CorridorGeometrySpec.js @@ -4,12 +4,11 @@ import { CorridorGeometry, Ellipsoid, GeometryOffsetAttribute, + Math as CesiumMath, Rectangle, VertexFormat, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; describe("Core/CorridorGeometry", function () { diff --git a/packages/engine/Specs/Core/CubicRealPolynomialSpec.js b/packages/engine/Specs/Core/CubicRealPolynomialSpec.js index 3ee4bca475b..5673df7ff91 100644 --- a/packages/engine/Specs/Core/CubicRealPolynomialSpec.js +++ b/packages/engine/Specs/Core/CubicRealPolynomialSpec.js @@ -1,6 +1,4 @@ -import { CubicRealPolynomial } from "../../index.js"; - -import { Math as CesiumMath } from "../../index.js"; +import { CubicRealPolynomial, Math as CesiumMath } from "../../index.js"; describe("Core/CubicRealPolynomial", function () { it("discriminant throws without a", function () { diff --git a/packages/engine/Specs/Core/EllipseGeometrySpec.js b/packages/engine/Specs/Core/EllipseGeometrySpec.js index 6aecd97936c..06a1463fb84 100644 --- a/packages/engine/Specs/Core/EllipseGeometrySpec.js +++ b/packages/engine/Specs/Core/EllipseGeometrySpec.js @@ -3,12 +3,11 @@ import { EllipseGeometry, Ellipsoid, GeometryOffsetAttribute, + Math as CesiumMath, Rectangle, VertexFormat, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; describe("Core/EllipseGeometry", function () { diff --git a/packages/engine/Specs/Core/EllipsoidGeodesicSpec.js b/packages/engine/Specs/Core/EllipsoidGeodesicSpec.js index e3a52f862aa..3b7c1edb274 100644 --- a/packages/engine/Specs/Core/EllipsoidGeodesicSpec.js +++ b/packages/engine/Specs/Core/EllipsoidGeodesicSpec.js @@ -1,6 +1,9 @@ -import { Cartographic, Ellipsoid, EllipsoidGeodesic } from "../../index.js"; - -import { Math as CesiumMath } from "../../index.js"; +import { + Cartographic, + Ellipsoid, + EllipsoidGeodesic, + Math as CesiumMath, +} from "../../index.js"; describe("Core/EllipsoidGeodesic", function () { it("throws without start", function () { diff --git a/packages/engine/Specs/Core/EllipsoidGeometrySpec.js b/packages/engine/Specs/Core/EllipsoidGeometrySpec.js index 1e175fe763a..7800e7afbba 100644 --- a/packages/engine/Specs/Core/EllipsoidGeometrySpec.js +++ b/packages/engine/Specs/Core/EllipsoidGeometrySpec.js @@ -2,11 +2,10 @@ import { Cartesian3, EllipsoidGeometry, GeometryOffsetAttribute, + Math as CesiumMath, VertexFormat, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; describe("Core/EllipsoidGeometry", function () { diff --git a/packages/engine/Specs/Core/EllipsoidOutlineGeometrySpec.js b/packages/engine/Specs/Core/EllipsoidOutlineGeometrySpec.js index 691d16402b5..e24be1fefa9 100644 --- a/packages/engine/Specs/Core/EllipsoidOutlineGeometrySpec.js +++ b/packages/engine/Specs/Core/EllipsoidOutlineGeometrySpec.js @@ -2,9 +2,9 @@ import { Cartesian3, EllipsoidOutlineGeometry, GeometryOffsetAttribute, + Math as CesiumMath, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; describe("Core/EllipsoidOutlineGeometry", function () { diff --git a/packages/engine/Specs/Core/EllipsoidRhumbLineSpec.js b/packages/engine/Specs/Core/EllipsoidRhumbLineSpec.js index 87157adea73..afc652627b0 100644 --- a/packages/engine/Specs/Core/EllipsoidRhumbLineSpec.js +++ b/packages/engine/Specs/Core/EllipsoidRhumbLineSpec.js @@ -4,10 +4,9 @@ import { Ellipsoid, EllipsoidGeodesic, EllipsoidRhumbLine, + Math as CesiumMath, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("Core/EllipsoidRhumbLine", function () { const oneDegree = CesiumMath.RADIANS_PER_DEGREE; const fifteenDegrees = Math.PI / 12; diff --git a/packages/engine/Specs/Core/EllipsoidalOccluderSpec.js b/packages/engine/Specs/Core/EllipsoidalOccluderSpec.js index 6992603a74b..154d4c502b5 100644 --- a/packages/engine/Specs/Core/EllipsoidalOccluderSpec.js +++ b/packages/engine/Specs/Core/EllipsoidalOccluderSpec.js @@ -4,12 +4,11 @@ import { Ellipsoid, EllipsoidalOccluder, IntersectionTests, + Math as CesiumMath, Ray, Rectangle, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("Core/EllipsoidalOccluder", function () { it("uses ellipsoid", function () { const ellipsoid = new Ellipsoid(2.0, 3.0, 4.0); diff --git a/packages/engine/Specs/Core/FrustumGeometrySpec.js b/packages/engine/Specs/Core/FrustumGeometrySpec.js index b0073b16784..24af379c258 100644 --- a/packages/engine/Specs/Core/FrustumGeometrySpec.js +++ b/packages/engine/Specs/Core/FrustumGeometrySpec.js @@ -1,13 +1,12 @@ import { Cartesian3, FrustumGeometry, + Math as CesiumMath, PerspectiveFrustum, Quaternion, VertexFormat, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; describe("Core/FrustumGeometry", function () { diff --git a/packages/engine/Specs/Core/FrustumOutlineGeometrySpec.js b/packages/engine/Specs/Core/FrustumOutlineGeometrySpec.js index bb4d2643d63..e5435ea98dd 100644 --- a/packages/engine/Specs/Core/FrustumOutlineGeometrySpec.js +++ b/packages/engine/Specs/Core/FrustumOutlineGeometrySpec.js @@ -1,13 +1,12 @@ import { Cartesian3, FrustumOutlineGeometry, + Math as CesiumMath, PerspectiveFrustum, Quaternion, VertexFormat, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; describe("Core/FrustumOutlineGeometry", function () { diff --git a/packages/engine/Specs/Core/GeographicProjectionSpec.js b/packages/engine/Specs/Core/GeographicProjectionSpec.js index ba405515f81..19f890867cb 100644 --- a/packages/engine/Specs/Core/GeographicProjectionSpec.js +++ b/packages/engine/Specs/Core/GeographicProjectionSpec.js @@ -3,10 +3,9 @@ import { Cartographic, Ellipsoid, GeographicProjection, + Math as CesiumMath, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("Core/GeographicProjection", function () { it("construct0", function () { const projection = new GeographicProjection(); diff --git a/packages/engine/Specs/Core/GeographicTilingSchemeSpec.js b/packages/engine/Specs/Core/GeographicTilingSchemeSpec.js index 53ba59db214..e08cc000e89 100644 --- a/packages/engine/Specs/Core/GeographicTilingSchemeSpec.js +++ b/packages/engine/Specs/Core/GeographicTilingSchemeSpec.js @@ -3,12 +3,11 @@ import { Cartographic, GeographicProjection, GeographicTilingScheme, + Math as CesiumMath, Rectangle, TilingScheme, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("Core/GeographicTilingScheme", function () { it("conforms to TilingScheme interface.", function () { expect(GeographicTilingScheme).toConformToInterface(TilingScheme); diff --git a/packages/engine/Specs/Core/GeometryPipelineSpec.js b/packages/engine/Specs/Core/GeometryPipelineSpec.js index 10ccf984273..4cba2dd3c47 100644 --- a/packages/engine/Specs/Core/GeometryPipelineSpec.js +++ b/packages/engine/Specs/Core/GeometryPipelineSpec.js @@ -14,6 +14,7 @@ import { GeometryInstance, GeometryPipeline, GeometryType, + Math as CesiumMath, Matrix4, PolygonGeometry, PrimitiveType, @@ -21,8 +22,6 @@ import { VertexFormat, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("Core/GeometryPipeline", function () { it("converts triangles to wireframe in place", function () { const geometry = GeometryPipeline.toWireframe( diff --git a/packages/engine/Specs/Core/GeometrySpec.js b/packages/engine/Specs/Core/GeometrySpec.js index 2c80342e238..c07668cb52e 100644 --- a/packages/engine/Specs/Core/GeometrySpec.js +++ b/packages/engine/Specs/Core/GeometrySpec.js @@ -6,12 +6,11 @@ import { Geometry, GeometryAttribute, GeometryType, + Math as CesiumMath, PrimitiveType, Rectangle, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("Core/Geometry", function () { it("constructor", function () { const attributes = { diff --git a/packages/engine/Specs/Core/GoogleEarthEnterpriseTerrainDataSpec.js b/packages/engine/Specs/Core/GoogleEarthEnterpriseTerrainDataSpec.js index 5ddf66bbdf0..25bc601ff70 100644 --- a/packages/engine/Specs/Core/GoogleEarthEnterpriseTerrainDataSpec.js +++ b/packages/engine/Specs/Core/GoogleEarthEnterpriseTerrainDataSpec.js @@ -4,13 +4,12 @@ import { Ellipsoid, GeographicTilingScheme, GoogleEarthEnterpriseTerrainData, + Math as CesiumMath, Rectangle, TerrainData, TerrainMesh, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("Core/GoogleEarthEnterpriseTerrainData", function () { const sizeOfUint8 = Uint8Array.BYTES_PER_ELEMENT; const sizeOfUint16 = Uint16Array.BYTES_PER_ELEMENT; diff --git a/packages/engine/Specs/Core/GroundPolylineGeometrySpec.js b/packages/engine/Specs/Core/GroundPolylineGeometrySpec.js index d308b26210c..84af45fa9cb 100644 --- a/packages/engine/Specs/Core/GroundPolylineGeometrySpec.js +++ b/packages/engine/Specs/Core/GroundPolylineGeometrySpec.js @@ -6,11 +6,10 @@ import { Ellipsoid, GeographicProjection, GroundPolylineGeometry, + Math as CesiumMath, WebMercatorProjection, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; describe("Core/GroundPolylineGeometry", function () { diff --git a/packages/engine/Specs/Core/HeadingPitchRollSpec.js b/packages/engine/Specs/Core/HeadingPitchRollSpec.js index 9cb6dbf4fb3..a65df32d563 100644 --- a/packages/engine/Specs/Core/HeadingPitchRollSpec.js +++ b/packages/engine/Specs/Core/HeadingPitchRollSpec.js @@ -1,6 +1,8 @@ -import { HeadingPitchRoll, Quaternion } from "../../index.js"; - -import { Math as CesiumMath } from "../../index.js"; +import { + HeadingPitchRoll, + Math as CesiumMath, + Quaternion, +} from "../../index.js"; describe("Core/HeadingPitchRoll", function () { const deg2rad = CesiumMath.RADIANS_PER_DEGREE; diff --git a/packages/engine/Specs/Core/HermiteSplineSpec.js b/packages/engine/Specs/Core/HermiteSplineSpec.js index 28307fad357..3b04ea68238 100644 --- a/packages/engine/Specs/Core/HermiteSplineSpec.js +++ b/packages/engine/Specs/Core/HermiteSplineSpec.js @@ -1,6 +1,9 @@ -import { Cartesian3, HermiteSpline, Quaternion } from "../../index.js"; - -import { Math as CesiumMath } from "../../index.js"; +import { + Cartesian3, + HermiteSpline, + Math as CesiumMath, + Quaternion, +} from "../../index.js"; describe("Core/HermiteSpline", function () { let points; diff --git a/packages/engine/Specs/Core/IauOrientationAxesSpec.js b/packages/engine/Specs/Core/IauOrientationAxesSpec.js index c43d5c5e424..8d220d4f1a1 100644 --- a/packages/engine/Specs/Core/IauOrientationAxesSpec.js +++ b/packages/engine/Specs/Core/IauOrientationAxesSpec.js @@ -3,11 +3,10 @@ import { IauOrientationAxes, JulianDate, Matrix3, + Math as CesiumMath, TimeStandard, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("Core/IauOrientationAxes", function () { it("compute ICRF to Moon Fixed", function () { const date = new JulianDate(2451545.0, -32.184, TimeStandard.TAI); diff --git a/packages/engine/Specs/Core/IndexDatatypeSpec.js b/packages/engine/Specs/Core/IndexDatatypeSpec.js index 636b59e44da..a3a8132643b 100644 --- a/packages/engine/Specs/Core/IndexDatatypeSpec.js +++ b/packages/engine/Specs/Core/IndexDatatypeSpec.js @@ -1,6 +1,4 @@ -import { IndexDatatype } from "../../index.js"; - -import { Math as CesiumMath } from "../../index.js"; +import { IndexDatatype, Math as CesiumMath } from "../../index.js"; describe("Core/IndexDatatype", function () { it("validate validates input", function () { diff --git a/packages/engine/Specs/Core/IntersectionTestsSpec.js b/packages/engine/Specs/Core/IntersectionTestsSpec.js index 8e884ace515..8b1a1eb776f 100644 --- a/packages/engine/Specs/Core/IntersectionTestsSpec.js +++ b/packages/engine/Specs/Core/IntersectionTestsSpec.js @@ -3,12 +3,11 @@ import { Cartesian3, Ellipsoid, IntersectionTests, + Math as CesiumMath, Plane, Ray, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("Core/IntersectionTests", function () { it("rayPlane intersects", function () { const ray = new Ray( diff --git a/packages/engine/Specs/Core/JulianDateSpec.js b/packages/engine/Specs/Core/JulianDateSpec.js index 751cb95e68e..4a034a29365 100644 --- a/packages/engine/Specs/Core/JulianDateSpec.js +++ b/packages/engine/Specs/Core/JulianDateSpec.js @@ -1,12 +1,11 @@ import { Iso8601, JulianDate, + Math as CesiumMath, TimeConstants, TimeStandard, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("Core/JulianDate", function () { // All exact Julian Dates found using NASA's Time Conversion Tool: http://ssd.jpl.nasa.gov/tc.cgi it("Construct a default date", function () { diff --git a/packages/engine/Specs/Core/Matrix2Spec.js b/packages/engine/Specs/Core/Matrix2Spec.js index 839b54df2fd..540b550d0c2 100644 --- a/packages/engine/Specs/Core/Matrix2Spec.js +++ b/packages/engine/Specs/Core/Matrix2Spec.js @@ -1,6 +1,4 @@ -import { Cartesian2, Matrix2 } from "../../index.js"; - -import { Math as CesiumMath } from "../../index.js"; +import { Cartesian2, Math as CesiumMath, Matrix2 } from "../../index.js"; import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; import createPackableArraySpecs from "../../../../Specs/createPackableArraySpecs.js"; diff --git a/packages/engine/Specs/Core/Matrix3Spec.js b/packages/engine/Specs/Core/Matrix3Spec.js index ff05dd3e084..e0ada12c175 100644 --- a/packages/engine/Specs/Core/Matrix3Spec.js +++ b/packages/engine/Specs/Core/Matrix3Spec.js @@ -1,12 +1,11 @@ import { Cartesian3, HeadingPitchRoll, + Math as CesiumMath, Matrix3, Quaternion, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; import createPackableArraySpecs from "../../../../Specs/createPackableArraySpecs.js"; diff --git a/packages/engine/Specs/Core/Matrix4Spec.js b/packages/engine/Specs/Core/Matrix4Spec.js index 3109a8220d9..ae2c6fa15a8 100644 --- a/packages/engine/Specs/Core/Matrix4Spec.js +++ b/packages/engine/Specs/Core/Matrix4Spec.js @@ -1,6 +1,7 @@ import { Cartesian3, Cartesian4, + Math as CesiumMath, Matrix3, Matrix4, Quaternion, @@ -8,8 +9,6 @@ import { RuntimeError, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; import createPackableArraySpecs from "../../../../Specs/createPackableArraySpecs.js"; diff --git a/packages/engine/Specs/Core/OccluderSpec.js b/packages/engine/Specs/Core/OccluderSpec.js index 798f850ea84..d4e18ff9b12 100644 --- a/packages/engine/Specs/Core/OccluderSpec.js +++ b/packages/engine/Specs/Core/OccluderSpec.js @@ -2,13 +2,12 @@ import { BoundingSphere, Cartesian3, Ellipsoid, + Math as CesiumMath, Occluder, Rectangle, Visibility, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("Core/Occluder", function () { it("throws an exception during construction (1 of 3)", function () { expect(function () { diff --git a/packages/engine/Specs/Core/OrientedBoundingBoxSpec.js b/packages/engine/Specs/Core/OrientedBoundingBoxSpec.js index 37d506dfc38..a424c6561c3 100644 --- a/packages/engine/Specs/Core/OrientedBoundingBoxSpec.js +++ b/packages/engine/Specs/Core/OrientedBoundingBoxSpec.js @@ -4,6 +4,7 @@ import { Cartesian4, Ellipsoid, Intersect, + Math as CesiumMath, Matrix3, Matrix4, Occluder, @@ -13,8 +14,6 @@ import { Rectangle, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; describe("Core/OrientedBoundingBox", function () { diff --git a/packages/engine/Specs/Core/OrthographicFrustumSpec.js b/packages/engine/Specs/Core/OrthographicFrustumSpec.js index 1a65cbaba34..fa90747bbd1 100644 --- a/packages/engine/Specs/Core/OrthographicFrustumSpec.js +++ b/packages/engine/Specs/Core/OrthographicFrustumSpec.js @@ -2,12 +2,11 @@ import { Cartesian2, Cartesian3, Cartesian4, + Math as CesiumMath, Matrix4, OrthographicFrustum, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; describe("Core/OrthographicFrustum", function () { diff --git a/packages/engine/Specs/Core/OrthographicOffCenterFrustumSpec.js b/packages/engine/Specs/Core/OrthographicOffCenterFrustumSpec.js index 9f87f5f5ad0..4040ffc5df3 100644 --- a/packages/engine/Specs/Core/OrthographicOffCenterFrustumSpec.js +++ b/packages/engine/Specs/Core/OrthographicOffCenterFrustumSpec.js @@ -2,12 +2,11 @@ import { Cartesian2, Cartesian3, Cartesian4, + Math as CesiumMath, Matrix4, OrthographicOffCenterFrustum, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("Core/OrthographicOffCenterFrustum", function () { let frustum, planes; diff --git a/packages/engine/Specs/Core/PerspectiveFrustumSpec.js b/packages/engine/Specs/Core/PerspectiveFrustumSpec.js index afea2402bfd..3e3c16fdcf1 100644 --- a/packages/engine/Specs/Core/PerspectiveFrustumSpec.js +++ b/packages/engine/Specs/Core/PerspectiveFrustumSpec.js @@ -2,12 +2,11 @@ import { Cartesian2, Cartesian3, Cartesian4, + Math as CesiumMath, Matrix4, PerspectiveFrustum, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; describe("Core/PerspectiveFrustum", function () { diff --git a/packages/engine/Specs/Core/PerspectiveOffCenterFrustumSpec.js b/packages/engine/Specs/Core/PerspectiveOffCenterFrustumSpec.js index 7da3ff6afac..3d4201bff5c 100644 --- a/packages/engine/Specs/Core/PerspectiveOffCenterFrustumSpec.js +++ b/packages/engine/Specs/Core/PerspectiveOffCenterFrustumSpec.js @@ -2,12 +2,11 @@ import { Cartesian2, Cartesian3, Cartesian4, + Math as CesiumMath, Matrix4, PerspectiveOffCenterFrustum, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("Core/PerspectiveOffCenterFrustum", function () { let frustum, planes; diff --git a/packages/engine/Specs/Core/PlaneSpec.js b/packages/engine/Specs/Core/PlaneSpec.js index 0d573a0f0b2..cd41d22d07b 100644 --- a/packages/engine/Specs/Core/PlaneSpec.js +++ b/packages/engine/Specs/Core/PlaneSpec.js @@ -1,13 +1,12 @@ import { Cartesian3, Cartesian4, + Math as CesiumMath, Matrix3, Matrix4, Plane, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("Core/Plane", function () { it("constructs", function () { const normal = Cartesian3.UNIT_X; diff --git a/packages/engine/Specs/Core/PolygonGeometrySpec.js b/packages/engine/Specs/Core/PolygonGeometrySpec.js index 33c92d35032..14d51ec7191 100644 --- a/packages/engine/Specs/Core/PolygonGeometrySpec.js +++ b/packages/engine/Specs/Core/PolygonGeometrySpec.js @@ -7,13 +7,12 @@ import { Ellipsoid, GeometryOffsetAttribute, GeometryPipeline, + Math as CesiumMath, PolygonGeometry, Rectangle, VertexFormat, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; describe("Core/PolygonGeometry", function () { diff --git a/packages/engine/Specs/Core/PolygonOutlineGeometrySpec.js b/packages/engine/Specs/Core/PolygonOutlineGeometrySpec.js index 582fbbd8c07..92838d833a1 100644 --- a/packages/engine/Specs/Core/PolygonOutlineGeometrySpec.js +++ b/packages/engine/Specs/Core/PolygonOutlineGeometrySpec.js @@ -4,11 +4,10 @@ import { Cartesian3, Ellipsoid, GeometryOffsetAttribute, + Math as CesiumMath, PolygonOutlineGeometry, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; describe("Core/PolygonOutlineGeometry", function () { diff --git a/packages/engine/Specs/Core/PolygonPipelineSpec.js b/packages/engine/Specs/Core/PolygonPipelineSpec.js index 77823cb0f24..b39594523ec 100644 --- a/packages/engine/Specs/Core/PolygonPipelineSpec.js +++ b/packages/engine/Specs/Core/PolygonPipelineSpec.js @@ -2,12 +2,11 @@ import { Cartesian2, Cartesian3, Ellipsoid, + Math as CesiumMath, PolygonPipeline, WindingOrder, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("Core/PolygonPipeline", function () { beforeEach(function () { CesiumMath.setRandomNumberSeed(0.0); diff --git a/packages/engine/Specs/Core/PolylineGeometrySpec.js b/packages/engine/Specs/Core/PolylineGeometrySpec.js index 3ac021c212c..46f0bf04b4d 100644 --- a/packages/engine/Specs/Core/PolylineGeometrySpec.js +++ b/packages/engine/Specs/Core/PolylineGeometrySpec.js @@ -1,14 +1,15 @@ import { + ArcType, Cartesian3, Color, + defaultValue, Ellipsoid, + Math as CesiumMath, PolylineGeometry, VertexFormat, } from "../../index.js"; -import { ArcType, defaultValue } from "../../index.js"; import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; -import CesiumMath from "../../Source/Core/Math.js"; describe("Core/PolylineGeometry", function () { it("constructor throws with no positions", function () { diff --git a/packages/engine/Specs/Core/PolylinePipelineSpec.js b/packages/engine/Specs/Core/PolylinePipelineSpec.js index cd1e1ca6089..2c8d62b014e 100644 --- a/packages/engine/Specs/Core/PolylinePipelineSpec.js +++ b/packages/engine/Specs/Core/PolylinePipelineSpec.js @@ -1,12 +1,11 @@ import { Cartesian3, Ellipsoid, + Math as CesiumMath, PolylinePipeline, Transforms, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("Core/PolylinePipeline", function () { it("wrapLongitude", function () { const positions = Cartesian3.fromDegreesArray([ diff --git a/packages/engine/Specs/Core/QuadraticRealPolynomialSpec.js b/packages/engine/Specs/Core/QuadraticRealPolynomialSpec.js index e3956505a9a..283e769fab9 100644 --- a/packages/engine/Specs/Core/QuadraticRealPolynomialSpec.js +++ b/packages/engine/Specs/Core/QuadraticRealPolynomialSpec.js @@ -1,5 +1,4 @@ -import { QuadraticRealPolynomial } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; +import { Math as CesiumMath, QuadraticRealPolynomial } from "../../index.js"; describe("Core/QuadraticRealPolynomial", function () { it("discriminant throws without a", function () { diff --git a/packages/engine/Specs/Core/QuantizedMeshTerrainDataSpec.js b/packages/engine/Specs/Core/QuantizedMeshTerrainDataSpec.js index 10357fdad70..11097df0680 100644 --- a/packages/engine/Specs/Core/QuantizedMeshTerrainDataSpec.js +++ b/packages/engine/Specs/Core/QuantizedMeshTerrainDataSpec.js @@ -3,13 +3,12 @@ import { Cartesian3, defined, GeographicTilingScheme, + Math as CesiumMath, QuantizedMeshTerrainData, TerrainData, TerrainMesh, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("Core/QuantizedMeshTerrainData", function () { it("conforms to TerrainData interface", function () { expect(QuantizedMeshTerrainData).toConformToInterface(TerrainData); diff --git a/packages/engine/Specs/Core/QuarticRealPolynomialSpec.js b/packages/engine/Specs/Core/QuarticRealPolynomialSpec.js index 82fcc76e15a..ff3259814cf 100644 --- a/packages/engine/Specs/Core/QuarticRealPolynomialSpec.js +++ b/packages/engine/Specs/Core/QuarticRealPolynomialSpec.js @@ -1,5 +1,4 @@ -import { QuarticRealPolynomial } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; +import { Math as CesiumMath, QuarticRealPolynomial } from "../../index.js"; describe("Core/QuarticRealPolynomial", function () { it("discriminant throws without a", function () { diff --git a/packages/engine/Specs/Core/QuaternionSpec.js b/packages/engine/Specs/Core/QuaternionSpec.js index 8bfc1730513..b5186d4e1ee 100644 --- a/packages/engine/Specs/Core/QuaternionSpec.js +++ b/packages/engine/Specs/Core/QuaternionSpec.js @@ -1,12 +1,11 @@ import { Cartesian3, HeadingPitchRoll, + Math as CesiumMath, Matrix3, Quaternion, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; describe("Core/Quaternion", function () { diff --git a/packages/engine/Specs/Core/QuaternionSplineSpec.js b/packages/engine/Specs/Core/QuaternionSplineSpec.js index 300ea367ab5..e8c953433e6 100644 --- a/packages/engine/Specs/Core/QuaternionSplineSpec.js +++ b/packages/engine/Specs/Core/QuaternionSplineSpec.js @@ -1,6 +1,9 @@ -import { Cartesian3, Quaternion, QuaternionSpline } from "../../index.js"; - -import { Math as CesiumMath } from "../../index.js"; +import { + Cartesian3, + Math as CesiumMath, + Quaternion, + QuaternionSpline, +} from "../../index.js"; describe("Core/QuaternionSpline", function () { let points; diff --git a/packages/engine/Specs/Core/RectangleGeometrySpec.js b/packages/engine/Specs/Core/RectangleGeometrySpec.js index 9a4feb0e0d7..2c2451a1835 100644 --- a/packages/engine/Specs/Core/RectangleGeometrySpec.js +++ b/packages/engine/Specs/Core/RectangleGeometrySpec.js @@ -4,14 +4,13 @@ import { Ellipsoid, GeographicProjection, GeometryOffsetAttribute, + Math as CesiumMath, Matrix2, Rectangle, RectangleGeometry, VertexFormat, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; describe("Core/RectangleGeometry", function () { diff --git a/packages/engine/Specs/Core/RectangleOutlineGeometrySpec.js b/packages/engine/Specs/Core/RectangleOutlineGeometrySpec.js index ff095efbab0..47def1381cc 100644 --- a/packages/engine/Specs/Core/RectangleOutlineGeometrySpec.js +++ b/packages/engine/Specs/Core/RectangleOutlineGeometrySpec.js @@ -4,13 +4,12 @@ import { Ellipsoid, GeographicProjection, GeometryOffsetAttribute, + Math as CesiumMath, Matrix2, Rectangle, RectangleOutlineGeometry, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; describe("Core/RectangleOutlineGeometry", function () { diff --git a/packages/engine/Specs/Core/S2CellSpec.js b/packages/engine/Specs/Core/S2CellSpec.js index ae41af33367..57a4f7ef264 100644 --- a/packages/engine/Specs/Core/S2CellSpec.js +++ b/packages/engine/Specs/Core/S2CellSpec.js @@ -1,8 +1,9 @@ -import { Cartesian3, FeatureDetection, S2Cell } from "../../index.js"; -/* eslint-disable new-cap */ -/* eslint-disable no-undef */ - -import { Math as CesiumMath } from "../../index.js"; +import { + Cartesian3, + FeatureDetection, + Math as CesiumMath, + S2Cell, +} from "../../index.js"; describe("Core/S2Cell", function () { if (!FeatureDetection.supportsBigInt()) { @@ -15,16 +16,16 @@ describe("Core/S2Cell", function () { }); it("throws for invalid cell ID in constructor", function () { - // eslint-disable-next-line new-cap expect(function () { - S2Cell(BigInt(-1)); + // eslint-disable-next-line no-unused-vars + const cell = new S2Cell(BigInt(-1)); }).toThrowDeveloperError(); }); it("throws for missing cell ID in constructor", function () { - // eslint-disable-next-line new-cap expect(function () { - S2Cell(); + // eslint-disable-next-line no-unused-vars + const cell = new S2Cell(); }).toThrowDeveloperError(); }); diff --git a/packages/engine/Specs/Core/SimplePolylineGeometrySpec.js b/packages/engine/Specs/Core/SimplePolylineGeometrySpec.js index d1d3da5a043..1375664dfda 100644 --- a/packages/engine/Specs/Core/SimplePolylineGeometrySpec.js +++ b/packages/engine/Specs/Core/SimplePolylineGeometrySpec.js @@ -4,12 +4,11 @@ import { Cartesian3, Color, Ellipsoid, + Math as CesiumMath, PrimitiveType, SimplePolylineGeometry, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; describe("Core/SimplePolylineGeometry", function () { diff --git a/packages/engine/Specs/Core/SphereGeometrySpec.js b/packages/engine/Specs/Core/SphereGeometrySpec.js index a19991ff77d..d4aa38e45c5 100644 --- a/packages/engine/Specs/Core/SphereGeometrySpec.js +++ b/packages/engine/Specs/Core/SphereGeometrySpec.js @@ -1,6 +1,9 @@ -import { Cartesian3, SphereGeometry, VertexFormat } from "../../index.js"; - -import { Math as CesiumMath } from "../../index.js"; +import { + Cartesian3, + Math as CesiumMath, + SphereGeometry, + VertexFormat, +} from "../../index.js"; import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; diff --git a/packages/engine/Specs/Core/SphereOutlineGeometrySpec.js b/packages/engine/Specs/Core/SphereOutlineGeometrySpec.js index 97e4f78023e..fe20690fb5b 100644 --- a/packages/engine/Specs/Core/SphereOutlineGeometrySpec.js +++ b/packages/engine/Specs/Core/SphereOutlineGeometrySpec.js @@ -1,7 +1,6 @@ -import { SphereOutlineGeometry } from "../../index.js"; +import { Math as CesiumMath, SphereOutlineGeometry } from "../../index.js"; import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; -import { Math as CesiumMath } from "../../index.js"; describe("Core/SphereOutlineGeometry", function () { it("constructor throws if stackPartitions less than 1", function () { diff --git a/packages/engine/Specs/Core/SphericalSpec.js b/packages/engine/Specs/Core/SphericalSpec.js index 6b174fdd276..c5515a14f86 100644 --- a/packages/engine/Specs/Core/SphericalSpec.js +++ b/packages/engine/Specs/Core/SphericalSpec.js @@ -1,6 +1,4 @@ -import { Cartesian3, Spherical } from "../../index.js"; - -import { Math as CesiumMath } from "../../index.js"; +import { Cartesian3, Math as CesiumMath, Spherical } from "../../index.js"; describe("Core/Spherical", function () { //Mock object to make sure methods take non-sphericals. diff --git a/packages/engine/Specs/Core/TaskProcessorSpec.js b/packages/engine/Specs/Core/TaskProcessorSpec.js index 449209df579..80c541b8776 100644 --- a/packages/engine/Specs/Core/TaskProcessorSpec.js +++ b/packages/engine/Specs/Core/TaskProcessorSpec.js @@ -1,4 +1,9 @@ -import { FeatureDetection, RuntimeError, TaskProcessor } from "../../index.js"; +import { + buildModuleUrl, + FeatureDetection, + RuntimeError, + TaskProcessor, +} from "../../index.js"; import absolutize from "../../../../Specs/absolutize.js"; @@ -60,6 +65,46 @@ describe("Core/TaskProcessor", function () { ); }); + it("when workers loaded via module ID and it is cross-origin, loads worker with appropriate shim", async function () { + // Setup a cross origin BASE_URL + const oldCESIUM_BASE_URL = window.CESIUM_BASE_URL; + window.CESIUM_BASE_URL = "http://test.com/source/"; + buildModuleUrl._clearBaseResource(); + + const blobSpy = spyOn(window, "Blob").and.callThrough(); + + // Provide just the module ID, as is prevalent in the codebase + taskProcessor = new TaskProcessor("transferTypedArrayTest"); + // Create the worker, but don't execute the task this frame + taskProcessor._activeTasks = taskProcessor._maximumActiveTasks; + + await taskProcessor.scheduleTask(); + + expect(blobSpy).toHaveBeenCalledWith( + [`import "http://test.com/source/Workers/transferTypedArrayTest.js";`], + { type: "application/javascript" } + ); + + // Reset old values for BASE_URL + window.CESIUM_BASE_URL = oldCESIUM_BASE_URL; + buildModuleUrl._clearBaseResource(); + }); + + it("when provided a cross-origin URI, loads worker with appropriate shim", async function () { + const blobSpy = spyOn(window, "Blob").and.callThrough(); + + taskProcessor = new TaskProcessor("http://test.com/Workers/testing.js"); + // Create the worker, but don't execute the task this frame + taskProcessor._activeTasks = taskProcessor._maximumActiveTasks; + + await taskProcessor.scheduleTask(); + + expect(blobSpy).toHaveBeenCalledWith( + [`import "http://test.com/Workers/testing.js";`], + { type: "application/javascript" } + ); + }); + it("can be destroyed", function () { taskProcessor = new TaskProcessor( absolutize("../Specs/Build/TestWorkers/returnParameters.js") diff --git a/packages/engine/Specs/Core/TerrainEncodingSpec.js b/packages/engine/Specs/Core/TerrainEncodingSpec.js index 2407ed32fff..3856b6a5952 100644 --- a/packages/engine/Specs/Core/TerrainEncodingSpec.js +++ b/packages/engine/Specs/Core/TerrainEncodingSpec.js @@ -4,6 +4,7 @@ import { Cartesian2, Cartesian3, Ellipsoid, + Math as CesiumMath, Matrix4, TerrainEncoding, VerticalExaggeration, @@ -11,8 +12,6 @@ import { Transforms, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("Core/TerrainEncoding", function () { let center; let maximum; diff --git a/packages/engine/Specs/Core/TransformsSpec.js b/packages/engine/Specs/Core/TransformsSpec.js index f1cd9b75b5b..30306adc419 100644 --- a/packages/engine/Specs/Core/TransformsSpec.js +++ b/packages/engine/Specs/Core/TransformsSpec.js @@ -9,6 +9,7 @@ import { HeadingPitchRoll, Iau2006XysData, JulianDate, + Math as CesiumMath, Matrix3, Matrix4, Quaternion, @@ -18,8 +19,6 @@ import { Transforms, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("Core/Transforms", function () { const negativeX = new Cartesian4(-1, 0, 0, 0); const negativeY = new Cartesian4(0, -1, 0, 0); diff --git a/packages/engine/Specs/Core/TridiagonalSystemSolverSpec.js b/packages/engine/Specs/Core/TridiagonalSystemSolverSpec.js index 39c55821936..b96c8720ab3 100644 --- a/packages/engine/Specs/Core/TridiagonalSystemSolverSpec.js +++ b/packages/engine/Specs/Core/TridiagonalSystemSolverSpec.js @@ -1,6 +1,8 @@ -import { Cartesian3, TridiagonalSystemSolver } from "../../index.js"; - -import { Math as CesiumMath } from "../../index.js"; +import { + Cartesian3, + Math as CesiumMath, + TridiagonalSystemSolver, +} from "../../index.js"; describe("Core/TridiagonalSystemSolver", function () { it("solve throws exception without lower diagonal", function () { diff --git a/packages/engine/Specs/Core/VideoSynchronizerSpec.js b/packages/engine/Specs/Core/VideoSynchronizerSpec.js index 4993cb4c9c1..2b7e578238d 100644 --- a/packages/engine/Specs/Core/VideoSynchronizerSpec.js +++ b/packages/engine/Specs/Core/VideoSynchronizerSpec.js @@ -3,11 +3,10 @@ import { FeatureDetection, Iso8601, JulianDate, + Math as CesiumMath, VideoSynchronizer, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import pollToPromise from "../../../../Specs/pollToPromise.js"; describe("Core/VideoSynchronizer", function () { diff --git a/packages/engine/Specs/Core/WallGeometrySpec.js b/packages/engine/Specs/Core/WallGeometrySpec.js index 98af438006c..d8f430d9f0a 100644 --- a/packages/engine/Specs/Core/WallGeometrySpec.js +++ b/packages/engine/Specs/Core/WallGeometrySpec.js @@ -1,12 +1,11 @@ import { Cartesian3, Ellipsoid, + Math as CesiumMath, VertexFormat, WallGeometry, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; describe("Core/WallGeometry", function () { diff --git a/packages/engine/Specs/Core/WallOutlineGeometrySpec.js b/packages/engine/Specs/Core/WallOutlineGeometrySpec.js index 28236e4fb74..42435f0eb47 100644 --- a/packages/engine/Specs/Core/WallOutlineGeometrySpec.js +++ b/packages/engine/Specs/Core/WallOutlineGeometrySpec.js @@ -1,6 +1,9 @@ -import { Cartesian3, Ellipsoid, WallOutlineGeometry } from "../../index.js"; - -import { Math as CesiumMath } from "../../index.js"; +import { + Cartesian3, + Ellipsoid, + Math as CesiumMath, + WallOutlineGeometry, +} from "../../index.js"; import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; diff --git a/packages/engine/Specs/Core/WebMercatorProjectionSpec.js b/packages/engine/Specs/Core/WebMercatorProjectionSpec.js index 67d1af2fda8..e8c8d0eee17 100644 --- a/packages/engine/Specs/Core/WebMercatorProjectionSpec.js +++ b/packages/engine/Specs/Core/WebMercatorProjectionSpec.js @@ -3,11 +3,10 @@ import { Cartesian3, Cartographic, Ellipsoid, + Math as CesiumMath, WebMercatorProjection, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("Core/WebMercatorProjection", function () { it("construct0", function () { const projection = new WebMercatorProjection(); diff --git a/packages/engine/Specs/Core/WebMercatorTilingSchemeSpec.js b/packages/engine/Specs/Core/WebMercatorTilingSchemeSpec.js index 71aead9eb65..8c1b325fbea 100644 --- a/packages/engine/Specs/Core/WebMercatorTilingSchemeSpec.js +++ b/packages/engine/Specs/Core/WebMercatorTilingSchemeSpec.js @@ -2,14 +2,13 @@ import { Cartesian2, Cartographic, Ellipsoid, + Math as CesiumMath, Rectangle, TilingScheme, WebMercatorProjection, WebMercatorTilingScheme, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("Core/WebMercatorTilingScheme", function () { let tilingScheme; beforeEach(function () { diff --git a/packages/engine/Specs/Core/arrayRemoveDuplicatesSpec.js b/packages/engine/Specs/Core/arrayRemoveDuplicatesSpec.js index b787cba4f47..fa7bd7714a7 100644 --- a/packages/engine/Specs/Core/arrayRemoveDuplicatesSpec.js +++ b/packages/engine/Specs/Core/arrayRemoveDuplicatesSpec.js @@ -1,6 +1,9 @@ -import { arrayRemoveDuplicates, Cartesian3, Spherical } from "../../index.js"; - -import { Math as CesiumMath } from "../../index.js"; +import { + arrayRemoveDuplicates, + Cartesian3, + Math as CesiumMath, + Spherical, +} from "../../index.js"; describe("Core/arrayRemoveDuplicates", function () { it("removeDuplicates returns positions if none removed - length === 1", function () { diff --git a/packages/engine/Specs/Core/barycentricCoordinatesSpec.js b/packages/engine/Specs/Core/barycentricCoordinatesSpec.js index 59af6f8c5ed..3b8f81d4638 100644 --- a/packages/engine/Specs/Core/barycentricCoordinatesSpec.js +++ b/packages/engine/Specs/Core/barycentricCoordinatesSpec.js @@ -1,6 +1,8 @@ -import { barycentricCoordinates, Cartesian3 } from "../../index.js"; - -import { Math as CesiumMath } from "../../index.js"; +import { + barycentricCoordinates, + Cartesian3, + Math as CesiumMath, +} from "../../index.js"; describe("Core/barycentricCoordinates", function () { const p0 = new Cartesian3(-1.0, 0.0, 0.0); diff --git a/packages/engine/Specs/Core/sampleTerrainSpec.js b/packages/engine/Specs/Core/sampleTerrainSpec.js index c88c1a5ddff..ce265ee5ca5 100644 --- a/packages/engine/Specs/Core/sampleTerrainSpec.js +++ b/packages/engine/Specs/Core/sampleTerrainSpec.js @@ -104,6 +104,16 @@ describe("Core/sampleTerrain", function () { ).toBeRejected(); }); + it("rejects if terrain data is not available for the second position and rejectOnTileFail is true", function () { + const positionWithData = Cartographic.fromDegrees(86.925145, 27.988257); + const positionWithoutData = Cartographic.fromDegrees(0.0, 0.0, 0.0); + + const positions = [positionWithData, positionWithoutData]; + return expectAsync( + sampleTerrain(worldTerrain, 12, positions, true) + ).toBeRejected(); + }); + it("fills in what it can when given a mix of positions with and without valid tiles", function () { const positions = [ Cartographic.fromDegrees(86.925145, 27.988257), diff --git a/packages/engine/Specs/DataSources/CorridorGeometryUpdaterSpec.js b/packages/engine/Specs/DataSources/CorridorGeometryUpdaterSpec.js index 9f25bedf82e..6f455e96ce6 100644 --- a/packages/engine/Specs/DataSources/CorridorGeometryUpdaterSpec.js +++ b/packages/engine/Specs/DataSources/CorridorGeometryUpdaterSpec.js @@ -3,6 +3,7 @@ import { Cartesian3, CornerType, JulianDate, + Math as CesiumMath, TimeInterval, TimeIntervalCollection, ConstantProperty, @@ -16,8 +17,6 @@ import { PrimitiveCollection, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createDynamicGeometryUpdaterSpecs from "../../../../Specs/createDynamicGeometryUpdaterSpecs.js"; import createDynamicProperty from "../../../../Specs/createDynamicProperty.js"; import createGeometryUpdaterGroundGeometrySpecs from "../../../../Specs/createGeometryUpdaterGroundGeometrySpecs.js"; diff --git a/packages/engine/Specs/DataSources/EllipsoidGeometryUpdaterSpec.js b/packages/engine/Specs/DataSources/EllipsoidGeometryUpdaterSpec.js index 8d3e910ee5b..15429632c91 100644 --- a/packages/engine/Specs/DataSources/EllipsoidGeometryUpdaterSpec.js +++ b/packages/engine/Specs/DataSources/EllipsoidGeometryUpdaterSpec.js @@ -4,6 +4,7 @@ import { ColorGeometryInstanceAttribute, GeometryOffsetAttribute, JulianDate, + Math as CesiumMath, Quaternion, TimeIntervalCollection, ColorMaterialProperty, @@ -18,8 +19,6 @@ import { PrimitiveCollection, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createDynamicGeometryUpdaterSpecs from "../../../../Specs/createDynamicGeometryUpdaterSpecs.js"; import createDynamicProperty from "../../../../Specs/createDynamicProperty.js"; import createGeometryUpdaterSpecs from "../../../../Specs/createGeometryUpdaterSpecs.js"; diff --git a/packages/engine/Specs/DataSources/KmlDataSourceSpec.js b/packages/engine/Specs/DataSources/KmlDataSourceSpec.js index 15f9bfd6c5f..0fe44e005c4 100644 --- a/packages/engine/Specs/DataSources/KmlDataSourceSpec.js +++ b/packages/engine/Specs/DataSources/KmlDataSourceSpec.js @@ -16,6 +16,7 @@ import { isDataUri, Iso8601, JulianDate, + Math as CesiumMath, NearFarScalar, PerspectiveFrustum, Rectangle, @@ -38,8 +39,6 @@ import { SceneMode, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createCamera from "../../../../Specs/createCamera.js"; import pollToPromise from "../../../../Specs/pollToPromise.js"; diff --git a/packages/engine/Specs/DataSources/KmlTourFlyToSpec.js b/packages/engine/Specs/DataSources/KmlTourFlyToSpec.js index 6430da63c06..da982b9920a 100644 --- a/packages/engine/Specs/DataSources/KmlTourFlyToSpec.js +++ b/packages/engine/Specs/DataSources/KmlTourFlyToSpec.js @@ -5,10 +5,9 @@ import { KmlCamera, KmlLookAt, KmlTourFlyTo, + Math as CesiumMath, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import pollToPromise from "../../../../Specs/pollToPromise.js"; describe("DataSources/KmlTourFlyTo", function () { diff --git a/packages/engine/Specs/DataSources/PolygonGeometryUpdaterSpec.js b/packages/engine/Specs/DataSources/PolygonGeometryUpdaterSpec.js index 8d1fdea0b76..7e01741214f 100644 --- a/packages/engine/Specs/DataSources/PolygonGeometryUpdaterSpec.js +++ b/packages/engine/Specs/DataSources/PolygonGeometryUpdaterSpec.js @@ -8,6 +8,7 @@ import { CoplanarPolygonOutlineGeometry, Ellipsoid, JulianDate, + Math as CesiumMath, PolygonGeometry, PolygonHierarchy, PolygonOutlineGeometry, @@ -24,8 +25,6 @@ import { PrimitiveCollection, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createDynamicGeometryUpdaterSpecs from "../../../../Specs/createDynamicGeometryUpdaterSpecs.js"; import createDynamicProperty from "../../../../Specs/createDynamicProperty.js"; import createGeometryUpdaterGroundGeometrySpecs from "../../../../Specs/createGeometryUpdaterGroundGeometrySpecs.js"; diff --git a/packages/engine/Specs/DataSources/RectangleGeometryUpdaterSpec.js b/packages/engine/Specs/DataSources/RectangleGeometryUpdaterSpec.js index 8d376e20dfb..551b4e52397 100644 --- a/packages/engine/Specs/DataSources/RectangleGeometryUpdaterSpec.js +++ b/packages/engine/Specs/DataSources/RectangleGeometryUpdaterSpec.js @@ -2,6 +2,7 @@ import { ApproximateTerrainHeights, Cartesian3, JulianDate, + Math as CesiumMath, Rectangle, TimeIntervalCollection, ConstantProperty, @@ -12,8 +13,6 @@ import { PrimitiveCollection, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createDynamicGeometryUpdaterSpecs from "../../../../Specs/createDynamicGeometryUpdaterSpecs.js"; import createDynamicProperty from "../../../../Specs/createDynamicProperty.js"; import createGeometryUpdaterGroundGeometrySpecs from "../../../../Specs/createGeometryUpdaterGroundGeometrySpecs.js"; diff --git a/packages/engine/Specs/DataSources/RotationSpec.js b/packages/engine/Specs/DataSources/RotationSpec.js index 7603863f99d..97a5d09b5cd 100644 --- a/packages/engine/Specs/DataSources/RotationSpec.js +++ b/packages/engine/Specs/DataSources/RotationSpec.js @@ -1,6 +1,9 @@ -import { JulianDate, Rotation, SampledProperty } from "../../index.js"; - -import { Math as CesiumMath } from "../../index.js"; +import { + JulianDate, + Math as CesiumMath, + Rotation, + SampledProperty, +} from "../../index.js"; import createPackableSpecs from "../../../../Specs/createPackableSpecs.js"; diff --git a/packages/engine/Specs/DataSources/SampledPropertySpec.js b/packages/engine/Specs/DataSources/SampledPropertySpec.js index 1eb6a80aaa6..8f98ee27507 100644 --- a/packages/engine/Specs/DataSources/SampledPropertySpec.js +++ b/packages/engine/Specs/DataSources/SampledPropertySpec.js @@ -6,13 +6,12 @@ import { JulianDate, LagrangePolynomialApproximation, LinearApproximation, + Math as CesiumMath, Quaternion, TimeInterval, SampledProperty, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("DataSources/SampledProperty", function () { it("constructor sets expected defaults", function () { let property = new SampledProperty(Cartesian3); diff --git a/packages/engine/Specs/DataSources/StaticGeometryColorBatchSpec.js b/packages/engine/Specs/DataSources/StaticGeometryColorBatchSpec.js index 4f032c5563c..379410a2a3b 100644 --- a/packages/engine/Specs/DataSources/StaticGeometryColorBatchSpec.js +++ b/packages/engine/Specs/DataSources/StaticGeometryColorBatchSpec.js @@ -3,6 +3,7 @@ import { Color, DistanceDisplayCondition, JulianDate, + Math as CesiumMath, TimeInterval, TimeIntervalCollection, CallbackProperty, @@ -17,8 +18,6 @@ import { ShadowMode, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createScene from "../../../../Specs/createScene.js"; import pollToPromise from "../../../../Specs/pollToPromise.js"; diff --git a/packages/engine/Specs/DataSources/StaticGeometryPerMaterialBatchSpec.js b/packages/engine/Specs/DataSources/StaticGeometryPerMaterialBatchSpec.js index d47aefd4491..ea0933a13df 100644 --- a/packages/engine/Specs/DataSources/StaticGeometryPerMaterialBatchSpec.js +++ b/packages/engine/Specs/DataSources/StaticGeometryPerMaterialBatchSpec.js @@ -4,6 +4,7 @@ import { Color, DistanceDisplayCondition, JulianDate, + Math as CesiumMath, TimeInterval, TimeIntervalCollection, BoxGeometryUpdater, @@ -27,8 +28,6 @@ import { ShadowMode, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createScene from "../../../../Specs/createScene.js"; import pollToPromise from "../../../../Specs/pollToPromise.js"; diff --git a/packages/engine/Specs/DataSources/StaticGroundGeometryColorBatchSpec.js b/packages/engine/Specs/DataSources/StaticGroundGeometryColorBatchSpec.js index ed74bebc081..24711775a35 100644 --- a/packages/engine/Specs/DataSources/StaticGroundGeometryColorBatchSpec.js +++ b/packages/engine/Specs/DataSources/StaticGroundGeometryColorBatchSpec.js @@ -4,6 +4,7 @@ import { Color, DistanceDisplayCondition, JulianDate, + Math as CesiumMath, TimeInterval, TimeIntervalCollection, CallbackProperty, @@ -15,8 +16,6 @@ import { GroundPrimitive, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createScene from "../../../../Specs/createScene.js"; import pollToPromise from "../../../../Specs/pollToPromise.js"; diff --git a/packages/engine/Specs/DataSources/StaticGroundGeometryPerMaterialBatchSpec.js b/packages/engine/Specs/DataSources/StaticGroundGeometryPerMaterialBatchSpec.js index 26bb7fd8ba8..6f7ceb39ab5 100644 --- a/packages/engine/Specs/DataSources/StaticGroundGeometryPerMaterialBatchSpec.js +++ b/packages/engine/Specs/DataSources/StaticGroundGeometryPerMaterialBatchSpec.js @@ -5,6 +5,7 @@ import { Color, DistanceDisplayCondition, JulianDate, + Math as CesiumMath, TimeInterval, TimeIntervalCollection, ConstantProperty, @@ -19,8 +20,6 @@ import { MaterialAppearance, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createScene from "../../../../Specs/createScene.js"; import pollToPromise from "../../../../Specs/pollToPromise.js"; diff --git a/packages/engine/Specs/DataSources/StaticGroundPolylinePerMaterialBatchSpec.js b/packages/engine/Specs/DataSources/StaticGroundPolylinePerMaterialBatchSpec.js index 028ed7db0de..32ade306d4f 100644 --- a/packages/engine/Specs/DataSources/StaticGroundPolylinePerMaterialBatchSpec.js +++ b/packages/engine/Specs/DataSources/StaticGroundPolylinePerMaterialBatchSpec.js @@ -6,6 +6,7 @@ import { defined, DistanceDisplayCondition, JulianDate, + Math as CesiumMath, TimeInterval, TimeIntervalCollection, BoundingSphereState, @@ -21,8 +22,6 @@ import { GroundPolylinePrimitive, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createScene from "../../../../Specs/createScene.js"; import pollToPromise from "../../../../Specs/pollToPromise.js"; diff --git a/packages/engine/Specs/DataSources/StaticOutlineGeometryBatchSpec.js b/packages/engine/Specs/DataSources/StaticOutlineGeometryBatchSpec.js index f468076338a..3af4d26484a 100644 --- a/packages/engine/Specs/DataSources/StaticOutlineGeometryBatchSpec.js +++ b/packages/engine/Specs/DataSources/StaticOutlineGeometryBatchSpec.js @@ -3,6 +3,7 @@ import { Color, DistanceDisplayCondition, JulianDate, + Math as CesiumMath, TimeInterval, TimeIntervalCollection, CallbackProperty, @@ -13,8 +14,6 @@ import { ShadowMode, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createScene from "../../../../Specs/createScene.js"; import pollToPromise from "../../../../Specs/pollToPromise.js"; diff --git a/packages/engine/Specs/DataSources/VelocityVectorPropertySpec.js b/packages/engine/Specs/DataSources/VelocityVectorPropertySpec.js index 0ee09930845..7a65f3b3b3a 100644 --- a/packages/engine/Specs/DataSources/VelocityVectorPropertySpec.js +++ b/packages/engine/Specs/DataSources/VelocityVectorPropertySpec.js @@ -3,14 +3,13 @@ import { Event, ExtrapolationType, JulianDate, + Math as CesiumMath, CallbackProperty, ConstantPositionProperty, SampledPositionProperty, VelocityVectorProperty, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("DataSources/VelocityVectorProperty", function () { const time = JulianDate.now(); diff --git a/packages/engine/Specs/DataSources/exportKmlSpec.js b/packages/engine/Specs/DataSources/exportKmlSpec.js index 542a2edcc33..61c40af5615 100644 --- a/packages/engine/Specs/DataSources/exportKmlSpec.js +++ b/packages/engine/Specs/DataSources/exportKmlSpec.js @@ -8,6 +8,7 @@ import { defined, Iso8601, JulianDate, + Math as CesiumMath, PolygonHierarchy, Rectangle, TimeInterval, @@ -24,8 +25,6 @@ import { VerticalOrigin, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("DataSources/exportKml", function () { let kmlDoc; function checkKmlDoc(entities, properties, options) { diff --git a/packages/engine/Specs/Scene/AxisSpec.js b/packages/engine/Specs/Scene/AxisSpec.js index 5478e5e413b..f01d807ed0f 100644 --- a/packages/engine/Specs/Scene/AxisSpec.js +++ b/packages/engine/Specs/Scene/AxisSpec.js @@ -1,6 +1,4 @@ -import { Cartesian4, Matrix4, Axis } from "../../index.js"; - -import { Math as CesiumMath } from "../../index.js"; +import { Cartesian4, Math as CesiumMath, Matrix4, Axis } from "../../index.js"; describe("Scene/Axis", function () { function convertUpAxis(upAxis, transformation, expected) { diff --git a/packages/engine/Specs/Scene/BatchTableSpec.js b/packages/engine/Specs/Scene/BatchTableSpec.js index feb3c823c6c..ea765487e13 100644 --- a/packages/engine/Specs/Scene/BatchTableSpec.js +++ b/packages/engine/Specs/Scene/BatchTableSpec.js @@ -1,13 +1,12 @@ import { Cartesian4, ComponentDatatype, + Math as CesiumMath, PixelDatatype, Texture, BatchTable, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createScene from "../../../../Specs/createScene.js"; describe( diff --git a/packages/engine/Specs/Scene/BillboardCollectionSpec.js b/packages/engine/Specs/Scene/BillboardCollectionSpec.js index 58b341e8fc7..a47d5246846 100644 --- a/packages/engine/Specs/Scene/BillboardCollectionSpec.js +++ b/packages/engine/Specs/Scene/BillboardCollectionSpec.js @@ -9,6 +9,7 @@ import { createGuid, DistanceDisplayCondition, Globe, + Math as CesiumMath, NearFarScalar, OrthographicOffCenterFrustum, PerspectiveFrustum, @@ -23,8 +24,6 @@ import { VerticalOrigin, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createScene from "../../../../Specs/createScene.js"; import pollToPromise from "../../../../Specs/pollToPromise.js"; diff --git a/packages/engine/Specs/Scene/CameraFlightPathSpec.js b/packages/engine/Specs/Scene/CameraFlightPathSpec.js index 795c7bc0255..a4573e7688e 100644 --- a/packages/engine/Specs/Scene/CameraFlightPathSpec.js +++ b/packages/engine/Specs/Scene/CameraFlightPathSpec.js @@ -4,13 +4,12 @@ import { Ellipsoid, GeographicProjection, Globe, + Math as CesiumMath, OrthographicOffCenterFrustum, CameraFlightPath, SceneMode, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createScene from "../../../../Specs/createScene.js"; describe( diff --git a/packages/engine/Specs/Scene/CameraSpec.js b/packages/engine/Specs/Scene/CameraSpec.js index c6340f832ab..6f90f345f17 100644 --- a/packages/engine/Specs/Scene/CameraSpec.js +++ b/packages/engine/Specs/Scene/CameraSpec.js @@ -8,6 +8,7 @@ import { Ellipsoid, GeographicProjection, HeadingPitchRange, + Math as CesiumMath, Matrix3, Matrix4, OrthographicFrustum, @@ -23,8 +24,6 @@ import { TweenCollection, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("Scene/Camera", function () { let scene; let camera; diff --git a/packages/engine/Specs/Scene/CloudCollectionSpec.js b/packages/engine/Specs/Scene/CloudCollectionSpec.js index fae53214550..a8283482baa 100644 --- a/packages/engine/Specs/Scene/CloudCollectionSpec.js +++ b/packages/engine/Specs/Scene/CloudCollectionSpec.js @@ -7,13 +7,11 @@ import { ComputeCommand, DrawCommand, defined, + Math as CesiumMath, PerspectiveFrustum, } from "../../index.js"; import createScene from "../../../../Specs/createScene.js"; - -import { Math as CesiumMath } from "../../index.js"; - import pollToPromise from "../../../../Specs/pollToPromise.js"; describe( diff --git a/packages/engine/Specs/Scene/ConeEmitterSpec.js b/packages/engine/Specs/Scene/ConeEmitterSpec.js index 54e62f1ce1e..f3f94dd75ad 100644 --- a/packages/engine/Specs/Scene/ConeEmitterSpec.js +++ b/packages/engine/Specs/Scene/ConeEmitterSpec.js @@ -1,6 +1,9 @@ -import { Cartesian3, ConeEmitter, Particle } from "../../index.js"; - -import { Math as CesiumMath } from "../../index.js"; +import { + Cartesian3, + ConeEmitter, + Math as CesiumMath, + Particle, +} from "../../index.js"; describe("Scene/ConeEmitter", function () { it("default constructor", function () { diff --git a/packages/engine/Specs/Scene/DeviceOrientationCameraControllerSpec.js b/packages/engine/Specs/Scene/DeviceOrientationCameraControllerSpec.js index 245d90f9639..af76fa49b6d 100644 --- a/packages/engine/Specs/Scene/DeviceOrientationCameraControllerSpec.js +++ b/packages/engine/Specs/Scene/DeviceOrientationCameraControllerSpec.js @@ -1,6 +1,8 @@ -import { Cartesian3, DeviceOrientationCameraController } from "../../index.js"; - -import { Math as CesiumMath } from "../../index.js"; +import { + Cartesian3, + DeviceOrientationCameraController, + Math as CesiumMath, +} from "../../index.js"; import createCamera from "../../../../Specs/createCamera.js"; import createCanvas from "../../../../Specs/createCanvas.js"; diff --git a/packages/engine/Specs/Scene/ExpressionSpec.js b/packages/engine/Specs/Scene/ExpressionSpec.js index a5a5c7f3942..c1f1d8c9d7b 100644 --- a/packages/engine/Specs/Scene/ExpressionSpec.js +++ b/packages/engine/Specs/Scene/ExpressionSpec.js @@ -5,11 +5,10 @@ import { Color, Expression, ExpressionNodeType, + Math as CesiumMath, RuntimeError, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("Scene/Expression", function () { function MockFeature() { this._properties = {}; diff --git a/packages/engine/Specs/Scene/GeometryRenderingSpec.js b/packages/engine/Specs/Scene/GeometryRenderingSpec.js index 46ebb2e0348..316131be6ef 100644 --- a/packages/engine/Specs/Scene/GeometryRenderingSpec.js +++ b/packages/engine/Specs/Scene/GeometryRenderingSpec.js @@ -19,6 +19,7 @@ import { Geometry, GeometryAttribute, GeometryInstance, + Math as CesiumMath, Matrix4, PerspectiveFrustum, PlaneGeometry, @@ -40,8 +41,6 @@ import { SceneMode, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createScene from "../../../../Specs/createScene.js"; import pollToPromise from "../../../../Specs/pollToPromise.js"; diff --git a/packages/engine/Specs/Scene/GltfLoaderSpec.js b/packages/engine/Specs/Scene/GltfLoaderSpec.js index 24a7f780784..cfcab67f19d 100644 --- a/packages/engine/Specs/Scene/GltfLoaderSpec.js +++ b/packages/engine/Specs/Scene/GltfLoaderSpec.js @@ -122,6 +122,12 @@ describe( "./Data/Models/glTF-2.0/TorusQuantized/glTF/TorusQuantized.gltf"; const boxWeb3dQuantizedAttributes = "./Data/Models/glTF-2.0/BoxWeb3dQuantizedAttributes/glTF/BoxWeb3dQuantizedAttributes.gltf"; + const specularTestData = + "./Data/Models/glTF-2.0/BoxSpecular/glTF/BoxSpecular.gltf"; + const anisotropyTestData = + "./Data/Models/glTF-2.0/BoxAnisotropy/glTF/BoxAnisotropy.gltf"; + const clearcoatTestData = + "./Data/Models/glTF-2.0/BoxClearcoat/glTF/BoxClearcoat.gltf"; let scene; const gltfLoaders = []; @@ -4138,6 +4144,53 @@ describe( }); }); + it("loads model with KHR_materials_specular extension", async function () { + const gltfLoader = await loadGltf(specularTestData); + + const { material } = gltfLoader.components.nodes[1].primitives[0]; + + expect(material.specular.specularFactor).toEqual(0.7); + expect(material.specular.specularTexture.texture.width).toBe(256); + expect(material.specular.specularColorFactor).toEqual( + Cartesian3.fromElements(50, 0, 0) + ); + expect(material.specular.specularTexture.texture.width).toBe(256); + }); + + it("loads model with KHR_materials_anisotropy extension", async function () { + const gltfLoader = await loadGltf(anisotropyTestData); + + const { material } = gltfLoader.components.nodes[1].primitives[0]; + const { + anisotropyStrength, + anisotropyRotation, + anisotropyTexture, + } = material.anisotropy; + + expect(anisotropyStrength).toBe(0.5); + expect(anisotropyRotation).toBe(0.349065850398866); + expect(anisotropyTexture.texture.width).toBe(256); + }); + + it("loads model with KHR_materials_clearcoat extension", async function () { + const gltfLoader = await loadGltf(clearcoatTestData); + + const { material } = gltfLoader.components.nodes[1].primitives[0]; + const { + clearcoatFactor, + clearcoatTexture, + clearcoatRoughnessFactor, + clearcoatRoughnessTexture, + clearcoatNormalTexture, + } = material.clearcoat; + + expect(clearcoatFactor).toBe(0.5); + expect(clearcoatTexture.texture.width).toBe(256); + expect(clearcoatRoughnessFactor).toBe(0.2); + expect(clearcoatRoughnessTexture.texture.width).toBe(256); + expect(clearcoatNormalTexture.texture.width).toBe(256); + }); + it("parses copyright field", function () { return loadGltf(boxWithCredits).then(function (gltfLoader) { const components = gltfLoader.components; diff --git a/packages/engine/Specs/Scene/GroundPolylinePrimitiveSpec.js b/packages/engine/Specs/Scene/GroundPolylinePrimitiveSpec.js index 3e394c60955..fd9f8eeb639 100644 --- a/packages/engine/Specs/Scene/GroundPolylinePrimitiveSpec.js +++ b/packages/engine/Specs/Scene/GroundPolylinePrimitiveSpec.js @@ -10,6 +10,7 @@ import { GeometryInstance, GroundPolylineGeometry, HeadingPitchRange, + Math as CesiumMath, Rectangle, RectangleGeometry, ShowGeometryInstanceAttribute, @@ -21,8 +22,6 @@ import { Primitive, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createCanvas from "../../../../Specs/createCanvas.js"; import createScene from "../../../../Specs/createScene.js"; import pollToPromise from "../../../../Specs/pollToPromise.js"; diff --git a/packages/engine/Specs/Scene/GroundPrimitiveSpec.js b/packages/engine/Specs/Scene/GroundPrimitiveSpec.js index 20a453354b2..1fffa328d6f 100644 --- a/packages/engine/Specs/Scene/GroundPrimitiveSpec.js +++ b/packages/engine/Specs/Scene/GroundPrimitiveSpec.js @@ -7,6 +7,7 @@ import { Ellipsoid, GeometryInstance, HeadingPitchRange, + Math as CesiumMath, PolygonGeometry, Rectangle, RectangleGeometry, @@ -23,8 +24,6 @@ import { StencilConstants, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createCanvas from "../../../../Specs/createCanvas.js"; import createScene from "../../../../Specs/createScene.js"; import pollToPromise from "../../../../Specs/pollToPromise.js"; diff --git a/packages/engine/Specs/Scene/HeightmapTessellatorSpec.js b/packages/engine/Specs/Scene/HeightmapTessellatorSpec.js index 9505296676e..06835f4d42a 100644 --- a/packages/engine/Specs/Scene/HeightmapTessellatorSpec.js +++ b/packages/engine/Specs/Scene/HeightmapTessellatorSpec.js @@ -3,12 +3,11 @@ import { Cartesian3, Ellipsoid, HeightmapTessellator, + Math as CesiumMath, Rectangle, WebMercatorProjection, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("Scene/HeightmapTessellator", function () { it("throws when heightmap is not provided", function () { expect(function () { diff --git a/packages/engine/Specs/Scene/LabelCollectionSpec.js b/packages/engine/Specs/Scene/LabelCollectionSpec.js index 70d96c24404..352e8fcfd82 100644 --- a/packages/engine/Specs/Scene/LabelCollectionSpec.js +++ b/packages/engine/Specs/Scene/LabelCollectionSpec.js @@ -7,6 +7,7 @@ import { Color, defined, DistanceDisplayCondition, + Math as CesiumMath, NearFarScalar, Rectangle, BlendOption, @@ -19,7 +20,6 @@ import { VerticalOrigin, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; import createScene from "../../../../Specs/createScene.js"; import pollToPromise from "../../../../Specs/pollToPromise.js"; diff --git a/packages/engine/Specs/Scene/MapboxImageryProviderSpec.js b/packages/engine/Specs/Scene/MapboxImageryProviderSpec.js index e2f3374f26a..201da71b3e6 100644 --- a/packages/engine/Specs/Scene/MapboxImageryProviderSpec.js +++ b/packages/engine/Specs/Scene/MapboxImageryProviderSpec.js @@ -1,4 +1,5 @@ import { + Math as CesiumMath, Rectangle, Request, RequestScheduler, @@ -10,7 +11,6 @@ import { ImageryState, MapboxImageryProvider, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; import pollToPromise from "../../../../Specs/pollToPromise.js"; diff --git a/packages/engine/Specs/Scene/MapboxStyleImageryProviderSpec.js b/packages/engine/Specs/Scene/MapboxStyleImageryProviderSpec.js index 16fa51193a1..a44d3c25c3e 100644 --- a/packages/engine/Specs/Scene/MapboxStyleImageryProviderSpec.js +++ b/packages/engine/Specs/Scene/MapboxStyleImageryProviderSpec.js @@ -1,4 +1,5 @@ import { + Math as CesiumMath, Rectangle, Request, RequestScheduler, @@ -10,7 +11,6 @@ import { ImageryState, MapboxStyleImageryProvider, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; import pollToPromise from "../../../../Specs/pollToPromise.js"; diff --git a/packages/engine/Specs/Scene/Model/MaterialPipelineStageSpec.js b/packages/engine/Specs/Scene/Model/MaterialPipelineStageSpec.js index 9c6f090d70a..389be73969a 100644 --- a/packages/engine/Specs/Scene/Model/MaterialPipelineStageSpec.js +++ b/packages/engine/Specs/Scene/Model/MaterialPipelineStageSpec.js @@ -85,6 +85,12 @@ describe( const triangle = "./Data/Models/glTF-2.0/Triangle/glTF/Triangle.gltf"; const twoSidedPlane = "./Data/Models/glTF-2.0/TwoSidedPlane/glTF/TwoSidedPlane.gltf"; + const specularTestData = + "./Data/Models/glTF-2.0/BoxSpecular/glTF/BoxSpecular.gltf"; + const anisotropyTestData = + "./Data/Models/glTF-2.0/BoxAnisotropy/glTF/BoxAnisotropy.gltf"; + const clearcoatTestData = + "./Data/Models/glTF-2.0/BoxClearcoat/glTF/BoxClearcoat.gltf"; function expectUniformMap(uniformMap, expected) { for (const key in expected) { @@ -111,656 +117,671 @@ describe( }; } - it("processes default material", function () { - return loadGltf(triangle).then(function (gltfLoader) { - const components = gltfLoader.components; - const primitive = components.nodes[0].primitives[0]; + it("processes default material", async function () { + const gltfLoader = await loadGltf(triangle); + const primitive = gltfLoader.components.nodes[0].primitives[0]; - const renderResources = mockRenderResources(); - const shaderBuilder = renderResources.shaderBuilder; - const uniformMap = renderResources.uniformMap; + const renderResources = mockRenderResources(); + const { shaderBuilder, uniformMap } = renderResources; - MaterialPipelineStage.process( - renderResources, - primitive, - mockFrameState - ); + MaterialPipelineStage.process(renderResources, primitive, mockFrameState); - ShaderBuilderTester.expectHasVertexUniforms(shaderBuilder, []); - ShaderBuilderTester.expectHasFragmentUniforms(shaderBuilder, []); + ShaderBuilderTester.expectHasVertexUniforms(shaderBuilder, []); + ShaderBuilderTester.expectHasFragmentUniforms(shaderBuilder, []); - ShaderBuilderTester.expectHasVertexDefines(shaderBuilder, []); - ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [ - "USE_METALLIC_ROUGHNESS", - ]); + ShaderBuilderTester.expectHasVertexDefines(shaderBuilder, []); + ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [ + "USE_METALLIC_ROUGHNESS", + ]); - const expectedUniforms = {}; - expectUniformMap(uniformMap, expectedUniforms); - }); + const expectedUniforms = {}; + expectUniformMap(uniformMap, expectedUniforms); }); - it("adds material and metallic roughness uniforms", function () { - return loadGltf(boomBox).then(function (gltfLoader) { - const components = gltfLoader.components; - const primitive = components.nodes[0].primitives[0]; - const renderResources = mockRenderResources(); - const shaderBuilder = renderResources.shaderBuilder; - const uniformMap = renderResources.uniformMap; - - MaterialPipelineStage.process( - renderResources, - primitive, - mockFrameState - ); - - ShaderBuilderTester.expectHasVertexUniforms(shaderBuilder, []); - ShaderBuilderTester.expectHasFragmentUniforms(shaderBuilder, [ - "uniform sampler2D u_baseColorTexture;", - "uniform sampler2D u_emissiveTexture;", - "uniform sampler2D u_metallicRoughnessTexture;", - "uniform sampler2D u_normalTexture;", - "uniform sampler2D u_occlusionTexture;", - "uniform vec3 u_emissiveFactor;", - ]); - - ShaderBuilderTester.expectHasVertexDefines(shaderBuilder, []); - ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [ - "HAS_BASE_COLOR_TEXTURE", - "HAS_EMISSIVE_FACTOR", - "HAS_EMISSIVE_TEXTURE", - "HAS_METALLIC_ROUGHNESS_TEXTURE", - "HAS_NORMAL_TEXTURE", - "HAS_OCCLUSION_TEXTURE", - "TEXCOORD_BASE_COLOR v_texCoord_0", - "TEXCOORD_EMISSIVE v_texCoord_0", - "TEXCOORD_METALLIC_ROUGHNESS v_texCoord_0", - "TEXCOORD_NORMAL v_texCoord_0", - "TEXCOORD_OCCLUSION v_texCoord_0", - "USE_METALLIC_ROUGHNESS", - ]); - - const metallicRoughness = primitive.material.metallicRoughness; - const material = primitive.material; - const expectedUniforms = { - u_emissiveTexture: material.emissiveTexture.texture, - u_emissiveFactor: material.emissiveFactor, - u_normalTexture: material.normalTexture.texture, - u_occlusionTexture: material.occlusionTexture.texture, - u_baseColorTexture: metallicRoughness.baseColorTexture.texture, - u_metallicRoughnessTexture: - metallicRoughness.metallicRoughnessTexture.texture, - }; - expectUniformMap(uniformMap, expectedUniforms); - }); + it("adds material and metallic roughness uniforms", async function () { + const gltfLoader = await loadGltf(boomBox); + const primitive = gltfLoader.components.nodes[0].primitives[0]; + const renderResources = mockRenderResources(); + const { shaderBuilder, uniformMap } = renderResources; + + MaterialPipelineStage.process(renderResources, primitive, mockFrameState); + + ShaderBuilderTester.expectHasVertexUniforms(shaderBuilder, []); + ShaderBuilderTester.expectHasFragmentUniforms(shaderBuilder, [ + "uniform sampler2D u_baseColorTexture;", + "uniform sampler2D u_emissiveTexture;", + "uniform sampler2D u_metallicRoughnessTexture;", + "uniform sampler2D u_normalTexture;", + "uniform sampler2D u_occlusionTexture;", + "uniform vec3 u_emissiveFactor;", + ]); + + ShaderBuilderTester.expectHasVertexDefines(shaderBuilder, []); + ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [ + "HAS_BASE_COLOR_TEXTURE", + "HAS_EMISSIVE_FACTOR", + "HAS_EMISSIVE_TEXTURE", + "HAS_METALLIC_ROUGHNESS_TEXTURE", + "HAS_NORMAL_TEXTURE", + "HAS_OCCLUSION_TEXTURE", + "TEXCOORD_BASE_COLOR v_texCoord_0", + "TEXCOORD_EMISSIVE v_texCoord_0", + "TEXCOORD_METALLIC_ROUGHNESS v_texCoord_0", + "TEXCOORD_NORMAL v_texCoord_0", + "TEXCOORD_OCCLUSION v_texCoord_0", + "USE_METALLIC_ROUGHNESS", + ]); + + const metallicRoughness = primitive.material.metallicRoughness; + const material = primitive.material; + const expectedUniforms = { + u_emissiveTexture: material.emissiveTexture.texture, + u_emissiveFactor: material.emissiveFactor, + u_normalTexture: material.normalTexture.texture, + u_occlusionTexture: material.occlusionTexture.texture, + u_baseColorTexture: metallicRoughness.baseColorTexture.texture, + u_metallicRoughnessTexture: + metallicRoughness.metallicRoughnessTexture.texture, + }; + expectUniformMap(uniformMap, expectedUniforms); }); - it("adds metallic roughness uniforms without defaults", function () { - return loadGltf(boomBox).then(function (gltfLoader) { - const components = gltfLoader.components; - const primitive = components.nodes[0].primitives[0]; - - const metallicRoughness = primitive.material.metallicRoughness; - metallicRoughness.baseColorFactor = new Cartesian4(0.5, 0.5, 0.5, 0.5); - metallicRoughness.metallicFactor = 0.5; - metallicRoughness.roughnessFactor = 0.5; - - const renderResources = mockRenderResources(); - const shaderBuilder = renderResources.shaderBuilder; - const uniformMap = renderResources.uniformMap; - - MaterialPipelineStage.process( - renderResources, - primitive, - mockFrameState - ); - - ShaderBuilderTester.expectHasVertexUniforms(shaderBuilder, []); - ShaderBuilderTester.expectHasFragmentUniforms(shaderBuilder, [ - "uniform float u_metallicFactor;", - "uniform float u_roughnessFactor;", - "uniform sampler2D u_baseColorTexture;", - "uniform sampler2D u_emissiveTexture;", - "uniform sampler2D u_metallicRoughnessTexture;", - "uniform sampler2D u_normalTexture;", - "uniform sampler2D u_occlusionTexture;", - "uniform vec3 u_emissiveFactor;", - "uniform vec4 u_baseColorFactor;", - ]); - - ShaderBuilderTester.expectHasVertexDefines(shaderBuilder, []); - ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [ - "HAS_BASE_COLOR_FACTOR", - "HAS_BASE_COLOR_TEXTURE", - "HAS_EMISSIVE_FACTOR", - "HAS_EMISSIVE_TEXTURE", - "HAS_METALLIC_FACTOR", - "HAS_METALLIC_ROUGHNESS_TEXTURE", - "HAS_NORMAL_TEXTURE", - "HAS_OCCLUSION_TEXTURE", - "HAS_ROUGHNESS_FACTOR", - "TEXCOORD_BASE_COLOR v_texCoord_0", - "TEXCOORD_EMISSIVE v_texCoord_0", - "TEXCOORD_METALLIC_ROUGHNESS v_texCoord_0", - "TEXCOORD_NORMAL v_texCoord_0", - "TEXCOORD_OCCLUSION v_texCoord_0", - "USE_METALLIC_ROUGHNESS", - ]); - - const expectedUniforms = { - u_baseColorTexture: metallicRoughness.baseColorTexture.texture, - u_baseColorFactor: metallicRoughness.baseColorFactor, - u_metallicRoughnessTexture: - metallicRoughness.metallicRoughnessTexture.texture, - u_metallicFactor: metallicRoughness.metallicFactor, - u_roughnessFactor: metallicRoughness.roughnessFactor, - }; - expectUniformMap(uniformMap, expectedUniforms); - }); + it("adds metallic roughness uniforms without defaults", async function () { + const gltfLoader = await loadGltf(boomBox); + const primitive = gltfLoader.components.nodes[0].primitives[0]; + + const metallicRoughness = primitive.material.metallicRoughness; + metallicRoughness.baseColorFactor = new Cartesian4(0.5, 0.5, 0.5, 0.5); + metallicRoughness.metallicFactor = 0.5; + metallicRoughness.roughnessFactor = 0.5; + + const renderResources = mockRenderResources(); + const { shaderBuilder, uniformMap } = renderResources; + + MaterialPipelineStage.process(renderResources, primitive, mockFrameState); + + ShaderBuilderTester.expectHasVertexUniforms(shaderBuilder, []); + ShaderBuilderTester.expectHasFragmentUniforms(shaderBuilder, [ + "uniform float u_metallicFactor;", + "uniform float u_roughnessFactor;", + "uniform sampler2D u_baseColorTexture;", + "uniform sampler2D u_emissiveTexture;", + "uniform sampler2D u_metallicRoughnessTexture;", + "uniform sampler2D u_normalTexture;", + "uniform sampler2D u_occlusionTexture;", + "uniform vec3 u_emissiveFactor;", + "uniform vec4 u_baseColorFactor;", + ]); + + ShaderBuilderTester.expectHasVertexDefines(shaderBuilder, []); + ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [ + "HAS_BASE_COLOR_FACTOR", + "HAS_BASE_COLOR_TEXTURE", + "HAS_EMISSIVE_FACTOR", + "HAS_EMISSIVE_TEXTURE", + "HAS_METALLIC_FACTOR", + "HAS_METALLIC_ROUGHNESS_TEXTURE", + "HAS_NORMAL_TEXTURE", + "HAS_OCCLUSION_TEXTURE", + "HAS_ROUGHNESS_FACTOR", + "TEXCOORD_BASE_COLOR v_texCoord_0", + "TEXCOORD_EMISSIVE v_texCoord_0", + "TEXCOORD_METALLIC_ROUGHNESS v_texCoord_0", + "TEXCOORD_NORMAL v_texCoord_0", + "TEXCOORD_OCCLUSION v_texCoord_0", + "USE_METALLIC_ROUGHNESS", + ]); + + const expectedUniforms = { + u_baseColorTexture: metallicRoughness.baseColorTexture.texture, + u_baseColorFactor: metallicRoughness.baseColorFactor, + u_metallicRoughnessTexture: + metallicRoughness.metallicRoughnessTexture.texture, + u_metallicFactor: metallicRoughness.metallicFactor, + u_roughnessFactor: metallicRoughness.roughnessFactor, + }; + expectUniformMap(uniformMap, expectedUniforms); }); - it("doesn't add emissive uniforms when emissive factor is default", function () { - return loadGltf(boomBox).then(function (gltfLoader) { - const components = gltfLoader.components; - const primitive = components.nodes[0].primitives[0]; - - const material = primitive.material; - material.emissiveFactor = Cartesian3.clone( - ModelComponents.Material.DEFAULT_EMISSIVE_FACTOR - ); - const metallicRoughness = material.metallicRoughness; - - const renderResources = mockRenderResources(); - const shaderBuilder = renderResources.shaderBuilder; - const uniformMap = renderResources.uniformMap; - - MaterialPipelineStage.process( - renderResources, - primitive, - mockFrameState - ); - - ShaderBuilderTester.expectHasVertexUniforms(shaderBuilder, []); - ShaderBuilderTester.expectHasFragmentUniforms(shaderBuilder, [ - "uniform sampler2D u_baseColorTexture;", - "uniform sampler2D u_metallicRoughnessTexture;", - "uniform sampler2D u_normalTexture;", - "uniform sampler2D u_occlusionTexture;", - ]); - - ShaderBuilderTester.expectHasVertexDefines(shaderBuilder, []); - ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [ - "HAS_BASE_COLOR_TEXTURE", - "HAS_METALLIC_ROUGHNESS_TEXTURE", - "HAS_NORMAL_TEXTURE", - "HAS_OCCLUSION_TEXTURE", - "TEXCOORD_BASE_COLOR v_texCoord_0", - "TEXCOORD_METALLIC_ROUGHNESS v_texCoord_0", - "TEXCOORD_NORMAL v_texCoord_0", - "TEXCOORD_OCCLUSION v_texCoord_0", - "USE_METALLIC_ROUGHNESS", - ]); - - const expectedUniforms = { - u_normalTexture: material.normalTexture.texture, - u_occlusionTexture: material.occlusionTexture.texture, - u_baseColorTexture: metallicRoughness.baseColorTexture.texture, - u_metallicRoughnessTexture: - metallicRoughness.metallicRoughnessTexture.texture, - }; - expectUniformMap(uniformMap, expectedUniforms); - }); + it("doesn't add emissive uniforms when emissive factor is default", async function () { + const gltfLoader = await loadGltf(boomBox); + const primitive = gltfLoader.components.nodes[0].primitives[0]; + + const material = primitive.material; + material.emissiveFactor = Cartesian3.clone( + ModelComponents.Material.DEFAULT_EMISSIVE_FACTOR + ); + const metallicRoughness = material.metallicRoughness; + + const renderResources = mockRenderResources(); + const { shaderBuilder, uniformMap } = renderResources; + + MaterialPipelineStage.process(renderResources, primitive, mockFrameState); + + ShaderBuilderTester.expectHasVertexUniforms(shaderBuilder, []); + ShaderBuilderTester.expectHasFragmentUniforms(shaderBuilder, [ + "uniform sampler2D u_baseColorTexture;", + "uniform sampler2D u_metallicRoughnessTexture;", + "uniform sampler2D u_normalTexture;", + "uniform sampler2D u_occlusionTexture;", + ]); + + ShaderBuilderTester.expectHasVertexDefines(shaderBuilder, []); + ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [ + "HAS_BASE_COLOR_TEXTURE", + "HAS_METALLIC_ROUGHNESS_TEXTURE", + "HAS_NORMAL_TEXTURE", + "HAS_OCCLUSION_TEXTURE", + "TEXCOORD_BASE_COLOR v_texCoord_0", + "TEXCOORD_METALLIC_ROUGHNESS v_texCoord_0", + "TEXCOORD_NORMAL v_texCoord_0", + "TEXCOORD_OCCLUSION v_texCoord_0", + "USE_METALLIC_ROUGHNESS", + ]); + + const expectedUniforms = { + u_normalTexture: material.normalTexture.texture, + u_occlusionTexture: material.occlusionTexture.texture, + u_baseColorTexture: metallicRoughness.baseColorTexture.texture, + u_metallicRoughnessTexture: + metallicRoughness.metallicRoughnessTexture.texture, + }; + expectUniformMap(uniformMap, expectedUniforms); }); - it("adds specular glossiness uniforms", function () { - return loadGltf(boomBoxSpecularGlossiness).then(function (gltfLoader) { - const components = gltfLoader.components; - const primitive = components.nodes[0].primitives[0]; - const renderResources = mockRenderResources(); - const shaderBuilder = renderResources.shaderBuilder; - const uniformMap = renderResources.uniformMap; - - MaterialPipelineStage.process( - renderResources, - primitive, - mockFrameState - ); - ShaderBuilderTester.expectHasVertexUniforms(shaderBuilder, []); - ShaderBuilderTester.expectHasFragmentUniforms(shaderBuilder, [ - "uniform float u_glossinessFactor;", - "uniform sampler2D u_diffuseTexture;", - "uniform sampler2D u_emissiveTexture;", - "uniform sampler2D u_normalTexture;", - "uniform sampler2D u_occlusionTexture;", - "uniform sampler2D u_specularGlossinessTexture;", - "uniform vec3 u_emissiveFactor;", - ]); - - ShaderBuilderTester.expectHasVertexDefines(shaderBuilder, []); - ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [ - "HAS_DIFFUSE_TEXTURE", - "HAS_EMISSIVE_FACTOR", - "HAS_EMISSIVE_TEXTURE", - "HAS_GLOSSINESS_FACTOR", - "HAS_NORMAL_TEXTURE", - "HAS_OCCLUSION_TEXTURE", - "HAS_SPECULAR_GLOSSINESS_TEXTURE", - "TEXCOORD_DIFFUSE v_texCoord_0", - "TEXCOORD_EMISSIVE v_texCoord_0", - "TEXCOORD_NORMAL v_texCoord_0", - "TEXCOORD_OCCLUSION v_texCoord_0", - "TEXCOORD_SPECULAR_GLOSSINESS v_texCoord_0", - "USE_SPECULAR_GLOSSINESS", - ]); - - const specularGlossiness = primitive.material.specularGlossiness; - const expectedUniforms = { - u_diffuseTexture: specularGlossiness.diffuseTexture.texture, - u_specularGlossinessTexture: - specularGlossiness.specularGlossinessTexture.texture, - u_glossinessFactor: specularGlossiness.glossinessFactor, - }; - expectUniformMap(uniformMap, expectedUniforms); - }); + it("adds specular glossiness uniforms", async function () { + const gltfLoader = await loadGltf(boomBoxSpecularGlossiness); + const primitive = gltfLoader.components.nodes[0].primitives[0]; + const renderResources = mockRenderResources(); + const { shaderBuilder, uniformMap } = renderResources; + + MaterialPipelineStage.process(renderResources, primitive, mockFrameState); + ShaderBuilderTester.expectHasVertexUniforms(shaderBuilder, []); + ShaderBuilderTester.expectHasFragmentUniforms(shaderBuilder, [ + "uniform float u_glossinessFactor;", + "uniform sampler2D u_diffuseTexture;", + "uniform sampler2D u_emissiveTexture;", + "uniform sampler2D u_normalTexture;", + "uniform sampler2D u_occlusionTexture;", + "uniform sampler2D u_specularGlossinessTexture;", + "uniform vec3 u_emissiveFactor;", + ]); + + ShaderBuilderTester.expectHasVertexDefines(shaderBuilder, []); + ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [ + "HAS_DIFFUSE_TEXTURE", + "HAS_EMISSIVE_FACTOR", + "HAS_EMISSIVE_TEXTURE", + "HAS_GLOSSINESS_FACTOR", + "HAS_NORMAL_TEXTURE", + "HAS_OCCLUSION_TEXTURE", + "HAS_SPECULAR_GLOSSINESS_TEXTURE", + "TEXCOORD_DIFFUSE v_texCoord_0", + "TEXCOORD_EMISSIVE v_texCoord_0", + "TEXCOORD_NORMAL v_texCoord_0", + "TEXCOORD_OCCLUSION v_texCoord_0", + "TEXCOORD_SPECULAR_GLOSSINESS v_texCoord_0", + "USE_SPECULAR_GLOSSINESS", + ]); + + const specularGlossiness = primitive.material.specularGlossiness; + const expectedUniforms = { + u_diffuseTexture: specularGlossiness.diffuseTexture.texture, + u_specularGlossinessTexture: + specularGlossiness.specularGlossinessTexture.texture, + u_glossinessFactor: specularGlossiness.glossinessFactor, + }; + expectUniformMap(uniformMap, expectedUniforms); }); - it("adds specular glossiness uniforms without defaults", function () { - return loadGltf(boomBoxSpecularGlossiness).then(function (gltfLoader) { - const components = gltfLoader.components; - const primitive = components.nodes[0].primitives[0]; - - const specularGlossiness = primitive.material.specularGlossiness; - specularGlossiness.diffuseFactor = new Cartesian4(0.5, 0.5, 0.5, 0.5); - specularGlossiness.specularFactor = new Cartesian3(0.5, 0.5, 0.5); - - const renderResources = mockRenderResources(); - const shaderBuilder = renderResources.shaderBuilder; - const uniformMap = renderResources.uniformMap; - - MaterialPipelineStage.process( - renderResources, - primitive, - mockFrameState - ); - - ShaderBuilderTester.expectHasVertexUniforms(shaderBuilder, []); - ShaderBuilderTester.expectHasFragmentUniforms(shaderBuilder, [ - "uniform float u_glossinessFactor;", - "uniform sampler2D u_diffuseTexture;", - "uniform sampler2D u_emissiveTexture;", - "uniform sampler2D u_normalTexture;", - "uniform sampler2D u_occlusionTexture;", - "uniform sampler2D u_specularGlossinessTexture;", - "uniform vec3 u_emissiveFactor;", - "uniform vec3 u_specularFactor;", - "uniform vec4 u_diffuseFactor;", - ]); - - ShaderBuilderTester.expectHasVertexDefines(shaderBuilder, []); - ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [ - "HAS_DIFFUSE_FACTOR", - "HAS_DIFFUSE_TEXTURE", - "HAS_EMISSIVE_FACTOR", - "HAS_EMISSIVE_TEXTURE", - "HAS_GLOSSINESS_FACTOR", - "HAS_NORMAL_TEXTURE", - "HAS_OCCLUSION_TEXTURE", - "HAS_SPECULAR_FACTOR", - "HAS_SPECULAR_GLOSSINESS_TEXTURE", - "TEXCOORD_DIFFUSE v_texCoord_0", - "TEXCOORD_EMISSIVE v_texCoord_0", - "TEXCOORD_NORMAL v_texCoord_0", - "TEXCOORD_OCCLUSION v_texCoord_0", - "TEXCOORD_SPECULAR_GLOSSINESS v_texCoord_0", - "USE_SPECULAR_GLOSSINESS", - ]); - - const expectedUniforms = { - u_diffuseTexture: specularGlossiness.diffuseTexture.texture, - u_diffuseFactor: specularGlossiness.diffuseFactor, - u_specularGlossinessTexture: - specularGlossiness.specularGlossinessTexture.texture, - u_specularFactor: specularGlossiness.specularFactor, - u_glossinessFactor: specularGlossiness.glossinessFactor, - }; - expectUniformMap(uniformMap, expectedUniforms); - }); + it("adds specular glossiness uniforms without defaults", async function () { + const gltfLoader = await loadGltf(boomBoxSpecularGlossiness); + const primitive = gltfLoader.components.nodes[0].primitives[0]; + + const specularGlossiness = primitive.material.specularGlossiness; + specularGlossiness.diffuseFactor = new Cartesian4(0.5, 0.5, 0.5, 0.5); + specularGlossiness.specularFactor = new Cartesian3(0.5, 0.5, 0.5); + + const renderResources = mockRenderResources(); + const { shaderBuilder, uniformMap } = renderResources; + + MaterialPipelineStage.process(renderResources, primitive, mockFrameState); + + ShaderBuilderTester.expectHasVertexUniforms(shaderBuilder, []); + ShaderBuilderTester.expectHasFragmentUniforms(shaderBuilder, [ + "uniform float u_glossinessFactor;", + "uniform sampler2D u_diffuseTexture;", + "uniform sampler2D u_emissiveTexture;", + "uniform sampler2D u_normalTexture;", + "uniform sampler2D u_occlusionTexture;", + "uniform sampler2D u_specularGlossinessTexture;", + "uniform vec3 u_emissiveFactor;", + "uniform vec3 u_legacySpecularFactor;", + "uniform vec4 u_diffuseFactor;", + ]); + + ShaderBuilderTester.expectHasVertexDefines(shaderBuilder, []); + ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [ + "HAS_DIFFUSE_FACTOR", + "HAS_DIFFUSE_TEXTURE", + "HAS_EMISSIVE_FACTOR", + "HAS_EMISSIVE_TEXTURE", + "HAS_GLOSSINESS_FACTOR", + "HAS_NORMAL_TEXTURE", + "HAS_OCCLUSION_TEXTURE", + "HAS_LEGACY_SPECULAR_FACTOR", + "HAS_SPECULAR_GLOSSINESS_TEXTURE", + "TEXCOORD_DIFFUSE v_texCoord_0", + "TEXCOORD_EMISSIVE v_texCoord_0", + "TEXCOORD_NORMAL v_texCoord_0", + "TEXCOORD_OCCLUSION v_texCoord_0", + "TEXCOORD_SPECULAR_GLOSSINESS v_texCoord_0", + "USE_SPECULAR_GLOSSINESS", + ]); + + const expectedUniforms = { + u_diffuseTexture: specularGlossiness.diffuseTexture.texture, + u_diffuseFactor: specularGlossiness.diffuseFactor, + u_specularGlossinessTexture: + specularGlossiness.specularGlossinessTexture.texture, + u_legacySpecularFactor: specularGlossiness.specularFactor, + u_glossinessFactor: specularGlossiness.glossinessFactor, + }; + expectUniformMap(uniformMap, expectedUniforms); }); - it("doesn't add texture uniforms for classification models", function () { - return loadGltf(boomBox).then(function (gltfLoader) { - const components = gltfLoader.components; - const primitive = components.nodes[0].primitives[0]; - const renderResources = mockRenderResources(ClassificationType.BOTH); - const shaderBuilder = renderResources.shaderBuilder; - const uniformMap = renderResources.uniformMap; - - MaterialPipelineStage.process( - renderResources, - primitive, - mockFrameState - ); - - ShaderBuilderTester.expectHasVertexUniforms(shaderBuilder, []); - ShaderBuilderTester.expectHasFragmentUniforms(shaderBuilder, [ - "uniform vec3 u_emissiveFactor;", - ]); - - ShaderBuilderTester.expectHasVertexDefines(shaderBuilder, []); - ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [ - "HAS_EMISSIVE_FACTOR", - "USE_METALLIC_ROUGHNESS", - ]); - const material = primitive.material; - const expectedUniforms = { - u_emissiveFactor: material.emissiveFactor, - }; - expectUniformMap(uniformMap, expectedUniforms); - }); + it("adds uniforms and defines for KHR_materials_specular", async function () { + const gltfLoader = await loadGltf(specularTestData); + + const primitive = gltfLoader.components.nodes[1].primitives[0]; + + const renderResources = mockRenderResources(); + const { shaderBuilder, uniformMap } = renderResources; + + MaterialPipelineStage.process(renderResources, primitive, mockFrameState); + ShaderBuilderTester.expectHasVertexUniforms(shaderBuilder, []); + ShaderBuilderTester.expectHasFragmentUniforms(shaderBuilder, [ + "uniform float u_metallicFactor;", + "uniform float u_specularFactor;", + "uniform sampler2D u_baseColorTexture;", + "uniform sampler2D u_specularColorTexture;", + "uniform sampler2D u_specularTexture;", + "uniform vec3 u_specularColorFactor;", + ]); + + ShaderBuilderTester.expectHasVertexDefines(shaderBuilder, []); + ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [ + "HAS_BASE_COLOR_TEXTURE", + "HAS_METALLIC_FACTOR", + "HAS_SPECULAR_COLOR_FACTOR", + "HAS_SPECULAR_COLOR_TEXTURE", + "HAS_SPECULAR_FACTOR", + "HAS_SPECULAR_TEXTURE", + "TEXCOORD_BASE_COLOR v_texCoord_0", + "TEXCOORD_SPECULAR v_texCoord_0", + "TEXCOORD_SPECULAR_COLOR v_texCoord_0", + "USE_METALLIC_ROUGHNESS", + "USE_SPECULAR", + ]); + + const { + specularFactor, + specularTexture, + specularColorFactor, + specularColorTexture, + } = primitive.material.specular; + const expectedUniforms = { + u_specularFactor: specularFactor, + u_specularColorFactor: specularColorFactor, + u_specularTexture: specularTexture.texture, + u_specularColorTexture: specularColorTexture.texture, + }; + expectUniformMap(uniformMap, expectedUniforms); }); - it("doesn't add metallic roughness textures for classification models", function () { - return loadGltf(boomBox).then(function (gltfLoader) { - const components = gltfLoader.components; - const primitive = components.nodes[0].primitives[0]; - - const metallicRoughness = primitive.material.metallicRoughness; - metallicRoughness.baseColorFactor = new Cartesian4(0.5, 0.5, 0.5, 0.5); - metallicRoughness.metallicFactor = 0.5; - metallicRoughness.roughnessFactor = 0.5; - - const renderResources = mockRenderResources(); - const shaderBuilder = renderResources.shaderBuilder; - const uniformMap = renderResources.uniformMap; - - MaterialPipelineStage.process( - renderResources, - primitive, - mockFrameState - ); - - ShaderBuilderTester.expectHasVertexUniforms(shaderBuilder, []); - ShaderBuilderTester.expectHasFragmentUniforms(shaderBuilder, [ - "uniform float u_metallicFactor;", - "uniform float u_roughnessFactor;", - "uniform sampler2D u_baseColorTexture;", - "uniform sampler2D u_emissiveTexture;", - "uniform sampler2D u_metallicRoughnessTexture;", - "uniform sampler2D u_normalTexture;", - "uniform sampler2D u_occlusionTexture;", - "uniform vec3 u_emissiveFactor;", - "uniform vec4 u_baseColorFactor;", - ]); - - ShaderBuilderTester.expectHasVertexDefines(shaderBuilder, []); - ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [ - "HAS_BASE_COLOR_FACTOR", - "HAS_BASE_COLOR_TEXTURE", - "HAS_EMISSIVE_FACTOR", - "HAS_EMISSIVE_TEXTURE", - "HAS_METALLIC_FACTOR", - "HAS_METALLIC_ROUGHNESS_TEXTURE", - "HAS_NORMAL_TEXTURE", - "HAS_OCCLUSION_TEXTURE", - "HAS_ROUGHNESS_FACTOR", - "TEXCOORD_BASE_COLOR v_texCoord_0", - "TEXCOORD_EMISSIVE v_texCoord_0", - "TEXCOORD_METALLIC_ROUGHNESS v_texCoord_0", - "TEXCOORD_NORMAL v_texCoord_0", - "TEXCOORD_OCCLUSION v_texCoord_0", - "USE_METALLIC_ROUGHNESS", - ]); - - const expectedUniforms = { - u_baseColorFactor: metallicRoughness.baseColorFactor, - u_metallicFactor: metallicRoughness.metallicFactor, - u_roughnessFactor: metallicRoughness.roughnessFactor, - }; - expectUniformMap(uniformMap, expectedUniforms); - }); + it("adds uniforms and defines for KHR_materials_anisotropy", async function () { + const gltfLoader = await loadGltf(anisotropyTestData); + + const primitive = gltfLoader.components.nodes[1].primitives[0]; + const renderResources = mockRenderResources(); + MaterialPipelineStage.process(renderResources, primitive, mockFrameState); + const { shaderBuilder, uniformMap } = renderResources; + + ShaderBuilderTester.expectHasVertexUniforms(shaderBuilder, []); + ShaderBuilderTester.expectHasFragmentUniforms(shaderBuilder, [ + "uniform float u_metallicFactor;", + "uniform sampler2D u_anisotropyTexture;", + "uniform sampler2D u_baseColorTexture;", + "uniform sampler2D u_normalTexture;", + "uniform vec3 u_anisotropy;", + ]); + + ShaderBuilderTester.expectHasVertexDefines(shaderBuilder, []); + ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [ + "HAS_ANISOTROPY_TEXTURE", + "HAS_BASE_COLOR_TEXTURE", + "HAS_METALLIC_FACTOR", + "HAS_NORMAL_TEXTURE", + "TEXCOORD_ANISOTROPY v_texCoord_0", + "TEXCOORD_BASE_COLOR v_texCoord_0", + "TEXCOORD_NORMAL v_texCoord_0", + "USE_ANISOTROPY", + "USE_METALLIC_ROUGHNESS", + ]); + + const { + anisotropyStrength, + anisotropyRotation, + anisotropyTexture, + } = primitive.material.anisotropy; + const expectedAnisotropy = Cartesian3.fromElements( + Math.cos(anisotropyRotation), + Math.sin(anisotropyRotation), + anisotropyStrength + ); + const expectedUniforms = { + u_anisotropy: expectedAnisotropy, + u_anisotropyTexture: anisotropyTexture.texture, + }; + expectUniformMap(uniformMap, expectedUniforms); }); - it("enables PBR lighting for metallic roughness materials", function () { - return loadGltf(boomBox).then(function (gltfLoader) { - const components = gltfLoader.components; - const primitive = components.nodes[0].primitives[0]; - const renderResources = mockRenderResources(); - const lightingOptions = renderResources.lightingOptions; - - MaterialPipelineStage.process( - renderResources, - primitive, - mockFrameState - ); - expect(lightingOptions.lightingModel).toBe(LightingModel.PBR); - }); + it("adds uniforms and defines for KHR_materials_clearcoat", async function () { + const gltfLoader = await loadGltf(clearcoatTestData); + + const primitive = gltfLoader.components.nodes[1].primitives[0]; + const renderResources = mockRenderResources(); + MaterialPipelineStage.process(renderResources, primitive, mockFrameState); + const { shaderBuilder, uniformMap } = renderResources; + + ShaderBuilderTester.expectHasVertexUniforms(shaderBuilder, []); + ShaderBuilderTester.expectHasFragmentUniforms(shaderBuilder, [ + "uniform float u_metallicFactor;", + "uniform float u_clearcoatFactor;", + "uniform float u_clearcoatRoughnessFactor;", + "uniform sampler2D u_baseColorTexture;", + "uniform sampler2D u_clearcoatTexture;", + "uniform sampler2D u_clearcoatRoughnessTexture;", + "uniform sampler2D u_clearcoatNormalTexture;", + ]); + + ShaderBuilderTester.expectHasVertexDefines(shaderBuilder, []); + ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [ + "HAS_BASE_COLOR_TEXTURE", + "HAS_CLEARCOAT_FACTOR", + "HAS_CLEARCOAT_NORMAL_TEXTURE", + "HAS_CLEARCOAT_ROUGHNESS_FACTOR", + "HAS_CLEARCOAT_ROUGHNESS_TEXTURE", + "HAS_CLEARCOAT_TEXTURE", + "HAS_METALLIC_FACTOR", + "TEXCOORD_CLEARCOAT v_texCoord_0", + "TEXCOORD_CLEARCOAT_ROUGHNESS v_texCoord_0", + "TEXCOORD_CLEARCOAT_NORMAL v_texCoord_0", + "TEXCOORD_BASE_COLOR v_texCoord_0", + "USE_CLEARCOAT", + "USE_METALLIC_ROUGHNESS", + ]); + + const { + clearcoatFactor, + clearcoatRoughnessFactor, + clearcoatTexture, + clearcoatRoughnessTexture, + clearcoatNormalTexture, + } = primitive.material.clearcoat; + const expectedUniforms = { + u_clearcoatFactor: clearcoatFactor, + u_clearcoatRoughnessFactor: clearcoatRoughnessFactor, + u_clearcoatTexture: clearcoatTexture.texture, + u_clearcoatRoughnessTexture: clearcoatRoughnessTexture.texture, + u_clearcoatNormalTexture: clearcoatNormalTexture.texture, + }; + expectUniformMap(uniformMap, expectedUniforms); }); - it("enables PBR lighting for specular glossiness materials", function () { - return loadGltf(boomBoxSpecularGlossiness).then(function (gltfLoader) { - const components = gltfLoader.components; - const primitive = components.nodes[0].primitives[0]; - const renderResources = mockRenderResources(); - const lightingOptions = renderResources.lightingOptions; - - MaterialPipelineStage.process( - renderResources, - primitive, - mockFrameState - ); - expect(lightingOptions.lightingModel).toBe(LightingModel.PBR); - }); + it("doesn't add texture uniforms for classification models", async function () { + const gltfLoader = await loadGltf(boomBox); + const primitive = gltfLoader.components.nodes[0].primitives[0]; + const renderResources = mockRenderResources(ClassificationType.BOTH); + const { shaderBuilder, uniformMap } = renderResources; + + MaterialPipelineStage.process(renderResources, primitive, mockFrameState); + + ShaderBuilderTester.expectHasVertexUniforms(shaderBuilder, []); + ShaderBuilderTester.expectHasFragmentUniforms(shaderBuilder, [ + "uniform vec3 u_emissiveFactor;", + ]); + + ShaderBuilderTester.expectHasVertexDefines(shaderBuilder, []); + ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [ + "HAS_EMISSIVE_FACTOR", + "USE_METALLIC_ROUGHNESS", + ]); + const material = primitive.material; + const expectedUniforms = { + u_emissiveFactor: material.emissiveFactor, + }; + expectUniformMap(uniformMap, expectedUniforms); }); - it("enables unlit lighting when KHR_materials_unlit is present", function () { - return loadGltf(boxUnlit).then(function (gltfLoader) { - const components = gltfLoader.components; - const primitive = components.nodes[1].primitives[0]; - const renderResources = mockRenderResources(); - const lightingOptions = renderResources.lightingOptions; - - MaterialPipelineStage.process( - renderResources, - primitive, - mockFrameState - ); - expect(lightingOptions.lightingModel).toBe(LightingModel.UNLIT); - }); + it("doesn't add metallic roughness textures for classification models", async function () { + const gltfLoader = await loadGltf(boomBox); + const primitive = gltfLoader.components.nodes[0].primitives[0]; + + const metallicRoughness = primitive.material.metallicRoughness; + metallicRoughness.baseColorFactor = new Cartesian4(0.5, 0.5, 0.5, 0.5); + metallicRoughness.metallicFactor = 0.5; + metallicRoughness.roughnessFactor = 0.5; + + const renderResources = mockRenderResources(); + const { shaderBuilder, uniformMap } = renderResources; + + MaterialPipelineStage.process(renderResources, primitive, mockFrameState); + + ShaderBuilderTester.expectHasVertexUniforms(shaderBuilder, []); + ShaderBuilderTester.expectHasFragmentUniforms(shaderBuilder, [ + "uniform float u_metallicFactor;", + "uniform float u_roughnessFactor;", + "uniform sampler2D u_baseColorTexture;", + "uniform sampler2D u_emissiveTexture;", + "uniform sampler2D u_metallicRoughnessTexture;", + "uniform sampler2D u_normalTexture;", + "uniform sampler2D u_occlusionTexture;", + "uniform vec3 u_emissiveFactor;", + "uniform vec4 u_baseColorFactor;", + ]); + + ShaderBuilderTester.expectHasVertexDefines(shaderBuilder, []); + ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [ + "HAS_BASE_COLOR_FACTOR", + "HAS_BASE_COLOR_TEXTURE", + "HAS_EMISSIVE_FACTOR", + "HAS_EMISSIVE_TEXTURE", + "HAS_METALLIC_FACTOR", + "HAS_METALLIC_ROUGHNESS_TEXTURE", + "HAS_NORMAL_TEXTURE", + "HAS_OCCLUSION_TEXTURE", + "HAS_ROUGHNESS_FACTOR", + "TEXCOORD_BASE_COLOR v_texCoord_0", + "TEXCOORD_EMISSIVE v_texCoord_0", + "TEXCOORD_METALLIC_ROUGHNESS v_texCoord_0", + "TEXCOORD_NORMAL v_texCoord_0", + "TEXCOORD_OCCLUSION v_texCoord_0", + "USE_METALLIC_ROUGHNESS", + ]); + + const expectedUniforms = { + u_baseColorFactor: metallicRoughness.baseColorFactor, + u_metallicFactor: metallicRoughness.metallicFactor, + u_roughnessFactor: metallicRoughness.roughnessFactor, + }; + expectUniformMap(uniformMap, expectedUniforms); }); - it("enables unlit lighting for classification models", function () { - return loadGltf(boxUnlit).then(function (gltfLoader) { - const components = gltfLoader.components; - const primitive = components.nodes[1].primitives[0]; - const renderResources = mockRenderResources(ClassificationType.BOTH); - const lightingOptions = renderResources.lightingOptions; - - MaterialPipelineStage.process( - renderResources, - primitive, - mockFrameState - ); - expect(lightingOptions.lightingModel).toBe(LightingModel.UNLIT); - }); + it("enables PBR lighting for metallic roughness materials", async function () { + const gltfLoader = await loadGltf(boomBox); + const primitive = gltfLoader.components.nodes[0].primitives[0]; + const renderResources = mockRenderResources(); + const lightingOptions = renderResources.lightingOptions; + + MaterialPipelineStage.process(renderResources, primitive, mockFrameState); + expect(lightingOptions.lightingModel).toBe(LightingModel.PBR); }); - it("gracefully falls back to unlit shading for models without normals", function () { - return loadGltf(boxNoNormals).then(function (gltfLoader) { - const components = gltfLoader.components; - const primitive = components.nodes[1].primitives[0]; - const renderResources = mockRenderResources(); - const lightingOptions = renderResources.lightingOptions; - - MaterialPipelineStage.process( - renderResources, - primitive, - mockFrameState - ); - expect(lightingOptions.lightingModel).toBe(LightingModel.UNLIT); - }); + it("enables PBR lighting for specular glossiness materials", async function () { + const gltfLoader = await loadGltf(boomBox); + const primitive = gltfLoader.components.nodes[0].primitives[0]; + const renderResources = mockRenderResources(); + const lightingOptions = renderResources.lightingOptions; + + MaterialPipelineStage.process(renderResources, primitive, mockFrameState); + expect(lightingOptions.lightingModel).toBe(LightingModel.PBR); }); - it("handles opaque material", function () { - return loadGltf(boomBox).then(function (gltfLoader) { - const components = gltfLoader.components; - const primitive = components.nodes[0].primitives[0]; - const renderResources = mockRenderResources(); + it("enables unlit lighting when KHR_materials_unlit is present", async function () { + const gltfLoader = await loadGltf(boxUnlit); + const primitive = gltfLoader.components.nodes[1].primitives[0]; + const renderResources = mockRenderResources(); + const lightingOptions = renderResources.lightingOptions; - MaterialPipelineStage.process( - renderResources, - primitive, - mockFrameState - ); + MaterialPipelineStage.process(renderResources, primitive, mockFrameState); + expect(lightingOptions.lightingModel).toBe(LightingModel.UNLIT); + }); - expect(renderResources.alphaOptions.pass).not.toBeDefined(); - expect(renderResources.alphaOptions.alphaCutoff).not.toBeDefined(); - }); + it("enables unlit lighting for classification models", async function () { + const gltfLoader = await loadGltf(boxUnlit); + const primitive = gltfLoader.components.nodes[1].primitives[0]; + const renderResources = mockRenderResources(ClassificationType.BOTH); + const lightingOptions = renderResources.lightingOptions; + + MaterialPipelineStage.process(renderResources, primitive, mockFrameState); + expect(lightingOptions.lightingModel).toBe(LightingModel.UNLIT); }); - it("handles alpha mask material", function () { - return loadGltf(boomBox).then(function (gltfLoader) { - const cutoff = 0.6; - const components = gltfLoader.components; - const primitive = components.nodes[0].primitives[0]; - primitive.material.alphaMode = AlphaMode.MASK; - primitive.material.alphaCutoff = cutoff; - - const renderResources = mockRenderResources(); - MaterialPipelineStage.process( - renderResources, - primitive, - mockFrameState - ); - - expect(renderResources.alphaOptions.pass).not.toBeDefined(); - expect(renderResources.alphaOptions.alphaCutoff).toBe(cutoff); - }); + it("gracefully falls back to unlit shading for models without normals", async function () { + const gltfLoader = await loadGltf(boxNoNormals); + const primitive = gltfLoader.components.nodes[1].primitives[0]; + const renderResources = mockRenderResources(); + const lightingOptions = renderResources.lightingOptions; + + MaterialPipelineStage.process(renderResources, primitive, mockFrameState); + expect(lightingOptions.lightingModel).toBe(LightingModel.UNLIT); }); - it("handles translucent material", function () { - return loadGltf(boomBox).then(function (gltfLoader) { - const components = gltfLoader.components; - const primitive = components.nodes[0].primitives[0]; - primitive.material.alphaMode = AlphaMode.BLEND; + it("handles opaque material", async function () { + const gltfLoader = await loadGltf(boomBox); + const primitive = gltfLoader.components.nodes[0].primitives[0]; + const renderResources = mockRenderResources(); - const renderResources = mockRenderResources(); - renderResources.pass = Pass.OPAQUE; + MaterialPipelineStage.process(renderResources, primitive, mockFrameState); - MaterialPipelineStage.process( - renderResources, - primitive, - mockFrameState - ); + expect(renderResources.alphaOptions.pass).not.toBeDefined(); + expect(renderResources.alphaOptions.alphaCutoff).not.toBeDefined(); + }); - expect(renderResources.alphaOptions.pass).toBe(Pass.TRANSLUCENT); - expect(renderResources.alphaOptions.alphaCutoff).not.toBeDefined(); - }); + it("handles alpha mask material", async function () { + const gltfLoader = await loadGltf(boomBox); + const cutoff = 0.6; + const primitive = gltfLoader.components.nodes[0].primitives[0]; + primitive.material.alphaMode = AlphaMode.MASK; + primitive.material.alphaCutoff = cutoff; + + const renderResources = mockRenderResources(); + MaterialPipelineStage.process(renderResources, primitive, mockFrameState); + + expect(renderResources.alphaOptions.pass).not.toBeDefined(); + expect(renderResources.alphaOptions.alphaCutoff).toBe(cutoff); }); - it("disables back-face culling if model.backFaceCulling is false", function () { - return loadGltf(boxUnlit).then(function (gltfLoader) { - const components = gltfLoader.components; - const primitive = components.nodes[1].primitives[0]; - - const renderResources = mockRenderResources(); - const renderStateOptions = renderResources.renderStateOptions; - renderResources.model.backFaceCulling = false; - renderResources.cull = true; - - MaterialPipelineStage.process( - renderResources, - primitive, - mockFrameState - ); - expect(renderStateOptions.cull.enabled).toBe(false); - }); + it("handles translucent material", async function () { + const gltfLoader = await loadGltf(boomBox); + const primitive = gltfLoader.components.nodes[0].primitives[0]; + primitive.material.alphaMode = AlphaMode.BLEND; + + const renderResources = mockRenderResources(); + renderResources.pass = Pass.OPAQUE; + + MaterialPipelineStage.process(renderResources, primitive, mockFrameState); + + expect(renderResources.alphaOptions.pass).toBe(Pass.TRANSLUCENT); + expect(renderResources.alphaOptions.alphaCutoff).not.toBeDefined(); }); - it("enables back-face culling if material is not double-sided", function () { - return loadGltf(boxUnlit).then(function (gltfLoader) { - const components = gltfLoader.components; - const primitive = components.nodes[1].primitives[0]; - const renderResources = mockRenderResources(); - const renderStateOptions = renderResources.renderStateOptions; - renderResources.model.backFaceCulling = true; - renderResources.cull = true; - - MaterialPipelineStage.process( - renderResources, - primitive, - mockFrameState - ); - expect(renderStateOptions.cull.enabled).toBe(true); - }); + it("disables back-face culling if model.backFaceCulling is false", async function () { + const gltfLoader = await loadGltf(boxUnlit); + const primitive = gltfLoader.components.nodes[1].primitives[0]; + + const renderResources = mockRenderResources(); + const renderStateOptions = renderResources.renderStateOptions; + renderResources.model.backFaceCulling = false; + renderResources.cull = true; + + MaterialPipelineStage.process(renderResources, primitive, mockFrameState); + expect(renderStateOptions.cull.enabled).toBe(false); }); - it("disables back-face culling if material is double-sided", function () { - return loadGltf(boxUnlit).then(function (gltfLoader) { - const components = gltfLoader.components; - const primitive = components.nodes[1].primitives[0]; - const renderResources = mockRenderResources(); - renderResources.model.backFaceCulling = true; - const renderStateOptions = renderResources.renderStateOptions; - - primitive.material.doubleSided = true; - MaterialPipelineStage.process( - renderResources, - primitive, - mockFrameState - ); - - expect(renderStateOptions.cull.enabled).toBe(false); - }); + it("enables back-face culling if material is not double-sided", async function () { + const gltfLoader = await loadGltf(boxUnlit); + const primitive = gltfLoader.components.nodes[1].primitives[0]; + const renderResources = mockRenderResources(); + const renderStateOptions = renderResources.renderStateOptions; + renderResources.model.backFaceCulling = true; + renderResources.cull = true; + + MaterialPipelineStage.process(renderResources, primitive, mockFrameState); + expect(renderStateOptions.cull.enabled).toBe(true); }); - it("adds material stage functions to the fragment shader", function () { - return loadGltf(boxUnlit).then(function (gltfLoader) { - const components = gltfLoader.components; - const primitive = components.nodes[1].primitives[0]; - primitive.material.doubleSided = true; - - const renderResources = mockRenderResources(); - const shaderBuilder = renderResources.shaderBuilder; - - MaterialPipelineStage.process( - renderResources, - primitive, - mockFrameState - ); - - ShaderBuilderTester.expectVertexLinesEqual(shaderBuilder, []); - ShaderBuilderTester.expectFragmentLinesEqual(shaderBuilder, [ - _shadersMaterialStageFS, - ]); - }); + it("disables back-face culling if material is double-sided", async function () { + const gltfLoader = await loadGltf(boxUnlit); + const primitive = gltfLoader.components.nodes[1].primitives[0]; + const renderResources = mockRenderResources(); + renderResources.model.backFaceCulling = true; + const renderStateOptions = renderResources.renderStateOptions; + + primitive.material.doubleSided = true; + MaterialPipelineStage.process(renderResources, primitive, mockFrameState); + + expect(renderStateOptions.cull.enabled).toBe(false); }); - it("adds define to shader if material is double-sided", function () { - return loadGltf(twoSidedPlane).then(function (gltfLoader) { - const components = gltfLoader.components; - const primitive = components.nodes[0].primitives[0]; - const renderResources = mockRenderResources(); - const shaderBuilder = renderResources.shaderBuilder; - - MaterialPipelineStage.process( - renderResources, - primitive, - mockFrameState - ); - - ShaderBuilderTester.expectHasVertexDefines(shaderBuilder, [ - "HAS_DOUBLE_SIDED_MATERIAL", - ]); - ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [ - "HAS_BASE_COLOR_TEXTURE", - "HAS_DOUBLE_SIDED_MATERIAL", - "HAS_METALLIC_ROUGHNESS_TEXTURE", - "HAS_NORMAL_TEXTURE", - "TEXCOORD_BASE_COLOR v_texCoord_0", - "TEXCOORD_METALLIC_ROUGHNESS v_texCoord_0", - "TEXCOORD_NORMAL v_texCoord_0", - "USE_METALLIC_ROUGHNESS", - ]); - }); + it("adds material stage functions to the fragment shader", async function () { + const gltfLoader = await loadGltf(boxUnlit); + const primitive = gltfLoader.components.nodes[1].primitives[0]; + primitive.material.doubleSided = true; + + const renderResources = mockRenderResources(); + const shaderBuilder = renderResources.shaderBuilder; + + MaterialPipelineStage.process(renderResources, primitive, mockFrameState); + + ShaderBuilderTester.expectVertexLinesEqual(shaderBuilder, []); + ShaderBuilderTester.expectFragmentLinesEqual(shaderBuilder, [ + _shadersMaterialStageFS, + ]); + }); + + it("adds define to shader if material is double-sided", async function () { + const gltfLoader = await loadGltf(twoSidedPlane); + const primitive = gltfLoader.components.nodes[0].primitives[0]; + const renderResources = mockRenderResources(); + const shaderBuilder = renderResources.shaderBuilder; + + MaterialPipelineStage.process(renderResources, primitive, mockFrameState); + + ShaderBuilderTester.expectHasVertexDefines(shaderBuilder, [ + "HAS_DOUBLE_SIDED_MATERIAL", + ]); + ShaderBuilderTester.expectHasFragmentDefines(shaderBuilder, [ + "HAS_BASE_COLOR_TEXTURE", + "HAS_DOUBLE_SIDED_MATERIAL", + "HAS_METALLIC_ROUGHNESS_TEXTURE", + "HAS_NORMAL_TEXTURE", + "TEXCOORD_BASE_COLOR v_texCoord_0", + "TEXCOORD_METALLIC_ROUGHNESS v_texCoord_0", + "TEXCOORD_NORMAL v_texCoord_0", + "USE_METALLIC_ROUGHNESS", + ]); }); it("_processTextureTransform updates the shader and uniform map", function () { diff --git a/packages/engine/Specs/Scene/Model/ModelSpec.js b/packages/engine/Specs/Scene/Model/ModelSpec.js index 767b78df552..7fc682127e0 100644 --- a/packages/engine/Specs/Scene/Model/ModelSpec.js +++ b/packages/engine/Specs/Scene/Model/ModelSpec.js @@ -106,6 +106,12 @@ describe( "./Data/Models/glTF-2.0/BoxEmissive/glTF/BoxEmissive.gltf"; const boomBoxUrl = "./Data/Models/glTF-2.0/BoomBox/glTF-pbrSpecularGlossiness/BoomBox.gltf"; + const boxSpecularUrl = + "./Data/Models/glTF-2.0/BoxSpecular/glTF/BoxSpecular.gltf"; + const boxAnisotropyUrl = + "./Data/Models/glTF-2.0/BoxAnisotropy/glTF/BoxAnisotropy.gltf"; + const boxClearcoatUrl = + "./Data/Models/glTF-2.0/BoxClearcoat/glTF/BoxClearcoat.gltf"; const riggedFigureUrl = "./Data/Models/glTF-2.0/RiggedFigureTest/glTF/RiggedFigureTest.gltf"; const dracoCesiumManUrl = @@ -267,75 +273,67 @@ describe( ).toBeRejectedWithDeveloperError(); }); - it("initializes and renders from Uint8Array", function () { + it("initializes and renders from Uint8Array", async function () { const resource = Resource.createIfNeeded(boxTexturedGlbUrl); - const loadPromise = resource.fetchArrayBuffer(); - return loadPromise.then(function (buffer) { - return loadAndZoomToModelAsync( - { gltf: new Uint8Array(buffer) }, - scene - ).then(function (model) { - expect(model.ready).toEqual(true); - expect(model._sceneGraph).toBeDefined(); - expect(model._resourcesLoaded).toEqual(true); - verifyRender(model, true); - }); - }); + const buffer = await resource.fetchArrayBuffer(); + const model = await loadAndZoomToModelAsync( + { gltf: new Uint8Array(buffer) }, + scene + ); + expect(model.ready).toEqual(true); + expect(model._sceneGraph).toBeDefined(); + expect(model._resourcesLoaded).toEqual(true); + verifyRender(model, true); }); - it("initializes and renders from JSON object", function () { + it("initializes and renders from JSON object", async function () { const resource = Resource.createIfNeeded(boxTexturedGltfUrl); - return resource.fetchJson().then(function (gltf) { - return loadAndZoomToModelAsync( - { - gltf: gltf, - basePath: boxTexturedGltfUrl, - }, - scene - ).then(function (model) { - expect(model.ready).toEqual(true); - expect(model._sceneGraph).toBeDefined(); - expect(model._resourcesLoaded).toEqual(true); - verifyRender(model, true); - }); - }); + const gltf = await resource.fetchJson(); + const model = await loadAndZoomToModelAsync( + { + gltf: gltf, + basePath: boxTexturedGltfUrl, + }, + scene + ); + expect(model.ready).toEqual(true); + expect(model._sceneGraph).toBeDefined(); + expect(model._resourcesLoaded).toEqual(true); + verifyRender(model, true); }); - it("initializes and renders from JSON object with external buffers", function () { + it("initializes and renders from JSON object with external buffers", async function () { const resource = Resource.createIfNeeded(microcosm); - return resource.fetchJson().then(function (gltf) { - return loadAndZoomToModelAsync( - { - gltf: gltf, - basePath: microcosm, - }, - scene - ).then(function (model) { - expect(model.ready).toEqual(true); - expect(model._sceneGraph).toBeDefined(); - expect(model._resourcesLoaded).toEqual(true); - verifyRender(model, true); - }); - }); + const gltf = await resource.fetchJson(); + const model = await loadAndZoomToModelAsync( + { + gltf: gltf, + basePath: microcosm, + }, + scene + ); + expect(model.ready).toEqual(true); + expect(model._sceneGraph).toBeDefined(); + expect(model._resourcesLoaded).toEqual(true); + verifyRender(model, true); }); - it("initializes and renders with url", function () { - return loadAndZoomToModelAsync( + it("initializes and renders with url", async function () { + const model = await loadAndZoomToModelAsync( { url: boxTexturedGltfUrl, }, scene - ).then(function (model) { - expect(model.ready).toEqual(true); - expect(model._sceneGraph).toBeDefined(); - expect(model._resourcesLoaded).toEqual(true); - verifyRender(model, true); - }); + ); + expect(model.ready).toEqual(true); + expect(model._sceneGraph).toBeDefined(); + expect(model._resourcesLoaded).toEqual(true); + verifyRender(model, true); }); - it("calls gltfCallback", function () { + it("calls gltfCallback", async function () { let wasCalled = false; - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { url: boxTexturedGltfUrl, gltfCallback: (gltf) => { @@ -348,13 +346,12 @@ describe( }, }, scene - ).then(function (model) { - expect(model.ready).toEqual(true); - expect(model._sceneGraph).toBeDefined(); - expect(model._resourcesLoaded).toEqual(true); - expect(wasCalled).toBeTrue(); - verifyRender(model, true); - }); + ); + expect(model.ready).toEqual(true); + expect(model._sceneGraph).toBeDefined(); + expect(model._resourcesLoaded).toEqual(true); + expect(wasCalled).toBeTrue(); + verifyRender(model, true); }); it("raises errorEvent when a texture fails to load and incrementallyLoadTextures is true", async function () { @@ -438,294 +435,320 @@ describe( }); }); - it("loads with asynchronous set to true", function () { + it("loads with asynchronous set to true", async function () { const jobSchedulerExecute = spyOn( JobScheduler.prototype, "execute" ).and.callThrough(); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, asynchronous: true, }, scene - ).then(function (model) { - const loader = model.loader; - expect(loader._asynchronous).toBe(true); + ); + const loader = model.loader; + expect(loader._asynchronous).toBe(true); - expect(jobSchedulerExecute).toHaveBeenCalled(); - }); + expect(jobSchedulerExecute).toHaveBeenCalled(); }); - it("loads with asynchronous set to false", function () { + it("loads with asynchronous set to false", async function () { const jobSchedulerExecute = spyOn( JobScheduler.prototype, "execute" ).and.callThrough(); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, asynchronous: false, }, scene - ).then(function (model) { - const loader = model.loader; - expect(loader._asynchronous).toBe(false); + ); + const loader = model.loader; + expect(loader._asynchronous).toBe(false); - expect(jobSchedulerExecute).not.toHaveBeenCalled(); - }); + expect(jobSchedulerExecute).not.toHaveBeenCalled(); }); - it("initializes feature table", function () { - return loadAndZoomToModelAsync({ gltf: buildingsMetadata }, scene).then( - function (model) { - expect(model.ready).toEqual(true); - expect(model.featureTables).toBeDefined(); - - const featureTable = model.featureTables[0]; - expect(featureTable).toBeDefined(); - - const featuresLength = featureTable.featuresLength; - expect(featuresLength).toEqual(10); - expect(featureTable.batchTexture).toBeDefined(); - expect(featureTable.batchTexture._featuresLength).toEqual(10); - - for (let i = 0; i < featuresLength; i++) { - const modelFeature = featureTable.getFeature(i); - expect(modelFeature instanceof ModelFeature).toEqual(true); - expect(modelFeature._featureId).toEqual(i); - expect(modelFeature.primitive).toEqual(model); - expect(modelFeature.featureTable).toEqual(featureTable); - } - - expect(model._resourcesLoaded).toEqual(true); - } + it("initializes feature table", async function () { + const model = await loadAndZoomToModelAsync( + { gltf: buildingsMetadata }, + scene ); + expect(model.ready).toEqual(true); + expect(model.featureTables).toBeDefined(); + + const featureTable = model.featureTables[0]; + expect(featureTable).toBeDefined(); + + const featuresLength = featureTable.featuresLength; + expect(featuresLength).toEqual(10); + expect(featureTable.batchTexture).toBeDefined(); + expect(featureTable.batchTexture._featuresLength).toEqual(10); + + for (let i = 0; i < featuresLength; i++) { + const modelFeature = featureTable.getFeature(i); + expect(modelFeature instanceof ModelFeature).toEqual(true); + expect(modelFeature._featureId).toEqual(i); + expect(modelFeature.primitive).toEqual(model); + expect(modelFeature.featureTable).toEqual(featureTable); + } + + expect(model._resourcesLoaded).toEqual(true); }); - it("sets default properties", function () { - return loadAndZoomToModelAsync( + it("sets default properties", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, }, scene - ).then(function (model) { - expect(model.show).toEqual(true); - expect(model.modelMatrix).toEqual(Matrix4.IDENTITY); - expect(model.scale).toEqual(1.0); - expect(model.minimumPixelSize).toEqual(0.0); - expect(model.maximumScale).toBeUndefined(); - - expect(model.id).toBeUndefined(); - expect(model.allowPicking).toEqual(true); - - expect(model.activeAnimations).toBeDefined(); - expect(model.clampAnimations).toEqual(true); - - expect(model.shadows).toEqual(ShadowMode.ENABLED); - expect(model.debugShowBoundingVolume).toEqual(false); - expect(model._enableDebugWireframe).toEqual(false); - expect(model.debugWireframe).toEqual(false); - - expect(model.cull).toEqual(true); - expect(model.backFaceCulling).toEqual(true); - expect(model.opaquePass).toEqual(Pass.OPAQUE); - expect(model.customShader).toBeUndefined(); - - expect(model.heightReference).toEqual(HeightReference.NONE); - expect(model.scene).toBeUndefined(); - expect(model.distanceDisplayCondition).toBeUndefined(); - - expect(model.color).toBeUndefined(); - expect(model.colorBlendMode).toEqual(ColorBlendMode.HIGHLIGHT); - expect(model.colorBlendAmount).toEqual(0.5); - expect(model.silhouetteColor).toEqual(Color.RED); - expect(model.silhouetteSize).toEqual(0.0); - - expect(model._enableShowOutline).toEqual(true); - expect(model.showOutline).toEqual(true); - expect(model.outlineColor).toEqual(Color.BLACK); - - expect(model.clippingPlanes).toBeUndefined(); - expect(model.lightColor).toBeUndefined(); - expect(model.imageBasedLighting).toBeDefined(); - - expect(model.credit).toBeUndefined(); - expect(model.showCreditsOnScreen).toEqual(false); - expect(model.splitDirection).toEqual(SplitDirection.NONE); - expect(model._projectTo2D).toEqual(false); - }); + ); + expect(model.show).toEqual(true); + expect(model.modelMatrix).toEqual(Matrix4.IDENTITY); + expect(model.scale).toEqual(1.0); + expect(model.minimumPixelSize).toEqual(0.0); + expect(model.maximumScale).toBeUndefined(); + + expect(model.id).toBeUndefined(); + expect(model.allowPicking).toEqual(true); + + expect(model.activeAnimations).toBeDefined(); + expect(model.clampAnimations).toEqual(true); + + expect(model.shadows).toEqual(ShadowMode.ENABLED); + expect(model.debugShowBoundingVolume).toEqual(false); + expect(model._enableDebugWireframe).toEqual(false); + expect(model.debugWireframe).toEqual(false); + + expect(model.cull).toEqual(true); + expect(model.backFaceCulling).toEqual(true); + expect(model.opaquePass).toEqual(Pass.OPAQUE); + expect(model.customShader).toBeUndefined(); + + expect(model.heightReference).toEqual(HeightReference.NONE); + expect(model.scene).toBeUndefined(); + expect(model.distanceDisplayCondition).toBeUndefined(); + + expect(model.color).toBeUndefined(); + expect(model.colorBlendMode).toEqual(ColorBlendMode.HIGHLIGHT); + expect(model.colorBlendAmount).toEqual(0.5); + expect(model.silhouetteColor).toEqual(Color.RED); + expect(model.silhouetteSize).toEqual(0.0); + + expect(model._enableShowOutline).toEqual(true); + expect(model.showOutline).toEqual(true); + expect(model.outlineColor).toEqual(Color.BLACK); + + expect(model.clippingPlanes).toBeUndefined(); + expect(model.lightColor).toBeUndefined(); + expect(model.imageBasedLighting).toBeDefined(); + + expect(model.credit).toBeUndefined(); + expect(model.showCreditsOnScreen).toEqual(false); + expect(model.splitDirection).toEqual(SplitDirection.NONE); + expect(model._projectTo2D).toEqual(false); }); - it("renders model without indices", function () { + it("renders model without indices", async function () { const resource = Resource.createIfNeeded(triangleWithoutIndicesUrl); - return resource.fetchJson().then(function (gltf) { - return loadAndZoomToModelAsync( - { - gltf: gltf, - basePath: triangleWithoutIndicesUrl, - modelMatrix: Transforms.eastNorthUpToFixedFrame( - Cartesian3.fromDegrees(0.0, 0.0, 100.0) - ), - }, - scene - ).then(function (model) { - // Orient the camera so it doesn't back-face cull the triangle. - const center = model.boundingSphere.center; - const range = 4.0 * model.boundingSphere.radius; - scene.camera.lookAt( - center, - new HeadingPitchRange(-CesiumMath.PI_OVER_TWO, 0, range) - ); + const gltf = await resource.fetchJson(); + const model = await loadAndZoomToModelAsync( + { + gltf: gltf, + basePath: triangleWithoutIndicesUrl, + modelMatrix: Transforms.eastNorthUpToFixedFrame( + Cartesian3.fromDegrees(0.0, 0.0, 100.0) + ), + }, + scene + ); + // Orient the camera so it doesn't back-face cull the triangle. + const center = model.boundingSphere.center; + const range = 4.0 * model.boundingSphere.radius; + scene.camera.lookAt( + center, + new HeadingPitchRange(-CesiumMath.PI_OVER_TWO, 0, range) + ); - // The triangle's diagonal edge is slightly out of frame. - scene.camera.moveDown(0.1); + // The triangle's diagonal edge is slightly out of frame. + scene.camera.moveDown(0.1); - verifyRender(model, true, { - zoomToModel: false, - }); - }); + verifyRender(model, true, { + zoomToModel: false, }); }); - it("renders model with vertex colors", function () { + it("renders model with vertex colors", async function () { const resource = Resource.createIfNeeded(vertexColorTestUrl); - return resource.fetchJson().then(function (gltf) { - return loadAndZoomToModelAsync( - { - gltf: gltf, - basePath: vertexColorTestUrl, - }, - scene - ).then(function (model) { - const renderOptions = { - scene: scene, - time: defaultDate, - }; - // Move the camera to the blue plane. - scene.camera.moveLeft(0.5); - - expect(renderOptions).toRenderAndCall(function (rgba) { - expect(rgba[0]).toEqual(0); - expect(rgba[1]).toEqual(0); - expect(rgba[2]).toEqual(255); - expect(rgba[3]).toEqual(255); - }); - - // Move the camera to the red plane. - scene.camera.moveRight(1.0); - expect(renderOptions).toRenderAndCall(function (rgba) { - expect(rgba[0]).toEqual(255); - expect(rgba[1]).toEqual(0); - expect(rgba[2]).toEqual(0); - expect(rgba[3]).toEqual(255); - }); - }); + const gltf = await resource.fetchJson(); + await loadAndZoomToModelAsync( + { + gltf: gltf, + basePath: vertexColorTestUrl, + }, + scene + ); + const renderOptions = { + scene: scene, + time: defaultDate, + }; + // Move the camera to the blue plane. + scene.camera.moveLeft(0.5); + + expect(renderOptions).toRenderAndCall(function (rgba) { + expect(rgba[0]).toEqual(0); + expect(rgba[1]).toEqual(0); + expect(rgba[2]).toEqual(255); + expect(rgba[3]).toEqual(255); + }); + + // Move the camera to the red plane. + scene.camera.moveRight(1.0); + expect(renderOptions).toRenderAndCall(function (rgba) { + expect(rgba[0]).toEqual(255); + expect(rgba[1]).toEqual(0); + expect(rgba[2]).toEqual(0); + expect(rgba[3]).toEqual(255); }); }); - it("renders model with double-sided material", function () { + it("renders model with double-sided material", async function () { const resource = Resource.createIfNeeded(twoSidedPlaneUrl); - return resource.fetchJson().then(function (gltf) { - return loadAndZoomToModelAsync( - { - gltf: gltf, - basePath: twoSidedPlaneUrl, - modelMatrix: Transforms.eastNorthUpToFixedFrame( - Cartesian3.fromDegrees(0.0, 0.0, 100.0) - ), - }, - scene - ).then(function (model) { - const renderOptions = { - scene: scene, - time: defaultDate, - }; - - const center = model.boundingSphere.center; - const range = 4.0 * model.boundingSphere.radius; - scene.camera.lookAt( - center, - new HeadingPitchRange(0, -CesiumMath.PI_OVER_TWO, range) - ); + const gltf = await resource.fetchJson(); + const model = await loadAndZoomToModelAsync( + { + gltf: gltf, + basePath: twoSidedPlaneUrl, + modelMatrix: Transforms.eastNorthUpToFixedFrame( + Cartesian3.fromDegrees(0.0, 0.0, 100.0) + ), + }, + scene + ); + const renderOptions = { + scene: scene, + time: defaultDate, + }; - // The top of the double-sided plane should render brightly, since - // its normal is pointing towards the light - let result; - expect(renderOptions).toRenderAndCall(function (rgba) { - expect(rgba).not.toEqual([0, 0, 0, 255]); - result = rgba; - }); - - scene.camera.lookAt( - center, - new HeadingPitchRange(0, CesiumMath.PI_OVER_TWO, range) - ); + const center = model.boundingSphere.center; + const range = 4.0 * model.boundingSphere.radius; + scene.camera.lookAt( + center, + new HeadingPitchRange(0, -CesiumMath.PI_OVER_TWO, range) + ); + + // The top of the double-sided plane should render brightly, since + // its normal is pointing towards the light + let result; + expect(renderOptions).toRenderAndCall(function (rgba) { + expect(rgba).not.toEqual([0, 0, 0, 255]); + result = rgba; + }); - // The bottom of the plane should render darker than the top, since - // its normal is pointing away from the light. - expect(renderOptions).toRenderAndCall(function (rgba) { - expect(rgba).not.toEqual([0, 0, 0, 255]); + scene.camera.lookAt( + center, + new HeadingPitchRange(0, CesiumMath.PI_OVER_TWO, range) + ); - expect(rgba[0]).toBeLessThan(result[0]); - expect(rgba[1]).toBeLessThan(result[1]); - expect(rgba[2]).toBeLessThan(result[2]); - expect(rgba[3]).toEqual(result[3]); - }); - }); + // The bottom of the plane should render darker than the top, since + // its normal is pointing away from the light. + expect(renderOptions).toRenderAndCall(function (rgba) { + expect(rgba).not.toEqual([0, 0, 0, 255]); + + expect(rgba[0]).toBeLessThan(result[0]); + expect(rgba[1]).toBeLessThan(result[1]); + expect(rgba[2]).toBeLessThan(result[2]); + expect(rgba[3]).toEqual(result[3]); }); }); // This test does not yet work since models without normals are // rendered as unlit. See https://github.com/CesiumGS/cesium/issues/6506 - xit("renders model with emissive texture", function () { + xit("renders model with emissive texture", async function () { const resource = Resource.createIfNeeded(emissiveTextureUrl); - return resource.fetchJson().then(function (gltf) { - return loadAndZoomToModelAsync( - { - gltf: gltf, - basePath: emissiveTextureUrl, - }, - scene - ).then(function (model) { - const renderOptions = { - scene: scene, - time: defaultDate, - }; - - expect(renderOptions).toRenderAndCall(function (rgba) { - // Emissive texture is red - expect(rgba[0]).toBeGreaterThan(20); - expect(rgba[1]).toBeLessThan(20); - expect(rgba[2]).toBeLessThan(20); - expect(rgba[3]).toEqual(255); - }); - }); + const gltf = await resource.fetchJson(); + await loadAndZoomToModelAsync( + { + gltf: gltf, + basePath: emissiveTextureUrl, + }, + scene + ); + const renderOptions = { + scene: scene, + time: defaultDate, + }; + + expect(renderOptions).toRenderAndCall(function (rgba) { + // Emissive texture is red + expect(rgba[0]).toBeGreaterThan(20); + expect(rgba[1]).toBeLessThan(20); + expect(rgba[2]).toBeLessThan(20); + expect(rgba[3]).toEqual(255); }); }); - it("renders model with the KHR_materials_pbrSpecularGlossiness extension", function () { + it("renders model with the KHR_materials_pbrSpecularGlossiness extension", async function () { // This model gets clipped if log depth is disabled, so zoom out // the camera just a little const offset = new HeadingPitchRange(0, -CesiumMath.PI_OVER_FOUR, 2); const resource = Resource.createIfNeeded(boomBoxUrl); - return resource.fetchJson().then(function (gltf) { - return loadAndZoomToModelAsync( - { - gltf: gltf, - basePath: boomBoxUrl, - // This model is tiny, so scale it up so it's visible. - scale: 10.0, - offset: offset, - }, - scene - ).then(function (model) { - verifyRender(model, true); - }); - }); + const gltf = await resource.fetchJson(); + const model = await loadAndZoomToModelAsync( + { + gltf: gltf, + basePath: boomBoxUrl, + // This model is tiny, so scale it up so it's visible. + scale: 10.0, + offset: offset, + }, + scene + ); + verifyRender(model, true); + }); + + it("renders model with the KHR_materials_specular extension", async function () { + const resource = Resource.createIfNeeded(boxSpecularUrl); + const gltf = await resource.fetchJson(); + const model = await loadAndZoomToModelAsync( + { + gltf: gltf, + basePath: boxSpecularUrl, + }, + scene + ); + verifyRender(model, true); + }); + + it("renders model with the KHR_materials_anisotropy extension", async function () { + const resource = Resource.createIfNeeded(boxAnisotropyUrl); + const gltf = await resource.fetchJson(); + const model = await loadAndZoomToModelAsync( + { + gltf: gltf, + basePath: boxAnisotropyUrl, + }, + scene + ); + verifyRender(model, true); + }); + + it("renders model with the KHR_materials_clearcoat extension", async function () { + const resource = Resource.createIfNeeded(boxClearcoatUrl); + const gltf = await resource.fetchJson(); + const model = await loadAndZoomToModelAsync( + { + gltf: gltf, + basePath: boxClearcoatUrl, + }, + scene + ); + verifyRender(model, true); }); it("transforms property textures with KHR_texture_transform", async function () { @@ -863,44 +886,42 @@ describe( }); }); - it("renders model with morph targets", function () { + it("renders model with morph targets", async function () { // This model gets clipped if log depth is disabled, so zoom out // the camera just a little const offset = new HeadingPitchRange(0, -CesiumMath.PI_OVER_FOUR, 2); const resource = Resource.createIfNeeded(morphPrimitivesTestUrl); - return resource.fetchJson().then(function (gltf) { - return loadAndZoomToModelAsync( - { - gltf: gltf, - basePath: morphPrimitivesTestUrl, - offset: offset, - }, - scene - ).then(function (model) { - // The background color must be changed because the model's texture - // contains black, which can confuse the test. - const renderOptions = { - backgroundColor: Color.BLUE, - zoomToModel: false, - }; + const gltf = await resource.fetchJson(); + const model = await loadAndZoomToModelAsync( + { + gltf: gltf, + basePath: morphPrimitivesTestUrl, + offset: offset, + }, + scene + ); + // The background color must be changed because the model's texture + // contains black, which can confuse the test. + const renderOptions = { + backgroundColor: Color.BLUE, + zoomToModel: false, + }; - // Move the camera down slightly so the morphed part is in view. - scene.camera.moveDown(0.25); + // Move the camera down slightly so the morphed part is in view. + scene.camera.moveDown(0.25); - // The model is a plane made three-dimensional by morph targets. - // If morph targets aren't supported, the model won't appear in the camera. - verifyRender(model, true, renderOptions); - }); - }); + // The model is a plane made three-dimensional by morph targets. + // If morph targets aren't supported, the model won't appear in the camera. + verifyRender(model, true, renderOptions); }); - it("renders Draco-compressed model", function () { - return loadAndZoomToModelAsync({ gltf: dracoCesiumManUrl }, scene).then( - function (model) { - verifyRender(model, true); - } + it("renders Draco-compressed model", async function () { + const model = await loadAndZoomToModelAsync( + { gltf: dracoCesiumManUrl }, + scene ); + verifyRender(model, true); }); it("fails to load with Draco decoding error", async function () { @@ -940,86 +961,83 @@ describe( ); }); - it("renders model without animations added", function () { - return loadAndZoomToModelAsync( + it("renders model without animations added", async function () { + const model = await loadAndZoomToModelAsync( { gltf: animatedTriangleUrl, offset: animatedTriangleOffset, }, scene - ).then(function (model) { - const animationCollection = model.activeAnimations; - expect(animationCollection).toBeDefined(); - expect(animationCollection.length).toBe(0); + ); + const animationCollection = model.activeAnimations; + expect(animationCollection).toBeDefined(); + expect(animationCollection.length).toBe(0); - // Move camera so that the triangle is in view. - scene.camera.moveDown(0.5); - verifyRender(model, true, { - zoomToModel: false, - }); + // Move camera so that the triangle is in view. + scene.camera.moveDown(0.5); + verifyRender(model, true, { + zoomToModel: false, }); }); - it("renders model with animations added", function () { - return loadAndZoomToModelAsync( + it("renders model with animations added", async function () { + const model = await loadAndZoomToModelAsync( { gltf: animatedTriangleUrl, offset: animatedTriangleOffset, }, scene - ).then(function (model) { - // Move camera so that the triangle is in view. - scene.camera.moveDown(0.5); - - // The model rotates such that it leaves the view of the camera - // halfway into its animation. - const startTime = defaultDate; - const animationCollection = model.activeAnimations; - animationCollection.add({ - index: 0, - startTime: startTime, - }); - expect(animationCollection.length).toBe(1); - verifyRender(model, true, { - zoomToModel: false, - time: startTime, - }); - - const time = JulianDate.addSeconds(startTime, 0.5, new JulianDate()); - verifyRender(model, false, { - zoomToModel: false, - time: time, - }); + ); + // Move camera so that the triangle is in view. + scene.camera.moveDown(0.5); + + // The model rotates such that it leaves the view of the camera + // halfway into its animation. + const startTime = defaultDate; + const animationCollection = model.activeAnimations; + animationCollection.add({ + index: 0, + startTime: startTime, + }); + expect(animationCollection.length).toBe(1); + verifyRender(model, true, { + zoomToModel: false, + time: startTime, + }); + + const time = JulianDate.addSeconds(startTime, 0.5, new JulianDate()); + verifyRender(model, false, { + zoomToModel: false, + time: time, }); }); - it("renders model with CESIUM_RTC extension", function () { - return loadAndZoomToModelAsync( + it("renders model with CESIUM_RTC extension", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxCesiumRtcUrl, }, scene - ).then(function (model) { - verifyRender(model, true); - }); + ); + verifyRender(model, true); }); - it("adds animation to draco-compressed model", function () { - return loadAndZoomToModelAsync({ gltf: dracoCesiumManUrl }, scene).then( - function (model) { - verifyRender(model, true); - - const animationCollection = model.activeAnimations; - const animation = animationCollection.add({ - index: 0, - }); - expect(animation).toBeDefined(); - expect(animationCollection.length).toBe(1); - } + it("adds animation to draco-compressed model", async function () { + const model = await loadAndZoomToModelAsync( + { gltf: dracoCesiumManUrl }, + scene ); + verifyRender(model, true); + + const animationCollection = model.activeAnimations; + const animation = animationCollection.add({ + index: 0, + }); + expect(animation).toBeDefined(); + expect(animationCollection.length).toBe(1); }); - it("renders model with instancing but no normals", function () { + it("renders model with instancing but no normals", async function () { // None of the 4 instanced cubes are in the center of the model's bounding // sphere, so set up a camera view that focuses in on one of them. const offset = new HeadingPitchRange( @@ -1029,61 +1047,55 @@ describe( ); const resource = Resource.createIfNeeded(boxInstancedNoNormalsUrl); - return resource.fetchJson().then(function (gltf) { - return loadAndZoomToModelAsync( - { - gltf: gltf, - basePath: boxInstancedNoNormalsUrl, - offset: offset, - }, - scene - ).then(function (model) { - const renderOptions = { - zoomToModel: false, - }; - - verifyRender(model, true, renderOptions); - }); - }); + const gltf = await resource.fetchJson(); + const model = await loadAndZoomToModelAsync( + { + gltf: gltf, + basePath: boxInstancedNoNormalsUrl, + offset: offset, + }, + scene + ); + const renderOptions = { + zoomToModel: false, + }; + + verifyRender(model, true, renderOptions); }); - it("show works", function () { + it("show works", async function () { const resource = Resource.createIfNeeded(boxTexturedGlbUrl); - const loadPromise = resource.fetchArrayBuffer(); - return loadPromise.then(function (buffer) { - return loadAndZoomToModelAsync( - { gltf: new Uint8Array(buffer), show: false }, - scene - ).then(function (model) { - expect(model.ready).toEqual(true); - expect(model.show).toEqual(false); - verifyRender(model, false); - - model.show = true; - expect(model.show).toEqual(true); - verifyRender(model, true); - }); - }); + const buffer = await resource.fetchArrayBuffer(); + const model = await loadAndZoomToModelAsync( + { gltf: new Uint8Array(buffer), show: false }, + scene + ); + expect(model.ready).toEqual(true); + expect(model.show).toEqual(false); + verifyRender(model, false); + + model.show = true; + expect(model.show).toEqual(true); + verifyRender(model, true); }); - it("renders in 2D", function () { - return loadAndZoomToModelAsync( + it("renders in 2D", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, modelMatrix: modelMatrix, }, scene2D - ).then(function (model) { - expect(model.ready).toEqual(true); - verifyRender(model, true, { - zoomToModel: false, - scene: scene2D, - }); + ); + expect(model.ready).toEqual(true); + verifyRender(model, true, { + zoomToModel: false, + scene: scene2D, }); }); - it("renders in 2D over the IDL", function () { - return loadAndZoomToModelAsync( + it("renders in 2D over the IDL", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, modelMatrix: Transforms.eastNorthUpToFixedFrame( @@ -1091,65 +1103,62 @@ describe( ), }, scene2D - ).then(function (model) { - expect(model.ready).toEqual(true); - verifyRender(model, true, { - zoomToModel: false, - scene: scene2D, - }); + ); + expect(model.ready).toEqual(true); + verifyRender(model, true, { + zoomToModel: false, + scene: scene2D, + }); - model.modelMatrix = Transforms.eastNorthUpToFixedFrame( - Cartesian3.fromDegrees(-180.0, 0.0) - ); - verifyRender(model, true, { - zoomToModel: false, - scene: scene2D, - }); + model.modelMatrix = Transforms.eastNorthUpToFixedFrame( + Cartesian3.fromDegrees(-180.0, 0.0) + ); + verifyRender(model, true, { + zoomToModel: false, + scene: scene2D, }); }); - it("renders in CV", function () { - return loadAndZoomToModelAsync( + it("renders in CV", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, modelMatrix: modelMatrix, }, sceneCV - ).then(function (model) { - expect(model.ready).toEqual(true); - scene.camera.moveBackward(1.0); - verifyRender(model, true, { - zoomToModel: false, - scene: sceneCV, - }); + ); + expect(model.ready).toEqual(true); + scene.camera.moveBackward(1.0); + verifyRender(model, true, { + zoomToModel: false, + scene: sceneCV, }); }); - it("renders in CV after draw commands are reset", function () { - return loadAndZoomToModelAsync( + it("renders in CV after draw commands are reset", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, modelMatrix: modelMatrix, }, sceneCV - ).then(function (model) { - expect(model.ready).toEqual(true); - scene.camera.moveBackward(1.0); - verifyRender(model, true, { - zoomToModel: false, - scene: sceneCV, - }); + ); + expect(model.ready).toEqual(true); + scene.camera.moveBackward(1.0); + verifyRender(model, true, { + zoomToModel: false, + scene: sceneCV, + }); - model._drawCommandsBuilt = false; - verifyRender(model, true, { - zoomToModel: false, - scene: sceneCV, - }); + model._drawCommandsBuilt = false; + verifyRender(model, true, { + zoomToModel: false, + scene: sceneCV, }); }); - it("projectTo2D works for 2D", function () { - return loadAndZoomToModelAsync( + it("projectTo2D works for 2D", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, modelMatrix: modelMatrix, @@ -1157,17 +1166,16 @@ describe( incrementallyLoadTextures: false, }, scene2D - ).then(function (model) { - expect(model.ready).toEqual(true); - verifyRender(model, true, { - zoomToModel: false, - scene: scene2D, - }); + ); + expect(model.ready).toEqual(true); + verifyRender(model, true, { + zoomToModel: false, + scene: scene2D, }); }); - it("projectTo2D works for CV", function () { - return loadAndZoomToModelAsync( + it("projectTo2D works for CV", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, modelMatrix: modelMatrix, @@ -1175,174 +1183,153 @@ describe( incrementallyLoadTextures: false, }, sceneCV - ).then(function (model) { - expect(model.ready).toEqual(true); - sceneCV.camera.moveBackward(1.0); - verifyRender(model, true, { - zoomToModel: false, - scene: sceneCV, - }); + ); + expect(model.ready).toEqual(true); + sceneCV.camera.moveBackward(1.0); + verifyRender(model, true, { + zoomToModel: false, + scene: sceneCV, }); }); - it("does not render during morph", function () { - return loadAndZoomToModelAsync( + it("does not render during morph", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, modelMatrix: modelMatrix, projectTo2D: true, }, scene - ).then(function (model) { - const commandList = scene.frameState.commandList; - expect(model.ready).toEqual(true); + ); + const commandList = scene.frameState.commandList; + expect(model.ready).toEqual(true); - scene.renderForSpecs(); - expect(commandList.length).toBeGreaterThan(0); + scene.renderForSpecs(); + expect(commandList.length).toBeGreaterThan(0); - scene.morphTo2D(1.0); - scene.renderForSpecs(); - expect(commandList.length).toBe(0); + scene.morphTo2D(1.0); + scene.renderForSpecs(); + expect(commandList.length).toBe(0); - scene.completeMorph(); - scene.morphTo3D(0.0); - scene.renderForSpecs(); - expect(commandList.length).toBeGreaterThan(0); - }); + scene.completeMorph(); + scene.morphTo3D(0.0); + scene.renderForSpecs(); + expect(commandList.length).toBeGreaterThan(0); }); describe("style", function () { - it("applies style to model with feature table", function () { - let model; - let style; - return loadAndZoomToModelAsync({ gltf: buildingsMetadata }, scene).then( - function (result) { - model = result; - // Renders without style. - verifyRender(model, true); - - // Renders with opaque style. - style = new Cesium3DTileStyle({ - color: { - conditions: [["${height} > 1", "color('red')"]], - }, - }); - - model.style = style; - verifyRender(model, true); - expect(model._styleCommandsNeeded).toBe( - StyleCommandsNeeded.ALL_OPAQUE - ); + it("applies style to model with feature table", async function () { + const model = await loadAndZoomToModelAsync( + { gltf: buildingsMetadata }, + scene + ); - // Renders with translucent style. - style = new Cesium3DTileStyle({ - color: { - conditions: [["${height} > 1", "color('red', 0.5)"]], - }, - }); - - model.style = style; - verifyRender(model, true); - expect(model._styleCommandsNeeded).toBe( - StyleCommandsNeeded.ALL_TRANSLUCENT - ); + // Renders without style. + verifyRender(model, true); - // Does not render with invisible color. - style = new Cesium3DTileStyle({ - color: { - conditions: [["${height} > 1", "color('red', 0.0)"]], - }, - }); - - // Does not render when style disables show. - style = new Cesium3DTileStyle({ - show: { - conditions: [["${height} > 1", "false"]], - }, - }); - - model.style = style; - verifyRender(model, false); - - // Render when style is removed. - model.style = undefined; - verifyRender(model, true); - } + // Renders with opaque style. + model.style = new Cesium3DTileStyle({ + color: { + conditions: [["${height} > 1", "color('red')"]], + }, + }); + verifyRender(model, true); + expect(model._styleCommandsNeeded).toBe(StyleCommandsNeeded.ALL_OPAQUE); + + // Renders with translucent style. + model.style = new Cesium3DTileStyle({ + color: { + conditions: [["${height} > 1", "color('red', 0.5)"]], + }, + }); + verifyRender(model, true); + expect(model._styleCommandsNeeded).toBe( + StyleCommandsNeeded.ALL_TRANSLUCENT ); + + // Does not render with invisible color. + model.style = new Cesium3DTileStyle({ + color: { + conditions: [["${height} > 1", "color('red', 0.0)"]], + }, + }); + verifyRender(model, false); + + // Does not render when style disables show. + model.style = new Cesium3DTileStyle({ + show: { + conditions: [["${height} > 1", "false"]], + }, + }); + verifyRender(model, false); + + // Render when style is removed. + model.style = undefined; + verifyRender(model, true); }); - it("applies style to model without feature table", function () { - let model; - let style; - return loadAndZoomToModelAsync({ gltf: boxTexturedGlbUrl }, scene).then( - function (result) { - const renderOptions = { - scene: scene, - time: defaultDate, - }; - model = result; - - // Renders without style. - let original; - verifyRender(model, true); - expect(renderOptions).toRenderAndCall(function (rgba) { - original = rgba; - }); - - // Renders with opaque style. - style = new Cesium3DTileStyle({ - color: "color('red')", - }); - - model.style = style; - verifyRender(model, true); - expect(renderOptions).toRenderAndCall(function (rgba) { - expect(rgba[0]).toEqual(original[0]); - expect(rgba[1]).toBeLessThan(original[1]); - expect(rgba[2]).toBeLessThan(original[2]); - expect(rgba[3]).toEqual(original[3]); - }); - - // Renders with translucent style. - style = new Cesium3DTileStyle({ - color: "color('red', 0.5)", - }); - - model.style = style; - verifyRender(model, true); - expect(renderOptions).toRenderAndCall(function (rgba) { - expect(rgba[0]).toBeLessThan(original[0]); - expect(rgba[1]).toBeLessThan(original[1]); - expect(rgba[2]).toBeLessThan(original[2]); - expect(rgba[3]).toEqual(original[3]); - }); - - // Does not render with invisible color. - style = new Cesium3DTileStyle({ - color: "color('red', 0.0)", - }); - - model.style = style; - verifyRender(model, false, { zoomToModel: false }); - - // Does not render when style disables show. - style = new Cesium3DTileStyle({ - show: "false", - }); - - model.style = style; - verifyRender(model, false, { zoomToModel: false }); - - // Render when style is removed. - model.style = undefined; - expect(renderOptions).toRenderAndCall(function (rgba) { - expect(rgba[0]).toEqual(original[0]); - expect(rgba[1]).toEqual(original[1]); - expect(rgba[2]).toEqual(original[2]); - expect(rgba[3]).toEqual(original[3]); - }); - } + it("applies style to model without feature table", async function () { + const model = await loadAndZoomToModelAsync( + { gltf: boxTexturedGlbUrl }, + scene ); + + const renderOptions = { + scene: scene, + time: defaultDate, + }; + + // Renders without style. + let original; + verifyRender(model, true); + expect(renderOptions).toRenderAndCall(function (rgba) { + original = rgba; + }); + + // Renders with opaque style. + model.style = new Cesium3DTileStyle({ + color: "color('red')", + }); + verifyRender(model, true); + expect(renderOptions).toRenderAndCall(function (rgba) { + expect(rgba[0]).toEqual(original[0]); + expect(rgba[1]).toBeLessThan(original[1]); + expect(rgba[2]).toBeLessThan(original[2]); + expect(rgba[3]).toEqual(original[3]); + }); + + // Renders with translucent style. + model.style = new Cesium3DTileStyle({ + color: "color('red', 0.5)", + }); + verifyRender(model, true); + expect(renderOptions).toRenderAndCall(function (rgba) { + expect(rgba[0]).toBeLessThan(original[0]); + expect(rgba[1]).toBeLessThan(original[1]); + expect(rgba[2]).toBeLessThan(original[2]); + expect(rgba[3]).toEqual(original[3]); + }); + + // Does not render with invisible color. + model.style = new Cesium3DTileStyle({ + color: "color('red', 0.0)", + }); + verifyRender(model, false, { zoomToModel: false }); + + // Does not render when style disables show. + model.style = new Cesium3DTileStyle({ + show: "false", + }); + verifyRender(model, false, { zoomToModel: false }); + + // Render when style is removed. + model.style = undefined; + expect(renderOptions).toRenderAndCall(function (rgba) { + expect(rgba[0]).toEqual(original[0]); + expect(rgba[1]).toEqual(original[1]); + expect(rgba[2]).toEqual(original[2]); + expect(rgba[3]).toEqual(original[3]); + }); }); }); @@ -1350,227 +1337,198 @@ describe( const boxWithCreditsUrl = "./Data/Models/glTF-2.0/BoxWithCopyright/glTF/Box.gltf"; - it("initializes with credit", function () { + it("initializes with credit", async function () { const credit = new Credit("User Credit"); const resource = Resource.createIfNeeded(boxTexturedGltfUrl); - return resource.fetchJson().then(function (gltf) { - return loadAndZoomToModelAsync( - { - gltf: gltf, - basePath: boxTexturedGltfUrl, - credit: credit, - }, - scene - ).then(function (model) { - scene.renderForSpecs(); - const creditDisplay = scene.frameState.creditDisplay; - const credits = - creditDisplay._currentFrameCredits.lightboxCredits.values; - const length = credits.length; - expect(length).toEqual(1); - expect(credits[0].credit.html).toEqual("User Credit"); - }); - }); + const gltf = await resource.fetchJson(); + await loadAndZoomToModelAsync( + { + gltf: gltf, + basePath: boxTexturedGltfUrl, + credit: credit, + }, + scene + ); + scene.renderForSpecs(); + const creditDisplay = scene.frameState.creditDisplay; + const credits = + creditDisplay._currentFrameCredits.lightboxCredits.values; + expect(credits.length).toEqual(1); + expect(credits[0].credit.html).toEqual("User Credit"); }); - it("initializes with credit string", function () { + it("initializes with credit string", async function () { const creditString = "User Credit"; const resource = Resource.createIfNeeded(boxTexturedGltfUrl); - return resource.fetchJson().then(function (gltf) { - return loadAndZoomToModelAsync( - { - gltf: gltf, - basePath: boxTexturedGltfUrl, - credit: creditString, - }, - scene - ).then(function (model) { - scene.renderForSpecs(); - const creditDisplay = scene.frameState.creditDisplay; - const credits = - creditDisplay._currentFrameCredits.lightboxCredits.values; - const length = credits.length; - expect(length).toEqual(1); - expect(credits[0].credit.html).toEqual(creditString); - }); - }); + const gltf = await resource.fetchJson(); + await loadAndZoomToModelAsync( + { + gltf: gltf, + basePath: boxTexturedGltfUrl, + credit: creditString, + }, + scene + ); + scene.renderForSpecs(); + const creditDisplay = scene.frameState.creditDisplay; + const credits = + creditDisplay._currentFrameCredits.lightboxCredits.values; + expect(credits.length).toEqual(1); + expect(credits[0].credit.html).toEqual(creditString); }); - it("gets copyrights from gltf", function () { + it("gets copyrights from gltf", async function () { const resource = Resource.createIfNeeded(boxWithCreditsUrl); - return resource.fetchJson().then(function (gltf) { - return loadAndZoomToModelAsync( - { - gltf: gltf, - basePath: boxWithCreditsUrl, - }, - scene - ).then(function (model) { - const expectedCredits = [ - "First Source", - "Second Source", - "Third Source", - ]; - - scene.renderForSpecs(); - const creditDisplay = scene.frameState.creditDisplay; - const credits = - creditDisplay._currentFrameCredits.lightboxCredits.values; - const length = credits.length; - expect(length).toEqual(expectedCredits.length); - for (let i = 0; i < length; i++) { - expect(credits[i].credit.html).toEqual(expectedCredits[i]); - } - }); - }); + const gltf = await resource.fetchJson(); + await loadAndZoomToModelAsync( + { + gltf: gltf, + basePath: boxWithCreditsUrl, + }, + scene + ); + const expectedCredits = [ + "First Source", + "Second Source", + "Third Source", + ]; + + scene.renderForSpecs(); + const creditDisplay = scene.frameState.creditDisplay; + const credits = + creditDisplay._currentFrameCredits.lightboxCredits.values; + expect(credits.length).toEqual(expectedCredits.length); + for (let i = 0; i < credits.length; i++) { + expect(credits[i].credit.html).toEqual(expectedCredits[i]); + } }); - it("displays all types of credits", function () { + it("displays all types of credits", async function () { const resource = Resource.createIfNeeded(boxWithCreditsUrl); - return resource.fetchJson().then(function (gltf) { - return loadAndZoomToModelAsync( - { - gltf: gltf, - basePath: boxWithCreditsUrl, - credit: "User Credit", - }, - scene - ).then(function (model) { - model._resourceCredits = [new Credit("Resource Credit")]; - const expectedCredits = [ - "User Credit", - "Resource Credit", - "First Source", - "Second Source", - "Third Source", - ]; - - scene.renderForSpecs(); - const creditDisplay = scene.frameState.creditDisplay; - const credits = - creditDisplay._currentFrameCredits.lightboxCredits.values; - const length = credits.length; - expect(length).toEqual(expectedCredits.length); - for (let i = 0; i < length; i++) { - expect(credits[i].credit.html).toEqual(expectedCredits[i]); - } - }); - }); + const gltf = await resource.fetchJson(); + const model = await loadAndZoomToModelAsync( + { + gltf: gltf, + basePath: boxWithCreditsUrl, + credit: "User Credit", + }, + scene + ); + model._resourceCredits = [new Credit("Resource Credit")]; + const expectedCredits = [ + "User Credit", + "Resource Credit", + "First Source", + "Second Source", + "Third Source", + ]; + + scene.renderForSpecs(); + const creditDisplay = scene.frameState.creditDisplay; + const credits = + creditDisplay._currentFrameCredits.lightboxCredits.values; + expect(credits.length).toEqual(expectedCredits.length); + for (let i = 0; i < credits.length; i++) { + expect(credits[i].credit.html).toEqual(expectedCredits[i]); + } }); - it("initializes with showCreditsOnScreen", function () { + it("initializes with showCreditsOnScreen", async function () { const resource = Resource.createIfNeeded(boxWithCreditsUrl); - return resource.fetchJson().then(function (gltf) { - return loadAndZoomToModelAsync( - { - gltf: gltf, - basePath: boxWithCreditsUrl, - credit: "User Credit", - showCreditsOnScreen: true, - }, - scene - ).then(function (model) { - const expectedCredits = [ - "User Credit", - "First Source", - "Second Source", - "Third Source", - ]; - - scene.renderForSpecs(); - const creditDisplay = scene.frameState.creditDisplay; - const credits = - creditDisplay._currentFrameCredits.screenCredits.values; - const length = credits.length; - expect(length).toEqual(expectedCredits.length); - for (let i = 0; i < length; i++) { - expect(credits[i].credit.html).toEqual(expectedCredits[i]); - } - }); - }); + const gltf = await resource.fetchJson(); + await loadAndZoomToModelAsync( + { + gltf: gltf, + basePath: boxWithCreditsUrl, + credit: "User Credit", + showCreditsOnScreen: true, + }, + scene + ); + const expectedCredits = [ + "User Credit", + "First Source", + "Second Source", + "Third Source", + ]; + + scene.renderForSpecs(); + const creditDisplay = scene.frameState.creditDisplay; + const credits = creditDisplay._currentFrameCredits.screenCredits.values; + expect(credits.length).toEqual(expectedCredits.length); + for (let i = 0; i < credits.length; i++) { + expect(credits[i].credit.html).toEqual(expectedCredits[i]); + } }); - it("changing showCreditsOnScreen works", function () { + it("changing showCreditsOnScreen works", async function () { const resource = Resource.createIfNeeded(boxWithCreditsUrl); - return resource.fetchJson().then(function (gltf) { - return loadAndZoomToModelAsync( - { - gltf: gltf, - basePath: boxWithCreditsUrl, - credit: "User Credit", - showCreditsOnScreen: false, - }, - scene - ).then(function (model) { - const expectedCredits = [ - "User Credit", - "First Source", - "Second Source", - "Third Source", - ]; - - scene.renderForSpecs(); - const creditDisplay = scene.frameState.creditDisplay; - const lightboxCredits = - creditDisplay._currentFrameCredits.lightboxCredits.values; - const screenCredits = - creditDisplay._currentFrameCredits.screenCredits.values; - - let length = lightboxCredits.length; - expect(length).toEqual(expectedCredits.length); - for (let i = 0; i < length; i++) { - expect(lightboxCredits[i].credit.html).toEqual( - expectedCredits[i] - ); - } - expect(screenCredits.length).toEqual(0); - - model.showCreditsOnScreen = true; - scene.renderForSpecs(); - length = screenCredits.length; - expect(length).toEqual(expectedCredits.length); - for (let i = 0; i < length; i++) { - expect(screenCredits[i].credit.html).toEqual(expectedCredits[i]); - } - expect(lightboxCredits.length).toEqual(0); - - model.showCreditsOnScreen = false; - scene.renderForSpecs(); - length = lightboxCredits.length; - expect(length).toEqual(expectedCredits.length); - for (let i = 0; i < length; i++) { - expect(lightboxCredits[i].credit.html).toEqual( - expectedCredits[i] - ); - } - expect(screenCredits.length).toEqual(0); - }); - }); + const gltf = await resource.fetchJson(); + const model = await loadAndZoomToModelAsync( + { + gltf: gltf, + basePath: boxWithCreditsUrl, + credit: "User Credit", + showCreditsOnScreen: false, + }, + scene + ); + const expectedCredits = [ + "User Credit", + "First Source", + "Second Source", + "Third Source", + ]; + + scene.renderForSpecs(); + const creditDisplay = scene.frameState.creditDisplay; + const lightboxCredits = + creditDisplay._currentFrameCredits.lightboxCredits.values; + const screenCredits = + creditDisplay._currentFrameCredits.screenCredits.values; + + expect(lightboxCredits.length).toEqual(expectedCredits.length); + for (let i = 0; i < lightboxCredits.length; i++) { + expect(lightboxCredits[i].credit.html).toEqual(expectedCredits[i]); + } + expect(screenCredits.length).toEqual(0); + + model.showCreditsOnScreen = true; + scene.renderForSpecs(); + expect(screenCredits.length).toEqual(expectedCredits.length); + for (let i = 0; i < screenCredits.length; i++) { + expect(screenCredits[i].credit.html).toEqual(expectedCredits[i]); + } + expect(lightboxCredits.length).toEqual(0); + + model.showCreditsOnScreen = false; + scene.renderForSpecs(); + expect(lightboxCredits.length).toEqual(expectedCredits.length); + for (let i = 0; i < lightboxCredits.length; i++) { + expect(lightboxCredits[i].credit.html).toEqual(expectedCredits[i]); + } + expect(screenCredits.length).toEqual(0); }); - it("showCreditsOnScreen overrides existing credit setting", function () { + it("showCreditsOnScreen overrides existing credit setting", async function () { const resource = Resource.createIfNeeded(boxTexturedGltfUrl); - return resource.fetchJson().then(function (gltf) { - return loadAndZoomToModelAsync( - { - gltf: gltf, - basePath: boxTexturedGltfUrl, - credit: new Credit("User Credit", false), - showCreditsOnScreen: true, - }, - scene - ).then(function (model) { - scene.renderForSpecs(); - const creditDisplay = scene.frameState.creditDisplay; - const credits = - creditDisplay._currentFrameCredits.screenCredits.values; - const length = credits.length; - expect(length).toEqual(1); - for (let i = 0; i < length; i++) { - expect(credits[i].credit.html).toEqual("User Credit"); - } - }); - }); + const gltf = await resource.fetchJson(); + await loadAndZoomToModelAsync( + { + gltf: gltf, + basePath: boxTexturedGltfUrl, + credit: new Credit("User Credit", false), + showCreditsOnScreen: true, + }, + scene + ); + scene.renderForSpecs(); + const creditDisplay = scene.frameState.creditDisplay; + const credits = creditDisplay._currentFrameCredits.screenCredits.values; + expect(credits.length).toEqual(1); + for (let i = 0; i < credits.length; i++) { + expect(credits[i].credit.html).toEqual("User Credit"); + } }); }); @@ -1598,143 +1556,124 @@ describe( sceneWithWebgl1.destroyForSpecs(); }); - it("debugWireframe works for WebGL1 if enableDebugWireframe is true", function () { + it("debugWireframe works for WebGL1 if enableDebugWireframe is true", async function () { const resource = Resource.createIfNeeded(boxTexturedGlbUrl); - const loadPromise = resource.fetchArrayBuffer(); - return loadPromise.then(function (buffer) { - return loadAndZoomToModelAsync( - { gltf: new Uint8Array(buffer), enableDebugWireframe: true }, - sceneWithWebgl1 - ).then(function (model) { - verifyDebugWireframe(model, PrimitiveType.TRIANGLES); - }); - }); + const buffer = await resource.fetchArrayBuffer(); + const model = await loadAndZoomToModelAsync( + { gltf: new Uint8Array(buffer), enableDebugWireframe: true }, + sceneWithWebgl1 + ); + verifyDebugWireframe(model, PrimitiveType.TRIANGLES); }); - it("debugWireframe does nothing in WebGL1 if enableDebugWireframe is false", function () { + it("debugWireframe does nothing in WebGL1 if enableDebugWireframe is false", async function () { const resource = Resource.createIfNeeded(boxTexturedGlbUrl); - const loadPromise = resource.fetchArrayBuffer(); - return loadPromise.then(function (buffer) { - return loadAndZoomToModelAsync( - { gltf: new Uint8Array(buffer), enableDebugWireframe: false }, - sceneWithWebgl1 - ).then(function (model) { - const commandList = scene.frameState.commandList; - const commandCounts = []; - let i, command; - sceneWithWebgl1.renderForSpecs(); - for (i = 0; i < commandList.length; i++) { - command = commandList[i]; - expect(command.primitiveType).toBe(PrimitiveType.TRIANGLES); - commandCounts.push(command.count); - } + const buffer = await resource.fetchArrayBuffer(); + const model = await loadAndZoomToModelAsync( + { gltf: new Uint8Array(buffer), enableDebugWireframe: false }, + sceneWithWebgl1 + ); + const commandList = scene.frameState.commandList; + const commandCounts = []; + sceneWithWebgl1.renderForSpecs(); + for (let i = 0; i < commandList.length; i++) { + const command = commandList[i]; + expect(command.primitiveType).toBe(PrimitiveType.TRIANGLES); + commandCounts.push(command.count); + } - model.debugWireframe = true; - expect(model._drawCommandsBuilt).toBe(false); + model.debugWireframe = true; + expect(model._drawCommandsBuilt).toBe(false); - sceneWithWebgl1.renderForSpecs(); - for (i = 0; i < commandList.length; i++) { - command = commandList[i]; - expect(command.primitiveType).toBe(PrimitiveType.TRIANGLES); - expect(command.count).toEqual(commandCounts[i]); - } - }); - }); + sceneWithWebgl1.renderForSpecs(); + for (let i = 0; i < commandList.length; i++) { + const command = commandList[i]; + expect(command.primitiveType).toBe(PrimitiveType.TRIANGLES); + expect(command.count).toEqual(commandCounts[i]); + } }); - it("debugWireframe works for WebGL2", function () { + it("debugWireframe works for WebGL2", async function () { if (!scene.context.webgl2) { return; } const resource = Resource.createIfNeeded(boxTexturedGlbUrl); - const loadPromise = resource.fetchArrayBuffer(); - return loadPromise.then(function (buffer) { - return loadAndZoomToModelAsync( - { gltf: new Uint8Array(buffer) }, - scene - ).then(function (model) { - verifyDebugWireframe(model, PrimitiveType.TRIANGLES, { - scene: scene, - }); - }); + const buffer = await resource.fetchArrayBuffer(); + const model = await loadAndZoomToModelAsync( + { gltf: new Uint8Array(buffer) }, + scene + ); + verifyDebugWireframe(model, PrimitiveType.TRIANGLES, { + scene: scene, }); }); - it("debugWireframe works for model without indices", function () { - return loadAndZoomToModelAsync( + it("debugWireframe works for model without indices", async function () { + const model = await loadAndZoomToModelAsync( { gltf: triangleWithoutIndicesUrl, enableDebugWireframe: true }, scene - ).then(function (model) { - verifyDebugWireframe(model, PrimitiveType.TRIANGLES, { - hasIndices: false, - }); + ); + verifyDebugWireframe(model, PrimitiveType.TRIANGLES, { + hasIndices: false, }); }); - it("debugWireframe works for model with triangle strip", function () { - return loadAndZoomToModelAsync( + it("debugWireframe works for model with triangle strip", async function () { + const model = await loadAndZoomToModelAsync( { gltf: triangleStripUrl, enableDebugWireframe: true }, scene - ).then(function (model) { - verifyDebugWireframe(model, PrimitiveType.TRIANGLE_STRIP); - }); + ); + verifyDebugWireframe(model, PrimitiveType.TRIANGLE_STRIP); }); - it("debugWireframe works for model with triangle fan", function () { - return loadAndZoomToModelAsync( + it("debugWireframe works for model with triangle fan", async function () { + const model = await loadAndZoomToModelAsync( { gltf: triangleFanUrl, enableDebugWireframe: true }, scene - ).then(function (model) { - verifyDebugWireframe(model, PrimitiveType.TRIANGLE_FAN); - }); + ); + verifyDebugWireframe(model, PrimitiveType.TRIANGLE_FAN); }); - it("debugWireframe ignores points", function () { - return loadAndZoomToModelAsync( + it("debugWireframe ignores points", async function () { + const model = await loadAndZoomToModelAsync( { gltf: pointCloudUrl, enableDebugWireframe: true }, scene - ).then(function (model) { - let i; - scene.renderForSpecs(); - const commandList = scene.frameState.commandList; - for (i = 0; i < commandList.length; i++) { - const command = commandList[i]; - expect(command.primitiveType).toBe(PrimitiveType.POINTS); - expect(command.vertexArray.indexBuffer).toBeUndefined(); - } + ); + scene.renderForSpecs(); + const commandList = scene.frameState.commandList; + for (let i = 0; i < commandList.length; i++) { + const command = commandList[i]; + expect(command.primitiveType).toBe(PrimitiveType.POINTS); + expect(command.vertexArray.indexBuffer).toBeUndefined(); + } - model.debugWireframe = true; - for (i = 0; i < commandList.length; i++) { - const command = commandList[i]; - expect(command.primitiveType).toBe(PrimitiveType.POINTS); - expect(command.vertexArray.indexBuffer).toBeUndefined(); - } - }); + model.debugWireframe = true; + for (let i = 0; i < commandList.length; i++) { + const command = commandList[i]; + expect(command.primitiveType).toBe(PrimitiveType.POINTS); + expect(command.vertexArray.indexBuffer).toBeUndefined(); + } }); }); - it("debugShowBoundingVolume works", function () { + it("debugShowBoundingVolume works", async function () { const resource = Resource.createIfNeeded(boxTexturedGlbUrl); - const loadPromise = resource.fetchArrayBuffer(); - return loadPromise.then(function (buffer) { - return loadAndZoomToModelAsync( - { gltf: new Uint8Array(buffer), debugShowBoundingVolume: true }, - scene - ).then(function (model) { - let i; - scene.renderForSpecs(); - const commandList = scene.frameState.commandList; - for (i = 0; i < commandList.length; i++) { - expect(commandList[i].debugShowBoundingVolume).toBe(true); - } - model.debugShowBoundingVolume = false; - expect(model._debugShowBoundingVolumeDirty).toBe(true); - scene.renderForSpecs(); - for (i = 0; i < commandList.length; i++) { - expect(commandList[i].debugShowBoundingVolume).toBe(false); - } - }); - }); + const buffer = await resource.fetchArrayBuffer(); + const model = await loadAndZoomToModelAsync( + { gltf: new Uint8Array(buffer), debugShowBoundingVolume: true }, + scene + ); + scene.renderForSpecs(); + const commandList = scene.frameState.commandList; + for (let i = 0; i < commandList.length; i++) { + expect(commandList[i].debugShowBoundingVolume).toBe(true); + } + model.debugShowBoundingVolume = false; + expect(model._debugShowBoundingVolumeDirty).toBe(true); + scene.renderForSpecs(); + for (let i = 0; i < commandList.length; i++) { + expect(commandList[i].debugShowBoundingVolume).toBe(false); + } }); describe("boundingSphere", function () { @@ -1747,133 +1686,123 @@ describe( }).toThrowDeveloperError(); }); - it("boundingSphere works", function () { + it("boundingSphere works", async function () { const resource = Resource.createIfNeeded(boxTexturedGlbUrl); - const loadPromise = resource.fetchArrayBuffer(); - return loadPromise.then(function (buffer) { - return loadAndZoomToModelAsync( - { gltf: new Uint8Array(buffer) }, - scene - ).then(function (model) { - const boundingSphere = model.boundingSphere; - expect(boundingSphere).toBeDefined(); - expect(boundingSphere.center).toEqual(new Cartesian3()); - expect(boundingSphere.radius).toEqualEpsilon( - 0.8660254037844386, - CesiumMath.EPSILON8 - ); - }); - }); + const buffer = await resource.fetchArrayBuffer(); + const model = await loadAndZoomToModelAsync( + { gltf: new Uint8Array(buffer) }, + scene + ); + const boundingSphere = model.boundingSphere; + expect(boundingSphere).toBeDefined(); + expect(boundingSphere.center).toEqual(new Cartesian3()); + expect(boundingSphere.radius).toEqualEpsilon( + 0.8660254037844386, + CesiumMath.EPSILON8 + ); }); - it("boundingSphere accounts for axis correction", function () { + it("boundingSphere accounts for axis correction", async function () { const resource = Resource.createIfNeeded(riggedFigureUrl); - return resource.fetchJson().then(function (gltf) { - return loadAndZoomToModelAsync({ gltf: gltf }, scene).then(function ( - model - ) { - // The bounding sphere should transform from z-forward - // to x-forward. - const boundingSphere = model.boundingSphere; - expect(boundingSphere).toBeDefined(); - expect(boundingSphere.center).toEqualEpsilon( - new Cartesian3(0.0320296511054039, 0, 0.7249599695205688), - CesiumMath.EPSILON3 - ); - expect(boundingSphere.radius).toEqualEpsilon( - 0.9484635280120018, - CesiumMath.EPSILON3 - ); - }); - }); + const gltf = await resource.fetchJson(); + const model = await loadAndZoomToModelAsync({ gltf: gltf }, scene); + // The bounding sphere should transform from z-forward + // to x-forward. + const boundingSphere = model.boundingSphere; + expect(boundingSphere).toBeDefined(); + expect(boundingSphere.center).toEqualEpsilon( + new Cartesian3(0.0320296511054039, 0, 0.7249599695205688), + CesiumMath.EPSILON3 + ); + expect(boundingSphere.radius).toEqualEpsilon( + 0.9484635280120018, + CesiumMath.EPSILON3 + ); }); - it("boundingSphere accounts for transform from CESIUM_RTC extension", function () { - return loadAndZoomToModelAsync( + it("boundingSphere accounts for transform from CESIUM_RTC extension", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxCesiumRtcUrl, }, scene - ).then(function (model) { - const boundingSphere = model.boundingSphere; - expect(boundingSphere).toBeDefined(); - expect(boundingSphere.center).toEqual(new Cartesian3(6378137, 0, 0)); - }); + ); + const boundingSphere = model.boundingSphere; + expect(boundingSphere).toBeDefined(); + expect(boundingSphere.center).toEqual(new Cartesian3(6378137, 0, 0)); }); - it("boundingSphere updates bounding sphere when invoked", function () { - return loadAndZoomToModelAsync({ gltf: boxTexturedGlbUrl }, scene).then( - function (model) { - const expectedRadius = 0.8660254037844386; - const translation = new Cartesian3(10, 0, 0); - const modelMatrix = Matrix4.fromTranslation(translation); - model.modelMatrix = modelMatrix; - model.scale = 2.0; - - // boundingSphere should still account for the model matrix - // even though the scene has not yet updated. - const boundingSphere = model.boundingSphere; - expect(boundingSphere.center).toEqual(translation); - expect(boundingSphere.radius).toEqualEpsilon( - 2.0 * expectedRadius, - CesiumMath.EPSILON8 - ); - } + it("boundingSphere updates bounding sphere when invoked", async function () { + const model = await loadAndZoomToModelAsync( + { gltf: boxTexturedGlbUrl }, + scene + ); + const expectedRadius = 0.8660254037844386; + const translation = new Cartesian3(10, 0, 0); + const modelMatrix = Matrix4.fromTranslation(translation); + model.modelMatrix = modelMatrix; + model.scale = 2.0; + + // boundingSphere should still account for the model matrix + // even though the scene has not yet updated. + const boundingSphere = model.boundingSphere; + expect(boundingSphere.center).toEqual(translation); + expect(boundingSphere.radius).toEqualEpsilon( + 2.0 * expectedRadius, + CesiumMath.EPSILON8 ); }); }); describe("picking and id", function () { - it("initializes with id", function () { + it("initializes with id", async function () { // This model gets clipped if log depth is disabled, so zoom out // the camera just a little const offset = new HeadingPitchRange(0, -CesiumMath.PI_OVER_FOUR, 2); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, offset: offset, id: boxTexturedGlbUrl, }, scene - ).then(function (model) { - expect(model.id).toBe(boxTexturedGlbUrl); + ); + expect(model.id).toBe(boxTexturedGlbUrl); - const pickIds = model._pickIds; - expect(pickIds.length).toEqual(1); - expect(pickIds[0].object.id).toEqual(boxTexturedGlbUrl); - }); + const pickIds = model._pickIds; + expect(pickIds.length).toEqual(1); + expect(pickIds[0].object.id).toEqual(boxTexturedGlbUrl); }); - it("changing id works", function () { + it("changing id works", async function () { // This model gets clipped if log depth is disabled, so zoom out // the camera just a little const offset = new HeadingPitchRange(0, -CesiumMath.PI_OVER_FOUR, 2); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, offset: offset, }, scene - ).then(function (model) { - expect(model.id).toBeUndefined(); + ); + expect(model.id).toBeUndefined(); - const pickIds = model._pickIds; - expect(pickIds.length).toEqual(1); - expect(pickIds[0].object.id).toBeUndefined(); + const pickIds = model._pickIds; + expect(pickIds.length).toEqual(1); + expect(pickIds[0].object.id).toBeUndefined(); - model.id = boxTexturedGlbUrl; - scene.renderForSpecs(); - expect(pickIds[0].object.id).toBe(boxTexturedGlbUrl); + model.id = boxTexturedGlbUrl; + scene.renderForSpecs(); + expect(pickIds[0].object.id).toBe(boxTexturedGlbUrl); - model.id = undefined; - scene.renderForSpecs(); - expect(pickIds[0].object.id).toBeUndefined(); - }); + model.id = undefined; + scene.renderForSpecs(); + expect(pickIds[0].object.id).toBeUndefined(); }); - it("picks box textured", function () { + it("picks box textured", async function () { if (FeatureDetection.isInternetExplorer()) { // Workaround IE 11.0.9. This test fails when all tests are ran without a breakpoint here. return; @@ -1883,21 +1812,20 @@ describe( // the camera just a little const offset = new HeadingPitchRange(0, -CesiumMath.PI_OVER_FOUR, 2); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, offset: offset, }, scene - ).then(function (model) { - expect(scene).toPickAndCall(function (result) { - expect(result.primitive).toBeInstanceOf(Model); - expect(result.primitive).toEqual(model); - }); + ); + expect(scene).toPickAndCall(function (result) { + expect(result.primitive).toBeInstanceOf(Model); + expect(result.primitive).toEqual(model); }); }); - it("picks box textured with id", function () { + it("picks box textured with id", async function () { if (FeatureDetection.isInternetExplorer()) { // Workaround IE 11.0.9. This test fails when all tests are ran without a breakpoint here. return; @@ -1907,23 +1835,22 @@ describe( // the camera just a little const offset = new HeadingPitchRange(0, -CesiumMath.PI_OVER_FOUR, 2); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, offset: offset, id: boxTexturedGlbUrl, }, scene - ).then(function (model) { - expect(scene).toPickAndCall(function (result) { - expect(result.primitive).toBeInstanceOf(Model); - expect(result.primitive).toEqual(model); - expect(result.id).toEqual(boxTexturedGlbUrl); - }); + ); + expect(scene).toPickAndCall(function (result) { + expect(result.primitive).toBeInstanceOf(Model); + expect(result.primitive).toEqual(model); + expect(result.id).toEqual(boxTexturedGlbUrl); }); }); - it("picks box textured with a new id", function () { + it("picks box textured with a new id", async function () { if (FeatureDetection.isInternetExplorer()) { // Workaround IE 11.0.9. This test fails when all tests are ran without a breakpoint here. return; @@ -1933,30 +1860,29 @@ describe( // the camera just a little const offset = new HeadingPitchRange(0, -CesiumMath.PI_OVER_FOUR, 2); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, offset: offset, id: boxTexturedGlbUrl, }, scene - ).then(function (model) { - expect(scene).toPickAndCall(function (result) { - expect(result.primitive).toBeInstanceOf(Model); - expect(result.primitive).toEqual(model); - expect(result.id).toEqual(boxTexturedGlbUrl); - }); - - model.id = "new id"; - expect(scene).toPickAndCall(function (result) { - expect(result.primitive).toBeInstanceOf(Model); - expect(result.primitive).toEqual(model); - expect(result.id).toEqual("new id"); - }); + ); + expect(scene).toPickAndCall(function (result) { + expect(result.primitive).toBeInstanceOf(Model); + expect(result.primitive).toEqual(model); + expect(result.id).toEqual(boxTexturedGlbUrl); + }); + + model.id = "new id"; + expect(scene).toPickAndCall(function (result) { + expect(result.primitive).toBeInstanceOf(Model); + expect(result.primitive).toEqual(model); + expect(result.id).toEqual("new id"); }); }); - it("doesn't pick when allowPicking is false", function () { + it("doesn't pick when allowPicking is false", async function () { if (FeatureDetection.isInternetExplorer()) { // Workaround IE 11.0.9. This test fails when all tests are ran without a breakpoint here. return; @@ -1966,21 +1892,20 @@ describe( // the camera just a little const offset = new HeadingPitchRange(0, -CesiumMath.PI_OVER_FOUR, 2); - return loadAndZoomToModelAsync( + await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, allowPicking: false, offset: offset, }, scene - ).then(function () { - expect(scene).toPickAndCall(function (result) { - expect(result).toBeUndefined(); - }); + ); + expect(scene).toPickAndCall(function (result) { + expect(result).toBeUndefined(); }); }); - it("doesn't pick when model is hidden", function () { + it("doesn't pick when model is hidden", async function () { if (FeatureDetection.isInternetExplorer()) { // Workaround IE 11.0.9. This test fails when all tests are ran without a breakpoint here. return; @@ -1990,17 +1915,16 @@ describe( // the camera just a little const offset = new HeadingPitchRange(0, -CesiumMath.PI_OVER_FOUR, 2); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, offset: offset, }, scene - ).then(function (model) { - model.show = false; - expect(scene).toPickAndCall(function (result) { - expect(result).toBeUndefined(); - }); + ); + model.show = false; + expect(scene).toPickAndCall(function (result) { + expect(result).toBeUndefined(); }); }); }); @@ -2011,141 +1935,134 @@ describe( opaqueFeaturesLength, translucentFeaturesLength ) { - let i, feature; - for (i = 0; i < opaqueFeaturesLength; i++) { - feature = featureTable.getFeature(i); + for (let i = 0; i < opaqueFeaturesLength; i++) { + const feature = featureTable.getFeature(i); feature.color = Color.RED; } for ( - i = opaqueFeaturesLength; + let i = opaqueFeaturesLength; i < opaqueFeaturesLength + translucentFeaturesLength; i++ ) { - feature = featureTable.getFeature(i); + const feature = featureTable.getFeature(i); feature.color = Color.RED.withAlpha(0.5); } } - it("resets draw commands when the style commands needed are changed", function () { - return loadAndZoomToModelAsync( + it("resets draw commands when the style commands needed are changed", async function () { + const model = await loadAndZoomToModelAsync( { gltf: buildingsMetadata, }, scene - ).then(function (model) { - const featureTable = model.featureTables[model.featureTableId]; - - // Set all features to opaque. - setFeaturesWithOpacity(featureTable, 10, 0); - scene.renderForSpecs(); - expect(featureTable.styleCommandsNeededDirty).toEqual(false); - expect(featureTable._styleCommandsNeeded).toEqual( - StyleCommandsNeeded.ALL_OPAQUE - ); + ); + const featureTable = model.featureTables[model.featureTableId]; - // Set some features to translucent. - setFeaturesWithOpacity(featureTable, 8, 2); - scene.renderForSpecs(); - expect(featureTable.styleCommandsNeededDirty).toEqual(true); - expect(featureTable._styleCommandsNeeded).toEqual( - StyleCommandsNeeded.OPAQUE_AND_TRANSLUCENT - ); + // Set all features to opaque. + setFeaturesWithOpacity(featureTable, 10, 0); + scene.renderForSpecs(); + expect(featureTable.styleCommandsNeededDirty).toEqual(false); + expect(featureTable._styleCommandsNeeded).toEqual( + StyleCommandsNeeded.ALL_OPAQUE + ); - // Set some more features to translucent. - setFeaturesWithOpacity(featureTable, 2, 8); - scene.renderForSpecs(); - expect(featureTable.styleCommandsNeededDirty).toEqual(false); - expect(featureTable._styleCommandsNeeded).toEqual( - StyleCommandsNeeded.OPAQUE_AND_TRANSLUCENT - ); + // Set some features to translucent. + setFeaturesWithOpacity(featureTable, 8, 2); + scene.renderForSpecs(); + expect(featureTable.styleCommandsNeededDirty).toEqual(true); + expect(featureTable._styleCommandsNeeded).toEqual( + StyleCommandsNeeded.OPAQUE_AND_TRANSLUCENT + ); - // Set all features to translucent. - setFeaturesWithOpacity(featureTable, 0, 10); - scene.renderForSpecs(); - expect(featureTable.styleCommandsNeededDirty).toEqual(true); - expect(featureTable._styleCommandsNeeded).toEqual( - StyleCommandsNeeded.ALL_TRANSLUCENT - ); - }); + // Set some more features to translucent. + setFeaturesWithOpacity(featureTable, 2, 8); + scene.renderForSpecs(); + expect(featureTable.styleCommandsNeededDirty).toEqual(false); + expect(featureTable._styleCommandsNeeded).toEqual( + StyleCommandsNeeded.OPAQUE_AND_TRANSLUCENT + ); + + // Set all features to translucent. + setFeaturesWithOpacity(featureTable, 0, 10); + scene.renderForSpecs(); + expect(featureTable.styleCommandsNeededDirty).toEqual(true); + expect(featureTable._styleCommandsNeeded).toEqual( + StyleCommandsNeeded.ALL_TRANSLUCENT + ); }); - it("selects feature table for instanced feature ID attributes", function () { + it("selects feature table for instanced feature ID attributes", async function () { if (webglStub) { return; } - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxInstanced, instanceFeatureIdLabel: "section", }, scene - ).then(function (model) { - expect(model.featureTableId).toEqual(1); - }); + ); + expect(model.featureTableId).toEqual(1); }); - it("selects feature table for feature ID textures", function () { - return loadAndZoomToModelAsync( + it("selects feature table for feature ID textures", async function () { + const model = await loadAndZoomToModelAsync( { gltf: microcosm, }, scene - ).then(function (model) { - expect(model.featureTableId).toEqual(0); - }); + ); + expect(model.featureTableId).toEqual(0); }); - it("selects feature table for feature ID attributes", function () { - return loadAndZoomToModelAsync( + it("selects feature table for feature ID attributes", async function () { + const model = await loadAndZoomToModelAsync( { gltf: buildingsMetadata, }, scene - ).then(function (model) { - expect(model.featureTableId).toEqual(0); - }); + ); + expect(model.featureTableId).toEqual(0); }); - it("featureIdLabel setter works", function () { - return loadAndZoomToModelAsync( + it("featureIdLabel setter works", async function () { + const model = await loadAndZoomToModelAsync( { gltf: buildingsMetadata, }, scene - ).then(function (model) { - expect(model.featureIdLabel).toBe("featureId_0"); - model.featureIdLabel = "buildings"; - expect(model.featureIdLabel).toBe("buildings"); - model.featureIdLabel = 1; - expect(model.featureIdLabel).toBe("featureId_1"); - }); + ); + expect(model.featureIdLabel).toBe("featureId_0"); + model.featureIdLabel = "buildings"; + expect(model.featureIdLabel).toBe("buildings"); + model.featureIdLabel = 1; + expect(model.featureIdLabel).toBe("featureId_1"); }); - it("instanceFeatureIdLabel setter works", function () { + it("instanceFeatureIdLabel setter works", async function () { if (webglStub) { return; } - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxInstanced, }, scene - ).then(function (model) { - expect(model.instanceFeatureIdLabel).toBe("instanceFeatureId_0"); - model.instanceFeatureIdLabel = "section"; - expect(model.instanceFeatureIdLabel).toBe("section"); - model.instanceFeatureIdLabel = 1; - expect(model.instanceFeatureIdLabel).toBe("instanceFeatureId_1"); - }); + ); + expect(model.instanceFeatureIdLabel).toBe("instanceFeatureId_0"); + model.instanceFeatureIdLabel = "section"; + expect(model.instanceFeatureIdLabel).toBe("section"); + model.instanceFeatureIdLabel = 1; + expect(model.instanceFeatureIdLabel).toBe("instanceFeatureId_1"); }); }); describe("model matrix", function () { - it("initializes with model matrix", function () { + it("initializes with model matrix", async function () { const translation = new Cartesian3(10, 0, 0); const transform = Matrix4.fromTranslation(translation); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, upAxis: Axis.Z, @@ -2153,106 +2070,99 @@ describe( modelMatrix: transform, }, scene - ).then(function (model) { - const sceneGraph = model.sceneGraph; - scene.renderForSpecs(); - expect(sceneGraph.computedModelMatrix).toEqual(transform); - expect(model.boundingSphere.center).toEqual(translation); - verifyRender(model, true); + ); + const sceneGraph = model.sceneGraph; + scene.renderForSpecs(); + expect(sceneGraph.computedModelMatrix).toEqual(transform); + expect(model.boundingSphere.center).toEqual(translation); + verifyRender(model, true); - expect(sceneGraph.computedModelMatrix).not.toBe(transform); - expect(model.modelMatrix).not.toBe(transform); - }); + expect(sceneGraph.computedModelMatrix).not.toBe(transform); + expect(model.modelMatrix).not.toBe(transform); }); - it("changing model matrix works", function () { + it("changing model matrix works", async function () { const translation = new Cartesian3(10, 0, 0); const updateModelMatrix = spyOn( ModelSceneGraph.prototype, "updateModelMatrix" ).and.callThrough(); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, upAxis: Axis.Z, forwardAxis: Axis.X }, scene - ).then(function (model) { - verifyRender(model, true); - const sceneGraph = model.sceneGraph; + ); + verifyRender(model, true); + const sceneGraph = model.sceneGraph; - const transform = Matrix4.fromTranslation(translation); - Matrix4.multiplyTransformation( - model.modelMatrix, - transform, - model.modelMatrix - ); - scene.renderForSpecs(); + const transform = Matrix4.fromTranslation(translation); + Matrix4.multiplyTransformation( + model.modelMatrix, + transform, + model.modelMatrix + ); + scene.renderForSpecs(); - expect(updateModelMatrix).toHaveBeenCalled(); - expect(sceneGraph.computedModelMatrix).toEqual(transform); + expect(updateModelMatrix).toHaveBeenCalled(); + expect(sceneGraph.computedModelMatrix).toEqual(transform); - // Keep the camera in-place to confirm that the model matrix moves the model out of view. - verifyRender(model, false, { - zoomToModel: false, - }); + // Keep the camera in-place to confirm that the model matrix moves the model out of view. + verifyRender(model, false, { + zoomToModel: false, }); }); - it("changing model matrix affects bounding sphere", function () { + it("changing model matrix affects bounding sphere", async function () { const translation = new Cartesian3(10, 0, 0); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, upAxis: Axis.Z, forwardAxis: Axis.X }, scene - ).then(function (model) { - const transform = Matrix4.fromTranslation(translation); - expect(model.boundingSphere.center).toEqual(Cartesian3.ZERO); + ); + const transform = Matrix4.fromTranslation(translation); + expect(model.boundingSphere.center).toEqual(Cartesian3.ZERO); - Matrix4.multiplyTransformation( - model.modelMatrix, - transform, - model.modelMatrix - ); - scene.renderForSpecs(); + Matrix4.multiplyTransformation( + model.modelMatrix, + transform, + model.modelMatrix + ); + scene.renderForSpecs(); - expect(model.boundingSphere.center).toEqual(translation); - }); + expect(model.boundingSphere.center).toEqual(translation); }); - it("changing model matrix in 2D mode works if projectTo2D is false", function () { - return loadAndZoomToModelAsync( + it("changing model matrix in 2D mode works if projectTo2D is false", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, modelMatrix: modelMatrix, }, scene2D - ).then(function (model) { - verifyRender(model, true, { - zoomToModel: false, - scene: scene2D, - }); - - model.modelMatrix = Matrix4.fromTranslation( - new Cartesian3(10, 10, 10) - ); - verifyRender(model, false, { - zoomToModel: false, - scene: scene2D, - }); + ); + verifyRender(model, true, { + zoomToModel: false, + scene: scene2D, + }); + + model.modelMatrix = Matrix4.fromTranslation(new Cartesian3(10, 10, 10)); + verifyRender(model, false, { + zoomToModel: false, + scene: scene2D, }); }); - it("changing model matrix in 2D mode throws if projectTo2D is true", function () { - return loadAndZoomToModelAsync( + it("changing model matrix in 2D mode throws if projectTo2D is true", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, modelMatrix: modelMatrix, projectTo2D: true, }, scene2D - ).then(function (model) { - expect(function () { - model.modelMatrix = Matrix4.IDENTITY; - scene2D.renderForSpecs(); - }).toThrowDeveloperError(); - }); + ); + expect(function () { + model.modelMatrix = Matrix4.IDENTITY; + scene2D.renderForSpecs(); + }).toThrowDeveloperError(); }); }); @@ -2605,175 +2515,167 @@ describe( }); describe("distance display condition", function () { - it("initializes with distance display condition", function () { + it("initializes with distance display condition", async function () { const near = 10.0; const far = 100.0; const condition = new DistanceDisplayCondition(near, far); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, distanceDisplayCondition: condition, }, scene - ).then(function (model) { - verifyRender(model, false); - }); + ); + verifyRender(model, false); }); - it("changing distance display condition works", function () { + it("changing distance display condition works", async function () { const near = 10.0; const far = 100.0; const condition = new DistanceDisplayCondition(near, far); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, }, scene - ).then(function (model) { - verifyRender(model, true); + ); + verifyRender(model, true); - model.distanceDisplayCondition = condition; - verifyRender(model, false); + model.distanceDisplayCondition = condition; + verifyRender(model, false); - model.distanceDisplayCondition = undefined; - verifyRender(model, true); - }); + model.distanceDisplayCondition = undefined; + verifyRender(model, true); }); - it("distanceDisplayCondition works with camera movement", function () { + it("distanceDisplayCondition works with camera movement", async function () { const near = 10.0; const far = 100.0; const condition = new DistanceDisplayCondition(near, far); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, }, scene - ).then(function (model) { - verifyRender(model, true); + ); + verifyRender(model, true); - // Model distance is smaller than near value, should not render - model.distanceDisplayCondition = condition; - verifyRender(model, false); + // Model distance is smaller than near value, should not render + model.distanceDisplayCondition = condition; + verifyRender(model, false); - const frameState = scene.frameState; + const frameState = scene.frameState; - // Model distance is between near and far values, should render - frameState.camera.lookAt( - Cartesian3.ZERO, - new HeadingPitchRange(0.0, 0.0, (far + near) * 0.5) - ); - verifyRender(model, true, { - zoomToModel: false, - }); - - // Model distance is greater than far value, should not render - frameState.camera.lookAt( - Cartesian3.ZERO, - new HeadingPitchRange(0.0, 0.0, far + 10.0) - ); - verifyRender(model, false, { - zoomToModel: false, - }); + // Model distance is between near and far values, should render + frameState.camera.lookAt( + Cartesian3.ZERO, + new HeadingPitchRange(0.0, 0.0, (far + near) * 0.5) + ); + verifyRender(model, true, { + zoomToModel: false, + }); + + // Model distance is greater than far value, should not render + frameState.camera.lookAt( + Cartesian3.ZERO, + new HeadingPitchRange(0.0, 0.0, far + 10.0) + ); + verifyRender(model, false, { + zoomToModel: false, }); }); - it("distanceDisplayCondition throws when near >= far", function () { + it("distanceDisplayCondition throws when near >= far", async function () { const near = 101.0; const far = 100.0; const condition = new DistanceDisplayCondition(near, far); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, }, scene - ).then(function (model) { - expect(function () { - model.distanceDisplayCondition = condition; - }).toThrowDeveloperError(); - }); + ); + expect(function () { + model.distanceDisplayCondition = condition; + }).toThrowDeveloperError(); }); }); describe("model color", function () { - it("initializes with model color", function () { - return loadAndZoomToModelAsync( + it("initializes with model color", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, color: Color.BLACK }, scene - ).then(function (model) { - verifyRender(model, false); - }); + ); + verifyRender(model, false); }); - it("changing model color works", function () { - return loadAndZoomToModelAsync( + it("changing model color works", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl }, scene - ).then(function (model) { - verifyRender(model, true); + ); + verifyRender(model, true); - model.color = Color.BLACK; - verifyRender(model, false); + model.color = Color.BLACK; + verifyRender(model, false); - model.color = Color.RED; - verifyRender(model, true); + model.color = Color.RED; + verifyRender(model, true); - model.color = undefined; - verifyRender(model, true); - }); + model.color = undefined; + verifyRender(model, true); }); - it("renders with translucent color", function () { + it("renders with translucent color", async function () { // This model gets clipped if log depth is disabled, so zoom out // the camera just a little const offset = new HeadingPitchRange(0, -CesiumMath.PI_OVER_FOUR, 2); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, offset: offset, }, scene - ).then(function (model) { - const renderOptions = { - scene: scene, - time: defaultDate, - }; - - let result; - expect(renderOptions).toRenderAndCall(function (rgba) { - result = rgba; - }); - - model.color = Color.fromAlpha(Color.WHITE, 0.5); - expect(renderOptions).toRenderAndCall(function (rgba) { - expect(rgba[0]).toBeLessThan(result[0]); - expect(rgba[1]).toBeLessThan(result[1]); - expect(rgba[2]).toBeLessThan(result[2]); - expect(rgba[3]).toBe(255); - }); + ); + const renderOptions = { + scene: scene, + time: defaultDate, + }; + + let result; + expect(renderOptions).toRenderAndCall(function (rgba) { + result = rgba; + }); + + model.color = Color.fromAlpha(Color.WHITE, 0.5); + expect(renderOptions).toRenderAndCall(function (rgba) { + expect(rgba[0]).toBeLessThan(result[0]); + expect(rgba[1]).toBeLessThan(result[1]); + expect(rgba[2]).toBeLessThan(result[2]); + expect(rgba[3]).toBe(255); }); }); - it("doesn't render invisible model", function () { + it("doesn't render invisible model", async function () { // This model gets clipped if log depth is disabled, so zoom out // the camera just a little const offset = new HeadingPitchRange(0, -CesiumMath.PI_OVER_FOUR, 2); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, color: Color.fromAlpha(Color.BLACK, 0.0), offset: offset, }, scene - ).then(function (model) { - verifyRender(model, false); + ); + verifyRender(model, false); - // No commands should have been submitted - const commands = scene.frameState.commandList; - expect(commands.length).toBe(0); - }); + // No commands should have been submitted + const commands = scene.frameState.commandList; + expect(commands.length).toBe(0); }); }); @@ -2809,8 +2711,8 @@ describe( // the camera just a little const offset = new HeadingPitchRange(0, -CesiumMath.PI_OVER_FOUR, 2); - it("initializes with ColorBlendMode.HIGHLIGHT", function () { - return loadAndZoomToModelAsync( + it("initializes with ColorBlendMode.HIGHLIGHT", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, offset: offset, @@ -2818,21 +2720,20 @@ describe( colorBlendMode: ColorBlendMode.HIGHLIGHT, }, scene - ).then(function (model) { - expect(model.colorBlendMode).toEqual(ColorBlendMode.HIGHLIGHT); + ); + expect(model.colorBlendMode).toEqual(ColorBlendMode.HIGHLIGHT); - const renderOptions = { - scene: scene, - time: defaultDate, - }; - expect(renderOptions).toRenderAndCall(function (rgba) { - verifyHighlightColor(rgba); - }); + const renderOptions = { + scene: scene, + time: defaultDate, + }; + expect(renderOptions).toRenderAndCall(function (rgba) { + verifyHighlightColor(rgba); }); }); - it("initializes with ColorBlendMode.REPLACE", function () { - return loadAndZoomToModelAsync( + it("initializes with ColorBlendMode.REPLACE", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, offset: offset, @@ -2840,21 +2741,20 @@ describe( colorBlendMode: ColorBlendMode.REPLACE, }, scene - ).then(function (model) { - expect(model.colorBlendMode).toEqual(ColorBlendMode.REPLACE); + ); + expect(model.colorBlendMode).toEqual(ColorBlendMode.REPLACE); - const renderOptions = { - scene: scene, - time: defaultDate, - }; - expect(renderOptions).toRenderAndCall(function (rgba) { - verifyReplaceColor(rgba); - }); + const renderOptions = { + scene: scene, + time: defaultDate, + }; + expect(renderOptions).toRenderAndCall(function (rgba) { + verifyReplaceColor(rgba); }); }); - it("initializes with ColorBlendMode.MIX", function () { - return loadAndZoomToModelAsync( + it("initializes with ColorBlendMode.MIX", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, offset: offset, @@ -2862,21 +2762,20 @@ describe( colorBlendMode: ColorBlendMode.MIX, }, scene - ).then(function (model) { - expect(model.colorBlendMode).toEqual(ColorBlendMode.MIX); + ); + expect(model.colorBlendMode).toEqual(ColorBlendMode.MIX); - const renderOptions = { - scene: scene, - time: defaultDate, - }; - expect(renderOptions).toRenderAndCall(function (rgba) { - verifyMixColor(rgba); - }); + const renderOptions = { + scene: scene, + time: defaultDate, + }; + expect(renderOptions).toRenderAndCall(function (rgba) { + verifyMixColor(rgba); }); }); - it("toggles colorBlendMode", function () { - return loadAndZoomToModelAsync( + it("toggles colorBlendMode", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, offset: offset, @@ -2884,30 +2783,29 @@ describe( colorBlendMode: ColorBlendMode.REPLACE, }, scene - ).then(function (model) { - expect(model.colorBlendMode).toEqual(ColorBlendMode.REPLACE); + ); + expect(model.colorBlendMode).toEqual(ColorBlendMode.REPLACE); - const renderOptions = { - scene: scene, - time: defaultDate, - }; - expect(renderOptions).toRenderAndCall(function (rgba) { - verifyReplaceColor(rgba); - }); + const renderOptions = { + scene: scene, + time: defaultDate, + }; + expect(renderOptions).toRenderAndCall(function (rgba) { + verifyReplaceColor(rgba); + }); - model.colorBlendMode = ColorBlendMode.HIGHLIGHT; - expect(model.colorBlendMode).toEqual(ColorBlendMode.HIGHLIGHT); + model.colorBlendMode = ColorBlendMode.HIGHLIGHT; + expect(model.colorBlendMode).toEqual(ColorBlendMode.HIGHLIGHT); - expect(renderOptions).toRenderAndCall(function (rgba) { - verifyHighlightColor(rgba); - }); + expect(renderOptions).toRenderAndCall(function (rgba) { + verifyHighlightColor(rgba); + }); - model.colorBlendMode = ColorBlendMode.MIX; - expect(model.colorBlendMode).toEqual(ColorBlendMode.MIX); + model.colorBlendMode = ColorBlendMode.MIX; + expect(model.colorBlendMode).toEqual(ColorBlendMode.MIX); - expect(renderOptions).toRenderAndCall(function (rgba) { - verifyMixColor(rgba); - }); + expect(renderOptions).toRenderAndCall(function (rgba) { + verifyMixColor(rgba); }); }); }); @@ -2917,8 +2815,8 @@ describe( // the camera just a little const offset = new HeadingPitchRange(0, -CesiumMath.PI_OVER_FOUR, 2); - it("initializes with colorBlendAmount", function () { - return loadAndZoomToModelAsync( + it("initializes with colorBlendAmount", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, offset: offset, @@ -2927,203 +2825,195 @@ describe( colorBlendAmount: 1.0, }, scene - ).then(function (model) { - expect(model.colorBlendAmount).toEqual(1.0); + ); + expect(model.colorBlendAmount).toEqual(1.0); - const renderOptions = { - scene: scene, - time: defaultDate, - }; - // colorBlendAmount = 1.0 is visually equivalent to - // ColorBlendMode.REPLACE - expect(renderOptions).toRenderAndCall(function (rgba) { - verifyReplaceColor(rgba); - }); + const renderOptions = { + scene: scene, + time: defaultDate, + }; + // colorBlendAmount = 1.0 is visually equivalent to + // ColorBlendMode.REPLACE + expect(renderOptions).toRenderAndCall(function (rgba) { + verifyReplaceColor(rgba); }); }); - it("changing colorBlendAmount works", function () { - return loadAndZoomToModelAsync( + it("changing colorBlendAmount works", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, offset: offset, }, scene - ).then(function (model) { - const renderOptions = { - scene: scene, - time: defaultDate, - }; - - let originalColor; - expect(renderOptions).toRenderAndCall(function (rgba) { - originalColor = rgba; - }); - - model.color = Color.RED; - model.colorBlendMode = ColorBlendMode.MIX; - model.colorBlendAmount = 1.0; - expect(model.colorBlendAmount).toEqual(1.0); - - // colorBlendAmount = 1.0 is visually equivalent to - // ColorBlendMode.REPLACE - expect(renderOptions).toRenderAndCall(function (rgba) { - verifyReplaceColor(rgba); - }); - - model.colorBlendAmount = 0.5; - expect(model.colorBlendAmount).toEqual(0.5); - expect(renderOptions).toRenderAndCall(function (rgba) { - verifyMixColor(rgba); - }); - - model.colorBlendAmount = 0.0; - expect(model.colorBlendAmount).toEqual(0.0); - // colorBlendAmount = 0.0 is visually equivalent to - // having no color applied to the model. - expect(renderOptions).toRenderAndCall(function (rgba) { - expect(rgba[0]).toEqual(originalColor[0]); - expect(rgba[1]).toEqual(originalColor[1]); - expect(rgba[2]).toEqual(originalColor[2]); - expect(rgba[3]).toEqual(originalColor[3]); - }); + ); + const renderOptions = { + scene: scene, + time: defaultDate, + }; + + let originalColor; + expect(renderOptions).toRenderAndCall(function (rgba) { + originalColor = rgba; + }); + + model.color = Color.RED; + model.colorBlendMode = ColorBlendMode.MIX; + model.colorBlendAmount = 1.0; + expect(model.colorBlendAmount).toEqual(1.0); + + // colorBlendAmount = 1.0 is visually equivalent to + // ColorBlendMode.REPLACE + expect(renderOptions).toRenderAndCall(function (rgba) { + verifyReplaceColor(rgba); + }); + + model.colorBlendAmount = 0.5; + expect(model.colorBlendAmount).toEqual(0.5); + expect(renderOptions).toRenderAndCall(function (rgba) { + verifyMixColor(rgba); + }); + + model.colorBlendAmount = 0.0; + expect(model.colorBlendAmount).toEqual(0.0); + // colorBlendAmount = 0.0 is visually equivalent to + // having no color applied to the model. + expect(renderOptions).toRenderAndCall(function (rgba) { + expect(rgba[0]).toEqual(originalColor[0]); + expect(rgba[1]).toEqual(originalColor[1]); + expect(rgba[2]).toEqual(originalColor[2]); + expect(rgba[3]).toEqual(originalColor[3]); }); }); }); describe("silhouette", function () { - it("initializes with silhouette size", function () { - return loadAndZoomToModelAsync( + it("initializes with silhouette size", async function () { + await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, silhouetteSize: 1.0 }, scene - ).then(function (model) { - const commands = scene.frameState.commandList; - scene.renderForSpecs(); - expect(commands.length).toBe(2); - expect(commands[0].renderState.stencilTest.enabled).toBe(true); - expect(commands[0].pass).toBe(Pass.OPAQUE); - expect(commands[1].renderState.stencilTest.enabled).toBe(true); - expect(commands[1].pass).toBe(Pass.OPAQUE); - }); + ); + const commands = scene.frameState.commandList; + scene.renderForSpecs(); + expect(commands.length).toBe(2); + expect(commands[0].renderState.stencilTest.enabled).toBe(true); + expect(commands[0].pass).toBe(Pass.OPAQUE); + expect(commands[1].renderState.stencilTest.enabled).toBe(true); + expect(commands[1].pass).toBe(Pass.OPAQUE); }); - it("changing silhouette size works", function () { - return loadAndZoomToModelAsync( + it("changing silhouette size works", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl }, scene - ).then(function (model) { - const commands = scene.frameState.commandList; - scene.renderForSpecs(); - expect(commands.length).toBe(1); - expect(commands[0].renderState.stencilTest.enabled).toBe(false); - expect(commands[0].pass).toBe(Pass.OPAQUE); + ); + const commands = scene.frameState.commandList; + scene.renderForSpecs(); + expect(commands.length).toBe(1); + expect(commands[0].renderState.stencilTest.enabled).toBe(false); + expect(commands[0].pass).toBe(Pass.OPAQUE); - model.silhouetteSize = 1.0; - scene.renderForSpecs(); - expect(commands.length).toBe(2); - expect(commands[0].renderState.stencilTest.enabled).toBe(true); - expect(commands[0].pass).toBe(Pass.OPAQUE); - expect(commands[1].renderState.stencilTest.enabled).toBe(true); - expect(commands[1].pass).toBe(Pass.OPAQUE); + model.silhouetteSize = 1.0; + scene.renderForSpecs(); + expect(commands.length).toBe(2); + expect(commands[0].renderState.stencilTest.enabled).toBe(true); + expect(commands[0].pass).toBe(Pass.OPAQUE); + expect(commands[1].renderState.stencilTest.enabled).toBe(true); + expect(commands[1].pass).toBe(Pass.OPAQUE); - model.silhouetteSize = 0.0; - scene.renderForSpecs(); - expect(commands.length).toBe(1); - expect(commands[0].renderState.stencilTest.enabled).toBe(false); - expect(commands[0].pass).toBe(Pass.OPAQUE); - }); + model.silhouetteSize = 0.0; + scene.renderForSpecs(); + expect(commands.length).toBe(1); + expect(commands[0].renderState.stencilTest.enabled).toBe(false); + expect(commands[0].pass).toBe(Pass.OPAQUE); }); - it("silhouette works with translucent color", function () { - return loadAndZoomToModelAsync( + it("silhouette works with translucent color", async function () { + await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, silhouetteSize: 1.0, silhouetteColor: Color.fromAlpha(Color.GREEN, 0.5), }, scene - ).then(function (model) { - const commands = scene.frameState.commandList; - scene.renderForSpecs(); - expect(commands.length).toBe(2); - expect(commands[0].renderState.stencilTest.enabled).toBe(true); - expect(commands[0].pass).toBe(Pass.OPAQUE); - expect(commands[1].renderState.stencilTest.enabled).toBe(true); - expect(commands[1].pass).toBe(Pass.TRANSLUCENT); - }); + ); + const commands = scene.frameState.commandList; + scene.renderForSpecs(); + expect(commands.length).toBe(2); + expect(commands[0].renderState.stencilTest.enabled).toBe(true); + expect(commands[0].pass).toBe(Pass.OPAQUE); + expect(commands[1].renderState.stencilTest.enabled).toBe(true); + expect(commands[1].pass).toBe(Pass.TRANSLUCENT); }); - it("silhouette is disabled by invisible color", function () { - return loadAndZoomToModelAsync( + it("silhouette is disabled by invisible color", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, silhouetteSize: 1.0 }, scene - ).then(function (model) { - const commands = scene.frameState.commandList; - scene.renderForSpecs(); - expect(commands.length).toBe(2); - expect(commands[0].renderState.stencilTest.enabled).toBe(true); - expect(commands[0].pass).toBe(Pass.OPAQUE); - expect(commands[1].renderState.stencilTest.enabled).toBe(true); - expect(commands[1].pass).toBe(Pass.OPAQUE); + ); + const commands = scene.frameState.commandList; + scene.renderForSpecs(); + expect(commands.length).toBe(2); + expect(commands[0].renderState.stencilTest.enabled).toBe(true); + expect(commands[0].pass).toBe(Pass.OPAQUE); + expect(commands[1].renderState.stencilTest.enabled).toBe(true); + expect(commands[1].pass).toBe(Pass.OPAQUE); - model.silhouetteColor = Color.fromAlpha(Color.GREEN, 0.0); - scene.renderForSpecs(); - expect(commands.length).toBe(1); - expect(commands[0].renderState.stencilTest.enabled).toBe(false); - expect(commands[0].pass).toBe(Pass.OPAQUE); - }); + model.silhouetteColor = Color.fromAlpha(Color.GREEN, 0.0); + scene.renderForSpecs(); + expect(commands.length).toBe(1); + expect(commands[0].renderState.stencilTest.enabled).toBe(false); + expect(commands[0].pass).toBe(Pass.OPAQUE); }); - it("silhouette works for invisible model", function () { - return loadAndZoomToModelAsync( + it("silhouette works for invisible model", async function () { + await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, silhouetteSize: 1.0, color: Color.fromAlpha(Color.WHITE, 0.0), }, scene - ).then(function (model) { - const commands = scene.frameState.commandList; - scene.renderForSpecs(); - expect(commands.length).toBe(2); - expect(commands[0].renderState.colorMask).toEqual({ - red: false, - green: false, - blue: false, - alpha: false, - }); - expect(commands[0].renderState.depthMask).toEqual(false); - expect(commands[0].renderState.stencilTest.enabled).toBe(true); - expect(commands[0].pass).toBe(Pass.TRANSLUCENT); - expect(commands[1].renderState.stencilTest.enabled).toBe(true); - expect(commands[1].pass).toBe(Pass.TRANSLUCENT); - }); - }); - - it("silhouette works for translucent model", function () { - return loadAndZoomToModelAsync( + ); + const commands = scene.frameState.commandList; + scene.renderForSpecs(); + expect(commands.length).toBe(2); + expect(commands[0].renderState.colorMask).toEqual({ + red: false, + green: false, + blue: false, + alpha: false, + }); + expect(commands[0].renderState.depthMask).toEqual(false); + expect(commands[0].renderState.stencilTest.enabled).toBe(true); + expect(commands[0].pass).toBe(Pass.TRANSLUCENT); + expect(commands[1].renderState.stencilTest.enabled).toBe(true); + expect(commands[1].pass).toBe(Pass.TRANSLUCENT); + }); + + it("silhouette works for translucent model", async function () { + await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, silhouetteSize: 1.0, color: Color.fromAlpha(Color.WHITE, 0.5), }, scene - ).then(function (model) { - const commands = scene.frameState.commandList; - scene.renderForSpecs(); - expect(commands.length).toBe(2); - - // Even though the silhouette color is opaque, the silhouette - // needs to be placed in the translucent pass. - expect(commands[0].renderState.stencilTest.enabled).toBe(true); - expect(commands[0].pass).toBe(Pass.TRANSLUCENT); - expect(commands[1].renderState.stencilTest.enabled).toBe(true); - expect(commands[1].pass).toBe(Pass.TRANSLUCENT); - }); + ); + const commands = scene.frameState.commandList; + scene.renderForSpecs(); + expect(commands.length).toBe(2); + + // Even though the silhouette color is opaque, the silhouette + // needs to be placed in the translucent pass. + expect(commands[0].renderState.stencilTest.enabled).toBe(true); + expect(commands[0].pass).toBe(Pass.TRANSLUCENT); + expect(commands[1].renderState.stencilTest.enabled).toBe(true); + expect(commands[1].pass).toBe(Pass.TRANSLUCENT); }); - it("silhouette works for translucent model and translucent silhouette color", function () { - return loadAndZoomToModelAsync( + it("silhouette works for translucent model and translucent silhouette color", async function () { + await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, silhouetteSize: 1.0, @@ -3131,91 +3021,85 @@ describe( silhouetteColor: Color.fromAlpha(Color.RED, 0.5), }, scene - ).then(function (model) { - const commands = scene.frameState.commandList; - scene.renderForSpecs(); - expect(commands.length).toBe(2); + ); + const commands = scene.frameState.commandList; + scene.renderForSpecs(); + expect(commands.length).toBe(2); - expect(commands[0].renderState.stencilTest.enabled).toBe(true); - expect(commands[0].pass).toBe(Pass.TRANSLUCENT); - expect(commands[1].renderState.stencilTest.enabled).toBe(true); - expect(commands[1].pass).toBe(Pass.TRANSLUCENT); - }); + expect(commands[0].renderState.stencilTest.enabled).toBe(true); + expect(commands[0].pass).toBe(Pass.TRANSLUCENT); + expect(commands[1].renderState.stencilTest.enabled).toBe(true); + expect(commands[1].pass).toBe(Pass.TRANSLUCENT); }); - it("silhouette works for multiple models", function () { - return loadAndZoomToModelAsync( + it("silhouette works for multiple models", async function () { + await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, silhouetteSize: 1.0, }, scene - ).then(function (model) { - return loadAndZoomToModelAsync( - { - gltf: boxTexturedGltfUrl, - silhouetteSize: 1.0, - }, - scene - ).then(function (model2) { - const commands = scene.frameState.commandList; - scene.renderForSpecs(); - const length = commands.length; - expect(length).toBe(4); - for (let i = 0; i < length; i++) { - const command = commands[i]; - expect(command.renderState.stencilTest.enabled).toBe(true); - expect(command.pass).toBe(Pass.OPAQUE); - } + ); + await loadAndZoomToModelAsync( + { + gltf: boxTexturedGltfUrl, + silhouetteSize: 1.0, + }, + scene + ); + const commands = scene.frameState.commandList; + scene.renderForSpecs(); + expect(commands.length).toBe(4); + for (let i = 0; i < commands.length; i++) { + const command = commands[i]; + expect(command.renderState.stencilTest.enabled).toBe(true); + expect(command.pass).toBe(Pass.OPAQUE); + } - const reference1 = commands[0].renderState.stencilTest.reference; - const reference2 = commands[2].renderState.stencilTest.reference; - expect(reference2).toEqual(reference1 + 1); - }); - }); + const reference1 = commands[0].renderState.stencilTest.reference; + const reference2 = commands[2].renderState.stencilTest.reference; + expect(reference2).toEqual(reference1 + 1); }); }); describe("light color", function () { - it("initializes with light color", function () { - return loadAndZoomToModelAsync( + it("initializes with light color", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, lightColor: Cartesian3.ZERO }, scene - ).then(function (model) { - verifyRender(model, false); - }); + ); + verifyRender(model, false); }); - it("changing light color works", function () { - return loadAndZoomToModelAsync( + it("changing light color works", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl }, scene - ).then(function (model) { - model.lightColor = Cartesian3.ZERO; - verifyRender(model, false); + ); + model.lightColor = Cartesian3.ZERO; + verifyRender(model, false); - model.lightColor = new Cartesian3(1.0, 0.0, 0.0); - verifyRender(model, true); + model.lightColor = new Cartesian3(1.0, 0.0, 0.0); + verifyRender(model, true); - model.lightColor = undefined; - verifyRender(model, true); - }); + model.lightColor = undefined; + verifyRender(model, true); }); - it("light color doesn't affect unlit models", function () { - return loadAndZoomToModelAsync({ gltf: boxUnlitUrl }, scene).then( - function (model) { - const options = { - zoomToModel: false, - }; - // Move the camera to face one of the two boxes. - scene.camera.moveRight(1.0); - verifyRender(model, true, options); + it("light color doesn't affect unlit models", async function () { + const model = await loadAndZoomToModelAsync( + { gltf: boxUnlitUrl }, + scene + ); + const options = { + zoomToModel: false, + }; + // Move the camera to face one of the two boxes. + scene.camera.moveRight(1.0); + verifyRender(model, true, options); - model.lightColor = Cartesian3.ZERO; - verifyRender(model, true, options); - } - ); + model.lightColor = Cartesian3.ZERO; + verifyRender(model, true, options); }); }); @@ -3224,68 +3108,65 @@ describe( scene.highDynamicRange = false; }); - it("initializes with imageBasedLighting", function () { + it("initializes with imageBasedLighting", async function () { const ibl = new ImageBasedLighting({ imageBasedLightingFactor: Cartesian2.ZERO, luminanceAtZenith: 0.5, }); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, imageBasedLighting: ibl }, scene - ).then(function (model) { - expect(model.imageBasedLighting).toBe(ibl); - }); + ); + expect(model.imageBasedLighting).toBe(ibl); }); - it("creates default imageBasedLighting", function () { - return loadAndZoomToModelAsync( + it("creates default imageBasedLighting", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl }, scene - ).then(function (model) { - const imageBasedLighting = model.imageBasedLighting; - expect(imageBasedLighting).toBeDefined(); - expect( - Cartesian2.equals( - imageBasedLighting.imageBasedLightingFactor, - new Cartesian2(1, 1) - ) - ).toBe(true); - expect(imageBasedLighting.luminanceAtZenith).toBe(0.2); - expect( - imageBasedLighting.sphericalHarmonicCoefficients - ).toBeUndefined(); - expect(imageBasedLighting.specularEnvironmentMaps).toBeUndefined(); - }); + ); + const imageBasedLighting = model.imageBasedLighting; + expect(imageBasedLighting).toBeDefined(); + expect( + Cartesian2.equals( + imageBasedLighting.imageBasedLightingFactor, + new Cartesian2(1, 1) + ) + ).toBe(true); + expect(imageBasedLighting.luminanceAtZenith).toBe(0.2); + expect( + imageBasedLighting.sphericalHarmonicCoefficients + ).toBeUndefined(); + expect(imageBasedLighting.specularEnvironmentMaps).toBeUndefined(); }); - it("changing imageBasedLighting works", function () { + it("changing imageBasedLighting works", async function () { const imageBasedLighting = new ImageBasedLighting({ imageBasedLightingFactor: Cartesian2.ZERO, }); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl }, scene - ).then(function (model) { - const renderOptions = { - scene: scene, - time: defaultDate, - }; - - let result; - verifyRender(model, true); - expect(renderOptions).toRenderAndCall(function (rgba) { - result = rgba; - }); - - model.imageBasedLighting = imageBasedLighting; - expect(renderOptions).toRenderAndCall(function (rgba) { - expect(rgba).not.toEqual(result); - }); + ); + const renderOptions = { + scene: scene, + time: defaultDate, + }; + + let result; + verifyRender(model, true); + expect(renderOptions).toRenderAndCall(function (rgba) { + result = rgba; + }); + + model.imageBasedLighting = imageBasedLighting; + expect(renderOptions).toRenderAndCall(function (rgba) { + expect(rgba).not.toEqual(result); }); }); - it("changing imageBasedLightingFactor works", function () { - return loadAndZoomToModelAsync( + it("changing imageBasedLightingFactor works", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, imageBasedLighting: new ImageBasedLighting({ @@ -3293,28 +3174,27 @@ describe( }), }, scene - ).then(function (model) { - const renderOptions = { - scene: scene, - time: defaultDate, - }; - - let result; - verifyRender(model, true); - expect(renderOptions).toRenderAndCall(function (rgba) { - result = rgba; - }); - - const ibl = model.imageBasedLighting; - ibl.imageBasedLightingFactor = new Cartesian2(1, 1); - expect(renderOptions).toRenderAndCall(function (rgba) { - expect(rgba).not.toEqual(result); - }); + ); + const renderOptions = { + scene: scene, + time: defaultDate, + }; + + let result; + verifyRender(model, true); + expect(renderOptions).toRenderAndCall(function (rgba) { + result = rgba; + }); + + const ibl = model.imageBasedLighting; + ibl.imageBasedLightingFactor = new Cartesian2(1, 1); + expect(renderOptions).toRenderAndCall(function (rgba) { + expect(rgba).not.toEqual(result); }); }); - it("changing luminanceAtZenith works", function () { - return loadAndZoomToModelAsync( + it("changing luminanceAtZenith works", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, imageBasedLighting: new ImageBasedLighting({ @@ -3322,27 +3202,26 @@ describe( }), }, scene - ).then(function (model) { - const renderOptions = { - scene: scene, - time: defaultDate, - }; - - let result; - verifyRender(model, true); - expect(renderOptions).toRenderAndCall(function (rgba) { - result = rgba; - }); - - const ibl = model.imageBasedLighting; - ibl.luminanceAtZenith = 0.2; - expect(renderOptions).toRenderAndCall(function (rgba) { - expect(rgba).not.toEqual(result); - }); + ); + const renderOptions = { + scene: scene, + time: defaultDate, + }; + + let result; + verifyRender(model, true); + expect(renderOptions).toRenderAndCall(function (rgba) { + result = rgba; + }); + + const ibl = model.imageBasedLighting; + ibl.luminanceAtZenith = 0.2; + expect(renderOptions).toRenderAndCall(function (rgba) { + expect(rgba).not.toEqual(result); }); }); - it("changing sphericalHarmonicCoefficients works", function () { + it("changing sphericalHarmonicCoefficients works", async function () { if (!scene.highDynamicRangeSupported) { return; } @@ -3392,7 +3271,7 @@ describe( 0.121102528320197 ); // L22, irradiance, pre-scaled base const coefficients = [L00, L1_1, L10, L11, L2_2, L2_1, L20, L21, L22]; - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, imageBasedLighting: new ImageBasedLighting({ @@ -3400,34 +3279,33 @@ describe( }), }, scene - ).then(function (model) { - scene.highDynamicRange = true; + ); + scene.highDynamicRange = true; - const renderOptions = { - scene: scene, - time: defaultDate, - }; - - let result; - verifyRender(model, true); - expect(renderOptions).toRenderAndCall(function (rgba) { - result = rgba; - }); - - const ibl = model.imageBasedLighting; - ibl.sphericalHarmonicCoefficients = undefined; - expect(renderOptions).toRenderAndCall(function (rgba) { - expect(rgba).not.toEqual(result); - }); + const renderOptions = { + scene: scene, + time: defaultDate, + }; + + let result; + verifyRender(model, true); + expect(renderOptions).toRenderAndCall(function (rgba) { + result = rgba; + }); + + const ibl = model.imageBasedLighting; + ibl.sphericalHarmonicCoefficients = undefined; + expect(renderOptions).toRenderAndCall(function (rgba) { + expect(rgba).not.toEqual(result); }); }); - it("changing specularEnvironmentMaps works", function () { + it("changing specularEnvironmentMaps works", async function () { if (!scene.highDynamicRangeSupported) { return; } const url = "./Data/EnvironmentMap/kiara_6_afternoon_2k_ibl.ktx2"; - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boomBoxUrl, scale: 10.0, @@ -3436,56 +3314,53 @@ describe( }), }, scene - ).then(function (model) { - const ibl = model.imageBasedLighting; + ); + const ibl = model.imageBasedLighting; - return pollToPromise(function () { - scene.render(); - return ( - defined(ibl.specularEnvironmentMapAtlas) && - ibl.specularEnvironmentMapAtlas.ready - ); - }).then(function () { - scene.highDynamicRange = true; + await pollToPromise(function () { + scene.render(); + return ( + defined(ibl.specularEnvironmentMapAtlas) && + ibl.specularEnvironmentMapAtlas.ready + ); + }); + scene.highDynamicRange = true; - const renderOptions = { - scene: scene, - time: defaultDate, - }; + const renderOptions = { + scene: scene, + time: defaultDate, + }; - let result; - verifyRender(model, true); - expect(renderOptions).toRenderAndCall(function (rgba) { - result = rgba; - }); - - ibl.specularEnvironmentMaps = undefined; - expect(renderOptions).toRenderAndCall(function (rgba) { - expect(rgba).not.toEqual(result); - }); - }); + let result; + verifyRender(model, true); + expect(renderOptions).toRenderAndCall(function (rgba) { + result = rgba; + }); + + ibl.specularEnvironmentMaps = undefined; + expect(renderOptions).toRenderAndCall(function (rgba) { + expect(rgba).not.toEqual(result); }); }); - it("renders when specularEnvironmentMaps aren't supported", function () { + it("renders when specularEnvironmentMaps aren't supported", async function () { spyOn(OctahedralProjectedCubeMap, "isSupported").and.returnValue(false); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boomBoxUrl, scale: 10.0, }, scene - ).then(function (model) { - expect(scene.specularEnvironmentMapsSupported).toBe(false); - verifyRender(model, true); - }); + ); + expect(scene.specularEnvironmentMapsSupported).toBe(false); + verifyRender(model, true); }); }); describe("scale", function () { - it("initializes with scale", function () { - return loadAndZoomToModelAsync( + it("initializes with scale", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, upAxis: Axis.Z, @@ -3493,173 +3368,158 @@ describe( scale: 0.0, }, scene - ).then(function (model) { - scene.renderForSpecs(); + ); + scene.renderForSpecs(); - verifyRender(model, false); - expect(model.boundingSphere.center).toEqual(Cartesian3.ZERO); - expect(model.boundingSphere.radius).toEqual(0.0); - }); + verifyRender(model, false); + expect(model.boundingSphere.center).toEqual(Cartesian3.ZERO); + expect(model.boundingSphere.radius).toEqual(0.0); }); - it("changing scale works", function () { + it("changing scale works", async function () { const updateModelMatrix = spyOn( ModelSceneGraph.prototype, "updateModelMatrix" ).and.callThrough(); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, upAxis: Axis.Z, forwardAxis: Axis.X, }, scene - ).then(function (model) { - verifyRender(model, true); - model.scale = 0.0; - scene.renderForSpecs(); - expect(updateModelMatrix).toHaveBeenCalled(); - verifyRender(model, false); + ); + verifyRender(model, true); + model.scale = 0.0; + scene.renderForSpecs(); + expect(updateModelMatrix).toHaveBeenCalled(); + verifyRender(model, false); - model.scale = 1.0; - scene.renderForSpecs(); - expect(updateModelMatrix).toHaveBeenCalled(); - verifyRender(model, true); - }); + model.scale = 1.0; + scene.renderForSpecs(); + expect(updateModelMatrix).toHaveBeenCalled(); + verifyRender(model, true); }); - it("changing scale affects bounding sphere", function () { + it("changing scale affects bounding sphere", async function () { const resource = Resource.createIfNeeded(boxTexturedGlbUrl); - const loadPromise = resource.fetchArrayBuffer(); - return loadPromise.then(function (buffer) { - return loadAndZoomToModelAsync( - { - gltf: new Uint8Array(buffer), - scale: 10, - }, - scene - ).then(function (model) { - scene.renderForSpecs(); - - const expectedRadius = 0.866; - const boundingSphere = model.boundingSphere; - expect(boundingSphere.center).toEqual(Cartesian3.ZERO); - expect(boundingSphere.radius).toEqualEpsilon( - expectedRadius * 10.0, - CesiumMath.EPSILON3 - ); + const buffer = await resource.fetchArrayBuffer(); + const model = await loadAndZoomToModelAsync( + { + gltf: new Uint8Array(buffer), + scale: 10, + }, + scene + ); + scene.renderForSpecs(); - model.scale = 0.0; - scene.renderForSpecs(); - expect(boundingSphere.center).toEqual(Cartesian3.ZERO); - expect(boundingSphere.radius).toEqual(0.0); - - model.scale = 1.0; - scene.renderForSpecs(); - expect(boundingSphere.center).toEqual(Cartesian3.ZERO); - expect(boundingSphere.radius).toEqualEpsilon( - expectedRadius, - CesiumMath.EPSILON3 - ); - }); - }); + const expectedRadius = 0.866; + const boundingSphere = model.boundingSphere; + expect(boundingSphere.center).toEqual(Cartesian3.ZERO); + expect(boundingSphere.radius).toEqualEpsilon( + expectedRadius * 10.0, + CesiumMath.EPSILON3 + ); + + model.scale = 0.0; + scene.renderForSpecs(); + expect(boundingSphere.center).toEqual(Cartesian3.ZERO); + expect(boundingSphere.radius).toEqual(0.0); + + model.scale = 1.0; + scene.renderForSpecs(); + expect(boundingSphere.center).toEqual(Cartesian3.ZERO); + expect(boundingSphere.radius).toEqualEpsilon( + expectedRadius, + CesiumMath.EPSILON3 + ); }); - it("changing scale affects bounding sphere for uncentered models", function () { + it("changing scale affects bounding sphere for uncentered models", async function () { const resource = Resource.createIfNeeded(boxWithOffsetUrl); - const loadPromise = resource.fetchArrayBuffer(); - return loadPromise.then(function (buffer) { - return loadAndZoomToModelAsync( - { - gltf: new Uint8Array(buffer), - scale: 10, - }, - scene - ).then(function (model) { - const expectedRadius = 0.866; - const expectedCenter = new Cartesian3(5.0, 0.0, 0.0); - const expectedTranslation = Matrix4.fromTranslation(expectedCenter); - const axisCorrectionMatrix = ModelUtility.getAxisCorrectionMatrix( - Axis.Y, - Axis.Z, - new Matrix4() - ); - Matrix4.multiplyTransformation( - axisCorrectionMatrix, - expectedTranslation, - expectedTranslation - ); - Matrix4.getTranslation(expectedTranslation, expectedCenter); - - const boundingSphere = model.boundingSphere; - expect(boundingSphere.center).toEqual( - Cartesian3.multiplyByScalar( - expectedCenter, - 10.0, - new Cartesian3() - ) - ); - expect(boundingSphere.radius).toEqualEpsilon( - expectedRadius * 10.0, - CesiumMath.EPSILON3 - ); + const buffer = await resource.fetchArrayBuffer(); + const model = await loadAndZoomToModelAsync( + { + gltf: new Uint8Array(buffer), + scale: 10, + }, + scene + ); + const expectedRadius = 0.866; + const expectedCenter = new Cartesian3(5.0, 0.0, 0.0); + const expectedTranslation = Matrix4.fromTranslation(expectedCenter); + const axisCorrectionMatrix = ModelUtility.getAxisCorrectionMatrix( + Axis.Y, + Axis.Z, + new Matrix4() + ); + Matrix4.multiplyTransformation( + axisCorrectionMatrix, + expectedTranslation, + expectedTranslation + ); + Matrix4.getTranslation(expectedTranslation, expectedCenter); - model.scale = 0.0; - scene.renderForSpecs(); - expect(boundingSphere.center).toEqual(Cartesian3.ZERO); - expect(boundingSphere.radius).toEqual(0.0); - - model.scale = 1.0; - scene.renderForSpecs(); - expect(boundingSphere.center).toEqual(expectedCenter); - expect(boundingSphere.radius).toEqualEpsilon( - expectedRadius, - CesiumMath.EPSILON3 - ); - }); - }); + const boundingSphere = model.boundingSphere; + expect(boundingSphere.center).toEqual( + Cartesian3.multiplyByScalar(expectedCenter, 10.0, new Cartesian3()) + ); + expect(boundingSphere.radius).toEqualEpsilon( + expectedRadius * 10.0, + CesiumMath.EPSILON3 + ); + + model.scale = 0.0; + scene.renderForSpecs(); + expect(boundingSphere.center).toEqual(Cartesian3.ZERO); + expect(boundingSphere.radius).toEqual(0.0); + + model.scale = 1.0; + scene.renderForSpecs(); + expect(boundingSphere.center).toEqual(expectedCenter); + expect(boundingSphere.radius).toEqualEpsilon( + expectedRadius, + CesiumMath.EPSILON3 + ); }); }); describe("minimumPixelSize", function () { - it("initializes with minimumPixelSize", function () { + it("initializes with minimumPixelSize", async function () { const resource = Resource.createIfNeeded(boxTexturedGlbUrl); - const loadPromise = resource.fetchArrayBuffer(); - return loadPromise.then(function (buffer) { - return loadAndZoomToModelAsync( - { - gltf: new Uint8Array(buffer), - upAxis: Axis.Z, - forwardAxis: Axis.X, - minimumPixelSize: 1, - offset: new HeadingPitchRange(0, 0, 500), - }, - scene - ).then(function (model) { - const renderOptions = { - zoomToModel: false, - }; + const buffer = await resource.fetchArrayBuffer(); + const model = await loadAndZoomToModelAsync( + { + gltf: new Uint8Array(buffer), + upAxis: Axis.Z, + forwardAxis: Axis.X, + minimumPixelSize: 1, + offset: new HeadingPitchRange(0, 0, 500), + }, + scene + ); + const renderOptions = { + zoomToModel: false, + }; - const expectedRadius = 0.866; - scene.renderForSpecs(); - verifyRender(model, true, renderOptions); + const expectedRadius = 0.866; + scene.renderForSpecs(); + verifyRender(model, true, renderOptions); - // Verify that minimumPixelSize didn't affect other parameters - expect(model.scale).toEqual(1.0); - expect(model.boundingSphere.radius).toEqualEpsilon( - expectedRadius, - CesiumMath.EPSILON3 - ); - }); - }); + // Verify that minimumPixelSize didn't affect other parameters + expect(model.scale).toEqual(1.0); + expect(model.boundingSphere.radius).toEqualEpsilon( + expectedRadius, + CesiumMath.EPSILON3 + ); }); - it("changing minimumPixelSize works", function () { + it("changing minimumPixelSize works", async function () { const updateModelMatrix = spyOn( ModelSceneGraph.prototype, "updateModelMatrix" ).and.callThrough(); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, upAxis: Axis.Z, @@ -3668,33 +3528,32 @@ describe( offset: new HeadingPitchRange(0, 0, 500), }, scene - ).then(function (model) { - const renderOptions = { - zoomToModel: false, - }; + ); + const renderOptions = { + zoomToModel: false, + }; - scene.renderForSpecs(); - expect(updateModelMatrix).toHaveBeenCalled(); - verifyRender(model, true, renderOptions); + scene.renderForSpecs(); + expect(updateModelMatrix).toHaveBeenCalled(); + verifyRender(model, true, renderOptions); - model.minimumPixelSize = 0.0; - scene.renderForSpecs(); - expect(updateModelMatrix).toHaveBeenCalled(); - verifyRender(model, false, renderOptions); + model.minimumPixelSize = 0.0; + scene.renderForSpecs(); + expect(updateModelMatrix).toHaveBeenCalled(); + verifyRender(model, false, renderOptions); - model.minimumPixelSize = 1; - scene.renderForSpecs(); - expect(updateModelMatrix).toHaveBeenCalled(); - verifyRender(model, true, renderOptions); - }); + model.minimumPixelSize = 1; + scene.renderForSpecs(); + expect(updateModelMatrix).toHaveBeenCalled(); + verifyRender(model, true, renderOptions); }); - it("changing minimumPixelSize doesn't affect bounding sphere or scale", function () { + it("changing minimumPixelSize doesn't affect bounding sphere or scale", async function () { const updateModelMatrix = spyOn( ModelSceneGraph.prototype, "updateModelMatrix" ).and.callThrough(); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, upAxis: Axis.Z, @@ -3703,65 +3562,61 @@ describe( offset: new HeadingPitchRange(0, 0, 500), }, scene - ).then(function (model) { - const expectedRadius = 0.866; - scene.renderForSpecs(); - expect(updateModelMatrix).toHaveBeenCalled(); - expect(model.scale).toEqual(1.0); - expect(model.boundingSphere.radius).toEqualEpsilon( - expectedRadius, - CesiumMath.EPSILON3 - ); + ); + const expectedRadius = 0.866; + scene.renderForSpecs(); + expect(updateModelMatrix).toHaveBeenCalled(); + expect(model.scale).toEqual(1.0); + expect(model.boundingSphere.radius).toEqualEpsilon( + expectedRadius, + CesiumMath.EPSILON3 + ); - model.minimumPixelSize = 0.0; - scene.renderForSpecs(); - expect(updateModelMatrix).toHaveBeenCalled(); - expect(model.scale).toEqual(1.0); - expect(model.boundingSphere.radius).toEqualEpsilon( - expectedRadius, - CesiumMath.EPSILON3 - ); + model.minimumPixelSize = 0.0; + scene.renderForSpecs(); + expect(updateModelMatrix).toHaveBeenCalled(); + expect(model.scale).toEqual(1.0); + expect(model.boundingSphere.radius).toEqualEpsilon( + expectedRadius, + CesiumMath.EPSILON3 + ); - model.minimumPixelSize = 1; - scene.renderForSpecs(); - expect(updateModelMatrix).toHaveBeenCalled(); - expect(model.scale).toEqual(1.0); - expect(model.boundingSphere.radius).toEqualEpsilon( - expectedRadius, - CesiumMath.EPSILON3 - ); - }); + model.minimumPixelSize = 1; + scene.renderForSpecs(); + expect(updateModelMatrix).toHaveBeenCalled(); + expect(model.scale).toEqual(1.0); + expect(model.boundingSphere.radius).toEqualEpsilon( + expectedRadius, + CesiumMath.EPSILON3 + ); }); }); describe("maximumScale", function () { - it("initializes with maximumScale", function () { + it("initializes with maximumScale", async function () { const resource = Resource.createIfNeeded(boxTexturedGlbUrl); - const loadPromise = resource.fetchArrayBuffer(); - return loadPromise.then(function (buffer) { - return loadAndZoomToModelAsync( - { - gltf: new Uint8Array(buffer), - upAxis: Axis.Z, - forwardAxis: Axis.X, - maximumScale: 0.0, - }, - scene - ).then(function (model) { - scene.renderForSpecs(); - verifyRender(model, false); - expect(model.boundingSphere.center).toEqual(Cartesian3.ZERO); - expect(model.boundingSphere.radius).toEqual(0.0); - }); - }); + const buffer = await resource.fetchArrayBuffer(); + const model = await loadAndZoomToModelAsync( + { + gltf: new Uint8Array(buffer), + upAxis: Axis.Z, + forwardAxis: Axis.X, + maximumScale: 0.0, + }, + scene + ); + scene.renderForSpecs(); + verifyRender(model, false); + expect(model.boundingSphere.center).toEqual(Cartesian3.ZERO); + expect(model.boundingSphere.radius).toEqual(0.0); }); - it("changing maximumScale works", function () { + it("changing maximumScale works", async function () { const updateModelMatrix = spyOn( ModelSceneGraph.prototype, "updateModelMatrix" ).and.callThrough(); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, upAxis: Axis.Z, @@ -3769,180 +3624,169 @@ describe( scale: 2.0, }, scene - ).then(function (model) { - scene.renderForSpecs(); - verifyRender(model, true); + ); + scene.renderForSpecs(); + verifyRender(model, true); - model.maximumScale = 0.0; - scene.renderForSpecs(); - expect(updateModelMatrix).toHaveBeenCalled(); - verifyRender(model, false); + model.maximumScale = 0.0; + scene.renderForSpecs(); + expect(updateModelMatrix).toHaveBeenCalled(); + verifyRender(model, false); - model.maximumScale = 1.0; - scene.renderForSpecs(); - expect(updateModelMatrix).toHaveBeenCalled(); - verifyRender(model, true); - }); + model.maximumScale = 1.0; + scene.renderForSpecs(); + expect(updateModelMatrix).toHaveBeenCalled(); + verifyRender(model, true); }); - it("changing maximumScale affects bounding sphere", function () { + it("changing maximumScale affects bounding sphere", async function () { const resource = Resource.createIfNeeded(boxTexturedGlbUrl); - const loadPromise = resource.fetchArrayBuffer(); - return loadPromise.then(function (buffer) { - return loadAndZoomToModelAsync( - { - gltf: new Uint8Array(buffer), - scale: 20, - maximumScale: 10, - }, - scene - ).then(function (model) { - scene.renderForSpecs(); - - const expectedRadius = 0.866; - const boundingSphere = model.boundingSphere; - expect(boundingSphere.center).toEqual(Cartesian3.ZERO); - expect(boundingSphere.radius).toEqualEpsilon( - expectedRadius * 10.0, - CesiumMath.EPSILON3 - ); + const buffer = await resource.fetchArrayBuffer(); + const model = await loadAndZoomToModelAsync( + { + gltf: new Uint8Array(buffer), + scale: 20, + maximumScale: 10, + }, + scene + ); + scene.renderForSpecs(); - model.maximumScale = 0.0; - scene.renderForSpecs(); - expect(boundingSphere.center).toEqual(Cartesian3.ZERO); - expect(boundingSphere.radius).toEqual(0.0); - - model.maximumScale = 1.0; - scene.renderForSpecs(); - expect(boundingSphere.center).toEqual(Cartesian3.ZERO); - expect(boundingSphere.radius).toEqualEpsilon( - expectedRadius, - CesiumMath.EPSILON3 - ); - }); - }); + const expectedRadius = 0.866; + const boundingSphere = model.boundingSphere; + expect(boundingSphere.center).toEqual(Cartesian3.ZERO); + expect(boundingSphere.radius).toEqualEpsilon( + expectedRadius * 10.0, + CesiumMath.EPSILON3 + ); + + model.maximumScale = 0.0; + scene.renderForSpecs(); + expect(boundingSphere.center).toEqual(Cartesian3.ZERO); + expect(boundingSphere.radius).toEqual(0.0); + + model.maximumScale = 1.0; + scene.renderForSpecs(); + expect(boundingSphere.center).toEqual(Cartesian3.ZERO); + expect(boundingSphere.radius).toEqualEpsilon( + expectedRadius, + CesiumMath.EPSILON3 + ); }); - it("changing maximumScale affects minimumPixelSize", function () { + it("changing maximumScale affects minimumPixelSize", async function () { const resource = Resource.createIfNeeded(boxTexturedGlbUrl); - const loadPromise = resource.fetchArrayBuffer(); - return loadPromise.then(function (buffer) { - return loadAndZoomToModelAsync( - { - gltf: new Uint8Array(buffer), - minimumPixelSize: 1, - maximumScale: 10, - }, - scene - ).then(function (model) { - scene.renderForSpecs(); - - const expectedRadius = 0.866; - const boundingSphere = model.boundingSphere; - expect(boundingSphere.center).toEqual(Cartesian3.ZERO); - expect(boundingSphere.radius).toEqualEpsilon( - expectedRadius, - CesiumMath.EPSILON3 - ); + const buffer = await resource.fetchArrayBuffer(); + const model = await loadAndZoomToModelAsync( + { + gltf: new Uint8Array(buffer), + minimumPixelSize: 1, + maximumScale: 10, + }, + scene + ); + scene.renderForSpecs(); - model.maximumScale = 0.0; - scene.renderForSpecs(); - expect(boundingSphere.center).toEqual(Cartesian3.ZERO); - expect(boundingSphere.radius).toEqual(0.0); - - model.maximumScale = 10.0; - scene.renderForSpecs(); - expect(boundingSphere.center).toEqual(Cartesian3.ZERO); - expect(boundingSphere.radius).toEqualEpsilon( - expectedRadius, - CesiumMath.EPSILON3 - ); - }); - }); + const expectedRadius = 0.866; + const boundingSphere = model.boundingSphere; + expect(boundingSphere.center).toEqual(Cartesian3.ZERO); + expect(boundingSphere.radius).toEqualEpsilon( + expectedRadius, + CesiumMath.EPSILON3 + ); + + model.maximumScale = 0.0; + scene.renderForSpecs(); + expect(boundingSphere.center).toEqual(Cartesian3.ZERO); + expect(boundingSphere.radius).toEqual(0.0); + + model.maximumScale = 10.0; + scene.renderForSpecs(); + expect(boundingSphere.center).toEqual(Cartesian3.ZERO); + expect(boundingSphere.radius).toEqualEpsilon( + expectedRadius, + CesiumMath.EPSILON3 + ); }); }); - it("resets draw commands when vertical exaggeration changes", function () { - return loadAndZoomToModelAsync( + it("resets draw commands when vertical exaggeration changes", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, }, scene - ).then(function (model) { - const resetDrawCommands = spyOn( - model, - "resetDrawCommands" - ).and.callThrough(); - expect(model.ready).toBe(true); + ); + const resetDrawCommands = spyOn( + model, + "resetDrawCommands" + ).and.callThrough(); + expect(model.ready).toBe(true); - scene.verticalExaggeration = 2.0; - scene.renderForSpecs(); - expect(resetDrawCommands).toHaveBeenCalled(); - scene.verticalExaggeration = 1.0; - }); + scene.verticalExaggeration = 2.0; + scene.renderForSpecs(); + expect(resetDrawCommands).toHaveBeenCalled(); + scene.verticalExaggeration = 1.0; }); - it("does not issue draw commands when ignoreCommands is true", function () { - return loadAndZoomToModelAsync( + it("does not issue draw commands when ignoreCommands is true", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, }, scene - ).then(function (model) { - expect(model.ready).toBe(true); - model._ignoreCommands = true; + ); + expect(model.ready).toBe(true); + model._ignoreCommands = true; - scene.renderForSpecs(); - expect(scene.frameState.commandList.length).toEqual(0); - }); + scene.renderForSpecs(); + expect(scene.frameState.commandList.length).toEqual(0); }); describe("frustum culling ", function () { - it("enables frustum culling", function () { - return loadAndZoomToModelAsync( + it("enables frustum culling", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, cull: true, }, scene - ).then(function (model) { - expect(model.cull).toEqual(true); + ); + expect(model.cull).toEqual(true); - // Commands should be submitted while viewing the model. - scene.renderForSpecs(); - expect(scene.frustumCommandsList.length).toBeGreaterThan(0); + // Commands should be submitted while viewing the model. + scene.renderForSpecs(); + expect(scene.frustumCommandsList.length).toBeGreaterThan(0); - // Commands should not be submitted when model is out of view. - model.modelMatrix = Matrix4.fromTranslation( - new Cartesian3(100.0, 0.0, 0.0) - ); - scene.renderForSpecs(); - expect(scene.frustumCommandsList.length).toEqual(0); - }); + // Commands should not be submitted when model is out of view. + model.modelMatrix = Matrix4.fromTranslation( + new Cartesian3(100.0, 0.0, 0.0) + ); + scene.renderForSpecs(); + expect(scene.frustumCommandsList.length).toEqual(0); }); - it("disables frustum culling", function () { - return loadAndZoomToModelAsync( + it("disables frustum culling", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, cull: false, }, scene - ).then(function (model) { - expect(model.cull).toEqual(false); + ); + expect(model.cull).toEqual(false); - // Commands should be submitted while viewing the model. - scene.renderForSpecs(); - const length = scene.frustumCommandsList.length; - expect(length).toBeGreaterThan(0); + // Commands should be submitted while viewing the model. + scene.renderForSpecs(); + const length = scene.frustumCommandsList.length; + expect(length).toBeGreaterThan(0); - // Commands should still be submitted when model is out of view. - model.modelMatrix = Matrix4.fromTranslation( - new Cartesian3(0.0, 100.0, 0.0) - ); - scene.renderForSpecs(); - expect(scene.frustumCommandsList.length).toEqual(length); - }); + // Commands should still be submitted when model is out of view. + model.modelMatrix = Matrix4.fromTranslation( + new Cartesian3(0.0, 100.0, 0.0) + ); + scene.renderForSpecs(); + expect(scene.frustumCommandsList.length).toEqual(length); }); }); @@ -3955,80 +3799,76 @@ describe( 2.0 ); - it("enables back-face culling", function () { - return loadAndZoomToModelAsync( + it("enables back-face culling", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxBackFaceCullingUrl, backFaceCulling: true, offset: boxBackFaceCullingOffset, }, scene - ).then(function (model) { - verifyRender(model, false, { - zoomToModel: false, - }); + ); + verifyRender(model, false, { + zoomToModel: false, }); }); - it("disables back-face culling", function () { - return loadAndZoomToModelAsync( + it("disables back-face culling", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxBackFaceCullingUrl, backFaceCulling: false, offset: boxBackFaceCullingOffset, }, scene - ).then(function (model) { - verifyRender(model, true, { - zoomToModel: false, - }); + ); + verifyRender(model, true, { + zoomToModel: false, }); }); - it("ignores back-face culling when translucent", function () { - return loadAndZoomToModelAsync( + it("ignores back-face culling when translucent", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxBackFaceCullingUrl, backFaceCulling: true, offset: boxBackFaceCullingOffset, }, scene - ).then(function (model) { - verifyRender(model, false, { - zoomToModel: false, - }); + ); + verifyRender(model, false, { + zoomToModel: false, + }); - model.color = new Color(0, 0, 1.0, 0.5); + model.color = new Color(0, 0, 1.0, 0.5); - verifyRender(model, true, { - zoomToModel: false, - }); + verifyRender(model, true, { + zoomToModel: false, }); }); - it("toggles back-face culling at runtime", function () { - return loadAndZoomToModelAsync( + it("toggles back-face culling at runtime", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxBackFaceCullingUrl, backFaceCulling: false, offset: boxBackFaceCullingOffset, }, scene - ).then(function (model) { - verifyRender(model, true, { - zoomToModel: false, - }); + ); + verifyRender(model, true, { + zoomToModel: false, + }); - model.backFaceCulling = true; + model.backFaceCulling = true; - verifyRender(model, false, { - zoomToModel: false, - }); + verifyRender(model, false, { + zoomToModel: false, }); }); - it("ignores back-face culling toggles when translucent", function () { - return loadAndZoomToModelAsync( + it("ignores back-face culling toggles when translucent", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxBackFaceCullingUrl, backFaceCulling: false, @@ -4036,123 +3876,117 @@ describe( color: new Color(0, 0, 1.0, 0.5), }, scene - ).then(function (model) { - verifyRender(model, true, { - zoomToModel: false, - }); + ); + verifyRender(model, true, { + zoomToModel: false, + }); - model.backFaceCulling = true; + model.backFaceCulling = true; - verifyRender(model, true, { - zoomToModel: false, - }); + verifyRender(model, true, { + zoomToModel: false, + }); - model.backFaceCulling = false; + model.backFaceCulling = false; - verifyRender(model, true, { - zoomToModel: false, - }); + verifyRender(model, true, { + zoomToModel: false, }); }); }); - it("reverses winding order for negatively scaled models", function () { - return loadAndZoomToModelAsync( + it("reverses winding order for negatively scaled models", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, modelMatrix: Matrix4.fromUniformScale(-1.0), }, scene - ).then(function (model) { - const renderOptions = { - scene: scene, - time: defaultDate, - }; + ); + const renderOptions = { + scene: scene, + time: defaultDate, + }; - // The model should look the same whether it has -1.0 scale or 1.0 scale. - // The initial scale is -1.0. Test switching this at runtime. - let initialRgba; - expect(renderOptions).toRenderAndCall(function (rgba) { - initialRgba = rgba; - }); + // The model should look the same whether it has -1.0 scale or 1.0 scale. + // The initial scale is -1.0. Test switching this at runtime. + let initialRgba; + expect(renderOptions).toRenderAndCall(function (rgba) { + initialRgba = rgba; + }); - model.modelMatrix = Matrix4.IDENTITY; + model.modelMatrix = Matrix4.IDENTITY; - expect(renderOptions).toRenderAndCall(function (rgba) { - expect(rgba).toEqual(initialRgba); - }); + expect(renderOptions).toRenderAndCall(function (rgba) { + expect(rgba).toEqual(initialRgba); + }); - model.modelMatrix = Matrix4.fromUniformScale(-1.0); + model.modelMatrix = Matrix4.fromUniformScale(-1.0); - expect(renderOptions).toRenderAndCall(function (rgba) { - expect(rgba).toEqual(initialRgba); - }); + expect(renderOptions).toRenderAndCall(function (rgba) { + expect(rgba).toEqual(initialRgba); }); }); describe("clipping planes", function () { - it("throws when given clipping planes attached to another model", function () { + it("throws when given clipping planes attached to another model", async function () { const plane = new ClippingPlane(Cartesian3.UNIT_X, 0.0); const clippingPlanes = new ClippingPlaneCollection({ planes: [plane], }); - return loadAndZoomToModelAsync( + await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, clippingPlanes: clippingPlanes }, scene - ) - .then(function (model) { - return loadAndZoomToModelAsync({ gltf: boxTexturedGlbUrl }, scene); - }) - .then(function (model2) { - expect(function () { - model2.clippingPlanes = clippingPlanes; - }).toThrowDeveloperError(); - }); + ); + const model = await loadAndZoomToModelAsync( + { gltf: boxTexturedGlbUrl }, + scene + ); + expect(function () { + model.clippingPlanes = clippingPlanes; + }).toThrowDeveloperError(); }); - it("updates clipping planes when clipping planes are enabled", function () { + it("updates clipping planes when clipping planes are enabled", async function () { const plane = new ClippingPlane(Cartesian3.UNIT_X, 0.0); const clippingPlanes = new ClippingPlaneCollection({ planes: [plane], }); - return loadAndZoomToModelAsync({ gltf: boxTexturedGlbUrl }, scene).then( - function (model) { - const gl = scene.frameState.context._gl; - spyOn(gl, "texImage2D").and.callThrough(); - - scene.renderForSpecs(); - const callsBeforeClipping = gl.texImage2D.calls.count(); - - model.clippingPlanes = clippingPlanes; - scene.renderForSpecs(); - scene.renderForSpecs(); - // When clipping planes are created, we expect two calls to texImage2D - // (one for initial creation, and one for copying the data in) - // because clipping planes is stored inside a texture. - expect(gl.texImage2D.calls.count() - callsBeforeClipping).toEqual( - 2 - ); - } + const model = await loadAndZoomToModelAsync( + { gltf: boxTexturedGlbUrl }, + scene ); + const gl = scene.frameState.context._gl; + spyOn(gl, "texImage2D").and.callThrough(); + + scene.renderForSpecs(); + const callsBeforeClipping = gl.texImage2D.calls.count(); + + model.clippingPlanes = clippingPlanes; + scene.renderForSpecs(); + scene.renderForSpecs(); + // When clipping planes are created, we expect two calls to texImage2D + // (one for initial creation, and one for copying the data in) + // because clipping planes is stored inside a texture. + expect(gl.texImage2D.calls.count() - callsBeforeClipping).toEqual(2); }); - it("initializes and updates with clipping planes", function () { + it("initializes and updates with clipping planes", async function () { const plane = new ClippingPlane(Cartesian3.UNIT_X, -2.5); const clippingPlanes = new ClippingPlaneCollection({ planes: [plane], }); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, clippingPlanes: clippingPlanes }, scene - ).then(function (model) { - verifyRender(model, false); + ); + verifyRender(model, false); - model.clippingPlanes = undefined; - verifyRender(model, true); - }); + model.clippingPlanes = undefined; + verifyRender(model, true); }); - it("updating clipping planes properties works", function () { + it("updating clipping planes properties works", async function () { const direction = Cartesian3.multiplyByScalar( Cartesian3.UNIT_X, -1, @@ -4162,62 +3996,60 @@ describe( const clippingPlanes = new ClippingPlaneCollection({ planes: [plane], }); - return loadAndZoomToModelAsync({ gltf: boxTexturedGlbUrl }, scene).then( - function (model) { - let modelColor; - verifyRender(model, true); - expect(scene).toRenderAndCall(function (rgba) { - modelColor = rgba; - }); - - // The clipping plane should cut the model in half such that - // we see the back faces. - model.clippingPlanes = clippingPlanes; - expect(scene).toRenderAndCall(function (rgba) { - expect(rgba).not.toEqual(modelColor); - }); - - plane.distance = 10.0; // Move the plane away from the model - expect(scene).toRenderAndCall(function (rgba) { - expect(rgba).toEqual(modelColor); - }); - } + const model = await loadAndZoomToModelAsync( + { gltf: boxTexturedGlbUrl }, + scene ); + let modelColor; + verifyRender(model, true); + expect(scene).toRenderAndCall(function (rgba) { + modelColor = rgba; + }); + + // The clipping plane should cut the model in half such that + // we see the back faces. + model.clippingPlanes = clippingPlanes; + expect(scene).toRenderAndCall(function (rgba) { + expect(rgba).not.toEqual(modelColor); + }); + + plane.distance = 10.0; // Move the plane away from the model + expect(scene).toRenderAndCall(function (rgba) { + expect(rgba).toEqual(modelColor); + }); }); - it("removing clipping plane from collection works", function () { + it("removing clipping plane from collection works", async function () { const plane = new ClippingPlane(Cartesian3.UNIT_X, -2.5); const clippingPlanes = new ClippingPlaneCollection({ planes: [plane], }); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, clippingPlanes: clippingPlanes }, scene - ).then(function (model) { - verifyRender(model, false); + ); + verifyRender(model, false); - clippingPlanes.removeAll(); - verifyRender(model, true); - }); + clippingPlanes.removeAll(); + verifyRender(model, true); }); - it("removing clipping planes collection works", function () { + it("removing clipping planes collection works", async function () { const plane = new ClippingPlane(Cartesian3.UNIT_X, -2.5); const clippingPlanes = new ClippingPlaneCollection({ planes: [plane], }); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, clippingPlanes: clippingPlanes }, scene - ).then(function (model) { - verifyRender(model, false); + ); + verifyRender(model, false); - model.clippingPlanes = undefined; - verifyRender(model, true); - }); + model.clippingPlanes = undefined; + verifyRender(model, true); }); - it("replacing clipping planes with another collection works", function () { + it("replacing clipping planes with another collection works", async function () { const modelClippedPlane = new ClippingPlane(Cartesian3.UNIT_X, -2.5); const modelVisiblePlane = new ClippingPlane(Cartesian3.UNIT_X, 2.5); @@ -4225,27 +4057,26 @@ describe( planes: [modelClippedPlane], }); - return loadAndZoomToModelAsync( + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, clippingPlanes: clippingPlanes }, scene - ).then(function (model) { - verifyRender(model, false); + ); + verifyRender(model, false); - // Replace the clipping plane collection with one that makes the model visible. - model.clippingPlanes = new ClippingPlaneCollection({ - planes: [modelVisiblePlane], - }); - verifyRender(model, true); + // Replace the clipping plane collection with one that makes the model visible. + model.clippingPlanes = new ClippingPlaneCollection({ + planes: [modelVisiblePlane], + }); + verifyRender(model, true); - // Replace the clipping plane collection with one that clips the model. - model.clippingPlanes = new ClippingPlaneCollection({ - planes: [modelClippedPlane], - }); - verifyRender(model, false); + // Replace the clipping plane collection with one that clips the model. + model.clippingPlanes = new ClippingPlaneCollection({ + planes: [modelClippedPlane], }); + verifyRender(model, false); }); - it("clipping planes apply edge styling", function () { + it("clipping planes apply edge styling", async function () { const plane = new ClippingPlane(Cartesian3.UNIT_X, 0); const clippingPlanes = new ClippingPlaneCollection({ planes: [plane], @@ -4253,29 +4084,29 @@ describe( edgeColor: Color.BLUE, }); - return loadAndZoomToModelAsync({ gltf: boxTexturedGlbUrl }, scene).then( - function (model) { - let modelColor; - verifyRender(model, true); - expect(scene).toRenderAndCall(function (rgba) { - modelColor = rgba; - }); + const model = await loadAndZoomToModelAsync( + { gltf: boxTexturedGlbUrl }, + scene + ); + let modelColor; + verifyRender(model, true); + expect(scene).toRenderAndCall(function (rgba) { + modelColor = rgba; + }); - model.clippingPlanes = clippingPlanes; + model.clippingPlanes = clippingPlanes; - expect(scene).toRenderAndCall(function (rgba) { - expect(rgba).toEqual([0, 0, 255, 255]); - }); + expect(scene).toRenderAndCall(function (rgba) { + expect(rgba).toEqual([0, 0, 255, 255]); + }); - clippingPlanes.edgeWidth = 0.0; - expect(scene).toRenderAndCall(function (rgba) { - expect(rgba).toEqual(modelColor); - }); - } - ); + clippingPlanes.edgeWidth = 0.0; + expect(scene).toRenderAndCall(function (rgba) { + expect(rgba).toEqual(modelColor); + }); }); - it("clipping planes union regions", function () { + it("clipping planes union regions", async function () { const clippingPlanes = new ClippingPlaneCollection({ planes: [ new ClippingPlane(Cartesian3.UNIT_Z, 5.0), @@ -4283,58 +4114,55 @@ describe( ], unionClippingRegions: true, }); - return loadAndZoomToModelAsync({ gltf: boxTexturedGlbUrl }, scene).then( - function (model) { - verifyRender(model, true); + const model = await loadAndZoomToModelAsync( + { gltf: boxTexturedGlbUrl }, + scene + ); + verifyRender(model, true); - // These planes are defined such that the model is outside their union. - model.clippingPlanes = clippingPlanes; - verifyRender(model, false); + // These planes are defined such that the model is outside their union. + model.clippingPlanes = clippingPlanes; + verifyRender(model, false); - model.clippingPlanes.unionClippingRegions = false; - verifyRender(model, true); - } - ); + model.clippingPlanes.unionClippingRegions = false; + verifyRender(model, true); }); - it("destroys attached ClippingPlaneCollections", function () { - return loadAndZoomToModelAsync( + it("destroys attached ClippingPlaneCollections", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, }, scene - ).then(function (model) { - const clippingPlanes = new ClippingPlaneCollection({ - planes: [new ClippingPlane(Cartesian3.UNIT_X, 0.0)], - }); + ); + const clippingPlanes = new ClippingPlaneCollection({ + planes: [new ClippingPlane(Cartesian3.UNIT_X, 0.0)], + }); - model.clippingPlanes = clippingPlanes; - expect(model.isDestroyed()).toEqual(false); - expect(clippingPlanes.isDestroyed()).toEqual(false); + model.clippingPlanes = clippingPlanes; + expect(model.isDestroyed()).toEqual(false); + expect(clippingPlanes.isDestroyed()).toEqual(false); - scene.primitives.remove(model); - expect(model.isDestroyed()).toEqual(true); - expect(clippingPlanes.isDestroyed()).toEqual(true); - }); + scene.primitives.remove(model); + expect(model.isDestroyed()).toEqual(true); + expect(clippingPlanes.isDestroyed()).toEqual(true); }); - it("destroys ClippingPlaneCollections that are detached", function () { - let clippingPlanes; - return loadAndZoomToModelAsync( + it("destroys ClippingPlaneCollections that are detached", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGlbUrl, }, scene - ).then(function (model) { - clippingPlanes = new ClippingPlaneCollection({ - planes: [new ClippingPlane(Cartesian3.UNIT_X, 0.0)], - }); - model.clippingPlanes = clippingPlanes; - expect(clippingPlanes.isDestroyed()).toBe(false); - - model.clippingPlanes = undefined; - expect(clippingPlanes.isDestroyed()).toBe(true); + ); + const clippingPlanes = new ClippingPlaneCollection({ + planes: [new ClippingPlane(Cartesian3.UNIT_X, 0.0)], }); + model.clippingPlanes = clippingPlanes; + expect(clippingPlanes.isDestroyed()).toBe(false); + + model.clippingPlanes = undefined; + expect(clippingPlanes.isDestroyed()).toBe(true); }); }); @@ -4504,68 +4332,63 @@ describe( }); }); - it("renders with classificationType", function () { - return loadAndZoomToModelAsync( + it("renders with classificationType", async function () { + const model = await loadAndZoomToModelAsync( { url: boxTexturedGltfUrl, classificationType: ClassificationType.CESIUM_3D_TILE, }, scene - ).then(function (model) { - expect(model.classificationType).toBe( - ClassificationType.CESIUM_3D_TILE - ); + ); + expect(model.classificationType).toBe(ClassificationType.CESIUM_3D_TILE); - // There's nothing to classify, so the model won't render. - verifyRender(model, false); - }); + // There's nothing to classify, so the model won't render. + verifyRender(model, false); }); describe("statistics", function () { - it("gets triangle count", function () { - return loadAndZoomToModelAsync( + it("gets triangle count", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl }, scene - ).then(function (model) { - const statistics = model.statistics; - expect(statistics.trianglesLength).toEqual(12); - }); + ); + const statistics = model.statistics; + expect(statistics.trianglesLength).toEqual(12); }); - it("gets point count", function () { - return loadAndZoomToModelAsync({ gltf: pointCloudUrl }, scene).then( - function (model) { - const statistics = model.statistics; - expect(statistics.pointsLength).toEqual(2500); - } + it("gets point count", async function () { + const model = await loadAndZoomToModelAsync( + { gltf: pointCloudUrl }, + scene ); + const statistics = model.statistics; + expect(statistics.pointsLength).toEqual(2500); }); - it("gets memory usage for geometry and textures", function () { - return loadAndZoomToModelAsync( + it("gets memory usage for geometry and textures", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxTexturedGltfUrl, incrementallyLoadTextures: false }, scene - ).then(function (model) { - const expectedGeometryMemory = 840; - // Texture is 256*256 and then is mipmapped - const expectedTextureMemory = Math.floor(256 * 256 * 4 * (4 / 3)); + ); + const expectedGeometryMemory = 840; + // Texture is 256*256 and then is mipmapped + const expectedTextureMemory = Math.floor(256 * 256 * 4 * (4 / 3)); - const statistics = model.statistics; - expect(statistics.geometryByteLength).toEqual(expectedGeometryMemory); - expect(statistics.texturesByteLength).toEqual(expectedTextureMemory); - }); + const statistics = model.statistics; + expect(statistics.geometryByteLength).toEqual(expectedGeometryMemory); + expect(statistics.texturesByteLength).toEqual(expectedTextureMemory); }); - it("gets memory usage for property tables", function () { - return loadAndZoomToModelAsync({ gltf: buildingsMetadata }, scene).then( - function (model) { - const expectedPropertyTableMemory = 110; + it("gets memory usage for property tables", async function () { + const model = await loadAndZoomToModelAsync( + { gltf: buildingsMetadata }, + scene + ); + const expectedPropertyTableMemory = 110; - const statistics = model.statistics; - expect(statistics.propertyTablesByteLength).toEqual( - expectedPropertyTableMemory - ); - } + const statistics = model.statistics; + expect(statistics.propertyTablesByteLength).toEqual( + expectedPropertyTableMemory ); }); }); @@ -4581,17 +4404,16 @@ describe( }).toThrowDeveloperError(); }); - it("setArticulationStage throws with invalid value", function () { - return loadAndZoomToModelAsync( + it("setArticulationStage throws with invalid value", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxArticulationsUrl, }, scene - ).then(function (model) { - expect(function () { - model.setArticulationStage("SampleArticulation MoveX", "bad"); - }).toThrowDeveloperError(); - }); + ); + expect(function () { + model.setArticulationStage("SampleArticulation MoveX", "bad"); + }).toThrowDeveloperError(); }); it("applyArticulations throws when model is not ready", async function () { @@ -4604,31 +4426,30 @@ describe( }).toThrowDeveloperError(); }); - it("applies articulations", function () { - return loadAndZoomToModelAsync( + it("applies articulations", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxArticulationsUrl, }, scene - ).then(function (model) { - verifyRender(model, true); + ); + verifyRender(model, true); - model.setArticulationStage("SampleArticulation MoveX", 10.0); - model.applyArticulations(); - verifyRender(model, false); + model.setArticulationStage("SampleArticulation MoveX", 10.0); + model.applyArticulations(); + verifyRender(model, false); - model.setArticulationStage("SampleArticulation MoveX", 0.0); - model.applyArticulations(); - verifyRender(model, true); + model.setArticulationStage("SampleArticulation MoveX", 0.0); + model.applyArticulations(); + verifyRender(model, true); - model.setArticulationStage("SampleArticulation Size", 0.0); - model.applyArticulations(); - verifyRender(model, false); + model.setArticulationStage("SampleArticulation Size", 0.0); + model.applyArticulations(); + verifyRender(model, false); - model.setArticulationStage("SampleArticulation Size", 1.0); - model.applyArticulations(); - verifyRender(model, true); - }); + model.setArticulationStage("SampleArticulation Size", 1.0); + model.applyArticulations(); + verifyRender(model, true); }); }); @@ -4643,82 +4464,77 @@ describe( }).toThrowDeveloperError(); }); - it("getNode throws when name is undefined", function () { - return loadAndZoomToModelAsync( + it("getNode throws when name is undefined", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxArticulationsUrl, }, scene - ).then(function (model) { - expect(function () { - model.getNode(); - }).toThrowDeveloperError(); - }); + ); + expect(function () { + model.getNode(); + }).toThrowDeveloperError(); }); - it("getNode returns undefined for nonexistent node", function () { - return loadAndZoomToModelAsync( + it("getNode returns undefined for nonexistent node", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxArticulationsUrl, }, scene - ).then(function (model) { - const node = model.getNode("I don't exist"); - expect(node).toBeUndefined(); - }); + ); + const node = model.getNode("I don't exist"); + expect(node).toBeUndefined(); }); - it("getNode returns a node", function () { - return loadAndZoomToModelAsync( + it("getNode returns a node", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxArticulationsUrl, }, scene - ).then(function (model) { - const node = model.getNode("Root"); + ); + const node = model.getNode("Root"); - expect(node).toBeDefined(); - expect(node.name).toEqual("Root"); - expect(node.id).toEqual(0); - expect(node.show).toEqual(true); - expect(node.matrix).toEqual(boxArticulationsMatrix); - expect(node.originalMatrix).toEqual(boxArticulationsMatrix); - }); + expect(node).toBeDefined(); + expect(node.name).toEqual("Root"); + expect(node.id).toEqual(0); + expect(node.show).toEqual(true); + expect(node.matrix).toEqual(boxArticulationsMatrix); + expect(node.originalMatrix).toEqual(boxArticulationsMatrix); }); - it("changing node.show works", function () { - return loadAndZoomToModelAsync( + it("changing node.show works", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxArticulationsUrl, }, scene - ).then(function (model) { - verifyRender(model, true); - const node = model.getNode("Root"); - expect(node.show).toEqual(true); + ); + verifyRender(model, true); + const node = model.getNode("Root"); + expect(node.show).toEqual(true); - node.show = false; - verifyRender(model, false); - }); + node.show = false; + verifyRender(model, false); }); - it("changing node.matrix works", function () { - return loadAndZoomToModelAsync( + it("changing node.matrix works", async function () { + const model = await loadAndZoomToModelAsync( { gltf: boxArticulationsUrl, }, scene - ).then(function (model) { - verifyRender(model, true); - const node = model.getNode("Root"); - expect(node.matrix).toEqual(boxArticulationsMatrix); - expect(node.originalMatrix).toEqual(boxArticulationsMatrix); + ); + verifyRender(model, true); + const node = model.getNode("Root"); + expect(node.matrix).toEqual(boxArticulationsMatrix); + expect(node.originalMatrix).toEqual(boxArticulationsMatrix); - node.matrix = Matrix4.fromTranslation(new Cartesian3(10, 0, 0)); - // The model's bounding sphere doesn't account for animations, - // so the camera will not account for the node's new transform. - verifyRender(model, false); - }); + node.matrix = Matrix4.fromTranslation(new Cartesian3(10, 0, 0)); + // The model's bounding sphere doesn't account for animations, + // so the camera will not account for the node's new transform. + verifyRender(model, false); }); }); @@ -5178,66 +4994,63 @@ describe( ); }); - it("destroy works", function () { + it("destroy works", async function () { spyOn(ShaderProgram.prototype, "destroy").and.callThrough(); - return loadAndZoomToModelAsync({ gltf: boxTexturedGlbUrl }, scene).then( - function (model) { - const resources = model._pipelineResources; - const loader = model._loader; - let resource; - - let i; - for (i = 0; i < resources.length; i++) { - resource = resources[i]; - if (defined(resource.isDestroyed)) { - expect(resource.isDestroyed()).toEqual(false); - } - } - expect(loader.isDestroyed()).toEqual(false); - expect(model.isDestroyed()).toEqual(false); - scene.primitives.remove(model); - if (!webglStub) { - expect(ShaderProgram.prototype.destroy).toHaveBeenCalled(); - } - for (i = 0; i < resources.length - 1; i++) { - resource = resources[i]; - if (defined(resource.isDestroyed)) { - expect(resource.isDestroyed()).toEqual(true); - } - } - expect(loader.isDestroyed()).toEqual(true); - expect(model.isDestroyed()).toEqual(true); - } + const model = await loadAndZoomToModelAsync( + { gltf: boxTexturedGlbUrl }, + scene ); + const resources = model._pipelineResources; + const loader = model._loader; + + for (let i = 0; i < resources.length; i++) { + const resource = resources[i]; + if (defined(resource.isDestroyed)) { + expect(resource.isDestroyed()).toEqual(false); + } + } + expect(loader.isDestroyed()).toEqual(false); + expect(model.isDestroyed()).toEqual(false); + scene.primitives.remove(model); + if (!webglStub) { + expect(ShaderProgram.prototype.destroy).toHaveBeenCalled(); + } + for (let i = 0; i < resources.length - 1; i++) { + const resource = resources[i]; + if (defined(resource.isDestroyed)) { + expect(resource.isDestroyed()).toEqual(true); + } + } + expect(loader.isDestroyed()).toEqual(true); + expect(model.isDestroyed()).toEqual(true); }); - it("destroy doesn't destroy resources when they're in use", function () { - return Promise.all([ + it("destroy doesn't destroy resources when they're in use", async function () { + const models = await Promise.all([ loadAndZoomToModelAsync({ gltf: boxTexturedGlbUrl }, scene), loadAndZoomToModelAsync({ gltf: boxTexturedGlbUrl }, scene), - ]).then(function (models) { - const cacheEntries = ResourceCache.cacheEntries; - let cacheKey; - let cacheEntry; + ]); + const cacheEntries = ResourceCache.cacheEntries; + let cacheKey; + let cacheEntry; - scene.primitives.remove(models[0]); + scene.primitives.remove(models[0]); - for (cacheKey in cacheEntries) { - if (cacheEntries.hasOwnProperty(cacheKey)) { - cacheEntry = cacheEntries[cacheKey]; - expect(cacheEntry.referenceCount).toBeGreaterThan(0); - } + for (cacheKey in cacheEntries) { + if (cacheEntries.hasOwnProperty(cacheKey)) { + cacheEntry = cacheEntries[cacheKey]; + expect(cacheEntry.referenceCount).toBeGreaterThan(0); } + } - scene.primitives.remove(models[1]); + scene.primitives.remove(models[1]); - for (cacheKey in cacheEntries) { - if (cacheEntries.hasOwnProperty(cacheKey)) { - cacheEntry = cacheEntries[cacheKey]; - expect(cacheEntry.referenceCount).toBe(0); - } + for (cacheKey in cacheEntries) { + if (cacheEntries.hasOwnProperty(cacheKey)) { + cacheEntry = cacheEntries[cacheKey]; + expect(cacheEntry.referenceCount).toBe(0); } - }); + } }); }, "WebGL" diff --git a/packages/engine/Specs/Scene/MultifrustumSpec.js b/packages/engine/Specs/Scene/MultifrustumSpec.js index aa9917256f0..5c417c6f4a7 100644 --- a/packages/engine/Specs/Scene/MultifrustumSpec.js +++ b/packages/engine/Specs/Scene/MultifrustumSpec.js @@ -8,6 +8,7 @@ import { defined, destroyObject, GeometryPipeline, + Math as CesiumMath, Matrix4, Resource, BufferUsage, @@ -22,8 +23,6 @@ import { TextureAtlas, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createScene from "../../../../Specs/createScene.js"; import pollToPromise from "../../../../Specs/pollToPromise.js"; diff --git a/packages/engine/Specs/Scene/OctahedralProjectedCubeMapSpec.js b/packages/engine/Specs/Scene/OctahedralProjectedCubeMapSpec.js index 2d13eba58fb..ac9efc89fb9 100644 --- a/packages/engine/Specs/Scene/OctahedralProjectedCubeMapSpec.js +++ b/packages/engine/Specs/Scene/OctahedralProjectedCubeMapSpec.js @@ -1,9 +1,10 @@ import { + Cartesian3, + defined, ComputeEngine, Pass, OctahedralProjectedCubeMap, } from "../../index.js"; -import { Cartesian3, defined } from "../../index.js"; import createContext from "../../../../Specs/createContext.js"; import createFrameState from "../../../../Specs/createFrameState.js"; diff --git a/packages/engine/Specs/Scene/OpenStreetMapImageryProviderSpec.js b/packages/engine/Specs/Scene/OpenStreetMapImageryProviderSpec.js index 4300e9d8d37..b097f2c020e 100644 --- a/packages/engine/Specs/Scene/OpenStreetMapImageryProviderSpec.js +++ b/packages/engine/Specs/Scene/OpenStreetMapImageryProviderSpec.js @@ -1,4 +1,5 @@ import { + Math as CesiumMath, Rectangle, Request, RequestScheduler, @@ -10,7 +11,6 @@ import { ImageryState, UrlTemplateImageryProvider, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; import pollToPromise from "../../../../Specs/pollToPromise.js"; diff --git a/packages/engine/Specs/Scene/PickingSpec.js b/packages/engine/Specs/Scene/PickingSpec.js index bbf53c690f6..362fb4ca53b 100644 --- a/packages/engine/Specs/Scene/PickingSpec.js +++ b/packages/engine/Specs/Scene/PickingSpec.js @@ -6,6 +6,7 @@ import { Color, Ellipsoid, GeometryInstance, + Math as CesiumMath, Matrix4, OrthographicFrustum, PerspectiveFrustum, @@ -23,8 +24,6 @@ import { VoxelPrimitive, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import Cesium3DTilesTester from "../../../../Specs/Cesium3DTilesTester.js"; import createCanvas from "../../../../Specs/createCanvas.js"; import createScene from "../../../../Specs/createScene.js"; diff --git a/packages/engine/Specs/Scene/PointCloudEyeDomeLightingSpec.js b/packages/engine/Specs/Scene/PointCloudEyeDomeLightingSpec.js index 2b502bb8ddd..7668c5c4d02 100644 --- a/packages/engine/Specs/Scene/PointCloudEyeDomeLightingSpec.js +++ b/packages/engine/Specs/Scene/PointCloudEyeDomeLightingSpec.js @@ -2,12 +2,11 @@ import { Cartesian3, Cesium3DTileStyle, HeadingPitchRange, + Math as CesiumMath, PerspectiveFrustum, PointCloudEyeDomeLighting, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import Cesium3DTilesTester from "../../../../Specs/Cesium3DTilesTester.js"; import createScene from "../../../../Specs/createScene.js"; diff --git a/packages/engine/Specs/Scene/PointPrimitiveCollectionSpec.js b/packages/engine/Specs/Scene/PointPrimitiveCollectionSpec.js index fc5844f0bdf..bbe04eebdd3 100644 --- a/packages/engine/Specs/Scene/PointPrimitiveCollectionSpec.js +++ b/packages/engine/Specs/Scene/PointPrimitiveCollectionSpec.js @@ -5,6 +5,7 @@ import { Cartesian3, Color, DistanceDisplayCondition, + Math as CesiumMath, NearFarScalar, Rectangle, BlendOption, @@ -12,8 +13,6 @@ import { PointPrimitiveCollection, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createScene from "../../../../Specs/createScene.js"; describe( diff --git a/packages/engine/Specs/Scene/PolylineCollectionSpec.js b/packages/engine/Specs/Scene/PolylineCollectionSpec.js index d931227c045..f237f0a4aef 100644 --- a/packages/engine/Specs/Scene/PolylineCollectionSpec.js +++ b/packages/engine/Specs/Scene/PolylineCollectionSpec.js @@ -4,6 +4,7 @@ import { Color, DistanceDisplayCondition, HeadingPitchRange, + Math as CesiumMath, Matrix4, Camera, Material, @@ -11,8 +12,6 @@ import { SceneMode, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createScene from "../../../../Specs/createScene.js"; describe( diff --git a/packages/engine/Specs/Scene/PrimitiveCullingSpec.js b/packages/engine/Specs/Scene/PrimitiveCullingSpec.js index 7fd59d356f3..e9f311e4b55 100644 --- a/packages/engine/Specs/Scene/PrimitiveCullingSpec.js +++ b/packages/engine/Specs/Scene/PrimitiveCullingSpec.js @@ -5,6 +5,7 @@ import { defaultValue, defined, GeometryInstance, + Math as CesiumMath, PerspectiveFrustum, Rectangle, RectangleGeometry, @@ -22,8 +23,6 @@ import { VerticalOrigin, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createScene from "../../../../Specs/createScene.js"; import pollToPromise from "../../../../Specs/pollToPromise.js"; diff --git a/packages/engine/Specs/Scene/PrimitiveSpec.js b/packages/engine/Specs/Scene/PrimitiveSpec.js index 4c229a09a1e..c218d444315 100644 --- a/packages/engine/Specs/Scene/PrimitiveSpec.js +++ b/packages/engine/Specs/Scene/PrimitiveSpec.js @@ -13,6 +13,7 @@ import { GeometryInstance, GeometryInstanceAttribute, HeadingPitchRange, + Math as CesiumMath, Matrix4, PerspectiveFrustum, PolygonGeometry, @@ -28,8 +29,6 @@ import { SceneMode, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import BadGeometry from "../../../../Specs/BadGeometry.js"; import createContext from "../../../../Specs/createContext.js"; import createFrameState from "../../../../Specs/createFrameState.js"; diff --git a/packages/engine/Specs/Scene/QuadtreeTileSpec.js b/packages/engine/Specs/Scene/QuadtreeTileSpec.js index 350e5ca4816..2e6d6c7edcb 100644 --- a/packages/engine/Specs/Scene/QuadtreeTileSpec.js +++ b/packages/engine/Specs/Scene/QuadtreeTileSpec.js @@ -1,12 +1,11 @@ import { GeographicTilingScheme, Rectangle, + Math as CesiumMath, WebMercatorTilingScheme, QuadtreeTile, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("Scene/QuadtreeTile", function () { it("throws without a options", function () { expect(function () { diff --git a/packages/engine/Specs/Scene/SceneSpec.js b/packages/engine/Specs/Scene/SceneSpec.js index 99f09001915..7e3fc5fdaa6 100644 --- a/packages/engine/Specs/Scene/SceneSpec.js +++ b/packages/engine/Specs/Scene/SceneSpec.js @@ -11,6 +11,7 @@ import { GeometryInstance, HeadingPitchRoll, JulianDate, + Math as CesiumMath, PixelFormat, Rectangle, RectangleGeometry, @@ -48,8 +49,6 @@ import { Resource, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createCanvas from "../../../../Specs/createCanvas.js"; import createScene from "../../../../Specs/createScene.js"; import pollToPromise from "../../../../Specs/pollToPromise.js"; diff --git a/packages/engine/Specs/Scene/SceneTransformsSpec.js b/packages/engine/Specs/Scene/SceneTransformsSpec.js index adaad81640a..0839423d89e 100644 --- a/packages/engine/Specs/Scene/SceneTransformsSpec.js +++ b/packages/engine/Specs/Scene/SceneTransformsSpec.js @@ -2,6 +2,7 @@ import { Cartesian2, Cartesian3, Ellipsoid, + Math as CesiumMath, OrthographicFrustum, Rectangle, Camera, @@ -9,8 +10,6 @@ import { SceneTransforms, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createScene from "../../../../Specs/createScene.js"; describe( diff --git a/packages/engine/Specs/Scene/ScreenSpaceCameraControllerSpec.js b/packages/engine/Specs/Scene/ScreenSpaceCameraControllerSpec.js index 5da26e0c64a..9611aac90c4 100644 --- a/packages/engine/Specs/Scene/ScreenSpaceCameraControllerSpec.js +++ b/packages/engine/Specs/Scene/ScreenSpaceCameraControllerSpec.js @@ -7,6 +7,7 @@ import { GeographicProjection, IntersectionTests, KeyboardEventModifier, + Math as CesiumMath, OrthographicFrustum, OrthographicOffCenterFrustum, Ray, @@ -18,8 +19,6 @@ import { ScreenSpaceCameraController, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createCamera from "../../../../Specs/createCamera.js"; import createCanvas from "../../../../Specs/createCanvas.js"; import DomEventSimulator from "../../../../Specs/DomEventSimulator.js"; diff --git a/packages/engine/Specs/Scene/ShadowMapSpec.js b/packages/engine/Specs/Scene/ShadowMapSpec.js index 231ea6088e7..762791743a0 100644 --- a/packages/engine/Specs/Scene/ShadowMapSpec.js +++ b/packages/engine/Specs/Scene/ShadowMapSpec.js @@ -12,6 +12,7 @@ import { HeadingPitchRoll, HeightmapTerrainData, JulianDate, + Math as CesiumMath, Matrix4, OrthographicOffCenterFrustum, PixelFormat, @@ -31,8 +32,6 @@ import { ShadowMode, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createScene from "../../../../Specs/createScene.js"; import pollToPromise from "../../../../Specs/pollToPromise.js"; diff --git a/packages/engine/Specs/Scene/ShadowVolumeAppearanceSpec.js b/packages/engine/Specs/Scene/ShadowVolumeAppearanceSpec.js index a24bad1fcbb..8eba7af6b61 100644 --- a/packages/engine/Specs/Scene/ShadowVolumeAppearanceSpec.js +++ b/packages/engine/Specs/Scene/ShadowVolumeAppearanceSpec.js @@ -4,6 +4,7 @@ import { ComponentDatatype, Ellipsoid, EncodedCartesian3, + Math as CesiumMath, Matrix4, Rectangle, Transforms, @@ -14,8 +15,6 @@ import { ShadowVolumeAppearance, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("Scene/ShadowVolumeAppearance", function () { // using ShadowVolumeAppearanceVS directly fails on CI with the --release test const testVs = diff --git a/packages/engine/Specs/Scene/SkyAtmosphereSpec.js b/packages/engine/Specs/Scene/SkyAtmosphereSpec.js index b7be045cfd3..71a215cff6c 100644 --- a/packages/engine/Specs/Scene/SkyAtmosphereSpec.js +++ b/packages/engine/Specs/Scene/SkyAtmosphereSpec.js @@ -2,12 +2,11 @@ import { Cartesian3, DynamicAtmosphereLightingType, Ellipsoid, + Math as CesiumMath, SceneMode, SkyAtmosphere, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createScene from "../../../../Specs/createScene.js"; describe( diff --git a/packages/engine/Specs/Scene/SunSpec.js b/packages/engine/Specs/Scene/SunSpec.js index f892f6e0a37..caa9fd39793 100644 --- a/packages/engine/Specs/Scene/SunSpec.js +++ b/packages/engine/Specs/Scene/SunSpec.js @@ -1,6 +1,10 @@ -import { BoundingSphere, Color, SceneMode, Sun } from "../../index.js"; - -import { Math as CesiumMath } from "../../index.js"; +import { + BoundingSphere, + Color, + Math as CesiumMath, + SceneMode, + Sun, +} from "../../index.js"; import createScene from "../../../../Specs/createScene.js"; diff --git a/packages/engine/Specs/Scene/TerrainFillMeshSpec.js b/packages/engine/Specs/Scene/TerrainFillMeshSpec.js index 0d604f43b21..cf3589dd19a 100644 --- a/packages/engine/Specs/Scene/TerrainFillMeshSpec.js +++ b/packages/engine/Specs/Scene/TerrainFillMeshSpec.js @@ -4,6 +4,7 @@ import { GeographicProjection, HeightmapTerrainData, Intersect, + Math as CesiumMath, Camera, GlobeSurfaceTileProvider, ImageryLayerCollection, @@ -16,8 +17,6 @@ import { import MockTerrainProvider from "../../../../Specs/MockTerrainProvider.js"; import TerrainTileProcessor from "../../../../Specs/TerrainTileProcessor.js"; -import { Math as CesiumMath } from "../../index.js"; - describe("Scene/TerrainFillMesh", function () { let processor; let scene; diff --git a/packages/engine/Specs/Scene/TileBoundingRegionSpec.js b/packages/engine/Specs/Scene/TileBoundingRegionSpec.js index eda4730996d..92beba6e486 100644 --- a/packages/engine/Specs/Scene/TileBoundingRegionSpec.js +++ b/packages/engine/Specs/Scene/TileBoundingRegionSpec.js @@ -6,14 +6,13 @@ import { Ellipsoid, GeographicTilingScheme, Intersect, + Math as CesiumMath, Plane, Rectangle, SceneMode, TileBoundingRegion, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createFrameState from "../../../../Specs/createFrameState.js"; describe("Scene/TileBoundingRegion", function () { diff --git a/packages/engine/Specs/Scene/TileBoundingS2CellSpec.js b/packages/engine/Specs/Scene/TileBoundingS2CellSpec.js index 4777629003c..61f0d8f20f1 100644 --- a/packages/engine/Specs/Scene/TileBoundingS2CellSpec.js +++ b/packages/engine/Specs/Scene/TileBoundingS2CellSpec.js @@ -3,13 +3,12 @@ import { Color, Ellipsoid, Intersect, + Math as CesiumMath, Plane, S2Cell, TileBoundingS2Cell, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createFrameState from "../../../../Specs/createFrameState.js"; describe("Scene/TileBoundingS2Cell", function () { diff --git a/packages/engine/Specs/Scene/TileBoundingSphereSpec.js b/packages/engine/Specs/Scene/TileBoundingSphereSpec.js index 05164ba32e6..32c87cb0078 100644 --- a/packages/engine/Specs/Scene/TileBoundingSphereSpec.js +++ b/packages/engine/Specs/Scene/TileBoundingSphereSpec.js @@ -2,12 +2,11 @@ import { Cartesian3, Color, Intersect, + Math as CesiumMath, Plane, TileBoundingSphere, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createFrameState from "../../../../Specs/createFrameState.js"; describe("Scene/TileBoundingSphere", function () { diff --git a/packages/engine/Specs/Scene/TileMapServiceImageryProviderSpec.js b/packages/engine/Specs/Scene/TileMapServiceImageryProviderSpec.js index 293813ecca8..72494dceb68 100644 --- a/packages/engine/Specs/Scene/TileMapServiceImageryProviderSpec.js +++ b/packages/engine/Specs/Scene/TileMapServiceImageryProviderSpec.js @@ -4,6 +4,7 @@ import { GeographicProjection, GeographicTilingScheme, getAbsoluteUri, + Math as CesiumMath, Rectangle, Request, RequestErrorEvent, @@ -19,8 +20,6 @@ import { UrlTemplateImageryProvider, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import pollToPromise from "../../../../Specs/pollToPromise.js"; describe("Scene/TileMapServiceImageryProvider", function () { diff --git a/packages/engine/Specs/Scene/TileOrientedBoundingBoxSpec.js b/packages/engine/Specs/Scene/TileOrientedBoundingBoxSpec.js index 9748bfd03c3..91ad1dbfc72 100644 --- a/packages/engine/Specs/Scene/TileOrientedBoundingBoxSpec.js +++ b/packages/engine/Specs/Scene/TileOrientedBoundingBoxSpec.js @@ -2,13 +2,12 @@ import { Cartesian3, Color, Intersect, + Math as CesiumMath, Matrix3, Plane, TileOrientedBoundingBox, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createFrameState from "../../../../Specs/createFrameState.js"; describe("Scene/TileOrientedBoundingBox", function () { diff --git a/packages/engine/Specs/Scene/UrlTemplateImageryProviderSpec.js b/packages/engine/Specs/Scene/UrlTemplateImageryProviderSpec.js index eabc3f55f44..a7e6e2a3761 100644 --- a/packages/engine/Specs/Scene/UrlTemplateImageryProviderSpec.js +++ b/packages/engine/Specs/Scene/UrlTemplateImageryProviderSpec.js @@ -1,6 +1,7 @@ import { Ellipsoid, GeographicTilingScheme, + Math as CesiumMath, Rectangle, Request, RequestScheduler, @@ -15,8 +16,6 @@ import { UrlTemplateImageryProvider, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import pollToPromise from "../../../../Specs/pollToPromise.js"; describe("Scene/UrlTemplateImageryProvider", function () { diff --git a/packages/engine/Specs/Scene/Vector3DTilePointsSpec.js b/packages/engine/Specs/Scene/Vector3DTilePointsSpec.js index c1a22dfedf6..eb701fc8236 100644 --- a/packages/engine/Specs/Scene/Vector3DTilePointsSpec.js +++ b/packages/engine/Specs/Scene/Vector3DTilePointsSpec.js @@ -8,6 +8,7 @@ import { defined, DistanceDisplayCondition, Ellipsoid, + Math as CesiumMath, NearFarScalar, Rectangle, Cesium3DTileBatchTable, @@ -19,8 +20,6 @@ import { VerticalOrigin, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createScene from "../../../../Specs/createScene.js"; import pollToPromise from "../../../../Specs/pollToPromise.js"; diff --git a/packages/engine/Specs/Scene/Vector3DTilePolylinesSpec.js b/packages/engine/Specs/Scene/Vector3DTilePolylinesSpec.js index 7a82e8db713..1ca2cffad46 100644 --- a/packages/engine/Specs/Scene/Vector3DTilePolylinesSpec.js +++ b/packages/engine/Specs/Scene/Vector3DTilePolylinesSpec.js @@ -3,14 +3,13 @@ import { Cartesian3, Cartographic, Ellipsoid, + Math as CesiumMath, Rectangle, Cesium3DTileBatchTable, ColorBlendMode, Vector3DTilePolylines, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createScene from "../../../../Specs/createScene.js"; import pollToPromise from "../../../../Specs/pollToPromise.js"; diff --git a/packages/engine/Specs/Scene/WebMapServiceImageryProviderSpec.js b/packages/engine/Specs/Scene/WebMapServiceImageryProviderSpec.js index 320052224e0..fe750f3c434 100644 --- a/packages/engine/Specs/Scene/WebMapServiceImageryProviderSpec.js +++ b/packages/engine/Specs/Scene/WebMapServiceImageryProviderSpec.js @@ -12,6 +12,7 @@ import { ImageryProvider, ImageryState, JulianDate, + Math as CesiumMath, queryToObject, Rectangle, Request, @@ -23,8 +24,6 @@ import { WebMercatorTilingScheme, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import pollToPromise from "../../../../Specs/pollToPromise.js"; describe("Scene/WebMapServiceImageryProvider", function () { diff --git a/packages/engine/Specs/Scene/createElevationBandMaterialSpec.js b/packages/engine/Specs/Scene/createElevationBandMaterialSpec.js index b0bb626bf89..1b1ee0ee4a7 100644 --- a/packages/engine/Specs/Scene/createElevationBandMaterialSpec.js +++ b/packages/engine/Specs/Scene/createElevationBandMaterialSpec.js @@ -2,13 +2,12 @@ import { Cartesian4, Color, createElevationBandMaterial, + Math as CesiumMath, PixelFormat, Texture, TextureMinificationFilter, } from "../../index.js"; -import { Math as CesiumMath } from "../../index.js"; - import createScene from "../../../../Specs/createScene.js"; describe("Scene/createElevationBandMaterial", function () { diff --git a/packages/engine/package.json b/packages/engine/package.json index 46ac0a1772d..91727f56299 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -1,6 +1,6 @@ { "name": "@cesium/engine", - "version": "9.1.0", + "version": "9.2.0", "description": "CesiumJS is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin.", "keywords": [ "3D", diff --git a/packages/widgets/Specs/.eslintrc.json b/packages/widgets/Specs/.eslintrc.json deleted file mode 100644 index 5b6725648bf..00000000000 --- a/packages/widgets/Specs/.eslintrc.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "../../.eslintrc.json", - "env": { - "jasmine": true - }, - "rules": { - "no-self-assign": "off", - "no-duplicate-imports": "off" - } -} \ No newline at end of file diff --git a/packages/widgets/Specs/I3SBSLExplorer/I3SBSLExplorerViewModelSpec.js b/packages/widgets/Specs/I3SBSLExplorer/I3SBSLExplorerViewModelSpec.js index 94ecb6361b2..8d8c22af3c4 100644 --- a/packages/widgets/Specs/I3SBSLExplorer/I3SBSLExplorerViewModelSpec.js +++ b/packages/widgets/Specs/I3SBSLExplorer/I3SBSLExplorerViewModelSpec.js @@ -1,6 +1,7 @@ -import { I3SBuildingSceneLayerExplorerViewModel } from "../../index.js"; - -import { knockout } from "../../index.js"; +import { + I3SBuildingSceneLayerExplorerViewModel, + knockout, +} from "../../index.js"; describe("Widgets/I3SBuildingSceneLayerExplorer/I3SBuildingSceneLayerExplorerViewModel", function () { const i3sProvider = { diff --git a/packages/widgets/package.json b/packages/widgets/package.json index 0832b3e0536..7e157710951 100644 --- a/packages/widgets/package.json +++ b/packages/widgets/package.json @@ -28,7 +28,7 @@ "node": ">=14.0.0" }, "dependencies": { - "@cesium/engine": "^9.1.0", + "@cesium/engine": "^9.2.0", "nosleep.js": "^0.12.0" }, "type": "module", @@ -52,4 +52,4 @@ "bugs": { "url": "https://github.com/CesiumGS/cesium/issues" } -} +} \ No newline at end of file diff --git a/scripts/build.js b/scripts/build.js index 4a35e6a3eb0..a28de85995a 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -1,17 +1,16 @@ -/*eslint-env node*/ import child_process from "child_process"; import { existsSync, readFileSync, statSync } from "fs"; import { readFile, writeFile } from "fs/promises"; import { EOL } from "os"; import path from "path"; import { createRequire } from "module"; +import { finished } from 'stream/promises'; import esbuild from "esbuild"; import { globby } from "globby"; import glslStripComments from "glsl-strip-comments"; import gulp from "gulp"; import { rimraf } from "rimraf"; -import streamToPromise from "stream-to-promise"; import { mkdirp } from "mkdirp"; @@ -640,7 +639,7 @@ export async function createGalleryList(noDevelopmentGallery) { .toString() .trim() .split("\n"); - } catch (e) { + } catch { // On a Cesium fork, tags don't exist so we can't generate the list. } @@ -715,10 +714,11 @@ const has_new_gallery_demos = ${newDemos.length > 0 ? "true;" : "false;"}\n`; */ export async function copyFiles(globs, destination, base) { const stream = gulp - .src(globs, { nodir: true, base: base ?? "" }) + .src(globs, { nodir: true, base: base ?? "", encoding: false }) .pipe(gulp.dest(destination)); - return streamToPromise(stream); + await finished(stream); + return stream; } /** diff --git a/server.js b/server.js index 590470ef1ba..057beb0f0d9 100644 --- a/server.js +++ b/server.js @@ -1,4 +1,3 @@ -/*eslint-env node*/ import fs from "fs"; import path from "path"; import { performance } from "perf_hooks";