commit 1fd5e48ec77dab6949e13c32dfcc860852224b60 parent d744adf1adf247c5103688e468062d545621198c Author: Michael Savage <mikejsavage@gmail.com> Date: Mon May 15 03:31:21 +0300 First attempt at refactoring the shadow map module to use the new renderer/shaders APIs Diffstat:
renderer.h | | | 6 | +++++- |
shaders.cc | | | 8 | ++++++++ |
shaders.h | | | 3 | +++ |
shaders/debug_render_shadow_map.glsl | | | 31 | +++++++++++++++++++++++++++++++ |
shaders/shadowed_vertex_colours.glsl | | | 82 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
shaders/write_shadow_map.glsl | | | 22 | ++++++++++++++++++++++ |
shadow_map.cc | | | 317 | ++++++++++++++++++++++--------------------------------------------------------- |
diff --git a/renderer.h b/renderer.h @@ -2,7 +2,6 @@ #include "intrinsics.h" #include "linear_algebra.h" -#define GLSL( shader ) "#version 330\n" #shader /* * forward declare things so only the implementation includes the full GL headers @@ -20,6 +19,9 @@ const u32 UB_VS_HOT = 0; const u32 UB_VS_COLD = 1; const u32 UB_FS_HOT = 2; const u32 UB_FS_COLD = 3; +const u32 UB_VIEW = 4; +const u32 UB_MODEL = 5; +const u32 UB_LIGHT_VIEW = 6; const u32 INVALID_SHADER = 0; @@ -173,6 +175,8 @@ enum ClearColourBool { CLEARCOLOUR_DONT, CLEARCOLOUR_DO }; enum ClearDepthBool { CLEARDEPTH_DONT, CLEARDEPTH_DO }; void renderer_begin_frame( ClearColourBool clear_colour = CLEARCOLOUR_DO, ClearDepthBool clear_depth = CLEARDEPTH_DO ); +// TODO +#define renderer_clear renderer_begin_frame VB renderer_new_vb( const void * data = NULL, u32 len = 0, BufferUsage usage = BUFFERUSAGE_STATIC ); void renderer_delete_vb( VB vb ); diff --git a/shaders.cc b/shaders.cc @@ -43,6 +43,14 @@ void shaders_init() { shaders[ SHADER_TERRAIN ].texture_buffer_uniform_names[ 0 ] = "point_light_origins"; shaders[ SHADER_TERRAIN ].texture_buffer_uniform_names[ 1 ] = "point_light_colours"; + shaders[ SHADER_WRITE_SHADOW_MAP ].path = "shaders/write_shadow_map.glsl"; + + shaders[ SHADER_DEBUG_RENDER_SHADOW_MAP ].path = "shaders/debug_render_shadow_map.glsl"; + shaders[ SHADER_DEBUG_RENDER_SHADOW_MAP ].texture_uniform_names[ 0 ] = "tex"; + + shaders[ SHADER_SHADOWED_VERTEX_COLOURS ].path = "shaders/shadowed_vertex_colours.glsl"; + shaders[ SHADER_SHADOWED_VERTEX_COLOURS ].texture_uniform_names[ 0 ] = "shadowmap"; + int failed = hotload_shaders(); if( failed != 0 ) { FATAL( "failed to load shaders" ); diff --git a/shaders.h b/shaders.h @@ -10,6 +10,9 @@ enum ShaderID { SHADER_SHIT, SHADER_TREE, SHADER_TERRAIN, + SHADER_WRITE_SHADOW_MAP, + SHADER_DEBUG_RENDER_SHADOW_MAP, + SHADER_SHADOWED_VERTEX_COLOURS, SHADER_COUNT, }; diff --git a/shaders/debug_render_shadow_map.glsl b/shaders/debug_render_shadow_map.glsl @@ -0,0 +1,31 @@ +uniform sampler2D tex; + +#if VERTEX_SHADER + +in vec2 position; +out vec2 uv; + +void main() { + gl_Position = vec4( position, 0.0, 1.0 ); + uv.x = ( position.x + 1.0 ) / 0.2; + uv.y = ( position.y + 1.0 ) / 0.3; +} + +#else + +in vec2 uv; +out vec4 screen_colour; + +float LinearizeDepth(float depth) +{ + float z = depth * 2.0 - 1.0; // Back to NDC + return (2.0 * 0.1 * 50000.0) / (50000.0 + 0.1 - z * (50000.0 - 0.1)); +} + +void main() { + float Depth = texture( tex, uv ).x; + Depth = 1.0 - (1.0 - Depth) * 25.0; + screen_colour = vec4( vec3( LinearizeDepth( Depth ) ), 1.0 ); +} + +#endif diff --git a/shaders/shadowed_vertex_colours.glsl b/shaders/shadowed_vertex_colours.glsl @@ -0,0 +1,82 @@ +layout( std140 ) uniform model { + mat4 M; +}; + +layout( std140 ) uniform view { + mat4 V; + mat4 P; +}; + +layout( std140 ) uniform light_view { + mat4 lightV; + mat4 lightP; +}; + +layout( std140 ) uniform v_cold { + vec3 light_pos; + float bias; +}; + +uniform sampler2D shadowmap; + +struct VSOut { + vec4 light_space_position; + vec3 position; + vec3 normal; + vec3 colour; +}; + +#if VERTEX_SHADER + +in vec3 position; +in vec3 normal; +in vec3 colour; + +out VSOut v2f; + +void main() { + vec4 world_space = M * vec4( position, 1.0 ); + gl_Position = P * V * world_space; + v2f.light_space_position = lightP * lightV * world_space; + v2f.position = world_space.xyz; + v2f.normal = mat3( M ) * normal; + v2f.colour = colour; +} + +#else + +in VSOut v2f; +out vec4 screen_colour; + +void main() { + vec3 light_colour = vec3( 1.0, 1.0, 1.0 ); + vec3 lightdir = normalize( v2f.position - light_pos ); + + float lambert = max( 0, dot( -lightdir, normalize( v2f.normal ) ) ); + + vec3 light_ndc = v2f.light_space_position.xyz / v2f.light_space_position.w; + vec3 light_norm = light_ndc * 0.5 + 0.5; + float bias2 = max( bias * ( 1.0 + dot( lightdir, v2f.normal ) ), bias / 100 ); + float shadow = 0.1; + + if( light_norm.z > 1.0 ) { + shadow = 1.0; + } + else { + vec2 inv_shadowmap_size = 1.0 / textureSize( shadowmap, 0 ); + for( int x = -1; x <= 1; x++ ) { + for( int y = -1; y <= 1; y++ ) { + vec2 offset = vec2( x, y ) * inv_shadowmap_size; + float shadow_depth = texture( shadowmap, light_norm.xy + offset ).r; + if( light_norm.z - bias2 <= shadow_depth ) { + shadow += 0.1; + } + } + } + } + + screen_colour = vec4( v2f.colour * light_colour * lambert * shadow, 1.0 ); + // screen_colour = screen_colour * 0 + vec4( ( v2f.normal + 1.0 ) / 2.0, 1 ); +} + +#endif diff --git a/shaders/write_shadow_map.glsl b/shaders/write_shadow_map.glsl @@ -0,0 +1,22 @@ +#if VERTEX_SHADER + +in vec3 position; + +layout( std140 ) uniform model { + mat4 M; +}; + +layout( std140 ) uniform light_view { + mat4 V; + mat4 P; +}; + +void main() { + gl_Position = P * V * M * vec4( position, 1.0 ); +} + +#else + +void main() { } + +#endif diff --git a/shadow_map.cc b/shadow_map.cc @@ -4,6 +4,7 @@ #include "intrinsics.h" #include "linear_algebra.h" #include "renderer.h" +#include "shaders.h" #include "text_renderer.h" #include "log.h" @@ -12,154 +13,23 @@ static ImmediateTriangle triangles[ 512000 ]; static ImmediateContext imm; -static GLuint screen_vao, screen_vbo; - -static Shader prog; -static GLint un_m; -static GLint un_vp; - -static Shader depth_prog; -static GLint depth_at_position; -static GLint depth_un_tex; - -static Shader shadow_prog; -static GLint shadow_un_m; -static GLint shadow_un_vp; -static GLint shadow_un_lightvp; -static GLint shadow_un_lightpos; -static GLint shadow_un_shadowmap; -static GLint shadow_un_bias; - -static GLuint fbo; -static GLuint tex_depth; - +static Mesh square; +static UB ub_model; +static UB ub_light_view; +static UB ub_view; +static FB shadow_fb; static Mesh tree_mesh; static float bias = 0.00005; -static const char * vert_src = GLSL( - in vec3 position; - - uniform mat4 M; - uniform mat4 VP; - - void main() { - gl_Position = VP * M * vec4( position, 1.0 ); - } -); - -static const char * frag_src = GLSL( - void main() { } -); - -static const char * depth_vert_src = GLSL( - in vec2 position; - - out vec2 smooth_position; - - void main() { - gl_Position = vec4( position, 0.0, 1.0 ); - smooth_position.x = ( position.x + 1.0 ) / 0.2; - smooth_position.y = ( position.y + 1.0 ) / 0.3; - } -); - -static const char * depth_frag_src = GLSL( - in vec2 smooth_position; - - out vec4 screen_colour; - - uniform sampler2D tex; - - float LinearizeDepth(float depth) - { - float z = depth * 2.0 - 1.0; // Back to NDC - return (2.0 * 0.1 * 50000.0) / (50000.0 + 0.1 - z * (50000.0 - 0.1)); - } - - void main() { - vec2 texcoord = smooth_position; - float Depth = texture( tex, texcoord ).x; - Depth = 1.0 - (1.0 - Depth) * 25.0; - screen_colour = vec4( vec3( LinearizeDepth( Depth ) ), 1.0 ); - } -); - -static const char * shadow_vert_src = GLSL( - in vec3 position; - in vec3 normal; - in vec3 colour; - - uniform mat4 M; - uniform mat4 VP; - uniform mat4 lightVP; - - out vec4 smooth_light_position; - out vec3 frag_position; - out vec3 frag_normal; - out vec3 frag_colour; - - void main() { - vec4 world_space = M * vec4( position, 1.0 ); - gl_Position = VP * world_space; - smooth_light_position = lightVP * world_space; - frag_position = world_space.xyz; - frag_normal = mat3( M ) * normal; - frag_colour = colour; - } -); - -static const char * shadow_frag_src = GLSL( - in vec4 smooth_light_position; - in vec3 frag_position; - in vec3 frag_normal; - in vec3 frag_colour; - - uniform sampler2D shadowmap; - uniform float bias; - uniform vec3 lightpos; - - out vec4 screen_colour; - - void main() { - vec3 light_colour = vec3( 1.0, 1.0, 1.0 ); - vec3 lightdir = normalize( frag_position - lightpos ); - - float lambert = max( 0, dot( -lightdir, normalize( frag_normal ) ) ); - - vec3 light_ndc = smooth_light_position.xyz / smooth_light_position.w; - vec3 light_norm = light_ndc * 0.5 + 0.5; - float bias2 = max( bias * ( 1.0 + dot( lightdir, frag_normal ) ), bias / 100 ); - float shadow = 0.1; - - if( light_norm.z > 1.0 ) { - shadow = 1.0; - } - else { - for( int x = -1; x <= 1; x++ ) { - for( int y = -1; y <= 1; y++ ) { - vec2 offset = vec2( x * 1.0 / 1024.0, y * 1.0 / 1024.0 ); - float shadow_depth = texture( shadowmap, light_norm.xy + offset ).r; - if( light_norm.z - bias2 <= shadow_depth ) { - shadow += 0.1; - } - } - } - } - - screen_colour = vec4( frag_colour * light_colour * lambert * shadow, 1.0 ); - // screen_colour = screen_colour * 0 + vec4( ( frag_normal + 1.0 ) / 2.0, 1 ); - } -); - static v3 light_pos( -0, -10, 15 ); static v3 light_dir = v3_forward( -60, 90 ); -static void draw_scene( Shader shader, bool draw_light = false ) { +static void draw_scene( const RenderState & render_state, bool draw_light = false ) { immediate_init( &imm, triangles, ARRAY_COUNT( triangles ) ); m4 I = m4_identity(); - glUniformMatrix4fv( shader == shadow_prog ? shadow_un_m : un_m, 1, GL_FALSE, ( float * ) &I ); + renderer_ub_easy( render_state.ubs[ UB_MODEL ], I ); immediate_sphere( &imm, v3( 0, 0, 2 ), 2, v4( 1, 0, 0, 1 ) ); immediate_sphere( &imm, v3( -3, 7, 2 ), 2, v4( 0, 1, 0, 1 ) ); @@ -181,72 +51,62 @@ static void draw_scene( Shader shader, bool draw_light = false ) { 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 ) ); - immediate_render( &imm, shader ); + immediate_render( &imm, render_state ); m4 M = m4_translation( v3( -7, -2, 0 ) ) * m4_rotx( deg_to_rad( 90 ) ); - glUniformMatrix4fv( shader == shadow_prog ? shadow_un_m : un_m, 1, GL_FALSE, ( float * ) &M ); + renderer_ub_easy( render_state.ubs[ UB_MODEL ], M ); glCullFace( GL_BACK ); - RenderState render_state; - render_state.shader = shader; renderer_draw_mesh( tree_mesh, render_state ); glCullFace( GL_FRONT ); } -const u32 SHADOW_WIDTH = 1024; -const u32 SHADOW_HEIGHT = 1024; +const u32 SHADOW_SIZE = 1024; + +struct UniformsMVP { + m4 M; + m4 V; + m4 P; +}; + +struct UniformsLightMVP { + m4 M; + m4 light_V; + m4 light_P; +}; extern "C" GAME_INIT( game_init ) { - prog = renderer_new_shader( vert_src, frag_src ); - un_m = glGetUniformLocation( prog, "M" ); - un_vp = glGetUniformLocation( prog, "VP" ); - - depth_prog = renderer_new_shader( depth_vert_src, depth_frag_src ); - 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_m = glGetUniformLocation( shadow_prog, "M" ); - shadow_un_vp = glGetUniformLocation( shadow_prog, "VP" ); - shadow_un_lightvp = glGetUniformLocation( shadow_prog, "lightVP" ); - shadow_un_lightpos = glGetUniformLocation( shadow_prog, "lightpos" ); - shadow_un_shadowmap = glGetUniformLocation( shadow_prog, "shadowmap" ); - shadow_un_bias = glGetUniformLocation( shadow_prog, "bias" ); - - glGenTextures( 1, &tex_depth ); - glBindTexture( GL_TEXTURE_2D, tex_depth ); - glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 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_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 ); - glFramebufferTexture2D( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, tex_depth, 0 ); - glDrawBuffer( GL_NONE ); - glReadBuffer( GL_NONE ); - - ASSERT( glCheckFramebufferStatus( GL_FRAMEBUFFER ) == GL_FRAMEBUFFER_COMPLETE ); - - glBindFramebuffer( GL_FRAMEBUFFER, 0 ); + ub_model = renderer_new_ub(); + ub_light_view = renderer_new_ub(); + ub_view = renderer_new_ub(); + + { + TextureConfig config; + config.width = SHADOW_SIZE; + config.height = SHADOW_SIZE; + config.format = TEXFMT_DEPTH; + config.wrap = TEXWRAP_BORDER; + config.border_colour = v4( 1, 1, 1, 1 ); + shadow_fb = renderer_new_fb( config, FB_DEPTH ); + } game->pos = v3( -10, -10, 5 ); game->pitch = 0; game->yaw = 45; - float verts[] = { -1, -1, -1, -0.7, -0.8, -1, -0.8, -0.7 }; - glGenVertexArrays( 1, &screen_vao ); - glBindVertexArray( screen_vao ); - glGenBuffers( 1, &screen_vbo ); - glBindBuffer( GL_ARRAY_BUFFER, screen_vbo ); - glBufferData( GL_ARRAY_BUFFER, sizeof( verts ), verts, GL_STATIC_DRAW ); - glEnableVertexAttribArray( depth_at_position ); - glVertexAttribPointer( depth_at_position, 2, GL_FLOAT, GL_FALSE, sizeof( float ) * 2, 0 ); - glBindVertexArray( 0 ); - glBindBuffer( GL_ARRAY_BUFFER, 0 ); + { + float verts[] = { + -1.0, -1.0, 0, + -1.0, -0.7, 0, + -0.8, -1.0, 0, + -0.8, -0.7, 0, + }; + MeshConfig config; + config.positions = renderer_new_vb( verts, sizeof( verts ) ); + config.num_vertices = 4; + config.primitive_type = PRIMITIVETYPE_TRIANGLE_STRIP; + square = renderer_new_mesh( config ); + } { size_t len; @@ -270,7 +130,7 @@ extern "C" GAME_INIT( game_init ) { c = v3( 0.2, 0.6, 0 ); } - for( unsigned int i = 0; i < num_verts; i++ ) { + for( u32 i = 0; i < num_verts; i++ ) { indices[ i ] = attrib.faces[ i ].v_idx; } @@ -312,67 +172,64 @@ extern "C" GAME_FRAME( game_frame ) { 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; light_pos = v3( cos( current_time ) * 10, sin( current_time ) * 10, 10 ); - m4 lightVP; - // fill shadow map + renderer_begin_frame(); + + renderer_ub_easy( ub_view, V, P ); + { + m4 lightVP; v3 target( 0, 0, 0 ); light_dir = normalize( target - light_pos ); - + const m4 lightP = m4_perspective( 90, 1, NEAR_PLANE_DEPTH, 500.0f ); m4 lightV = m4_lookat( light_pos, target, world_up ); - const m4 lightP = m4_perspective( 90, ( float ) SHADOW_WIDTH / ( float ) SHADOW_HEIGHT, NEAR_PLANE_DEPTH, 500.0f ); - lightVP = lightP * lightV; + renderer_ub_easy( ub_light_view, lightV, lightP ); + } + + // fill shadow map + { + RenderState render_state; + render_state.shader = get_shader( SHADER_WRITE_SHADOW_MAP ); + render_state.ubs[ UB_MODEL ] = ub_model; + render_state.ubs[ UB_LIGHT_VIEW ] = ub_light_view; + render_state.fb = shadow_fb; + + glViewport( 0, 0, SHADOW_SIZE, SHADOW_SIZE ); - glUseProgram( prog ); - glUniformMatrix4fv( un_vp, 1, GL_FALSE, ( float * ) &lightVP ); + // renderer_clear( CLEARCOLOUR_DONT ); + draw_scene( render_state ); - 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 ); } - glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - // render shadow map { - glUseProgram( depth_prog ); - 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 ); + RenderState state; + state.shader = get_shader( SHADER_DEBUG_RENDER_SHADOW_MAP ); + state.textures[ 0 ] = shadow_fb.texture; + renderer_draw_mesh( square, state ); } // draw world bias += ( input->keys[ KEY_EQUALS ] - input->keys[ KEY_MINUS ] ) * 0.00001; bias = max( bias, 0.0f ); { - glUseProgram( shadow_prog ); - glUniformMatrix4fv( shadow_un_vp, 1, GL_FALSE, ( float * ) &VP ); - glUniformMatrix4fv( shadow_un_lightvp, 1, GL_FALSE, ( float * ) &lightVP ); - - glUniform3f( shadow_un_lightpos, light_pos.x, light_pos.y, light_pos.z ); - glUniform1f( shadow_un_bias, bias ); - - glActiveTexture( GL_TEXTURE0 ); - glBindTexture( GL_TEXTURE_2D, tex_depth ); - glUniform1i( shadow_un_shadowmap, 0 ); - - draw_scene( shadow_prog, true ); - - glUseProgram( 0 ); + RenderState render_state; + // render_state.shader = get_shader( SHADER_SHADOWED_VERTEX_COLOURS ); + render_state.shader = get_shader( SHADER_FLAT_VERTEX_COLOURS ); + render_state.ubs[ UB_MODEL ] = ub_model; + // render_state.ubs[ UB_VIEW ] = ub_view; + render_state.ubs[ UB_VS_HOT ] = ub_view; + // render_state.ubs[ UB_LIGHT_VIEW ] = ub_light_view; + // render_state.textures[ 0 ] = shadow_fb.texture; + + // glUniform3f( shadow_un_lightpos, light_pos.x, light_pos.y, light_pos.z ); + // glUniform1f( shadow_un_bias, bias ); + + draw_scene( render_state, true ); } {