-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwebgl.js
More file actions
124 lines (99 loc) · 3.93 KB
/
webgl.js
File metadata and controls
124 lines (99 loc) · 3.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// This is terrible code but it provides enough abstraction to ignore it
export default class WebGLShaderRenderer {
vertexShaderPath = "./shader/vertex.glsl";
programInfo = {
shaders: [
{ type: "vertex", },
{ type: "fragment" },
],
uniforms: [],
attributes: [ "position" ],
};
constructor(id, resolution) {
this.id = id;
this.resolution = resolution;
this.initCanvas();
this.initWebGLRenderingContext();
this.initVertexBuffer();
};
static async downloadShader(path) {
const response = await fetch(path);
return response.text();
}
initCanvas() {
this.canvas = document.getElementById(this.id);
this.canvas.width = this.resolution[0];
this.canvas.height = this.resolution[1];
this.canvas.style.width = this.resolution[0];
this.canvas.style.height = this.resolution[1];
}
initWebGLRenderingContext() {
this.gl = this.canvas.getContext("webgl", {
antialias: false,
depth: false,
});
if (!this.gl) return alert("WebGL not supported");
this.shader = {
[this.gl.VERTEX_SHADER]: "vertex",
[this.gl.FRAGMENT_SHADER]: "fragment",
vertex: this.gl.VERTEX_SHADER,
fragment: this.gl.FRAGMENT_SHADER,
};
}
initVertexBuffer() {
this.vertices = new Float32Array([
-1, 1, 0, 0,
1, 1, 1, 0,
-1, -1, 0, 1,
1, -1, 1, 1,
]);
this.vertexBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.vertexBuffer);
this.gl.bufferData(this.gl.ARRAY_BUFFER, this.vertices, this.gl.STATIC_DRAW);
this.vertexCount = this.vertices.length / 4;
}
async setShader(vertex, fragment) {
this.programInfo.shaders[0].code = await WebGLShaderRenderer.downloadShader(vertex);
this.programInfo.shaders[1].code = await WebGLShaderRenderer.downloadShader(fragment);
this.shaderProgram = this.buildShaderProgram();
this.gl.enableVertexAttribArray(this.shaderProgram.attributes.position);
this.gl.vertexAttribPointer(this.shaderProgram.attributes.position, 2, this.gl.FLOAT, false, 4 * 4, 0);
}
compileShader(code, type) {
const gl = this.gl;
let shader = gl.createShader(type);
gl.shaderSource(shader, code);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error(`Error compiling ${this.shader[type]} shader:\n${gl.getShaderInfoLog(shader)}`);
}
return shader;
}
buildShaderProgram() {
let program = this.gl.createProgram();
this.programInfo.shaders.forEach(desc => {
let shader = this.compileShader(desc.code, this.shader[desc.type]);
if (shader) this.gl.attachShader(program, shader);
});
this.gl.linkProgram(program);
if (!this.gl.getProgramParameter(program, this.gl.LINK_STATUS)) {
console.error(`Error linking shader program:\n${this.gl.getProgramInfoLog(program)}`);
}
let uniforms = Object.fromEntries(this.programInfo.uniforms.map(name => [ name, this.gl.getUniformLocation(program, name) ]));
let attributes = Object.fromEntries(this.programInfo.attributes.map(name => [ name, this.gl.getAttribLocation(program, name) ]));
return { program, uniforms, attributes };
}
start() {
this.ms = 0;
window.requestAnimationFrame(ts => this.loop(ts));
}
loop(ts) {
window.requestAnimationFrame(ts => this.loop(ts));
this.dt = ts - this.ms;
this.ms = ts;
this.gl.useProgram(this.shaderProgram.program);
this.callback(this.gl, this.shaderProgram);
this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, this.vertexCount);
}
callback() { }
};