Skip to content

Commit aee4943

Browse files
Chau TranChau Tran
authored andcommitted
feat(soba): add mesh distort and mesh wobble material
1 parent e86ebc8 commit aee4943

File tree

16 files changed

+401
-2
lines changed

16 files changed

+401
-2
lines changed

libs/soba/materials/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# angular-three-soba/materials
2+
3+
Secondary entry point of `angular-three-soba`. It can be used by importing from `angular-three-soba/materials`.

libs/soba/materials/ng-package.json

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+
}

libs/soba/materials/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './mesh-distort-material/mesh-distort-material';
2+
export * from './mesh-wobble-material/mesh-wobble-material';
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { Component, CUSTOM_ELEMENTS_SCHEMA, inject, Input } from '@angular/core';
2+
import { injectBeforeRender, injectNgtRef, NgtArgs, NgtSignalStore } from 'angular-three';
3+
import { MeshDistortMaterial, NGTS_DISTORT_MATERIAL_SHADER } from 'angular-three-soba/shaders';
4+
5+
export interface NgtsMeshDistortMaterialState {
6+
time: number;
7+
distort: number;
8+
radius: number;
9+
speed: number;
10+
}
11+
12+
@Component({
13+
selector: 'ngts-mesh-distort-material',
14+
standalone: true,
15+
template: `
16+
<ngt-primitive
17+
*args="[material]"
18+
[ref]="materialRef"
19+
[time]="distortTime()"
20+
[distort]="distortDistort()"
21+
[radius]="distortRadius()"
22+
ngtCompound
23+
attach="material"
24+
/>
25+
`,
26+
imports: [NgtArgs],
27+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
28+
})
29+
export class NgtsMeshDistortMaterial extends NgtSignalStore<NgtsMeshDistortMaterialState> {
30+
readonly material = new (inject(NGTS_DISTORT_MATERIAL_SHADER))();
31+
32+
@Input() materialRef = injectNgtRef<InstanceType<MeshDistortMaterial>>();
33+
34+
@Input() set time(time: number) {
35+
this.set({ time });
36+
}
37+
38+
@Input() set distort(distort: number) {
39+
this.set({ distort });
40+
}
41+
42+
@Input() set radius(radius: number) {
43+
this.set({ radius });
44+
}
45+
46+
@Input() set speed(speed: number) {
47+
this.set({ speed });
48+
}
49+
50+
readonly distortTime = this.select('time');
51+
readonly distortDistort = this.select('distort');
52+
readonly distortRadius = this.select('radius');
53+
54+
constructor() {
55+
super({ speed: 1, time: 0, distort: 0.4, radius: 1 });
56+
injectBeforeRender(({ clock }) => {
57+
this.material.time = clock.getElapsedTime() * this.get('speed');
58+
});
59+
}
60+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { Component, CUSTOM_ELEMENTS_SCHEMA, Input } from '@angular/core';
2+
import { extend, injectBeforeRender, injectNgtRef, NgtArgs, NgtSignalStore } from 'angular-three';
3+
import { MeshWobbleMaterial } from 'angular-three-soba/shaders';
4+
5+
extend({ MeshWobbleMaterial });
6+
7+
export interface NgtsMeshWobbleMaterialState {
8+
time: number;
9+
factor: number;
10+
speed: number;
11+
}
12+
13+
@Component({
14+
selector: 'ngts-mesh-wobble-material',
15+
standalone: true,
16+
template: `
17+
<ngt-primitive
18+
*args="[material]"
19+
[ref]="materialRef"
20+
[time]="wobbleTime()"
21+
[factor]="wobbleFactor()"
22+
attach="material"
23+
ngtCompound
24+
/>
25+
`,
26+
imports: [NgtArgs],
27+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
28+
})
29+
export class NgtsMeshWobbleMaterial extends NgtSignalStore<NgtsMeshWobbleMaterialState> {
30+
readonly material = new MeshWobbleMaterial();
31+
32+
@Input() materialRef = injectNgtRef<MeshWobbleMaterial>();
33+
34+
@Input() set time(time: number) {
35+
this.set({ time });
36+
}
37+
38+
@Input() set factor(factor: number) {
39+
this.set({ factor });
40+
}
41+
42+
@Input() set speed(speed: number) {
43+
this.set({ speed });
44+
}
45+
46+
readonly wobbleTime = this.select('time');
47+
readonly wobbleFactor = this.select('factor');
48+
49+
constructor() {
50+
super({ speed: 1, time: 0, factor: 1 });
51+
injectBeforeRender(({ clock }) => {
52+
this.material.time = clock.getElapsedTime() * this.get('speed');
53+
});
54+
}
55+
}

libs/soba/ng-package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
},
77
"assets": [
88
{
9-
"input": "./shaders/src/assets/",
9+
"input": "./shaders/assets/",
1010
"glob": "**/*",
1111
"output": "assets"
1212
}

libs/soba/project.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@
5858
"libs/soba/loaders/**/*.ts",
5959
"libs/soba/loaders/**/*.html",
6060
"libs/soba/shaders/**/*.ts",
61-
"libs/soba/shaders/**/*.html"
61+
"libs/soba/shaders/**/*.html",
62+
"libs/soba/materials/**/*.ts",
63+
"libs/soba/materials/**/*.html"
6264
]
6365
}
6466
},
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#pragma glslify: snoise3 = require(glsl-noise/simplex/3d)

libs/soba/shaders/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
export * from './caustics-material/caustics-material';
22
export * from './caustics-material/caustics-projection-material';
33
export * from './discard-material/discard-material';
4+
export * from './mesh-distort-material/mesh-distort-material';
5+
export * from './mesh-wobble-material/mesh-wobble-material';
46
export * from './soft-shadow-material/soft-shadow-material';
57
export * from './sparkles-material/sparkles-material';
68
export * from './spot-light-material/spot-light-material';
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import { InjectionToken, Type } from '@angular/core';
2+
import * as THREE from 'three';
3+
4+
interface Uniform<T> {
5+
value: T;
6+
}
7+
8+
/**
9+
* npm i -D raw-loader glslify-loader glsl-noise
10+
* Usage: import distort from 'raw-loader!glslify-loader!angular-three-soba/assets/distort.vert.glsl'
11+
*
12+
* provideNgtsMeshDistortMaterialShader(distort)
13+
*/
14+
15+
export type MeshDistortMaterial = Type<{ time: number; distort: number; radius: number } & THREE.MeshPhysicalMaterial>;
16+
17+
export const NGTS_DISTORT_MATERIAL_SHADER = new InjectionToken<MeshDistortMaterial>('DistortMaterialShader');
18+
19+
export function provideNgtsMeshDistortMaterialShader(distortShader: string) {
20+
return {
21+
provide: NGTS_DISTORT_MATERIAL_SHADER,
22+
useFactory: () => {
23+
return class extends THREE.MeshPhysicalMaterial {
24+
_time: Uniform<number>;
25+
_distort: Uniform<number>;
26+
_radius: Uniform<number>;
27+
28+
constructor(parameters: THREE.MeshPhysicalMaterialParameters = {}) {
29+
super(parameters);
30+
this.setValues(parameters);
31+
this._time = { value: 0 };
32+
this._distort = { value: 0.4 };
33+
this._radius = { value: 1 };
34+
}
35+
36+
override onBeforeCompile(shader: THREE.Shader) {
37+
shader.uniforms['time'] = this._time;
38+
shader.uniforms['radius'] = this._radius;
39+
shader.uniforms['distort'] = this._distort;
40+
41+
shader.vertexShader = `
42+
uniform float time;
43+
uniform float radius;
44+
uniform float distort;
45+
${distortShader}
46+
${shader.vertexShader}
47+
`;
48+
shader.vertexShader = shader.vertexShader.replace(
49+
'#include <begin_vertex>',
50+
`
51+
float updateTime = time / 50.0;
52+
float noise = snoise(vec3(position / 2.0 + updateTime * 5.0));
53+
vec3 transformed = vec3(position * (noise * pow(distort, 2.0) + radius));
54+
`
55+
);
56+
}
57+
58+
get time() {
59+
return this._time.value;
60+
}
61+
62+
set time(v) {
63+
this._time.value = v;
64+
}
65+
66+
get distort() {
67+
return this._distort.value;
68+
}
69+
70+
set distort(v) {
71+
this._distort.value = v;
72+
}
73+
74+
get radius() {
75+
return this._radius.value;
76+
}
77+
78+
set radius(v) {
79+
this._radius.value = v;
80+
}
81+
};
82+
},
83+
};
84+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import * as THREE from 'three';
2+
3+
interface Uniform<T> {
4+
value: T;
5+
}
6+
7+
export class MeshWobbleMaterial extends THREE.MeshStandardMaterial {
8+
_time: Uniform<number>;
9+
_factor: Uniform<number>;
10+
11+
constructor(parameters: THREE.MeshStandardMaterialParameters = {}) {
12+
super(parameters);
13+
this.setValues(parameters);
14+
this._time = { value: 0 };
15+
this._factor = { value: 1 };
16+
}
17+
18+
override onBeforeCompile(shader: THREE.Shader) {
19+
shader.uniforms['time'] = this._time;
20+
shader.uniforms['factor'] = this._factor;
21+
22+
shader.vertexShader = `
23+
uniform float time;
24+
uniform float factor;
25+
${shader.vertexShader}
26+
`;
27+
shader.vertexShader = shader.vertexShader.replace(
28+
'#include <begin_vertex>',
29+
`float theta = sin( time + position.y ) / 2.0 * factor;
30+
float c = cos( theta );
31+
float s = sin( theta );
32+
mat3 m = mat3( c, 0, s, 0, 1, 0, -s, 0, c );
33+
vec3 transformed = vec3( position ) * m;
34+
vNormal = vNormal * m;`
35+
);
36+
}
37+
38+
get time() {
39+
return this._time.value;
40+
}
41+
42+
set time(v) {
43+
this._time.value = v;
44+
}
45+
46+
get factor() {
47+
return this._factor.value;
48+
}
49+
50+
set factor(v) {
51+
this._factor.value = v;
52+
}
53+
54+
declare speed: number;
55+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { Component, CUSTOM_ELEMENTS_SCHEMA, Input } from '@angular/core';
2+
import { Meta, moduleMetadata } from '@storybook/angular';
3+
import { injectBeforeRender, injectNgtRef, NgtArgs } from 'angular-three';
4+
import { NgtsMeshDistortMaterial } from 'angular-three-soba/materials';
5+
import { MeshDistortMaterial, provideNgtsMeshDistortMaterialShader } from 'angular-three-soba/shaders';
6+
import { makeStoryFunction, makeStoryObject, number, StorybookSetup } from '../setup-canvas';
7+
// @ts-ignore
8+
import distort from '../../shaders/assets/distort.vert.glsl';
9+
10+
@Component({
11+
standalone: true,
12+
template: `
13+
<ngt-mesh>
14+
<ngts-mesh-distort-material color="#f25042" [materialRef]="ref" />
15+
<ngt-icosahedron-geometry *args="[1, 4]" />
16+
</ngt-mesh>
17+
`,
18+
imports: [NgtsMeshDistortMaterial, NgtArgs],
19+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
20+
})
21+
class RefMeshDistortMaterialStory {
22+
readonly ref = injectNgtRef<InstanceType<MeshDistortMaterial>>();
23+
24+
constructor() {
25+
injectBeforeRender(({ clock }) => {
26+
this.ref.nativeElement.distort = Math.sin(clock.getElapsedTime());
27+
});
28+
}
29+
}
30+
31+
@Component({
32+
standalone: true,
33+
template: `
34+
<ngt-mesh>
35+
<ngts-mesh-distort-material color="#f25042" [speed]="speed" [distort]="distort" [radius]="radius" />
36+
<ngt-icosahedron-geometry *args="[1, 4]" />
37+
</ngt-mesh>
38+
`,
39+
imports: [NgtsMeshDistortMaterial, NgtArgs],
40+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
41+
})
42+
class DefaultMeshDistortMaterialStory {
43+
@Input() speed = 1;
44+
@Input() distort = 0.6;
45+
@Input() radius = 1;
46+
}
47+
48+
export default {
49+
title: 'Shaders/MeshDistortMaterial',
50+
decorators: [
51+
moduleMetadata({ imports: [StorybookSetup], providers: [provideNgtsMeshDistortMaterialShader(distort)] }),
52+
],
53+
} as Meta;
54+
55+
export const Default = makeStoryObject(DefaultMeshDistortMaterialStory, {
56+
argsOptions: {
57+
speed: number(1, { range: true, max: 10, step: 0.1 }),
58+
distort: number(0.6, { range: true, max: 1, step: 0.1 }),
59+
radius: number(1, { range: true, max: 1, step: 0.1 }),
60+
},
61+
});
62+
63+
export const Ref = makeStoryFunction(RefMeshDistortMaterialStory);

0 commit comments

Comments
 (0)