feat: Implement multi-pass rendering using WebGL framebuffers and integrate random texture generation directly into the shader background component.
This commit is contained in:
parent
54bf5b38c2
commit
d2a8edb004
@ -1,5 +1,5 @@
|
|||||||
import { useEffect, useRef } from "react";
|
import { useEffect, useRef } from "react";
|
||||||
import { createAndBindRandomTextureToIChannel0 } from "./randomTextureForShader";
|
import { generateRandomRGBABytes } from "./randomTextureForShader";
|
||||||
|
|
||||||
const buffer_1 = `#version 300 es
|
const buffer_1 = `#version 300 es
|
||||||
precision mediump float;
|
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(
|
function render(
|
||||||
gl: WebGL2RenderingContext,
|
gl: WebGL2RenderingContext,
|
||||||
canvas: HTMLCanvasElement,
|
canvas: HTMLCanvasElement,
|
||||||
now: number
|
now: number
|
||||||
) {
|
) {
|
||||||
|
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, frameBuffer);
|
||||||
|
|
||||||
//Clear with Clear color
|
//Clear with Clear color
|
||||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
gl.useProgram(buffer_1_program);
|
gl.useProgram(buffer_1_program);
|
||||||
setResolution(buffer_1_program as WebGLProgram, canvas, gl);
|
setResolution(buffer_1_program as WebGLProgram, canvas, gl);
|
||||||
setTime(buffer_1_program as WebGLProgram, now, gl);
|
setTime(buffer_1_program as WebGLProgram, now, gl);
|
||||||
const tex = createAndBindRandomTextureToIChannel0(
|
const bytes = generateRandomRGBABytes(canvas.width, canvas.height);
|
||||||
gl,
|
|
||||||
buffer_1_program as WebGLProgram,
|
const tex = gl.createTexture();
|
||||||
canvas.width,
|
if (!tex) throw new Error("Failed to create texture");
|
||||||
canvas.height
|
|
||||||
);
|
// Activate texture unit 0 and bind the texture
|
||||||
gl.activeTexture(gl.TEXTURE0);
|
gl.activeTexture(gl.TEXTURE0);
|
||||||
gl.bindTexture(gl.TEXTURE_2D, tex);
|
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
|
// 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);
|
gl.useProgram(buffer_2_program);
|
||||||
setResolution(buffer_2_program as WebGLProgram, canvas, gl);
|
setResolution(buffer_2_program as WebGLProgram, canvas, gl);
|
||||||
|
|
||||||
// RENDER 2
|
// 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);
|
gl.useProgram(buffer_3_program);
|
||||||
setResolution(buffer_3_program as WebGLProgram, canvas, gl);
|
setResolution(buffer_3_program as WebGLProgram, canvas, gl);
|
||||||
|
|
||||||
// RENDER 3
|
// 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);
|
gl.useProgram(buffer_4_program);
|
||||||
setResolution(buffer_4_program as WebGLProgram, canvas, gl);
|
setResolution(buffer_4_program as WebGLProgram, canvas, gl);
|
||||||
|
|
||||||
// RENDER 4
|
// 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);
|
gl.useProgram(finalProgram);
|
||||||
setResolution(finalProgram as WebGLProgram, canvas, gl);
|
setResolution(finalProgram as WebGLProgram, canvas, gl);
|
||||||
|
|
||||||
// FINAL RENDER
|
// 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);
|
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1024,5 +1200,7 @@ export function ShaderBackground() {
|
|||||||
requestAnimationFrame(update);
|
requestAnimationFrame(update);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return <canvas ref={canvasRef} />;
|
return (
|
||||||
|
<canvas ref={canvasRef} id="blackhole_canvas" width="800" height="450" />
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,61 +33,3 @@ export function generateRandomRGBABytes(
|
|||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a WebGL texture from random data and bind it to texture unit 0,
|
|
||||||
* then set the sampler2D uniform named `iChannel0` to use unit 0.
|
|
||||||
*
|
|
||||||
* gl: WebGLRenderingContext or WebGL2RenderingContext
|
|
||||||
* program: compiled & linked shader program (must be in use or will be used)
|
|
||||||
*/
|
|
||||||
export function createAndBindRandomTextureToIChannel0(
|
|
||||||
gl: WebGLRenderingContext | WebGL2RenderingContext,
|
|
||||||
program: WebGLProgram,
|
|
||||||
width: number,
|
|
||||||
height: number
|
|
||||||
): WebGLTexture {
|
|
||||||
const bytes = generateRandomRGBABytes(width, 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,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
0,
|
|
||||||
gl.RGBA,
|
|
||||||
gl.UNSIGNED_BYTE,
|
|
||||||
bytes
|
|
||||||
);
|
|
||||||
|
|
||||||
const location = gl.getUniformLocation(program, "iChannel0");
|
|
||||||
if (location === null) {
|
|
||||||
// Clean up binding and return but signal with thrown error if desired
|
|
||||||
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
||||||
throw new Error("Uniform 'iChannel0' not found in program");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set sampler uniform to texture unit 0
|
|
||||||
gl.uniform1i(location, 0);
|
|
||||||
|
|
||||||
// Unbind the texture if you prefer (not strictly necessary)
|
|
||||||
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
||||||
|
|
||||||
return tex;
|
|
||||||
}
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user