|
1 | | -import { color, mix, uv, sin, time } from 'three/tsl'; |
| 1 | +import { mix, uv, sin, time, vec3 } from 'three/tsl'; |
2 | 2 | import { NodeMaterial } from 'three/webgpu'; |
3 | 3 |
|
4 | | -export function createMaterial(): NodeMaterial { |
| 4 | +type PreviewRuntime = { |
| 5 | + uniforms?: Record<string, unknown> |
| 6 | +}; |
| 7 | + |
| 8 | +function readVec3(value: unknown, fallback: [number, number, number]): [number, number, number] { |
| 9 | + if ( |
| 10 | + Array.isArray(value) && |
| 11 | + value.length === 3 && |
| 12 | + value.every((entry) => typeof entry === 'number') |
| 13 | + ) { |
| 14 | + return value as [number, number, number]; |
| 15 | + } |
| 16 | + |
| 17 | + return fallback; |
| 18 | +} |
| 19 | + |
| 20 | +function readNumber(value: unknown, fallback: number): number { |
| 21 | + return typeof value === 'number' ? value : fallback; |
| 22 | +} |
| 23 | + |
| 24 | +export function createMaterial(runtime?: PreviewRuntime): NodeMaterial { |
5 | 25 | const material = new NodeMaterial(); |
6 | | - const t = sin(time.mul(2.0)).mul(0.5).add(0.5); |
| 26 | + |
| 27 | + const uniforms = runtime?.uniforms ?? {}; |
| 28 | + const colorA = readVec3(uniforms.uColorA, [0.1019607843, 0.1019607843, 0.1803921569]); |
| 29 | + const colorB = readVec3(uniforms.uColorB, [0.9137254902, 0.2705882353, 0.3764705882]); |
| 30 | + const waveSpeed = readNumber(uniforms.uWaveSpeed, 2.0); |
| 31 | + const waveMix = readNumber(uniforms.uWaveMix, 0.5); |
| 32 | + const waveFrequency = readNumber(uniforms.uWaveFrequency, 6.0); |
| 33 | + |
| 34 | + const uvMix = mix(uv().x, uv().y, waveMix).mul(waveFrequency); |
| 35 | + const t = sin(uvMix.add(time.mul(waveSpeed))).mul(0.5).add(0.5); |
| 36 | + |
7 | 37 | material.colorNode = mix( |
8 | | - color(0x1a1a2e), |
9 | | - color(0xe94560), |
10 | | - mix(uv().x, uv().y, t), |
| 38 | + vec3(...colorA), |
| 39 | + vec3(...colorB), |
| 40 | + t, |
11 | 41 | ); |
| 42 | + |
12 | 43 | return material; |
13 | 44 | } |
0 commit comments