forked from Snapchat/Spectacles-Sample
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSpatialImageAngleValidator.ts
More file actions
107 lines (95 loc) · 3.18 KB
/
Copy pathSpatialImageAngleValidator.ts
File metadata and controls
107 lines (95 loc) · 3.18 KB
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
import { ContainerFrame } from "SpectaclesInteractionKit.lspkg/Components/UI/ContainerFrame/ContainerFrame"
/**
* Tracks the users point of view and emits events on whether they are viewing
* from a valid angle or not.
*
* @version 1.0.0
*/
@component
export class SpatialImageAngleValidator extends BaseScriptComponent {
@input
private image: SceneObject
@input
@allowUndefined
private frame: ContainerFrame
/**
* A focal point, set behind the image, where the angle is measured from.
*/
@input
public validZoneFocal: number = 2.0
/**
* The angular range, in degrees, where no flattening is applied.
*/
@input
public validZoneAngle: number = 25
/**
* The threshold, in degrees, which must be exceeded when moving between the
* dead zone.
*/
@input
private validZoneThreshold: number = 5
@input
private camera: SceneObject
private onValidityCallbacks: ((valid: boolean) => void)[] = []
private lastAngle: number
onAwake(): void {
this.createEvent("UpdateEvent").bind(() => {
const angle = this.calculateObservationAngle()
if (this.lastAngle < this.validZoneAngle && angle > this.validZoneAngle) {
this.onValidityCallbacks.forEach((callback) => callback(false))
} else if (
this.lastAngle > this.validZoneAngle - this.validZoneThreshold &&
angle < this.validZoneAngle - this.validZoneThreshold
) {
this.onValidityCallbacks.forEach((callback) => callback(true))
}
this.lastAngle = angle
})
}
private calculateObservationAngle() {
const cameraPosition = this.camera.getTransform().getWorldPosition()
const imageTransform = this.image.getTransform()
const imagePos = imageTransform.getWorldPosition()
const imageFocalDisplacement = imageTransform
.getWorldRotation()
.multiplyVec3(new vec3(0, 0, this.validZoneFocal))
const imageFocal = imagePos.sub(imageFocalDisplacement)
const displacement = cameraPosition.sub(imageFocal)
const displacementDirection = displacement.normalize()
let angle = displacementDirection.dot(
this.image.getTransform().getWorldRotation().multiplyVec3(vec3.forward())
)
return (1 - angle) * 90
}
/**
* Sets the focal point of the valid zone.
*
* @remarks This allows the user to move their head around in front of the
* image without it being considered an extreme angle.
*/
public setValidZoneFocal(focal: number): void {
this.validZoneFocal = focal
}
/**
* Sets the angle, in degrees, at which the angle is considered valid.
*/
public setValidZoneAngle(angle: number): void {
this.validZoneAngle = angle
}
/**
* Add a callback to onValidityCallbacks, to be called when the image is fully loaded.
* @param callback - the callback to add
*/
public addOnValidityCallback(callback: (entered: boolean) => void): void {
this.onValidityCallbacks.push(callback)
}
/**
* Remove a callback from the onValidityCallbacks.
* @param callback - the callback to remove
*/
public removeOnValidityCallback(callback: (entered: boolean) => void): void {
this.onValidityCallbacks = this.onValidityCallbacks.filter(
(cb) => cb !== callback
)
}
}