forked from peterqliu/threebox
-
Notifications
You must be signed in to change notification settings - Fork 150
/
09-raycaster.html
229 lines (195 loc) · 8.16 KB
/
09-raycaster.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
<!doctype html>
<head>
<title>Threebox raycaster of Objects3D, 3D models and Fill-extrusions</title>
<link href="https://api.mapbox.com/mapbox-gl-js/v2.2.0/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v2.2.0/mapbox-gl.js"></script>
<script src="../dist/threebox.js" type="text/javascript"></script>
<link href="../dist/threebox.css" rel="stylesheet" />
<script src="config.js"></script>
<style>
body, html {
width: 100%;
height: 100%;
margin: 0;
}
#map {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div id='map' class='map'></div>
<script type="module">
if (!config) console.error("Config not set! Make a copy of 'config_template.js', add in your access token, and save the file as 'config.js'.");
mapboxgl.accessToken = config.accessToken;
let origin1 = [-122.3512, 47.6202, 0];
let origin2 = [-122.34548, 47.617538, 0];
let origin3 = [-122.3491, 47.6207, 0];
let minZoom = 12;
let names = {
compositeSource: "composite",
compositeSourceLayer: "building",
compositeLayer: "3d-buildings"
}
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/outdoors-v11',
center: origin3,
zoom: 16.5,
pitch: 60,
antialias: true,
heading: 0, hash: true
});
// we can add Threebox to mapbox to add built-in mouseover/mouseout and click behaviors
window.tb = new Threebox(
map,
map.getCanvas().getContext('webgl'),
{
defaultLights: true,
enableSelectingFeatures: true, //change this to false to disable fill-extrusion features selection
enableSelectingObjects: true, //change this to false to disable 3D objects selection
enableDraggingObjects: true, //change this to false to disable 3D objects drag & move once selected
enableRotatingObjects: true, //change this to false to disable 3D objects rotation once selected
enableTooltips: true, // change this to false to disable default tooltips on fill-extrusion and 3D models
}
);
var redMaterial = new THREE.MeshPhongMaterial({
color: 0x660000,
side: THREE.DoubleSide
});
import { GUI } from 'https://threejs.org/examples/jsm/libs/dat.gui.module.js';
import Stats from 'https://threejs.org/examples/jsm/libs/stats.module.js';
let stats, gui;
function animate() {
requestAnimationFrame(animate);
stats.update();
}
var active = false
map.on('style.load', function () {
init();
map.addLayer(createCompositeLayer());
map.addLayer({
id: 'custom_layer',
type: 'custom',
renderingMode: '3d',
onAdd: function (map, mbxContext) {
tb.altitudeStep = 1;
//// initialize geometry and material of our cube object
var geometry = new THREE.BoxGeometry(30, 60, 120);
//[jscastro] we add a cube with no bbox and despite is raycasted
let cube = new THREE.Mesh(geometry, redMaterial);
cube = tb.Object3D({ obj: cube, units: 'meters', bbox: false})
.setCoords(origin1);
cube.addTooltip("This object is selectable but without bounding box", true);
tb.add(cube);
//[jscastro] we add a sphere
let sphere = tb.sphere(
{
radius: 30,
units: 'meters',
sides: 120,
color: 'green',
material: 'MeshPhysicalMaterial',
}
).setCoords(origin2);
tb.add(sphere);
// import soldier from an external glb file, scaling up its size 20x
// IMPORTANT: .glb is not a standard MIME TYPE, you'll have to add it to your web server config,
// otherwise you'll receive a 404 error
// Attribution: Soldier animated model by T. Choonyung at https://www.mixamo.com
// from https://www.mixamo.com/#/?page=1&query=vanguard&type=Character
var options = {
obj: './models/soldier.glb',
type: 'gltf',
scale: 100,
units: 'meters',
rotation: { x: 90, y: 0, z: 0 }, //default rotation
anchor: 'center'
}
tb.loadObj(options, function (model) {
//origin3[2] += model.modelSize.z;
let soldier = model.setCoords(origin3);
model.addLabel(createLabelIcon("Status: Radioactive"), true); //+ '
' + feature.properties.name
model.addTooltip("This is a custom tooltip", true);
tb.add(soldier);
// play animation 3, for 10 seconds
soldier.playAnimation(options = { animation: 1, duration: 10000 });
})
},
render: function (gl, matrix) {
tb.update();
}
});
});
function createCompositeLayer() {
let layer = {
'id': names.compositeLayer,
'source': names.compositeSource,
'source-layer': names.compositeSourceLayer,
'filter': ['==', 'extrude', 'true'],
'type': 'fill-extrusion',
'minzoom': minZoom,
'paint': {
'fill-extrusion-color':
[
'case',
['boolean', ['feature-state', 'select'], false],
"lightgreen",
['boolean', ['feature-state', 'hover'], false],
"lightblue",
'#aaa'
],
// use an 'interpolate' expression to add a smooth transition effect to the
// buildings as the user zooms in
'fill-extrusion-height': [
'interpolate',
['linear'],
['zoom'],
minZoom,
0,
minZoom + 0.05,
['get', 'height']
],
'fill-extrusion-base': [
'interpolate',
['linear'],
['zoom'],
minZoom,
0,
minZoom + 0.05,
['get', 'min_height']
],
'fill-extrusion-opacity': 0.9
}
};
return layer;
}
function createLabelIcon(text) {
let popup = document.createElement('div');
popup.innerHTML = '<span title="' + text + '" style="font-size: 30px;color: yellow;">☢</span>';
return popup;
}
let api = {
fov: Math.atan(3 / 4) * 180 / Math.PI,
orthographic: false
};
function init() {
// stats
stats = new Stats();
map.getContainer().appendChild(stats.dom);
animate();
// gui
gui = new GUI();
// going below 2.5 degrees will start to generate serious issues with polygons in fill-extrusions and 3D meshes
// going above 45 degrees will also produce clipping and performance issues
gui.add(api, 'fov', 2.5, 45.0).step(0.1).onChange(changeFOV);
// this will set 0.01 degrees in Mapbox which is the minimum possible and an OrthographicCamera in three.js
gui.add(api, 'orthographic').name('pure orthographic').onChange(changeFOV);
}
function changeFOV() {
tb.orthographic = api.orthographic;
tb.fov = api.fov;
}
</script>
</body>