OpenGL Shadows
In a three-dimensional scenario, in order to make the scene look more realistic, you often need to add a shadow to it, OpenGL can use many techniques to achieve the shadow, and one of the very classic implementations is to use a shadow map implementation, in this section we will use a shadow map to achieve a simple scene of the shadow.
Principle
Using shadow maps to implement shading, the principle is to use OpenGL rendering to the map to render the current scene through depth test of the depth value of the slice to a depth map, and then render the object again by depth comparison to determine whether the slice is in the shadow.
Implementation steps
It consists of two steps:
1. Render the scene from the angle of the light source, this time the rendering we don't care what the scene looks like, just to get the depth value of the element and store the depth value in a depth map, which represents the maximum depth of light the light source can reach;
2. Render the scene again from the camera's point of view, while calculating the depth value of the slice in the light source coordinate when the slice is rendered, using this depth value and the depth value of the same element stored in the depth map, if it is less than or equal to the depth value in the depth map, it is not in the shadow or in the shadow.
Code
Creates a depth map, which is attached to the frame cache as a render attachment.
//Create frame Cache
Glgenframebuffers (1,&FBO);
Glbindframebuffer (GL_DRAW_FRAMEBUFFER,FBO);
//create a depth textureGlgentextures (1,&Depthtex); Glbindtexture (Gl_texture_2d,depthtex); Glteximage2d (gl_texture_2d,0, Gl_depth_component,width,height,0, Gl_depth_component, Gl_float, NULL); 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_compare_mode, gl_compare_ref_to_texture); //Gltexparameteri (gl_texture_2d, gl_texture_compare_func,gl_lequal);Gltexparameteri (Gl_texture_2d,gl_texture_wrap_s,gl_clamp_to_edge); Gltexparameteri (Gl_texture_2d,gl_texture_wrap_t,gl_clamp_to_edge); //bindingGlframebuffertexture2d (Gl_draw_framebuffer,gl_depth_attachment,gl_texture_2d,depthtex,0);
The frame cache is bound to store the rendering results in the depth map.
//Render Shadow MapsGlbindframebuffer (GL_DRAW_FRAMEBUFFER,FBO); Glviewport (0,0, Width,height); Glcleardepth (1.0); Glclear (Gl_color_buffer_bit|gl_depth_buffer_bit); //turn on polygon offset to avoid zfighting of deep dataglenable (Gl_polygon_offset_fill); Glpolygonoffset (2.0f,4.0f); //RenderingTshader->Use (); Tshader->setmatrix ("Model", Boxmodelmat.get ()); Glbindvertexarray (Boxvao); Gldrawarrays (Gl_triangles,0, $); Tshader->setmatrix ("Model", Planemodelmat.get ()); Glbindvertexarray (VAO); Gldrawarrays (Gl_triangles,0,6); Gldisable (Gl_polygon_offset_fill);
The shader used to render the shadow map is just the simplest shader, and the slice shader doesn't even do anything.
Shadow.vert
the Core layout (location =0 in vec3 ipos;uniform mat4 model;uniform mat4 lightspace; void Main () { = lightspace * Model * VEC4 (IPos,1.0);}
Shadow.frag
The gl_fragcoord.zvoid main () {;}
You can also release the code of the comment to show the depth of the set element, but it is more efficient when commented out, because the bottom layer will set the depth buffer anyway.
When you finish rendering the shadow map, render the scene again and use the shadow map.
//back to Camera viewGlbindframebuffer (Gl_framebuffer,0); Glviewport (0,0, Width,height); Glclear (Gl_color_buffer_bit|gl_depth_buffer_bit); //draw a scenePlaneshader->Use (); Glbindtexture (GL_TEXTURE_2D,TT); Planeshader->setmatrix ("Model", Boxmodelmat.get ()); Glbindvertexarray (Boxvao); Gldrawarrays (Gl_triangles,0, $); Planeshader-Use (); Glbindtexture (Gl_texture_2d,depthtex); Modelshader->setmatrix ("Model", Planemodelmat.get ()); Glbindvertexarray (VAO); Gldrawarrays (Gl_triangles,0,6); Glbindtexture (gl_texture_2d,0);
Shadow map shader, note in this practice, because only the simplest box is rendered and no textures are used, the default glbindtexture is used to bind the shadow map, but when rendering a complex model, be sure to pay attention to the binding of the shadow map (using multiple textures in the shader).
Plane.vert
#version theCorelayout ( location=0)inchvec3 ipos;layout ( location=1)inchvec2 itexcoords;uniform mat4 model;uniform mat4 view;uniform mat4 proj;uniform mat4 Lightview; outvs_out {vec3 fragpos; VEC4 Fragposlightspace;} Vs_out; outvec2 texcoords;voidMain () {Vs_out.fragpos= VEC3 (Model * VEC4 (IPos,1.0)); Vs_out.fragposlightspace= Lightview * VEC4 (Vs_out.fragpos,1.0); Texcoords=itexcoords; Gl_position= proj * View * model * VEC4 (IPos,1.0);}
Plane.frag
#version theCoreinchvs_out {vec3 fragpos; VEC4 Fragposlightspace;} fs_in;inchvec2 texcoords;uniform sampler2d shadowmap; outVEC4 color;floatshadowcalculation (Vec4 fragposlightspace) {vec3 projcoords= FRAGPOSLIGHTSPACE.XYZ/FRAGPOSLIGHTSPACE.W; Projcoords= Projcoords *0.5+0.5; floatClosestdepth =Texture (Shadowmap, projcoords.xy). R; floatCurrentdepth =projcoords.z; floatShadow = currentdepth > Closestdepth?1.0:0.0; returnShadow;}voidMain () {VEC4 fragposlightspace=Fs_in.fragposlightspace; VEC3 Projcoords= FRAGPOSLIGHTSPACE.XYZ/FRAGPOSLIGHTSPACE.W; Projcoords= Projcoords *0.5+0.5; floatShadow =shadowcalculation (fs_in.fragposlightspace); VEC3 Red= VEC3 (1,0,0); VEC3 Lighting= VEC3 (0.1,0.1,0.1) + (1-shadow) *Red; Color= VEC4 (lighting,1.0);}
Effect
Full code:
Https://github.com/xin-lover/opengl-learn/tree/master/chapter-11-shadow
Linux OpenGL Practice Chapter -11-shadow