feat: Implement multi-pass rendering using WebGL framebuffers and integrate random texture generation directly into the shader background component.

This commit is contained in:
2025-12-06 19:45:28 +01:00
parent 54bf5b38c2
commit d2a8edb004
2 changed files with 190 additions and 70 deletions
+190 -12
View File
@@ -1,5 +1,5 @@
import { useEffect, useRef } from "react";
import { createAndBindRandomTextureToIChannel0 } from "./randomTextureForShader";
import { generateRandomRGBABytes } from "./randomTextureForShader";
const buffer_1 = `#version 300 es
precision mediump float;
@@ -964,51 +964,227 @@ export function ShaderBackground() {
}
}
const frameBufferTexture = gl.createTexture();
if (!frameBufferTexture) return;
gl.bindTexture(gl.TEXTURE_2D, frameBufferTexture);
gl.texImage2D(
gl.TEXTURE_2D,
0,
gl.RGBA,
canvas.width,
canvas.height,
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);
const frameBufferTexture2 = gl.createTexture();
if (!frameBufferTexture2) return;
gl.bindTexture(gl.TEXTURE_2D, frameBufferTexture2);
gl.texImage2D(
gl.TEXTURE_2D,
0,
gl.RGBA,
canvas.width,
canvas.height,
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);
const frameBuffer = gl.createFramebuffer();
if (!frameBuffer) return;
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, frameBuffer);
gl.framebufferTexture2D(
gl.DRAW_FRAMEBUFFER,
gl.COLOR_ATTACHMENT0,
gl.TEXTURE_2D,
frameBufferTexture,
0
);
const status = gl.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER);
switch (status) {
case gl.FRAMEBUFFER_COMPLETE:
console.log("Framebuffer is complete");
break;
case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
console.log("Framebuffer is incomplete attachment");
break;
case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
console.log("Framebuffer is incomplete missing attachment");
break;
case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
console.log("Framebuffer is incomplete dimensions");
break;
case gl.FRAMEBUFFER_UNSUPPORTED:
console.log("Framebuffer is unsupported");
break;
default:
console.log("Framebuffer is unknown");
}
const posBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array([0, 0, 1, 0, 0, 1, 1, 1]),
gl.STATIC_DRAW
);
const ichannel0_location_buffer_1 = gl.getUniformLocation(
buffer_1_program as WebGLProgram,
"iChannel0"
);
const ichannel0_location_buffer_2 = gl.getUniformLocation(
buffer_2_program as WebGLProgram,
"iChannel0"
);
const ichannel0_location_buffer_3 = gl.getUniformLocation(
buffer_3_program as WebGLProgram,
"iChannel0"
);
const ichannel0_location_buffer_4 = gl.getUniformLocation(
buffer_4_program as WebGLProgram,
"iChannel0"
);
const ichannel0_location_final = gl.getUniformLocation(
finalProgram as WebGLProgram,
"iChannel0"
);
function render(
gl: WebGL2RenderingContext,
canvas: HTMLCanvasElement,
now: number
) {
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, frameBuffer);
//Clear with Clear color
gl.clear(gl.COLOR_BUFFER_BIT);
gl.useProgram(buffer_1_program);
setResolution(buffer_1_program as WebGLProgram, canvas, gl);
setTime(buffer_1_program as WebGLProgram, now, gl);
const tex = createAndBindRandomTextureToIChannel0(
gl,
buffer_1_program as WebGLProgram,
canvas.width,
canvas.height
);
const bytes = generateRandomRGBABytes(canvas.width, canvas.height);
const tex = gl.createTexture();
if (!tex) throw new Error("Failed to create texture");
// Activate texture unit 0 and bind the texture
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, tex);
// Texture parameters suitable for data textures
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
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);
// Upload pixel data as RGBA UNSIGNED_BYTE
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
gl.texImage2D(
gl.TEXTURE_2D,
0,
gl.RGBA,
canvas.width,
canvas.height,
0,
gl.RGBA,
gl.UNSIGNED_BYTE,
bytes
);
// Set sampler uniform to texture unit 0
gl.uniform1i(ichannel0_location_buffer_1, 0);
// RENDER 1
gl.drawBuffers([gl.BACK]);
gl.framebufferTexture2D(
gl.DRAW_FRAMEBUFFER,
gl.COLOR_ATTACHMENT0,
gl.TEXTURE_2D,
frameBufferTexture,
0
);
gl.drawArrays(gl.TRIANGLES, 0, 6);
gl.useProgram(buffer_2_program);
setResolution(buffer_2_program as WebGLProgram, canvas, gl);
// RENDER 2
gl.drawBuffers([gl.BACK]);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, frameBufferTexture);
gl.uniform1i(ichannel0_location_buffer_2, 1);
gl.framebufferTexture2D(
gl.DRAW_FRAMEBUFFER,
gl.COLOR_ATTACHMENT0,
gl.TEXTURE_2D,
frameBufferTexture2,
0
);
gl.drawArrays(gl.TRIANGLES, 0, 6);
gl.useProgram(buffer_3_program);
setResolution(buffer_3_program as WebGLProgram, canvas, gl);
// RENDER 3
gl.drawBuffers([gl.BACK]);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, frameBufferTexture2);
gl.uniform1i(ichannel0_location_buffer_3, 1);
gl.framebufferTexture2D(
gl.DRAW_FRAMEBUFFER,
gl.COLOR_ATTACHMENT0,
gl.TEXTURE_2D,
frameBufferTexture,
0
);
gl.drawArrays(gl.TRIANGLES, 0, 6);
gl.useProgram(buffer_4_program);
setResolution(buffer_4_program as WebGLProgram, canvas, gl);
// RENDER 4
gl.drawBuffers([gl.BACK]);
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, frameBufferTexture);
gl.uniform1i(ichannel0_location_buffer_4, 1);
gl.framebufferTexture2D(
gl.DRAW_FRAMEBUFFER,
gl.COLOR_ATTACHMENT0,
gl.TEXTURE_2D,
frameBufferTexture2,
0
);
gl.drawArrays(gl.TRIANGLES, 0, 6);
gl.useProgram(finalProgram);
setResolution(finalProgram as WebGLProgram, canvas, gl);
// FINAL RENDER
gl.activeTexture(gl.TEXTURE1);
gl.bindTexture(gl.TEXTURE_2D, frameBufferTexture2);
gl.uniform1i(ichannel0_location_final, 1);
gl.framebufferTexture2D(
gl.DRAW_FRAMEBUFFER,
gl.COLOR_ATTACHMENT0,
gl.TEXTURE_2D,
frameBufferTexture,
0
);
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
@@ -1024,5 +1200,7 @@ export function ShaderBackground() {
requestAnimationFrame(update);
}, []);
return <canvas ref={canvasRef} />;
return (
<canvas ref={canvasRef} id="blackhole_canvas" width="800" height="450" />
);
}