Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e6ce306

Browse files
committed
intersect
1 parent 4c61180 commit e6ce306

File tree

3 files changed

+76
-1
lines changed

3 files changed

+76
-1
lines changed

libs/soba/misc/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ export * from './lib/depth-buffer';
88
export * from './lib/fbo';
99
export * from './lib/html/html';
1010
export * from './lib/html/html-content';
11+
export * from './lib/intersect';
1112
export * from './lib/sampler';

libs/soba/misc/src/lib/intersect.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { afterNextRender, Directive, ElementRef, inject, Injector, model, signal, WritableSignal } from '@angular/core';
2+
import { addAfterEffect, addEffect, resolveRef } from 'angular-three';
3+
import { assertInjector } from 'ngxtension/assert-injector';
4+
import { injectAutoEffect } from 'ngxtension/auto-effect';
5+
import { Object3D } from 'three';
6+
7+
export function injectIntersect<TObject extends Object3D>(
8+
object: () => ElementRef<TObject> | TObject | undefined | null,
9+
{ injector, source = signal(false) }: { injector?: Injector; source?: WritableSignal<boolean> } = {},
10+
) {
11+
return assertInjector(injectIntersect, injector, () => {
12+
let check = false;
13+
let temp = false;
14+
15+
const autoEffect = injectAutoEffect();
16+
17+
afterNextRender(() => {
18+
autoEffect(() => {
19+
const obj = resolveRef(object());
20+
if (!obj) return;
21+
22+
// Stamp out frustum check pre-emptively
23+
const unsub1 = addEffect(() => {
24+
check = false;
25+
return true;
26+
});
27+
28+
// If the object is inside the frustum three will call onRender
29+
const oldOnRender = obj.onBeforeRender.bind(obj);
30+
obj.onBeforeRender = () => (check = true);
31+
32+
// Compare the check value against the temp value, if it differs set state
33+
const unsub2 = addAfterEffect(() => {
34+
if (check !== temp) source.set((temp = check));
35+
return true;
36+
});
37+
38+
return () => {
39+
obj.onBeforeRender = oldOnRender;
40+
unsub1();
41+
unsub2();
42+
};
43+
});
44+
});
45+
46+
return source.asReadonly();
47+
});
48+
}
49+
50+
@Directive({ standalone: true, selector: '[intersect]' })
51+
export class NgtsIntersect {
52+
intersect = model(false);
53+
54+
constructor() {
55+
const host = inject<ElementRef<Object3D>>(ElementRef);
56+
injectIntersect(() => host, { source: this.intersect });
57+
}
58+
}

libs/soba/src/controls/scroll-controls.stories.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ import {
33
Component,
44
computed,
55
CUSTOM_ELEMENTS_SCHEMA,
6+
ElementRef,
67
inject,
78
input,
89
signal,
910
Signal,
11+
viewChild,
1012
} from '@angular/core';
1113
import { Meta } from '@storybook/angular';
1214
import { injectBeforeRender, injectStore, NgtArgs, NgtHTML } from 'angular-three';
@@ -17,7 +19,7 @@ import {
1719
NgtsScrollHtml,
1820
} from 'angular-three-soba/controls';
1921
import { injectGLTF } from 'angular-three-soba/loaders';
20-
import { injectAnimations } from 'angular-three-soba/misc';
22+
import { injectAnimations, NgtsIntersect } from 'angular-three-soba/misc';
2123
import { NgtsSky } from 'angular-three-soba/staging';
2224
import { MathUtils, Mesh } from 'three';
2325
import { makeDecorators, makeStoryFunction, makeStoryObject } from '../setup-canvas';
@@ -111,6 +113,8 @@ class LittlestTokyoStory {
111113
<ngt-group [position]="position()" [scale]="scale()">
112114
@if (gltf(); as gltf) {
113115
<ngt-mesh
116+
#mesh
117+
[(intersect)]="isIntersect"
114118
[geometry]="gltf.nodes.Suzanne.geometry"
115119
(pointerover)="hovered.set(true)"
116120
(pointerout)="hovered.set(false)"
@@ -123,6 +127,7 @@ class LittlestTokyoStory {
123127

124128
schemas: [CUSTOM_ELEMENTS_SCHEMA],
125129
changeDetection: ChangeDetectionStrategy.OnPush,
130+
imports: [NgtsIntersect],
126131
})
127132
class Suzanne {
128133
position = input([0, 0, 0]);
@@ -131,6 +136,17 @@ class Suzanne {
131136
gltf = injectGLTF(() => './suzanne.glb') as Signal<any>;
132137

133138
hovered = signal(false);
139+
isIntersect = signal(false);
140+
141+
meshRef = viewChild<ElementRef<Mesh>>('mesh');
142+
143+
constructor() {
144+
injectBeforeRender(({ delta, viewport }) => {
145+
const mesh = this.meshRef()?.nativeElement;
146+
if (!mesh) return;
147+
mesh.rotation.x = MathUtils.damp(mesh.rotation.x, this.isIntersect() ? 0 : -viewport.height / 2 + 1, 4, delta);
148+
});
149+
}
134150
}
135151

136152
@Component({

0 commit comments

Comments
 (0)