Cesium3DTilesInspector.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. import Check from "../../Core/Check.js";
  2. import defaultValue from "../../Core/defaultValue.js";
  3. import defined from "../../Core/defined.js";
  4. import destroyObject from "../../Core/destroyObject.js";
  5. import knockout from "../../ThirdParty/knockout.js";
  6. import getElement from "../getElement.js";
  7. import InspectorShared from "../InspectorShared.js";
  8. import Cesium3DTilesInspectorViewModel from "./Cesium3DTilesInspectorViewModel.js";
  9. /**
  10. * Inspector widget to aid in debugging 3D Tiles
  11. *
  12. * @alias Cesium3DTilesInspector
  13. * @constructor
  14. *
  15. * @param {Element|String} container The DOM element or ID that will contain the widget.
  16. * @param {Scene} scene the Scene instance to use.
  17. */
  18. function Cesium3DTilesInspector(container, scene) {
  19. //>>includeStart('debug', pragmas.debug);
  20. Check.defined("container", container);
  21. Check.typeOf.object("scene", scene);
  22. //>>includeEnd('debug');
  23. container = getElement(container);
  24. const element = document.createElement("div");
  25. const performanceContainer = document.createElement("div");
  26. performanceContainer.setAttribute("data-bind", "visible: performance");
  27. const viewModel = new Cesium3DTilesInspectorViewModel(
  28. scene,
  29. performanceContainer
  30. );
  31. this._viewModel = viewModel;
  32. this._container = container;
  33. this._element = element;
  34. const text = document.createElement("div");
  35. text.textContent = "3D Tiles Inspector";
  36. text.className = "cesium-cesiumInspector-button";
  37. text.setAttribute("data-bind", "click: toggleInspector");
  38. element.appendChild(text);
  39. element.className = "cesium-cesiumInspector cesium-3DTilesInspector";
  40. element.setAttribute(
  41. "data-bind",
  42. 'css: { "cesium-cesiumInspector-visible" : inspectorVisible, "cesium-cesiumInspector-hidden" : !inspectorVisible}'
  43. );
  44. container.appendChild(element);
  45. const panel = document.createElement("div");
  46. this._panel = panel;
  47. panel.className = "cesium-cesiumInspector-dropDown";
  48. element.appendChild(panel);
  49. const createSection = InspectorShared.createSection;
  50. const createCheckbox = InspectorShared.createCheckbox;
  51. const tilesetPanelContents = createSection(
  52. panel,
  53. "Tileset",
  54. "tilesetVisible",
  55. "toggleTileset"
  56. );
  57. const displayPanelContents = createSection(
  58. panel,
  59. "Display",
  60. "displayVisible",
  61. "toggleDisplay"
  62. );
  63. const updatePanelContents = createSection(
  64. panel,
  65. "Update",
  66. "updateVisible",
  67. "toggleUpdate"
  68. );
  69. const loggingPanelContents = createSection(
  70. panel,
  71. "Logging",
  72. "loggingVisible",
  73. "toggleLogging"
  74. );
  75. const tileDebugLabelsPanelContents = createSection(
  76. panel,
  77. "Tile Debug Labels",
  78. "tileDebugLabelsVisible",
  79. "toggleTileDebugLabels"
  80. );
  81. const stylePanelContents = createSection(
  82. panel,
  83. "Style",
  84. "styleVisible",
  85. "toggleStyle"
  86. );
  87. const optimizationPanelContents = createSection(
  88. panel,
  89. "Optimization",
  90. "optimizationVisible",
  91. "toggleOptimization"
  92. );
  93. const properties = document.createElement("div");
  94. properties.className = "field-group";
  95. const propertiesLabel = document.createElement("label");
  96. propertiesLabel.className = "field-label";
  97. propertiesLabel.appendChild(document.createTextNode("Properties: "));
  98. const propertiesField = document.createElement("div");
  99. propertiesField.setAttribute("data-bind", "text: properties");
  100. properties.appendChild(propertiesLabel);
  101. properties.appendChild(propertiesField);
  102. tilesetPanelContents.appendChild(properties);
  103. tilesetPanelContents.appendChild(
  104. makeButton("togglePickTileset", "Pick Tileset", "pickActive")
  105. );
  106. tilesetPanelContents.appendChild(
  107. makeButton("trimTilesCache", "Trim Tiles Cache")
  108. );
  109. tilesetPanelContents.appendChild(createCheckbox("Enable Picking", "picking"));
  110. displayPanelContents.appendChild(createCheckbox("Colorize", "colorize"));
  111. displayPanelContents.appendChild(createCheckbox("Wireframe", "wireframe"));
  112. displayPanelContents.appendChild(
  113. createCheckbox("Bounding Volumes", "showBoundingVolumes")
  114. );
  115. displayPanelContents.appendChild(
  116. createCheckbox("Content Volumes", "showContentBoundingVolumes")
  117. );
  118. displayPanelContents.appendChild(
  119. createCheckbox("Request Volumes", "showRequestVolumes")
  120. );
  121. displayPanelContents.appendChild(
  122. createCheckbox("Point Cloud Shading", "pointCloudShading")
  123. );
  124. const pointCloudShadingContainer = document.createElement("div");
  125. pointCloudShadingContainer.setAttribute(
  126. "data-bind",
  127. "visible: pointCloudShading"
  128. );
  129. pointCloudShadingContainer.appendChild(
  130. makeRangeInput("geometricErrorScale", 0, 2, 0.01, "Geometric Error Scale")
  131. );
  132. pointCloudShadingContainer.appendChild(
  133. makeRangeInput("maximumAttenuation", 0, 32, 1, "Maximum Attenuation")
  134. );
  135. pointCloudShadingContainer.appendChild(
  136. makeRangeInput("baseResolution", 0, 1, 0.01, "Base Resolution")
  137. );
  138. pointCloudShadingContainer.appendChild(
  139. createCheckbox("Eye Dome Lighting (EDL)", "eyeDomeLighting")
  140. );
  141. displayPanelContents.appendChild(pointCloudShadingContainer);
  142. const edlContainer = document.createElement("div");
  143. edlContainer.setAttribute("data-bind", "visible: eyeDomeLighting");
  144. edlContainer.appendChild(
  145. makeRangeInput("eyeDomeLightingStrength", 0, 2.0, 0.1, "EDL Strength")
  146. );
  147. edlContainer.appendChild(
  148. makeRangeInput("eyeDomeLightingRadius", 0, 4.0, 0.1, "EDL Radius")
  149. );
  150. pointCloudShadingContainer.appendChild(edlContainer);
  151. updatePanelContents.appendChild(
  152. createCheckbox("Freeze Frame", "freezeFrame")
  153. );
  154. updatePanelContents.appendChild(
  155. createCheckbox("Dynamic Screen Space Error", "dynamicScreenSpaceError")
  156. );
  157. const sseContainer = document.createElement("div");
  158. sseContainer.appendChild(
  159. makeRangeInput(
  160. "maximumScreenSpaceError",
  161. 0,
  162. 128,
  163. 1,
  164. "Maximum Screen Space Error"
  165. )
  166. );
  167. updatePanelContents.appendChild(sseContainer);
  168. const dynamicScreenSpaceErrorContainer = document.createElement("div");
  169. dynamicScreenSpaceErrorContainer.setAttribute(
  170. "data-bind",
  171. "visible: dynamicScreenSpaceError"
  172. );
  173. dynamicScreenSpaceErrorContainer.appendChild(
  174. makeRangeInput(
  175. "dynamicScreenSpaceErrorDensitySliderValue",
  176. 0,
  177. 1,
  178. 0.005,
  179. "Screen Space Error Density",
  180. "dynamicScreenSpaceErrorDensity"
  181. )
  182. );
  183. dynamicScreenSpaceErrorContainer.appendChild(
  184. makeRangeInput(
  185. "dynamicScreenSpaceErrorFactor",
  186. 1,
  187. 10,
  188. 0.1,
  189. "Screen Space Error Factor"
  190. )
  191. );
  192. updatePanelContents.appendChild(dynamicScreenSpaceErrorContainer);
  193. loggingPanelContents.appendChild(
  194. createCheckbox("Performance", "performance")
  195. );
  196. loggingPanelContents.appendChild(performanceContainer);
  197. loggingPanelContents.appendChild(
  198. createCheckbox("Statistics", "showStatistics")
  199. );
  200. const statistics = document.createElement("div");
  201. statistics.className = "cesium-3dTilesInspector-statistics";
  202. statistics.setAttribute(
  203. "data-bind",
  204. "html: statisticsText, visible: showStatistics"
  205. );
  206. loggingPanelContents.appendChild(statistics);
  207. loggingPanelContents.appendChild(
  208. createCheckbox("Pick Statistics", "showPickStatistics")
  209. );
  210. const pickStatistics = document.createElement("div");
  211. pickStatistics.className = "cesium-3dTilesInspector-statistics";
  212. pickStatistics.setAttribute(
  213. "data-bind",
  214. "html: pickStatisticsText, visible: showPickStatistics"
  215. );
  216. loggingPanelContents.appendChild(pickStatistics);
  217. const stylePanelEditor = document.createElement("div");
  218. stylePanelContents.appendChild(stylePanelEditor);
  219. stylePanelEditor.appendChild(document.createTextNode("Color Blend Mode: "));
  220. const blendDropdown = document.createElement("select");
  221. blendDropdown.setAttribute(
  222. "data-bind",
  223. "options: colorBlendModes, " +
  224. 'optionsText: "text", ' +
  225. 'optionsValue: "value", ' +
  226. "value: colorBlendMode"
  227. );
  228. stylePanelEditor.appendChild(blendDropdown);
  229. const styleEditor = document.createElement("textarea");
  230. styleEditor.setAttribute(
  231. "data-bind",
  232. "textInput: styleString, event: { keydown: styleEditorKeyPress }"
  233. );
  234. stylePanelEditor.className = "cesium-cesiumInspector-styleEditor";
  235. stylePanelEditor.appendChild(styleEditor);
  236. const closeStylesBtn = makeButton("compileStyle", "Compile (Ctrl+Enter)");
  237. stylePanelEditor.appendChild(closeStylesBtn);
  238. const errorBox = document.createElement("div");
  239. errorBox.className = "cesium-cesiumInspector-error";
  240. errorBox.setAttribute("data-bind", "text: editorError");
  241. stylePanelEditor.appendChild(errorBox);
  242. tileDebugLabelsPanelContents.appendChild(
  243. createCheckbox("Show Picked Only", "showOnlyPickedTileDebugLabel")
  244. );
  245. tileDebugLabelsPanelContents.appendChild(
  246. createCheckbox("Geometric Error", "showGeometricError")
  247. );
  248. tileDebugLabelsPanelContents.appendChild(
  249. createCheckbox("Rendering Statistics", "showRenderingStatistics")
  250. );
  251. tileDebugLabelsPanelContents.appendChild(
  252. createCheckbox("Memory Usage (MB)", "showMemoryUsage")
  253. );
  254. tileDebugLabelsPanelContents.appendChild(createCheckbox("Url", "showUrl"));
  255. optimizationPanelContents.appendChild(
  256. createCheckbox("Skip Tile LODs", "skipLevelOfDetail")
  257. );
  258. const skipScreenSpaceErrorFactorContainer = document.createElement("div");
  259. skipScreenSpaceErrorFactorContainer.appendChild(
  260. makeRangeInput("skipScreenSpaceErrorFactor", 1, 50, 1, "Skip SSE Factor")
  261. );
  262. optimizationPanelContents.appendChild(skipScreenSpaceErrorFactorContainer);
  263. const baseScreenSpaceError = document.createElement("div");
  264. baseScreenSpaceError.appendChild(
  265. makeRangeInput(
  266. "baseScreenSpaceError",
  267. 0,
  268. 4096,
  269. 1,
  270. "SSE before skipping LOD"
  271. )
  272. );
  273. optimizationPanelContents.appendChild(baseScreenSpaceError);
  274. const skipLevelsContainer = document.createElement("div");
  275. skipLevelsContainer.appendChild(
  276. makeRangeInput("skipLevels", 0, 10, 1, "Min. levels to skip")
  277. );
  278. optimizationPanelContents.appendChild(skipLevelsContainer);
  279. optimizationPanelContents.appendChild(
  280. createCheckbox(
  281. "Load only tiles that meet the max SSE.",
  282. "immediatelyLoadDesiredLevelOfDetail"
  283. )
  284. );
  285. optimizationPanelContents.appendChild(
  286. createCheckbox("Load siblings of visible tiles", "loadSiblings")
  287. );
  288. knockout.applyBindings(viewModel, element);
  289. }
  290. Object.defineProperties(Cesium3DTilesInspector.prototype, {
  291. /**
  292. * Gets the parent container.
  293. * @memberof Cesium3DTilesInspector.prototype
  294. *
  295. * @type {Element}
  296. */
  297. container: {
  298. get: function () {
  299. return this._container;
  300. },
  301. },
  302. /**
  303. * Gets the view model.
  304. * @memberof Cesium3DTilesInspector.prototype
  305. *
  306. * @type {Cesium3DTilesInspectorViewModel}
  307. */
  308. viewModel: {
  309. get: function () {
  310. return this._viewModel;
  311. },
  312. },
  313. });
  314. /**
  315. * @returns {Boolean} true if the object has been destroyed, false otherwise.
  316. */
  317. Cesium3DTilesInspector.prototype.isDestroyed = function () {
  318. return false;
  319. };
  320. /**
  321. * Destroys the widget. Should be called if permanently
  322. * removing the widget from layout.
  323. */
  324. Cesium3DTilesInspector.prototype.destroy = function () {
  325. knockout.cleanNode(this._element);
  326. this._container.removeChild(this._element);
  327. this.viewModel.destroy();
  328. return destroyObject(this);
  329. };
  330. function makeRangeInput(property, min, max, step, text, displayProperty) {
  331. displayProperty = defaultValue(displayProperty, property);
  332. const input = document.createElement("input");
  333. input.setAttribute("data-bind", `value: ${displayProperty}`);
  334. input.type = "number";
  335. const slider = document.createElement("input");
  336. slider.type = "range";
  337. slider.min = min;
  338. slider.max = max;
  339. slider.step = step;
  340. slider.setAttribute("data-bind", `valueUpdate: "input", value: ${property}`);
  341. const wrapper = document.createElement("div");
  342. wrapper.appendChild(slider);
  343. const container = document.createElement("div");
  344. container.className = "cesium-cesiumInspector-slider";
  345. container.appendChild(document.createTextNode(text));
  346. container.appendChild(input);
  347. container.appendChild(wrapper);
  348. return container;
  349. }
  350. function makeButton(action, text, active) {
  351. const button = document.createElement("button");
  352. button.type = "button";
  353. button.textContent = text;
  354. button.className = "cesium-cesiumInspector-pickButton";
  355. let binding = `click: ${action}`;
  356. if (defined(active)) {
  357. binding += `, css: {"cesium-cesiumInspector-pickButtonHighlight" : ${active}}`;
  358. }
  359. button.setAttribute("data-bind", binding);
  360. return button;
  361. }
  362. export default Cesium3DTilesInspector;