212 lines
5.9 KiB
JavaScript
212 lines
5.9 KiB
JavaScript
/* Canvas set-up */
|
|
const canvas = document.getElementsByTagName("canvas")[0];
|
|
const gl = canvas.getContext("webgl", { antialias: false, preserveDrawingBuffer: false });
|
|
|
|
/* Utility */
|
|
const fetchText = async url => (await fetch(url)).text();
|
|
|
|
/* Viewport, etc. */
|
|
/* The actual canvas is statically sized in HTML, and from there scaled with CSS */
|
|
/* So, this does not need to be updated ever */
|
|
var projectionMatrix = mat4.create();
|
|
mat4.perspective(
|
|
projectionMatrix,
|
|
(45 * Math.PI) / 180,
|
|
gl.drawingBufferWidth / gl.drawingBufferHeight,
|
|
0.1, 100.0
|
|
);
|
|
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
|
|
|
|
/* WebGL set-up */
|
|
// gl.clearColor(.1137, .1254, .1294, 1.0);
|
|
gl.clearColor(0.0, 0.0, 0.0, 1.0);
|
|
gl.enable(gl.DEPTH_TEST);
|
|
gl.enable(gl.CULL_FACE);
|
|
|
|
// If this gets gc'd the extension stops working supposedly
|
|
const ext_depthTexture = gl.getExtension('WEBGL_depth_texture');
|
|
if (!ext_depthTexture) {
|
|
console.log("no depth texture support!");
|
|
}
|
|
|
|
/* Load model */
|
|
const [vertsOut, vertsCount] = parseObj(await fetchText("/model/untitled.obj"));
|
|
|
|
const modelViewMatrix = mat4.create();
|
|
mat4.translate(
|
|
modelViewMatrix,
|
|
modelViewMatrix,
|
|
[0.0, -0.6, -4.0]
|
|
);
|
|
|
|
/* Create vertex buffer */
|
|
const vertexBuffer = gl.createBuffer();
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
|
|
gl.bufferData(gl.ARRAY_BUFFER, vertsOut, gl.STATIC_DRAW);
|
|
|
|
/* Shader programs */
|
|
const FSIZE = vertsOut.BYTES_PER_ELEMENT;
|
|
class ShaderProgram {
|
|
constructor(vsSrc, fsSrc, skipNormals = false) {
|
|
this.pgm = compile(gl, vsSrc, fsSrc);
|
|
|
|
/* get attributes that we need for rendering */
|
|
this.a_position = gl.getAttribLocation(this.pgm, "a_position");
|
|
this.a_normal = gl.getAttribLocation(this.pgm, "a_normal");
|
|
this.u_projectionMtx = gl.getUniformLocation(this.pgm, "u_projectionMtx");
|
|
this.u_modelViewMtx = gl.getUniformLocation(this.pgm, "u_modelViewMtx");
|
|
|
|
/* vertex attributes */
|
|
gl.vertexAttribPointer(this.a_position, 3, gl.FLOAT, false, FSIZE * 6, 0);
|
|
gl.enableVertexAttribArray(this.a_position);
|
|
|
|
if (!skipNormals) {
|
|
gl.vertexAttribPointer(this.a_normal, 3, gl.FLOAT, false, FSIZE * 6, FSIZE * 3);
|
|
gl.enableVertexAttribArray(this.a_normal);
|
|
}
|
|
|
|
/* set our projection matrix, because it doesn't change */
|
|
gl.uniformMatrix4fv(this.u_projectionMtx, false, projectionMatrix);
|
|
}
|
|
|
|
use() {
|
|
gl.useProgram(this.pgm);
|
|
}
|
|
|
|
preRender(mvMtx) {
|
|
gl.uniformMatrix4fv(this.u_modelViewMtx, false, mvMtx);
|
|
}
|
|
}
|
|
|
|
const spVis = new ShaderProgram(
|
|
await fetchText("/shader/my.vert"),
|
|
await fetchText("/shader/my.frag")
|
|
);
|
|
const spVis_u_clock = gl.getUniformLocation(spVis.pgm, "u_clock");
|
|
const spVis_u_depthSampler = gl.getUniformLocation(spVis.pgm, "u_depthSampler");
|
|
|
|
const spDepth = new ShaderProgram(
|
|
await fetchText("/shader/depth.vert"),
|
|
await fetchText("/shader/depth.frag"),
|
|
true
|
|
);
|
|
|
|
/* Utility function */
|
|
const rotate3D = (mtx, x, y, z) => {
|
|
mat4.rotate(
|
|
mtx, mtx,
|
|
x,
|
|
[1, 0, 0]
|
|
);
|
|
mat4.rotate(
|
|
mtx, mtx,
|
|
y,
|
|
[0, 1, 0]
|
|
);
|
|
mat4.rotate(
|
|
mtx, mtx,
|
|
z,
|
|
[0, 0, 1]
|
|
);
|
|
};
|
|
|
|
rotate3D(modelViewMatrix, 0.0, 0.0, 0.0);
|
|
|
|
/* Set up depth texture... */
|
|
// Color texture
|
|
const colorTexture = gl.createTexture();
|
|
gl.bindTexture(gl.TEXTURE_2D, colorTexture);
|
|
// gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_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);
|
|
gl.texImage2D(
|
|
gl.TEXTURE_2D, 0, gl.RGBA,
|
|
gl.drawingBufferWidth, gl.drawingBufferHeight,
|
|
0, gl.RGBA, gl.UNSIGNED_BYTE, null
|
|
);
|
|
// Depth texture
|
|
const depthTexture = gl.createTexture();
|
|
gl.bindTexture(gl.TEXTURE_2D, depthTexture);
|
|
// gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_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);
|
|
gl.texImage2D(
|
|
gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT,
|
|
gl.drawingBufferWidth, gl.drawingBufferHeight,
|
|
0, gl.DEPTH_COMPONENT, gl.UNSIGNED_SHORT, null
|
|
);
|
|
// Framebuffer to render the texture with
|
|
const frameBuffer = gl.createFramebuffer();
|
|
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
|
|
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTexture, 0);
|
|
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.TEXTURE_2D, depthTexture, 0);
|
|
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
|
|
/* Set uniforms we don't update */
|
|
spVis.use();
|
|
gl.activeTexture(gl.TEXTURE0);
|
|
gl.bindTexture(gl.TEXTURE_2D, depthTexture);
|
|
gl.uniform1i(spVis_u_depthSampler, 0);
|
|
|
|
const draw_update = () => {
|
|
// Rotate camera
|
|
var delta = performance.now() - lastDraw + 0.001;
|
|
lastDraw = performance.now();
|
|
|
|
var r1 = 1 / delta;
|
|
r1 = (r1 * Math.PI) / 180;
|
|
// rotate3D(modelViewMatrix, 0, r1, 0);
|
|
};
|
|
|
|
const draw_depthPass = () => {
|
|
// Bind to framebuffer for depth texture
|
|
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
|
|
gl.colorMask(false, false, false, false);
|
|
|
|
// Do I even need to do this?
|
|
gl.clear(gl.DEPTH_BUFFER_BIT);
|
|
|
|
// Draw geometry
|
|
gl.drawArrays(gl.TRIANGLES, 0, vertsCount);
|
|
};
|
|
|
|
const draw_visualPass = () => {
|
|
// Bind back
|
|
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
gl.colorMask(true, true, true, true);
|
|
|
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
|
|
|
// Draw everything
|
|
gl.drawArrays(gl.TRIANGLES, 0, vertsCount);
|
|
};
|
|
|
|
/* Render */
|
|
var lastDraw = performance.now();
|
|
const draw = () => {
|
|
requestAnimationFrame(draw);
|
|
|
|
// Perform any updates to the scene
|
|
draw_update();
|
|
|
|
// Pre-render setup (depth)
|
|
spDepth.use();
|
|
spDepth.preRender(modelViewMatrix);
|
|
|
|
// Do depth pass
|
|
draw_depthPass();
|
|
|
|
// Pre-render setup (visual)
|
|
spVis.use();
|
|
spVis.preRender(modelViewMatrix);
|
|
gl.uniform1f(spVis_u_clock, performance.now() % 4000);
|
|
|
|
// Do the real visual pass
|
|
draw_visualPass();
|
|
}
|
|
|
|
/* Start */
|
|
requestAnimationFrame(draw);
|