OpenGL Shadow Map detailed

Source: Internet
Author: User

Since the simulation of the light, there is also the shadow, the shadow is due to the object closer to the light of the object to block the distant objects, resulting in the occlusion of the object to receive less light than the occlusion, so the production of the shadow and the object to the position of the light source, the shadow of a static object can be simulated with a light map, While dynamic shadows are implemented with a shadow cone or shadow map, the Shadow Cone introduces many additional vertices to burden the pipeline, and the most popular shadow simulation method is the shadow map, which has the advantage of storing the object's depth information with a texture rather than introducing additional vertices.

There are several steps to implementing a shadow map:

First, a texture cache is created so that you can then save the world's depth information:

Create the Shadow Map textureglgentextures (1, &shadowmaptextureleft); Glbindtexture (gl_texture_2d, Shadowmaptextureleft); Gltexparameteri (gl_texture_2d, Gl_texture_min_filter, gl_linear); GlTexParameteri (GL_ texture_2d, Gl_texture_mag_filter, gl_linear); Gltexparameteri (gl_texture_2d, gl_texture_wrap_s, GL_CLAMP_TO_EDGE); Gltexparameteri (gl_texture_2d, gl_texture_wrap_t, Gl_clamp_to_edge); Gltexparameteri (GL_TEXTURE_2D, GL_TEXTURE_ Compare_mode_arb, Gl_compare_r_to_texture_arb); Gltexparameteri (gl_texture_2d, Gl_texture_compare_func_arb, GL_ lequal); glteximage2d (gl_texture_2d, 0, Gl_depth_component, shadowmapsize, shadowmapsize,0, GL_DEPTH_COMPONENT, GL_ Unsigned_byte, 0); Glbindtexture (gl_texture_2d, 0);
I've opened two deep textures shadowmaptextureleft and shadowmaptextureright.

The new render target object, FBO,FBO, is similar to a framebuffer, except that the rendered fragment is saved to the other cache instead of the frame buffer on the screen:

Glgenframebuffersext (1, &fboid); Glbindframebufferext (Gl_framebuffer_ext, fboid); Gldrawbuffer (GL_NONE); Glreadbuffer (Gl_none); Glbindframebufferext (Gl_framebuffer_ext, 0);
This side of the Gldrawbuffer (Gl_none), and Glreadbuffer (Gl_none), is to mask the input output of the color, because this FBO is used to write depth information.

Buffer preparation completed.

Then set the light source:

void Changelightpos (float lx,float ly,float LZ) {lightpos.x=lx;lightpos.y=ly;lightpos.z=lz;lightpos.w=0;}

Then set the projection matrix that renders the shadow map:

Calculate Light projection matrixfloat size=128*2;lightprojectionmatrixleft = Ortho (-size-size,size-size,-size*2, SIZE*2,-SIZE*2,SIZE*2);

Here I'm using the directional light, so set the parallel projection.

Then set the view matrix that renders the shadow map, place the viewpoint in the light source position, and position the light vector in the direction:

Lightviewmatrixleft=lookat (Lightpos.x, Lightpos.y, Lightpos.z,cx, CY, cz,0.0f, 1.0f, 0.0f);

Okay , now that the prep work is done, the shadow map is rendered :

    Glbindframebufferext (gl_framebuffer_ext,fboid); Glframebuffertexture2dext (gl_framebuffer_ext,gl_depth_ attachment_ext,gl_texture_2d, Shadowmaptextureleft, 0);//use viewport the same size as the shadow Mapglviewport (0, 0, shad Owmapsize, shadowmapsize);//first Pass-from Light's point of Viewglmatrixmode (gl_projection); GLLOADMATRIXF ( Lightprojectionmatrixleft); Glmatrixmode (Gl_modelview); glloadmatrixf (lightviewmatrixleft);//Draw back faces into The Shadow Mapglcullface (Gl_front); Glclear (gl_depth_buffer_bit);//draw the Scenecallback ();
Attach a depth texture to the FBO, and the next rendered content will be preserved in the depth texture, removing the front side of the mask, as the back of the mask will produce the correct shading.

Then restore the render target and clear the frame buffer contents

    Glbindframebufferext (gl_framebuffer_ext,0);//restore statesglcullface (Gl_back); Glclear (GL_DEPTH_BUFFER_BIT|GL_ Color_buffer_bit);

Then go through normal rendering, resetting the projection and view matrix:

Glviewport (0, 0, windowwidth, windowheight); Glmatrixmode (gl_projection); glloadmatrixf (Cameraprojectionmatrix); Glmatrixmode (Gl_modelview); glloadmatrixf (Cameraviewmatrix);

Pass in a depth texture for a normal rendering:

Glactivetexturearb (Gl_texture1_arb); Glbindtexture (gl_texture_2d, Shadowmaptextureleft); GlActiveTextureARB (GL_ Texture2_arb); Glbindtexture (gl_texture_2d, Shadowmaptextureright); callback (); Glactivetexturearb (GL_TEXTURE1_ARB ); Glbindtexture (gl_texture_2d, 0); Glactivetexturearb (Gl_texture2_arb); Glbindtexture (gl_texture_2d, 0);

For normal rendering, use shadow maps to compare shaders for shadow rendering.

One thing to note is that the fragment depth information in the shadow map is the point in the texture coordinate system, so when we do normal rendering we pass in the view matrix and projection matrix used to render the shadow map, and then make the following transformations:

Shadow Map texture space---space--shadow projection space--World space--model space

The following matrix is then passed to the shader:

Calculate texture matrix for projection//this matrix takes us from eye space to the light's clip space//it is Postmultip Lied by the inverse of the current view matrix when specifying Texgenstatic matrix4x4 Biasmatrix (0.5f, 0.0f, 0.0f, 0.0f,0. 0f, 0.5f, 0.0f, 0.0f,0.0f, 0.0f, 0.5f, 0.0f,0.5f, 0.5f, 0.5f, 1.0f),//bias from [-1, 1] to [0, 1]shadowmatrix=biasmatrix*l Ightprojectionmatrixleft*lightviewmatrixleft;

So the vertex shader can write this:

Uniform mat4 viewmatrix,modelmatrix,normalmatrix;uniform mat4 shadowleftmatrix,shadowrightmatrix;varying vec4 Shadowvertleft,shadowvertright;............shadowvertleft = Shadowleftmatrix * Modelmatrix * GL_VERTEX;    Shadowvertright = Shadowrightmatrix * Modelmatrix * Gl_vertex;viewvertex = VEC3 (Viewmatrix * Modelmatrix * Gl_Vertex); 
   
    gl_position = Gl_projectionmatrix * Viewmatrix * Modelmatrix * GL_VERTEX;  
   

Then divide the incoming shadowvertleft and shadowvertright in the fragment shader by their W coordinate values to get the coordinates of the normally rendered slice in the shadow map coordinate system, and then the depth of the coordinate value (that is, the z value). The depth value in the shadow map is compared with shadow2d, here I stole a lazy, with shadow2dproj do, use Proj function can achieve homogeneous division, that is, the vertex value divided by W.

Fragment Shader writes this:

Uniform Sampler2dshadow texshadowleft,texshadowright;varying vec4 shadowvertleft,shadowvertright; ...... vec4 Texcoordoffset = shadowvertleft;    if (texcoordoffset.x >= 0.0 && texcoordoffset.y >= 0.0 &&        texcoordoffset.x <= 1.0 && Texcoordoffset.y <= 1.0) {       texcoordoffset.z+=bias;    float depth = shadow2dproj (Texshadowleft, texcoordoffset). Z;    if (depth<1.0 && factor>=0.2) factor-= 0.1;if (factor<0.4) factor=0.4;}

The z coordinate of the fragment is added with an offset, for the reason:



The last returned factor value is the shadow value, which multiplies the ambient color to output the fragment.

The final effect is as follows:



It is also possible to filter the depth texture using shaders at the point of rendering the shadow map to produce a penumbra area, where I use the PCF method to process the shadows.

OpenGL Shadow Map detailed

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.