diff --git a/bind/v4k.lua b/bind/v4k.lua index b242eba..01f05ae 100644 --- a/bind/v4k.lua +++ b/bind/v4k.lua @@ -1148,7 +1148,7 @@ enum SHADOW_TECHNIQUE { SHADOW_CSM, }; typedef struct light_t { - char type; + unsigned type; vec3 diffuse, specular, ambient; vec3 pos, dir; struct { @@ -1158,12 +1158,16 @@ typedef struct light_t { float specularPower; float innerCone, outerCone; bool cast_shadows; - bool processed_shadows; unsigned shadow_technique; float shadow_distance; - float shadow_bias; + float shadow_near_clip; mat44 shadow_matrix[4]; + float min_variance; + float variance_transition; + float shadow_bias; + float normal_bias; bool cached; + bool processed_shadows; } light_t; light_t light(); void light_type(light_t* l, char type); @@ -1177,6 +1181,8 @@ typedef struct light_t { void light_falloff(light_t* l, float constant, float linear, float quadratic); void light_cone(light_t* l, float innerCone, float outerCone); void light_update(unsigned num_lights, light_t *lv); + void ui_light(light_t *l); + void ui_lights(unsigned num_lights, light_t *lights); typedef struct shadowmap_t { mat44 V; mat44 PV; @@ -1198,11 +1204,13 @@ typedef struct shadowmap_t { uint64_t vram_usage_total; uint64_t vram_usage_vsm; uint64_t vram_usage_csm; + handle depth_texture; + handle depth_texture_2d; struct { int gen; unsigned shadow_technique; - handle texture, depth_texture; - handle texture_2d[4], depth_texture_2d[4]; + handle texture; + handle texture_2d[4]; handle blur_texture, blur_texture_2d; float cascade_distances[4]; } maps[MAX_LIGHTS]; @@ -2054,6 +2062,10 @@ enum PANEL_FLAGS { int ui_int(const char *label, int *value); int ui_bool(const char *label, bool *value); int ui_short(const char *label, short *value); + int ui_float_(const char *label, float *value, float step); + int ui_float2_(const char *label, float value[2], float step); + int ui_float3_(const char *label, float value[3], float step); + int ui_float4_(const char *label, float value[4], float step); int ui_float(const char *label, float *value); int ui_float2(const char *label, float value[2]); int ui_float3(const char *label, float value[3]); @@ -2090,6 +2102,7 @@ enum PANEL_FLAGS { int ui_bitmask8(const char *label, uint8_t *bits); int ui_bitmask16(const char *label, uint16_t *bits); int ui_console(); + int ui_clampf_(const char *label, float *value, float minf, float maxf, float step); int ui_clampf(const char *label, float *value, float minf, float maxf); int ui_label(const char *label); int ui_label2(const char *label, const char *caption); diff --git a/demos/09-shadows.c b/demos/09-shadows.c index 48b9769..4ebf7f5 100644 --- a/demos/09-shadows.c +++ b/demos/09-shadows.c @@ -206,6 +206,8 @@ int main(int argc, char** argv) { must_reload = 1; } ui_separator(); + ui_lights(array_count(lights), lights); + ui_separator(); ui_bool("CSM Blur", &sm.blur_csm); ui_slider("CSM Blur Scale", &sm.csm_blur_scale); ui_bool("VSM Blur", &sm.blur_vsm); diff --git a/engine/art/shaderlib/light.glsl b/engine/art/shaderlib/light.glsl index 6821eda..e4b3846 100644 --- a/engine/art/shaderlib/light.glsl +++ b/engine/art/shaderlib/light.glsl @@ -26,6 +26,10 @@ struct light_t { // shadows mat4 shadow_matrix[NUM_SHADOW_CASCADES]; + float shadow_bias; + float normal_bias; + float min_variance; + float variance_transition; }; const int LIGHT_DIRECTIONAL = 0; diff --git a/engine/art/shaderlib/shadowmap.glsl b/engine/art/shaderlib/shadowmap.glsl index 5e01207..a535700 100644 --- a/engine/art/shaderlib/shadowmap.glsl +++ b/engine/art/shaderlib/shadowmap.glsl @@ -12,7 +12,7 @@ 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); //// From http://fabiensanglard.net/shadowmappingVSM/index.php -float shadow_vsm(float distance, vec3 dir, int light_index) { +float shadow_vsm(float distance, vec3 dir, int light_index, float min_variance, float variance_transition) { distance = distance/200; // Define offsets for 3x3 PCF @@ -49,9 +49,9 @@ float shadow_vsm(float distance, vec3 dir, int light_index) { // Calculate VSM for this sample float p = step(distance, moments.x); - float variance = max(moments.y - (moments.x * moments.x), 0.00002); + float variance = max(moments.y - (moments.x * moments.x), min_variance); float d = distance - moments.x; - float p_max = linstep(0.2, 1.0, variance / (variance + d*d)); + float p_max = linstep(variance_transition, 1.0, variance / (variance + d*d)); shadow += min(max(p, p_max), 1.0); } @@ -60,7 +60,7 @@ float shadow_vsm(float distance, vec3 dir, int light_index) { return shadow / 9.0; } -float shadow_csm(float distance, vec3 lightDir, int light_index) { +float shadow_csm(float distance, vec3 lightDir, int light_index, float shadow_bias, float normal_bias) { // Determine which cascade to use int cascade_index = -1; int min_cascades_range = light_index * NUM_SHADOW_CASCADES; @@ -94,7 +94,7 @@ float shadow_csm(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); + float bias = max(normal_bias * (1.0 - dot(normal, lightDir)), shadow_bias); bias *= 1 / (u_cascade_distances[cascade_index] * bias_modifier[matrix_index]); // CSM @@ -116,7 +116,7 @@ float shadow_csm(float distance, vec3 lightDir, int light_index) { { for(int y = -1; y <= 1; ++y) { - float csmDepth = texture(shadowMap2D[cascade_index], projCoords.xy + vec2(x, y) * texelSize).r; + float csmDepth = texture(shadowMap2D[cascade_index], projCoords.xy + vec2(x, y) * texelSize * (rand(vec2(projCoords.x + x, projCoords.y + y))*0.75f + 0.25f)).r; shadow += currentDepth - bias > csmDepth ? 1.0 : 0.0; } } @@ -132,12 +132,12 @@ vec4 shadowmap(int idx, in vec4 peye, in vec4 neye) { if (light.processed_shadows) { if (light.type == LIGHT_DIRECTIONAL) { - shadowFactor = shadow_csm(-peye.z, light.dir, idx); + shadowFactor = shadow_csm(-peye.z, light.dir, idx, light.shadow_bias, light.normal_bias); } else if (light.type == LIGHT_POINT || light.type == LIGHT_SPOT) { vec3 light_pos = (view * vec4(light.pos, 1.0)).xyz; vec3 dir = light_pos - fragment; vec4 sc = inv_view * vec4(dir, 0.0); - shadowFactor = shadow_vsm(length(dir), -sc.xyz, idx); + shadowFactor = shadow_vsm(length(dir), -sc.xyz, idx, light.min_variance, light.variance_transition); } } diff --git a/engine/joint/v4k.h b/engine/joint/v4k.h index 82a322e..113d634 100644 --- a/engine/joint/v4k.h +++ b/engine/joint/v4k.h @@ -17270,7 +17270,7 @@ enum SHADOW_TECHNIQUE { #define NUM_SHADOW_CASCADES 4 typedef struct light_t { - char type; + unsigned type; vec3 diffuse, specular, ambient; vec3 pos, dir; struct { @@ -17283,14 +17283,18 @@ typedef struct light_t { // Shadowmapping bool cast_shadows; - bool processed_shadows; unsigned shadow_technique; float shadow_distance; - float shadow_bias; + float shadow_near_clip; mat44 shadow_matrix[NUM_SHADOW_CASCADES]; + float min_variance; //< VSM + float variance_transition; //< VSM + float shadow_bias; //< CSM + float normal_bias; //< CSM // internals bool cached; //< used by scene to invalidate cached light data + bool processed_shadows; } light_t; API light_t light(); @@ -17307,6 +17311,10 @@ API void light_falloff(light_t* l, float constant, float linear, float quadra API void light_cone(light_t* l, float innerCone, float outerCone); API void light_update(unsigned num_lights, light_t *lv); +API void ui_light(light_t *l); +API void ui_lights(unsigned num_lights, light_t *lights); + + // ----------------------------------------------------------------------------- // shadowmaps @@ -17336,11 +17344,15 @@ typedef struct shadowmap_t { uint64_t vram_usage_vsm; uint64_t vram_usage_csm; + // depth texture + handle depth_texture; + handle depth_texture_2d; + struct { int gen; unsigned shadow_technique; - handle texture, depth_texture; - handle texture_2d[NUM_SHADOW_CASCADES], depth_texture_2d[NUM_SHADOW_CASCADES]; + handle texture; + handle texture_2d[NUM_SHADOW_CASCADES]; handle blur_texture, blur_texture_2d; // handle blur_fbo_cubemap, blur_texture_cubemap; float cascade_distances[NUM_SHADOW_CASCADES]; @@ -18699,6 +18711,10 @@ API int ui_section(const char *title); API int ui_int(const char *label, int *value); API int ui_bool(const char *label, bool *value); API int ui_short(const char *label, short *value); +API int ui_float_(const char *label, float *value, float step); +API int ui_float2_(const char *label, float value[2], float step); +API int ui_float3_(const char *label, float value[3], float step); +API int ui_float4_(const char *label, float value[4], float step); API int ui_float(const char *label, float *value); API int ui_float2(const char *label, float value[2]); API int ui_float3(const char *label, float value[3]); @@ -18735,6 +18751,7 @@ API int ui_separator(); API int ui_bitmask8(const char *label, uint8_t *bits); API int ui_bitmask16(const char *label, uint16_t *bits); API int ui_console(); +API int ui_clampf_(const char *label, float *value, float minf, float maxf, float step); API int ui_clampf(const char *label, float *value, float minf, float maxf); API int ui_label(const char *label); API int ui_label2(const char *label, const char *caption); @@ -228865,6 +228882,8 @@ struct nk_context { #define NK_PI 3.141592654f #define NK_UTF_INVALID 0xFFFD #define NK_MAX_FLOAT_PRECISION 2 +#define NK_MAX_FLOAT_PRECISION2 6 +#define NK_FLOAT_DECIMAL_POS_THRESHOLD 0.0005 #define NK_UNUSED(x) ((void)(x)) #define NK_SATURATE(x) (NK_MAX(0, NK_MIN(1.0f, x))) @@ -251323,11 +251342,11 @@ nk_do_property(nk_flags *ws, break; case NK_PROPERTY_FLOAT: NK_DTOA(string, (double)variant->value.f); - num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION); + num_len = nk_string_float_limit(string, variant->step.f <= NK_FLOAT_DECIMAL_POS_THRESHOLD ? NK_MAX_FLOAT_PRECISION2 : NK_MAX_FLOAT_PRECISION); break; case NK_PROPERTY_DOUBLE: NK_DTOA(string, variant->value.d); - num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION); + num_len = nk_string_float_limit(string, variant->step.f <= NK_FLOAT_DECIMAL_POS_THRESHOLD ? NK_MAX_FLOAT_PRECISION2 : NK_MAX_FLOAT_PRECISION); break; } size = font->width(font->userdata, font->height, string, num_len); @@ -251423,12 +251442,12 @@ nk_do_property(nk_flags *ws, variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i, variant->max_value.i); break; case NK_PROPERTY_FLOAT: - nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION); + nk_string_float_limit(buffer, variant->step.f <= NK_FLOAT_DECIMAL_POS_THRESHOLD ? NK_MAX_FLOAT_PRECISION2 : NK_MAX_FLOAT_PRECISION); variant->value.f = nk_strtof(buffer, 0); variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f, variant->max_value.f); break; case NK_PROPERTY_DOUBLE: - nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION); + nk_string_float_limit(buffer, variant->step.f <= NK_FLOAT_DECIMAL_POS_THRESHOLD ? NK_MAX_FLOAT_PRECISION2 : NK_MAX_FLOAT_PRECISION); variant->value.d = nk_strtod(buffer, 0); variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d); break; @@ -368386,13 +368405,42 @@ int ui_short(const char *label, short *v) { return *v = (short)i, ret; } -int ui_float(const char *label, float *v) { +static inline +float ui_float_adjust_step(float step) { + if ((input(KEY_LSHIFT) || input(KEY_RSHIFT))&&(input(KEY_LCTRL) || input(KEY_RCTRL))) step *= 100.0f; + else if (input(KEY_LSHIFT) || input(KEY_RSHIFT)) step *= 10.0f; + else if (input(KEY_LCTRL) || input(KEY_RCTRL)) step *= 0.1f; + else if (input(KEY_LALT) || input(KEY_RALT)) step *= 0.01f; + return step; +} + +int ui_float_(const char *label, float *v, float step) { if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + float inc_per_pixel = ui_float_adjust_step(0.005f); + step = ui_float_adjust_step(step); + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); - float prev = v[0]; v[0] = nk_propertyf(ui_ctx, "#", -FLT_MAX, v[0], FLT_MAX, 0.01f,0.005f); + float prev = v[0]; v[0] = nk_propertyf(ui_ctx, "#", -FLT_MAX, v[0], FLT_MAX, step, inc_per_pixel); + return prev != v[0]; +} + +int ui_float(const char *label, float *v) { + return ui_float_(label, v, 0.01f); +} + +int ui_double_(const char *label, double *v, double step) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + + float inc_per_pixel = ui_float_adjust_step(0.005f); + step = ui_float_adjust_step(step); + + nk_layout_row_dynamic(ui_ctx, 0, 2); + ui_label_(label, NK_TEXT_LEFT); + + double prev = v[0]; v[0] = nk_propertyd(ui_ctx, "#", -DBL_MAX, v[0], DBL_MAX, step, inc_per_pixel); return prev != v[0]; } @@ -368406,21 +368454,30 @@ int ui_double(const char *label, double *v) { return prev != v[0]; } -int ui_clampf(const char *label, float *v, float minf, float maxf) { +int ui_clampf_(const char *label, float *v, float minf, float maxf, float step) { if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + float inc_per_pixel = ui_float_adjust_step(0.005f); + step = ui_float_adjust_step(step); + if( minf > maxf ) return ui_clampf(label, v, maxf, minf); nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); - float prev = v[0]; v[0] = nk_propertyf(ui_ctx, "#", minf, v[0], maxf, 0.1f,0.05f); + float prev = v[0]; v[0] = nk_propertyf(ui_ctx, "#", minf, v[0], maxf, step, inc_per_pixel); return prev != v[0]; } -int ui_float2(const char *label, float *v) { +int ui_clampf(const char *label, float *v, float minf, float maxf) { + return ui_clampf_(label, v, minf, maxf, 0.1f); +} + +int ui_float2_(const char *label, float *v, float step) { if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + float inc_per_pixel = ui_float_adjust_step(0.5f); + step = ui_float_adjust_step(step); nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -368430,17 +368487,23 @@ int ui_float2(const char *label, float *v) { if (nk_combo_begin_label(ui_ctx, buffer, nk_vec2(200,200))) { nk_layout_row_dynamic(ui_ctx, 0, 1); - float prev0 = v[0]; nk_property_float(ui_ctx, "#X:", -FLT_MAX, &v[0], FLT_MAX, 1,0.5f); - float prev1 = v[1]; nk_property_float(ui_ctx, "#Y:", -FLT_MAX, &v[1], FLT_MAX, 1,0.5f); + float prev0 = v[0]; nk_property_float(ui_ctx, "#X:", -FLT_MAX, &v[0], FLT_MAX, step, inc_per_pixel); + float prev1 = v[1]; nk_property_float(ui_ctx, "#Y:", -FLT_MAX, &v[1], FLT_MAX, step, inc_per_pixel); nk_combo_end(ui_ctx); return prev0 != v[0] || prev1 != v[1]; } return 0; } -int ui_float3(const char *label, float *v) { +int ui_float2(const char *label, float *v) { + return ui_float2_(label, v, 1.0f); +} + +int ui_float3_(const char *label, float *v, float step) { if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + float inc_per_pixel = ui_float_adjust_step(0.5f); + step = ui_float_adjust_step(step); nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -368450,18 +368513,25 @@ int ui_float3(const char *label, float *v) { if (nk_combo_begin_label(ui_ctx, buffer, nk_vec2(200,200))) { nk_layout_row_dynamic(ui_ctx, 0, 1); - float prev0 = v[0]; nk_property_float(ui_ctx, "#X:", -FLT_MAX, &v[0], FLT_MAX, 1,0.5f); - float prev1 = v[1]; nk_property_float(ui_ctx, "#Y:", -FLT_MAX, &v[1], FLT_MAX, 1,0.5f); - float prev2 = v[2]; nk_property_float(ui_ctx, "#Z:", -FLT_MAX, &v[2], FLT_MAX, 1,0.5f); + float prev0 = v[0]; nk_property_float(ui_ctx, "#X:", -FLT_MAX, &v[0], FLT_MAX, step, inc_per_pixel); + float prev1 = v[1]; nk_property_float(ui_ctx, "#Y:", -FLT_MAX, &v[1], FLT_MAX, step, inc_per_pixel); + float prev2 = v[2]; nk_property_float(ui_ctx, "#Z:", -FLT_MAX, &v[2], FLT_MAX, step, inc_per_pixel); nk_combo_end(ui_ctx); return prev0 != v[0] || prev1 != v[1] || prev2 != v[2]; } return 0; } -int ui_float4(const char *label, float *v) { + +int ui_float3(const char *label, float *v) { + return ui_float3_(label, v, 1.0f); +} + +int ui_float4_(const char *label, float *v, float step) { if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + float inc_per_pixel = ui_float_adjust_step(0.5f); + step = ui_float_adjust_step(step); nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -368471,10 +368541,10 @@ int ui_float4(const char *label, float *v) { if (nk_combo_begin_label(ui_ctx, buffer, nk_vec2(200,200))) { nk_layout_row_dynamic(ui_ctx, 0, 1); - float prev0 = v[0]; nk_property_float(ui_ctx, "#X:", -FLT_MAX, &v[0], FLT_MAX, 1,0.5f); - float prev1 = v[1]; nk_property_float(ui_ctx, "#Y:", -FLT_MAX, &v[1], FLT_MAX, 1,0.5f); - float prev2 = v[2]; nk_property_float(ui_ctx, "#Z:", -FLT_MAX, &v[2], FLT_MAX, 1,0.5f); - float prev3 = v[3]; nk_property_float(ui_ctx, "#W:", -FLT_MAX, &v[3], FLT_MAX, 1,0.5f); + float prev0 = v[0]; nk_property_float(ui_ctx, "#X:", -FLT_MAX, &v[0], FLT_MAX, step, inc_per_pixel); + float prev1 = v[1]; nk_property_float(ui_ctx, "#Y:", -FLT_MAX, &v[1], FLT_MAX, step, inc_per_pixel); + float prev2 = v[2]; nk_property_float(ui_ctx, "#Z:", -FLT_MAX, &v[2], FLT_MAX, step, inc_per_pixel); + float prev3 = v[3]; nk_property_float(ui_ctx, "#W:", -FLT_MAX, &v[3], FLT_MAX, step, inc_per_pixel); nk_combo_end(ui_ctx); return prev0 != v[0] || prev1 != v[1] || prev2 != v[2] || prev3 != v[3]; } @@ -368482,6 +368552,10 @@ int ui_float4(const char *label, float *v) { return 0; } +int ui_float4(const char *label, float *v) { + return ui_float4_(label, v, 1.0f); +} + int ui_mat33(const char *label, float M[9]) { if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; @@ -383226,7 +383300,11 @@ light_t light() { l.cast_shadows = true; l.processed_shadows = false; l.shadow_distance = 200.0f; - l.shadow_bias = 0.01f; + l.shadow_near_clip = 0.01f; + l.shadow_bias = 0.005f; + l.normal_bias = 0.05f; + l.min_variance = 0.00002f; + l.variance_transition = 0.2f; return l; } @@ -383305,6 +383383,10 @@ void light_update(unsigned num_lights, light_t *lv) { shader_float(va("u_lights[%d].quadratic", i), lv[i].falloff.quadratic); shader_float(va("u_lights[%d].innerCone", i), lv[i].innerCone); shader_float(va("u_lights[%d].outerCone", i), lv[i].outerCone); + shader_float(va("u_lights[%d].shadow_bias", i), lv[i].shadow_bias); + shader_float(va("u_lights[%d].normal_bias", i), lv[i].normal_bias); + shader_float(va("u_lights[%d].min_variance", i), lv[i].min_variance); + shader_float(va("u_lights[%d].variance_transition", i), lv[i].variance_transition); shader_bool(va("u_lights[%d].processed_shadows", i), lv[i].processed_shadows); if (lv[i].processed_shadows) { for (int j = 0; j < NUM_SHADOW_CASCADES; j++) { @@ -383314,10 +383396,58 @@ void light_update(unsigned num_lights, light_t *lv) { } } +void ui_light(light_t *l) { + ui_int("Type", &l->type); + ui_vec3("Position", &l->pos); + ui_vec3("Direction", &l->dir); + ui_color3f("Diffuse", &l->diffuse.x); + ui_color3f("Specular", &l->specular.x); + ui_color3f("Ambient", &l->ambient.x); + ui_float("Specular Power", &l->specularPower); + ui_clampf("Radius", &l->radius, 0.0f, FLT_MAX); + ui_clampf_("Constant Falloff", &l->falloff.constant, 0.0, FLT_MAX, 0.005); + ui_clampf_("Linear Falloff", &l->falloff.linear, 0.0, FLT_MAX, 0.005); + ui_clampf_("Quadratic Falloff", &l->falloff.quadratic, 0.0, FLT_MAX, 0.005); + ui_float("Inner Cone", &l->innerCone); + ui_float("Outer Cone", &l->outerCone); + ui_float_("Shadow Bias", &l->shadow_bias, 0.00005); + ui_float_("Normal Bias", &l->normal_bias, 0.00005); + ui_float_("Min Variance", &l->min_variance, 0.00005); + ui_float_("Variance Transition", &l->variance_transition, 0.0005); +} + +void ui_lights(unsigned num_lights, light_t *lights) { + for (unsigned i = 0; i < num_lights; ++i) { + if (ui_collapse(va("Light %d", i), va("light_%d", i))) { + ui_light(&lights[i]); + ui_collapse_end(); + } + } +} + // ----------------------------------------------------------------------------- // shadowmaps +static inline +void shadowmap_init_common_resources(shadowmap_t *s, int vsm_texture_width, int csm_texture_width) { + // Create a cubemap depth texture + glGenTextures(1, &s->depth_texture); + glBindTexture(GL_TEXTURE_CUBE_MAP, s->depth_texture); + for (int i = 0; i < 6; i++) { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT, vsm_texture_width, vsm_texture_width, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); + } + + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); + + // Create a 2D depth texture + glGenTextures(1, &s->depth_texture_2d); + glBindTexture(GL_TEXTURE_2D, s->depth_texture_2d); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, csm_texture_width, csm_texture_width, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); + + glBindTexture(GL_TEXTURE_2D, 0); +} + static inline void shadowmap_init_caster_vsm(shadowmap_t *s, int light_index, int texture_width) { float borderColor[] = {1.0, 1.0, 1.0, 1.0}; @@ -383341,19 +383471,6 @@ shadowmap_init_caster_vsm(shadowmap_t *s, int light_index, int texture_width) { glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); glTexParameterfv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BORDER_COLOR, borderColor); - // Create a cubemap depth texture - glGenTextures(1, &s->maps[light_index].depth_texture); - glBindTexture(GL_TEXTURE_CUBE_MAP, s->maps[light_index].depth_texture); - for (int i = 0; i < 6; i++) { - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT, texture_width, texture_width, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); - } - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - glTexParameterfv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BORDER_COLOR, borderColor); - glBindTexture(GL_TEXTURE_CUBE_MAP, 0); } @@ -383375,15 +383492,6 @@ shadowmap_init_caster_csm(shadowmap_t *s, int light_index, int texture_width) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); - - glGenTextures(1, &s->maps[light_index].depth_texture_2d[i]); - glBindTexture(GL_TEXTURE_2D, s->maps[light_index].depth_texture_2d[i]); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, texture_width, texture_width, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); } glBindTexture(GL_TEXTURE_2D, 0); @@ -383434,6 +383542,8 @@ shadowmap_t shadowmap(int vsm_texture_width, int csm_texture_width) { // = 512, } #endif + shadowmap_init_common_resources(&s, vsm_texture_width, csm_texture_width); + glBindFramebuffer(GL_FRAMEBUFFER, s.saved_fb); return s; } @@ -383447,20 +383557,12 @@ void shadowmap_destroy_light(shadowmap_t *s, int light_index) { glDeleteTextures(1, &s->maps[light_index].texture); s->maps[light_index].texture = 0; } - if (s->maps[light_index].depth_texture) { - glDeleteTextures(1, &s->maps[light_index].depth_texture); - s->maps[light_index].depth_texture = 0; - } - + for (int i = 0; i < NUM_SHADOW_CASCADES; i++) { if (s->maps[light_index].texture_2d[i]) { glDeleteTextures(1, &s->maps[light_index].texture_2d[i]); s->maps[light_index].texture_2d[i] = 0; } - if (s->maps[light_index].depth_texture_2d[i]) { - glDeleteTextures(1, &s->maps[light_index].depth_texture_2d[i]); - s->maps[light_index].depth_texture_2d[i] = 0; - } } if (s->maps[light_index].blur_texture_2d) { @@ -383478,6 +383580,18 @@ void shadowmap_destroy(shadowmap_t *s) { for (int i = 0; i < MAX_LIGHTS; i++) { shadowmap_destroy_light(s, i); } + + + if (s->depth_texture) { + glDeleteTextures(1, &s->depth_texture); + s->depth_texture = 0; + } + + if (s->depth_texture_2d) { + glDeleteTextures(1, &s->depth_texture_2d); + s->depth_texture_2d = 0; + } + shadowmap_t z = {0}; *s = z; } @@ -383505,7 +383619,7 @@ void shadowmap_begin(shadowmap_t *s) { static void shadowmap_light_point(shadowmap_t *s, light_t *l, int dir) { if(dir<0) return; mat44 P, V, PV; - perspective44(P, 90.0f, 1.0f, l->shadow_bias, l->shadow_distance); + perspective44(P, 90.0f, 1.0f, l->shadow_near_clip, l->shadow_distance); vec3 lightPos = l->pos; /**/ if(dir == 0) lookat44(V, lightPos, add3(lightPos, vec3(+1, 0, 0)), vec3(0, -1, 0)); // +X @@ -383558,7 +383672,7 @@ static void shadowmap_light_directional(shadowmap_t *s, light_t *l, int dir, flo float near_plane = 0.0f; if (s->cascade_index == 0) { - near_plane = l->shadow_bias; + near_plane = l->shadow_near_clip; far_plane = l->shadow_distance * s->cascade_splits[0]; } else if (s->cascade_index < NUM_SHADOW_CASCADES - 1) { near_plane = l->shadow_distance * s->cascade_splits[s->cascade_index-1]; @@ -383873,12 +383987,12 @@ void shadowmap_light(shadowmap_t *s, light_t *l, mat44 cam_proj, mat44 cam_view) if (l->type == LIGHT_DIRECTIONAL) { glBindFramebuffer(GL_FRAMEBUFFER, s->fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s->maps[s->light_step].texture_2d[s->cascade_index], 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, s->maps[s->light_step].depth_texture_2d[s->cascade_index], 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, s->depth_texture_2d, 0); shadowmap_clear_fbo(); } else { glBindFramebuffer(GL_FRAMEBUFFER, s->fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + step, s->maps[s->light_step].texture, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + step, s->maps[s->light_step].depth_texture, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + step, s->depth_texture, 0); shadowmap_clear_fbo(); } @@ -383900,19 +384014,25 @@ void shadowmap_end(shadowmap_t *s) { { const int faces = 6; const int cascades = NUM_SHADOW_CASCADES; + + // Depth textures + s->vram_usage += s->vsm_texture_width * s->vsm_texture_width * faces * 1; + s->vram_usage += s->csm_texture_width * s->csm_texture_width * 1; + s->vram_usage_total += s->vsm_texture_width * s->vsm_texture_width * faces * 1; + s->vram_usage_vsm += s->vsm_texture_width * s->vsm_texture_width * faces * 8; + s->vram_usage_total += s->vsm_texture_width * s->vsm_texture_width * faces * 8; + s->vram_usage_csm += s->csm_texture_width * s->csm_texture_width * 1; + for (int i = 0; i < MAX_LIGHTS; i++) { // VSM textures if (s->maps[i].texture != 0) { // Color texture (GL_RG32F) s->vram_usage += s->vsm_texture_width * s->vsm_texture_width * faces * 8; // 8 bytes per pixel (2 * 32-bit float) - // Depth texture (GL_DEPTH_COMPONENT, assuming 8-bit depth) - s->vram_usage += s->vsm_texture_width * s->vsm_texture_width * faces * 1; } // Color texture (GL_RG32F) s->vram_usage_total += s->vsm_texture_width * s->vsm_texture_width * faces * 8; // 8 bytes per pixel (2 * 32-bit float) // Depth texture (GL_DEPTH_COMPONENT, assuming 8-bit depth) - s->vram_usage_total += s->vsm_texture_width * s->vsm_texture_width * faces * 1; // Color texture (GL_RG32F) s->vram_usage_vsm += s->vsm_texture_width * s->vsm_texture_width * faces * 8; // 8 bytes per pixel (2 * 32-bit float) @@ -383925,20 +384045,13 @@ void shadowmap_end(shadowmap_t *s) { for (int j = 0; j < cascades; j++) { // Color texture (GL_R32F) s->vram_usage += s->csm_texture_width * s->csm_texture_width * 4; // 4 bytes per pixel (1 * 32-bit float) - // Depth texture (GL_DEPTH_COMPONENT, assuming 8-bit depth) - s->vram_usage += s->csm_texture_width * s->csm_texture_width * 1; } } for (int j = 0; j < cascades; j++) { // Color texture (GL_R32F) s->vram_usage_total += s->csm_texture_width * s->csm_texture_width * 4; // 4 bytes per pixel (1 * 32-bit float) - // Depth texture (GL_DEPTH_COMPONENT, assuming 8-bit depth) - s->vram_usage_total += s->csm_texture_width * s->csm_texture_width * 1; - s->vram_usage_csm += s->csm_texture_width * s->csm_texture_width * 4; // 4 bytes per pixel (1 * 32-bit float) - // Depth texture (GL_DEPTH_COMPONENT, assuming 8-bit depth) - s->vram_usage_csm += s->csm_texture_width * s->csm_texture_width * 1; } // VSM blur texture (if used) @@ -383946,8 +384059,6 @@ void shadowmap_end(shadowmap_t *s) { s->vram_usage += s->vsm_texture_width * s->vsm_texture_width * faces * 8; // Assuming same format as VSM color texture } - s->vram_usage_total += s->vsm_texture_width * s->vsm_texture_width * faces * 8; // Assuming same format as VSM color texture - s->vram_usage_vsm += s->vsm_texture_width * s->vsm_texture_width * faces * 8; // Assuming same format as VSM color texture // CSM blur texture (if used) if (s->maps[i].blur_texture_2d != 0) { diff --git a/engine/split/3rd_nuklear.h b/engine/split/3rd_nuklear.h index b152626..ea92981 100644 --- a/engine/split/3rd_nuklear.h +++ b/engine/split/3rd_nuklear.h @@ -5690,6 +5690,8 @@ struct nk_context { #define NK_PI 3.141592654f #define NK_UTF_INVALID 0xFFFD #define NK_MAX_FLOAT_PRECISION 2 +#define NK_MAX_FLOAT_PRECISION2 6 +#define NK_FLOAT_DECIMAL_POS_THRESHOLD 0.0005 #define NK_UNUSED(x) ((void)(x)) #define NK_SATURATE(x) (NK_MAX(0, NK_MIN(1.0f, x))) @@ -28148,11 +28150,11 @@ nk_do_property(nk_flags *ws, break; case NK_PROPERTY_FLOAT: NK_DTOA(string, (double)variant->value.f); - num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION); + num_len = nk_string_float_limit(string, variant->step.f <= NK_FLOAT_DECIMAL_POS_THRESHOLD ? NK_MAX_FLOAT_PRECISION2 : NK_MAX_FLOAT_PRECISION); break; case NK_PROPERTY_DOUBLE: NK_DTOA(string, variant->value.d); - num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION); + num_len = nk_string_float_limit(string, variant->step.f <= NK_FLOAT_DECIMAL_POS_THRESHOLD ? NK_MAX_FLOAT_PRECISION2 : NK_MAX_FLOAT_PRECISION); break; } size = font->width(font->userdata, font->height, string, num_len); @@ -28248,12 +28250,12 @@ nk_do_property(nk_flags *ws, variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i, variant->max_value.i); break; case NK_PROPERTY_FLOAT: - nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION); + nk_string_float_limit(buffer, variant->step.f <= NK_FLOAT_DECIMAL_POS_THRESHOLD ? NK_MAX_FLOAT_PRECISION2 : NK_MAX_FLOAT_PRECISION); variant->value.f = nk_strtof(buffer, 0); variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f, variant->max_value.f); break; case NK_PROPERTY_DOUBLE: - nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION); + nk_string_float_limit(buffer, variant->step.f <= NK_FLOAT_DECIMAL_POS_THRESHOLD ? NK_MAX_FLOAT_PRECISION2 : NK_MAX_FLOAT_PRECISION); variant->value.d = nk_strtod(buffer, 0); variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d); break; diff --git a/engine/split/v4k_render.c b/engine/split/v4k_render.c index 01cc910..e89f3f3 100644 --- a/engine/split/v4k_render.c +++ b/engine/split/v4k_render.c @@ -1483,7 +1483,11 @@ light_t light() { l.cast_shadows = true; l.processed_shadows = false; l.shadow_distance = 200.0f; - l.shadow_bias = 0.01f; + l.shadow_near_clip = 0.01f; + l.shadow_bias = 0.005f; + l.normal_bias = 0.05f; + l.min_variance = 0.00002f; + l.variance_transition = 0.2f; return l; } @@ -1562,6 +1566,10 @@ void light_update(unsigned num_lights, light_t *lv) { shader_float(va("u_lights[%d].quadratic", i), lv[i].falloff.quadratic); shader_float(va("u_lights[%d].innerCone", i), lv[i].innerCone); shader_float(va("u_lights[%d].outerCone", i), lv[i].outerCone); + shader_float(va("u_lights[%d].shadow_bias", i), lv[i].shadow_bias); + shader_float(va("u_lights[%d].normal_bias", i), lv[i].normal_bias); + shader_float(va("u_lights[%d].min_variance", i), lv[i].min_variance); + shader_float(va("u_lights[%d].variance_transition", i), lv[i].variance_transition); shader_bool(va("u_lights[%d].processed_shadows", i), lv[i].processed_shadows); if (lv[i].processed_shadows) { for (int j = 0; j < NUM_SHADOW_CASCADES; j++) { @@ -1571,10 +1579,58 @@ void light_update(unsigned num_lights, light_t *lv) { } } +void ui_light(light_t *l) { + ui_int("Type", &l->type); + ui_vec3("Position", &l->pos); + ui_vec3("Direction", &l->dir); + ui_color3f("Diffuse", &l->diffuse.x); + ui_color3f("Specular", &l->specular.x); + ui_color3f("Ambient", &l->ambient.x); + ui_float("Specular Power", &l->specularPower); + ui_clampf("Radius", &l->radius, 0.0f, FLT_MAX); + ui_clampf_("Constant Falloff", &l->falloff.constant, 0.0, FLT_MAX, 0.005); + ui_clampf_("Linear Falloff", &l->falloff.linear, 0.0, FLT_MAX, 0.005); + ui_clampf_("Quadratic Falloff", &l->falloff.quadratic, 0.0, FLT_MAX, 0.005); + ui_float("Inner Cone", &l->innerCone); + ui_float("Outer Cone", &l->outerCone); + ui_float_("Shadow Bias", &l->shadow_bias, 0.00005); + ui_float_("Normal Bias", &l->normal_bias, 0.00005); + ui_float_("Min Variance", &l->min_variance, 0.00005); + ui_float_("Variance Transition", &l->variance_transition, 0.0005); +} + +void ui_lights(unsigned num_lights, light_t *lights) { + for (unsigned i = 0; i < num_lights; ++i) { + if (ui_collapse(va("Light %d", i), va("light_%d", i))) { + ui_light(&lights[i]); + ui_collapse_end(); + } + } +} + // ----------------------------------------------------------------------------- // shadowmaps +static inline +void shadowmap_init_common_resources(shadowmap_t *s, int vsm_texture_width, int csm_texture_width) { + // Create a cubemap depth texture + glGenTextures(1, &s->depth_texture); + glBindTexture(GL_TEXTURE_CUBE_MAP, s->depth_texture); + for (int i = 0; i < 6; i++) { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT, vsm_texture_width, vsm_texture_width, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); + } + + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); + + // Create a 2D depth texture + glGenTextures(1, &s->depth_texture_2d); + glBindTexture(GL_TEXTURE_2D, s->depth_texture_2d); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, csm_texture_width, csm_texture_width, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); + + glBindTexture(GL_TEXTURE_2D, 0); +} + static inline void shadowmap_init_caster_vsm(shadowmap_t *s, int light_index, int texture_width) { float borderColor[] = {1.0, 1.0, 1.0, 1.0}; @@ -1598,19 +1654,6 @@ shadowmap_init_caster_vsm(shadowmap_t *s, int light_index, int texture_width) { glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); glTexParameterfv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BORDER_COLOR, borderColor); - // Create a cubemap depth texture - glGenTextures(1, &s->maps[light_index].depth_texture); - glBindTexture(GL_TEXTURE_CUBE_MAP, s->maps[light_index].depth_texture); - for (int i = 0; i < 6; i++) { - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT, texture_width, texture_width, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); - } - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - glTexParameterfv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BORDER_COLOR, borderColor); - glBindTexture(GL_TEXTURE_CUBE_MAP, 0); } @@ -1632,15 +1675,6 @@ shadowmap_init_caster_csm(shadowmap_t *s, int light_index, int texture_width) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); - - glGenTextures(1, &s->maps[light_index].depth_texture_2d[i]); - glBindTexture(GL_TEXTURE_2D, s->maps[light_index].depth_texture_2d[i]); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, texture_width, texture_width, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); } glBindTexture(GL_TEXTURE_2D, 0); @@ -1691,6 +1725,8 @@ shadowmap_t shadowmap(int vsm_texture_width, int csm_texture_width) { // = 512, } #endif + shadowmap_init_common_resources(&s, vsm_texture_width, csm_texture_width); + glBindFramebuffer(GL_FRAMEBUFFER, s.saved_fb); return s; } @@ -1704,20 +1740,12 @@ void shadowmap_destroy_light(shadowmap_t *s, int light_index) { glDeleteTextures(1, &s->maps[light_index].texture); s->maps[light_index].texture = 0; } - if (s->maps[light_index].depth_texture) { - glDeleteTextures(1, &s->maps[light_index].depth_texture); - s->maps[light_index].depth_texture = 0; - } - + for (int i = 0; i < NUM_SHADOW_CASCADES; i++) { if (s->maps[light_index].texture_2d[i]) { glDeleteTextures(1, &s->maps[light_index].texture_2d[i]); s->maps[light_index].texture_2d[i] = 0; } - if (s->maps[light_index].depth_texture_2d[i]) { - glDeleteTextures(1, &s->maps[light_index].depth_texture_2d[i]); - s->maps[light_index].depth_texture_2d[i] = 0; - } } if (s->maps[light_index].blur_texture_2d) { @@ -1735,6 +1763,18 @@ void shadowmap_destroy(shadowmap_t *s) { for (int i = 0; i < MAX_LIGHTS; i++) { shadowmap_destroy_light(s, i); } + + + if (s->depth_texture) { + glDeleteTextures(1, &s->depth_texture); + s->depth_texture = 0; + } + + if (s->depth_texture_2d) { + glDeleteTextures(1, &s->depth_texture_2d); + s->depth_texture_2d = 0; + } + shadowmap_t z = {0}; *s = z; } @@ -1762,7 +1802,7 @@ void shadowmap_begin(shadowmap_t *s) { static void shadowmap_light_point(shadowmap_t *s, light_t *l, int dir) { if(dir<0) return; mat44 P, V, PV; - perspective44(P, 90.0f, 1.0f, l->shadow_bias, l->shadow_distance); + perspective44(P, 90.0f, 1.0f, l->shadow_near_clip, l->shadow_distance); vec3 lightPos = l->pos; /**/ if(dir == 0) lookat44(V, lightPos, add3(lightPos, vec3(+1, 0, 0)), vec3(0, -1, 0)); // +X @@ -1815,7 +1855,7 @@ static void shadowmap_light_directional(shadowmap_t *s, light_t *l, int dir, flo float near_plane = 0.0f; if (s->cascade_index == 0) { - near_plane = l->shadow_bias; + near_plane = l->shadow_near_clip; far_plane = l->shadow_distance * s->cascade_splits[0]; } else if (s->cascade_index < NUM_SHADOW_CASCADES - 1) { near_plane = l->shadow_distance * s->cascade_splits[s->cascade_index-1]; @@ -2130,12 +2170,12 @@ void shadowmap_light(shadowmap_t *s, light_t *l, mat44 cam_proj, mat44 cam_view) if (l->type == LIGHT_DIRECTIONAL) { glBindFramebuffer(GL_FRAMEBUFFER, s->fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s->maps[s->light_step].texture_2d[s->cascade_index], 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, s->maps[s->light_step].depth_texture_2d[s->cascade_index], 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, s->depth_texture_2d, 0); shadowmap_clear_fbo(); } else { glBindFramebuffer(GL_FRAMEBUFFER, s->fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + step, s->maps[s->light_step].texture, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + step, s->maps[s->light_step].depth_texture, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + step, s->depth_texture, 0); shadowmap_clear_fbo(); } @@ -2157,19 +2197,25 @@ void shadowmap_end(shadowmap_t *s) { { const int faces = 6; const int cascades = NUM_SHADOW_CASCADES; + + // Depth textures + s->vram_usage += s->vsm_texture_width * s->vsm_texture_width * faces * 1; + s->vram_usage += s->csm_texture_width * s->csm_texture_width * 1; + s->vram_usage_total += s->vsm_texture_width * s->vsm_texture_width * faces * 1; + s->vram_usage_vsm += s->vsm_texture_width * s->vsm_texture_width * faces * 8; + s->vram_usage_total += s->vsm_texture_width * s->vsm_texture_width * faces * 8; + s->vram_usage_csm += s->csm_texture_width * s->csm_texture_width * 1; + for (int i = 0; i < MAX_LIGHTS; i++) { // VSM textures if (s->maps[i].texture != 0) { // Color texture (GL_RG32F) s->vram_usage += s->vsm_texture_width * s->vsm_texture_width * faces * 8; // 8 bytes per pixel (2 * 32-bit float) - // Depth texture (GL_DEPTH_COMPONENT, assuming 8-bit depth) - s->vram_usage += s->vsm_texture_width * s->vsm_texture_width * faces * 1; } // Color texture (GL_RG32F) s->vram_usage_total += s->vsm_texture_width * s->vsm_texture_width * faces * 8; // 8 bytes per pixel (2 * 32-bit float) // Depth texture (GL_DEPTH_COMPONENT, assuming 8-bit depth) - s->vram_usage_total += s->vsm_texture_width * s->vsm_texture_width * faces * 1; // Color texture (GL_RG32F) s->vram_usage_vsm += s->vsm_texture_width * s->vsm_texture_width * faces * 8; // 8 bytes per pixel (2 * 32-bit float) @@ -2182,20 +2228,13 @@ void shadowmap_end(shadowmap_t *s) { for (int j = 0; j < cascades; j++) { // Color texture (GL_R32F) s->vram_usage += s->csm_texture_width * s->csm_texture_width * 4; // 4 bytes per pixel (1 * 32-bit float) - // Depth texture (GL_DEPTH_COMPONENT, assuming 8-bit depth) - s->vram_usage += s->csm_texture_width * s->csm_texture_width * 1; } } for (int j = 0; j < cascades; j++) { // Color texture (GL_R32F) s->vram_usage_total += s->csm_texture_width * s->csm_texture_width * 4; // 4 bytes per pixel (1 * 32-bit float) - // Depth texture (GL_DEPTH_COMPONENT, assuming 8-bit depth) - s->vram_usage_total += s->csm_texture_width * s->csm_texture_width * 1; - s->vram_usage_csm += s->csm_texture_width * s->csm_texture_width * 4; // 4 bytes per pixel (1 * 32-bit float) - // Depth texture (GL_DEPTH_COMPONENT, assuming 8-bit depth) - s->vram_usage_csm += s->csm_texture_width * s->csm_texture_width * 1; } // VSM blur texture (if used) @@ -2203,8 +2242,6 @@ void shadowmap_end(shadowmap_t *s) { s->vram_usage += s->vsm_texture_width * s->vsm_texture_width * faces * 8; // Assuming same format as VSM color texture } - s->vram_usage_total += s->vsm_texture_width * s->vsm_texture_width * faces * 8; // Assuming same format as VSM color texture - s->vram_usage_vsm += s->vsm_texture_width * s->vsm_texture_width * faces * 8; // Assuming same format as VSM color texture // CSM blur texture (if used) if (s->maps[i].blur_texture_2d != 0) { diff --git a/engine/split/v4k_render.h b/engine/split/v4k_render.h index 0473b41..7195707 100644 --- a/engine/split/v4k_render.h +++ b/engine/split/v4k_render.h @@ -302,7 +302,7 @@ enum SHADOW_TECHNIQUE { #define NUM_SHADOW_CASCADES 4 typedef struct light_t { - char type; + unsigned type; vec3 diffuse, specular, ambient; vec3 pos, dir; struct { @@ -315,14 +315,18 @@ typedef struct light_t { // Shadowmapping bool cast_shadows; - bool processed_shadows; unsigned shadow_technique; float shadow_distance; - float shadow_bias; + float shadow_near_clip; mat44 shadow_matrix[NUM_SHADOW_CASCADES]; + float min_variance; //< VSM + float variance_transition; //< VSM + float shadow_bias; //< CSM + float normal_bias; //< CSM // internals bool cached; //< used by scene to invalidate cached light data + bool processed_shadows; } light_t; API light_t light(); @@ -339,6 +343,10 @@ API void light_falloff(light_t* l, float constant, float linear, float quadra API void light_cone(light_t* l, float innerCone, float outerCone); API void light_update(unsigned num_lights, light_t *lv); +API void ui_light(light_t *l); +API void ui_lights(unsigned num_lights, light_t *lights); + + // ----------------------------------------------------------------------------- // shadowmaps @@ -368,11 +376,15 @@ typedef struct shadowmap_t { uint64_t vram_usage_vsm; uint64_t vram_usage_csm; + // depth texture + handle depth_texture; + handle depth_texture_2d; + struct { int gen; unsigned shadow_technique; - handle texture, depth_texture; - handle texture_2d[NUM_SHADOW_CASCADES], depth_texture_2d[NUM_SHADOW_CASCADES]; + handle texture; + handle texture_2d[NUM_SHADOW_CASCADES]; handle blur_texture, blur_texture_2d; // handle blur_fbo_cubemap, blur_texture_cubemap; float cascade_distances[NUM_SHADOW_CASCADES]; diff --git a/engine/split/v4k_ui.c b/engine/split/v4k_ui.c index 6ac2b49..5e47d86 100644 --- a/engine/split/v4k_ui.c +++ b/engine/split/v4k_ui.c @@ -2234,13 +2234,42 @@ int ui_short(const char *label, short *v) { return *v = (short)i, ret; } -int ui_float(const char *label, float *v) { +static inline +float ui_float_adjust_step(float step) { + if ((input(KEY_LSHIFT) || input(KEY_RSHIFT))&&(input(KEY_LCTRL) || input(KEY_RCTRL))) step *= 100.0f; + else if (input(KEY_LSHIFT) || input(KEY_RSHIFT)) step *= 10.0f; + else if (input(KEY_LCTRL) || input(KEY_RCTRL)) step *= 0.1f; + else if (input(KEY_LALT) || input(KEY_RALT)) step *= 0.01f; + return step; +} + +int ui_float_(const char *label, float *v, float step) { if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + float inc_per_pixel = ui_float_adjust_step(0.005f); + step = ui_float_adjust_step(step); + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); - float prev = v[0]; v[0] = nk_propertyf(ui_ctx, "#", -FLT_MAX, v[0], FLT_MAX, 0.01f,0.005f); + float prev = v[0]; v[0] = nk_propertyf(ui_ctx, "#", -FLT_MAX, v[0], FLT_MAX, step, inc_per_pixel); + return prev != v[0]; +} + +int ui_float(const char *label, float *v) { + return ui_float_(label, v, 0.01f); +} + +int ui_double_(const char *label, double *v, double step) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + + float inc_per_pixel = ui_float_adjust_step(0.005f); + step = ui_float_adjust_step(step); + + nk_layout_row_dynamic(ui_ctx, 0, 2); + ui_label_(label, NK_TEXT_LEFT); + + double prev = v[0]; v[0] = nk_propertyd(ui_ctx, "#", -DBL_MAX, v[0], DBL_MAX, step, inc_per_pixel); return prev != v[0]; } @@ -2254,21 +2283,30 @@ int ui_double(const char *label, double *v) { return prev != v[0]; } -int ui_clampf(const char *label, float *v, float minf, float maxf) { +int ui_clampf_(const char *label, float *v, float minf, float maxf, float step) { if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + float inc_per_pixel = ui_float_adjust_step(0.005f); + step = ui_float_adjust_step(step); + if( minf > maxf ) return ui_clampf(label, v, maxf, minf); nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); - float prev = v[0]; v[0] = nk_propertyf(ui_ctx, "#", minf, v[0], maxf, 0.1f,0.05f); + float prev = v[0]; v[0] = nk_propertyf(ui_ctx, "#", minf, v[0], maxf, step, inc_per_pixel); return prev != v[0]; } -int ui_float2(const char *label, float *v) { +int ui_clampf(const char *label, float *v, float minf, float maxf) { + return ui_clampf_(label, v, minf, maxf, 0.1f); +} + +int ui_float2_(const char *label, float *v, float step) { if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + float inc_per_pixel = ui_float_adjust_step(0.5f); + step = ui_float_adjust_step(step); nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -2278,17 +2316,23 @@ int ui_float2(const char *label, float *v) { if (nk_combo_begin_label(ui_ctx, buffer, nk_vec2(200,200))) { nk_layout_row_dynamic(ui_ctx, 0, 1); - float prev0 = v[0]; nk_property_float(ui_ctx, "#X:", -FLT_MAX, &v[0], FLT_MAX, 1,0.5f); - float prev1 = v[1]; nk_property_float(ui_ctx, "#Y:", -FLT_MAX, &v[1], FLT_MAX, 1,0.5f); + float prev0 = v[0]; nk_property_float(ui_ctx, "#X:", -FLT_MAX, &v[0], FLT_MAX, step, inc_per_pixel); + float prev1 = v[1]; nk_property_float(ui_ctx, "#Y:", -FLT_MAX, &v[1], FLT_MAX, step, inc_per_pixel); nk_combo_end(ui_ctx); return prev0 != v[0] || prev1 != v[1]; } return 0; } -int ui_float3(const char *label, float *v) { +int ui_float2(const char *label, float *v) { + return ui_float2_(label, v, 1.0f); +} + +int ui_float3_(const char *label, float *v, float step) { if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + float inc_per_pixel = ui_float_adjust_step(0.5f); + step = ui_float_adjust_step(step); nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -2298,18 +2342,25 @@ int ui_float3(const char *label, float *v) { if (nk_combo_begin_label(ui_ctx, buffer, nk_vec2(200,200))) { nk_layout_row_dynamic(ui_ctx, 0, 1); - float prev0 = v[0]; nk_property_float(ui_ctx, "#X:", -FLT_MAX, &v[0], FLT_MAX, 1,0.5f); - float prev1 = v[1]; nk_property_float(ui_ctx, "#Y:", -FLT_MAX, &v[1], FLT_MAX, 1,0.5f); - float prev2 = v[2]; nk_property_float(ui_ctx, "#Z:", -FLT_MAX, &v[2], FLT_MAX, 1,0.5f); + float prev0 = v[0]; nk_property_float(ui_ctx, "#X:", -FLT_MAX, &v[0], FLT_MAX, step, inc_per_pixel); + float prev1 = v[1]; nk_property_float(ui_ctx, "#Y:", -FLT_MAX, &v[1], FLT_MAX, step, inc_per_pixel); + float prev2 = v[2]; nk_property_float(ui_ctx, "#Z:", -FLT_MAX, &v[2], FLT_MAX, step, inc_per_pixel); nk_combo_end(ui_ctx); return prev0 != v[0] || prev1 != v[1] || prev2 != v[2]; } return 0; } -int ui_float4(const char *label, float *v) { + +int ui_float3(const char *label, float *v) { + return ui_float3_(label, v, 1.0f); +} + +int ui_float4_(const char *label, float *v, float step) { if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + float inc_per_pixel = ui_float_adjust_step(0.5f); + step = ui_float_adjust_step(step); nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -2319,10 +2370,10 @@ int ui_float4(const char *label, float *v) { if (nk_combo_begin_label(ui_ctx, buffer, nk_vec2(200,200))) { nk_layout_row_dynamic(ui_ctx, 0, 1); - float prev0 = v[0]; nk_property_float(ui_ctx, "#X:", -FLT_MAX, &v[0], FLT_MAX, 1,0.5f); - float prev1 = v[1]; nk_property_float(ui_ctx, "#Y:", -FLT_MAX, &v[1], FLT_MAX, 1,0.5f); - float prev2 = v[2]; nk_property_float(ui_ctx, "#Z:", -FLT_MAX, &v[2], FLT_MAX, 1,0.5f); - float prev3 = v[3]; nk_property_float(ui_ctx, "#W:", -FLT_MAX, &v[3], FLT_MAX, 1,0.5f); + float prev0 = v[0]; nk_property_float(ui_ctx, "#X:", -FLT_MAX, &v[0], FLT_MAX, step, inc_per_pixel); + float prev1 = v[1]; nk_property_float(ui_ctx, "#Y:", -FLT_MAX, &v[1], FLT_MAX, step, inc_per_pixel); + float prev2 = v[2]; nk_property_float(ui_ctx, "#Z:", -FLT_MAX, &v[2], FLT_MAX, step, inc_per_pixel); + float prev3 = v[3]; nk_property_float(ui_ctx, "#W:", -FLT_MAX, &v[3], FLT_MAX, step, inc_per_pixel); nk_combo_end(ui_ctx); return prev0 != v[0] || prev1 != v[1] || prev2 != v[2] || prev3 != v[3]; } @@ -2330,6 +2381,10 @@ int ui_float4(const char *label, float *v) { return 0; } +int ui_float4(const char *label, float *v) { + return ui_float4_(label, v, 1.0f); +} + int ui_mat33(const char *label, float M[9]) { if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; diff --git a/engine/split/v4k_ui.h b/engine/split/v4k_ui.h index d83f433..645a03d 100644 --- a/engine/split/v4k_ui.h +++ b/engine/split/v4k_ui.h @@ -19,6 +19,10 @@ API int ui_section(const char *title); API int ui_int(const char *label, int *value); API int ui_bool(const char *label, bool *value); API int ui_short(const char *label, short *value); +API int ui_float_(const char *label, float *value, float step); +API int ui_float2_(const char *label, float value[2], float step); +API int ui_float3_(const char *label, float value[3], float step); +API int ui_float4_(const char *label, float value[4], float step); API int ui_float(const char *label, float *value); API int ui_float2(const char *label, float value[2]); API int ui_float3(const char *label, float value[3]); @@ -55,6 +59,7 @@ API int ui_separator(); API int ui_bitmask8(const char *label, uint8_t *bits); API int ui_bitmask16(const char *label, uint16_t *bits); API int ui_console(); +API int ui_clampf_(const char *label, float *value, float minf, float maxf, float step); API int ui_clampf(const char *label, float *value, float minf, float maxf); API int ui_label(const char *label); API int ui_label2(const char *label, const char *caption); diff --git a/engine/v4k b/engine/v4k index c2aa9e2..d424925 100644 --- a/engine/v4k +++ b/engine/v4k @@ -209788,6 +209788,8 @@ struct nk_context { #define NK_PI 3.141592654f #define NK_UTF_INVALID 0xFFFD #define NK_MAX_FLOAT_PRECISION 2 +#define NK_MAX_FLOAT_PRECISION2 6 +#define NK_FLOAT_DECIMAL_POS_THRESHOLD 0.0005 #define NK_UNUSED(x) ((void)(x)) #define NK_SATURATE(x) (NK_MAX(0, NK_MIN(1.0f, x))) @@ -232246,11 +232248,11 @@ nk_do_property(nk_flags *ws, break; case NK_PROPERTY_FLOAT: NK_DTOA(string, (double)variant->value.f); - num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION); + num_len = nk_string_float_limit(string, variant->step.f <= NK_FLOAT_DECIMAL_POS_THRESHOLD ? NK_MAX_FLOAT_PRECISION2 : NK_MAX_FLOAT_PRECISION); break; case NK_PROPERTY_DOUBLE: NK_DTOA(string, variant->value.d); - num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION); + num_len = nk_string_float_limit(string, variant->step.f <= NK_FLOAT_DECIMAL_POS_THRESHOLD ? NK_MAX_FLOAT_PRECISION2 : NK_MAX_FLOAT_PRECISION); break; } size = font->width(font->userdata, font->height, string, num_len); @@ -232346,12 +232348,12 @@ nk_do_property(nk_flags *ws, variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i, variant->max_value.i); break; case NK_PROPERTY_FLOAT: - nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION); + nk_string_float_limit(buffer, variant->step.f <= NK_FLOAT_DECIMAL_POS_THRESHOLD ? NK_MAX_FLOAT_PRECISION2 : NK_MAX_FLOAT_PRECISION); variant->value.f = nk_strtof(buffer, 0); variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f, variant->max_value.f); break; case NK_PROPERTY_DOUBLE: - nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION); + nk_string_float_limit(buffer, variant->step.f <= NK_FLOAT_DECIMAL_POS_THRESHOLD ? NK_MAX_FLOAT_PRECISION2 : NK_MAX_FLOAT_PRECISION); variant->value.d = nk_strtod(buffer, 0); variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d); break; diff --git a/engine/v4k.c b/engine/v4k.c index ddeada8..4c03c68 100644 --- a/engine/v4k.c +++ b/engine/v4k.c @@ -3442,13 +3442,42 @@ int ui_short(const char *label, short *v) { return *v = (short)i, ret; } -int ui_float(const char *label, float *v) { +static inline +float ui_float_adjust_step(float step) { + if ((input(KEY_LSHIFT) || input(KEY_RSHIFT))&&(input(KEY_LCTRL) || input(KEY_RCTRL))) step *= 100.0f; + else if (input(KEY_LSHIFT) || input(KEY_RSHIFT)) step *= 10.0f; + else if (input(KEY_LCTRL) || input(KEY_RCTRL)) step *= 0.1f; + else if (input(KEY_LALT) || input(KEY_RALT)) step *= 0.01f; + return step; +} + +int ui_float_(const char *label, float *v, float step) { if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + float inc_per_pixel = ui_float_adjust_step(0.005f); + step = ui_float_adjust_step(step); + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); - float prev = v[0]; v[0] = nk_propertyf(ui_ctx, "#", -FLT_MAX, v[0], FLT_MAX, 0.01f,0.005f); + float prev = v[0]; v[0] = nk_propertyf(ui_ctx, "#", -FLT_MAX, v[0], FLT_MAX, step, inc_per_pixel); + return prev != v[0]; +} + +int ui_float(const char *label, float *v) { + return ui_float_(label, v, 0.01f); +} + +int ui_double_(const char *label, double *v, double step) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + + float inc_per_pixel = ui_float_adjust_step(0.005f); + step = ui_float_adjust_step(step); + + nk_layout_row_dynamic(ui_ctx, 0, 2); + ui_label_(label, NK_TEXT_LEFT); + + double prev = v[0]; v[0] = nk_propertyd(ui_ctx, "#", -DBL_MAX, v[0], DBL_MAX, step, inc_per_pixel); return prev != v[0]; } @@ -3462,21 +3491,30 @@ int ui_double(const char *label, double *v) { return prev != v[0]; } -int ui_clampf(const char *label, float *v, float minf, float maxf) { +int ui_clampf_(const char *label, float *v, float minf, float maxf, float step) { if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + float inc_per_pixel = ui_float_adjust_step(0.005f); + step = ui_float_adjust_step(step); + if( minf > maxf ) return ui_clampf(label, v, maxf, minf); nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); - float prev = v[0]; v[0] = nk_propertyf(ui_ctx, "#", minf, v[0], maxf, 0.1f,0.05f); + float prev = v[0]; v[0] = nk_propertyf(ui_ctx, "#", minf, v[0], maxf, step, inc_per_pixel); return prev != v[0]; } -int ui_float2(const char *label, float *v) { +int ui_clampf(const char *label, float *v, float minf, float maxf) { + return ui_clampf_(label, v, minf, maxf, 0.1f); +} + +int ui_float2_(const char *label, float *v, float step) { if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + float inc_per_pixel = ui_float_adjust_step(0.5f); + step = ui_float_adjust_step(step); nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -3486,17 +3524,23 @@ int ui_float2(const char *label, float *v) { if (nk_combo_begin_label(ui_ctx, buffer, nk_vec2(200,200))) { nk_layout_row_dynamic(ui_ctx, 0, 1); - float prev0 = v[0]; nk_property_float(ui_ctx, "#X:", -FLT_MAX, &v[0], FLT_MAX, 1,0.5f); - float prev1 = v[1]; nk_property_float(ui_ctx, "#Y:", -FLT_MAX, &v[1], FLT_MAX, 1,0.5f); + float prev0 = v[0]; nk_property_float(ui_ctx, "#X:", -FLT_MAX, &v[0], FLT_MAX, step, inc_per_pixel); + float prev1 = v[1]; nk_property_float(ui_ctx, "#Y:", -FLT_MAX, &v[1], FLT_MAX, step, inc_per_pixel); nk_combo_end(ui_ctx); return prev0 != v[0] || prev1 != v[1]; } return 0; } -int ui_float3(const char *label, float *v) { +int ui_float2(const char *label, float *v) { + return ui_float2_(label, v, 1.0f); +} + +int ui_float3_(const char *label, float *v, float step) { if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + float inc_per_pixel = ui_float_adjust_step(0.5f); + step = ui_float_adjust_step(step); nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -3506,18 +3550,25 @@ int ui_float3(const char *label, float *v) { if (nk_combo_begin_label(ui_ctx, buffer, nk_vec2(200,200))) { nk_layout_row_dynamic(ui_ctx, 0, 1); - float prev0 = v[0]; nk_property_float(ui_ctx, "#X:", -FLT_MAX, &v[0], FLT_MAX, 1,0.5f); - float prev1 = v[1]; nk_property_float(ui_ctx, "#Y:", -FLT_MAX, &v[1], FLT_MAX, 1,0.5f); - float prev2 = v[2]; nk_property_float(ui_ctx, "#Z:", -FLT_MAX, &v[2], FLT_MAX, 1,0.5f); + float prev0 = v[0]; nk_property_float(ui_ctx, "#X:", -FLT_MAX, &v[0], FLT_MAX, step, inc_per_pixel); + float prev1 = v[1]; nk_property_float(ui_ctx, "#Y:", -FLT_MAX, &v[1], FLT_MAX, step, inc_per_pixel); + float prev2 = v[2]; nk_property_float(ui_ctx, "#Z:", -FLT_MAX, &v[2], FLT_MAX, step, inc_per_pixel); nk_combo_end(ui_ctx); return prev0 != v[0] || prev1 != v[1] || prev2 != v[2]; } return 0; } -int ui_float4(const char *label, float *v) { + +int ui_float3(const char *label, float *v) { + return ui_float3_(label, v, 1.0f); +} + +int ui_float4_(const char *label, float *v, float step) { if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + float inc_per_pixel = ui_float_adjust_step(0.5f); + step = ui_float_adjust_step(step); nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -3527,10 +3578,10 @@ int ui_float4(const char *label, float *v) { if (nk_combo_begin_label(ui_ctx, buffer, nk_vec2(200,200))) { nk_layout_row_dynamic(ui_ctx, 0, 1); - float prev0 = v[0]; nk_property_float(ui_ctx, "#X:", -FLT_MAX, &v[0], FLT_MAX, 1,0.5f); - float prev1 = v[1]; nk_property_float(ui_ctx, "#Y:", -FLT_MAX, &v[1], FLT_MAX, 1,0.5f); - float prev2 = v[2]; nk_property_float(ui_ctx, "#Z:", -FLT_MAX, &v[2], FLT_MAX, 1,0.5f); - float prev3 = v[3]; nk_property_float(ui_ctx, "#W:", -FLT_MAX, &v[3], FLT_MAX, 1,0.5f); + float prev0 = v[0]; nk_property_float(ui_ctx, "#X:", -FLT_MAX, &v[0], FLT_MAX, step, inc_per_pixel); + float prev1 = v[1]; nk_property_float(ui_ctx, "#Y:", -FLT_MAX, &v[1], FLT_MAX, step, inc_per_pixel); + float prev2 = v[2]; nk_property_float(ui_ctx, "#Z:", -FLT_MAX, &v[2], FLT_MAX, step, inc_per_pixel); + float prev3 = v[3]; nk_property_float(ui_ctx, "#W:", -FLT_MAX, &v[3], FLT_MAX, step, inc_per_pixel); nk_combo_end(ui_ctx); return prev0 != v[0] || prev1 != v[1] || prev2 != v[2] || prev3 != v[3]; } @@ -3538,6 +3589,10 @@ int ui_float4(const char *label, float *v) { return 0; } +int ui_float4(const char *label, float *v) { + return ui_float4_(label, v, 1.0f); +} + int ui_mat33(const char *label, float M[9]) { if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; @@ -18282,7 +18337,11 @@ light_t light() { l.cast_shadows = true; l.processed_shadows = false; l.shadow_distance = 200.0f; - l.shadow_bias = 0.01f; + l.shadow_near_clip = 0.01f; + l.shadow_bias = 0.005f; + l.normal_bias = 0.05f; + l.min_variance = 0.00002f; + l.variance_transition = 0.2f; return l; } @@ -18361,6 +18420,10 @@ void light_update(unsigned num_lights, light_t *lv) { shader_float(va("u_lights[%d].quadratic", i), lv[i].falloff.quadratic); shader_float(va("u_lights[%d].innerCone", i), lv[i].innerCone); shader_float(va("u_lights[%d].outerCone", i), lv[i].outerCone); + shader_float(va("u_lights[%d].shadow_bias", i), lv[i].shadow_bias); + shader_float(va("u_lights[%d].normal_bias", i), lv[i].normal_bias); + shader_float(va("u_lights[%d].min_variance", i), lv[i].min_variance); + shader_float(va("u_lights[%d].variance_transition", i), lv[i].variance_transition); shader_bool(va("u_lights[%d].processed_shadows", i), lv[i].processed_shadows); if (lv[i].processed_shadows) { for (int j = 0; j < NUM_SHADOW_CASCADES; j++) { @@ -18370,10 +18433,58 @@ void light_update(unsigned num_lights, light_t *lv) { } } +void ui_light(light_t *l) { + ui_int("Type", &l->type); + ui_vec3("Position", &l->pos); + ui_vec3("Direction", &l->dir); + ui_color3f("Diffuse", &l->diffuse.x); + ui_color3f("Specular", &l->specular.x); + ui_color3f("Ambient", &l->ambient.x); + ui_float("Specular Power", &l->specularPower); + ui_clampf("Radius", &l->radius, 0.0f, FLT_MAX); + ui_clampf_("Constant Falloff", &l->falloff.constant, 0.0, FLT_MAX, 0.005); + ui_clampf_("Linear Falloff", &l->falloff.linear, 0.0, FLT_MAX, 0.005); + ui_clampf_("Quadratic Falloff", &l->falloff.quadratic, 0.0, FLT_MAX, 0.005); + ui_float("Inner Cone", &l->innerCone); + ui_float("Outer Cone", &l->outerCone); + ui_float_("Shadow Bias", &l->shadow_bias, 0.00005); + ui_float_("Normal Bias", &l->normal_bias, 0.00005); + ui_float_("Min Variance", &l->min_variance, 0.00005); + ui_float_("Variance Transition", &l->variance_transition, 0.0005); +} + +void ui_lights(unsigned num_lights, light_t *lights) { + for (unsigned i = 0; i < num_lights; ++i) { + if (ui_collapse(va("Light %d", i), va("light_%d", i))) { + ui_light(&lights[i]); + ui_collapse_end(); + } + } +} + // ----------------------------------------------------------------------------- // shadowmaps +static inline +void shadowmap_init_common_resources(shadowmap_t *s, int vsm_texture_width, int csm_texture_width) { + // Create a cubemap depth texture + glGenTextures(1, &s->depth_texture); + glBindTexture(GL_TEXTURE_CUBE_MAP, s->depth_texture); + for (int i = 0; i < 6; i++) { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT, vsm_texture_width, vsm_texture_width, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); + } + + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); + + // Create a 2D depth texture + glGenTextures(1, &s->depth_texture_2d); + glBindTexture(GL_TEXTURE_2D, s->depth_texture_2d); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, csm_texture_width, csm_texture_width, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); + + glBindTexture(GL_TEXTURE_2D, 0); +} + static inline void shadowmap_init_caster_vsm(shadowmap_t *s, int light_index, int texture_width) { float borderColor[] = {1.0, 1.0, 1.0, 1.0}; @@ -18397,19 +18508,6 @@ shadowmap_init_caster_vsm(shadowmap_t *s, int light_index, int texture_width) { glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); glTexParameterfv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BORDER_COLOR, borderColor); - // Create a cubemap depth texture - glGenTextures(1, &s->maps[light_index].depth_texture); - glBindTexture(GL_TEXTURE_CUBE_MAP, s->maps[light_index].depth_texture); - for (int i = 0; i < 6; i++) { - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT, texture_width, texture_width, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); - } - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - glTexParameterfv(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BORDER_COLOR, borderColor); - glBindTexture(GL_TEXTURE_CUBE_MAP, 0); } @@ -18431,15 +18529,6 @@ shadowmap_init_caster_csm(shadowmap_t *s, int light_index, int texture_width) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); - - glGenTextures(1, &s->maps[light_index].depth_texture_2d[i]); - glBindTexture(GL_TEXTURE_2D, s->maps[light_index].depth_texture_2d[i]); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, texture_width, texture_width, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); } glBindTexture(GL_TEXTURE_2D, 0); @@ -18490,6 +18579,8 @@ shadowmap_t shadowmap(int vsm_texture_width, int csm_texture_width) { // = 512, } #endif + shadowmap_init_common_resources(&s, vsm_texture_width, csm_texture_width); + glBindFramebuffer(GL_FRAMEBUFFER, s.saved_fb); return s; } @@ -18503,20 +18594,12 @@ void shadowmap_destroy_light(shadowmap_t *s, int light_index) { glDeleteTextures(1, &s->maps[light_index].texture); s->maps[light_index].texture = 0; } - if (s->maps[light_index].depth_texture) { - glDeleteTextures(1, &s->maps[light_index].depth_texture); - s->maps[light_index].depth_texture = 0; - } - + for (int i = 0; i < NUM_SHADOW_CASCADES; i++) { if (s->maps[light_index].texture_2d[i]) { glDeleteTextures(1, &s->maps[light_index].texture_2d[i]); s->maps[light_index].texture_2d[i] = 0; } - if (s->maps[light_index].depth_texture_2d[i]) { - glDeleteTextures(1, &s->maps[light_index].depth_texture_2d[i]); - s->maps[light_index].depth_texture_2d[i] = 0; - } } if (s->maps[light_index].blur_texture_2d) { @@ -18534,6 +18617,18 @@ void shadowmap_destroy(shadowmap_t *s) { for (int i = 0; i < MAX_LIGHTS; i++) { shadowmap_destroy_light(s, i); } + + + if (s->depth_texture) { + glDeleteTextures(1, &s->depth_texture); + s->depth_texture = 0; + } + + if (s->depth_texture_2d) { + glDeleteTextures(1, &s->depth_texture_2d); + s->depth_texture_2d = 0; + } + shadowmap_t z = {0}; *s = z; } @@ -18561,7 +18656,7 @@ void shadowmap_begin(shadowmap_t *s) { static void shadowmap_light_point(shadowmap_t *s, light_t *l, int dir) { if(dir<0) return; mat44 P, V, PV; - perspective44(P, 90.0f, 1.0f, l->shadow_bias, l->shadow_distance); + perspective44(P, 90.0f, 1.0f, l->shadow_near_clip, l->shadow_distance); vec3 lightPos = l->pos; /**/ if(dir == 0) lookat44(V, lightPos, add3(lightPos, vec3(+1, 0, 0)), vec3(0, -1, 0)); // +X @@ -18614,7 +18709,7 @@ static void shadowmap_light_directional(shadowmap_t *s, light_t *l, int dir, flo float near_plane = 0.0f; if (s->cascade_index == 0) { - near_plane = l->shadow_bias; + near_plane = l->shadow_near_clip; far_plane = l->shadow_distance * s->cascade_splits[0]; } else if (s->cascade_index < NUM_SHADOW_CASCADES - 1) { near_plane = l->shadow_distance * s->cascade_splits[s->cascade_index-1]; @@ -18929,12 +19024,12 @@ void shadowmap_light(shadowmap_t *s, light_t *l, mat44 cam_proj, mat44 cam_view) if (l->type == LIGHT_DIRECTIONAL) { glBindFramebuffer(GL_FRAMEBUFFER, s->fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, s->maps[s->light_step].texture_2d[s->cascade_index], 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, s->maps[s->light_step].depth_texture_2d[s->cascade_index], 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, s->depth_texture_2d, 0); shadowmap_clear_fbo(); } else { glBindFramebuffer(GL_FRAMEBUFFER, s->fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + step, s->maps[s->light_step].texture, 0); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + step, s->maps[s->light_step].depth_texture, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + step, s->depth_texture, 0); shadowmap_clear_fbo(); } @@ -18956,19 +19051,25 @@ void shadowmap_end(shadowmap_t *s) { { const int faces = 6; const int cascades = NUM_SHADOW_CASCADES; + + // Depth textures + s->vram_usage += s->vsm_texture_width * s->vsm_texture_width * faces * 1; + s->vram_usage += s->csm_texture_width * s->csm_texture_width * 1; + s->vram_usage_total += s->vsm_texture_width * s->vsm_texture_width * faces * 1; + s->vram_usage_vsm += s->vsm_texture_width * s->vsm_texture_width * faces * 8; + s->vram_usage_total += s->vsm_texture_width * s->vsm_texture_width * faces * 8; + s->vram_usage_csm += s->csm_texture_width * s->csm_texture_width * 1; + for (int i = 0; i < MAX_LIGHTS; i++) { // VSM textures if (s->maps[i].texture != 0) { // Color texture (GL_RG32F) s->vram_usage += s->vsm_texture_width * s->vsm_texture_width * faces * 8; // 8 bytes per pixel (2 * 32-bit float) - // Depth texture (GL_DEPTH_COMPONENT, assuming 8-bit depth) - s->vram_usage += s->vsm_texture_width * s->vsm_texture_width * faces * 1; } // Color texture (GL_RG32F) s->vram_usage_total += s->vsm_texture_width * s->vsm_texture_width * faces * 8; // 8 bytes per pixel (2 * 32-bit float) // Depth texture (GL_DEPTH_COMPONENT, assuming 8-bit depth) - s->vram_usage_total += s->vsm_texture_width * s->vsm_texture_width * faces * 1; // Color texture (GL_RG32F) s->vram_usage_vsm += s->vsm_texture_width * s->vsm_texture_width * faces * 8; // 8 bytes per pixel (2 * 32-bit float) @@ -18981,20 +19082,13 @@ void shadowmap_end(shadowmap_t *s) { for (int j = 0; j < cascades; j++) { // Color texture (GL_R32F) s->vram_usage += s->csm_texture_width * s->csm_texture_width * 4; // 4 bytes per pixel (1 * 32-bit float) - // Depth texture (GL_DEPTH_COMPONENT, assuming 8-bit depth) - s->vram_usage += s->csm_texture_width * s->csm_texture_width * 1; } } for (int j = 0; j < cascades; j++) { // Color texture (GL_R32F) s->vram_usage_total += s->csm_texture_width * s->csm_texture_width * 4; // 4 bytes per pixel (1 * 32-bit float) - // Depth texture (GL_DEPTH_COMPONENT, assuming 8-bit depth) - s->vram_usage_total += s->csm_texture_width * s->csm_texture_width * 1; - s->vram_usage_csm += s->csm_texture_width * s->csm_texture_width * 4; // 4 bytes per pixel (1 * 32-bit float) - // Depth texture (GL_DEPTH_COMPONENT, assuming 8-bit depth) - s->vram_usage_csm += s->csm_texture_width * s->csm_texture_width * 1; } // VSM blur texture (if used) @@ -19002,8 +19096,6 @@ void shadowmap_end(shadowmap_t *s) { s->vram_usage += s->vsm_texture_width * s->vsm_texture_width * faces * 8; // Assuming same format as VSM color texture } - s->vram_usage_total += s->vsm_texture_width * s->vsm_texture_width * faces * 8; // Assuming same format as VSM color texture - s->vram_usage_vsm += s->vsm_texture_width * s->vsm_texture_width * faces * 8; // Assuming same format as VSM color texture // CSM blur texture (if used) if (s->maps[i].blur_texture_2d != 0) { diff --git a/engine/v4k.h b/engine/v4k.h index eaae701..b0f299d 100644 --- a/engine/v4k.h +++ b/engine/v4k.h @@ -3337,7 +3337,7 @@ enum SHADOW_TECHNIQUE { #define NUM_SHADOW_CASCADES 4 typedef struct light_t { - char type; + unsigned type; vec3 diffuse, specular, ambient; vec3 pos, dir; struct { @@ -3350,14 +3350,18 @@ typedef struct light_t { // Shadowmapping bool cast_shadows; - bool processed_shadows; unsigned shadow_technique; float shadow_distance; - float shadow_bias; + float shadow_near_clip; mat44 shadow_matrix[NUM_SHADOW_CASCADES]; + float min_variance; //< VSM + float variance_transition; //< VSM + float shadow_bias; //< CSM + float normal_bias; //< CSM // internals bool cached; //< used by scene to invalidate cached light data + bool processed_shadows; } light_t; API light_t light(); @@ -3374,6 +3378,10 @@ API void light_falloff(light_t* l, float constant, float linear, float quadra API void light_cone(light_t* l, float innerCone, float outerCone); API void light_update(unsigned num_lights, light_t *lv); +API void ui_light(light_t *l); +API void ui_lights(unsigned num_lights, light_t *lights); + + // ----------------------------------------------------------------------------- // shadowmaps @@ -3403,11 +3411,15 @@ typedef struct shadowmap_t { uint64_t vram_usage_vsm; uint64_t vram_usage_csm; + // depth texture + handle depth_texture; + handle depth_texture_2d; + struct { int gen; unsigned shadow_technique; - handle texture, depth_texture; - handle texture_2d[NUM_SHADOW_CASCADES], depth_texture_2d[NUM_SHADOW_CASCADES]; + handle texture; + handle texture_2d[NUM_SHADOW_CASCADES]; handle blur_texture, blur_texture_2d; // handle blur_fbo_cubemap, blur_texture_cubemap; float cascade_distances[NUM_SHADOW_CASCADES]; @@ -4766,6 +4778,10 @@ API int ui_section(const char *title); API int ui_int(const char *label, int *value); API int ui_bool(const char *label, bool *value); API int ui_short(const char *label, short *value); +API int ui_float_(const char *label, float *value, float step); +API int ui_float2_(const char *label, float value[2], float step); +API int ui_float3_(const char *label, float value[3], float step); +API int ui_float4_(const char *label, float value[4], float step); API int ui_float(const char *label, float *value); API int ui_float2(const char *label, float value[2]); API int ui_float3(const char *label, float value[3]); @@ -4802,6 +4818,7 @@ API int ui_separator(); API int ui_bitmask8(const char *label, uint8_t *bits); API int ui_bitmask16(const char *label, uint16_t *bits); API int ui_console(); +API int ui_clampf_(const char *label, float *value, float minf, float maxf, float step); API int ui_clampf(const char *label, float *value, float minf, float maxf); API int ui_label(const char *label); API int ui_label2(const char *label, const char *caption);