const CANVAS_WIDTH = 700; const CANVAS_HEIGHT = 700; let TIME = 0; let camera_pos = [0, 0, 0]; let camera_rot = [0, 0, 0]; // ** 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 const vert_shader = await fetch_local("./vert.glsl"); const frag_shader = await fetch_local("./raymarcher.glsl"); // 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); return [gl, program, canvas]; } // 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(); } // 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); // update the canvas function draw(gl, program) { // Create uniform const loc = gl.getUniformLocation(program, "time"); TIME += 1 / 60; gl.uniform1f(loc, TIME); updateCamera(gl, program); // 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; } // 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); }); // Request pointer Lock canvas.addEventListener("click", async () => { await canvas.requestPointerLock(); }); // Update loop draw(gl, program);