2024-12-17 23:35:18 -08:00
|
|
|
const CANVAS_WIDTH = 700;
|
|
|
|
const CANVAS_HEIGHT = 700;
|
2024-12-16 23:20:25 -08:00
|
|
|
let TIME = 0;
|
2024-12-17 23:36:23 -08:00
|
|
|
let camera_pos = [0, 0, 0];
|
|
|
|
let camera_rot = [0, 0, 0];
|
2024-12-16 23:20:25 -08:00
|
|
|
|
|
|
|
// ** Initialization stuffs ** //
|
|
|
|
|
|
|
|
async function initShader() {
|
|
|
|
// Get GL contexts and stuffs
|
|
|
|
const canvas = document.getElementById("shader");
|
|
|
|
const gl = canvas.getContext("webgl2");
|
|
|
|
|
|
|
|
canvas.width = CANVAS_WIDTH;
|
|
|
|
canvas.height = CANVAS_HEIGHT;
|
|
|
|
|
|
|
|
gl.viewport(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
|
|
|
|
|
|
|
|
// Create Vertex Array
|
|
|
|
const vao = gl.createVertexArray();
|
|
|
|
gl.bindVertexArray(vao);
|
|
|
|
|
|
|
|
// manipulating bitfield for canvas
|
|
|
|
gl.clearColor(1, 1, 0, 1);
|
|
|
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
|
|
|
|
|
|
// Array of verticies for gpu to render
|
|
|
|
const verticies = new Float32Array([
|
|
|
|
-1, -1, -1, 1, 1, 1, -1, -1, 1, -1, 1, 1,
|
|
|
|
]);
|
|
|
|
|
|
|
|
// Managing the pixel buffer
|
|
|
|
const buf = gl.createBuffer();
|
|
|
|
|
|
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
|
|
|
|
gl.bufferData(gl.ARRAY_BUFFER, verticies, gl.STATIC_DRAW);
|
|
|
|
|
|
|
|
// fetch shaders
|
2024-12-17 23:34:53 -08:00
|
|
|
const vert_shader = await fetch_local("./vert.glsl");
|
|
|
|
const frag_shader = await fetch_local("./raymarcher.glsl");
|
2024-12-16 23:20:25 -08:00
|
|
|
|
|
|
|
// Compile Shaders
|
|
|
|
const vert = compileShader(vert_shader, gl.VERTEX_SHADER, gl);
|
|
|
|
const frag = compileShader(frag_shader, gl.FRAGMENT_SHADER, gl);
|
|
|
|
|
|
|
|
// Link shaders into program
|
|
|
|
const program = gl.createProgram();
|
|
|
|
|
|
|
|
gl.attachShader(program, vert);
|
|
|
|
gl.attachShader(program, frag);
|
|
|
|
|
|
|
|
gl.linkProgram(program);
|
|
|
|
|
|
|
|
// Check errors
|
|
|
|
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
|
|
const info = gl.getProgramInfoLog(program);
|
|
|
|
throw `bitch you messed up\n\n${info}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set this as the program that is used to render
|
|
|
|
gl.useProgram(program);
|
|
|
|
|
|
|
|
// assign shader variables
|
|
|
|
const vert_pos_loc = gl.getAttribLocation(program, "vertex_position");
|
|
|
|
gl.enableVertexAttribArray(vert_pos_loc);
|
|
|
|
|
|
|
|
gl.vertexAttribPointer(vert_pos_loc, 2, gl.FLOAT, true, 0, 0);
|
|
|
|
|
|
|
|
// Load Textures
|
|
|
|
loadTexture(gl, "./favicon.ico", gl.TEXTURE0);
|
|
|
|
const tex1_attr = gl.getUniformLocation(program, "uSampler1");
|
|
|
|
gl.uniform1i(tex1_attr, 0);
|
|
|
|
loadTexture(gl, "./brain.webp", gl.TEXTURE1);
|
|
|
|
const tex2_attr = gl.getUniformLocation(program, "uSampler2");
|
|
|
|
gl.uniform1i(tex2_attr, 1);
|
|
|
|
|
2024-12-17 23:36:23 -08:00
|
|
|
return [gl, program, canvas];
|
2024-12-16 23:20:25 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Compile Shader Function
|
|
|
|
function compileShader(source, type, gl) {
|
|
|
|
// Set up shader
|
|
|
|
const shader = gl.createShader(type);
|
|
|
|
gl.shaderSource(shader, source);
|
|
|
|
|
|
|
|
// compile the shaders
|
|
|
|
gl.compileShader(shader);
|
|
|
|
|
|
|
|
return shader;
|
|
|
|
}
|
|
|
|
|
|
|
|
// fetch local source as a text string
|
|
|
|
async function fetch_local(src) {
|
|
|
|
const res = await fetch(src);
|
|
|
|
return await res.text();
|
|
|
|
}
|
|
|
|
|
2024-12-17 23:36:23 -08:00
|
|
|
// Update the Camera position
|
|
|
|
function updateCamera(gl, program) {
|
|
|
|
if (keymap.get("w")) {
|
|
|
|
camera_pos[2] += 0.1;
|
|
|
|
}
|
|
|
|
if (keymap.get("a")) {
|
|
|
|
camera_pos[0] += -0.1;
|
|
|
|
}
|
|
|
|
if (keymap.get("s")) {
|
|
|
|
camera_pos[2] += -0.1;
|
|
|
|
}
|
|
|
|
if (keymap.get("d")) {
|
|
|
|
camera_pos[0] += 0.1;
|
|
|
|
}
|
|
|
|
if (keymap.get("e")) {
|
|
|
|
camera_pos[1] += 0.1;
|
|
|
|
}
|
|
|
|
if (keymap.get("q")) {
|
|
|
|
camera_pos[1] += -0.1;
|
|
|
|
}
|
|
|
|
const pos = gl.getUniformLocation(program, "camera_pos");
|
|
|
|
gl.uniform3fv(pos, camera_pos);
|
2024-12-16 23:20:25 -08:00
|
|
|
// update the canvas
|
|
|
|
function draw(gl, program) {
|
|
|
|
// Create uniform
|
|
|
|
const loc = gl.getUniformLocation(program, "time");
|
|
|
|
TIME += 1 / 60;
|
|
|
|
gl.uniform1f(loc, TIME);
|
|
|
|
|
2024-12-17 23:36:23 -08:00
|
|
|
updateCamera(gl, program);
|
|
|
|
|
2024-12-16 23:20:25 -08:00
|
|
|
// Draw the frame recursively on next frame
|
|
|
|
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
|
|
requestAnimationFrame(() => draw(gl, program));
|
|
|
|
}
|
|
|
|
|
|
|
|
function loadTexture(gl, url, gl_tex) {
|
|
|
|
// Create texture
|
|
|
|
const texture = gl.createTexture();
|
|
|
|
gl.activeTexture(gl_tex);
|
|
|
|
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
|
|
|
|
|
|
// Create the javascript image
|
|
|
|
const image = new Image();
|
|
|
|
image.onload = () => {
|
|
|
|
// Create GL Texture Buffer
|
|
|
|
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
|
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
|
|
|
|
};
|
|
|
|
|
|
|
|
image.src = url;
|
|
|
|
|
|
|
|
// gl.NEAREST is also allowed, instead of gl.LINEAR, as neither mipmap.
|
|
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
|
|
// Prevents s-coordinate wrapping (repeating).
|
|
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
|
|
// Prevents t-coordinate wrapping (repeating).
|
|
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
|
|
|
|
|
|
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
|
|
|
|
|
|
|
|
return texture;
|
|
|
|
}
|
|
|
|
|
2024-12-17 23:36:23 -08:00
|
|
|
// Initialize the shader
|
|
|
|
const [gl, program, canvas] = await initShader();
|
|
|
|
|
|
|
|
// Key Presses
|
|
|
|
let keymap = new Map();
|
|
|
|
document.addEventListener("keydown", function (event) {
|
|
|
|
keymap.set(event.key, true);
|
|
|
|
});
|
|
|
|
document.addEventListener("keyup", function (event) {
|
|
|
|
keymap.set(event.key, false);
|
|
|
|
});
|
2024-12-16 23:20:25 -08:00
|
|
|
// Update loop
|
|
|
|
draw(gl, program);
|