X-Git-Url: https://git.r.bdr.sh/rbdr/lissajous/blobdiff_plain/5f6ef99eae91f53239f08143cead1249893fef81..32e2eed2a003c9be98f344ae70248139162b6969:/lib/systems/webgl_renderer.js diff --git a/lib/systems/webgl_renderer.js b/lib/systems/webgl_renderer.js index 8535fde..b677c6c 100644 --- a/lib/systems/webgl_renderer.js +++ b/lib/systems/webgl_renderer.js @@ -1,16 +1,34 @@ +import { mat4, vec3 } from 'gl-matrix'; import { System } from '@serpentity/serpentity'; import Drawable from '../nodes/drawable'; +import Configurable from '../nodes/configurable'; +import Cameras from '../nodes/cameras'; import { initializeShaderProgram, initializeBuffers } from '../webgl_utils'; const internals = { - kWidthRatio: 2.76, + kDefaultLineLength: 1000, + kCameraRadius: 5, + kCameraAngularVelocity: Math.PI / 180, + kFieldOfView: 45, // degrees + kNearLimit: 0.1, + kFarLimit: 100, + kWidthRatio: 1.5, kHeightRatio: 1, - kTargetVerticalResolution: 32 + Math.round(Math.random() * 1024), + kTargetVerticalResolution: 1024, kVertexShader: ` - attribute vec3 aVertexPosition; + attribute vec4 aVertexPosition; + attribute vec4 aColor; + + varying vec4 vColor; + + uniform mat4 uViewMatrix; + uniform mat4 uProjectionMatrix; + void main() { - gl_Position = vec4(aVertexPosition.xy, 0.0, 1.0); + + gl_Position = uProjectionMatrix * uViewMatrix * aVertexPosition; + vColor = aColor; gl_PointSize = 10.0; // Set the point size } `, @@ -18,25 +36,31 @@ const internals = { kFragmentShader: ` precision mediump float; - uniform vec4 uColor; + varying vec4 vColor; + void main() { - gl_FragColor = uColor; + + gl_FragColor = vColor; } ` }; +/** + * Does all the WebGL rendering. I'm not super familiar with WebGL so I need + * to revisit this in a while and see how I would restructure this. + */ export default class WebGLRenderer extends System { - constructor(canvasId) { + constructor(canvas) { super(); - this.canvasId = canvasId; + this.canvas = canvas; } added(engine){ // Set up canvas - const canvas = document.getElementById(this.canvasId); + const { canvas } = this; window.addEventListener('resize', () => this._resizeCanvas(canvas)); // Set up WebGL @@ -45,6 +69,12 @@ export default class WebGLRenderer extends System { }); this.gl = gl; + gl.clearColor(0.05882, 0.14902, 0.12157, 1); + gl.enable(gl.DEPTH_TEST); + gl.depthFunc(gl.LEQUAL); + + this.colorBuffer = gl.createBuffer(); + const shaderProgram = initializeShaderProgram( gl, internals.kVertexShader, @@ -54,10 +84,12 @@ export default class WebGLRenderer extends System { this.programInfo = { program: shaderProgram, attribLocations: { - vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition') + vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'), + vertexColor: gl.getAttribLocation(shaderProgram, 'aColor') }, uniformLocations: { - color: gl.getUniformLocation(shaderProgram, 'uColor') + projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'), + viewMatrix: gl.getUniformLocation(shaderProgram, 'uViewMatrix') } }; @@ -65,11 +97,23 @@ export default class WebGLRenderer extends System { this._resizeCanvas(canvas); this.points = engine.getNodes(Drawable); + this.positions = []; + this.colors = []; + + this.configurations = engine.getNodes(Configurable); + this.cameras = engine.getNodes(Cameras); } removed(engine){ - this.points = undefined; + delete this.gl; + delete this.points; + delete this.colorBuffer; + delete this.buffers; + delete this.positions; + delete this.colors; + delete this.configurations; + delete this.cameras; } update(){ @@ -78,31 +122,100 @@ export default class WebGLRenderer extends System { gl.useProgram(programInfo.program); - { - const color = [1, 1, 1, 1]; - gl.uniform4fv(programInfo.uniformLocations.color, color); + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + + const fieldOfView = internals.kFieldOfView * Math.PI / 180; + const aspectRatio = internals.kWidthRatio / internals.kHeightRatio; + const projectionMatrix = mat4.create(); + + mat4.perspective( + projectionMatrix, + fieldOfView, + aspectRatio, + internals.kNearLimit, + internals.kFarLimit + ); + + gl.uniformMatrix4fv( + programInfo.uniformLocations.projectionMatrix, + false, + projectionMatrix + ); + + // We only support one camera for now. + const camera = this.cameras.nodes[0]; + if (camera != undefined) { + const eye = vec3.fromValues(camera.position.x, camera.position.y, camera.position.z); + const center = vec3.fromValues(0, 0, 0); + const up = vec3.fromValues(camera.up.x, camera.up.y, camera.up.z); + const viewMatrix = mat4.create(); + mat4.lookAt(viewMatrix, eye, center, up); + gl.uniformMatrix4fv( + programInfo.uniformLocations.viewMatrix, + false, + viewMatrix + ); } - const positions = []; + let i = 0; for (const point of this.points) { - positions.push(point.position.x, point.position.y, point.position.z); - positions.push( + this.positions[i] = this.positions[i] || []; + this.positions[i].push(point.position.x, point.position.y, point.position.z, 1); + this.positions[i].push( point.position.prevX || point.position.x, point.position.prevY || point.position.y, - point.position.prevZ || point.position.z + point.position.prevZ || point.position.z, + 1 ); point.position.prevX = point.position.x; point.position.prevY = point.position.y; point.position.prevZ = point.position.z; + + this.colors[i] = this.colors[i] || []; + this.colors[i].push( + 0.5 + point.position.z / 4 + point.position.x / 4, + 0.5 + point.position.z / 4 + point.position.y / 4, + 0.75 + point.position.z / 4, 1, + 0.5 + point.position.prevZ / 4 + point.position.prevX / 4, + 0.5 + point.position.prevZ / 4 + point.position.prevY / 4, + 0.75 + point.position.prevZ / 4,1); + + ++i; + } + + gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); + const colors = this.colors.flat(); + gl.bufferData(gl.ARRAY_BUFFER, + new Float32Array(colors), + gl.STATIC_DRAW); + + { + const numberOfComponents = 4; + const type = gl.FLOAT; + const normalize = false; + const stride = 0; + const offset = 0; + + gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer); + gl.vertexAttribPointer( + programInfo.attribLocations.vertexColor, + numberOfComponents, + type, + normalize, + stride, + offset + ); + gl.enableVertexAttribArray(programInfo.attribLocations.vertexColor); } gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position); + const positions = this.positions.flat(); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW); { - const numberOfComponents = 3; + const numberOfComponents = 4; const type = gl.FLOAT; const normalize = false; const stride = 0; @@ -122,20 +235,20 @@ export default class WebGLRenderer extends System { { gl.lineWidth(2); - gl.drawArrays(gl.LINES, 0, this.points.nodes.length * 2); + gl.drawArrays(gl.LINES, 0, positions.length / 4); } + + this._cullLines(); } _resizeCanvas(canvas) { - console.log('Resizing Canvas'); let width = window.innerWidth; let height = Math.round(width * internals.kHeightRatio / internals.kWidthRatio); if (window.innerHeight < height) { height = window.innerHeight; width = Math.round(height * internals.kWidthRatio / internals.kHeightRatio); - console.log(width, height); } canvas.style.width = `${width}px`; @@ -146,4 +259,16 @@ export default class WebGLRenderer extends System { this.gl.viewport(0, 0, canvas.width, canvas.height); } + + _cullLines() { + const lineLength = this.configurations.nodes[0]?.configuration.lineLength || internals.kDefaultLineLength; + + for (const [i, position] of Object.entries(this.positions)) { + this.positions[i] = position.slice(-lineLength * 8); + } + + for (const [i, color] of Object.entries(this.colors)) { + this.colors[i] = color.slice(-lineLength * 8); + } + } };