Skip to content

Commit 4775d08

Browse files
committed
add framebuffers
1 parent 013629c commit 4775d08

File tree

3 files changed

+109
-2
lines changed

3 files changed

+109
-2
lines changed

toc.hanson

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@
106106
"reference": [
107107
"webgl-attributes.md",
108108
"webgl-texture-units.md",
109+
"webgl-framebuffers.md",
109110
"webgl-readpixels.md",
110111
"webgl-references.md",
111112
],

webgl/lessons/webgl-framebuffers.md

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
2+
Title: WebGL Framebuffers
3+
Description: What are framebuffers in WebGL?
4+
TOC: Framebuffers
5+
6+
This article is meant to try to give you a mental image
7+
of what a framebuffer is in WebGL. Framebuffers come up
8+
as they allow you to [render to a texture](webgl-render-to-texture.html).
9+
10+
A Framebuffer is just a *collection of attachments*. That's it! It is
11+
used to allow rendering to textures and renderbuffers.
12+
13+
You can think of a Framebuffer object like this
14+
15+
```js
16+
class Framebuffer {
17+
constructor() {
18+
this.attachments = new Map(); // attachments by attachment point
19+
}
20+
}
21+
```
22+
23+
And the `WebGLRenderingContext` (the `gl` object) like this
24+
25+
```js
26+
// pseudo code
27+
gl = {
28+
framebuffer: defaultFramebufferForCanvas,
29+
}
30+
```
31+
32+
There are 2 binding points. They are set like this
33+
34+
```js
35+
gl.bindFramebuffer(target, framebuffer) {
36+
framebuffer = framebuffer || defaultFramebufferForCanvas; // if null use canvas
37+
switch (target) {
38+
case: gl.FRAMEBUFFER:
39+
this.framebufferBinding = framebuffer;
40+
break;
41+
default:
42+
... error ...
43+
}
44+
}
45+
```
46+
47+
You can add attachments to a framebuffer via 2 functions, `framebufferTexture2D`,
48+
and `framebufferRenderbuffer`.
49+
50+
We can imagine their implementation to be something like
51+
52+
```js
53+
// pseudo code
54+
gl._getFramebufferByTarget(target) {
55+
switch (target) {
56+
case gl.FRAMEBUFFER:
57+
return this.framebufferBinding;
58+
}
59+
}
60+
gl.framebufferTexture2D(target, attachmentPoint, texTarget, texture, mipLevel) {
61+
const framebuffer = this._getFramebufferByTarget(target);
62+
framebuffer.attachments.set(attachmentPoint, {
63+
texture, texTarget, mipLevel,
64+
});
65+
}
66+
gl.framebufferRenderbuffer(target, attachmentPoint, renderbufferTarget, renderbuffer) {
67+
const framebuffer = this._getFramebufferByTarget(target);
68+
framebuffer.attachments.set(attachmentPoint, {
69+
renderbufferTarget, renderbuffer
70+
});
71+
}
72+
```
73+
74+
If you have and enable the [`WEBGL_draw_buffers`](https://www.khronos.org/registry/webgl/extensions/WEBGL_draw_buffers/)
75+
extension then a `Framebuffer` conceptually expands to this
76+
77+
```js
78+
class Framebuffer {
79+
constructor() {
80+
this.attachments = new Map();
81+
+ this.drawBuffers = [gl.COLOR_ATTACHMENT0, gl.NONE, gl.NONE, gl.NONE, ...];
82+
}
83+
}
84+
```
85+
86+
You can set the drawing buffer array with `gl.drawBuffers` which we can
87+
imagine is implemented like this
88+
89+
```js
90+
// pseudo code
91+
ext.drawBuffersWebGL(drawBuffers) {
92+
const framebuffer = gl._getFramebufferByTarget(gl.FRAMEBUFFER);
93+
for (let i = 0; i > maxDrawBuffers; ++i) {
94+
framebuffer.drawBuffers[i] = i < drawBuffers.length
95+
? drawBuffers[i]
96+
: gl.NONE
97+
}
98+
}
99+
```
100+
101+
The important part is a *framebuffer* is just a simple collection of attachments.
102+
The complications are the restrictions on what those attachments
103+
can be and the combinations that work. For example a floating point texture
104+
attachment can not be rendered to by default. Extensions can enable that like
105+
`WEBGL_color_buffer_float`. Similarly if there is
106+
more than one attachment they must all be the same dimensions.

webgl/lessons/webgl-render-to-texture.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ Rendering to a texture is pretty simple. We create a texture of a certain size
4242
Notice how `data` is `null`. We don't need to supply any data. We just need WebGL to
4343
allocate the texture.
4444

45-
Next we create a framebuffer. A framebuffer is just a collection of attachments. Attachments
46-
are either textures or renderbuffers. We've gone over textures before. Renderbuffers are very similar
45+
Next we create a framebuffer. [A framebuffer is just a collection of attachments](webgl-framebuffers.html).
46+
Attachments are either textures or renderbuffers. We've gone over textures before. Renderbuffers are very similar
4747
to textures but they support formats and options that textures don't support. Also, unlike a texture
4848
you can't directly use a renderbuffer as input to a shader.
4949

0 commit comments

Comments
 (0)