Reflection probe support in GLES2 back-end.

This commit is contained in:
Juan Linietsky 2018-09-28 16:40:20 -03:00
parent 40c3c8745d
commit f2ed26d71e
16 changed files with 937 additions and 36 deletions

View File

@ -517,6 +517,7 @@ public:
void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) {} void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) {}
void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) {} void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) {}
void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) {} void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) {}
void reflection_probe_set_resolution(RID p_probe, int p_resolution) {}
AABB reflection_probe_get_aabb(RID p_probe) const { return AABB(); } AABB reflection_probe_get_aabb(RID p_probe) const { return AABB(); }
VS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const { return VisualServer::REFLECTION_PROBE_UPDATE_ONCE; } VS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const { return VisualServer::REFLECTION_PROBE_UPDATE_ONCE; }

View File

@ -437,29 +437,182 @@ void RasterizerSceneGLES2::reflection_atlas_set_subdivision(RID p_ref_atlas, int
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
RID RasterizerSceneGLES2::reflection_probe_instance_create(RID p_probe) { RID RasterizerSceneGLES2::reflection_probe_instance_create(RID p_probe) {
return RID();
RasterizerStorageGLES2::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;
rpi->current_resolution = 0;
rpi->dirty = true;
rpi->last_pass = 0;
rpi->index = 0;
for (int i = 0; i < 6; i++) {
glGenFramebuffers(1, &rpi->fbo[i]);
}
glGenFramebuffers(1, &rpi->fbo_blur);
glGenRenderbuffers(1, &rpi->depth);
glGenTextures(1, &rpi->cubemap);
return rpi->self;
} }
void RasterizerSceneGLES2::reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) { void RasterizerSceneGLES2::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 RasterizerSceneGLES2::reflection_probe_release_atlas_index(RID p_instance) { void RasterizerSceneGLES2::reflection_probe_release_atlas_index(RID p_instance) {
} }
bool RasterizerSceneGLES2::reflection_probe_instance_needs_redraw(RID p_instance) { bool RasterizerSceneGLES2::reflection_probe_instance_needs_redraw(RID p_instance) {
return false; const ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
ERR_FAIL_COND_V(!rpi, false);
bool need_redraw = rpi->probe_ptr->resolution != rpi->current_resolution || rpi->dirty || rpi->probe_ptr->update_mode == VS::REFLECTION_PROBE_UPDATE_ALWAYS;
rpi->dirty = false;
return need_redraw;
} }
bool RasterizerSceneGLES2::reflection_probe_instance_has_reflection(RID p_instance) { bool RasterizerSceneGLES2::reflection_probe_instance_has_reflection(RID p_instance) {
return false; return true;
} }
bool RasterizerSceneGLES2::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) { bool RasterizerSceneGLES2::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) {
return false;
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
ERR_FAIL_COND_V(!rpi, false);
rpi->render_step = 0;
if (rpi->probe_ptr->resolution != rpi->current_resolution) {
//update cubemap if resolution changed
int size = rpi->probe_ptr->resolution;
rpi->current_resolution = size;
int lod = 0;
GLenum internal_format = GL_RGBA;
GLenum format = GL_RGBA;
GLenum type = GL_UNSIGNED_BYTE;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, rpi->cubemap);
// Set the initial (empty) mipmaps, all need to be set for this to work in GLES2, even if later wont be used.
while (size >= 1) {
for (int i = 0; i < 6; i++) {
glTexImage2D(_cube_side_enum[i], lod, internal_format, size, size, 0, format, type, NULL);
if (size == rpi->current_resolution) {
//adjust framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, rpi->fbo[i]);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], rpi->cubemap, 0);
glBindRenderbuffer(GL_RENDERBUFFER, rpi->depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size, size);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rpi->depth);
#ifdef DEBUG_ENABLED
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
ERR_CONTINUE(status != GL_FRAMEBUFFER_COMPLETE);
#endif
}
}
lod++;
size >>= 1;
}
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
return true;
} }
bool RasterizerSceneGLES2::reflection_probe_instance_postprocess_step(RID p_instance) { bool RasterizerSceneGLES2::reflection_probe_instance_postprocess_step(RID p_instance) {
return false;
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
ERR_FAIL_COND_V(!rpi, false);
int size = rpi->probe_ptr->resolution;
{
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glDisable(GL_SCISSOR_TEST);
glDisable(GL_BLEND);
glDepthMask(GL_FALSE);
for (int i = 0; i < VS::ARRAY_MAX - 1; i++) {
glDisableVertexAttribArray(i);
}
}
//vdc cache
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, storage->resources.radical_inverse_vdc_cache_tex);
glBindFramebuffer(GL_FRAMEBUFFER, rpi->fbo_blur);
// now render to the framebuffer, mipmap level for mipmap level
int lod = 1;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, rpi->cubemap);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); //use linear, no mipmaps so it does not read from what is being written to
size >>= 1;
int mipmaps = 6;
int mm_level = mipmaps - 1;
storage->shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, false);
storage->shaders.cubemap_filter.bind();
//blur
while (size >= 1) {
for (int i = 0; i < 6; i++) {
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], rpi->cubemap, lod);
glViewport(0, 0, size, size);
storage->bind_quad_array();
storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::FACE_ID, i);
float roughness = CLAMP(lod / (float)(mipmaps - 1), 0, 1);
storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::ROUGHNESS, roughness);
storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::Z_FLIP, false);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
size >>= 1;
mm_level--;
lod++;
}
// restore ranges
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return true;
} }
/* ENVIRONMENT API */ /* ENVIRONMENT API */
@ -779,17 +932,37 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G
e->material_index = e->material->index; e->material_index = e->material->index;
e->refprobe_0_index = 0xFF; //refprobe disabled by default e->refprobe_0_index = RenderList::MAX_REFLECTION_PROBES; //refprobe disabled by default
e->refprobe_1_index = 0xFF; //refprobe disabled by default e->refprobe_1_index = RenderList::MAX_REFLECTION_PROBES; //refprobe disabled by default
if (!p_depth_pass) { if (!p_depth_pass) {
e->depth_layer = e->instance->depth_layer; e->depth_layer = e->instance->depth_layer;
e->priority = p_material->render_priority; e->priority = p_material->render_priority;
//if (e->instance->reflection_probe_instances.size() > 0 ) { int rpsize = e->instance->reflection_probe_instances.size();
// RasterizerStorageGLES2:: if (rpsize > 0) {
//} bool first = true;
for (int i = 0; i < rpsize; i++) {
ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(e->instance->reflection_probe_instances[i]);
if (rpi->last_pass != render_pass) {
continue;
}
if (first) {
e->refprobe_0_index = rpi->index;
first = false;
} else {
e->refprobe_1_index = rpi->index;
break;
}
}
if (e->refprobe_0_index > e->refprobe_1_index) { //if both are valid, swap them to keep order as best as possible
uint16_t tmp = e->refprobe_0_index;
e->refprobe_0_index = e->refprobe_1_index;
e->refprobe_1_index = tmp;
}
}
//add directional lights //add directional lights
@ -1505,7 +1678,7 @@ void RasterizerSceneGLES2::_setup_light_type(LightInstance *p_light, ShadowAtlas
} }
state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, p_light->light_ptr->directional_blend_splits); state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, p_light->light_ptr->directional_blend_splits);
if (p_light->light_ptr->shadow) { if (!state.render_no_shadows && p_light->light_ptr->shadow) {
state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true); state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true);
glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3);
glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); glBindTexture(GL_TEXTURE_2D, directional_shadow.depth);
@ -1517,7 +1690,7 @@ void RasterizerSceneGLES2::_setup_light_type(LightInstance *p_light, ShadowAtlas
case VS::LIGHT_OMNI: { case VS::LIGHT_OMNI: {
state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_OMNI, true); state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_OMNI, true);
if (shadow_atlas && p_light->light_ptr->shadow) { if (!state.render_no_shadows && shadow_atlas && p_light->light_ptr->shadow) {
state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true); state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true);
glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3);
glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth);
@ -1528,7 +1701,7 @@ void RasterizerSceneGLES2::_setup_light_type(LightInstance *p_light, ShadowAtlas
case VS::LIGHT_SPOT: { case VS::LIGHT_SPOT: {
state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_SPOT, true); state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_SPOT, true);
if (shadow_atlas && p_light->light_ptr->shadow) { if (!state.render_no_shadows && shadow_atlas && p_light->light_ptr->shadow) {
state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true); state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true);
glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3);
glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth);
@ -1562,7 +1735,7 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado
CameraMatrix matrices[4]; CameraMatrix matrices[4];
if (light_ptr->shadow && directional_shadow.depth) { if (!state.render_no_shadows && light_ptr->shadow && directional_shadow.depth) {
int shadow_count = 0; int shadow_count = 0;
Color split_offsets; Color split_offsets;
@ -1657,7 +1830,7 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado
attenuation.a = light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; attenuation.a = light_ptr->param[VS::LIGHT_PARAM_ATTENUATION];
state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ATTENUATION, attenuation); state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ATTENUATION, attenuation);
if (light_ptr->shadow && shadow_atlas->shadow_owners.has(light->self)) { if (!state.render_no_shadows && light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(light->self)) {
uint32_t key = shadow_atlas->shadow_owners[light->self]; uint32_t key = shadow_atlas->shadow_owners[light->self];
@ -1719,7 +1892,7 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado
state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPOT_ANGLE, angle); state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPOT_ANGLE, angle);
state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_RANGE, range); state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_RANGE, range);
if (light->light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(light->self)) { if (!state.render_no_shadows && light->light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(light->self)) {
uint32_t key = shadow_atlas->shadow_owners[light->self]; uint32_t key = shadow_atlas->shadow_owners[light->self];
uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x03; uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x03;
@ -1768,13 +1941,60 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado
} }
} }
void RasterizerSceneGLES2::_setup_refprobes(ReflectionProbeInstance *p_refprobe1, ReflectionProbeInstance *p_refprobe2, const Transform &p_view_transform, Environment *p_env) {
if (p_refprobe1) {
state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_USE_BOX_PROJECT, p_refprobe1->probe_ptr->box_projection);
state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_BOX_EXTENTS, p_refprobe1->probe_ptr->extents);
state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_BOX_OFFSET, p_refprobe1->probe_ptr->origin_offset);
state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_EXTERIOR, !p_refprobe1->probe_ptr->interior);
state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_INTENSITY, p_refprobe1->probe_ptr->intensity);
Color ambient;
if (p_refprobe1->probe_ptr->interior) {
ambient = p_refprobe1->probe_ptr->interior_ambient * p_refprobe1->probe_ptr->interior_ambient_energy;
ambient.a = p_refprobe1->probe_ptr->interior_ambient_probe_contrib;
} else if (p_env) {
ambient = p_env->ambient_color * p_env->ambient_energy;
ambient.a = p_env->ambient_sky_contribution;
}
state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_AMBIENT, ambient);
Transform proj = (p_view_transform.inverse() * p_refprobe1->transform).affine_inverse();
state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_LOCAL_MATRIX, proj);
}
if (p_refprobe2) {
state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_USE_BOX_PROJECT, p_refprobe2->probe_ptr->box_projection);
state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_BOX_EXTENTS, p_refprobe2->probe_ptr->extents);
state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_BOX_OFFSET, p_refprobe2->probe_ptr->origin_offset);
state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_EXTERIOR, !p_refprobe2->probe_ptr->interior);
state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_INTENSITY, p_refprobe2->probe_ptr->intensity);
Color ambient;
if (p_refprobe2->probe_ptr->interior) {
ambient = p_refprobe2->probe_ptr->interior_ambient * p_refprobe2->probe_ptr->interior_ambient_energy;
ambient.a = p_refprobe2->probe_ptr->interior_ambient_probe_contrib;
} else if (p_env) {
ambient = p_env->ambient_color * p_env->ambient_energy;
ambient.a = p_env->ambient_sky_contribution;
}
state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_AMBIENT, ambient);
Transform proj = (p_view_transform.inverse() * p_refprobe2->transform).affine_inverse();
state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_LOCAL_MATRIX, proj);
}
}
void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, int p_element_count, const Transform &p_view_transform, const CameraMatrix &p_projection, RID p_shadow_atlas, Environment *p_env, GLuint p_base_env, float p_shadow_bias, float p_shadow_normal_bias, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow) { void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, int p_element_count, const Transform &p_view_transform, const CameraMatrix &p_projection, RID p_shadow_atlas, Environment *p_env, GLuint p_base_env, float p_shadow_bias, float p_shadow_normal_bias, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow) {
ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas);
Vector2 screen_pixel_size; Vector2 screen_pixel_size = state.screen_pixel_size;
screen_pixel_size.x = 1.0 / storage->frame.current_rt->width;
screen_pixel_size.y = 1.0 / storage->frame.current_rt->height;
bool use_radiance_map = false; bool use_radiance_map = false;
if (!p_shadow && p_base_env) { if (!p_shadow && p_base_env) {
@ -1797,6 +2017,8 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
bool prev_base_pass = false; bool prev_base_pass = false;
LightInstance *prev_light = NULL; LightInstance *prev_light = NULL;
bool prev_vertex_lit = false; bool prev_vertex_lit = false;
ReflectionProbeInstance *prev_refprobe_1 = NULL;
ReflectionProbeInstance *prev_refprobe_2 = NULL;
int prev_blend_mode = -2; //will always catch the first go int prev_blend_mode = -2; //will always catch the first go
@ -1815,6 +2037,8 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
bool accum_pass = *e->use_accum_ptr; bool accum_pass = *e->use_accum_ptr;
*e->use_accum_ptr = true; //set to accum for next time this is found *e->use_accum_ptr = true; //set to accum for next time this is found
LightInstance *light = NULL; LightInstance *light = NULL;
ReflectionProbeInstance *refprobe_1 = NULL;
ReflectionProbeInstance *refprobe_2 = NULL;
if (!p_shadow) { if (!p_shadow) {
@ -1911,6 +2135,27 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
state.scene_shader.set_conditional(SceneShaderGLES2::USE_VERTEX_LIGHTING, vertex_lit); state.scene_shader.set_conditional(SceneShaderGLES2::USE_VERTEX_LIGHTING, vertex_lit);
prev_vertex_lit = vertex_lit; prev_vertex_lit = vertex_lit;
} }
if (!unshaded && !accum_pass && e->refprobe_0_index != RenderList::MAX_REFLECTION_PROBES) {
refprobe_1 = reflection_probe_instances[e->refprobe_0_index];
}
if (!unshaded && !accum_pass && e->refprobe_1_index != RenderList::MAX_REFLECTION_PROBES) {
refprobe_2 = reflection_probe_instances[e->refprobe_1_index];
}
if (refprobe_1 != prev_refprobe_1 || refprobe_2 != prev_refprobe_2) {
state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE1, refprobe_1 != NULL);
state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE2, refprobe_2 != NULL);
if (refprobe_1 != NULL && refprobe_1 != prev_refprobe_1) {
glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4);
glBindTexture(GL_TEXTURE_CUBE_MAP, refprobe_1->cubemap);
}
if (refprobe_2 != NULL && refprobe_2 != prev_refprobe_2) {
glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 5);
glBindTexture(GL_TEXTURE_CUBE_MAP, refprobe_2->cubemap);
}
rebind = true;
}
} }
bool instancing = e->instancing; bool instancing = e->instancing;
@ -1975,6 +2220,10 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
if (light) { if (light) {
_setup_light(light, shadow_atlas, p_view_transform); _setup_light(light, shadow_atlas, p_view_transform);
} }
if (refprobe_1 || refprobe_2) {
_setup_refprobes(refprobe_1, refprobe_2, p_view_transform, p_env);
}
} }
state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_MATRIX, view_transform_inverse); state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_MATRIX, view_transform_inverse);
@ -1997,6 +2246,8 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
prev_skeleton = skeleton; prev_skeleton = skeleton;
prev_instancing = instancing; prev_instancing = instancing;
prev_light = light; prev_light = light;
prev_refprobe_1 = refprobe_1;
prev_refprobe_2 = refprobe_2;
} }
_setup_light_type(NULL, NULL); //clear light stuff _setup_light_type(NULL, NULL); //clear light stuff
@ -2007,6 +2258,8 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, false); state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, false);
state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, false); state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, false);
state.scene_shader.set_conditional(SceneShaderGLES2::USE_VERTEX_LIGHTING, false); state.scene_shader.set_conditional(SceneShaderGLES2::USE_VERTEX_LIGHTING, false);
state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE1, false);
state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE2, false);
} }
void RasterizerSceneGLES2::_draw_sky(RasterizerStorageGLES2::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_custom_fov, float p_energy) { void RasterizerSceneGLES2::_draw_sky(RasterizerStorageGLES2::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_custom_fov, float p_energy) {
@ -2101,6 +2354,36 @@ void RasterizerSceneGLES2::_draw_sky(RasterizerStorageGLES2::Sky *p_sky, const C
void RasterizerSceneGLES2::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) { void RasterizerSceneGLES2::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) {
GLuint current_fb = 0;
Environment *env = NULL;
int viewport_width, viewport_height;
if (p_reflection_probe.is_valid()) {
ReflectionProbeInstance *probe = reflection_probe_instance_owner.getornull(p_reflection_probe);
ERR_FAIL_COND(!probe);
state.render_no_shadows = !probe->probe_ptr->enable_shadows;
if (!probe->probe_ptr->interior) { //use env only if not interior
env = environment_owner.getornull(p_environment);
}
current_fb = probe->fbo[p_reflection_probe_pass];
state.screen_pixel_size.x = 1.0 / probe->probe_ptr->resolution;
state.screen_pixel_size.y = 1.0 / probe->probe_ptr->resolution;
viewport_width = probe->probe_ptr->resolution;
viewport_height = probe->probe_ptr->resolution;
} else {
state.render_no_shadows = false;
current_fb = storage->frame.current_rt->fbo;
env = environment_owner.getornull(p_environment);
state.screen_pixel_size.x = 1.0 / storage->frame.current_rt->width;
state.screen_pixel_size.y = 1.0 / storage->frame.current_rt->height;
viewport_width = storage->frame.current_rt->width;
viewport_height = storage->frame.current_rt->height;
}
//push back the directional lights //push back the directional lights
if (p_light_cull_count) { if (p_light_cull_count) {
@ -2133,10 +2416,21 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
render_light_instance_count = 0; render_light_instance_count = 0;
} }
glEnable(GL_BLEND); if (p_reflection_probe_cull_count) {
GLuint current_fb = storage->frame.current_rt->fbo; reflection_probe_instances = (ReflectionProbeInstance **)alloca(sizeof(ReflectionProbeInstance *) * p_reflection_probe_cull_count);
Environment *env = environment_owner.getornull(p_environment);
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);
rpi->last_pass = render_pass + 1; //will be incremented later
rpi->index = i;
reflection_probe_instances[i] = rpi;
}
} else {
reflection_probe_instances = NULL;
}
// render list stuff // render list stuff
@ -2146,6 +2440,7 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
// other stuff // other stuff
glBindFramebuffer(GL_FRAMEBUFFER, current_fb); glBindFramebuffer(GL_FRAMEBUFFER, current_fb);
glViewport(0, 0, viewport_width, viewport_height);
glDepthFunc(GL_LEQUAL); glDepthFunc(GL_LEQUAL);
glDepthMask(GL_TRUE); glDepthMask(GL_TRUE);
@ -2247,6 +2542,8 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const
void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) { void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) {
state.render_no_shadows = false;
LightInstance *light_instance = light_instance_owner.getornull(p_light); LightInstance *light_instance = light_instance_owner.getornull(p_light);
ERR_FAIL_COND(!light_instance); ERR_FAIL_COND(!light_instance);

View File

@ -204,6 +204,9 @@ public:
float dual_parbolloid_direction; float dual_parbolloid_direction;
float dual_parbolloid_zfar; float dual_parbolloid_zfar;
bool render_no_shadows;
Vector2 screen_pixel_size;
} state; } state;
/* SHADOW ATLAS API */ /* SHADOW ATLAS API */
@ -287,6 +290,37 @@ public:
/* REFLECTION PROBE INSTANCE */ /* REFLECTION PROBE INSTANCE */
struct ReflectionProbeInstance : public RID_Data {
RasterizerStorageGLES2::ReflectionProbe *probe_ptr;
RID probe;
RID self;
RID atlas;
int reflection_atlas_index;
int render_step;
int reflection_index;
GLuint fbo[6];
GLuint cubemap;
GLuint depth;
GLuint fbo_blur;
int current_resolution;
mutable bool dirty;
uint64_t last_pass;
uint32_t index;
Transform transform;
};
mutable RID_Owner<ReflectionProbeInstance> reflection_probe_instance_owner;
ReflectionProbeInstance **reflection_probe_instances;
virtual RID reflection_probe_instance_create(RID p_probe); 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_instance_set_transform(RID p_instance, const Transform &p_transform);
virtual void reflection_probe_release_atlas_index(RID p_instance); virtual void reflection_probe_release_atlas_index(RID p_instance);
@ -424,6 +458,7 @@ public:
enum { enum {
MAX_LIGHTS = 255, MAX_LIGHTS = 255,
MAX_REFLECTION_PROBES = 255,
DEFAULT_MAX_ELEMENTS = 65536 DEFAULT_MAX_ELEMENTS = 65536
}; };
@ -587,6 +622,7 @@ public:
_FORCE_INLINE_ void _setup_geometry(RenderList::Element *p_element, RasterizerStorageGLES2::Skeleton *p_skeleton); _FORCE_INLINE_ void _setup_geometry(RenderList::Element *p_element, RasterizerStorageGLES2::Skeleton *p_skeleton);
_FORCE_INLINE_ void _setup_light_type(LightInstance *p_light, ShadowAtlas *shadow_atlas); _FORCE_INLINE_ void _setup_light_type(LightInstance *p_light, ShadowAtlas *shadow_atlas);
_FORCE_INLINE_ void _setup_light(LightInstance *p_light, ShadowAtlas *shadow_atlas, const Transform &p_view_transform); _FORCE_INLINE_ void _setup_light(LightInstance *p_light, ShadowAtlas *shadow_atlas, const Transform &p_view_transform);
_FORCE_INLINE_ void _setup_refprobes(ReflectionProbeInstance *p_refprobe1, ReflectionProbeInstance *p_refprobe2, const Transform &p_view_transform, Environment *p_env);
_FORCE_INLINE_ void _render_geometry(RenderList::Element *p_element); _FORCE_INLINE_ void _render_geometry(RenderList::Element *p_element);
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_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);

View File

@ -3307,69 +3307,194 @@ AABB RasterizerStorageGLES2::light_get_aabb(RID p_light) const {
/* PROBE API */ /* PROBE API */
RID RasterizerStorageGLES2::reflection_probe_create() { RID RasterizerStorageGLES2::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;
reflection_probe->resolution = 128;
return reflection_probe_owner.make_rid(reflection_probe);
} }
void RasterizerStorageGLES2::reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode) { void RasterizerStorageGLES2::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 RasterizerStorageGLES2::reflection_probe_set_intensity(RID p_probe, float p_intensity) { void RasterizerStorageGLES2::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 RasterizerStorageGLES2::reflection_probe_set_interior_ambient(RID p_probe, const Color &p_ambient) { void RasterizerStorageGLES2::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 RasterizerStorageGLES2::reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy) { void RasterizerStorageGLES2::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 RasterizerStorageGLES2::reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib) { void RasterizerStorageGLES2::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 RasterizerStorageGLES2::reflection_probe_set_max_distance(RID p_probe, float p_distance) { void RasterizerStorageGLES2::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 RasterizerStorageGLES2::reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) { void RasterizerStorageGLES2::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 RasterizerStorageGLES2::reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) { void RasterizerStorageGLES2::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 RasterizerStorageGLES2::reflection_probe_set_as_interior(RID p_probe, bool p_enable) { void RasterizerStorageGLES2::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 RasterizerStorageGLES2::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) { void RasterizerStorageGLES2::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 RasterizerStorageGLES2::reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) { void RasterizerStorageGLES2::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 RasterizerStorageGLES2::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();
} }
void RasterizerStorageGLES2::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) { void RasterizerStorageGLES2::reflection_probe_set_resolution(RID p_probe, int p_resolution) {
ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
ERR_FAIL_COND(!reflection_probe);
reflection_probe->resolution = p_resolution;
} }
AABB RasterizerStorageGLES2::reflection_probe_get_aabb(RID p_probe) const { AABB RasterizerStorageGLES2::reflection_probe_get_aabb(RID p_probe) const {
return AABB(); const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
ERR_FAIL_COND_V(!reflection_probe, AABB());
AABB aabb;
aabb.position = -reflection_probe->extents;
aabb.size = reflection_probe->extents * 2.0;
return aabb;
} }
VS::ReflectionProbeUpdateMode RasterizerStorageGLES2::reflection_probe_get_update_mode(RID p_probe) const { VS::ReflectionProbeUpdateMode RasterizerStorageGLES2::reflection_probe_get_update_mode(RID p_probe) const {
return VS::REFLECTION_PROBE_UPDATE_ALWAYS;
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 RasterizerStorageGLES2::reflection_probe_get_cull_mask(RID p_probe) const { uint32_t RasterizerStorageGLES2::reflection_probe_get_cull_mask(RID p_probe) const {
return 0;
const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
ERR_FAIL_COND_V(!reflection_probe, 0);
return reflection_probe->cull_mask;
} }
Vector3 RasterizerStorageGLES2::reflection_probe_get_extents(RID p_probe) const { Vector3 RasterizerStorageGLES2::reflection_probe_get_extents(RID p_probe) const {
return Vector3();
const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
ERR_FAIL_COND_V(!reflection_probe, Vector3());
return reflection_probe->extents;
} }
Vector3 RasterizerStorageGLES2::reflection_probe_get_origin_offset(RID p_probe) const { Vector3 RasterizerStorageGLES2::reflection_probe_get_origin_offset(RID p_probe) const {
return Vector3();
const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
ERR_FAIL_COND_V(!reflection_probe, Vector3());
return reflection_probe->origin_offset;
} }
bool RasterizerStorageGLES2::reflection_probe_renders_shadows(RID p_probe) const { bool RasterizerStorageGLES2::reflection_probe_renders_shadows(RID p_probe) const {
return false;
const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
ERR_FAIL_COND_V(!reflection_probe, false);
return reflection_probe->enable_shadows;
} }
float RasterizerStorageGLES2::reflection_probe_get_origin_max_distance(RID p_probe) const { float RasterizerStorageGLES2::reflection_probe_get_origin_max_distance(RID p_probe) const {
return 0;
const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
ERR_FAIL_COND_V(!reflection_probe, 0);
return reflection_probe->max_distance;
}
int RasterizerStorageGLES2::reflection_probe_get_resolution(RID p_probe) const {
const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
ERR_FAIL_COND_V(!reflection_probe, 0);
return reflection_probe->resolution;
} }
RID RasterizerStorageGLES2::gi_probe_create() { RID RasterizerStorageGLES2::gi_probe_create() {
@ -3601,15 +3726,115 @@ void RasterizerStorageGLES2::update_particles() {
//////// ////////
void RasterizerStorageGLES2::instance_add_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) { void RasterizerStorageGLES2::instance_add_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) {
Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
ERR_FAIL_COND(!skeleton);
skeleton->instances.insert(p_instance);
} }
void RasterizerStorageGLES2::instance_remove_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) { void RasterizerStorageGLES2::instance_remove_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) {
Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
ERR_FAIL_COND(!skeleton);
skeleton->instances.erase(p_instance);
} }
void RasterizerStorageGLES2::instance_add_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) { void RasterizerStorageGLES2::instance_add_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) {
Instanciable *inst = NULL;
switch (p_instance->base_type) {
case VS::INSTANCE_MESH: {
inst = mesh_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;
case VS::INSTANCE_MULTIMESH: {
inst = multimesh_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;
case VS::INSTANCE_IMMEDIATE: {
inst = immediate_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;
/*case VS::INSTANCE_PARTICLES: {
inst = particles_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);
} break;
/*case VS::INSTANCE_GI_PROBE: {
inst = gi_probe_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;*/
/*case VS::INSTANCE_LIGHTMAP_CAPTURE: {
inst = lightmap_capture_data_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;*/
default: {
if (!inst) {
ERR_FAIL();
}
}
}
inst->instance_list.add(&p_instance->dependency_item);
} }
void RasterizerStorageGLES2::instance_remove_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) { void RasterizerStorageGLES2::instance_remove_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) {
Instanciable *inst = NULL;
switch (p_instance->base_type) {
case VS::INSTANCE_MESH: {
inst = mesh_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;
case VS::INSTANCE_MULTIMESH: {
inst = multimesh_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;
case VS::INSTANCE_IMMEDIATE: {
inst = immediate_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;
/*case VS::INSTANCE_PARTICLES: {
inst = particles_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);
} break;
/*case VS::INSTANCE_GI_PROBE: {
inst = gi_probe_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;
case VS::INSTANCE_LIGHTMAP_CAPTURE: {
inst = lightmap_capture_data_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;*/
default: {
if (!inst) {
ERR_FAIL();
}
}
}
ERR_FAIL_COND(!inst);
inst->instance_list.remove(&p_instance->dependency_item);
} }
/* RENDER TARGET */ /* RENDER TARGET */
@ -3867,6 +4092,8 @@ VS::InstanceType RasterizerStorageGLES2::get_base_type(RID p_rid) const {
return VS::INSTANCE_MULTIMESH; return VS::INSTANCE_MULTIMESH;
} else if (immediate_owner.owns(p_rid)) { } else if (immediate_owner.owns(p_rid)) {
return VS::INSTANCE_IMMEDIATE; return VS::INSTANCE_IMMEDIATE;
} else if (reflection_probe_owner.owns(p_rid)) {
return VS::INSTANCE_REFLECTION_PROBE;
} else { } else {
return VS::INSTANCE_NONE; return VS::INSTANCE_NONE;
} }
@ -4044,6 +4271,17 @@ bool RasterizerStorageGLES2::free(RID p_rid) {
memdelete(light); memdelete(light);
return true; return true;
} else if (reflection_probe_owner.owns(p_rid)) {
// delete the texture
ReflectionProbe *reflection_probe = reflection_probe_owner.get(p_rid);
reflection_probe->instance_remove_deps();
reflection_probe_owner.free(p_rid);
memdelete(reflection_probe);
return true;
} else { } else {
return false; return false;
} }
@ -4095,6 +4333,7 @@ void RasterizerStorageGLES2::initialize() {
} }
config.shrink_textures_x2 = false; config.shrink_textures_x2 = false;
config.float_texture_supported = config.extensions.has("GL_ARB_texture_float") || config.extensions.has("GL_OES_texture_float"); config.float_texture_supported = config.extensions.has("GL_ARB_texture_float") || config.extensions.has("GL_OES_texture_float");
config.s3tc_supported = config.extensions.has("GL_EXT_texture_compression_s3tc"); config.s3tc_supported = config.extensions.has("GL_EXT_texture_compression_s3tc");
config.etc1_supported = config.extensions.has("GL_OES_compressed_ETC1_RGB8_texture"); config.etc1_supported = config.extensions.has("GL_OES_compressed_ETC1_RGB8_texture");

View File

@ -955,6 +955,26 @@ public:
virtual uint64_t light_get_version(RID p_light) const; virtual uint64_t light_get_version(RID p_light) const;
/* PROBE API */ /* PROBE API */
struct ReflectionProbe : Instanciable {
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;
int resolution;
};
mutable RID_Owner<ReflectionProbe> reflection_probe_owner;
virtual RID reflection_probe_create(); virtual RID reflection_probe_create();
virtual void reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode); virtual void reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode);
@ -969,11 +989,14 @@ public:
virtual void reflection_probe_set_enable_box_projection(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_enable_shadows(RID p_probe, bool p_enable);
virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers); virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers);
virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution);
virtual AABB reflection_probe_get_aabb(RID p_probe) const; virtual AABB reflection_probe_get_aabb(RID p_probe) const;
virtual VS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(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 uint32_t reflection_probe_get_cull_mask(RID p_probe) const;
virtual int reflection_probe_get_resolution(RID p_probe) const;
virtual Vector3 reflection_probe_get_extents(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 Vector3 reflection_probe_get_origin_offset(RID p_probe) const;
virtual float reflection_probe_get_origin_max_distance(RID p_probe) const; virtual float reflection_probe_get_origin_max_distance(RID p_probe) const;

View File

@ -176,7 +176,6 @@ void main() {
#ifdef USE_SOURCE_PANORAMA #ifdef USE_SOURCE_PANORAMA
sum.rgb += texturePanorama(source_panorama, L).rgb * NdotL; sum.rgb += texturePanorama(source_panorama, L).rgb * NdotL;
#else #else
L.y = -L.y;
sum.rgb += textureCubeLod(source_cube, L, 0.0).rgb * NdotL; sum.rgb += textureCubeLod(source_cube, L, 0.0).rgb * NdotL;
#endif #endif

View File

@ -262,6 +262,35 @@ void light_compute(
#endif #endif
#ifdef USE_VERTEX_LIGHTING
#ifdef USE_REFLECTION_PROBE1
uniform mat4 refprobe1_local_matrix;
varying mediump vec4 refprobe1_reflection_normal_blend;
uniform vec3 refprobe1_box_extents;
#ifndef USE_LIGHTMAP
varying mediump vec3 refprobe1_ambient_normal;
#endif
#endif //reflection probe1
#ifdef USE_REFLECTION_PROBE2
uniform mat4 refprobe2_local_matrix;
varying mediump vec4 refprobe2_reflection_normal_blend;
uniform vec3 refprobe2_box_extents;
#ifndef USE_LIGHTMAP
varying mediump vec3 refprobe2_ambient_normal;
#endif
#endif //reflection probe2
#endif //vertex lighting for refprobes
void main() { void main() {
highp vec4 vertex = vertex_attrib; highp vec4 vertex = vertex_attrib;
@ -498,6 +527,52 @@ VERTEX_SHADER_CODE
#endif //use shadow and use lighting #endif //use shadow and use lighting
#ifdef USE_VERTEX_LIGHTING
#ifdef USE_REFLECTION_PROBE1
{
vec3 ref_normal = normalize(reflect(vertex_interp, normal_interp));
vec3 local_pos = (refprobe1_local_matrix * vec4(vertex_interp, 1.0)).xyz;
vec3 inner_pos = abs(local_pos / refprobe1_box_extents);
float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z));
{
vec3 local_ref_vec = (refprobe1_local_matrix * vec4(ref_normal, 0.0)).xyz;
refprobe1_reflection_normal_blend.xyz = local_ref_vec;
refprobe1_reflection_normal_blend.a = blend;
}
#ifndef USE_LIGHTMAP
refprobe1_ambient_normal = (refprobe1_local_matrix * vec4(normal_interp, 0.0)).xyz;
#endif
}
#endif //USE_REFLECTION_PROBE1
#ifdef USE_REFLECTION_PROBE2
{
vec3 ref_normal = normalize(reflect(vertex_interp, normal_interp));
vec3 local_pos = (refprobe2_local_matrix * vec4(vertex_interp, 1.0)).xyz;
vec3 inner_pos = abs(local_pos / refprobe2_box_extents);
float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z));
{
vec3 local_ref_vec = (refprobe2_local_matrix * vec4(ref_normal, 0.0)).xyz;
refprobe2_reflection_normal_blend.xyz = local_ref_vec;
refprobe2_reflection_normal_blend.a = blend;
}
#ifndef USE_LIGHTMAP
refprobe2_ambient_normal = (refprobe2_local_matrix * vec4(normal_interp, 0.0)).xyz;
#endif
}
#endif //USE_REFLECTION_PROBE2
#endif //use vertex lighting
gl_Position = projection_matrix * vec4(vertex_interp, 1.0); gl_Position = projection_matrix * vec4(vertex_interp, 1.0);
} }
@ -548,10 +623,161 @@ uniform vec2 screen_pixel_size;
uniform highp sampler2D screen_texture; //texunit:-4 uniform highp sampler2D screen_texture; //texunit:-4
#endif #endif
#ifdef USE_RADIANCE_MAP #ifdef USE_REFLECTION_PROBE1
#ifdef USE_VERTEX_LIGHTING
varying mediump vec4 refprobe1_reflection_normal_blend;
#ifndef USE_LIGHTMAP
varying mediump vec3 refprobe1_ambient_normal;
#endif
#else
uniform bool refprobe1_use_box_project;
uniform vec3 refprobe1_box_extents;
uniform vec3 refprobe1_box_offset;
uniform mat4 refprobe1_local_matrix;
#endif //use vertex lighting
uniform bool refprobe1_exterior;
uniform highp samplerCube reflection_probe1; //texunit:-4
uniform float refprobe1_intensity;
uniform vec4 refprobe1_ambient;
#endif //USE_REFLECTION_PROBE1
#ifdef USE_REFLECTION_PROBE2
#ifdef USE_VERTEX_LIGHTING
varying mediump vec4 refprobe2_reflection_normal_blend;
#ifndef USE_LIGHTMAP
varying mediump vec3 refprobe2_ambient_normal;
#endif
#else
uniform bool refprobe2_use_box_project;
uniform vec3 refprobe2_box_extents;
uniform vec3 refprobe2_box_offset;
uniform mat4 refprobe2_local_matrix;
#endif //use vertex lighting
uniform bool refprobe2_exterior;
uniform highp samplerCube reflection_probe2; //texunit:-5
uniform float refprobe2_intensity;
uniform vec4 refprobe2_ambient;
#endif //USE_REFLECTION_PROBE2
#define RADIANCE_MAX_LOD 6.0 #define RADIANCE_MAX_LOD 6.0
#if defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2)
void reflection_process(samplerCube reflection_map,
#ifdef USE_VERTEX_LIGHTING
vec3 ref_normal,
#ifndef USE_LIGHTMAP
vec3 amb_normal,
#endif
float ref_blend,
#else //no vertex lighting
vec3 normal, vec3 vertex,
mat4 local_matrix,
bool use_box_project, vec3 box_extents, vec3 box_offset,
#endif //vertex lighting
bool exterior,float intensity, vec4 ref_ambient, float roughness, vec3 ambient, vec3 skybox, inout highp vec4 reflection_accum, inout highp vec4 ambient_accum) {
vec4 reflection;
#ifdef USE_VERTEX_LIGHTING
reflection.rgb = textureCubeLod(reflection_map, ref_normal, roughness * RADIANCE_MAX_LOD).rgb;
float blend = ref_blend; //crappier blend formula for vertex
blend *= blend;
blend = max(0.0, 1.0 - blend);
#else //fragment lighting
vec3 local_pos = (local_matrix * vec4(vertex, 1.0)).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));
blend = mix(length(inner_pos), blend, blend);
blend *= blend;
blend = max(0.0, 1.0 - blend);
//reflect and make local
vec3 ref_normal = normalize(reflect(vertex, normal));
ref_normal = (local_matrix * vec4(ref_normal, 0.0)).xyz;
if (use_box_project) { //box project
vec3 nrdir = normalize(ref_normal);
vec3 rbmax = (box_extents - local_pos) / nrdir;
vec3 rbmin = (-box_extents - local_pos) / nrdir;
vec3 rbminmax = mix(rbmin, rbmax, vec3(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;
ref_normal = posonbox - box_offset.xyz;
}
reflection.rgb = textureCubeLod(reflection_map, ref_normal, roughness * RADIANCE_MAX_LOD).rgb;
#endif
if (exterior) {
reflection.rgb = mix(skybox, reflection.rgb, blend);
}
reflection.rgb *= intensity;
reflection.a = blend;
reflection.rgb *= blend;
reflection_accum += reflection;
#ifndef USE_LIGHTMAP
vec4 ambient_out;
#ifndef USE_VERTEX_LIGHTING
vec3 amb_normal = (local_matrix * vec4(normal, 0.0)).xyz;
#endif
ambient_out.rgb = textureCubeLod(reflection_map, amb_normal, RADIANCE_MAX_LOD).rgb;
ambient_out.a = blend;
ambient_out.rgb = mix(ref_ambient.rgb, ambient_out.rgb, ref_ambient.a);
if (exterior) {
ambient_out.rgb = mix(ambient, ambient_out.rgb, blend);
}
ambient_out.rgb *= blend;
ambient_accum += ambient_out;
#endif
}
#endif //use refprobe 1 or 2
#ifdef USE_RADIANCE_MAP
uniform samplerCube radiance_map; // texunit:-2 uniform samplerCube radiance_map; // texunit:-2
uniform mat4 radiance_inverse_xform; uniform mat4 radiance_inverse_xform;
@ -660,6 +886,8 @@ vec3 metallic_to_specular_color(float metallic, float specular, vec3 albedo) {
return mix(vec3(dielectric), albedo, metallic); // TODO: reference? return mix(vec3(dielectric), albedo, metallic); // TODO: reference?
} }
/* clang-format off */ /* clang-format off */
FRAGMENT_SHADER_GLOBALS FRAGMENT_SHADER_GLOBALS
@ -1123,6 +1351,59 @@ FRAGMENT_SHADER_CODE
ambient_light *= ambient_energy; ambient_light *= ambient_energy;
#ifdef USE_REFLECTION_PROBE1
vec4 ambient_accum = vec4(0.0);
vec4 reflection_accum = vec4(0.0);
reflection_process(reflection_probe1,
#ifdef USE_VERTEX_LIGHTING
refprobe1_reflection_normal_blend.rgb,
#ifndef USE_LIGHTMAP
refprobe1_ambient_normal,
#endif
refprobe1_reflection_normal_blend.a,
#else
normal_interp,vertex_interp,refprobe1_local_matrix,
refprobe1_use_box_project,refprobe1_box_extents,refprobe1_box_offset,
#endif
refprobe1_exterior,refprobe1_intensity, refprobe1_ambient, roughness,
ambient_light, specular_light, reflection_accum, ambient_accum);
#ifdef USE_REFLECTION_PROBE2
reflection_process(reflection_probe2,
#ifdef USE_VERTEX_LIGHTING
refprobe2_reflection_normal_blend.rgb,
#ifndef USE_LIGHTMAP
refprobe2_ambient_normal,
#endif
refprobe2_reflection_normal_blend.a,
#else
normal_interp,vertex_interp,refprobe2_local_matrix,
refprobe2_use_box_project,refprobe2_box_extents,refprobe2_box_offset,
#endif
refprobe2_exterior,refprobe2_intensity, refprobe2_ambient, roughness,
ambient_light, specular_light, reflection_accum, ambient_accum);
#endif // USE_REFLECTION_PROBE2
if (reflection_accum.a > 0.0) {
specular_light = reflection_accum.rgb / reflection_accum.a;
}
#ifndef USE_LIGHTMAP
if (ambient_accum.a > 0.0) {
ambient_light = ambient_accum.rgb / ambient_accum.a;
}
#endif
#endif //use reflection probe 1
#endif //BASE PASS #endif //BASE PASS
// //

View File

@ -5295,6 +5295,9 @@ void RasterizerStorageGLES3::reflection_probe_set_cull_mask(RID p_probe, uint32_
reflection_probe->instance_change_notify(); reflection_probe->instance_change_notify();
} }
void RasterizerStorageGLES3::reflection_probe_set_resolution(RID p_probe, int p_resolution) {
}
AABB RasterizerStorageGLES3::reflection_probe_get_aabb(RID p_probe) const { AABB RasterizerStorageGLES3::reflection_probe_get_aabb(RID p_probe) const {
const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe);
ERR_FAIL_COND_V(!reflection_probe, AABB()); ERR_FAIL_COND_V(!reflection_probe, AABB());

View File

@ -1005,6 +1005,7 @@ public:
virtual void reflection_probe_set_enable_box_projection(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_enable_shadows(RID p_probe, bool p_enable);
virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers); virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers);
virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution);
virtual AABB reflection_probe_get_aabb(RID p_probe) const; virtual AABB reflection_probe_get_aabb(RID p_probe) const;
virtual VS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const; virtual VS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const;

View File

@ -4523,6 +4523,16 @@ void EditorNode::_bottom_panel_raise_toggled(bool p_pressed) {
} }
} }
void EditorNode::_update_video_driver_color() {
//todo probably should de-harcode this and add to editor settings
if (video_driver->get_text() == "GLES2") {
video_driver->add_color_override("font_color", Color::hex(0x5586a4ff));
} else if (video_driver->get_text() == "GLES3") {
video_driver->add_color_override("font_color", Color::hex(0xa5557dff));
}
}
void EditorNode::_video_driver_selected(int p_which) { void EditorNode::_video_driver_selected(int p_which) {
String driver = video_driver->get_item_metadata(p_which); String driver = video_driver->get_item_metadata(p_which);
@ -4536,6 +4546,7 @@ void EditorNode::_video_driver_selected(int p_which) {
video_driver_request = driver; video_driver_request = driver;
video_restart_dialog->popup_centered_minsize(); video_restart_dialog->popup_centered_minsize();
video_driver->select(video_driver_current); video_driver->select(video_driver_current);
_update_video_driver_color();
} }
void EditorNode::_bind_methods() { void EditorNode::_bind_methods() {
@ -5398,6 +5409,7 @@ EditorNode::EditorNode() {
video_driver->set_focus_mode(Control::FOCUS_NONE); video_driver->set_focus_mode(Control::FOCUS_NONE);
video_driver->set_v_size_flags(Control::SIZE_SHRINK_CENTER); video_driver->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
video_driver->connect("item_selected", this, "_video_driver_selected"); video_driver->connect("item_selected", this, "_video_driver_selected");
video_driver->add_font_override("font", gui_base->get_font("bold", "EditorFonts"));
menu_hb->add_child(video_driver); menu_hb->add_child(video_driver);
String video_drivers = ProjectSettings::get_singleton()->get_custom_property_info()["rendering/quality/driver/driver_name"].hint_string; String video_drivers = ProjectSettings::get_singleton()->get_custom_property_info()["rendering/quality/driver/driver_name"].hint_string;
@ -5414,6 +5426,8 @@ EditorNode::EditorNode() {
} }
} }
_update_video_driver_color();
video_restart_dialog = memnew(ConfirmationDialog); video_restart_dialog = memnew(ConfirmationDialog);
video_restart_dialog->set_text(TTR("Changing the video driver requires restarting the editor.")); video_restart_dialog->set_text(TTR("Changing the video driver requires restarting the editor."));
video_restart_dialog->get_ok()->set_text(TTR("Save & Restart")); video_restart_dialog->get_ok()->set_text(TTR("Save & Restart"));

View File

@ -208,6 +208,7 @@ private:
int video_driver_current; int video_driver_current;
String video_driver_request; String video_driver_request;
void _video_driver_selected(int); void _video_driver_selected(int);
void _update_video_driver_color();
// Split containers // Split containers

View File

@ -397,6 +397,7 @@ public:
virtual RID reflection_probe_create() = 0; 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_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode) = 0;
virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution) = 0;
virtual void reflection_probe_set_intensity(RID p_probe, float p_intensity) = 0; virtual void reflection_probe_set_intensity(RID p_probe, float p_intensity) = 0;
virtual void reflection_probe_set_interior_ambient(RID p_probe, const Color &p_ambient) = 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_energy(RID p_probe, float p_energy) = 0;

View File

@ -337,6 +337,7 @@ public:
BIND2(reflection_probe_set_enable_box_projection, RID, bool) BIND2(reflection_probe_set_enable_box_projection, RID, bool)
BIND2(reflection_probe_set_enable_shadows, RID, bool) BIND2(reflection_probe_set_enable_shadows, RID, bool)
BIND2(reflection_probe_set_cull_mask, RID, uint32_t) BIND2(reflection_probe_set_cull_mask, RID, uint32_t)
BIND2(reflection_probe_set_resolution, RID, int)
/* BAKED LIGHT API */ /* BAKED LIGHT API */

View File

@ -2141,6 +2141,8 @@ bool VisualServerScene::_render_reflection_probe_step(Instance *p_instance, int
Scenario *scenario = p_instance->scenario; Scenario *scenario = p_instance->scenario;
ERR_FAIL_COND_V(!scenario, true); ERR_FAIL_COND_V(!scenario, true);
VisualServerRaster::redraw_request(); //update, so it updates in editor
if (p_step == 0) { if (p_step == 0) {
if (!VSG::scene_render->reflection_probe_instance_begin_render(reflection_probe->instance, scenario->reflection_atlas)) { if (!VSG::scene_render->reflection_probe_instance_begin_render(reflection_probe->instance, scenario->reflection_atlas)) {

View File

@ -271,6 +271,7 @@ public:
FUNC2(reflection_probe_set_enable_box_projection, RID, bool) FUNC2(reflection_probe_set_enable_box_projection, RID, bool)
FUNC2(reflection_probe_set_enable_shadows, RID, bool) FUNC2(reflection_probe_set_enable_shadows, RID, bool)
FUNC2(reflection_probe_set_cull_mask, RID, uint32_t) FUNC2(reflection_probe_set_cull_mask, RID, uint32_t)
FUNC2(reflection_probe_set_resolution, RID, int)
/* BAKED LIGHT API */ /* BAKED LIGHT API */

View File

@ -490,6 +490,7 @@ public:
virtual void reflection_probe_set_enable_box_projection(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_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 void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) = 0;
virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution) = 0;
/* GI PROBE API */ /* GI PROBE API */