-
Notifications
You must be signed in to change notification settings - Fork 0
/
3dtilesProcessing.js
138 lines (122 loc) · 4.63 KB
/
3dtilesProcessing.js
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
import * as THREE from 'three';
import * as itowns from 'itowns';
const boundingVolumeBox = new THREE.Box3();
const boundingVolumeSphere = new THREE.Sphere();
let isReversed = false;
let mousePosition = null;
let useCameraPosition = false;
// This method is a copy of the `computeNodeSSE` by iTowns
// but is using either camera position or mouse position
// https://github.com/iTowns/itowns/blob/7a9457075067afa1a7aa2dc3cb72999033105ff6/src/Process/3dTilesProcessing.js#L257
const computeNodeSSE = (camera, node) => {
node.distance = 0;
let position = null;
let preSSE = camera._preSSE;
if (useCameraPosition || mousePosition == null)
position = camera.camera3D.position;
else {
position = mousePosition;
preSSE = preSSE / 10;
}
if (node.boundingVolume.region) {
boundingVolumeBox.copy(node.boundingVolume.region.box3D);
boundingVolumeBox.applyMatrix4(node.boundingVolume.region.matrixWorld);
node.distance = boundingVolumeBox.distanceToPoint(position);
} else if (node.boundingVolume.box) {
boundingVolumeBox.copy(node.boundingVolume.box);
boundingVolumeBox.applyMatrix4(node.matrixWorld);
node.distance = boundingVolumeBox.distanceToPoint(position);
} else if (node.boundingVolume.sphere) {
boundingVolumeSphere.copy(node.boundingVolume.sphere);
boundingVolumeSphere.applyMatrix4(node.matrixWorld);
node.distance = Math.max(
0.0,
boundingVolumeSphere.distanceToPoint(position)
);
} else return Infinity;
if (node.distance === 0) return Infinity;
return preSSE * (node.geometricError / node.distance);
};
// This method is a copy of the `$3dTilesSubdivisionControl` by iTowns
// but does the opposite of what its suppose to do
// https://github.com/iTowns/itowns/blob/7a9457075067afa1a7aa2dc3cb72999033105ff6/src/Process/3dTilesProcessing.js#L374
const reverseSubdivision = (context, layer, node) => {
if (layer.tileset.tiles[node.tileId].children === undefined) return false;
if (layer.tileset.tiles[node.tileId].isTileset) return true;
const sse = computeNodeSSE(context.camera, node);
if (node.parent.type === 'Object3D') return sse < layer.sseThreshold;
else return sse > layer.sseThreshold;
};
// This method is a copy of the `$3dTilesSubdivisionControl` by iTowns
// but uses the local "computeNodeSSE" method
// https://github.com/iTowns/itowns/blob/7a9457075067afa1a7aa2dc3cb72999033105ff6/src/Process/3dTilesProcessing.js#L374
const subdivision = (context, layer, node) => {
if (layer.tileset.tiles[node.tileId].children === undefined) return false;
if (layer.tileset.tiles[node.tileId].isTileset) return true;
const sse = computeNodeSSE(context.camera, node);
return sse > layer.sseThreshold;
};
function culling(layer, camera, node, tileMatrixWorld) {
if (!node.transform) return false;
let cameraPos = camera.camera3D.position;
let box = node.boundingVolume.box;
let nodePos = new THREE.Vector3(
tileMatrixWorld.elements[12],
tileMatrixWorld.elements[13],
tileMatrixWorld.elements[14]
);
let box_min = new THREE.Vector3(
nodePos.x + box.min.x,
nodePos.y + box.min.y,
nodePos.z + box.min.z
);
let box_max = new THREE.Vector3(
nodePos.x + box.max.x,
nodePos.y + box.max.y,
nodePos.z + box.max.z
);
let dx = Math.max(box_min.x - cameraPos.x, 0, cameraPos.x - box_max.x);
let dy = Math.max(box_min.y - cameraPos.y, 0, cameraPos.y - box_max.y);
let dz = Math.max(box_min.z - cameraPos.z, 0, cameraPos.z - box_max.z);
let distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
return distance > 20000;
}
const reversedRefinement = () => {
return itowns.process3dTilesNode(itowns.$3dTilesCulling, reverseSubdivision);
};
const refinement = () => {
return itowns.process3dTilesNode(itowns.$3dTilesCulling, subdivision);
};
const distanceCulling = () => {
return itowns.process3dTilesNode(culling, itowns.$3dTilesSubdivisionControl);
};
export function reverseRefinement(c3dtilesLayers) {
if (isReversed) {
c3dtilesLayers.forEach(function (layer) {
layer.update = refinement();
});
isReversed = false;
} else {
c3dtilesLayers.forEach(function (layer) {
layer.update = reversedRefinement();
});
isReversed = true;
}
}
export function setLayersDefaultRefinement(c3dtilesLayers) {
c3dtilesLayers.forEach(function (layer) {
layer.update = refinement();
});
}
export function setLayersDistanceCulling(c3dtilesLayers) {
c3dtilesLayers.forEach(function (layer) {
layer.update = distanceCulling();
});
}
export function switchPositionReference() {
useCameraPosition = !useCameraPosition;
return useCameraPosition;
}
export function setMousePosition(position) {
mousePosition = position;
}