From 27b220c1040fa0552a6309fc516d659362f63895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Madar=C3=A1sz?= Date: Fri, 30 Aug 2024 12:19:50 +0200 Subject: [PATCH] pcf improved, yes --- bind/v4k.lua | 11 +- demos/09-shadows.c | 6 +- demos/99-spot.c | 633 ------------------------ engine/art/shaderlib/light.glsl | 2 +- engine/art/shaderlib/shadowmap-old.glsl | 118 ----- engine/art/shaderlib/shadowmap.glsl | 29 +- engine/joint/v4k.h | 48 +- engine/split/v4k_render.c | 37 +- engine/split/v4k_render.h | 4 +- engine/split/v4k_scene.c | 6 +- engine/split/v4k_scene.h | 1 + engine/v4k.c | 43 +- engine/v4k.h | 5 +- 13 files changed, 138 insertions(+), 805 deletions(-) delete mode 100644 demos/99-spot.c delete mode 100644 engine/art/shaderlib/shadowmap-old.glsl diff --git a/bind/v4k.lua b/bind/v4k.lua index b6971a7..f794a2a 100644 --- a/bind/v4k.lua +++ b/bind/v4k.lua @@ -1161,7 +1161,7 @@ typedef struct light_t { unsigned shadow_technique; float shadow_distance; float shadow_bias; - mat44 shadow_matrix[4]; + mat44 shadow_matrix[6]; bool cached; } light_t; light_t light(); @@ -1185,8 +1185,8 @@ typedef struct shadowmap_t { int light_step; int cascade_index; unsigned shadow_technique; - float cascade_splits[4]; - float cascade_distances[4]; + float cascade_splits[6]; + float cascade_distances[6]; bool blur_pcf; float blur_scale; bool skip_render; @@ -1194,7 +1194,7 @@ typedef struct shadowmap_t { struct { unsigned shadow_technique; handle fbos[6], texture, depth_texture; - handle fbo_2d[4], texture_2d[4], depth_texture_2d[4]; + handle fbo_2d[6], texture_2d[6], depth_texture_2d[6]; handle blur_fbo_2d, blur_texture_2d; } maps[MAX_LIGHTS]; handle saved_fb; @@ -1205,7 +1205,7 @@ typedef struct shadowmap_t { void shadowmap_destroy(shadowmap_t *s); void shadowmap_begin(shadowmap_t *s); bool shadowmap_step(shadowmap_t *s); - void shadowmap_light(shadowmap_t *s, light_t *l, float cam_fov, float cam_far, mat44 cam_view); + void shadowmap_light(shadowmap_t *s, light_t *l, mat44 cam_proj, mat44 cam_view); void shadowmap_end(shadowmap_t *s); unsigned shader(const char *vs, const char *fs, const char *attribs, const char *fragcolor, const char *defines); unsigned shader_geom(const char *gs, const char *vs, const char *fs, const char *attribs, const char *fragcolor, const char *defines); @@ -1619,6 +1619,7 @@ typedef struct camera_t { vec3 position, updir, lookdir; float yaw, pitch, roll; float speed, fov; + float near_clip, far_clip; float move_friction, move_damping; float look_friction, look_damping; vec3 last_look; vec3 last_move; diff --git a/demos/09-shadows.c b/demos/09-shadows.c index 9e089ba..0668459 100644 --- a/demos/09-shadows.c +++ b/demos/09-shadows.c @@ -86,8 +86,8 @@ int main(int argc, char** argv) { if( !initialized ) { initialized = 1; sky = skybox(flag("--mie") ? 0 : SKY_DIRS[SKY_DIR], 0); - sm = shadowmap(512, 2048); - // sm.blur_pcf = 0; + sm = shadowmap(512, 4096); + // sm.blur_pcf = 1; mdl = model(OBJ_MDLS[OBJ_MDL], 0); shader_bind(mdl.program); cubemap_sh_shader(&sky.cubemap); @@ -167,7 +167,7 @@ int main(int argc, char** argv) { { for (int i = 0; i < array_count(lights); i++) { while (shadowmap_step(&sm)) { - shadowmap_light(&sm, &lights[i], cam.fov, 2000.0f, cam.view); + shadowmap_light(&sm, &lights[i], cam.proj, cam.view); model_render(mdl, cam.proj, cam.view, mdl.pivot, 0); } } diff --git a/demos/99-spot.c b/demos/99-spot.c deleted file mode 100644 index 2544aef..0000000 --- a/demos/99-spot.c +++ /dev/null @@ -1,633 +0,0 @@ -// [ref] http://fabiensanglard.net/shadowmappingVSM/index.php -// [ref] http://www.opengl-tutorial.org/es/intermediate-tutorials/tutorial-16-shadow-mapping/ -// [ref] https://github.com/cforfang/opengl-shadowmapping -// [ref] https://learnopengl.com/Advanced-Lighting/Shadows/Shadow-Mapping - -// @todo: spotlight (cone light) -// @todo: pointlight (cubemap light) -// @todo: area light (rect or circle light) -// @todo: directional light (sunlight) - -// further reading (in order): -// DPSM [3] Brabec, Annen: Shadow mapping for hemispherical and omnidirectional light sources (2002) -// DPSM* [4] Osman, Bukowski: Practical implementation of dual paraboloid shadow maps (2006) -// IPSM [5] Vanek, Herout: High-quality Shadows with Improved Paraboloid Mapping (2011) -// LiSPSMs -// CSMs - -// status: CUBE(0)+BLUR(0): ok -// status: CUBE(0)+BLUR(1): ok -// status: CUBE(1)+BLUR(1): ok -// status: CUBE(1)+BLUR(0): ok -// status: CUBE(?)+BLUR(?): no { -// 003.470s|!cannot find uniform 'shadowMap' in shader program 21 |shader_uniform|fwk_render.c:772 -// 001: 00007FF7AF6A3FDA callstack (C:\prj\thread\FWK\fwk_system.c:250) -// 002: 00007FF7AF8E7CBC shader_uniform (C:\prj\thread\FWK\fwk_render.c:772) -// 003: 00007FF7AF691C27 shader_int (C:\prj\thread\FWK\fwk_render.c:777) -// 004: 00007FF7AF8F54EF color_begin (C:\prj\thread\FWK\spot.c:525) -// 005: 00007FF7AF8F5BF7 main (C:\prj\thread\FWK\spot.c:607) -// } - -#ifndef VSMCUBE -#define VSMCUBE 0 -#endif -#ifndef VSMBLUR -#define VSMBLUR 1 -#endif - -#include "v4k.h" - -model_t sponza; - -typedef struct Mesh -{ - GLuint vao; - GLuint vbo; -} Mesh; - -static float quadVertices[] = { - // Front-face - // Pos // Color //Tex // Norm - -1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Top-left - 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Top-right - 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // Bottom-right - - 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, // Bottom-right - -1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, //Bottom-left - -1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Top-left -}; - -static Mesh create_mesh(float* verts, int size) { - Mesh mesh; - - // Create VAO - glGenVertexArrays(1, &mesh.vao); - glBindVertexArray(mesh.vao); - - // Create VBO and copy the vertex data to it - glGenBuffers(1, &mesh.vbo); - glBindBuffer(GL_ARRAY_BUFFER, mesh.vbo); - glBufferData(GL_ARRAY_BUFFER, size, verts, GL_STATIC_DRAW); - - // Enable attribs - // Position - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), 0); - // Color - glEnableVertexAttribArray(3); - glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), (void*)(3 * sizeof(float))); - // Texcoords - glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 11 * sizeof(float), (void*)(6 * sizeof(float))); - // Normal - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(float), (void*)(8 * sizeof(float))); - - return mesh; -} - -Mesh create_quad() { - return create_mesh(quadVertices, sizeof(quadVertices)); -} - - - - -/* -#define Mesh model_t -model_t create_cube() { - model_t m = model("#meshes/cube.obj", 0); //MESH_TRIANGLE_STRIP); - return m; -} -*/ -static const char* const vs_shadow_blur = "//" FILELINE "\n" - "in vec3 position;\n" - "in vec2 texcoord;\n" - "out vec2 Texcoord;\n" - - "void main() {\n" - " gl_Position = vec4(position, 1.0);\n" - " Texcoord = texcoord;\n" - "}\n"; - -static const char* const fs_shadow_blur = "//" FILELINE "\n" - "uniform sampler2D textureSource;\n" - "uniform vec2 ScaleU;\n" - - "in vec2 Texcoord;\n" - "out vec4 outColor;\n" - - "void main() {\n" - " vec4 color = vec4(0.0);\n" - " color += texture( textureSource, Texcoord.st + vec2( -3.0*ScaleU.x, -3.0*ScaleU.y ) ) * 0.015625;\n" - " color += texture( textureSource, Texcoord.st + vec2( -2.0*ScaleU.x, -2.0*ScaleU.y ) )*0.09375;\n" - " color += texture( textureSource, Texcoord.st + vec2( -1.0*ScaleU.x, -1.0*ScaleU.y ) )*0.234375;\n" - " color += texture( textureSource, Texcoord.st + vec2( 0.0 , 0.0) )*0.3125;\n" - " color += texture( textureSource, Texcoord.st + vec2( 1.0*ScaleU.x, 1.0*ScaleU.y ) )*0.234375;\n" - " color += texture( textureSource, Texcoord.st + vec2( 2.0*ScaleU.x, 2.0*ScaleU.y ) )*0.09375;\n" - " color += texture( textureSource, Texcoord.st + vec2( 3.0*ScaleU.x, -3.0*ScaleU.y ) ) * 0.015625;\n" - " outColor = vec4(color.xyz, 1.0);\n" - "}\n"; - - - -static const char* const vs_shadow_vsm = "//" FILELINE "\n" - "uniform mat4 model;\n" - "uniform mat4 cameraToShadowView;\n" - "uniform mat4 cameraToShadowProjector;\n" - - "in vec3 position;\n" - "out vec4 v_position;\n" - - "void main() {\n" - " gl_Position = cameraToShadowProjector * model * vec4(position, 1.0);\n" -#if VSMCUBE - " v_position = cameraToShadowView * model * vec4(position, 1.0);\n" -#else - " v_position = gl_Position;\n" -#endif - "}\n"; - -static const char* const fs_shadow_vsm = "//" FILELINE "\n" - "in vec4 v_position;\n" - "out vec4 outColor;\n" - - "void main() {\n" -#if VSMCUBE - " float depth = length( vec3(v_position) ) / 20;\n" -#else - " float depth = v_position.z / v_position.w;\n" - " depth = depth * 0.5 + 0.5;\n" -#endif - - " float moment1 = depth;\n" - " float moment2 = depth * depth;\n" - - " float dx = dFdx(depth);\n" - " float dy = dFdy(depth);\n" - " moment2 += 0.25*(dx*dx+dy*dy);\n" - " outColor = vec4( moment1, moment2, 0.0, 0.0);\n" - "}\n"; - - -struct shadow { - // Resources - GLuint shadowProgram, blurProgram; - Mesh quadMesh; - GLuint shadowMapFBO, shadowMapTex, shadowMapTexDepth; - GLuint blurFBO, blurTex; - // Options - bool do_blur; - bool do_debugshadow; - float BLUR_SCALE; // Amount of blurring [0..100] - GLuint SHADOWMAP_WIDTH; // 256,512,1024,2048 - // State - int shadow_active; - vec3 lightPos; - vec3 lightAimPos; - - // VSM cubemap - GLuint cubeTex, cubeDepthTex, cubeFBOs[6]; - GLuint currentSideTex, currentSideDepthTex; - GLuint toCurrentSideFBO; -} shadow; - -#define shadowProgram shadow.shadowProgram -#define blurProgram shadow.blurProgram -#define quadMesh shadow.quadMesh -#define shadowMapFBO shadow.shadowMapFBO -#define shadowMapTex shadow.shadowMapTex -#define shadowMapTexDepth shadow.shadowMapTexDepth -#define blurFBO shadow.blurFBO -#define blurTex shadow.blurTex -#define do_blur shadow.do_blur -#define do_debugshadow shadow.do_debugshadow -#define BLUR_SCALE shadow.BLUR_SCALE -#define SHADOWMAP_WIDTH shadow.SHADOWMAP_WIDTH -#define shadow_active shadow.shadow_active -#define lightPos shadow.lightPos -#define lightAimPos shadow.lightAimPos -// vsm cubemap -#define cubeTex shadow.cubeTex -#define cubeDepthTex shadow.cubeDepthTex -#define cubeFBOs shadow.cubeFBOs -#define currentSideTex shadow.currentSideTex -#define currentSideDepthTex shadow.currentSideDepthTex -#define toCurrentSideFBO shadow.toCurrentSideFBO - - - -static GLuint cubemap_create(GLsizei size, int flags) { - GLenum texel = flags & TEXTURE_DEPTH ? GL_DEPTH_COMPONENT : GL_RGB32F; - GLenum pixel = flags & TEXTURE_DEPTH ? GL_DEPTH_COMPONENT : GL_RGB; - GLenum storage = flags & TEXTURE_DEPTH ? GL_FLOAT : GL_UNSIGNED_BYTE; // swap? - GLuint id; - glGenTextures(1, &id); - glBindTexture(GL_TEXTURE_CUBE_MAP, id); - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, texel, size, size, 0, pixel, storage, NULL); - glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, texel, size, size, 0, pixel, storage, NULL); - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, texel, size, size, 0, pixel, storage, NULL); - glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, texel, size, size, 0, pixel, storage, NULL); - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, texel, size, size, 0, pixel, storage, NULL); - glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, texel, size, size, 0, pixel, storage, NULL); - if( flags & TEXTURE_DEPTH ) { - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - } else { - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0); - } - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - return id; -} -static void framebuffer_cube_create(GLuint cube_fbo[6], GLuint cube_texture, GLuint cube_texture_depth) { - glGenFramebuffers(6, cube_fbo); - for (int i = 0; i < 6; i++) { - glBindFramebuffer(GL_FRAMEBUFFER, cube_fbo[i]); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, cube_texture, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, cube_texture_depth, 0); - GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (GL_FRAMEBUFFER_COMPLETE != result) { - printf("ERROR: Framebuffer is not complete.\n"); - } - } - glBindFramebuffer(GL_FRAMEBUFFER, 0); -} -static void set_shadow_matrix_uniform(const GLuint program, int dir) { - if(dir<0) return; - mat44 P, V, PV; - perspective44(P, 90.0f, 1.0f, 0.5f, 100.0f); - - /**/ if(dir == 0) lookat44(V, lightPos, add3(lightPos, vec3(+1, 0, 0)), vec3(0, -1, 0)); // +X - else if(dir == 1) lookat44(V, lightPos, add3(lightPos, vec3(-1, 0, 0)), vec3(0, -1, 0)); // -X - else if(dir == 2) lookat44(V, lightPos, add3(lightPos, vec3( 0, +1, 0)), vec3(0, 0, +1)); // +Y - else if(dir == 3) lookat44(V, lightPos, add3(lightPos, vec3( 0, -1, 0)), vec3(0, 0, -1)); // -Y - else if(dir == 4) lookat44(V, lightPos, add3(lightPos, vec3( 0, 0, +1)), vec3(0, -1, 0)); // +Z - else /*dir == 5*/ lookat44(V, lightPos, add3(lightPos, vec3( 0, 0, -1)), vec3(0, -1, 0)); // -Z - multiply44x2(PV, P, V); // -Z - - shader_bind(program); shader_mat44("cameraToShadowView", V); - shader_bind(program); shader_mat44("cameraToShadowProjector", PV); -} - -void shadow_create(int RESOLUTION) { - do_blur = 1; - do_debugshadow = 0; - BLUR_SCALE = 0.5; // Amount of blurring [0..1] - SHADOWMAP_WIDTH = RESOLUTION; // 256,512,1024,2048 - lightPos = vec3(-2, 2.0, -2); - lightAimPos = vec3(0.0, 0, -5.0); - - // Create programs - shadowProgram = shader(vs_shadow_vsm, fs_shadow_vsm, "position", "outColor", 0); - blurProgram = shader(vs_shadow_blur, fs_shadow_blur, "position,,texcoord", "outColor", 0); - - // ShadowMap-textures and FBO // @todo: GL_RG32F+GL_RG also GL_CLAMP to remove artifacts - shadowMapTex = texture_create(SHADOWMAP_WIDTH, SHADOWMAP_WIDTH, 2, NULL, TEXTURE_FLOAT).id; - shadowMapTexDepth = texture_create(SHADOWMAP_WIDTH, SHADOWMAP_WIDTH, 0, NULL, TEXTURE_DEPTH | TEXTURE_FLOAT).id; - shadowMapFBO = fbo(shadowMapTex, shadowMapTexDepth, 0); - - // Textures and FBO to perform blurring - blurTex = texture_create(SHADOWMAP_WIDTH, SHADOWMAP_WIDTH, 2, NULL, TEXTURE_FLOAT).id; - blurFBO = fbo(blurTex, 0, 0); - -#if VSMCUBE - // Create cubemap - cubeTex = cubemap_create(SHADOWMAP_WIDTH, 0); - cubeDepthTex = cubemap_create(SHADOWMAP_WIDTH, TEXTURE_DEPTH); - framebuffer_cube_create(cubeFBOs, cubeTex, cubeDepthTex); - // Temporary storage - currentSideTex = texture_create(SHADOWMAP_WIDTH, SHADOWMAP_WIDTH, 2, NULL, TEXTURE_FLOAT /*| TEXTURE_EDGE*/ ).id; - currentSideDepthTex = texture_create(SHADOWMAP_WIDTH, SHADOWMAP_WIDTH, 0, NULL, TEXTURE_DEPTH | TEXTURE_FLOAT).id; - toCurrentSideFBO = fbo(currentSideTex, currentSideDepthTex, 0); -#endif -} -void shadow_destroy() { - glDeleteProgram(shadowProgram); - glDeleteProgram(blurProgram); - - glDeleteTextures(1, &blurTex); - glDeleteFramebuffers(1, &blurFBO); - - glDeleteTextures(1, &shadowMapTex); - glDeleteTextures(1, &shadowMapTexDepth); - glDeleteFramebuffers(1, &shadowMapFBO); -} -bool shadow_is_active() { - return shadow_active; -} -void shadow_pv_matrix(mat44 PV) { - mat44 P,V; -// perspective44(P, 45.0f, 1.0f, 2.0f, 100.0f); -perspective44(P, 45*2, window_width() / ((float)window_height()+!window_height()), 1.f, 100.f); - - lookat44(V, lightPos, lightAimPos, vec3(0, 1, 0)); // Point toward object regardless of position - multiply44x2(PV, P, V); -} -void shadow_position(vec3 p) { - lightPos = p; -} -void shadow_target(vec3 p) { - lightAimPos = p; -} -void shadow_begin() { - shadow_active = 1; - - // shadow_state() { - glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); - glEnable(GL_CULL_FACE); glCullFace(GL_BACK); - glFrontFace(GL_CW); - glBlendFunc(1, 0); -#if VSMCUBE - glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); -#endif - // } - - glBindFramebuffer(GL_FRAMEBUFFER, shadowMapFBO); - - glViewport(0, 0, SHADOWMAP_WIDTH, SHADOWMAP_WIDTH); - //glClearColor(1.0f, 1.0f, 1.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - mat44 PV; shadow_pv_matrix(PV); - shader_bind(shadowProgram);shader_mat44("cameraToShadowProjector", PV); -} -static void draw_fullscreen_quad() { - //delete_mesh(quadMesh); - if(!quadMesh.vao) quadMesh = create_quad(); - - glBindVertexArray(quadMesh.vao); - glDrawArrays(GL_TRIANGLES, 0, 6); - glBindVertexArray(0); -} -static void shadow_blur() { - // remap 0(min)..1(max) -> 2(min)..epsilon(max) - float blur_scale = 1.999 * (1 - BLUR_SCALE) + 0.001; - - glDisable(GL_DEPTH_TEST); - - // Blur shadowMapTex (horizontally) to blurTex - glBindFramebuffer(GL_FRAMEBUFFER, blurFBO); - glViewport(0, 0, SHADOWMAP_WIDTH, SHADOWMAP_WIDTH); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, shadowMapTex); //Input-texture - shader_bind(blurProgram); shader_vec2("ScaleU", vec2(1.0 / (SHADOWMAP_WIDTH*blur_scale), 0)); - shader_int("textureSource",0); -// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - draw_fullscreen_quad(); - - // Blur blurTex vertically and write to shadowMapTex - glBindFramebuffer(GL_FRAMEBUFFER, shadowMapFBO); - glViewport(0, 0, SHADOWMAP_WIDTH, SHADOWMAP_WIDTH); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, blurTex); - shader_bind(blurProgram); shader_vec2("ScaleU", vec2(0, 1.0 / (SHADOWMAP_WIDTH*blur_scale))); - shader_int("textureSource",0); -// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - draw_fullscreen_quad(); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); - glEnable(GL_DEPTH_TEST); -} -void shadow_end() { - // Reset - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); - - if(do_blur) shadow_blur(); - shadow_active = 0; - - glViewport(0, 0, window_width(), window_height()); -} -void shadow_ui() { - // UI - if( ui_panel("Shadow", 0) ) { - if(ui_toggle("Debug", &do_debugshadow)) {} - if(ui_toggle("Blur shadow", &do_blur)) {} - if(ui_slider("Blur amount", &BLUR_SCALE)) {} - ui_panel_end(); - } - - if(do_debugshadow) { - // Blur and draw to screen - shader_bind(blurProgram); shader_vec2("ScaleU", vec2(0, 0)); // ... but make sure we don't actually blur - glBindTexture(GL_TEXTURE_2D, shadowMapTex); - draw_fullscreen_quad(); - glBindTexture(GL_TEXTURE_2D, 0); - } -} - -#define USER_DRAWCALL(shader) do { \ - model_render(sponza, camera_get_active()->proj, camera_get_active()->view, sponza.pivot, shader); \ -} while(0) - - -static void vsm_cube_draw() -{ - glViewport(0, 0, SHADOWMAP_WIDTH, SHADOWMAP_WIDTH); - - glClearColor(1.0f, 1.0f, 1.0f, 1.0f); - shader_bind(shadowProgram); - - // For each side of cubemap - for (int i = 0; i < 6; ++i) { -#if VSMBLUR - // Draw to temp. storage - shader_bind(shadowProgram); - glBindFramebuffer(GL_FRAMEBUFFER, toCurrentSideFBO); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - set_shadow_matrix_uniform(shadowProgram, i); - USER_DRAWCALL(shadowProgram); - - // Blur horizontally to blurTex - glDisable(GL_DEPTH_TEST); - - shader_bind(blurProgram); - shader_vec2("ScaleU", vec2(1.0 / SHADOWMAP_WIDTH, 0)); - - glBindFramebuffer(GL_FRAMEBUFFER, blurFBO); - glBindTexture(GL_TEXTURE_2D, currentSideTex); - glClear(GL_COLOR_BUFFER_BIT); - draw_fullscreen_quad(); - - // Blur vertically to actual cubemap - glBindFramebuffer(GL_FRAMEBUFFER, cubeFBOs[i]); - - glBindTexture(GL_TEXTURE_2D, blurTex); - shader_bind(blurProgram); - shader_vec2("ScaleU", vec2(0, 1.0 / SHADOWMAP_WIDTH)); - - draw_fullscreen_quad(); - - glEnable(GL_DEPTH_TEST); -#else - // Draw directly to cubemap - glBindFramebuffer(GL_FRAMEBUFFER, cubeFBOs[i]); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - set_shadow_matrix_uniform(shadowProgram, i); - USER_DRAWCALL(shadowProgram); -#endif - } - - // Reset state - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glBindTexture(GL_TEXTURE_2D, 0); -} - -#undef shadowProgram -#undef blurProgram -#undef quadMesh -#undef shadowMapFBO -#undef shadowMapTex -#undef shadowMapTexDepth -#undef blurFBO -#undef blurTex -#undef do_blur -#undef do_debugshadow -#undef BLUR_SCALE -#undef SHADOWMAP_WIDTH -#undef shadow_active -#undef lightPos -#undef lightAimPos - - - - - -// Geometry (world coordinates) -static bool do_animate = 1; - -static void color_begin(const GLuint program) { - glCullFace(GL_BACK); - -#if 1 // VSMCUBE -glViewport(0, 0, window_width(), window_height()); -glClearColor(0.5f, 0.5f, 0.5f, 1.0f); -glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -#endif - - // Upload uniforms - shader_bind(program); - shader_mat44("view", camera_get_active()->view); -// shader_mat44("proj", camera_get_active()->proj); - shader_vec3("lightPos", shadow.lightPos); - -#if VSMCUBE - set_shadow_matrix_uniform(program, -1); -#else - mat44 PV; shadow_pv_matrix(PV); - shader_mat44("cameraToShadowProjector", PV); -#endif - - glActiveTexture(GL_TEXTURE0+1); -#if VSMCUBE - glBindTexture(GL_TEXTURE_CUBE_MAP, cubeTex); -#else - glBindTexture(GL_TEXTURE_2D, shadow.shadowMapTex); //Input-texture -#endif - shader_int("shadowMap",1); -} -static void color_end() { -#if VSMCUBE - glBindTexture(GL_TEXTURE_CUBE_MAP, 0); -#else - glBindTexture(GL_TEXTURE_2D, 0); -#endif -} - - -int main(int argc, char **argv) -{ - window_create(0.75f, 0); - - camera_t cam = camera(); - - // init shadowing 384x384 // 512x512 - shadow_create(argc > 1 ? atoi(argv[1]) : 384); - - sponza = model("sponza.obj", 0); - translation44(sponza.pivot, 0,-1,0); - rotate44(sponza.pivot, -90,1,0,0); - scale44(sponza.pivot, 10,10,10); - - model_t suzanne = model("suzanne.obj", 0); - - // create geometry - GLuint vsm_program = sponza.iqm->program; - #if 1 - const char *tpl[] = { - "{{include-shadowmap}}", fs_0_0_shadowmap_lit, - }; - vsm_program = shader(strlerp(1,tpl,vs_323444143_16_332_model), strlerp(1,tpl,fs_32_4_model), "att_position,att_texcoord,att_normal", "fragColor"); - #endif - - while (window_swap()) - { - // input - if (input(KEY_ESC)) - break; - - // fps camera - bool active = ui_active() ? 0 : input(MOUSE_L) || input(MOUSE_M) || input(MOUSE_R); - vec3 wasdec = scale3( vec3(input(KEY_D)-input(KEY_A),input(KEY_E)-input(KEY_C),input(KEY_W)-input(KEY_S)), 0.2f); - vec2 mouse = scale2( vec2(input_diff(MOUSE_X), -input_diff(MOUSE_Y)), 0.2f * active); - camera_move(&cam, wasdec.x,wasdec.y,wasdec.z); - camera_fps(&cam, mouse.x,mouse.y); - window_cursor( !active ); - -#if 1 - // animate light - if( do_animate ) { - static vec3 lightPos; - do_once { - lightPos = cam.position; - }; - vec3 offs = vec3(sin(window_time()) * 15, 0, cos(window_time()) * 15); - shadow_position(add3(lightPos, offs)); -// shadow_target(vec3(0,0,0)); // good for pointlight - shadow_target(add3(add3(lightPos, offs), vec3(0,0,-1))); - } -#else - shadow_position(cam.position); - shadow_target(add3(cam.position, cam.look)); -#endif - - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - // render - -#if VSMCUBE - shadow_begin(); - vsm_cube_draw(); - shadow_end(); -#else - shadow_begin(); - model_render(sponza, camera_get_active()->proj, camera_get_active()->view, sponza.pivot, shadow.shadowProgram); //< typo!, but works! - shadow_end(); -#endif - - color_begin(vsm_program); - model_render(sponza, camera_get_active()->proj, camera_get_active()->view, sponza.pivot, vsm_program); // does not work without program - color_end(); - - - // light bulb (suzanne) - { - mat44 M; scaling44(M, 10,10,10); relocate44(M, shadow.lightPos.x, shadow.lightPos.y, shadow.lightPos.z ); - model_render(suzanne, camera_get_active()->proj, camera_get_active()->view, M, 0); - } - - - if( ui_panel("App", 0) ) { - if(ui_toggle("Animate light", &do_animate)) {} - ui_panel_end(); - } - - shadow_ui(); - } -} diff --git a/engine/art/shaderlib/light.glsl b/engine/art/shaderlib/light.glsl index 2f9d36b..570f284 100644 --- a/engine/art/shaderlib/light.glsl +++ b/engine/art/shaderlib/light.glsl @@ -5,7 +5,7 @@ uniform int u_num_lights; -#define NUM_SHADOW_CASCADES 4 +#define NUM_SHADOW_CASCADES 6 struct light_t { int type; diff --git a/engine/art/shaderlib/shadowmap-old.glsl b/engine/art/shaderlib/shadowmap-old.glsl deleted file mode 100644 index 8be434c..0000000 --- a/engine/art/shaderlib/shadowmap-old.glsl +++ /dev/null @@ -1,118 +0,0 @@ -// WIP -#ifndef SHADOWMAP_GLSL -#define SHADOWMAP_GLSL - -// uniform mat4 view = mat4(1.0); -uniform vec3 lightPos; /// set:1,1,1 -uniform float doTexture; /// set:1 -#ifdef VSMCUBE -uniform samplerCube shadowMap; // VSMCUBE -#else -uniform sampler2D shadowMap; // !VSMCUBE -#endif - - -struct light { - vec3 position; // world-space - vec4 diffuse; - vec4 specular; - float constantAttenuation, linearAttenuation, quadraticAttenuation; - }; - - light light0 = light( - vec3(1,1,1), // lightPos - vec4(1,1,1,1), // diffuse - vec4(1,1,1,1), // specular - 1.0, 0.0, 0.0 // attenuation (const, linear, quad) - ); - - // From http://fabiensanglard.net/shadowmappingVSM/index.php - #ifdef VSMCUBE - float chebyshevUpperBound(float distance, vec3 dir) { - distance = distance/20 ; - vec2 moments = texture(shadowMap, dir).rg; - #else - float chebyshevUpperBound(float distance, vec4 scPostW) { - vec2 moments = texture(shadowMap,scPostW.xy).rg; - #endif - // Surface is fully lit. as the current fragment is before the light occluder - if (distance <= moments.x) - return 1.0; - - // The fragment is either in shadow or penumbra. We now use chebyshev's upperBound to check - // How likely this pixel is to be lit (p_max) - float variance = moments.y - (moments.x*moments.x); - //variance = max(variance, 0.000002); - variance = max(variance, 0.00002); - - float d = distance - moments.x; - float p_max = variance / (variance + d*d); - - return p_max; - } - - - vec4 shadowmap(in vec4 vpeye, in vec4 vneye, in vec2 uv, in vec4 sc) { - #ifndef VSMCUBE - return vec4(1.); - #else - vec3 fragment = vec3(vpeye); - vec3 normal = vec3(normalize(vneye)); - vec3 viewDir = normalize(-fragment); - - // Lighting - // Convert to eye-space - vec3 light = vec3(view * vec4(light0.position, 1.0)); - - #ifdef VSMCUBE - // Vectors - vec3 fragmentToLight = light - fragment; - vec3 fragmentToLightDir = normalize(fragmentToLight); - - // Shadows - vec4 fragmentToLight_world = inverse(view) * vec4(fragmentToLightDir, 0.0); - float shadowFactor = chebyshevUpperBound(length(fragmentToLight), -fragmentToLight_world.xyz); - #else - // Shadows - vec4 scPostW = sc / sc.w; - scPostW = scPostW * 0.5 + 0.5; - - float shadowFactor = 1.0; // Not in shadow - - bool outsideShadowMap = sc.w <= 0.0f || (scPostW.x < 0 || scPostW.y < 0) || (scPostW.x >= 1 || scPostW.y >= 1); - if (!outsideShadowMap) { - shadowFactor = chebyshevUpperBound(scPostW.z, scPostW); - } - #endif - - vec4 diffColor = vec4(1,1,1,1); - #ifdef VSMCUBE - if(doTexture != 0) diffColor = vec4(vec3(texture(shadowMap, -fragmentToLight_world.xyz).r), 1.0); - #else - if(doTexture != 0) diffColor = vec4(vec3(texture(shadowMap, vec2(uv.x, 1.0 - uv.y)).r), 1.0); - #endif - - #if 1 - vec3 positionToLight = light - fragment; - vec3 lightDir = normalize(positionToLight); - - // Angle between fragment-normal and incoming light - float cosAngIncidence = dot(lightDir, normal); - cosAngIncidence = clamp(cosAngIncidence, 0, 1); - - float attenuation = 1.0f; - attenuation = 1.0 / (light0.constantAttenuation + light0.linearAttenuation * length(positionToLight) + light0.quadraticAttenuation * pow(length(positionToLight),2)); - - vec4 diffuse = diffColor * light0.diffuse * cosAngIncidence * attenuation; - - vec4 total_lighting; - total_lighting += vec4(0.1, 0.1, 0.1, 1.0) * diffColor; // Ambient - total_lighting += diffuse * shadowFactor; // Diffuse - #else - vec4 total_lighting = diffColor; - #endif - return vec4(clamp(vec3(total_lighting), 0., 1.), 1.0); - #endif - } - -#endif \ No newline at end of file diff --git a/engine/art/shaderlib/shadowmap.glsl b/engine/art/shaderlib/shadowmap.glsl index ea20217..bcc05fc 100644 --- a/engine/art/shaderlib/shadowmap.glsl +++ b/engine/art/shaderlib/shadowmap.glsl @@ -1,3 +1,5 @@ +#include "utils.glsl" + in vec4 vpeye; in vec4 vneye; uniform bool u_shadow_receiver; @@ -6,6 +8,8 @@ uniform float u_cascade_distances[NUM_SHADOW_CASCADES]; uniform samplerCube shadowMap[MAX_LIGHTS]; uniform sampler2D shadowMap2D[MAX_LIGHTS * NUM_SHADOW_CASCADES]; +const float bias_modifier[NUM_SHADOW_CASCADES] = float[NUM_SHADOW_CASCADES](0.95, 0.35, 0.20, 0.15, 0.15, 0.15); + //// From http://fabiensanglard.net/shadowmappingVSM/index.php float shadow_vsm(float distance, vec3 dir, int light_index) { distance = distance/20; @@ -59,26 +63,33 @@ float shadow_pcf(float distance, vec3 lightDir, int light_index) { // Calculate bias vec3 normal = normalize(vneye.xyz); float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005); - const float bias_modifier = 0.45; - if (cascade_index == NUM_SHADOW_CASCADES-1) { - bias *= 1 / (u_cascade_distances[NUM_SHADOW_CASCADES-1] * bias_modifier); - } else { - bias *= 1 / (u_cascade_distances[cascade_index] * bias_modifier); - } - + bias *= 1 / (u_cascade_distances[cascade_index] * bias_modifier[cascade_index]); + // PCF float shadow = 0.0; vec2 texelSize = 1.0 / textureSize(shadowMap2D[index], 0); + +#if 1 for(int x = -3; x <= 3; ++x) { for(int y = -3; y <= 3; ++y) + { + float pcfDepth = texture(shadowMap2D[index], projCoords.xy + vec2(x, y) * texelSize * (rand(vec2(projCoords.x + x, projCoords.y + y))*0.75f + 0.25f)).r; + shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0; + } + } + shadow /= 36.0; +#else + for(int x = -1; x <= 1; ++x) + { + for(int y = -1; y <= 1; ++y) { float pcfDepth = texture(shadowMap2D[index], projCoords.xy + vec2(x, y) * texelSize).r; shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0; } } - shadow /= 36.0; - + shadow /= 9.0; +#endif return 1.0 - shadow; } diff --git a/engine/joint/v4k.h b/engine/joint/v4k.h index 9787ecc..34e82a4 100644 --- a/engine/joint/v4k.h +++ b/engine/joint/v4k.h @@ -17267,7 +17267,7 @@ enum SHADOW_TECHNIQUE { SHADOW_PCF, }; -#define NUM_SHADOW_CASCADES 4 +#define NUM_SHADOW_CASCADES 6 typedef struct light_t { char type; @@ -17351,7 +17351,7 @@ API void shadowmap_destroy(shadowmap_t *s); API void shadowmap_begin(shadowmap_t *s); API bool shadowmap_step(shadowmap_t *s); -API void shadowmap_light(shadowmap_t *s, light_t *l, float cam_fov, float cam_far, mat44 cam_view); //< can be called once per shadowmap_step +API void shadowmap_light(shadowmap_t *s, light_t *l, mat44 cam_proj, mat44 cam_view); //< can be called once per shadowmap_step API void shadowmap_end(shadowmap_t *s); // ----------------------------------------------------------------------------- @@ -17971,6 +17971,7 @@ typedef struct camera_t { vec3 position, updir, lookdir; float yaw, pitch, roll; // mirror of (x,y) lookdir in deg; float speed, fov; // fov in deg(45) + float near_clip, far_clip; float move_friction, move_damping; float look_friction, look_damping; @@ -383431,12 +383432,14 @@ shadowmap_t shadowmap(int vsm_texture_width, int pcf_texture_width) { // = 512, s.vsm_texture_width = vsm_texture_width; s.pcf_texture_width = pcf_texture_width; s.saved_fb = 0; - s.blur_pcf = true; + s.blur_pcf = false; s.blur_scale = 0.5f; s.cascade_splits[0] = 0.1f; s.cascade_splits[1] = 0.3f; s.cascade_splits[2] = 0.5f; - s.cascade_splits[3] = 1.0f; + s.cascade_splits[3] = 0.7f; + s.cascade_splits[5] = 1.0f; + s.cascade_splits[6] = 1.0f; /* sticks to camera far plane */ glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &s.saved_fb); @@ -383614,10 +383617,21 @@ static void shadowmap_light_directional(shadowmap_t *s, light_t *l, int dir, flo maxZ = max(maxZ, corner.z); } +#if 0 + float tmpZ = -minZ; + minZ = -maxZ; + maxZ = tmpZ; + + float mid = (maxZ + minZ) * 0.5f; + minZ -= mid * 5.0f; + maxZ += mid * 5.0f; +#endif + mat44 P, PV; ortho44(P, minX, maxX, minY, maxY, + // minZ, maxZ); -maxZ, -minZ); multiply44x2(PV, P, V); @@ -383738,10 +383752,20 @@ void shadowmap_clear_fbo() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } -void shadowmap_light(shadowmap_t *s, light_t *l, float cam_fov, float cam_far, mat44 cam_view) { +void shadowmap_light(shadowmap_t *s, light_t *l, mat44 cam_proj, mat44 cam_view) { if (l->cast_shadows) { int step = s->step - 1; + float y_scale = cam_proj[5]; + float cam_fov = (2.0f * atan(1.0f / y_scale)) * TO_DEG; + float cam_far = 0.0f; { + float m22 = cam_proj[10]; + float m32 = cam_proj[14]; + float near_plane = -m32 / (m22 + 1.0f); + cam_far = (2.0f * near_plane) / (m22 - 1.0f); + cam_far *= 0.5f; + } + if (l->type == LIGHT_POINT) { shadowmap_light_point(s, l, step); } else if (l->type == LIGHT_SPOT) { @@ -386588,12 +386612,10 @@ void model_set_renderstates(model_t *m) { // Shadow pass renderstate_t *pcf_shadow_rs = &m->rs[RENDER_PASS_SHADOW_PCF]; { - pcf_shadow_rs->blend_enabled = 1; - pcf_shadow_rs->blend_src = GL_SRC_ALPHA; - pcf_shadow_rs->blend_dst = GL_ONE_MINUS_SRC_ALPHA; + pcf_shadow_rs->blend_enabled = 0; pcf_shadow_rs->cull_face_enabled = 1; - pcf_shadow_rs->cull_face_mode = GL_FRONT; - pcf_shadow_rs->front_face = GL_CCW; + pcf_shadow_rs->cull_face_mode = GL_BACK; + pcf_shadow_rs->front_face = GL_CW; pcf_shadow_rs->depth_clamp_enabled = 1; } @@ -388714,6 +388736,8 @@ camera_t camera() { cam.fov = 45; cam.orthographic = false; cam.distance = 3; // len3(cam.position); + cam.near_clip = 0.1f; + cam.far_clip = 1000.f; cam.damping = false; cam.move_friction = 0.09f; @@ -388810,12 +388834,12 @@ void camera_fov(camera_t *cam, float fov) { cam->fov = fov; if( cam->orthographic ) { - ortho44(cam->proj, -cam->fov * aspect, cam->fov * aspect, -cam->fov, cam->fov, 0.01f, 2000); + ortho44(cam->proj, -cam->fov * aspect, cam->fov * aspect, -cam->fov, cam->fov, cam->near_clip, cam->far_clip); // [ref] https://commons.wikimedia.org/wiki/File:Isometric_dimetric_camera_views.png // float pitch = cam->dimetric ? 30.000f : 35.264f; // dimetric or isometric // cam->pitch = -pitch; // quickly reorient towards origin } else { - perspective44(cam->proj, cam->fov, aspect, 0.01f, 2000.f); + perspective44(cam->proj, cam->fov, aspect, cam->near_clip, cam->far_clip); } } diff --git a/engine/split/v4k_render.c b/engine/split/v4k_render.c index a2c8096..19b3ddf 100644 --- a/engine/split/v4k_render.c +++ b/engine/split/v4k_render.c @@ -1696,12 +1696,14 @@ shadowmap_t shadowmap(int vsm_texture_width, int pcf_texture_width) { // = 512, s.vsm_texture_width = vsm_texture_width; s.pcf_texture_width = pcf_texture_width; s.saved_fb = 0; - s.blur_pcf = true; + s.blur_pcf = false; s.blur_scale = 0.5f; s.cascade_splits[0] = 0.1f; s.cascade_splits[1] = 0.3f; s.cascade_splits[2] = 0.5f; - s.cascade_splits[3] = 1.0f; + s.cascade_splits[3] = 0.7f; + s.cascade_splits[5] = 1.0f; + s.cascade_splits[6] = 1.0f; /* sticks to camera far plane */ glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &s.saved_fb); @@ -1879,10 +1881,21 @@ static void shadowmap_light_directional(shadowmap_t *s, light_t *l, int dir, flo maxZ = max(maxZ, corner.z); } +#if 0 + float tmpZ = -minZ; + minZ = -maxZ; + maxZ = tmpZ; + + float mid = (maxZ + minZ) * 0.5f; + minZ -= mid * 5.0f; + maxZ += mid * 5.0f; +#endif + mat44 P, PV; ortho44(P, minX, maxX, minY, maxY, + // minZ, maxZ); -maxZ, -minZ); multiply44x2(PV, P, V); @@ -2003,10 +2016,20 @@ void shadowmap_clear_fbo() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } -void shadowmap_light(shadowmap_t *s, light_t *l, float cam_fov, float cam_far, mat44 cam_view) { +void shadowmap_light(shadowmap_t *s, light_t *l, mat44 cam_proj, mat44 cam_view) { if (l->cast_shadows) { int step = s->step - 1; + float y_scale = cam_proj[5]; + float cam_fov = (2.0f * atan(1.0f / y_scale)) * TO_DEG; + float cam_far = 0.0f; { + float m22 = cam_proj[10]; + float m32 = cam_proj[14]; + float near_plane = -m32 / (m22 + 1.0f); + cam_far = (2.0f * near_plane) / (m22 - 1.0f); + cam_far *= 0.5f; + } + if (l->type == LIGHT_POINT) { shadowmap_light_point(s, l, step); } else if (l->type == LIGHT_SPOT) { @@ -4853,12 +4876,10 @@ void model_set_renderstates(model_t *m) { // Shadow pass renderstate_t *pcf_shadow_rs = &m->rs[RENDER_PASS_SHADOW_PCF]; { - pcf_shadow_rs->blend_enabled = 1; - pcf_shadow_rs->blend_src = GL_SRC_ALPHA; - pcf_shadow_rs->blend_dst = GL_ONE_MINUS_SRC_ALPHA; + pcf_shadow_rs->blend_enabled = 0; pcf_shadow_rs->cull_face_enabled = 1; - pcf_shadow_rs->cull_face_mode = GL_FRONT; - pcf_shadow_rs->front_face = GL_CCW; + pcf_shadow_rs->cull_face_mode = GL_BACK; + pcf_shadow_rs->front_face = GL_CW; pcf_shadow_rs->depth_clamp_enabled = 1; } diff --git a/engine/split/v4k_render.h b/engine/split/v4k_render.h index 3889369..0a15f0c 100644 --- a/engine/split/v4k_render.h +++ b/engine/split/v4k_render.h @@ -299,7 +299,7 @@ enum SHADOW_TECHNIQUE { SHADOW_PCF, }; -#define NUM_SHADOW_CASCADES 4 +#define NUM_SHADOW_CASCADES 6 typedef struct light_t { char type; @@ -383,7 +383,7 @@ API void shadowmap_destroy(shadowmap_t *s); API void shadowmap_begin(shadowmap_t *s); API bool shadowmap_step(shadowmap_t *s); -API void shadowmap_light(shadowmap_t *s, light_t *l, float cam_fov, float cam_far, mat44 cam_view); //< can be called once per shadowmap_step +API void shadowmap_light(shadowmap_t *s, light_t *l, mat44 cam_proj, mat44 cam_view); //< can be called once per shadowmap_step API void shadowmap_end(shadowmap_t *s); // ----------------------------------------------------------------------------- diff --git a/engine/split/v4k_scene.c b/engine/split/v4k_scene.c index ae73906..8450439 100644 --- a/engine/split/v4k_scene.c +++ b/engine/split/v4k_scene.c @@ -14,6 +14,8 @@ camera_t camera() { cam.fov = 45; cam.orthographic = false; cam.distance = 3; // len3(cam.position); + cam.near_clip = 0.1f; + cam.far_clip = 1000.f; cam.damping = false; cam.move_friction = 0.09f; @@ -110,12 +112,12 @@ void camera_fov(camera_t *cam, float fov) { cam->fov = fov; if( cam->orthographic ) { - ortho44(cam->proj, -cam->fov * aspect, cam->fov * aspect, -cam->fov, cam->fov, 0.01f, 2000); + ortho44(cam->proj, -cam->fov * aspect, cam->fov * aspect, -cam->fov, cam->fov, cam->near_clip, cam->far_clip); // [ref] https://commons.wikimedia.org/wiki/File:Isometric_dimetric_camera_views.png // float pitch = cam->dimetric ? 30.000f : 35.264f; // dimetric or isometric // cam->pitch = -pitch; // quickly reorient towards origin } else { - perspective44(cam->proj, cam->fov, aspect, 0.01f, 2000.f); + perspective44(cam->proj, cam->fov, aspect, cam->near_clip, cam->far_clip); } } diff --git a/engine/split/v4k_scene.h b/engine/split/v4k_scene.h index 067763d..9728ad5 100644 --- a/engine/split/v4k_scene.h +++ b/engine/split/v4k_scene.h @@ -9,6 +9,7 @@ typedef struct camera_t { vec3 position, updir, lookdir; float yaw, pitch, roll; // mirror of (x,y) lookdir in deg; float speed, fov; // fov in deg(45) + float near_clip, far_clip; float move_friction, move_damping; float look_friction, look_damping; diff --git a/engine/v4k.c b/engine/v4k.c index c8ed8db..0a806c1 100644 --- a/engine/v4k.c +++ b/engine/v4k.c @@ -18495,12 +18495,14 @@ shadowmap_t shadowmap(int vsm_texture_width, int pcf_texture_width) { // = 512, s.vsm_texture_width = vsm_texture_width; s.pcf_texture_width = pcf_texture_width; s.saved_fb = 0; - s.blur_pcf = true; + s.blur_pcf = false; s.blur_scale = 0.5f; s.cascade_splits[0] = 0.1f; s.cascade_splits[1] = 0.3f; s.cascade_splits[2] = 0.5f; - s.cascade_splits[3] = 1.0f; + s.cascade_splits[3] = 0.7f; + s.cascade_splits[5] = 1.0f; + s.cascade_splits[6] = 1.0f; /* sticks to camera far plane */ glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &s.saved_fb); @@ -18678,10 +18680,21 @@ static void shadowmap_light_directional(shadowmap_t *s, light_t *l, int dir, flo maxZ = max(maxZ, corner.z); } +#if 0 + float tmpZ = -minZ; + minZ = -maxZ; + maxZ = tmpZ; + + float mid = (maxZ + minZ) * 0.5f; + minZ -= mid * 5.0f; + maxZ += mid * 5.0f; +#endif + mat44 P, PV; ortho44(P, minX, maxX, minY, maxY, + // minZ, maxZ); -maxZ, -minZ); multiply44x2(PV, P, V); @@ -18802,10 +18815,20 @@ void shadowmap_clear_fbo() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } -void shadowmap_light(shadowmap_t *s, light_t *l, float cam_fov, float cam_far, mat44 cam_view) { +void shadowmap_light(shadowmap_t *s, light_t *l, mat44 cam_proj, mat44 cam_view) { if (l->cast_shadows) { int step = s->step - 1; + float y_scale = cam_proj[5]; + float cam_fov = (2.0f * atan(1.0f / y_scale)) * TO_DEG; + float cam_far = 0.0f; { + float m22 = cam_proj[10]; + float m32 = cam_proj[14]; + float near_plane = -m32 / (m22 + 1.0f); + cam_far = (2.0f * near_plane) / (m22 - 1.0f); + cam_far *= 0.5f; + } + if (l->type == LIGHT_POINT) { shadowmap_light_point(s, l, step); } else if (l->type == LIGHT_SPOT) { @@ -21652,12 +21675,10 @@ void model_set_renderstates(model_t *m) { // Shadow pass renderstate_t *pcf_shadow_rs = &m->rs[RENDER_PASS_SHADOW_PCF]; { - pcf_shadow_rs->blend_enabled = 1; - pcf_shadow_rs->blend_src = GL_SRC_ALPHA; - pcf_shadow_rs->blend_dst = GL_ONE_MINUS_SRC_ALPHA; + pcf_shadow_rs->blend_enabled = 0; pcf_shadow_rs->cull_face_enabled = 1; - pcf_shadow_rs->cull_face_mode = GL_FRONT; - pcf_shadow_rs->front_face = GL_CCW; + pcf_shadow_rs->cull_face_mode = GL_BACK; + pcf_shadow_rs->front_face = GL_CW; pcf_shadow_rs->depth_clamp_enabled = 1; } @@ -23778,6 +23799,8 @@ camera_t camera() { cam.fov = 45; cam.orthographic = false; cam.distance = 3; // len3(cam.position); + cam.near_clip = 0.1f; + cam.far_clip = 1000.f; cam.damping = false; cam.move_friction = 0.09f; @@ -23874,12 +23897,12 @@ void camera_fov(camera_t *cam, float fov) { cam->fov = fov; if( cam->orthographic ) { - ortho44(cam->proj, -cam->fov * aspect, cam->fov * aspect, -cam->fov, cam->fov, 0.01f, 2000); + ortho44(cam->proj, -cam->fov * aspect, cam->fov * aspect, -cam->fov, cam->fov, cam->near_clip, cam->far_clip); // [ref] https://commons.wikimedia.org/wiki/File:Isometric_dimetric_camera_views.png // float pitch = cam->dimetric ? 30.000f : 35.264f; // dimetric or isometric // cam->pitch = -pitch; // quickly reorient towards origin } else { - perspective44(cam->proj, cam->fov, aspect, 0.01f, 2000.f); + perspective44(cam->proj, cam->fov, aspect, cam->near_clip, cam->far_clip); } } diff --git a/engine/v4k.h b/engine/v4k.h index 841eac2..17471e3 100644 --- a/engine/v4k.h +++ b/engine/v4k.h @@ -3334,7 +3334,7 @@ enum SHADOW_TECHNIQUE { SHADOW_PCF, }; -#define NUM_SHADOW_CASCADES 4 +#define NUM_SHADOW_CASCADES 6 typedef struct light_t { char type; @@ -3418,7 +3418,7 @@ API void shadowmap_destroy(shadowmap_t *s); API void shadowmap_begin(shadowmap_t *s); API bool shadowmap_step(shadowmap_t *s); -API void shadowmap_light(shadowmap_t *s, light_t *l, float cam_fov, float cam_far, mat44 cam_view); //< can be called once per shadowmap_step +API void shadowmap_light(shadowmap_t *s, light_t *l, mat44 cam_proj, mat44 cam_view); //< can be called once per shadowmap_step API void shadowmap_end(shadowmap_t *s); // ----------------------------------------------------------------------------- @@ -4038,6 +4038,7 @@ typedef struct camera_t { vec3 position, updir, lookdir; float yaw, pitch, roll; // mirror of (x,y) lookdir in deg; float speed, fov; // fov in deg(45) + float near_clip, far_clip; float move_friction, move_damping; float look_friction, look_damping;