From fb51b33ca1e5ad35cd9a04da78a26e6b1eef0f5a Mon Sep 17 00:00:00 2001 From: Warinyourself Date: Wed, 24 Jun 2026 01:27:48 +0300 Subject: [PATCH] Remove postprocess.ts (bloom moved to vividgl) --- package-lock.json | 8 +- package.json | 2 +- src/utils/postprocess.ts | 354 --------------------------------------- vite.config.ts | 4 +- 4 files changed, 8 insertions(+), 360 deletions(-) delete mode 100644 src/utils/postprocess.ts diff --git a/package-lock.json b/package-lock.json index 669be99..5e8c3f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "@lucide/vue": "^1.17.0", "@vueuse/core": "^14.3.0", "pinia": "^3.0.4", - "vividgl": "^0.1.1", + "vividgl": "^0.1.2", "vue": "^3.5.32", "vue-i18n": "^11.4.5", "vue-router": "^5.0.4" @@ -3692,9 +3692,9 @@ } }, "node_modules/vividgl": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/vividgl/-/vividgl-0.1.1.tgz", - "integrity": "sha512-QIbmxrlkQXgx0swPCvGHiOTcBt76M10LfblNLiuF188EJv8AznDPpP4ZRhjy8qmV+IJn3qWa1B0XFNzSvKlU9Q==", + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/vividgl/-/vividgl-0.1.2.tgz", + "integrity": "sha512-ZamrlMQPzL2WjZ91tsTvRPqGqte4/H8sh9TV1LptmhYp3anRBbmmwIC3CKlyQB2lxiF8hu+NEc9Mv35Tr2mWXg==", "license": "MIT" }, "node_modules/vscode-uri": { diff --git a/package.json b/package.json index 44e3928..6e12774 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "@lucide/vue": "^1.17.0", "@vueuse/core": "^14.3.0", "pinia": "^3.0.4", - "vividgl": "^0.1.1", + "vividgl": "^0.1.2", "vue": "^3.5.32", "vue-i18n": "^11.4.5", "vue-router": "^5.0.4" diff --git a/src/utils/postprocess.ts b/src/utils/postprocess.ts deleted file mode 100644 index 128af20..0000000 --- a/src/utils/postprocess.ts +++ /dev/null @@ -1,354 +0,0 @@ -import GL from './gl' - -interface RenderTarget { - fbo: WebGLFramebuffer - texture: WebGLTexture -} - -// ─── Shared pass vertex shader ─────────────────────────────────────────────── -const PASS_VERT = `#version 300 es -in vec2 aPosition; -out vec2 vUv; -void main() { - vUv = aPosition * 0.5 + 0.5; - gl_Position = vec4(aPosition, 0.0, 1.0); -}` - -// ─── Separable Gaussian blur ───────────────────────────────────────────────── -// Call twice (horizontal then vertical) for a full 2D Gaussian blur. -// uDirection = (1,0) for horizontal, (0,1) for vertical. -const BLUR_FRAG = `#version 300 es -precision highp float; -uniform sampler2D uTexture; -uniform vec2 uResolution; -uniform vec2 uDirection; -uniform float uRadius; -// Step multiplier: sample every N pixels instead of every 1. -// Higher values cover a wider area with the same 17 taps — key for wide diffuse bloom. -uniform float uStepMult; -in vec2 vUv; -out vec4 fragColor; -void main() { - vec2 step = uDirection / uResolution * uStepMult; - vec4 color = vec4(0.0); - float total = 0.0; - for (float i = -8.0; i <= 8.0; i++) { - float w = exp(-i * i / (2.0 * uRadius * uRadius)); - color += texture(uTexture, vUv + step * i) * w; - total += w; - } - fragColor = color / total; -}` - -// ─── Brightness extraction ──────────────────────────────────────────────────── -// Keeps only pixels whose luminance exceeds uThreshold; everything else goes black. -// Used before the wide bloom pass so scattering only originates from bright light sources. -const EXTRACT_FRAG = `#version 300 es -precision highp float; -uniform sampler2D uTexture; -uniform float uThreshold; -in vec2 vUv; -out vec4 fragColor; -void main() { - vec4 c = texture(uTexture, vUv); - float lum = dot(c.rgb, vec3(0.2126, 0.7152, 0.0722)); - float bright = max(0.0, lum - uThreshold) / max(1.0 - uThreshold, 0.001); - fragColor = vec4(c.rgb * bright, 1.0); -}` - -// ─── Pixelation ────────────────────────────────────────────────────────────── -// Quantises screen coordinates to uPixelSize×uPixelSize blocks, sampling from -// the block centre — gives a retro pixel-art look applied before bloom. -const PIXELATE_FRAG = `#version 300 es -precision highp float; -uniform sampler2D uTexture; -uniform vec2 uResolution; -uniform float uPixelSize; // block size in screen pixels (1 = no effect) -in vec2 vUv; -out vec4 fragColor; -void main() { - vec2 block = floor(gl_FragCoord.xy / uPixelSize) * uPixelSize + uPixelSize * 0.5; - fragColor = texture(uTexture, block / uResolution); -}` - -// ─── Dual-bloom composite ───────────────────────────────────────────────────── -// Combines the original render with two independent bloom layers: -// bloom1 — bright tight bloom (enhances perceived saturation / intensity) -// bloom2 — wide dim bloom (simulates lens scattering / atmospheric glow) -const COMPOSITE_FRAG = `#version 300 es -precision highp float; -uniform sampler2D uBase; -uniform sampler2D uBloom1; // bright tight bloom -uniform sampler2D uBloom2; // wide dim bloom -uniform float uIntensity1; -uniform float uIntensity2; -in vec2 vUv; -out vec4 fragColor; -void main() { - vec4 base = texture(uBase, vUv); - vec4 bloom1 = texture(uBloom1, vUv); - vec4 bloom2 = texture(uBloom2, vUv); - fragColor = clamp(base + bloom1 * uIntensity1 + bloom2 * uIntensity2, 0.0, 1.0); -}` - -const QUAD = new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]) - -export interface PostProcessOptions { - // Tight bloom — bright, few passes, small radius - // Bloom layer A - passesA?: number - radiusA?: number - intensityA?: number - stepMultA?: number // sample stride (1 = every pixel, 3 = every 3rd pixel → 3× wider spread) - // Bloom layer B — optionally extract bright pixels first for true scattering effect - passesB?: number - radiusB?: number - intensityB?: number - stepMultB?: number - thresholdB?: number // luminance threshold before blur: 0 = blur everything, 0.5 = only bright pixels - // Pixelation applied before bloom — 1 = off, higher = larger pixel blocks - pixelSize?: number -} - -export default class PostProcessGL extends GL { - private _mainTarget!: RenderTarget - private _pingTarget!: RenderTarget - private _pongTarget!: RenderTarget - private _extraTarget!: RenderTarget // holds one bloom result while the other is computed - - private _blurProgram!: WebGLProgram - private _extractProgram!: WebGLProgram - private _pixelateProgram!: WebGLProgram - private _compositeProgram!: WebGLProgram - private _quadBuffer!: WebGLBuffer - private _extractTarget!: RenderTarget - private _pixelateTarget!: RenderTarget - - ppOptions: Required - ppEnabled: boolean - - constructor( - el: HTMLCanvasElement, - vertexShader: string, - fragmentShader: string, - width: number, - height: number, - glOptions?: ConstructorParameters[5], - ppOptions: PostProcessOptions = {} - ) { - super(el, vertexShader, fragmentShader, width, height, glOptions) - this.ppEnabled = Object.keys(ppOptions).length > 0 - this.ppOptions = { - passesA: 1, radiusA: 5, intensityA: 1.2, stepMultA: 1, - passesB: 1, radiusB: 0.5, intensityB: 1.2, stepMultB: 1, thresholdB: 0, - pixelSize: 1, - ...ppOptions - } - this._initPostProcess() - } - - // ─── Setup ────────────────────────────────────────────────────────────────── - - private _createTarget(w: number, h: number): RenderTarget { - const gl = this.ctx - const texture = gl.createTexture()! - gl.bindTexture(gl.TEXTURE_2D, texture) - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, w, h, 0, gl.RGBA, gl.UNSIGNED_BYTE, null) - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE) - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE) - const fbo = gl.createFramebuffer()! - gl.bindFramebuffer(gl.FRAMEBUFFER, fbo) - gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0) - gl.bindFramebuffer(gl.FRAMEBUFFER, null) - gl.bindTexture(gl.TEXTURE_2D, null) - return { fbo, texture } - } - - private _compilePassProgram(fragSrc: string): WebGLProgram { - const gl = this.ctx - const compile = (type: number, src: string) => { - const s = gl.createShader(type)! - gl.shaderSource(s, src) - gl.compileShader(s) - return s - } - const prog = gl.createProgram()! - gl.attachShader(prog, compile(gl.VERTEX_SHADER, PASS_VERT)) - gl.attachShader(prog, compile(gl.FRAGMENT_SHADER, fragSrc)) - gl.linkProgram(prog) - return prog - } - - private _initPostProcess() { - const w = this.el.width - const h = this.el.height - this._mainTarget = this._createTarget(w, h) - this._pingTarget = this._createTarget(w, h) - this._pongTarget = this._createTarget(w, h) - this._extraTarget = this._createTarget(w, h) - this._extractTarget = this._createTarget(w, h) - this._pixelateTarget = this._createTarget(w, h) - this._blurProgram = this._compilePassProgram(BLUR_FRAG) - this._extractProgram = this._compilePassProgram(EXTRACT_FRAG) - this._pixelateProgram = this._compilePassProgram(PIXELATE_FRAG) - this._compositeProgram = this._compilePassProgram(COMPOSITE_FRAG) - this._quadBuffer = this.ctx.createBuffer()! - this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this._quadBuffer) - this.ctx.bufferData(this.ctx.ARRAY_BUFFER, QUAD, this.ctx.STATIC_DRAW) - } - - // ─── Blur helpers ──────────────────────────────────────────────────────────── - - private _bindQuad(program: WebGLProgram) { - const gl = this.ctx - gl.bindBuffer(gl.ARRAY_BUFFER, this._quadBuffer) - const loc = gl.getAttribLocation(program, 'aPosition') - gl.enableVertexAttribArray(loc) - gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0) - } - - private _blurPass(src: RenderTarget, dst: RenderTarget, dir: [number, number], radius: number, stepMult = 1) { - const gl = this.ctx - gl.bindFramebuffer(gl.FRAMEBUFFER, dst.fbo) - gl.useProgram(this._blurProgram) - this._bindQuad(this._blurProgram) - gl.activeTexture(gl.TEXTURE0) - gl.bindTexture(gl.TEXTURE_2D, src.texture) - gl.uniform1i(gl.getUniformLocation(this._blurProgram, 'uTexture'), 0) - gl.uniform2f(gl.getUniformLocation(this._blurProgram, 'uResolution'), this.el.width, this.el.height) - gl.uniform2f(gl.getUniformLocation(this._blurProgram, 'uDirection'), dir[0], dir[1]) - gl.uniform1f(gl.getUniformLocation(this._blurProgram, 'uRadius'), radius) - gl.uniform1f(gl.getUniformLocation(this._blurProgram, 'uStepMult'), stepMult) - gl.drawArrays(gl.TRIANGLES, 0, 6) - } - - private _runBlur(src: RenderTarget, passes: number, radius: number, useExtra: boolean, stepMult = 1): RenderTarget { - const a = this._pingTarget - const b = useExtra ? this._extraTarget : this._pongTarget - let cur: RenderTarget = src - let scratch: [RenderTarget, RenderTarget] = [a, b] - let idx = 0 - for (let i = 0; i < passes; i++) { - const dst0 = scratch[idx % 2]! - const dst1 = scratch[(idx + 1) % 2]! - this._blurPass(cur, dst0, [1, 0], radius, stepMult) - this._blurPass(dst0, dst1, [0, 1], radius, stepMult) - cur = dst1 - idx += 2 - } - return cur - } - - private _extractPass(src: RenderTarget, threshold: number) { - const gl = this.ctx - gl.bindFramebuffer(gl.FRAMEBUFFER, this._extractTarget.fbo) - gl.useProgram(this._extractProgram) - this._bindQuad(this._extractProgram) - gl.activeTexture(gl.TEXTURE0) - gl.bindTexture(gl.TEXTURE_2D, src.texture) - gl.uniform1i(gl.getUniformLocation(this._extractProgram, 'uTexture'), 0) - gl.uniform1f(gl.getUniformLocation(this._extractProgram, 'uThreshold'), threshold) - gl.drawArrays(gl.TRIANGLES, 0, 6) - } - - private _pixelatePass(src: RenderTarget) { - const gl = this.ctx - gl.bindFramebuffer(gl.FRAMEBUFFER, this._pixelateTarget.fbo) - gl.useProgram(this._pixelateProgram) - this._bindQuad(this._pixelateProgram) - gl.activeTexture(gl.TEXTURE0) - gl.bindTexture(gl.TEXTURE_2D, src.texture) - gl.uniform1i(gl.getUniformLocation(this._pixelateProgram, 'uTexture'), 0) - gl.uniform2f(gl.getUniformLocation(this._pixelateProgram, 'uResolution'), this.el.width, this.el.height) - gl.uniform1f(gl.getUniformLocation(this._pixelateProgram, 'uPixelSize'), this.ppOptions.pixelSize) - gl.drawArrays(gl.TRIANGLES, 0, 6) - } - - // ─── Resize ───────────────────────────────────────────────────────────────── - - override resize() { - super.resize() - if (!this._mainTarget) return - const w = this.el.width - const h = this.el.height - for (const t of [this._mainTarget, this._pingTarget, this._pongTarget, this._extraTarget, this._extractTarget, this._pixelateTarget]) { - this.ctx.bindTexture(this.ctx.TEXTURE_2D, t.texture) - this.ctx.texImage2D(this.ctx.TEXTURE_2D, 0, this.ctx.RGBA, w, h, 0, this.ctx.RGBA, this.ctx.UNSIGNED_BYTE, null) - } - this.ctx.bindTexture(this.ctx.TEXTURE_2D, null) - } - - // ─── Render ───────────────────────────────────────────────────────────────── - - override render() { - if (!this.running) return - requestAnimationFrame(this.render.bind(this)) - - const gl = this.ctx - - // Bypass: render directly to screen without any post-processing - if (!this.ppEnabled) { - gl.useProgram(this.program) - this.initBuffers(this.positions) - gl.bindFramebuffer(gl.FRAMEBUFFER, null) - gl.viewport(0, 0, this.el.width, this.el.height) - if (!this.renderOptions.externalTimeUse) { - this.time = (Date.now() - this.startTime) / 1000 - gl.uniform1f(this.programInfo.uniforms.time, this.time) - } - if (this.renderHook) this.renderHook() - gl.drawArrays(gl.TRIANGLES, 0, 6) - return - } - - const { passesA, radiusA, intensityA, stepMultA, passesB, radiusB, intensityB, stepMultB, thresholdB, pixelSize } = this.ppOptions - - // Pass 1: render main shader to offscreen texture - gl.useProgram(this.program) - this.initBuffers(this.positions) - gl.bindFramebuffer(gl.FRAMEBUFFER, this._mainTarget.fbo) - gl.viewport(0, 0, this.el.width, this.el.height) - if (!this.renderOptions.externalTimeUse) { - this.time = (Date.now() - this.startTime) / 1000 - gl.uniform1f(this.programInfo.uniforms.time, this.time) - } - if (this.renderHook) this.renderHook() - gl.drawArrays(gl.TRIANGLES, 0, 6) - - // Optional pixelation applied before bloom so the effect covers both base and glow - const renderBase = pixelSize > 1 - ? (this._pixelatePass(this._mainTarget), this._pixelateTarget) - : this._mainTarget - - const bloomA = this._runBlur(renderBase, passesA, radiusA, false, stepMultA) - - // If thresholdB > 0: extract bright pixels first so bloom B scatters only from light sources - const bloomBSrc = thresholdB > 0 - ? (this._extractPass(this._mainTarget, thresholdB), this._extractTarget) - : this._mainTarget - const bloomB = this._runBlur(bloomBSrc, passesB, radiusB, true, stepMultB) - - gl.bindFramebuffer(gl.FRAMEBUFFER, null) - gl.useProgram(this._compositeProgram) - this._bindQuad(this._compositeProgram) - - gl.activeTexture(gl.TEXTURE0) - gl.bindTexture(gl.TEXTURE_2D, renderBase.texture) - gl.uniform1i(gl.getUniformLocation(this._compositeProgram, 'uBase'), 0) - - gl.activeTexture(gl.TEXTURE1) - gl.bindTexture(gl.TEXTURE_2D, bloomA.texture) - gl.uniform1i(gl.getUniformLocation(this._compositeProgram, 'uBloom1'), 1) - - gl.activeTexture(gl.TEXTURE2) - gl.bindTexture(gl.TEXTURE_2D, bloomB.texture) - gl.uniform1i(gl.getUniformLocation(this._compositeProgram, 'uBloom2'), 2) - - gl.uniform1f(gl.getUniformLocation(this._compositeProgram, 'uIntensity1'), intensityA) - gl.uniform1f(gl.getUniformLocation(this._compositeProgram, 'uIntensity2'), intensityB) - - gl.drawArrays(gl.TRIANGLES, 0, 6) - } -} diff --git a/vite.config.ts b/vite.config.ts index db09160..1c37948 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -34,7 +34,9 @@ export default defineConfig({ } }, optimizeDeps: { - exclude: ['vividgl'] + // Rolldown (Vite 8) dep scanner fails to parse JSX syntax. + // All deps ship ESM so pre-bundling is not needed. + disabled: true }, css: { preprocessorOptions: {