Skip to content

Commit a7f43ac

Browse files
author
Andrew Adamson
committed
Adding episodes 25 and 27 Framebuffer Object and Deferred Rendering code
1 parent 177f83c commit a7f43ac

File tree

3 files changed

+1344
-0
lines changed

3 files changed

+1344
-0
lines changed

25.framebuffer.basics.js

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
// PART 1: INITIALIZATION
2+
3+
// Step 1: Prepare the environment
4+
5+
const canvas = document.querySelector('canvas');
6+
const gl = canvas.getContext('webgl2');
7+
8+
// We'll be using transparency when rendering the second
9+
// program. We'll enable blending before its draw call and
10+
// disable it after, but we can set the blending function
11+
// here now since it will never change.
12+
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
13+
14+
15+
// Multiple programs are needed, so let's abstract the
16+
// creation process
17+
const createProgram = (gl, vs, fs) => {
18+
const program = gl.createProgram();
19+
20+
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
21+
gl.shaderSource(vertexShader, vs);
22+
gl.compileShader(vertexShader);
23+
gl.attachShader(program, vertexShader);
24+
25+
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
26+
gl.shaderSource(fragmentShader, fs);
27+
gl.compileShader(fragmentShader);
28+
gl.attachShader(program, fragmentShader);
29+
30+
gl.linkProgram(program);
31+
32+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
33+
console.log(gl.getShaderInfoLog(vertexShader));
34+
console.log(gl.getShaderInfoLog(fragmentShader));
35+
}
36+
37+
return program;
38+
};
39+
40+
41+
42+
43+
// Step 2: Create the triangle program and configure its buffers
44+
const triangleVerexShaderSource =
45+
`#version 300 es
46+
#pragma vscode_glsllint_stage: vert
47+
48+
uniform vec2 offset;
49+
50+
layout(location=0) in vec4 aPosition;
51+
layout(location=1) in vec4 aColor;
52+
53+
out vec4 vColor;
54+
55+
void main()
56+
{
57+
vColor = aColor;
58+
gl_Position = aPosition + vec4(offset, 0.0, 0.0);
59+
}`;
60+
61+
const triangleFragmentShaderSource =
62+
`#version 300 es
63+
#pragma vscode_glsllint_stage: frag
64+
65+
precision mediump float;
66+
67+
in vec4 vColor;
68+
69+
layout(location=0) out vec4 fragColor;
70+
layout(location=1) out vec4 solidColor;
71+
72+
void main()
73+
{
74+
fragColor = vColor;
75+
solidColor = vec4(0.0, 1.0, 0.0, 1.0);
76+
}`;
77+
78+
const triangleProgram = createProgram(gl, triangleVerexShaderSource, triangleFragmentShaderSource);
79+
80+
const triangleData = new Float32Array([
81+
// Pos (xyz) // Color (rgb)
82+
-.5,-.5, -.5, 0,0,1,
83+
0.5,-.5, -.5, 0,0,1,
84+
0.0,0.4, -.5, 0,0,1,
85+
86+
-.5,0.5, 0.5, 1,0,0,
87+
0.5,0.5, 0.5, 1,0,0,
88+
0.0,-.4, 0.5, 1,0,0,
89+
90+
]);
91+
92+
// Two programs? Use vertex array objects. They will
93+
// allow you to easily and instantly bind the buffers
94+
// you need before you issue your draw calls.
95+
const triangleVAO = gl.createVertexArray();
96+
gl.bindVertexArray(triangleVAO);
97+
98+
const triangleBuffer = gl.createBuffer();
99+
gl.bindBuffer(gl.ARRAY_BUFFER, triangleBuffer);
100+
gl.bufferData(gl.ARRAY_BUFFER, triangleData, gl.STATIC_DRAW);
101+
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 24, 0);
102+
gl.vertexAttribPointer(1, 3, gl.FLOAT, false, 24, 12);
103+
gl.enableVertexAttribArray(0);
104+
gl.enableVertexAttribArray(1);
105+
106+
gl.bindVertexArray(null);
107+
108+
// And get the uniform location in the first program of its `offset` uniform
109+
const offsetUniformLocation = gl.getUniformLocation(triangleProgram, 'offset');
110+
111+
// Step 3: Create the (emtpy) texture
112+
const fragColorTexture = gl.createTexture();
113+
gl.bindTexture(gl.TEXTURE_2D, fragColorTexture);
114+
gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, 480, 480);
115+
116+
const solidColorTexture = gl.createTexture();
117+
gl.bindTexture(gl.TEXTURE_2D, solidColorTexture);
118+
gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, 480, 480);
119+
120+
gl.bindTexture(gl.TEXTURE_2D, null);
121+
122+
const renderbuffer = gl.createRenderbuffer();
123+
gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
124+
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, 480, 480);
125+
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
126+
127+
128+
// Step 5: Add the quad program and configure its buffers
129+
const quadVertexShaderSource =
130+
`#version 300 es
131+
#pragma vscode_glsllint_stage: vert
132+
133+
layout(location=0) in vec4 aPosition;
134+
layout(location=1) in vec2 aTexCoord;
135+
136+
out vec2 vTexCoord;
137+
138+
void main()
139+
{
140+
gl_Position = aPosition;
141+
vTexCoord = aTexCoord;
142+
}`;
143+
144+
145+
const quadFragmentShaderSource =
146+
`#version 300 es
147+
#pragma vscode_glsllint_stage: frag
148+
149+
precision mediump float;
150+
151+
uniform sampler2D sampler;
152+
153+
in vec2 vTexCoord;
154+
155+
out vec4 fragColor;
156+
157+
void main()
158+
{
159+
fragColor = texture(sampler, vTexCoord);
160+
}`;
161+
162+
const quadProgram = createProgram(gl, quadVertexShaderSource, quadFragmentShaderSource);
163+
164+
const quadData = new Float32Array([
165+
// Pos (xy) // UV coordinate
166+
-1,1, 0,1,
167+
-1,-1, 0,0,
168+
1,1, 1,1,
169+
1,-1, 1,0,
170+
]);
171+
172+
const quadVAO = gl.createVertexArray();
173+
gl.bindVertexArray(quadVAO);
174+
175+
const quadBuffer = gl.createBuffer();
176+
gl.bindBuffer(gl.ARRAY_BUFFER, quadBuffer);
177+
gl.bufferData(gl.ARRAY_BUFFER, quadData, gl.STATIC_DRAW);
178+
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 16, 0);
179+
gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 16, 8);
180+
gl.enableVertexAttribArray(0);
181+
gl.enableVertexAttribArray(1);
182+
183+
gl.bindVertexArray(null);
184+
185+
186+
// Step 5: Initialize the framebuffer
187+
// a) attach the two textures color attachments
188+
// b) attach the depth buffer renderbuffer
189+
// c) tell WebGL which outputs to draw
190+
const fbo = gl.createFramebuffer();
191+
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
192+
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, fragColorTexture, 0);
193+
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.TEXTURE_2D, solidColorTexture, 0);
194+
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, renderbuffer);
195+
196+
gl.drawBuffers([ gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1 ]);
197+
198+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
199+
200+
201+
//PART 2: ANIMATE & RENDER
202+
let angle = 0;
203+
const animate = () => {
204+
angle += 0.05;
205+
206+
// Step 1: Draw the first triangle to the FBO with depth testing enabled
207+
gl.useProgram(triangleProgram);
208+
gl.uniform2f(offsetUniformLocation, Math.cos(angle), Math.sin(angle));
209+
gl.bindVertexArray(triangleVAO);
210+
gl.enable(gl.DEPTH_TEST);
211+
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
212+
213+
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
214+
215+
gl.drawArrays(gl.TRIANGLES, 0, 6);
216+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
217+
gl.disable(gl.DEPTH_TEST);
218+
219+
// Step 2: Draw the quad and pick a texture to render
220+
gl.useProgram(quadProgram);
221+
gl.bindVertexArray(quadVAO);
222+
gl.bindTexture(gl.TEXTURE_2D, fragColorTexture); // fragColorTexture or solidColorTexture
223+
gl.enable(gl.BLEND);
224+
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
225+
gl.disable(gl.BLEND);
226+
gl.bindTexture(gl.TEXTURE_2D, null);
227+
gl.bindVertexArray(null);
228+
229+
requestAnimationFrame(animate);
230+
};
231+
animate();

0 commit comments

Comments
 (0)