From 7bc7b64c8ba3e7b27ad6822210601549e029862c Mon Sep 17 00:00:00 2001 From: Paul Mathieu Date: Wed, 15 Dec 2021 12:00:10 -0800 Subject: [PATCH] Performance refactor --- index.js | 146 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 95 insertions(+), 51 deletions(-) diff --git a/index.js b/index.js index 4d076de..fdc86f1 100644 --- a/index.js +++ b/index.js @@ -53,7 +53,9 @@ void main() { * @param {WebGLRenderingContext} gl */ function draw(gl, params, objects) { - gl.clearColor(0.6, 0.8, 1.0, 1.0); + const skyColor = [0.6, 0.8, 1.0]; + + gl.clearColor(...skyColor, 1.0); gl.clearDepth(1.0); gl.enable(gl.DEPTH_TEST); gl.depthFunc(gl.LEQUAL); @@ -65,55 +67,32 @@ function draw(gl, params, objects) { const camrot = params.camera.orientation; const campos = params.camera.position; - const viewMat = se3.product( + const viewMatrix = se3.product( se3.rotxyz(-camrot[0], -camrot[1], -camrot[2]), se3.translation(-campos[0], -campos[1], -campos[2]) ); - for (const {program, texture, position, orientation, geometry} of objects) { - // load those ahead of time - const viewLoc = gl.getUniformLocation(program, 'uView'); - const modelLoc = gl.getUniformLocation(program, 'uModel'); - const projLoc = gl.getUniformLocation(program, 'uProjection'); - const samplerLoc = gl.getUniformLocation(program, 'uSampler'); - const fogColorLoc = gl.getUniformLocation(program, 'uFogColor'); - const lightDirectionLoc = gl.getUniformLocation(program, 'uLightDirection'); - const ambiantLoc = gl.getUniformLocation(program, 'uAmbiantLight'); + let lastGlContext; - const positionLoc = gl.getAttribLocation(program, 'aPosition'); - const normalLoc = gl.getAttribLocation(program, 'aNormal'); - const textureLoc = gl.getAttribLocation(program, 'aTextureCoord'); + for (const {glContext, position, orientation, geometry} of objects) { + if (glContext !== lastGlContext) { + glContext.setupScene({ + projectionMatrix: params.projMatrix, + viewMatrix, + fogColor: skyColor, + lightDirection: params.lightDirection, + ambiantLightAmount: params.ambiantLight, + }); + } - //const mvMatrix = se3.product(se3.translation(...position), se3.rotxyz(...orientation)); - const mvMatrix = se3.identity(); + lastGlContext = glContext; - gl.useProgram(program); - - gl.uniformMatrix4fv(viewLoc, false, new Float32Array(viewMat)); - gl.uniformMatrix4fv(modelLoc, false, new Float32Array(mvMatrix)); - gl.uniformMatrix4fv(projLoc, false, new Float32Array(params.projMatrix)); - gl.uniform3f(fogColorLoc, 0.6, 0.8, 1.0); - gl.uniform3f(lightDirectionLoc, ...params.lightDirection); - gl.uniform1f(ambiantLoc, params.ambiantLight); - - gl.bindBuffer(gl.ARRAY_BUFFER, geometry.glBuffer); - - gl.vertexAttribPointer(positionLoc, 3, gl.FLOAT, false, 20, 0); - gl.enableVertexAttribArray(positionLoc); - - gl.vertexAttribPointer(normalLoc, 3, gl.BYTE, true, 20, 12); - gl.enableVertexAttribArray(normalLoc); - - gl.vertexAttribPointer(textureLoc, 2, gl.UNSIGNED_SHORT, true, 20, 16); - gl.enableVertexAttribArray(textureLoc); - - gl.activeTexture(gl.TEXTURE0); - gl.bindTexture(gl.TEXTURE_2D, texture); - gl.uniform1i(samplerLoc, 0); - - gl.drawArrays(gl.TRIANGLES, 0, geometry.numVertices); -// gl.bindTexture(gl.TEXTURE_2D, null); -// gl.drawArrays(gl.LINE_STRIP, 0, geometry.numVertices); + glContext.drawObject({ + position, + orientation, + glBuffer: geometry.glBuffer, + numVertices: geometry.numVertices, + }); } } @@ -180,7 +159,7 @@ function handleKeys(params) { }); } -function getObjects(world, z, x, program, texture) { +function getObjects(world, z, x, glContext) { return world.chunks .filter(chunk => { if (chunk.position.z < z - 8 * 16) return false; @@ -197,9 +176,8 @@ function getObjects(world, z, x, program, texture) { .map(chunk => ({ position: [0.0, 0.0, 0.0], orientation: [0.0, 0.0, 0.0], - program, geometry: chunk.buffer, - texture, + glContext, })); } @@ -239,7 +217,7 @@ function tick(time, gl, params) { } } - const objects = getObjects(params.world, campos[2], campos[0], params.program, params.texture); + const objects = getObjects(params.world, campos[2], campos[0], params.worldGl); draw(gl, params, objects); const dt = (time - stuff.lastFrameTime) * 0.001; @@ -324,6 +302,74 @@ function checkCollision(curPos, newPos, world) { // [x] better controls // [ ] save the world (yay) to local storage (bah) +async function initWorldGl(gl) { + const program = makeProgram(gl, TEST_VSHADER, TEST_FSHADER); + const texture = await loadTexture(gl, 'texture.png'); + + // load those ahead of time + const viewLoc = gl.getUniformLocation(program, 'uView'); + const modelLoc = gl.getUniformLocation(program, 'uModel'); + const projLoc = gl.getUniformLocation(program, 'uProjection'); + const samplerLoc = gl.getUniformLocation(program, 'uSampler'); + const fogColorLoc = gl.getUniformLocation(program, 'uFogColor'); + const lightDirectionLoc = gl.getUniformLocation(program, 'uLightDirection'); + const ambiantLoc = gl.getUniformLocation(program, 'uAmbiantLight'); + + const positionLoc = gl.getAttribLocation(program, 'aPosition'); + const normalLoc = gl.getAttribLocation(program, 'aNormal'); + const textureLoc = gl.getAttribLocation(program, 'aTextureCoord'); + + const setupScene = (sceneParams) => { + const { + projectionMatrix, + viewMatrix, + fogColor, + lightDirection, + ambiantLightAmount, + } = sceneParams; + + gl.useProgram(program); + + gl.uniformMatrix4fv(projLoc, false, new Float32Array(projectionMatrix)); + gl.uniformMatrix4fv(viewLoc, false, new Float32Array(viewMatrix)); + gl.uniform3fv(fogColorLoc, fogColor); + gl.uniform3fv(lightDirectionLoc, lightDirection); + gl.uniform1f(ambiantLoc, ambiantLightAmount); + + // doing this here because it's the same for all world stuff + gl.uniformMatrix4fv(modelLoc, false, new Float32Array(se3.identity())); + gl.uniform1i(samplerLoc, 0); + }; + + const drawObject = (objectParams) => { + const { + glBuffer, + numVertices, + } = objectParams; + + gl.bindBuffer(gl.ARRAY_BUFFER, glBuffer); + + gl.vertexAttribPointer(positionLoc, 3, gl.FLOAT, false, 20, 0); + gl.enableVertexAttribArray(positionLoc); + + gl.vertexAttribPointer(normalLoc, 3, gl.BYTE, true, 20, 12); + gl.enableVertexAttribArray(normalLoc); + + gl.vertexAttribPointer(textureLoc, 2, gl.UNSIGNED_SHORT, true, 20, 16); + gl.enableVertexAttribArray(textureLoc); + + gl.activeTexture(gl.TEXTURE0); + gl.bindTexture(gl.TEXTURE_2D, texture); + + gl.drawArrays(gl.TRIANGLES, 0, numVertices); + }; + + return { + setupScene, + drawObject, + }; +} + async function main() { const canvas = document.querySelector('#game'); const gl = canvas.getContext('webgl'); @@ -333,8 +379,7 @@ async function main() { return; } - const program = makeProgram(gl, TEST_VSHADER, TEST_FSHADER); - const texture = await loadTexture(gl, 'texture.png'); + const worldGl = await initWorldGl(gl); const params = { projMatrix: se3.perspective(Math.PI / 3, canvas.clientWidth / canvas.clientHeight, 0.1, 100.0), @@ -345,12 +390,11 @@ async function main() { }, keys: new Set(), world: makeWorld(), - texture, - program, lightDirection: [-0.2, -0.5, 0.4], ambiantLight: 0.7, flying: false, isOnGround: false, + worldGl, } document.querySelector('#lightx').oninput = e => {