summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/image.cpp22
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp85
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h26
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp317
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.h79
-rw-r--r--drivers/gles3/shaders/scene.glsl135
-rw-r--r--scene/3d/baked_light_instance.cpp1722
-rw-r--r--scene/3d/baked_light_instance.h122
-rw-r--r--scene/3d/gi_probe.cpp1248
-rw-r--r--scene/3d/gi_probe.h174
-rw-r--r--scene/3d/light.cpp34
-rw-r--r--scene/3d/light.h6
-rw-r--r--scene/3d/visual_instance.cpp65
-rw-r--r--scene/3d/visual_instance.h10
-rw-r--r--scene/register_scene_types.cpp5
-rw-r--r--scene/resources/baked_light.cpp574
-rw-r--r--scene/resources/baked_light.h163
-rw-r--r--servers/visual/rasterizer.h45
-rw-r--r--servers/visual/visual_server_light_baker.cpp6
-rw-r--r--servers/visual/visual_server_light_baker.h29
-rw-r--r--servers/visual/visual_server_raster.cpp3
-rw-r--r--servers/visual/visual_server_raster.h30
-rw-r--r--servers/visual/visual_server_scene.cpp865
-rw-r--r--servers/visual/visual_server_scene.h162
-rw-r--r--servers/visual_server.h38
-rw-r--r--tools/editor/io_plugins/editor_import_collada.cpp17
-rw-r--r--tools/editor/io_plugins/editor_scene_import_plugin.cpp2
-rw-r--r--tools/editor/spatial_editor_gizmos.cpp170
-rw-r--r--tools/editor/spatial_editor_gizmos.h22
29 files changed, 5217 insertions, 959 deletions
diff --git a/core/image.cpp b/core/image.cpp
index 73a2ab8013..0b63d9c524 100644
--- a/core/image.cpp
+++ b/core/image.cpp
@@ -390,16 +390,16 @@ void Image::convert( Format p_new_format ){
case FORMAT_R8|(FORMAT_RG8<<8): _convert<1,false,2,false,false,false>( width, height,rptr, wptr ); break;
case FORMAT_R8|(FORMAT_RGB8<<8): _convert<1,false,3,false,false,false>( width, height,rptr, wptr ); break;
case FORMAT_R8|(FORMAT_RGBA8<<8): _convert<1,false,3,true,false,false>( width, height,rptr, wptr ); break;
- case FORMAT_RG8|(FORMAT_L8<<8): _convert<1,false,1,false,false,true>( width, height,rptr, wptr ); break;
- case FORMAT_RG8|(FORMAT_LA8<<8): _convert<1,false,1,true,false,true>( width, height,rptr, wptr ); break;
- case FORMAT_RG8|(FORMAT_R8<<8): _convert<1,false,1,false,false,false>( width, height,rptr, wptr ); break;
- case FORMAT_RG8|(FORMAT_RGB8<<8): _convert<1,false,3,false,false,false>( width, height,rptr, wptr ); break;
- case FORMAT_RG8|(FORMAT_RGBA8<<8): _convert<1,false,3,true,false,false>( width, height,rptr, wptr ); break;
- case FORMAT_RGB8|(FORMAT_L8<<8): _convert<2,false,1,false,false,true>( width, height,rptr, wptr ); break;
- case FORMAT_RGB8|(FORMAT_LA8<<8): _convert<2,false,1,true,false,true>( width, height,rptr, wptr ); break;
- case FORMAT_RGB8|(FORMAT_R8<<8): _convert<2,false,1,false,false,false>( width, height,rptr, wptr ); break;
- case FORMAT_RGB8|(FORMAT_RG8<<8): _convert<2,false,2,false,false,false>( width, height,rptr, wptr ); break;
- case FORMAT_RGB8|(FORMAT_RGBA8<<8): _convert<2,false,3,true,false,false>( width, height,rptr, wptr ); break;
+ case FORMAT_RG8|(FORMAT_L8<<8): _convert<2,false,1,false,false,true>( width, height,rptr, wptr ); break;
+ case FORMAT_RG8|(FORMAT_LA8<<8): _convert<2,false,1,true,false,true>( width, height,rptr, wptr ); break;
+ case FORMAT_RG8|(FORMAT_R8<<8): _convert<2,false,1,false,false,false>( width, height,rptr, wptr ); break;
+ case FORMAT_RG8|(FORMAT_RGB8<<8): _convert<2,false,3,false,false,false>( width, height,rptr, wptr ); break;
+ case FORMAT_RG8|(FORMAT_RGBA8<<8): _convert<2,false,3,true,false,false>( width, height,rptr, wptr ); break;
+ case FORMAT_RGB8|(FORMAT_L8<<8): _convert<3,false,1,false,false,true>( width, height,rptr, wptr ); break;
+ case FORMAT_RGB8|(FORMAT_LA8<<8): _convert<3,false,1,true,false,true>( width, height,rptr, wptr ); break;
+ case FORMAT_RGB8|(FORMAT_R8<<8): _convert<3,false,1,false,false,false>( width, height,rptr, wptr ); break;
+ case FORMAT_RGB8|(FORMAT_RG8<<8): _convert<3,false,2,false,false,false>( width, height,rptr, wptr ); break;
+ case FORMAT_RGB8|(FORMAT_RGBA8<<8): _convert<3,false,3,true,false,false>( width, height,rptr, wptr ); break;
case FORMAT_RGBA8|(FORMAT_L8<<8): _convert<3,true,1,false,false,true>( width, height,rptr, wptr ); break;
case FORMAT_RGBA8|(FORMAT_LA8<<8): _convert<3,true,1,true,false,true>( width, height,rptr, wptr ); break;
case FORMAT_RGBA8|(FORMAT_R8<<8): _convert<3,true,1,false,false,false>( width, height,rptr, wptr ); break;
@@ -414,7 +414,7 @@ void Image::convert( Format p_new_format ){
bool gen_mipmaps=mipmaps;
- mipmaps=false;
+// mipmaps=false;
*this=new_img;
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index 2c6c9dd9ba..524e683738 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -1010,6 +1010,48 @@ void RasterizerSceneGLES3::light_instance_mark_visible(RID p_light_instance) {
light_instance->last_scene_pass=scene_pass;
}
+
+//////////////////////
+
+RID RasterizerSceneGLES3::gi_probe_instance_create() {
+
+ GIProbeInstance *gipi = memnew(GIProbeInstance);
+
+ return gi_probe_instance_owner.make_rid(gipi);
+}
+
+void RasterizerSceneGLES3::gi_probe_instance_set_light_data(RID p_probe,RID p_data) {
+
+ GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_probe);
+ ERR_FAIL_COND(!gipi);
+ gipi->data=p_data;
+ if (p_data.is_valid()) {
+ RasterizerStorageGLES3::GIProbeData *gipd = storage->gi_probe_data_owner.getornull(p_data);
+ ERR_FAIL_COND(!gipd);
+ if (gipd) {
+ gipi->tex_cache=gipd->tex_id;
+ gipi->cell_size_cache.x=1.0/gipd->width;
+ gipi->cell_size_cache.y=1.0/gipd->height;
+ gipi->cell_size_cache.z=1.0/gipd->depth;
+ }
+ }
+}
+void RasterizerSceneGLES3::gi_probe_instance_set_transform_to_data(RID p_probe,const Transform& p_xform) {
+
+ GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_probe);
+ ERR_FAIL_COND(!gipi);
+ gipi->transform_to_data=p_xform;
+
+}
+
+void RasterizerSceneGLES3::gi_probe_instance_set_bounds(RID p_probe,const Vector3& p_bounds) {
+
+ GIProbeInstance *gipi = gi_probe_instance_owner.getornull(p_probe);
+ ERR_FAIL_COND(!gipi);
+ gipi->bounds=p_bounds;
+
+}
+
////////////////////////////
////////////////////////////
////////////////////////////
@@ -1438,7 +1480,7 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) {
}
-void RasterizerSceneGLES3::_setup_light(RenderList::Element *e) {
+void RasterizerSceneGLES3::_setup_light(RenderList::Element *e,const Transform& p_view_transform) {
int omni_indices[16];
int omni_count=0;
@@ -1509,7 +1551,33 @@ void RasterizerSceneGLES3::_setup_light(RenderList::Element *e) {
glUniform1iv(state.scene_shader.get_uniform(SceneShaderGLES3::REFLECTION_INDICES),reflection_count,reflection_indices);
}
+ int gi_probe_count = e->instance->gi_probe_instances.size();
+ if (gi_probe_count) {
+ const RID * ridp = e->instance->gi_probe_instances.ptr();
+ GIProbeInstance *gipi = gi_probe_instance_owner.getptr(ridp[0]);
+
+ glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-6);
+ glBindTexture(GL_TEXTURE_3D,gipi->tex_cache);
+ state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_XFORM1, gipi->transform_to_data * p_view_transform);
+ state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_BOUNDS1, gipi->bounds);
+ state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_CELL_SIZE1, gipi->cell_size_cache);
+ if (gi_probe_count>1) {
+
+ GIProbeInstance *gipi2 = gi_probe_instance_owner.getptr(ridp[1]);
+
+ glActiveTexture(GL_TEXTURE0+storage->config.max_texture_image_units-7);
+ glBindTexture(GL_TEXTURE_3D,gipi2->tex_cache);
+ state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_XFORM2, gipi2->transform_to_data * p_view_transform);
+ state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_BOUNDS2, gipi2->bounds);
+ state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE_CELL_SIZE2, gipi2->cell_size_cache);
+
+ state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE2_ENABLED, true );
+ } else {
+
+ state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE2_ENABLED, false );
+ }
+ }
}
@@ -1672,11 +1740,15 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e
state.scene_shader.set_conditional(SceneShaderGLES3::LIGHT_USE_PSSM_BLEND,false);
state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_5,false);
state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_13,false);
+ state.scene_shader.set_conditional(SceneShaderGLES3::USE_GI_PROBES,false);
//state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,true);
} else {
+
+ state.scene_shader.set_conditional(SceneShaderGLES3::USE_GI_PROBES,e->instance->gi_probe_instances.size()>0);
+
state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,false);
state.scene_shader.set_conditional(SceneShaderGLES3::USE_FORWARD_LIGHTING,!p_directional_add);
state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHT_DIRECTIONAL,false);
@@ -1711,9 +1783,12 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e
}
+
+
rebind=true;
}
+
if (p_alpha_pass || p_directional_add) {
int desired_blend_mode;
if (p_directional_add) {
@@ -1794,7 +1869,8 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e
}
if (!(e->sort_key&RenderList::SORT_KEY_UNSHADED_FLAG) && !p_directional_add && !p_shadow) {
- _setup_light(e);
+ _setup_light(e,p_view_transform);
+
}
@@ -1837,6 +1913,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements,int p_e
state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS,false);
state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_5,false);
state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_13,false);
+ state.scene_shader.set_conditional(SceneShaderGLES3::USE_GI_PROBES,false);
}
@@ -1950,6 +2027,10 @@ void RasterizerSceneGLES3::_add_geometry( RasterizerStorageGLES3::Geometry* p_g
copymem(oe,e,sizeof(RenderList::Element));
}
+
+ if (e->instance->gi_probe_instances.size()) {
+ e->sort_key|=RenderList::SORT_KEY_GI_PROBES_FLAG;
+ }
}
//if (e->geometry->type==RasterizerStorageGLES3::Geometry::GEOMETRY_MULTISURFACE)
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index 78e8b3e477..5eb2be1cc2 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -526,6 +526,25 @@ 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);
virtual void light_instance_mark_visible(RID p_light_instance);
+ /* REFLECTION INSTANCE */
+
+ struct GIProbeInstance : public RID_Data {
+ RID data;
+ GLuint tex_cache;
+ Vector3 cell_size_cache;
+ Vector3 bounds;
+ Transform transform_to_data;
+ };
+
+
+
+ mutable RID_Owner<GIProbeInstance> gi_probe_instance_owner;
+
+ virtual RID gi_probe_instance_create();
+ virtual void gi_probe_instance_set_light_data(RID p_probe,RID p_data);
+ virtual void gi_probe_instance_set_transform_to_data(RID p_probe,const Transform& p_xform);
+ virtual void gi_probe_instance_set_bounds(RID p_probe,const Vector3& p_bounds);
+
/* RENDER LIST */
struct RenderList {
@@ -541,8 +560,9 @@ public:
SORT_KEY_DEPTH_LAYER_SHIFT=60,
SORT_KEY_UNSHADED_FLAG=uint64_t(1)<<59,
SORT_KEY_NO_DIRECTIONAL_FLAG=uint64_t(1)<<58,
- SORT_KEY_SHADING_SHIFT=58,
- SORT_KEY_SHADING_MASK=3,
+ SORT_KEY_GI_PROBES_FLAG=uint64_t(1)<<57,
+ SORT_KEY_SHADING_SHIFT=57,
+ SORT_KEY_SHADING_MASK=7,
SORT_KEY_MATERIAL_INDEX_SHIFT=40,
SORT_KEY_GEOMETRY_INDEX_SHIFT=20,
SORT_KEY_GEOMETRY_TYPE_SHIFT=15,
@@ -669,7 +689,7 @@ public:
_FORCE_INLINE_ void _setup_transform(InstanceBase *p_instance,const Transform& p_view_transform,const CameraMatrix& p_projection);
_FORCE_INLINE_ void _setup_geometry(RenderList::Element *e);
_FORCE_INLINE_ void _render_geometry(RenderList::Element *e);
- _FORCE_INLINE_ void _setup_light(RenderList::Element *e);
+ _FORCE_INLINE_ void _setup_light(RenderList::Element *e,const Transform& p_view_transform);
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);
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
index cfa50f6100..8262487f9d 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/drivers/gles3/rasterizer_storage_gles3.cpp
@@ -1514,6 +1514,7 @@ void RasterizerStorageGLES3::_update_shader(Shader* p_shader) const {
p_shader->valid=true;
p_shader->version++;
+
}
void RasterizerStorageGLES3::update_dirty_shaders() {
@@ -3600,16 +3601,15 @@ void RasterizerStorageGLES3::multimesh_instance_set_color(RID p_multimesh,int p_
ERR_FAIL_COND(multimesh->color_format==VS::MULTIMESH_COLOR_NONE);
int stride = multimesh->color_floats+multimesh->xform_floats;
- float *dataptr=&multimesh->data[stride*p_index+multimesh->color_floats];
+ float *dataptr=&multimesh->data[stride*p_index+multimesh->xform_floats];
if (multimesh->color_format==VS::MULTIMESH_COLOR_8BIT) {
- union {
- uint32_t colu;
- float colf;
- } cu;
- cu.colu=p_color.to_32();
- dataptr[ 0]=cu.colf;
+ uint8_t *data8=(uint8_t*)dataptr;
+ data8[0]=CLAMP(p_color.r*255.0,0,255);
+ data8[1]=CLAMP(p_color.g*255.0,0,255);
+ data8[2]=CLAMP(p_color.b*255.0,0,255);
+ data8[3]=CLAMP(p_color.a*255.0,0,255);
} else if (multimesh->color_format==VS::MULTIMESH_COLOR_FLOAT) {
dataptr[ 0]=p_color.r;
@@ -3701,7 +3701,7 @@ Color RasterizerStorageGLES3::multimesh_instance_get_color(RID p_multimesh,int p
float colf;
} cu;
- return Color::hex(cu.colu);
+ return Color::hex(BSWAP32(cu.colu));
} else if (multimesh->color_format==VS::MULTIMESH_COLOR_FLOAT) {
Color c;
@@ -4385,6 +4385,15 @@ float RasterizerStorageGLES3::light_get_param(RID p_light,VS::LightParam p_param
return light->param[p_param];
}
+Color RasterizerStorageGLES3::light_get_color(RID p_light) {
+
+ const Light * light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light,Color());
+
+ return light->color;
+
+}
+
bool RasterizerStorageGLES3::light_has_shadow(RID p_light) const {
const Light * light = light_owner.getornull(p_light);
@@ -4668,6 +4677,261 @@ void RasterizerStorageGLES3::portal_set_disabled_color(RID p_portal, const Color
}
+RID RasterizerStorageGLES3::gi_probe_create() {
+
+ GIProbe *gip = memnew( GIProbe );
+
+ gip->data_width=0;
+ gip->data_height=0;
+ gip->data_depth=0;
+ gip->bounds=AABB(Vector3(),Vector3(1,1,1));
+ gip->dynamic_range=1.0;
+ gip->version=1;
+ gip->cell_size=1.0;
+
+ return gi_probe_owner.make_rid(gip);
+}
+
+void RasterizerStorageGLES3::gi_probe_set_bounds(RID p_probe,const AABB& p_bounds){
+
+ GIProbe *gip = gi_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND(!gip);
+
+ gip->bounds=p_bounds;
+ gip->version++;
+ gip->instance_change_notify();
+}
+AABB RasterizerStorageGLES3::gi_probe_get_bounds(RID p_probe) const{
+
+ const GIProbe *gip = gi_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND_V(!gip,AABB());
+
+ return gip->bounds;
+}
+
+void RasterizerStorageGLES3::gi_probe_set_cell_size(RID p_probe,float p_size) {
+
+ GIProbe *gip = gi_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND(!gip);
+
+ gip->cell_size=p_size;
+ gip->version++;
+ gip->instance_change_notify();
+}
+
+float RasterizerStorageGLES3::gi_probe_get_cell_size(RID p_probe) const {
+
+ const GIProbe *gip = gi_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND_V(!gip,0);
+
+ return gip->cell_size;
+
+}
+
+void RasterizerStorageGLES3::gi_probe_set_to_cell_xform(RID p_probe,const Transform& p_xform) {
+
+ GIProbe *gip = gi_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND(!gip);
+
+ gip->to_cell=p_xform;
+}
+
+Transform RasterizerStorageGLES3::gi_probe_get_to_cell_xform(RID p_probe) const {
+
+ const GIProbe *gip = gi_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND_V(!gip,Transform());
+
+ return gip->to_cell;
+
+}
+
+
+
+void RasterizerStorageGLES3::gi_probe_set_dynamic_data(RID p_probe,const DVector<int>& p_data){
+ GIProbe *gip = gi_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND(!gip);
+
+ gip->dynamic_data=p_data;
+ gip->version++;
+ gip->instance_change_notify();
+
+}
+DVector<int> RasterizerStorageGLES3::gi_probe_get_dynamic_data(RID p_probe) const{
+
+ const GIProbe *gip = gi_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND_V(!gip,DVector<int>());
+
+ return gip->dynamic_data;
+}
+
+void RasterizerStorageGLES3::gi_probe_set_dynamic_range(RID p_probe,float p_range){
+
+ GIProbe *gip = gi_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND(!gip);
+
+ gip->dynamic_range=p_range;
+
+}
+float RasterizerStorageGLES3::gi_probe_get_dynamic_range(RID p_probe) const{
+
+ const GIProbe *gip = gi_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND_V(!gip,0);
+
+ return gip->dynamic_range;
+}
+
+
+void RasterizerStorageGLES3::gi_probe_set_static_data(RID p_gi_probe,const DVector<uint8_t>& p_data,VS::GIProbeDataFormat p_format,int p_width,int p_height,int p_depth) {
+
+ GIProbe *gip = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND(!gip);
+
+ if (gip->data.is_valid()) {
+ free(gip->data);
+ }
+
+ gip->data=RID();
+ //this is platform dependent
+
+ gip->version++;
+ gip->instance_change_notify();
+
+}
+DVector<uint8_t> RasterizerStorageGLES3::gi_probe_get_static_data(RID p_gi_probe) const {
+
+ const GIProbe *gip = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gip,DVector<uint8_t>());
+
+ //platform dependent
+ return DVector<uint8_t>();
+}
+VS::GIProbeDataFormat RasterizerStorageGLES3::gi_probe_get_static_data_format(RID p_gi_probe) const {
+
+ const GIProbe *gip = gi_probe_owner.getornull(p_gi_probe);
+ ERR_FAIL_COND_V(!gip,VS::GI_PROBE_DATA_RGBA8);
+
+ return gip->data_format;
+}
+int RasterizerStorageGLES3::gi_probe_get_static_data_width(RID p_probe) const {
+
+ const GIProbe *gip = gi_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND_V(!gip,0);
+
+ return gip->data_width;
+}
+int RasterizerStorageGLES3::gi_probe_get_static_data_height(RID p_probe) const {
+
+ const GIProbe *gip = gi_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND_V(!gip,0);
+ return gip->data_height;
+}
+int RasterizerStorageGLES3::gi_probe_get_static_data_depth(RID p_probe) const {
+
+ const GIProbe *gip = gi_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND_V(!gip,0);
+ return gip->data_depth;
+}
+
+RID RasterizerStorageGLES3::gi_probe_get_data(RID p_probe) {
+
+ const GIProbe *gip = gi_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND_V(!gip,RID());
+
+ return gip->data;
+}
+
+uint32_t RasterizerStorageGLES3::gi_probe_get_version(RID p_probe) {
+
+ const GIProbe *gip = gi_probe_owner.getornull(p_probe);
+ ERR_FAIL_COND_V(!gip,0);
+
+ return gip->version;
+}
+
+RID RasterizerStorageGLES3::gi_probe_dynamic_data_create(int p_width,int p_height,int p_depth) {
+
+ GIProbeData *gipd = memnew( GIProbeData );
+
+ gipd->width=p_width;
+ gipd->height=p_height;
+ gipd->depth=p_depth;
+
+ glActiveTexture(GL_TEXTURE0);
+ glGenTextures(1,&gipd->tex_id);
+ glBindTexture(GL_TEXTURE_3D,gipd->tex_id);
+
+ int level=0;
+
+ print_line("dyndata create");
+ while(true) {
+
+ Vector<uint8_t> data;
+ data.resize(p_width*p_height*p_depth*4);
+
+
+ for(int i=0;i<data.size();i+=4) {
+
+ data[i+0]=0xFF;
+ data[i+1]=0x00;
+ data[i+2]=0xFF;
+ data[i+3]=0xFF;
+ }
+
+ glTexImage3D(GL_TEXTURE_3D,level,GL_RGBA8,p_width,p_height,p_depth,0,GL_RGBA,GL_UNSIGNED_BYTE,data.ptr());
+ if (p_width<=1 || p_height<=1 || p_depth<=1)
+ break;
+ p_width>>=1;
+ p_height>>=1;
+ p_depth>>=1;
+ level++;
+ }
+
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, level);
+
+ gipd->levels=level+1;
+
+ return gi_probe_data_owner.make_rid(gipd);
+}
+
+void RasterizerStorageGLES3::gi_probe_dynamic_data_update_rgba8(RID p_gi_probe_data, int p_depth_slice, int p_slice_count, int p_mipmap, const void *p_data) {
+
+ GIProbeData *gipd = gi_probe_data_owner.getornull(p_gi_probe_data);
+ ERR_FAIL_COND(!gipd);
+/*
+ Vector<uint8_t> data;
+ data.resize((gipd->width>>p_mipmap)*(gipd->height>>p_mipmap)*(gipd->depth>>p_mipmap)*4);
+
+ for(int i=0;i<(gipd->width>>p_mipmap);i++) {
+ for(int j=0;j<(gipd->height>>p_mipmap);j++) {
+ for(int k=0;k<(gipd->depth>>p_mipmap);k++) {
+
+ int ofs = (k*(gipd->height>>p_mipmap)*(gipd->width>>p_mipmap)) + j *(gipd->width>>p_mipmap) + i;
+ ofs*=4;
+ data[ofs+0]=i*0xFF/(gipd->width>>p_mipmap);
+ data[ofs+1]=j*0xFF/(gipd->height>>p_mipmap);
+ data[ofs+2]=k*0xFF/(gipd->depth>>p_mipmap);
+ data[ofs+3]=0xFF;
+ }
+ }
+ }
+*/
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_3D,gipd->tex_id);
+ glTexSubImage3D(GL_TEXTURE_3D,p_mipmap,0,0,p_depth_slice,gipd->width>>p_mipmap,gipd->height>>p_mipmap,p_slice_count,GL_RGBA,GL_UNSIGNED_BYTE,p_data);
+ //glTexImage3D(GL_TEXTURE_3D,p_mipmap,GL_RGBA8,gipd->width>>p_mipmap,gipd->height>>p_mipmap,gipd->depth>>p_mipmap,0,GL_RGBA,GL_UNSIGNED_BYTE,p_data);
+ //glTexImage3D(GL_TEXTURE_3D,p_mipmap,GL_RGBA8,gipd->width>>p_mipmap,gipd->height>>p_mipmap,gipd->depth>>p_mipmap,0,GL_RGBA,GL_UNSIGNED_BYTE,data.ptr());
+ print_line("update rgba8 "+itos(p_mipmap));
+}
+
+
+
+
void RasterizerStorageGLES3::instance_add_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance) {
Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
@@ -4709,6 +4973,10 @@ void RasterizerStorageGLES3::instance_add_dependency(RID p_base,RasterizerScene:
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;
default: {
if (!inst) {
ERR_FAIL();
@@ -4744,6 +5012,10 @@ void RasterizerStorageGLES3::instance_remove_dependency(RID p_base,RasterizerSce
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;
default: {
if (!inst) {
@@ -5395,19 +5667,27 @@ VS::InstanceType RasterizerStorageGLES3::get_base_type(RID p_rid) const {
if (mesh_owner.owns(p_rid)) {
return VS::INSTANCE_MESH;
}
+
if (multimesh_owner.owns(p_rid)) {
return VS::INSTANCE_MULTIMESH;
}
+
if (immediate_owner.owns(p_rid)) {
return VS::INSTANCE_IMMEDIATE;
}
+
if (light_owner.owns(p_rid)) {
return VS::INSTANCE_LIGHT;
}
+
if (reflection_probe_owner.owns(p_rid)) {
return VS::INSTANCE_REFLECTION_PROBE;
}
+ if (gi_probe_owner.owns(p_rid)) {
+ return VS::INSTANCE_GI_PROBE;
+ }
+
return VS::INSTANCE_NONE;
}
@@ -5561,6 +5841,27 @@ bool RasterizerStorageGLES3::free(RID p_rid){
reflection_probe_owner.free(p_rid);
memdelete(reflection_probe);
+ } else if (gi_probe_owner.owns(p_rid)) {
+
+ // delete the texture
+ GIProbe *gi_probe = gi_probe_owner.get(p_rid);
+
+ if (gi_probe->data.is_valid()) {
+ free(gi_probe->data);
+ }
+
+ gi_probe_owner.free(p_rid);
+ memdelete(gi_probe);
+ } else if (gi_probe_data_owner.owns(p_rid)) {
+
+ // delete the texture
+ GIProbeData *gi_probe_data = gi_probe_data_owner.get(p_rid);
+
+ print_line("dyndata delete");
+ glDeleteTextures(1,&gi_probe_data->tex_id);
+ gi_probe_owner.free(p_rid);
+ memdelete(gi_probe_data);
+
} else if (canvas_occluder_owner.owns(p_rid)) {
diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h
index 7802b28158..b81c3df78a 100644
--- a/drivers/gles3/rasterizer_storage_gles3.h
+++ b/drivers/gles3/rasterizer_storage_gles3.h
@@ -799,6 +799,7 @@ public:
virtual VS::LightType light_get_type(RID p_light) const;
virtual float light_get_param(RID p_light,VS::LightParam p_param);
+ virtual Color light_get_color(RID p_light);
virtual AABB light_get_aabb(RID p_light) const;
virtual uint64_t light_get_version(RID p_light) const;
@@ -868,6 +869,84 @@ public:
virtual void portal_set_disable_distance(RID p_portal, float p_distance);
virtual void portal_set_disabled_color(RID p_portal, const Color& p_color);
+
+
+
+
+
+
+ /* GI PROBE API */
+
+ struct GIProbe : public Instantiable {
+
+
+ AABB bounds;
+ Transform to_cell;
+ float cell_size;
+
+ float dynamic_range;
+
+ uint32_t version;
+
+ DVector<int> dynamic_data;
+
+ RID data;
+ int data_width;
+ int data_height;
+ int data_depth;
+ VS::GIProbeDataFormat data_format;
+
+
+ };
+
+ mutable RID_Owner<GIProbe> gi_probe_owner;
+
+ virtual RID gi_probe_create();
+
+ virtual void gi_probe_set_bounds(RID p_probe,const AABB& p_bounds);
+ virtual AABB gi_probe_get_bounds(RID p_probe) const;
+
+ virtual void gi_probe_set_cell_size(RID p_probe, float p_size);
+ virtual float gi_probe_get_cell_size(RID p_probe) const;
+
+ virtual void gi_probe_set_to_cell_xform(RID p_probe,const Transform& p_xform);
+ virtual Transform gi_probe_get_to_cell_xform(RID p_probe) const;
+
+ virtual void gi_probe_set_dynamic_data(RID p_probe,const DVector<int>& p_data);
+ virtual DVector<int> gi_probe_get_dynamic_data(RID p_probe) const;
+
+ virtual void gi_probe_set_dynamic_range(RID p_probe,float p_range);
+ virtual float gi_probe_get_dynamic_range(RID p_probe) const;
+
+
+ virtual void gi_probe_set_static_data(RID p_gi_probe,const DVector<uint8_t>& p_data,VS::GIProbeDataFormat p_format,int p_width,int p_height,int p_depth);
+ virtual DVector<uint8_t> gi_probe_get_static_data(RID p_gi_probe) const;
+ virtual VS::GIProbeDataFormat gi_probe_get_static_data_format(RID p_gi_probe) const;
+ virtual int gi_probe_get_static_data_width(RID p_probe) const;
+ virtual int gi_probe_get_static_data_height(RID p_probe) const;
+ virtual int gi_probe_get_static_data_depth(RID p_probe) const;
+
+ virtual RID gi_probe_get_data(RID p_probe); //get data in case this is static
+ virtual uint32_t gi_probe_get_version(RID p_probe);
+
+ struct GIProbeData : public RID_Data {
+
+ int width;
+ int height;
+ int depth;
+ int levels;
+ GLuint tex_id;
+
+ GIProbeData() {
+ }
+ };
+
+ mutable RID_Owner<GIProbeData> gi_probe_data_owner;
+
+ virtual RID gi_probe_dynamic_data_create(int p_width,int p_height,int p_depth);
+ virtual void gi_probe_dynamic_data_update_rgba8(RID p_gi_probe_data,int p_depth_slice,int p_slice_count,int p_mipmap,const void* p_data);
+
+
virtual void instance_add_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance);
virtual void instance_remove_skeleton(RID p_skeleton,RasterizerScene::InstanceBase *p_instance);
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index 61e9e37d2b..bf561a7e46 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -838,6 +838,131 @@ void reflection_process(int idx, vec3 vertex, vec3 normal,vec3 binormal, vec3 ta
}
}
+#ifdef USE_GI_PROBES
+
+uniform mediump sampler3D gi_probe1; //texunit:-6
+uniform highp mat4 gi_probe_xform1;
+uniform highp vec3 gi_probe_bounds1;
+uniform highp vec3 gi_probe_cell_size1;
+
+uniform mediump sampler3D gi_probe2; //texunit:-7
+uniform highp mat4 gi_probe_xform2;
+uniform highp vec3 gi_probe_bounds2;
+uniform highp vec3 gi_probe_cell_size2;
+uniform bool gi_probe2_enabled;
+
+vec3 voxel_cone_trace(sampler3D probe, vec3 cell_size, vec3 pos, vec3 direction, float tan_half_angle, float max_distance) {
+
+
+ float dist = dot(direction,mix(vec3(-1.0),vec3(1.0),greaterThan(direction,vec3(0.0))))*2.0;
+ float alpha=0.0;
+ vec4 color = vec4(0.0);
+
+ while(dist < max_distance && alpha < 0.95) {
+ float diameter = max(1.0, 2.0 * tan_half_angle * dist);
+ vec4 scolor = textureLod(probe, (pos + dist * direction) * cell_size, log2(diameter) );
+ float a = (1.0 - alpha);
+ color.rgb += a * scolor.rgb;
+ alpha += a * scolor.a;
+ dist += diameter * 0.5;
+ }
+
+ return color.rgb;
+}
+
+void gi_probe_compute(sampler3D probe, mat4 probe_xform, vec3 bounds,vec3 cell_size,vec3 pos, mat3 normal_mtx,vec3 ref_vec, float roughness, out vec4 out_spec, out vec4 out_diff) {
+
+
+
+ vec3 probe_pos = (probe_xform * vec4(pos,1.0)).xyz;
+ vec3 ref_pos = (probe_xform * vec4(pos+ref_vec,1.0)).xyz;
+
+ ref_vec = normalize(ref_pos - probe_pos);
+
+/* out_diff.rgb = voxel_cone_trace(probe,cell_size,probe_pos,normalize((probe_xform * vec4(ref_vec,0.0)).xyz),0.0 ,100.0);
+ out_diff.a = 1.0;
+ return;*/
+ //out_diff = vec4(textureLod(probe,probe_pos*cell_size,3.0).rgb,1.0);
+ //return;
+
+ if (any(bvec2(any(lessThan(probe_pos,vec3(0.0))),any(greaterThan(probe_pos,bounds)))))
+ return;
+
+ vec3 blendv = probe_pos/bounds * 2.0 - 1.0;
+ float blend = 1.001-max(blendv.x,max(blendv.y,blendv.z));
+ blend=1.0;
+
+ //radiance
+
+#define MAX_CONE_DIRS 6
+ vec3 cone_dirs[MAX_CONE_DIRS] = vec3[] (
+ vec3(0, 0, 1),
+ vec3(0.866025, 0, 0.5),
+ vec3(0.267617, 0.823639, 0.5),
+ vec3(-0.700629, 0.509037, 0.5),
+ vec3(-0.700629, -0.509037, 0.5),
+ vec3(0.267617, -0.823639, 0.5)
+ );
+
+ float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.15, 0.15, 0.15, 0.15, 0.15);
+
+ float max_distance = length(bounds);
+ vec3 light=vec3(0.0);
+ for(int i=0;i<MAX_CONE_DIRS;i++) {
+
+ vec3 dir = normalize( (probe_xform * vec4(pos + normal_mtx * cone_dirs[i],1.0)).xyz - probe_pos);
+ light+=cone_weights[i] * voxel_cone_trace(probe,cell_size,probe_pos,dir,0.577,max_distance);
+
+ }
+
+ out_diff = vec4(light*blend,blend);
+
+ //irradiance
+
+ vec3 irr_light = voxel_cone_trace(probe,cell_size,probe_pos,ref_vec,tan(roughness * 0.5 * M_PI) ,max_distance);
+ //irr_light=vec3(0.0);
+
+ out_spec = vec4(irr_light*blend,blend);
+}
+
+
+void gi_probes_compute(vec3 pos, vec3 normal, float roughness, vec3 specular, inout vec3 out_specular, inout vec3 out_ambient) {
+
+
+ vec3 ref_vec = normalize(reflect(normalize(pos),normal));
+
+ //find arbitrary tangent and bitangent, then build a matrix
+ vec3 v0 = abs(normal.z) < 0.999 ? vec3(0, 0, 1) : vec3(0, 1, 0);
+ vec3 tangent = normalize(cross(v0, normal));
+ vec3 bitangent = normalize(cross(tangent, normal));
+ mat3 normal_mat = mat3(tangent,bitangent,normal);
+
+ vec4 diff_accum = vec4(0.0);
+ vec4 spec_accum = vec4(0.0);
+
+ gi_probe_compute(gi_probe1,gi_probe_xform1,gi_probe_bounds1,gi_probe_cell_size1,pos,normal_mat,ref_vec,roughness,spec_accum,diff_accum);
+
+ if (gi_probe2_enabled) {
+
+ gi_probe_compute(gi_probe2,gi_probe_xform2,gi_probe_bounds2,gi_probe_cell_size2,pos,normal_mat,ref_vec,roughness,spec_accum,diff_accum);
+ }
+
+ if (diff_accum.a>0.0) {
+ diff_accum.rgb/=diff_accum.a;
+ }
+
+ if (spec_accum.a>0.0) {
+ spec_accum.rgb/=spec_accum.a;
+ }
+
+ out_specular+=spec_accum.rgb;
+ out_ambient+=diff_accum.rgb;
+
+}
+
+#endif
+
+
void main() {
#ifdef RENDER_SHADOW_DUAL_PARABOLOID
@@ -1161,21 +1286,27 @@ FRAGMENT_SHADER_CODE
#endif //#USE_LIGHT_DIRECTIONAL
+#ifdef USE_GI_PROBES
+ gi_probes_compute(vertex,normal,roughness,specular,specular_light,ambient_light);
+#endif
+
#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,binormal,tangent,roughness,anisotropy,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+=reflection_accum.rgb/reflection_accum.a;
}
if (ambient_accum.a>0.0) {
- ambient_light=ambient_accum.rgb/ambient_accum.a;
+ ambient_light+=ambient_accum.rgb/ambient_accum.a;
}
for(int i=0;i<omni_light_count;i++) {
diff --git a/scene/3d/baked_light_instance.cpp b/scene/3d/baked_light_instance.cpp
index 07f0e4ee57..29b66b270a 100644
--- a/scene/3d/baked_light_instance.cpp
+++ b/scene/3d/baked_light_instance.cpp
@@ -28,83 +28,1737 @@
/*************************************************************************/
#include "baked_light_instance.h"
#include "scene/scene_string_names.h"
+#include "mesh_instance.h"
+#include "light.h"
+#include "math.h"
+#define FINDMINMAX(x0,x1,x2,min,max) \
+ min = max = x0; \
+ if(x1<min) min=x1;\
+ if(x1>max) max=x1;\
+ if(x2<min) min=x2;\
+ if(x2>max) max=x2;
+
+static bool planeBoxOverlap(Vector3 normal,float d, Vector3 maxbox)
+{
+ int q;
+ Vector3 vmin,vmax;
+ for(q=0;q<=2;q++)
+ {
+ if(normal[q]>0.0f)
+ {
+ vmin[q]=-maxbox[q];
+ vmax[q]=maxbox[q];
+ }
+ else
+ {
+ vmin[q]=maxbox[q];
+ vmax[q]=-maxbox[q];
+ }
+ }
+ if(normal.dot(vmin)+d>0.0f) return false;
+ if(normal.dot(vmax)+d>=0.0f) return true;
+
+ return false;
+}
+
+
+/*======================== X-tests ========================*/
+#define AXISTEST_X01(a, b, fa, fb) \
+ p0 = a*v0.y - b*v0.z; \
+ p2 = a*v2.y - b*v2.z; \
+ if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;} \
+ rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \
+ if(min>rad || max<-rad) return false;
+
+#define AXISTEST_X2(a, b, fa, fb) \
+ p0 = a*v0.y - b*v0.z; \
+ p1 = a*v1.y - b*v1.z; \
+ if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
+ rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \
+ if(min>rad || max<-rad) return false;
+
+/*======================== Y-tests ========================*/
+#define AXISTEST_Y02(a, b, fa, fb) \
+ p0 = -a*v0.x + b*v0.z; \
+ p2 = -a*v2.x + b*v2.z; \
+ if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;} \
+ rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \
+ if(min>rad || max<-rad) return false;
+
+#define AXISTEST_Y1(a, b, fa, fb) \
+ p0 = -a*v0.x + b*v0.z; \
+ p1 = -a*v1.x + b*v1.z; \
+ if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
+ rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \
+ if(min>rad || max<-rad) return false;
+
+/*======================== Z-tests ========================*/
+
+#define AXISTEST_Z12(a, b, fa, fb) \
+ p1 = a*v1.x - b*v1.y; \
+ p2 = a*v2.x - b*v2.y; \
+ if(p2<p1) {min=p2; max=p1;} else {min=p1; max=p2;} \
+ rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \
+ if(min>rad || max<-rad) return false;
+
+#define AXISTEST_Z0(a, b, fa, fb) \
+ p0 = a*v0.x - b*v0.y; \
+ p1 = a*v1.x - b*v1.y; \
+ if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
+ rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \
+ if(min>rad || max<-rad) return false;
+
+static bool fast_tri_box_overlap(const Vector3& boxcenter,const Vector3 boxhalfsize,const Vector3 *triverts) {
+
+ /* use separating axis theorem to test overlap between triangle and box */
+ /* need to test for overlap in these directions: */
+ /* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */
+ /* we do not even need to test these) */
+ /* 2) normal of the triangle */
+ /* 3) crossproduct(edge from tri, {x,y,z}-directin) */
+ /* this gives 3x3=9 more tests */
+ Vector3 v0,v1,v2;
+ float min,max,d,p0,p1,p2,rad,fex,fey,fez;
+ Vector3 normal,e0,e1,e2;
+
+ /* This is the fastest branch on Sun */
+ /* move everything so that the boxcenter is in (0,0,0) */
+
+ v0=triverts[0]-boxcenter;
+ v1=triverts[1]-boxcenter;
+ v2=triverts[2]-boxcenter;
+
+ /* compute triangle edges */
+ e0=v1-v0; /* tri edge 0 */
+ e1=v2-v1; /* tri edge 1 */
+ e2=v0-v2; /* tri edge 2 */
+
+ /* Bullet 3: */
+ /* test the 9 tests first (this was faster) */
+ fex = Math::abs(e0.x);
+ fey = Math::abs(e0.y);
+ fez = Math::abs(e0.z);
+ AXISTEST_X01(e0.z, e0.y, fez, fey);
+ AXISTEST_Y02(e0.z, e0.x, fez, fex);
+ AXISTEST_Z12(e0.y, e0.x, fey, fex);
+
+ fex = Math::abs(e1.x);
+ fey = Math::abs(e1.y);
+ fez = Math::abs(e1.z);
+ AXISTEST_X01(e1.z, e1.y, fez, fey);
+ AXISTEST_Y02(e1.z, e1.x, fez, fex);
+ AXISTEST_Z0(e1.y, e1.x, fey, fex);
+
+ fex = Math::abs(e2.x);
+ fey = Math::abs(e2.y);
+ fez = Math::abs(e2.z);
+ AXISTEST_X2(e2.z, e2.y, fez, fey);
+ AXISTEST_Y1(e2.z, e2.x, fez, fex);
+ AXISTEST_Z12(e2.y, e2.x, fey, fex);
+
+ /* Bullet 1: */
+ /* first test overlap in the {x,y,z}-directions */
+ /* find min, max of the triangle each direction, and test for overlap in */
+ /* that direction -- this is equivalent to testing a minimal AABB around */
+ /* the triangle against the AABB */
+
+ /* test in X-direction */
+ FINDMINMAX(v0.x,v1.x,v2.x,min,max);
+ if(min>boxhalfsize.x || max<-boxhalfsize.x) return false;
+
+ /* test in Y-direction */
+ FINDMINMAX(v0.y,v1.y,v2.y,min,max);
+ if(min>boxhalfsize.y || max<-boxhalfsize.y) return false;
+
+ /* test in Z-direction */
+ FINDMINMAX(v0.z,v1.z,v2.z,min,max);
+ if(min>boxhalfsize.z || max<-boxhalfsize.z) return false;
+
+ /* Bullet 2: */
+ /* test if the box intersects the plane of the triangle */
+ /* compute plane equation of triangle: normal*x+d=0 */
+ normal=e0.cross(e1);
+ d=-normal.dot(v0); /* plane eq: normal.x+d=0 */
+ if(!planeBoxOverlap(normal,d,boxhalfsize)) return false;
+
+ return true; /* box and triangle overlaps */
+}
+
+
+Vector<Color> BakedLight::_get_bake_texture(Image &p_image,const Color& p_color) {
+
+ Vector<Color> ret;
+
+ if (p_image.empty()) {
+
+ ret.resize(bake_texture_size*bake_texture_size);
+ for(int i=0;i<bake_texture_size*bake_texture_size;i++) {
+ ret[i]=p_color;
+ }
+
+ return ret;
+ }
+
+ p_image.convert(Image::FORMAT_RGBA8);
+ p_image.resize(bake_texture_size,bake_texture_size,Image::INTERPOLATE_CUBIC);
+
+
+ DVector<uint8_t>::Read r = p_image.get_data().read();
+ ret.resize(bake_texture_size*bake_texture_size);
+
+ for(int i=0;i<bake_texture_size*bake_texture_size;i++) {
+ Color c;
+ c.r = r[i*4+0]/255.0;
+ c.g = r[i*4+1]/255.0;
+ c.b = r[i*4+2]/255.0;
+ c.a = r[i*4+3]/255.0;
+ ret[i]=c;
+
+ }
+
+ return ret;
+}
+
+
+BakedLight::MaterialCache BakedLight::_get_material_cache(Ref<Material> p_material) {
+
+ //this way of obtaining materials is inaccurate and also does not support some compressed formats very well
+ Ref<FixedSpatialMaterial> mat = p_material;
+
+ Ref<Material> material = mat; //hack for now
+
+ if (material_cache.has(material)) {
+ return material_cache[material];
+ }
+
+ MaterialCache mc;
+
+ if (mat.is_valid()) {
+
+
+ Ref<ImageTexture> albedo_tex = mat->get_texture(FixedSpatialMaterial::TEXTURE_ALBEDO);
+
+ Image img_albedo;
+ if (albedo_tex.is_valid()) {
+
+ img_albedo = albedo_tex->get_data();
+ }
+
+ mc.albedo=_get_bake_texture(img_albedo,mat->get_albedo());
+
+ Ref<ImageTexture> emission_tex = mat->get_texture(FixedSpatialMaterial::TEXTURE_EMISSION);
+
+ Color emission_col = mat->get_emission();
+ emission_col.r*=mat->get_emission_energy();
+ emission_col.g*=mat->get_emission_energy();
+ emission_col.b*=mat->get_emission_energy();
+
+ Image img_emission;
+
+ if (emission_tex.is_valid()) {
+
+ img_emission = emission_tex->get_data();
+ }
+
+ mc.emission=_get_bake_texture(img_emission,emission_col);
+
+ } else {
+ Image empty;
+
+ mc.albedo=_get_bake_texture(empty,Color(0.7,0.7,0.7));
+ mc.emission=_get_bake_texture(empty,Color(0,0,0));
+
+
+ }
+
+ material_cache[p_material]=mc;
+ return mc;
+
+
+}
+
+
+
+static _FORCE_INLINE_ Vector2 get_uv(const Vector3& p_pos, const Vector3 *p_vtx, const Vector2* p_uv) {
+
+ if (p_pos.distance_squared_to(p_vtx[0])<CMP_EPSILON2)
+ return p_uv[0];
+ if (p_pos.distance_squared_to(p_vtx[1])<CMP_EPSILON2)
+ return p_uv[1];
+ if (p_pos.distance_squared_to(p_vtx[2])<CMP_EPSILON2)
+ return p_uv[2];
+
+ Vector3 v0 = p_vtx[1] - p_vtx[0];
+ Vector3 v1 = p_vtx[2] - p_vtx[0];
+ Vector3 v2 = p_pos - p_vtx[0];
+
+ float d00 = v0.dot( v0);
+ float d01 = v0.dot( v1);
+ float d11 = v1.dot( v1);
+ float d20 = v2.dot( v0);
+ float d21 = v2.dot( v1);
+ float denom = (d00 * d11 - d01 * d01);
+ if (denom==0)
+ return p_uv[0];
+ float v = (d11 * d20 - d01 * d21) / denom;
+ float w = (d00 * d21 - d01 * d20) / denom;
+ float u = 1.0f - v - w;
+
+ return p_uv[0]*u + p_uv[1]*v + p_uv[2]*w;
+}
+
+void BakedLight::_plot_face(int p_idx, int p_level, const Vector3 *p_vtx, const Vector2* p_uv, const MaterialCache& p_material, const AABB &p_aabb) {
+
+
+
+ if (p_level==cell_subdiv-1) {
+ //plot the face by guessing it's albedo and emission value
+
+ //find best axis to map to, for scanning values
+ int closest_axis;
+ float closest_dot;
+
+ Vector3 normal = Plane(p_vtx[0],p_vtx[1],p_vtx[2]).normal;
+
+ for(int i=0;i<3;i++) {
+
+ Vector3 axis;
+ axis[i]=1.0;
+ float dot=ABS(normal.dot(axis));
+ if (i==0 || dot>closest_dot) {
+ closest_axis=i;
+ closest_dot=dot;
+ }
+ }
+
+ Vector3 axis;
+ axis[closest_axis]=1.0;
+ Vector3 t1;
+ t1[(closest_axis+1)%3]=1.0;
+ Vector3 t2;
+ t2[(closest_axis+2)%3]=1.0;
+
+ t1*=p_aabb.size[(closest_axis+1)%3]/float(color_scan_cell_width);
+ t2*=p_aabb.size[(closest_axis+2)%3]/float(color_scan_cell_width);
+
+ Color albedo_accum;
+ Color emission_accum;
+ float alpha=0.0;
+
+ //map to a grid average in the best axis for this face
+ for(int i=0;i<color_scan_cell_width;i++) {
+
+ Vector3 ofs_i=float(i)*t1;
+
+ for(int j=0;j<color_scan_cell_width;j++) {
+
+ Vector3 ofs_j=float(j)*t2;
+
+ Vector3 from = p_aabb.pos+ofs_i+ofs_j;
+ Vector3 to = from + t1 + t2 + axis * p_aabb.size[closest_axis];
+ Vector3 half = (to-from)*0.5;
+
+ //is in this cell?
+ if (!fast_tri_box_overlap(from+half,half,p_vtx)) {
+ continue; //face does not span this cell
+ }
+
+ //go from -size to +size*2 to avoid skipping collisions
+ Vector3 ray_from = from + (t1+t2)*0.5 - axis * p_aabb.size[closest_axis];
+ Vector3 ray_to = ray_from + axis * p_aabb.size[closest_axis]*2;
+
+ Vector3 intersection;
+
+ if (!Geometry::ray_intersects_triangle(ray_from,ray_to,p_vtx[0],p_vtx[1],p_vtx[2],&intersection)) {
+ //no intersect? look in edges
+
+ float closest_dist=1e20;
+ for(int j=0;j<3;j++) {
+ Vector3 c;
+ Vector3 inters;
+ Geometry::get_closest_points_between_segments(p_vtx[j],p_vtx[(j+1)%3],ray_from,ray_to,inters,c);
+ float d=c.distance_to(intersection);
+ if (j==0 || d<closest_dist) {
+ closest_dist=d;
+ intersection=inters;
+ }
+ }
+ }
+
+ Vector2 uv = get_uv(intersection,p_vtx,p_uv);
+
+
+ int uv_x = CLAMP(Math::fposmod(uv.x,1.0)*bake_texture_size,0,bake_texture_size-1);
+ int uv_y = CLAMP(Math::fposmod(uv.y,1.0)*bake_texture_size,0,bake_texture_size-1);
+
+ int ofs = uv_y*bake_texture_size+uv_x;
+ albedo_accum.r+=p_material.albedo[ofs].r;
+ albedo_accum.g+=p_material.albedo[ofs].g;
+ albedo_accum.b+=p_material.albedo[ofs].b;
+ albedo_accum.a+=p_material.albedo[ofs].a;
+
+ emission_accum.r+=p_material.emission[ofs].r;
+ emission_accum.g+=p_material.emission[ofs].g;
+ emission_accum.b+=p_material.emission[ofs].b;
+ alpha+=1.0;
+
+ }
+ }
+
+
+ if (alpha==0) {
+ //could not in any way get texture information.. so use closest point to center
+
+ Face3 f( p_vtx[0],p_vtx[1],p_vtx[2]);
+ Vector3 inters = f.get_closest_point_to(p_aabb.pos+p_aabb.size*0.5);
+
+ Vector2 uv = get_uv(inters,p_vtx,p_uv);
+
+ int uv_x = CLAMP(Math::fposmod(uv.x,1.0)*bake_texture_size,0,bake_texture_size-1);
+ int uv_y = CLAMP(Math::fposmod(uv.y,1.0)*bake_texture_size,0,bake_texture_size-1);
+
+ int ofs = uv_y*bake_texture_size+uv_x;
+
+ alpha = 1.0/(color_scan_cell_width*color_scan_cell_width);
+
+ albedo_accum.r=p_material.albedo[ofs].r*alpha;
+ albedo_accum.g=p_material.albedo[ofs].g*alpha;
+ albedo_accum.b=p_material.albedo[ofs].b*alpha;
+ albedo_accum.a=p_material.albedo[ofs].a*alpha;
+
+ emission_accum.r=p_material.emission[ofs].r*alpha;
+ emission_accum.g=p_material.emission[ofs].g*alpha;
+ emission_accum.b=p_material.emission[ofs].b*alpha;
+
+
+ zero_alphas++;
+ } else {
+
+ float accdiv = 1.0/(color_scan_cell_width*color_scan_cell_width);
+ alpha*=accdiv;
+
+ albedo_accum.r*=accdiv;
+ albedo_accum.g*=accdiv;
+ albedo_accum.b*=accdiv;
+ albedo_accum.a*=accdiv;
+
+ emission_accum.r*=accdiv;
+ emission_accum.g*=accdiv;
+ emission_accum.b*=accdiv;
+ }
+
+ //put this temporarily here, corrected in a later step
+ bake_cells_write[p_idx].albedo[0]+=albedo_accum.r;
+ bake_cells_write[p_idx].albedo[1]+=albedo_accum.g;
+ bake_cells_write[p_idx].albedo[2]+=albedo_accum.b;
+ bake_cells_write[p_idx].light[0]+=emission_accum.r;
+ bake_cells_write[p_idx].light[1]+=emission_accum.g;
+ bake_cells_write[p_idx].light[2]+=emission_accum.b;
+ bake_cells_write[p_idx].alpha+=alpha;
+
+ static const Vector3 side_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),
+ };
+
+ for(int i=0;i<6;i++) {
+ if (normal.dot(side_normals[i])>CMP_EPSILON) {
+ bake_cells_write[p_idx].used_sides|=(1<<i);
+ }
+ }
+
+
+ } else {
+ //go down
+ for(int i=0;i<8;i++) {
+
+ AABB aabb=p_aabb;
+ aabb.size*=0.5;
+
+ if (i&1)
+ aabb.pos.x+=aabb.size.x;
+ if (i&2)
+ aabb.pos.y+=aabb.size.y;
+ if (i&4)
+ aabb.pos.z+=aabb.size.z;
+
+ {
+ AABB test_aabb=aabb;
+ //test_aabb.grow_by(test_aabb.get_longest_axis_size()*0.05); //grow a bit to avoid numerical error in real-time
+ Vector3 qsize = test_aabb.size*0.5; //quarter size, for fast aabb test
+
+ if (!fast_tri_box_overlap(test_aabb.pos+qsize,qsize,p_vtx)) {
+ //if (!Face3(p_vtx[0],p_vtx[1],p_vtx[2]).intersects_aabb2(aabb)) {
+ //does not fit in child, go on
+ continue;
+ }
+
+ }
+
+ if (bake_cells_write[p_idx].childs[i]==CHILD_EMPTY) {
+ //sub cell must be created
+
+ if (bake_cells_used==(1<<bake_cells_alloc)) {
+ //exhausted cells, creating more space
+ bake_cells_alloc++;
+ bake_cells_write=DVector<BakeCell>::Write();
+ bake_cells.resize(1<<bake_cells_alloc);
+ bake_cells_write=bake_cells.write();
+ }
+
+ bake_cells_write[p_idx].childs[i]=bake_cells_used;
+ bake_cells_level_used[p_level+1]++;
+ bake_cells_used++;
+
+
+ }
+
+
+ _plot_face(bake_cells_write[p_idx].childs[i],p_level+1,p_vtx,p_uv,p_material,aabb);
+ }
+ }
+}
+
+
+
+void BakedLight::_fixup_plot(int p_idx, int p_level,int p_x,int p_y, int p_z) {
+
+
+
+ if (p_level==cell_subdiv-1) {
+
+
+ float alpha = bake_cells_write[p_idx].alpha;
+
+ bake_cells_write[p_idx].albedo[0]/=alpha;
+ bake_cells_write[p_idx].albedo[1]/=alpha;
+ bake_cells_write[p_idx].albedo[2]/=alpha;
+
+ //transfer emission to light
+ bake_cells_write[p_idx].light[0]/=alpha;
+ bake_cells_write[p_idx].light[1]/=alpha;
+ bake_cells_write[p_idx].light[2]/=alpha;
+
+ bake_cells_write[p_idx].alpha=1.0;
+
+ //remove neighbours from used sides
+
+ for(int n=0;n<6;n++) {
+
+ int ofs[3]={0,0,0};
+
+ ofs[n/2]=(n&1)?1:-1;
+
+ //convert to x,y,z on this level
+ int x=p_x;
+ int y=p_y;
+ int z=p_z;
+
+ x+=ofs[0];
+ y+=ofs[1];
+ z+=ofs[2];
+
+ int ofs_x=0;
+ int ofs_y=0;
+ int ofs_z=0;
+ int size = 1<<p_level;
+ int half=size/2;
+
+
+ if (x<0 || x>=size || y<0 || y>=size || z<0 || z>=size) {
+ //neighbour is out, can't use it
+ bake_cells_write[p_idx].used_sides&=~(1<<uint32_t(n));
+ continue;
+ }
+
+ uint32_t neighbour=0;
+
+ for(int i=0;i<cell_subdiv-1;i++) {
+
+ BakeCell *bc = &bake_cells_write[neighbour];
+
+ int child = 0;
+ if (x >= ofs_x + half) {
+ child|=1;
+ ofs_x+=half;
+ }
+ if (y >= ofs_y + half) {
+ child|=2;
+ ofs_y+=half;
+ }
+ if (z >= ofs_z + half) {
+ child|=4;
+ ofs_z+=half;
+ }
+
+ neighbour = bc->childs[child];
+ if (neighbour==CHILD_EMPTY) {
+ break;
+ }
+
+ half>>=1;
+ }
+
+ if (neighbour!=CHILD_EMPTY) {
+ bake_cells_write[p_idx].used_sides&=~(1<<uint32_t(n));
+ }
+ }
+ } else {
+
+
+ //go down
+
+ float alpha_average=0;
+ int half = cells_per_axis >> (p_level+1);
+ for(int i=0;i<8;i++) {
+
+ uint32_t child = bake_cells_write[p_idx].childs[i];
+
+ if (child==CHILD_EMPTY)
+ continue;
+
+
+ int nx=p_x;
+ int ny=p_y;
+ int nz=p_z;
+
+ if (i&1)
+ nx+=half;
+ if (i&2)
+ ny+=half;
+ if (i&4)
+ nz+=half;
+
+ _fixup_plot(child,p_level+1,nx,ny,nz);
+ alpha_average+=bake_cells_write[child].alpha;
+ }
+
+ bake_cells_write[p_idx].alpha=alpha_average/8.0;
+ bake_cells_write[p_idx].light[0]=0;
+ bake_cells_write[p_idx].light[1]=0;
+ bake_cells_write[p_idx].light[2]=0;
+ bake_cells_write[p_idx].albedo[0]=0;
+ bake_cells_write[p_idx].albedo[1]=0;
+ bake_cells_write[p_idx].albedo[2]=0;
+
+ }
+
+ //clean up light
+ bake_cells_write[p_idx].light_pass=0;
+ //find neighbours
+
+
+
+}
+
+
+void BakedLight::_bake_add_mesh(const Transform& p_xform,Ref<Mesh>& p_mesh) {
+
+
+ for(int i=0;i<p_mesh->get_surface_count();i++) {
+
+ if (p_mesh->surface_get_primitive_type(i)!=Mesh::PRIMITIVE_TRIANGLES)
+ continue; //only triangles
+
+ MaterialCache material = _get_material_cache(p_mesh->surface_get_material(i));
+
+ Array a = p_mesh->surface_get_arrays(i);
+
+
+ DVector<Vector3> vertices = a[Mesh::ARRAY_VERTEX];
+ DVector<Vector3>::Read vr=vertices.read();
+ DVector<Vector2> uv = a[Mesh::ARRAY_TEX_UV];
+ DVector<Vector2>::Read uvr;
+ DVector<int> index = a[Mesh::ARRAY_INDEX];
+
+ bool read_uv=false;
+
+ if (uv.size()) {
+
+ uvr=uv.read();
+ read_uv=true;
+ }
+
+ if (index.size()) {
+
+ int facecount = index.size()/3;
+ DVector<int>::Read ir=index.read();
+
+ for(int j=0;j<facecount;j++) {
+
+ Vector3 vtxs[3];
+ Vector2 uvs[3];
+
+ for(int k=0;k<3;k++) {
+ vtxs[k]=p_xform.xform(vr[ir[j*3+k]]);
+ }
+
+ if (read_uv) {
+ for(int k=0;k<3;k++) {
+ uvs[k]=uvr[ir[j*3+k]];
+ }
+ }
+
+ //plot face
+ _plot_face(0,0,vtxs,uvs,material,bounds);
+ }
+
+
+
+ } else {
+
+ int facecount = vertices.size()/3;
+
+ for(int j=0;j<facecount;j++) {
+
+ Vector3 vtxs[3];
+ Vector2 uvs[3];
+
+ for(int k=0;k<3;k++) {
+ vtxs[k]=p_xform.xform(vr[j*3+k]);
+ }
+
+ if (read_uv) {
+ for(int k=0;k<3;k++) {
+ uvs[k]=uvr[j*3+k];
+ }
+ }
+
+ //plot face
+ _plot_face(0,0,vtxs,uvs,material,bounds);
+ }
+
+ }
+ }
+}
+
+
+
+void BakedLight::_bake_add_to_aabb(const Transform& p_xform,Ref<Mesh>& p_mesh,bool &first) {
+
+ for(int i=0;i<p_mesh->get_surface_count();i++) {
+
+ if (p_mesh->surface_get_primitive_type(i)!=Mesh::PRIMITIVE_TRIANGLES)
+ continue; //only triangles
+
+ Array a = p_mesh->surface_get_arrays(i);
+ DVector<Vector3> vertices = a[Mesh::ARRAY_VERTEX];
+ int vc = vertices.size();
+ DVector<Vector3>::Read vr=vertices.read();
+
+ if (first) {
+ bounds.pos=p_xform.xform(vr[0]);
+ first=false;
+ }
+
+
+ for(int j=0;j<vc;j++) {
+ bounds.expand_to(p_xform.xform(vr[j]));
+ }
+ }
+}
+
+void BakedLight::bake() {
+
+
+ bake_cells_alloc=16;
+ bake_cells.resize(1<<bake_cells_alloc);
+ bake_cells_used=1;
+ cells_per_axis=(1<<(cell_subdiv-1));
+ zero_alphas=0;
+
+ bool aabb_first=true;
+ print_line("Generating AABB");
+
+ bake_cells_level_used.resize(cell_subdiv);
+ for(int i=0;i<cell_subdiv;i++) {
+ bake_cells_level_used[i]=0;
+ }
+
+ int count=0;
+ for (Set<GeometryInstance*>::Element *E=geometries.front();E;E=E->next()) {
+
+ print_line("aabb geom "+itos(count)+"/"+itos(geometries.size()));
+
+ GeometryInstance *geom = E->get();
+
+ if (geom->cast_to<MeshInstance>()) {
+
+ MeshInstance *mesh_instance = geom->cast_to<MeshInstance>();
+ Ref<Mesh> mesh = mesh_instance->get_mesh();
+ if (mesh.is_valid()) {
+
+ _bake_add_to_aabb(geom->get_relative_transform(this),mesh,aabb_first);
+ }
+ }
+ count++;
+ }
+
+ print_line("AABB: "+bounds);
+ ERR_FAIL_COND(aabb_first);
+
+ bake_cells_write = bake_cells.write();
+ count=0;
+
+ for (Set<GeometryInstance*>::Element *E=geometries.front();E;E=E->next()) {
+
+ GeometryInstance *geom = E->get();
+ print_line("plot geom "+itos(count)+"/"+itos(geometries.size()));
+
+ if (geom->cast_to<MeshInstance>()) {
+
+ MeshInstance *mesh_instance = geom->cast_to<MeshInstance>();
+ Ref<Mesh> mesh = mesh_instance->get_mesh();
+ if (mesh.is_valid()) {
+
+ _bake_add_mesh(geom->get_relative_transform(this),mesh);
+ }
+ }
+
+ count++;
+ }
+
+
+ _fixup_plot(0, 0,0,0,0);
+
+
+ bake_cells_write=DVector<BakeCell>::Write();
+
+ bake_cells.resize(bake_cells_used);
+
+
+
+ print_line("total bake cells used: "+itos(bake_cells_used));
+ for(int i=0;i<cell_subdiv;i++) {
+ print_line("level "+itos(i)+": "+itos(bake_cells_level_used[i]));
+ }
+ print_line("zero alphas: "+itos(zero_alphas));
+
+
+
+}
+
+
+
+void BakedLight::_bake_directional(int p_idx, int p_level, int p_x,int p_y,int p_z,const Vector3& p_dir,const Color& p_color,int p_sign) {
+
+
+
+
+ if (p_level==cell_subdiv-1) {
+
+ Vector3 end;
+ end.x = float(p_x+0.5) / cells_per_axis;
+ end.y = float(p_y+0.5) / cells_per_axis;
+ end.z = float(p_z+0.5) / cells_per_axis;
+
+ end = bounds.pos + bounds.size*end;
+
+ float max_ray_len = (bounds.size).length()*1.2;
+
+ Vector3 begin = end + max_ray_len*-p_dir;
+
+ //clip begin
+
+ for(int i=0;i<3;i++) {
+
+ if (ABS(p_dir[i])<CMP_EPSILON) {
+ continue; // parallel to axis, don't clip
+ }
+
+ Plane p;
+ p.normal[i]=1.0;
+ p.d=bounds.pos[i];
+ if (p_dir[i]<0) {
+ p.d+=bounds.size[i];
+ }
+
+ Vector3 inters;
+ if (p.intersects_segment(end,begin,&inters)) {
+ begin=inters;
+ }
+
+ }
+
+
+ int idx = _plot_ray(begin,end);
+
+ if (idx>=0 && light_pass!=bake_cells_write[idx].light_pass) {
+ //hit something, add or remove light to it
+
+ Color albedo = Color(bake_cells_write[idx].albedo[0],bake_cells_write[idx].albedo[1],bake_cells_write[idx].albedo[2]);
+ bake_cells_write[idx].light[0]+=albedo.r*p_color.r*p_sign;
+ bake_cells_write[idx].light[1]+=albedo.g*p_color.g*p_sign;
+ bake_cells_write[idx].light[2]+=albedo.b*p_color.b*p_sign;
+ bake_cells_write[idx].light_pass=light_pass;
+
+ }
+
+
+ } else {
+
+ int half = cells_per_axis >> (p_level+1);
+
+ //go down
+ for(int i=0;i<8;i++) {
+
+ uint32_t child = bake_cells_write[p_idx].childs[i];
+
+ if (child==CHILD_EMPTY)
+ continue;
+
+ int nx=p_x;
+ int ny=p_y;
+ int nz=p_z;
+
+ if (i&1)
+ nx+=half;
+ if (i&2)
+ ny+=half;
+ if (i&4)
+ nz+=half;
+
+
+ _bake_directional(child,p_level+1,nx,ny,nz,p_dir,p_color,p_sign);
+ }
+ }
+}
+
+
+
+
+void BakedLight::_bake_light(Light* p_light) {
+
+ if (p_light->cast_to<DirectionalLight>()) {
+
+ DirectionalLight * dl = p_light->cast_to<DirectionalLight>();
+
+ Transform rel_xf = dl->get_relative_transform(this);
+
+ Vector3 light_dir = -rel_xf.basis.get_axis(2);
+
+ Color color = dl->get_color();
+ float nrg = dl->get_param(Light::PARAM_ENERGY);;
+ color.r*=nrg;
+ color.g*=nrg;
+ color.b*=nrg;
+
+ light_pass++;
+ _bake_directional(0,0,0,0,0,light_dir,color,1);
+
+ }
+}
+
+
+void BakedLight::_upscale_light(int p_idx,int p_level) {
+
+
+ //go down
+
+ float light_accum[3]={0,0,0};
+ float alpha_accum=0;
+
+ bool check_children = p_level < (cell_subdiv -2);
+
+ for(int i=0;i<8;i++) {
+
+ uint32_t child = bake_cells_write[p_idx].childs[i];
+
+ if (child==CHILD_EMPTY)
+ continue;
+
+ if (check_children) {
+ _upscale_light(child,p_level+1);
+ }
+
+ light_accum[0]+=bake_cells_write[child].light[0];
+ light_accum[1]+=bake_cells_write[child].light[1];
+ light_accum[2]+=bake_cells_write[child].light[2];
+ alpha_accum+=bake_cells_write[child].alpha;
+
+ }
+
+ bake_cells_write[p_idx].light[0]=light_accum[0]/8.0;
+ bake_cells_write[p_idx].light[1]=light_accum[1]/8.0;
+ bake_cells_write[p_idx].light[2]=light_accum[2]/8.0;
+ bake_cells_write[p_idx].alpha=alpha_accum/8.0;
+
+}
+
+
+void BakedLight::bake_lights() {
+
+ ERR_FAIL_COND(bake_cells.size()==0);
+
+ bake_cells_write = bake_cells.write();
+
+ for(Set<Light*>::Element *E=lights.front();E;E=E->next()) {
+
+ _bake_light(E->get());
+ }
+
+
+ _upscale_light(0,0);
+
+ bake_cells_write=DVector<BakeCell>::Write();
+
+}
+
+
+
+Color BakedLight::_cone_trace(const Vector3& p_from, const Vector3& p_dir, float p_half_angle) {
+
+
+ Color color(0,0,0,0);
+ float tha = Math::tan(p_half_angle);//tan half angle
+ Vector3 from =(p_from-bounds.pos)/bounds.size; //convert to 0..1
+ from/=cells_per_axis; //convert to voxels of size 1
+ Vector3 dir = (p_dir/bounds.size).normalized();
+
+ float max_dist = Vector3(cells_per_axis,cells_per_axis,cells_per_axis).length();
+
+ float dist = 1.0;
+ // self occlusion in flat surfaces
+
+ float alpha=0;
+
+
+ while(dist < max_dist && alpha < 0.95) {
+
+#if 0
+ // smallest sample diameter possible is the voxel size
+ float diameter = MAX(1.0, 2.0 * tha * dist);
+ float lod = log2(diameter);
+
+ Vector3 sample_pos = from + dist * dir;
+
+
+ Color samples_base[2][8]={{Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0)},
+ {Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0),Color(0,0,0,0)}};
+
+ float levelf = Math::fposmod(lod,1.0);
+ float fx = Math::fposmod(sample_pos.x,1.0);
+ float fy = Math::fposmod(sample_pos.y,1.0);
+ float fz = Math::fposmod(sample_pos.z,1.0);
+
+ for(int l=0;l<2;l++){
+
+ int bx = Math::floor(sample_pos.x);
+ int by = Math::floor(sample_pos.y);
+ int bz = Math::floor(sample_pos.z);
+
+ int lodn=int(Math::floor(lod))-l;
+
+ bx>>=lodn;
+ by>>=lodn;
+ bz>>=lodn;
+
+ int limit = MAX(0,cell_subdiv-lodn-1);
+
+ for(int c=0;c<8;c++) {
+
+ int x = bx;
+ int y = by;
+ int z = bz;
+
+ if (c&1) {
+ x+=1;
+ }
+ if (c&2) {
+ y+=1;
+ }
+ if (c&4) {
+ z+=1;
+ }
+
+ int ofs_x=0;
+ int ofs_y=0;
+ int ofs_z=0;
+ int size = cells_per_axis>>lodn;
+ int half=size/2;
+
+ bool outside=x<0 || x>=size || y<0 || y>=size || z<0 || z>=size;
+
+ if (outside)
+ continue;
+
+
+ uint32_t cell=0;
+
+ for(int i=0;i<limit;i++) {
+
+ BakeCell *bc = &bake_cells_write[cell];
+
+ int child = 0;
+ if (x >= ofs_x + half) {
+ child|=1;
+ ofs_x+=half;
+ }
+ if (y >= ofs_y + half) {
+ child|=2;
+ ofs_y+=half;
+ }
+ if (z >= ofs_z + half) {
+ child|=4;
+ ofs_z+=half;
+ }
+
+ cell = bc->childs[child];
+ if (cell==CHILD_EMPTY)
+ break;
+
+ half>>=1;
+ }
+
+ if (cell!=CHILD_EMPTY) {
+
+ samples_base[l][c].r=bake_cells_write[cell].light[0];
+ samples_base[l][c].g=bake_cells_write[cell].light[1];
+ samples_base[l][c].b=bake_cells_write[cell].light[2];
+ samples_base[l][c].a=bake_cells_write[cell].alpha;
+ }
+
+ }
+
+
+ }
+
+ Color m0x0 = samples_base[0][0].linear_interpolate(samples_base[0][1],fx);
+ Color m0x1 = samples_base[0][2].linear_interpolate(samples_base[0][3],fx);
+ Color m0y0 = m0x0.linear_interpolate(m0x1,fy);
+ m0x0 = samples_base[0][4].linear_interpolate(samples_base[0][5],fx);
+ m0x1 = samples_base[0][6].linear_interpolate(samples_base[0][7],fx);
+ Color m0y1 = m0x0.linear_interpolate(m0x1,fy);
+ Color m0z = m0y0.linear_interpolate(m0y1,fz);
+
+ Color m1x0 = samples_base[1][0].linear_interpolate(samples_base[1][1],fx);
+ Color m1x1 = samples_base[1][2].linear_interpolate(samples_base[1][3],fx);
+ Color m1y0 = m1x0.linear_interpolate(m1x1,fy);
+ m1x0 = samples_base[1][4].linear_interpolate(samples_base[1][5],fx);
+ m1x1 = samples_base[1][6].linear_interpolate(samples_base[1][7],fx);
+ Color m1y1 = m1x0.linear_interpolate(m1x1,fy);
+ Color m1z = m1y0.linear_interpolate(m1y1,fz);
+
+ Color m = m0z.linear_interpolate(m1z,levelf);
+#else
+ float diameter = 1.0;
+ Vector3 sample_pos = from + dist * dir;
+
+ Color m(0,0,0,0);
+ {
+ int x = Math::floor(sample_pos.x);
+ int y = Math::floor(sample_pos.y);
+ int z = Math::floor(sample_pos.z);
+
+ int ofs_x=0;
+ int ofs_y=0;
+ int ofs_z=0;
+ int size = cells_per_axis;
+ int half=size/2;
+
+ bool outside=x<0 || x>=size || y<0 || y>=size || z<0 || z>=size;
+
+ if (!outside) {
+
+
+ uint32_t cell=0;
+
+ for(int i=0;i<cell_subdiv-1;i++) {
+
+ BakeCell *bc = &bake_cells_write[cell];
+
+ int child = 0;
+ if (x >= ofs_x + half) {
+ child|=1;
+ ofs_x+=half;
+ }
+ if (y >= ofs_y + half) {
+ child|=2;
+ ofs_y+=half;
+ }
+ if (z >= ofs_z + half) {
+ child|=4;
+ ofs_z+=half;
+ }
+
+ cell = bc->childs[child];
+ if (cell==CHILD_EMPTY)
+ break;
+
+ half>>=1;
+ }
+
+ if (cell!=CHILD_EMPTY) {
+
+ m.r=bake_cells_write[cell].light[0];
+ m.g=bake_cells_write[cell].light[1];
+ m.b=bake_cells_write[cell].light[2];
+ m.a=bake_cells_write[cell].alpha;
+ }
+ }
+ }
+
+#endif
+ // front-to-back compositing
+ float a = (1.0 - alpha);
+ color.r += a * m.r;
+ color.g += a * m.g;
+ color.b += a * m.b;
+ alpha += a * m.a;
+ //occlusion += a * voxelColor.a;
+ //occlusion += (a * voxelColor.a) / (1.0 + 0.03 * diameter);
+ dist += diameter * 0.5; // smoother
+ //dist += diameter; // faster but misses more voxels
+ }
+
+ return color;
+}
+
+
+
+void BakedLight::_bake_radiance(int p_idx, int p_level, int p_x,int p_y,int p_z) {
+
+
+
+
+ if (p_level==cell_subdiv-1) {
+
+ const int NUM_CONES = 6;
+ Vector3 cone_directions[6] = {
+ Vector3(1, 0, 0),
+ Vector3(0.5, 0.866025, 0),
+ Vector3( 0.5, 0.267617, 0.823639),
+ Vector3( 0.5, -0.700629, 0.509037),
+ Vector3( 0.5, -0.700629, -0.509037),
+ Vector3( 0.5, 0.267617, -0.823639)
+ };
+ float coneWeights[6] = {0.25, 0.15, 0.15, 0.15, 0.15, 0.15};
+
+ Vector3 pos = (Vector3(p_x,p_y,p_z)/float(cells_per_axis))*bounds.size+bounds.pos;
+ Vector3 voxel_size = bounds.size/float(cells_per_axis);
+ pos+=voxel_size*0.5;
+
+ Color accum;
+
+ bake_cells_write[p_idx].light[0]=0;
+ bake_cells_write[p_idx].light[1]=0;
+ bake_cells_write[p_idx].light[2]=0;
+
+ int freepix=0;
+ for(int i=0;i<6;i++) {
+
+ if (!(bake_cells_write[p_idx].used_sides&(1<<i)))
+ continue;
+
+ if ((i&1)==0)
+ bake_cells_write[p_idx].light[i/2]=1.0;
+ freepix++;
+ continue;
+
+ int ofs = i/2;
+
+ Vector3 dir;
+ if ((i&1)==0)
+ dir[ofs]=1.0;
+ else
+ dir[ofs]=-1.0;
+
+ for(int j=0;j<1;j++) {
+
+
+ Vector3 cone_dir;
+ cone_dir.x = cone_directions[j][(ofs+0)%3];
+ cone_dir.y = cone_directions[j][(ofs+1)%3];
+ cone_dir.z = cone_directions[j][(ofs+2)%3];
+
+ cone_dir[ofs]*=dir[ofs];
+
+ Color res = _cone_trace(pos+dir*voxel_size,cone_dir,Math::deg2rad(29.9849));
+ accum.r+=res.r;//*coneWeights[j];
+ accum.g+=res.g;//*coneWeights[j];
+ accum.b+=res.b;//*coneWeights[j];
+ }
+
+
+ }
#if 0
+ if (freepix==0) {
+ bake_cells_write[p_idx].light[0]=0;
+ bake_cells_write[p_idx].light[1]=0;
+ bake_cells_write[p_idx].light[2]=0;
+ }
+
+ if (freepix==1) {
+ bake_cells_write[p_idx].light[0]=1;
+ bake_cells_write[p_idx].light[1]=0;
+ bake_cells_write[p_idx].light[2]=0;
+ }
+
+ if (freepix==2) {
+ bake_cells_write[p_idx].light[0]=0;
+ bake_cells_write[p_idx].light[1]=1;
+ bake_cells_write[p_idx].light[2]=0;
+ }
+
+ if (freepix==3) {
+ bake_cells_write[p_idx].light[0]=1;
+ bake_cells_write[p_idx].light[1]=1;
+ bake_cells_write[p_idx].light[2]=0;
+ }
-RID BakedLightInstance::get_baked_light_instance() const {
+ if (freepix==4) {
+ bake_cells_write[p_idx].light[0]=0;
+ bake_cells_write[p_idx].light[1]=0;
+ bake_cells_write[p_idx].light[2]=1;
+ }
- if (baked_light.is_null())
- return RID();
- else
- return get_instance();
+ if (freepix==5) {
+ bake_cells_write[p_idx].light[0]=1;
+ bake_cells_write[p_idx].light[1]=0;
+ bake_cells_write[p_idx].light[2]=1;
+ }
+ if (freepix==6) {
+ bake_cells_write[p_idx].light[0]=0;
+ bake_cells_write[p_idx].light[0]=1;
+ bake_cells_write[p_idx].light[0]=1;
+ }
+#endif
+ //bake_cells_write[p_idx].radiance[0]=accum.r;
+ //bake_cells_write[p_idx].radiance[1]=accum.g;
+ //bake_cells_write[p_idx].radiance[2]=accum.b;
+
+
+ } else {
+
+ int half = cells_per_axis >> (p_level+1);
+
+ //go down
+ for(int i=0;i<8;i++) {
+
+ uint32_t child = bake_cells_write[p_idx].childs[i];
+
+ if (child==CHILD_EMPTY)
+ continue;
+
+ int nx=p_x;
+ int ny=p_y;
+ int nz=p_z;
+
+ if (i&1)
+ nx+=half;
+ if (i&2)
+ ny+=half;
+ if (i&4)
+ nz+=half;
+
+
+ _bake_radiance(child,p_level+1,nx,ny,nz);
+ }
+ }
}
-void BakedLightInstance::set_baked_light(const Ref<BakedLight>& p_baked_light) {
+void BakedLight::bake_radiance() {
+
+ ERR_FAIL_COND(bake_cells.size()==0);
- baked_light=p_baked_light;
+ bake_cells_write = bake_cells.write();
+
+ _bake_radiance(0,0,0,0,0);
+
+ bake_cells_write=DVector<BakeCell>::Write();
+
+}
+int BakedLight::_find_cell(int x,int y, int z) {
- RID base_rid;
- if (baked_light.is_valid())
- base_rid=baked_light->get_rid();
- else
- base_rid=RID();
+ uint32_t cell=0;
- set_base(base_rid);
+ int ofs_x=0;
+ int ofs_y=0;
+ int ofs_z=0;
+ int size = cells_per_axis;
+ int half=size/2;
- if (is_inside_world()) {
+ if (x<0 || x>=size)
+ return -1;
+ if (y<0 || y>=size)
+ return -1;
+ if (z<0 || z>=size)
+ return -1;
- emit_signal(SceneStringNames::get_singleton()->baked_light_changed);
+ for(int i=0;i<cell_subdiv-1;i++) {
-// for (List<Node*>::Element *E=baked_geometry.front();E;E=E->next()) {
-// VS::get_singleton()->instance_geometry_set_baked_light(E->get()->get_instance(),baked_light.is_valid()?get_instance():RID());
-// }
+ BakeCell *bc = &bake_cells_write[cell];
+
+ int child = 0;
+ if (x >= ofs_x + half) {
+ child|=1;
+ ofs_x+=half;
+ }
+ if (y >= ofs_y + half) {
+ child|=2;
+ ofs_y+=half;
+ }
+ if (z >= ofs_z + half) {
+ child|=4;
+ ofs_z+=half;
+ }
+
+ cell = bc->childs[child];
+ if (cell==CHILD_EMPTY)
+ return -1;
+
+ half>>=1;
}
- update_configuration_warning();
+ return cell;
+
}
-Ref<BakedLight> BakedLightInstance::get_baked_light() const{
- return baked_light;
+int BakedLight::_plot_ray(const Vector3& p_from, const Vector3& p_to) {
+
+ Vector3 from = (p_from - bounds.pos) / bounds.size;
+ Vector3 to = (p_to - bounds.pos) / bounds.size;
+
+ int x1 = Math::floor(from.x*cells_per_axis);
+ int y1 = Math::floor(from.y*cells_per_axis);
+ int z1 = Math::floor(from.z*cells_per_axis);
+
+ int x2 = Math::floor(to.x*cells_per_axis);
+ int y2 = Math::floor(to.y*cells_per_axis);
+ int z2 = Math::floor(to.z*cells_per_axis);
+
+
+ int i, dx, dy, dz, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2;
+ int point[3];
+
+ point[0] = x1;
+ point[1] = y1;
+ point[2] = z1;
+ dx = x2 - x1;
+ dy = y2 - y1;
+ dz = z2 - z1;
+ x_inc = (dx < 0) ? -1 : 1;
+ l = ABS(dx);
+ y_inc = (dy < 0) ? -1 : 1;
+ m = ABS(dy);
+ z_inc = (dz < 0) ? -1 : 1;
+ n = ABS(dz);
+ dx2 = l << 1;
+ dy2 = m << 1;
+ dz2 = n << 1;
+
+ if ((l >= m) && (l >= n)) {
+ err_1 = dy2 - l;
+ err_2 = dz2 - l;
+ for (i = 0; i < l; i++) {
+ int cell = _find_cell(point[0],point[1],point[2]);
+ if (cell>=0)
+ return cell;
+
+ if (err_1 > 0) {
+ point[1] += y_inc;
+ err_1 -= dx2;
+ }
+ if (err_2 > 0) {
+ point[2] += z_inc;
+ err_2 -= dx2;
+ }
+ err_1 += dy2;
+ err_2 += dz2;
+ point[0] += x_inc;
+ }
+ } else if ((m >= l) && (m >= n)) {
+ err_1 = dx2 - m;
+ err_2 = dz2 - m;
+ for (i = 0; i < m; i++) {
+ int cell = _find_cell(point[0],point[1],point[2]);
+ if (cell>=0)
+ return cell;
+ if (err_1 > 0) {
+ point[0] += x_inc;
+ err_1 -= dy2;
+ }
+ if (err_2 > 0) {
+ point[2] += z_inc;
+ err_2 -= dy2;
+ }
+ err_1 += dx2;
+ err_2 += dz2;
+ point[1] += y_inc;
+ }
+ } else {
+ err_1 = dy2 - n;
+ err_2 = dx2 - n;
+ for (i = 0; i < n; i++) {
+ int cell = _find_cell(point[0],point[1],point[2]);
+ if (cell>=0)
+ return cell;
+
+ if (err_1 > 0) {
+ point[1] += y_inc;
+ err_1 -= dz2;
+ }
+ if (err_2 > 0) {
+ point[0] += x_inc;
+ err_2 -= dz2;
+ }
+ err_1 += dy2;
+ err_2 += dx2;
+ point[2] += z_inc;
+ }
+ }
+ return _find_cell(point[0],point[1],point[2]);
+
}
-AABB BakedLightInstance::get_aabb() const {
+
+void BakedLight::set_cell_subdiv(int p_subdiv) {
+
+ cell_subdiv=p_subdiv;
+
+// VS::get_singleton()->baked_light_set_subdivision(baked_light,p_subdiv);
+}
+
+int BakedLight::get_cell_subdiv() const {
+
+ return cell_subdiv;
+}
+
+
+
+AABB BakedLight::get_aabb() const {
return AABB(Vector3(0,0,0),Vector3(1,1,1));
}
-DVector<Face3> BakedLightInstance::get_faces(uint32_t p_usage_flags) const {
+DVector<Face3> BakedLight::get_faces(uint32_t p_usage_flags) const {
return DVector<Face3>();
}
-String BakedLightInstance::get_configuration_warning() const {
- if (get_baked_light().is_null()) {
- return TTR("BakedLightInstance does not contain a BakedLight resource.");
- }
+String BakedLight::get_configuration_warning() const {
return String();
}
-void BakedLightInstance::_bind_methods() {
+void BakedLight::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb,DebugMode p_mode,Ref<MultiMesh> &p_multimesh,int &idx) {
+
+
+ if (p_level==cell_subdiv-1) {
+
+ Vector3 center = p_aabb.pos+p_aabb.size*0.5;
+ Transform xform;
+ xform.origin=center;
+ xform.basis.scale(p_aabb.size*0.5);
+ p_multimesh->set_instance_transform(idx,xform);
+ Color col;
+ switch(p_mode) {
+ case DEBUG_ALBEDO: {
+ col=Color(bake_cells_write[p_idx].albedo[0],bake_cells_write[p_idx].albedo[1],bake_cells_write[p_idx].albedo[2]);
+ } break;
+ case DEBUG_LIGHT: {
+ col=Color(bake_cells_write[p_idx].light[0],bake_cells_write[p_idx].light[1],bake_cells_write[p_idx].light[2]);
+ Color colr=Color(bake_cells_write[p_idx].radiance[0],bake_cells_write[p_idx].radiance[1],bake_cells_write[p_idx].radiance[2]);
+ col.r+=colr.r;
+ col.g+=colr.g;
+ col.b+=colr.b;
+ } break;
+
+ }
+ p_multimesh->set_instance_color(idx,col);
+
+
+ idx++;
+
+ } else {
+
+ for(int i=0;i<8;i++) {
+
+ if (bake_cells_write[p_idx].childs[i]==CHILD_EMPTY)
+ continue;
+
+ AABB aabb=p_aabb;
+ aabb.size*=0.5;
+
+ if (i&1)
+ aabb.pos.x+=aabb.size.x;
+ if (i&2)
+ aabb.pos.y+=aabb.size.y;
+ if (i&4)
+ aabb.pos.z+=aabb.size.z;
+
+ _debug_mesh(bake_cells_write[p_idx].childs[i],p_level+1,aabb,p_mode,p_multimesh,idx);
+ }
+
+ }
+
+}
+
+
+void BakedLight::create_debug_mesh(DebugMode p_mode) {
+
+ Ref<MultiMesh> mm;
+ mm.instance();
+
+ mm->set_transform_format(MultiMesh::TRANSFORM_3D);
+ mm->set_color_format(MultiMesh::COLOR_8BIT);
+ mm->set_instance_count(bake_cells_level_used[cell_subdiv-1]);
+
+ Ref<Mesh> mesh;
+ mesh.instance();
+
+
+
+ {
+ Array arr;
+ arr.resize(Mesh::ARRAY_MAX);
+
+ DVector<Vector3> vertices;
+ DVector<Color> colors;
+
+ int vtx_idx=0;
+ #define ADD_VTX(m_idx);\
+ vertices.push_back( face_points[m_idx] );\
+ colors.push_back( Color(1,1,1,1) );\
+ vtx_idx++;\
+
+ for (int i=0;i<6;i++) {
+
+
+ Vector3 face_points[4];
+
+ for (int j=0;j<4;j++) {
+
+ float v[3];
+ v[0]=1.0;
+ v[1]=1-2*((j>>1)&1);
+ v[2]=v[1]*(1-2*(j&1));
+
+ for (int k=0;k<3;k++) {
+
+ if (i<3)
+ face_points[j][(i+k)%3]=v[k]*(i>=3?-1:1);
+ else
+ face_points[3-j][(i+k)%3]=v[k]*(i>=3?-1:1);
+ }
+ }
+
+ //tri 1
+ ADD_VTX(0);
+ ADD_VTX(1);
+ ADD_VTX(2);
+ //tri 2
+ ADD_VTX(2);
+ ADD_VTX(3);
+ ADD_VTX(0);
+
+ }
+
+
+ arr[Mesh::ARRAY_VERTEX]=vertices;
+ arr[Mesh::ARRAY_COLOR]=colors;
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES,arr);
+ }
+
+ {
+ Ref<FixedSpatialMaterial> fsm;
+ fsm.instance();
+ fsm->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR,true);
+ fsm->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR,true);
+ fsm->set_flag(FixedSpatialMaterial::FLAG_UNSHADED,true);
+ fsm->set_albedo(Color(1,1,1,1));
+
+ mesh->surface_set_material(0,fsm);
+ }
- ObjectTypeDB::bind_method(_MD("set_baked_light","baked_light"),&BakedLightInstance::set_baked_light);
- ObjectTypeDB::bind_method(_MD("get_baked_light"),&BakedLightInstance::get_baked_light);
- ObjectTypeDB::bind_method(_MD("get_baked_light_instance"),&BakedLightInstance::get_baked_light_instance);
+ mm->set_mesh(mesh);
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"baked_light",PROPERTY_HINT_RESOURCE_TYPE,"BakedLight"),_SCS("set_baked_light"),_SCS("get_baked_light"));
+
+ bake_cells_write = bake_cells.write();
+
+
+
+ int idx=0;
+ _debug_mesh(0,0,bounds,p_mode,mm,idx);
+
+ print_line("written: "+itos(idx)+" total: "+itos(bake_cells_level_used[cell_subdiv-1]));
+
+
+ MultiMeshInstance *mmi = memnew( MultiMeshInstance );
+ mmi->set_multimesh(mm);
+ add_child(mmi);
+ if (get_tree()->get_edited_scene_root()==this){
+ mmi->set_owner(this);
+ } else {
+ mmi->set_owner(get_owner());
+
+ }
+
+}
+
+void BakedLight::_debug_mesh_albedo() {
+ create_debug_mesh(DEBUG_ALBEDO);
+}
+
+void BakedLight::_debug_mesh_light() {
+ create_debug_mesh(DEBUG_LIGHT);
+}
+
+
+void BakedLight::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_cell_subdiv","steps"),&BakedLight::set_cell_subdiv);
+ ObjectTypeDB::bind_method(_MD("get_cell_subdiv"),&BakedLight::get_cell_subdiv);
+
+ ObjectTypeDB::bind_method(_MD("bake"),&BakedLight::bake);
+ ObjectTypeDB::set_method_flags(get_type_static(),_SCS("bake"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
+
+ ObjectTypeDB::bind_method(_MD("bake_lights"),&BakedLight::bake_lights);
+ ObjectTypeDB::set_method_flags(get_type_static(),_SCS("bake_lights"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
+
+ ObjectTypeDB::bind_method(_MD("bake_radiance"),&BakedLight::bake_radiance);
+ ObjectTypeDB::set_method_flags(get_type_static(),_SCS("bake_radiance"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
+
+ ObjectTypeDB::bind_method(_MD("debug_mesh_albedo"),&BakedLight::_debug_mesh_albedo);
+ ObjectTypeDB::set_method_flags(get_type_static(),_SCS("debug_mesh_albedo"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
+
+
+ ObjectTypeDB::bind_method(_MD("debug_mesh_light"),&BakedLight::_debug_mesh_light);
+ ObjectTypeDB::set_method_flags(get_type_static(),_SCS("debug_mesh_light"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"cell_subdiv"),_SCS("set_cell_subdiv"),_SCS("get_cell_subdiv"));
ADD_SIGNAL( MethodInfo("baked_light_changed"));
+
}
-BakedLightInstance::BakedLightInstance() {
+BakedLight::BakedLight() {
+// baked_light=VisualServer::get_singleton()->baked_light_create();
+ VS::get_singleton()->instance_set_base(get_instance(),baked_light);
+ cell_subdiv=8;
+ bake_texture_size=128;
+ color_scan_cell_width=8;
+ light_pass=0;
}
-/////////////////////////
+BakedLight::~BakedLight() {
+
+ VS::get_singleton()->free(baked_light);
+}
+
+/////////////////////////
+
+#if 0
void BakedLightSampler::set_param(Param p_param,float p_value) {
ERR_FAIL_INDEX(p_param,PARAM_MAX);
params[p_param]=p_value;
diff --git a/scene/3d/baked_light_instance.h b/scene/3d/baked_light_instance.h
index 15f04fea31..314e5f1450 100644
--- a/scene/3d/baked_light_instance.h
+++ b/scene/3d/baked_light_instance.h
@@ -31,38 +31,142 @@
#include "scene/3d/visual_instance.h"
#include "scene/resources/baked_light.h"
+#include "scene/3d/multimesh_instance.h"
+
-#if 0
class BakedLightBaker;
+class Light;
+
+class BakedLight : public VisualInstance {
+ OBJ_TYPE(BakedLight,VisualInstance);
+
+public:
+ enum DebugMode {
+ DEBUG_ALBEDO,
+ DEBUG_LIGHT
+ };
+
+private:
+ RID baked_light;
+ int cell_subdiv;
+ AABB bounds;
+ int cells_per_axis;
+
+ enum {
+ CHILD_EMPTY=0xFFFFFFFF,
+ };
+
+
+ /* BAKE DATA */
+
+ struct BakeCell {
+
+ uint32_t childs[8];
+ float albedo[3]; //albedo in RGB24
+ float light[3]; //accumulated light in 16:16 fixed point (needs to be integer for moving lights fast)
+ float radiance[3]; //accumulated light in 16:16 fixed point (needs to be integer for moving lights fast)
+ uint32_t used_sides;
+ float alpha; //used for upsampling
+ uint32_t light_pass; //used for baking light
+
+ BakeCell() {
+ for(int i=0;i<8;i++) {
+ childs[i]=0xFFFFFFFF;
+ }
+
+ for(int i=0;i<3;i++) {
+ light[i]=0;
+ albedo[i]=0;
+ radiance[i]=0;
+ }
+ alpha=0;
+ light_pass=0;
+ used_sides=0;
+ }
+ };
+
+
+ int bake_texture_size;
+ int color_scan_cell_width;
+
+ struct MaterialCache {
+ //128x128 textures
+ Vector<Color> albedo;
+ Vector<Color> emission;
+ };
+
+ Vector<Color> _get_bake_texture(Image &p_image, const Color &p_color);
-class BakedLightInstance : public VisualInstance {
- OBJ_TYPE(BakedLightInstance,VisualInstance);
- Ref<BakedLight> baked_light;
+ Map<Ref<Material>,MaterialCache> material_cache;
+ MaterialCache _get_material_cache(Ref<Material> p_material);
+ int bake_cells_alloc;
+ int bake_cells_used;
+ int zero_alphas;
+ Vector<int> bake_cells_level_used;
+ DVector<BakeCell> bake_cells;
+ DVector<BakeCell>::Write bake_cells_write;
+
+
+
+ void _plot_face(int p_idx,int p_level,const Vector3 *p_vtx,const Vector2* p_uv, const MaterialCache& p_material,const AABB& p_aabb);
+ void _fixup_plot(int p_idx, int p_level, int p_x, int p_y, int p_z);
+ void _bake_add_mesh(const Transform& p_xform,Ref<Mesh>& p_mesh);
+ void _bake_add_to_aabb(const Transform& p_xform,Ref<Mesh>& p_mesh,bool &first);
+
+ void _debug_mesh(int p_idx, int p_level, const AABB &p_aabb,DebugMode p_mode,Ref<MultiMesh> &p_multimesh,int &idx);
+ void _debug_mesh_albedo();
+ void _debug_mesh_light();
+
+
+ _FORCE_INLINE_ int _find_cell(int x,int y, int z);
+ int _plot_ray(const Vector3& p_from, const Vector3& p_to);
+
+ uint32_t light_pass;
+
+
+ void _bake_directional(int p_idx, int p_level, int p_x,int p_y,int p_z,const Vector3& p_dir,const Color& p_color,int p_sign);
+ void _upscale_light(int p_idx,int p_level);
+ void _bake_light(Light* p_light);
+
+ Color _cone_trace(const Vector3& p_from, const Vector3& p_dir, float p_half_angle);
+ void _bake_radiance(int p_idx, int p_level, int p_x,int p_y,int p_z);
+
+friend class GeometryInstance;
+
+ Set<GeometryInstance*> geometries;
+friend class Light;
+
+ Set<Light*> lights;
protected:
static void _bind_methods();
public:
+ void set_cell_subdiv(int p_subdiv);
+ int get_cell_subdiv() const;
+
+ void bake();
+ void bake_lights();
+ void bake_radiance();
- RID get_baked_light_instance() const;
- void set_baked_light(const Ref<BakedLight>& baked_light);
- Ref<BakedLight> get_baked_light() const;
+ void create_debug_mesh(DebugMode p_mode);
virtual AABB get_aabb() const;
virtual DVector<Face3> get_faces(uint32_t p_usage_flags) const;
String get_configuration_warning() const;
- BakedLightInstance();
+ BakedLight();
+ ~BakedLight();
};
-
+#if 0
class BakedLightSampler : public VisualInstance {
OBJ_TYPE(BakedLightSampler,VisualInstance);
diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp
new file mode 100644
index 0000000000..ce360859d6
--- /dev/null
+++ b/scene/3d/gi_probe.cpp
@@ -0,0 +1,1248 @@
+#include "gi_probe.h"
+#include "mesh_instance.h"
+
+enum DataFormat {
+ DATA_RGBA8,
+ DATA_DXT5,
+ DATA_ETC2_EAC,
+};
+
+
+void GIProbeData::set_bounds(const AABB& p_bounds) {
+
+ VS::get_singleton()->gi_probe_set_bounds(probe,p_bounds);
+}
+
+AABB GIProbeData::get_bounds() const{
+
+ return VS::get_singleton()->gi_probe_get_bounds(probe);
+}
+
+void GIProbeData::set_cell_size(float p_size) {
+
+ VS::get_singleton()->gi_probe_set_cell_size(probe,p_size);
+
+}
+
+float GIProbeData::get_cell_size() const {
+
+ return VS::get_singleton()->gi_probe_get_cell_size(probe);
+
+}
+
+void GIProbeData::set_to_cell_xform(const Transform& p_xform) {
+
+ VS::get_singleton()->gi_probe_set_to_cell_xform(probe,p_xform);
+
+}
+
+Transform GIProbeData::get_to_cell_xform() const {
+
+ return VS::get_singleton()->gi_probe_get_to_cell_xform(probe);
+
+}
+
+
+void GIProbeData::set_dynamic_data(const DVector<int>& p_data){
+
+ VS::get_singleton()->gi_probe_set_dynamic_data(probe,p_data);
+
+}
+DVector<int> GIProbeData::get_dynamic_data() const{
+
+ return VS::get_singleton()->gi_probe_get_dynamic_data(probe);
+}
+
+void GIProbeData::set_dynamic_range(float p_range){
+
+ VS::get_singleton()->gi_probe_set_dynamic_range(probe,p_range);
+
+}
+float GIProbeData::get_dynamic_range() const{
+
+
+ return VS::get_singleton()->gi_probe_get_dynamic_range(probe);
+}
+
+void GIProbeData::set_static_data(const DVector<uint8_t>& p_data,DataFormat p_format,int p_width,int p_height,int p_depth){
+
+ VS::get_singleton()->gi_probe_set_static_data(probe,p_data,VS::GIProbeDataFormat(p_format),p_width,p_height,p_depth);
+
+}
+DVector<uint8_t> GIProbeData::get_static_data() const{
+
+ return VS::get_singleton()->gi_probe_get_static_data(probe);
+
+}
+GIProbeData::DataFormat GIProbeData::get_static_data_format() const{
+
+ return GIProbeData::DataFormat(VS::get_singleton()->gi_probe_get_static_data_format(probe));
+
+}
+int GIProbeData::get_static_data_width() const{
+
+ return VS::get_singleton()->gi_probe_get_static_data_width(probe);
+
+}
+int GIProbeData::get_static_data_height() const{
+
+ return VS::get_singleton()->gi_probe_get_static_data_height(probe);
+
+}
+int GIProbeData::get_static_data_depth() const{
+
+ return VS::get_singleton()->gi_probe_get_static_data_depth(probe);
+
+}
+
+RID GIProbeData::get_rid() const {
+
+ return probe;
+}
+
+GIProbeData::GIProbeData() {
+
+ probe=VS::get_singleton()->gi_probe_create();
+}
+
+GIProbeData::~GIProbeData() {
+
+ VS::get_singleton()->free(probe);
+}
+
+
+//////////////////////
+//////////////////////
+
+
+void GIProbe::set_probe_data(const Ref<GIProbeData>& p_data) {
+
+ if (p_data.is_valid()) {
+ VS::get_singleton()->instance_set_base(get_instance(),p_data->get_rid());
+ } else {
+ VS::get_singleton()->instance_set_base(get_instance(),RID());
+ }
+
+ probe_data=p_data;
+}
+
+Ref<GIProbeData> GIProbe::get_probe_data() const {
+
+ return probe_data;
+}
+
+void GIProbe::set_subdiv(Subdiv p_subdiv) {
+
+ ERR_FAIL_INDEX(p_subdiv,SUBDIV_MAX);
+ subdiv=p_subdiv;
+ update_gizmo();
+}
+
+GIProbe::Subdiv GIProbe::get_subdiv() const {
+
+ return subdiv;
+}
+
+void GIProbe::set_extents(const Vector3& p_extents) {
+
+ extents=p_extents;
+ update_gizmo();
+}
+
+Vector3 GIProbe::get_extents() const {
+
+ return extents;
+}
+
+void GIProbe::set_dynamic_range(float p_dynamic_range) {
+
+ dynamic_range=p_dynamic_range;
+}
+float GIProbe::get_dynamic_range() const {
+
+ return dynamic_range;
+}
+
+#include "math.h"
+
+#define FINDMINMAX(x0,x1,x2,min,max) \
+ min = max = x0; \
+ if(x1<min) min=x1;\
+ if(x1>max) max=x1;\
+ if(x2<min) min=x2;\
+ if(x2>max) max=x2;
+
+static bool planeBoxOverlap(Vector3 normal,float d, Vector3 maxbox)
+{
+ int q;
+ Vector3 vmin,vmax;
+ for(q=0;q<=2;q++)
+ {
+ if(normal[q]>0.0f)
+ {
+ vmin[q]=-maxbox[q];
+ vmax[q]=maxbox[q];
+ }
+ else
+ {
+ vmin[q]=maxbox[q];
+ vmax[q]=-maxbox[q];
+ }
+ }
+ if(normal.dot(vmin)+d>0.0f) return false;
+ if(normal.dot(vmax)+d>=0.0f) return true;
+
+ return false;
+}
+
+
+/*======================== X-tests ========================*/
+#define AXISTEST_X01(a, b, fa, fb) \
+ p0 = a*v0.y - b*v0.z; \
+ p2 = a*v2.y - b*v2.z; \
+ if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;} \
+ rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \
+ if(min>rad || max<-rad) return false;
+
+#define AXISTEST_X2(a, b, fa, fb) \
+ p0 = a*v0.y - b*v0.z; \
+ p1 = a*v1.y - b*v1.z; \
+ if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
+ rad = fa * boxhalfsize.y + fb * boxhalfsize.z; \
+ if(min>rad || max<-rad) return false;
+
+/*======================== Y-tests ========================*/
+#define AXISTEST_Y02(a, b, fa, fb) \
+ p0 = -a*v0.x + b*v0.z; \
+ p2 = -a*v2.x + b*v2.z; \
+ if(p0<p2) {min=p0; max=p2;} else {min=p2; max=p0;} \
+ rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \
+ if(min>rad || max<-rad) return false;
+
+#define AXISTEST_Y1(a, b, fa, fb) \
+ p0 = -a*v0.x + b*v0.z; \
+ p1 = -a*v1.x + b*v1.z; \
+ if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
+ rad = fa * boxhalfsize.x + fb * boxhalfsize.z; \
+ if(min>rad || max<-rad) return false;
+
+/*======================== Z-tests ========================*/
+
+#define AXISTEST_Z12(a, b, fa, fb) \
+ p1 = a*v1.x - b*v1.y; \
+ p2 = a*v2.x - b*v2.y; \
+ if(p2<p1) {min=p2; max=p1;} else {min=p1; max=p2;} \
+ rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \
+ if(min>rad || max<-rad) return false;
+
+#define AXISTEST_Z0(a, b, fa, fb) \
+ p0 = a*v0.x - b*v0.y; \
+ p1 = a*v1.x - b*v1.y; \
+ if(p0<p1) {min=p0; max=p1;} else {min=p1; max=p0;} \
+ rad = fa * boxhalfsize.x + fb * boxhalfsize.y; \
+ if(min>rad || max<-rad) return false;
+
+static bool fast_tri_box_overlap(const Vector3& boxcenter,const Vector3 boxhalfsize,const Vector3 *triverts) {
+
+ /* use separating axis theorem to test overlap between triangle and box */
+ /* need to test for overlap in these directions: */
+ /* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */
+ /* we do not even need to test these) */
+ /* 2) normal of the triangle */
+ /* 3) crossproduct(edge from tri, {x,y,z}-directin) */
+ /* this gives 3x3=9 more tests */
+ Vector3 v0,v1,v2;
+ float min,max,d,p0,p1,p2,rad,fex,fey,fez;
+ Vector3 normal,e0,e1,e2;
+
+ /* This is the fastest branch on Sun */
+ /* move everything so that the boxcenter is in (0,0,0) */
+
+ v0=triverts[0]-boxcenter;
+ v1=triverts[1]-boxcenter;
+ v2=triverts[2]-boxcenter;
+
+ /* compute triangle edges */
+ e0=v1-v0; /* tri edge 0 */
+ e1=v2-v1; /* tri edge 1 */
+ e2=v0-v2; /* tri edge 2 */
+
+ /* Bullet 3: */
+ /* test the 9 tests first (this was faster) */
+ fex = Math::abs(e0.x);
+ fey = Math::abs(e0.y);
+ fez = Math::abs(e0.z);
+ AXISTEST_X01(e0.z, e0.y, fez, fey);
+ AXISTEST_Y02(e0.z, e0.x, fez, fex);
+ AXISTEST_Z12(e0.y, e0.x, fey, fex);
+
+ fex = Math::abs(e1.x);
+ fey = Math::abs(e1.y);
+ fez = Math::abs(e1.z);
+ AXISTEST_X01(e1.z, e1.y, fez, fey);
+ AXISTEST_Y02(e1.z, e1.x, fez, fex);
+ AXISTEST_Z0(e1.y, e1.x, fey, fex);
+
+ fex = Math::abs(e2.x);
+ fey = Math::abs(e2.y);
+ fez = Math::abs(e2.z);
+ AXISTEST_X2(e2.z, e2.y, fez, fey);
+ AXISTEST_Y1(e2.z, e2.x, fez, fex);
+ AXISTEST_Z12(e2.y, e2.x, fey, fex);
+
+ /* Bullet 1: */
+ /* first test overlap in the {x,y,z}-directions */
+ /* find min, max of the triangle each direction, and test for overlap in */
+ /* that direction -- this is equivalent to testing a minimal AABB around */
+ /* the triangle against the AABB */
+
+ /* test in X-direction */
+ FINDMINMAX(v0.x,v1.x,v2.x,min,max);
+ if(min>boxhalfsize.x || max<-boxhalfsize.x) return false;
+
+ /* test in Y-direction */
+ FINDMINMAX(v0.y,v1.y,v2.y,min,max);
+ if(min>boxhalfsize.y || max<-boxhalfsize.y) return false;
+
+ /* test in Z-direction */
+ FINDMINMAX(v0.z,v1.z,v2.z,min,max);
+ if(min>boxhalfsize.z || max<-boxhalfsize.z) return false;
+
+ /* Bullet 2: */
+ /* test if the box intersects the plane of the triangle */
+ /* compute plane equation of triangle: normal*x+d=0 */
+ normal=e0.cross(e1);
+ d=-normal.dot(v0); /* plane eq: normal.x+d=0 */
+ if(!planeBoxOverlap(normal,d,boxhalfsize)) return false;
+
+ return true; /* box and triangle overlaps */
+}
+
+
+
+static _FORCE_INLINE_ Vector2 get_uv(const Vector3& p_pos, const Vector3 *p_vtx, const Vector2* p_uv) {
+
+ if (p_pos.distance_squared_to(p_vtx[0])<CMP_EPSILON2)
+ return p_uv[0];
+ if (p_pos.distance_squared_to(p_vtx[1])<CMP_EPSILON2)
+ return p_uv[1];
+ if (p_pos.distance_squared_to(p_vtx[2])<CMP_EPSILON2)
+ return p_uv[2];
+
+ Vector3 v0 = p_vtx[1] - p_vtx[0];
+ Vector3 v1 = p_vtx[2] - p_vtx[0];
+ Vector3 v2 = p_pos - p_vtx[0];
+
+ float d00 = v0.dot( v0);
+ float d01 = v0.dot( v1);
+ float d11 = v1.dot( v1);
+ float d20 = v2.dot( v0);
+ float d21 = v2.dot( v1);
+ float denom = (d00 * d11 - d01 * d01);
+ if (denom==0)
+ return p_uv[0];
+ float v = (d11 * d20 - d01 * d21) / denom;
+ float w = (d00 * d21 - d01 * d20) / denom;
+ float u = 1.0f - v - w;
+
+ return p_uv[0]*u + p_uv[1]*v + p_uv[2]*w;
+}
+
+void GIProbe::_plot_face(int p_idx, int p_level,int p_x,int p_y,int p_z, const Vector3 *p_vtx, const Vector2* p_uv, const Baker::MaterialCache& p_material, const AABB &p_aabb,Baker *p_baker) {
+
+
+
+ if (p_level==p_baker->cell_subdiv-1) {
+ //plot the face by guessing it's albedo and emission value
+
+ //find best axis to map to, for scanning values
+ int closest_axis;
+ float closest_dot;
+
+ Vector3 normal = Plane(p_vtx[0],p_vtx[1],p_vtx[2]).normal;
+
+ for(int i=0;i<3;i++) {
+
+ Vector3 axis;
+ axis[i]=1.0;
+ float dot=ABS(normal.dot(axis));
+ if (i==0 || dot>closest_dot) {
+ closest_axis=i;
+ closest_dot=dot;
+ }
+ }
+
+ Vector3 axis;
+ axis[closest_axis]=1.0;
+ Vector3 t1;
+ t1[(closest_axis+1)%3]=1.0;
+ Vector3 t2;
+ t2[(closest_axis+2)%3]=1.0;
+
+ t1*=p_aabb.size[(closest_axis+1)%3]/float(color_scan_cell_width);
+ t2*=p_aabb.size[(closest_axis+2)%3]/float(color_scan_cell_width);
+
+ Color albedo_accum;
+ Color emission_accum;
+ float alpha=0.0;
+
+ //map to a grid average in the best axis for this face
+ for(int i=0;i<color_scan_cell_width;i++) {
+
+ Vector3 ofs_i=float(i)*t1;
+
+ for(int j=0;j<color_scan_cell_width;j++) {
+
+ Vector3 ofs_j=float(j)*t2;
+
+ Vector3 from = p_aabb.pos+ofs_i+ofs_j;
+ Vector3 to = from + t1 + t2 + axis * p_aabb.size[closest_axis];
+ Vector3 half = (to-from)*0.5;
+
+ //is in this cell?
+ if (!fast_tri_box_overlap(from+half,half,p_vtx)) {
+ continue; //face does not span this cell
+ }
+
+ //go from -size to +size*2 to avoid skipping collisions
+ Vector3 ray_from = from + (t1+t2)*0.5 - axis * p_aabb.size[closest_axis];
+ Vector3 ray_to = ray_from + axis * p_aabb.size[closest_axis]*2;
+
+ Vector3 intersection;
+
+ if (!Geometry::ray_intersects_triangle(ray_from,ray_to,p_vtx[0],p_vtx[1],p_vtx[2],&intersection)) {
+ //no intersect? look in edges
+
+ float closest_dist=1e20;
+ for(int j=0;j<3;j++) {
+ Vector3 c;
+ Vector3 inters;
+ Geometry::get_closest_points_between_segments(p_vtx[j],p_vtx[(j+1)%3],ray_from,ray_to,inters,c);
+ float d=c.distance_to(intersection);
+ if (j==0 || d<closest_dist) {
+ closest_dist=d;
+ intersection=inters;
+ }
+ }
+ }
+
+ Vector2 uv = get_uv(intersection,p_vtx,p_uv);
+
+
+ int uv_x = CLAMP(Math::fposmod(uv.x,1.0)*bake_texture_size,0,bake_texture_size-1);
+ int uv_y = CLAMP(Math::fposmod(uv.y,1.0)*bake_texture_size,0,bake_texture_size-1);
+
+ int ofs = uv_y*bake_texture_size+uv_x;
+ albedo_accum.r+=p_material.albedo[ofs].r;
+ albedo_accum.g+=p_material.albedo[ofs].g;
+ albedo_accum.b+=p_material.albedo[ofs].b;
+ albedo_accum.a+=p_material.albedo[ofs].a;
+
+ emission_accum.r+=p_material.emission[ofs].r;
+ emission_accum.g+=p_material.emission[ofs].g;
+ emission_accum.b+=p_material.emission[ofs].b;
+ alpha+=1.0;
+
+ }
+ }
+
+
+ if (alpha==0) {
+ //could not in any way get texture information.. so use closest point to center
+
+ Face3 f( p_vtx[0],p_vtx[1],p_vtx[2]);
+ Vector3 inters = f.get_closest_point_to(p_aabb.pos+p_aabb.size*0.5);
+
+ Vector2 uv = get_uv(inters,p_vtx,p_uv);
+
+ int uv_x = CLAMP(Math::fposmod(uv.x,1.0)*bake_texture_size,0,bake_texture_size-1);
+ int uv_y = CLAMP(Math::fposmod(uv.y,1.0)*bake_texture_size,0,bake_texture_size-1);
+
+ int ofs = uv_y*bake_texture_size+uv_x;
+
+ alpha = 1.0/(color_scan_cell_width*color_scan_cell_width);
+
+ albedo_accum.r=p_material.albedo[ofs].r*alpha;
+ albedo_accum.g=p_material.albedo[ofs].g*alpha;
+ albedo_accum.b=p_material.albedo[ofs].b*alpha;
+ albedo_accum.a=p_material.albedo[ofs].a*alpha;
+
+ emission_accum.r=p_material.emission[ofs].r*alpha;
+ emission_accum.g=p_material.emission[ofs].g*alpha;
+ emission_accum.b=p_material.emission[ofs].b*alpha;
+
+
+
+ } else {
+
+ float accdiv = 1.0/(color_scan_cell_width*color_scan_cell_width);
+ alpha*=accdiv;
+
+ albedo_accum.r*=accdiv;
+ albedo_accum.g*=accdiv;
+ albedo_accum.b*=accdiv;
+ albedo_accum.a*=accdiv;
+
+ emission_accum.r*=accdiv;
+ emission_accum.g*=accdiv;
+ emission_accum.b*=accdiv;
+ }
+
+ //put this temporarily here, corrected in a later step
+ p_baker->bake_cells[p_idx].albedo[0]+=albedo_accum.r;
+ p_baker->bake_cells[p_idx].albedo[1]+=albedo_accum.g;
+ p_baker->bake_cells[p_idx].albedo[2]+=albedo_accum.b;
+ p_baker->bake_cells[p_idx].emission[0]+=emission_accum.r;
+ p_baker->bake_cells[p_idx].emission[1]+=emission_accum.g;
+ p_baker->bake_cells[p_idx].emission[2]+=emission_accum.b;
+ p_baker->bake_cells[p_idx].alpha+=alpha;
+
+ static const Vector3 side_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),
+ };
+
+ for(int i=0;i<6;i++) {
+ if (normal.dot(side_normals[i])>CMP_EPSILON) {
+ p_baker->bake_cells[p_idx].used_sides|=(1<<i);
+ }
+ }
+
+
+ } else {
+ //go down
+
+ int half = (1<<(p_baker->cell_subdiv-1)) >> (p_level+1);
+ for(int i=0;i<8;i++) {
+
+ AABB aabb=p_aabb;
+ aabb.size*=0.5;
+
+ int nx=p_x;
+ int ny=p_y;
+ int nz=p_z;
+
+ if (i&1) {
+ aabb.pos.x+=aabb.size.x;
+ nx+=half;
+ }
+ if (i&2) {
+ aabb.pos.y+=aabb.size.y;
+ ny+=half;
+ }
+ if (i&4) {
+ aabb.pos.z+=aabb.size.z;
+ nz+=half;
+ }
+ //make sure to not plot beyond limits
+ if (nx<0 || nx>=p_baker->axis_cell_size[0] || ny<0 || ny>=p_baker->axis_cell_size[1] || nz<0 || nz>=p_baker->axis_cell_size[2])
+ continue;
+
+ {
+ AABB test_aabb=aabb;
+ //test_aabb.grow_by(test_aabb.get_longest_axis_size()*0.05); //grow a bit to avoid numerical error in real-time
+ Vector3 qsize = test_aabb.size*0.5; //quarter size, for fast aabb test
+
+ if (!fast_tri_box_overlap(test_aabb.pos+qsize,qsize,p_vtx)) {
+ //if (!Face3(p_vtx[0],p_vtx[1],p_vtx[2]).intersects_aabb2(aabb)) {
+ //does not fit in child, go on
+ continue;
+ }
+
+ }
+
+ if (p_baker->bake_cells[p_idx].childs[i]==Baker::CHILD_EMPTY) {
+ //sub cell must be created
+
+ p_baker->bake_cells[p_idx].childs[i]=p_baker->bake_cells.size();
+ p_baker->bake_cells.resize( p_baker->bake_cells.size() + 1);
+
+ }
+
+
+ _plot_face(p_baker->bake_cells[p_idx].childs[i],p_level+1,nx,ny,nz,p_vtx,p_uv,p_material,aabb,p_baker);
+ }
+ }
+}
+
+
+
+void GIProbe::_fixup_plot(int p_idx, int p_level,int p_x,int p_y, int p_z,Baker *p_baker) {
+
+
+
+ if (p_level==p_baker->cell_subdiv-1) {
+
+ p_baker->leaf_voxel_count++;
+ float alpha = p_baker->bake_cells[p_idx].alpha;
+
+ p_baker->bake_cells[p_idx].albedo[0]/=alpha;
+ p_baker->bake_cells[p_idx].albedo[1]/=alpha;
+ p_baker->bake_cells[p_idx].albedo[2]/=alpha;
+
+ //transfer emission to light
+ p_baker->bake_cells[p_idx].emission[0]/=alpha;
+ p_baker->bake_cells[p_idx].emission[1]/=alpha;
+ p_baker->bake_cells[p_idx].emission[2]/=alpha;
+
+ p_baker->bake_cells[p_idx].alpha=1.0;
+
+ //remove neighbours from used sides
+
+ for(int n=0;n<6;n++) {
+
+ int ofs[3]={0,0,0};
+
+ ofs[n/2]=(n&1)?1:-1;
+
+ //convert to x,y,z on this level
+ int x=p_x;
+ int y=p_y;
+ int z=p_z;
+
+ x+=ofs[0];
+ y+=ofs[1];
+ z+=ofs[2];
+
+ int ofs_x=0;
+ int ofs_y=0;
+ int ofs_z=0;
+ int size = 1<<p_level;
+ int half=size/2;
+
+
+ if (x<0 || x>=size || y<0 || y>=size || z<0 || z>=size) {
+ //neighbour is out, can't use it
+ p_baker->bake_cells[p_idx].used_sides&=~(1<<uint32_t(n));
+ continue;
+ }
+
+ uint32_t neighbour=0;
+
+ for(int i=0;i<p_baker->cell_subdiv-1;i++) {
+
+ Baker::Cell *bc = &p_baker->bake_cells[neighbour];
+
+ int child = 0;
+ if (x >= ofs_x + half) {
+ child|=1;
+ ofs_x+=half;
+ }
+ if (y >= ofs_y + half) {
+ child|=2;
+ ofs_y+=half;
+ }
+ if (z >= ofs_z + half) {
+ child|=4;
+ ofs_z+=half;
+ }
+
+ neighbour = bc->childs[child];
+ if (neighbour==Baker::CHILD_EMPTY) {
+ break;
+ }
+
+ half>>=1;
+ }
+
+ if (neighbour!=Baker::CHILD_EMPTY) {
+ p_baker->bake_cells[p_idx].used_sides&=~(1<<uint32_t(n));
+ }
+ }
+ } else {
+
+
+ //go down
+
+ float alpha_average=0;
+ int half = (1<<(p_baker->cell_subdiv-1)) >> (p_level+1);
+ for(int i=0;i<8;i++) {
+
+ uint32_t child = p_baker->bake_cells[p_idx].childs[i];
+
+ if (child==Baker::CHILD_EMPTY)
+ continue;
+
+
+ int nx=p_x;
+ int ny=p_y;
+ int nz=p_z;
+
+ if (i&1)
+ nx+=half;
+ if (i&2)
+ ny+=half;
+ if (i&4)
+ nz+=half;
+
+ _fixup_plot(child,p_level+1,nx,ny,nz,p_baker);
+ alpha_average+=p_baker->bake_cells[child].alpha;
+ }
+
+ p_baker->bake_cells[p_idx].alpha=alpha_average/8.0;
+ p_baker->bake_cells[p_idx].emission[0]=0;
+ p_baker->bake_cells[p_idx].emission[1]=0;
+ p_baker->bake_cells[p_idx].emission[2]=0;
+ p_baker->bake_cells[p_idx].albedo[0]=0;
+ p_baker->bake_cells[p_idx].albedo[1]=0;
+ p_baker->bake_cells[p_idx].albedo[2]=0;
+
+ }
+
+}
+
+
+
+Vector<Color> GIProbe::_get_bake_texture(Image &p_image,const Color& p_color) {
+
+ Vector<Color> ret;
+
+ if (p_image.empty()) {
+
+ ret.resize(bake_texture_size*bake_texture_size);
+ for(int i=0;i<bake_texture_size*bake_texture_size;i++) {
+ ret[i]=p_color;
+ }
+
+ return ret;
+ }
+
+ p_image.convert(Image::FORMAT_RGBA8);
+ p_image.resize(bake_texture_size,bake_texture_size,Image::INTERPOLATE_CUBIC);
+
+
+ DVector<uint8_t>::Read r = p_image.get_data().read();
+ ret.resize(bake_texture_size*bake_texture_size);
+
+ for(int i=0;i<bake_texture_size*bake_texture_size;i++) {
+ Color c;
+ c.r = r[i*4+0]/255.0;
+ c.g = r[i*4+1]/255.0;
+ c.b = r[i*4+2]/255.0;
+ c.a = r[i*4+3]/255.0;
+ ret[i]=c;
+
+ }
+
+ return ret;
+}
+
+
+GIProbe::Baker::MaterialCache GIProbe::_get_material_cache(Ref<Material> p_material,Baker *p_baker) {
+
+ //this way of obtaining materials is inaccurate and also does not support some compressed formats very well
+ Ref<FixedSpatialMaterial> mat = p_material;
+
+ Ref<Material> material = mat; //hack for now
+
+ if (p_baker->material_cache.has(material)) {
+ return p_baker->material_cache[material];
+ }
+
+ Baker::MaterialCache mc;
+
+ if (mat.is_valid()) {
+
+
+ Ref<ImageTexture> albedo_tex = mat->get_texture(FixedSpatialMaterial::TEXTURE_ALBEDO);
+
+ Image img_albedo;
+ if (albedo_tex.is_valid()) {
+
+ img_albedo = albedo_tex->get_data();
+ }
+
+ mc.albedo=_get_bake_texture(img_albedo,mat->get_albedo());
+
+ Ref<ImageTexture> emission_tex = mat->get_texture(FixedSpatialMaterial::TEXTURE_EMISSION);
+
+ Color emission_col = mat->get_emission();
+ emission_col.r*=mat->get_emission_energy();
+ emission_col.g*=mat->get_emission_energy();
+ emission_col.b*=mat->get_emission_energy();
+
+ Image img_emission;
+
+ if (emission_tex.is_valid()) {
+
+ img_emission = emission_tex->get_data();
+ }
+
+ mc.emission=_get_bake_texture(img_emission,emission_col);
+
+ } else {
+ Image empty;
+
+ mc.albedo=_get_bake_texture(empty,Color(0.7,0.7,0.7));
+ mc.emission=_get_bake_texture(empty,Color(0,0,0));
+
+
+ }
+
+ p_baker->material_cache[p_material]=mc;
+ return mc;
+
+
+}
+
+void GIProbe::_plot_mesh(const Transform& p_xform, Ref<Mesh>& p_mesh, Baker *p_baker) {
+
+
+ for(int i=0;i<p_mesh->get_surface_count();i++) {
+
+ if (p_mesh->surface_get_primitive_type(i)!=Mesh::PRIMITIVE_TRIANGLES)
+ continue; //only triangles
+
+ Baker::MaterialCache material = _get_material_cache(p_mesh->surface_get_material(i),p_baker);
+
+ Array a = p_mesh->surface_get_arrays(i);
+
+
+ DVector<Vector3> vertices = a[Mesh::ARRAY_VERTEX];
+ DVector<Vector3>::Read vr=vertices.read();
+ DVector<Vector2> uv = a[Mesh::ARRAY_TEX_UV];
+ DVector<Vector2>::Read uvr;
+ DVector<int> index = a[Mesh::ARRAY_INDEX];
+
+ bool read_uv=false;
+
+ if (uv.size()) {
+
+ uvr=uv.read();
+ read_uv=true;
+ }
+
+ if (index.size()) {
+
+ int facecount = index.size()/3;
+ DVector<int>::Read ir=index.read();
+
+ for(int j=0;j<facecount;j++) {
+
+ Vector3 vtxs[3];
+ Vector2 uvs[3];
+
+ for(int k=0;k<3;k++) {
+ vtxs[k]=p_xform.xform(vr[ir[j*3+k]]);
+ }
+
+ if (read_uv) {
+ for(int k=0;k<3;k++) {
+ uvs[k]=uvr[ir[j*3+k]];
+ }
+ }
+
+ //test against original bounds
+ if (!fast_tri_box_overlap(-extents,extents*2,vtxs))
+ continue;
+ //plot
+ _plot_face(0,0,0,0,0,vtxs,uvs,material,p_baker->po2_bounds,p_baker);
+ }
+
+
+
+ } else {
+
+ int facecount = vertices.size()/3;
+
+ for(int j=0;j<facecount;j++) {
+
+ Vector3 vtxs[3];
+ Vector2 uvs[3];
+
+ for(int k=0;k<3;k++) {
+ vtxs[k]=p_xform.xform(vr[j*3+k]);
+ }
+
+ if (read_uv) {
+ for(int k=0;k<3;k++) {
+ uvs[k]=uvr[j*3+k];
+ }
+ }
+
+ //test against original bounds
+ if (!fast_tri_box_overlap(-extents,extents*2,vtxs))
+ continue;
+ //plot face
+ _plot_face(0,0,0,0,0,vtxs,uvs,material,p_baker->po2_bounds,p_baker);
+ }
+
+ }
+ }
+}
+
+
+
+void GIProbe::_find_meshes(Node *p_at_node,Baker *p_baker){
+
+ MeshInstance *mi = p_at_node->cast_to<MeshInstance>();
+ if (mi && mi->get_flag(GeometryInstance::FLAG_USE_BAKED_LIGHT)) {
+ Ref<Mesh> mesh = mi->get_mesh();
+ if (mesh.is_valid()) {
+
+ AABB aabb = mesh->get_aabb();
+
+ Transform xf = get_global_transform().affine_inverse() * mi->get_global_transform();
+
+ if (AABB(-extents,extents*2).intersects(xf.xform(aabb))) {
+ Baker::PlotMesh pm;
+ pm.local_xform=xf;
+ pm.mesh=mesh;
+ p_baker->mesh_list.push_back(pm);
+
+ }
+ }
+ }
+
+ for(int i=0;i<p_at_node->get_child_count();i++) {
+
+ Node *child = p_at_node->get_child(i);
+ if (!child->get_owner())
+ continue; //maybe a helper
+
+ _find_meshes(child,p_baker);
+
+ }
+}
+
+
+
+
+void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug){
+
+ Baker baker;
+
+ static const int subdiv_value[SUBDIV_MAX]={7,8,9,10};
+
+ baker.cell_subdiv=subdiv_value[subdiv];
+ baker.bake_cells.resize(1);
+
+ //find out the actual real bounds, power of 2, which gets the highest subdivision
+ baker.po2_bounds=AABB(-extents,extents*2.0);
+ int longest_axis = baker.po2_bounds.get_longest_axis_index();
+ baker.axis_cell_size[longest_axis]=(1<<(baker.cell_subdiv-1));
+ baker.leaf_voxel_count=0;
+
+ for(int i=0;i<3;i++) {
+
+ if (i==longest_axis)
+ continue;
+
+ baker.axis_cell_size[i]=baker.axis_cell_size[longest_axis];
+ float axis_size = baker.po2_bounds.size[longest_axis];
+
+ //shrink until fit subdiv
+ while (axis_size/2.0 >= baker.po2_bounds.size[i]) {
+ axis_size/=2.0;
+ baker.axis_cell_size[i]>>=1;
+ }
+
+ baker.po2_bounds.size[i]=baker.po2_bounds.size[longest_axis];
+ }
+
+
+
+ Transform to_bounds;
+ to_bounds.basis.scale(Vector3(baker.po2_bounds.size[longest_axis],baker.po2_bounds.size[longest_axis],baker.po2_bounds.size[longest_axis]));
+ to_bounds.origin=baker.po2_bounds.pos;
+
+ Transform to_grid;
+ to_grid.basis.scale(Vector3(baker.axis_cell_size[longest_axis],baker.axis_cell_size[longest_axis],baker.axis_cell_size[longest_axis]));
+
+ baker.to_cell_space = to_grid * to_bounds.affine_inverse();
+
+
+ _find_meshes(p_from_node?p_from_node:get_parent(),&baker);
+
+
+
+ int pmc=0;
+
+ for(List<Baker::PlotMesh>::Element *E=baker.mesh_list.front();E;E=E->next()) {
+
+ print_line("plotting mesh "+itos(pmc++)+"/"+itos(baker.mesh_list.size()));
+
+ _plot_mesh(E->get().local_xform,E->get().mesh,&baker);
+ }
+
+ _fixup_plot(0,0,0,0,0,&baker);
+
+ //create the data for visual server
+
+ DVector<int> data;
+
+ data.resize( 16+(8+1+1+1+1)*baker.bake_cells.size() ); //4 for header, rest for rest.
+
+ {
+ DVector<int>::Write w = data.write();
+
+ uint32_t * w32 = (uint32_t*)w.ptr();
+
+ w32[0]=0;//version
+ w32[1]=baker.cell_subdiv; //subdiv
+ w32[2]=baker.axis_cell_size[0];
+ w32[3]=baker.axis_cell_size[1];
+ w32[4]=baker.axis_cell_size[2];
+ w32[5]=baker.bake_cells.size();
+ w32[6]=baker.leaf_voxel_count;
+
+ int ofs=16;
+
+ for(int i=0;i<baker.bake_cells.size();i++) {
+
+ for(int j=0;j<8;j++) {
+ w32[ofs++]=baker.bake_cells[i].childs[j];
+ }
+
+ { //albedo
+ uint32_t rgba=uint32_t(CLAMP(baker.bake_cells[i].albedo[0]*255.0,0,255))<<16;
+ rgba|=uint32_t(CLAMP(baker.bake_cells[i].albedo[1]*255.0,0,255))<<8;
+ rgba|=uint32_t(CLAMP(baker.bake_cells[i].albedo[2]*255.0,0,255))<<0;
+
+ w32[ofs++]=rgba;
+
+
+ }
+ { //emission
+
+ Vector3 e(baker.bake_cells[i].emission[0],baker.bake_cells[i].emission[1],baker.bake_cells[i].emission[2]);
+ float l = e.length();
+ if (l>0) {
+ e.normalize();
+ l=CLAMP(l/8.0,0,1.0);
+ }
+
+ uint32_t em=uint32_t(CLAMP(e[0]*255,0,255))<<24;
+ em|=uint32_t(CLAMP(e[1]*255,0,255))<<16;
+ em|=uint32_t(CLAMP(e[2]*255,0,255))<<8;
+ em|=uint32_t(CLAMP(l*255,0,255));
+
+ w32[ofs++]=em;
+ }
+
+ w32[ofs++]=baker.bake_cells[i].used_sides;
+ w32[ofs++]=uint32_t(baker.bake_cells[i].alpha*65535.0);
+
+ }
+
+ }
+
+ Ref<GIProbeData> probe_data;
+ probe_data.instance();
+ probe_data->set_bounds(AABB(-extents,extents*2.0));
+ probe_data->set_cell_size(baker.po2_bounds.size[longest_axis]/baker.axis_cell_size[longest_axis]);
+ probe_data->set_dynamic_data(data);
+ probe_data->set_to_cell_xform(baker.to_cell_space);
+
+ set_probe_data(probe_data);
+
+
+ if (p_create_visual_debug) {
+ // _create_debug_mesh(&baker);
+ }
+
+
+
+}
+
+
+void GIProbe::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb,Ref<MultiMesh> &p_multimesh,int &idx,Baker *p_baker) {
+
+
+ if (p_level==p_baker->cell_subdiv-1) {
+
+ Vector3 center = p_aabb.pos+p_aabb.size*0.5;
+ Transform xform;
+ xform.origin=center;
+ xform.basis.scale(p_aabb.size*0.5);
+ p_multimesh->set_instance_transform(idx,xform);
+ Color col=Color(p_baker->bake_cells[p_idx].albedo[0],p_baker->bake_cells[p_idx].albedo[1],p_baker->bake_cells[p_idx].albedo[2]);
+ p_multimesh->set_instance_color(idx,col);
+
+ idx++;
+
+ } else {
+
+ for(int i=0;i<8;i++) {
+
+ if (p_baker->bake_cells[p_idx].childs[i]==Baker::CHILD_EMPTY)
+ continue;
+
+ AABB aabb=p_aabb;
+ aabb.size*=0.5;
+
+ if (i&1)
+ aabb.pos.x+=aabb.size.x;
+ if (i&2)
+ aabb.pos.y+=aabb.size.y;
+ if (i&4)
+ aabb.pos.z+=aabb.size.z;
+
+ _debug_mesh(p_baker->bake_cells[p_idx].childs[i],p_level+1,aabb,p_multimesh,idx,p_baker);
+ }
+
+ }
+
+}
+
+
+void GIProbe::_create_debug_mesh(Baker *p_baker) {
+
+ Ref<MultiMesh> mm;
+ mm.instance();
+
+ mm->set_transform_format(MultiMesh::TRANSFORM_3D);
+ mm->set_color_format(MultiMesh::COLOR_8BIT);
+ print_line("leaf voxels: "+itos(p_baker->leaf_voxel_count));
+ mm->set_instance_count(p_baker->leaf_voxel_count);
+
+ Ref<Mesh> mesh;
+ mesh.instance();
+
+ {
+ Array arr;
+ arr.resize(Mesh::ARRAY_MAX);
+
+ DVector<Vector3> vertices;
+ DVector<Color> colors;
+
+ int vtx_idx=0;
+ #define ADD_VTX(m_idx);\
+ vertices.push_back( face_points[m_idx] );\
+ colors.push_back( Color(1,1,1,1) );\
+ vtx_idx++;\
+
+ for (int i=0;i<6;i++) {
+
+
+ Vector3 face_points[4];
+
+ for (int j=0;j<4;j++) {
+
+ float v[3];
+ v[0]=1.0;
+ v[1]=1-2*((j>>1)&1);
+ v[2]=v[1]*(1-2*(j&1));
+
+ for (int k=0;k<3;k++) {
+
+ if (i<3)
+ face_points[j][(i+k)%3]=v[k]*(i>=3?-1:1);
+ else
+ face_points[3-j][(i+k)%3]=v[k]*(i>=3?-1:1);
+ }
+ }
+
+ //tri 1
+ ADD_VTX(0);
+ ADD_VTX(1);
+ ADD_VTX(2);
+ //tri 2
+ ADD_VTX(2);
+ ADD_VTX(3);
+ ADD_VTX(0);
+
+ }
+
+
+ arr[Mesh::ARRAY_VERTEX]=vertices;
+ arr[Mesh::ARRAY_COLOR]=colors;
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES,arr);
+ }
+
+ {
+ Ref<FixedSpatialMaterial> fsm;
+ fsm.instance();
+ fsm->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR,true);
+ fsm->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR,true);
+ fsm->set_flag(FixedSpatialMaterial::FLAG_UNSHADED,true);
+ fsm->set_albedo(Color(1,1,1,1));
+
+ mesh->surface_set_material(0,fsm);
+ }
+
+ mm->set_mesh(mesh);
+
+
+ int idx=0;
+ _debug_mesh(0,0,p_baker->po2_bounds,mm,idx,p_baker);
+
+ MultiMeshInstance *mmi = memnew( MultiMeshInstance );
+ mmi->set_multimesh(mm);
+ add_child(mmi);
+ if (get_tree()->get_edited_scene_root()==this){
+ mmi->set_owner(this);
+ } else {
+ mmi->set_owner(get_owner());
+
+ }
+
+}
+
+void GIProbe::_debug_bake() {
+
+ bake(NULL,true);
+}
+
+AABB GIProbe::get_aabb() const {
+
+ return AABB(-extents,extents*2);
+}
+
+DVector<Face3> GIProbe::get_faces(uint32_t p_usage_flags) const {
+
+ return DVector<Face3>();
+}
+
+void GIProbe::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_probe_data","data"),&GIProbe::set_probe_data);
+ ObjectTypeDB::bind_method(_MD("get_probe_data"),&GIProbe::get_probe_data);
+
+ ObjectTypeDB::bind_method(_MD("set_subdiv","subdiv"),&GIProbe::set_subdiv);
+ ObjectTypeDB::bind_method(_MD("get_subdiv"),&GIProbe::get_subdiv);
+
+ ObjectTypeDB::bind_method(_MD("set_extents","extents"),&GIProbe::set_extents);
+ ObjectTypeDB::bind_method(_MD("get_extents"),&GIProbe::get_extents);
+
+ ObjectTypeDB::bind_method(_MD("set_dynamic_range","max"),&GIProbe::set_dynamic_range);
+ ObjectTypeDB::bind_method(_MD("get_dynamic_range"),&GIProbe::get_dynamic_range);
+
+ ObjectTypeDB::bind_method(_MD("bake","from_node","create_visual_debug"),&GIProbe::bake,DEFVAL(Variant()),DEFVAL(false));
+ ObjectTypeDB::bind_method(_MD("debug_bake"),&GIProbe::_debug_bake);
+ ObjectTypeDB::set_method_flags(get_type_static(),_SCS("debug_bake"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
+
+ ADD_PROPERTY( PropertyInfo(Variant::INT,"subdiv",PROPERTY_HINT_ENUM,"64,128,256,512"),_SCS("set_subdiv"),_SCS("get_subdiv"));
+ ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"extents"),_SCS("set_extents"),_SCS("get_extents"));
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"dynamic_range",PROPERTY_HINT_RANGE,"0,8,0.01"),_SCS("set_dynamic_range"),_SCS("get_dynamic_range"));
+ ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"data",PROPERTY_HINT_RESOURCE_TYPE,"GIProbeData"),_SCS("set_probe_data"),_SCS("get_probe_data"));
+
+
+ BIND_CONSTANT( SUBDIV_64 );
+ BIND_CONSTANT( SUBDIV_128 );
+ BIND_CONSTANT( SUBDIV_256 );
+ BIND_CONSTANT( SUBDIV_MAX );
+
+}
+
+GIProbe::GIProbe() {
+
+ subdiv=SUBDIV_128;
+ dynamic_range=1.0;
+ extents=Vector3(10,10,10);
+ color_scan_cell_width=4;
+ bake_texture_size=128;
+
+ gi_probe = VS::get_singleton()->gi_probe_create();
+
+
+}
+
+GIProbe::~GIProbe() {
+
+
+}
diff --git a/scene/3d/gi_probe.h b/scene/3d/gi_probe.h
new file mode 100644
index 0000000000..e2017acfc3
--- /dev/null
+++ b/scene/3d/gi_probe.h
@@ -0,0 +1,174 @@
+#ifndef GIPROBE_H
+#define GIPROBE_H
+
+#include "scene/3d/visual_instance.h"
+#include "multimesh_instance.h"
+
+class GIProbeData : public Resource {
+
+ OBJ_TYPE(GIProbeData,Resource);
+
+ RID probe;
+
+public:
+
+ enum DataFormat {
+ DATA_RGBA8,
+ DATA_DXT5,
+ DATA_ETC2_EAC,
+ };
+
+
+ void set_bounds(const AABB& p_bounds);
+ AABB get_bounds() const;
+
+ void set_cell_size(float p_size);
+ float get_cell_size() const;
+
+ void set_to_cell_xform(const Transform& p_xform);
+ Transform get_to_cell_xform() const;
+
+ void set_dynamic_data(const DVector<int>& p_data);
+ DVector<int> get_dynamic_data() const;
+
+ void set_dynamic_range(float p_range);
+ float get_dynamic_range() const;
+
+ void set_static_data(const DVector<uint8_t>& p_data,DataFormat p_format,int p_width,int p_height,int p_depth);
+ DVector<uint8_t> get_static_data() const;
+ DataFormat get_static_data_format() const;
+ int get_static_data_width() const;
+ int get_static_data_height() const;
+ int get_static_data_depth() const;
+
+ virtual RID get_rid() const;
+
+ GIProbeData();
+ ~GIProbeData();
+};
+
+VARIANT_ENUM_CAST(GIProbeData::DataFormat);
+
+class GIProbe : public VisualInstance {
+ OBJ_TYPE(GIProbe,VisualInstance);
+public:
+ enum Subdiv{
+ SUBDIV_64,
+ SUBDIV_128,
+ SUBDIV_256,
+ SUBDIV_512,
+ SUBDIV_MAX
+
+ };
+private:
+
+ //stuff used for bake
+ struct Baker {
+
+ enum {
+ CHILD_EMPTY=0xFFFFFFFF
+ };
+ struct Cell {
+
+ uint32_t childs[8];
+ float albedo[3]; //albedo in RGB24
+ float emission[3]; //accumulated light in 16:16 fixed point (needs to be integer for moving lights fast)
+ uint32_t used_sides;
+ float alpha; //used for upsampling
+
+ Cell() {
+ for(int i=0;i<8;i++) {
+ childs[i]=CHILD_EMPTY;
+ }
+
+ for(int i=0;i<3;i++) {
+ emission[i]=0;
+ albedo[i]=0;
+ }
+ alpha=0;
+ used_sides=0;
+ }
+ };
+
+ Vector<Cell> bake_cells;
+ int cell_subdiv;
+
+ struct MaterialCache {
+ //128x128 textures
+ Vector<Color> albedo;
+ Vector<Color> emission;
+ };
+
+
+ Vector<Color> _get_bake_texture(Image &p_image, const Color &p_color);
+ Map<Ref<Material>,MaterialCache> material_cache;
+ MaterialCache _get_material_cache(Ref<Material> p_material);
+ int leaf_voxel_count;
+
+
+ AABB po2_bounds;
+ int axis_cell_size[3];
+
+ struct PlotMesh {
+ Ref<Mesh> mesh;
+ Transform local_xform;
+ };
+
+ Transform to_cell_space;
+
+ List<PlotMesh> mesh_list;
+ };
+
+
+ Ref<GIProbeData> probe_data;
+
+ RID gi_probe;
+
+ Subdiv subdiv;
+ Vector3 extents;
+ float dynamic_range;
+
+ int color_scan_cell_width;
+ int bake_texture_size;
+
+ Vector<Color> _get_bake_texture(Image &p_image,const Color& p_color);
+ Baker::MaterialCache _get_material_cache(Ref<Material> p_material,Baker *p_baker);
+ void _plot_face(int p_idx, int p_level, int p_x,int p_y,int p_z,const Vector3 *p_vtx, const Vector2* p_uv, const Baker::MaterialCache& p_material, const AABB &p_aabb,Baker *p_baker);
+ void _plot_mesh(const Transform& p_xform, Ref<Mesh>& p_mesh, Baker *p_baker);
+ void _find_meshes(Node *p_at_node,Baker *p_baker);
+ void _fixup_plot(int p_idx, int p_level,int p_x,int p_y, int p_z,Baker *p_baker);
+
+ void _debug_mesh(int p_idx, int p_level, const AABB &p_aabb,Ref<MultiMesh> &p_multimesh,int &idx,Baker *p_baker);
+ void _create_debug_mesh(Baker *p_baker);
+
+ void _debug_bake();
+
+protected:
+
+ static void _bind_methods();
+public:
+
+ void set_probe_data(const Ref<GIProbeData>& p_data);
+ Ref<GIProbeData> get_probe_data() const;
+
+ void set_subdiv(Subdiv p_subdiv);
+ Subdiv get_subdiv() const;
+
+ void set_extents(const Vector3& p_extents);
+ Vector3 get_extents() const;
+
+ void set_dynamic_range(float p_dynamic_range);
+ float get_dynamic_range() const;
+
+ void bake(Node *p_from_node=NULL,bool p_create_visual_debug=false);
+
+ virtual AABB get_aabb() const;
+ virtual DVector<Face3> get_faces(uint32_t p_usage_flags) const;
+
+ GIProbe();
+ ~GIProbe();
+};
+
+VARIANT_ENUM_CAST(GIProbe::Subdiv)
+
+#endif // GIPROBE_H
diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp
index 7177e21e1e..1566743e1b 100644
--- a/scene/3d/light.cpp
+++ b/scene/3d/light.cpp
@@ -30,7 +30,7 @@
#include "globals.h"
#include "scene/resources/surface_tool.h"
-
+#include "baked_light_instance.h"
bool Light::_can_gizmo_scale() const {
@@ -168,9 +168,37 @@ void Light::_update_visibility() {
void Light::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_TREE || p_what==NOTIFICATION_VISIBILITY_CHANGED) {
+
+ if (p_what==NOTIFICATION_VISIBILITY_CHANGED) {
+
_update_visibility();
+
+ }
+
+ if (p_what==NOTIFICATION_ENTER_TREE) {
+ _update_visibility();
+
+ Node *node = this;
+
+ while(node) {
+
+ baked_light=node->cast_to<BakedLight>();
+ if (baked_light) {
+ baked_light->lights.insert(this);
+ break;
+ }
+
+ node=node->get_parent();
+ }
}
+
+ if (p_what==NOTIFICATION_EXIT_TREE) {
+
+ if (baked_light) {
+ baked_light->lights.erase(this);
+ }
+ }
+
}
@@ -247,6 +275,8 @@ Light::Light(VisualServer::LightType p_type) {
light=VisualServer::get_singleton()->light_create(p_type);
VS::get_singleton()->instance_set_base(get_instance(),light);
+ baked_light=NULL;
+
editor_only=false;
set_color(Color(1,1,1,1));
set_shadow(false);
diff --git a/scene/3d/light.h b/scene/3d/light.h
index fcf5ce90f9..45adfc1dee 100644
--- a/scene/3d/light.h
+++ b/scene/3d/light.h
@@ -37,6 +37,10 @@
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
+
+
+class BakedLight;
+
class Light : public VisualInstance {
OBJ_TYPE( Light, VisualInstance );
@@ -72,6 +76,8 @@ private:
VS::LightType type;
bool editor_only;
void _update_visibility();
+
+ BakedLight *baked_light;
// bind helpers
protected:
diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp
index 5bc332f8fb..f5dbf7c53a 100644
--- a/scene/3d/visual_instance.cpp
+++ b/scene/3d/visual_instance.cpp
@@ -31,7 +31,6 @@
#include "servers/visual_server.h"
#include "room_instance.h"
#include "scene/scene_string_names.h"
-#include "baked_light_instance.h"
#include "skeleton.h"
AABB VisualInstance::get_transformed_aabb() const {
@@ -227,7 +226,6 @@ void GeometryInstance::_notification(int p_what) {
if (flags[FLAG_USE_BAKED_LIGHT]) {
- _find_baked_light();
}
_update_visibility();
@@ -236,11 +234,6 @@ void GeometryInstance::_notification(int p_what) {
if (flags[FLAG_USE_BAKED_LIGHT]) {
- if (baked_light_instance) {
- // baked_light_instance->disconnect(SceneStringNames::get_singleton()->baked_light_changed,this,SceneStringNames::get_singleton()->_baked_light_changed);
- // baked_light_instance=NULL;
- }
- _baked_light_changed();
}
@@ -252,37 +245,6 @@ void GeometryInstance::_notification(int p_what) {
}
-void GeometryInstance::_baked_light_changed() {
-
- //if (!baked_light_instance)
- // VS::get_singleton()->instance_geometry_set_baked_light(get_instance(),RID());
-// else
-// VS::get_singleton()->instance_geometry_set_baked_light(get_instance(),baked_light_instance->get_baked_light_instance());
-
-}
-
-void GeometryInstance::_find_baked_light() {
-/*
- Node *n=get_parent();
- while(n) {
-
- BakedLightInstance *bl=n->cast_to<BakedLightInstance>();
- if (bl) {
-
- baked_light_instance=bl;
- baked_light_instance->connect(SceneStringNames::get_singleton()->baked_light_changed,this,SceneStringNames::get_singleton()->_baked_light_changed);
- _baked_light_changed();
-
- return;
- }
-
- n=n->get_parent();
- }
-
- _baked_light_changed();
- */
-}
-
void GeometryInstance::_update_visibility() {
if (!is_inside_tree())
@@ -314,17 +276,6 @@ void GeometryInstance::set_flag(Flags p_flag,bool p_value) {
}
if (p_flag==FLAG_USE_BAKED_LIGHT) {
- /* if (is_inside_world()) {
- if (!p_value) {
- if (baked_light_instance) {
- baked_light_instance->disconnect(SceneStringNames::get_singleton()->baked_light_changed,this,SceneStringNames::get_singleton()->_baked_light_changed);
- baked_light_instance=NULL;
- }
- _baked_light_changed();
- } else {
- _find_baked_light();
- }
- }*/
}
}
@@ -357,17 +308,8 @@ GeometryInstance::ShadowCastingSetting GeometryInstance::get_cast_shadows_settin
return shadow_casting_setting;
}
-void GeometryInstance::set_baked_light_texture_id(int p_id) {
-// baked_light_texture_id=p_id;
-// VS::get_singleton()->instance_geometry_set_baked_light_texture_index(get_instance(),baked_light_texture_id);
-}
-
-int GeometryInstance::get_baked_light_texture_id() const{
-
- return baked_light_texture_id;
-}
void GeometryInstance::set_extra_cull_margin(float p_margin) {
@@ -405,15 +347,11 @@ void GeometryInstance::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_lod_min_distance"), &GeometryInstance::get_lod_min_distance);
- ObjectTypeDB::bind_method(_MD("set_baked_light_texture_id","id"), &GeometryInstance::set_baked_light_texture_id);
- ObjectTypeDB::bind_method(_MD("get_baked_light_texture_id"), &GeometryInstance::get_baked_light_texture_id);
-
ObjectTypeDB::bind_method(_MD("set_extra_cull_margin","margin"), &GeometryInstance::set_extra_cull_margin);
ObjectTypeDB::bind_method(_MD("get_extra_cull_margin"), &GeometryInstance::get_extra_cull_margin);
ObjectTypeDB::bind_method(_MD("get_aabb"),&GeometryInstance::get_aabb);
- ObjectTypeDB::bind_method(_MD("_baked_light_changed"), &GeometryInstance::_baked_light_changed);
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/visible"), _SCS("set_flag"), _SCS("get_flag"),FLAG_VISIBLE);
ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "geometry/material_override",PROPERTY_HINT_RESOURCE_TYPE,"Material"), _SCS("set_material_override"), _SCS("get_material_override"));
@@ -424,7 +362,6 @@ void GeometryInstance::_bind_methods() {
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/depth_scale"), _SCS("set_flag"), _SCS("get_flag"),FLAG_DEPH_SCALE);
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/visible_in_all_rooms"), _SCS("set_flag"), _SCS("get_flag"),FLAG_VISIBLE_IN_ALL_ROOMS);
ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "geometry/use_baked_light"), _SCS("set_flag"), _SCS("get_flag"),FLAG_USE_BAKED_LIGHT);
- ADD_PROPERTY( PropertyInfo( Variant::INT, "geometry/baked_light_tex_id"), _SCS("set_baked_light_texture_id"), _SCS("get_baked_light_texture_id"));
ADD_PROPERTY( PropertyInfo( Variant::INT, "lod/min_distance",PROPERTY_HINT_RANGE,"0,32768,0.01"), _SCS("set_lod_min_distance"), _SCS("get_lod_min_distance"));
ADD_PROPERTY( PropertyInfo( Variant::INT, "lod/min_hysteresis",PROPERTY_HINT_RANGE,"0,32768,0.01"), _SCS("set_lod_min_hysteresis"), _SCS("get_lod_min_hysteresis"));
ADD_PROPERTY( PropertyInfo( Variant::INT, "lod/max_distance",PROPERTY_HINT_RANGE,"0,32768,0.01"), _SCS("set_lod_max_distance"), _SCS("get_lod_max_distance"));
@@ -461,8 +398,6 @@ GeometryInstance::GeometryInstance() {
flags[FLAG_CAST_SHADOW]=true;
shadow_casting_setting=SHADOW_CASTING_SETTING_ON;
- baked_light_instance=NULL;
- baked_light_texture_id=0;
extra_cull_margin=0;
// VS::get_singleton()->instance_geometry_set_baked_light_texture_index(get_instance(),0);
diff --git a/scene/3d/visual_instance.h b/scene/3d/visual_instance.h
index b168bcbfe5..5fd0830d3f 100644
--- a/scene/3d/visual_instance.h
+++ b/scene/3d/visual_instance.h
@@ -79,7 +79,7 @@ public:
};
-class BakedLightInstance;
+class BakedLight;
class GeometryInstance : public VisualInstance {
@@ -114,12 +114,9 @@ private:
float lod_max_distance;
float lod_min_hysteresis;
float lod_max_hysteresis;
- void _find_baked_light();
- BakedLightInstance *baked_light_instance;
- int baked_light_texture_id;
+
float extra_cull_margin;
- void _baked_light_changed();
void _update_visibility();
protected:
@@ -148,9 +145,6 @@ public:
void set_material_override(const Ref<Material>& p_material);
Ref<Material> get_material_override() const;
- void set_baked_light_texture_id(int p_id);
- int get_baked_light_texture_id() const;
-
void set_extra_cull_margin(float p_margin);
float get_extra_cull_margin() const;
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index d2b9def5c7..1c2620ec9a 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -205,6 +205,7 @@
#include "scene/3d/quad.h"
#include "scene/3d/light.h"
#include "scene/3d/reflection_probe.h"
+#include "scene/3d/gi_probe.h"
#include "scene/3d/particles.h"
#include "scene/3d/portal.h"
#include "scene/resources/environment.h"
@@ -424,6 +425,8 @@ void register_scene_types() {
ObjectTypeDB::register_type<OmniLight>();
ObjectTypeDB::register_type<SpotLight>();
ObjectTypeDB::register_type<ReflectionProbe>();
+ ObjectTypeDB::register_type<GIProbe>();
+ ObjectTypeDB::register_type<GIProbeData>();
ObjectTypeDB::register_type<AnimationTreePlayer>();
ObjectTypeDB::register_type<Portal>();
//ObjectTypeDB::register_type<Particles>();
@@ -455,7 +458,7 @@ void register_scene_types() {
ObjectTypeDB::register_type<PathFollow>();
ObjectTypeDB::register_type<VisibilityNotifier>();
ObjectTypeDB::register_type<VisibilityEnabler>();
- //ObjectTypeDB::register_type<BakedLightInstance>();
+ ObjectTypeDB::register_type<BakedLight>();
//ObjectTypeDB::register_type<BakedLightSampler>();
ObjectTypeDB::register_type<WorldEnvironment>();
ObjectTypeDB::register_type<RemoteTransform>();
diff --git a/scene/resources/baked_light.cpp b/scene/resources/baked_light.cpp
index 38ed661cdd..0d53eff7d3 100644
--- a/scene/resources/baked_light.cpp
+++ b/scene/resources/baked_light.cpp
@@ -29,577 +29,3 @@
#include "baked_light.h"
#include "servers/visual_server.h"
-#if 0
-
-void BakedLight::set_mode(Mode p_mode) {
-
- mode=p_mode;
- VS::get_singleton()->baked_light_set_mode(baked_light,(VS::BakedLightMode(p_mode)));
-
-}
-
-BakedLight::Mode BakedLight::get_mode() const{
-
- return mode;
-}
-
-void BakedLight::set_octree(const DVector<uint8_t>& p_octree) {
-
- VS::get_singleton()->baked_light_set_octree(baked_light,p_octree);
-}
-
-DVector<uint8_t> BakedLight::get_octree() const {
-
- return VS::get_singleton()->baked_light_get_octree(baked_light);
-}
-
-void BakedLight::set_light(const DVector<uint8_t>& p_light) {
-
- VS::get_singleton()->baked_light_set_light(baked_light,p_light);
-}
-
-DVector<uint8_t> BakedLight::get_light() const {
-
- return VS::get_singleton()->baked_light_get_light(baked_light);
-}
-
-
-void BakedLight::set_sampler_octree(const DVector<int>& p_sampler_octree) {
-
- VS::get_singleton()->baked_light_set_sampler_octree(baked_light,p_sampler_octree);
-}
-
-DVector<int> BakedLight::get_sampler_octree() const {
-
- return VS::get_singleton()->baked_light_get_sampler_octree(baked_light);
-}
-
-
-
-
-
-void BakedLight::add_lightmap(const Ref<Texture> &p_texture,Size2 p_gen_size) {
-
- LightMap lm;
- lm.texture=p_texture;
- lm.gen_size=p_gen_size;
- lightmaps.push_back(lm);
- _update_lightmaps();
- _change_notify();
-}
-
-void BakedLight::set_lightmap_gen_size(int p_idx,const Size2& p_size){
-
- ERR_FAIL_INDEX(p_idx,lightmaps.size());
- lightmaps[p_idx].gen_size=p_size;
- _update_lightmaps();
-}
-Size2 BakedLight::get_lightmap_gen_size(int p_idx) const{
-
- ERR_FAIL_INDEX_V(p_idx,lightmaps.size(),Size2());
- return lightmaps[p_idx].gen_size;
-
-}
-void BakedLight::set_lightmap_texture(int p_idx,const Ref<Texture> &p_texture){
-
- ERR_FAIL_INDEX(p_idx,lightmaps.size());
- lightmaps[p_idx].texture=p_texture;
- _update_lightmaps();
-
-}
-Ref<Texture> BakedLight::get_lightmap_texture(int p_idx) const{
-
- ERR_FAIL_INDEX_V(p_idx,lightmaps.size(),Ref<Texture>());
- return lightmaps[p_idx].texture;
-
-}
-void BakedLight::erase_lightmap(int p_idx){
-
- ERR_FAIL_INDEX(p_idx,lightmaps.size());
- lightmaps.remove(p_idx);
- _update_lightmaps();
- _change_notify();
-
-}
-int BakedLight::get_lightmaps_count() const{
-
- return lightmaps.size();
-}
-void BakedLight::clear_lightmaps(){
-
- lightmaps.clear();
- _update_lightmaps();
- _change_notify();
-}
-
-
-
-void BakedLight::_update_lightmaps() {
-
- VS::get_singleton()->baked_light_clear_lightmaps(baked_light);
- for(int i=0;i<lightmaps.size();i++) {
-
- RID tid;
- if (lightmaps[i].texture.is_valid())
- tid=lightmaps[i].texture->get_rid();
- VS::get_singleton()->baked_light_add_lightmap(baked_light,tid,i);
- }
-}
-
-
-
-RID BakedLight::get_rid() const {
-
- return baked_light;
-}
-
-Array BakedLight::_get_lightmap_data() const {
-
- Array ret;
- ret.resize(lightmaps.size()*2);
-
- int idx=0;
- for(int i=0;i<lightmaps.size();i++) {
-
- ret[idx++]=Size2(lightmaps[i].gen_size);
- ret[idx++]=lightmaps[i].texture;
- }
- return ret;
-
-}
-
-void BakedLight::_set_lightmap_data(Array p_array){
-
- lightmaps.clear();
- for(int i=0;i<p_array.size();i+=2) {
-
- Size2 size = p_array[i];
- Ref<Texture> tex = p_array[i+1];
-// ERR_CONTINUE(tex.is_null());
- LightMap lm;
- lm.gen_size=size;
- lm.texture=tex;
- lightmaps.push_back(lm);
- }
- _update_lightmaps();
-}
-
-
-void BakedLight::set_cell_subdivision(int p_subdiv) {
-
- cell_subdiv=p_subdiv;
-}
-
-int BakedLight::get_cell_subdivision() const{
-
- return cell_subdiv;
-}
-
-void BakedLight::set_initial_lattice_subdiv(int p_size){
-
- lattice_subdiv=p_size;
-}
-int BakedLight::get_initial_lattice_subdiv() const{
-
- return lattice_subdiv;
-}
-
-void BakedLight::set_plot_size(float p_size){
-
- plot_size=p_size;
-}
-float BakedLight::get_plot_size() const{
-
- return plot_size;
-}
-
-void BakedLight::set_bounces(int p_size){
-
- bounces=p_size;
-}
-int BakedLight::get_bounces() const{
-
- return bounces;
-}
-
-void BakedLight::set_cell_extra_margin(float p_margin) {
- cell_extra_margin=p_margin;
-}
-
-float BakedLight::get_cell_extra_margin() const {
-
- return cell_extra_margin;
-}
-
-void BakedLight::set_edge_damp(float p_margin) {
- edge_damp=p_margin;
-}
-
-float BakedLight::get_edge_damp() const {
-
- return edge_damp;
-}
-
-
-void BakedLight::set_normal_damp(float p_margin) {
- normal_damp=p_margin;
-}
-
-float BakedLight::get_normal_damp() const {
-
- return normal_damp;
-}
-
-void BakedLight::set_tint(float p_margin) {
- tint=p_margin;
-}
-
-float BakedLight::get_tint() const {
-
- return tint;
-}
-
-void BakedLight::set_saturation(float p_margin) {
- saturation=p_margin;
-}
-
-float BakedLight::get_saturation() const {
-
- return saturation;
-}
-
-void BakedLight::set_ao_radius(float p_ao_radius) {
- ao_radius=p_ao_radius;
-}
-
-float BakedLight::get_ao_radius() const {
- return ao_radius;
-}
-
-void BakedLight::set_ao_strength(float p_ao_strength) {
-
- ao_strength=p_ao_strength;
-}
-
-float BakedLight::get_ao_strength() const {
-
- return ao_strength;
-}
-
-void BakedLight::set_realtime_color_enabled(const bool p_realtime_color_enabled) {
-
- VS::get_singleton()->baked_light_set_realtime_color_enabled(baked_light, p_realtime_color_enabled);
-}
-
-bool BakedLight::get_realtime_color_enabled() const {
-
- return VS::get_singleton()->baked_light_get_realtime_color_enabled(baked_light);
-}
-
-
-void BakedLight::set_realtime_color(const Color &p_realtime_color) {
-
- VS::get_singleton()->baked_light_set_realtime_color(baked_light, p_realtime_color);
-}
-
-Color BakedLight::get_realtime_color() const {
-
- return VS::get_singleton()->baked_light_get_realtime_color(baked_light);
-}
-
-void BakedLight::set_realtime_energy(const float p_realtime_energy) {
-
- VS::get_singleton()->baked_light_set_realtime_energy(baked_light, p_realtime_energy);
-}
-
-float BakedLight::get_realtime_energy() const {
-
- return VS::get_singleton()->baked_light_get_realtime_energy(baked_light);
-}
-
-
-
-void BakedLight::set_energy_multiplier(float p_multiplier){
-
- energy_multiply=p_multiplier;
-}
-float BakedLight::get_energy_multiplier() const{
-
- return energy_multiply;
-}
-
-void BakedLight::set_gamma_adjust(float p_adjust){
-
- gamma_adjust=p_adjust;
-}
-float BakedLight::get_gamma_adjust() const{
-
- return gamma_adjust;
-}
-
-void BakedLight::set_bake_flag(BakeFlags p_flags,bool p_enable){
-
- flags[p_flags]=p_enable;
-}
-bool BakedLight::get_bake_flag(BakeFlags p_flags) const{
-
- return flags[p_flags];
-}
-
-void BakedLight::set_format(Format p_format) {
-
- format=p_format;
- VS::get_singleton()->baked_light_set_lightmap_multiplier(baked_light,format==FORMAT_HDR8?8.0:1.0);
-}
-
-BakedLight::Format BakedLight::get_format() const{
-
- return format;
-}
-
-void BakedLight::set_transfer_lightmaps_only_to_uv2(bool p_enable) {
-
- transfer_only_uv2=p_enable;
-}
-
-bool BakedLight::get_transfer_lightmaps_only_to_uv2() const{
-
- return transfer_only_uv2;
-}
-
-
-bool BakedLight::_set(const StringName& p_name, const Variant& p_value) {
-
- String n = p_name;
- if (!n.begins_with("lightmap"))
- return false;
- int idx = n.get_slicec('/',1).to_int();
- ERR_FAIL_COND_V(idx<0,false);
- ERR_FAIL_COND_V(idx>lightmaps.size(),false);
-
- String what = n.get_slicec('/',2);
- Ref<Texture> tex;
- Size2 gens;
-
- if (what=="texture")
- tex=p_value;
- else if (what=="gen_size")
- gens=p_value;
-
- if (idx==lightmaps.size()) {
- if (tex.is_valid() || gens!=Size2())
- add_lightmap(tex,gens);
- } else {
- if (tex.is_valid())
- set_lightmap_texture(idx,tex);
- else if (gens!=Size2())
- set_lightmap_gen_size(idx,gens);
- }
-
-
- return true;
-}
-
-bool BakedLight::_get(const StringName& p_name,Variant &r_ret) const{
-
- String n = p_name;
- if (!n.begins_with("lightmap"))
- return false;
- int idx = n.get_slicec('/',1).to_int();
- ERR_FAIL_COND_V(idx<0,false);
- ERR_FAIL_COND_V(idx>lightmaps.size(),false);
-
- String what = n.get_slicec('/',2);
-
- if (what=="texture") {
- if (idx==lightmaps.size())
- r_ret=Ref<Texture>();
- else
- r_ret=lightmaps[idx].texture;
-
- } else if (what=="gen_size") {
-
- if (idx==lightmaps.size())
- r_ret=Size2();
- else
- r_ret=Size2(lightmaps[idx].gen_size);
- } else
- return false;
-
- return true;
-
-
-}
-void BakedLight::_get_property_list( List<PropertyInfo> *p_list) const{
-
- for(int i=0;i<=lightmaps.size();i++) {
-
- p_list->push_back(PropertyInfo(Variant::VECTOR2,"lightmaps/"+itos(i)+"/gen_size",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_EDITOR));
- p_list->push_back(PropertyInfo(Variant::OBJECT,"lightmaps/"+itos(i)+"/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture",PROPERTY_USAGE_EDITOR));
- }
-}
-
-
-void BakedLight::_bind_methods(){
-
-
- ObjectTypeDB::bind_method(_MD("set_mode","mode"),&BakedLight::set_mode);
- ObjectTypeDB::bind_method(_MD("get_mode"),&BakedLight::get_mode);
-
- ObjectTypeDB::bind_method(_MD("set_octree","octree"),&BakedLight::set_octree);
- ObjectTypeDB::bind_method(_MD("get_octree"),&BakedLight::get_octree);
-
- ObjectTypeDB::bind_method(_MD("set_light","light"),&BakedLight::set_light);
- ObjectTypeDB::bind_method(_MD("get_light"),&BakedLight::get_light);
-
- ObjectTypeDB::bind_method(_MD("set_sampler_octree","sampler_octree"),&BakedLight::set_sampler_octree);
- ObjectTypeDB::bind_method(_MD("get_sampler_octree"),&BakedLight::get_sampler_octree);
-
-
- ObjectTypeDB::bind_method(_MD("add_lightmap","texture:Texture","gen_size"),&BakedLight::add_lightmap);
- ObjectTypeDB::bind_method(_MD("erase_lightmap","id"),&BakedLight::erase_lightmap);
- ObjectTypeDB::bind_method(_MD("clear_lightmaps"),&BakedLight::clear_lightmaps);
-
- ObjectTypeDB::bind_method(_MD("_set_lightmap_data","lightmap_data"),&BakedLight::_set_lightmap_data);
- ObjectTypeDB::bind_method(_MD("_get_lightmap_data"),&BakedLight::_get_lightmap_data);
-
- ObjectTypeDB::bind_method(_MD("set_cell_subdivision","cell_subdivision"),&BakedLight::set_cell_subdivision);
- ObjectTypeDB::bind_method(_MD("get_cell_subdivision"),&BakedLight::get_cell_subdivision);
-
- ObjectTypeDB::bind_method(_MD("set_initial_lattice_subdiv","cell_subdivision"),&BakedLight::set_initial_lattice_subdiv);
- ObjectTypeDB::bind_method(_MD("get_initial_lattice_subdiv","cell_subdivision"),&BakedLight::get_initial_lattice_subdiv);
-
- ObjectTypeDB::bind_method(_MD("set_plot_size","plot_size"),&BakedLight::set_plot_size);
- ObjectTypeDB::bind_method(_MD("get_plot_size"),&BakedLight::get_plot_size);
-
- ObjectTypeDB::bind_method(_MD("set_bounces","bounces"),&BakedLight::set_bounces);
- ObjectTypeDB::bind_method(_MD("get_bounces"),&BakedLight::get_bounces);
-
- ObjectTypeDB::bind_method(_MD("set_cell_extra_margin","cell_extra_margin"),&BakedLight::set_cell_extra_margin);
- ObjectTypeDB::bind_method(_MD("get_cell_extra_margin"),&BakedLight::get_cell_extra_margin);
-
- ObjectTypeDB::bind_method(_MD("set_edge_damp","edge_damp"),&BakedLight::set_edge_damp);
- ObjectTypeDB::bind_method(_MD("get_edge_damp"),&BakedLight::get_edge_damp);
-
- ObjectTypeDB::bind_method(_MD("set_normal_damp","normal_damp"),&BakedLight::set_normal_damp);
- ObjectTypeDB::bind_method(_MD("get_normal_damp"),&BakedLight::get_normal_damp);
-
- ObjectTypeDB::bind_method(_MD("set_tint","tint"),&BakedLight::set_tint);
- ObjectTypeDB::bind_method(_MD("get_tint"),&BakedLight::get_tint);
-
- ObjectTypeDB::bind_method(_MD("set_saturation","saturation"),&BakedLight::set_saturation);
- ObjectTypeDB::bind_method(_MD("get_saturation"),&BakedLight::get_saturation);
-
- ObjectTypeDB::bind_method(_MD("set_ao_radius","ao_radius"),&BakedLight::set_ao_radius);
- ObjectTypeDB::bind_method(_MD("get_ao_radius"),&BakedLight::get_ao_radius);
-
- ObjectTypeDB::bind_method(_MD("set_ao_strength","ao_strength"),&BakedLight::set_ao_strength);
- ObjectTypeDB::bind_method(_MD("get_ao_strength"),&BakedLight::get_ao_strength);
-
- ObjectTypeDB::bind_method(_MD("set_realtime_color_enabled", "enabled"), &BakedLight::set_realtime_color_enabled);
- ObjectTypeDB::bind_method(_MD("get_realtime_color_enabled"), &BakedLight::get_realtime_color_enabled);
-
- ObjectTypeDB::bind_method(_MD("set_realtime_color", "tint"), &BakedLight::set_realtime_color);
- ObjectTypeDB::bind_method(_MD("get_realtime_color"), &BakedLight::get_realtime_color);
-
- ObjectTypeDB::bind_method(_MD("set_realtime_energy", "energy"), &BakedLight::set_realtime_energy);
- ObjectTypeDB::bind_method(_MD("get_realtime_energy"), &BakedLight::get_realtime_energy);
-
- ObjectTypeDB::bind_method(_MD("set_format","format"),&BakedLight::set_format);
- ObjectTypeDB::bind_method(_MD("get_format"),&BakedLight::get_format);
-
- ObjectTypeDB::bind_method(_MD("set_transfer_lightmaps_only_to_uv2","enable"),&BakedLight::set_transfer_lightmaps_only_to_uv2);
- ObjectTypeDB::bind_method(_MD("get_transfer_lightmaps_only_to_uv2"),&BakedLight::get_transfer_lightmaps_only_to_uv2);
-
-
-
-
- ObjectTypeDB::bind_method(_MD("set_energy_multiplier","energy_multiplier"),&BakedLight::set_energy_multiplier);
- ObjectTypeDB::bind_method(_MD("get_energy_multiplier"),&BakedLight::get_energy_multiplier);
-
- ObjectTypeDB::bind_method(_MD("set_gamma_adjust","gamma_adjust"),&BakedLight::set_gamma_adjust);
- ObjectTypeDB::bind_method(_MD("get_gamma_adjust"),&BakedLight::get_gamma_adjust);
-
- ObjectTypeDB::bind_method(_MD("set_bake_flag","flag","enabled"),&BakedLight::set_bake_flag);
- ObjectTypeDB::bind_method(_MD("get_bake_flag","flag"),&BakedLight::get_bake_flag);
-
- ADD_PROPERTY( PropertyInfo(Variant::INT,"mode/mode",PROPERTY_HINT_ENUM,"Octree,Lightmaps"),_SCS("set_mode"),_SCS("get_mode"));
-
- ADD_PROPERTY( PropertyInfo(Variant::INT,"baking/format",PROPERTY_HINT_ENUM,"RGB,HDR8,HDR16"),_SCS("set_format"),_SCS("get_format"));
- ADD_PROPERTY( PropertyInfo(Variant::INT,"baking/cell_subdiv",PROPERTY_HINT_RANGE,"4,14,1"),_SCS("set_cell_subdivision"),_SCS("get_cell_subdivision"));
- ADD_PROPERTY( PropertyInfo(Variant::INT,"baking/lattice_subdiv",PROPERTY_HINT_RANGE,"1,5,1"),_SCS("set_initial_lattice_subdiv"),_SCS("get_initial_lattice_subdiv"));
- ADD_PROPERTY( PropertyInfo(Variant::INT,"baking/light_bounces",PROPERTY_HINT_RANGE,"0,3,1"),_SCS("set_bounces"),_SCS("get_bounces"));
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"baking/plot_size",PROPERTY_HINT_RANGE,"1.0,16.0,0.01"),_SCS("set_plot_size"),_SCS("get_plot_size"));
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"baking/energy_mult",PROPERTY_HINT_RANGE,"0.01,4096.0,0.01"),_SCS("set_energy_multiplier"),_SCS("get_energy_multiplier"));
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"baking/gamma_adjust",PROPERTY_HINT_EXP_EASING),_SCS("set_gamma_adjust"),_SCS("get_gamma_adjust"));
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"baking/saturation",PROPERTY_HINT_RANGE,"0,8,0.01"),_SCS("set_saturation"),_SCS("get_saturation"));
- ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/diffuse"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_DIFFUSE);
- ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/specular"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_SPECULAR);
- ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/translucent"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_TRANSLUCENT);
- ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/conserve_energy"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_CONSERVE_ENERGY);
- ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/linear_color"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_LINEAR_COLOR);
- ADD_PROPERTY( PropertyInfo(Variant::BOOL,"lightmap/use_only_uv2"),_SCS("set_transfer_lightmaps_only_to_uv2"),_SCS("get_transfer_lightmaps_only_to_uv2"));
-
- ADD_PROPERTY( PropertyInfo(Variant::RAW_ARRAY,"octree",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_octree"),_SCS("get_octree"));
- ADD_PROPERTY( PropertyInfo(Variant::RAW_ARRAY,"light",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_light"),_SCS("get_light"));
- ADD_PROPERTY( PropertyInfo(Variant::INT_ARRAY,"sampler_octree",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_sampler_octree"),_SCS("get_sampler_octree"));
- ADD_PROPERTY( PropertyInfo(Variant::ARRAY,"lightmaps",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_lightmap_data"),_SCS("_get_lightmap_data"));
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/cell_margin",PROPERTY_HINT_RANGE,"0.01,0.8,0.01"),_SCS("set_cell_extra_margin"),_SCS("get_cell_extra_margin"));
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/edge_damp",PROPERTY_HINT_RANGE,"0.0,8.0,0.1"),_SCS("set_edge_damp"),_SCS("get_edge_damp"));
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/normal_damp",PROPERTY_HINT_RANGE,"0.0,1.0,0.01"),_SCS("set_normal_damp"),_SCS("get_normal_damp"));
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/light_tint",PROPERTY_HINT_RANGE,"0.0,1.0,0.01"),_SCS("set_tint"),_SCS("get_tint"));
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/ao_radius",PROPERTY_HINT_RANGE,"0.0,16.0,0.01"),_SCS("set_ao_radius"),_SCS("get_ao_radius"));
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/ao_strength",PROPERTY_HINT_RANGE,"0.0,1.0,0.01"),_SCS("set_ao_strength"),_SCS("get_ao_strength"));
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "realtime/enabled"), _SCS("set_realtime_color_enabled"), _SCS("get_realtime_color_enabled"));
- ADD_PROPERTY(PropertyInfo(Variant::COLOR, "realtime/color", PROPERTY_HINT_COLOR_NO_ALPHA), _SCS("set_realtime_color"), _SCS("get_realtime_color"));
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "realtime/energy", PROPERTY_HINT_RANGE, "0.01,4096.0,0.01"), _SCS("set_realtime_energy"), _SCS("get_realtime_energy"));
-
-
- BIND_CONSTANT( MODE_OCTREE );
- BIND_CONSTANT( MODE_LIGHTMAPS );
-
- BIND_CONSTANT( BAKE_DIFFUSE );
- BIND_CONSTANT( BAKE_SPECULAR );
- BIND_CONSTANT( BAKE_TRANSLUCENT );
- BIND_CONSTANT( BAKE_CONSERVE_ENERGY );
- BIND_CONSTANT( BAKE_MAX );
-
-
-}
-
-
-BakedLight::BakedLight() {
-
- cell_subdiv=8;
- lattice_subdiv=4;
- plot_size=2.5;
- bounces=1;
- energy_multiply=2.0;
- gamma_adjust=0.7;
- cell_extra_margin=0.05;
- edge_damp=0.0;
- normal_damp=0.0;
- saturation=1;
- tint=0.0;
- ao_radius=2.5;
- ao_strength=0.7;
- format=FORMAT_RGB8;
- transfer_only_uv2=false;
-
-
- flags[BAKE_DIFFUSE]=true;
- flags[BAKE_SPECULAR]=false;
- flags[BAKE_TRANSLUCENT]=true;
- flags[BAKE_CONSERVE_ENERGY]=false;
- flags[BAKE_LINEAR_COLOR]=false;
-
- mode=MODE_OCTREE;
- baked_light=VS::get_singleton()->baked_light_create();
-}
-
-BakedLight::~BakedLight() {
-
- VS::get_singleton()->free(baked_light);
-}
-#endif
diff --git a/scene/resources/baked_light.h b/scene/resources/baked_light.h
index 0eaa3df276..6a0742dd27 100644
--- a/scene/resources/baked_light.h
+++ b/scene/resources/baked_light.h
@@ -32,169 +32,6 @@
#include "resource.h"
#include "scene/resources/texture.h"
-#if 0
-class BakedLight : public Resource {
- OBJ_TYPE( BakedLight, Resource);
-public:
- enum Mode {
- MODE_OCTREE,
- MODE_LIGHTMAPS
- };
-
- enum Format {
-
- FORMAT_RGB8,
- FORMAT_HDR8,
- FORMAT_HDR16
- };
-
- enum BakeFlags {
- BAKE_DIFFUSE,
- BAKE_SPECULAR,
- BAKE_TRANSLUCENT,
- BAKE_CONSERVE_ENERGY,
- BAKE_LINEAR_COLOR,
- BAKE_MAX
- };
-
-private:
-
- RID baked_light;
- Mode mode;
- struct LightMap {
- Size2i gen_size;
- Ref<Texture> texture;
- };
-
-
- Vector< LightMap> lightmaps;
-
- //bake vars
- int cell_subdiv;
- int lattice_subdiv;
- float plot_size;
- float energy_multiply;
- float gamma_adjust;
- float cell_extra_margin;
- float edge_damp;
- float normal_damp;
- float tint;
- float ao_radius;
- float ao_strength;
- float saturation;
- int bounces;
- bool transfer_only_uv2;
- Format format;
- bool flags[BAKE_MAX];
-
-
-
- void _update_lightmaps();
-
- Array _get_lightmap_data() const;
- void _set_lightmap_data(Array p_array);
-
-protected:
-
- bool _set(const StringName& p_name, const Variant& p_value);
- bool _get(const StringName& p_name,Variant &r_ret) const;
- void _get_property_list( List<PropertyInfo> *p_list) const;
-
- static void _bind_methods();
-
-public:
-
- void set_cell_subdivision(int p_subdiv);
- int get_cell_subdivision() const;
-
- void set_initial_lattice_subdiv(int p_size);
- int get_initial_lattice_subdiv() const;
-
- void set_plot_size(float p_size);
- float get_plot_size() const;
-
- void set_bounces(int p_size);
- int get_bounces() const;
-
- void set_energy_multiplier(float p_multiplier);
- float get_energy_multiplier() const;
-
- void set_gamma_adjust(float p_adjust);
- float get_gamma_adjust() const;
-
- void set_cell_extra_margin(float p_margin);
- float get_cell_extra_margin() const;
-
- void set_edge_damp(float p_margin);
- float get_edge_damp() const;
-
- void set_normal_damp(float p_margin);
- float get_normal_damp() const;
-
- void set_tint(float p_margin);
- float get_tint() const;
-
- void set_saturation(float p_saturation);
- float get_saturation() const;
-
- void set_ao_radius(float p_ao_radius);
- float get_ao_radius() const;
-
- void set_ao_strength(float p_ao_strength);
- float get_ao_strength() const;
-
- void set_realtime_color_enabled(const bool p_enabled);
- bool get_realtime_color_enabled() const;
-
- void set_realtime_color(const Color& p_realtime_color);
- Color get_realtime_color() const;
-
- void set_realtime_energy(const float p_realtime_energy);
- float get_realtime_energy() const;
-
- void set_bake_flag(BakeFlags p_flags,bool p_enable);
- bool get_bake_flag(BakeFlags p_flags) const;
-
- void set_format(Format p_margin);
- Format get_format() const;
-
- void set_transfer_lightmaps_only_to_uv2(bool p_enable);
- bool get_transfer_lightmaps_only_to_uv2() const;
-
- void set_mode(Mode p_mode);
- Mode get_mode() const;
-
- void set_octree(const DVector<uint8_t>& p_octree);
- DVector<uint8_t> get_octree() const;
-
- void set_light(const DVector<uint8_t>& p_light);
- DVector<uint8_t> get_light() const;
-
- void set_sampler_octree(const DVector<int>& p_sampler_octree);
- DVector<int> get_sampler_octree() const;
-
-
-
- void add_lightmap(const Ref<Texture> &p_texture,Size2 p_gen_size=Size2(256,256));
- void set_lightmap_gen_size(int p_idx,const Size2& p_size);
- Size2 get_lightmap_gen_size(int p_idx) const;
- void set_lightmap_texture(int p_idx,const Ref<Texture> &p_texture);
- Ref<Texture> get_lightmap_texture(int p_idx) const;
- void erase_lightmap(int p_idx);
- int get_lightmaps_count() const;
- void clear_lightmaps();
-
- virtual RID get_rid() const;
-
- BakedLight();
- ~BakedLight();
-};
-
-
-VARIANT_ENUM_CAST(BakedLight::Format);
-VARIANT_ENUM_CAST(BakedLight::Mode);
-VARIANT_ENUM_CAST(BakedLight::BakeFlags);
-#endif
#endif // BAKED_LIGHT_H
diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h
index 228afffdb5..79560f3486 100644
--- a/servers/visual/rasterizer.h
+++ b/servers/visual/rasterizer.h
@@ -91,6 +91,7 @@ public:
Vector<RID> materials;
Vector<RID> light_instances;
Vector<RID> reflection_probe_instances;
+ Vector<RID> gi_probe_instances;
Vector<float> morph_values;
@@ -108,12 +109,14 @@ public:
float depth; //used for sorting
SelfList<InstanceBase> dependency_item;
+ InstanceBase *baked_light; //baked light to use
+ SelfList<InstanceBase> baked_light_item;
virtual void base_removed()=0;
virtual void base_changed()=0;
virtual void base_material_changed()=0;
- InstanceBase() : dependency_item(this) {
+ InstanceBase() : dependency_item(this), baked_light_item(this) {
base_type=VS::INSTANCE_NONE;
cast_shadows=VS::SHADOW_CASTING_SETTING_ON;
@@ -123,6 +126,7 @@ public:
billboard_y=false;
depth_layer=0;
layer_mask=1;
+ baked_light=NULL;
}
};
@@ -144,6 +148,11 @@ public:
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 RID gi_probe_instance_create()=0;
+ virtual void gi_probe_instance_set_light_data(RID p_probe,RID p_data)=0;
+ virtual void gi_probe_instance_set_transform_to_data(RID p_probe,const Transform& p_xform)=0;
+ virtual void gi_probe_instance_set_bounds(RID p_probe,const Vector3& p_bounds)=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;
@@ -340,6 +349,7 @@ public:
virtual VS::LightType light_get_type(RID p_light) const=0;
virtual AABB light_get_aabb(RID p_light) const=0;
virtual float light_get_param(RID p_light,VS::LightParam p_param)=0;
+ virtual Color light_get_color(RID p_light)=0;
virtual uint64_t light_get_version(RID p_light) const=0;
@@ -392,6 +402,39 @@ public:
virtual void instance_add_dependency(RID p_base,RasterizerScene::InstanceBase *p_instance)=0;
virtual void instance_remove_dependency(RID p_base,RasterizerScene::InstanceBase *p_instance)=0;
+ /* GI PROBE API */
+
+ virtual RID gi_probe_create()=0;
+
+ virtual void gi_probe_set_bounds(RID p_probe,const AABB& p_bounds)=0;
+ virtual AABB gi_probe_get_bounds(RID p_probe) const=0;
+
+ virtual void gi_probe_set_cell_size(RID p_probe,float p_range)=0;
+ virtual float gi_probe_get_cell_size(RID p_probe) const=0;
+
+ virtual void gi_probe_set_to_cell_xform(RID p_probe,const Transform& p_xform)=0;
+ virtual Transform gi_probe_get_to_cell_xform(RID p_probe) const=0;
+
+ virtual void gi_probe_set_dynamic_data(RID p_probe,const DVector<int>& p_data)=0;
+ virtual DVector<int> gi_probe_get_dynamic_data(RID p_probe) const=0;
+
+ virtual void gi_probe_set_dynamic_range(RID p_probe,float p_range)=0;
+ virtual float gi_probe_get_dynamic_range(RID p_probe) const=0;
+
+
+ virtual void gi_probe_set_static_data(RID p_gi_probe,const DVector<uint8_t>& p_data,VS::GIProbeDataFormat p_format,int p_width,int p_height,int p_depth)=0;
+ virtual DVector<uint8_t> gi_probe_get_static_data(RID p_gi_probe) const=0;
+ virtual VS::GIProbeDataFormat gi_probe_get_static_data_format(RID p_gi_probe) const=0;
+ virtual int gi_probe_get_static_data_width(RID p_probe) const=0;
+ virtual int gi_probe_get_static_data_height(RID p_probe) const=0;
+ virtual int gi_probe_get_static_data_depth(RID p_probe) const=0;
+
+ virtual RID gi_probe_get_data(RID p_probe)=0; //get data in case this is static
+ virtual uint32_t gi_probe_get_version(RID p_probe)=0;
+
+ virtual RID gi_probe_dynamic_data_create(int p_width,int p_height,int p_depth)=0;
+ virtual void gi_probe_dynamic_data_update_rgba8(RID p_gi_probe_data,int p_depth_slice,int p_slice_count,int p_mipmap,const void* p_data)=0;
+
/* RENDER TARGET */
enum RenderTargetFlags {
diff --git a/servers/visual/visual_server_light_baker.cpp b/servers/visual/visual_server_light_baker.cpp
new file mode 100644
index 0000000000..4956d78ab0
--- /dev/null
+++ b/servers/visual/visual_server_light_baker.cpp
@@ -0,0 +1,6 @@
+#include "visual_server_light_baker.h"
+
+VisualServerLightBaker::VisualServerLightBaker()
+{
+
+}
diff --git a/servers/visual/visual_server_light_baker.h b/servers/visual/visual_server_light_baker.h
new file mode 100644
index 0000000000..42f016f614
--- /dev/null
+++ b/servers/visual/visual_server_light_baker.h
@@ -0,0 +1,29 @@
+#ifndef VISUALSERVERLIGHTBAKER_H
+#define VISUALSERVERLIGHTBAKER_H
+
+#include "servers/visual_server.h"
+
+class VisualServerLightBaker {
+public:
+
+ struct BakeCell {
+
+ uint32_t cells[8];
+ uint32_t neighbours[7]; //one unused
+ uint32_t albedo; //albedo in RGBE
+ uint32_t emission; //emissive light in RGBE
+ uint32_t light[4]; //accumulated light in 16:16 fixed point (needs to be integer for moving lights fast)
+ float alpha; //used for upsampling
+ uint32_t directional_pass; //used for baking directional
+
+ };
+
+
+
+
+
+
+ VisualServerLightBaker();
+};
+
+#endif // VISUALSERVERLIGHTBAKER_H
diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp
index 6ba63a7690..2fa45d1796 100644
--- a/servers/visual/visual_server_raster.cpp
+++ b/servers/visual/visual_server_raster.cpp
@@ -90,9 +90,10 @@ void VisualServerRaster::draw(){
changes=0;
+ VSG::rasterizer->begin_frame();
+
VSG::scene->update_dirty_instances(); //update scene stuff
- VSG::rasterizer->begin_frame();
VSG::viewport->draw_viewports();
VSG::scene->render_probes();
//_draw_cursors_and_margins();
diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h
index 78b0e3cadd..191330c66c 100644
--- a/servers/visual/visual_server_raster.h
+++ b/servers/visual/visual_server_raster.h
@@ -803,12 +803,39 @@ public:
BIND2(portal_set_disable_distance,RID , float )
BIND2(portal_set_disabled_color,RID , const Color& )
- /* CAMERA API */
+ /* BAKED LIGHT API */
+
+ BIND0R(RID, gi_probe_create)
+
+ BIND2(gi_probe_set_bounds,RID,const AABB&)
+ BIND1RC(AABB,gi_probe_get_bounds,RID)
+
+ BIND2(gi_probe_set_cell_size,RID,float)
+ BIND1RC(float,gi_probe_get_cell_size,RID)
+
+ BIND2(gi_probe_set_to_cell_xform,RID,const Transform&)
+ BIND1RC(Transform,gi_probe_get_to_cell_xform,RID)
+
+ BIND2(gi_probe_set_dynamic_range,RID,float)
+ BIND1RC(float,gi_probe_get_dynamic_range,RID)
+
+ BIND2(gi_probe_set_dynamic_data,RID,const DVector<int>& )
+ BIND1RC( DVector<int>,gi_probe_get_dynamic_data,RID)
+
+ BIND6(gi_probe_set_static_data,RID,const DVector<uint8_t>&,GIProbeDataFormat,int,int,int)
+ BIND1RC(DVector<uint8_t>,gi_probe_get_static_data,RID)
+ BIND1RC(GIProbeDataFormat,gi_probe_get_static_data_format,RID)
+ BIND1RC(int,gi_probe_get_static_data_width,RID)
+ BIND1RC(int,gi_probe_get_static_data_height,RID)
+ BIND1RC(int,gi_probe_get_static_data_depth,RID)
+
#undef BINDBASE
//from now on, calls forwarded to this singleton
#define BINDBASE VSG::scene
+ /* CAMERA API */
+
BIND0R(RID, camera_create)
BIND4(camera_set_perspective,RID,float, float , float )
@@ -936,7 +963,6 @@ public:
BIND5(instance_geometry_set_draw_range,RID,float ,float ,float ,float )
BIND2(instance_geometry_set_as_instance_lod,RID,RID )
-
#undef BINDBASE
//from now on, calls forwarded to this singleton
#define BINDBASE VSG::canvas
diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp
index 6f7dac7f4d..62b3a23788 100644
--- a/servers/visual/visual_server_scene.cpp
+++ b/servers/visual/visual_server_scene.cpp
@@ -1,9 +1,12 @@
#include "visual_server_scene.h"
#include "visual_server_global.h"
-
+#include "os/os.h"
/* CAMERA API */
+
+
+
RID VisualServerScene::camera_create() {
Camera * camera = memnew( Camera );
@@ -118,6 +121,28 @@ void* VisualServerScene::_instance_pair(void *p_self, OctreeElementID, Instance
geom->reflection_dirty=true;
return E; //this element should make freeing faster
+ } else if (B->base_type==VS::INSTANCE_GI_PROBE && (1<<A->base_type)&VS::INSTANCE_GEOMETRY_MASK) {
+
+ InstanceGIProbeData * gi_probe = static_cast<InstanceGIProbeData*>(B->base_data);
+ InstanceGeometryData * geom = static_cast<InstanceGeometryData*>(A->base_data);
+
+
+ InstanceGIProbeData::PairInfo pinfo;
+ pinfo.geometry=A;
+ pinfo.L = geom->gi_probes.push_back(B);
+
+ List<InstanceGIProbeData::PairInfo>::Element *E = gi_probe->geometries.push_back(pinfo);
+
+ geom->gi_probes_dirty=true;
+
+ return E; //this element should make freeing faster
+
+ } else if (B->base_type==VS::INSTANCE_GI_PROBE && A->base_type==VS::INSTANCE_LIGHT) {
+
+ InstanceGIProbeData * gi_probe = static_cast<InstanceGIProbeData*>(B->base_data);
+ InstanceLightData * light = static_cast<InstanceLightData*>(A->base_data);
+
+ return gi_probe->lights.insert(A);
}
@@ -134,14 +159,14 @@ void* VisualServerScene::_instance_pair(void *p_self, OctreeElementID, Instance
//attempt to conncet portal A (will go through B anyway)
//this is a little hackish, but works fine in practice
- } else if (A->base_type==INSTANCE_BAKED_LIGHT || B->base_type==INSTANCE_BAKED_LIGHT) {
+ } else if (A->base_type==INSTANCE_GI_PROBE || B->base_type==INSTANCE_GI_PROBE) {
- if (B->base_type==INSTANCE_BAKED_LIGHT) {
+ if (B->base_type==INSTANCE_GI_PROBE) {
SWAP(A,B);
}
- ERR_FAIL_COND_V(B->base_type!=INSTANCE_BAKED_LIGHT_SAMPLER,NULL);
- B->baked_light_sampler_info->baked_lights.insert(A);
+ ERR_FAIL_COND_V(B->base_type!=INSTANCE_GI_PROBE_SAMPLER,NULL);
+ B->gi_probe_sampler_info->gi_probes.insert(A);
} else if (A->base_type==INSTANCE_ROOM || B->base_type==INSTANCE_ROOM) {
@@ -218,6 +243,28 @@ void VisualServerScene::_instance_unpair(void *p_self, OctreeElementID, Instance
geom->reflection_dirty=true;
+ } else if (B->base_type==VS::INSTANCE_GI_PROBE && (1<<A->base_type)&VS::INSTANCE_GEOMETRY_MASK) {
+
+ InstanceGIProbeData * gi_probe = static_cast<InstanceGIProbeData*>(B->base_data);
+ InstanceGeometryData * geom = static_cast<InstanceGeometryData*>(A->base_data);
+
+ List<InstanceGIProbeData::PairInfo>::Element *E = reinterpret_cast<List<InstanceGIProbeData::PairInfo>::Element*>(udata);
+
+ geom->gi_probes.erase(E->get().L);
+ gi_probe->geometries.erase(E);
+
+ geom->gi_probes_dirty=true;
+
+
+ } else if (B->base_type==VS::INSTANCE_GI_PROBE && A->base_type==VS::INSTANCE_LIGHT) {
+
+ InstanceGIProbeData * gi_probe = static_cast<InstanceGIProbeData*>(B->base_data);
+ InstanceLightData * light = static_cast<InstanceLightData*>(A->base_data);
+
+
+ Set<Instance*>::Element *E = reinterpret_cast<Set<Instance*>::Element*>(udata);
+
+ gi_probe->lights.erase(E);
}
#if 0
if (A->base_type==INSTANCE_PORTAL) {
@@ -232,14 +279,14 @@ void VisualServerScene::_instance_unpair(void *p_self, OctreeElementID, Instance
self->_portal_attempt_connect(A);
self->_portal_attempt_connect(B);
- } else if (A->base_type==INSTANCE_BAKED_LIGHT || B->base_type==INSTANCE_BAKED_LIGHT) {
+ } else if (A->base_type==INSTANCE_GI_PROBE || B->base_type==INSTANCE_GI_PROBE) {
- if (B->base_type==INSTANCE_BAKED_LIGHT) {
+ if (B->base_type==INSTANCE_GI_PROBE) {
SWAP(A,B);
}
- ERR_FAIL_COND(B->base_type!=INSTANCE_BAKED_LIGHT_SAMPLER);
- B->baked_light_sampler_info->baked_lights.erase(A);
+ ERR_FAIL_COND(B->base_type!=INSTANCE_GI_PROBE_SAMPLER);
+ B->gi_probe_sampler_info->gi_probes.erase(A);
} else if (A->base_type==INSTANCE_ROOM || B->base_type==INSTANCE_ROOM) {
@@ -397,6 +444,25 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base){
reflection_probe_render_list.remove(&reflection_probe->update_list);
}
} break;
+ case VS::INSTANCE_GI_PROBE: {
+
+ InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData*>(instance->base_data);
+
+ while(gi_probe->dynamic.updating_stage==GI_UPDATE_STAGE_LIGHTING) {
+ //wait until bake is done if it's baking
+ OS::get_singleton()->delay_usec(1);
+ }
+ if (gi_probe->update_element.in_list()) {
+ gi_probe_update_list.remove(&gi_probe->update_element);
+ }
+ if (gi_probe->dynamic.probe_data.is_valid()) {
+ VSG::storage->free(gi_probe->dynamic.probe_data);
+ }
+
+ VSG::scene_render->free(gi_probe->probe_instance);
+
+ } break;
+
}
if (instance->base_data) {
@@ -455,20 +521,20 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base){
}
- if (instance->baked_light_info) {
+ if (instance->gi_probe_info) {
- while(instance->baked_light_info->owned_instances.size()) {
+ while(instance->gi_probe_info->owned_instances.size()) {
- Instance *owned=instance->baked_light_info->owned_instances.front()->get();
- owned->baked_light=NULL;
- owned->data.baked_light=NULL;
- owned->data.baked_light_octree_xform=NULL;
+ Instance *owned=instance->gi_probe_info->owned_instances.front()->get();
+ owned->gi_probe=NULL;
+ owned->data.gi_probe=NULL;
+ owned->data.gi_probe_octree_xform=NULL;
owned->BLE=NULL;
- instance->baked_light_info->owned_instances.pop_front();
+ instance->gi_probe_info->owned_instances.pop_front();
}
- memdelete(instance->baked_light_info);
- instance->baked_light_info=NULL;
+ memdelete(instance->gi_probe_info);
+ instance->gi_probe_info=NULL;
}
@@ -517,18 +583,18 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base){
}
- if (instance->baked_light_sampler_info) {
+ if (instance->gi_probe_sampler_info) {
- while (instance->baked_light_sampler_info->owned_instances.size()) {
+ while (instance->gi_probe_sampler_info->owned_instances.size()) {
- instance_geometry_set_baked_light_sampler(instance->baked_light_sampler_info->owned_instances.front()->get()->self,RID());
+ instance_geometry_set_gi_probe_sampler(instance->gi_probe_sampler_info->owned_instances.front()->get()->self,RID());
}
- if (instance->baked_light_sampler_info->sampled_light.is_valid()) {
- rasterizer->free(instance->baked_light_sampler_info->sampled_light);
+ if (instance->gi_probe_sampler_info->sampled_light.is_valid()) {
+ rasterizer->free(instance->gi_probe_sampler_info->sampled_light);
}
- memdelete( instance->baked_light_sampler_info );
- instance->baked_light_sampler_info=NULL;
+ memdelete( instance->gi_probe_sampler_info );
+ instance->gi_probe_sampler_info=NULL;
}
#endif
@@ -572,6 +638,19 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base){
reflection_probe->instance=VSG::scene_render->reflection_probe_instance_create(p_base);
} break;
+ case VS::INSTANCE_GI_PROBE: {
+
+ InstanceGIProbeData *gi_probe = memnew( InstanceGIProbeData );
+ instance->base_data=gi_probe;
+ gi_probe->owner=instance;
+
+ if (scenario && !gi_probe->update_element.in_list()) {
+ gi_probe_update_list.add(&gi_probe->update_element);
+ }
+
+ gi_probe->probe_instance=VSG::scene_render->gi_probe_instance_create();
+
+ } break;
}
@@ -615,20 +694,20 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base){
instance->base_type=INSTANCE_PORTAL;
instance->portal_info = memnew(Instance::PortalInfo);
instance->portal_info->portal=portal_owner.get(p_base);
- } else if (baked_light_owner.owns(p_base)) {
+ } else if (gi_probe_owner.owns(p_base)) {
- instance->base_type=INSTANCE_BAKED_LIGHT;
- instance->baked_light_info=memnew(Instance::BakedLightInfo);
- instance->baked_light_info->baked_light=baked_light_owner.get(p_base);
+ instance->base_type=INSTANCE_GI_PROBE;
+ instance->gi_probe_info=memnew(Instance::BakedLightInfo);
+ instance->gi_probe_info->gi_probe=gi_probe_owner.get(p_base);
//instance->portal_info = memnew(Instance::PortalInfo);
//instance->portal_info->portal=portal_owner.get(p_base);
- } else if (baked_light_sampler_owner.owns(p_base)) {
+ } else if (gi_probe_sampler_owner.owns(p_base)) {
- instance->base_type=INSTANCE_BAKED_LIGHT_SAMPLER;
- instance->baked_light_sampler_info=memnew( Instance::BakedLightSamplerInfo);
- instance->baked_light_sampler_info->sampler=baked_light_sampler_owner.get(p_base);
+ instance->base_type=INSTANCE_GI_PROBE_SAMPLER;
+ instance->gi_probe_sampler_info=memnew( Instance::BakedLightSamplerInfo);
+ instance->gi_probe_sampler_info->sampler=gi_probe_sampler_owner.get(p_base);
//instance->portal_info = memnew(Instance::PortalInfo);
//instance->portal_info->portal=portal_owner.get(p_base);
@@ -676,6 +755,13 @@ void VisualServerScene::instance_set_scenario(RID p_instance, RID p_scenario){
InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData*>(instance->base_data);
VSG::scene_render->reflection_probe_release_atlas_index(reflection_probe->instance);
} break;
+ case VS::INSTANCE_GI_PROBE: {
+
+ InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData*>(instance->base_data);
+ if (gi_probe->update_element.in_list()) {
+ gi_probe_update_list.remove(&gi_probe->update_element);
+ }
+ } break;
}
@@ -704,6 +790,13 @@ void VisualServerScene::instance_set_scenario(RID p_instance, RID p_scenario){
light->D = scenario->directional_lights.push_back(instance);
}
} break;
+ case VS::INSTANCE_GI_PROBE: {
+
+ InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData*>(instance->base_data);
+ if (!gi_probe->update_element.in_list()) {
+ gi_probe_update_list.add(&gi_probe->update_element);
+ }
+ } break;
}
_instance_queue_update(instance,true,true);
@@ -1006,13 +1099,13 @@ void VisualServerScene::_update_instance(Instance *p_instance) {
else if (p_instance->base_type == INSTANCE_ROOM) {
p_instance->room_info->affine_inverse=p_instance->data.transform.affine_inverse();
- } else if (p_instance->base_type == INSTANCE_BAKED_LIGHT) {
+ } else if (p_instance->base_type == INSTANCE_GI_PROBE) {
Transform scale;
- scale.basis.scale(p_instance->baked_light_info->baked_light->octree_aabb.size);
- scale.origin=p_instance->baked_light_info->baked_light->octree_aabb.pos;
+ scale.basis.scale(p_instance->gi_probe_info->gi_probe->octree_aabb.size);
+ scale.origin=p_instance->gi_probe_info->gi_probe->octree_aabb.pos;
//print_line("scale: "+scale);
- p_instance->baked_light_info->affine_inverse=(p_instance->data.transform*scale).affine_inverse();
+ p_instance->gi_probe_info->affine_inverse=(p_instance->data.transform*scale).affine_inverse();
}
@@ -1077,6 +1170,13 @@ void VisualServerScene::_update_instance(Instance *p_instance) {
pairable_mask=p_instance->visible?VS::INSTANCE_GEOMETRY_MASK:0;
pairable=true;
}
+
+ if (p_instance->base_type == VS::INSTANCE_GI_PROBE) {
+ //lights and geometries
+ pairable_mask=p_instance->visible?VS::INSTANCE_GEOMETRY_MASK|(1<<VS::INSTANCE_LIGHT):0;
+ pairable=true;
+ }
+
#if 0
if (p_instance->base_type == VS::INSTANCE_PORTAL) {
@@ -1085,9 +1185,9 @@ void VisualServerScene::_update_instance(Instance *p_instance) {
pairable=true;
}
- if (p_instance->base_type == VS::INSTANCE_BAKED_LIGHT_SAMPLER) {
+ if (p_instance->base_type == VS::INSTANCE_GI_PROBE_SAMPLER) {
- pairable_mask=(1<<INSTANCE_BAKED_LIGHT);
+ pairable_mask=(1<<INSTANCE_GI_PROBE);
pairable=true;
}
@@ -1181,6 +1281,11 @@ void VisualServerScene::_update_instance_aabb(Instance *p_instance) {
new_aabb = VSG::storage->reflection_probe_get_aabb(p_instance->base);
} break;
+ case VisualServer::INSTANCE_GI_PROBE: {
+
+ new_aabb = VSG::storage->gi_probe_get_bounds(p_instance->base);
+
+ } break;
#if 0
case VisualServer::INSTANCE_ROOM: {
@@ -1208,18 +1313,18 @@ void VisualServerScene::_update_instance_aabb(Instance *p_instance) {
}
} break;
- case VisualServer::INSTANCE_BAKED_LIGHT: {
+ case VisualServer::INSTANCE_GI_PROBE: {
- BakedLight *baked_light = baked_light_owner.get( p_instance->base );
- ERR_FAIL_COND(!baked_light);
- new_aabb=baked_light->octree_aabb;
+ BakedLight *gi_probe = gi_probe_owner.get( p_instance->base );
+ ERR_FAIL_COND(!gi_probe);
+ new_aabb=gi_probe->octree_aabb;
} break;
- case VisualServer::INSTANCE_BAKED_LIGHT_SAMPLER: {
+ case VisualServer::INSTANCE_GI_PROBE_SAMPLER: {
- BakedLightSampler *baked_light_sampler = baked_light_sampler_owner.get( p_instance->base );
- ERR_FAIL_COND(!baked_light_sampler);
- float radius = baked_light_sampler->params[VS::BAKED_LIGHT_SAMPLER_RADIUS];
+ BakedLightSampler *gi_probe_sampler = gi_probe_sampler_owner.get( p_instance->base );
+ ERR_FAIL_COND(!gi_probe_sampler);
+ float radius = gi_probe_sampler->params[VS::BAKED_LIGHT_SAMPLER_RADIUS];
new_aabb=AABB(Vector3(-radius,-radius,-radius),Vector3(radius*2,radius*2,radius*2));
@@ -1805,6 +1910,13 @@ void VisualServerScene::_render_scene(const Transform p_cam_transform,const Came
}
}
+ } else if (ins->base_type==VS::INSTANCE_GI_PROBE && ins->visible) {
+
+ InstanceGIProbeData * gi_probe = static_cast<InstanceGIProbeData*>(ins->base_data);
+ if (!gi_probe->update_element.in_list()) {
+ gi_probe_update_list.add(&gi_probe->update_element);
+ }
+
} else if ((1<<ins->base_type)&VS::INSTANCE_GEOMETRY_MASK && ins->visible && ins->cast_shadows!=VS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) {
keep=true;
@@ -1865,10 +1977,10 @@ void VisualServerScene::_render_scene(const Transform p_cam_transform,const Came
if (max>cull_range.max)
cull_range.max=max;
- if (ins->sampled_light && ins->sampled_light->baked_light_sampler_info->last_pass!=render_pass) {
+ if (ins->sampled_light && ins->sampled_light->gi_probe_sampler_info->last_pass!=render_pass) {
if (light_samplers_culled<MAX_LIGHT_SAMPLERS) {
light_sampler_cull_result[light_samplers_culled++]=ins->sampled_light;
- ins->sampled_light->baked_light_sampler_info->last_pass=render_pass;
+ ins->sampled_light->gi_probe_sampler_info->last_pass=render_pass;
}
}
}
@@ -1908,6 +2020,21 @@ void VisualServerScene::_render_scene(const Transform p_cam_transform,const Came
geom->reflection_dirty=false;
}
+ if (geom->gi_probes_dirty) {
+ int l=0;
+ //only called when reflection probe AABB enter/exit this geometry
+ ins->gi_probe_instances.resize(geom->gi_probes.size());
+
+ for (List<Instance*>::Element *E=geom->gi_probes.front();E;E=E->next()) {
+
+ InstanceGIProbeData * gi_probe = static_cast<InstanceGIProbeData*>(E->get()->base_data);
+
+ ins->gi_probe_instances[l++]=gi_probe->probe_instance;
+ }
+
+ geom->gi_probes_dirty=false;
+ }
+
ins->depth = near_plane.distance_to(ins->transform.origin);
ins->depth_layer=CLAMP(int(ins->depth*8/z_far),0,7);
@@ -2117,7 +2244,7 @@ void VisualServerScene::_render_scene(const Transform p_cam_transform,const Came
}
-bool VisualServerScene::_render_probe_step(Instance* p_instance,int p_step) {
+bool VisualServerScene::_render_reflection_probe_step(Instance* p_instance,int p_step) {
InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData*>(p_instance->base_data);
Scenario *scenario = p_instance->scenario;
@@ -2188,18 +2315,539 @@ bool VisualServerScene::_render_probe_step(Instance* p_instance,int p_step) {
return false;
}
+void VisualServerScene::_gi_probe_fill_local_data(int p_idx, int p_level, int p_x, int p_y, int p_z, const GIProbeDataCell* p_cell, const GIProbeDataHeader *p_header, InstanceGIProbeData::LocalData *p_local_data, Vector<uint32_t> *prev_cell) {
+
+ if (p_level==p_header->cell_subdiv-1) {
+
+ Vector3 emission;
+ emission.x=(p_cell[p_idx].emission>>24)/255.0;
+ emission.y=((p_cell[p_idx].emission>>16)&0xFF)/255.0;
+ emission.z=((p_cell[p_idx].emission>>8)&0xFF)/255.0;
+ float l = (p_cell[p_idx].emission&0xFF)/255.0;
+ l*=8.0;
+
+ emission*=l;
+
+ p_local_data[p_idx].energy[0]=uint16_t(emission.x*1024); //go from 0 to 1024 for light
+ p_local_data[p_idx].energy[1]=uint16_t(emission.y*1024); //go from 0 to 1024 for light
+ p_local_data[p_idx].energy[2]=uint16_t(emission.z*1024); //go from 0 to 1024 for light
+ } else {
+
+ p_local_data[p_idx].energy[0]=0;
+ p_local_data[p_idx].energy[1]=0;
+ p_local_data[p_idx].energy[2]=0;
+
+ int half=(1<<(p_header->cell_subdiv-1))>>(p_level+1);
+
+ for(int i=0;i<8;i++) {
+
+ uint32_t child = p_cell[p_idx].children[i];
+
+ if (child==0xFFFFFFFF)
+ continue;
+
+ int x = p_x;
+ int y = p_y;
+ int z = p_z;
+
+ if (i&1)
+ x+=half;
+ if (i&2)
+ y+=half;
+ if (i&4)
+ z+=half;
+
+ _gi_probe_fill_local_data(child,p_level+1,x,y,z,p_cell,p_header,p_local_data,prev_cell);
+ }
+ }
+
+ //position for each part of the mipmaped texture
+ p_local_data[p_idx].pos[0]=p_x>>(p_header->cell_subdiv-p_level-1);
+ p_local_data[p_idx].pos[1]=p_y>>(p_header->cell_subdiv-p_level-1);
+ p_local_data[p_idx].pos[2]=p_z>>(p_header->cell_subdiv-p_level-1);
+
+ prev_cell[p_level].push_back(p_idx);
+
+}
+
+
+void VisualServerScene::_gi_probe_bake_threads(void* self) {
+
+ VisualServerScene* vss = (VisualServerScene*)self;
+ vss->_gi_probe_bake_thread();
+}
+
+void VisualServerScene::_setup_gi_probe(Instance *p_instance) {
+
+
+ InstanceGIProbeData *probe = static_cast<InstanceGIProbeData*>(p_instance->base_data);
+
+ if (probe->dynamic.probe_data.is_valid()) {
+ VSG::storage->free(probe->dynamic.probe_data);
+ probe->dynamic.probe_data=RID();
+ }
+
+ probe->dynamic.light_data=VSG::storage->gi_probe_get_dynamic_data(p_instance->base);
+
+ if (probe->dynamic.light_data.size()) {
+ //using dynamic data
+ DVector<int>::Read r=probe->dynamic.light_data.read();
+
+ const GIProbeDataHeader *header = (GIProbeDataHeader *)r.ptr();
+
+ probe->dynamic.local_data.resize(header->cell_count);
+
+ DVector<InstanceGIProbeData::LocalData>::Write ldw = probe->dynamic.local_data.write();
+
+ const GIProbeDataCell *cells = (GIProbeDataCell*)&r[16];
+
+ probe->dynamic.level_cell_lists.resize(header->cell_subdiv);
+
+ _gi_probe_fill_local_data(0,0,0,0,0,cells,header,ldw.ptr(),probe->dynamic.level_cell_lists.ptr());
+
+ probe->dynamic.probe_data=VSG::storage->gi_probe_dynamic_data_create(header->width,header->height,header->depth);
+
+
+ probe->dynamic.mipmaps_3d.clear();
+
+ probe->dynamic.grid_size[0]=header->width;
+ probe->dynamic.grid_size[1]=header->height;
+ probe->dynamic.grid_size[2]=header->depth;
+
+ for(int i=0;i<(int)header->cell_subdiv;i++) {
+
+ uint32_t x = header->width >> i;
+ uint32_t y = header->height >> i;
+ uint32_t z = header->depth >> i;
+
+ //create and clear mipmap
+ DVector<uint8_t> mipmap;
+ mipmap.resize(x*y*z*4);
+ DVector<uint8_t>::Write w = mipmap.write();
+ zeromem(w.ptr(),x*y*z*4);
+ w = DVector<uint8_t>::Write();
+
+ probe->dynamic.mipmaps_3d.push_back(mipmap);
+
+ if (x<=1 || y<=1 || z<=1)
+ break;
+ }
+
+ probe->dynamic.updating_stage=GI_UPDATE_STAGE_CHECK;
+ probe->invalid=false;
+ probe->dynamic.enabled=true;
+
+ Transform cell_to_xform = VSG::storage->gi_probe_get_to_cell_xform(p_instance->base);
+ AABB bounds = VSG::storage->gi_probe_get_bounds(p_instance->base);
+ float cell_size = VSG::storage->gi_probe_get_cell_size(p_instance->base);
+
+ probe->dynamic.light_to_cell_xform=cell_to_xform * p_instance->transform.affine_inverse();
+
+ VSG::scene_render->gi_probe_instance_set_light_data(probe->probe_instance,probe->dynamic.probe_data);
+ VSG::scene_render->gi_probe_instance_set_transform_to_data(probe->probe_instance,probe->dynamic.light_to_cell_xform);
+
+
+
+ VSG::scene_render->gi_probe_instance_set_bounds(probe->probe_instance,bounds.size/cell_size);
+
+
+ } else {
+ RID data = VSG::storage->gi_probe_get_data(p_instance->base);
+
+ probe->dynamic.enabled=false;
+ probe->invalid=!data.is_valid();
+ if (data.is_valid()) {
+ VSG::scene_render->gi_probe_instance_set_light_data(probe->probe_instance,data);
+ }
+ }
+
+ probe->base_version=VSG::storage->gi_probe_get_version(p_instance->base);
+
+}
+
+void VisualServerScene::_gi_probe_bake_thread() {
+
+ while(true) {
+
+ probe_bake_sem->wait();
+ if (probe_bake_thread_exit) {
+ break;
+ }
+
+ Instance* to_bake=NULL;
+
+ probe_bake_mutex->lock();
+
+ if (!probe_bake_list.empty()) {
+ to_bake=probe_bake_list.front()->get();
+ probe_bake_list.pop_front();
+
+ }
+ probe_bake_mutex->unlock();
+
+ if (!to_bake)
+ continue;
+
+ _bake_gi_probe(to_bake);
+ }
+}
+
+
+
+uint32_t VisualServerScene::_gi_bake_find_cell(const GIProbeDataCell *cells,int x,int y, int z,int p_cell_subdiv) {
+
+
+ uint32_t cell=0;
+
+ int ofs_x=0;
+ int ofs_y=0;
+ int ofs_z=0;
+ int size = 1<<(p_cell_subdiv-1);
+ int half=size/2;
+
+ if (x<0 || x>=size)
+ return -1;
+ if (y<0 || y>=size)
+ return -1;
+ if (z<0 || z>=size)
+ return -1;
+
+ for(int i=0;i<p_cell_subdiv-1;i++) {
+
+ const GIProbeDataCell *bc = &cells[cell];
+
+ int child = 0;
+ if (x >= ofs_x + half) {
+ child|=1;
+ ofs_x+=half;
+ }
+ if (y >= ofs_y + half) {
+ child|=2;
+ ofs_y+=half;
+ }
+ if (z >= ofs_z + half) {
+ child|=4;
+ ofs_z+=half;
+ }
+
+ cell = bc->children[child];
+ if (cell==0xFFFFFFFF)
+ return 0xFFFFFFFF;
+
+ half>>=1;
+ }
+
+ return cell;
+
+}
+
+void VisualServerScene::_bake_gi_probe_light(const GIProbeDataHeader *header,const GIProbeDataCell *cells,InstanceGIProbeData::LocalData *local_data,const uint32_t *leaves,int leaf_count, const InstanceGIProbeData::LightCache& light_cache,int sign) {
+
+
+ int light_r = int(light_cache.color.r * light_cache.energy * 1024.0)*sign;
+ int light_g = int(light_cache.color.g * light_cache.energy * 1024.0)*sign;
+ int light_b = int(light_cache.color.b * light_cache.energy * 1024.0)*sign;
+
+ switch(light_cache.type) {
+
+ case VS::LIGHT_DIRECTIONAL: {
+
+ float limits[3]={float(header->width),float(header->height),float(header->depth)};
+ Plane clip[3];
+ int clip_planes=0;
+ float max_len = Vector3(limits[0],limits[1],limits[2]).length()*1.1;
+
+ Vector3 light_axis = -light_cache.transform.basis.get_axis(2).normalized();
+
+ print_line("transform directional, axis: "+light_axis);
+ print_line("limits: "+Vector3(limits[0],limits[1],limits[2]));
+
+ for(int i=0;i<3;i++) {
+
+ if (ABS(light_axis[i])<CMP_EPSILON)
+ continue;
+ clip[clip_planes].normal[i]=1.0;
+
+ if (light_axis[i]<0) {
+
+ clip[clip_planes].d=limits[i]+1;
+ } else {
+ clip[clip_planes].d-=1.0;
+ }
+
+ clip_planes++;
+ }
+
+ float distance_adv;
+ {
+ Vector3 normal = light_axis;
+ Vector3 unorm = normal.abs();
+
+ if ( (unorm.x >= unorm.y) && (unorm.x >= unorm.z) ) {
+ // x code
+ unorm = normal.x > 0.0 ? Vector3( 1.0, 0.0, 0.0 ) : Vector3( -1.0, 0.0, 0.0 ) ;
+ } else if ( (unorm.y > unorm.x) && (unorm.y >= unorm.z) ) {
+ // y code
+ unorm = normal.y > 0.0 ? Vector3( 0.0, 1.0, 0.0 ) : Vector3( 0.0, -1.0, 0.0 ) ;
+ } else if ( (unorm.z > unorm.x) && (unorm.z > unorm.y) ) {
+ // z code
+ unorm = normal.z > 0.0 ? Vector3( 0.0, 0.0, 1.0 ) : Vector3( 0.0, 0.0, -1.0 ) ;
+ } else {
+ // oh-no we messed up code
+ // has to be
+ unorm = Vector3( 1.0, 0.0, 0.0 );
+ }
+
+ distance_adv = 1.0/normal.dot(unorm);
+
+ }
+
+ int success_count=0;
+
+ uint64_t us = OS::get_singleton()->get_ticks_usec();
+
+ for(int i=0;i<leaf_count;i++) {
+
+ uint32_t idx = leaves[i];
+
+ const GIProbeDataCell *cell = &cells[idx];
+ InstanceGIProbeData::LocalData *light = &local_data[idx];
+
+ Vector3 to(light->pos[0]+0.5,light->pos[1]+0.5,light->pos[2]+0.5);
+
+
+ Vector3 from = to - max_len * light_axis;
+
+ for(int j=0;j<clip_planes;j++) {
+
+ clip[j].intersects_segment(from,to,&from);
+ }
+
+ float distance = (to - from).length();
+ distance+=distance_adv-Math::fmod(distance,distance_adv); //make it reach the center of the box always
+ from = to - light_axis * distance;
+
+ uint32_t result=0xFFFFFFFF;
+
+ while(distance>-distance_adv) { //use this to avoid precision errors
+
+ result = _gi_bake_find_cell(cells,int(floor(from.x)),int(floor(from.y)),int(floor(from.z)),header->cell_subdiv);
+ if (result!=0xFFFFFFFF) {
+ break;
+ }
+
+ from+=light_axis*distance_adv;
+ distance-=distance_adv;
+ }
+
+ if (result==idx) {
+ //cell hit itself! hooray!
+ light->energy[0]+=(uint32_t(light_r)*((cell->albedo>>16)&0xFF))>>8;
+ light->energy[1]+=(uint32_t(light_g)*((cell->albedo>>8)&0xFF))>>8;
+ light->energy[2]+=(uint32_t(light_b)*((cell->albedo)&0xFF))>>8;
+ success_count++;
+ }
+ }
+ print_line("BAKE TIME: "+rtos((OS::get_singleton()->get_ticks_usec()-us)/1000000.0));
+ print_line("valid cells: "+itos(success_count));
+
+
+ } break;
+ }
+}
+
+
+void VisualServerScene::_bake_gi_downscale_light(int p_idx, int p_level, const GIProbeDataCell* p_cells, const GIProbeDataHeader *p_header, InstanceGIProbeData::LocalData *p_local_data) {
+
+ //average light to upper level
+ p_local_data[p_idx].energy[0]=0;
+ p_local_data[p_idx].energy[1]=0;
+ p_local_data[p_idx].energy[2]=0;
+
+ for(int i=0;i<8;i++) {
+
+ uint32_t child = p_cells[p_idx].children[i];
+
+ if (child==0xFFFFFFFF)
+ continue;
+
+ if (p_level+1 < (int)p_header->cell_subdiv-1) {
+ _bake_gi_downscale_light(child,p_level+1,p_cells,p_header,p_local_data);
+ }
+
+ p_local_data[p_idx].energy[0]+=p_local_data[child].energy[0];
+ p_local_data[p_idx].energy[1]+=p_local_data[child].energy[1];
+ p_local_data[p_idx].energy[2]+=p_local_data[child].energy[2];
+
+ }
+
+ //divide by eight for average
+ p_local_data[p_idx].energy[0]>>=3;
+ p_local_data[p_idx].energy[1]>>=3;
+ p_local_data[p_idx].energy[2]>>=3;
+
+}
+
+
+void VisualServerScene::_bake_gi_probe(Instance *p_gi_probe) {
+
+ InstanceGIProbeData * probe_data = static_cast<InstanceGIProbeData*>(p_gi_probe->base_data);
+
+ DVector<int>::Read r=probe_data->dynamic.light_data.read();
+
+ const GIProbeDataHeader *header = (const GIProbeDataHeader *)r.ptr();
+ const GIProbeDataCell *cells = (const GIProbeDataCell*)&r[16];
+
+ int leaf_count = probe_data->dynamic.level_cell_lists[ header->cell_subdiv -1 ].size();
+ const uint32_t *leaves = probe_data->dynamic.level_cell_lists[ header->cell_subdiv -1 ].ptr();
+
+ DVector<InstanceGIProbeData::LocalData>::Write ldw = probe_data->dynamic.local_data.write();
+
+ InstanceGIProbeData::LocalData *local_data = ldw.ptr();
+
+
+ //remove what must be removed
+ for (Map<RID,InstanceGIProbeData::LightCache>::Element *E=probe_data->dynamic.light_cache.front();E;E=E->next()) {
+
+ RID rid = E->key();
+ const InstanceGIProbeData::LightCache& lc = E->get();
+
+ if (!probe_data->dynamic.light_cache_changes.has(rid) || !(probe_data->dynamic.light_cache_changes[rid]==lc)) {
+ //erase light data
+
+ _bake_gi_probe_light(header,cells,local_data,leaves,leaf_count,lc,-1);
+ }
+
+ }
+
+ //add what must be added
+ for (Map<RID,InstanceGIProbeData::LightCache>::Element *E=probe_data->dynamic.light_cache_changes.front();E;E=E->next()) {
+
+ RID rid = E->key();
+ const InstanceGIProbeData::LightCache& lc = E->get();
+
+ if (!probe_data->dynamic.light_cache.has(rid) || !(probe_data->dynamic.light_cache[rid]==lc)) {
+ //add light data
+
+ _bake_gi_probe_light(header,cells,local_data,leaves,leaf_count,lc,1);
+ }
+ }
+
+ SWAP(probe_data->dynamic.light_cache_changes,probe_data->dynamic.light_cache);
+
+ //downscale to lower res levels
+ _bake_gi_downscale_light(0,0,cells,header,local_data);
+
+ //plot result to 3D texture!
+
+ for(int i=0;i<(int)header->cell_subdiv;i++) {
+
+ int stage = header->cell_subdiv - i -1;
+
+ if (stage >= probe_data->dynamic.mipmaps_3d.size())
+ continue; //no mipmap for this one
+
+ print_line("generating mipmap stage: "+itos(stage));
+ int level_cell_count = probe_data->dynamic.level_cell_lists[ i ].size();
+ const uint32_t *level_cells = probe_data->dynamic.level_cell_lists[ i ].ptr();
+
+ DVector<uint8_t>::Write lw = probe_data->dynamic.mipmaps_3d[stage].write();
+ uint8_t *mipmapw = lw.ptr();
+
+ uint32_t sizes[3]={header->width>>stage,header->height>>stage,header->depth>>stage};
+
+ for(int j=0;j<level_cell_count;j++) {
+
+ uint32_t idx = level_cells[j];
+
+ uint32_t r = local_data[idx].energy[0]>>2;
+ uint32_t g = local_data[idx].energy[1]>>2;
+ uint32_t b = local_data[idx].energy[2]>>2;
+ uint32_t a = cells[idx].alpha>>8;
+
+ uint32_t mm_ofs = sizes[0]*sizes[1]*(local_data[idx].pos[2]) + sizes[0]*(local_data[idx].pos[1]) + (local_data[idx].pos[0]);
+ mm_ofs*=4; //for RGBA (4 bytes)
+
+ mipmapw[mm_ofs+0]=uint8_t(CLAMP(r,0,255));
+ mipmapw[mm_ofs+1]=uint8_t(CLAMP(g,0,255));
+ mipmapw[mm_ofs+2]=uint8_t(CLAMP(b,0,255));
+ mipmapw[mm_ofs+3]=uint8_t(CLAMP(a,0,255));
+
+
+ }
+ }
+
+ //send back to main thread to update un little chunks
+ probe_data->dynamic.updating_stage=GI_UPDATE_STAGE_UPLOADING;
+
+}
+
+bool VisualServerScene::_check_gi_probe(Instance *p_gi_probe) {
+
+ InstanceGIProbeData * probe_data = static_cast<InstanceGIProbeData*>(p_gi_probe->base_data);
+
+ probe_data->dynamic.light_cache_changes.clear();
+
+ bool all_equal=true;
+
+
+ for (List<Instance*>::Element *E=p_gi_probe->scenario->directional_lights.front();E;E=E->next()) {
+
+ InstanceGIProbeData::LightCache lc;
+ lc.type=VSG::storage->light_get_type(E->get()->base);
+ lc.color=VSG::storage->light_get_color(E->get()->base);
+ lc.energy=VSG::storage->light_get_param(E->get()->base,VS::LIGHT_PARAM_ENERGY);
+ lc.radius=VSG::storage->light_get_param(E->get()->base,VS::LIGHT_PARAM_RANGE);
+ lc.attenuation=VSG::storage->light_get_param(E->get()->base,VS::LIGHT_PARAM_ATTENUATION);
+ lc.spot_angle=VSG::storage->light_get_param(E->get()->base,VS::LIGHT_PARAM_SPOT_ANGLE);
+ lc.spot_attenuation=VSG::storage->light_get_param(E->get()->base,VS::LIGHT_PARAM_SPOT_ATTENUATION);
+ lc.transform = probe_data->dynamic.light_to_cell_xform * E->get()->transform;
+
+ if (!probe_data->dynamic.light_cache.has(E->get()->self) || !(probe_data->dynamic.light_cache[E->get()->self]==lc)) {
+ all_equal=false;
+ }
+
+ probe_data->dynamic.light_cache_changes[E->get()->self]=lc;
+
+ }
+
+
+ for (Set<Instance*>::Element *E=probe_data->lights.front();E;E=E->next()) {
+
+ InstanceGIProbeData::LightCache lc;
+ lc.type=VSG::storage->light_get_type(E->get()->base);
+ lc.color=VSG::storage->light_get_color(E->get()->base);
+ lc.energy=VSG::storage->light_get_param(E->get()->base,VS::LIGHT_PARAM_ENERGY);
+ lc.radius=VSG::storage->light_get_param(E->get()->base,VS::LIGHT_PARAM_RANGE);
+ lc.attenuation=VSG::storage->light_get_param(E->get()->base,VS::LIGHT_PARAM_ATTENUATION);
+ lc.spot_angle=VSG::storage->light_get_param(E->get()->base,VS::LIGHT_PARAM_SPOT_ANGLE);
+ lc.spot_attenuation=VSG::storage->light_get_param(E->get()->base,VS::LIGHT_PARAM_SPOT_ATTENUATION);
+ lc.transform = probe_data->dynamic.light_to_cell_xform * E->get()->transform;
+
+ if (!probe_data->dynamic.light_cache.has(E->get()->self) || !(probe_data->dynamic.light_cache[E->get()->self]==lc)) {
+ all_equal=false;
+ }
+
+ probe_data->dynamic.light_cache_changes[E->get()->self]=lc;
+ }
+
+ //lighting changed from after to before, must do some updating
+ return !all_equal || probe_data->dynamic.light_cache_changes.size()!=probe_data->dynamic.light_cache.size();
+
+}
void VisualServerScene::render_probes() {
+ /* REFLECTION PROBES */
- SelfList<InstanceReflectionProbeData> *probe = reflection_probe_render_list.first();
+ SelfList<InstanceReflectionProbeData> *ref_probe = reflection_probe_render_list.first();
bool busy=false;
- while(probe) {
+ while(ref_probe) {
- SelfList<InstanceReflectionProbeData> *next=probe->next();
- RID base = probe->self()->owner->base;
+ SelfList<InstanceReflectionProbeData> *next=ref_probe->next();
+ RID base = ref_probe->self()->owner->base;
switch(VSG::storage->reflection_probe_get_update_mode(base)) {
@@ -2207,11 +2855,11 @@ void VisualServerScene::render_probes() {
if (busy) //already rendering something
break;
- bool done = _render_probe_step(probe->self()->owner,probe->self()->render_step);
+ bool done = _render_reflection_probe_step(ref_probe->self()->owner,ref_probe->self()->render_step);
if (done) {
- reflection_probe_render_list.remove(probe);
+ reflection_probe_render_list.remove(ref_probe);
} else {
- probe->self()->render_step++;
+ ref_probe->self()->render_step++;
}
busy=true; //do not render another one of this kind
@@ -2221,17 +2869,92 @@ void VisualServerScene::render_probes() {
int step=0;
bool done=false;
while(!done) {
- done = _render_probe_step(probe->self()->owner,step);
+ done = _render_reflection_probe_step(ref_probe->self()->owner,step);
step++;
}
- reflection_probe_render_list.remove(probe);
+ reflection_probe_render_list.remove(ref_probe);
} break;
}
- probe=next;
+ ref_probe=next;
}
+
+ /* GI PROBES */
+
+ SelfList<InstanceGIProbeData> *gi_probe = gi_probe_update_list.first();
+
+ while(gi_probe) {
+
+ SelfList<InstanceGIProbeData> *next=gi_probe->next();
+
+ InstanceGIProbeData *probe = gi_probe->self();
+ Instance *instance_probe = probe->owner;
+
+ //check if probe must be setup, but don't do if on the lighting thread
+
+ bool force_lighting=false;
+
+ if (probe->invalid || (probe->dynamic.updating_stage==GI_UPDATE_STAGE_CHECK && probe->base_version!=VSG::storage->gi_probe_get_version(instance_probe->base))) {
+
+ _setup_gi_probe(instance_probe);
+ force_lighting=true;
+ }
+
+ if (probe->invalid==false && probe->dynamic.enabled) {
+
+ switch(probe->dynamic.updating_stage) {
+ case GI_UPDATE_STAGE_CHECK: {
+
+ if (_check_gi_probe(instance_probe) || force_lighting) {
+ //send to lighting thread
+ probe->dynamic.updating_stage=GI_UPDATE_STAGE_LIGHTING;
+
+#ifndef NO_THREADS
+ probe_bake_mutex->lock();
+ probe_bake_list.push_back(instance_probe);
+ probe_bake_mutex->unlock();
+ probe_bake_sem->post();
+
+#else
+
+ _bake_gi_probe(instance_probe);
+#endif
+
+ }
+ } break;
+ case GI_UPDATE_STAGE_LIGHTING: {
+ //do none, wait til done!
+
+ } break;
+ case GI_UPDATE_STAGE_UPLOADING: {
+
+ uint64_t us = OS::get_singleton()->get_ticks_usec();
+
+ for(int i=0;i<(int)probe->dynamic.mipmaps_3d.size();i++) {
+
+ int mmsize = probe->dynamic.mipmaps_3d[i].size();
+ DVector<uint8_t>::Read r = probe->dynamic.mipmaps_3d[i].read();
+ VSG::storage->gi_probe_dynamic_data_update_rgba8(probe->dynamic.probe_data,0,probe->dynamic.grid_size[2]>>i,i,r.ptr());
+ }
+
+
+ probe->dynamic.updating_stage=GI_UPDATE_STAGE_CHECK;
+
+// print_line("UPLOAD TIME: "+rtos((OS::get_singleton()->get_ticks_usec()-us)/1000000.0));
+ } break;
+
+ }
+ }
+ //_update_gi_probe(gi_probe->self()->owner);
+
+
+ gi_probe=next;
+ }
+
+
+
}
void VisualServerScene::_update_dirty_instance(Instance *p_instance) {
@@ -2423,10 +3146,32 @@ bool VisualServerScene::free(RID p_rid) {
VisualServerScene *VisualServerScene::singleton=NULL;
+
VisualServerScene::VisualServerScene() {
+#ifndef NO_THREADS
+ probe_bake_sem = Semaphore::create();
+ probe_bake_mutex = Mutex::create();
+ probe_bake_thread = Thread::create(_gi_probe_bake_threads,this);
+ probe_bake_thread_exit=false;
+#endif
+
render_pass=1;
singleton=this;
}
+
+VisualServerScene::~VisualServerScene() {
+
+#ifndef NO_THREADS
+ probe_bake_thread_exit=true;
+ Thread::wait_to_finish(probe_bake_thread);
+ memdelete(probe_bake_thread);
+ memdelete(probe_bake_sem);
+ memdelete(probe_bake_mutex);
+
+#endif
+
+
+}
diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h
index 0eaad45c97..63cb1fd2b8 100644
--- a/servers/visual/visual_server_scene.h
+++ b/servers/visual/visual_server_scene.h
@@ -7,6 +7,9 @@
#include "allocators.h"
#include "octree.h"
#include "self_list.h"
+#include "os/thread.h"
+#include "os/semaphore.h"
+#include "semaphore.h"
class VisualServerScene {
public:
@@ -69,6 +72,8 @@ public:
#endif
+ /* CAMERA API */
+
struct Camera : public RID_Data {
enum Type {
@@ -141,6 +146,7 @@ public:
*/
+
/* SCENARIO API */
struct Instance;
@@ -296,11 +302,15 @@ public:
List<Instance*> reflection_probes;
bool reflection_dirty;
+ List<Instance*> gi_probes;
+ bool gi_probes_dirty;
+
InstanceGeometryData() {
lighting_dirty=false;
reflection_dirty=true;
can_cast_shadows=true;
+ gi_probes_dirty=true;
}
};
@@ -310,7 +320,7 @@ public:
Instance *owner;
struct PairInfo {
- List<Instance*>::Element *L; //light iterator in geometry
+ List<Instance*>::Element *L; //reflection iterator in geometry
Instance *geometry;
};
List<PairInfo> geometries;
@@ -346,14 +356,112 @@ public:
List<PairInfo> geometries;
+ Instance *baked_light;
+
InstanceLightData() {
shadow_dirty=true;
D=NULL;
last_version=0;
+ baked_light=NULL;
}
};
+ struct InstanceGIProbeData : public InstanceBaseData {
+
+
+ Instance *owner;
+
+ struct PairInfo {
+ List<Instance*>::Element *L; //gi probe iterator in geometry
+ Instance *geometry;
+ };
+
+ List<PairInfo> geometries;
+
+ Set<Instance*> lights;
+
+ struct LightCache {
+
+ VS::LightType type;
+ Transform transform;
+ Color color;
+ float energy;
+ float radius;
+ float attenuation;
+ float spot_angle;
+ float spot_attenuation;
+
+ bool operator==(const LightCache& p_cache) {
+
+ return (type==p_cache.type &&
+ transform==p_cache.transform &&
+ color==p_cache.color &&
+ energy==p_cache.energy &&
+ radius==p_cache.radius &&
+ attenuation==p_cache.attenuation &&
+ spot_angle==p_cache.spot_angle &&
+ spot_attenuation==p_cache.spot_attenuation);
+ }
+
+ LightCache() {
+
+ type=VS::LIGHT_DIRECTIONAL;
+ energy=1.0;
+ radius=1.0;
+ attenuation=1.0;
+ spot_angle=1.0;
+ spot_attenuation=1.0;
+
+ }
+
+ };
+
+ struct LocalData {
+ uint16_t pos[3];
+ uint16_t energy[3]; //using 0..1024 for float range 0..1. integer is needed for deterministic add/remove of lights
+ };
+
+
+ struct Dynamic {
+
+ Map<RID,LightCache> light_cache;
+ Map<RID,LightCache> light_cache_changes;
+ DVector<int> light_data;
+ DVector<LocalData> local_data;
+ Vector<Vector<uint32_t> > level_cell_lists;
+ RID probe_data;
+ bool enabled;
+
+ Vector< DVector<uint8_t> > mipmaps_3d;
+
+ int updating_stage;
+
+ int grid_size[3];
+
+ Transform light_to_cell_xform;
+
+ } dynamic;
+
+
+ RID probe_instance;
+
+
+ bool invalid;
+ uint32_t base_version;
+
+ SelfList<InstanceGIProbeData> update_element;
+
+ InstanceGIProbeData() : update_element(this) {
+ invalid=true;
+ base_version=0;
+ }
+
+ };
+
+
+ SelfList<InstanceGIProbeData>::List gi_probe_update_list;
+
Instance *instance_cull_result[MAX_INSTANCE_CULL];
Instance *instance_shadow_cull_result[MAX_INSTANCE_CULL]; //used for generating shadowmaps
@@ -410,11 +518,61 @@ public:
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);
+ //probes
+ struct GIProbeDataHeader {
+
+ uint32_t version;
+ uint32_t cell_subdiv;
+ uint32_t width;
+ uint32_t height;
+ uint32_t depth;
+ uint32_t cell_count;
+ uint32_t leaf_cell_count;
+ };
+
+
+ struct GIProbeDataCell {
+
+ uint32_t children[8];
+ uint32_t albedo;
+ uint32_t emission;
+ uint32_t sides_used;
+ uint32_t alpha;
+ };
+
+ enum {
+ GI_UPDATE_STAGE_CHECK,
+ GI_UPDATE_STAGE_LIGHTING,
+ GI_UPDATE_STAGE_UPLOADING,
+ };
+
+ void _gi_probe_bake_thread();
+ static void _gi_probe_bake_threads(void*);
+
+ volatile bool probe_bake_thread_exit;
+ Thread *probe_bake_thread;
+ Semaphore *probe_bake_sem;
+ Mutex *probe_bake_mutex;
+ List<Instance*> probe_bake_list;
+
+ bool _render_reflection_probe_step(Instance* p_instance,int p_step);
+ void _gi_probe_fill_local_data(int p_idx,int p_level,int p_x,int p_y,int p_z,const GIProbeDataCell* p_cell,const GIProbeDataHeader *p_header,InstanceGIProbeData::LocalData *p_local_data,Vector<uint32_t> *prev_cell);
+
+ _FORCE_INLINE_ uint32_t _gi_bake_find_cell(const GIProbeDataCell *cells,int x,int y, int z,int p_cell_subdiv);
+ void _bake_gi_downscale_light(int p_idx, int p_level, const GIProbeDataCell* p_cells, const GIProbeDataHeader *p_header, InstanceGIProbeData::LocalData *p_local_data);
+
+ void _bake_gi_probe_light(const GIProbeDataHeader *header,const GIProbeDataCell *cells,InstanceGIProbeData::LocalData *local_data,const uint32_t *leaves,int p_leaf_count, const InstanceGIProbeData::LightCache& light_cache,int p_sign);
+ void _bake_gi_probe(Instance *p_probe);
+ bool _check_gi_probe(Instance *p_gi_probe);
+ void _setup_gi_probe(Instance *p_instance);
+
void render_probes();
+
+
bool free(RID p_rid);
VisualServerScene();
+ ~VisualServerScene();
};
#endif // VISUALSERVERSCENE_H
diff --git a/servers/visual_server.h b/servers/visual_server.h
index 7558fbf818..6f2aa73952 100644
--- a/servers/visual_server.h
+++ b/servers/visual_server.h
@@ -445,7 +445,39 @@ public:
virtual void portal_set_disable_distance(RID p_portal, float p_distance)=0;
virtual void portal_set_disabled_color(RID p_portal, const Color& p_color)=0;
- /* BAKED LIGHT API */
+ /* GI PROBE API */
+
+ virtual RID gi_probe_create()=0;
+
+ virtual void gi_probe_set_bounds(RID p_probe,const AABB& p_bounds)=0;
+ virtual AABB gi_probe_get_bounds(RID p_probe) const=0;
+
+ virtual void gi_probe_set_cell_size(RID p_probe,float p_range)=0;
+ virtual float gi_probe_get_cell_size(RID p_probe) const=0;
+
+ virtual void gi_probe_set_to_cell_xform(RID p_probe,const Transform& p_xform)=0;
+ virtual Transform gi_probe_get_to_cell_xform(RID p_probe) const=0;
+
+ virtual void gi_probe_set_dynamic_data(RID p_probe,const DVector<int>& p_data)=0;
+ virtual DVector<int> gi_probe_get_dynamic_data(RID p_probe) const=0;
+
+ virtual void gi_probe_set_dynamic_range(RID p_probe,float p_range)=0;
+ virtual float gi_probe_get_dynamic_range(RID p_probe) const=0;
+
+ enum GIProbeDataFormat {
+ GI_PROBE_DATA_RGBA8,
+ GI_PROBE_DATA_DXT5,
+ GI_PROBE_DATA_ETC2_EAC,
+ };
+
+ virtual void gi_probe_set_static_data(RID p_gi_probe,const DVector<uint8_t>& p_data,GIProbeDataFormat p_format,int p_width,int p_height,int p_depth)=0;
+ virtual DVector<uint8_t> gi_probe_get_static_data(RID p_gi_probe) const=0;
+ virtual GIProbeDataFormat gi_probe_get_static_data_format(RID p_gi_probe) const=0;
+ virtual int gi_probe_get_static_data_width(RID p_probe) const=0;
+ virtual int gi_probe_get_static_data_height(RID p_probe) const=0;
+ virtual int gi_probe_get_static_data_depth(RID p_probe) const=0;
+
+
/* CAMERA API */
@@ -600,9 +632,9 @@ public:
INSTANCE_REFLECTION_PROBE,
INSTANCE_ROOM,
INSTANCE_PORTAL,
+ INSTANCE_GI_PROBE,
INSTANCE_MAX,
- /*INSTANCE_BAKED_LIGHT,
- INSTANCE_BAKED_LIGHT_SAMPLER,*/
+ /*INSTANCE_BAKED_LIGHT_SAMPLER,*/
INSTANCE_GEOMETRY_MASK=(1<<INSTANCE_MESH)|(1<<INSTANCE_MULTIMESH)|(1<<INSTANCE_IMMEDIATE)
};
diff --git a/tools/editor/io_plugins/editor_import_collada.cpp b/tools/editor/io_plugins/editor_import_collada.cpp
index 217a5fe78d..1d53ccf1ef 100644
--- a/tools/editor/io_plugins/editor_import_collada.cpp
+++ b/tools/editor/io_plugins/editor_import_collada.cpp
@@ -394,7 +394,8 @@ Error ColladaImport::_create_material(const String& p_target) {
Ref<Texture> texture = ResourceLoader::load(texfile,"Texture");
if (texture.is_valid()) {
-// material->set_texture(FixedSpatialMaterial::PARAM_DIFFUSE,texture);
+ material->set_texture(FixedSpatialMaterial::TEXTURE_ALBEDO,texture);
+ material->set_albedo(Color(1,1,1,1));
// material->set_parameter(FixedSpatialMaterial::PARAM_DIFFUSE,Color(1,1,1,1));
} else {
missing_textures.push_back(texfile.get_file());
@@ -413,6 +414,8 @@ Error ColladaImport::_create_material(const String& p_target) {
Ref<Texture> texture = ResourceLoader::load(texfile,"Texture");
if (texture.is_valid()) {
+ material->set_texture(FixedSpatialMaterial::TEXTURE_SPECULAR,texture);
+ material->set_specular(Color(1,1,1,1));
// material->set_texture(FixedSpatialMaterial::PARAM_SPECULAR,texture);
// material->set_parameter(FixedSpatialMaterial::PARAM_SPECULAR,Color(1,1,1,1));
@@ -435,7 +438,9 @@ Error ColladaImport::_create_material(const String& p_target) {
Ref<Texture> texture = ResourceLoader::load(texfile,"Texture");
if (texture.is_valid()) {
-// material->set_texture(FixedSpatialMaterial::PARAM_EMISSION,texture);
+ material->set_texture(FixedSpatialMaterial::TEXTURE_EMISSION,texture);
+ material->set_emission(Color(1,1,1,1));
+
// material->set_parameter(FixedSpatialMaterial::PARAM_EMISSION,Color(1,1,1,1));
}else {
// missing_textures.push_back(texfile.get_file());
@@ -455,6 +460,8 @@ Error ColladaImport::_create_material(const String& p_target) {
Ref<Texture> texture = ResourceLoader::load(texfile,"Texture");
if (texture.is_valid()) {
+ material->set_texture(FixedSpatialMaterial::TEXTURE_NORMAL,texture);
+// material->set_emission(Color(1,1,1,1));
// material->set_texture(FixedSpatialMaterial::PARAM_NORMAL,texture);
}else {
@@ -466,8 +473,10 @@ Error ColladaImport::_create_material(const String& p_target) {
// material->set_parameter(FixedSpatialMaterial::PARAM_SPECULAR_EXP,effect.shininess);
-// material->set_flag(Material::FLAG_DOUBLE_SIDED,effect.double_sided);
-// material->set_flag(Material::FLAG_UNSHADED,effect.unshaded);
+ if (effect.double_sided) {
+ material->set_cull_mode(FixedSpatialMaterial::CULL_DISABLED);
+ }
+ material->set_flag(FixedSpatialMaterial::FLAG_UNSHADED,effect.unshaded);
diff --git a/tools/editor/io_plugins/editor_scene_import_plugin.cpp b/tools/editor/io_plugins/editor_scene_import_plugin.cpp
index 41b245eb7d..e3fb8986c6 100644
--- a/tools/editor/io_plugins/editor_scene_import_plugin.cpp
+++ b/tools/editor/io_plugins/editor_scene_import_plugin.cpp
@@ -1692,7 +1692,7 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>
String str=name;
int layer = str.substr(str.find("lm")+3,str.length()).to_int();
- mi->set_baked_light_texture_id(layer);
+ //mi->set_baked_light_texture_id(layer);
}
if (p_flags&SCENE_FLAG_CREATE_COLLISIONS && _teststr(name,"colonly")) {
diff --git a/tools/editor/spatial_editor_gizmos.cpp b/tools/editor/spatial_editor_gizmos.cpp
index a4a1aaedf0..98b9a126dc 100644
--- a/tools/editor/spatial_editor_gizmos.cpp
+++ b/tools/editor/spatial_editor_gizmos.cpp
@@ -2397,6 +2397,163 @@ ReflectionProbeGizmo::ReflectionProbeGizmo(ReflectionProbe* p_probe){
+///
+
+
+String GIProbeGizmo::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";
+ }
+
+ return "";
+}
+Variant GIProbeGizmo::get_handle_value(int p_idx) const{
+
+ return probe->get_extents();
+}
+void GIProbeGizmo::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();
+
+
+ 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);
+
+}
+
+void GIProbeGizmo::commit_handle(int p_idx,const Variant& p_restore,bool p_cancel){
+
+ Vector3 restore = p_restore;
+
+ if (p_cancel) {
+ probe->set_extents(restore);
+ 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_undo_method(probe,"set_extents",restore);
+ ur->commit_action();
+
+}
+
+void GIProbeGizmo::redraw(){
+
+ clear();
+
+ Vector<Vector3> lines;
+ Vector3 extents = probe->get_extents();
+
+ static const int subdivs[GIProbe::SUBDIV_MAX]={64,128,256,512};
+
+ AABB aabb = AABB(-extents,extents*2);
+ int subdiv = subdivs[probe->get_subdiv()];
+ float cell_size = aabb.get_longest_axis_size()/subdiv;
+
+
+ for(int i=0;i<12;i++) {
+ Vector3 a,b;
+ aabb.get_edge(i,a,b);
+ lines.push_back(a);
+ lines.push_back(b);
+ }
+
+ add_lines(lines,SpatialEditorGizmos::singleton->gi_probe_material);
+ add_collision_segments(lines);
+
+ lines.clear();
+
+ for(int i=1;i<subdiv;i++) {
+
+ for(int j=0;j<3;j++) {
+
+
+
+ if (cell_size*i>aabb.size[j]) {
+ continue;
+ }
+
+ Vector2 dir;
+ dir[j]=1.0;
+ Vector2 ta,tb;
+ int j_n1=(j+1)%3;
+ int j_n2=(j+2)%3;
+ ta[j_n1]=1.0;
+ tb[j_n2]=1.0;
+
+
+ for(int k=0;k<4;k++) {
+
+ Vector3 from=aabb.pos,to=aabb.pos;
+ from[j]+= cell_size*i;
+ to[j]+=cell_size*i;
+
+ if (k&1) {
+ to[j_n1]+=aabb.size[j_n1];
+ } else {
+
+ to[j_n2]+=aabb.size[j_n2];
+ }
+
+ if (k&2) {
+ from[j_n1]+=aabb.size[j_n1];
+ from[j_n2]+=aabb.size[j_n2];
+ }
+
+ lines.push_back(from);
+ lines.push_back(to);
+ }
+
+ }
+
+ }
+
+ add_lines(lines,SpatialEditorGizmos::singleton->reflection_probe_material_internal);
+
+ Vector<Vector3> handles;
+
+
+ for(int i=0;i<3;i++) {
+
+ Vector3 ax;
+ ax[i]=aabb.pos[i]+aabb.size[i];
+ handles.push_back(ax);
+ }
+
+
+ add_handles(handles);
+
+}
+GIProbeGizmo::GIProbeGizmo(GIProbe* p_probe){
+
+ probe=p_probe;
+ set_spatial_node(p_probe);
+}
+
+////////
+
void NavigationMeshSpatialGizmo::redraw() {
@@ -3093,6 +3250,11 @@ Ref<SpatialEditorGizmo> SpatialEditorGizmos::get_gizmo(Spatial *p_spatial) {
Ref<ReflectionProbeGizmo> misg = memnew( ReflectionProbeGizmo(p_spatial->cast_to<ReflectionProbe>()) );
return misg;
}
+ if (p_spatial->cast_to<GIProbe>()) {
+
+ Ref<GIProbeGizmo> misg = memnew( GIProbeGizmo(p_spatial->cast_to<GIProbe>()) );
+ return misg;
+ }
if (p_spatial->cast_to<VehicleWheel>()) {
@@ -3146,8 +3308,8 @@ Ref<FixedSpatialMaterial> SpatialEditorGizmos::create_line_material(const Color&
line_material->set_flag(FixedSpatialMaterial::FLAG_UNSHADED, true);
line_material->set_line_width(3.0);
line_material->set_feature(FixedSpatialMaterial::FEATURE_TRANSPARENT, true);
- line_material->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
- line_material->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
+ //line_material->set_flag(FixedSpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ //->set_flag(FixedSpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true);
line_material->set_albedo(p_base_color);
return line_material;
@@ -3298,7 +3460,9 @@ SpatialEditorGizmos::SpatialEditorGizmos() {
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));
+ reflection_probe_material_internal = create_line_material(Color(0.3,0.8,0.5,0.15));
+ gi_probe_material = create_line_material(Color(0.7,1.0,0.5));
+ gi_probe_material_internal = create_line_material(Color(0.5,0.8,0.3,0.4));
joint_material = create_line_material(Color(0.6,0.8,1.0));
stream_player_icon = Ref<FixedSpatialMaterial>( memnew( FixedSpatialMaterial ));
diff --git a/tools/editor/spatial_editor_gizmos.h b/tools/editor/spatial_editor_gizmos.h
index 2cc1a7eab8..eba143d32b 100644
--- a/tools/editor/spatial_editor_gizmos.h
+++ b/tools/editor/spatial_editor_gizmos.h
@@ -46,6 +46,7 @@
#include "scene/3d/ray_cast.h"
#include "scene/3d/navigation_mesh.h"
#include "scene/3d/reflection_probe.h"
+#include "scene/3d/gi_probe.h"
#include "scene/3d/vehicle_body.h"
#include "scene/3d/collision_polygon.h"
@@ -327,6 +328,25 @@ public:
};
+class GIProbeGizmo : public EditorSpatialGizmo {
+
+ OBJ_TYPE(GIProbeGizmo ,EditorSpatialGizmo);
+
+
+ GIProbe* 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();
+ GIProbeGizmo(GIProbe* p_notifier=NULL);
+
+};
+
class CollisionShapeSpatialGizmo : public EditorSpatialGizmo {
@@ -496,6 +516,8 @@ public:
Ref<FixedSpatialMaterial> skeleton_material;
Ref<FixedSpatialMaterial> reflection_probe_material;
Ref<FixedSpatialMaterial> reflection_probe_material_internal;
+ Ref<FixedSpatialMaterial> gi_probe_material;
+ Ref<FixedSpatialMaterial> gi_probe_material_internal;
Ref<FixedSpatialMaterial> room_material;
Ref<FixedSpatialMaterial> portal_material;
Ref<FixedSpatialMaterial> raycast_material;