MENU
Rendered Texture
By default, WebGL draws on the default color framebuffer, causing the canvas to display the drawing. You may draw on a manually created framebuffer in the memory, without showing the drawing on the canvas. The drawing may then be used as a texture.
To initialize a framebuffer object:
Step 1: Create a framebuffer object. This is done by calling createFramebuffer(). The framebuffer object may be deleted by calling deleteFramebuffer(framebuffer).
Step 2: Prepare a texture object.
Step 3: Prepare a renderbuffer object for the depth buffer.
A renderbuffer object may be created by createRenderbuffer(). (It can be deleted by deleteRenderbuffer().) Then, bind it by calling bindRenderbuffer(gl.RENDERBUFFER, renderbuffer). When the binding is complete, specify the storage parameters by calling renderbufferStorage(gl.RENDERBUFFER, internalformat, width, height).
internalformat | |
DEPTH_COMPONENT16 | This uses the renderbuffer as a depth buffer. |
STENCIL_INDEX8 | This uses the renderbuffer as a stencil buffer. |
RGBA4 | This uses the renderbuffer as a color buffer. Each component has 4 bits. |
RGB5_A1 | This uses the renderbuffer as a color buffer. Each RGB component has 5 bits, and A has 1 bit. |
RGB565 | This uses the renderbuffer as a color buffer. Each RGB component has 5, 6, 5 bits respectively, |
Step 4: Attach the texture object to the framebuffer obect,
First, bind the framebuffer by calling bindFramebuffer(gl.FRAMEBUFFER, framebuffer). Then, set the texture object by calling framebufferTexture2D(gl.FRAMEBUFFER, attachment, textarget, texture, level), where 'attachment' can be 'COLOR_ATTACHMENT0' for a color buffer, or 'DEPTH_ATTACHMENT' for a depth buffer.
Step 5: Attach the renderbuffer object to the framebuffer object.
This is done by calling framebufferRenderbuffer(gl.FRAMEBUFFER, attachment, gl.RENDERBUFFER, renderbuffer), where 'attachment' can be 'COLOR_ATTACHMENT0', 'DEPTH_ATTACHMENT' or 'STENCIL_ATTACHMENT'.
Step 6: Check the configuration of the framebuffer object.
This is done by calling checkFramebufferStatus(gl.FRAMEBUFFER).
Return value for checkFramebufferStatus() |
FRAMEBUFFER_COMPLETE: Correct configuration. |
FRAMEBUFFER_INCOMPLETE_ATTACHMENT: An incomplete framebuffer attachment point. |
FRAMEBUFFER_INCOMPLETE_DEMENSIONS: The width or height of the attachment is different. |
FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: No valid attachment found. |
To draw in the framebuffer object, call:
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
To draw in the default color framebuffer, call:
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
RESETRUNFULL
// /shared/webgl-library.js
function initFramebufferObject(gl, width, height) {
var framebuffer, texture, depthBuffer;
framebuffer = gl.createFramebuffer();
texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
framebuffer.texture = texture;
depthBuffer = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, width, height);
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer);
var e = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
if (gl.FRAMEBUFFER_COMPLETE !== e) {
alert('Frame buffer object is incomplete: ' + e.toString());
return error();
} // Unbind the buffer object
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.bindTexture(gl.TEXTURE_2D, null);
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
return framebuffer;
}
<!DOCTYPE html><html><head>
<script src="/shared/webgl-library.js"></script>
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec4 a_Position;
attribute vec2 a_TexCoord;
varying vec2 v_TexCoord;
void main() {
gl_Position = a_Position;
v_TexCoord = a_TexCoord;
}
</script>
<script id="shader-fs" type="x-shader/x-fragment">
#ifdef GL_ES
precision mediump float;
#endif
uniform sampler2D u_Sampler;
varying vec2 v_TexCoord;
void main() {
gl_FragColor = texture2D(u_Sampler, v_TexCoord);
}
</script>
<script>
function WebGLStart() {
var canvas = document.getElementById('cv');
var gl = canvas.getContext('webgl');
initShaders(gl, "shader-vs", "shader-fs");
img = new Image();
img.onload = function(){
var fbo = draw_in_framebufferObject(gl, img);
draw_in_defaultFramebuffer(gl, fbo.texture);
}
img.src = '/shared/webgl_dog.jpeg';
}
function draw_in_framebufferObject(gl, img){
var n=initVertexBuffers(gl);
var texture = gl.createTexture();
var u_Sampler = gl.getUniformLocation(gl.program, 'u_Sampler');
var fbo = initFramebufferObject(gl, 512, 512);
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.viewport(0, 0, 512, 512);
gl.clearColor(0.7, 0.7, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
loadTexture(gl, n, texture, u_Sampler, img, gl.TEXTURE0, 0);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, n);
return fbo;
}
function draw_in_defaultFramebuffer(gl, texture){
var n=initVertexBuffers(gl);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.viewport(0, 0, 500, 500);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, n);
}
function initVertexBuffers(gl) {
var verticesTexCoords = new Float32Array([ // Vertex coordinate --> Texture coordinate
-0.8, 0.8, 0.0, 1.0,
-0.8, -0.8, 0.0, 0.0,
0.8, 0.8, 1.0, 1.0,
0.8, -0.8, 1.0, 0.0,
]);
var n = 4; // The number of vertices
var vertexTexCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexTexCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, verticesTexCoords, gl.STATIC_DRAW);
var FSIZE = verticesTexCoords.BYTES_PER_ELEMENT;
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE*4, 0);
gl.enableVertexAttribArray(a_Position);
var a_TexCoord=gl.getAttribLocation(gl.program, 'a_TexCoord');
gl.vertexAttribPointer(a_TexCoord, 2, gl.FLOAT, false, FSIZE * 4, FSIZE * 2);
gl.enableVertexAttribArray(a_TexCoord);
return n;
}
</script>
</head>
<body onload="WebGLStart();">
<canvas id="cv" style="border: none;" width="500" height="500"></canvas>
</body></html>
isFramebuffer(fb) returns true if 'fb' is a framebuffer object.
framebufferTexture2D(gl.FRAMEBUFFER, attachment, textarget, texture, level) attaches a texture image to a framebuffer object.
'attachment' can be 'COLOR_ATTACHMENT0', 'DEPTH_ATTACHMENT' or 'STENCIL_ATTACHMENT'.
'textarget' can be 'TEXTURE_2D', 'TEXTURE_CUBE_MAP_POSITIVE{X,Y,Z}' or'TEXTURE_CUBE_MAP_NEGATIVE{X,Y,Z}'.
getFramebufferAttachmentParameter(gl.FRAMEBUFFER, attachment, pname) returns attachment parameters for a framebuffer object.
'attachment' can be 'COLOR_ATTACHMENT0', 'DEPTH_ATTACHMENT' or 'STENCIL_ATTACHMENT'.
'pname' can be
FRAMEBUFFER_ATTACHMENT_OBJECT_{TYPE,NAME},
FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL, or
FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE.
isRenderbuffer(rbf) returns true if 'rbf' is is a renderbuffer object.
getRenderbufferParameter(gl.RENDERBUFFER, pname) returns the paratemeters for a renderbuffer. 'pname' can be
RENDERBUFFER_{WIDTH, HEIGHT, INTERNAL_FORMAT},
RENDERBUFFER_{RED, GREEN, BLUE, ALPHA, DEPTH, STENCIL}_SIZE.