-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
110 additions
and
122 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,86 +1,101 @@ | ||
import * as THREE from "three"; | ||
import { CSS2DObject } from "three/examples/jsm/renderers/CSS2DRenderer"; | ||
import { PlanetaryObject } from "./planetary-object"; | ||
|
||
export const getLabelOpacity = ( | ||
camera: THREE.Camera, | ||
label: CSS2DObject, | ||
radius: number | ||
) => { | ||
const rotationOpacity = getRotationOpacity(camera, label); | ||
const distanceOpacity = getDistanceOpacity(camera, radius); | ||
return rotationOpacity * distanceOpacity; | ||
}; | ||
|
||
const getRotationOpacity = ( | ||
camera: THREE.Camera, | ||
label: CSS2DObject | ||
): number => { | ||
const hideThreshold = 1; | ||
const fadeThreshold = 0.75; | ||
const cameraVector = camera.position.clone().normalize(); | ||
const labelVector = label.position.clone().normalize(); | ||
const delta = Math.acos(cameraVector.dot(labelVector)); | ||
|
||
if (delta > hideThreshold) { | ||
return 0; | ||
} else if (delta > fadeThreshold) { | ||
return (hideThreshold - delta) / (hideThreshold - fadeThreshold); | ||
} else { | ||
return 1; | ||
} | ||
}; | ||
|
||
const getDistanceOpacity = (camera: THREE.Camera, radius: number): number => { | ||
const hideThreshold = radius * 12; | ||
const fadeThreshold = radius * 8; | ||
const distance = camera.position.length(); | ||
|
||
if (distance > hideThreshold) { | ||
return 0; | ||
} else if (distance > fadeThreshold) { | ||
return (hideThreshold - distance) / (hideThreshold - fadeThreshold); | ||
} else { | ||
return 1; | ||
} | ||
}; | ||
|
||
export const rotateLabel = (radius: number, y: number, z: number) => { | ||
const vector = new THREE.Vector3(radius, 0, 0); | ||
vector.applyAxisAngle(new THREE.Vector3(0, 1, 0), y); | ||
vector.applyAxisAngle(new THREE.Vector3(0, 0, 1), z); | ||
return vector; | ||
}; | ||
|
||
export const createLabel = ( | ||
name: string, | ||
y: number, | ||
z: number, | ||
parent: PlanetaryObject, | ||
type = "" | ||
): [CSS2DObject, HTMLElement] => { | ||
const container = document.createElement("div"); | ||
container.className = "label"; | ||
|
||
if (type) { | ||
const img = document.createElement("img"); | ||
img.src = `./icons/${type}.svg`; | ||
container.appendChild(img); | ||
|
||
export interface PointOfInterest { | ||
name: string; | ||
y: number; | ||
z: number; | ||
type?: string; | ||
} | ||
|
||
export class Label { | ||
parent: THREE.Object3D; | ||
parentRadius: number; | ||
elements: CSS2DObject[]; | ||
|
||
constructor(parent: THREE.Object3D, parentRadius: number) { | ||
this.parent = parent; | ||
this.parentRadius = parentRadius; | ||
this.elements = []; | ||
} | ||
|
||
const text = document.createElement("p"); | ||
text.textContent = name; | ||
container.appendChild(text); | ||
createPOILabel = (poi: PointOfInterest) => { | ||
const container = document.createElement("div"); | ||
container.className = "label"; | ||
|
||
if (poi.type) { | ||
const img = document.createElement("img"); | ||
img.src = `./icons/${poi.type}.svg`; | ||
container.appendChild(img); | ||
} | ||
|
||
const text = document.createElement("p"); | ||
text.textContent = poi.name; | ||
container.appendChild(text); | ||
|
||
const label = new CSS2DObject(container); | ||
label.visible = false; | ||
label.center.set(0, 0); | ||
label.layers.set(2); | ||
|
||
const labelPosition = this.rotateLabel(poi.y, poi.z).toArray(); | ||
label.position.set(...labelPosition); | ||
|
||
this.parent.add(label); | ||
this.elements.push(label); | ||
}; | ||
|
||
showAll = () => { | ||
this.elements.forEach((label) => (label.visible = true)); | ||
}; | ||
|
||
hideAll = () => { | ||
this.elements.forEach((label) => (label.visible = false)); | ||
}; | ||
|
||
update = (camera: THREE.Camera) => { | ||
this.elements.forEach((label) => { | ||
const rotationOpacity = this.getRotationOpacity(camera, label); | ||
const distanceOpacity = this.getDistanceOpacity(camera); | ||
const opacity = rotationOpacity * distanceOpacity; | ||
label.element.style.opacity = opacity.toString(); | ||
}); | ||
}; | ||
|
||
rotateLabel = (y: number, z: number) => { | ||
const vector = new THREE.Vector3(this.parentRadius, 0, 0); | ||
vector.applyAxisAngle(new THREE.Vector3(0, 1, 0), y); | ||
vector.applyAxisAngle(new THREE.Vector3(0, 0, 1), z); | ||
return vector; | ||
}; | ||
|
||
const label = new CSS2DObject(container); | ||
label.visible = false; | ||
label.center.set(0, 0); | ||
label.layers.set(2); | ||
getRotationOpacity = (camera: THREE.Camera, label: CSS2DObject): number => { | ||
const hideThreshold = 1; | ||
const fadeThreshold = 0.75; | ||
const cameraVector = camera.position.clone().normalize(); | ||
const labelVector = label.position.clone().normalize(); | ||
const delta = Math.acos(cameraVector.dot(labelVector)); | ||
|
||
const labelPosition = rotateLabel(parent.radius, y, z).toArray(); | ||
label.position.set(...labelPosition); | ||
if (delta > hideThreshold) { | ||
return 0; | ||
} else if (delta > fadeThreshold) { | ||
return (hideThreshold - delta) / (hideThreshold - fadeThreshold); | ||
} else { | ||
return 1; | ||
} | ||
}; | ||
|
||
parent.addLabel(label, container); | ||
getDistanceOpacity = (camera: THREE.Camera): number => { | ||
const hideThreshold = this.parentRadius * 12; | ||
const fadeThreshold = this.parentRadius * 8; | ||
const distance = camera.position.length(); | ||
|
||
return [label, container]; | ||
}; | ||
if (distance > hideThreshold) { | ||
return 0; | ||
} else if (distance > fadeThreshold) { | ||
return (hideThreshold - distance) / (hideThreshold - fadeThreshold); | ||
} else { | ||
return 1; | ||
} | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters