Skip to content

Commit 0c93a3d

Browse files
committed
cleaned up more
1 parent 8a9083e commit 0c93a3d

File tree

4 files changed

+330
-726
lines changed

4 files changed

+330
-726
lines changed

src/DebugVisualization.ts

Lines changed: 300 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,300 @@
1+
import { Scene, MeshBuilder, StandardMaterial, Color3, Vector3 } from '@babylonjs/core';
2+
3+
export class DebugVisualization {
4+
private babylonScene: Scene;
5+
private cesiumTileset: any;
6+
7+
private cameraUpdatePaused = false;
8+
private boundingVolumesVisible = false;
9+
private frustumVisible = false;
10+
11+
private frustumVisualization: any = null;
12+
private boundingVolumeWireframes: any[] = [];
13+
private frustumWireframes: any[] = [];
14+
private lastFrustumUpdate = 0;
15+
16+
constructor(babylonScene: Scene, cesiumTileset: any) {
17+
this.babylonScene = babylonScene;
18+
this.cesiumTileset = cesiumTileset;
19+
this.setupKeyboardControls();
20+
}
21+
22+
private setupKeyboardControls(): void {
23+
document.addEventListener('keydown', (event) => {
24+
switch (event.key.toLowerCase()) {
25+
case ' ':
26+
event.preventDefault();
27+
this.toggleCameraStepMode();
28+
break;
29+
case 'b':
30+
event.preventDefault();
31+
this.toggleBoundingVolumeVisibility();
32+
break;
33+
case 'f':
34+
event.preventDefault();
35+
this.toggleFrustumVisibility();
36+
break;
37+
}
38+
});
39+
}
40+
41+
get isPaused(): boolean {
42+
return this.cameraUpdatePaused;
43+
}
44+
45+
private toggleCameraStepMode(): void {
46+
this.cameraUpdatePaused = !this.cameraUpdatePaused;
47+
console.log(this.cameraUpdatePaused ? '⏸️ Camera paused' : '▶️ Camera resumed');
48+
}
49+
50+
private toggleBoundingVolumeVisibility(): void {
51+
this.boundingVolumesVisible = !this.boundingVolumesVisible;
52+
console.log(this.boundingVolumesVisible ? '🔳 Bounding volumes on' : '🔳 Bounding volumes off');
53+
54+
if (this.boundingVolumesVisible) {
55+
this.createBoundingVolumeWireframes();
56+
} else {
57+
this.clearBoundingVolumeWireframes();
58+
}
59+
}
60+
61+
private toggleFrustumVisibility(): void {
62+
this.frustumVisible = !this.frustumVisible;
63+
console.log(this.frustumVisible ? '🔲 Frustum on' : '🔲 Frustum off');
64+
65+
if (this.frustumVisible) {
66+
this.createFrustumWireframe();
67+
} else {
68+
this.clearFrustumWireframes();
69+
}
70+
}
71+
72+
updateVisualizations(camera: any, frameNumber: number): void {
73+
if (this.frustumVisible) {
74+
this.updateFrustumVisualization(camera, frameNumber);
75+
}
76+
}
77+
78+
private updateFrustumVisualization(camera: any, frameNumber: number): void {
79+
if (frameNumber - this.lastFrustumUpdate > 60) {
80+
this.lastFrustumUpdate = frameNumber;
81+
this.visualizeCesiumFrustum(camera, camera.frustum);
82+
}
83+
}
84+
85+
private visualizeCesiumFrustum(cesiumCamera: any, frustum: any): void {
86+
try {
87+
if (this.frustumVisualization) {
88+
this.frustumVisualization.dispose();
89+
this.frustumVisualization = null;
90+
}
91+
92+
if (!this.babylonScene) return;
93+
94+
const corners = this.getFrustumCorners(cesiumCamera, frustum);
95+
const babylonCorners = corners.map((corner) => new Vector3(corner.x, corner.z, -corner.y));
96+
97+
this.frustumVisualization = MeshBuilder.CreateBox(
98+
'frustumViz',
99+
{ size: 0.1 },
100+
this.babylonScene
101+
);
102+
this.frustumVisualization.setEnabled(false);
103+
104+
const frustumMaterial = new StandardMaterial('frustumMaterial', this.babylonScene);
105+
frustumMaterial.emissiveColor = new Color3(1, 0, 1);
106+
frustumMaterial.disableLighting = true;
107+
frustumMaterial.backFaceCulling = false;
108+
109+
this.drawFrustumLines(babylonCorners, frustumMaterial, this.babylonScene);
110+
} catch (error) {
111+
console.error('❌ Failed to create frustum visualization:', error);
112+
}
113+
}
114+
115+
private getFrustumCorners(cesiumCamera: any, frustum: any): any[] {
116+
const position = cesiumCamera.position;
117+
const direction = cesiumCamera.direction;
118+
const up = cesiumCamera.up;
119+
const right = cesiumCamera.right;
120+
121+
const nearHeight = 2 * Math.tan(frustum.fov / 2) * frustum.near;
122+
const nearWidth = nearHeight * frustum.aspectRatio;
123+
const farHeight = 2 * Math.tan(frustum.fov / 2) * frustum.far;
124+
const farWidth = farHeight * frustum.aspectRatio;
125+
126+
const nearCenter = {
127+
x: position.x + direction.x * frustum.near,
128+
y: position.y + direction.y * frustum.near,
129+
z: position.z + direction.z * frustum.near,
130+
};
131+
132+
const farCenter = {
133+
x: position.x + direction.x * frustum.far,
134+
y: position.y + direction.y * frustum.far,
135+
z: position.z + direction.z * frustum.far,
136+
};
137+
138+
return [
139+
position,
140+
{
141+
x: nearCenter.x - (right.x * nearWidth) / 2 - (up.x * nearHeight) / 2,
142+
y: nearCenter.y - (right.y * nearWidth) / 2 - (up.y * nearHeight) / 2,
143+
z: nearCenter.z - (right.z * nearWidth) / 2 - (up.z * nearHeight) / 2,
144+
},
145+
{
146+
x: nearCenter.x + (right.x * nearWidth) / 2 - (up.x * nearHeight) / 2,
147+
y: nearCenter.y + (right.y * nearWidth) / 2 - (up.y * nearHeight) / 2,
148+
z: nearCenter.z + (right.z * nearWidth) / 2 - (up.z * nearHeight) / 2,
149+
},
150+
{
151+
x: nearCenter.x + (right.x * nearWidth) / 2 + (up.x * nearHeight) / 2,
152+
y: nearCenter.y + (right.y * nearWidth) / 2 + (up.y * nearHeight) / 2,
153+
z: nearCenter.z + (right.z * nearWidth) / 2 + (up.z * nearHeight) / 2,
154+
},
155+
{
156+
x: nearCenter.x - (right.x * nearWidth) / 2 + (up.x * nearHeight) / 2,
157+
y: nearCenter.y - (right.y * nearWidth) / 2 + (up.y * nearHeight) / 2,
158+
z: nearCenter.z - (right.z * nearWidth) / 2 + (up.z * nearHeight) / 2,
159+
},
160+
{
161+
x: farCenter.x - (right.x * farWidth) / 2 - (up.x * farHeight) / 2,
162+
y: farCenter.y - (right.y * farWidth) / 2 - (up.y * farHeight) / 2,
163+
z: farCenter.z - (right.z * farWidth) / 2 - (up.z * farHeight) / 2,
164+
},
165+
{
166+
x: farCenter.x + (right.x * farWidth) / 2 - (up.x * farHeight) / 2,
167+
y: farCenter.y + (right.y * farWidth) / 2 - (up.y * farHeight) / 2,
168+
z: farCenter.z + (right.z * farWidth) / 2 - (up.z * farHeight) / 2,
169+
},
170+
{
171+
x: farCenter.x + (right.x * farWidth) / 2 + (up.x * farHeight) / 2,
172+
y: farCenter.y + (right.y * farWidth) / 2 + (up.y * farHeight) / 2,
173+
z: farCenter.z + (right.z * farWidth) / 2 + (up.z * farHeight) / 2,
174+
},
175+
{
176+
x: farCenter.x - (right.x * farWidth) / 2 + (up.x * farHeight) / 2,
177+
y: farCenter.y - (right.y * farWidth) / 2 + (up.y * farHeight) / 2,
178+
z: farCenter.z - (right.z * farWidth) / 2 + (up.z * farHeight) / 2,
179+
},
180+
];
181+
}
182+
183+
private drawFrustumLines(
184+
babylonCorners: Vector3[],
185+
_material: StandardMaterial,
186+
scene: Scene
187+
): void {
188+
try {
189+
const nearIndices = [1, 2, 3, 4, 1];
190+
const farIndices = [5, 6, 7, 8, 5];
191+
const connectionIndices = [
192+
[1, 5],
193+
[2, 6],
194+
[3, 7],
195+
[4, 8],
196+
];
197+
198+
[nearIndices, farIndices].forEach((indices, groupIndex) => {
199+
for (let i = 0; i < indices.length - 1; i++) {
200+
const line = MeshBuilder.CreateLines(
201+
`frustumLine_${groupIndex}_${i}`,
202+
{ points: [babylonCorners[indices[i]], babylonCorners[indices[i + 1]]] },
203+
scene
204+
);
205+
line.color = Color3.FromHexString('#ff00ff');
206+
line.parent = this.frustumVisualization;
207+
line.setEnabled(true);
208+
}
209+
});
210+
211+
connectionIndices.forEach(([start, end], i) => {
212+
const line = MeshBuilder.CreateLines(
213+
`frustumConnection_${i}`,
214+
{ points: [babylonCorners[start], babylonCorners[end]] },
215+
scene
216+
);
217+
line.color = Color3.FromHexString('#ff00ff');
218+
line.parent = this.frustumVisualization;
219+
line.setEnabled(true);
220+
});
221+
222+
const directionLine = MeshBuilder.CreateLines(
223+
'frustumDirection',
224+
{ points: [babylonCorners[0], babylonCorners[1]] },
225+
scene
226+
);
227+
directionLine.color = Color3.FromHexString('#00ffff');
228+
directionLine.parent = this.frustumVisualization;
229+
directionLine.setEnabled(true);
230+
231+
this.frustumVisualization.setEnabled(true);
232+
} catch (error) {
233+
console.error('❌ Failed to draw frustum lines:', error);
234+
}
235+
}
236+
237+
private createBoundingVolumeWireframes(): void {
238+
const selectedTiles = this.cesiumTileset._selectedTiles;
239+
if (!selectedTiles?.length) return;
240+
241+
selectedTiles.forEach((tile: any, index: number) => {
242+
const boundingVolume = tile.boundingVolume;
243+
if (!boundingVolume?.boundingSphere) return;
244+
245+
const sphere = boundingVolume.boundingSphere;
246+
const cesiumCenter = sphere.center;
247+
const cesiumRadius = sphere.radius;
248+
249+
const babylonCenter = new Vector3(cesiumCenter.x, cesiumCenter.z, -cesiumCenter.y);
250+
251+
const wireframeSphere = MeshBuilder.CreateSphere(
252+
`boundingVolume_${index}`,
253+
{ diameter: cesiumRadius * 2, segments: 8 },
254+
this.babylonScene
255+
);
256+
wireframeSphere.position = babylonCenter;
257+
258+
const material = new StandardMaterial(`boundingMaterial_${index}`, this.babylonScene);
259+
material.wireframe = true;
260+
const depthNormalized = Math.min(tile._depth / 10, 1);
261+
// Dark red (0.8, 0.1, 0.1) to light blue (0.3, 0.8, 1.0)
262+
const red = 0.8 - depthNormalized * 0.5; // 0.8 -> 0.3
263+
const green = 0.1 + depthNormalized * 0.7; // 0.1 -> 0.8
264+
const blue = 0.1 + depthNormalized * 0.9; // 0.1 -> 1.0
265+
material.emissiveColor = new Color3(red, green, blue);
266+
material.disableLighting = true;
267+
wireframeSphere.material = material;
268+
269+
this.boundingVolumeWireframes.push(wireframeSphere);
270+
});
271+
}
272+
273+
private clearBoundingVolumeWireframes(): void {
274+
this.boundingVolumeWireframes.forEach((wireframe) => {
275+
wireframe.material?.dispose();
276+
wireframe.dispose();
277+
});
278+
this.boundingVolumeWireframes = [];
279+
}
280+
281+
private createFrustumWireframe(): void {
282+
// Implementation for separate frustum wireframe if needed
283+
}
284+
285+
private clearFrustumWireframes(): void {
286+
this.frustumWireframes.forEach((wireframe) => {
287+
wireframe.dispose();
288+
});
289+
this.frustumWireframes = [];
290+
}
291+
292+
dispose(): void {
293+
this.clearBoundingVolumeWireframes();
294+
this.clearFrustumWireframes();
295+
if (this.frustumVisualization) {
296+
this.frustumVisualization.dispose();
297+
this.frustumVisualization = null;
298+
}
299+
}
300+
}

0 commit comments

Comments
 (0)