regret
This commit is contained in:
parent
f58ff49c46
commit
6128804352
@ -935,212 +935,71 @@ export function ShaderBackground() {
|
||||
gl.STATIC_DRAW
|
||||
);
|
||||
|
||||
{
|
||||
gl.useProgram(buffer_1_program);
|
||||
const posAttrLocation = gl.getAttribLocation(
|
||||
// Vertex attributes for each program
|
||||
const programs = [
|
||||
buffer_1_program,
|
||||
"a_position"
|
||||
);
|
||||
gl.vertexAttribPointer(posAttrLocation, 2, gl.FLOAT, false, 0, 0);
|
||||
gl.enableVertexAttribArray(posAttrLocation);
|
||||
}
|
||||
|
||||
{
|
||||
gl.useProgram(buffer_2_program);
|
||||
const posAttrLocation = gl.getAttribLocation(
|
||||
buffer_2_program,
|
||||
"a_position"
|
||||
);
|
||||
gl.vertexAttribPointer(posAttrLocation, 2, gl.FLOAT, false, 0, 0);
|
||||
gl.enableVertexAttribArray(posAttrLocation);
|
||||
}
|
||||
|
||||
{
|
||||
gl.useProgram(buffer_3_program);
|
||||
const posAttrLocation = gl.getAttribLocation(
|
||||
buffer_3_program,
|
||||
"a_position"
|
||||
);
|
||||
gl.vertexAttribPointer(posAttrLocation, 2, gl.FLOAT, false, 0, 0);
|
||||
gl.enableVertexAttribArray(posAttrLocation);
|
||||
}
|
||||
|
||||
{
|
||||
gl.useProgram(buffer_4_program);
|
||||
const posAttrLocation = gl.getAttribLocation(
|
||||
buffer_4_program,
|
||||
"a_position"
|
||||
);
|
||||
gl.vertexAttribPointer(posAttrLocation, 2, gl.FLOAT, false, 0, 0);
|
||||
gl.enableVertexAttribArray(posAttrLocation);
|
||||
}
|
||||
finalProgram,
|
||||
];
|
||||
programs.forEach((prog) => {
|
||||
gl.useProgram(prog);
|
||||
const loc = gl.getAttribLocation(prog, "a_position");
|
||||
gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);
|
||||
gl.enableVertexAttribArray(loc);
|
||||
});
|
||||
|
||||
{
|
||||
gl.useProgram(finalProgram);
|
||||
const posAttrLocation = gl.getAttribLocation(finalProgram, "a_position");
|
||||
gl.vertexAttribPointer(posAttrLocation, 2, gl.FLOAT, false, 0, 0);
|
||||
gl.enableVertexAttribArray(posAttrLocation);
|
||||
}
|
||||
|
||||
function setResolution(
|
||||
program: WebGLProgram,
|
||||
canvas: HTMLCanvasElement,
|
||||
gl: WebGL2RenderingContext
|
||||
) {
|
||||
const loc = gl.getUniformLocation(program, "iResolution");
|
||||
if (loc === null) {
|
||||
console.warn(
|
||||
"iResolution uniform not found (maybe not used by shader)."
|
||||
);
|
||||
} else {
|
||||
const w = canvas.width;
|
||||
const h = canvas.height;
|
||||
|
||||
gl.uniform3fv(loc, [w, h, 1]);
|
||||
}
|
||||
}
|
||||
|
||||
function setTime(
|
||||
program: WebGLProgram,
|
||||
now: number,
|
||||
gl: WebGL2RenderingContext
|
||||
) {
|
||||
const loc = gl.getUniformLocation(program, "iTime");
|
||||
if (loc === null) {
|
||||
console.warn(
|
||||
"iTime uniform not found (maybe not used by shader).",
|
||||
program
|
||||
);
|
||||
} else {
|
||||
gl.uniform1f(loc, now);
|
||||
}
|
||||
}
|
||||
|
||||
const frameBufferTexture = gl.createTexture();
|
||||
if (!frameBufferTexture) return;
|
||||
|
||||
gl.bindTexture(gl.TEXTURE_2D, frameBufferTexture);
|
||||
gl.texImage2D(
|
||||
gl.TEXTURE_2D,
|
||||
// --- HELPER FUNC ---
|
||||
function createFramebufferTexture(w: number, h: number) {
|
||||
const tex = gl!.createTexture();
|
||||
gl!.bindTexture(gl!.TEXTURE_2D, tex);
|
||||
gl!.texImage2D(
|
||||
gl!.TEXTURE_2D,
|
||||
0,
|
||||
gl.RGBA,
|
||||
canvas.width,
|
||||
canvas.height,
|
||||
gl!.RGBA,
|
||||
w,
|
||||
h,
|
||||
0,
|
||||
gl.RGBA,
|
||||
gl.UNSIGNED_BYTE,
|
||||
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_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 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,
|
||||
const fb = gl!.createFramebuffer();
|
||||
gl!.bindFramebuffer(gl!.DRAW_FRAMEBUFFER, fb);
|
||||
gl!.framebufferTexture2D(
|
||||
gl!.DRAW_FRAMEBUFFER,
|
||||
gl!.COLOR_ATTACHMENT0,
|
||||
gl!.TEXTURE_2D,
|
||||
tex,
|
||||
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");
|
||||
return { tex, fb };
|
||||
}
|
||||
|
||||
const ichannel0_location_buffer_1 = gl.getUniformLocation(
|
||||
buffer_1_program as WebGLProgram,
|
||||
"iChannel0"
|
||||
);
|
||||
// 1. Scene Buffer (Stores the main render)
|
||||
const sceneTarget = createFramebufferTexture(canvas.width, canvas.height);
|
||||
|
||||
const ichannel0_location_buffer_2 = gl.getUniformLocation(
|
||||
buffer_2_program as WebGLProgram,
|
||||
"iChannel0"
|
||||
);
|
||||
// 2. Ping-Pong Buffers (For doing multipass bloom effects)
|
||||
const pingTarget = createFramebufferTexture(canvas.width, canvas.height);
|
||||
const pongTarget = createFramebufferTexture(canvas.width, canvas.height);
|
||||
|
||||
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 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
|
||||
// --- NOISE TEXTURE ---
|
||||
// Fix: Create once, not every frame
|
||||
const noiseBytes = generateRandomRGBABytes(canvas.width, canvas.height);
|
||||
const noiseTexture = gl.createTexture();
|
||||
gl.activeTexture(gl.TEXTURE0);
|
||||
gl.bindTexture(gl.TEXTURE_2D, tex);
|
||||
|
||||
// Texture parameters suitable for data textures
|
||||
gl.bindTexture(gl.TEXTURE_2D, noiseTexture);
|
||||
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,
|
||||
@ -1150,98 +1009,154 @@ export function ShaderBackground() {
|
||||
0,
|
||||
gl.RGBA,
|
||||
gl.UNSIGNED_BYTE,
|
||||
bytes
|
||||
noiseBytes
|
||||
);
|
||||
|
||||
// Set sampler uniform to texture unit 0
|
||||
gl.uniform1i(ichannel0_location_buffer_1, 0);
|
||||
|
||||
// RENDER 1
|
||||
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.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.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.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);
|
||||
function setResolution(program: WebGLProgram) {
|
||||
const loc = gl!.getUniformLocation(program, "iResolution");
|
||||
if (loc) gl!.uniform3fv(loc, [canvas!.width, canvas!.height, 1]);
|
||||
}
|
||||
|
||||
function setTime(program: WebGLProgram, now: number) {
|
||||
const loc = gl!.getUniformLocation(program, "iTime");
|
||||
if (loc) gl!.uniform1f(loc, now);
|
||||
}
|
||||
|
||||
// Cache uniform locations
|
||||
const locs = {
|
||||
b1_iChannel0: gl.getUniformLocation(buffer_1_program, "iChannel0"),
|
||||
b2_iChannel0: gl.getUniformLocation(buffer_2_program, "iChannel0"),
|
||||
b3_iChannel0: gl.getUniformLocation(buffer_3_program, "iChannel0"),
|
||||
b4_iChannel0: gl.getUniformLocation(buffer_4_program, "iChannel0"),
|
||||
final_iChannel0: gl.getUniformLocation(finalProgram, "iChannel0"),
|
||||
final_iChannel3: gl.getUniformLocation(finalProgram, "iChannel3"), // Bloom result
|
||||
};
|
||||
|
||||
let reqId: number;
|
||||
const started = Date.now();
|
||||
|
||||
function update(now: number) {
|
||||
// time in seconds
|
||||
const time = (now - started) / 1000;
|
||||
render(gl as WebGL2RenderingContext, canvas as HTMLCanvasElement, time);
|
||||
|
||||
requestAnimationFrame(update);
|
||||
// ----------------------------------------------------
|
||||
// PASS 1: Render SCENE -> sceneTarget
|
||||
// ----------------------------------------------------
|
||||
gl!.bindFramebuffer(gl!.DRAW_FRAMEBUFFER, sceneTarget.fb);
|
||||
gl!.viewport(0, 0, canvas!.width, canvas!.height);
|
||||
gl!.clear(gl!.COLOR_BUFFER_BIT);
|
||||
|
||||
gl!.useProgram(buffer_1_program);
|
||||
setResolution(buffer_1_program!);
|
||||
setTime(buffer_1_program!, time);
|
||||
|
||||
// Bind Noise to Unit 0
|
||||
gl!.activeTexture(gl!.TEXTURE0);
|
||||
gl!.bindTexture(gl!.TEXTURE_2D, noiseTexture);
|
||||
gl!.uniform1i(locs.b1_iChannel0, 0);
|
||||
|
||||
gl!.drawArrays(gl!.TRIANGLES, 0, 6);
|
||||
|
||||
// ----------------------------------------------------
|
||||
// PASS 2: Bloom Prep (Buffer 2) -> pingTarget
|
||||
// input: sceneTarget (Unit 0)
|
||||
// ----------------------------------------------------
|
||||
gl!.bindFramebuffer(gl!.DRAW_FRAMEBUFFER, pingTarget.fb);
|
||||
|
||||
gl!.useProgram(buffer_2_program);
|
||||
setResolution(buffer_2_program!);
|
||||
|
||||
gl!.activeTexture(gl!.TEXTURE0);
|
||||
gl!.bindTexture(gl!.TEXTURE_2D, sceneTarget.tex);
|
||||
gl!.uniform1i(locs.b2_iChannel0, 0);
|
||||
|
||||
gl!.drawArrays(gl!.TRIANGLES, 0, 6);
|
||||
|
||||
// ----------------------------------------------------
|
||||
// PASS 3: Horizontal Blur (Buffer 3) -> pongTarget
|
||||
// input: pingTarget (Unit 0)
|
||||
// ----------------------------------------------------
|
||||
gl!.bindFramebuffer(gl!.DRAW_FRAMEBUFFER, pongTarget.fb);
|
||||
|
||||
gl!.useProgram(buffer_3_program);
|
||||
setResolution(buffer_3_program!);
|
||||
|
||||
gl!.activeTexture(gl!.TEXTURE0);
|
||||
gl!.bindTexture(gl!.TEXTURE_2D, pingTarget.tex);
|
||||
gl!.uniform1i(locs.b3_iChannel0, 0);
|
||||
|
||||
gl!.drawArrays(gl!.TRIANGLES, 0, 6);
|
||||
|
||||
// ----------------------------------------------------
|
||||
// PASS 4: Vertical Blur (Buffer 4) -> pingTarget (Final Bloom)
|
||||
// input: pongTarget (Unit 0)
|
||||
// ----------------------------------------------------
|
||||
// Reuse pingTarget to store the final bloom result
|
||||
gl!.bindFramebuffer(gl!.DRAW_FRAMEBUFFER, pingTarget.fb);
|
||||
|
||||
gl!.useProgram(buffer_4_program);
|
||||
setResolution(buffer_4_program!);
|
||||
|
||||
gl!.activeTexture(gl!.TEXTURE0);
|
||||
gl!.bindTexture(gl!.TEXTURE_2D, pongTarget.tex);
|
||||
gl!.uniform1i(locs.b4_iChannel0, 0);
|
||||
|
||||
gl!.drawArrays(gl!.TRIANGLES, 0, 6);
|
||||
|
||||
// ----------------------------------------------------
|
||||
// PASS 5: Final Composition -> Screen
|
||||
// Inputs:
|
||||
// - iChannel0: sceneTarget (Unit 0)
|
||||
// - iChannel3: pingTarget aka Bloom Result (Unit 3)
|
||||
// ----------------------------------------------------
|
||||
gl!.bindFramebuffer(gl!.DRAW_FRAMEBUFFER, null); // Screen
|
||||
|
||||
gl!.useProgram(finalProgram);
|
||||
setResolution(finalProgram!);
|
||||
|
||||
// Bind Scene to Unit 0
|
||||
gl!.activeTexture(gl!.TEXTURE0);
|
||||
gl!.bindTexture(gl!.TEXTURE_2D, sceneTarget.tex);
|
||||
gl!.uniform1i(locs.final_iChannel0, 0);
|
||||
|
||||
// Bind Bloom to Unit 3
|
||||
gl!.activeTexture(gl!.TEXTURE3);
|
||||
gl!.bindTexture(gl!.TEXTURE_2D, pingTarget.tex);
|
||||
gl!.uniform1i(locs.final_iChannel3, 3); // Tell shader iChannel3 is on unit 3
|
||||
|
||||
gl!.drawArrays(gl!.TRIANGLES, 0, 6);
|
||||
|
||||
reqId = requestAnimationFrame(update);
|
||||
}
|
||||
|
||||
requestAnimationFrame(update);
|
||||
reqId = requestAnimationFrame(update);
|
||||
|
||||
// CLEANUP
|
||||
return () => {
|
||||
cancelAnimationFrame(reqId);
|
||||
gl!.deleteProgram(buffer_1_program);
|
||||
gl!.deleteProgram(buffer_2_program);
|
||||
gl!.deleteProgram(buffer_3_program);
|
||||
gl!.deleteProgram(buffer_4_program);
|
||||
gl!.deleteProgram(finalProgram);
|
||||
|
||||
gl!.deleteShader(buffer_1_shader);
|
||||
gl!.deleteShader(buffer_2_shader);
|
||||
gl!.deleteShader(buffer_3_shader);
|
||||
gl!.deleteShader(buffer_4_shader);
|
||||
gl!.deleteShader(fragmentShader);
|
||||
gl!.deleteShader(vertexShader);
|
||||
|
||||
gl!.deleteBuffer(posBuffer);
|
||||
|
||||
gl!.deleteTexture(noiseTexture);
|
||||
gl!.deleteTexture(sceneTarget.tex);
|
||||
gl!.deleteFramebuffer(sceneTarget.fb);
|
||||
gl!.deleteTexture(pingTarget.tex);
|
||||
gl!.deleteFramebuffer(pingTarget.fb);
|
||||
gl!.deleteTexture(pongTarget.tex);
|
||||
gl!.deleteFramebuffer(pongTarget.fb);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
Loading…
x
Reference in New Issue
Block a user