diff options
| author | Ruben Beltran del Rio <git@r.bdr.sh> | 2024-05-07 22:37:27 +0200 |
|---|---|---|
| committer | Ruben Beltran del Rio <git@r.bdr.sh> | 2024-05-07 22:37:27 +0200 |
| commit | 362f91160b243453578633e3f9af67ce40179d8c (patch) | |
| tree | a9ee95e2f8a9c59189ea904ce87bfe54ed5be107 /lib/systems | |
| parent | 5f6ef99eae91f53239f08143cead1249893fef81 (diff) | |
Make 3D
Diffstat (limited to 'lib/systems')
| -rw-r--r-- | lib/systems/amplitude_adjuster.js | 64 | ||||
| -rw-r--r-- | lib/systems/camera_adjuster.js | 74 | ||||
| -rw-r--r-- | lib/systems/camera_rotator.js | 49 | ||||
| -rw-r--r-- | lib/systems/frequency_adjuster.js | 64 | ||||
| -rw-r--r-- | lib/systems/global_adjuster.js | 57 | ||||
| -rw-r--r-- | lib/systems/lissajous_position_updater.js | 13 | ||||
| -rw-r--r-- | lib/systems/webgl_renderer.js | 167 |
7 files changed, 458 insertions, 30 deletions
diff --git a/lib/systems/amplitude_adjuster.js b/lib/systems/amplitude_adjuster.js new file mode 100644 index 0000000..71f7277 --- /dev/null +++ b/lib/systems/amplitude_adjuster.js @@ -0,0 +1,64 @@ +import { System } from '@serpentity/serpentity'; +import Ample from '../nodes/ample'; +import { settingsContainer, slider } from '../factories/ui'; + +const internals = { + symbols: { + a: '𝛢', + b: '𝛣', + c: '𝛧' + } +}; + +export default class AmplitudeAdjuster extends System { + + constructor(container) { + + super(); + this.container = container; + } + + added(engine){ + + this.nodes = engine.getNodes(Ample); + this.adjusterContainer = settingsContainer({ + id: 'amplitude-adjuster', + label: 'Amplitude' + }); + + let i = 0; + for (const node of this.nodes) { + const nodeElement = settingsContainer({ + id: `amplitude-adjuster-${i}`, + label: `ɣ${i + 1}`, + level: 3 + }); + + ['a', 'b', 'c'].forEach(key => { + nodeElement.appendChild(slider({ + min: '0', + max: '1', + step: '0.01', + label: internals.symbols[key], + className: `amplitude`, + get: () => node.amplitude[key].toString(), + set: (value) => (node.amplitude[key] = parseFloat(value)) + })); + }); + + this.adjusterContainer.appendChild(nodeElement); + ++i; + } + + this.container.appendChild(this.adjusterContainer); + } + + removed(){ + + this.container.removeChild(this.adjusterContainer); + delete this.adjusterContainer; + delete this.nodes; + } + + update(){} +}; diff --git a/lib/systems/camera_adjuster.js b/lib/systems/camera_adjuster.js new file mode 100644 index 0000000..3b6ea41 --- /dev/null +++ b/lib/systems/camera_adjuster.js @@ -0,0 +1,74 @@ +import { System } from '@serpentity/serpentity'; +import Cameras from '../nodes/cameras'; +import { settingsContainer, slider } from '../factories/ui'; + +const internals = { + symbols: { + x: '𝜃', + y: '𝜓', + z: '𝜙' + } +}; + +export default class CameraAdjuster extends System { + + constructor(container) { + + super(); + this.container = container; + } + + added(engine){ + + this.nodes = engine.getNodes(Cameras); + this.adjusterContainer = settingsContainer({ + id: 'camera-adjuster', + label: 'Camera' + }) + + let i = 0; + for (const node of this.nodes) { + const nodeElement = settingsContainer({ + id: `camera-adjuster-${i}`, + label: `C${i + 1}`, + level: 3 + }); + + nodeElement.appendChild(slider({ + min: '2', + max: '10', + step: '0.1', + label: '𝑟', + className: 'radius', + get: () => node.radius.radius.toString(), + set: (value) => (node.radius.radius = parseFloat(value)) + })); + + ['x', 'y', 'z'].forEach(key => { + nodeElement.appendChild(slider({ + min: '0', + max: '0.5', + step: '0.001', + label: internals.symbols[key], + className: `rotation-${key}`, + get: () => node.velocity[key].toString(), + set: (value) => (node.velocity[key] = parseFloat(value)) + })); + }); + + this.adjusterContainer.appendChild(nodeElement); + ++i; + } + + this.container.appendChild(this.adjusterContainer); + } + + removed(){ + + this.container.removeChild(this.adjusterContainer); + delete this.adjusterContainer; + delete this.nodes; + } + + update(){} +}; diff --git a/lib/systems/camera_rotator.js b/lib/systems/camera_rotator.js new file mode 100644 index 0000000..3520f71 --- /dev/null +++ b/lib/systems/camera_rotator.js @@ -0,0 +1,49 @@ +import { mat4, vec3 } from 'gl-matrix'; +import { System } from '@serpentity/serpentity'; +import Cameras from '../nodes/cameras'; + +export default class CameraRotator extends System { + + constructor() { + + super(); + } + + added(engine){ + + this.cameras = engine.getNodes(Cameras); + } + + removed(){ + + delete this.cameras; + } + + update(dt){ + + for (const camera of this.cameras) { + + let rotationMatrix = mat4.create(); + mat4.rotateY(rotationMatrix, rotationMatrix, camera.angle.yaw); + mat4.rotateX(rotationMatrix, rotationMatrix, camera.angle.pitch); + mat4.rotateZ(rotationMatrix, rotationMatrix, camera.angle.roll); + + let eye = vec3.fromValues(0, 0, camera.radius.radius); + vec3.transformMat4(eye, eye, rotationMatrix); + + camera.position.x = eye[0]; + camera.position.y = eye[1]; + camera.position.z = eye[2]; + + let up = vec3.fromValues(0, 1, 0); + vec3.transformMat4(up, up, rotationMatrix); + camera.up.x = up[0]; + camera.up.y = up[1]; + camera.up.z = up[2]; + + camera.angle.pitch = (camera.angle.pitch + camera.velocity.x * dt / 100 + 2 * Math.PI) % (2 * Math.PI); + camera.angle.yaw = (camera.angle.yaw + camera.velocity.y * dt / 100 + 2 * Math.PI) % (2 * Math.PI); + camera.angle.roll = (camera.angle.roll + camera.velocity.z * dt / 100 + 2 * Math.PI) % (2 * Math.PI); + } + } +}; diff --git a/lib/systems/frequency_adjuster.js b/lib/systems/frequency_adjuster.js new file mode 100644 index 0000000..6aa11d4 --- /dev/null +++ b/lib/systems/frequency_adjuster.js @@ -0,0 +1,64 @@ +import { System } from '@serpentity/serpentity'; +import Frequent from '../nodes/frequent'; +import { settingsContainer, slider } from '../factories/ui'; + +const internals = { + symbols: { + a: '𝛼', + b: '𝛽', + c: '𝜁' + } +}; + +export default class FrequencyAdjuster extends System { + + constructor(container) { + + super(); + this.container = container; + } + + added(engine){ + + this.nodes = engine.getNodes(Frequent); + this.adjusterContainer = settingsContainer({ + id: 'frequency-adjuster', + label: 'Frequency' + }) + + let i = 0; + for (const node of this.nodes) { + const nodeElement = settingsContainer({ + id: `frequency-adjuster-${i}`, + label: `ɣ${i + 1}`, + level: 3 + }); + + ['a', 'b', 'c'].forEach(key => { + nodeElement.appendChild(slider({ + min: '0', + max: '1', + step: '0.01', + label: internals.symbols[key], + className: `frequency`, + get: () => node.frequency[key].toString(), + set: (value) => (node.frequency[key] = parseFloat(value)) + })); + }); + + this.adjusterContainer.appendChild(nodeElement); + ++i; + } + + this.container.appendChild(this.adjusterContainer); + } + + removed(){ + + this.container.removeChild(this.adjusterContainer); + delete this.adjusterContainer; + delete this.nodes; + } + + update(){} +}; diff --git a/lib/systems/global_adjuster.js b/lib/systems/global_adjuster.js new file mode 100644 index 0000000..7f6df91 --- /dev/null +++ b/lib/systems/global_adjuster.js @@ -0,0 +1,57 @@ +import { System } from '@serpentity/serpentity'; +import Frequent from '../nodes/configurable'; +import { settingsContainer, slider } from '../factories/ui'; + +export default class GlobalAdjuster extends System { + + constructor(container) { + + super(); + this.container = container; + } + + added(engine){ + + this.nodes = engine.getNodes(Frequent); + const container = document.getElementById('settings'); + this.adjusterContainer = settingsContainer({ + id: 'global-adjuster', + label: 'Global' + }); + + let i = 0; + for (const node of this.nodes) { + const nodeElement = settingsContainer({ + id: `global-adjuster-${i}`, + label: 'Line', + level: 3 + }); + + nodeElement.appendChild(slider({ + min: '5', + max: '2000', + step: '1', + label: '𝜆', + className: 'lineLength', + get: () => node.configuration.lineLength.toString(), + set: (value) => (node.configuration.lineLength = parseFloat(value)) + })); + + this.adjusterContainer.appendChild(nodeElement); + ++i; + } + + this.container.appendChild(this.adjusterContainer); + } + + removed(){ + + this.container.removeChild(this.adjusterContainer); + delete this.adjusterContainer; + delete this.nodes; + } + + update(){} +}; + + diff --git a/lib/systems/lissajous_position_updater.js b/lib/systems/lissajous_position_updater.js index 0f5792d..202ddc7 100644 --- a/lib/systems/lissajous_position_updater.js +++ b/lib/systems/lissajous_position_updater.js @@ -2,7 +2,7 @@ import { System } from '@serpentity/serpentity'; import LissajousCurve from '../nodes/lissajous_curve'; const internals = { - kAmplitude: 0.8, + kAmplitude: 1, kPeriod: Math.PI * 12000000 }; @@ -21,8 +21,8 @@ export default class WebGLRenderer extends System { removed(){ - this.curves = undefined; - this.time = undefined; + delete this.curves; + delete this.time; } update(dt){ @@ -30,11 +30,10 @@ export default class WebGLRenderer extends System { this.time = (this.time + dt / 100) % internals.kPeriod; for (const curve of this.curves) { - curve.position.x = this._getPosition(internals.kAmplitude, curve.frequency.a, this.time, 0); - curve.position.y = this._getPosition(internals.kAmplitude, curve.frequency.b, this.time, 0); - curve.position.z = this._getPosition(internals.kAmplitude, curve.frequency.c, this.time, 0); + curve.position.x = this._getPosition(curve.amplitude.a, curve.frequency.a, this.time, 0); + curve.position.y = this._getPosition(curve.amplitude.b, curve.frequency.b, this.time, 0); + curve.position.z = this._getPosition(curve.amplitude.c, curve.frequency.c, this.time, 0); } - console.log('UP'); } _getPosition(amplitude, frequency, time, phaseShift) { diff --git a/lib/systems/webgl_renderer.js b/lib/systems/webgl_renderer.js index 8535fde..3a92552 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,27 @@ const internals = { kFragmentShader: ` precision mediump float; - uniform vec4 uColor; + varying vec4 vColor; + void main() { - gl_FragColor = uColor; + + gl_FragColor = vColor; } ` }; 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 +65,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 +80,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 +93,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 +118,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 +231,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 +255,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); + } + } }; |