Skip to content

Commit f0818e8

Browse files
Chau TranChau Tran
Chau Tran
authored and
Chau Tran
committed
feat(postprocessing): initial work
1 parent f56549c commit f0818e8

24 files changed

+689
-76
lines changed

apps/demo/src/app/app.component.ts

Lines changed: 38 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,61 @@
1-
import { CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, Component, signal } from '@angular/core';
2-
import { NgtCanvas, extend } from 'angular-three';
1+
import { NgIf } from '@angular/common';
2+
import { CUSTOM_ELEMENTS_SCHEMA, Component, Signal } from '@angular/core';
3+
import { NgtArgs, NgtBeforeRenderEvent, NgtCanvas, extend } from 'angular-three';
4+
import { NgtpEffectComposer } from 'angular-three-postprocessing';
5+
import { NgtpBloom, NgtpDotScreen } from 'angular-three-postprocessing/effects';
36
import { NgtsOrbitControls } from 'angular-three-soba/controls';
7+
import { injectNgtsGLTFLoader } from 'angular-three-soba/loaders';
48
import * as THREE from 'three';
9+
import { GLTF } from 'three-stdlib';
510

611
extend(THREE);
712

13+
interface KeenGLTF extends GLTF {
14+
nodes: { mesh_0: THREE.Mesh };
15+
materials: { 'Scene_-_Root': THREE.MeshStandardMaterial };
16+
}
17+
818
@Component({
9-
selector: 'app-cube',
1019
standalone: true,
1120
template: `
12-
<ngt-mesh
13-
(beforeRender)="onBeforeRender($any($event).object)"
14-
(pointerover)="hover.set(true)"
15-
(pointerout)="hover.set(false)"
16-
(click)="active.set(!active())"
17-
[scale]="active() ? 1.5 : 1"
21+
<ngt-color *args="['black']" attach="background" />
22+
23+
<ngt-ambient-light />
24+
<ngt-directional-light [position]="[0, 1, 2]" />
25+
26+
<ngt-group
27+
*ngIf="keen() as keen"
28+
[position]="[0, -7, 0]"
29+
[rotation]="[-Math.PI / 2, 0, 0]"
30+
(beforeRender)="onBeforeRender($event)"
1831
>
19-
<ngt-box-geometry />
20-
<ngt-mesh-standard-material [color]="hover() ? 'hotpink' : 'orange'" />
21-
</ngt-mesh>
22-
`,
23-
schemas: [CUSTOM_ELEMENTS_SCHEMA],
24-
changeDetection: ChangeDetectionStrategy.OnPush,
25-
})
26-
export class Cube {
27-
hover = signal(false);
28-
active = signal(false);
32+
<ngt-mesh [material]="keen.materials['Scene_-_Root']" [geometry]="keen.nodes['mesh_0'].geometry" />
33+
</ngt-group>
2934
30-
onBeforeRender(mesh: THREE.Mesh) {
31-
mesh.rotation.x += 0.01;
32-
mesh.rotation.y += 0.01;
33-
}
34-
}
35+
<ngtp-effect-composer>
36+
<ngtp-bloom [intensity]="5" />
37+
<ngtp-dot-screen [scale]="3" />
38+
</ngtp-effect-composer>
3539
36-
@Component({
37-
standalone: true,
38-
template: `
39-
<ngt-spot-light [position]="5" />
40-
<ngt-point-light [position]="-5" />
41-
<app-cube />
4240
<ngts-orbit-controls />
4341
`,
44-
imports: [Cube, NgtsOrbitControls],
42+
imports: [NgtpEffectComposer, NgtpBloom, NgtpDotScreen, NgIf, NgtArgs, NgtsOrbitControls],
4543
schemas: [CUSTOM_ELEMENTS_SCHEMA],
46-
changeDetection: ChangeDetectionStrategy.OnPush,
4744
})
48-
export class Scene {}
45+
export class Scene {
46+
readonly Math = Math;
47+
readonly keen = injectNgtsGLTFLoader(() => 'assets/scene.gltf') as Signal<KeenGLTF>;
48+
49+
onBeforeRender({ object, state: { clock } }: NgtBeforeRenderEvent<THREE.Group>) {
50+
object.rotation.z = clock.elapsedTime;
51+
}
52+
}
4953

5054
@Component({
5155
standalone: true,
5256
imports: [NgtCanvas],
5357
selector: 'angular-three-root',
54-
template: ` <ngt-canvas [sceneGraph]="scene" />`,
58+
template: ` <ngt-canvas [sceneGraph]="scene" [camera]="{ position: [0, 0, 15], near: 5, far: 20 }" />`,
5559
})
5660
export class AppComponent {
5761
readonly scene = Scene;

apps/demo/src/assets/.gitkeep

Whitespace-only changes.

apps/demo/src/assets/scene.bin

80.5 KB
Binary file not shown.

apps/demo/src/assets/scene.gltf

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
{
2+
"accessors": [
3+
{
4+
"bufferView": 2,
5+
"componentType": 5126,
6+
"count": 1132,
7+
"max": [4, 3, 14],
8+
"min": [-4, -3, 0],
9+
"type": "VEC3"
10+
},
11+
{
12+
"bufferView": 2,
13+
"byteOffset": 13584,
14+
"componentType": 5126,
15+
"count": 1132,
16+
"max": [1, 1, 1],
17+
"min": [-1, -1, -1],
18+
"type": "VEC3"
19+
},
20+
{
21+
"bufferView": 3,
22+
"componentType": 5126,
23+
"count": 1132,
24+
"max": [0, 0, 0, 1],
25+
"min": [0, 0, 0, 1],
26+
"type": "VEC4"
27+
},
28+
{
29+
"bufferView": 3,
30+
"byteOffset": 18112,
31+
"componentType": 5126,
32+
"count": 1132,
33+
"max": [1, 1, 1, 1],
34+
"min": [0, 0.19607843458652496, 0, 1],
35+
"type": "VEC4"
36+
},
37+
{
38+
"bufferView": 1,
39+
"componentType": 5126,
40+
"count": 1132,
41+
"max": [0, 0],
42+
"min": [0, 0],
43+
"type": "VEC2"
44+
},
45+
{
46+
"bufferView": 0,
47+
"componentType": 5125,
48+
"count": 2484,
49+
"max": [1131],
50+
"min": [0],
51+
"type": "SCALAR"
52+
}
53+
],
54+
"asset": {
55+
"extras": {
56+
"author": "Acemir Sousa Mendes (https://sketchfab.com/acemir)",
57+
"license": "CC-BY-NC-SA-4.0 (http://creativecommons.org/licenses/by-nc-sa/4.0/)",
58+
"source": "https://sketchfab.com/3d-models/billy-blaze-aka-commander-keen-voxel-fanart-a64810a4026b445e9633ec758c6c969c",
59+
"title": "Billy Blaze aka Commander Keen (Voxel FanArt)"
60+
},
61+
"generator": "Sketchfab-6.24.0",
62+
"version": "2.0"
63+
},
64+
"bufferViews": [
65+
{
66+
"buffer": 0,
67+
"byteLength": 9936,
68+
"byteOffset": 0,
69+
"name": "floatBufferViews",
70+
"target": 34963
71+
},
72+
{
73+
"buffer": 0,
74+
"byteLength": 9056,
75+
"byteOffset": 9936,
76+
"byteStride": 8,
77+
"name": "floatBufferViews",
78+
"target": 34962
79+
},
80+
{
81+
"buffer": 0,
82+
"byteLength": 27168,
83+
"byteOffset": 18992,
84+
"byteStride": 12,
85+
"name": "floatBufferViews",
86+
"target": 34962
87+
},
88+
{
89+
"buffer": 0,
90+
"byteLength": 36224,
91+
"byteOffset": 46160,
92+
"byteStride": 16,
93+
"name": "floatBufferViews",
94+
"target": 34962
95+
}
96+
],
97+
"buffers": [
98+
{
99+
"byteLength": 82384,
100+
"uri": "scene.bin"
101+
}
102+
],
103+
"materials": [
104+
{
105+
"doubleSided": true,
106+
"emissiveFactor": [0, 0, 0],
107+
"name": "Scene_-_Root",
108+
"pbrMetallicRoughness": {
109+
"baseColorFactor": [0.5, 0.5, 0.5, 1],
110+
"metallicFactor": 0,
111+
"roughnessFactor": 0.59999999999999998
112+
}
113+
}
114+
],
115+
"meshes": [
116+
{
117+
"primitives": [
118+
{
119+
"attributes": {
120+
"COLOR_0": 3,
121+
"NORMAL": 1,
122+
"POSITION": 0,
123+
"TANGENT": 2,
124+
"TEXCOORD_0": 4
125+
},
126+
"indices": 5,
127+
"material": 0,
128+
"mode": 4
129+
}
130+
]
131+
}
132+
],
133+
"nodes": [
134+
{
135+
"children": [1],
136+
"name": "RootNode (gltf orientation matrix)",
137+
"rotation": [-0.70710678118654746, -0, -0, 0.70710678118654757]
138+
},
139+
{
140+
"children": [2],
141+
"name": "RootNode (model correction matrix)"
142+
},
143+
{
144+
"children": [3],
145+
"name": "Geode"
146+
},
147+
{
148+
"mesh": 0,
149+
"name": ""
150+
}
151+
],
152+
"scene": 0,
153+
"scenes": [
154+
{
155+
"name": "OSG_Scene",
156+
"nodes": [0]
157+
}
158+
]
159+
}

apps/demo/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"noImplicitOverride": true,
88
"noPropertyAccessFromIndexSignature": true,
99
"noImplicitReturns": true,
10-
"noFallthroughCasesInSwitch": true
10+
"noFallthroughCasesInSwitch": true,
11+
"skipLibCheck": true
1112
},
1213
"files": [],
1314
"include": [],

libs/angular-three/src/lib/types.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { ElementRef, EventEmitter, WritableSignal } from '@angular/core';
22
import * as THREE from 'three';
33
import type { NgtSignalStore } from './stores/signal.store';
4+
import { NgtObject3DNode } from './three-types';
45

56
export type NgtAnyRecord = Record<string, any>;
67
export type NgtProperties<T> = Pick<T, { [K in keyof T]: T[K] extends (_: any) => any ? never : K }[keyof T]>;
@@ -337,7 +338,14 @@ export type NgtCanvasInputs = {
337338
/** A `THREE.Scene` instance or props that go into the default scene */
338339
scene?: THREE.Scene | Partial<THREE.Scene>;
339340
/** A `Camera` instance or props that go into the default camera */
340-
camera?: (NgtCamera | Partial<THREE.Camera>) & {
341+
camera?: (
342+
| NgtCamera
343+
| Partial<
344+
NgtObject3DNode<THREE.Camera, typeof THREE.Camera> &
345+
NgtObject3DNode<THREE.PerspectiveCamera, typeof THREE.PerspectiveCamera> &
346+
NgtObject3DNode<THREE.OrthographicCamera, typeof THREE.OrthographicCamera>
347+
>
348+
) & {
341349
/** Flags the camera as manual, putting projection into your own hands */
342350
manual?: boolean;
343351
};

libs/postprocessing/effects/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# angular-three-postprocessing/effects
2+
3+
Secondary entry point of `angular-three-postprocessing`. It can be used by importing from `angular-three-postprocessing/effects`.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"lib": {
3+
"entryFile": "src/index.ts"
4+
}
5+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { CUSTOM_ELEMENTS_SCHEMA, Component } from '@angular/core';
2+
import { NgtArgs, extend } from 'angular-three';
3+
import { NgtpEffect } from 'angular-three-postprocessing';
4+
import { BlendFunction, BloomEffect } from 'postprocessing';
5+
6+
extend({ BloomEffect });
7+
8+
@Component({
9+
selector: 'ngtp-bloom',
10+
standalone: true,
11+
template: `
12+
<ngt-bloom-effect ngtCompound *args="args()" [ref]="effectRef" [camera]="camera()">
13+
<ng-content />
14+
</ngt-bloom-effect>
15+
`,
16+
imports: [NgtArgs],
17+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
18+
})
19+
export class NgtpBloom extends NgtpEffect<BloomEffect> {
20+
override defaultBlendFunction = BlendFunction.ADD;
21+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { CUSTOM_ELEMENTS_SCHEMA, Component } from '@angular/core';
2+
import { NgtArgs, extend } from 'angular-three';
3+
import { NgtpEffect } from 'angular-three-postprocessing';
4+
import { DotScreenEffect } from 'postprocessing';
5+
6+
extend({ DotScreenEffect });
7+
8+
@Component({
9+
selector: 'ngtp-dot-screen',
10+
standalone: true,
11+
template: `
12+
<ngt-dot-screen-effect ngtCompound *args="args()" [camera]="camera()" [ref]="effectRef">
13+
<ng-content />
14+
</ngt-dot-screen-effect>
15+
`,
16+
imports: [NgtArgs],
17+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
18+
})
19+
export class NgtpDotScreen extends NgtpEffect<DotScreenEffect> {}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from './bloom/bloom';
2+
export * from './dot-screen/dot-screen';
3+
export * from './scanline/scanline';
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { CUSTOM_ELEMENTS_SCHEMA, Component } from '@angular/core';
2+
import { NgtArgs, extend } from 'angular-three';
3+
import { NgtpEffect } from 'angular-three-postprocessing';
4+
import { BlendFunction, ScanlineEffect } from 'postprocessing';
5+
6+
extend({ ScanlineEffect });
7+
8+
@Component({
9+
selector: 'ngtp-scanline',
10+
standalone: true,
11+
template: `
12+
<ngt-scanline-effect ngtCompound *args="args()" [camera]="camera()" [ref]="effectRef">
13+
<ng-content />
14+
</ngt-scanline-effect>
15+
`,
16+
imports: [NgtArgs],
17+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
18+
})
19+
export class NgtpScanline extends NgtpEffect<ScanlineEffect> {
20+
override defaultBlendFunction = BlendFunction.OVERLAY;
21+
}

libs/postprocessing/ng-package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
"dest": "../../dist/libs/postprocessing",
44
"lib": {
55
"entryFile": "src/index.ts"
6-
}
6+
},
7+
"allowedNonPeerDependencies": ["@nx/devkit", "nx"]
78
}

0 commit comments

Comments
 (0)