medfall

A super great game engine
Log | Files | Refs

commit a1975509aa12e628abcf484bfdaa67635ac6bddf
parent 6370d0a572928bbfd3b8cae8a570dfc4915bbbe6
Author: Michael Savage <mikejsavage@gmail.com>
Date:   Sun Apr 30 13:55:19 +0300

Add a tree and lighting

Diffstat:
linear_algebra.h | 7+++++++
shadow_map.cc | 182+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
2 files changed, 147 insertions(+), 42 deletions(-)
diff --git a/linear_algebra.h b/linear_algebra.h @@ -743,6 +743,13 @@ forceinline m4 m4_view( const v3 & forward, const v3 & right, const v3 & up, con return rotation * m4_translation( -position ); } +forceinline m4 m4_lookat( const v3 & position, const v3 & target, const v3 & world_up ) { + v3 forward = normalize( target - position ); + v3 right = normalize( cross( forward, world_up ) ); + v3 up = normalize( cross( right, forward ) ); + return m4_view( forward, right, up, position ); +} + /* * quat */ diff --git a/shadow_map.cc b/shadow_map.cc @@ -4,14 +4,18 @@ #include "intrinsics.h" #include "linear_algebra.h" #include "renderer.h" +#include "text_renderer.h" #include "log.h" +#include "libs/tinyobjloader/tinyobjloader.h" + 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; @@ -19,20 +23,28 @@ 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 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 * vec4( position, 1.0 ); + gl_Position = VP * M * vec4( position, 1.0 ); } ); @@ -47,7 +59,8 @@ static const char * depth_vert_src = GLSL( void main() { gl_Position = vec4( position, 0.0, 1.0 ); - smooth_position = position; + smooth_position.x = ( position.x + 1.0 ) / 0.2; + smooth_position.y = ( position.y + 1.0 ) / 0.3; } ); @@ -58,61 +71,92 @@ static const char * depth_frag_src = GLSL( 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 + vec2( 1.0, 1.0 ) ) / 2.0; + vec2 texcoord = smooth_position; float Depth = texture( tex, texcoord ).x; Depth = 1.0 - (1.0 - Depth) * 25.0; - screen_colour = vec4( Depth ); + 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() { - gl_Position = VP * vec4( position, 1.0 ); - smooth_light_position = lightVP * vec4( position, 1.0 ); + 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; - out vec4 screen_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 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; + float bias2 = max( bias * ( 1.0 + dot( lightdir, frag_normal ) ), bias / 100 ); + float shadow = point_depth - bias2 <= shadow_depth ? 1.0 : 0.1; if( light_norm.z > 1.0 ) { shadow = 1.0; } - screen_colour = vec4( frag_colour, 1.0 ) * shadow; + + screen_colour = vec4( frag_colour * light_colour * lambert * shadow, 1.0 ); } ); -static v3 light_pos( -0, -5, 10 ); -static v3 light_dir = v3_forward( -45, 90 ); +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 ) { 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 ) ); + m4 I = m4_identity(); + glUniformMatrix4fv( shader == shadow_prog ? shadow_un_m : un_m, 1, GL_FALSE, ( float * ) &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 ) ); + + immediate_aabb( &imm, v3( 3, 3, 0 ), v3( 5, 5, 2 ), v4( 0, 0, 1, 1 ) ); + immediate_aabb( &imm, v3( 3, 0, 0 ), v3( 5, 2, 2 ), v4( 0, 0, 1, 1 ) ); + immediate_aabb( &imm, v3( 3, -3, 0 ), v3( 5, -1, 2 ), v4( 0, 0, 1, 1 ) ); + immediate_aabb( &imm, v3( 3, -6, 0 ), v3( 5, -4, 2 ), v4( 0, 0, 1, 1 ) ); if( draw_light ) { immediate_sphere( &imm, light_pos, 0.1, v4( 1, 1, 1, 1 ) ); @@ -127,13 +171,15 @@ static void draw_scene( Shader shader, bool draw_light = false ) { immediate_triangle( &imm, bl, tr, br, v4( 0.5, 0.5, 0.5, 1.0 ) ); immediate_render( &imm, shader ); -} -static void update_camera( - const GameInput * input, float dt, - v3 position, v3 angles, - v3 * out_position, v3 * out_pitch, m4 * V -) { + 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 ); + + 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; @@ -141,6 +187,7 @@ const u32 SHADOW_HEIGHT = 1024; 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 ); @@ -148,13 +195,16 @@ extern "C" GAME_INIT( game_init ) { 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_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL ); + 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 ); @@ -176,7 +226,7 @@ extern "C" GAME_INIT( game_init ) { game->pitch = 0; game->yaw = 45; - float verts[] = { -1, -1, -1, 1, 1, -1, 1, 1 }; + 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 ); @@ -186,6 +236,41 @@ extern "C" GAME_INIT( game_init ) { glVertexAttribPointer( depth_at_position, 2, GL_FLOAT, GL_FALSE, sizeof( float ) * 2, 0 ); glBindVertexArray( 0 ); glBindBuffer( GL_ARRAY_BUFFER, 0 ); + + { + size_t len; + const u8 * tree_data = file_get_contents( "models/trees/PineTree.obj", &len ); + tinyobj_attrib_t attrib; + tinyobj_shape_t * shapes = NULL; + size_t num_shapes; + tinyobj_material_t * materials = NULL; + size_t num_materials; + int ok = tinyobj_parse_obj( &attrib, &shapes, &num_shapes, &materials, &num_materials, ( const char * ) tree_data, len, TINYOBJ_FLAG_TRIANGULATE ); + + ggprint( "ok = {} num_shapes = {} num_materials = {}\n", ok, num_shapes, num_materials ); + + MEMARENA_SCOPED_CHECKPOINT( &mem->persistent_arena ); + + u32 num_verts = attrib.num_face_num_verts * 3; + array< v3 > colours = memarena_push_array( &mem->persistent_arena, v3, attrib.num_vertices ); + array< s32 > indices = memarena_push_array( &mem->persistent_arena, s32, num_verts ); + + for( v3 & c : colours ) { + c = v3( 0.2, 0.6, 0 ); + } + + for( unsigned int i = 0; i < num_verts; i++ ) { + indices[ i ] = attrib.faces[ i ].v_idx; + } + + MeshConfig mesh_config; + mesh_config.positions = renderer_new_vb( attrib.vertices, attrib.num_vertices * sizeof( attrib.vertices[ 0 ] ) * 3 ); + mesh_config.normals = renderer_new_vb( attrib.normals, attrib.num_vertices * sizeof( attrib.normals[ 0 ] ) * 3 ); + mesh_config.colours = renderer_new_vb( colours.ptr(), colours.num_bytes() ); + mesh_config.indices = renderer_new_ib( indices.ptr(), indices.num_bytes() ); + mesh_config.num_vertices = indices.n; + tree_mesh = renderer_new_mesh( mesh_config ); + } } extern "C" GAME_FRAME( game_frame ) { @@ -218,15 +303,17 @@ extern "C" GAME_FRAME( game_frame ) { 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 { - // TODO: lookat function - v3 lightRight = normalize( cross( light_dir, world_up ) ); - v3 lightUp = normalize( cross( lightRight, light_dir ) ); + v3 target( 0, 0, 0 ); + light_dir = normalize( target - light_pos ); + + m4 lightV = m4_lookat( light_pos, target, world_up ); - 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 ); + const m4 lightP = m4_perspective( 90, ( float ) SHADOW_WIDTH / ( float ) SHADOW_HEIGHT, NEAR_PLANE_DEPTH, 500.0f ); lightVP = lightP * lightV; glUseProgram( prog ); @@ -241,28 +328,33 @@ extern "C" GAME_FRAME( game_frame ) { glUseProgram( 0 ); } + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + // 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 ); - // } + { + 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 ); + } // draw world + bias += ( input->keys[ KEY_EQUALS ] - input->keys[ KEY_MINUS ] ) * 0.00001; + bias = max( bias, 0.0f ); { 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 ); + 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 ); @@ -271,4 +363,10 @@ extern "C" GAME_FRAME( game_frame ) { glUseProgram( 0 ); } + + { + const str< 128 > status( "Frame time: {.1}ms FPS: {.1} bias = {}", + dt * 1000.0f, 1.0f / dt, bias ); + draw_text( status.c_str(), 2.0f, 2.0f, 16.0f ); + } }