index.html 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. <html lang="en">
  2. <head>
  3. <meta charset="UTF-8">
  4. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  5. <title>3D Tiles Loader: Map overlay</title>
  6. <style>
  7. * {
  8. margin: 0;
  9. padding: 0;
  10. }
  11. body {
  12. width: 100vw;
  13. height: 100vh;
  14. overflow: hidden;
  15. }
  16. #canvas-parent {
  17. width: 100vw;
  18. height: 100vh;
  19. touch-action: none;
  20. }
  21. #guide {
  22. position: fixed;
  23. top: 0;
  24. right: 0;
  25. width: 300px;
  26. padding: 1rem 2rem;
  27. font-family:'Courier New', Courier, monospace;
  28. line-height: 1.2;
  29. background-color: white;
  30. color: black;
  31. }
  32. #guide p {
  33. margin-top: 10px;
  34. }
  35. #stats-widget {
  36. position: absolute;
  37. top: 70px;
  38. left: 10px;
  39. background-color: rgb(255 255 255 / 83%);
  40. padding: 10px;
  41. width: 300px;
  42. word-break: break-all;
  43. visibility: hidden;
  44. }
  45. #button {
  46. position: fixed;
  47. bottom: 16px;
  48. right: 16px;
  49. padding: 12px;
  50. border-radius: 50%;
  51. margin-bottom: 0px;
  52. background-color: #FFF;
  53. opacity: .9;
  54. z-index: 999;
  55. box-shadow: 0 0 4px rgb(0 0 0 / 15%);
  56. }
  57. @media (max-width:480px) {
  58. #guide, #stats-widget { display: none; }
  59. }
  60. </style>
  61. </head>
  62. <body>
  63. <div id="canvas-parent"></div>
  64. <div id="stats-widget"></div>
  65. <div id="guide">
  66. <p>
  67. <span id="example-desc">
  68. Map overlay provided by <b>OpenStreetMap</b> using the <b>geo-three</b> library.
  69. </span>
  70. </p>
  71. <p>
  72. Use arrow keys, mouse wheel/trackpad, or right click to move around, and left click and drag to turn/rotate the camera.
  73. </p>
  74. <p>
  75. <u>Available URL parameters:</u>
  76. <ul>
  77. <li><b>tilesetUrl</b>: Load another tileset json.</li>
  78. </ul>
  79. </p>
  80. </div>
  81. <script async src="https://ga.jspm.io/npm:es-module-shims@1.4.4/dist/es-module-shims.js"></script>
  82. <script type="importmap">
  83. {
  84. "imports": {
  85. "three": "https://cdn.skypack.dev/three@0.137.0",
  86. "three/examples/jsm/loaders/GLTFLoader.js": "https://cdn.skypack.dev/three@v0.137.0/examples/jsm/loaders/GLTFLoader",
  87. "three/examples/jsm/loaders/DRACOLoader.js": "https://cdn.skypack.dev/three@v0.137.0/examples/jsm/loaders/DRACOLoader",
  88. "three/examples/jsm/loaders/KTX2Loader.js": "https://cdn.skypack.dev/three@v0.137.0/examples/jsm/loaders/KTX2Loader",
  89. "three/examples/jsm/controls/OrbitControls": "https://cdn.skypack.dev/three@v0.137.0/examples/jsm/controls/OrbitControls",
  90. "three/examples/jsm/libs/stats.module.js": "https://cdn.skypack.dev/three@v0.137.0/examples/jsm/libs/stats.module",
  91. "@probe.gl/stats" : "https://cdn.skypack.dev/@probe.gl/stats@3.3.1",
  92. "@probe.gl/stats-widget" : "https://cdn.skypack.dev/@probe.gl/stats-widget@3.5.0",
  93. "three-loader-3dtiles" : "../../../dist/three-loader-3dtiles.esm.js",
  94. "geo-three": "https://cdn.skypack.dev/geo-three@0.0.18",
  95. "gsap": "https://cdn.skypack.dev/gsap@3.10.4"
  96. }
  97. }
  98. </script>
  99. <script type='module'>
  100. import {
  101. Scene,
  102. PerspectiveCamera,
  103. WebGLRenderer,
  104. GridHelper,
  105. Clock,
  106. Matrix4,
  107. Euler,
  108. sRGBEncoding
  109. } from 'three';
  110. import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
  111. import { Loader3DTiles, PointCloudColoring, GeoTransform } from 'three-loader-3dtiles';
  112. import { MapView, OpenStreetMapsProvider } from 'geo-three'
  113. import { TweenMax } from 'gsap'
  114. import Stats from 'three/examples/jsm/libs/stats.module.js';
  115. import StatsWidget from '@probe.gl/stats-widget';
  116. const ION_TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJlYWMxMzcyYy0zZjJkLTQwODctODNlNi01MDRkZmMzMjIxOWIiLCJpZCI6OTYyMCwic2NvcGVzIjpbImFzbCIsImFzciIsImdjIl0sImlhdCI6MTU2Mjg2NjI3M30.1FNiClUyk00YH_nWfSGpiQAjR5V2OvREDq1PJ5QMjWQ';
  117. const canvasParent = document.querySelector('#canvas-parent');
  118. const statsParent = document.querySelector('#stats-widget')
  119. const scene = new Scene();
  120. const camera = new PerspectiveCamera(
  121. 45,
  122. 1,
  123. 100,
  124. 1000000,
  125. );
  126. const renderer = new WebGLRenderer();
  127. renderer.preserveDrawingBuffer = true;
  128. const clock = new Clock()
  129. const controls = new OrbitControls( camera, canvasParent);
  130. controls.listenToKeyEvents( window );
  131. canvasParent.appendChild(renderer.domElement);
  132. const threeJsStats = new Stats();
  133. threeJsStats.domElement.style.position = 'absolute';
  134. threeJsStats.domElement.style.top = '10px';
  135. threeJsStats.domElement.style.left = '10px';
  136. canvasParent.appendChild( threeJsStats.domElement );
  137. const queryParams = new URLSearchParams(document.location.search);
  138. if (queryParams.get('tilesetUrl')) {
  139. renderer.outputEncoding = sRGBEncoding;
  140. }
  141. loadTileset();
  142. let tilesRuntime = undefined;
  143. let tilesModel = undefined;
  144. let statsRuntime = undefined;
  145. const provider = new OpenStreetMapsProvider();
  146. const map = new MapView(MapView.PLANAR, provider);
  147. scene.add(map)
  148. async function loadTileset() {
  149. const result = await Loader3DTiles.load(
  150. {
  151. url:
  152. queryParams.get('tilesetUrl') ??
  153. "https://assets.cesium.com/43978/tileset.json",
  154. renderer: renderer,
  155. options: {
  156. cesiumIONToken: queryParams.get('tilesetUrl') ? null : ION_TOKEN,
  157. dracoDecoderPath: 'https://cdn.jsdelivr.net/npm/three@0.137.0/examples/js/libs/draco',
  158. basisTranscoderPath: 'https://cdn.jsdelivr.net/npm/three@0.137.0/examples/js/libs/basis',
  159. pointCloudColoring: PointCloudColoring.RGB,
  160. maximumScreenSpaceError: queryParams.get('sse') ?? 6,
  161. geoTransform: GeoTransform.Mercator
  162. }
  163. }
  164. );
  165. const {model, runtime} = result;
  166. tilesRuntime = runtime;
  167. tilesModel = model;
  168. scene.add(model);
  169. statsRuntime = new StatsWidget(runtime.getStats(), {container: statsParent });
  170. statsParent.style.visibility = 'visible';
  171. if (!queryParams.get('tilesetUrl')) {
  172. // Scaling the scan to align with Maps, and bringing it up above the map
  173. model.scale.set(1.27, 1.27, 1.27);
  174. model.translateZ(230);
  175. }
  176. camera.position.copy(model.position);
  177. camera.translateY(80000);
  178. controls.target.copy(model.position);
  179. controls.update();
  180. zoomIn();
  181. }
  182. function zoomIn() {
  183. controls.enabled = false
  184. TweenMax.to( camera.position, {
  185. duration: 5,
  186. y: queryParams.get('tilesetUrl') ? 100 : 3000,
  187. onUpdate: function() {
  188. controls.update();
  189. },
  190. onComplete: function() {
  191. controls.enabled = true;
  192. camera.near = 1;
  193. camera.updateProjectionMatrix();
  194. }
  195. } );
  196. }
  197. function render(t) {
  198. const dt = clock.getDelta()
  199. controls.update();
  200. if (tilesRuntime) {
  201. tilesRuntime.update(dt, renderer, camera);
  202. }
  203. if (statsRuntime) {
  204. statsRuntime.update();
  205. }
  206. renderer.render(scene, camera);
  207. threeJsStats.update();
  208. window.requestAnimationFrame(render);
  209. }
  210. onWindowResize();
  211. function onWindowResize() {
  212. renderer.setSize(canvasParent.clientWidth, canvasParent.clientHeight);
  213. camera.aspect = canvasParent.clientWidth / canvasParent.clientHeight;
  214. camera.updateProjectionMatrix();
  215. }
  216. window.addEventListener('resize', onWindowResize)
  217. render();
  218. </script>
  219. <a id="button" target="_blank" href="https://github.com/nytimes/three-loader-3dtiles/blob/master/examples/demos/map-overlay/index.html" title="View source code for demo" style=""><img src="../ic_code_black_24dp.svg"></a>
  220. </body>
  221. </html>