-
Notifications
You must be signed in to change notification settings - Fork 32
/
Copy pathbillboard.ts
74 lines (64 loc) · 1.89 KB
/
billboard.ts
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
import {
ChangeDetectionStrategy,
Component,
CUSTOM_ELEMENTS_SCHEMA,
ElementRef,
input,
viewChild,
} from '@angular/core';
import { extend, injectBeforeRender, NgtGroup, omit } from 'angular-three';
import { mergeInputs } from 'ngxtension/inject-inputs';
import { Group, Quaternion } from 'three';
export interface NgtsBillboardOptions extends Partial<NgtGroup> {
follow?: boolean;
lockX?: boolean;
lockY?: boolean;
lockZ?: boolean;
}
const defaultOptions: NgtsBillboardOptions = {
follow: true,
lockX: false,
lockY: false,
lockZ: false,
};
@Component({
selector: 'ngts-billboard',
template: `
<ngt-group #group [parameters]="parameters()">
<ngt-group #inner>
<ng-content />
</ngt-group>
</ngt-group>
`,
schemas: [CUSTOM_ELEMENTS_SCHEMA],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class NgtsBillboard {
options = input(defaultOptions, { transform: mergeInputs(defaultOptions) });
parameters = omit(this.options, ['follow', 'lockX', 'lockY', 'lockZ']);
groupRef = viewChild.required<ElementRef<Group>>('group');
innerRef = viewChild.required<ElementRef<Group>>('inner');
constructor() {
extend({ Group });
const q = new Quaternion();
injectBeforeRender(({ camera }) => {
const [{ follow, lockX, lockY, lockZ }, group, inner] = [
this.options(),
this.groupRef().nativeElement,
this.innerRef().nativeElement,
];
if (!follow || !group) return;
// save previous rotation in case we're locking an axis
const prevRotation = inner.rotation.clone();
// always face the camera
group.updateMatrix();
group.updateWorldMatrix(false, false);
group.getWorldQuaternion(q);
camera.getWorldQuaternion(inner.quaternion).premultiply(q.invert());
// readjust any axis that is locked
if (lockX) inner.rotation.x = prevRotation.x;
if (lockY) inner.rotation.y = prevRotation.y;
if (lockZ) inner.rotation.z = prevRotation.z;
});
}
}