diff options
25 files changed, 2590 insertions, 225 deletions
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index c455d4bd11..4573f94d22 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -1382,10 +1382,6 @@ void RasterizerCanvasGLES3::reset_canvas() { glDisable(GL_CULL_FACE); glDisable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); -#ifdef GLEW_ENABLED - glDisable(GL_POINT_SPRITE); - glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); -#endif glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index c799cd12af..dabb7918a9 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -122,11 +122,13 @@ void RasterizerGLES3::begin_frame(){ storage->frame.time[1]=Math::fmod(time_total,3600); storage->frame.time[2]=Math::fmod(time_total,900); storage->frame.time[3]=Math::fmod(time_total,60); + storage->frame.count++; storage->update_dirty_shaders(); storage->update_dirty_materials(); scene->iteration(); + } void RasterizerGLES3::set_current_render_target(RID p_render_target){ diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 4ae257abc4..e04908ea67 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -446,6 +446,338 @@ int RasterizerSceneGLES3::get_directional_light_shadow_size(RID p_light_intance) return shadow_size; } +////////////////////////////////////////////////////// + +RID RasterizerSceneGLES3::reflection_atlas_create() { + + ReflectionAtlas *reflection_atlas = memnew( ReflectionAtlas ); + reflection_atlas->subdiv=0; + reflection_atlas->color=0; + for(int i=0;i<6;i++) { + reflection_atlas->fbo[i]=0; + } + + return reflection_atlas_owner.make_rid(reflection_atlas); +} + +void RasterizerSceneGLES3::reflection_atlas_set_size(RID p_ref_atlas,int p_size) { + + ReflectionAtlas *reflection_atlas = reflection_atlas_owner.getornull(p_ref_atlas); + ERR_FAIL_COND(!reflection_atlas); + + int size = nearest_power_of_2(p_size); + + if (size==reflection_atlas->size) + return; + if (reflection_atlas->size) { + for(int i=0;i<6;i++) { + glDeleteFramebuffers(1,&reflection_atlas->fbo[i]); + reflection_atlas->fbo[i]=0; + } + glDeleteTextures(1,&reflection_atlas->color); + reflection_atlas->color=0; + } + + reflection_atlas->size=size; + + for(int i=0;i<reflection_atlas->reflections.size();i++) { + //erase probes reference to this + if (reflection_atlas->reflections[i].owner.is_valid()) { + ReflectionProbeInstance *reflection_probe_instance = reflection_probe_instance_owner.getornull(reflection_atlas->reflections[i].owner); + reflection_atlas->reflections[i].owner=RID(); + + ERR_CONTINUE(!reflection_probe_instance); + reflection_probe_instance->reflection_atlas_index=-1; + reflection_probe_instance->atlas=RID(); + reflection_probe_instance->render_step=-1; + } + } + + + if (reflection_atlas->size) { + + bool use_float=true; + + + GLenum internal_format = use_float?GL_RGBA16F:GL_RGB10_A2; + GLenum format = GL_RGBA; + GLenum type = use_float?GL_HALF_FLOAT:GL_UNSIGNED_INT_2_10_10_10_REV; + + + // Create a texture for storing the color + glActiveTexture(GL_TEXTURE0); + glGenTextures(1, &reflection_atlas->color); + glBindTexture(GL_TEXTURE_2D, reflection_atlas->color); + + int mmsize=reflection_atlas->size; + + for(int i=0;i<6;i++) { + glTexImage2D(GL_TEXTURE_2D, i, internal_format, mmsize, mmsize, 0, + format, type, NULL); + + mmsize>>=1; + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + mmsize=reflection_atlas->size; + + for(int i=0;i<6;i++) { + glGenFramebuffers(1, &reflection_atlas->fbo[i]); + glBindFramebuffer(GL_FRAMEBUFFER, reflection_atlas->fbo[i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, reflection_atlas->color, i); + glDisable(GL_SCISSOR_TEST); + glViewport(0,0,mmsize,mmsize); + glClearColor(0,0,0,0); + glClear(GL_COLOR_BUFFER_BIT); //it needs to be cleared, to avoid generating garbage + + mmsize>>=1; + + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 5); + + } + + + +} +void RasterizerSceneGLES3::reflection_atlas_set_subdivision(RID p_ref_atlas,int p_subdiv) { + + ReflectionAtlas *reflection_atlas = reflection_atlas_owner.getornull(p_ref_atlas); + ERR_FAIL_COND(!reflection_atlas); + + uint32_t subdiv = nearest_power_of_2(p_subdiv); + if (subdiv&0xaaaaaaaa) { //sqrt(subdiv) must be integer + subdiv<<=1; + } + + subdiv=int(Math::sqrt(subdiv)); + + if (reflection_atlas->subdiv==subdiv) + return; + + + if (subdiv) { + + for(int i=0;i<reflection_atlas->reflections.size();i++) { + //erase probes reference to this + if (reflection_atlas->reflections[i].owner.is_valid()) { + ReflectionProbeInstance *reflection_probe_instance = reflection_probe_instance_owner.getornull(reflection_atlas->reflections[i].owner); + reflection_atlas->reflections[i].owner=RID(); + + ERR_CONTINUE(!reflection_probe_instance); + reflection_probe_instance->reflection_atlas_index=-1; + reflection_probe_instance->atlas=RID(); + reflection_probe_instance->render_step=-1; + } + } + } + + reflection_atlas->subdiv=subdiv; + + reflection_atlas->reflections.resize(subdiv*subdiv); +} + + +//////////////////////////////////////////////////// + +RID RasterizerSceneGLES3::reflection_probe_instance_create(RID p_probe) { + + RasterizerStorageGLES3::ReflectionProbe *probe = storage->reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!probe,RID()); + + ReflectionProbeInstance *rpi = memnew( ReflectionProbeInstance ); + + rpi->probe_ptr=probe; + rpi->self=reflection_probe_instance_owner.make_rid(rpi); + rpi->probe=p_probe; + rpi->reflection_atlas_index=-1; + rpi->render_step=-1; + rpi->last_pass=0; + + return rpi->self; +} + +void RasterizerSceneGLES3::reflection_probe_instance_set_transform(RID p_instance,const Transform& p_transform) { + + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND(!rpi); + rpi->transform=p_transform; + +} + +void RasterizerSceneGLES3::reflection_probe_release_atlas_index(RID p_instance) { + + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND(!rpi); + if (rpi->reflection_atlas_index==-1) + return; + + ReflectionAtlas *reflection_atlas = reflection_atlas_owner.getornull(rpi->atlas); + ERR_FAIL_COND(!reflection_atlas); + + ERR_FAIL_INDEX(rpi->reflection_atlas_index,reflection_atlas->reflections.size()); + + ERR_FAIL_COND(reflection_atlas->reflections[rpi->reflection_atlas_index].owner!=rpi->self); + + reflection_atlas->reflections[rpi->reflection_atlas_index].owner=RID(); + + rpi->reflection_atlas_index=-1; + rpi->atlas=RID(); + rpi->render_step=-1; + +} + +bool RasterizerSceneGLES3::reflection_probe_instance_needs_redraw(RID p_instance) { + + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!rpi,false); + + return rpi->reflection_atlas_index==-1 || rpi->probe_ptr->update_mode==VS::REFLECTION_PROBE_UPDATE_ALWAYS; +} + +bool RasterizerSceneGLES3::reflection_probe_instance_has_reflection(RID p_instance){ + + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!rpi,false); + + return rpi->reflection_atlas_index!=-1; +} + +bool RasterizerSceneGLES3::reflection_probe_instance_begin_render(RID p_instance,RID p_reflection_atlas) { + + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!rpi,false); + + rpi->render_step=0; + + if (rpi->reflection_atlas_index!=-1) { + return true; //got one already + } + + ReflectionAtlas *reflection_atlas = reflection_atlas_owner.getornull(p_reflection_atlas); + ERR_FAIL_COND_V(!reflection_atlas,false); + + + if (reflection_atlas->size==0 || reflection_atlas->subdiv==0) { + return false; + } + + + int best_free=-1; + int best_used=-1; + uint64_t best_used_frame; + + for(int i=0;i<reflection_atlas->reflections.size();i++) { + if (reflection_atlas->reflections[i].owner==RID()) { + best_free=i; + break; + } + + if (rpi->render_step<0 && reflection_atlas->reflections[i].last_frame<storage->frame.count && + (best_used==-1 || reflection_atlas->reflections[i].last_frame<best_used_frame)) { + best_used=i; + best_used_frame=reflection_atlas->reflections[i].last_frame; + } + } + + if (best_free==-1 && best_used==-1) { + return false ;// sorry, can not do. Try again next frame. + } + + if (best_free==-1) { + //find best from what is used + best_free=best_used; + + ReflectionProbeInstance *victim_rpi = reflection_probe_instance_owner.getornull(reflection_atlas->reflections[best_free].owner); + ERR_FAIL_COND_V(!victim_rpi,false); + victim_rpi->atlas=RID(); + victim_rpi->reflection_atlas_index=-1; + + } + + reflection_atlas->reflections[best_free].owner=p_instance; + reflection_atlas->reflections[best_free].last_frame=storage->frame.count; + + rpi->reflection_atlas_index=best_free; + rpi->atlas=p_reflection_atlas; + rpi->render_step=0; + + return true; +} + +bool RasterizerSceneGLES3::reflection_probe_instance_postprocess_step(RID p_instance) { + + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!rpi,true); + + ReflectionAtlas *reflection_atlas = reflection_atlas_owner.getornull(rpi->atlas); + ERR_FAIL_COND_V(!reflection_atlas,false); + + ERR_FAIL_COND_V(rpi->render_step>=6,true); + + glBindFramebuffer(GL_FRAMEBUFFER,reflection_atlas->fbo[rpi->render_step]); + state.cube_to_dp_shader.bind(); + + int target_size=reflection_atlas->size/reflection_atlas->subdiv; + + int cubemap_index=reflection_cubemaps.size()-1; + + for(int i=reflection_cubemaps.size()-1;i>=0;i--) { + //find appropriate cubemap to render to + if (reflection_cubemaps[i].size>target_size*2) + break; + + cubemap_index=i; + } + + glDisable(GL_BLEND); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP,reflection_cubemaps[cubemap_index].cubemap); + glDisable(GL_CULL_FACE); + + storage->shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID,true); + storage->shaders.cubemap_filter.bind(); + + int cell_size = reflection_atlas->size / reflection_atlas->subdiv; + for(int i=0;i<rpi->render_step;i++) { + cell_size>>=1; //mipmaps! + } + int x = (rpi->reflection_atlas_index % reflection_atlas->subdiv) * cell_size; + int y = (rpi->reflection_atlas_index / reflection_atlas->subdiv) * cell_size; + int width=cell_size; + int height=cell_size; + + storage->shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DIRECT_WRITE,rpi->render_step==0); + storage->shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::LOW_QUALITY,rpi->probe_ptr->update_mode==VS::REFLECTION_PROBE_UPDATE_ALWAYS); + for(int i=0;i<2;i++) { + + storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::Z_FLIP,i>0); + storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::ROUGHNESS,rpi->render_step/5.0); + + uint32_t local_width=width,local_height=height; + uint32_t local_x=x,local_y=y; + + local_height/=2; + local_y+=i*local_height; + + glViewport(local_x,local_y,local_width,local_height); + + _copy_screen(); + } + storage->shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DIRECT_WRITE,false); + storage->shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::LOW_QUALITY,false); + + + rpi->render_step++; + + return rpi->render_step==6; +} /* ENVIRONMENT API */ @@ -464,26 +796,12 @@ void RasterizerSceneGLES3::environment_set_background(RID p_env,VS::EnvironmentB env->bg_mode=p_bg; } -void RasterizerSceneGLES3::environment_set_skybox(RID p_env, RID p_skybox, int p_radiance_size){ +void RasterizerSceneGLES3::environment_set_skybox(RID p_env, RID p_skybox){ Environment *env=environment_owner.getornull(p_env); ERR_FAIL_COND(!env); - if (env->skybox_color.is_valid()) { - env->skybox_color=RID(); - } - if (env->skybox_radiance.is_valid()) { - storage->free(env->skybox_radiance); - env->skybox_radiance=RID(); - } - - - if (p_skybox.is_valid()) { - - env->skybox_color=p_skybox; - env->skybox_radiance=storage->texture_create_radiance_cubemap(p_skybox,p_radiance_size); - //env->skybox_irradiance=storage->texture_create_pbr_cubemap(p_skybox,VS::PBR_CUBEMAP_IRRADIANCE,p_irradiance_size); - } + env->skybox=p_skybox; } @@ -775,6 +1093,7 @@ void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e) { RasterizerStorageGLES3::Surface *s = static_cast<RasterizerStorageGLES3::Surface*>(e->geometry); glBindVertexArray(s->array_id); // everything is so easy nowadays + } break; } @@ -821,6 +1140,8 @@ void RasterizerSceneGLES3::_setup_light(RenderList::Element *e) { int omni_count=0; int spot_indices[16]; int spot_count=0; + int reflection_indices[16]; + int reflection_count=0; int maxobj = MIN(16,state.max_forward_lights_per_object); @@ -859,6 +1180,32 @@ void RasterizerSceneGLES3::_setup_light(RenderList::Element *e) { glUniform1iv(state.scene_shader.get_uniform(SceneShaderGLES3::SPOT_LIGHT_INDICES),spot_count,spot_indices); } + + int rc = e->instance->reflection_probe_instances.size(); + + + if (rc) { + + + const RID* reflections=e->instance->reflection_probe_instances.ptr(); + + for(int i=0;i<rc;i++) { + ReflectionProbeInstance *rpi=reflection_probe_instance_owner.getptr(reflections[i]); + if (rpi->last_pass!=render_pass) //not visible + continue; + + if (reflection_count<maxobj) { + reflection_indices[reflection_count++]=rpi->reflection_index; + } + } + } + + state.scene_shader.set_uniform(SceneShaderGLES3::REFLECTION_COUNT,reflection_count); + if (reflection_count) { + glUniform1iv(state.scene_shader.get_uniform(SceneShaderGLES3::REFLECTION_INDICES),reflection_count,reflection_indices); + } + + } @@ -932,9 +1279,9 @@ void RasterizerSceneGLES3::_set_cull(bool p_front,bool p_reverse_cull) { -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,bool p_directional_add) { +void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_element_count,const Transform& p_view_transform,const CameraMatrix& p_projection,GLuint p_base_env,bool p_reverse_cull,bool p_alpha_pass,bool p_shadow,bool p_directional_add,bool p_directional_shadows) { - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) { + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) { //p_reverse_cull=!p_reverse_cull; glFrontFace(GL_CCW); } else { @@ -951,15 +1298,15 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e 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); + glBindTexture(GL_TEXTURE_2D,p_base_env); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP,true); } else { - state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP,false); } } else { - state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP,false); } @@ -1038,7 +1385,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e if (p_directional_add || (directional_light && (e->sort_key&RenderList::SORT_KEY_NO_DIRECTIONAL_FLAG)==0)) { state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHT_DIRECTIONAL,true); - if (directional_light->light_ptr->shadow) { + if (p_directional_shadows && directional_light->light_ptr->shadow) { state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_DIRECTIONAL_SHADOW,true); switch(directional_light->light_ptr->directional_shadow_mode) { @@ -1076,7 +1423,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_MIX: { glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } else { @@ -1097,7 +1444,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e } break; case RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_MUL: { glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } else { @@ -1154,7 +1501,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e glFrontFace(GL_CW); glBindVertexArray(0); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_CUBEMAP,false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP,false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING,false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHT_DIRECTIONAL,false); state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_DIRECTIONAL_SHADOW,false); @@ -1290,9 +1637,12 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g } } -void RasterizerSceneGLES3::_draw_skybox(RID p_skybox,const CameraMatrix& p_projection,const Transform& p_transform,bool p_vflip,float p_scale) { +void RasterizerSceneGLES3::_draw_skybox(RasterizerStorageGLES3::SkyBox *p_skybox,const CameraMatrix& p_projection,const Transform& p_transform,bool p_vflip,float p_scale) { + + if (!p_skybox) + return; - RasterizerStorageGLES3::Texture *tex = storage->texture_owner.getornull(p_skybox); + RasterizerStorageGLES3::Texture *tex = storage->texture_owner.getornull(p_skybox->cubemap); ERR_FAIL_COND(!tex); glActiveTexture(GL_TEXTURE0); @@ -1461,7 +1811,7 @@ void RasterizerSceneGLES3::_setup_environment(Environment *env,const CameraMatri } -void RasterizerSceneGLES3::_setup_directional_light(int p_index,const Transform& p_camera_inverse_transform) { +void RasterizerSceneGLES3::_setup_directional_light(int p_index,const Transform& p_camera_inverse_transform,bool p_use_shadows) { LightInstance *li = directional_lights[p_index]; @@ -1499,7 +1849,7 @@ void RasterizerSceneGLES3::_setup_directional_light(int p_index,const Transform& ubo_data.light_shadow_color[3]=1.0; - if (li->light_ptr->shadow) { + if (p_use_shadows && li->light_ptr->shadow) { int shadow_count=0; @@ -1568,7 +1918,6 @@ void RasterizerSceneGLES3::_setup_directional_light(int p_index,const Transform& 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; @@ -1844,6 +2193,103 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result,int p_light_cu } +void RasterizerSceneGLES3::_setup_reflections(RID *p_reflection_probe_cull_result,int p_reflection_probe_cull_count,const Transform& p_camera_inverse_transform,const CameraMatrix& p_camera_projection,RID p_reflection_atlas,Environment *p_env) { + + state.reflection_probe_count=0; + + for(int i=0;i<p_reflection_probe_cull_count;i++) { + + ReflectionProbeInstance *rpi=reflection_probe_instance_owner.getornull(p_reflection_probe_cull_result[i]); + ERR_CONTINUE(!rpi); + + ReflectionAtlas *reflection_atlas=reflection_atlas_owner.getornull(p_reflection_atlas); + ERR_CONTINUE(!reflection_atlas); + + ERR_CONTINUE(rpi->reflection_atlas_index<0); + + + if (state.reflection_probe_count>=state.max_ubo_reflections) + break; + + rpi->last_pass=render_pass; + + + ReflectionProbeDataUBO reflection_ubo; + + reflection_ubo.box_extents[0]=rpi->probe_ptr->extents.x; + reflection_ubo.box_extents[1]=rpi->probe_ptr->extents.y; + reflection_ubo.box_extents[2]=rpi->probe_ptr->extents.z; + reflection_ubo.box_extents[3]=0; + + + + reflection_ubo.box_ofs[0]=rpi->probe_ptr->origin_offset.x; + reflection_ubo.box_ofs[1]=rpi->probe_ptr->origin_offset.y; + reflection_ubo.box_ofs[2]=rpi->probe_ptr->origin_offset.z; + reflection_ubo.box_ofs[3]=0; + + reflection_ubo.params[0]=rpi->probe_ptr->intensity; + reflection_ubo.params[1]=0; + reflection_ubo.params[2]=rpi->probe_ptr->interior?1.0:0.0; + reflection_ubo.params[3]=rpi->probe_ptr->box_projection?1.0:0.0; + + if (rpi->probe_ptr->interior) { + Color ambient_linear = rpi->probe_ptr->interior_ambient.to_linear(); + reflection_ubo.ambient[0]=ambient_linear.r*rpi->probe_ptr->interior_ambient_energy; + reflection_ubo.ambient[1]=ambient_linear.g*rpi->probe_ptr->interior_ambient_energy; + reflection_ubo.ambient[2]=ambient_linear.b*rpi->probe_ptr->interior_ambient_energy; + reflection_ubo.ambient[3]=rpi->probe_ptr->interior_ambient_probe_contrib; + } else { + Color ambient_linear; + float contrib=0; + if (p_env) { + ambient_linear=p_env->ambient_color.to_linear(); + ambient_linear.r*=p_env->ambient_energy; + ambient_linear.g*=p_env->ambient_energy; + ambient_linear.b*=p_env->ambient_energy; + contrib=p_env->ambient_skybox_contribution; + } + + reflection_ubo.ambient[0]=ambient_linear.r; + reflection_ubo.ambient[1]=ambient_linear.g; + reflection_ubo.ambient[2]=ambient_linear.b; + reflection_ubo.ambient[3]=0; + } + + int cell_size = reflection_atlas->size / reflection_atlas->subdiv; + int x = (rpi->reflection_atlas_index % reflection_atlas->subdiv) * cell_size; + int y = (rpi->reflection_atlas_index / reflection_atlas->subdiv) * cell_size; + int width=cell_size; + int height=cell_size; + + reflection_ubo.atlas_clamp[0]=float(x)/reflection_atlas->size; + reflection_ubo.atlas_clamp[1]=float(y)/reflection_atlas->size; + reflection_ubo.atlas_clamp[2]=float(width)/reflection_atlas->size; + reflection_ubo.atlas_clamp[3]=float(height/2)/reflection_atlas->size; + + Transform proj = (p_camera_inverse_transform * rpi->transform).inverse(); + store_transform(proj,reflection_ubo.local_matrix); + + rpi->reflection_index=state.reflection_probe_count; + copymem(&state.reflection_array_tmp[rpi->reflection_index*sizeof(ReflectionProbeDataUBO)],&reflection_ubo,sizeof(ReflectionProbeDataUBO)); + state.reflection_probe_count++; + + } + + + if (state.reflection_probe_count) { + + + glBindBuffer(GL_UNIFORM_BUFFER, state.reflection_array_ubo); + glBufferSubData(GL_UNIFORM_BUFFER, 0, state.reflection_probe_count*sizeof(ReflectionProbeDataUBO), state.reflection_array_tmp); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + + glBindBufferBase(GL_UNIFORM_BUFFER,6,state.reflection_array_ubo); + } + +} + + void RasterizerSceneGLES3::_copy_screen() { glBindVertexArray(storage->resources.quadie_array); @@ -1959,7 +2405,7 @@ void RasterizerSceneGLES3::_fill_render_list(InstanceBase** p_cull_result,int p_ } -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){ +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_reflection_probe_cull_result,int p_reflection_probe_cull_count,RID p_environment,RID p_shadow_atlas,RID p_reflection_atlas,RID p_reflection_probe,int p_reflection_probe_pass){ //first of all, make a new render pass render_pass++; @@ -1969,6 +2415,7 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C Environment *env = environment_owner.getornull(p_environment); ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); + ReflectionAtlas *reflection_atlas = reflection_atlas_owner.getornull(p_reflection_atlas); if (shadow_atlas && shadow_atlas->size) { glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-3); @@ -1979,9 +2426,21 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C state.ubo_data.shadow_atlas_pixel_size[1]=1.0/shadow_atlas->size; } + + if (reflection_atlas && reflection_atlas->size) { + glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-5); + glBindTexture(GL_TEXTURE_2D,reflection_atlas->color); + } + + if (p_reflection_probe.is_valid()) { + state.ubo_data.reflection_multiplier=0.0; + } else { + state.ubo_data.reflection_multiplier=1.0; + } _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); + _setup_reflections(p_reflection_probe_cull_result,p_reflection_probe_cull_count,p_cam_transform.affine_inverse(),p_cam_projection,p_reflection_atlas,env); render_list.clear(); @@ -1998,24 +2457,55 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C glEnable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); - RasterizerStorageGLES3::Texture* env_radiance_tex=NULL; - glViewport(0,0,storage->frame.current_rt->width,storage->frame.current_rt->height); + ReflectionProbeInstance *probe = reflection_probe_instance_owner.getornull(p_reflection_probe); + GLuint current_fbo; - if (use_mrt) { + if (probe) { - glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->buffers.fbo); - state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS,true); + ReflectionAtlas *ref_atlas = reflection_atlas_owner.getptr(probe->atlas); + ERR_FAIL_COND(!ref_atlas); - Color black(0,0,0,0); - glClearBufferfv(GL_COLOR,1,black.components); // specular - glClearBufferfv(GL_COLOR,2,black.components); // normal metal rough + int target_size=ref_atlas->size/ref_atlas->subdiv; - } else { + int cubemap_index=reflection_cubemaps.size()-1; - glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->buffers.alpha_fbo); + for(int i=reflection_cubemaps.size()-1;i>=0;i--) { + //find appropriate cubemap to render to + if (reflection_cubemaps[i].size>target_size*2) + break; + + cubemap_index=i; + } + + current_fbo=reflection_cubemaps[cubemap_index].fbo_id[p_reflection_probe_pass]; + use_mrt=false; state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS,false); + glViewport(0,0,reflection_cubemaps[cubemap_index].size,reflection_cubemaps[cubemap_index].size); + glBindFramebuffer(GL_FRAMEBUFFER,current_fbo); + } else { + + glViewport(0,0,storage->frame.current_rt->width,storage->frame.current_rt->height); + + if (use_mrt) { + + current_fbo=storage->frame.current_rt->buffers.fbo; + + glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->buffers.fbo); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS,true); + + Color black(0,0,0,0); + glClearBufferfv(GL_COLOR,1,black.components); // specular + glClearBufferfv(GL_COLOR,2,black.components); // normal metal rough + + } else { + + current_fbo = storage->frame.current_rt->buffers.alpha_fbo; + glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->buffers.alpha_fbo); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_MULTIPLE_RENDER_TARGETS,false); + + } } @@ -2024,6 +2514,9 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C Color clear_color(0,0,0,0); + RasterizerStorageGLES3::SkyBox *skybox=NULL; + GLuint env_radiance_tex=0; + if (!env || env->bg_mode==VS::ENV_BG_CLEAR_COLOR) { if (storage->frame.clear_request) { @@ -2039,8 +2532,10 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C storage->frame.clear_request=false; } else if (env->bg_mode==VS::ENV_BG_SKYBOX) { - if (env->skybox_radiance.is_valid()) { - env_radiance_tex = storage->texture_owner.getornull(env->skybox_radiance); + skybox = storage->skybox_owner.getornull(env->skybox); + + if (skybox) { + env_radiance_tex=skybox->radiance; } storage->frame.clear_request=false; @@ -2055,7 +2550,7 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } else { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -2065,23 +2560,25 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C render_list.sort_by_key(false); - if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } else { glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } + + if (state.directional_light_count==0) { directional_light=NULL; - _render_list(render_list.elements,render_list.element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,false,false,false); + _render_list(render_list.elements,render_list.element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,false,false,false,shadow_atlas!=NULL); } else { for(int i=0;i<state.directional_light_count;i++) { directional_light=directional_lights[i]; if (i>0) { glEnable(GL_BLEND); } - _setup_directional_light(i,p_cam_transform.affine_inverse()); - _render_list(render_list.elements,render_list.element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,false,false,i>0); + _setup_directional_light(i,p_cam_transform.affine_inverse(),shadow_atlas!=NULL); + _render_list(render_list.elements,render_list.element_count,p_cam_transform,p_cam_projection,env_radiance_tex,false,false,false,i>0,shadow_atlas!=NULL); } } @@ -2095,7 +2592,7 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->buffers.alpha_fbo); //switch to alpha fbo for skybox, only diffuse/ambient matters } - _draw_skybox(env->skybox_color,p_cam_projection,p_cam_transform,storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP],env->skybox_scale); + _draw_skybox(skybox,p_cam_projection,p_cam_transform,storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP],env->skybox_scale); } @@ -2112,24 +2609,30 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C glDepthMask(GL_TRUE); glEnable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); - glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->buffers.alpha_fbo); - - render_list.sort_by_depth(true); + if (use_mrt) { + glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->buffers.alpha_fbo); + } + render_list.sort_by_depth(true); if (state.directional_light_count==0) { directional_light=NULL; - _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,false); + _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,false,shadow_atlas!=NULL); } else { for(int i=0;i<state.directional_light_count;i++) { directional_light=directional_lights[i]; - _setup_directional_light(i,p_cam_transform.affine_inverse()); - _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,i>0); + _setup_directional_light(i,p_cam_transform.affine_inverse(),shadow_atlas!=NULL); + _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,i>0,shadow_atlas!=NULL); } } + if (probe) { + //rendering a probe, do no more! + return; + } + _copy_to_front_buffer(env); /* if (shadow_atlas) { @@ -2143,6 +2646,17 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C } */ + + if (false && reflection_atlas && storage->frame.current_rt) { + + //_copy_texture_to_front_buffer(shadow_atlas->depth); + storage->canvas->canvas_begin(); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D,reflection_atlas->color); + 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 (false && directional_shadow.fbo) { //_copy_texture_to_front_buffer(shadow_atlas->depth); @@ -2154,6 +2668,16 @@ void RasterizerSceneGLES3::render_scene(const Transform& p_cam_transform,const C } + if (false && env_radiance_tex) { + + //_copy_texture_to_front_buffer(shadow_atlas->depth); + storage->canvas->canvas_begin(); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D,env_radiance_tex); + 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) { @@ -2534,7 +3058,7 @@ void RasterizerSceneGLES3::render_shadow(RID p_light,RID p_shadow_atlas,int p_pa 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,false); + _render_list(render_list.elements,render_list.element_count,light_transform,light_projection,NULL,!flip_facing,false,true,false,false); state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_SHADOW,false); state.scene_shader.set_conditional(SceneShaderGLES3::RENDER_SHADOW_DUAL_PARABOLOID,false); @@ -2624,6 +3148,19 @@ bool RasterizerSceneGLES3::free(RID p_rid) { shadow_atlas_set_size(p_rid,0); shadow_atlas_owner.free(p_rid); memdelete(shadow_atlas); + } else if (reflection_atlas_owner.owns(p_rid)) { + + ReflectionAtlas *reflection_atlas = reflection_atlas_owner.get(p_rid); + reflection_atlas_set_size(p_rid,0); + reflection_atlas_owner.free(p_rid); + memdelete(reflection_atlas); + } else if (reflection_probe_instance_owner.owns(p_rid)) { + + ReflectionProbeInstance *reflection_instance = reflection_probe_instance_owner.get(p_rid); + + reflection_probe_release_atlas_index(p_rid); + reflection_probe_instance_owner.free(p_rid); + memdelete(reflection_instance); } else { return false; @@ -2890,6 +3427,7 @@ void RasterizerSceneGLES3::initialize() { const int ubo_light_size=160; state.ubo_light_size=ubo_light_size; state.max_ubo_lights=max_ubo_size/ubo_light_size; + print_line("max ubo light: "+itos(state.max_ubo_lights)); state.spot_array_tmp = (uint8_t*)memalloc(ubo_light_size*state.max_ubo_lights); state.omni_array_tmp = (uint8_t*)memalloc(ubo_light_size*state.max_ubo_lights); @@ -2912,10 +3450,21 @@ void RasterizerSceneGLES3::initialize() { state.max_forward_lights_per_object=8; + state.scene_shader.add_custom_define("#define MAX_LIGHT_DATA_STRUCTS "+itos(state.max_ubo_lights)+"\n"); state.scene_shader.add_custom_define("#define MAX_FORWARD_LIGHTS "+itos(state.max_forward_lights_per_object)+"\n"); + state.max_ubo_reflections=max_ubo_size/sizeof(ReflectionProbeDataUBO); + print_line("max ubo reflections: "+itos(state.max_ubo_reflections)+" ubo size: "+itos(sizeof(ReflectionProbeDataUBO))); + state.reflection_array_tmp = (uint8_t*)memalloc(sizeof(ReflectionProbeDataUBO)*state.max_ubo_reflections); + + glGenBuffers(1, &state.reflection_array_ubo); + glBindBuffer(GL_UNIFORM_BUFFER, state.reflection_array_ubo); + glBufferData(GL_UNIFORM_BUFFER, sizeof(ReflectionProbeDataUBO)*state.max_ubo_reflections, NULL, GL_DYNAMIC_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + + state.scene_shader.add_custom_define("#define MAX_REFLECTION_DATA_STRUCTS "+itos(state.max_ubo_reflections)+"\n"); } @@ -2923,6 +3472,73 @@ void RasterizerSceneGLES3::initialize() { Globals::get_singleton()->set_custom_property_info("rendering/gles3/shadow_filter_mode",PropertyInfo(Variant::INT,"rendering/gles3/shadow_filter_mode",PROPERTY_HINT_ENUM,"Disabled,PCF5,PCF13")); shadow_filter_mode=SHADOW_FILTER_NEAREST; + { //reflection cubemaps + int max_reflection_cubemap_sampler_size=512; + + int cube_size = max_reflection_cubemap_sampler_size; + + glActiveTexture(GL_TEXTURE0); + + bool use_float=true; + + GLenum internal_format = use_float?GL_RGBA16F:GL_RGB10_A2; + GLenum format = GL_RGBA; + GLenum type = use_float?GL_HALF_FLOAT:GL_UNSIGNED_INT_2_10_10_10_REV; + + while(cube_size>=32) { + + ReflectionCubeMap cube; + cube.size=cube_size; + + glGenTextures(1,&cube.depth); + glBindTexture(GL_TEXTURE_2D,cube.depth); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, cube.size, cube.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); + + + 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, internal_format, cube.size, cube.size, 0, format, type, 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 reflectionmap + 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_COLOR_ATTACHMENT0,_cube_side_enum[i], cube.cubemap, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,GL_TEXTURE_2D, cube.depth, 0); + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + ERR_CONTINUE(status!=GL_FRAMEBUFFER_COMPLETE); + } + + reflection_cubemaps.push_back(cube); + + cube_size>>=1; + } + } + + +#ifdef GLEW_ENABLED +//"desktop" opengl needs this. + glEnable(GL_POINT_SPRITE); + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + +#endif } void RasterizerSceneGLES3::iteration() { diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 24b6a36fcc..81c13bdc08 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -62,6 +62,7 @@ public: float shadow_dual_paraboloid_render_side; float shadow_atlas_pixel_size[2]; float shadow_directional_pixel_size[2]; + float reflection_multiplier; } ubo_data; @@ -87,17 +88,23 @@ public: GLuint spot_array_ubo; GLuint omni_array_ubo; + GLuint reflection_array_ubo; uint32_t ubo_light_size; uint8_t *spot_array_tmp; uint8_t *omni_array_tmp; + uint8_t *reflection_array_tmp; int max_ubo_lights; int max_forward_lights_per_object; + int max_ubo_reflections; + + int spot_light_count; int omni_light_count; int directional_light_count; + int reflection_probe_count; bool cull_front; @@ -176,6 +183,87 @@ public: virtual int get_directional_light_shadow_size(RID p_light_intance); virtual void set_directional_shadow_count(int p_count); + /* REFLECTION PROBE ATLAS API */ + + struct ReflectionAtlas : public RID_Data { + + int subdiv; + int size; + + struct Reflection { + RID owner; + uint64_t last_frame; + }; + + GLuint fbo[6]; + GLuint color; + + Vector<Reflection> reflections; + }; + + mutable RID_Owner<ReflectionAtlas> reflection_atlas_owner; + + virtual RID reflection_atlas_create(); + virtual void reflection_atlas_set_size(RID p_ref_atlas,int p_size); + virtual void reflection_atlas_set_subdivision(RID p_ref_atlas,int p_subdiv); + + /* REFLECTION CUBEMAPS */ + + struct ReflectionCubeMap { + + GLuint fbo_id[6]; + GLuint cubemap; + GLuint depth; + int size; + }; + + Vector<ReflectionCubeMap> reflection_cubemaps; + + /* REFLECTION PROBE INSTANCE */ + + struct ReflectionProbeInstance : public RID_Data { + + RasterizerStorageGLES3::ReflectionProbe *probe_ptr; + RID probe; + RID self; + RID atlas; + + int reflection_atlas_index; + + int render_step; + + + + uint64_t last_pass; + int reflection_index; + + Transform transform; + }; + + struct ReflectionProbeDataUBO { + + float box_extents[4]; + float box_ofs[4]; + float params[4]; // intensity, 0, 0, boxproject + float ambient[4]; //color, probe contrib + float atlas_clamp[4]; + float local_matrix[16]; //up to here for spot and omni, rest is for directional + //notes: for ambientblend, use distance to edge to blend between already existing global environment + }; + + + mutable RID_Owner<ReflectionProbeInstance> reflection_probe_instance_owner; + + virtual RID reflection_probe_instance_create(RID p_probe); + virtual void reflection_probe_instance_set_transform(RID p_instance,const Transform& p_transform); + virtual void reflection_probe_release_atlas_index(RID p_instance); + virtual bool reflection_probe_instance_needs_redraw(RID p_instance); + virtual bool reflection_probe_instance_has_reflection(RID p_instance); + virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas); + virtual bool reflection_probe_instance_postprocess_step(RID p_instance); + + + /* ENVIRONMENT API */ @@ -183,8 +271,7 @@ public: VS::EnvironmentBG bg_mode; - RID skybox_color; - RID skybox_radiance; + RID skybox; float skybox_scale; Color bg_color; @@ -214,7 +301,7 @@ public: virtual RID environment_create(); virtual void environment_set_background(RID p_env,VS::EnvironmentBG p_bg); - virtual void environment_set_skybox(RID p_env,RID p_skybox,int p_radiance_size); + virtual void environment_set_skybox(RID p_env,RID p_skybox); virtual void environment_set_skybox_scale(RID p_env,float p_scale); virtual void environment_set_bg_color(RID p_env,const Color& p_color); virtual void environment_set_bg_energy(RID p_env,float p_energy); @@ -441,23 +528,25 @@ public: _FORCE_INLINE_ void _render_geometry(RenderList::Element *e); _FORCE_INLINE_ void _setup_light(RenderList::Element *e); - 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, bool p_directional_add); + void _render_list(RenderList::Element **p_elements, int p_element_count, const Transform& p_view_transform, const CameraMatrix& p_projection, GLuint p_base_env, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow, bool p_directional_add, bool p_directional_shadows); _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, const CameraMatrix& p_projection, const Transform& p_transform, bool p_vflip, float p_scale); + void _draw_skybox(RasterizerStorageGLES3::SkyBox *p_skybox, const CameraMatrix& p_projection, const Transform& p_transform, bool p_vflip, float p_scale); void _setup_environment(Environment *env, const CameraMatrix &p_cam_projection, const Transform& p_cam_transform); - void _setup_directional_light(int p_index, const Transform &p_camera_inverse_transform); + void _setup_directional_light(int p_index, const Transform &p_camera_inverse_transformm, bool p_use_shadows); 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 _setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform& p_camera_inverse_transform, const CameraMatrix& p_camera_projection, RID p_reflection_atlas, Environment *p_env); + void _copy_screen(); void _copy_to_front_buffer(Environment *env); void _copy_texture_to_front_buffer(GLuint p_texture); //used for debug 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_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_reflection_probe_cull_result,int p_reflection_probe_cull_count,RID p_environment,RID p_shadow_atlas,RID p_reflection_atlas,RID p_reflection_probe,int p_reflection_probe_pass); 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); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 6e278e563b..8188fe3adb 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -1015,10 +1015,6 @@ RID RasterizerStorageGLES3::texture_create_radiance_cubemap(RID p_source,int p_r glDisable(GL_CULL_FACE); glDisable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); -#ifdef GLEW_ENABLED - glDisable(GL_POINT_SPRITE); - glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); -#endif glDisable(GL_BLEND); @@ -1086,6 +1082,8 @@ RID RasterizerStorageGLES3::texture_create_radiance_cubemap(RID p_source,int p_r size = p_resolution; + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID,false); + while(mm_level) { for(int i=0;i<6;i++) { @@ -1156,6 +1154,147 @@ RID RasterizerStorageGLES3::texture_create_radiance_cubemap(RID p_source,int p_r } +RID RasterizerStorageGLES3::skybox_create() { + + SkyBox *skybox = memnew( SkyBox ); + skybox->radiance=0; + return skybox_owner.make_rid(skybox); +} + +void RasterizerStorageGLES3::skybox_set_texture(RID p_skybox, RID p_cube_map, int p_radiance_size){ + + SkyBox *skybox = skybox_owner.getornull(p_skybox); + ERR_FAIL_COND(!skybox); + + if (skybox->cubemap.is_valid()) { + skybox->cubemap=RID(); + glDeleteTextures(1,&skybox->radiance); + skybox->radiance=0; + } + + skybox->cubemap=p_cube_map; + if (!skybox->cubemap.is_valid()) + return; //cleared + + Texture *texture = texture_owner.getornull(skybox->cubemap); + if (!texture || !(texture->flags&VS::TEXTURE_FLAG_CUBEMAP)) { + skybox->cubemap=RID(); + ERR_FAIL_COND(!texture || !(texture->flags&VS::TEXTURE_FLAG_CUBEMAP)); + } + + glBindVertexArray(0); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_BLEND); + + + glActiveTexture(GL_TEXTURE0); + glBindTexture(texture->target, texture->tex_id); + + if (config.srgb_decode_supported && texture->srgb && !texture->using_srgb) { + + glTexParameteri(texture->target,_TEXTURE_SRGB_DECODE_EXT,_DECODE_EXT); + texture->using_srgb=true; +#ifdef TOOLS_ENABLED + if (!(texture->flags&VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) { + texture->flags|=VS::TEXTURE_FLAG_CONVERT_TO_LINEAR; + //notify that texture must be set to linear beforehand, so it works in other platforms when exported + } +#endif + } + + + glActiveTexture(GL_TEXTURE1); + glGenTextures(1, &skybox->radiance); + glBindTexture(GL_TEXTURE_2D, skybox->radiance); + + GLuint tmp_fb; + + glGenFramebuffers(1, &tmp_fb); + glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb); + + + int size = p_radiance_size; + + int lod=0; + + + int mipmaps=6; + + int mm_level=mipmaps; + + bool use_float=true; + + GLenum internal_format = use_float?GL_RGBA16F:GL_RGB10_A2; + GLenum format = GL_RGBA; + GLenum type = use_float?GL_HALF_FLOAT:GL_UNSIGNED_INT_2_10_10_10_REV; + + while(mm_level) { + + glTexImage2D(GL_TEXTURE_2D, lod, internal_format, size, size*2, 0, format, type, NULL); + lod++; + mm_level--; + + if (size>1) + size>>=1; + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, lod-1); + + lod=0; + mm_level=mipmaps; + + size = p_radiance_size; + + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID,true); + shaders.cubemap_filter.bind(); + + while(mm_level) { + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, skybox->radiance, lod); +#ifdef DEBUG_ENABLED + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + ERR_CONTINUE(status!=GL_FRAMEBUFFER_COMPLETE); +#endif + + for(int i=0;i<2;i++) { + glViewport(0,i*size,size,size); + glBindVertexArray(resources.quadie_array); + + shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::Z_FLIP,i>0); + shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::ROUGHNESS,lod/float(mipmaps-1)); + + + glDrawArrays(GL_TRIANGLE_FAN,0,4); + glBindVertexArray(0); + } + + if (size>1) + size>>=1; + lod++; + mm_level--; + + } + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DUAL_PARABOLOID,false); + + + //restore ranges + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, lod-1); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glBindFramebuffer(GL_FRAMEBUFFER, config.system_fbo); + glDeleteFramebuffers(1, &tmp_fb); + +} + + /* SHADER API */ @@ -2144,7 +2283,7 @@ void RasterizerStorageGLES3::_update_material(Material* material) { Map<StringName,Variant>::Element *V = material->params.find(E->key()); if (V) { - //user provided + //user provided _fill_std140_variant_ubo_value(E->get().type,V->get(),data,material->shader->mode==VS::SHADER_SPATIAL); } else if (E->get().default_value.size()){ //default value @@ -3405,46 +3544,197 @@ AABB RasterizerStorageGLES3::light_get_aabb(RID p_light) const { RID RasterizerStorageGLES3::reflection_probe_create(){ - return RID(); + ReflectionProbe *reflection_probe = memnew( ReflectionProbe ); + + reflection_probe->intensity=1.0; + reflection_probe->interior_ambient=Color(); + reflection_probe->interior_ambient_energy=1.0; + reflection_probe->max_distance=0; + reflection_probe->extents=Vector3(1,1,1); + reflection_probe->origin_offset=Vector3(0,0,0); + reflection_probe->interior=false; + reflection_probe->box_projection=false; + reflection_probe->enable_shadows=false; + reflection_probe->cull_mask=(1<<20)-1; + reflection_probe->update_mode=VS::REFLECTION_PROBE_UPDATE_ONCE; + + return reflection_probe_owner.make_rid(reflection_probe); } -void RasterizerStorageGLES3::reflection_probe_set_intensity(RID p_probe, float p_intensity){ +void RasterizerStorageGLES3::reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode) { + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->update_mode=p_mode; + reflection_probe->instance_change_notify(); } -void RasterizerStorageGLES3::reflection_probe_set_clip(RID p_probe, float p_near, float p_far){ +void RasterizerStorageGLES3::reflection_probe_set_intensity(RID p_probe, float p_intensity) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->intensity=p_intensity; + +} + +void RasterizerStorageGLES3::reflection_probe_set_interior_ambient(RID p_probe, const Color& p_ambient) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->interior_ambient=p_ambient; + +} + +void RasterizerStorageGLES3::reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->interior_ambient_energy=p_energy; } -void RasterizerStorageGLES3::reflection_probe_set_min_blend_distance(RID p_probe, float p_distance){ +void RasterizerStorageGLES3::reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->interior_ambient_probe_contrib=p_contrib; + +} + + +void RasterizerStorageGLES3::reflection_probe_set_max_distance(RID p_probe, float p_distance){ + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->max_distance=p_distance; + reflection_probe->instance_change_notify(); } void RasterizerStorageGLES3::reflection_probe_set_extents(RID p_probe, const Vector3& p_extents){ + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->extents=p_extents; + reflection_probe->instance_change_notify(); } void RasterizerStorageGLES3::reflection_probe_set_origin_offset(RID p_probe, const Vector3& p_offset){ + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->origin_offset=p_offset; + reflection_probe->instance_change_notify(); } -void RasterizerStorageGLES3::reflection_probe_set_enable_parallax_correction(RID p_probe, bool p_enable){ +void RasterizerStorageGLES3::reflection_probe_set_as_interior(RID p_probe, bool p_enable){ + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->interior=p_enable; } -void RasterizerStorageGLES3::reflection_probe_set_resolution(RID p_probe, int p_resolution){ +void RasterizerStorageGLES3::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable){ + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + reflection_probe->box_projection=p_enable; } -void RasterizerStorageGLES3::reflection_probe_set_hide_skybox(RID p_probe, bool p_hide){ +void RasterizerStorageGLES3::reflection_probe_set_enable_shadows(RID p_probe, bool p_enable){ + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->enable_shadows=p_enable; + reflection_probe->instance_change_notify(); } void RasterizerStorageGLES3::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers){ + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->cull_mask=p_layers; + reflection_probe->instance_change_notify(); } +AABB RasterizerStorageGLES3::reflection_probe_get_aabb(RID p_probe) const { + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe,AABB()); + + AABB aabb; + aabb.pos=-reflection_probe->extents; + aabb.size=reflection_probe->extents*2.0; + + return aabb; + + +} +VS::ReflectionProbeUpdateMode RasterizerStorageGLES3::reflection_probe_get_update_mode(RID p_probe) const{ + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe,VS::REFLECTION_PROBE_UPDATE_ALWAYS); + + return reflection_probe->update_mode; +} + +uint32_t RasterizerStorageGLES3::reflection_probe_get_cull_mask(RID p_probe) const { + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe,0); + + return reflection_probe->cull_mask; + +} + +Vector3 RasterizerStorageGLES3::reflection_probe_get_extents(RID p_probe) const { + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe,Vector3()); + + return reflection_probe->extents; + +} +Vector3 RasterizerStorageGLES3::reflection_probe_get_origin_offset(RID p_probe) const{ + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe,Vector3()); + + return reflection_probe->origin_offset; + +} + +bool RasterizerStorageGLES3::reflection_probe_renders_shadows(RID p_probe) const { + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe,false); + + return reflection_probe->enable_shadows; + +} + +float RasterizerStorageGLES3::reflection_probe_get_origin_max_distance(RID p_probe) const{ + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe,0); + + return reflection_probe->max_distance; + +} /* ROOM API */ @@ -3495,6 +3785,10 @@ void RasterizerStorageGLES3::instance_add_dependency(RID p_base,RasterizerScene: inst = mesh_owner.getornull(p_base); ERR_FAIL_COND(!inst); } break; + case VS::INSTANCE_REFLECTION_PROBE: { + inst = reflection_probe_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; case VS::INSTANCE_LIGHT: { inst = light_owner.getornull(p_base); ERR_FAIL_COND(!inst); @@ -3517,6 +3811,10 @@ void RasterizerStorageGLES3::instance_remove_dependency(RID p_base,RasterizerSce ERR_FAIL_COND(!inst); } break; + case VS::INSTANCE_REFLECTION_PROBE: { + inst = reflection_probe_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; case VS::INSTANCE_LIGHT: { inst = light_owner.getornull(p_base); ERR_FAIL_COND(!inst); @@ -4005,6 +4303,9 @@ VS::InstanceType RasterizerStorageGLES3::get_base_type(RID p_rid) const { if (light_owner.owns(p_rid)) { return VS::INSTANCE_LIGHT; } + if (reflection_probe_owner.owns(p_rid)) { + return VS::INSTANCE_REFLECTION_PROBE; + } return VS::INSTANCE_NONE; } @@ -4028,6 +4329,12 @@ bool RasterizerStorageGLES3::free(RID p_rid){ info.texture_mem-=texture->total_data_size; texture_owner.free(p_rid); memdelete(texture); + } else if (skybox_owner.owns(p_rid)) { + // delete the skybox + SkyBox *skybox = skybox_owner.get(p_rid); + skybox_set_texture(p_rid,RID(),256); + skybox_owner.free(p_rid); + memdelete(skybox); } else if (shader_owner.owns(p_rid)) { @@ -4259,6 +4566,8 @@ void RasterizerStorageGLES3::initialize() { shaders.cubemap_filter.init(); glEnable(_EXT_TEXTURE_CUBE_MAP_SEAMLESS); + + frame.count=0; } void RasterizerStorageGLES3::finalize() { diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index 0e3d47b61f..5f07efeb0a 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -226,6 +226,19 @@ public: virtual RID texture_create_radiance_cubemap(RID p_source,int p_resolution=-1) const; + /* SKYBOX API */ + + struct SkyBox : public RID_Data { + + RID cubemap; + GLuint radiance; + int radiance_size; + }; + + mutable RID_Owner<SkyBox> skybox_owner; + + virtual RID skybox_create(); + virtual void skybox_set_texture(RID p_skybox,RID p_cube_map,int p_radiance_size); /* SHADER API */ @@ -679,18 +692,51 @@ public: /* PROBE API */ + struct ReflectionProbe : Instantiable { + + VS::ReflectionProbeUpdateMode update_mode; + float intensity; + Color interior_ambient; + float interior_ambient_energy; + float interior_ambient_probe_contrib; + float max_distance; + Vector3 extents; + Vector3 origin_offset; + bool interior; + bool box_projection; + bool enable_shadows; + uint32_t cull_mask; + + }; + + mutable RID_Owner<ReflectionProbe> reflection_probe_owner; + virtual RID reflection_probe_create(); + virtual void reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode); virtual void reflection_probe_set_intensity(RID p_probe, float p_intensity); - virtual void reflection_probe_set_clip(RID p_probe, float p_near, float p_far); - virtual void reflection_probe_set_min_blend_distance(RID p_probe, float p_distance); + virtual void reflection_probe_set_interior_ambient(RID p_probe, const Color& p_ambient); + virtual void reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy); + virtual void reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib); + virtual void reflection_probe_set_max_distance(RID p_probe, float p_distance); virtual void reflection_probe_set_extents(RID p_probe, const Vector3& p_extents); virtual void reflection_probe_set_origin_offset(RID p_probe, const Vector3& p_offset); - virtual void reflection_probe_set_enable_parallax_correction(RID p_probe, bool p_enable); - virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution); - virtual void reflection_probe_set_hide_skybox(RID p_probe, bool p_hide); + virtual void reflection_probe_set_as_interior(RID p_probe, bool p_enable); + virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable); + virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable); virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers); + virtual AABB reflection_probe_get_aabb(RID p_probe) const; + virtual VS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const; + virtual uint32_t reflection_probe_get_cull_mask(RID p_probe) const; + + virtual Vector3 reflection_probe_get_extents(RID p_probe) const; + virtual Vector3 reflection_probe_get_origin_offset(RID p_probe) const; + virtual float reflection_probe_get_origin_max_distance(RID p_probe) const; + virtual bool reflection_probe_renders_shadows(RID p_probe) const; + + + /* ROOM API */ @@ -813,6 +859,7 @@ public: Color clear_request_color; int canvas_draw_commands; float time[4]; + uint64_t count; } frame; void initialize(); diff --git a/drivers/gles3/shaders/cubemap_filter.glsl b/drivers/gles3/shaders/cubemap_filter.glsl index 998a59833e..768d20ad22 100644 --- a/drivers/gles3/shaders/cubemap_filter.glsl +++ b/drivers/gles3/shaders/cubemap_filter.glsl @@ -151,14 +151,47 @@ vec2 Hammersley(uint i, uint N) { return vec2(float(i)/float(N), radicalInverse_VdC(i)); } -#define SAMPLE_COUNT 1024u + + +#ifdef LOW_QUALITY + +#define SAMPLE_COUNT 64u + +#else + +#define SAMPLE_COUNT 512u + +#endif + +uniform bool z_flip; void main() { +#ifdef USE_DUAL_PARABOLOID + + vec3 N = vec3( uv_interp * 2.0 - 1.0, 0.0 ); + N.z = 0.5 - 0.5*((N.x * N.x) + (N.y * N.y)); + N = normalize(N); + + if (!z_flip) { + N.y=-N.y; //y is flipped to improve blending between both sides + } else { + N.z=-N.z; + } + + +#else vec2 uv = (uv_interp * 2.0) - 1.0; vec3 N = texelCoordToVec(uv, face_id); - +#endif //vec4 color = color_interp; + +#ifdef USE_DIRECT_WRITE + + frag_color=vec4(texture(N,source_cube).rgb,1.0); + +#else + vec4 sum = vec4(0.0, 0.0, 0.0, 0.0); for(uint sampleNum = 0u; sampleNum < SAMPLE_COUNT; sampleNum++) { @@ -178,5 +211,8 @@ void main() { sum /= sum.a; frag_color = vec4(sum.rgb, 1.0); + +#endif + } diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index ceb5a72118..a923c130dc 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -64,6 +64,8 @@ layout(std140) uniform SceneData { //ubo:0 vec2 shadow_atlas_pixel_size; vec2 directional_shadow_pixel_size; + float reflection_multiplier; + }; uniform highp mat4 world_transform; @@ -288,11 +290,11 @@ in vec3 normal_interp; //used on forward mainly uniform bool no_ambient_light; +uniform sampler2D brdf_texture; //texunit:-1 -#ifdef USE_RADIANCE_CUBEMAP +#ifdef USE_RADIANCE_MAP -uniform sampler2D brdf_texture; //texunit:-1 -uniform samplerCube radiance_cube; //texunit:-2 +uniform sampler2D radiance_map; //texunit:-2 layout(std140) uniform Radiance { //ubo:2 @@ -343,6 +345,8 @@ layout(std140) uniform SceneData { vec2 shadow_atlas_pixel_size; vec2 directional_shadow_pixel_size; + float reflection_multiplier; + }; //directional light data @@ -398,6 +402,24 @@ layout(std140) uniform SpotLightData { //ubo:5 uniform highp sampler2DShadow shadow_atlas; //texunit:-3 +struct ReflectionData { + + mediump vec4 box_extents; + mediump vec4 box_offset; + mediump vec4 params; // intensity, 0, interior , boxproject + mediump vec4 ambient; //ambient color, energy + mediump vec4 atlas_clamp; + highp mat4 local_matrix; //up to here for spot and omni, rest is for directional + //notes: for ambientblend, use distance to edge to blend between already existing global environment +}; + +layout(std140) uniform ReflectionProbeData { //ubo:6 + + ReflectionData reflections[MAX_REFLECTION_DATA_STRUCTS]; +}; +uniform mediump sampler2D reflection_atlas; //texunit:-5 + + #ifdef USE_FORWARD_LIGHTING uniform int omni_light_indices[MAX_FORWARD_LIGHTS]; @@ -406,6 +428,9 @@ uniform int omni_light_count; uniform int spot_light_indices[MAX_FORWARD_LIGHTS]; uniform int spot_light_count; +uniform int reflection_indices[MAX_FORWARD_LIGHTS]; +uniform int reflection_count; + #endif @@ -578,6 +603,120 @@ void light_process_spot(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 al } +void reflection_process(int idx, vec3 vertex, vec3 normal,float roughness,vec3 ambient,vec3 skybox,vec2 brdf, inout highp vec4 reflection_accum,inout highp vec4 ambient_accum) { + + vec3 ref_vec = normalize(reflect(vertex,normal)); + vec3 local_pos = (reflections[idx].local_matrix * vec4(vertex,1.0)).xyz; + vec3 box_extents = reflections[idx].box_extents.xyz; + + if (any(greaterThan(abs(local_pos),box_extents))) { //out of the reflection box + return; + } + + vec3 inner_pos = abs(local_pos / box_extents); + float blend = max(inner_pos.x,max(inner_pos.y,inner_pos.z)); + //make blend more rounded + blend=mix(length(inner_pos),blend,blend); + blend*=blend; + blend=1.001-blend; + + if (reflections[idx].params.x>0.0){// compute reflection + + vec3 local_ref_vec = (reflections[idx].local_matrix * vec4(ref_vec,0.0)).xyz; + + if (reflections[idx].params.w > 0.5) { //box project + + vec3 nrdir = normalize(local_ref_vec); + vec3 rbmax = (box_extents - local_pos)/nrdir; + vec3 rbmin = (-box_extents - local_pos)/nrdir; + + + vec3 rbminmax = mix(rbmin,rbmax,greaterThan(nrdir,vec3(0.0,0.0,0.0))); + + float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z); + vec3 posonbox = local_pos + nrdir * fa; + local_ref_vec = posonbox - reflections[idx].box_offset.xyz; + } + + + + vec3 splane=normalize(local_ref_vec); + vec4 clamp_rect=reflections[idx].atlas_clamp; + + splane.z*=-1.0; + if (splane.z>=0.0) { + splane.z+=1.0; + clamp_rect.y+=clamp_rect.w; + } else { + splane.z=1.0 - splane.z; + splane.y=-splane.y; + } + + splane.xy/=splane.z; + splane.xy=splane.xy * 0.5 + 0.5; + + splane.xy = splane.xy * clamp_rect.zw + clamp_rect.xy; + splane.xy = clamp(splane.xy,clamp_rect.xy,clamp_rect.xy+clamp_rect.zw); + + highp vec4 reflection; + reflection.rgb = textureLod(reflection_atlas,splane.xy,roughness*5.0).rgb * ( brdf.x + brdf.y); + if (reflections[idx].params.z < 0.5) { + reflection.rgb = mix(skybox,reflection.rgb,blend); + } + reflection.rgb*=reflections[idx].params.x; + reflection.a = blend; + reflection.rgb*=reflection.a; + + reflection_accum+=reflection; + } + + if (reflections[idx].ambient.a>0.0) { //compute ambient using skybox + + + vec3 local_amb_vec = (reflections[idx].local_matrix * vec4(normal,0.0)).xyz; + + vec3 splane=normalize(local_amb_vec); + vec4 clamp_rect=reflections[idx].atlas_clamp; + + splane.z*=-1.0; + if (splane.z>=0.0) { + splane.z+=1.0; + clamp_rect.y+=clamp_rect.w; + } else { + splane.z=1.0 - splane.z; + splane.y=-splane.y; + } + + splane.xy/=splane.z; + splane.xy=splane.xy * 0.5 + 0.5; + + splane.xy = splane.xy * clamp_rect.zw + clamp_rect.xy; + splane.xy = clamp(splane.xy,clamp_rect.xy,clamp_rect.xy+clamp_rect.zw); + + highp vec4 ambient_out; + ambient_out.a=blend; + ambient_out.rgb = textureLod(reflection_atlas,splane.xy,5.0).rgb; + ambient_out.rgb=mix(reflections[idx].ambient.rgb,ambient_out.rgb,reflections[idx].ambient.a); + if (reflections[idx].params.z < 0.5) { + ambient_out.rgb = mix(ambient,ambient_out.rgb,blend); + } + + ambient_out.rgb *= ambient_out.a; + ambient_accum+=ambient_out; + } else { + + highp vec4 ambient_out; + ambient_out.a=blend; + ambient_out.rgb=reflections[idx].ambient.rgb; + if (reflections[idx].params.z < 0.5) { + ambient_out.rgb = mix(ambient,ambient_out.rgb,blend); + } + ambient_out.rgb *= ambient_out.a; + ambient_accum+=ambient_out; + + } +} + void main() { #ifdef RENDER_SHADOW_DUAL_PARABOLOID @@ -666,31 +805,56 @@ FRAGMENT_SHADER_CODE vec3 eye_vec = -normalize( vertex_interp ); -#ifdef USE_RADIANCE_CUBEMAP +#ifndef RENDER_SHADOW + float ndotv = clamp(dot(normal,eye_vec),0.0,1.0); + vec2 brdf = texture(brdf_texture, vec2(roughness, ndotv)).xy; +#endif + +#ifdef USE_RADIANCE_MAP if (no_ambient_light) { ambient_light=vec3(0.0,0.0,0.0); } else { { - float ndotv = clamp(dot(normal,eye_vec),0.0,1.0); - vec2 brdf = texture(brdf_texture, vec2(roughness, ndotv)).xy; + float lod = roughness * 5.0; - vec3 r = reflect(-eye_vec,normal); //2.0 * ndotv * normal - view; // reflect(v, n); - r=normalize((radiance_inverse_xform * vec4(r,0.0)).xyz); - vec3 radiance = textureLod(radiance_cube, r, lod).xyz * ( brdf.x + brdf.y); - specular_light=mix(albedo,radiance,specular); + { //read radiance from dual paraboloid + + vec3 ref_vec = reflect(-eye_vec,normal); //2.0 * ndotv * normal - view; // reflect(v, n); + ref_vec=normalize((radiance_inverse_xform * vec4(ref_vec,0.0)).xyz); + + vec3 norm = normalize(ref_vec); + float y_ofs=0.0; + if (norm.z>=0.0) { + + norm.z+=1.0; + y_ofs+=0.5; + } else { + norm.z=1.0 - norm.z; + norm.y=-norm.y; + } + + norm.xy/=norm.z; + norm.xy=norm.xy * vec2(0.5,0.25) + vec2(0.5,0.25+y_ofs); + vec3 radiance = textureLod(radiance_map, norm.xy, lod).xyz * ( brdf.x + brdf.y); + specular_light=mix(albedo,radiance,specular); + + } + //no longer a cubemap + //vec3 radiance = textureLod(radiance_cube, r, lod).xyz * ( brdf.x + brdf.y); } { - vec3 ambient_dir=normalize((radiance_inverse_xform * vec4(normal,0.0)).xyz); + /*vec3 ambient_dir=normalize((radiance_inverse_xform * vec4(normal,0.0)).xyz); vec3 env_ambient=textureLod(radiance_cube, ambient_dir, 5.0).xyz; - ambient_light=mix(ambient_light_color.rgb,env_ambient,radiance_ambient_contribution); + ambient_light=mix(ambient_light_color.rgb,env_ambient,radiance_ambient_contribution);*/ + ambient_light=vec3(0.0,0.0,0.0); } } @@ -840,6 +1004,21 @@ FRAGMENT_SHADER_CODE #ifdef USE_FORWARD_LIGHTING + highp vec4 reflection_accum = vec4(0.0,0.0,0.0,0.0); + highp vec4 ambient_accum = vec4(0.0,0.0,0.0,0.0); + + for(int i=0;i<reflection_count;i++) { + reflection_process(reflection_indices[i],vertex,normal,roughness,ambient_light,specular_light,brdf,reflection_accum,ambient_accum); + } + + if (reflection_accum.a>0.0) { + specular_light=reflection_accum.rgb/reflection_accum.a; + specular_light*=specular; + } + if (ambient_accum.a>0.0) { + ambient_light=ambient_accum.rgb/ambient_accum.a; + } + for(int i=0;i<omni_light_count;i++) { light_process_omni(omni_light_indices[i],vertex,eye_vec,normal,albedo,specular,roughness,diffuse_light,specular_light); } @@ -848,6 +1027,8 @@ FRAGMENT_SHADER_CODE light_process_spot(spot_light_indices[i],vertex,eye_vec,normal,albedo,specular,roughness,diffuse_light,specular_light); } + + #endif @@ -866,6 +1047,7 @@ LIGHT_SHADER_CODE //nothing happens, so a tree-ssa optimizer will result in no fragment shader :) #else + specular_light*=reflection_multiplier; #ifdef USE_MULTIPLE_RENDER_TARGETS diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp new file mode 100644 index 0000000000..09082b0f28 --- /dev/null +++ b/scene/3d/reflection_probe.cpp @@ -0,0 +1,266 @@ +#include "reflection_probe.h" + + +void ReflectionProbe::set_intensity(float p_intensity) { + + intensity=p_intensity; + VS::get_singleton()->reflection_probe_set_intensity(probe,p_intensity); +} + +float ReflectionProbe::get_intensity() const{ + + return intensity; +} + + +void ReflectionProbe::set_interior_ambient(Color p_ambient) { + + interior_ambient=p_ambient; + VS::get_singleton()->reflection_probe_set_interior_ambient(probe,p_ambient); +} + +void ReflectionProbe::set_interior_ambient_energy(float p_energy) { + interior_ambient_energy=p_energy; + VS::get_singleton()->reflection_probe_set_interior_ambient_energy(probe,p_energy); +} + +float ReflectionProbe::get_interior_ambient_energy() const{ + return interior_ambient_energy; +} + + +Color ReflectionProbe::get_interior_ambient() const{ + + return interior_ambient; +} + +void ReflectionProbe::set_interior_ambient_probe_contribution(float p_contribution) { + + interior_ambient_probe_contribution=p_contribution; + VS::get_singleton()->reflection_probe_set_interior_ambient_probe_contribution(probe,p_contribution); +} + +float ReflectionProbe::get_interior_ambient_probe_contribution() const{ + + return interior_ambient_probe_contribution; +} + + +void ReflectionProbe::set_max_distance(float p_distance){ + + max_distance=p_distance; + VS::get_singleton()->reflection_probe_set_max_distance(probe,p_distance); +} +float ReflectionProbe::get_max_distance() const{ + + return max_distance; +} + + +void ReflectionProbe::set_extents(const Vector3& p_extents){ + + extents=p_extents; + + for(int i=0;i<3;i++) { + if (extents[i]<0.01) { + extents[i]=0.01; + } + + if (extents[i]-0.01<ABS(origin_offset[i])) { + origin_offset[i]=SGN(origin_offset[i])*(extents[i]-0.01); + _change_notify("origin_offset"); + } + } + + VS::get_singleton()->reflection_probe_set_extents(probe,extents); + VS::get_singleton()->reflection_probe_set_origin_offset(probe,origin_offset); + _change_notify("extents"); + update_gizmo(); + +} +Vector3 ReflectionProbe::get_extents() const{ + + return extents; +} + +void ReflectionProbe::set_origin_offset(const Vector3& p_extents){ + + origin_offset=p_extents; + + for(int i=0;i<3;i++) { + + if (extents[i]-0.01<ABS(origin_offset[i])) { + origin_offset[i]=SGN(origin_offset[i])*(extents[i]-0.01); + + } + } + VS::get_singleton()->reflection_probe_set_extents(probe,extents); + VS::get_singleton()->reflection_probe_set_origin_offset(probe,origin_offset); + + _change_notify("origin_offset"); + update_gizmo(); +} +Vector3 ReflectionProbe::get_origin_offset() const{ + + return origin_offset; +} + +void ReflectionProbe::set_enable_box_projection(bool p_enable){ + + box_projection=p_enable; + VS::get_singleton()->reflection_probe_set_enable_box_projection(probe,p_enable); + +} +bool ReflectionProbe::is_box_projection_enabled() const{ + + return box_projection; +} + + +void ReflectionProbe::set_as_interior(bool p_enable) { + + interior=p_enable; + VS::get_singleton()->reflection_probe_set_as_interior(probe,interior); + _change_notify(); + +} + +bool ReflectionProbe::is_set_as_interior() const { + + return interior; +} + + + +void ReflectionProbe::set_enable_shadows(bool p_enable) { + + enable_shadows=p_enable; + VS::get_singleton()->reflection_probe_set_enable_shadows(probe,p_enable); +} +bool ReflectionProbe::are_shadows_enabled() const { + + return enable_shadows; +} + +void ReflectionProbe::set_cull_mask(uint32_t p_layers) { + + cull_mask=p_layers; + VS::get_singleton()->reflection_probe_set_enable_shadows(probe,p_layers); +} +uint32_t ReflectionProbe::get_cull_mask() const { + + return cull_mask; +} + +void ReflectionProbe::set_update_mode(UpdateMode p_mode) { + update_mode=p_mode; + VS::get_singleton()->reflection_probe_set_update_mode(probe,VS::ReflectionProbeUpdateMode(p_mode)); +} + +ReflectionProbe::UpdateMode ReflectionProbe::get_update_mode() const { + return update_mode; +} + + +AABB ReflectionProbe::get_aabb() const { + + AABB aabb; + aabb.pos=-origin_offset; + aabb.size=origin_offset+extents; + return aabb; +} +DVector<Face3> ReflectionProbe::get_faces(uint32_t p_usage_flags) const { + + return DVector<Face3>(); +} + +void ReflectionProbe::_validate_property(PropertyInfo& property) const { + + if (property.name=="interior/ambient_color" || property.name=="interior/ambient_energy" || property.name=="interior/ambient_contrib") { + if (!interior) { + property.usage=PROPERTY_USAGE_NOEDITOR; + } + } +} + +void ReflectionProbe::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_intensity","intensity"),&ReflectionProbe::set_intensity); + ObjectTypeDB::bind_method(_MD("get_intensity"),&ReflectionProbe::get_intensity); + + ObjectTypeDB::bind_method(_MD("set_interior_ambient","ambient"),&ReflectionProbe::set_interior_ambient); + ObjectTypeDB::bind_method(_MD("get_interior_ambient"),&ReflectionProbe::get_interior_ambient); + + ObjectTypeDB::bind_method(_MD("set_interior_ambient_energy","ambient_energy"),&ReflectionProbe::set_interior_ambient_energy); + ObjectTypeDB::bind_method(_MD("get_interior_ambient_energy"),&ReflectionProbe::get_interior_ambient_energy); + + ObjectTypeDB::bind_method(_MD("set_interior_ambient_probe_contribution","ambient_probe_contribution"),&ReflectionProbe::set_interior_ambient_probe_contribution); + ObjectTypeDB::bind_method(_MD("get_interior_ambient_probe_contribution"),&ReflectionProbe::get_interior_ambient_probe_contribution); + + ObjectTypeDB::bind_method(_MD("set_max_distance","max_distance"),&ReflectionProbe::set_max_distance); + ObjectTypeDB::bind_method(_MD("get_max_distance"),&ReflectionProbe::get_max_distance); + + ObjectTypeDB::bind_method(_MD("set_extents","extents"),&ReflectionProbe::set_extents); + ObjectTypeDB::bind_method(_MD("get_extents"),&ReflectionProbe::get_extents); + + ObjectTypeDB::bind_method(_MD("set_origin_offset","origin_offset"),&ReflectionProbe::set_origin_offset); + ObjectTypeDB::bind_method(_MD("get_origin_offset"),&ReflectionProbe::get_origin_offset); + + ObjectTypeDB::bind_method(_MD("set_as_interior","enable"),&ReflectionProbe::set_as_interior); + ObjectTypeDB::bind_method(_MD("is_set_as_interior"),&ReflectionProbe::is_set_as_interior); + + ObjectTypeDB::bind_method(_MD("set_enable_box_projection","enable"),&ReflectionProbe::set_enable_box_projection); + ObjectTypeDB::bind_method(_MD("is_box_projection_enabled"),&ReflectionProbe::is_box_projection_enabled); + + + ObjectTypeDB::bind_method(_MD("set_enable_shadows","enable"),&ReflectionProbe::set_enable_shadows); + ObjectTypeDB::bind_method(_MD("are_shadows_enabled"),&ReflectionProbe::are_shadows_enabled); + + ObjectTypeDB::bind_method(_MD("set_cull_mask","layers"),&ReflectionProbe::set_cull_mask); + ObjectTypeDB::bind_method(_MD("get_cull_mask"),&ReflectionProbe::get_cull_mask); + + ObjectTypeDB::bind_method(_MD("set_update_mode","mode"),&ReflectionProbe::set_update_mode); + ObjectTypeDB::bind_method(_MD("get_update_mode"),&ReflectionProbe::get_update_mode); + + ADD_PROPERTY( PropertyInfo(Variant::INT,"update_mode",PROPERTY_HINT_ENUM,"Once,Always"),_SCS("set_update_mode"),_SCS("get_update_mode")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"intensity",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_intensity"),_SCS("get_intensity")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"max_distance",PROPERTY_HINT_RANGE,"0,16384,0.1"),_SCS("set_max_distance"),_SCS("get_max_distance")); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"extents"),_SCS("set_extents"),_SCS("get_extents")); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"origin_offset"),_SCS("set_origin_offset"),_SCS("get_origin_offset")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"box_projection"),_SCS("set_enable_box_projection"),_SCS("is_box_projection_enabled")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"enable_shadows"),_SCS("set_enable_shadows"),_SCS("are_shadows_enabled")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"cull_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_cull_mask"),_SCS("get_cull_mask")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"interior/enable"),_SCS("set_as_interior"),_SCS("is_set_as_interior")); + ADD_PROPERTY( PropertyInfo(Variant::COLOR,"interior/ambient_color",PROPERTY_HINT_COLOR_NO_ALPHA),_SCS("set_interior_ambient"),_SCS("get_interior_ambient")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"interior/ambient_energy",PROPERTY_HINT_RANGE,"0,16,0.01"),_SCS("set_interior_ambient_energy"),_SCS("get_interior_ambient_energy")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"interior/ambient_contrib",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_interior_ambient_probe_contribution"),_SCS("get_interior_ambient_probe_contribution")); + + + BIND_CONSTANT( UPDATE_ONCE ); + BIND_CONSTANT( UPDATE_ALWAYS ); + +} + +ReflectionProbe::ReflectionProbe() { + + intensity=1.0; + interior_ambient=Color(0,0,0); + interior_ambient_probe_contribution=0; + interior_ambient_energy=1.0; + max_distance=0; + extents=Vector3(1,1,1); + origin_offset=Vector3(0,0,0); + box_projection=false; + interior=false; + enable_shadows=false; + cull_mask=(1<<20)-1; + update_mode=UPDATE_ONCE; + + probe=VisualServer::get_singleton()->reflection_probe_create(); + VS::get_singleton()->instance_set_base(get_instance(),probe); +} + +ReflectionProbe::~ReflectionProbe() { + + VS::get_singleton()->free(probe); +} diff --git a/scene/3d/reflection_probe.h b/scene/3d/reflection_probe.h new file mode 100644 index 0000000000..5ea41a91c9 --- /dev/null +++ b/scene/3d/reflection_probe.h @@ -0,0 +1,92 @@ +#ifndef REFLECTIONPROBE_H +#define REFLECTIONPROBE_H + +#include "scene/3d/visual_instance.h" +#include "scene/resources/texture.h" +#include "scene/resources/sky_box.h" +#include "servers/visual_server.h" + +class ReflectionProbe : public VisualInstance { + OBJ_TYPE(ReflectionProbe,VisualInstance); + +public: + + enum UpdateMode { + UPDATE_ONCE, + UPDATE_ALWAYS, + }; + + +private: + + RID probe; + float intensity; + float max_distance; + Vector3 extents; + Vector3 origin_offset; + bool box_projection; + bool enable_shadows; + bool interior; + Color interior_ambient; + float interior_ambient_energy; + float interior_ambient_probe_contribution; + + uint32_t cull_mask; + UpdateMode update_mode; + +protected: + + static void _bind_methods(); + void _validate_property(PropertyInfo& property) const; + +public: + + void set_intensity(float p_intensity); + float get_intensity() const; + + void set_interior_ambient(Color p_ambient); + Color get_interior_ambient() const; + + void set_interior_ambient_energy(float p_energy); + float get_interior_ambient_energy() const; + + void set_interior_ambient_probe_contribution(float p_contribution); + float get_interior_ambient_probe_contribution() const; + + void set_max_distance(float p_distance); + float get_max_distance() const; + + void set_extents(const Vector3& p_extents); + Vector3 get_extents() const; + + void set_origin_offset(const Vector3& p_extents); + Vector3 get_origin_offset() const; + + void set_as_interior(bool p_enable); + bool is_set_as_interior() const; + + void set_enable_box_projection(bool p_enable); + bool is_box_projection_enabled() const; + + void set_enable_shadows(bool p_enable); + bool are_shadows_enabled() const; + + void set_cull_mask(uint32_t p_layers); + uint32_t get_cull_mask() const; + + void set_update_mode(UpdateMode p_mode); + UpdateMode get_update_mode() const; + + virtual AABB get_aabb() const; + virtual DVector<Face3> get_faces(uint32_t p_usage_flags) const; + + + + ReflectionProbe(); + ~ReflectionProbe(); +}; + + +VARIANT_ENUM_CAST( ReflectionProbe::UpdateMode ); + +#endif // REFLECTIONPROBE_H diff --git a/scene/main/scene_main_loop.cpp b/scene/main/scene_main_loop.cpp index ef619244d0..abc4bf3fe2 100644 --- a/scene/main/scene_main_loop.cpp +++ b/scene/main/scene_main_loop.cpp @@ -2296,6 +2296,7 @@ SceneTree::SceneTree() { collision_debug_contacts=GLOBAL_DEF("debug/collision_max_contacts_displayed",10000); + tree_version=1; fixed_process_time=1; idle_process_time=1; @@ -2319,6 +2320,12 @@ SceneTree::SceneTree() { root->set_as_audio_listener_2d(true); current_scene=NULL; + int ref_atlas_size = GLOBAL_DEF("rendering/reflections/atlas_size",2048); + int ref_atlas_subdiv = GLOBAL_DEF("rendering/reflections/atlas_subdiv",8); + + VS::get_singleton()->scenario_set_reflection_atlas_size(root->get_world()->get_scenario(),ref_atlas_size,ref_atlas_subdiv); + + stretch_mode=STRETCH_MODE_DISABLED; stretch_aspect=STRETCH_ASPECT_IGNORE; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index e2f5b56796..d2b9def5c7 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -166,6 +166,7 @@ #include "scene/resources/sample.h" #include "scene/audio/sample_player.h" #include "scene/resources/texture.h" +#include "scene/resources/sky_box.h" #include "scene/resources/material.h" #include "scene/resources/mesh.h" #include "scene/resources/room.h" @@ -203,6 +204,7 @@ #include "scene/3d/mesh_instance.h" #include "scene/3d/quad.h" #include "scene/3d/light.h" +#include "scene/3d/reflection_probe.h" #include "scene/3d/particles.h" #include "scene/3d/portal.h" #include "scene/resources/environment.h" @@ -421,6 +423,7 @@ void register_scene_types() { ObjectTypeDB::register_type<DirectionalLight>(); ObjectTypeDB::register_type<OmniLight>(); ObjectTypeDB::register_type<SpotLight>(); + ObjectTypeDB::register_type<ReflectionProbe>(); ObjectTypeDB::register_type<AnimationTreePlayer>(); ObjectTypeDB::register_type<Portal>(); //ObjectTypeDB::register_type<Particles>(); @@ -578,6 +581,8 @@ void register_scene_types() { ObjectTypeDB::register_type<Environment>(); ObjectTypeDB::register_type<World2D>(); ObjectTypeDB::register_virtual_type<Texture>(); + ObjectTypeDB::register_virtual_type<SkyBox>(); + ObjectTypeDB::register_type<ImageSkyBox>(); ObjectTypeDB::register_type<ImageTexture>(); ObjectTypeDB::register_type<AtlasTexture>(); ObjectTypeDB::register_type<LargeTexture>(); diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index 47f4370cc2..d35200d98c 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -44,16 +44,15 @@ void Environment::set_background(BGMode p_bg) { _change_notify(); } -void Environment::set_skybox(const Ref<CubeMap>& p_skybox){ +void Environment::set_skybox(const Ref<SkyBox> &p_skybox){ bg_skybox=p_skybox; RID sb_rid; if (bg_skybox.is_valid()) sb_rid=bg_skybox->get_rid(); - print_line("skybox valid: "+itos(sb_rid.is_valid())); - VS::get_singleton()->environment_set_skybox(environment,sb_rid,Globals::get_singleton()->get("rendering/skybox/radiance_cube_resolution")); + VS::get_singleton()->environment_set_skybox(environment,sb_rid); } void Environment::set_skybox_scale(float p_scale) { @@ -97,7 +96,7 @@ Environment::BGMode Environment::get_background() const{ return bg_mode; } -Ref<CubeMap> Environment::get_skybox() const{ +Ref<SkyBox> Environment::get_skybox() const{ return bg_skybox; } @@ -326,7 +325,7 @@ void Environment::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT,"background/mode",PROPERTY_HINT_ENUM,"Clear Color,Custom Color,Skybox,Canvas,Keep"),_SCS("set_background"),_SCS("get_background") ); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"background/skybox",PROPERTY_HINT_RESOURCE_TYPE,"CubeMap"),_SCS("set_skybox"),_SCS("get_skybox") ); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"background/skybox",PROPERTY_HINT_RESOURCE_TYPE,"SkyBox"),_SCS("set_skybox"),_SCS("get_skybox") ); ADD_PROPERTY(PropertyInfo(Variant::REAL,"background/skybox_scale",PROPERTY_HINT_RANGE,"0,32,0.01"),_SCS("set_skybox_scale"),_SCS("get_skybox_scale") ); ADD_PROPERTY(PropertyInfo(Variant::COLOR,"background/color"),_SCS("set_bg_color"),_SCS("get_bg_color") ); ADD_PROPERTY(PropertyInfo(Variant::REAL,"background/energy",PROPERTY_HINT_RANGE,"0,16,0.01"),_SCS("set_bg_energy"),_SCS("get_bg_energy") ); diff --git a/scene/resources/environment.h b/scene/resources/environment.h index 394b67dadf..ca55b51b20 100644 --- a/scene/resources/environment.h +++ b/scene/resources/environment.h @@ -32,6 +32,7 @@ #include "resource.h" #include "servers/visual_server.h" #include "scene/resources/texture.h" +#include "scene/resources/sky_box.h" class Environment : public Resource { @@ -69,7 +70,7 @@ private: RID environment; BGMode bg_mode; - Ref<CubeMap> bg_skybox; + Ref<SkyBox> bg_skybox; float bg_skybox_scale; Color bg_color; float bg_energy; @@ -102,7 +103,7 @@ public: void set_background(BGMode p_bg); - void set_skybox(const Ref<CubeMap>& p_skybox); + void set_skybox(const Ref<SkyBox>& p_skybox); void set_skybox_scale(float p_scale); void set_bg_color(const Color& p_color); void set_bg_energy(float p_energy); @@ -112,7 +113,7 @@ public: void set_ambient_light_skybox_contribution(float p_energy); BGMode get_background() const; - Ref<CubeMap> get_skybox() const; + Ref<SkyBox> get_skybox() const; float get_skybox_scale() const; Color get_bg_color() const; float get_bg_energy() const; diff --git a/scene/resources/sky_box.cpp b/scene/resources/sky_box.cpp new file mode 100644 index 0000000000..e8017cb084 --- /dev/null +++ b/scene/resources/sky_box.cpp @@ -0,0 +1,158 @@ +#include "sky_box.h" +#include "io/image_loader.h" + + +void SkyBox::set_radiance_size(RadianceSize p_size) { + ERR_FAIL_INDEX(p_size,RADIANCE_SIZE_MAX); + + radiance_size=p_size; + _radiance_changed(); +} + +SkyBox::RadianceSize SkyBox::get_radiance_size() const { + + return radiance_size; +} + +void SkyBox::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_radiance_size","size"),&SkyBox::set_radiance_size); + ObjectTypeDB::bind_method(_MD("get_radiance_size"),&SkyBox::get_radiance_size); + + ADD_PROPERTY(PropertyInfo(Variant::INT,"radiance_size",PROPERTY_HINT_ENUM,"256,512,1024,2048"),_SCS("set_radiance_size"),_SCS("get_radiance_size")); + + + BIND_CONSTANT( RADIANCE_SIZE_256 ); + BIND_CONSTANT( RADIANCE_SIZE_512 ); + BIND_CONSTANT( RADIANCE_SIZE_1024 ); + BIND_CONSTANT( RADIANCE_SIZE_2048 ); + BIND_CONSTANT( RADIANCE_SIZE_MAX ); +} + +SkyBox::SkyBox() +{ + radiance_size=RADIANCE_SIZE_512; +} + +///////////////////////////////////////// + + + +void ImageSkyBox::_radiance_changed() { + + if (cube_map_valid) { + static const int size[RADIANCE_SIZE_MAX]={ + 256,512,1024,2048 + }; + VS::get_singleton()->skybox_set_texture(sky_box,cube_map,size[get_radiance_size()]); + } +} + +void ImageSkyBox::set_image_path(ImagePath p_image,const String &p_path) { + + ERR_FAIL_INDEX(p_image,IMAGE_PATH_MAX); + image_path[p_image]=p_path; + + bool all_ok=true; + for(int i=0;i<IMAGE_PATH_MAX;i++) { + if (image_path[i]==String()) { + all_ok=false; + } + } + + cube_map_valid=false; + + if (all_ok) { + + Image images[IMAGE_PATH_MAX]; + int w=0,h=0; + Image::Format format; + + for(int i=0;i<IMAGE_PATH_MAX;i++) { + Error err = ImageLoader::load_image(image_path[i],&images[i]); + if (err) { + ERR_PRINTS("Error loading image for skybox: "+image_path[i]); + return; + } + + if (i==0) { + w=images[0].get_width(); + h=images[0].get_height(); + format=images[0].get_format(); + } else { + if (images[i].get_width()!=w || images[i].get_height()!=h || images[i].get_format()!=format) { + ERR_PRINTS("Image size mismatch ("+itos(images[i].get_width())+","+itos(images[i].get_height())+":"+Image::get_format_name(images[i].get_format())+" when it should be "+itos(w)+","+itos(h)+":"+Image::get_format_name(format)+"): "+image_path[i]); + return; + } + } + } + + VS::get_singleton()->texture_allocate(cube_map,w,h,format,VS::TEXTURE_FLAG_FILTER|VS::TEXTURE_FLAG_CUBEMAP|VS::TEXTURE_FLAG_MIPMAPS); + for(int i=0;i<IMAGE_PATH_MAX;i++) { + VS::get_singleton()->texture_set_data(cube_map,images[i],VS::CubeMapSide(i)); + } + + cube_map_valid=true; + _radiance_changed(); + } + + +} + +String ImageSkyBox::get_image_path(ImagePath p_image) const { + + ERR_FAIL_INDEX_V(p_image,IMAGE_PATH_MAX,String()); + return image_path[p_image]; + +} + +RID ImageSkyBox::get_rid() const { + + return sky_box; +} + +void ImageSkyBox::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_image_path","image","path"),&ImageSkyBox::set_image_path); + ObjectTypeDB::bind_method(_MD("get_image_path","image"),&ImageSkyBox::get_image_path); + + List<String> extensions; + ImageLoader::get_recognized_extensions(&extensions); + String hints; + for(List<String>::Element *E=extensions.front();E;E=E->next()) { + if (hints!=String()) { + hints+=","; + } + hints+="*."+E->get(); + } + + ADD_PROPERTYI(PropertyInfo(Variant::STRING,"image_path/negative_x",PROPERTY_HINT_FILE,hints),_SCS("set_image_path"),_SCS("get_image_path"),IMAGE_PATH_NEGATIVE_X); + ADD_PROPERTYI(PropertyInfo(Variant::STRING,"image_path/positive_x",PROPERTY_HINT_FILE,hints),_SCS("set_image_path"),_SCS("get_image_path"),IMAGE_PATH_POSITIVE_X); + ADD_PROPERTYI(PropertyInfo(Variant::STRING,"image_path/negative_y",PROPERTY_HINT_FILE,hints),_SCS("set_image_path"),_SCS("get_image_path"),IMAGE_PATH_NEGATIVE_Y); + ADD_PROPERTYI(PropertyInfo(Variant::STRING,"image_path/positive_y",PROPERTY_HINT_FILE,hints),_SCS("set_image_path"),_SCS("get_image_path"),IMAGE_PATH_POSITIVE_Y); + ADD_PROPERTYI(PropertyInfo(Variant::STRING,"image_path/negative_z",PROPERTY_HINT_FILE,hints),_SCS("set_image_path"),_SCS("get_image_path"),IMAGE_PATH_NEGATIVE_Z); + ADD_PROPERTYI(PropertyInfo(Variant::STRING,"image_path/positive_z",PROPERTY_HINT_FILE,hints),_SCS("set_image_path"),_SCS("get_image_path"),IMAGE_PATH_POSITIVE_Z); + + BIND_CONSTANT( IMAGE_PATH_NEGATIVE_X ); + BIND_CONSTANT( IMAGE_PATH_POSITIVE_X ); + BIND_CONSTANT( IMAGE_PATH_NEGATIVE_Y ); + BIND_CONSTANT( IMAGE_PATH_POSITIVE_Y ); + BIND_CONSTANT( IMAGE_PATH_NEGATIVE_Z ); + BIND_CONSTANT( IMAGE_PATH_POSITIVE_Z ); + BIND_CONSTANT( IMAGE_PATH_MAX ); + +} + +ImageSkyBox::ImageSkyBox() { + + cube_map=VS::get_singleton()->texture_create(); + sky_box=VS::get_singleton()->skybox_create(); + cube_map_valid=false; +} + +ImageSkyBox::~ImageSkyBox() { + + VS::get_singleton()->free(cube_map); + VS::get_singleton()->free(sky_box); +} + diff --git a/scene/resources/sky_box.h b/scene/resources/sky_box.h new file mode 100644 index 0000000000..3a3dd1b2de --- /dev/null +++ b/scene/resources/sky_box.h @@ -0,0 +1,71 @@ +#ifndef SKYBOX_H +#define SKYBOX_H + +#include "scene/resources/texture.h" + +class SkyBox : public Resource { + OBJ_TYPE(SkyBox,Resource); + +public: + + enum RadianceSize { + RADIANCE_SIZE_256, + RADIANCE_SIZE_512, + RADIANCE_SIZE_1024, + RADIANCE_SIZE_2048, + RADIANCE_SIZE_MAX + }; +private: + + RadianceSize radiance_size; +protected: + static void _bind_methods(); + virtual void _radiance_changed()=0; +public: + + void set_radiance_size(RadianceSize p_size); + RadianceSize get_radiance_size() const; + SkyBox(); +}; + +VARIANT_ENUM_CAST(SkyBox::RadianceSize) + + +class ImageSkyBox : public SkyBox { + OBJ_TYPE(ImageSkyBox,SkyBox); + +public: + + enum ImagePath { + IMAGE_PATH_NEGATIVE_X, + IMAGE_PATH_POSITIVE_X, + IMAGE_PATH_NEGATIVE_Y, + IMAGE_PATH_POSITIVE_Y, + IMAGE_PATH_NEGATIVE_Z, + IMAGE_PATH_POSITIVE_Z, + IMAGE_PATH_MAX + }; +private: + RID cube_map; + RID sky_box; + bool cube_map_valid; + + String image_path[IMAGE_PATH_MAX]; +protected: + static void _bind_methods(); + virtual void _radiance_changed(); +public: + + void set_image_path(ImagePath p_image, const String &p_path); + String get_image_path(ImagePath p_image) const; + + virtual RID get_rid() const; + + ImageSkyBox(); + ~ImageSkyBox(); +}; + +VARIANT_ENUM_CAST(ImageSkyBox::ImagePath) + + +#endif // SKYBOX_H diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 06509c6fd0..0f70b036a6 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -54,7 +54,7 @@ public: virtual RID environment_create()=0; virtual void environment_set_background(RID p_env,VS::EnvironmentBG p_bg)=0; - virtual void environment_set_skybox(RID p_env,RID p_skybox,int p_radiance_size)=0; + virtual void environment_set_skybox(RID p_env,RID p_skybox)=0; virtual void environment_set_skybox_scale(RID p_env,float p_scale)=0; virtual void environment_set_bg_color(RID p_env,const Color& p_color)=0; virtual void environment_set_bg_energy(RID p_env,float p_energy)=0; @@ -84,6 +84,7 @@ public: Vector<RID> materials; Vector<RID> light_instances; + Vector<RID> reflection_probe_instances; Vector<float> morph_values; @@ -125,7 +126,19 @@ public: 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)=0; virtual void light_instance_mark_visible(RID p_light_instance)=0; - 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)=0; + virtual RID reflection_atlas_create()=0; + virtual void reflection_atlas_set_size(RID p_ref_atlas,int p_size)=0; + virtual void reflection_atlas_set_subdivision(RID p_ref_atlas,int p_subdiv)=0; + + virtual RID reflection_probe_instance_create(RID p_probe)=0; + virtual void reflection_probe_instance_set_transform(RID p_instance,const Transform& p_transform)=0; + virtual void reflection_probe_release_atlas_index(RID p_instance)=0; + virtual bool reflection_probe_instance_needs_redraw(RID p_instance)=0; + virtual bool reflection_probe_instance_has_reflection(RID p_instance)=0; + virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas)=0; + virtual bool reflection_probe_instance_postprocess_step(RID p_instance)=0; + + 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_reflection_probe_cull_result,int p_reflection_probe_cull_count,RID p_environment,RID p_shadow_atlas,RID p_reflection_atlas,RID p_reflection_probe,int p_reflection_probe_pass)=0; virtual void render_shadow(RID p_light,RID p_shadow_atlas,int p_pass,InstanceBase** p_cull_result,int p_cull_count)=0; virtual void set_scene_pass(uint64_t p_pass)=0; @@ -165,6 +178,11 @@ public: virtual RID texture_create_radiance_cubemap(RID p_source,int p_resolution=-1) const=0; + /* SKYBOX API */ + + virtual RID skybox_create()=0; + virtual void skybox_set_texture(RID p_skybox,RID p_cube_map,int p_radiance_size)=0; + /* SHADER API */ @@ -324,16 +342,27 @@ public: virtual RID reflection_probe_create()=0; + virtual void reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode)=0; virtual void reflection_probe_set_intensity(RID p_probe, float p_intensity)=0; - virtual void reflection_probe_set_clip(RID p_probe, float p_near, float p_far)=0; - virtual void reflection_probe_set_min_blend_distance(RID p_probe, float p_distance)=0; + virtual void reflection_probe_set_interior_ambient(RID p_probe, const Color& p_ambient)=0; + virtual void reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy)=0; + virtual void reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib)=0; + virtual void reflection_probe_set_max_distance(RID p_probe, float p_distance)=0; virtual void reflection_probe_set_extents(RID p_probe, const Vector3& p_extents)=0; virtual void reflection_probe_set_origin_offset(RID p_probe, const Vector3& p_offset)=0; - virtual void reflection_probe_set_enable_parallax_correction(RID p_probe, bool p_enable)=0; - virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution)=0; - virtual void reflection_probe_set_hide_skybox(RID p_probe, bool p_hide)=0; + virtual void reflection_probe_set_as_interior(RID p_probe, bool p_enable)=0; + virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable)=0; + virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable)=0; virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers)=0; + virtual AABB reflection_probe_get_aabb(RID p_probe) const=0; + virtual VS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const=0; + virtual uint32_t reflection_probe_get_cull_mask(RID p_probe) const=0; + virtual Vector3 reflection_probe_get_extents(RID p_probe) const=0; + virtual Vector3 reflection_probe_get_origin_offset(RID p_probe) const=0; + virtual float reflection_probe_get_origin_max_distance(RID p_probe) const=0; + virtual bool reflection_probe_renders_shadows(RID p_probe) const=0; + /* ROOM API */ diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index bbad460f4f..6ba63a7690 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -94,6 +94,7 @@ void VisualServerRaster::draw(){ VSG::rasterizer->begin_frame(); VSG::viewport->draw_viewports(); + VSG::scene->render_probes(); //_draw_cursors_and_margins(); VSG::rasterizer->end_frame(); //draw_extra_frame=VS:rasterizer->needs_to_draw_next_frame(); diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 4d8a46122c..4e9110445b 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -629,7 +629,10 @@ public: BIND1(texture_set_shrink_all_x2_on_set_data,bool) BIND1(texture_debug_usage,List<TextureInfo>*) + /* SKYBOX API */ + BIND0R(RID,skybox_create) + BIND3(skybox_set_texture,RID,RID,int) /* SHADER API */ @@ -772,17 +775,19 @@ public: BIND0R(RID,reflection_probe_create) + BIND2(reflection_probe_set_update_mode,RID, ReflectionProbeUpdateMode ) BIND2(reflection_probe_set_intensity,RID, float ) - BIND3(reflection_probe_set_clip,RID, float , float ) - BIND2(reflection_probe_set_min_blend_distance,RID, float ) + BIND2(reflection_probe_set_interior_ambient,RID, const Color& ) + BIND2(reflection_probe_set_interior_ambient_energy,RID, float ) + BIND2(reflection_probe_set_interior_ambient_probe_contribution,RID, float ) + BIND2(reflection_probe_set_max_distance,RID, float ) BIND2(reflection_probe_set_extents,RID, const Vector3& ) BIND2(reflection_probe_set_origin_offset,RID, const Vector3& ) - BIND2(reflection_probe_set_enable_parallax_correction,RID, bool ) - BIND2(reflection_probe_set_resolution,RID, int ) - BIND2(reflection_probe_set_hide_skybox,RID, bool ) + BIND2(reflection_probe_set_as_interior,RID, bool ) + BIND2(reflection_probe_set_enable_box_projection,RID, bool ) + BIND2(reflection_probe_set_enable_shadows,RID, bool ) BIND2(reflection_probe_set_cull_mask,RID, uint32_t ) - /* ROOM API */ BIND0R(RID,room_create) @@ -866,7 +871,7 @@ public: BIND0R(RID,environment_create) BIND2(environment_set_background,RID ,EnvironmentBG ) - BIND3(environment_set_skybox,RID,RID ,int ) + BIND2(environment_set_skybox,RID,RID ) BIND2(environment_set_skybox_scale,RID,float) BIND2(environment_set_bg_color,RID,const Color& ) BIND2(environment_set_bg_energy,RID,float ) @@ -890,6 +895,7 @@ public: BIND2(scenario_set_debug,RID,ScenarioDebugMode ) BIND2(scenario_set_environment,RID, RID ) + BIND3(scenario_set_reflection_atlas_size,RID, int,int ) BIND2(scenario_set_fallback_environment,RID, RID ) diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index e214374f4d..74d77c5262 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -103,8 +103,25 @@ void* VisualServerScene::_instance_pair(void *p_self, OctreeElementID, Instance geom->lighting_dirty=true; return E; //this element should make freeing faster + } else if (B->base_type==VS::INSTANCE_REFLECTION_PROBE && (1<<A->base_type)&VS::INSTANCE_GEOMETRY_MASK) { + + InstanceReflectionProbeData * reflection_probe = static_cast<InstanceReflectionProbeData*>(B->base_data); + InstanceGeometryData * geom = static_cast<InstanceGeometryData*>(A->base_data); + + + InstanceReflectionProbeData::PairInfo pinfo; + pinfo.geometry=A; + pinfo.L = geom->reflection_probes.push_back(B); + + List<InstanceReflectionProbeData::PairInfo>::Element *E = reflection_probe->geometries.push_back(pinfo); + + geom->reflection_dirty=true; + + return E; //this element should make freeing faster } + + #if 0 if (A->base_type==INSTANCE_PORTAL) { @@ -189,6 +206,18 @@ void VisualServerScene::_instance_unpair(void *p_self, OctreeElementID, Instance geom->lighting_dirty=true; + } else if (B->base_type==VS::INSTANCE_REFLECTION_PROBE && (1<<A->base_type)&VS::INSTANCE_GEOMETRY_MASK) { + + InstanceReflectionProbeData * reflection_probe = static_cast<InstanceReflectionProbeData*>(B->base_data); + InstanceGeometryData * geom = static_cast<InstanceGeometryData*>(A->base_data); + + List<InstanceReflectionProbeData::PairInfo>::Element *E = reinterpret_cast<List<InstanceReflectionProbeData::PairInfo>::Element*>(udata); + + geom->reflection_probes.erase(E->get().L); + reflection_probe->geometries.erase(E); + + geom->reflection_dirty=true; + } #if 0 if (A->base_type==INSTANCE_PORTAL) { @@ -252,6 +281,13 @@ RID VisualServerScene::scenario_create() { scenario->octree.set_pair_callback(_instance_pair,this); scenario->octree.set_unpair_callback(_instance_unpair,this); + scenario->reflection_probe_shadow_atlas=VSG::scene_render->shadow_atlas_create(); + VSG::scene_render->shadow_atlas_set_size(scenario->reflection_probe_shadow_atlas,1024); //make enough shadows for close distance, don't bother with rest + VSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas,0,4); + VSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas,1,4); + VSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas,2,4); + VSG::scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas,3,8); + scenario->reflection_atlas=VSG::scene_render->reflection_atlas_create(); return scenario_rid; } @@ -281,6 +317,16 @@ void VisualServerScene::scenario_set_fallback_environment(RID p_scenario, RID p_ } +void VisualServerScene::scenario_set_reflection_atlas_size(RID p_scenario, int p_size,int p_subdiv) { + + Scenario *scenario = scenario_owner.get(p_scenario); + ERR_FAIL_COND(!scenario); + VSG::scene_render->reflection_atlas_set_size(scenario->reflection_atlas,p_size); + VSG::scene_render->reflection_atlas_set_subdivision(scenario->reflection_atlas,p_subdiv); + + +} + /* INSTANCING API */ @@ -343,6 +389,14 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base){ } VSG::scene_render->free(light->instance); } break; + case VS::INSTANCE_REFLECTION_PROBE: { + + InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData*>(instance->base_data); + VSG::scene_render->free(reflection_probe->instance); + if (reflection_probe->update_list.in_list()) { + reflection_probe_render_list.remove(&reflection_probe->update_list); + } + } break; } if (instance->base_data) { @@ -508,6 +562,14 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base){ InstanceGeometryData *geom = memnew( InstanceGeometryData ); instance->base_data=geom; } break; + case VS::INSTANCE_REFLECTION_PROBE: { + + InstanceReflectionProbeData *reflection_probe = memnew( InstanceReflectionProbeData ); + reflection_probe->owner=instance; + instance->base_data=reflection_probe; + + reflection_probe->instance=VSG::scene_render->reflection_probe_instance_create(p_base); + } break; } @@ -607,6 +669,12 @@ void VisualServerScene::instance_set_scenario(RID p_instance, RID p_scenario){ light->D=NULL; } } break; + case VS::INSTANCE_REFLECTION_PROBE: { + + InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData*>(instance->base_data); + VSG::scene_render->reflection_probe_release_atlas_index(reflection_probe->instance); + } break; + } instance->scenario=NULL; @@ -876,6 +944,15 @@ void VisualServerScene::_update_instance(Instance *p_instance) { } + if (p_instance->base_type == VS::INSTANCE_REFLECTION_PROBE) { + + InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData*>(p_instance->base_data); + + VSG::scene_render->reflection_probe_instance_set_transform( reflection_probe->instance, p_instance->transform ); + reflection_probe->reflection_dirty=true; + + } + if (p_instance->aabb.has_no_surface()) return; @@ -970,7 +1047,7 @@ void VisualServerScene::_update_instance(Instance *p_instance) { uint32_t pairable_mask=0; bool pairable=false; - if (p_instance->base_type == VS::INSTANCE_LIGHT) { + if (p_instance->base_type == VS::INSTANCE_LIGHT || p_instance->base_type==VS::INSTANCE_REFLECTION_PROBE) { pairable_mask=p_instance->visible?VS::INSTANCE_GEOMETRY_MASK:0; pairable=true; @@ -1072,6 +1149,12 @@ void VisualServerScene::_update_instance_aabb(Instance *p_instance) { new_aabb = VSG::storage->light_get_aabb(p_instance->base); } break; + case VisualServer::INSTANCE_REFLECTION_PROBE: { + + new_aabb = VSG::storage->reflection_probe_get_aabb(p_instance->base); + + } break; + #if 0 case VisualServer::INSTANCE_ROOM: { @@ -1129,7 +1212,7 @@ void VisualServerScene::_update_instance_aabb(Instance *p_instance) { -void VisualServerScene::_light_instance_update_shadow(Instance *p_instance,Camera* p_camera,RID p_shadow_atlas,Scenario* p_scenario,Size2 p_viewport_rect) { +void VisualServerScene::_light_instance_update_shadow(Instance *p_instance,const Transform p_cam_transform,const CameraMatrix& p_cam_projection,bool p_cam_orthogonal,RID p_shadow_atlas,Scenario* p_scenario) { InstanceLightData * light = static_cast<InstanceLightData*>(p_instance->base_data); @@ -1138,14 +1221,14 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance,Camer case VS::LIGHT_DIRECTIONAL: { - float max_distance = p_camera->zfar; + float max_distance =p_cam_projection.get_z_far(); float shadow_max = VSG::storage->light_get_param(p_instance->base,VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE); if (shadow_max>0) { max_distance=MIN(shadow_max,max_distance); } - max_distance=MAX(max_distance,p_camera->znear+0.001); + max_distance=MAX(max_distance,p_cam_projection.get_z_near()+0.001); - float range = max_distance-p_camera->znear; + float range = max_distance-p_cam_projection.get_z_near(); int splits=0; switch(VSG::storage->light_directional_get_shadow_mode(p_instance->base)) { @@ -1156,9 +1239,9 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance,Camer float distances[5]; - distances[0]=p_camera->znear; + distances[0]=p_cam_projection.get_z_near(); for(int i=0;i<splits;i++) { - distances[i+1]=p_camera->znear+VSG::storage->light_get_param(p_instance->base,VS::LightParam(VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET+i))*range; + distances[i+1]=p_cam_projection.get_z_near()+VSG::storage->light_get_param(p_instance->base,VS::LightParam(VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET+i))*range; }; distances[splits]=max_distance; @@ -1172,38 +1255,24 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance,Camer // setup a camera matrix for that range! CameraMatrix camera_matrix; - switch(p_camera->type) { - - case Camera::ORTHOGONAL: { - - camera_matrix.set_orthogonal( - p_camera->size, - p_viewport_rect.width / p_viewport_rect.height, - distances[(i==0 || !overlap )?i:i-1], - distances[i+1], - p_camera->vaspect - - ); - } break; - case Camera::PERSPECTIVE: { + float aspect = p_cam_projection.get_aspect(); - camera_matrix.set_perspective( - p_camera->fov, - p_viewport_rect.width / (float)p_viewport_rect.height, - distances[(i==0 || !overlap )?i:i-1], - distances[i+1], - p_camera->vaspect + if (p_cam_orthogonal) { - ); + float w,h; + p_cam_projection.get_viewport_size(w,h); + camera_matrix.set_orthogonal(w,aspect,distances[(i==0 || !overlap )?i:i-1],distances[i+1],false); + } else { - } break; + float fov = p_cam_projection.get_fov(); + camera_matrix.set_perspective(fov,aspect,distances[(i==0 || !overlap )?i:i-1],distances[i+1],false); } //obtain the frustum endpoints Vector3 endpoints[8]; // frustum plane endpoints - bool res = camera_matrix.get_endpoints(p_camera->transform,endpoints); + bool res = camera_matrix.get_endpoints(p_cam_transform,endpoints); ERR_CONTINUE(!res); // obtain the light frustm ranges (given endpoints) @@ -1459,8 +1528,8 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance,Camer float angle = VSG::storage->light_get_param( p_instance->base, VS::LIGHT_PARAM_SPOT_ANGLE); CameraMatrix cm; - cm.set_perspective( 90, 1.0, 0.01, radius ); - print_line("perspective: "+cm); + cm.set_perspective( angle, 1.0, 0.01, radius ); + Vector<Plane> planes = cm.get_projection_planes(p_instance->transform); int cull_count = p_scenario->octree.cull_convex(planes,instance_shadow_cull_result,MAX_INSTANCE_CULL,VS::INSTANCE_GEOMETRY_MASK); @@ -1477,7 +1546,6 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance,Camer } - print_line("MOMONGO"); VSG::scene_render->light_instance_set_shadow_transform(light->instance,cm,p_instance->transform,radius,0,0); VSG::scene_render->render_shadow(light->instance,p_shadow_atlas,0,(RasterizerScene::InstanceBase**)instance_shadow_cull_result,cull_count); @@ -1487,26 +1555,13 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance,Camer } - - - void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewport_size,RID p_shadow_atlas) { - Camera *camera = camera_owner.getornull(p_camera); ERR_FAIL_COND(!camera); - Scenario *scenario = scenario_owner.getornull(p_scenario); - - render_pass++; - uint32_t camera_layer_mask=camera->visible_layers; - - VSG::scene_render->set_scene_pass(render_pass); - - /* STEP 1 - SETUP CAMERA */ CameraMatrix camera_matrix; - Transform camera_inverse_xform = camera->transform.affine_inverse(); bool ortho=false; @@ -1538,16 +1593,36 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp } break; } + _render_scene(camera->transform,camera_matrix,ortho,camera->env,camera->visible_layers,p_scenario,p_shadow_atlas,RID(),-1); + +} + + +void VisualServerScene::_render_scene(const Transform p_cam_transform,const CameraMatrix& p_cam_projection,bool p_cam_orthogonal,RID p_force_environment,uint32_t p_visible_layers, RID p_scenario,RID p_shadow_atlas,RID p_reflection_probe,int p_reflection_probe_pass) { + + + + Scenario *scenario = scenario_owner.getornull(p_scenario); + + render_pass++; + uint32_t camera_layer_mask=p_visible_layers; + + VSG::scene_render->set_scene_pass(render_pass); + // rasterizer->set_camera(camera->transform, camera_matrix,ortho); - Vector<Plane> planes = camera_matrix.get_projection_planes(camera->transform); + Vector<Plane> planes = p_cam_projection.get_projection_planes(p_cam_transform); - Plane near_plane(camera->transform.origin,-camera->transform.basis.get_axis(2).normalized()); + Plane near_plane(p_cam_transform.origin,-p_cam_transform.basis.get_axis(2).normalized()); + float z_far = p_cam_projection.get_z_far(); /* STEP 2 - CULL */ int cull_count = scenario->octree.cull_convex(planes,instance_cull_result,MAX_INSTANCE_CULL); light_cull_count=0; + + reflection_probe_cull_count=0; + // light_samplers_culled=0; /* print_line("OT: "+rtos( (OS::get_singleton()->get_ticks_usec()-t)/1000.0)); @@ -1649,7 +1724,6 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp bool keep=false; - if ((camera_layer_mask&ins->layer_mask)==0) { //failure @@ -1673,6 +1747,36 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp } + } else if (ins->base_type==VS::INSTANCE_REFLECTION_PROBE && ins->visible) { + + + if (ins->visible && reflection_probe_cull_count<MAX_REFLECTION_PROBES_CULLED) { + + InstanceReflectionProbeData * reflection_probe = static_cast<InstanceReflectionProbeData*>(ins->base_data); + + if (p_reflection_probe!=reflection_probe->instance) { + //avoid entering The Matrix + + if (!reflection_probe->geometries.empty()) { + //do not add this light if no geometry is affected by it.. + + if (reflection_probe->reflection_dirty || VSG::scene_render->reflection_probe_instance_needs_redraw(reflection_probe->instance)) { + if (!reflection_probe->update_list.in_list()) { + reflection_probe->render_step=0; + reflection_probe_render_list.add(&reflection_probe->update_list); + } + + reflection_probe->reflection_dirty=false; + } + + if (VSG::scene_render->reflection_probe_instance_has_reflection(reflection_probe->instance)) { + reflection_probe_instance_cull_result[reflection_probe_cull_count]=reflection_probe->instance; + reflection_probe_cull_count++; + } + + } + } + } } else if ((1<<ins->base_type)&VS::INSTANCE_GEOMETRY_MASK && ins->visible && ins->cast_shadows!=VS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) { @@ -1746,6 +1850,7 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp InstanceGeometryData * geom = static_cast<InstanceGeometryData*>(ins->base_data); + if (geom->lighting_dirty) { int l=0; //only called when lights AABB enter/exit this geometry @@ -1761,7 +1866,23 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp geom->lighting_dirty=false; } + if (geom->reflection_dirty) { + int l=0; + //only called when reflection probe AABB enter/exit this geometry + ins->reflection_probe_instances.resize(geom->reflection_probes.size()); + + for (List<Instance*>::Element *E=geom->reflection_probes.front();E;E=E->next()) { + + InstanceReflectionProbeData * reflection_probe = static_cast<InstanceReflectionProbeData*>(E->get()->base_data); + + ins->reflection_probe_instances[l++]=reflection_probe->instance; + } + + geom->reflection_dirty=false; + } + ins->depth = near_plane.distance_to(ins->transform.origin); + ins->depth_layer=CLAMP(int(ins->depth*8/z_far),0,7); } @@ -1803,7 +1924,7 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp //check shadow.. - if (light && VSG::storage->light_has_shadow(E->get()->base)) { + if (light && p_shadow_atlas.is_valid() && VSG::storage->light_has_shadow(E->get()->base)) { lights_with_shadow[directional_shadow_count++]=E->get(); } @@ -1817,7 +1938,7 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp for(int i=0;i<directional_shadow_count;i++) { - _light_instance_update_shadow(lights_with_shadow[i],camera,p_shadow_atlas,scenario,p_viewport_size); + _light_instance_update_shadow(lights_with_shadow[i],p_cam_transform,p_cam_projection,p_cam_orthogonal,p_shadow_atlas,scenario); } } @@ -1841,12 +1962,12 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp { //compute coverage - Transform cam_xf = camera->transform; - float zn = camera_matrix.get_z_near(); + Transform cam_xf = p_cam_transform; + float zn = p_cam_projection.get_z_near(); Plane p (cam_xf.origin + cam_xf.basis.get_axis(2) * -zn, -cam_xf.basis.get_axis(2) ); //camera near plane float vp_w,vp_h; //near plane size in screen coordinates - camera_matrix.get_viewport_size(vp_w,vp_h); + p_cam_projection.get_viewport_size(vp_w,vp_h); switch(VSG::storage->light_get_type(ins->base)) { @@ -1861,7 +1982,7 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp ins->transform.origin+cam_xf.basis.get_axis(0)*radius }; - if (!ortho) { + if (!p_cam_orthogonal) { //if using perspetive, map them to near plane for(int j=0;j<2;j++) { if (p.distance_to(points[j]) < 0 ) { @@ -1895,7 +2016,7 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp base+cam_xf.basis.get_axis(0)*w }; - if (!ortho) { + if (!p_cam_orthogonal) { //if using perspetive, map them to near plane for(int j=0;j<2;j++) { if (p.distance_to(points[j]) < 0 ) { @@ -1933,7 +2054,7 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp if (redraw) { //must redraw! - _light_instance_update_shadow(ins,camera,p_shadow_atlas,scenario,p_viewport_size); + _light_instance_update_shadow(ins,p_cam_transform,p_cam_projection,p_cam_orthogonal,p_shadow_atlas,scenario); } } @@ -1942,8 +2063,8 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp /* ENVIRONMENT */ RID environment; - if (camera->env.is_valid()) //camera has more environment priority - environment=camera->env; + if (p_force_environment.is_valid()) //camera has more environment priority + environment=p_force_environment; else if (scenario->environment.is_valid()) environment=scenario->environment; else @@ -1964,45 +2085,129 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario,Size2 p_viewp #endif /* STEP 7 - PROCESS GEOMETRY AND DRAW SCENE*/ -#if 0 - // add lights + VSG::scene_render->render_scene(p_cam_transform, p_cam_projection,p_cam_orthogonal,(RasterizerScene::InstanceBase**)instance_cull_result,cull_count,light_instance_cull_result,light_cull_count+directional_light_count,reflection_probe_instance_cull_result,reflection_probe_cull_count,environment,p_shadow_atlas,scenario->reflection_atlas,p_reflection_probe,p_reflection_probe_pass); - { - List<RID>::Element *E=p_scenario->directional_lights.front(); +} - for(;E;E=E->next()) { - Instance *light = E->get().is_valid()?instance_owner.get(E->get()):NULL; +bool VisualServerScene::_render_probe_step(Instance* p_instance,int p_step) { - ERR_CONTINUE(!light); - if (!light->light_info->enabled) - continue; + InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData*>(p_instance->base_data); + Scenario *scenario = p_instance->scenario; + ERR_FAIL_COND_V(!scenario,true); - rasterizer->add_light(light->light_info->instance); - light->light_info->last_add_pass=render_pass; + if (p_step==0) { + + if (!VSG::scene_render->reflection_probe_instance_begin_render(reflection_probe->instance,scenario->reflection_atlas)) { + return true; //sorry, all full :( } + } - for (int i=0;i<light_cull_count;i++) { + if (p_step>=0 && p_step<6) { - Instance *ins = light_cull_result[i]; - rasterizer->add_light(ins->light_info->instance); - ins->light_info->last_add_pass=render_pass; + static const Vector3 view_normals[6]={ + Vector3(-1, 0, 0), + Vector3(+1, 0, 0), + Vector3( 0,-1, 0), + Vector3( 0,+1, 0), + Vector3( 0, 0,-1), + Vector3( 0, 0,+1) + }; + + Vector3 extents = VSG::storage->reflection_probe_get_extents(p_instance->base); + Vector3 origin_offset = VSG::storage->reflection_probe_get_origin_offset(p_instance->base); + float max_distance = VSG::storage->reflection_probe_get_origin_max_distance(p_instance->base); + + + Vector3 edge = view_normals[p_step]*extents; + float distance = ABS(view_normals[p_step].dot(edge)-view_normals[p_step].dot(origin_offset)); //distance from origin offset to actual view distance limit + + max_distance = MAX(max_distance,distance); + + + //render cubemap side + CameraMatrix cm; + cm.set_perspective(90,1,0.01,max_distance); + + + static const Vector3 view_up[6]={ + Vector3( 0,-1, 0), + Vector3( 0,-1, 0), + Vector3( 0, 0,-1), + Vector3( 0, 0,+1), + Vector3( 0,-1, 0), + Vector3( 0,-1, 0) + }; + + Transform local_view; + local_view.set_look_at(origin_offset,origin_offset+view_normals[p_step],view_up[p_step]); + + Transform xform = p_instance->transform * local_view; + + RID shadow_atlas; + + if (VSG::storage->reflection_probe_renders_shadows(p_instance->base)) { + + shadow_atlas=scenario->reflection_probe_shadow_atlas; } + + _render_scene(xform,cm,false,RID(),VSG::storage->reflection_probe_get_cull_mask(p_instance->base),p_instance->scenario->self,shadow_atlas,reflection_probe->instance,p_step); + + } else { + //do roughness postprocess step until it belives it's done + return VSG::scene_render->reflection_probe_instance_postprocess_step(reflection_probe->instance); } - // add geometry -#endif + return false; +} - VSG::scene_render->render_scene(camera->transform, camera_matrix,ortho,(RasterizerScene::InstanceBase**)instance_cull_result,cull_count,light_instance_cull_result,light_cull_count+directional_light_count,environment,p_shadow_atlas); +void VisualServerScene::render_probes() { -} + SelfList<InstanceReflectionProbeData> *probe = reflection_probe_render_list.first(); + bool busy=false; + while(probe) { -void VisualServerScene::_update_dirty_instance(Instance *p_instance) { + SelfList<InstanceReflectionProbeData> *next=probe->next(); + RID base = probe->self()->owner->base; + switch(VSG::storage->reflection_probe_get_update_mode(base)) { + + case VS::REFLECTION_PROBE_UPDATE_ONCE: { + if (busy) //already rendering something + break; + + bool done = _render_probe_step(probe->self()->owner,probe->self()->render_step); + if (done) { + reflection_probe_render_list.remove(probe); + } else { + probe->self()->render_step++; + } + + busy=true; //do not render another one of this kind + } break; + case VS::REFLECTION_PROBE_UPDATE_ALWAYS: { + + int step=0; + bool done=false; + while(!done) { + done = _render_probe_step(probe->self()->owner,step); + step++; + } + + reflection_probe_render_list.remove(probe); + } break; + + } + + probe=next; + } +} + +void VisualServerScene::_update_dirty_instance(Instance *p_instance) { if (p_instance->update_aabb) _update_instance_aabb(p_instance); @@ -2114,7 +2319,8 @@ bool VisualServerScene::free(RID p_rid) { while(scenario->instances.first()) { instance_set_scenario(scenario->instances.first()->self()->self,RID()); } - + VSG::scene_render->free(scenario->reflection_probe_shadow_atlas); + VSG::scene_render->free(scenario->reflection_atlas); scenario_owner.free(p_rid); memdelete(scenario); diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h index e4f06fee64..0eaad45c97 100644 --- a/servers/visual/visual_server_scene.h +++ b/servers/visual/visual_server_scene.h @@ -16,8 +16,9 @@ public: MAX_INSTANCE_CULL=65536, MAX_LIGHTS_CULLED=4096, + MAX_REFLECTION_PROBES_CULLED=4096, MAX_ROOM_CULL=32, - MAX_EXTERIOR_PORTALS=128, + MAX_EXTERIOR_PORTALS=128, }; uint64_t render_pass; @@ -156,6 +157,9 @@ public: List<Instance*> directional_lights; RID environment; RID fallback_environment; + RID reflection_probe_shadow_atlas; + RID reflection_atlas; + SelfList<Instance>::List instances; @@ -172,6 +176,7 @@ public: virtual void scenario_set_debug(RID p_scenario,VS::ScenarioDebugMode p_debug_mode); virtual void scenario_set_environment(RID p_scenario, RID p_environment); virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment); + virtual void scenario_set_reflection_atlas_size(RID p_scenario, int p_size,int p_subdiv); /* INSTANCING API */ @@ -288,13 +293,43 @@ public: bool lighting_dirty; bool can_cast_shadows; + List<Instance*> reflection_probes; + bool reflection_dirty; + InstanceGeometryData() { lighting_dirty=false; + reflection_dirty=true; can_cast_shadows=true; } }; + struct InstanceReflectionProbeData : public InstanceBaseData { + + + Instance *owner; + + struct PairInfo { + List<Instance*>::Element *L; //light iterator in geometry + Instance *geometry; + }; + List<PairInfo> geometries; + + + RID instance; + bool reflection_dirty; + SelfList<InstanceReflectionProbeData> update_list; + + int render_step; + + InstanceReflectionProbeData() : update_list(this) { + + reflection_dirty=true; + render_step=-1; + } + }; + + SelfList<InstanceReflectionProbeData>::List reflection_probe_render_list; struct InstanceLightData : public InstanceBaseData { @@ -325,6 +360,8 @@ public: Instance *light_cull_result[MAX_LIGHTS_CULLED]; RID light_instance_cull_result[MAX_LIGHTS_CULLED]; int light_cull_count; + RID reflection_probe_instance_cull_result[MAX_REFLECTION_PROBES_CULLED]; + int reflection_probe_cull_count; RID_Owner<Instance> instance_owner; @@ -366,10 +403,15 @@ public: _FORCE_INLINE_ void _update_instance_aabb(Instance *p_instance); _FORCE_INLINE_ void _update_dirty_instance(Instance *p_instance); - _FORCE_INLINE_ void _light_instance_update_shadow(Instance *p_instance,Camera* p_camera,RID p_shadow_atlas,Scenario* p_scenario,Size2 p_viewport_rect); + _FORCE_INLINE_ void _light_instance_update_shadow(Instance *p_instance,const Transform p_cam_transform,const CameraMatrix& p_cam_projection,bool p_cam_orthogonal,RID p_shadow_atlas,Scenario* p_scenario); - void render_camera(RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas); + void _render_scene(const Transform p_cam_transform, const CameraMatrix& p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass); + + void render_camera(RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas); void update_dirty_instances(); + + bool _render_probe_step(Instance* p_instance,int p_step); + void render_probes(); bool free(RID p_rid); VisualServerScene(); diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp index 18742aa21d..fa2c461f36 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -520,26 +520,29 @@ void VisualServerViewport::viewport_set_shadow_atlas_quadrant_subdivision(RID p_ bool VisualServerViewport::free(RID p_rid) { - Viewport * viewport = viewport_owner.getornull(p_rid); - if (!viewport) - return false; + if (viewport_owner.owns(p_rid)) { + Viewport * viewport = viewport_owner.getornull(p_rid); - VSG::storage->free( viewport->render_target ); - VSG::scene_render->free( viewport->shadow_atlas ); - while(viewport->canvas_map.front()) { - viewport_remove_canvas(p_rid,viewport->canvas_map.front()->key()); - } + VSG::storage->free( viewport->render_target ); + VSG::scene_render->free( viewport->shadow_atlas ); + + while(viewport->canvas_map.front()) { + viewport_remove_canvas(p_rid,viewport->canvas_map.front()->key()); + } - viewport_set_scenario(p_rid,RID()); - active_viewports.erase(viewport); + viewport_set_scenario(p_rid,RID()); + active_viewports.erase(viewport); + + viewport_owner.free(p_rid); + memdelete(viewport); - viewport_owner.free(p_rid); - memdelete(viewport); + return true; + } - return true; + return false; } diff --git a/servers/visual_server.h b/servers/visual_server.h index 148d090a07..5e318a4fe8 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -127,8 +127,6 @@ public: virtual void texture_set_shrink_all_x2_on_set_data(bool p_enable)=0; - virtual RID texture_create_radiance_cubemap(RID p_source,int p_resolution=-1) const=0; - struct TextureInfo { RID texture; Size2 size; @@ -139,6 +137,10 @@ public: virtual void texture_debug_usage(List<TextureInfo> *r_info)=0; + /* SKYBOX API */ + + virtual RID skybox_create()=0; + virtual void skybox_set_texture(RID p_skybox,RID p_cube_map,int p_radiance_size)=0; /* SHADER API */ @@ -406,14 +408,23 @@ public: virtual RID reflection_probe_create()=0; + enum ReflectionProbeUpdateMode { + REFLECTION_PROBE_UPDATE_ONCE, + REFLECTION_PROBE_UPDATE_ALWAYS, + }; + + + virtual void reflection_probe_set_update_mode(RID p_probe, ReflectionProbeUpdateMode p_mode)=0; virtual void reflection_probe_set_intensity(RID p_probe, float p_intensity)=0; - virtual void reflection_probe_set_clip(RID p_probe, float p_near, float p_far)=0; - virtual void reflection_probe_set_min_blend_distance(RID p_probe, float p_distance)=0; + virtual void reflection_probe_set_interior_ambient(RID p_probe, const Color& p_color)=0; + virtual void reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy)=0; + virtual void reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib)=0; + virtual void reflection_probe_set_max_distance(RID p_probe, float p_distance)=0; virtual void reflection_probe_set_extents(RID p_probe, const Vector3& p_extents)=0; virtual void reflection_probe_set_origin_offset(RID p_probe, const Vector3& p_offset)=0; - virtual void reflection_probe_set_enable_parallax_correction(RID p_probe, bool p_enable)=0; - virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution)=0; - virtual void reflection_probe_set_hide_skybox(RID p_probe, bool p_hide)=0; + virtual void reflection_probe_set_as_interior(RID p_probe, bool p_enable)=0; + virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable)=0; + virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable)=0; virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers)=0; @@ -514,7 +525,7 @@ public: }; virtual void environment_set_background(RID p_env,EnvironmentBG p_bg)=0; - virtual void environment_set_skybox(RID p_env,RID p_skybox,int p_radiance_size)=0; + virtual void environment_set_skybox(RID p_env,RID p_skybox)=0; virtual void environment_set_skybox_scale(RID p_env,float p_scale)=0; virtual void environment_set_bg_color(RID p_env,const Color& p_color)=0; virtual void environment_set_bg_energy(RID p_env,float p_energy)=0; @@ -563,6 +574,7 @@ public: virtual void scenario_set_debug(RID p_scenario,ScenarioDebugMode p_debug_mode)=0; virtual void scenario_set_environment(RID p_scenario, RID p_environment)=0; + virtual void scenario_set_reflection_atlas_size(RID p_scenario, int p_size,int p_subdiv)=0; virtual void scenario_set_fallback_environment(RID p_scenario, RID p_environment)=0; diff --git a/tools/editor/spatial_editor_gizmos.cpp b/tools/editor/spatial_editor_gizmos.cpp index cdd56bbac5..a4a1aaedf0 100644 --- a/tools/editor/spatial_editor_gizmos.cpp +++ b/tools/editor/spatial_editor_gizmos.cpp @@ -245,6 +245,7 @@ void EditorSpatialGizmo::add_handles(const Vector<Vector3> &p_handles, bool p_bi Array a; a.resize(VS::ARRAY_MAX); a[VS::ARRAY_VERTEX]=p_handles; + print_line("handles?: "+itos(p_handles.size())); DVector<Color> colors; { colors.resize(p_handles.size()); @@ -2238,6 +2239,164 @@ VisibilityNotifierGizmo::VisibilityNotifierGizmo(VisibilityNotifier* p_notifier) //////// +/// + + +String ReflectionProbeGizmo::get_handle_name(int p_idx) const { + + switch(p_idx) { + case 0: return "Extents X"; + case 1: return "Extents Y"; + case 2: return "Extents Z"; + case 3: return "Origin X"; + case 4: return "Origin Y"; + case 5: return "Origin Z"; + } + + return ""; +} +Variant ReflectionProbeGizmo::get_handle_value(int p_idx) const{ + + return AABB(probe->get_extents(),probe->get_origin_offset()); +} +void ReflectionProbeGizmo::set_handle(int p_idx,Camera *p_camera, const Point2& p_point){ + + Transform gt = probe->get_global_transform(); + //gt.orthonormalize(); + Transform gi = gt.affine_inverse(); + + + if (p_idx<3) { + Vector3 extents = probe->get_extents(); + + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2]={gi.xform(ray_from),gi.xform(ray_from+ray_dir*16384)}; + + Vector3 axis; + axis[p_idx]=1.0; + + Vector3 ra,rb; + Geometry::get_closest_points_between_segments(Vector3(),axis*16384,sg[0],sg[1],ra,rb); + float d = ra[p_idx]; + if (d<0.001) + d=0.001; + + extents[p_idx]=d; + probe->set_extents(extents); + } else { + + p_idx-=3; + + Vector3 origin = probe->get_origin_offset(); + origin[p_idx]=0; + + Vector3 ray_from = p_camera->project_ray_origin(p_point); + Vector3 ray_dir = p_camera->project_ray_normal(p_point); + + Vector3 sg[2]={gi.xform(ray_from),gi.xform(ray_from+ray_dir*16384)}; + + Vector3 axis; + axis[p_idx]=1.0; + + Vector3 ra,rb; + Geometry::get_closest_points_between_segments(origin-axis*16384,origin+axis*16384,sg[0],sg[1],ra,rb); + float d = ra[p_idx]; + d+=0.25; + + origin[p_idx]=d; + probe->set_origin_offset(origin); + + } +} + +void ReflectionProbeGizmo::commit_handle(int p_idx,const Variant& p_restore,bool p_cancel){ + + AABB restore = p_restore; + + if (p_cancel) { + probe->set_extents(restore.pos); + probe->set_origin_offset(restore.size); + return; + } + + UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo(); + ur->create_action(TTR("Change Probe Extents")); + ur->add_do_method(probe,"set_extents",probe->get_extents()); + ur->add_do_method(probe,"set_origin_offset",probe->get_origin_offset()); + ur->add_undo_method(probe,"set_extents",restore.pos); + ur->add_undo_method(probe,"set_origin_offset",restore.size); + ur->commit_action(); + +} + +void ReflectionProbeGizmo::redraw(){ + + clear(); + + Vector<Vector3> lines; + Vector<Vector3> internal_lines; + Vector3 extents = probe->get_extents(); + + AABB aabb; + aabb.pos=-extents; + aabb.size=extents*2; + + for(int i=0;i<12;i++) { + Vector3 a,b; + aabb.get_edge(i,a,b); + lines.push_back(a); + lines.push_back(b); + } + + for(int i=0;i<8;i++) { + Vector3 ep = aabb.get_endpoint(i); + internal_lines.push_back(probe->get_origin_offset()); + internal_lines.push_back(ep); + + + } + + Vector<Vector3> handles; + + + for(int i=0;i<3;i++) { + + Vector3 ax; + ax[i]=aabb.pos[i]+aabb.size[i]; + handles.push_back(ax); + } + + for(int i=0;i<3;i++) { + + + Vector3 orig_handle=probe->get_origin_offset(); + orig_handle[i]-=0.25; + lines.push_back(orig_handle); + handles.push_back(orig_handle); + + orig_handle[i]+=0.5; + lines.push_back(orig_handle); + } + + add_lines(lines,SpatialEditorGizmos::singleton->reflection_probe_material); + add_lines(internal_lines,SpatialEditorGizmos::singleton->reflection_probe_material_internal); + //add_unscaled_billboard(SpatialEditorGizmos::singleton->visi,0.05); + add_collision_segments(lines); + add_handles(handles); + +} +ReflectionProbeGizmo::ReflectionProbeGizmo(ReflectionProbe* p_probe){ + + probe=p_probe; + set_spatial_node(p_probe); +} + +//////// + + + void NavigationMeshSpatialGizmo::redraw() { @@ -2929,6 +3088,12 @@ Ref<SpatialEditorGizmo> SpatialEditorGizmos::get_gizmo(Spatial *p_spatial) { return misg; } + if (p_spatial->cast_to<ReflectionProbe>()) { + + Ref<ReflectionProbeGizmo> misg = memnew( ReflectionProbeGizmo(p_spatial->cast_to<ReflectionProbe>()) ); + return misg; + } + if (p_spatial->cast_to<VehicleWheel>()) { Ref<VehicleWheelSpatialGizmo> misg = memnew( VehicleWheelSpatialGizmo(p_spatial->cast_to<VehicleWheel>()) ); @@ -3132,6 +3297,8 @@ SpatialEditorGizmos::SpatialEditorGizmos() { raycast_material = create_line_material(Color(1.0,0.8,0.6)); car_wheel_material = create_line_material(Color(0.6,0.8,1.0)); visibility_notifier_material = create_line_material(Color(1.0,0.5,1.0)); + reflection_probe_material = create_line_material(Color(0.5,1.0,0.7)); + reflection_probe_material_internal = create_line_material(Color(0.3,0.8,0.5,0.4)); joint_material = create_line_material(Color(0.6,0.8,1.0)); stream_player_icon = Ref<FixedSpatialMaterial>( memnew( FixedSpatialMaterial )); diff --git a/tools/editor/spatial_editor_gizmos.h b/tools/editor/spatial_editor_gizmos.h index 2c0033cdca..2cc1a7eab8 100644 --- a/tools/editor/spatial_editor_gizmos.h +++ b/tools/editor/spatial_editor_gizmos.h @@ -45,6 +45,7 @@ #include "scene/3d/portal.h" #include "scene/3d/ray_cast.h" #include "scene/3d/navigation_mesh.h" +#include "scene/3d/reflection_probe.h" #include "scene/3d/vehicle_body.h" #include "scene/3d/collision_polygon.h" @@ -307,6 +308,25 @@ public: }; +class ReflectionProbeGizmo : public EditorSpatialGizmo { + + OBJ_TYPE(ReflectionProbeGizmo ,EditorSpatialGizmo); + + + ReflectionProbe* probe; + +public: + + virtual String get_handle_name(int p_idx) const; + virtual Variant get_handle_value(int p_idx) const; + virtual void set_handle(int p_idx,Camera *p_camera, const Point2& p_point); + virtual void commit_handle(int p_idx,const Variant& p_restore,bool p_cancel=false); + + void redraw(); + ReflectionProbeGizmo(ReflectionProbe* p_notifier=NULL); + +}; + class CollisionShapeSpatialGizmo : public EditorSpatialGizmo { @@ -339,6 +359,7 @@ public: }; + class RayCastSpatialGizmo : public EditorSpatialGizmo { OBJ_TYPE(RayCastSpatialGizmo,EditorSpatialGizmo); @@ -473,6 +494,8 @@ public: Ref<FixedSpatialMaterial> light_material_directional_icon; Ref<FixedSpatialMaterial> camera_material; Ref<FixedSpatialMaterial> skeleton_material; + Ref<FixedSpatialMaterial> reflection_probe_material; + Ref<FixedSpatialMaterial> reflection_probe_material_internal; Ref<FixedSpatialMaterial> room_material; Ref<FixedSpatialMaterial> portal_material; Ref<FixedSpatialMaterial> raycast_material; |