polyadvent

A game engine from scratch in C
git clone git://jb55.com/polyadvent
Log | Files | Refs | README

commit 0ff60c40ac67f3bd0b9daa70cafa7b37328dbfdd
parent bf16c6674db2a5dd3cfb23a22b418223502e3c25
Author: William Casarin <jb55@jb55.com>
Date:   Sun, 28 Oct 2018 23:05:41 -0700

shadows working

Diffstat:
MMakefile | 3++-
Metc/shaders/terrain.glsl | 4++++
Metc/shaders/test.f.glsl | 16+++++++++++++++-
Metc/shaders/vertex-color.glsl | 3+++
Asrc/entity.c | 10++++++++++
Msrc/entity.h | 3+++
Msrc/fbo.c | 17++++-------------
Msrc/game.c | 35+++++++++++++++++++----------------
Msrc/game.h | 1+
Msrc/main.c | 14+++++++-------
Msrc/node.c | 4++++
Msrc/node.h | 1+
Msrc/quat.c | 5+++++
Msrc/render.c | 25+++++++++++++++++++++++++
Msrc/render.h | 1+
Msrc/update.c | 35++++++++++++++++++++++++-----------
Msrc/util.c | 10+++++++---
Msrc/util.h | 1+
Msrc/vec3.h | 1+
19 files changed, 137 insertions(+), 52 deletions(-)

diff --git a/Makefile b/Makefile @@ -16,6 +16,7 @@ OBJS += $(SRC)/buffer.o OBJS += $(SRC)/camera.o OBJS += $(SRC)/debug.o OBJS += $(SRC)/delaunay.o +OBJS += $(SRC)/entity.o OBJS += $(SRC)/event.o OBJS += $(SRC)/fbo.o OBJS += $(SRC)/file.o @@ -34,11 +35,11 @@ OBJS += $(SRC)/quat.o OBJS += $(SRC)/render.o OBJS += $(SRC)/shader.o OBJS += $(SRC)/terrain.o +OBJS += $(SRC)/ui.o OBJS += $(SRC)/uniform.o OBJS += $(SRC)/update.o OBJS += $(SRC)/util.o OBJS += $(SRC)/vec3.o -OBJS += $(SRC)/ui.o SRCS=$(OBJS:.o=.c) diff --git a/etc/shaders/terrain.glsl b/etc/shaders/terrain.glsl @@ -7,6 +7,7 @@ in vec3 normal; uniform mat4 world; uniform mat4 mvp; +uniform mat4 depth_mvp; uniform mat4 model_view; uniform mat4 normal_matrix; uniform vec3 camera_position; @@ -16,6 +17,7 @@ uniform vec3 light_intensity; flat out float v_light; flat out vec3 v_color; out vec3 v_ray; +out vec4 shadow_coord; const int nlands = 6; @@ -58,6 +60,7 @@ void main() { vec4 v4_pos = vec4(position, 1.0); gl_Position = mvp * v4_pos; + shadow_coord = depth_mvp * v4_pos; vec3 color = land[0].xyz; @@ -71,6 +74,7 @@ void main() // v_color = vec3(0.2 + position.z*0.05, position.z*0.0095, position.z*0.0001) * 0.5; // v_color = vec3(position.z, position.z, position.z) * 0.005; + v_color = hemispherical(color); v_ray = camera_position - (world * v4_pos).xyz; } diff --git a/etc/shaders/test.f.glsl b/etc/shaders/test.f.glsl @@ -4,14 +4,18 @@ precision mediump float; flat in vec3 v_color; in vec3 v_ray; +in vec4 shadow_coord; out vec4 fragmentColor; uniform vec3 camera_position; uniform bool fog_on; uniform bool diffuse_on; uniform vec3 light_intensity; +uniform vec3 light_dir; uniform mat4 normal_matrix; +uniform sampler2D shadow_map; + vec3 apply_fog(in vec3 rgb, in float distance, in vec3 ray_orig, in vec3 ray_dir) { const float b = 0.00026; const float v = 1.0; @@ -32,7 +36,7 @@ vec3 apply_fog(in vec3 rgb, in float distance, in vec3 ray_orig, in vec3 ray_dir void main() { vec3 light_position = vec3(2.0,1.0,5.0); - + float visibility = 1.0; vec3 color; vec3 frag = v_color; @@ -44,6 +48,16 @@ void main() { else color = frag; + float bias = 0.0009; + float shadow_map_z = texture(shadow_map, shadow_coord.xy).z; + if (light_dir.z > 0.0 && shadow_map_z < shadow_coord.z - bias) { + float factor = 1.0/dot(light_dir, vec3(0.0, 0.0, 1.0)); + visibility = clamp(0.2 * factor, 0.5, 1.0); + + } + + color = color * visibility; + // fragmentColor = vec4(color + diffuse, 1.0); fragmentColor = vec4(color, 1.0); } diff --git a/etc/shaders/vertex-color.glsl b/etc/shaders/vertex-color.glsl @@ -9,6 +9,7 @@ in vec3 color; uniform mat4 world; uniform mat4 mvp; +uniform mat4 depth_mvp; uniform mat4 model_view; uniform mat4 normal_matrix; uniform vec3 camera_position; @@ -19,6 +20,7 @@ flat out float v_light; flat out vec3 v_color; flat out vec3 v_normal; out vec3 v_ray; +out vec4 shadow_coord; // TODO: includes // #include "lighting.glsl" @@ -54,6 +56,7 @@ void main() { vec4 v4_pos = vec4(position, 1.0); gl_Position = mvp * v4_pos; + shadow_coord = depth_mvp * v4_pos; v_color = hemispherical(color); // v_normal = trans_normal.xyz; diff --git a/src/entity.c b/src/entity.c @@ -0,0 +1,10 @@ + +#include "entity.h" +#include "node.h" +#include "model.h" + + +void init_entity(struct entity *ent) { + node_init(&ent->node); + ent->casts_shadows = 0; +} diff --git a/src/entity.h b/src/entity.h @@ -8,7 +8,10 @@ struct entity { struct node node; struct model model; + int casts_shadows; }; +void init_entity(struct entity *); + #endif /* ENTITY_H */ diff --git a/src/fbo.c b/src/fbo.c @@ -19,19 +19,12 @@ int fbo_attach_renderbuffer(struct fbo *fbo, GLuint *rbo = &fbo->attachments[fbo->n_attachments++]; glBindFramebuffer(GL_FRAMEBUFFER, fbo->handle); - check_gl(); glGenRenderbuffers(1, rbo); - check_gl(); glBindRenderbuffer(GL_RENDERBUFFER, *rbo); - check_gl(); glRenderbufferStorage(GL_RENDERBUFFER, internalformat, fbo->width, fbo->height); - check_gl(); glBindRenderbuffer(GL_RENDERBUFFER, 0); - check_gl(); glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, *rbo); - check_gl(); glBindFramebuffer(GL_FRAMEBUFFER, 0); - check_gl(); return *rbo; } @@ -49,18 +42,16 @@ int fbo_attach_texture(struct fbo *fbo, GLint internalformat, GLint format, GLuint *texture = &fbo->attachments[fbo->n_attachments++]; glBindFramebuffer(GL_FRAMEBUFFER, fbo->handle); - check_gl(); glGenTextures(1, texture); - check_gl(); glBindTexture(GL_TEXTURE_2D, *texture); - check_gl(); glTexImage2D(GL_TEXTURE_2D, 0, internalformat, fbo->width, fbo->height, 0, format, type, NULL); - check_gl(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - check_gl(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - check_gl(); + if (attachment == GL_DEPTH_ATTACHMENT) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, *texture, 0); diff --git a/src/game.c b/src/game.c @@ -7,6 +7,7 @@ #include "render.h" #include "util.h" #include "update.h" +#include "entity.h" #include <assert.h> mat4 *cam_init = (float[16]){ @@ -35,6 +36,7 @@ void game_init(struct game *game, int width, int height) { struct node *sun_camera = &res->sun_camera; struct entity *player = &res->player; struct terrain *terrain = &game->terrain; + mat4 *light_dir = res->light_dir; mat4 *light_intensity = res->light_intensity; int ok = 0; @@ -53,11 +55,13 @@ void game_init(struct game *game, int width, int height) { .scale = 1.0 }; + int shadowmap_scale = 1.0; + // default ortho screenspace projection - mat4_ortho(0.0, // left - width, // right - 0.0, // bottom - height, // top + mat4_ortho(-width/2.0 * shadowmap_scale, // left + width/2.0 * shadowmap_scale, // right + -height/2.0 * shadowmap_scale, // bottom + height/2.0 * shadowmap_scale, // top -10000.0, // near 10000.0, // far res->proj_ortho @@ -84,7 +88,7 @@ void game_init(struct game *game, int width, int height) { // FBO STUFF init_fbo(&res->shadow_buffer); - resize_fbos(game, width, height); + resize_fbos(game, width * shadowmap_scale, height * shadowmap_scale); // FBO STUFF END @@ -92,13 +96,16 @@ void game_init(struct game *game, int width, int height) { game->test_resources.diffuse_on = 0; node_init(root); - node_init(&player->node); node_init(camera); node_init(sun_camera); - node_init(&terrain->entity.node); + + init_entity(&terrain->entity); + init_entity(player); + player->casts_shadows = 1; + terrain->entity.casts_shadows = 0; // player init - ok = load_model(&player->model, "pirate-officer"); + ok = load_model(&player->model, "ship"); assert(ok); player->model.shading = SHADING_VERT_COLOR; player->node.label = "player"; @@ -109,20 +116,16 @@ void game_init(struct game *game, int width, int height) { node_attach(&player->node, root); node_attach(camera, &player->node); - node_attach(sun_camera, &player->node); + /* node_attach(sun_camera, root); */ quat_axis_angle(V3(1,0,0), -45, camera->orientation); - quat_axis_angle(V3(1,0,0), 5, sun_camera->orientation); - /* quat_axis_angle(V3(1,0,0), 0, sun_camera->orientation); */ - /* quat_axis_angle(V3(1,0,0), -45, alt_camera->orientation); */ + /* quat_axis_angle(V3(1,0,0), -90, camera->orientation); */ + /* node_rotate(sun_camera, V3(-7.5, 0, 0)); */ + /* node_translate(sun_camera, V3(width/shadowmap_scale, 2000, 0)); */ node_translate(&player->node, V3(terrain->size/2.,terrain->size/2.,0.0)); /* vec3_scale(player->node.scale, 10.0, player->node.scale); */ - /* node_translate(alt_camera, V3(0,60,-100)); */ - - node_translate(sun_camera, V3(width/2.0, height/2.0, 50)); - node_rotate(camera, V3(100, 0, 0)); node_translate(camera, V3(0,-40,20)); /* node_recalc(camera); */ diff --git a/src/game.h b/src/game.h @@ -32,6 +32,7 @@ struct resources { GLint light_dir; GLint light_intensity; GLint mvp; + GLint depth_mvp; GLint normal_matrix; GLint view; GLint fog_on; diff --git a/src/main.c b/src/main.c @@ -43,17 +43,21 @@ int main(void) check_gl(); u32 last = SDL_GetTicks(); + static float depth_mvp[MAT4_ELEMS]; + mat4_id(depth_mvp); struct render_config fbo_render_config = { .draw_ui = 0, .camera = game.test_resources.sun_camera.mat, - .projection = game.test_resources.proj_ortho + .projection = game.test_resources.proj_ortho, + .depth_mvp = depth_mvp }; struct render_config default_config = { .draw_ui = 1, .camera = game.test_resources.camera.mat, - .projection = game.test_resources.proj_persp + .projection = game.test_resources.proj_persp, + .depth_mvp = depth_mvp }; while (1) { @@ -67,11 +71,7 @@ int main(void) struct fbo *fbo = &game.test_resources.shadow_buffer; check_fbo(fbo); bind_fbo(fbo); - - /* glViewport( 0, 0, width, height ); */ - - /* glDrawBuffer(GL_NONE); */ - check_gl(); + /* glDrawBuffer(GL_NONE); */ render(&game, &fbo_render_config); unbind_fbo(&game.test_resources.shadow_buffer); render(&game, &default_config); diff --git a/src/node.c b/src/node.c @@ -115,6 +115,10 @@ void node_attach(struct node *node, struct node *to) { to->children[to->n_children++] = node; } +float *node_pos(struct node *node) { + return &node->mat[M_X]; +} + void node_forward(struct node *node, float *dir) { float movement[3] = {0}; float q[4] = {0}; diff --git a/src/node.h b/src/node.h @@ -19,6 +19,7 @@ struct node { struct node* children[MAX_NODE_CHILDREN]; }; +float *node_pos(struct node *node); int node_recalc(struct node *root); void node_attach(struct node *node, struct node *to); void node_mark_for_recalc(struct node *node); diff --git a/src/quat.c b/src/quat.c @@ -26,6 +26,11 @@ void quat_multiply(quat *a, quat *b, quat *dest) { dest[3] = aw * bw - ax * bx - ay * by - az * bz; } +/* void quat_from_vec3(float *vec3, quat *dest) { */ +/* float angle = atan2(vec3[0], vec3[2]); */ +/* dest[0] = 0; */ +/* dest[1] = 1 * sin(angle/2); */ +/* } */ void quat_axis_angle(float *axis, float angle, quat *dest) { float half_angle = angle / 2.0; diff --git a/src/render.c b/src/render.c @@ -102,6 +102,9 @@ init_gl(struct resources *resources, int width, int height) { resources->uniforms.camera_position = glGetUniformLocation(handle, "camera_position"); + resources->uniforms.depth_mvp = + glGetUniformLocation(handle, "depth_mvp"); + resources->uniforms.light_intensity = glGetUniformLocation(handle, "light_intensity"); @@ -164,6 +167,7 @@ void render (struct game *game, struct render_config *config) { static float view_proj[MAT4_ELEMS] = { 0 }; static float normal_matrix[MAT4_ELEMS] = { 0 }; static float model_view[MAT4_ELEMS] = { 0 }; + static float depth_bias[MAT4_ELEMS] = { 0 }; mat4_id(id); mat4_id(model_view); struct resources *res = &game->test_resources; @@ -180,8 +184,12 @@ void render (struct game *game, struct render_config *config) { , &game->test_resources.player }; + int is_shadow = config->draw_ui == 0; + for (size_t i = 0; i < ARRAY_SIZE(entities); ++i) { struct entity *entity = entities[i]; + if (is_shadow && !entity->casts_shadows) + continue; // TODO this is a bit wonky, refactor this if (i == 0) glUseProgram(game->test_resources.terrain_program.handle); @@ -192,6 +200,22 @@ void render (struct game *game, struct render_config *config) { mat4_inverse(camera, view); mat4_multiply(projection, view, view_proj); + // TODO: use something other than draw_ui to detect shadow map fbo phase + if (is_shadow) { + static const float bias_matrix[] = { + 0.5, 0.0, 0.0, 0.0, + 0.0, 0.5, 0.0, 0.0, + 0.0, 0.0, 0.5, 0.0, + 0.5, 0.5, 0.5, 1.0 + }; + + mat4_multiply(bias_matrix, view_proj, config->depth_mvp); + /* mat4_copy(view_proj, config->depth_mvp); */ + } + else { + glUniformMatrix4fv(res->uniforms.depth_mvp, 1, 0, config->depth_mvp); + } + glUniform3f(res->uniforms.camera_position, camera[M_X], camera[M_Y], @@ -207,6 +231,7 @@ void render (struct game *game, struct render_config *config) { mat4_copy(entity->node.mat, model_view); glUniformMatrix4fv(res->uniforms.mvp, 1, 0, mvp); + glUniformMatrix4fv(res->uniforms.depth_mvp, 1, 0, config->depth_mvp); glUniformMatrix4fv(res->uniforms.model_view, 1, 0, model_view); glUniformMatrix4fv(res->uniforms.world, 1, 0, entity->node.mat); diff --git a/src/render.h b/src/render.h @@ -9,6 +9,7 @@ struct render_config { int draw_ui; float *camera; float *projection; + float *depth_mvp; }; void init_gl(struct resources *resources, int width, int height); diff --git a/src/update.c b/src/update.c @@ -228,23 +228,28 @@ void resize_fbos(struct game *game, int width, int height) { static void day_night_cycle(float n, struct resources *res) { float darkest = 0.25; float val = n; - float roots = sin(val); - float circle = fmod(val, TAU); - float angle = circle/TAU; - float intensity = angle <= 0.5 - ? clamp(roots, darkest, 1.0) - : clamp(-roots * 0.4, darkest, 0.5); + float roots = vec3_dot(res->light_dir, V3(0.0, 0.0, 1.0)); + float intensity = 1.0;//clamp(roots, darkest, 1.0); + float light_pos[3]; - /* printf("intensity %f(%f) angle %f hour %f n %f\n", roots, intensity, angle, */ - /* hour, n); */ + /* float intensity = angle <= 0.5 */ + /* ? clamp(roots, darkest, 1.0) */ + /* : clamp(-roots * 0.4, darkest, 0.5); */ res->light_intensity[0] = intensity; res->light_intensity[1] = intensity; res->light_intensity[2] = intensity; - res->light_dir[0] = -cos(val); - res->light_dir[1] = -sin(val); - res->light_dir[2] = 0.8; + res->light_dir[0] = 0.0; + res->light_dir[1] = sin(val); + res->light_dir[2] = cos(val); + + /* printf("intensity %f(%f) n %f light_dir %f %f\n", roots, intensity, */ + /* n, res->light_dir[0], res->light_dir[1]); */ + + vec3_add(&res->player.node.mat[M_X], res->light_dir, light_pos); + + look_at(light_pos, node_pos(&res->player.node), V3(0, 0, 1.0), res->sun_camera.mat); } void update (struct game *game, u32 dt) { @@ -308,4 +313,12 @@ void update (struct game *game, u32 dt) { n += 0.00001f; node_recalc(root); + + /* look_at(&res->sun_camera.mat[M_X], */ + /* &res->player.node.mat[M_X], */ + /* V3(0,0,-1.0), */ + /* res->sun_camera.mat */ + /* ); */ + + } diff --git a/src/util.c b/src/util.c @@ -67,17 +67,21 @@ void look_at(vec3 *eye, vec3 *target, vec3 *up, mat4 *dest) { dest[0] = x[0]; dest[1] = x[1]; dest[2] = x[2]; - /* dest[3] = -vec3_dot(x, eye); */ + /* dest[3] = vec3_dot(x, eye); */ dest[4] = y[0]; dest[5] = y[1]; dest[6] = y[2]; - /* dest[7] = -vec3_dot(y, eye); */ + /* dest[7] = vec3_dot(y, eye); */ dest[8] = z[0]; dest[9] = z[1]; dest[10] = z[2]; - /* dest[11] = -vec3_dot(z, eye); */ + /* dest[11] = vec3_dot(z, eye); */ + + dest[12] = eye[0]; + dest[13] = eye[1]; + dest[14] = eye[2]; } diff --git a/src/util.h b/src/util.h @@ -18,6 +18,7 @@ #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +void look_at(vec3 *eye, vec3 *target, vec3 *up, mat4 *dest); int clampi(int a, int mina, int maxa); double clamp(double a, double mina, double maxa); double max(double a, double b); diff --git a/src/vec3.h b/src/vec3.h @@ -5,6 +5,7 @@ typedef float vec3; #define V_Y 1 #define V_Z 2 +vec3 *vec3_direction (vec3 *vec, vec3 *vec2, vec3 *dest); vec3 *vec3_scale(vec3 *vec, float val, vec3 *dest); vec3 *vec3_subtract(vec3 *vec, vec3 *vec2, vec3 *dest); vec3 *vec3_cross (vec3 *vec, vec3 *vec2, vec3 *dest);