commit aafda17ae65f14ec06b1e6a75467356e82be5c10 parent e04dee260b99690a8f6a4af0fa680fc1e80e5a2c Author: Michael Savage <mikejsavage@gmail.com> Date: Sun Apr 23 16:42:41 +0300 Semi-broken shadow mapping Diffstat:
shadow_map.cc | | | 163 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------- |
diff --git a/shadow_map.cc b/shadow_map.cc @@ -18,31 +18,26 @@ static Shader depth_prog; static GLint depth_at_position; static GLint depth_un_tex; +static Shader shadow_prog; +static GLint shadow_un_vp; +static GLint shadow_un_lightvp; +static GLint shadow_un_shadowmap; + static GLuint fbo; static GLuint tex_depth; static const char * vert_src = GLSL( in vec3 position; - in vec3 colour; - - out vec3 frag_colour; uniform mat4 VP; void main() { gl_Position = VP * vec4( position, 1.0 ); - frag_colour = colour; } ); static const char * frag_src = GLSL( - in vec3 frag_colour; - - out vec4 screen_colour; - - void main() { - screen_colour = vec4( frag_colour, 1.0 ); - } + void main() { } ); static const char * depth_vert_src = GLSL( @@ -71,16 +66,63 @@ static const char * depth_frag_src = GLSL( } ); -static void draw_scene( Shader shader ) { +static const char * shadow_vert_src = GLSL( + in vec3 position; + in vec3 colour; + + uniform mat4 VP; + uniform mat4 lightVP; + + out vec4 smooth_light_position; + out vec3 frag_colour; + + void main() { + gl_Position = VP * vec4( position, 1.0 ); + smooth_light_position = lightVP * vec4( position, 1.0 ); + frag_colour = colour; + } +); + +static const char * shadow_frag_src = GLSL( + in vec4 smooth_light_position; + in vec3 frag_colour; + + out vec4 screen_colour; + + uniform sampler2D shadowmap; + + void main() { + vec3 light_ndc = smooth_light_position.xyz / smooth_light_position.w; + vec3 light_norm = light_ndc * 0.5 + 0.5; + float shadow_depth = texture( shadowmap, light_norm.xy ).r; + float point_depth = light_norm.z; + float bias = 0.005; + float shadow = point_depth - bias <= shadow_depth ? 1.0 : 0.1; + if( light_norm.z > 1.0 ) { + shadow = 1.0; + } + screen_colour = vec4( frag_colour, 1.0 ) * shadow; + } +); + +static v3 light_pos( -0, -5, 10 ); +static v3 light_dir = v3_forward( -45, 90 ); + +static void draw_scene( Shader shader, bool draw_light = false ) { immediate_init( &imm, triangles, ARRAY_COUNT( triangles ) ); immediate_sphere( &imm, v3( 0, 0, 5 ), 3, v4( 1, 0, 0, 1 ) ); immediate_sphere( &imm, v3( -3, 7, 5 ), 2, v4( 0, 1, 0, 1 ) ); - v3 tl( -15, 15, 0 ); - v3 tr( 15, 15, 0 ); - v3 bl( -15, -15, 0 ); - v3 br( 15, -15, 0 ); + if( draw_light ) { + immediate_sphere( &imm, light_pos, 0.1, v4( 1, 1, 1, 1 ) ); + immediate_arrow( &imm, light_pos, light_dir, 0.5, v4( 1, 1, 1, 1 ) ); + } + + v3 tl( -50, 50, 0 ); + v3 tr( 50, 50, 0 ); + v3 bl( -50, -50, 0 ); + v3 br( 50, -50, 0 ); immediate_triangle( &imm, tl, tr, bl, v4( 0.5, 0.5, 0.5, 1.0 ) ); immediate_triangle( &imm, bl, tr, br, v4( 0.5, 0.5, 0.5, 1.0 ) ); @@ -105,13 +147,20 @@ extern "C" GAME_INIT( game_init ) { depth_at_position = glGetAttribLocation( depth_prog, "position" ); depth_un_tex = glGetUniformLocation( depth_prog, "tex" ); + shadow_prog = renderer_new_shader( shadow_vert_src, shadow_frag_src ); + shadow_un_vp = glGetUniformLocation( shadow_prog, "VP" ); + shadow_un_lightvp = glGetUniformLocation( shadow_prog, "lightVP" ); + shadow_un_shadowmap = glGetUniformLocation( shadow_prog, "shadowmap" ); + glGenTextures( 1, &tex_depth ); glBindTexture( GL_TEXTURE_2D, tex_depth ); glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); - glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER ); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER ); + const float border[] = { 1.0f, 1.0f, 1.0f, 1.0f }; + glTexParameterfv( GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border ); glGenFramebuffers( 1, &fbo ); glBindFramebuffer( GL_FRAMEBUFFER, fbo ); @@ -150,6 +199,9 @@ extern "C" GAME_FRAME( game_frame ) { float dpitch = input->keys[ KEY_DOWNARROW ] - input->keys[ KEY_UPARROW ]; float dyaw = input->keys[ KEY_LEFTARROW ] - input->keys[ KEY_RIGHTARROW ]; + dpitch += input->keys[ KEY_K ] - input->keys[ KEY_I ]; + dyaw += input->keys[ KEY_J ] - input->keys[ KEY_L ]; + game->pitch += dpitch * dt * angular_speed; game->yaw += dyaw * dt * angular_speed; @@ -162,30 +214,61 @@ extern "C" GAME_FRAME( game_frame ) { game->pos += right * dt * lr * speed; game->pos.z += dt * dz * speed; - const m4 P = m4_perspective( VERTICAL_FOV, ( float ) WIDTH / ( float ) HEIGHT, NEAR_PLANE_DEPTH, 25.0f ); + const m4 P = m4_perspective( VERTICAL_FOV, ( float ) WIDTH / ( float ) HEIGHT, NEAR_PLANE_DEPTH, FAR_PLANE_DEPTH ); m4 V = m4_view( forward, right, up, game->pos ); m4 VP = P * V; - glUseProgram( prog ); - glUniformMatrix4fv( un_vp, 1, GL_FALSE, ( float * ) &VP ); - - glViewport( 0, 0, SHADOW_WIDTH, SHADOW_HEIGHT ); - glBindFramebuffer( GL_DRAW_FRAMEBUFFER, fbo ); - glClear( GL_DEPTH_BUFFER_BIT ); - draw_scene( prog ); - glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 ); - glViewport( 0, 0, WIDTH, HEIGHT ); - glUseProgram( 0 ); - - glUseProgram( depth_prog ); - glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - glActiveTexture( GL_TEXTURE0 ); - glBindTexture( GL_TEXTURE_2D, tex_depth ); - glUniform1i( depth_un_tex, 0 ); - - glBindVertexArray( screen_vao ); - glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 ); - glBindVertexArray( 0 ); + m4 lightVP; + // fill shadow map + { + // TODO: lookat function + v3 lightRight = normalize( cross( light_dir, world_up ) ); + v3 lightUp = normalize( cross( lightRight, light_dir ) ); + + const m4 lightP = m4_perspective( VERTICAL_FOV, ( float ) SHADOW_WIDTH / ( float ) SHADOW_HEIGHT, NEAR_PLANE_DEPTH, 5000.0f ); + m4 lightV = m4_view( light_dir, lightRight, lightUp, light_pos ); + lightVP = lightP * lightV; + + glUseProgram( prog ); + glUniformMatrix4fv( un_vp, 1, GL_FALSE, ( float * ) &lightVP ); + + glViewport( 0, 0, SHADOW_WIDTH, SHADOW_HEIGHT ); + glBindFramebuffer( GL_DRAW_FRAMEBUFFER, fbo ); + glClear( GL_DEPTH_BUFFER_BIT ); + draw_scene( prog ); + glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 ); + glViewport( 0, 0, WIDTH, HEIGHT ); + glUseProgram( 0 ); + } - glUseProgram( 0 ); + // render shadow map + // { + // glUseProgram( depth_prog ); + // glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + // glActiveTexture( GL_TEXTURE0 ); + // glBindTexture( GL_TEXTURE_2D, tex_depth ); + // glUniform1i( depth_un_tex, 0 ); + // + // glBindVertexArray( screen_vao ); + // glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 ); + // glBindVertexArray( 0 ); + // + // glUseProgram( 0 ); + // } + + // draw world + { + glUseProgram( shadow_prog ); + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + glUniformMatrix4fv( shadow_un_vp, 1, GL_FALSE, ( float * ) &VP ); + glUniformMatrix4fv( shadow_un_lightvp, 1, GL_FALSE, ( float * ) &lightVP ); + + glActiveTexture( GL_TEXTURE0 ); + glBindTexture( GL_TEXTURE_2D, tex_depth ); + glUniform1i( shadow_un_shadowmap, 0 ); + + draw_scene( shadow_prog, true ); + + glUseProgram( 0 ); + } }