CS452/552; EE465/505 Shadow Mapping in WebGL 4-09 15
Outline! Shadow Mapping in WebGL Switching Shaders Framebuffer Objects (FBO) Read: Angel, Chapter 7: 7.12 Framebuffer Objects WebGL Programming Guide: Chapter 10 Project#2 posted due: April 23rd
Examples: WebGL Programming Guide, Chapter 10 Shadow.html Shadow_highp.html shadow of red triangle cast onto slanted white rectangle same, but uses more precision (fragment shader changed)
Examples: WebGL Programming Guide, Chapter 10 Shadow_highp_sphere.html high precision shadow of red triangle cast onto sphere
Recap: Shadow Mapping Concept! Basic Idea: the pixels seen by the light are lit all other pixels are in shadow
Recap: Shadow Mapping Concept! Two pass algorithm: 1 st pass: render the scene from the light s point of view and remember which pixels the light has seen the result is a shadow map essentially a 2D function indicating the depth of the closest pixels to the light 2 nd pass: render the scene as the camera sees it if we remembered that pixel o gl_fragcolor = ambient+diffuse+specular else o gl_fragcolor = ambient
Visualizing Shadow Mapping source: Mark Killgard, NVIDIA, GDC, 2001
Visualizing Shadow Mapping source: Mark Killgard, NVIDIA, GDC, 2001
Visualizing Shadow Mapping source: Mark Killgard, NVIDIA, GDC, 2001
Visualizing Shadow Mapping source: Mark Killgard, NVIDIA, GDC, 2001
Example1: cast shadow of red triangle shadow of red triangle cast onto slanted white rectangle full program is in Shadow.html and Shadow.js note: there are two vertex shaders and two fragment shaders source: WebGL Programming Guide, Chapter 10
Some techniques we ll need! Switching Shaders How to use different shaders on different objects example program: ProgramObject.js we ll use one set of shaders to generate the shadow map and another set to render the objects! FrameBuffer Objects (FBO) Can create a FBO to save content off-screen example program: FramebufferObject.js we ll use a framebuffer to store the shadow map 12
Example: switching shaders cube on left rendered in a single color with one set of shaders cube on right rendered with a texture image with another set of shaders full program is in ProgramObject.html and ProgramObject.js source: WebGL Programming Guide, Chapter 10
Assign Buffer Object to Attribute Variable JavaScript gl.array_buffer attribute variable gl.enablevertex AttribArray( ) Buffer Object Vertex Shader data repeat for Fragment Shader
Example: Switching Shaders 1. Prepare the shaders to draw an object shaded with a single color 2. Prepare the shaders to draw an object with a texture image 3. Create a program object that has the shaders from step1 with createprogram() 4. Create another program object that has the shaders from step2 with createprogram() 5. Specify the program object created by step 3 with gl.useprogram 6. Enable the buffer object after assigning it to the attribute variables 7. Draw a cube (in a single color) 8. Specify the program object created by step 4 with gl.useprogram 9. Enable the buffer object after assigning it to the attribute variables 10. Draw a cube (texture is pasted) 15
Example: Switching Shaders // ProgramObject.js // vertex shader for a single color var SOLID_VSHADER_SOURCE =... // fragment shader for a single color var SOLID_FSHADER_SOURCE =... // vertex shader for a texture drawing var TEXTURE_VSHADER_SOURCE =... // fragment shader for a texture drawing var TEXTURE_FSHADER_SOURCE =...
Switching shaders, continued function main() { // Initialize shaders var solidprogram = createprogram(gl, SOLID_VSHADER_SOURCE, SOLID_FSHADER_SOURCE); var texprogram = createprogram(gl, TEXTURE_VSHADER_SOURCE, TEXTURE_FSHADER_SOURCE); // Get the variables in the program object for single color solidprogram.a_position = gl.getattriblocation(solidprogram, 'a_position'); solidprogram.a_normal = gl.getattriblocation(solidprogram, a_normal'); // Get the variables in the program object for the texture texprogram.a_position = gl.getattriblocation(texprogram, 'a_position'); texprogram.a_normal = gl.getattriblocation(texprogram, a_normal ); texprogram.u_sampler = gl.getuniformlocation(texprogram, u_sampler ) // set vertex information var cube = initvertexbuffers(gl, solidprogram); // set texture var texture = inittextures(gl, texprogram);
Switching shaders, continued var currentangle = 0.0; var tick = function() { currentangle = animate(currentangle); // Draw the cube in the single color drawsolidcube(gl, solidprogram, cube, -2.0, currentangle, viewprojmatrix); // Draw the cube with texture drawtexcube(gl, texprogram, cube, texture, 2.0, currentangle, viewprojmatrix); window.requestanimationframe(tick, canvas); }; tick(); } // end of main
Switching shaders, continued function initvertexbuffers(gl, program) { var vertices = new Float32Array{[ // vertex coords var normals = new Float32Array{[ // normals var texcoords = new Float32Array{[ // texture coords var indices = new Uint8Array{[ // indices for vertices // use Object to return buffer objects var o = new Object(); // write vertex information to buffer objects o.vertexbuffer = initarraybuffer o.normalbuffer = initarraybuffer o.texcoordbuffer = initarraybuffer o.indexbuffer = initelementarraybuffer } o.numindices = indices.length; return o;
Switching shaders, continued function drawsolidcube(gl, program, o, x, angle, viewprojmatrix) { // use the program object made from the solid shaders gl.useprogram(program); // Assign the buffer objects and enable the assignment initattributevariable(gl, program.a_position, o.vertexbuffer); initattributevariable(gl, program.a_normal, o.normalbuffer); gl.bindbuffer(gl.element_array_buffer, o.indexbuffer); } drawcube(gl, program, o, x, angle, viewprojmatrix);
Switching shaders, continued // Assign the buffer objects and enable the assignment function initattributevariable(gl, a_attribute, buffer{ gl.bindbuffer(gl.array_buffer, buffer); gl.vertexattribpointer(a_attribute, buffer.num, buffer.type, false, 0, 0); } gl.enablevertexattribarray(a_attribute); function drawcube(gl, program, o, x, angle, viewprojmatrix){ // calculate a model matrix // calculate transformation matrix for normal // calculate a model view projection matrix gl.drawelements(gl.triangles, o.numindices, o.indexbuffer.type, 0); }
Switching shaders, continued function drawtexcube(gl, program, o, x, angle, viewprojmatrix){ // use the program object made from the texture shaders gl.useprogram(program); // Assign the buffer objects and enable the assignment initattributevariable(gl, program.a_position, o.vertexbuffer); initattributevariable(gl, program.a_normal, o.normalbuffer); initattributevariable(gl, program.a_texcoord, o.texcoordbufferbuffer); gl.bindbuffer(gl.element_array_buffer, o.indexbuffer); // bind texture object to texture unit 0 gl.activetexture(gl.texture0); gl.bindtexture(gl.texture_2d, texture); } drawcube(gl, program, o, x, angle, viewprojmatrix);
Example: using FrameBuffer objects maps a rotating cube drawn with WebGL to a rectangle as a texture object full program is in FramebufferObject.html and FramebufferObject.js source: WebGL Programming Guide, Chapter 10
Recap: WebGL Frame Buffer (Color buffer) Angel and Shreiner: Interactive Computer Graphics 7E Addison-Wesley 2015
Where are the Buffers?! HTML5 Canvas Default front and back color buffers Under control of local window system Physically on graphics card! Depth buffer also on graphics card! Stencil buffer Holds masks! Most RGBA buffers 8 bits per component! Latest are floating point (IEEE) Angel and Shreiner: Interactive Computer Graphics 7E Addison-Wesley 2015
Framebuffers & Renderbuffers! By default, WebGL draws using a color buffer, and when using hidden surface removal, a depth buffer. The final image is kept in the color buffer.! A framebuffer object is an alternative buffer content drawn in a frame buffer is not directly displayed on the <canvas> can use if you want to perform different types of processing before displaying the drawn content known as offscreen drawing 26
Framebuffer Objects! Framebuffer Objects (FBOs) are buffers that are created by the application Not under control of window system Cannot be displayed Can attach a renderbuffer to a FBO and can render off screen into the attached buffer Attached buffer can then be detached and used as a texture map for an on-screen render to the default frame buffer Angel and Shreiner: Interactive Computer Graphics 7E Addison-Wesley 2015
WebGL System JavaScript function main() { var gl = getwebgl Context initshaders ( ); } per-vertex processing Vertex Shader per-fragment processing Fragment Shader WebGL System Color Buffer
Framebuffer Objects JavaScript function main() { var gl = getwebgl Context initshaders ( ); } per-vertex processing Vertex Shader per-fragment processing Fragment Shader WebGL System Framebuffer Object Color Buffer
Framebuffer Objects! FBO supports substitutes for the color buffer, the depth buffer and stencils Framebuffer Object color attachment depth attachment stencil attachment Texture Object drawing area Texture Object drawing area Renderbuffer Object drawing area Renderbuffer Object drawing area
Framebuffer Objects! WebGL supports two types of attachments: texture objects and renderbuffer objects Framebuffer Object color attachment depth attachment stencil attachment Texture Object drawing area Texture Object drawing area Renderbuffer Object drawing area Renderbuffer Object drawing area
Framebuffer Objects! Note: drawing is not carried out in the framebuffer itself, but in the drawing areas of the attachment Framebuffer Object color attachment depth attachment stencil attachment Texture Object drawing area Texture Object drawing area Renderbuffer Object drawing area Renderbuffer Object drawing area
Framebuffer Objects! To use the content drawn into a framebuffer object as a texture object, need the following configuration Framebuffer Object color attachment depth attachment stencil attachment Texture Object drawing area Renderbuffer Object drawing area
Render-to-Texture (8 Steps) 1. Create a framebuffer object gl.createframebuffer 2. Create a texture object and set its size and parameters gl.createtexture, gl.bindtexture, gl.teximage2d, gl.parameteri 3. Create a renderbuffer object gl.createrenderbuffer 4. Bind the renderbuffer object to the target and set its size gl.bindrenderbuffer, gl.renderbufferstorage
Render-to-Texture Steps (cont) 5. Attach the texture object to the color attachment of the framebuffer object gl.bindframebuffer, gl.framebuffertexture2d 6. Attach the renderbuffer object to the depth attachment of the framebuffer object gl.framebufferrenderbuffer 7. Check whether the frame buffer object is configured correctly gl.checkframebufferstatus 8. Draw using the frame buffer object gl.bindframebuffer
FramebufferObject.js var OFFSCREEN_WIDTH = 2048, OFFSCREEN_HEIGHT = 2048; function main() { var cube = initvertexbuffersforcube(gl); var plane = initvertexbuffersforplane(gl); var texture = inittextures(gl); // Initialize FBO var fbo = initframebufferobject(gl); var viewprojmatrix = // for color buffer var viewprojmatrixfbo = // for FBO
FramebufferObject.js, continued function initframebufferobject(gl) { var framebuffer, texture, depthbuffer; // Create a framebuffer object (FBO) framebuffer = gl.createframebuffer(); // Create a texture object and set its // size and parameters texture = gl.createtexture(); gl.bindtexture(gl.texture_2d, texture); gl.teximage2d(gl.texture_2d, 0, gl.rgba, gl.unsigned_byte, null); gl.texparameteri( // store the texture object in the FBO framebuffer.texture = texture;
FramebufferObject.js, continued // function initframebufferobject, cont. // Create a renderbuffer object and set // its size and parameters depthbuffer = gl.createrenderbuffer(); gl.bindrenderbuffer(gl.renderbuffer, depthbuffer); gl.renderbufferstorage(gl.renderbuffer, gl.depth_component16, OFFSCREEN_WIDTH, OFFSCREEN_HEIGHT); // attach the texture and framebuffer to FBO 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); // check the FBO configuration var e = gl.checkframebufferstatus(gl.framebuffer);
Draw using the framebuffer iobject function draw(gl, canvas, fbo, plane, cube, angle, texture, viewprojmatrix, viewprojmatrixfbo) { gl.bindframebuffer(gl.framebuffer, fbo); gl.viewport(0,0,offscreen_width,offscreen_height); gl.clearcolor gl.clear //color buffer bit and depth buffer bit // draw the cube drawtexturedcube(gl,gl.program,cube,angle,texture, viewprojmatrixfbo); gl.bindframebuffer(gl.framebuffer, null); // detach gl.viewport(0, 0, canvas.width, canvas.height); gl.clearcolor.. gl.clear //color buffer bit and depth buffer bit // draw the plane drawtexturedplane(gl, gl.program, plane, angle, fbo.texture, viewprojmatrix);