1 import { mat4
, vec3
} from 'gl-matrix';
2 import { System
} from '@serpentity/serpentity';
3 import Drawable
from '../nodes/drawable';
4 import Configurable
from '../nodes/configurable';
5 import Cameras
from '../nodes/cameras';
6 import { initializeShaderProgram
, initializeBuffers
} from '../webgl_utils';
9 kDefaultLineLength: 1000,
11 kCameraAngularVelocity: Math
.PI
/ 180,
12 kFieldOfView: 45, // degrees
17 kTargetVerticalResolution: 1024,
20 attribute vec4 aVertexPosition;
21 attribute vec4 aColor;
25 uniform mat4 uViewMatrix;
26 uniform mat4 uProjectionMatrix;
30 gl_Position = uProjectionMatrix * uViewMatrix * aVertexPosition;
32 gl_PointSize = 10.0; // Set the point size
38 precision mediump float;
43 gl_FragColor = vColor;
48 export default class WebGLRenderer
extends System
{
59 const { canvas
} = this;
60 window
.addEventListener('resize', () => this._resizeCanvas(canvas
));
63 const gl
= canvas
.getContext('webgl', {
64 preserveDrawingBuffer: true
68 gl
.clearColor(0.05882, 0.14902, 0.12157, 1);
69 gl
.enable(gl
.DEPTH_TEST
);
70 gl
.depthFunc(gl
.LEQUAL
);
72 this.colorBuffer
= gl
.createBuffer();
74 const shaderProgram
= initializeShaderProgram(
76 internals
.kVertexShader
,
77 internals
.kFragmentShader
81 program: shaderProgram
,
83 vertexPosition: gl
.getAttribLocation(shaderProgram
, 'aVertexPosition'),
84 vertexColor: gl
.getAttribLocation(shaderProgram
, 'aColor')
87 projectionMatrix: gl
.getUniformLocation(shaderProgram
, 'uProjectionMatrix'),
88 viewMatrix: gl
.getUniformLocation(shaderProgram
, 'uViewMatrix')
92 this.buffers
= initializeBuffers(gl
);
93 this._resizeCanvas(canvas
);
95 this.points
= engine
.getNodes(Drawable
);
99 this.configurations
= engine
.getNodes(Configurable
);
100 this.cameras
= engine
.getNodes(Cameras
);
107 delete this.colorBuffer
;
109 delete this.positions
;
111 delete this.configurations
;
117 const {gl
, programInfo
, buffers
} = this;
119 gl
.useProgram(programInfo
.program
);
121 gl
.clear(gl
.COLOR_BUFFER_BIT
| gl
.DEPTH_BUFFER_BIT
);
123 const fieldOfView
= internals
.kFieldOfView
* Math
.PI
/ 180;
124 const aspectRatio
= internals
.kWidthRatio
/ internals
.kHeightRatio
;
125 const projectionMatrix
= mat4
.create();
131 internals
.kNearLimit
,
136 programInfo
.uniformLocations
.projectionMatrix
,
141 // We only support one camera for now.
142 const camera
= this.cameras
.nodes
[0];
143 if (camera
!= undefined) {
144 const eye
= vec3
.fromValues(camera
.position
.x
, camera
.position
.y
, camera
.position
.z
);
145 const center
= vec3
.fromValues(0, 0, 0);
146 const up
= vec3
.fromValues(camera
.up
.x
, camera
.up
.y
, camera
.up
.z
);
147 const viewMatrix
= mat4
.create();
148 mat4
.lookAt(viewMatrix
, eye
, center
, up
);
150 programInfo
.uniformLocations
.viewMatrix
,
157 for (const point
of this.points
) {
158 this.positions
[i
] = this.positions
[i
] || [];
159 this.positions
[i
].push(point
.position
.x
, point
.position
.y
, point
.position
.z
, 1);
160 this.positions
[i
].push(
161 point
.position
.prevX
|| point
.position
.x
,
162 point
.position
.prevY
|| point
.position
.y
,
163 point
.position
.prevZ
|| point
.position
.z
,
166 point
.position
.prevX
= point
.position
.x
;
167 point
.position
.prevY
= point
.position
.y
;
168 point
.position
.prevZ
= point
.position
.z
;
170 this.colors
[i
] = this.colors
[i
] || [];
172 0.5 + point
.position
.z
/ 4 + point
.position
.x
/ 4,
173 0.5 + point
.position
.z
/ 4 + point
.position
.y
/ 4,
174 0.75 + point
.position
.z
/ 4, 1,
175 0.5 + point
.position
.prevZ
/ 4 + point
.position
.prevX
/ 4,
176 0.5 + point
.position
.prevZ
/ 4 + point
.position
.prevY
/ 4,
177 0.75 + point
.position
.prevZ
/ 4,1);
182 gl
.bindBuffer(gl
.ARRAY_BUFFER
, this.colorBuffer
);
183 const colors
= this.colors
.flat();
184 gl
.bufferData(gl
.ARRAY_BUFFER
,
185 new Float32Array(colors
),
189 const numberOfComponents
= 4;
190 const type
= gl
.FLOAT
;
191 const normalize
= false;
195 gl
.bindBuffer(gl
.ARRAY_BUFFER
, this.colorBuffer
);
196 gl
.vertexAttribPointer(
197 programInfo
.attribLocations
.vertexColor
,
204 gl
.enableVertexAttribArray(programInfo
.attribLocations
.vertexColor
);
207 gl
.bindBuffer(gl
.ARRAY_BUFFER
, buffers
.position
);
208 const positions
= this.positions
.flat();
209 gl
.bufferData(gl
.ARRAY_BUFFER
,
210 new Float32Array(positions
),
214 const numberOfComponents
= 4;
215 const type
= gl
.FLOAT
;
216 const normalize
= false;
220 gl
.bindBuffer(gl
.ARRAY_BUFFER
, buffers
.position
);
221 gl
.vertexAttribPointer(
222 programInfo
.attribLocations
.vertexPosition
,
229 gl
.enableVertexAttribArray(programInfo
.attribLocations
.vertexPosition
);
234 gl
.drawArrays(gl
.LINES
, 0, positions
.length
/ 4);
240 _resizeCanvas(canvas
) {
242 let width
= window
.innerWidth
;
243 let height
= Math
.round(width
* internals
.kHeightRatio
/ internals
.kWidthRatio
);
245 if (window
.innerHeight
< height
) {
246 height
= window
.innerHeight
;
247 width
= Math
.round(height
* internals
.kWidthRatio
/ internals
.kHeightRatio
);
250 canvas
.style
.width
= `${width}px`;
251 canvas
.style
.height
= `${height}px`;
253 canvas
.width
= internals
.kTargetVerticalResolution
* internals
.kWidthRatio
;
254 canvas
.height
= internals
.kTargetVerticalResolution
;
256 this.gl
.viewport(0, 0, canvas
.width
, canvas
.height
);
260 const lineLength
= this.configurations
.nodes
[0]?.configuration
.lineLength
|| internals
.kDefaultLineLength
;
262 for (const [i
, position
] of Object
.entries(this.positions
)) {
263 this.positions
[i
] = position
.slice(-lineLength
* 8);
266 for (const [i
, color
] of Object
.entries(this.colors
)) {
267 this.colors
[i
] = color
.slice(-lineLength
* 8);