working reflection probes!!
This commit is contained in:
parent
a7078a4be9
commit
c39d2b3f42
25 changed files with 2605 additions and 240 deletions
|
@ -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]) {
|
||||
|
|
|
@ -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){
|
||||
|
|
|
@ -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) {
|
||||
|
||||
RasterizerStorageGLES3::Texture *tex = storage->texture_owner.getornull(p_skybox);
|
||||
if (!p_skybox)
|
||||
return;
|
||||
|
||||
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);
|
||||
|
||||
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() {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
||||
|
@ -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_min_blend_distance(RID p_probe, float p_distance){
|
||||
|
||||
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_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() {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
#ifdef USE_RADIANCE_CUBEMAP
|
||||
|
||||
uniform sampler2D brdf_texture; //texunit:-1
|
||||
uniform samplerCube radiance_cube; //texunit:-2
|
||||
|
||||
#ifdef USE_RADIANCE_MAP
|
||||
|
||||
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
|
||||
|
||||
|
|
266
scene/3d/reflection_probe.cpp
Normal file
266
scene/3d/reflection_probe.cpp
Normal file
|
@ -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);
|
||||
}
|
92
scene/3d/reflection_probe.h
Normal file
92
scene/3d/reflection_probe.h
Normal file
|
@ -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
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -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") );
|
||||
|
|
|
@ -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;
|
||||
|
|
158
scene/resources/sky_box.cpp
Normal file
158
scene/resources/sky_box.cpp
Normal file
|
@ -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);
|
||||
}
|
||||
|
71
scene/resources/sky_box.h
Normal file
71
scene/resources/sky_box.h
Normal file
|
@ -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
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 )
|
||||
|
||||
|
||||
|
|
|
@ -102,9 +102,26 @@ 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,46 +2085,130 @@ 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
|
||||
|
||||
{
|
||||
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;
|
||||
|
||||
ERR_CONTINUE(!light);
|
||||
if (!light->light_info->enabled)
|
||||
continue;
|
||||
|
||||
rasterizer->add_light(light->light_info->instance);
|
||||
light->light_info->last_add_pass=render_pass;
|
||||
}
|
||||
|
||||
for (int i=0;i<light_cull_count;i++) {
|
||||
|
||||
Instance *ins = light_cull_result[i];
|
||||
rasterizer->add_light(ins->light_info->instance);
|
||||
ins->light_info->last_add_pass=render_pass;
|
||||
}
|
||||
}
|
||||
// add geometry
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
|
||||
}
|
||||
|
||||
bool VisualServerScene::_render_probe_step(Instance* p_instance,int p_step) {
|
||||
|
||||
InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData*>(p_instance->base_data);
|
||||
Scenario *scenario = p_instance->scenario;
|
||||
ERR_FAIL_COND_V(!scenario,true);
|
||||
|
||||
if (p_step==0) {
|
||||
|
||||
if (!VSG::scene_render->reflection_probe_instance_begin_render(reflection_probe->instance,scenario->reflection_atlas)) {
|
||||
return true; //sorry, all full :(
|
||||
}
|
||||
}
|
||||
|
||||
if (p_step>=0 && p_step<6) {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void VisualServerScene::render_probes() {
|
||||
|
||||
|
||||
SelfList<InstanceReflectionProbeData> *probe = reflection_probe_render_list.first();
|
||||
|
||||
bool busy=false;
|
||||
|
||||
while(probe) {
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ public:
|
|||
|
||||
MAX_INSTANCE_CULL=65536,
|
||||
MAX_LIGHTS_CULLED=4096,
|
||||
MAX_REFLECTION_PROBES_CULLED=4096,
|
||||
MAX_ROOM_CULL=32,
|
||||
MAX_EXTERIOR_PORTALS=128,
|
||||
};
|
||||
|
@ -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_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();
|
||||
|
|
|
@ -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 );
|
||||
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());
|
||||
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_owner.free(p_rid);
|
||||
memdelete(viewport);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
viewport_set_scenario(p_rid,RID());
|
||||
active_viewports.erase(viewport);
|
||||
|
||||
viewport_owner.free(p_rid);
|
||||
memdelete(viewport);
|
||||
|
||||
|
||||
return true;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
@ -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 ));
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue