@basementstudio/shader-lab 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.biome/plugins/README.md +21 -0
- package/.biome/plugins/no-anchor-element.grit +12 -0
- package/.biome/plugins/no-relative-parent-imports.grit +10 -0
- package/.biome/plugins/no-unnecessary-forwardref.grit +9 -0
- package/.changeset/README.md +17 -0
- package/.changeset/config.json +11 -0
- package/.editorconfig +40 -0
- package/.env.example +81 -0
- package/.gitattributes +19 -0
- package/.github/workflows/canary.yml +80 -0
- package/.github/workflows/ci.yml +37 -0
- package/.github/workflows/release.yml +56 -0
- package/.tldrignore +84 -0
- package/.vscode/extensions.json +20 -0
- package/.vscode/settings.json +105 -0
- package/README.md +119 -0
- package/biome.json +249 -0
- package/bun.lock +1224 -0
- package/next.config.ts +131 -0
- package/package.json +73 -0
- package/packages/shader-lab-react/CHANGELOG.md +9 -0
- package/packages/shader-lab-react/README.md +119 -0
- package/packages/shader-lab-react/assets/patterns/bars/1.svg +3 -0
- package/packages/shader-lab-react/assets/patterns/bars/2.svg +3 -0
- package/packages/shader-lab-react/assets/patterns/bars/3.svg +3 -0
- package/packages/shader-lab-react/assets/patterns/bars/4.svg +3 -0
- package/packages/shader-lab-react/assets/patterns/bars/5.svg +3 -0
- package/packages/shader-lab-react/assets/patterns/bars/6.svg +3 -0
- package/packages/shader-lab-react/assets/patterns/candles/1.svg +3 -0
- package/packages/shader-lab-react/assets/patterns/candles/2.svg +3 -0
- package/packages/shader-lab-react/assets/patterns/candles/3.svg +3 -0
- package/packages/shader-lab-react/assets/patterns/candles/4.svg +3 -0
- package/packages/shader-lab-react/assets/patterns/shapes/1.svg +3 -0
- package/packages/shader-lab-react/assets/patterns/shapes/2.svg +3 -0
- package/packages/shader-lab-react/assets/patterns/shapes/3.svg +3 -0
- package/packages/shader-lab-react/assets/patterns/shapes/4.svg +4 -0
- package/packages/shader-lab-react/assets/patterns/shapes/5.svg +3 -0
- package/packages/shader-lab-react/assets/patterns/shapes/6.svg +4 -0
- package/packages/shader-lab-react/assets/textures/blue-noise.png +0 -0
- package/packages/shader-lab-react/package.json +36 -0
- package/packages/shader-lab-react/scripts/fix-esm-specifiers.mjs +57 -0
- package/packages/shader-lab-react/scripts/prepare-dist.mjs +4 -0
- package/packages/shader-lab-react/src/ambient/three-tsl.d.ts +146 -0
- package/packages/shader-lab-react/src/ambient/three-webgpu.d.ts +51 -0
- package/packages/shader-lab-react/src/easings.ts +4 -0
- package/packages/shader-lab-react/src/index.ts +35 -0
- package/packages/shader-lab-react/src/lib/editor/custom-shader/shared.ts +2 -0
- package/packages/shader-lab-react/src/renderer/ascii-atlas.ts +83 -0
- package/packages/shader-lab-react/src/renderer/ascii-pass.ts +416 -0
- package/packages/shader-lab-react/src/renderer/asset-url.ts +3 -0
- package/packages/shader-lab-react/src/renderer/blend-modes.ts +229 -0
- package/packages/shader-lab-react/src/renderer/contracts.ts +54 -0
- package/packages/shader-lab-react/src/renderer/create-webgpu-renderer.ts +48 -0
- package/packages/shader-lab-react/src/renderer/crt-pass.ts +1040 -0
- package/packages/shader-lab-react/src/renderer/custom-shader-pass.ts +108 -0
- package/packages/shader-lab-react/src/renderer/custom-shader-runtime.ts +309 -0
- package/packages/shader-lab-react/src/renderer/dither-textures.ts +99 -0
- package/packages/shader-lab-react/src/renderer/dithering-pass.ts +322 -0
- package/packages/shader-lab-react/src/renderer/gradient-pass.ts +521 -0
- package/packages/shader-lab-react/src/renderer/halftone-pass.ts +932 -0
- package/packages/shader-lab-react/src/renderer/ink-pass.ts +802 -0
- package/packages/shader-lab-react/src/renderer/live-pass.ts +194 -0
- package/packages/shader-lab-react/src/renderer/media-pass.ts +187 -0
- package/packages/shader-lab-react/src/renderer/media-texture.ts +66 -0
- package/packages/shader-lab-react/src/renderer/particle-grid-pass.ts +389 -0
- package/packages/shader-lab-react/src/renderer/pass-node.ts +209 -0
- package/packages/shader-lab-react/src/renderer/pattern-atlas.ts +133 -0
- package/packages/shader-lab-react/src/renderer/pattern-pass.ts +552 -0
- package/packages/shader-lab-react/src/renderer/pipeline-manager.ts +369 -0
- package/packages/shader-lab-react/src/renderer/pixel-sorting-pass.ts +277 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/color/tonemapping.ts +87 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/cosine-palette.ts +9 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/noise/common.ts +31 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/noise/curl-noise-3d.ts +36 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/noise/curl-noise-4d.ts +36 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/noise/fbm.ts +13 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/noise/perlin-noise-3d.ts +96 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/noise/ridge-noise.ts +24 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/noise/simplex-noise-3d.ts +79 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/noise/simplex-noise-4d.ts +89 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/noise/turbulence.ts +56 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/noise/value-noise-3d.ts +32 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/noise/voronoi-noise-3d.ts +60 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/patterns/bloom-edge-pattern.ts +15 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/patterns/bloom.ts +11 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/patterns/canvas-weave-pattern.ts +24 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/patterns/grain-texture-pattern.ts +9 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/patterns/repeating-pattern.ts +11 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/atan2.ts +9 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/complex-conj.ts +9 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/complex-cos.ts +10 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/complex-div.ts +11 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/complex-log.ts +7 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/complex-mobius.ts +12 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/complex-mul.ts +9 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/complex-pow.ts +16 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/complex-sin.ts +10 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/complex-sqrt.ts +18 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/complex-tan.ts +12 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/complex-to-polar.ts +10 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/hyperbolic.ts +20 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/index.ts +48 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/rotate.ts +15 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/screen-aspect-uv.ts +15 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/sd-box-2d.ts +6 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/sd-diamond.ts +6 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/sd-rhombus.ts +27 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/sd-sphere.ts +6 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/smax.ts +7 -0
- package/packages/shader-lab-react/src/renderer/shaders/tsl/utils/smin.ts +7 -0
- package/packages/shader-lab-react/src/renderer/text-pass.ts +176 -0
- package/packages/shader-lab-react/src/runtime-clock.ts +42 -0
- package/packages/shader-lab-react/src/runtime-frame.ts +29 -0
- package/packages/shader-lab-react/src/shader-lab-composition.tsx +163 -0
- package/packages/shader-lab-react/src/timeline.ts +283 -0
- package/packages/shader-lab-react/src/types/editor.ts +5 -0
- package/packages/shader-lab-react/src/types.ts +141 -0
- package/packages/shader-lab-react/tsconfig.build.json +8 -0
- package/packages/shader-lab-react/tsconfig.json +21 -0
- package/postcss.config.mjs +5 -0
- package/public/assets/fonts/msdf/geist-mono/GeistMono-Regular-msdf-atlas.png +0 -0
- package/public/assets/fonts/msdf/geist-mono/GeistMono-Regular-msdf.json +1412 -0
- package/public/assets/patterns/bars/1.svg +3 -0
- package/public/assets/patterns/bars/2.svg +3 -0
- package/public/assets/patterns/bars/3.svg +3 -0
- package/public/assets/patterns/bars/4.svg +3 -0
- package/public/assets/patterns/bars/5.svg +3 -0
- package/public/assets/patterns/bars/6.svg +3 -0
- package/public/assets/patterns/candles/1.svg +3 -0
- package/public/assets/patterns/candles/2.svg +3 -0
- package/public/assets/patterns/candles/3.svg +3 -0
- package/public/assets/patterns/candles/4.svg +3 -0
- package/public/assets/patterns/shapes/1.svg +3 -0
- package/public/assets/patterns/shapes/2.svg +3 -0
- package/public/assets/patterns/shapes/3.svg +3 -0
- package/public/assets/patterns/shapes/4.svg +4 -0
- package/public/assets/patterns/shapes/5.svg +3 -0
- package/public/assets/patterns/shapes/6.svg +4 -0
- package/public/fonts/geist/Geist-Mono.woff2 +0 -0
- package/public/textures/blue-noise.png +0 -0
- package/public/textures/crt-mask.png +0 -0
- package/src/app/design/page.tsx +398 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/globals.css +280 -0
- package/src/app/layout.tsx +89 -0
- package/src/app/page.tsx +20 -0
- package/src/app/robots.ts +13 -0
- package/src/app/sitemap.ts +13 -0
- package/src/components/editor/editor-canvas-viewport.tsx +116 -0
- package/src/components/editor/editor-export-dialog.tsx +1177 -0
- package/src/components/editor/editor-timeline-overlay.tsx +983 -0
- package/src/components/editor/editor-topbar.tsx +287 -0
- package/src/components/editor/layer-sidebar.tsx +738 -0
- package/src/components/editor/properties-sidebar-content.tsx +574 -0
- package/src/components/editor/properties-sidebar-fields.tsx +389 -0
- package/src/components/editor/properties-sidebar-utils.ts +178 -0
- package/src/components/editor/properties-sidebar.tsx +421 -0
- package/src/components/ui/button/index.tsx +57 -0
- package/src/components/ui/color-picker/index.tsx +358 -0
- package/src/components/ui/glass-panel/index.tsx +45 -0
- package/src/components/ui/icon-button/index.tsx +46 -0
- package/src/components/ui/select/index.tsx +136 -0
- package/src/components/ui/slider/index.tsx +192 -0
- package/src/components/ui/toggle/index.tsx +34 -0
- package/src/components/ui/typography/index.tsx +61 -0
- package/src/components/ui/xy-pad/index.tsx +160 -0
- package/src/features/editor/components/editor-export-dialog.module.css +271 -0
- package/src/hooks/use-editor-renderer.ts +182 -0
- package/src/lib/app.ts +6 -0
- package/src/lib/cn.ts +7 -0
- package/src/lib/easings.ts +240 -0
- package/src/lib/editor/config/layer-registry.ts +2434 -0
- package/src/lib/editor/custom-shader/shared.ts +28 -0
- package/src/lib/editor/export.ts +420 -0
- package/src/lib/editor/history.ts +71 -0
- package/src/lib/editor/layers.ts +76 -0
- package/src/lib/editor/parameter-schema.ts +75 -0
- package/src/lib/editor/project-file.ts +145 -0
- package/src/lib/editor/shader-export-snippet.ts +37 -0
- package/src/lib/editor/shader-export.ts +315 -0
- package/src/lib/editor/timeline/evaluate.ts +252 -0
- package/src/lib/editor/view-transform.ts +58 -0
- package/src/lib/fonts.ts +28 -0
- package/src/renderer/ascii-atlas.ts +83 -0
- package/src/renderer/ascii-pass.ts +416 -0
- package/src/renderer/blend-modes.ts +229 -0
- package/src/renderer/contracts.ts +161 -0
- package/src/renderer/create-webgpu-renderer.ts +48 -0
- package/src/renderer/crt-pass.ts +1040 -0
- package/src/renderer/custom-shader-pass.ts +117 -0
- package/src/renderer/custom-shader-runtime.ts +309 -0
- package/src/renderer/dither-textures.ts +99 -0
- package/src/renderer/dithering-pass.ts +322 -0
- package/src/renderer/gradient-pass.ts +520 -0
- package/src/renderer/halftone-pass.ts +932 -0
- package/src/renderer/ink-pass.ts +683 -0
- package/src/renderer/live-pass.ts +194 -0
- package/src/renderer/media-pass.ts +187 -0
- package/src/renderer/media-texture.ts +66 -0
- package/src/renderer/particle-grid-pass.ts +389 -0
- package/src/renderer/pass-node-factory.ts +33 -0
- package/src/renderer/pass-node.ts +209 -0
- package/src/renderer/pattern-atlas.ts +97 -0
- package/src/renderer/pattern-pass.ts +552 -0
- package/src/renderer/pipeline-manager.ts +343 -0
- package/src/renderer/pixel-sorting-pass.ts +277 -0
- package/src/renderer/project-clock.ts +57 -0
- package/src/renderer/shaders/tsl/color/tonemapping.ts +86 -0
- package/src/renderer/shaders/tsl/cosine-palette.ts +8 -0
- package/src/renderer/shaders/tsl/noise/common.ts +30 -0
- package/src/renderer/shaders/tsl/noise/curl-noise-3d.ts +35 -0
- package/src/renderer/shaders/tsl/noise/curl-noise-4d.ts +35 -0
- package/src/renderer/shaders/tsl/noise/fbm.ts +12 -0
- package/src/renderer/shaders/tsl/noise/perlin-noise-3d.ts +97 -0
- package/src/renderer/shaders/tsl/noise/ridge-noise.ts +23 -0
- package/src/renderer/shaders/tsl/noise/simplex-noise-3d.ts +78 -0
- package/src/renderer/shaders/tsl/noise/simplex-noise-4d.ts +88 -0
- package/src/renderer/shaders/tsl/noise/turbulence.ts +55 -0
- package/src/renderer/shaders/tsl/noise/value-noise-3d.ts +31 -0
- package/src/renderer/shaders/tsl/noise/voronoi-noise-3d.ts +59 -0
- package/src/renderer/shaders/tsl/patterns/bloom-edge-pattern.ts +14 -0
- package/src/renderer/shaders/tsl/patterns/bloom.ts +10 -0
- package/src/renderer/shaders/tsl/patterns/canvas-weave-pattern.ts +23 -0
- package/src/renderer/shaders/tsl/patterns/grain-texture-pattern.ts +8 -0
- package/src/renderer/shaders/tsl/patterns/repeating-pattern.ts +10 -0
- package/src/renderer/shaders/tsl/utils/atan2.ts +8 -0
- package/src/renderer/shaders/tsl/utils/complex-conj.ts +8 -0
- package/src/renderer/shaders/tsl/utils/complex-cos.ts +9 -0
- package/src/renderer/shaders/tsl/utils/complex-div.ts +10 -0
- package/src/renderer/shaders/tsl/utils/complex-log.ts +6 -0
- package/src/renderer/shaders/tsl/utils/complex-mobius.ts +11 -0
- package/src/renderer/shaders/tsl/utils/complex-mul.ts +8 -0
- package/src/renderer/shaders/tsl/utils/complex-pow.ts +15 -0
- package/src/renderer/shaders/tsl/utils/complex-sin.ts +9 -0
- package/src/renderer/shaders/tsl/utils/complex-sqrt.ts +17 -0
- package/src/renderer/shaders/tsl/utils/complex-tan.ts +11 -0
- package/src/renderer/shaders/tsl/utils/complex-to-polar.ts +9 -0
- package/src/renderer/shaders/tsl/utils/hyperbolic.ts +19 -0
- package/src/renderer/shaders/tsl/utils/index.ts +47 -0
- package/src/renderer/shaders/tsl/utils/rotate.ts +14 -0
- package/src/renderer/shaders/tsl/utils/screen-aspect-uv.ts +14 -0
- package/src/renderer/shaders/tsl/utils/sd-box-2d.ts +5 -0
- package/src/renderer/shaders/tsl/utils/sd-diamond.ts +5 -0
- package/src/renderer/shaders/tsl/utils/sd-rhombus.ts +26 -0
- package/src/renderer/shaders/tsl/utils/sd-sphere.ts +5 -0
- package/src/renderer/shaders/tsl/utils/smax.ts +7 -0
- package/src/renderer/shaders/tsl/utils/smin.ts +6 -0
- package/src/renderer/text-pass.ts +176 -0
- package/src/store/asset-store.ts +193 -0
- package/src/store/editor-store.ts +223 -0
- package/src/store/history-store.ts +172 -0
- package/src/store/index.ts +31 -0
- package/src/store/layer-store.ts +675 -0
- package/src/store/timeline-store.ts +572 -0
- package/src/types/assets.d.ts +6 -0
- package/src/types/css.d.ts +21 -0
- package/src/types/editor.ts +357 -0
- package/src/types/react.d.ts +15 -0
- package/src/types/three-tsl.d.ts +146 -0
- package/src/types/three-webgpu.d.ts +51 -0
- package/tsconfig.json +49 -0
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
import * as THREE from "three/webgpu"
|
|
2
|
+
import { bloom } from "three/examples/jsm/tsl/display/BloomNode.js"
|
|
3
|
+
import {
|
|
4
|
+
attribute,
|
|
5
|
+
clamp,
|
|
6
|
+
float,
|
|
7
|
+
positionLocal,
|
|
8
|
+
smoothstep,
|
|
9
|
+
texture as tslTexture,
|
|
10
|
+
type TSLNode,
|
|
11
|
+
uniform,
|
|
12
|
+
uv,
|
|
13
|
+
vec2,
|
|
14
|
+
vec3,
|
|
15
|
+
vec4,
|
|
16
|
+
} from "three/tsl"
|
|
17
|
+
import { PassNode } from "@/renderer/pass-node"
|
|
18
|
+
import { simplexNoise3d } from "@/renderer/shaders/tsl/noise/simplex-noise-3d"
|
|
19
|
+
import type { LayerParameterValues } from "@/types/editor"
|
|
20
|
+
|
|
21
|
+
type Node = TSLNode
|
|
22
|
+
|
|
23
|
+
function clamp01(value: number): number {
|
|
24
|
+
return Math.max(0, Math.min(1, value))
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class ParticleGridPass extends PassNode {
|
|
28
|
+
private readonly perspScene: THREE.Scene
|
|
29
|
+
private readonly perspCamera: THREE.PerspectiveCamera
|
|
30
|
+
private readonly internalRT: THREE.WebGLRenderTarget
|
|
31
|
+
private readonly blitInputNode: Node
|
|
32
|
+
|
|
33
|
+
private inputSamplerNode: Node | null = null
|
|
34
|
+
private readonly displacementUniform: Node
|
|
35
|
+
private readonly pointSizeUniform: Node
|
|
36
|
+
private readonly timeUniform: Node
|
|
37
|
+
private readonly noiseAmountUniform: Node
|
|
38
|
+
private readonly noiseScaleUniform: Node
|
|
39
|
+
private readonly noiseSpeedUniform: Node
|
|
40
|
+
|
|
41
|
+
// Bloom
|
|
42
|
+
private bloomEnabled = false
|
|
43
|
+
private bloomNode: ReturnType<typeof bloom> | null = null
|
|
44
|
+
private readonly bloomIntensityUniform: Node
|
|
45
|
+
private readonly bloomRadiusUniform: Node
|
|
46
|
+
private readonly bloomSoftnessUniform: Node
|
|
47
|
+
private readonly bloomThresholdUniform: Node
|
|
48
|
+
|
|
49
|
+
private mesh: THREE.Mesh | null = null
|
|
50
|
+
private meshMaterial: THREE.MeshBasicNodeMaterial | null = null
|
|
51
|
+
private readonly bgColor = new THREE.Color(0x000000)
|
|
52
|
+
private gridResolution = 64
|
|
53
|
+
private isAnimated = false
|
|
54
|
+
private needsRebuild = true
|
|
55
|
+
private width = 1
|
|
56
|
+
private height = 1
|
|
57
|
+
private readonly placeholder: THREE.Texture
|
|
58
|
+
|
|
59
|
+
constructor(layerId: string) {
|
|
60
|
+
super(layerId)
|
|
61
|
+
|
|
62
|
+
this.perspScene = new THREE.Scene()
|
|
63
|
+
this.perspCamera = new THREE.PerspectiveCamera(45, 1, 0.01, 100)
|
|
64
|
+
this.perspCamera.position.set(0, 0, 1.2)
|
|
65
|
+
this.perspCamera.lookAt(0, 0, 0)
|
|
66
|
+
|
|
67
|
+
this.placeholder = new THREE.Texture()
|
|
68
|
+
|
|
69
|
+
this.internalRT = new THREE.WebGLRenderTarget(1, 1, {
|
|
70
|
+
depthBuffer: true,
|
|
71
|
+
format: THREE.RGBAFormat,
|
|
72
|
+
generateMipmaps: false,
|
|
73
|
+
magFilter: THREE.LinearFilter,
|
|
74
|
+
minFilter: THREE.LinearFilter,
|
|
75
|
+
stencilBuffer: false,
|
|
76
|
+
type: THREE.HalfFloatType,
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
this.displacementUniform = uniform(0.5)
|
|
80
|
+
this.pointSizeUniform = uniform(3.0)
|
|
81
|
+
this.timeUniform = uniform(0.0)
|
|
82
|
+
this.noiseAmountUniform = uniform(0.0)
|
|
83
|
+
this.noiseScaleUniform = uniform(3.0)
|
|
84
|
+
this.noiseSpeedUniform = uniform(0.5)
|
|
85
|
+
|
|
86
|
+
this.bloomIntensityUniform = uniform(1.25)
|
|
87
|
+
this.bloomRadiusUniform = uniform(6)
|
|
88
|
+
this.bloomSoftnessUniform = uniform(0.35)
|
|
89
|
+
this.bloomThresholdUniform = uniform(0.6)
|
|
90
|
+
|
|
91
|
+
const blitUv = vec2(uv().x, float(1).sub(uv().y))
|
|
92
|
+
this.blitInputNode = tslTexture(new THREE.Texture(), blitUv)
|
|
93
|
+
|
|
94
|
+
this.rebuildEffectNode()
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
override render(
|
|
98
|
+
renderer: THREE.WebGPURenderer,
|
|
99
|
+
inputTexture: THREE.Texture,
|
|
100
|
+
outputTarget: THREE.WebGLRenderTarget,
|
|
101
|
+
time: number,
|
|
102
|
+
delta: number,
|
|
103
|
+
): void {
|
|
104
|
+
if (this.needsRebuild) {
|
|
105
|
+
this.rebuildGrid()
|
|
106
|
+
this.needsRebuild = false
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (this.inputSamplerNode) {
|
|
110
|
+
this.inputSamplerNode.value = inputTexture
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
renderer.setClearColor(this.bgColor, 1)
|
|
114
|
+
renderer.setRenderTarget(this.internalRT)
|
|
115
|
+
renderer.render(this.perspScene, this.perspCamera)
|
|
116
|
+
|
|
117
|
+
this.blitInputNode.value = this.internalRT.texture
|
|
118
|
+
super.render(renderer, inputTexture, outputTarget, time, delta)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
protected override beforeRender(time: number, _delta: number): void {
|
|
122
|
+
this.timeUniform.value = time
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
override needsContinuousRender(): boolean {
|
|
126
|
+
return this.isAnimated
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
override updateParams(params: LayerParameterValues): void {
|
|
130
|
+
const nextResolution =
|
|
131
|
+
typeof params.gridResolution === "number"
|
|
132
|
+
? Math.max(16, Math.min(512, Math.round(params.gridResolution)))
|
|
133
|
+
: 64
|
|
134
|
+
const nextPointSize =
|
|
135
|
+
typeof params.pointSize === "number" ? params.pointSize : 3
|
|
136
|
+
const nextBloomEnabled = params.bloomEnabled === true
|
|
137
|
+
|
|
138
|
+
if (nextResolution !== this.gridResolution || nextPointSize !== (this.pointSizeUniform.value as number)) {
|
|
139
|
+
this.gridResolution = nextResolution
|
|
140
|
+
this.pointSizeUniform.value = nextPointSize
|
|
141
|
+
this.needsRebuild = true
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
this.displacementUniform.value =
|
|
145
|
+
typeof params.displacement === "number" ? params.displacement : 0.5
|
|
146
|
+
|
|
147
|
+
this.bgColor.set(typeof params.backgroundColor === "string" ? params.backgroundColor : "#000000")
|
|
148
|
+
|
|
149
|
+
const noiseAmount = typeof params.noiseAmount === "number" ? params.noiseAmount : 0
|
|
150
|
+
this.noiseAmountUniform.value = noiseAmount
|
|
151
|
+
this.noiseScaleUniform.value =
|
|
152
|
+
typeof params.noiseScale === "number" ? params.noiseScale : 3
|
|
153
|
+
this.noiseSpeedUniform.value =
|
|
154
|
+
typeof params.noiseSpeed === "number" ? params.noiseSpeed : 0.5
|
|
155
|
+
this.isAnimated = noiseAmount > 0
|
|
156
|
+
|
|
157
|
+
this.bloomIntensityUniform.value =
|
|
158
|
+
typeof params.bloomIntensity === "number" ? Math.max(0, params.bloomIntensity) : 1.25
|
|
159
|
+
this.bloomThresholdUniform.value =
|
|
160
|
+
typeof params.bloomThreshold === "number" ? clamp01(params.bloomThreshold) : 0.6
|
|
161
|
+
this.bloomRadiusUniform.value =
|
|
162
|
+
typeof params.bloomRadius === "number" ? Math.max(0, params.bloomRadius) : 6
|
|
163
|
+
this.bloomSoftnessUniform.value =
|
|
164
|
+
typeof params.bloomSoftness === "number" ? clamp01(params.bloomSoftness) : 0.35
|
|
165
|
+
|
|
166
|
+
if (nextBloomEnabled !== this.bloomEnabled) {
|
|
167
|
+
this.bloomEnabled = nextBloomEnabled
|
|
168
|
+
this.rebuildEffectNode()
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (this.bloomNode) {
|
|
172
|
+
this.bloomNode.strength.value = this.bloomIntensityUniform.value as number
|
|
173
|
+
this.bloomNode.radius.value = this.normalizeBloomRadius(this.bloomRadiusUniform.value as number)
|
|
174
|
+
this.bloomNode.threshold.value = this.bloomThresholdUniform.value as number
|
|
175
|
+
this.bloomNode.smoothWidth.value = this.normalizeBloomSoftness(this.bloomSoftnessUniform.value as number)
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
override resize(width: number, height: number): void {
|
|
180
|
+
this.width = Math.max(1, width)
|
|
181
|
+
this.height = Math.max(1, height)
|
|
182
|
+
this.internalRT.setSize(this.width, this.height)
|
|
183
|
+
this.perspCamera.aspect = this.width / this.height
|
|
184
|
+
this.perspCamera.updateProjectionMatrix()
|
|
185
|
+
this.needsRebuild = true
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
override dispose(): void {
|
|
189
|
+
this.disposeBloomNode()
|
|
190
|
+
this.clearGrid()
|
|
191
|
+
this.placeholder.dispose()
|
|
192
|
+
this.internalRT.dispose()
|
|
193
|
+
super.dispose()
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
protected override buildEffectNode(): Node {
|
|
197
|
+
if (!this.blitInputNode) {
|
|
198
|
+
return this.inputNode
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
this.disposeBloomNode()
|
|
202
|
+
this.bloomNode = null
|
|
203
|
+
|
|
204
|
+
const baseColor = vec3(this.blitInputNode.r, this.blitInputNode.g, this.blitInputNode.b)
|
|
205
|
+
|
|
206
|
+
if (!this.bloomEnabled) {
|
|
207
|
+
return vec4(baseColor, float(1))
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const bloomInput = vec4(baseColor, float(1))
|
|
211
|
+
this.bloomNode = bloom(
|
|
212
|
+
bloomInput,
|
|
213
|
+
this.bloomIntensityUniform.value as number,
|
|
214
|
+
this.normalizeBloomRadius(this.bloomRadiusUniform.value as number),
|
|
215
|
+
this.bloomThresholdUniform.value as number,
|
|
216
|
+
)
|
|
217
|
+
this.bloomNode.smoothWidth.value = this.normalizeBloomSoftness(
|
|
218
|
+
this.bloomSoftnessUniform.value as number,
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
return vec4(
|
|
222
|
+
clamp(
|
|
223
|
+
baseColor.add(this.getBloomTextureNode().rgb),
|
|
224
|
+
vec3(float(0), float(0), float(0)),
|
|
225
|
+
vec3(float(1), float(1), float(1)),
|
|
226
|
+
),
|
|
227
|
+
float(1),
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
private rebuildGrid(): void {
|
|
232
|
+
this.clearGrid()
|
|
233
|
+
|
|
234
|
+
const res = this.gridResolution
|
|
235
|
+
const count = res * res
|
|
236
|
+
const aspect = this.width / this.height
|
|
237
|
+
const pointSize = this.pointSizeUniform.value as number
|
|
238
|
+
|
|
239
|
+
// Camera frustum at z=0
|
|
240
|
+
const halfH = Math.tan((45 * Math.PI) / 360) * 1.2
|
|
241
|
+
const halfW = halfH * aspect
|
|
242
|
+
|
|
243
|
+
// Size of each quad in world units — convert point size from pixels to world
|
|
244
|
+
// At z=0 with camera at 1.2, 1 world unit = canvas_height / (2 * halfH) pixels
|
|
245
|
+
const pixelsPerUnit = this.height / (2 * halfH)
|
|
246
|
+
const quadWorldSize = pointSize / pixelsPerUnit
|
|
247
|
+
|
|
248
|
+
// Base quad: unit plane centered at origin
|
|
249
|
+
const baseGeo = new THREE.PlaneGeometry(1, 1)
|
|
250
|
+
|
|
251
|
+
// Instance attributes
|
|
252
|
+
const offsets = new Float32Array(count * 3)
|
|
253
|
+
const gridUvs = new Float32Array(count * 2)
|
|
254
|
+
|
|
255
|
+
for (let row = 0; row < res; row++) {
|
|
256
|
+
for (let col = 0; col < res; col++) {
|
|
257
|
+
const i = row * res + col
|
|
258
|
+
const u = col / (res - 1)
|
|
259
|
+
const v = row / (res - 1)
|
|
260
|
+
|
|
261
|
+
offsets[i * 3] = (u * 2 - 1) * halfW
|
|
262
|
+
offsets[i * 3 + 1] = (v * 2 - 1) * halfH
|
|
263
|
+
offsets[i * 3 + 2] = 0
|
|
264
|
+
|
|
265
|
+
gridUvs[i * 2] = u
|
|
266
|
+
gridUvs[i * 2 + 1] = 1 - v
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const instancedGeo = new THREE.InstancedBufferGeometry()
|
|
271
|
+
instancedGeo.index = baseGeo.index
|
|
272
|
+
instancedGeo.setAttribute("position", baseGeo.getAttribute("position")!)
|
|
273
|
+
instancedGeo.setAttribute("normal", baseGeo.getAttribute("normal")!)
|
|
274
|
+
instancedGeo.setAttribute("uv", baseGeo.getAttribute("uv")!)
|
|
275
|
+
instancedGeo.setAttribute("instanceOffset", new THREE.InstancedBufferAttribute(offsets, 3))
|
|
276
|
+
instancedGeo.setAttribute("instanceGridUv", new THREE.InstancedBufferAttribute(gridUvs, 2))
|
|
277
|
+
instancedGeo.instanceCount = count
|
|
278
|
+
|
|
279
|
+
// GPU material
|
|
280
|
+
const instanceOffset = attribute("instanceOffset", "vec3")
|
|
281
|
+
const instanceGridUv = attribute("instanceGridUv", "vec2")
|
|
282
|
+
|
|
283
|
+
// Sample input texture per instance
|
|
284
|
+
this.inputSamplerNode = tslTexture(this.placeholder, instanceGridUv)
|
|
285
|
+
const sampledColor = this.inputSamplerNode
|
|
286
|
+
|
|
287
|
+
// Luma for Z displacement
|
|
288
|
+
const luma = sampledColor.r
|
|
289
|
+
.mul(0.2126)
|
|
290
|
+
.add(sampledColor.g.mul(0.7152))
|
|
291
|
+
.add(sampledColor.b.mul(0.0722))
|
|
292
|
+
|
|
293
|
+
// Per-particle noise using instance grid UV scaled by resolution
|
|
294
|
+
const noiseUv = vec2(
|
|
295
|
+
instanceGridUv.x.mul(float(res)).mul(this.noiseScaleUniform),
|
|
296
|
+
instanceGridUv.y.mul(float(res)).mul(this.noiseScaleUniform),
|
|
297
|
+
)
|
|
298
|
+
const noiseInputX = vec3(
|
|
299
|
+
noiseUv.x,
|
|
300
|
+
noiseUv.y,
|
|
301
|
+
this.timeUniform.mul(this.noiseSpeedUniform),
|
|
302
|
+
)
|
|
303
|
+
const noiseInputY = vec3(
|
|
304
|
+
noiseUv.x,
|
|
305
|
+
noiseUv.y,
|
|
306
|
+
this.timeUniform.mul(this.noiseSpeedUniform).add(float(100)),
|
|
307
|
+
)
|
|
308
|
+
const noiseOffsetX = simplexNoise3d(noiseInputX).mul(this.noiseAmountUniform).mul(0.01)
|
|
309
|
+
const noiseOffsetY = simplexNoise3d(noiseInputY).mul(this.noiseAmountUniform).mul(0.01)
|
|
310
|
+
|
|
311
|
+
// Scale quad vertices by world size, then offset to instance position + noise + displacement
|
|
312
|
+
const scaledPos = positionLocal.mul(float(quadWorldSize))
|
|
313
|
+
const finalPos = vec3(
|
|
314
|
+
scaledPos.x.add(instanceOffset.x).add(noiseOffsetX),
|
|
315
|
+
scaledPos.y.add(instanceOffset.y).add(noiseOffsetY),
|
|
316
|
+
scaledPos.z.add(instanceOffset.z).add(luma.mul(this.displacementUniform)),
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
// Circle mask using quad UV (0–1 per quad)
|
|
320
|
+
// Edge width scales with point size so anti-aliasing is always ~1.5px
|
|
321
|
+
const quadUv = uv()
|
|
322
|
+
const dist = vec2(quadUv.x.sub(0.5), quadUv.y.sub(0.5)).length()
|
|
323
|
+
const aaWidth = float(1.5).div(this.pointSizeUniform)
|
|
324
|
+
const circleMask = smoothstep(float(0.5), float(0.5).sub(aaWidth), dist)
|
|
325
|
+
|
|
326
|
+
const material = new THREE.MeshBasicNodeMaterial()
|
|
327
|
+
material.positionNode = finalPos as Node
|
|
328
|
+
material.colorNode = vec4(sampledColor.r, sampledColor.g, sampledColor.b, circleMask) as Node
|
|
329
|
+
material.transparent = true
|
|
330
|
+
material.alphaTest = 0.01
|
|
331
|
+
material.depthWrite = false
|
|
332
|
+
material.side = THREE.DoubleSide
|
|
333
|
+
|
|
334
|
+
this.meshMaterial = material
|
|
335
|
+
this.mesh = new THREE.Mesh(instancedGeo, material)
|
|
336
|
+
this.mesh.frustumCulled = false
|
|
337
|
+
this.perspScene.add(this.mesh)
|
|
338
|
+
|
|
339
|
+
baseGeo.dispose()
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
private clearGrid(): void {
|
|
343
|
+
if (this.mesh) {
|
|
344
|
+
this.perspScene.remove(this.mesh)
|
|
345
|
+
this.mesh.geometry.dispose()
|
|
346
|
+
this.mesh = null
|
|
347
|
+
}
|
|
348
|
+
if (this.meshMaterial) {
|
|
349
|
+
this.meshMaterial.dispose()
|
|
350
|
+
this.meshMaterial = null
|
|
351
|
+
}
|
|
352
|
+
this.inputSamplerNode = null
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
private normalizeBloomRadius(value: number): number {
|
|
356
|
+
return clamp01(value / 24)
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
private normalizeBloomSoftness(value: number): number {
|
|
360
|
+
return Math.max(0.001, value * 0.25)
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
private disposeBloomNode(): void {
|
|
364
|
+
;(this.bloomNode as { dispose?: () => void } | null)?.dispose?.()
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
private getBloomTextureNode(): Node {
|
|
368
|
+
const bloomNode = this.bloomNode as
|
|
369
|
+
| ({
|
|
370
|
+
getTexture?: () => Node
|
|
371
|
+
getTextureNode?: () => Node
|
|
372
|
+
} & object)
|
|
373
|
+
| null
|
|
374
|
+
|
|
375
|
+
if (!bloomNode) {
|
|
376
|
+
throw new Error("Bloom node is not initialized")
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
if ("getTextureNode" in bloomNode && typeof bloomNode.getTextureNode === "function") {
|
|
380
|
+
return bloomNode.getTextureNode()
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
if ("getTexture" in bloomNode && typeof bloomNode.getTexture === "function") {
|
|
384
|
+
return bloomNode.getTexture()
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
throw new Error("Bloom node does not expose a texture getter")
|
|
388
|
+
}
|
|
389
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { AsciiPass } from "@/renderer/ascii-pass"
|
|
2
|
+
import { CrtPass } from "@/renderer/crt-pass"
|
|
3
|
+
import { DitheringPass } from "@/renderer/dithering-pass"
|
|
4
|
+
import { HalftonePass } from "@/renderer/halftone-pass"
|
|
5
|
+
import { InkPass } from "@/renderer/ink-pass"
|
|
6
|
+
import { ParticleGridPass } from "@/renderer/particle-grid-pass"
|
|
7
|
+
import { PassNode } from "@/renderer/pass-node"
|
|
8
|
+
import { PatternPass } from "@/renderer/pattern-pass"
|
|
9
|
+
import { PixelSortingPass } from "@/renderer/pixel-sorting-pass"
|
|
10
|
+
import type { EffectLayerType } from "@/types/editor"
|
|
11
|
+
|
|
12
|
+
export function createPassNode(layerId: string, type: EffectLayerType): PassNode {
|
|
13
|
+
switch (type) {
|
|
14
|
+
case "ascii":
|
|
15
|
+
return new AsciiPass(layerId)
|
|
16
|
+
case "crt":
|
|
17
|
+
return new CrtPass(layerId)
|
|
18
|
+
case "dithering":
|
|
19
|
+
return new DitheringPass(layerId)
|
|
20
|
+
case "halftone":
|
|
21
|
+
return new HalftonePass(layerId)
|
|
22
|
+
case "ink":
|
|
23
|
+
return new InkPass(layerId)
|
|
24
|
+
case "pattern":
|
|
25
|
+
return new PatternPass(layerId)
|
|
26
|
+
case "particle-grid":
|
|
27
|
+
return new ParticleGridPass(layerId)
|
|
28
|
+
case "pixel-sorting":
|
|
29
|
+
return new PixelSortingPass(layerId)
|
|
30
|
+
default:
|
|
31
|
+
return new PassNode(layerId)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import * as THREE from "three/webgpu"
|
|
2
|
+
import {
|
|
3
|
+
clamp,
|
|
4
|
+
cos,
|
|
5
|
+
float,
|
|
6
|
+
mix,
|
|
7
|
+
sin,
|
|
8
|
+
texture as tslTexture,
|
|
9
|
+
type TSLNode,
|
|
10
|
+
uniform,
|
|
11
|
+
uv,
|
|
12
|
+
vec2,
|
|
13
|
+
vec3,
|
|
14
|
+
vec4,
|
|
15
|
+
} from "three/tsl"
|
|
16
|
+
import { buildBlendNode } from "@/renderer/blend-modes"
|
|
17
|
+
import type { LayerCompositeMode, LayerParameterValues } from "@/types/editor"
|
|
18
|
+
|
|
19
|
+
type Node = TSLNode
|
|
20
|
+
|
|
21
|
+
export class PassNode {
|
|
22
|
+
readonly layerId: string
|
|
23
|
+
|
|
24
|
+
enabled = true
|
|
25
|
+
|
|
26
|
+
protected readonly scene: THREE.Scene
|
|
27
|
+
protected readonly camera: THREE.OrthographicCamera
|
|
28
|
+
protected readonly material: THREE.MeshBasicNodeMaterial
|
|
29
|
+
protected readonly inputNode: Node
|
|
30
|
+
protected effectNode: Node
|
|
31
|
+
protected readonly hueUniform: Node
|
|
32
|
+
protected readonly saturationUniform: Node
|
|
33
|
+
|
|
34
|
+
private readonly opacityUniform: Node
|
|
35
|
+
private blendMode = "normal"
|
|
36
|
+
private compositeMode: LayerCompositeMode = "filter"
|
|
37
|
+
|
|
38
|
+
constructor(layerId: string) {
|
|
39
|
+
this.layerId = layerId
|
|
40
|
+
this.scene = new THREE.Scene()
|
|
41
|
+
this.camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1)
|
|
42
|
+
this.material = new THREE.MeshBasicNodeMaterial()
|
|
43
|
+
this.opacityUniform = uniform(1)
|
|
44
|
+
this.hueUniform = uniform(0)
|
|
45
|
+
this.saturationUniform = uniform(1)
|
|
46
|
+
|
|
47
|
+
const placeholder = new THREE.Texture()
|
|
48
|
+
const renderTargetUv = vec2(uv().x, float(1).sub(uv().y))
|
|
49
|
+
this.inputNode = tslTexture(placeholder, renderTargetUv)
|
|
50
|
+
this.effectNode = this.buildEffectNode()
|
|
51
|
+
this.rebuildColorNode()
|
|
52
|
+
|
|
53
|
+
const mesh = new THREE.Mesh(new THREE.PlaneGeometry(2, 2), this.material)
|
|
54
|
+
mesh.frustumCulled = false
|
|
55
|
+
this.scene.add(mesh)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
render(
|
|
59
|
+
renderer: THREE.WebGPURenderer,
|
|
60
|
+
inputTexture: THREE.Texture,
|
|
61
|
+
outputTarget: THREE.WebGLRenderTarget,
|
|
62
|
+
time: number,
|
|
63
|
+
delta: number,
|
|
64
|
+
): void {
|
|
65
|
+
this.inputNode.value = inputTexture
|
|
66
|
+
this.beforeRender(time, delta)
|
|
67
|
+
renderer.setRenderTarget(outputTarget)
|
|
68
|
+
renderer.render(this.scene, this.camera)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
updateOpacity(opacity: number): void {
|
|
72
|
+
this.opacityUniform.value = opacity
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
updateBlendMode(blendMode: string): boolean {
|
|
76
|
+
if (blendMode === this.blendMode) {
|
|
77
|
+
return false
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
this.blendMode = blendMode
|
|
81
|
+
this.rebuildColorNode()
|
|
82
|
+
this.material.needsUpdate = true
|
|
83
|
+
return true
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
updateCompositeMode(compositeMode: LayerCompositeMode): boolean {
|
|
87
|
+
if (compositeMode === this.compositeMode) {
|
|
88
|
+
return false
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
this.compositeMode = compositeMode
|
|
92
|
+
this.rebuildColorNode()
|
|
93
|
+
this.material.needsUpdate = true
|
|
94
|
+
return true
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
updateLayerColorAdjustments(hue: number, saturation: number): void {
|
|
98
|
+
this.hueUniform.value = (hue * Math.PI) / 180
|
|
99
|
+
this.saturationUniform.value = Math.max(0, saturation)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
updateParams(_params: LayerParameterValues): void {
|
|
103
|
+
// Default pass has no per-layer parameter handling.
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
resize(_width: number, _height: number): void {
|
|
107
|
+
// Default pass has no resize-dependent uniforms.
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
updateLogicalSize(_width: number, _height: number): void {
|
|
111
|
+
// Default pass has no logical-size-dependent uniforms.
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
needsContinuousRender(): boolean {
|
|
115
|
+
return false
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
dispose(): void {
|
|
119
|
+
this.scene.clear()
|
|
120
|
+
this.material.dispose()
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
getMaterialVersion(): number {
|
|
124
|
+
return this.material.version
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
protected beforeRender(_time: number, _delta: number): void {
|
|
128
|
+
// Default pass has no per-frame work.
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
protected buildEffectNode(): Node {
|
|
132
|
+
return this.inputNode
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
protected rebuildEffectNode(): void {
|
|
136
|
+
this.effectNode = this.buildEffectNode()
|
|
137
|
+
this.rebuildColorNode()
|
|
138
|
+
this.material.needsUpdate = true
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
protected rebuildColorNode(): void {
|
|
142
|
+
const adjustedEffectNode = this.applySharedColorAdjustments(this.effectNode)
|
|
143
|
+
this.material.colorNode = buildBlendNode(
|
|
144
|
+
this.blendMode,
|
|
145
|
+
this.inputNode,
|
|
146
|
+
adjustedEffectNode,
|
|
147
|
+
this.opacityUniform,
|
|
148
|
+
this.compositeMode,
|
|
149
|
+
) as Node
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
private applySharedColorAdjustments(sourceNode: Node): Node {
|
|
153
|
+
const sourceColor = vec3(
|
|
154
|
+
float(sourceNode.r),
|
|
155
|
+
float(sourceNode.g),
|
|
156
|
+
float(sourceNode.b),
|
|
157
|
+
)
|
|
158
|
+
const luma = float(sourceColor.x)
|
|
159
|
+
.mul(float(0.2126))
|
|
160
|
+
.add(float(sourceColor.y).mul(float(0.7152)))
|
|
161
|
+
.add(float(sourceColor.z).mul(float(0.0722)))
|
|
162
|
+
const saturated = mix(vec3(luma, luma, luma), sourceColor, this.saturationUniform)
|
|
163
|
+
const hueCos = float(cos(this.hueUniform))
|
|
164
|
+
const hueSin = float(sin(this.hueUniform))
|
|
165
|
+
const rotated = vec3(
|
|
166
|
+
float(saturated.x)
|
|
167
|
+
.mul(float(0.213).add(hueCos.mul(float(0.787))).sub(hueSin.mul(float(0.213))))
|
|
168
|
+
.add(
|
|
169
|
+
float(saturated.y).mul(
|
|
170
|
+
float(0.715).sub(hueCos.mul(float(0.715))).sub(hueSin.mul(float(0.715))),
|
|
171
|
+
),
|
|
172
|
+
)
|
|
173
|
+
.add(
|
|
174
|
+
float(saturated.z).mul(
|
|
175
|
+
float(0.072).sub(hueCos.mul(float(0.072))).add(hueSin.mul(float(0.928))),
|
|
176
|
+
),
|
|
177
|
+
),
|
|
178
|
+
float(saturated.x)
|
|
179
|
+
.mul(float(0.213).sub(hueCos.mul(float(0.213))).add(hueSin.mul(float(0.143))))
|
|
180
|
+
.add(
|
|
181
|
+
float(saturated.y).mul(
|
|
182
|
+
float(0.715).add(hueCos.mul(float(0.285))).add(hueSin.mul(float(0.14))),
|
|
183
|
+
),
|
|
184
|
+
)
|
|
185
|
+
.add(
|
|
186
|
+
float(saturated.z).mul(
|
|
187
|
+
float(0.072).sub(hueCos.mul(float(0.072))).sub(hueSin.mul(float(0.283))),
|
|
188
|
+
),
|
|
189
|
+
),
|
|
190
|
+
float(saturated.x)
|
|
191
|
+
.mul(float(0.213).sub(hueCos.mul(float(0.213))).sub(hueSin.mul(float(0.787))))
|
|
192
|
+
.add(
|
|
193
|
+
float(saturated.y).mul(
|
|
194
|
+
float(0.715).sub(hueCos.mul(float(0.715))).add(hueSin.mul(float(0.715))),
|
|
195
|
+
),
|
|
196
|
+
)
|
|
197
|
+
.add(
|
|
198
|
+
float(saturated.z).mul(
|
|
199
|
+
float(0.072).add(hueCos.mul(float(0.928))).add(hueSin.mul(float(0.072))),
|
|
200
|
+
),
|
|
201
|
+
),
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
return vec4(
|
|
205
|
+
clamp(rotated, vec3(float(0), float(0), float(0)), vec3(float(1), float(1), float(1))),
|
|
206
|
+
float(1),
|
|
207
|
+
)
|
|
208
|
+
}
|
|
209
|
+
}
|