diff options
author | Juan Linietsky <reduzio@gmail.com> | 2016-11-09 23:55:06 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2016-11-09 23:55:06 -0300 |
commit | cacf9ebb7fd8df8845daca9da2fe55456cc179aa (patch) | |
tree | 5881cb42ace5001916e9d1843f5a7acbc35332a6 /drivers/gles3 | |
parent | 6b2a27bbe5fa112365fc88b9b4678a61293bcb53 (diff) |
all light types and shadows are working, pending a lot of clean-up
Diffstat (limited to 'drivers/gles3')
-rw-r--r-- | drivers/gles3/rasterizer_canvas_gles3.cpp | 2 | ||||
-rw-r--r-- | drivers/gles3/rasterizer_scene_gles3.cpp | 1043 | ||||
-rw-r--r-- | drivers/gles3/rasterizer_scene_gles3.h | 74 | ||||
-rw-r--r-- | drivers/gles3/rasterizer_storage_gles3.cpp | 324 | ||||
-rw-r--r-- | drivers/gles3/rasterizer_storage_gles3.h | 101 | ||||
-rw-r--r-- | drivers/gles3/shader_compiler_gles3.cpp | 15 | ||||
-rw-r--r-- | drivers/gles3/shader_compiler_gles3.h | 7 | ||||
-rw-r--r-- | drivers/gles3/shaders/SCsub | 1 | ||||
-rw-r--r-- | drivers/gles3/shaders/cube_to_dp.glsl | 79 | ||||
-rw-r--r-- | drivers/gles3/shaders/scene.glsl | 341 |
10 files changed, 1678 insertions, 309 deletions
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index c10c5fee65..c455d4bd11 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -824,8 +824,6 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list,int p_z,const bool prev_distance_field=false; - - while(p_item_list) { Item *ci=p_item_list; diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 93dc01d473..287801b597 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1,8 +1,18 @@ #include "rasterizer_scene_gles3.h" #include "globals.h" #include "os/os.h" +#include "rasterizer_canvas_gles3.h" +static const GLenum _cube_side_enum[6]={ + GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + GL_TEXTURE_CUBE_MAP_POSITIVE_X, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, + +}; static _FORCE_INLINE_ void store_matrix32(const Matrix32& p_mtx, float* p_array) { @@ -78,6 +88,9 @@ void RasterizerSceneGLES3::shadow_atlas_set_size(RID p_atlas,int p_size){ ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas); ERR_FAIL_COND(!shadow_atlas); ERR_FAIL_COND(p_size<0); + + p_size = nearest_power_of_2(p_size); + if (p_size==shadow_atlas->size) return; @@ -104,7 +117,7 @@ void RasterizerSceneGLES3::shadow_atlas_set_size(RID p_atlas,int p_size){ //clear owners shadow_atlas->shadow_owners.clear(); - shadow_atlas->size=nearest_power_of_2(p_size); + shadow_atlas->size=p_size; if (shadow_atlas->size) { glGenFramebuffers(1, &shadow_atlas->fbo); @@ -188,7 +201,7 @@ void RasterizerSceneGLES3::shadow_atlas_set_quadrant_subdivision(RID p_atlas,int swaps=0; for(int i=0;i<3;i++) { - if (shadow_atlas->quadrants[shadow_atlas->size_order[i]].subdivision > shadow_atlas->quadrants[shadow_atlas->size_order[i+1]].subdivision) { + if (shadow_atlas->quadrants[shadow_atlas->size_order[i]].subdivision < shadow_atlas->quadrants[shadow_atlas->size_order[i+1]].subdivision) { SWAP(shadow_atlas->size_order[i],shadow_atlas->size_order[i+1]); swaps++; } @@ -260,20 +273,22 @@ bool RasterizerSceneGLES3::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas,i } -uint32_t RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version){ +bool RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version){ + ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas); - ERR_FAIL_COND_V(!shadow_atlas,ShadowAtlas::SHADOW_INVALID); + ERR_FAIL_COND_V(!shadow_atlas,false); LightInstance *li = light_instance_owner.getornull(p_light_intance); - ERR_FAIL_COND_V(!li,ShadowAtlas::SHADOW_INVALID); + ERR_FAIL_COND_V(!li,false); if (shadow_atlas->size==0 || shadow_atlas->smallest_subdiv==0) { - return ShadowAtlas::SHADOW_INVALID; + return false; } uint32_t quad_size = shadow_atlas->size>>1; - int desired_fit = MAX(quad_size/shadow_atlas->smallest_subdiv,nearest_power_of_2(quad_size*p_coverage)); + int desired_fit = MIN(quad_size/shadow_atlas->smallest_subdiv,nearest_power_of_2(quad_size*p_coverage)); + int valid_quadrants[4]; int valid_quadrant_count=0; @@ -300,8 +315,7 @@ uint32_t RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_ligh } } - - ERR_FAIL_COND_V(valid_quadrant_count==0,ShadowAtlas::SHADOW_INVALID); + ERR_FAIL_COND_V(valid_quadrant_count==0,false); uint64_t tick = OS::get_singleton()->get_ticks_msec(); @@ -317,13 +331,12 @@ uint32_t RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_ligh bool should_realloc=shadow_atlas->quadrants[q].subdivision!=best_subdiv && (shadow_atlas->quadrants[q].shadows[s].alloc_tick-tick > shadow_atlas_realloc_tolerance_msec); bool should_redraw=shadow_atlas->quadrants[q].shadows[s].version!=p_light_version; + + if (!should_realloc) { + shadow_atlas->quadrants[q].shadows[s].version=p_light_version; //already existing, see if it should redraw or it's just OK - if (should_redraw) { - key|=ShadowAtlas::SHADOW_INDEX_DIRTY_BIT; - } - - return key; + return should_redraw; } int new_quadrant,new_shadow; @@ -339,6 +352,10 @@ uint32_t RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_ligh sli->shadow_atlases.erase(p_atlas); } + //erase previous + shadow_atlas->quadrants[q].shadows[s].version=0; + shadow_atlas->quadrants[q].shadows[s].owner=RID(); + sh->owner=p_light_intance; sh->alloc_tick=tick; sh->version=p_light_version; @@ -349,19 +366,16 @@ uint32_t RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_ligh //update it in map shadow_atlas->shadow_owners[p_light_intance]=key; //make it dirty, as it should redraw anyway - key|=ShadowAtlas::SHADOW_INDEX_DIRTY_BIT; - - return key; + return true; } //no better place for this shadow found, keep current //already existing, see if it should redraw or it's just OK - if (should_redraw) { - key|=ShadowAtlas::SHADOW_INDEX_DIRTY_BIT; - } - return key; + shadow_atlas->quadrants[q].shadows[s].version=p_light_version; + + return should_redraw; } int new_quadrant,new_shadow; @@ -387,20 +401,49 @@ uint32_t RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_ligh //update it in map shadow_atlas->shadow_owners[p_light_intance]=key; //make it dirty, as it should redraw anyway - key|=ShadowAtlas::SHADOW_INDEX_DIRTY_BIT; - return key; + return true; } //no place to allocate this light, apologies - return ShadowAtlas::SHADOW_INVALID; + return false; } +void RasterizerSceneGLES3::set_directional_shadow_count(int p_count) { + + directional_shadow.light_count=p_count; + directional_shadow.current_light=0; +} + +int RasterizerSceneGLES3::get_directional_light_shadow_size(RID p_light_intance) { + + ERR_FAIL_COND_V(directional_shadow.light_count==0,0); + + int shadow_size; + + if (directional_shadow.light_count==1) { + shadow_size = directional_shadow.size; + } else { + shadow_size = directional_shadow.size/2; //more than 4 not supported anyway + } + + LightInstance *light_instance = light_instance_owner.getornull(p_light_intance); + ERR_FAIL_COND_V(!light_instance,0); + + switch(light_instance->light_ptr->directional_shadow_mode) { + case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: break; //none + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: shadow_size/=2; break; + } + + return shadow_size; + +} /* ENVIRONMENT API */ @@ -511,6 +554,7 @@ RID RasterizerSceneGLES3::light_instance_create(RID p_light) { light_instance->last_pass=0; light_instance->last_scene_pass=0; + light_instance->last_scene_shadow_pass=0; light_instance->light=p_light; light_instance->light_ptr=storage->light_owner.getornull(p_light); @@ -520,10 +564,11 @@ RID RasterizerSceneGLES3::light_instance_create(RID p_light) { glBufferData(GL_UNIFORM_BUFFER, sizeof(LightInstance::LightDataUBO), NULL, GL_DYNAMIC_DRAW); glBindBuffer(GL_UNIFORM_BUFFER, 0); - ERR_FAIL_COND_V(!light_instance->light_ptr,RID()); - return light_instance_owner.make_rid(light_instance); + light_instance->self=light_instance_owner.make_rid(light_instance); + + return light_instance->self; } void RasterizerSceneGLES3::light_instance_set_transform(RID p_light_instance,const Transform& p_transform){ @@ -534,6 +579,25 @@ void RasterizerSceneGLES3::light_instance_set_transform(RID p_light_instance,con light_instance->transform=p_transform; } +void RasterizerSceneGLES3::light_instance_set_shadow_transform(RID p_light_instance,const CameraMatrix& p_projection,const Transform& p_transform,float p_far,float p_split,int p_pass) { + + LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); + ERR_FAIL_COND(!light_instance); + + if (light_instance->light_ptr->type!=VS::LIGHT_DIRECTIONAL) { + p_pass=0; + } + + ERR_FAIL_INDEX(p_pass,4); + + light_instance->shadow_transform[p_pass].camera=p_projection; + light_instance->shadow_transform[p_pass].transform=p_transform; + light_instance->shadow_transform[p_pass].far=p_far; + light_instance->shadow_transform[p_pass].split=p_split; + +} + + void RasterizerSceneGLES3::light_instance_mark_visible(RID p_light_instance) { LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); @@ -542,7 +606,6 @@ void RasterizerSceneGLES3::light_instance_mark_visible(RID p_light_instance) { light_instance->last_scene_pass=scene_pass; } - //////////////////////////// //////////////////////////// //////////////////////////// @@ -757,9 +820,10 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { void RasterizerSceneGLES3::_setup_light(LightInstance *p_light) { - glBindBufferBase(GL_UNIFORM_BUFFER,3,p_light->light_ubo); //bind light uniform } + + void RasterizerSceneGLES3::_setup_transform(InstanceBase *p_instance,const Transform& p_view_transform,const CameraMatrix& p_projection) { if (p_instance->billboard || p_instance->billboard_y || p_instance->depth_scale) { @@ -815,7 +879,22 @@ void RasterizerSceneGLES3::_setup_transform(InstanceBase *p_instance,const Trans } } -void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_element_count,const Transform& p_view_transform,const CameraMatrix& p_projection,RasterizerStorageGLES3::Texture* p_base_env,bool p_reverse_cull,bool p_alpha_pass) { +void RasterizerSceneGLES3::_set_cull(bool p_front,bool p_reverse_cull) { + + bool front = p_front; + if (p_reverse_cull) + front=!front; + + if (front!=state.cull_front) { + + glCullFace(front?GL_FRONT:GL_BACK); + state.cull_front=front; + } +} + + + +void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_element_count,const Transform& p_view_transform,const CameraMatrix& p_projection,RasterizerStorageGLES3::Texture* p_base_env,bool p_reverse_cull,bool p_alpha_pass,bool p_shadow) { if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) { //p_reverse_cull=!p_reverse_cull; @@ -824,25 +903,30 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e glFrontFace(GL_CW); } - bool shadow=false; - glBindBufferBase(GL_UNIFORM_BUFFER,0,state.scene_ubo); //bind globals ubo - glBindBufferBase(GL_UNIFORM_BUFFER,2,state.env_radiance_ubo); //bind environment radiance info - glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-1); - glBindTexture(GL_TEXTURE_2D,state.brdf_texture); + if (!p_shadow) { + glBindBufferBase(GL_UNIFORM_BUFFER,2,state.env_radiance_ubo); //bind environment radiance info + glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-1); + glBindTexture(GL_TEXTURE_2D,state.brdf_texture); - if (p_base_env) { - glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-2); - glBindTexture(p_base_env->target,p_base_env->tex_id); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,true); + if (p_base_env) { + glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-2); + glBindTexture(p_base_env->target,p_base_env->tex_id); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,true); + } else { + state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,false); + + } } else { - state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,false); } + state.cull_front=false; + glCullFace(GL_BACK); state.scene_shader.set_conditional(SceneShaderGLES3::USE_SKELETON,false); @@ -875,28 +959,8 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e bool additive=false; - if (!shadow) { -#if 0 - if (texscreen_used && !texscreen_copied && material->shader_cache && material->shader_cache->valid && material->shader_cache->has_texscreen) { - texscreen_copied=true; - _copy_to_texscreen(); - - //force reset state - prev_material=NULL; - prev_light=0x777E; - prev_geometry_cmp=NULL; - prev_light_type=0xEF; - prev_skeleton =NULL; - prev_sort_flags=0xFF; - prev_morph_values=NULL; - prev_receive_shadows_state=-1; - glEnable(GL_BLEND); - glDepthMask(GL_TRUE); - glEnable(GL_DEPTH_TEST); - glDisable(GL_SCISSOR_TEST); + if (!p_shadow) { - } -#endif if (light_type!=prev_light_type /* || receive_shadows_state!=prev_receive_shadows_state*/) { if (material->shader->spatial.unshaded/* || current_debug==VS::SCENARIO_DEBUG_SHADELESS*/) { @@ -905,27 +969,38 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_OMNI,false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_SPOT,false); state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,true); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_DIRECTIONAL_SHADOW,false); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4,false); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM2,false); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM_BLEND,false); + //state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,true); } else { state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING,light_type!=0xF); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_DIRECTIONAL,light_type==VS::LIGHT_DIRECTIONAL); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_OMNI,light_type==VS::LIGHT_OMNI); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_SPOT,light_type==VS::LIGHT_SPOT); - /* - if (receive_shadows_state==1) { - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_SHADOW,(light_type&0x8)); - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM,(light_type&0x10)); - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4,(light_type&0x20)); - } - else { - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_SHADOW,false); - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM,false); - state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4,false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_DIRECTIONAL,(light_type&3)==VS::LIGHT_DIRECTIONAL); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_OMNI,(light_type&0xF)==VS::LIGHT_OMNI); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_SPOT,(light_type&0xF)==VS::LIGHT_SPOT); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_DIRECTIONAL_SHADOW,false); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4,false); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM2,false); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM_BLEND,false); + + if ((light_type&3)==VS::LIGHT_DIRECTIONAL) { + + if (light_instances[light_index]->light_ptr->shadow) { + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_DIRECTIONAL_SHADOW,true); + + switch(light_instances[light_index]->light_ptr->directional_shadow_mode) { + case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: break; //none + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM2,true); break; + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4,true); break; + } + } } - state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,false); - */ + + } rebind=true; @@ -1007,14 +1082,16 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e current_blend_mode=desired_blend_mode; } - } - if (light_index!=prev_light_index) { - if (light_index!=0xFFFF) { //not unshaded - _setup_light(light_instances[light_index]); + if (light_index!=prev_light_index) { + if (light_index!=0xFFFF) { //not unshaded + _setup_light(light_instances[light_index]); + } } + } + if (material!=prev_material || rebind) { rebind = _setup_material(material,p_alpha_pass); @@ -1027,20 +1104,17 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e _setup_geometry(e); } - if (rebind || prev_additive!=additive) { + if (!p_shadow && (rebind || prev_additive!=additive)) { state.scene_shader.set_uniform(SceneShaderGLES3::NO_AMBIENT_LIGHT, additive); } -// _set_cull(e->mirror,p_reverse_cull); + _set_cull(e->sort_key&RenderList::SORT_KEY_MIRROR_FLAG,p_reverse_cull); state.scene_shader.set_uniform(SceneShaderGLES3::NORMAL_MULT, e->instance->mirror?-1.0:1.0); _setup_transform(e->instance,p_view_transform,p_projection); - -// _render(e->geometry, material, skeleton,e->owner,e->instance->transform); - _render_geometry(e); prev_material=material; @@ -1052,15 +1126,26 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e } - //print_line("shaderchanges: "+itos(p_alpha_pass)+": "+itos(_rinfo.shader_change_count)); glFrontFace(GL_CW); glBindVertexArray(0); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING,false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_DIRECTIONAL,false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_OMNI,false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_SPOT,false); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_DIRECTIONAL_SHADOW,false); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM4,false); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM2,false); + state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM_BLEND,false); + state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,false); + } -void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner,int p_material) { + +void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner,int p_material,bool p_shadow) { RasterizerStorageGLES3::Material *m=NULL; RID m_src=p_instance->material_override.is_valid() ? p_instance->material_override :(p_material>=0?p_instance->materials[p_material]:p_geometry->material); @@ -1096,57 +1181,29 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g bool has_alpha = has_base_alpha || has_blend_alpha; bool shadow = false; -#if 0 - if (shadow) { + bool mirror = p_instance->mirror; - if (has_blend_alpha || (has_base_alpha && m->depth_draw_mode!=VS::MATERIAL_DEPTH_DRAW_OPAQUE_PRE_PASS_ALPHA)) + if (m->shader->spatial.cull_mode==RasterizerStorageGLES3::Shader::Spatial::CULL_MODE_FRONT) { + mirror=!mirror; + } + + if (p_shadow) { + + if (has_blend_alpha || (has_base_alpha && m->shader->spatial.depth_draw_mode!=RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS)) return; //bye - if (!m->shader_cache || (!m->shader_cache->writes_vertex && !m->shader_cache->uses_discard && m->depth_draw_mode!=VS::MATERIAL_DEPTH_DRAW_OPAQUE_PRE_PASS_ALPHA)) { + if (!m->shader->spatial.uses_vertex && !m->shader->spatial.uses_discard && m->shader->spatial.depth_draw_mode!=RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { //shader does not use discard and does not write a vertex position, use generic material if (p_instance->cast_shadows == VS::SHADOW_CASTING_SETTING_DOUBLE_SIDED) - m = shadow_mat_double_sided_ptr; + m = storage->material_owner.getptr(default_material_twosided); else - m = shadow_mat_ptr; - if (m->last_pass!=frame) { - - if (m->shader.is_valid()) { - - m->shader_cache=shader_owner.get(m->shader); - if (m->shader_cache) { - - - if (!m->shader_cache->valid) - m->shader_cache=NULL; - } else { - m->shader=RID(); - } - - } else { - m->shader_cache=NULL; - } - - m->last_pass=frame; - } + m = storage->material_owner.getptr(default_material); } - render_list = &opaque_render_list; - /* notyet - if (!m->shader_cache || m->shader_cache->can_zpass) - render_list = &alpha_render_list; - } else { - render_list = &opaque_render_list; - }*/ - - } else { - if (has_alpha) { - render_list = &alpha_render_list; - } else { - render_list = &opaque_render_list; + has_alpha=false; - } } -#endif + RenderList::Element *e = has_alpha ? render_list.add_alpha_element() : render_list.add_element(); @@ -1161,50 +1218,49 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g e->additive_ptr=&e->additive; e->sort_key=0; - if (e->geometry->last_pass!=render_pass) { e->geometry->last_pass=render_pass; e->geometry->index=current_geometry_index++; } + e->sort_key|=uint64_t(e->geometry->index)<<RenderList::SORT_KEY_GEOMETRY_INDEX_SHIFT; e->sort_key|=uint64_t(e->instance->base_type)<<RenderList::SORT_KEY_GEOMETRY_TYPE_SHIFT; - if (e->material->last_pass!=render_pass) { - e->material->last_pass=render_pass; - e->material->index=current_material_index++; - } + if (!p_shadow) { - e->sort_key|=uint64_t(e->material->index)<<RenderList::SORT_KEY_MATERIAL_INDEX_SHIFT; - e->sort_key|=uint64_t(e->instance->depth_layer)<<RenderList::SORT_KEY_DEPTH_LAYER_SHIFT; - //if (e->geometry->type==RasterizerStorageGLES3::Geometry::GEOMETRY_MULTISURFACE) - // e->sort_flags|=RenderList::SORT_FLAG_INSTANCING; + if (e->material->last_pass!=render_pass) { + e->material->last_pass=render_pass; + e->material->index=current_material_index++; + } - bool mirror = e->instance->mirror; + e->sort_key|=uint64_t(e->material->index)<<RenderList::SORT_KEY_MATERIAL_INDEX_SHIFT; + e->sort_key|=uint64_t(e->instance->depth_layer)<<RenderList::SORT_KEY_DEPTH_LAYER_SHIFT; - if (m->shader->spatial.cull_mode==RasterizerStorageGLES3::Shader::Spatial::CULL_MODE_FRONT) { - mirror=!mirror; - } + if (!has_blend_alpha && has_alpha && m->shader->spatial.depth_draw_mode==RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { - if (mirror) { - e->sort_key|=RenderList::SORT_KEY_MIRROR_FLAG; - } + //if nothing exists, add this element as opaque too + RenderList::Element *oe = render_list.add_element(); - //e->light_type=0xFF; // no lights! + if (!oe) + return; - if (!shadow && !has_blend_alpha && has_alpha && m->shader->spatial.depth_draw_mode==RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { + copymem(oe,e,sizeof(RenderList::Element)); + oe->additive_ptr=&oe->additive; + } + } - //if nothing exists, add this element as opaque too - RenderList::Element *oe = render_list.add_element(); + //if (e->geometry->type==RasterizerStorageGLES3::Geometry::GEOMETRY_MULTISURFACE) + // e->sort_flags|=RenderList::SORT_FLAG_INSTANCING; - if (!oe) - return; - copymem(oe,e,sizeof(RenderList::Element)); - oe->additive_ptr=&oe->additive; + if (mirror) { + e->sort_key|=RenderList::SORT_KEY_MIRROR_FLAG; } + //e->light_type=0xFF; // no lights! + @@ -1246,7 +1302,12 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g ec->sort_key&=~RenderList::SORT_KEY_LIGHT_MASK; ec->sort_key|=uint64_t(directional_light_instances[i]->light_index) << RenderList::SORT_KEY_LIGHT_INDEX_SHIFT; - ec->sort_key|=uint64_t(VS::LIGHT_DIRECTIONAL) << RenderList::SORT_KEY_LIGHT_TYPE_SHIFT; + ec->sort_key|=uint64_t(VS::LIGHT_DIRECTIONAL) << RenderList::SORT_KEY_LIGHT_TYPE_SHIFT; //this is zero byt whathever + + if (directional_light_instances[i]->light_ptr->shadow) { + //add proper flags for directional shadow mode + ec->sort_key|=uint64_t(directional_light_instances[i]->light_ptr->directional_shadow_mode+1) << (RenderList::SORT_KEY_LIGHT_TYPE_SHIFT+2); + } lit=true; } @@ -1302,7 +1363,7 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g } -void RasterizerSceneGLES3::_draw_skybox(RID p_skybox,CameraMatrix& p_projection,const Transform& p_transform,bool p_vflip,float p_scale) { +void RasterizerSceneGLES3::_draw_skybox(RID p_skybox,const CameraMatrix& p_projection,const Transform& p_transform,bool p_vflip,float p_scale) { RasterizerStorageGLES3::Texture *tex = storage->texture_owner.getornull(p_skybox); @@ -1382,7 +1443,7 @@ void RasterizerSceneGLES3::_draw_skybox(RID p_skybox,CameraMatrix& p_projection, } -void RasterizerSceneGLES3::_setup_environment(Environment *env,CameraMatrix& p_cam_projection,const Transform& p_cam_transform) { +void RasterizerSceneGLES3::_setup_environment(Environment *env,const CameraMatrix& p_cam_projection,const Transform& p_cam_transform) { //store camera into ubo @@ -1444,6 +1505,20 @@ void RasterizerSceneGLES3::_setup_environment(Environment *env,CameraMatrix& p_c } + { + //directional shadow + + state.ubo_data.shadow_directional_pixel_size[0]=1.0/directional_shadow.size; + state.ubo_data.shadow_directional_pixel_size[1]=1.0/directional_shadow.size; + + glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-4); + glBindTexture(GL_TEXTURE_2D,directional_shadow.depth); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS); + } + + + glBindBuffer(GL_UNIFORM_BUFFER, state.scene_ubo); glBufferSubData(GL_UNIFORM_BUFFER, 0,sizeof(State::SceneDataUBO), &state.ubo_data); glBindBuffer(GL_UNIFORM_BUFFER, 0); @@ -1459,13 +1534,14 @@ void RasterizerSceneGLES3::_setup_environment(Environment *env,CameraMatrix& p_c } -void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cull_count,const Transform& p_camera_inverse_transform,const CameraMatrix& p_camera_projection) { +void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cull_count,const Transform& p_camera_inverse_transform,const CameraMatrix& p_camera_projection,RID p_shadow_atlas) { + + + ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); directional_light_instance_count=0; light_instance_count=0; - Vector<float> lpercent; - for(int i=0;i<p_light_cull_count;i++) { ERR_BREAK( i>=RenderList::MAX_LIGHTS ); @@ -1502,23 +1578,90 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cu li->light_ubo_data.light_params[2]=0; li->light_ubo_data.light_params[3]=0; + if (li->light_ptr->shadow) { + int shadow_count=0; + switch(li->light_ptr->directional_shadow_mode) { + case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: { + shadow_count=1; + } break; + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: { + shadow_count=2; + } break; + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: { + shadow_count=4; + } break; -#if 0 - if (li->light_ptr->shadow_enabled) { - CameraMatrix bias; - bias.set_light_bias(); + } + + for(int j=0;j<shadow_count;j++) { + + + uint32_t x=li->directional_rect.pos.x; + uint32_t y=li->directional_rect.pos.y; + uint32_t width=li->directional_rect.size.x; + uint32_t height=li->directional_rect.size.y; + + + + if (li->light_ptr->directional_shadow_mode==VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) { + + + width/=2; + height/=2; + + if (j==0) { + + } else if (j==1) { + x+=width; + } else if (j==2) { + y+=height; + } else if (j==3) { + x+=width; + y+=height; + + } + + + + } else if (li->light_ptr->directional_shadow_mode==VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) { - int passes=light_instance_get_shadow_passes(p_light_instance); + height/=2; + + if (j==0) { + + } else { + y+=height; + } + + } + + li->light_ubo_data.shadow_split_offsets[j]=1.0/li->shadow_transform[j].split; + + Transform modelview = (p_camera_inverse_transform * li->shadow_transform[j].transform).inverse(); + + CameraMatrix bias; + bias.set_light_bias(); + CameraMatrix rectm; + Rect2 atlas_rect = Rect2(float(x)/directional_shadow.size,float(y)/directional_shadow.size,float(width)/directional_shadow.size,float(height)/directional_shadow.size); + rectm.set_light_atlas_rect(atlas_rect); + +// print_line("atlas rect: "+atlas_rect); + + CameraMatrix shadow_mtx = rectm * bias * li->shadow_transform[j].camera * modelview; + + store_camera(shadow_mtx,&li->light_ubo_data.shadow_matrix1[16*j]); + + li->light_ubo_data.light_clamp[0]=atlas_rect.pos.x; + li->light_ubo_data.light_clamp[1]=atlas_rect.pos.y; + li->light_ubo_data.light_clamp[2]=atlas_rect.size.x; + li->light_ubo_data.light_clamp[3]=atlas_rect.size.y; - for(int i=0;i<passes;i++) { - Transform modelview=Transform(camera_transform_inverse * li->custom_transform[i]).inverse(); - li->shadow_projection[i] = bias * li->custom_projection[i] * modelview; } - lights_use_shadow=true; + } -#endif + } break; case VS::LIGHT_OMNI: { @@ -1542,29 +1685,57 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cu li->light_ubo_data.light_direction_attenuation[3]=li->light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; li->light_ubo_data.light_params[0]=0; - li->light_ubo_data.light_params[1]=li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; - li->light_ubo_data.light_params[2]=0; + li->light_ubo_data.light_params[1]=0; + li->light_ubo_data.light_params[2]=li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; li->light_ubo_data.light_params[3]=0; -#if 0 - Transform ai = p_camera_inverse_transform.affine_inverse(); - float zn = p_camera_projection.get_z_near(); - Plane p (ai.origin + ai.basis.get_axis(2) * -zn, -ai.basis.get_axis(2) ); + if (li->light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(li->self)) { + // fill in the shadow information - Vector3 point1 = li->transform.origin; - Vector3 point2 = li->transform.origin+p_camera_inverse_transform.affine_inverse().basis.get_axis(1).normalized()*li->light_ptr->param[VS::LIGHT_PARAM_RANGE]; + uint32_t key = shadow_atlas->shadow_owners[li->self]; - p.intersects_segment(ai.origin,point1,&point1); - p.intersects_segment(ai.origin,point2,&point2); - float r = point1.distance_to(point2); + uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT)&0x3; + uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; + + ERR_CONTINUE(shadow>=shadow_atlas->quadrants[quadrant].shadows.size()); + + uint32_t atlas_size = shadow_atlas->size; + uint32_t quadrant_size = atlas_size>>1; + + uint32_t x=(quadrant&1)*quadrant_size; + uint32_t y=(quadrant>>1)*quadrant_size; + + uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); + x+=(shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + y+=(shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + + uint32_t width=shadow_size; + uint32_t height=shadow_size; + + + if (li->light_ptr->omni_shadow_detail==VS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) { + + height/=2; + } else { + width/=2; + + } + + Transform proj = (p_camera_inverse_transform * li->transform).inverse(); + + store_transform(proj,li->light_ubo_data.shadow_matrix1); + + li->light_ubo_data.light_params[3]=1.0; //means it has shadow + li->light_ubo_data.light_clamp[0]=float(x)/atlas_size; + li->light_ubo_data.light_clamp[1]=float(y)/atlas_size; + li->light_ubo_data.light_clamp[2]=float(width)/atlas_size; + li->light_ubo_data.light_clamp[3]=float(height)/atlas_size; + + } - float vp_w,vp_h; - p_camera_projection.get_viewport_size(vp_w,vp_h); - lpercent.push_back(r*2/((vp_h+vp_w)*0.5)); -#endif #if 0 if (li->light_ptr->shadow_enabled) { @@ -1596,10 +1767,54 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cu li->light_ubo_data.light_direction_attenuation[3]=li->light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; li->light_ubo_data.light_params[0]=li->light_ptr->param[VS::LIGHT_PARAM_SPOT_ATTENUATION]; - li->light_ubo_data.light_params[1]=li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; - li->light_ubo_data.light_params[2]=0; + li->light_ubo_data.light_params[1]=Math::cos(Math::deg2rad(li->light_ptr->param[VS::LIGHT_PARAM_SPOT_ANGLE])); + li->light_ubo_data.light_params[2]=li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; li->light_ubo_data.light_params[3]=0; + if (li->light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(li->self)) { + // fill in the shadow information + + uint32_t key = shadow_atlas->shadow_owners[li->self]; + + uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT)&0x3; + uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; + + ERR_CONTINUE(shadow>=shadow_atlas->quadrants[quadrant].shadows.size()); + + uint32_t atlas_size = shadow_atlas->size; + uint32_t quadrant_size = atlas_size>>1; + + uint32_t x=(quadrant&1)*quadrant_size; + uint32_t y=(quadrant>>1)*quadrant_size; + + uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); + x+=(shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + y+=(shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + + uint32_t width=shadow_size; + uint32_t height=shadow_size; + + Rect2 rect(float(x)/atlas_size,float(y)/atlas_size,float(width)/atlas_size,float(height)/atlas_size); + + li->light_ubo_data.light_params[3]=1.0; //means it has shadow + li->light_ubo_data.light_clamp[0]=rect.pos.x; + li->light_ubo_data.light_clamp[1]=rect.pos.y; + li->light_ubo_data.light_clamp[2]=rect.size.x; + li->light_ubo_data.light_clamp[3]=rect.size.y; + + Transform modelview = (p_camera_inverse_transform * li->transform).inverse(); + + CameraMatrix bias; + bias.set_light_bias(); + CameraMatrix rectm; + rectm.set_light_atlas_rect(rect); + + CameraMatrix shadow_mtx = rectm * bias * li->shadow_transform[0].camera * modelview; + + store_camera(shadow_mtx,li->light_ubo_data.shadow_matrix1); + + + } #if 0 if (li->light_ptr->shadow_enabled) { CameraMatrix bias; @@ -1679,24 +1894,39 @@ void RasterizerSceneGLES3::_copy_to_front_buffer(Environment *env) { } -void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID* p_directional_lights,int p_directional_light_count,RID p_environment){ +void RasterizerSceneGLES3::_copy_texture_to_front_buffer(GLuint p_texture) { - //first of all, make a new render pass - render_pass++; + //copy to front buffer + glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->front.fbo); - //fill up ubo + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glDisable(GL_BLEND); + glDepthFunc(GL_LEQUAL); + glColorMask(1,1,1,1); - Environment *env = environment_owner.getornull(p_environment); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D,p_texture); - _setup_environment(env,p_cam_projection,p_cam_transform); + glViewport(0,0,storage->frame.current_rt->width*0.5,storage->frame.current_rt->height*0.5); - _setup_lights(p_light_cull_result,p_light_cull_count,p_cam_transform.affine_inverse(),p_cam_projection); + storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA,true); + storage->shaders.copy.bind(); - render_list.clear(); + _copy_screen(); - current_material_index=0; + //turn off everything used + storage->shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB,false); + storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA,false); - bool use_mrt=false; + +} + +void RasterizerSceneGLES3::_fill_render_list(InstanceBase** p_cull_result,int p_cull_count,bool p_shadow){ + + current_geometry_index=0; + current_material_index=0; //fill list @@ -1716,7 +1946,7 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM int mat_idx = inst->materials[i].is_valid() ? i : -1; RasterizerStorageGLES3::Surface *s = mesh->surfaces[i]; - _add_geometry(s,inst,NULL,mat_idx); + _add_geometry(s,inst,NULL,mat_idx,p_shadow); } //mesh->last_pass=frame; @@ -1731,7 +1961,39 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM } } +} + + +void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID p_environment,RID p_shadow_atlas){ + + //first of all, make a new render pass + render_pass++; + + //fill up ubo + + Environment *env = environment_owner.getornull(p_environment); + ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); + + if (shadow_atlas && shadow_atlas->size) { + glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-3); + glBindTexture(GL_TEXTURE_2D,shadow_atlas->depth); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS); + state.ubo_data.shadow_atlas_pixel_size[0]=1.0/shadow_atlas->size; + state.ubo_data.shadow_atlas_pixel_size[1]=1.0/shadow_atlas->size; + } + + _setup_environment(env,p_cam_projection,p_cam_transform); + + _setup_lights(p_light_cull_result,p_light_cull_count,p_cam_transform.affine_inverse(),p_cam_projection,p_shadow_atlas); + + render_list.clear(); + + bool use_mrt=false; + + + _fill_render_list(p_cull_result,p_cull_count,false); // @@ -1742,6 +2004,8 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM RasterizerStorageGLES3::Texture* env_radiance_tex=NULL; + glViewport(0,0,storage->frame.current_rt->width,storage->frame.current_rt->height); + if (use_mrt) { glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->buffers.fbo); @@ -1811,7 +2075,7 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } - _render_list(render_list.elements,render_list.element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,false); + _render_list(render_list.elements,render_list.element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,false,false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS,false); @@ -1843,11 +2107,34 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM render_list.sort_by_depth(true); - _render_list(&render_list.elements[render_list.max_elements-render_list.alpha_element_count],render_list.alpha_element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,true); + _render_list(&render_list.elements[render_list.max_elements-render_list.alpha_element_count],render_list.alpha_element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,true,false); _copy_to_front_buffer(env); +/* if (shadow_atlas) { + + //_copy_texture_to_front_buffer(shadow_atlas->depth); + storage->canvas->canvas_begin(); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D,shadow_atlas->depth); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); + storage->canvas->draw_generic_textured_rect(Rect2(0,0,storage->frame.current_rt->width/2,storage->frame.current_rt->height/2),Rect2(0,0,1,1)); + + } +*/ + if (directional_shadow.fbo) { + + //_copy_texture_to_front_buffer(shadow_atlas->depth); + storage->canvas->canvas_begin(); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D,directional_shadow.depth); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); + storage->canvas->draw_generic_textured_rect(Rect2(0,0,storage->frame.current_rt->width/2,storage->frame.current_rt->height/2),Rect2(0,0,1,1)); + + } + + #if 0 if (use_fb) { @@ -1994,6 +2281,294 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,CameraM #endif } +void RasterizerSceneGLES3::render_shadow(RID p_light,RID p_shadow_atlas,int p_pass,InstanceBase** p_cull_result,int p_cull_count) { + + render_pass++; + + LightInstance *light_instance = light_instance_owner.getornull(p_light); + ERR_FAIL_COND(!light_instance); + RasterizerStorageGLES3::Light *light = storage->light_owner.getornull(light_instance->light); + ERR_FAIL_COND(!light); + + uint32_t x,y,width,height,vp_height; + + + float dp_direction=0.0; + float zfar=0; + bool flip_facing=false; + int custom_vp_size=0; + GLuint fbo; + int current_cubemap=-1; + float bias=0; + float normal_bias=0; + + CameraMatrix light_projection; + Transform light_transform; + + + if (light->type==VS::LIGHT_DIRECTIONAL) { + //set pssm stuff + if (light_instance->last_scene_shadow_pass!=scene_pass) { + //assign rect if unassigned + light_instance->light_directional_index = directional_shadow.current_light; + light_instance->last_scene_shadow_pass=scene_pass; + directional_shadow.current_light++; + + if (directional_shadow.light_count==1) { + light_instance->directional_rect=Rect2(0,0,directional_shadow.size,directional_shadow.size); + } else if (directional_shadow.light_count==2) { + light_instance->directional_rect=Rect2(0,0,directional_shadow.size,directional_shadow.size/2); + if (light_instance->light_directional_index==1) { + light_instance->directional_rect.pos.x+=light_instance->directional_rect.size.x; + } + } else { //3 and 4 + light_instance->directional_rect=Rect2(0,0,directional_shadow.size/2,directional_shadow.size/2); + if (light_instance->light_directional_index&1) { + light_instance->directional_rect.pos.x+=light_instance->directional_rect.size.x; + } + if (light_instance->light_directional_index/2) { + light_instance->directional_rect.pos.y+=light_instance->directional_rect.size.y; + } + } + } + + light_projection=light_instance->shadow_transform[p_pass].camera; + light_transform=light_instance->shadow_transform[p_pass].transform; + + x=light_instance->directional_rect.pos.x; + y=light_instance->directional_rect.pos.y; + width=light_instance->directional_rect.size.x; + height=light_instance->directional_rect.size.y; + + + + if (light->directional_shadow_mode==VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) { + + + width/=2; + height/=2; + + if (p_pass==0) { + + } else if (p_pass==1) { + x+=width; + } else if (p_pass==2) { + y+=height; + } else if (p_pass==3) { + x+=width; + y+=height; + + } + + + + } else if (light->directional_shadow_mode==VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) { + + height/=2; + + if (p_pass==0) { + + } else { + y+=height; + } + + } + + zfar=light->param[VS::LIGHT_PARAM_RANGE]; + bias=light->param[VS::LIGHT_PARAM_SHADOW_BIAS]; + normal_bias=light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS]; + fbo=directional_shadow.fbo; + vp_height=directional_shadow.size; + + } else { + //set from shadow atlas + + ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); + ERR_FAIL_COND(!shadow_atlas); + ERR_FAIL_COND(!shadow_atlas->shadow_owners.has(p_light)); + + fbo=shadow_atlas->fbo; + vp_height=shadow_atlas->size; + + + uint32_t key = shadow_atlas->shadow_owners[p_light]; + + uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT)&0x3; + uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; + + ERR_FAIL_INDEX(shadow,shadow_atlas->quadrants[quadrant].shadows.size()); + + uint32_t quadrant_size = shadow_atlas->size>>1; + + x=(quadrant&1)*quadrant_size; + y=(quadrant>>1)*quadrant_size; + + uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); + x+=(shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + y+=(shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + + width=shadow_size; + height=shadow_size; + + if (light->type==VS::LIGHT_OMNI) { + + + if (light->omni_shadow_mode==VS::LIGHT_OMNI_SHADOW_CUBE) { + + int cubemap_index=shadow_cubemaps.size()-1; + + for(int i=shadow_cubemaps.size()-1;i>=0;i--) { + //find appropriate cubemap to render to + if (shadow_cubemaps[i].size>shadow_size*2) + break; + + cubemap_index=i; + } + + fbo=shadow_cubemaps[cubemap_index].fbo_id[p_pass]; + light_projection=light_instance->shadow_transform[0].camera; + light_transform=light_instance->shadow_transform[0].transform; + custom_vp_size=shadow_cubemaps[cubemap_index].size; + zfar=light->param[VS::LIGHT_PARAM_RANGE]; + + current_cubemap=cubemap_index; + + + } else { + + light_projection=light_instance->shadow_transform[0].camera; + light_transform=light_instance->shadow_transform[0].transform; + + if (light->omni_shadow_detail==VS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) { + + height/=2; + y+=p_pass*height; + } else { + width/=2; + x+=p_pass*width; + + } + + dp_direction = p_pass==0?1.0:-1.0; + flip_facing = (p_pass == 1); + zfar=light->param[VS::LIGHT_PARAM_RANGE]; + bias=light->param[VS::LIGHT_PARAM_SHADOW_BIAS]; + + state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_SHADOW_DUAL_PARABOLOID,true); + } + + } else if (light->type==VS::LIGHT_SPOT) { + + light_projection=light_instance->shadow_transform[0].camera; + light_transform=light_instance->shadow_transform[0].transform; + + dp_direction = 1.0; + flip_facing = false; + zfar=light->param[VS::LIGHT_PARAM_RANGE]; + bias=light->param[VS::LIGHT_PARAM_SHADOW_BIAS]; + normal_bias=light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS]; + } + + } + + //todo hacer que se redibuje cuando corresponde + + + render_list.clear(); + _fill_render_list(p_cull_result,p_cull_count,true); + + render_list.sort_by_depth(false); //shadow is front to back for performance + + glDepthMask(true); + glColorMask(0,0,0,0); + glDisable(GL_BLEND); + glDisable(GL_DITHER); + glEnable(GL_DEPTH_TEST); + + glBindFramebuffer(GL_FRAMEBUFFER,fbo); + + if (custom_vp_size) { + glViewport(0,0,custom_vp_size,custom_vp_size); + glScissor(0,0,custom_vp_size,custom_vp_size); + + } else { + glViewport(x,y,width,height); + glScissor(x,y,width,height); + } + + //glViewport(x,vp_height-(height+y),width,height); + //glScissor(x,vp_height-(height+y),width,height); + glEnable(GL_SCISSOR_TEST); + glClearDepth(1.0); + glClear(GL_DEPTH_BUFFER_BIT); + glDisable(GL_SCISSOR_TEST); + + state.ubo_data.shadow_z_offset=bias; + state.ubo_data.shadow_slope_scale=normal_bias; + state.ubo_data.shadow_dual_paraboloid_render_side=dp_direction; + state.ubo_data.shadow_dual_paraboloid_render_zfar=zfar; + + _setup_environment(NULL,light_projection,light_transform); + + state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_SHADOW,true); + + _render_list(render_list.elements,render_list.element_count,light_transform,light_projection,NULL,!flip_facing,false,true); + + state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_SHADOW,false); + state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_SHADOW_DUAL_PARABOLOID,false); + + + if (light->type==VS::LIGHT_OMNI && light->omni_shadow_mode==VS::LIGHT_OMNI_SHADOW_CUBE && p_pass==5) { + //convert the chosen cubemap to dual paraboloid! + + ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); + + glBindFramebuffer(GL_FRAMEBUFFER,shadow_atlas->fbo); + state.cube_to_dp_shader.bind(); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP,shadow_cubemaps[current_cubemap].cubemap); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_MODE, GL_NONE); + glDisable(GL_CULL_FACE); + + for(int i=0;i<2;i++) { + + state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES3::Z_FLIP,i==1); + state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES3::Z_NEAR,light_projection.get_z_near()); + state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES3::Z_FAR,light_projection.get_z_far()); + state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES3::BIAS,light->param[VS::LIGHT_PARAM_SHADOW_BIAS]); + + uint32_t local_width=width,local_height=height; + uint32_t local_x=x,local_y=y; + if (light->omni_shadow_detail==VS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) { + + local_height/=2; + local_y+=i*local_height; + } else { + local_width/=2; + local_x+=i*local_width; + } + + glViewport(local_x,local_y,local_width,local_height); + glScissor(local_x,local_y,local_width,local_height); + glEnable(GL_SCISSOR_TEST); + glClearDepth(1.0); + glClear(GL_DEPTH_BUFFER_BIT); + glDisable(GL_SCISSOR_TEST); + //glDisable(GL_DEPTH_TEST); + glDisable(GL_BLEND); + + _copy_screen(); + + } + + } + + glColorMask(1,1,1,1); + + +} + void RasterizerSceneGLES3::set_scene_pass(uint64_t p_pass) { scene_pass=p_pass; } @@ -2169,6 +2744,12 @@ void RasterizerSceneGLES3::initialize() { default_material = storage->material_create(); storage->material_set_shader(default_material,default_shader); + default_shader_twosided = storage->shader_create(VS::SHADER_SPATIAL); + default_material_twosided = storage->material_create(); + storage->shader_set_code(default_shader_twosided,"render_mode cull_disabled;\n"); + storage->material_set_shader(default_material_twosided,default_shader_twosided); + + glGenBuffers(1, &state.scene_ubo); glBindBuffer(GL_UNIFORM_BUFFER, state.scene_ubo); glBufferData(GL_UNIFORM_BUFFER, sizeof(State::SceneDataUBO), &state.scene_ubo, GL_DYNAMIC_DRAW); @@ -2208,9 +2789,77 @@ void RasterizerSceneGLES3::initialize() { glBindBuffer(GL_ARRAY_BUFFER,0); //unbind } render_list.init(); + state.cube_to_dp_shader.init(); _generate_brdf(); shadow_atlas_realloc_tolerance_msec=500; + + + + + + int max_shadow_cubemap_sampler_size=512; + + int cube_size = max_shadow_cubemap_sampler_size; + + glActiveTexture(GL_TEXTURE0); + + while(cube_size>=32) { + + ShadowCubeMap cube; + cube.size=cube_size; + + glGenTextures(1,&cube.cubemap); + glBindTexture(GL_TEXTURE_CUBE_MAP,cube.cubemap); + //gen cubemap first + for(int i=0;i<6;i++) { + + glTexImage2D(_cube_side_enum[i], 0, GL_DEPTH_COMPONENT, cube.size, cube.size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); + } + + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + // Remove artifact on the edges of the shadowmap + 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); + + //gen renderbuffers second, because it needs a complete cubemap + for(int i=0;i<6;i++) { + + glGenFramebuffers(1, &cube.fbo_id[i]); + glBindFramebuffer(GL_FRAMEBUFFER, cube.fbo_id[i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,_cube_side_enum[i], cube.cubemap, 0); + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + ERR_CONTINUE(status!=GL_FRAMEBUFFER_COMPLETE); + } + + shadow_cubemaps.push_back(cube); + + cube_size>>=1; + } + + { + //directional light shadow + directional_shadow.light_count=0; + directional_shadow.size=nearest_power_of_2(GLOBAL_DEF("renderer/directional_shadow_size",2048)); + glGenFramebuffers(1,&directional_shadow.fbo); + glBindFramebuffer(GL_FRAMEBUFFER,directional_shadow.fbo); + glGenTextures(1,&directional_shadow.depth); + glBindTexture(GL_TEXTURE_2D,directional_shadow.depth); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, directional_shadow.size, directional_shadow.size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,GL_TEXTURE_2D, directional_shadow.depth, 0); + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status!=GL_FRAMEBUFFER_COMPLETE) { + ERR_PRINT("Directional shadow framebuffer status invalid"); + } + } } void RasterizerSceneGLES3::finalize(){ diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 9df6315e45..d7beebbcf6 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -3,6 +3,7 @@ #include "rasterizer_storage_gles3.h" #include "drivers/gles3/shaders/scene.glsl.h" +#include "drivers/gles3/shaders/cube_to_dp.glsl.h" class RasterizerSceneGLES3 : public RasterizerScene { public: @@ -16,10 +17,13 @@ public: uint32_t current_geometry_index; RID default_material; + RID default_material_twosided; RID default_shader; + RID default_shader_twosided; RasterizerStorageGLES3 *storage; + struct State { @@ -29,6 +33,7 @@ public: int current_depth_draw; SceneShaderGLES3 scene_shader; + CubeToDpShaderGLES3 cube_to_dp_shader; struct SceneDataUBO { @@ -41,6 +46,12 @@ public: float bg_color[4]; float ambient_energy; float bg_energy; + float shadow_z_offset; + float shadow_slope_scale; + float shadow_dual_paraboloid_render_zfar; + float shadow_dual_paraboloid_render_side; + float shadow_atlas_pixel_size[2]; + float shadow_directional_pixel_size[2]; } ubo_data; @@ -62,7 +73,7 @@ public: GLuint skybox_verts; GLuint skybox_array; - + bool cull_front; } state; @@ -71,7 +82,6 @@ public: struct ShadowAtlas : public RID_Data { enum { - SHADOW_INDEX_DIRTY_BIT=(1<<31), QUADRANT_SHIFT=27, SHADOW_INDEX_MASK=(1<<QUADRANT_SHIFT)-1, SHADOW_INVALID=0xFFFFFFFF @@ -111,13 +121,35 @@ public: Map<RID,uint32_t> shadow_owners; }; + struct ShadowCubeMap { + + GLuint fbo_id[6]; + GLuint cubemap; + int size; + }; + + Vector<ShadowCubeMap> shadow_cubemaps; + RID_Owner<ShadowAtlas> shadow_atlas_owner; RID shadow_atlas_create(); void shadow_atlas_set_size(RID p_atlas,int p_size); void shadow_atlas_set_quadrant_subdivision(RID p_atlas,int p_quadrant,int p_subdivision); bool _shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow); - uint32_t shadow_atlas_update_light(RID p_atlas,RID p_light_intance,float p_coverage,uint64_t p_light_version); + bool shadow_atlas_update_light(RID p_atlas,RID p_light_intance,float p_coverage,uint64_t p_light_version); + + + struct DirectionalShadow { + GLuint fbo; + GLuint depth; + int light_count; + int size; + int current_light; + } directional_shadow; + + virtual int get_directional_light_shadow_size(RID p_light_intance); + virtual void set_directional_shadow_count(int p_count); + /* ENVIRONMENT API */ @@ -174,12 +206,12 @@ public: struct LightInstance : public RID_Data { - struct SplitInfo { + struct ShadowTransform { CameraMatrix camera; Transform transform; - float near; float far; + float split; }; struct LightDataUBO { @@ -188,6 +220,7 @@ public: float light_direction_attenuation[4]; float light_color_energy[4]; float light_params[4]; //cone attenuation, specular, shadow darkening, + float light_clamp[4]; //cone attenuation, specular, shadow darkening, float shadow_split_offsets[4]; float shadow_matrix1[16]; float shadow_matrix2[16]; @@ -197,13 +230,11 @@ public: } light_ubo_data; - SplitInfo split_info[4]; + ShadowTransform shadow_transform[4]; + RID self; RID light; RasterizerStorageGLES3::Light *light_ptr; - - CameraMatrix shadow_matrix[4]; - Transform transform; Vector3 light_vector; @@ -214,12 +245,17 @@ public: uint64_t shadow_pass; uint64_t last_scene_pass; + uint64_t last_scene_shadow_pass; uint64_t last_pass; uint16_t light_index; + uint16_t light_directional_index; + + uint32_t current_shadow_atlas_key; Vector2 dp; - CameraMatrix shadow_projection[4]; + Rect2 directional_rect; + Set<RID> shadow_atlases; //shadow atlases where this light is registered @@ -231,6 +267,7 @@ public: virtual RID light_instance_create(RID p_light); virtual void light_instance_set_transform(RID p_light_instance,const Transform& p_transform); + virtual void light_instance_set_shadow_transform(RID p_light_instance,const CameraMatrix& p_projection,const Transform& p_transform,float p_far,float p_split,int p_pass); virtual void light_instance_mark_visible(RID p_light_instance); /* RENDER LIST */ @@ -371,26 +408,31 @@ public: RenderList render_list; + _FORCE_INLINE_ void _set_cull(bool p_front,bool p_reverse_cull); + _FORCE_INLINE_ bool _setup_material(RasterizerStorageGLES3::Material* p_material,bool p_alpha_pass); _FORCE_INLINE_ void _setup_transform(InstanceBase *p_instance,const Transform& p_view_transform,const CameraMatrix& p_projection); _FORCE_INLINE_ void _setup_geometry(RenderList::Element *e); _FORCE_INLINE_ void _render_geometry(RenderList::Element *e); _FORCE_INLINE_ void _setup_light(LightInstance *p_light); - void _render_list(RenderList::Element **p_elements, int p_element_count, const Transform& p_view_transform, const CameraMatrix& p_projection, RasterizerStorageGLES3::Texture *p_base_env, bool p_reverse_cull, bool p_alpha_pass); + void _render_list(RenderList::Element **p_elements, int p_element_count, const Transform& p_view_transform, const CameraMatrix& p_projection, RasterizerStorageGLES3::Texture *p_base_env, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow); - _FORCE_INLINE_ void _add_geometry( RasterizerStorageGLES3::Geometry* p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner,int p_material); + _FORCE_INLINE_ void _add_geometry( RasterizerStorageGLES3::Geometry* p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner,int p_material,bool p_shadow); - void _draw_skybox(RID p_skybox, CameraMatrix& p_projection, const Transform& p_transform, bool p_vflip, float p_scale); + void _draw_skybox(RID p_skybox, const CameraMatrix& p_projection, const Transform& p_transform, bool p_vflip, float p_scale); - void _setup_environment(Environment *env,CameraMatrix& p_cam_projection, const Transform& p_cam_transform); - void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform,const CameraMatrix& p_camera_projection); + void _setup_environment(Environment *env, const CameraMatrix &p_cam_projection, const Transform& p_cam_transform); + void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, const CameraMatrix& p_camera_projection, RID p_shadow_atlas); void _copy_screen(); void _copy_to_front_buffer(Environment *env); + void _copy_texture_to_front_buffer(GLuint p_texture); //used for debug - virtual void render_scene(const Transform& p_cam_transform,CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID* p_directional_lights,int p_directional_light_count,RID p_environment); + void _fill_render_list(InstanceBase** p_cull_result,int p_cull_count,bool p_shadow); + virtual void render_scene(const Transform& p_cam_transform,const CameraMatrix& p_cam_projection,bool p_cam_ortogonal,InstanceBase** p_cull_result,int p_cull_count,RID* p_light_cull_result,int p_light_cull_count,RID p_environment,RID p_shadow_atlas); + virtual void render_shadow(RID p_light,RID p_shadow_atlas,int p_pass,InstanceBase** p_cull_result,int p_cull_count); virtual bool free(RID p_rid); void _generate_brdf(); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 4b2c607297..b988781e14 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -1290,12 +1290,13 @@ void RasterizerStorageGLES3::_update_shader(Shader* p_shader) const { shaders.actions_scene.render_mode_values["cull_front"]=Pair<int*,int>(&p_shader->spatial.cull_mode,Shader::Spatial::CULL_MODE_FRONT); shaders.actions_scene.render_mode_values["cull_back"]=Pair<int*,int>(&p_shader->spatial.cull_mode,Shader::Spatial::CULL_MODE_BACK); - shaders.actions_scene.render_mode_values["cull_disable"]=Pair<int*,int>(&p_shader->spatial.cull_mode,Shader::Spatial::CULL_MODE_DISABLED); + shaders.actions_scene.render_mode_values["cull_disabled"]=Pair<int*,int>(&p_shader->spatial.cull_mode,Shader::Spatial::CULL_MODE_DISABLED); shaders.actions_scene.render_mode_flags["unshaded"]=&p_shader->spatial.unshaded; shaders.actions_scene.render_mode_flags["ontop"]=&p_shader->spatial.ontop; shaders.actions_scene.usage_flag_pointers["ALPHA"]=&p_shader->spatial.uses_alpha; + shaders.actions_scene.usage_flag_pointers["VERTEX"]=&p_shader->spatial.uses_vertex; actions=&shaders.actions_scene; actions->uniforms=&p_shader->uniforms; @@ -1318,6 +1319,9 @@ void RasterizerStorageGLES3::_update_shader(Shader* p_shader) const { p_shader->texture_count=gen_code.texture_uniforms.size(); p_shader->texture_hints=gen_code.texture_hints; + p_shader->uses_vertex_time=gen_code.uses_vertex_time; + p_shader->uses_fragment_time=gen_code.uses_fragment_time; + //all materials using this shader will have to be invalidated, unfortunately for (SelfList<Material>* E = p_shader->materials.first();E;E=E->next() ) { @@ -1535,6 +1539,57 @@ void RasterizerStorageGLES3::material_set_line_width(RID p_material, float p_wid } +bool RasterizerStorageGLES3::material_is_animated(RID p_material) { + + Material *material = material_owner.get( p_material ); + ERR_FAIL_COND_V(!material,false); + if (material->dirty_list.in_list()) { + _update_material(material); + } + + return material->is_animated_cache; + +} +bool RasterizerStorageGLES3::material_casts_shadows(RID p_material) { + + Material *material = material_owner.get( p_material ); + ERR_FAIL_COND_V(!material,false); + if (material->dirty_list.in_list()) { + _update_material(material); + } + + return material->can_cast_shadow_cache; +} + +void RasterizerStorageGLES3::material_add_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance) { + + Material *material = material_owner.get( p_material ); + ERR_FAIL_COND(!material); + + Map<RasterizerScene::InstanceBase*,int>::Element *E=material->instance_owners.find(p_instance); + if (E) { + E->get()++; + } else { + material->instance_owners[p_instance]=1; + } +} + +void RasterizerStorageGLES3::material_remove_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance) { + + Material *material = material_owner.get( p_material ); + ERR_FAIL_COND(!material); + + Map<RasterizerScene::InstanceBase*,int>::Element *E=material->instance_owners.find(p_instance); + ERR_FAIL_COND(!E); + E->get()--; + + if (E->get()==0) { + material->instance_owners.erase(E); + } +} + + + _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, const Variant& value, uint8_t *data,bool p_linear_color) { switch(type) { case ShaderLanguage::TYPE_BOOL: { @@ -2011,6 +2066,48 @@ void RasterizerStorageGLES3::_update_material(Material* material) { if (material->dirty_list.in_list()) _material_dirty_list.remove( &material->dirty_list ); + + if (material->shader && material->shader->dirty_list.in_list()) { + _update_shader(material->shader); + } + //update caches + + { + bool can_cast_shadow = false; + bool is_animated = false; + + if (material->shader && material->shader->mode==VS::SHADER_SPATIAL) { + if (!material->shader->spatial.uses_alpha && material->shader->spatial.blend_mode==Shader::Spatial::BLEND_MODE_MIX) { + can_cast_shadow=true; + } + + if (material->shader->spatial.uses_discard && material->shader->uses_fragment_time) { + is_animated=true; + } + + if (material->shader->spatial.uses_vertex && material->shader->uses_vertex_time) { + is_animated=true; + } + + } + + if (can_cast_shadow!=material->can_cast_shadow_cache || is_animated!=material->is_animated_cache) { + material->can_cast_shadow_cache=can_cast_shadow; + material->is_animated_cache=is_animated; + + for(Map<Instantiable*,int>::Element *E=material->instantiable_owners.front();E;E=E->next()) { + E->key()->instance_material_change_notify(); + } + + for(Map<RasterizerScene::InstanceBase*,int>::Element *E=material->instance_owners.front();E;E=E->next()) { + E->key()->base_material_changed(); + } + + } + + } + + //clear ubo if it needs to be cleared if (material->ubo_size) { @@ -2102,6 +2199,36 @@ void RasterizerStorageGLES3::_update_material(Material* material) { } +void RasterizerStorageGLES3::_material_add_instantiable(RID p_material,Instantiable *p_instantiable) { + + Material * material = material_owner.getornull(p_material); + ERR_FAIL_COND(!material); + + Map<Instantiable*,int>::Element *I = material->instantiable_owners.find(p_instantiable); + + if (I) { + I->get()++; + } else { + material->instantiable_owners[p_instantiable]=1; + } + +} + +void RasterizerStorageGLES3::_material_remove_instantiable(RID p_material,Instantiable *p_instantiable) { + + Material * material = material_owner.getornull(p_material); + ERR_FAIL_COND(!material); + + Map<Instantiable*,int>::Element *I = material->instantiable_owners.find(p_instantiable); + ERR_FAIL_COND(!I); + + I->get()--; + if (I->get()==0) { + material->instantiable_owners.erase(I); + } +} + + void RasterizerStorageGLES3::update_dirty_materials() { while( _material_dirty_list.first() ) { @@ -2406,6 +2533,8 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh,uint32_t p_format,VS::P surface->active=true; surface->array_len=p_vertex_count; surface->index_array_len=p_index_count; + surface->array_byte_size=p_array.size(); + surface->index_array_byte_size=p_index_array.size(); surface->primitive=p_primitive; surface->mesh=mesh; surface->format=p_format; @@ -2556,8 +2685,22 @@ void RasterizerStorageGLES3::mesh_surface_set_material(RID p_mesh, int p_surface ERR_FAIL_COND(!mesh); ERR_FAIL_INDEX(p_surface,mesh->surfaces.size()); + if (mesh->surfaces[p_surface]->material==p_material) + return; + + if (mesh->surfaces[p_surface]->material.is_valid()) { + _material_remove_instantiable(mesh->surfaces[p_surface]->material,mesh); + } + mesh->surfaces[p_surface]->material=p_material; + if (mesh->surfaces[p_surface]->material.is_valid()) { + _material_add_instantiable(mesh->surfaces[p_surface]->material,mesh); + } + + mesh->instance_material_change_notify(); + + } RID RasterizerStorageGLES3::mesh_surface_get_material(RID p_mesh, int p_surface) const{ @@ -2595,17 +2738,17 @@ DVector<uint8_t> RasterizerStorageGLES3::mesh_surface_get_array(RID p_mesh, int Surface *surface = mesh->surfaces[p_surface]; glBindBuffer(GL_ARRAY_BUFFER,surface->vertex_id); - void * data = glMapBufferRange(GL_ARRAY_BUFFER,0,surface->array_len,GL_MAP_READ_BIT); + void * data = glMapBufferRange(GL_ARRAY_BUFFER,0,surface->array_byte_size,GL_MAP_READ_BIT); ERR_FAIL_COND_V(!data,DVector<uint8_t>()); DVector<uint8_t> ret; - ret.resize(surface->array_len); + ret.resize(surface->array_byte_size); { DVector<uint8_t>::Write w = ret.write(); - copymem(w.ptr(),data,surface->array_len); + copymem(w.ptr(),data,surface->array_byte_size); } glUnmapBuffer(GL_ARRAY_BUFFER); @@ -2622,18 +2765,18 @@ DVector<uint8_t> RasterizerStorageGLES3::mesh_surface_get_index_array(RID p_mesh ERR_FAIL_COND_V(surface->index_array_len==0,DVector<uint8_t>()); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,surface->vertex_id); - void * data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER,0,surface->index_array_len,GL_MAP_READ_BIT); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,surface->index_id); + void * data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER,0,surface->index_array_byte_size,GL_MAP_READ_BIT); ERR_FAIL_COND_V(!data,DVector<uint8_t>()); DVector<uint8_t> ret; - ret.resize(surface->index_array_len); + ret.resize(surface->index_array_byte_size); { DVector<uint8_t>::Write w = ret.write(); - copymem(w.ptr(),data,surface->index_array_len); + copymem(w.ptr(),data,surface->index_array_byte_size); } glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); @@ -2662,6 +2805,59 @@ VS::PrimitiveType RasterizerStorageGLES3::mesh_surface_get_primitive_type(RID p_ return mesh->surfaces[p_surface]->primitive; } +AABB RasterizerStorageGLES3::mesh_surface_get_aabb(RID p_mesh, int p_surface) const { + + const Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND_V(!mesh,AABB()); + ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),AABB()); + + return mesh->surfaces[p_surface]->aabb; + + +} +Vector<DVector<uint8_t> > RasterizerStorageGLES3::mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const{ + + const Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND_V(!mesh,Vector<DVector<uint8_t> >()); + ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),Vector<DVector<uint8_t> >()); + + Vector<DVector<uint8_t> > bsarr; + + for(int i=0;i<mesh->surfaces[p_surface]->morph_targets.size();i++) { + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,mesh->surfaces[p_surface]->morph_targets[i].vertex_id); + void * data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER,0,mesh->surfaces[p_surface]->array_byte_size,GL_MAP_READ_BIT); + + ERR_FAIL_COND_V(!data,Vector<DVector<uint8_t> >()); + + DVector<uint8_t> ret; + ret.resize(mesh->surfaces[p_surface]->array_byte_size); + + { + + DVector<uint8_t>::Write w = ret.write(); + copymem(w.ptr(),data,mesh->surfaces[p_surface]->array_byte_size); + } + + bsarr.push_back(ret); + + glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); + } + + return bsarr; + +} +Vector<AABB> RasterizerStorageGLES3::mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const{ + + const Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND_V(!mesh,Vector<AABB >()); + ERR_FAIL_INDEX_V(p_surface,mesh->surfaces.size(),Vector<AABB >()); + + return mesh->surfaces[p_surface]->skeleton_bone_aabb; + +} + + void RasterizerStorageGLES3::mesh_remove_surface(RID p_mesh, int p_surface){ Mesh *mesh = mesh_owner.getornull(p_mesh); @@ -2670,6 +2866,10 @@ void RasterizerStorageGLES3::mesh_remove_surface(RID p_mesh, int p_surface){ Surface *surface = mesh->surfaces[p_surface]; + if (surface->material.is_valid()) { + _material_remove_instantiable(surface->material,mesh); + } + glDeleteBuffers(1,&surface->vertex_id); if (surface->index_id) { glDeleteBuffers(1,&surface->index_id); @@ -2683,6 +2883,8 @@ void RasterizerStorageGLES3::mesh_remove_surface(RID p_mesh, int p_surface){ glDeleteVertexArrays(1,&surface->morph_targets[i].array_id); } + mesh->instance_material_change_notify(); + memdelete(surface); mesh->surfaces.remove(p_surface); @@ -2971,7 +3173,6 @@ RID RasterizerStorageGLES3::light_create(VS::LightType p_type){ light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET]=0.1; light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET]=0.3; light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET]=0.6; - light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_4_OFFSET]=1.0; light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS]=0.1; light->param[VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE]=0.1; @@ -2981,6 +3182,10 @@ RID RasterizerStorageGLES3::light_create(VS::LightType p_type){ light->negative=false; light->cull_mask=0xFFFFFFFF; light->directional_shadow_mode=VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL; + light->omni_shadow_mode=VS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID; + light->omni_shadow_detail=VS::LIGHT_OMNI_SHADOW_DETAIL_VERTICAL; + + light->version=0; return light_owner.make_rid(light); } @@ -2998,9 +3203,23 @@ void RasterizerStorageGLES3::light_set_param(RID p_light,VS::LightParam p_param, ERR_FAIL_COND(!light); ERR_FAIL_INDEX(p_param,VS::LIGHT_PARAM_MAX); - if (p_param==VS::LIGHT_PARAM_RANGE || p_param==VS::LIGHT_PARAM_SPOT_ANGLE) { - light->instance_change_notify(); + switch(p_param) { + case VS::LIGHT_PARAM_RANGE: + case VS::LIGHT_PARAM_SPOT_ANGLE: + case VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE: + case VS::LIGHT_PARAM_SHADOW_DARKNESS: + case VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET: + case VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET: + case VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET: + case VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS: + case VS::LIGHT_PARAM_SHADOW_BIAS: + case VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE: { + + light->version++; + light->instance_change_notify(); + } break; } + light->param[p_param]=p_value; } void RasterizerStorageGLES3::light_set_shadow(RID p_light,bool p_enabled){ @@ -3009,6 +3228,10 @@ void RasterizerStorageGLES3::light_set_shadow(RID p_light,bool p_enabled){ ERR_FAIL_COND(!light); light->shadow=p_enabled; + light->version++; + light->instance_change_notify(); + + } void RasterizerStorageGLES3::light_set_projector(RID p_light,RID p_texture){ @@ -3021,9 +3244,8 @@ void RasterizerStorageGLES3::light_set_attenuation_texure(RID p_light,RID p_text Light * light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); - - } + void RasterizerStorageGLES3::light_set_negative(RID p_light,bool p_enable){ Light * light = light_owner.getornull(p_light); @@ -3037,6 +3259,10 @@ void RasterizerStorageGLES3::light_set_cull_mask(RID p_light,uint32_t p_mask){ ERR_FAIL_COND(!light); light->cull_mask=p_mask; + + light->version++; + light->instance_change_notify(); + } void RasterizerStorageGLES3::light_set_shader(RID p_light,RID p_shader){ @@ -3045,22 +3271,92 @@ void RasterizerStorageGLES3::light_set_shader(RID p_light,RID p_shader){ } +void RasterizerStorageGLES3::light_omni_set_shadow_mode(RID p_light,VS::LightOmniShadowMode p_mode) { + + Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + + light->omni_shadow_mode=p_mode; + + light->version++; + light->instance_change_notify(); + + +} + +VS::LightOmniShadowMode RasterizerStorageGLES3::light_omni_get_shadow_mode(RID p_light) { + + const Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light,VS::LIGHT_OMNI_SHADOW_CUBE); + + return light->omni_shadow_mode; +} + + +void RasterizerStorageGLES3::light_omni_set_shadow_detail(RID p_light,VS::LightOmniShadowDetail p_detail) { + + Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + + light->omni_shadow_detail=p_detail; + light->version++; + light->instance_change_notify(); +} + void RasterizerStorageGLES3::light_directional_set_shadow_mode(RID p_light,VS::LightDirectionalShadowMode p_mode){ Light * light = light_owner.getornull(p_light); ERR_FAIL_COND(!light); + light->directional_shadow_mode=p_mode; + light->version++; + light->instance_change_notify(); + +} + +VS::LightDirectionalShadowMode RasterizerStorageGLES3::light_directional_get_shadow_mode(RID p_light) { + + const Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light,VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL); + + return light->directional_shadow_mode; } + VS::LightType RasterizerStorageGLES3::light_get_type(RID p_light) const { const Light * light = light_owner.getornull(p_light); ERR_FAIL_COND_V(!light,VS::LIGHT_DIRECTIONAL); - return VS::LIGHT_DIRECTIONAL; + return light->type; } +float RasterizerStorageGLES3::light_get_param(RID p_light,VS::LightParam p_param) { + + const Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light,VS::LIGHT_DIRECTIONAL); + + return light->param[p_param]; +} + +bool RasterizerStorageGLES3::light_has_shadow(RID p_light) const { + + const Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light,VS::LIGHT_DIRECTIONAL); + + return light->shadow; +} + +uint64_t RasterizerStorageGLES3::light_get_version(RID p_light) const { + + const Light * light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light,0); + + return light->version; +} + + AABB RasterizerStorageGLES3::light_get_aabb(RID p_light) const { const Light * light = light_owner.getornull(p_light); diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index b12c2d93b6..f8b34d6a16 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -99,6 +99,38 @@ public: + struct Instantiable : public RID_Data { + + SelfList<RasterizerScene::InstanceBase>::List instance_list; + + _FORCE_INLINE_ void instance_change_notify() { + + SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first(); + while(instances) { + + instances->self()->base_changed(); + instances=instances->next(); + } + } + + _FORCE_INLINE_ void instance_material_change_notify() { + + SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first(); + while(instances) { + + instances->self()->base_material_changed(); + instances=instances->next(); + } + } + + Instantiable() { } + virtual ~Instantiable() { + + while(instance_list.first()) { + instance_list.first()->self()->base_removed(); + } + } + }; @@ -282,9 +314,14 @@ public: bool uses_alpha; bool unshaded; bool ontop; + bool uses_vertex; + bool uses_discard; } spatial; + bool uses_vertex_time; + bool uses_fragment_time; + Shader() : dirty_list(this) { shader=NULL; @@ -315,6 +352,8 @@ public: void update_dirty_shaders(); + + /* COMMON MATERIAL API */ struct Material : public RID_Data { @@ -331,7 +370,15 @@ public: uint32_t index; uint64_t last_pass; + Map<Instantiable*,int> instantiable_owners; + Map<RasterizerScene::InstanceBase*,int> instance_owners; + + bool can_cast_shadow_cache; + bool is_animated_cache; + Material() : list(this), dirty_list(this) { + can_cast_shadow_cache=false; + is_animated_cache=false; shader=NULL; line_width=1.0; ubo_id=0; @@ -343,6 +390,8 @@ public: mutable SelfList<Material>::List _material_dirty_list; void _material_make_dirty(Material *p_material) const; + void _material_add_instantiable(RID p_material,Instantiable *p_instantiable); + void _material_remove_instantiable(RID p_material, Instantiable *p_instantiable); mutable RID_Owner<Material> material_owner; @@ -357,34 +406,18 @@ public: virtual void material_set_line_width(RID p_material, float p_width); + virtual bool material_is_animated(RID p_material); + virtual bool material_casts_shadows(RID p_material); + + virtual void material_add_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance); + virtual void material_remove_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance); + void _update_material(Material* material); void update_dirty_materials(); /* MESH API */ - struct Instantiable : public RID_Data { - - SelfList<RasterizerScene::InstanceBase>::List instance_list; - - _FORCE_INLINE_ void instance_change_notify() { - - SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first(); - while(instances) { - - instances->self()->base_changed(); - instances=instances->next(); - } - } - - Instantiable() { } - virtual ~Instantiable() { - - while(instance_list.first()) { - instance_list.first()->self()->base_removed(); - } - } - }; struct Geometry : Instantiable { @@ -455,7 +488,8 @@ public: int index_array_len; int max_bone; - int array_bytes; + int array_byte_size; + int index_array_byte_size; VS::PrimitiveType primitive; @@ -464,7 +498,8 @@ public: Surface() { - array_bytes=0; + array_byte_size=0; + index_array_byte_size=0; mesh=NULL; format=0; array_id=0; @@ -526,6 +561,10 @@ public: virtual uint32_t mesh_surface_get_format(RID p_mesh, int p_surface) const; virtual VS::PrimitiveType mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const; + virtual AABB mesh_surface_get_aabb(RID p_mesh, int p_surface) const; + virtual Vector<DVector<uint8_t> > mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const; + virtual Vector<AABB> mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const; + virtual void mesh_remove_surface(RID p_mesh, int p_surface); virtual int mesh_get_surface_count(RID p_mesh) const; @@ -598,7 +637,10 @@ public: bool shadow; bool negative; uint32_t cull_mask; + VS::LightOmniShadowMode omni_shadow_mode; + VS::LightOmniShadowDetail omni_shadow_detail; VS::LightDirectionalShadowMode directional_shadow_mode; + uint64_t version; }; mutable RID_Owner<Light> light_owner; @@ -614,11 +656,22 @@ public: virtual void light_set_cull_mask(RID p_light,uint32_t p_mask); virtual void light_set_shader(RID p_light,RID p_shader); + virtual void light_omni_set_shadow_mode(RID p_light,VS::LightOmniShadowMode p_mode); + + virtual void light_omni_set_shadow_detail(RID p_light,VS::LightOmniShadowDetail p_detail); virtual void light_directional_set_shadow_mode(RID p_light,VS::LightDirectionalShadowMode p_mode); + virtual VS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light); + virtual VS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light); + + virtual bool light_has_shadow(RID p_light) const; virtual VS::LightType light_get_type(RID p_light) const; + virtual float light_get_param(RID p_light,VS::LightParam p_param); + virtual AABB light_get_aabb(RID p_light) const; + virtual uint64_t light_get_version(RID p_light) const; + /* PROBE API */ virtual RID reflection_probe_create(); diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index 0dff53bfb9..dce52ecd93 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -330,6 +330,7 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener SL::FunctionNode *fnode=pnode->functions[i].function; + current_func_name=fnode->name; if (fnode->name=="vertex") { @@ -401,6 +402,14 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener else code=_mkid(vnode->name); + if (vnode->name==time_name) { + if (current_func_name==vertex_name) { + r_gen_code.uses_vertex_time=true; + } + if (current_func_name==fragment_name) { + r_gen_code.uses_fragment_time=true; + } + } } break; case SL::Node::TYPE_CONSTANT: { @@ -536,6 +545,8 @@ Error ShaderCompilerGLES3::compile(VS::ShaderMode p_mode, const String& p_code, r_gen_code.fragment=String(); r_gen_code.fragment_global=String(); r_gen_code.light=String(); + r_gen_code.uses_fragment_time=false; + r_gen_code.uses_vertex_time=false; @@ -645,7 +656,9 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { - + vertex_name="vertex"; + fragment_name="fragment"; + time_name="TIME"; diff --git a/drivers/gles3/shader_compiler_gles3.h b/drivers/gles3/shader_compiler_gles3.h index dcea82d773..3549526808 100644 --- a/drivers/gles3/shader_compiler_gles3.h +++ b/drivers/gles3/shader_compiler_gles3.h @@ -32,6 +32,9 @@ public: String fragment; String light; + bool uses_fragment_time; + bool uses_vertex_time; + }; private: @@ -49,6 +52,10 @@ private: String _dump_node_code(ShaderLanguage::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions& p_actions, const DefaultIdentifierActions& p_default_actions); + StringName current_func_name; + StringName vertex_name; + StringName fragment_name; + StringName time_name; Set<StringName> used_name_defines; Set<StringName> used_rmode_defines; diff --git a/drivers/gles3/shaders/SCsub b/drivers/gles3/shaders/SCsub index afffe10316..44d325b091 100644 --- a/drivers/gles3/shaders/SCsub +++ b/drivers/gles3/shaders/SCsub @@ -6,4 +6,5 @@ if env['BUILDERS'].has_key('GLES3_GLSL'): env.GLES3_GLSL('canvas_shadow.glsl'); env.GLES3_GLSL('scene.glsl'); env.GLES3_GLSL('cubemap_filter.glsl'); + env.GLES3_GLSL('cube_to_dp.glsl'); diff --git a/drivers/gles3/shaders/cube_to_dp.glsl b/drivers/gles3/shaders/cube_to_dp.glsl new file mode 100644 index 0000000000..5ffc78c0b9 --- /dev/null +++ b/drivers/gles3/shaders/cube_to_dp.glsl @@ -0,0 +1,79 @@ +[vertex] + + +layout(location=0) in highp vec4 vertex_attrib; +layout(location=4) in vec2 uv_in; + +out vec2 uv_interp; + +void main() { + + uv_interp = uv_in; + gl_Position = vertex_attrib; +} + +[fragment] + + +uniform highp samplerCube source_cube; //texunit:0 +in vec2 uv_interp; + +uniform bool z_flip; +uniform highp float z_far; +uniform highp float z_near; +uniform highp float bias; + +void main() { + + highp vec3 normal = vec3( uv_interp * 2.0 - 1.0, 0.0 ); +/* + if(z_flip) { + normal.z = 0.5 - 0.5*((normal.x * normal.x) + (normal.y * normal.y)); + } else { + normal.z = -0.5 + 0.5*((normal.x * normal.x) + (normal.y * normal.y)); + } +*/ + + //normal.z = sqrt(1.0-dot(normal.xy,normal.xy)); + //normal.xy*=1.0+normal.z; + + normal.z = 0.5 - 0.5*((normal.x * normal.x) + (normal.y * normal.y)); + normal = normalize(normal); + +/* + normal.z=0.5; + normal=normalize(normal); +*/ + if (!z_flip) { + normal.z=-normal.z; + } + + //normal = normalize(vec3( uv_interp * 2.0 - 1.0, 1.0 )); + float depth = texture(source_cube,normal).r; + + // absolute values for direction cosines, bigger value equals closer to basis axis + vec3 unorm = abs(normal); + + if ( (unorm.x >= unorm.y) && (unorm.x >= unorm.z) ) { + // x code + unorm = normal.x > 0.0 ? vec3( 1.0, 0.0, 0.0 ) : vec3( -1.0, 0.0, 0.0 ) ; + } else if ( (unorm.y > unorm.x) && (unorm.y >= unorm.z) ) { + // y code + unorm = normal.y > 0.0 ? vec3( 0.0, 1.0, 0.0 ) : vec3( 0.0, -1.0, 0.0 ) ; + } else if ( (unorm.z > unorm.x) && (unorm.z > unorm.y) ) { + // z code + unorm = normal.z > 0.0 ? vec3( 0.0, 0.0, 1.0 ) : vec3( 0.0, 0.0, -1.0 ) ; + } else { + // oh-no we messed up code + // has to be + unorm = vec3( 1.0, 0.0, 0.0 ); + } + + float depth_fix = 1.0 / dot(normal,unorm); + + + depth = 2.0 * depth - 1.0; + float linear_depth = 2.0 * z_near * z_far / (z_far + z_near - depth * (z_far - z_near)); + gl_FragDepth = (linear_depth*depth_fix+bias) / z_far; +} + diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 60ac015a17..de1591e8ff 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -1,7 +1,6 @@ [vertex] -#define ENABLE_UV_INTERP /* from VisualServer: @@ -56,6 +55,15 @@ layout(std140) uniform SceneData { //ubo:0 highp vec4 bg_color; float ambient_energy; float bg_energy; + + float shadow_z_offset; + float shadow_z_slope_scale; + float shadow_dual_paraboloid_render_zfar; + float shadow_dual_paraboloid_render_side; + + vec2 shadow_atlas_pixel_size; + vec2 directional_shadow_pixel_size; + }; uniform highp mat4 world_transform; @@ -68,6 +76,7 @@ layout(std140) uniform LightData { //ubo:3 mediump vec4 light_direction_attenuation; mediump vec4 light_color_energy; mediump vec4 light_params; //cone attenuation, specular, shadow darkening, + mediump vec4 light_clamp; mediump vec4 shadow_split_offsets; highp mat4 shadow_matrix1; highp mat4 shadow_matrix2; @@ -75,19 +84,6 @@ layout(std140) uniform LightData { //ubo:3 highp mat4 shadow_matrix4; }; -#ifdef USE_FORWARD_1_SHADOW_MAP -out mediump vec4 forward_shadow_pos1; -#endif - -#ifdef USE_FORWARD_2_SHADOW_MAP -out mediump vec4 forward_shadow_pos2; -#endif - -#ifdef USE_FORWARD_4_SHADOW_MAP -out mediump vec4 forward_shadow_pos3; -out mediump vec4 forward_shadow_pos4; -#endif - #endif /* Varyings */ @@ -120,13 +116,6 @@ varying vec4 position_interp; #endif -#ifdef USE_SHADOW_PASS - -uniform highp float shadow_z_offset; -uniform highp float shadow_z_slope_scale; - -#endif - VERTEX_SHADER_GLOBALS @@ -141,6 +130,11 @@ MATERIAL_UNIFORMS #endif +#ifdef RENDER_SHADOW_DUAL_PARABOLOID + +out highp float dp_clip; + +#endif void main() { @@ -206,24 +200,49 @@ VERTEX_SHADER_CODE } + vertex_interp = vertex.xyz; + normal_interp = normal; + +#if defined(ENABLE_TANGENT_INTERP) + tangent_interp = tangent; + binormal_interp = binormal; +#endif + +#ifdef RENDER_SHADOW + + +#ifdef RENDER_SHADOW_DUAL_PARABOLOID + + vertex_interp.z*= shadow_dual_paraboloid_render_side; + normal_interp.z*= shadow_dual_paraboloid_render_side; -#ifdef USE_SHADOW_PASS + dp_clip=vertex_interp.z; //this attempts to avoid noise caused by objects sent to the other parabolloid side due to bias + + //for dual paraboloid shadow mapping, this is the fastest but least correct way, as it curves straight edges + + highp vec3 vtx = vertex_interp+normalize(vertex_interp)*shadow_z_offset; + highp float distance = length(vtx); + vtx = normalize(vtx); + vtx.xy/=1.0-vtx.z; + vtx.z=(distance/shadow_dual_paraboloid_render_zfar); + vtx.z=vtx.z * 2.0 - 1.0; + + vertex.xyz=vtx; + vertex.w=1.0; + + +#else float z_ofs = shadow_z_offset; z_ofs += (1.0-abs(normal_interp.z))*shadow_z_slope_scale; vertex_interp.z-=z_ofs; -#endif +#endif //RENDER_SHADOW_DUAL_PARABOLOID - vertex_interp = vertex.xyz; - normal_interp = normal; +#endif //RENDER_SHADOW -#if defined(ENABLE_TANGENT_INTERP) - tangent_interp = tangent; - binormal_interp = binormal; -#endif -#if !defined(SKIP_TRANSFORM_USED) +#if !defined(SKIP_TRANSFORM_USED) && !defined(RENDER_SHADOW_DUAL_PARABOLOID) gl_Position = projection_matrix * vec4(vertex_interp,1.0); #else gl_Position = vertex; @@ -239,11 +258,6 @@ VERTEX_SHADER_CODE #define M_PI 3.14159265359 - -#define ENABLE_UV_INTERP -//hack to use uv if no uv present so it works with lightmap - - /* Varyings */ #if defined(ENABLE_COLOR_INTERP) @@ -318,6 +332,15 @@ layout(std140) uniform SceneData { highp vec4 bg_color; float ambient_energy; float bg_energy; + + float shadow_z_offset; + float shadow_z_slope_scale; + float shadow_dual_paraboloid_render_zfar; + float shadow_dual_paraboloid_render_side; + + vec2 shadow_atlas_pixel_size; + vec2 directional_shadow_pixel_size; + }; @@ -328,7 +351,8 @@ layout(std140) uniform LightData { highp vec4 light_pos_inv_radius; mediump vec4 light_direction_attenuation; mediump vec4 light_color_energy; - mediump vec4 light_params; //cone attenuation, specular, shadow darkening, + mediump vec4 light_params; //cone attenuation, specular, shadow darkening, shadow enabled + mediump vec4 light_clamp; mediump vec4 shadow_split_offsets; highp mat4 shadow_matrix1; highp mat4 shadow_matrix2; @@ -336,20 +360,12 @@ layout(std140) uniform LightData { highp mat4 shadow_matrix4; }; -#ifdef USE_FORWARD_1_SHADOW_MAP -in mediump vec4 forward_shadow_pos1; #endif -#ifdef USE_FORWARD_2_SHADOW_MAP -in mediump vec4 forward_shadow_pos2; -#endif -#ifdef USE_FORWARD_4_SHADOW_MAP -in mediump vec4 forward_shadow_pos3; -in mediump vec4 forward_shadow_pos4; -#endif +uniform highp sampler2DShadow directional_shadow; //texunit:-4 +uniform highp sampler2DShadow shadow_atlas; //texunit:-3 -#endif #ifdef USE_MULTIPLE_RENDER_TARGETS @@ -408,10 +424,27 @@ void light_compute(vec3 normal, vec3 light_vec,vec3 eye_vec,vec3 diffuse_color, } +float sample_shadow(highp sampler2DShadow shadow, vec2 shadow_pixel_size, vec2 pos, float depth, vec4 clamp_rect) { + + return textureProj(shadow,vec4(pos,depth,1.0)); +} + +#ifdef RENDER_SHADOW_DUAL_PARABOLOID + +in highp float dp_clip; + +#endif + void main() { +#ifdef RENDER_SHADOW_DUAL_PARABOLOID + + if (dp_clip>0.0) + discard; +#endif + //lay out everything, whathever is unused is optimized away anyway - vec3 vertex = vertex_interp; + highp vec3 vertex = vertex_interp; vec3 albedo = vec3(0.8,0.8,0.8); vec3 specular = vec3(0.2,0.2,0.2); float roughness = 1.0; @@ -528,27 +561,216 @@ FRAGMENT_SHADER_CODE #endif -#ifdef USE_FORWARD_LIGHTING - #ifdef USE_FORWARD_DIRECTIONAL - light_compute(normal,light_direction_attenuation.xyz,eye_vec,albedo,specular,roughness,1.0,diffuse_light,specular_light); + float light_attenuation=1.0; + +#ifdef LIGHT_DIRECTIONAL_SHADOW + + if (gl_FragCoord.w > shadow_split_offsets.w) { + + vec3 pssm_coord; + +#ifdef LIGHT_USE_PSSM_BLEND + float pssm_blend; + vec3 pssm_coord2; + bool use_blend=true; + vec3 light_pssm_split_inv = 1.0/shadow_split_offsets.xyz; + float w_inv = 1.0/gl_FragCoord.w; #endif + +#ifdef LIGHT_USE_PSSM4 + + + if (gl_FragCoord.w > shadow_split_offsets.y) { + + if (gl_FragCoord.w > shadow_split_offsets.x) { + + highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0)); + pssm_coord=splane.xyz/splane.w; + ambient_light=vec3(1.0,0.4,0.4); + + +#if defined(LIGHT_USE_PSSM_BLEND) + + splane=(shadow_matrix2 * vec4(vertex,1.0)); + pssm_coord2=splane.xyz/splane.w; + pssm_blend=smoothstep(0.0,light_pssm_split_inv.x,w_inv); +#endif + + } else { + + highp vec4 splane=(shadow_matrix2 * vec4(vertex,1.0)); + pssm_coord=splane.xyz/splane.w; + ambient_light=vec3(0.4,1.0,0.4); + +#if defined(LIGHT_USE_PSSM_BLEND) + splane=(shadow_matrix3 * vec4(vertex,1.0)); + pssm_coord2=splane.xyz/splane.w; + pssm_blend=smoothstep(light_pssm_split_inv.x,light_pssm_split_inv.y,w_inv); +#endif + + } + } else { + + + if (gl_FragCoord.w > shadow_split_offsets.z) { + + highp vec4 splane=(shadow_matrix3 * vec4(vertex,1.0)); + pssm_coord=splane.xyz/splane.w; + ambient_light=vec3(0.4,0.4,1.0); + +#if defined(LIGHT_USE_PSSM_BLEND) + splane=(shadow_matrix4 * vec4(vertex,1.0)); + pssm_coord2=splane.xyz/splane.w; + pssm_blend=smoothstep(light_pssm_split_inv.y,light_pssm_split_inv.z,w_inv); +#endif + + } else { + highp vec4 splane=(shadow_matrix4 * vec4(vertex,1.0)); + pssm_coord=splane.xyz/splane.w; + diffuse_light*=vec3(1.0,0.4,1.0); + +#if defined(LIGHT_USE_PSSM_BLEND) + use_blend=false; + +#endif + + } + } + +#endif //LIGHT_USE_PSSM4 + +#ifdef LIGHT_USE_PSSM2 + + if (gl_FragCoord.w > shadow_split_offsets.x) { + + highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0)); + pssm_coord=splane.xyz/splane.w; + + +#if defined(LIGHT_USE_PSSM_BLEND) + + splane=(shadow_matrix2 * vec4(vertex,1.0)); + pssm_coord2=splane.xyz/splane.w; + pssm_blend=smoothstep(0.0,light_pssm_split_inv.x,w_inv); +#endif + + } else { + highp vec4 splane=(shadow_matrix2 * vec4(vertex,1.0)); + pssm_coord=splane.xyz/splane.w; +#if defined(LIGHT_USE_PSSM_BLEND) + use_blend=false; + +#endif + + } + +#endif //LIGHT_USE_PSSM2 + +#if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2) + { //regular orthogonal + highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0)); + pssm_coord=splane.xyz/splane.w; + } +#endif + + + //one one sample + light_attenuation=sample_shadow(directional_shadow,directional_shadow_pixel_size,pssm_coord.xy,pssm_coord.z,light_clamp); + + +#if defined(LIGHT_USE_PSSM_BLEND) + if (use_blend) { + float light_attenuation2=sample_shadow(directional_shadow,directional_shadow_pixel_size,pssm_coord2.xy,pssm_coord2.z,light_clamp); + light_attenuation=mix(light_attenuation,light_attenuation2,pssm_blend); + } +#endif + + } + +#endif //LIGHT_DIRECTIONAL_SHADOW + + light_compute(normal,-light_direction_attenuation.xyz,eye_vec,albedo,specular,roughness,light_attenuation,diffuse_light,specular_light); + + +#endif //USE_FORWARD_DIRECTIONAL + + #ifdef USE_FORWARD_OMNI vec3 light_rel_vec = light_pos_inv_radius.xyz-vertex; float normalized_distance = length( light_rel_vec )*light_pos_inv_radius.w; float light_attenuation = pow( max(1.0 - normalized_distance, 0.0), light_direction_attenuation.w ); + + if (light_params.w>0.5) { + //there is a shadowmap + + highp vec3 splane=(shadow_matrix1 * vec4(vertex,1.0)).xyz; + float shadow_len=length(splane); + splane=normalize(splane); + vec4 clamp_rect=light_clamp; + + if (splane.z>=0.0) { + + splane.z+=1.0; + + clamp_rect.y+=clamp_rect.w; + + } else { + + splane.z=1.0 - splane.z; + + //if (clamp_rect.z<clamp_rect.w) { + // clamp_rect.x+=clamp_rect.z; + //} else { + // clamp_rect.y+=clamp_rect.w; + //} + + } + + splane.xy/=splane.z; + splane.xy=splane.xy * 0.5 + 0.5; + splane.z = shadow_len * light_pos_inv_radius.w; + + splane.xy = clamp_rect.xy+splane.xy*clamp_rect.zw; + + light_attenuation*=sample_shadow(shadow_atlas,shadow_atlas_pixel_size,splane.xy,splane.z,clamp_rect); + } + light_compute(normal,normalize(light_rel_vec),eye_vec,albedo,specular,roughness,light_attenuation,diffuse_light,specular_light); -#endif + +#endif //USE_FORWARD_OMNI #ifdef USE_FORWARD_SPOT -#endif + vec3 light_rel_vec = light_pos_inv_radius.xyz-vertex; + float normalized_distance = length( light_rel_vec )*light_pos_inv_radius.w; + float light_attenuation = pow( max(1.0 - normalized_distance, 0.0), light_direction_attenuation.w ); + vec3 spot_dir = light_direction_attenuation.xyz; + float spot_cutoff=light_params.y; + float scos = max(dot(-normalize(light_rel_vec), spot_dir),spot_cutoff); + float rim = (1.0 - scos) / (1.0 - spot_cutoff); + light_attenuation *= 1.0 - pow( rim, light_params.x); + + if (light_params.w>0.5) { + //there is a shadowmap + + highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0)); + splane.xyz/=splane.w; + // splane.xy=splane.xy*0.5+0.5; + + //splane.xy=light_clamp.xy+splane.xy*light_clamp.zw; + light_attenuation*=sample_shadow(shadow_atlas,shadow_atlas_pixel_size,splane.xy,splane.z,light_clamp); + + } + + light_compute(normal,normalize(light_rel_vec),eye_vec,albedo,specular,roughness,light_attenuation,diffuse_light,specular_light); + +#endif //USE_FORWARD_SPOT -#endif #if defined(USE_LIGHT_SHADER_CODE) @@ -560,6 +782,11 @@ LIGHT_SHADER_CODE } #endif +#ifdef RENDER_SHADOW +//nothing happens, so a tree-ssa optimizer will result in no fragment shader :) +#else + + #ifdef USE_MULTIPLE_RENDER_TARGETS //approximate ambient scale for SSAO, since we will lack full ambient @@ -574,13 +801,17 @@ LIGHT_SHADER_CODE #else + #ifdef SHADELESS frag_color=vec4(albedo,alpha); #else frag_color=vec4(ambient_light+diffuse_light+specular_light,alpha); -#endif +#endif //SHADELESS + +#endif //USE_MULTIPLE_RENDER_TARGETS + +#endif //RENDER_SHADOW -#endif } |