├── .nvmrc
├── src
├── sass
│ ├── _geometry.sass
│ ├── _colors.sass
│ ├── _typography.sass
│ └── home.sass
├── textures
│ ├── agri-small-dem.tif
│ ├── agri-medium-dem.tif
│ ├── agri-medium-autumn.jpg
│ ├── agri-small-autumn.jpg
│ └── agri-small-winter.jpg
├── templates
│ └── index.html
└── js
│ ├── vendor
│ └── Detector.js
│ └── index.js
├── .babelrc
├── renovate.json
├── preview.gif
├── .eslintignore
├── .prettierrc
├── .prettierignore
├── webpack.prod.js
├── .gitignore
├── webpack.dev.js
├── .eslintrc
├── wipe-dependencies.js
├── LICENSE
├── README.md
├── package.json
└── webpack.common.js
/.nvmrc:
--------------------------------------------------------------------------------
1 | v16.14.2
2 |
--------------------------------------------------------------------------------
/src/sass/_geometry.sass:
--------------------------------------------------------------------------------
1 | $footer-height: 50px
2 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env"],
3 | "plugins": []
4 | }
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "config:base"
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/src/sass/_colors.sass:
--------------------------------------------------------------------------------
1 | $description-color: #f00
2 | $header-color: #0f0
3 |
--------------------------------------------------------------------------------
/preview.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orabazu/threejs-dem-visualizer/HEAD/preview.gif
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | *.d.ts
4 | *.config.js
5 | .json
6 | src/js/vendor
--------------------------------------------------------------------------------
/src/textures/agri-small-dem.tif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orabazu/threejs-dem-visualizer/HEAD/src/textures/agri-small-dem.tif
--------------------------------------------------------------------------------
/src/textures/agri-medium-dem.tif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orabazu/threejs-dem-visualizer/HEAD/src/textures/agri-medium-dem.tif
--------------------------------------------------------------------------------
/src/textures/agri-medium-autumn.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orabazu/threejs-dem-visualizer/HEAD/src/textures/agri-medium-autumn.jpg
--------------------------------------------------------------------------------
/src/textures/agri-small-autumn.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orabazu/threejs-dem-visualizer/HEAD/src/textures/agri-small-autumn.jpg
--------------------------------------------------------------------------------
/src/textures/agri-small-winter.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/orabazu/threejs-dem-visualizer/HEAD/src/textures/agri-small-winter.jpg
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "trailingComma": "es5",
3 | "tabWidth": 2,
4 | "semi": true,
5 | "singleQuote": true,
6 | "printWidth": 100
7 | }
8 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | package.json
2 | package-lock.json
3 | node_modules
4 | dist
5 | build
6 |
7 | # Ignore all HTML files:
8 | *.json
9 | webpack.*
10 |
--------------------------------------------------------------------------------
/webpack.prod.js:
--------------------------------------------------------------------------------
1 | const { merge } = require('webpack-merge');
2 | const common = require('./webpack.common.js');
3 |
4 | module.exports = merge(common, {
5 | mode: 'production',
6 | });
--------------------------------------------------------------------------------
/src/sass/_typography.sass:
--------------------------------------------------------------------------------
1 | // 1rem in most browsers is 16px, so 1.125rem is 18px
2 | $description-font-size: 1.125rem
3 | $header-font-size: 3rem
4 | $header-font-family: 'Raleway', 'Open Sans', sans-serif
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OSX
2 | .DS_Store
3 |
4 | # editor
5 | .vscode/
6 |
7 | node_modules/
8 |
9 |
10 | # webpack bundles
11 | dist/
12 | build/
13 |
14 | # unignore the favicon
15 | !/build/favicon.ico
16 |
17 |
18 | # logs
19 | *.log
20 |
21 | # linters
22 | .eslintrc.json
23 |
24 | # aux files
25 | src/textures/**.xml
26 | stats.json
27 |
28 |
29 |
--------------------------------------------------------------------------------
/webpack.dev.js:
--------------------------------------------------------------------------------
1 | const { merge } = require('webpack-merge');
2 | const ESLintPlugin = require('eslint-webpack-plugin');
3 | const common = require('./webpack.common.js');
4 |
5 | module.exports = merge(common, {
6 | mode: 'development',
7 | devtool: 'eval-cheap-module-source-map', // TODO add multiple webpack conf
8 | performance: {
9 | hints: "warning"
10 | },
11 | plugins: [new ESLintPlugin()],
12 | });
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "parser": "@babel/eslint-parser",
4 | "parserOptions": {
5 | "ecmaVersion": 2020
6 | },
7 | "extends": [
8 | "eslint:recommended",
9 | "plugin:prettier/recommended"
10 | ],
11 | "plugins": [
12 | "prettier"
13 | ],
14 | "rules": {
15 | "prettier/prettier": [
16 | "error",
17 | {
18 | "usePrettierrc": true
19 | }
20 | ]
21 | },
22 | "env": {
23 | "browser": true,
24 | "node": true,
25 | "es6": true
26 | },
27 | "globals": {
28 | "GeoTIFF": "readonly"
29 | }
30 | }
--------------------------------------------------------------------------------
/src/sass/home.sass:
--------------------------------------------------------------------------------
1 | @import 'colors'
2 | @import 'geometry'
3 | @import 'typography'
4 |
5 |
6 | body
7 | margin: 0
8 |
9 | h1
10 | color: $header-color
11 | font-family: $header-font-family
12 | font-size: $header-font-size
13 |
14 | .container
15 | height: 80%
16 | width: 80%
17 |
18 | canvas
19 | display: block
20 |
21 | #loader
22 | position: absolute
23 | width: 100vw
24 | height: 100vh
25 | background: linear-gradient(to right, #F44336, #3F51B5);
26 | opacity: 0.7;
27 | transition: all 1.5s;
28 |
29 |
30 | h1
31 | font-family: monospace
32 | text-align: center
33 |
--------------------------------------------------------------------------------
/wipe-dependencies.js:
--------------------------------------------------------------------------------
1 | // https://medium.com/@_jh3y/how-to-update-all-npm-packages-in-your-project-at-once-17a8981860ea
2 | var fs = require("fs"),
3 | wipeDependencies = function() {
4 | var file = fs.readFileSync("package.json"),
5 | content = JSON.parse(file);
6 | for (var devDep in content.devDependencies) {
7 | content.devDependencies[devDep] = "*";
8 | }
9 | for (var dep in content.dependencies) {
10 | content.dependencies[dep] = "*";
11 | }
12 | fs.writeFileSync("package.json", JSON.stringify(content));
13 | };
14 | if (require.main === module) {
15 | wipeDependencies();
16 | } else {
17 | module.exports = wipeDependencies;
18 | }
19 |
--------------------------------------------------------------------------------
/src/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Three.js DEM and Satellite Visualization
7 |
8 |
9 |
10 |
11 |
12 |
13 |
Generating 3D Model ...
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 jackaljack
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # threejs-dem-visualizer
2 |
3 | 
4 |
5 | ## Detailed explanation on Medium:
6 |
7 | https://medium.com/@zubazor/visualizing-a-mountain-using-three-js-landsat-and-srtm-26275c920e34
8 |
9 | ### Features :
10 |
11 | - DEM(Digital Elevation Model) and satellite image data is downloaded from [USGS](https://earthexplorer.usgs.gov/)
12 | - ASTER and LANDSAT satellite's data is used.
13 | - Geotiff files generated using QGIS [QGIS](https://qgis.org/tr/site/)
14 |
15 | ### Installation
16 |
17 | ```
18 | git clone git@github.com:orabazu/threejs-dem-visualizer.git
19 | cd threejs-dem-visualizer
20 |
21 | yarn install
22 | ```
23 |
24 | ### Usage
25 |
26 | Generate all js/css bundles
27 |
28 | ```
29 | yarn build
30 | ```
31 |
32 | Developement
33 |
34 | ```
35 | yarn start
36 | ```
37 |
38 | Go to `localhost:8080` to see your project live!
39 |
40 | ### Credits
41 |
42 | Skeleton of the code is built on https://github.com/jackdbd/threejs-es6-webpack-starter project. I added some css for loading since reading geotiff files take time. If you have problems on build better to follow original instructions.
43 |
44 | Demo of [jonathanlurie](https://github.com/jonathanlurie/ThreejsDEM) and [mapmasters] (http://blog.mastermaps.com/2013/10/terrain-building-with-threejs.html) were realy helpfull to understand the logic of DEM to three.js convertion
45 |
--------------------------------------------------------------------------------
/src/js/vendor/Detector.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author alteredq / http://alteredqualia.com/
3 | * @author mr.doob / http://mrdoob.com/
4 | */
5 |
6 | var Detector = {
7 | canvas: !!window.CanvasRenderingContext2D,
8 | webgl: (function() {
9 | try {
10 | var canvas = document.createElement("canvas");
11 | return !!(
12 | window.WebGLRenderingContext &&
13 | (canvas.getContext("webgl") || canvas.getContext("experimental-webgl"))
14 | );
15 | } catch (e) {
16 | return false;
17 | }
18 | })(),
19 | workers: !!window.Worker,
20 | fileapi: window.File && window.FileReader && window.FileList && window.Blob,
21 |
22 | getWebGLErrorMessage: function() {
23 | var element = document.createElement("div");
24 | element.id = "webgl-error-message";
25 | element.style.fontFamily = "monospace";
26 | element.style.fontSize = "13px";
27 | element.style.fontWeight = "normal";
28 | element.style.textAlign = "center";
29 | element.style.background = "#fff";
30 | element.style.color = "#000";
31 | element.style.padding = "1.5em";
32 | element.style.width = "400px";
33 | element.style.margin = "5em auto 0";
34 |
35 | if (!this.webgl) {
36 | element.innerHTML = window.WebGLRenderingContext
37 | ? [
38 | 'Your graphics card does not seem to support WebGL.
',
39 | 'Find out how to get it here.'
40 | ].join("\n")
41 | : [
42 | 'Your browser does not seem to support WebGL.
',
43 | 'Find out how to get it here.'
44 | ].join("\n");
45 | }
46 |
47 | return element;
48 | },
49 |
50 | addGetWebGLMessage: function(parameters) {
51 | var parent, id, element;
52 |
53 | parameters = parameters || {};
54 |
55 | parent =
56 | parameters.parent !== undefined ? parameters.parent : document.body;
57 | id = parameters.id !== undefined ? parameters.id : "oldie";
58 |
59 | element = Detector.getWebGLErrorMessage();
60 | element.id = id;
61 |
62 | parent.appendChild(element);
63 | }
64 | };
65 |
66 | // browserify support
67 | if (typeof module === "object") {
68 | module.exports = Detector;
69 | }
70 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "threejs-es6-webpack-starter-landsat",
3 | "version": "0.1.1",
4 | "description": "A starter project for Three.js with support for ES6 and Webpack 5",
5 | "scripts": {
6 | "build": "webpack --config webpack.prod.js --progress --env production",
7 | "start": "webpack serve --mode development --config ./webpack.dev.js --open",
8 | "ci": "yarn run test && yarn run coverage",
9 | "deploy": "npx gh-pages -d build",
10 | "format": "prettier --write '{,!(node_modules)/}**/*.{js,jsx}'",
11 | "nuke": "rimraf node_modules && rm yarn.lock",
12 | "predeploy": "yarn build",
13 | "lint": "eslint ./src --ext .js ",
14 | "lint:fix": "eslint ./src --ext .js --fix",
15 | "analyze-bundle": "npx webpack --json > stats.json && yarn webpack-bundle-analyzer stats.json"
16 | },
17 | "repository": "https://github.com/orabazu/threejs-dem-visualizer",
18 | "author": "orabazu ",
19 | "license": "MIT",
20 | "dependencies": {
21 | "three": "^0.145.0"
22 | },
23 | "devDependencies": {
24 | "@babel/core": "^7.19.6",
25 | "@babel/eslint-parser": "^7.19.1",
26 | "@babel/preset-env": "^7.19.4",
27 | "clean-webpack-plugin": "^4.0.0",
28 | "compression-webpack-plugin": "^10.0.0",
29 | "css-loader": "^6.7.1",
30 | "esbuild-loader": "^2.20.0",
31 | "eslint": "^8.25.0",
32 | "eslint-config-prettier": "^8.5.0",
33 | "eslint-plugin-prettier": "^4.2.1",
34 | "eslint-webpack-plugin": "^3.2.0",
35 | "file-loader": "^6.2.0",
36 | "gh-pages": "^4.0.0",
37 | "html-webpack-plugin": "^5.5.0",
38 | "image-webpack-loader": "^8.1.0",
39 | "mini-css-extract-plugin": "^2.6.1",
40 | "node-sass": "^7.0.3",
41 | "prettier": "^2.3.2",
42 | "rimraf": "^3.0.2",
43 | "sass-loader": "^13.1.0",
44 | "style-loader": "^3.3.1",
45 | "webpack": "^5.46.0",
46 | "webpack-bundle-analyzer": "^4.6.1",
47 | "webpack-cli": "^4.10.0",
48 | "webpack-dev-server": "^4.11.1",
49 | "webpack-glsl-loader": "^1.0.1",
50 | "webpack-merge": "^5.8.0"
51 | },
52 | "keywords": [
53 | "threejs",
54 | "three.js",
55 | "boilerplate",
56 | "webpack",
57 | "es6",
58 | "babel",
59 | "sass"
60 | ],
61 | "bugs": {
62 | "url": "https://github.com/orabazu/threejs-dem-visualizer/issues"
63 | },
64 | "homepage": "https://github.com/orabazu/threejs-dem-visualizer"
65 | }
66 |
--------------------------------------------------------------------------------
/webpack.common.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const MiniCssExtractPlugin = require("mini-css-extract-plugin");
3 | const HtmlWebpackPlugin = require("html-webpack-plugin");
4 | const { CleanWebpackPlugin } = require("clean-webpack-plugin");
5 | // const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
6 |
7 | module.exports = {
8 | target: "web",
9 | context: __dirname,
10 | entry: {
11 | home: ["/src/js/index.js", "/src/sass/home.sass"],
12 | },
13 | output: {
14 | path: path.resolve(__dirname, "build"),
15 | filename: "[chunkhash].js",
16 | chunkFilename: "[id].bundle.js"
17 | },
18 | module: {
19 | rules: [
20 | {
21 | test: /\.(js|jsx)$/,
22 | include: [path.resolve(__dirname, "js", "src")],
23 | exclude: [path.resolve(__dirname, "node_modules")],
24 | use: {
25 | loader: "esbuild-loader",
26 | }
27 | },
28 | {
29 | test: /\.(css|sass|scss)$/,
30 | use: [
31 | MiniCssExtractPlugin.loader,
32 | {
33 | loader: "css-loader",
34 | options: {
35 | // modules: true,
36 | // importLoaders allows to configure how many loaders before css-loader should be applied to @imported resources.
37 | // 0 => no loaders (default); 1 => postcss-loader; 2 => postcss-loader, sass-loader
38 | importLoaders: 2,
39 | }
40 | },
41 | {
42 | loader: "sass-loader",
43 | }
44 | ]
45 | },
46 | // rule for textures (images)
47 | {
48 | test: /\.(jpe?g|png|tif)$/i,
49 | include: path.resolve(__dirname, "src", "textures"),
50 | use: [
51 | "file-loader",
52 | {
53 | loader: "image-webpack-loader",
54 | options: {
55 | disable: true, // webpack@2.x and newer
56 | mozjpeg: {
57 | progressive: true,
58 | },
59 | optipng: {
60 | optimizationLevel: 7,
61 | },
62 | gifsicle: {
63 | interlaced: false,
64 | },
65 | pngquant: {
66 | quality: [0.65, 0.90],
67 | speed: 4
68 | },
69 | }
70 | }
71 | ]
72 | }
73 | ]
74 | },
75 | devServer: {
76 | host: "localhost",
77 | port: 8080,
78 | open: true,
79 | hot: true,
80 | historyApiFallback: true,
81 | client: {
82 | overlay: {
83 | errors: true,
84 | warnings: false
85 | }
86 | }
87 | },
88 |
89 | plugins: [
90 | // new BundleAnalyzerPlugin(),
91 | new CleanWebpackPlugin({
92 | root: __dirname,
93 | exclude: ["favicon.ico"],
94 | verbose: true
95 | }),
96 | new MiniCssExtractPlugin({
97 | filename: '[name].[hash].css',
98 | chunkFilename: '[id].[hash].css',
99 | }),
100 | new HtmlWebpackPlugin({
101 | template: path.resolve(__dirname, "src", "templates", "index.html"),
102 | hash: true,
103 | filename: "index.html",
104 | chunks: ["commons", "home"]
105 | }),
106 | ],
107 |
108 | externals: {
109 | GeoTIFF: 'GeoTIFF',
110 | },
111 | };
112 |
--------------------------------------------------------------------------------
/src/js/index.js:
--------------------------------------------------------------------------------
1 | import {
2 | Scene,
3 | PerspectiveCamera,
4 | DirectionalLight,
5 | WebGLRenderer,
6 | PlaneGeometry,
7 | GridHelper,
8 | AxesHelper,
9 | TextureLoader,
10 | MeshLambertMaterial,
11 | DoubleSide,
12 | Mesh,
13 | } from 'three'; // import min because three.js is not tree-shakable for now
14 | import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
15 | import * as Detector from '../js/vendor/Detector';
16 | // TODO: Major performance problems on reading big images
17 | // import terrain from '../textures/agri-medium-dem.tif';
18 | // import mountainImage from '../textures/agri-medium-autumn.jpg';
19 |
20 | import terrain from '../textures/agri-small-dem.tif';
21 | import mountainImage from '../textures/agri-small-autumn.jpg';
22 |
23 | require('../sass/home.sass');
24 |
25 | class Application {
26 | constructor(opts = {}) {
27 | this.width = window.innerWidth;
28 | this.height = window.innerHeight;
29 |
30 | if (opts.container) {
31 | this.container = opts.container;
32 | } else {
33 | const div = Application.createContainer();
34 | document.body.appendChild(div);
35 | this.container = div;
36 | }
37 |
38 | if (Detector.webgl) {
39 | this.init();
40 | this.render();
41 | } else {
42 | // TODO: style warning message
43 | console.log('WebGL NOT supported in your browser!');
44 | const warning = Detector.getWebGLErrorMessage();
45 | this.container.appendChild(warning);
46 | }
47 | }
48 |
49 | init() {
50 | this.scene = new Scene();
51 | this.setupRenderer();
52 | this.setupCamera();
53 | this.setupControls();
54 | this.setupLight();
55 | this.setupTerrainModel();
56 | this.setupHelpers();
57 |
58 | window.addEventListener('resize', () => {
59 | const w = window.innerWidth;
60 | const h = window.innerHeight;
61 | this.renderer.setSize(w, h);
62 | this.camera.aspect = w / h;
63 | this.camera.updateProjectionMatrix();
64 | });
65 | }
66 |
67 | render() {
68 | this.controls.update();
69 | this.renderer.render(this.scene, this.camera);
70 | // when render is invoked via requestAnimationFrame(this.render) there is
71 | // no 'this', so either we bind it explicitly or use an es6 arrow function.
72 | // requestAnimationFrame(this.render.bind(this));
73 | requestAnimationFrame(() => this.render());
74 | }
75 |
76 | static createContainer() {
77 | const div = document.createElement('div');
78 | div.setAttribute('id', 'canvas-container');
79 | div.setAttribute('class', 'container');
80 | return div;
81 | }
82 |
83 | setupRenderer() {
84 | this.renderer = new WebGLRenderer({ antialias: true });
85 | this.renderer.setClearColor(0xd3d3d3); // it's a dark gray
86 | this.renderer.setPixelRatio(window.devicePixelRatio || 1);
87 | this.renderer.setSize(this.width, this.height);
88 | this.renderer.shadowMap.enabled = true;
89 | this.container.appendChild(this.renderer.domElement);
90 | }
91 |
92 | setupCamera() {
93 | const fov = 75;
94 | const aspect = this.width / this.height;
95 | const near = 0.1;
96 | const far = 10000;
97 | this.camera = new PerspectiveCamera(fov, aspect, near, far);
98 | this.camera.position.set(1000, 1000, 1000);
99 | this.camera.lookAt(this.scene.position);
100 | }
101 |
102 | setupControls() {
103 | this.controls = new OrbitControls(this.camera, this.renderer.domElement);
104 | this.controls.enabled = true;
105 | this.controls.maxDistance = 1500;
106 | this.controls.minDistance = 0;
107 | this.controls.autoRotate = true;
108 | }
109 |
110 | setupLight() {
111 | this.light = new DirectionalLight(0xffffff);
112 | this.light.position.set(500, 1000, 250);
113 | this.scene.add(this.light);
114 | // this.scene.add(new AmbientLight(0xeeeeee));
115 | }
116 |
117 | setupTerrainModel() {
118 | const readGeoTif = async () => {
119 | const rawTiff = await GeoTIFF.fromUrl(terrain);
120 | const tifImage = await rawTiff.getImage();
121 | const image = {
122 | width: tifImage.getWidth(),
123 | height: tifImage.getHeight(),
124 | };
125 |
126 | /*
127 | The third and fourth parameter are image segments and we are subtracting one from each,
128 | otherwise our 3D model goes crazy.
129 | https://github.com/mrdoob/three.js/blob/master/src/geometries/PlaneGeometry.js#L57
130 | */
131 | const geometry = new PlaneGeometry(
132 | image.width,
133 | image.height,
134 | image.width - 1,
135 | image.height - 1
136 | );
137 | const data = await tifImage.readRasters({ interleave: true });
138 | console.time('parseGeom');
139 | const arr1 = new Array(geometry.attributes.position.count);
140 | const arr = arr1.fill(1);
141 | arr.forEach((a, index) => {
142 | geometry.attributes.position.setZ(index, (data[index] / 10) * -1);
143 | });
144 | console.timeEnd('parseGeom');
145 |
146 | const texture = new TextureLoader().load(mountainImage);
147 | const material = new MeshLambertMaterial({
148 | wireframe: false,
149 | side: DoubleSide,
150 | map: texture,
151 | });
152 |
153 | const mountain = new Mesh(geometry, material);
154 | mountain.position.y = 0;
155 | mountain.rotation.x = Math.PI / 2;
156 |
157 | this.scene.add(mountain);
158 |
159 | const loader = document.getElementById('loader');
160 | loader.style.opacity = '-1';
161 |
162 | // After a proper animation on opacity, hide element to make canvas clickable again
163 | setTimeout(() => {
164 | loader.style.display = 'none';
165 | }, 1500);
166 | };
167 |
168 | readGeoTif();
169 | }
170 |
171 | setupHelpers() {
172 | const gridHelper = new GridHelper(1000, 40);
173 | this.scene.add(gridHelper);
174 | console.log('The X axis is red. The Y axis is green. The Z axis is blue.');
175 | const axesHelper = new AxesHelper(500);
176 | this.scene.add(axesHelper);
177 | }
178 | }
179 |
180 | (() => {
181 | const app = new Application({
182 | container: document.getElementById('canvas-container'),
183 | });
184 | console.log(app);
185 | })();
186 |
--------------------------------------------------------------------------------