Skip to content

Commit 7452ffe

Browse files
committed
cloud
1 parent a0bfa2b commit 7452ffe

File tree

4 files changed

+170
-1
lines changed

4 files changed

+170
-1
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
2+
import { Meta } from '@storybook/angular';
3+
import { NgtsOrbitControls } from 'angular-three-soba/controls';
4+
import { NgtsCloud } from 'angular-three-soba/staging';
5+
import { makeDecorators, makeStoryFunction } from '../setup-canvas';
6+
7+
@Component({
8+
standalone: true,
9+
template: `
10+
<ngts-cloud [position]="[-4, -2, 0]" />
11+
<ngts-cloud [position]="[-4, 2, 0]" />
12+
<ngts-cloud />
13+
<ngts-cloud [position]="[4, -2, 0]" />
14+
<ngts-cloud [position]="[4, 2, 0]" />
15+
<ngts-orbit-controls [enablePan]="false" [zoomSpeed]="0.5" />
16+
`,
17+
imports: [NgtsCloud, NgtsOrbitControls],
18+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
19+
})
20+
class DefaultCloudStory {}
21+
22+
export default {
23+
title: 'Staging/Cloud',
24+
decorators: makeDecorators(),
25+
} as Meta;
26+
27+
export const Default = makeStoryFunction(DefaultCloudStory, {
28+
camera: { position: [0, 0, 10] },
29+
controls: false,
30+
});

libs/soba/staging/src/cloud/cloud.ts

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import { NgFor, NgIf } from '@angular/common';
2+
import { CUSTOM_ELEMENTS_SCHEMA, Component, Input, computed } from '@angular/core';
3+
import { extend, injectNgtRef, signalStore, type NgtBeforeRenderEvent, type NgtGroup } from 'angular-three';
4+
import { NgtsBillboard } from 'angular-three-soba/abstractions';
5+
import { injectNgtsTextureLoader } from 'angular-three-soba/loaders';
6+
import { Group, Mesh, MeshStandardMaterial, PlaneGeometry } from 'three';
7+
8+
const CLOUD_URL = 'https://rawcdn.githack.com/pmndrs/drei-assets/9225a9f1fbd449d9411125c2f419b843d0308c9f/cloud.png';
9+
(injectNgtsTextureLoader as any).preload(() => CLOUD_URL);
10+
11+
extend({ Group, Mesh, PlaneGeometry, MeshStandardMaterial });
12+
13+
export type NgtsCloudState = {
14+
opacity: number;
15+
speed: number;
16+
width: number;
17+
depth: number;
18+
segments: number;
19+
texture: string;
20+
color: THREE.ColorRepresentation;
21+
depthTest: boolean;
22+
};
23+
24+
declare global {
25+
interface HTMLElementTagNameMap {
26+
/**
27+
* @extends ngt-group
28+
*/
29+
'ngts-cloud': NgtsCloudState & NgtGroup;
30+
}
31+
}
32+
33+
@Component({
34+
selector: 'ngts-cloud',
35+
standalone: true,
36+
template: `
37+
<ngt-group ngtCompound>
38+
<ngt-group
39+
[position]="[0, 0, (segments() / 2) * depth()]"
40+
[ref]="groupRef"
41+
(beforeRender)="onBeforeRender($event)"
42+
>
43+
<ngts-billboard
44+
*ngFor="let cloud of clouds(); let i = index"
45+
[position]="[cloud.x, cloud.y, -i * depth()]"
46+
>
47+
<ngt-mesh [scale]="cloud.scale" [rotation]="[0, 0, 0]">
48+
<ngt-plane-geometry />
49+
<ngt-mesh-standard-material
50+
[map]="texture()"
51+
[transparent]="true"
52+
[opacity]="(cloud.scale / 6) * cloud.density * opacity()"
53+
[depthTest]="depthTest()"
54+
[color]="color()"
55+
/>
56+
</ngt-mesh>
57+
</ngts-billboard>
58+
</ngt-group>
59+
</ngt-group>
60+
`,
61+
imports: [NgFor, NgtsBillboard, NgIf],
62+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
63+
})
64+
export class NgtsCloud {
65+
private inputs = signalStore<NgtsCloudState>({
66+
opacity: 0.5,
67+
speed: 0.4,
68+
width: 10,
69+
depth: 1.5,
70+
segments: 20,
71+
texture: CLOUD_URL,
72+
color: '#ffffff',
73+
depthTest: true,
74+
});
75+
76+
@Input() groupRef = injectNgtRef<Group>();
77+
78+
@Input({ alias: 'opacity' }) set _opacity(opacity: number) {
79+
this.inputs.set({ opacity });
80+
}
81+
82+
@Input({ alias: 'speed' }) set _speed(speed: number) {
83+
this.inputs.set({ speed });
84+
}
85+
86+
@Input({ alias: 'width' }) set _width(width: number) {
87+
this.inputs.set({ width });
88+
}
89+
90+
@Input({ alias: 'depth' }) set _depth(depth: number) {
91+
this.inputs.set({ depth });
92+
}
93+
94+
@Input({ alias: 'segments' }) set _segments(segments: number) {
95+
this.inputs.set({ segments });
96+
}
97+
98+
@Input({ alias: 'texture' }) set _texture(texture: string) {
99+
this.inputs.set({ texture });
100+
}
101+
102+
@Input({ alias: 'color' }) set _color(color: THREE.ColorRepresentation) {
103+
this.inputs.set({ color });
104+
}
105+
106+
@Input({ alias: 'depthTest' }) set _depthTest(depthTest: boolean) {
107+
this.inputs.set({ depthTest });
108+
}
109+
110+
private width = this.inputs.select('width');
111+
private speed = this.inputs.select('speed');
112+
113+
readonly segments = this.inputs.select('segments');
114+
readonly depth = this.inputs.select('depth');
115+
readonly depthTest = this.inputs.select('depthTest');
116+
readonly opacity = this.inputs.select('opacity');
117+
readonly color = this.inputs.select('color');
118+
readonly texture = injectNgtsTextureLoader(this.inputs.select('texture'));
119+
120+
readonly clouds = computed(() =>
121+
[...new Array(this.segments())].map((_, index) => ({
122+
x: this.width() / 2 - Math.random() * this.width(),
123+
y: this.width() / 2 - Math.random() * this.width(),
124+
scale: 0.4 + Math.sin(((index + 1) / this.segments()) * Math.PI) * ((0.2 + Math.random()) * 10),
125+
density: Math.max(0.2, Math.random()),
126+
rotation: Math.max(0.002, 0.005 * Math.random()) * this.speed(),
127+
})),
128+
);
129+
onBeforeRender({ state, object }: NgtBeforeRenderEvent<Group>) {
130+
const clouds = this.clouds();
131+
object.children.forEach((cloud, index) => {
132+
cloud.children[0].rotation.z += clouds[index].rotation;
133+
cloud.children[0].scale.setScalar(
134+
clouds[index].scale + (((1 + Math.sin(state.clock.getElapsedTime() / 10)) / 2) * index) / 10,
135+
);
136+
});
137+
}
138+
}

libs/soba/staging/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from './camera-shake/camera-shake';
22
export * from './center/center';
3+
export * from './cloud/cloud';
34
export * from './float/float';
45
export * from './matcap-texture/matcap-texture';

tools/scripts/generate-soba-json.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const entryPoints = {
3030
controls: ['orbit-controls'],
3131
abstractions: ['billboard', 'text', 'grid', 'text-3d'],
3232
cameras: ['perspective-camera', 'orthographic-camera', 'cube-camera'],
33-
staging: ['center', 'float', 'camera-shake'],
33+
staging: ['center', 'float', 'camera-shake', 'cloud'],
3434
};
3535

3636
const paths = [];

0 commit comments

Comments
 (0)