-Add lightmapper

-Fixes to unwrapper (remove degenerates), makes Thekla not crash
-Added optional cancel button in EditorProgress
-Added function to force processing of events (needed for cancel button)
This commit is contained in:
Juan Linietsky 2017-12-14 08:59:46 -03:00
parent aa6772d7ab
commit f3ad14224e
44 changed files with 4585 additions and 1139 deletions

View File

@ -168,6 +168,7 @@ opts.Add(BoolVariable('vsproj', "Generate Visual Studio Project.", False))
opts.Add(EnumVariable('warnings', "Set the level of warnings emitted during compilation", 'no', ('extra', 'all', 'moderate', 'no'))) opts.Add(EnumVariable('warnings', "Set the level of warnings emitted during compilation", 'no', ('extra', 'all', 'moderate', 'no')))
opts.Add(BoolVariable('progress', "Show a progress indicator during build", True)) opts.Add(BoolVariable('progress', "Show a progress indicator during build", True))
opts.Add(BoolVariable('dev', "If yes, alias for verbose=yes warnings=all", False)) opts.Add(BoolVariable('dev', "If yes, alias for verbose=yes warnings=all", False))
opts.Add(BoolVariable('openmp', "If yes, enable OpenMP", True))
# Thirdparty libraries # Thirdparty libraries
opts.Add(BoolVariable('builtin_enet', "Use the builtin enet library", True)) opts.Add(BoolVariable('builtin_enet', "Use the builtin enet library", True))

View File

@ -442,6 +442,7 @@ public:
virtual int get_power_seconds_left(); virtual int get_power_seconds_left();
virtual int get_power_percent_left(); virtual int get_power_percent_left();
virtual void force_process_input(){};
bool has_feature(const String &p_feature); bool has_feature(const String &p_feature);
/** /**

View File

@ -1849,6 +1849,20 @@ void RasterizerSceneGLES3::_setup_light(RenderList::Element *e, const Transform
state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE2_ENABLED, false); state.scene_shader.set_uniform(SceneShaderGLES3::GI_PROBE2_ENABLED, false);
} }
} else if (!e->instance->lightmap_capture_data.empty()) {
glUniform4fv(state.scene_shader.get_uniform_location(SceneShaderGLES3::LIGHTMAP_CAPTURES), 12, (const GLfloat *)e->instance->lightmap_capture_data.ptr());
state.scene_shader.set_uniform(SceneShaderGLES3::LIGHTMAP_CAPTURE_SKY, false);
} else if (e->instance->lightmap.is_valid()) {
RasterizerStorageGLES3::Texture *lightmap = storage->texture_owner.getornull(e->instance->lightmap);
RasterizerStorageGLES3::LightmapCapture *capture = storage->lightmap_capture_data_owner.getornull(e->instance->lightmap_capture->base);
if (lightmap && capture) {
glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 9);
glBindTexture(GL_TEXTURE_2D, lightmap->tex_id);
state.scene_shader.set_uniform(SceneShaderGLES3::LIGHTMAP_ENERGY, capture->energy);
}
} }
} }
@ -1971,6 +1985,8 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_
state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_5, 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::SHADOW_MODE_PCF_13, false);
state.scene_shader.set_conditional(SceneShaderGLES3::USE_GI_PROBES, false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_GI_PROBES, false);
state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHTMAP_CAPTURE, false);
state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHTMAP, false);
state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP, false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_RADIANCE_MAP, false);
state.scene_shader.set_conditional(SceneShaderGLES3::USE_CONTACT_SHADOWS, false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_CONTACT_SHADOWS, false);
@ -1978,6 +1994,8 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_
} else { } else {
state.scene_shader.set_conditional(SceneShaderGLES3::USE_GI_PROBES, e->instance->gi_probe_instances.size() > 0); state.scene_shader.set_conditional(SceneShaderGLES3::USE_GI_PROBES, e->instance->gi_probe_instances.size() > 0);
state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHTMAP, e->instance->lightmap.is_valid() && e->instance->gi_probe_instances.size() == 0);
state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHTMAP_CAPTURE, !e->instance->lightmap_capture_data.empty() && !e->instance->lightmap.is_valid() && e->instance->gi_probe_instances.size() == 0);
state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS, false); state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS, false);
@ -2148,6 +2166,8 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_
state.scene_shader.set_conditional(SceneShaderGLES3::SHADOW_MODE_PCF_5, 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::SHADOW_MODE_PCF_13, false);
state.scene_shader.set_conditional(SceneShaderGLES3::USE_GI_PROBES, false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_GI_PROBES, false);
state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHTMAP, false);
state.scene_shader.set_conditional(SceneShaderGLES3::USE_LIGHTMAP_CAPTURE, false);
state.scene_shader.set_conditional(SceneShaderGLES3::USE_CONTACT_SHADOWS, false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_CONTACT_SHADOWS, false);
state.scene_shader.set_conditional(SceneShaderGLES3::USE_VERTEX_LIGHTING, false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_VERTEX_LIGHTING, false);
state.scene_shader.set_conditional(SceneShaderGLES3::USE_OPAQUE_PREPASS, false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_OPAQUE_PREPASS, false);
@ -2274,6 +2294,14 @@ void RasterizerSceneGLES3::_add_geometry_with_material(RasterizerStorageGLES3::G
e->sort_key |= SORT_KEY_GI_PROBES_FLAG; e->sort_key |= SORT_KEY_GI_PROBES_FLAG;
} }
if (e->instance->lightmap.is_valid()) {
e->sort_key |= SORT_KEY_LIGHTMAP_FLAG;
}
if (!e->instance->lightmap_capture_data.empty()) {
e->sort_key |= SORT_KEY_LIGHTMAP_CAPTURE_FLAG;
}
e->sort_key |= uint64_t(p_material->render_priority + 128) << RenderList::SORT_KEY_PRIORITY_SHIFT; e->sort_key |= uint64_t(p_material->render_priority + 128) << RenderList::SORT_KEY_PRIORITY_SHIFT;
} else { } else {
e->sort_key |= uint64_t(e->instance->depth_layer) << RenderList::SORT_KEY_OPAQUE_DEPTH_LAYER_SHIFT; e->sort_key |= uint64_t(e->instance->depth_layer) << RenderList::SORT_KEY_OPAQUE_DEPTH_LAYER_SHIFT;

View File

@ -662,19 +662,21 @@ public:
SORT_KEY_OPAQUE_DEPTH_LAYER_SHIFT = 52, SORT_KEY_OPAQUE_DEPTH_LAYER_SHIFT = 52,
SORT_KEY_OPAQUE_DEPTH_LAYER_MASK = 0xF, SORT_KEY_OPAQUE_DEPTH_LAYER_MASK = 0xF,
//64 bits unsupported in MSVC //64 bits unsupported in MSVC
#define SORT_KEY_UNSHADED_FLAG (uint64_t(1) << 51) #define SORT_KEY_UNSHADED_FLAG (uint64_t(1) << 49)
#define SORT_KEY_NO_DIRECTIONAL_FLAG (uint64_t(1) << 50) #define SORT_KEY_NO_DIRECTIONAL_FLAG (uint64_t(1) << 48)
#define SORT_KEY_GI_PROBES_FLAG (uint64_t(1) << 49) #define SORT_KEY_LIGHTMAP_CAPTURE_FLAG (uint64_t(1) << 47)
#define SORT_KEY_VERTEX_LIT_FLAG (uint64_t(1) << 48) #define SORT_KEY_LIGHTMAP_FLAG (uint64_t(1) << 46)
SORT_KEY_SHADING_SHIFT = 48, #define SORT_KEY_GI_PROBES_FLAG (uint64_t(1) << 45)
SORT_KEY_SHADING_MASK = 15, #define SORT_KEY_VERTEX_LIT_FLAG (uint64_t(1) << 44)
//48-32 material index SORT_KEY_SHADING_SHIFT = 44,
SORT_KEY_MATERIAL_INDEX_SHIFT = 32, SORT_KEY_SHADING_MASK = 63,
//32-12 geometry index //44-28 material index
SORT_KEY_GEOMETRY_INDEX_SHIFT = 12, SORT_KEY_MATERIAL_INDEX_SHIFT = 28,
//bits 12-8 geometry type //28-8 geometry index
SORT_KEY_GEOMETRY_TYPE_SHIFT = 8, SORT_KEY_GEOMETRY_INDEX_SHIFT = 8,
//bits 0-7 for flags //bits 5-7 geometry type
SORT_KEY_GEOMETRY_TYPE_SHIFT = 5,
//bits 0-5 for flags
SORT_KEY_OPAQUE_PRE_PASS = 8, SORT_KEY_OPAQUE_PRE_PASS = 8,
SORT_KEY_CULL_DISABLED_FLAG = 4, SORT_KEY_CULL_DISABLED_FLAG = 4,
SORT_KEY_SKELETON_FLAG = 2, SORT_KEY_SKELETON_FLAG = 2,

View File

@ -5216,6 +5216,104 @@ void RasterizerStorageGLES3::gi_probe_dynamic_data_update(RID p_gi_probe_data, i
//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,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()); //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());
} }
/////////////////////////////
RID RasterizerStorageGLES3::lightmap_capture_create() {
LightmapCapture *capture = memnew(LightmapCapture);
return lightmap_capture_data_owner.make_rid(capture);
}
void RasterizerStorageGLES3::lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds) {
LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
ERR_FAIL_COND(!capture);
capture->bounds = p_bounds;
capture->instance_change_notify();
}
AABB RasterizerStorageGLES3::lightmap_capture_get_bounds(RID p_capture) const {
const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
ERR_FAIL_COND_V(!capture, AABB());
return capture->bounds;
}
void RasterizerStorageGLES3::lightmap_capture_set_octree(RID p_capture, const PoolVector<uint8_t> &p_octree) {
LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
ERR_FAIL_COND(!capture);
ERR_FAIL_COND(p_octree.size() == 0 || (p_octree.size() % sizeof(LightmapCaptureOctree)) != 0);
capture->octree.resize(p_octree.size() / sizeof(LightmapCaptureOctree));
if (p_octree.size()) {
PoolVector<LightmapCaptureOctree>::Write w = capture->octree.write();
PoolVector<uint8_t>::Read r = p_octree.read();
copymem(w.ptr(), r.ptr(), p_octree.size());
}
capture->instance_change_notify();
}
PoolVector<uint8_t> RasterizerStorageGLES3::lightmap_capture_get_octree(RID p_capture) const {
const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
ERR_FAIL_COND_V(!capture, PoolVector<uint8_t>());
if (capture->octree.size() == 0)
return PoolVector<uint8_t>();
PoolVector<uint8_t> ret;
ret.resize(capture->octree.size() * sizeof(LightmapCaptureOctree));
{
PoolVector<LightmapCaptureOctree>::Read r = capture->octree.read();
PoolVector<uint8_t>::Write w = ret.write();
copymem(w.ptr(), r.ptr(), ret.size());
}
return ret;
}
void RasterizerStorageGLES3::lightmap_capture_set_octree_cell_transform(RID p_capture, const Transform &p_xform) {
LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
ERR_FAIL_COND(!capture);
capture->cell_xform = p_xform;
}
Transform RasterizerStorageGLES3::lightmap_capture_get_octree_cell_transform(RID p_capture) const {
const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
ERR_FAIL_COND_V(!capture, Transform());
return capture->cell_xform;
}
void RasterizerStorageGLES3::lightmap_capture_set_octree_cell_subdiv(RID p_capture, int p_subdiv) {
LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
ERR_FAIL_COND(!capture);
capture->cell_subdiv = p_subdiv;
}
int RasterizerStorageGLES3::lightmap_capture_get_octree_cell_subdiv(RID p_capture) const {
const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
ERR_FAIL_COND_V(!capture, 0);
return capture->cell_subdiv;
}
void RasterizerStorageGLES3::lightmap_capture_set_energy(RID p_capture, float p_energy) {
LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
ERR_FAIL_COND(!capture);
capture->energy = p_energy;
}
float RasterizerStorageGLES3::lightmap_capture_get_energy(RID p_capture) const {
const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
ERR_FAIL_COND_V(!capture, 0);
return capture->energy;
}
const PoolVector<RasterizerStorage::LightmapCaptureOctree> *RasterizerStorageGLES3::lightmap_capture_get_octree_ptr(RID p_capture) const {
const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
ERR_FAIL_COND_V(!capture, NULL);
return &capture->octree;
}
/////// ///////
@ -5817,6 +5915,10 @@ void RasterizerStorageGLES3::instance_add_dependency(RID p_base, RasterizerScene
inst = gi_probe_owner.getornull(p_base); inst = gi_probe_owner.getornull(p_base);
ERR_FAIL_COND(!inst); ERR_FAIL_COND(!inst);
} break; } break;
case VS::INSTANCE_LIGHTMAP_CAPTURE: {
inst = lightmap_capture_data_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;
default: { default: {
if (!inst) { if (!inst) {
ERR_FAIL(); ERR_FAIL();
@ -5860,6 +5962,10 @@ void RasterizerStorageGLES3::instance_remove_dependency(RID p_base, RasterizerSc
inst = gi_probe_owner.getornull(p_base); inst = gi_probe_owner.getornull(p_base);
ERR_FAIL_COND(!inst); ERR_FAIL_COND(!inst);
} break; } break;
case VS::INSTANCE_LIGHTMAP_CAPTURE: {
inst = lightmap_capture_data_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;
default: { default: {
if (!inst) { if (!inst) {
@ -6609,6 +6715,10 @@ VS::InstanceType RasterizerStorageGLES3::get_base_type(RID p_rid) const {
return VS::INSTANCE_GI_PROBE; return VS::INSTANCE_GI_PROBE;
} }
if (lightmap_capture_data_owner.owns(p_rid)) {
return VS::INSTANCE_LIGHTMAP_CAPTURE;
}
return VS::INSTANCE_NONE; return VS::INSTANCE_NONE;
} }
@ -6795,6 +6905,13 @@ bool RasterizerStorageGLES3::free(RID p_rid) {
glDeleteTextures(1, &gi_probe_data->tex_id); glDeleteTextures(1, &gi_probe_data->tex_id);
gi_probe_owner.free(p_rid); gi_probe_owner.free(p_rid);
memdelete(gi_probe_data); memdelete(gi_probe_data);
} else if (lightmap_capture_data_owner.owns(p_rid)) {
// delete the texture
LightmapCapture *lightmap_capture = lightmap_capture_data_owner.get(p_rid);
gi_probe_owner.free(p_rid);
memdelete(lightmap_capture);
} else if (canvas_occluder_owner.owns(p_rid)) { } else if (canvas_occluder_owner.owns(p_rid)) {

View File

@ -1069,6 +1069,38 @@ public:
virtual RID gi_probe_dynamic_data_create(int p_width, int p_height, int p_depth, GIProbeCompression p_compression); virtual RID gi_probe_dynamic_data_create(int p_width, int p_height, int p_depth, GIProbeCompression p_compression);
virtual void gi_probe_dynamic_data_update(RID p_gi_probe_data, int p_depth_slice, int p_slice_count, int p_mipmap, const void *p_data); virtual void gi_probe_dynamic_data_update(RID p_gi_probe_data, int p_depth_slice, int p_slice_count, int p_mipmap, const void *p_data);
/* LIGHTMAP CAPTURE */
virtual RID lightmap_capture_create();
virtual void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds);
virtual AABB lightmap_capture_get_bounds(RID p_capture) const;
virtual void lightmap_capture_set_octree(RID p_capture, const PoolVector<uint8_t> &p_octree);
virtual PoolVector<uint8_t> lightmap_capture_get_octree(RID p_capture) const;
virtual void lightmap_capture_set_octree_cell_transform(RID p_capture, const Transform &p_xform);
virtual Transform lightmap_capture_get_octree_cell_transform(RID p_capture) const;
virtual void lightmap_capture_set_octree_cell_subdiv(RID p_capture, int p_subdiv);
virtual int lightmap_capture_get_octree_cell_subdiv(RID p_capture) const;
virtual void lightmap_capture_set_energy(RID p_capture, float p_energy);
virtual float lightmap_capture_get_energy(RID p_capture) const;
virtual const PoolVector<LightmapCaptureOctree> *lightmap_capture_get_octree_ptr(RID p_capture) const;
struct LightmapCapture : public Instantiable {
PoolVector<LightmapCaptureOctree> octree;
AABB bounds;
Transform cell_xform;
int cell_subdiv;
float energy;
LightmapCapture() {
energy = 1.0;
cell_subdiv = 1;
}
};
mutable RID_Owner<LightmapCapture> lightmap_capture_data_owner;
/* PARTICLES */ /* PARTICLES */
struct Particles : public GeometryOwner { struct Particles : public GeometryOwner {

View File

@ -35,7 +35,7 @@ layout(location=3) in vec4 color_attrib;
layout(location=4) in vec2 uv_attrib; layout(location=4) in vec2 uv_attrib;
#endif #endif
#if defined(ENABLE_UV2_INTERP) #if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP)
layout(location=5) in vec2 uv2_attrib; layout(location=5) in vec2 uv2_attrib;
#endif #endif
@ -223,7 +223,7 @@ out vec4 color_interp;
out vec2 uv_interp; out vec2 uv_interp;
#endif #endif
#if defined(ENABLE_UV2_INTERP) #if defined(ENABLE_UV2_INTERP) || defined (USE_LIGHTMAP)
out vec2 uv2_interp; out vec2 uv2_interp;
#endif #endif
@ -234,9 +234,6 @@ out vec3 binormal_interp;
#endif #endif
#if defined(USE_MATERIAL) #if defined(USE_MATERIAL)
layout(std140) uniform UniformData { //ubo:1 layout(std140) uniform UniformData { //ubo:1
@ -356,7 +353,7 @@ void main() {
uv_interp = uv_attrib; uv_interp = uv_attrib;
#endif #endif
#if defined(ENABLE_UV2_INTERP) #if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP)
uv2_interp = uv2_attrib; uv2_interp = uv2_attrib;
#endif #endif
@ -549,7 +546,7 @@ in vec4 color_interp;
in vec2 uv_interp; in vec2 uv_interp;
#endif #endif
#if defined(ENABLE_UV2_INTERP) #if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP)
in vec2 uv2_interp; in vec2 uv2_interp;
#endif #endif
@ -1357,7 +1354,7 @@ void reflection_process(int idx, vec3 vertex, vec3 normal,vec3 binormal, vec3 ta
reflection_accum+=reflection; reflection_accum+=reflection;
} }
#ifndef USE_LIGHTMAP
if (reflections[idx].ambient.a>0.0) { //compute ambient using skybox if (reflections[idx].ambient.a>0.0) { //compute ambient using skybox
@ -1403,8 +1400,20 @@ void reflection_process(int idx, vec3 vertex, vec3 normal,vec3 binormal, vec3 ta
ambient_accum+=ambient_out; ambient_accum+=ambient_out;
} }
#endif
} }
#ifdef USE_LIGHTMAP
uniform mediump sampler2D lightmap; //texunit:-9
uniform mediump float lightmap_energy;
#endif
#ifdef USE_LIGHTMAP_CAPTURE
uniform mediump vec4[12] lightmap_captures;
uniform bool lightmap_capture_sky;
#endif
#ifdef USE_GI_PROBES #ifdef USE_GI_PROBES
uniform mediump sampler3D gi_probe1; //texunit:-9 uniform mediump sampler3D gi_probe1; //texunit:-9
@ -1632,7 +1641,7 @@ void main() {
vec2 uv = uv_interp; vec2 uv = uv_interp;
#endif #endif
#if defined(ENABLE_UV2_INTERP) #if defined(ENABLE_UV2_INTERP) || defined (USE_LIGHTMAP)
vec2 uv2 = uv2_interp; vec2 uv2 = uv2_interp;
#endif #endif
@ -1745,7 +1754,7 @@ FRAGMENT_SHADER_CODE
//vec3 radiance = textureLod(radiance_cube, r, lod).xyz * ( brdf.x + brdf.y); //vec3 radiance = textureLod(radiance_cube, r, lod).xyz * ( brdf.x + brdf.y);
} }
#ifndef USE_LIGHTMAP
{ {
vec3 ambient_dir=normalize((radiance_inverse_xform * vec4(normal,0.0)).xyz); vec3 ambient_dir=normalize((radiance_inverse_xform * vec4(normal,0.0)).xyz);
@ -1754,6 +1763,7 @@ FRAGMENT_SHADER_CODE
ambient_light=mix(ambient_light_color.rgb,env_ambient,radiance_ambient_contribution); ambient_light=mix(ambient_light_color.rgb,env_ambient,radiance_ambient_contribution);
//ambient_light=vec3(0.0,0.0,0.0); //ambient_light=vec3(0.0,0.0,0.0);
} }
#endif
} }
#else #else
@ -1938,6 +1948,48 @@ FRAGMENT_SHADER_CODE
#endif #endif
#ifdef USE_LIGHTMAP
ambient_light = texture(lightmap,uv2).rgb * lightmap_energy;
#endif
#ifdef USE_LIGHTMAP_CAPTURE
{
vec3 cone_dirs[12] = 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),
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)
);
vec3 local_normal = normalize(camera_matrix * vec4(normal,0.0)).xyz;
vec4 captured = vec4(0.0);
float sum = 0.0;
for(int i=0;i<12;i++) {
float amount = max(0.0,dot(local_normal,cone_dirs[i])); //not correct, but creates a nice wrap around effect
captured += lightmap_captures[i]*amount;
sum+=amount;
}
captured/=sum;
if (lightmap_capture_sky) {
ambient_light = mix( ambient_light, captured.rgb, captured.a);
} else {
ambient_light = captured.rgb;
}
}
#endif
#ifdef USE_FORWARD_LIGHTING #ifdef USE_FORWARD_LIGHTING
@ -1952,11 +2004,11 @@ FRAGMENT_SHADER_CODE
} else { } else {
specular_light+=env_reflection_light; specular_light+=env_reflection_light;
} }
#ifndef USE_LIGHTMAP
if (ambient_accum.a>0.0) { if (ambient_accum.a>0.0) {
ambient_light+=ambient_accum.rgb/ambient_accum.a; ambient_light+=ambient_accum.rgb/ambient_accum.a;
} }
#endif
#ifdef USE_VERTEX_LIGHTING #ifdef USE_VERTEX_LIGHTING

View File

@ -67,6 +67,7 @@
#include "editor/plugins/animation_player_editor_plugin.h" #include "editor/plugins/animation_player_editor_plugin.h"
#include "editor/plugins/animation_tree_editor_plugin.h" #include "editor/plugins/animation_tree_editor_plugin.h"
#include "editor/plugins/asset_library_editor_plugin.h" #include "editor/plugins/asset_library_editor_plugin.h"
#include "editor/plugins/baked_lightmap_editor_plugin.h"
#include "editor/plugins/camera_editor_plugin.h" #include "editor/plugins/camera_editor_plugin.h"
#include "editor/plugins/canvas_item_editor_plugin.h" #include "editor/plugins/canvas_item_editor_plugin.h"
#include "editor/plugins/collision_polygon_2d_editor_plugin.h" #include "editor/plugins/collision_polygon_2d_editor_plugin.h"
@ -3384,14 +3385,14 @@ void EditorNode::stop_child_process() {
_menu_option_confirm(RUN_STOP, false); _menu_option_confirm(RUN_STOP, false);
} }
void EditorNode::progress_add_task(const String &p_task, const String &p_label, int p_steps) { void EditorNode::progress_add_task(const String &p_task, const String &p_label, int p_steps, bool p_can_cancel) {
singleton->progress_dialog->add_task(p_task, p_label, p_steps); singleton->progress_dialog->add_task(p_task, p_label, p_steps, p_can_cancel);
} }
void EditorNode::progress_task_step(const String &p_task, const String &p_state, int p_step, bool p_force_refresh) { bool EditorNode::progress_task_step(const String &p_task, const String &p_state, int p_step, bool p_force_refresh) {
singleton->progress_dialog->task_step(p_task, p_state, p_step, p_force_refresh); return singleton->progress_dialog->task_step(p_task, p_state, p_step, p_force_refresh);
} }
void EditorNode::progress_end_task(const String &p_task) { void EditorNode::progress_end_task(const String &p_task) {
@ -5659,6 +5660,7 @@ EditorNode::EditorNode() {
add_editor_plugin(memnew(TextureRegionEditorPlugin(this))); add_editor_plugin(memnew(TextureRegionEditorPlugin(this)));
add_editor_plugin(memnew(Particles2DEditorPlugin(this))); add_editor_plugin(memnew(Particles2DEditorPlugin(this)));
add_editor_plugin(memnew(GIProbeEditorPlugin(this))); add_editor_plugin(memnew(GIProbeEditorPlugin(this)));
add_editor_plugin(memnew(BakedLightmapEditorPlugin(this)));
add_editor_plugin(memnew(Path2DEditorPlugin(this))); add_editor_plugin(memnew(Path2DEditorPlugin(this)));
add_editor_plugin(memnew(PathEditorPlugin(this))); add_editor_plugin(memnew(PathEditorPlugin(this)));
add_editor_plugin(memnew(Line2DEditorPlugin(this))); add_editor_plugin(memnew(Line2DEditorPlugin(this)));

View File

@ -745,8 +745,8 @@ public:
static void add_io_error(const String &p_error); static void add_io_error(const String &p_error);
static void progress_add_task(const String &p_task, const String &p_label, int p_steps); static void progress_add_task(const String &p_task, const String &p_label, int p_steps, bool p_can_cancel = false);
static void progress_task_step(const String &p_task, const String &p_state, int p_step = -1, bool p_force_refresh = true); static bool progress_task_step(const String &p_task, const String &p_state, int p_step = -1, bool p_force_refresh = true);
static void progress_end_task(const String &p_task); static void progress_end_task(const String &p_task);
static void progress_add_task_bg(const String &p_task, const String &p_label, int p_steps); static void progress_add_task_bg(const String &p_task, const String &p_label, int p_steps);
@ -807,9 +807,9 @@ public:
struct EditorProgress { struct EditorProgress {
String task; String task;
void step(const String &p_state, int p_step = -1, bool p_force_refresh = true) { EditorNode::progress_task_step(task, p_state, p_step, p_force_refresh); } bool step(const String &p_state, int p_step = -1, bool p_force_refresh = true) { return EditorNode::progress_task_step(task, p_state, p_step, p_force_refresh); }
EditorProgress(const String &p_task, const String &p_label, int p_amount) { EditorProgress(const String &p_task, const String &p_label, int p_amount, bool p_can_cancel = false) {
EditorNode::progress_add_task(p_task, p_label, p_amount); EditorNode::progress_add_task(p_task, p_label, p_amount, p_can_cancel);
task = p_task; task = p_task;
} }
~EditorProgress() { EditorNode::progress_end_task(task); } ~EditorProgress() { EditorNode::progress_end_task(task); }

View File

@ -1165,8 +1165,8 @@ void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, in
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/compress"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/compress"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/ensure_tangents"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "meshes/ensure_tangents"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/storage", PROPERTY_HINT_ENUM, "Built-In,Files"), meshes_out ? 1 : 0)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/storage", PROPERTY_HINT_ENUM, "Built-In,Files"), meshes_out ? 1 : 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/light_baking", PROPERTY_HINT_ENUM, "Disabled,Enable,Gen Lightmaps"), 0)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "meshes/light_baking", PROPERTY_HINT_ENUM, "Disabled,Enable,Gen Lightmaps", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "meshes/lightmap_texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.05)); r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "meshes/lightmap_texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.1));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "external_files/store_in_subdir"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "external_files/store_in_subdir"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 15)); r_options->push_back(ImportOption(PropertyInfo(Variant::REAL, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 15));

View File

@ -0,0 +1,95 @@
#include "baked_lightmap_editor_plugin.h"
void BakedLightmapEditorPlugin::_bake() {
if (lightmap) {
BakedLightmap::BakeError err;
if (get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root() == lightmap) {
err = lightmap->bake(lightmap);
} else {
err = lightmap->bake(lightmap->get_parent());
}
switch (err) {
case BakedLightmap::BAKE_ERROR_NO_SAVE_PATH:
EditorNode::get_singleton()->show_warning(TTR("Can't determine a save path for lightmap images.\nSave your scene (for images to be saved in the same dir), or pick a save path from the BakedLightmap properties."));
break;
case BakedLightmap::BAKE_ERROR_NO_MESHES:
EditorNode::get_singleton()->show_warning(TTR("No meshes to bake. Make sure they contain an UV2 channel and that the 'Bake Light' flag is on."));
break;
case BakedLightmap::BAKE_ERROR_CANT_CREATE_IMAGE:
EditorNode::get_singleton()->show_warning(TTR("Failed creating lightmap images, make sure path is writable."));
break;
defaut : {}
}
}
}
void BakedLightmapEditorPlugin::edit(Object *p_object) {
BakedLightmap *s = Object::cast_to<BakedLightmap>(p_object);
if (!s)
return;
lightmap = s;
}
bool BakedLightmapEditorPlugin::handles(Object *p_object) const {
return p_object->is_class("BakedLightmap");
}
void BakedLightmapEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
bake->show();
} else {
bake->hide();
}
}
EditorProgress *BakedLightmapEditorPlugin::tmp_progress = NULL;
void BakedLightmapEditorPlugin::bake_func_begin(int p_steps) {
ERR_FAIL_COND(tmp_progress != NULL);
tmp_progress = memnew(EditorProgress("bake_lightmaps", TTR("Bake Lightmaps"), p_steps, true));
}
bool BakedLightmapEditorPlugin::bake_func_step(int p_step, const String &p_description) {
ERR_FAIL_COND_V(tmp_progress == NULL, false);
return tmp_progress->step(p_description, p_step);
}
void BakedLightmapEditorPlugin::bake_func_end() {
ERR_FAIL_COND(tmp_progress == NULL);
memdelete(tmp_progress);
tmp_progress = NULL;
}
void BakedLightmapEditorPlugin::_bind_methods() {
ClassDB::bind_method("_bake", &BakedLightmapEditorPlugin::_bake);
}
BakedLightmapEditorPlugin::BakedLightmapEditorPlugin(EditorNode *p_node) {
editor = p_node;
bake = memnew(Button);
bake->set_icon(editor->get_gui_base()->get_icon("BakedLight", "EditorIcons"));
bake->set_text(TTR("Bake Lightmaps"));
bake->hide();
bake->connect("pressed", this, "_bake");
add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, bake);
lightmap = NULL;
BakedLightmap::bake_begin_function = bake_func_begin;
BakedLightmap::bake_step_function = bake_func_step;
BakedLightmap::bake_end_function = bake_func_end;
}
BakedLightmapEditorPlugin::~BakedLightmapEditorPlugin() {
}

View File

@ -0,0 +1,39 @@
#ifndef BAKED_LIGHTMAP_EDITOR_PLUGIN_H
#define BAKED_LIGHTMAP_EDITOR_PLUGIN_H
#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "scene/3d/baked_lightmap.h"
#include "scene/resources/material.h"
class BakedLightmapEditorPlugin : public EditorPlugin {
GDCLASS(BakedLightmapEditorPlugin, EditorPlugin);
BakedLightmap *lightmap;
Button *bake;
EditorNode *editor;
static EditorProgress *tmp_progress;
static void bake_func_begin(int p_steps);
static bool bake_func_step(int p_step, const String &p_description);
static void bake_func_end();
void _bake();
protected:
static void _bind_methods();
public:
virtual String get_name() const { return "BakedLightmap"; }
bool has_main_screen() const { return false; }
virtual void edit(Object *p_object);
virtual bool handles(Object *p_object) const;
virtual void make_visible(bool p_visible);
BakedLightmapEditorPlugin(EditorNode *p_node);
~BakedLightmapEditorPlugin();
};
#endif // BAKED_LIGHTMAP_EDITOR_PLUGIN_H

View File

@ -163,7 +163,7 @@ void ProgressDialog::_popup() {
popup_centered(ms); popup_centered(ms);
} }
void ProgressDialog::add_task(const String &p_task, const String &p_label, int p_steps) { void ProgressDialog::add_task(const String &p_task, const String &p_label, int p_steps, bool p_can_cancel) {
ERR_FAIL_COND(tasks.has(p_task)); ERR_FAIL_COND(tasks.has(p_task));
Task t; Task t;
@ -180,17 +180,24 @@ void ProgressDialog::add_task(const String &p_task, const String &p_label, int p
main->add_child(t.vb); main->add_child(t.vb);
tasks[p_task] = t; tasks[p_task] = t;
if (p_can_cancel) {
cancel_hb->show();
} else {
cancel_hb->hide();
}
cancel_hb->raise();
cancelled = false;
_popup(); _popup();
} }
void ProgressDialog::task_step(const String &p_task, const String &p_state, int p_step, bool p_force_redraw) { bool ProgressDialog::task_step(const String &p_task, const String &p_state, int p_step, bool p_force_redraw) {
ERR_FAIL_COND(!tasks.has(p_task)); ERR_FAIL_COND_V(!tasks.has(p_task), cancelled);
if (!p_force_redraw) { if (!p_force_redraw) {
uint64_t tus = OS::get_singleton()->get_ticks_usec(); uint64_t tus = OS::get_singleton()->get_ticks_usec();
if (tus - last_progress_tick < 50000) //50ms if (tus - last_progress_tick < 50000) //50ms
return; return cancelled;
} }
Task &t = tasks[p_task]; Task &t = tasks[p_task];
@ -201,7 +208,11 @@ void ProgressDialog::task_step(const String &p_task, const String &p_state, int
t.state->set_text(p_state); t.state->set_text(p_state);
last_progress_tick = OS::get_singleton()->get_ticks_usec(); last_progress_tick = OS::get_singleton()->get_ticks_usec();
if (cancel_hb->is_visible()) {
OS::get_singleton()->force_process_input();
}
Main::iteration(); // this will not work on a lot of platforms, so it's only meant for the editor Main::iteration(); // this will not work on a lot of platforms, so it's only meant for the editor
return cancelled;
} }
void ProgressDialog::end_task(const String &p_task) { void ProgressDialog::end_task(const String &p_task) {
@ -218,6 +229,14 @@ void ProgressDialog::end_task(const String &p_task) {
_popup(); _popup();
} }
void ProgressDialog::_cancel_pressed() {
cancelled = true;
}
void ProgressDialog::_bind_methods() {
ClassDB::bind_method("_cancel_pressed", &ProgressDialog::_cancel_pressed);
}
ProgressDialog::ProgressDialog() { ProgressDialog::ProgressDialog() {
main = memnew(VBoxContainer); main = memnew(VBoxContainer);
@ -226,4 +245,13 @@ ProgressDialog::ProgressDialog() {
set_exclusive(true); set_exclusive(true);
last_progress_tick = 0; last_progress_tick = 0;
singleton = this; singleton = this;
cancel_hb = memnew(HBoxContainer);
main->add_child(cancel_hb);
cancel_hb->hide();
cancel = memnew(Button);
cancel_hb->add_spacer();
cancel_hb->add_child(cancel);
cancel->set_text(TTR("Cancel"));
cancel_hb->add_spacer();
cancel->connect("pressed", this, "_cancel_pressed");
} }

View File

@ -31,6 +31,7 @@
#define PROGRESS_DIALOG_H #define PROGRESS_DIALOG_H
#include "scene/gui/box_container.h" #include "scene/gui/box_container.h"
#include "scene/gui/button.h"
#include "scene/gui/label.h" #include "scene/gui/label.h"
#include "scene/gui/popup.h" #include "scene/gui/popup.h"
#include "scene/gui/progress_bar.h" #include "scene/gui/progress_bar.h"
@ -76,6 +77,8 @@ class ProgressDialog : public Popup {
ProgressBar *progress; ProgressBar *progress;
Label *state; Label *state;
}; };
HBoxContainer *cancel_hb;
Button *cancel;
Map<String, Task> tasks; Map<String, Task> tasks;
VBoxContainer *main; VBoxContainer *main;
@ -84,13 +87,17 @@ class ProgressDialog : public Popup {
static ProgressDialog *singleton; static ProgressDialog *singleton;
void _popup(); void _popup();
void _cancel_pressed();
bool cancelled;
protected: protected:
void _notification(int p_what); void _notification(int p_what);
static void _bind_methods();
public: public:
static ProgressDialog *get_singleton() { return singleton; } static ProgressDialog *get_singleton() { return singleton; }
void add_task(const String &p_task, const String &p_label, int p_steps); void add_task(const String &p_task, const String &p_label, int p_steps, bool p_can_cancel = false);
void task_step(const String &p_task, const String &p_state, int p_step = -1, bool p_force_redraw = true); bool task_step(const String &p_task, const String &p_state, int p_step = -1, bool p_force_redraw = true);
void end_task(const String &p_task); void end_task(const String &p_task);
ProgressDialog(); ProgressDialog();

View File

@ -2752,8 +2752,123 @@ GIProbeGizmo::GIProbeGizmo(GIProbe *p_probe) {
set_spatial_node(p_probe); set_spatial_node(p_probe);
} }
////////
//////// ////////
///
String BakedIndirectLightGizmo::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 BakedIndirectLightGizmo::get_handle_value(int p_idx) const {
return baker->get_extents();
}
void BakedIndirectLightGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_point) {
Transform gt = baker->get_global_transform();
//gt.orthonormalize();
Transform gi = gt.affine_inverse();
Vector3 extents = baker->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;
baker->set_extents(extents);
}
void BakedIndirectLightGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p_cancel) {
Vector3 restore = p_restore;
if (p_cancel) {
baker->set_extents(restore);
return;
}
UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
ur->create_action(TTR("Change Probe Extents"));
ur->add_do_method(baker, "set_extents", baker->get_extents());
ur->add_undo_method(baker, "set_extents", restore);
ur->commit_action();
}
void BakedIndirectLightGizmo::redraw() {
Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/baked_indirect_light");
Ref<Material> material = create_material("baked_indirect_light_material", gizmo_color);
Ref<Material> icon = create_icon_material("baked_indirect_light_icon", SpatialEditor::get_singleton()->get_icon("GizmoGIProbe", "EditorIcons"));
Color gizmo_color_internal = gizmo_color;
gizmo_color_internal.a = 0.1;
Ref<Material> material_internal = create_material("baked_indirect_light_internal_material", gizmo_color_internal);
clear();
Vector<Vector3> lines;
Vector3 extents = baker->get_extents();
static const int subdivs[BakedLightmap::SUBDIV_MAX] = { 64, 128, 256, 512 };
AABB aabb = AABB(-extents, extents * 2);
int subdiv = subdivs[baker->get_bake_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, material);
add_collision_segments(lines);
Vector<Vector3> handles;
for (int i = 0; i < 3; i++) {
Vector3 ax;
ax[i] = aabb.position[i] + aabb.size[i];
handles.push_back(ax);
}
if (is_selected()) {
gizmo_color.a = 0.1;
Ref<Material> solid_material = create_material("baked_indirect_light_solid_material", gizmo_color);
add_solid_box(solid_material, aabb.get_size());
}
add_unscaled_billboard(icon, 0.05);
add_handles(handles);
}
BakedIndirectLightGizmo::BakedIndirectLightGizmo(BakedLightmap *p_baker) {
baker = p_baker;
set_spatial_node(p_baker);
}
////////
void NavigationMeshSpatialGizmo::redraw() { void NavigationMeshSpatialGizmo::redraw() {
Ref<Material> edge_material = create_material("navigation_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/navigation_edge")); Ref<Material> edge_material = create_material("navigation_material", EDITOR_GET("editors/3d_gizmos/gizmo_colors/navigation_edge"));
@ -3409,6 +3524,11 @@ Ref<SpatialEditorGizmo> SpatialEditorGizmos::get_gizmo(Spatial *p_spatial) {
Ref<GIProbeGizmo> misg = memnew(GIProbeGizmo(Object::cast_to<GIProbe>(p_spatial))); Ref<GIProbeGizmo> misg = memnew(GIProbeGizmo(Object::cast_to<GIProbe>(p_spatial)));
return misg; return misg;
} }
if (Object::cast_to<BakedLightmap>(p_spatial)) {
Ref<BakedIndirectLightGizmo> misg = memnew(BakedIndirectLightGizmo(Object::cast_to<BakedLightmap>(p_spatial)));
return misg;
}
if (Object::cast_to<VehicleWheel>(p_spatial)) { if (Object::cast_to<VehicleWheel>(p_spatial)) {
@ -3495,6 +3615,7 @@ SpatialEditorGizmos::SpatialEditorGizmos() {
EDITOR_DEF("editors/3d_gizmos/gizmo_colors/particles", Color(0.8, 0.7, 0.4)); EDITOR_DEF("editors/3d_gizmos/gizmo_colors/particles", Color(0.8, 0.7, 0.4));
EDITOR_DEF("editors/3d_gizmos/gizmo_colors/reflection_probe", Color(0.6, 1, 0.5)); EDITOR_DEF("editors/3d_gizmos/gizmo_colors/reflection_probe", Color(0.6, 1, 0.5));
EDITOR_DEF("editors/3d_gizmos/gizmo_colors/gi_probe", Color(0.5, 1, 0.6)); EDITOR_DEF("editors/3d_gizmos/gizmo_colors/gi_probe", Color(0.5, 1, 0.6));
EDITOR_DEF("editors/3d_gizmos/gizmo_colors/baked_indirect_light", Color(0.5, 0.6, 1));
EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1)); EDITOR_DEF("editors/3d_gizmos/gizmo_colors/shape", Color(0.5, 0.7, 1));
EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint", Color(0.5, 0.8, 1)); EDITOR_DEF("editors/3d_gizmos/gizmo_colors/joint", Color(0.5, 0.8, 1));
EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_edge", Color(0.5, 1, 1)); EDITOR_DEF("editors/3d_gizmos/gizmo_colors/navigation_edge", Color(0.5, 1, 1));

View File

@ -32,6 +32,7 @@
#include "editor/plugins/spatial_editor_plugin.h" #include "editor/plugins/spatial_editor_plugin.h"
#include "scene/3d/audio_stream_player_3d.h" #include "scene/3d/audio_stream_player_3d.h"
#include "scene/3d/baked_lightmap.h"
#include "scene/3d/camera.h" #include "scene/3d/camera.h"
#include "scene/3d/collision_polygon.h" #include "scene/3d/collision_polygon.h"
#include "scene/3d/collision_shape.h" #include "scene/3d/collision_shape.h"
@ -288,6 +289,22 @@ public:
GIProbeGizmo(GIProbe *p_probe = NULL); GIProbeGizmo(GIProbe *p_probe = NULL);
}; };
class BakedIndirectLightGizmo : public EditorSpatialGizmo {
GDCLASS(BakedIndirectLightGizmo, EditorSpatialGizmo);
BakedLightmap *baker;
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();
BakedIndirectLightGizmo(BakedLightmap *p_baker = NULL);
};
class CollisionShapeSpatialGizmo : public EditorSpatialGizmo { class CollisionShapeSpatialGizmo : public EditorSpatialGizmo {
GDCLASS(CollisionShapeSpatialGizmo, EditorSpatialGizmo); GDCLASS(CollisionShapeSpatialGizmo, EditorSpatialGizmo);

View File

@ -42,7 +42,7 @@ bool thekla_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
input_mesh.face_array[i].vertex_index[0] = p_indices[i * 3 + 0]; input_mesh.face_array[i].vertex_index[0] = p_indices[i * 3 + 0];
input_mesh.face_array[i].vertex_index[1] = p_indices[i * 3 + 1]; input_mesh.face_array[i].vertex_index[1] = p_indices[i * 3 + 1];
input_mesh.face_array[i].vertex_index[2] = p_indices[i * 3 + 2]; input_mesh.face_array[i].vertex_index[2] = p_indices[i * 3 + 2];
printf("face %i - %i, %i, %i - mat %i\n", i, input_mesh.face_array[i].vertex_index[0], input_mesh.face_array[i].vertex_index[1], input_mesh.face_array[i].vertex_index[2], p_face_materials[i]); //printf("face %i - %i, %i, %i - mat %i\n", i, input_mesh.face_array[i].vertex_index[0], input_mesh.face_array[i].vertex_index[1], input_mesh.face_array[i].vertex_index[2], p_face_materials[i]);
input_mesh.face_array[i].material_index = p_face_materials[i]; input_mesh.face_array[i].material_index = p_face_materials[i];
} }
input_mesh.vertex_array = new Thekla::Atlas_Input_Vertex[p_vertex_count]; input_mesh.vertex_array = new Thekla::Atlas_Input_Vertex[p_vertex_count];
@ -54,8 +54,8 @@ bool thekla_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
} }
input_mesh.vertex_array[i].uv[0] = 0; input_mesh.vertex_array[i].uv[0] = 0;
input_mesh.vertex_array[i].uv[1] = 0; input_mesh.vertex_array[i].uv[1] = 0;
printf("vertex %i - %f, %f, %f\n", i, input_mesh.vertex_array[i].position[0], input_mesh.vertex_array[i].position[1], input_mesh.vertex_array[i].position[2]); //printf("vertex %i - %f, %f, %f\n", i, input_mesh.vertex_array[i].position[0], input_mesh.vertex_array[i].position[1], input_mesh.vertex_array[i].position[2]);
printf("normal %i - %f, %f, %f\n", i, input_mesh.vertex_array[i].normal[0], input_mesh.vertex_array[i].normal[1], input_mesh.vertex_array[i].normal[2]); //printf("normal %i - %f, %f, %f\n", i, input_mesh.vertex_array[i].normal[0], input_mesh.vertex_array[i].normal[1], input_mesh.vertex_array[i].normal[2]);
} }
input_mesh.face_count = p_index_count / 3; input_mesh.face_count = p_index_count / 3;
input_mesh.vertex_count = p_vertex_count; input_mesh.vertex_count = p_vertex_count;
@ -65,6 +65,7 @@ bool thekla_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
Thekla::atlas_set_default_options(&options); Thekla::atlas_set_default_options(&options);
options.packer_options.witness.packing_quality = 1; options.packer_options.witness.packing_quality = 1;
options.packer_options.witness.texel_area = 1.0 / p_texel_size; options.packer_options.witness.texel_area = 1.0 / p_texel_size;
options.packer_options.witness.conservative = true;
//generate //generate
Thekla::Atlas_Error err; Thekla::Atlas_Error err;

View File

@ -228,6 +228,8 @@ public:
virtual Error move_to_trash(const String &p_path); virtual Error move_to_trash(const String &p_path);
void force_process_input();
OS_OSX(); OS_OSX();
private: private:

View File

@ -1971,6 +1971,13 @@ void OS_OSX::push_input(const Ref<InputEvent> &p_event) {
input->parse_input_event(ev); input->parse_input_event(ev);
} }
void OS_OSX::force_process_input() {
process_events(); // get rid of pending events
joypad_osx->process_joypads();
}
void OS_OSX::run() { void OS_OSX::run() {
force_quit = false; force_quit = false;

View File

@ -188,6 +188,9 @@ def configure(env):
else: else:
VC_PATH = "" VC_PATH = ""
if (env["openmp"]):
env.Append(CPPFLAGS=['/openmp'])
env.Append(CCFLAGS=["/I" + p for p in os.getenv("INCLUDE").split(";")]) env.Append(CCFLAGS=["/I" + p for p in os.getenv("INCLUDE").split(";")])
env.Append(LIBPATH=[p for p in os.getenv("LIB").split(";")]) env.Append(LIBPATH=[p for p in os.getenv("LIB").split(";")])
@ -264,6 +267,10 @@ def configure(env):
env.Append(CCFLAGS=['-flto']) env.Append(CCFLAGS=['-flto'])
env.Append(LINKFLAGS=['-flto=' + str(env.GetOption("num_jobs"))]) env.Append(LINKFLAGS=['-flto=' + str(env.GetOption("num_jobs"))])
if (env["openmp"]):
env.Append(CPPFLAGS=['-fopenmp'])
env.Append(LIBS=['gomp'])
## Compile flags ## Compile flags
env.Append(CCFLAGS=['-DWINDOWS_ENABLED', '-mwindows']) env.Append(CCFLAGS=['-DWINDOWS_ENABLED', '-mwindows'])

View File

@ -2156,6 +2156,10 @@ void OS_Windows::swap_buffers() {
gl_context->swap_buffers(); gl_context->swap_buffers();
} }
void OS_Windows::force_process_input() {
process_events(); // get rid of pending events
}
void OS_Windows::run() { void OS_Windows::run() {
if (!main_loop) if (!main_loop)

View File

@ -287,6 +287,8 @@ public:
void disable_crash_handler(); void disable_crash_handler();
bool is_disable_crash_handler() const; bool is_disable_crash_handler() const;
void force_process_input();
virtual Error move_to_trash(const String &p_path); virtual Error move_to_trash(const String &p_path);
OS_Windows(HINSTANCE _hInstance); OS_Windows(HINSTANCE _hInstance);

View File

@ -158,6 +158,7 @@ def configure(env):
if not env['builtin_libwebp']: if not env['builtin_libwebp']:
env.ParseConfig('pkg-config libwebp --cflags --libs') env.ParseConfig('pkg-config libwebp --cflags --libs')
# freetype depends on libpng and zlib, so bundling one of them while keeping others # freetype depends on libpng and zlib, so bundling one of them while keeping others
# as shared libraries leads to weird issues # as shared libraries leads to weird issues
if env['builtin_freetype'] or env['builtin_libpng'] or env['builtin_zlib']: if env['builtin_freetype'] or env['builtin_libpng'] or env['builtin_zlib']:
@ -263,5 +264,10 @@ def configure(env):
env.Append(CPPFLAGS=['-m64']) env.Append(CPPFLAGS=['-m64'])
env.Append(LINKFLAGS=['-m64', '-L/usr/lib/i686-linux-gnu']) env.Append(LINKFLAGS=['-m64', '-L/usr/lib/i686-linux-gnu'])
if (env["openmp"]):
env.Append(CPPFLAGS=['-fopenmp'])
env.Append(LIBS=['gomp'])
if env['use_static_cpp']: if env['use_static_cpp']:
env.Append(LINKFLAGS=['-static-libstdc++']) env.Append(LINKFLAGS=['-static-libstdc++'])

View File

@ -2264,6 +2264,13 @@ void OS_X11::set_icon(const Ref<Image> &p_icon) {
XFlush(x11_display); XFlush(x11_display);
} }
void OS_X11::force_process_input() {
process_xevents(); // get rid of pending events
#ifdef JOYDEV_ENABLED
joypad->process_joypads();
#endif
}
void OS_X11::run() { void OS_X11::run() {
force_quit = false; force_quit = false;

View File

@ -279,6 +279,7 @@ public:
virtual bool _check_internal_feature_support(const String &p_feature); virtual bool _check_internal_feature_support(const String &p_feature);
virtual void force_process_input();
void run(); void run();
void disable_crash_handler(); void disable_crash_handler();

717
scene/3d/baked_lightmap.cpp Normal file
View File

@ -0,0 +1,717 @@
#include "baked_lightmap.h"
#include "io/resource_saver.h"
#include "os/dir_access.h"
#include "os/os.h"
#include "voxel_light_baker.h"
void BakedLightmapData::set_bounds(const AABB &p_bounds) {
bounds = p_bounds;
VS::get_singleton()->lightmap_capture_set_bounds(baked_light, p_bounds);
}
AABB BakedLightmapData::get_bounds() const {
return bounds;
}
void BakedLightmapData::set_octree(const PoolVector<uint8_t> &p_octree) {
VS::get_singleton()->lightmap_capture_set_octree(baked_light, p_octree);
}
PoolVector<uint8_t> BakedLightmapData::get_octree() const {
return VS::get_singleton()->lightmap_capture_get_octree(baked_light);
}
void BakedLightmapData::set_cell_space_transform(const Transform &p_xform) {
cell_space_xform = p_xform;
VS::get_singleton()->lightmap_capture_set_octree_cell_transform(baked_light, p_xform);
}
Transform BakedLightmapData::get_cell_space_transform() const {
return cell_space_xform;
}
void BakedLightmapData::set_cell_subdiv(int p_cell_subdiv) {
cell_subdiv = p_cell_subdiv;
VS::get_singleton()->lightmap_capture_set_octree_cell_subdiv(baked_light, p_cell_subdiv);
}
int BakedLightmapData::get_cell_subdiv() const {
return cell_subdiv;
}
void BakedLightmapData::set_energy(float p_energy) {
energy = p_energy;
VS::get_singleton()->lightmap_capture_set_energy(baked_light, energy);
}
float BakedLightmapData::get_energy() const {
return energy;
}
void BakedLightmapData::add_user(const NodePath &p_path, const Ref<Texture> &p_lightmap) {
ERR_FAIL_COND(p_lightmap.is_null());
User user;
user.path = p_path;
user.lightmap = p_lightmap;
users.push_back(user);
}
int BakedLightmapData::get_user_count() const {
return users.size();
}
NodePath BakedLightmapData::get_user_path(int p_user) const {
ERR_FAIL_INDEX_V(p_user, users.size(), NodePath());
return users[p_user].path;
}
Ref<Texture> BakedLightmapData::get_user_lightmap(int p_user) const {
ERR_FAIL_INDEX_V(p_user, users.size(), Ref<Texture>());
return users[p_user].lightmap;
}
void BakedLightmapData::clear_users() {
users.clear();
}
void BakedLightmapData::_set_user_data(const Array &p_data) {
ERR_FAIL_COND(p_data.size() & 1);
for (int i = 0; i < p_data.size(); i += 2) {
add_user(p_data[i], p_data[i + 1]);
}
}
Array BakedLightmapData::_get_user_data() const {
Array ret;
for (int i = 0; i < users.size(); i++) {
ret.push_back(users[i].path);
ret.push_back(users[i].lightmap);
}
return ret;
}
RID BakedLightmapData::get_rid() const {
return baked_light;
}
void BakedLightmapData::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_user_data", "data"), &BakedLightmapData::_set_user_data);
ClassDB::bind_method(D_METHOD("_get_user_data"), &BakedLightmapData::_get_user_data);
ClassDB::bind_method(D_METHOD("set_bounds", "bounds"), &BakedLightmapData::set_bounds);
ClassDB::bind_method(D_METHOD("get_bounds"), &BakedLightmapData::get_bounds);
ClassDB::bind_method(D_METHOD("set_cell_space_transform", "xform"), &BakedLightmapData::set_cell_space_transform);
ClassDB::bind_method(D_METHOD("get_cell_space_transform"), &BakedLightmapData::get_cell_space_transform);
ClassDB::bind_method(D_METHOD("set_cell_subdiv", "cell_subdiv"), &BakedLightmapData::set_cell_subdiv);
ClassDB::bind_method(D_METHOD("get_cell_subdiv"), &BakedLightmapData::get_cell_subdiv);
ClassDB::bind_method(D_METHOD("set_octree", "octree"), &BakedLightmapData::set_octree);
ClassDB::bind_method(D_METHOD("get_octree"), &BakedLightmapData::get_octree);
ClassDB::bind_method(D_METHOD("set_energy", "energy"), &BakedLightmapData::set_energy);
ClassDB::bind_method(D_METHOD("get_energy"), &BakedLightmapData::get_energy);
ClassDB::bind_method(D_METHOD("add_user", "path", "lightmap"), &BakedLightmapData::add_user);
ClassDB::bind_method(D_METHOD("get_user_count"), &BakedLightmapData::get_user_count);
ClassDB::bind_method(D_METHOD("get_user_path", "user_idx"), &BakedLightmapData::get_user_path);
ClassDB::bind_method(D_METHOD("get_user_lightmap", "user_idx"), &BakedLightmapData::get_user_lightmap);
ClassDB::bind_method(D_METHOD("clear_users"), &BakedLightmapData::clear_users);
ADD_PROPERTY(PropertyInfo(Variant::AABB, "bounds", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_bounds", "get_bounds");
ADD_PROPERTY(PropertyInfo(Variant::POOL_BYTE_ARRAY, "octree", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_octree", "get_octree");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "cell_space_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_cell_space_transform", "get_cell_space_transform");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_subdiv", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_cell_subdiv", "get_cell_subdiv");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_energy", "get_energy");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "user_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_user_data", "_get_user_data");
}
BakedLightmapData::BakedLightmapData() {
baked_light = VS::get_singleton()->lightmap_capture_create();
energy = 1;
cell_subdiv = 1;
}
BakedLightmapData::~BakedLightmapData() {
VS::get_singleton()->free(baked_light);
}
///////////////////////////
BakedLightmap::BakeBeginFunc BakedLightmap::bake_begin_function = NULL;
BakedLightmap::BakeStepFunc BakedLightmap::bake_step_function = NULL;
BakedLightmap::BakeEndFunc BakedLightmap::bake_end_function = NULL;
void BakedLightmap::set_bake_subdiv(Subdiv p_subdiv) {
bake_subdiv = p_subdiv;
}
BakedLightmap::Subdiv BakedLightmap::get_bake_subdiv() const {
return bake_subdiv;
}
void BakedLightmap::set_capture_subdiv(Subdiv p_subdiv) {
capture_subdiv = p_subdiv;
}
BakedLightmap::Subdiv BakedLightmap::get_capture_subdiv() const {
return capture_subdiv;
}
void BakedLightmap::set_extents(const Vector3 &p_extents) {
extents = p_extents;
}
Vector3 BakedLightmap::get_extents() const {
return extents;
}
void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, List<PlotMesh> &plot_meshes, List<PlotLight> &plot_lights) {
MeshInstance *mi = Object::cast_to<MeshInstance>(p_at_node);
if (mi && mi->get_flag(GeometryInstance::FLAG_USE_BAKED_LIGHT) && mi->is_visible_in_tree()) {
Ref<Mesh> mesh = mi->get_mesh();
if (mesh.is_valid()) {
bool all_have_uv2 = true;
for (int i = 0; i < mesh->get_surface_count(); i++) {
if (!(mesh->surface_get_format(i) & Mesh::ARRAY_FORMAT_TEX_UV2)) {
all_have_uv2 = false;
break;
}
}
if (all_have_uv2 && mesh->get_lightmap_size_hint() != Size2()) {
//READY TO BAKE! size hint could be computed if not found, actually..
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))) {
PlotMesh pm;
pm.local_xform = xf;
pm.mesh = mesh;
pm.path = get_path_to(mi);
for (int i = 0; i < mesh->get_surface_count(); i++) {
pm.instance_materials.push_back(mi->get_surface_material(i));
}
pm.override_material = mi->get_material_override();
plot_meshes.push_back(pm);
}
}
}
}
Light *light = Object::cast_to<Light>(p_at_node);
if (light && light->get_bake_mode() != Light::BAKE_DISABLED) {
PlotLight pl;
Transform xf = get_global_transform().affine_inverse() * light->get_global_transform();
pl.local_xform = xf;
pl.light = light;
plot_lights.push_back(pl);
}
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_and_lights(child, plot_meshes, plot_lights);
}
}
void BakedLightmap::set_hdr(bool p_enable) {
hdr = p_enable;
}
bool BakedLightmap::is_hdr() const {
return hdr;
}
bool BakedLightmap::_bake_time(void *ud, float p_secs, float p_progress) {
uint64_t time = OS::get_singleton()->get_ticks_usec();
BakeTimeData *btd = (BakeTimeData *)ud;
if (time - btd->last_step > 1000000) {
int mins_left = p_secs / 60;
int secs_left = Math::fmod(p_secs, 60.0);
int percent = p_progress * 100;
bool abort = bake_step_function(btd->pass + percent, btd->text + " " + itos(percent) + "% (Time Left: " + itos(mins_left) + ":" + itos(secs_left) + "s)");
btd->last_step = time;
if (abort)
return true;
}
return false;
}
BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_visual_debug) {
String save_path;
if (image_path.begins_with("res://")) {
save_path = image_path;
} else {
if (get_filename() != "") {
save_path = get_filename().get_base_dir();
} else if (get_owner() && get_owner()->get_filename() != "") {
save_path = get_owner()->get_filename().get_base_dir();
}
if (save_path == "") {
return BAKE_ERROR_NO_SAVE_PATH;
}
if (image_path != "") {
save_path.plus_file(image_path);
}
}
{
//check for valid save path
DirAccessRef d = DirAccess::open(save_path);
if (!d) {
ERR_PRINTS("Invalid Save Path: " + save_path);
return BAKE_ERROR_NO_SAVE_PATH;
}
}
Ref<BakedLightmapData> new_light_data;
new_light_data.instance();
static const int subdiv_value[SUBDIV_MAX] = { 8, 9, 10, 11, 12, 13 };
VoxelLightBaker baker;
baker.begin_bake(subdiv_value[bake_subdiv], AABB(-extents, extents * 2.0));
List<PlotMesh> mesh_list;
List<PlotLight> light_list;
_find_meshes_and_lights(p_from_node ? p_from_node : get_parent(), mesh_list, light_list);
if (bake_begin_function) {
bake_begin_function(mesh_list.size() + light_list.size() + 1 + mesh_list.size() * 100);
}
int step = 0;
int pmc = 0;
for (List<PlotMesh>::Element *E = mesh_list.front(); E; E = E->next()) {
if (bake_step_function) {
bake_step_function(step++, RTR("Plotting Meshes: ") + " (" + itos(pmc + 1) + "/" + itos(mesh_list.size()) + ")");
}
pmc++;
baker.plot_mesh(E->get().local_xform, E->get().mesh, E->get().instance_materials, E->get().override_material);
}
pmc = 0;
baker.begin_bake_light(VoxelLightBaker::BakeQuality(bake_quality), VoxelLightBaker::BakeMode(bake_mode), propagation, energy);
for (List<PlotLight>::Element *E = light_list.front(); E; E = E->next()) {
if (bake_step_function) {
bake_step_function(step++, RTR("Plotting Lights:") + " (" + itos(pmc + 1) + "/" + itos(light_list.size()) + ")");
}
pmc++;
PlotLight pl = E->get();
switch (pl.light->get_light_type()) {
case VS::LIGHT_DIRECTIONAL: {
baker.plot_light_directional(-pl.local_xform.basis.get_axis(2), pl.light->get_color(), pl.light->get_param(Light::PARAM_ENERGY), pl.light->get_param(Light::PARAM_INDIRECT_ENERGY), pl.light->get_bake_mode() == Light::BAKE_ALL);
} break;
case VS::LIGHT_OMNI: {
baker.plot_light_omni(pl.local_xform.origin, pl.light->get_color(), pl.light->get_param(Light::PARAM_ENERGY), pl.light->get_param(Light::PARAM_INDIRECT_ENERGY), pl.light->get_param(Light::PARAM_RANGE), pl.light->get_param(Light::PARAM_ATTENUATION), pl.light->get_bake_mode() == Light::BAKE_ALL);
} break;
case VS::LIGHT_SPOT: {
baker.plot_light_spot(pl.local_xform.origin, pl.local_xform.basis.get_axis(2), pl.light->get_color(), pl.light->get_param(Light::PARAM_ENERGY), pl.light->get_param(Light::PARAM_INDIRECT_ENERGY), pl.light->get_param(Light::PARAM_RANGE), pl.light->get_param(Light::PARAM_ATTENUATION), pl.light->get_param(Light::PARAM_SPOT_ANGLE), pl.light->get_param(Light::PARAM_SPOT_ATTENUATION), pl.light->get_bake_mode() == Light::BAKE_ALL);
} break;
}
}
/*if (bake_step_function) {
bake_step_function(pmc++, RTR("Finishing Plot"));
}*/
baker.end_bake();
Set<String> used_mesh_names;
pmc = 0;
for (List<PlotMesh>::Element *E = mesh_list.front(); E; E = E->next()) {
String mesh_name = E->get().mesh->get_name();
if (mesh_name == "" || mesh_name.find(":") != -1 || mesh_name.find("/") != -1) {
mesh_name = "LightMap";
}
if (used_mesh_names.has(mesh_name)) {
int idx = 2;
String base = mesh_name;
while (true) {
mesh_name = base + itos(idx);
if (!used_mesh_names.has(mesh_name))
break;
idx++;
}
}
used_mesh_names.insert(mesh_name);
pmc++;
VoxelLightBaker::LightMapData lm;
Error err;
if (bake_step_function) {
BakeTimeData btd;
btd.text = RTR("Lighting Meshes: ") + mesh_name + " (" + itos(pmc) + "/" + itos(mesh_list.size()) + ")";
btd.pass = step;
btd.last_step = 0;
err = baker.make_lightmap(E->get().local_xform, E->get().mesh, lm, _bake_time, &btd);
if (err != OK) {
bake_end_function();
if (err == ERR_SKIP)
return BAKE_ERROR_USER_ABORTED;
return BAKE_ERROR_CANT_CREATE_IMAGE;
}
step += 100;
} else {
err = baker.make_lightmap(E->get().local_xform, E->get().mesh, lm);
}
if (err == OK) {
Ref<Image> image;
image.instance();
uint32_t tex_flags = Texture::FLAGS_DEFAULT;
if (hdr) {
//just save a regular image
PoolVector<uint8_t> data;
int s = lm.light.size();
data.resize(lm.light.size() * 2);
{
PoolVector<uint8_t>::Write w = data.write();
PoolVector<float>::Read r = lm.light.read();
uint16_t *hfw = (uint16_t *)w.ptr();
for (int i = 0; i < s; i++) {
hfw[i] = Math::make_half_float(r[i]);
}
}
image->create(lm.width, lm.height, false, Image::FORMAT_RGBH, data);
} else {
//just save a regular image
PoolVector<uint8_t> data;
int s = lm.light.size();
data.resize(lm.light.size());
{
PoolVector<uint8_t>::Write w = data.write();
PoolVector<float>::Read r = lm.light.read();
for (int i = 0; i < s; i += 3) {
Color c(r[i + 0], r[i + 1], r[i + 2]);
c = c.to_srgb();
w[i + 0] = CLAMP(c.r * 255, 0, 255);
w[i + 1] = CLAMP(c.g * 255, 0, 255);
w[i + 2] = CLAMP(c.b * 255, 0, 255);
}
}
image->create(lm.width, lm.height, false, Image::FORMAT_RGB8, data);
//This texture is saved to SRGB for two reasons:
// 1) first is so it looks better when doing the LINEAR->SRGB conversion (more accurate)
// 2) So it can be used in the GLES2 backend, which does not support linkear workflow
tex_flags |= Texture::FLAG_CONVERT_TO_LINEAR;
}
Ref<ImageTexture> tex;
String image_path = save_path.plus_file(mesh_name + ".tex");
bool set_path = true;
if (ResourceCache::has(image_path)) {
tex = Ref<Resource>((Resource *)ResourceCache::get(image_path));
set_path = false;
}
if (!tex.is_valid()) {
tex.instance();
}
tex->create_from_image(image, tex_flags);
err = ResourceSaver::save(image_path, tex, ResourceSaver::FLAG_CHANGE_PATH);
if (err != OK) {
if (bake_end_function) {
bake_end_function();
}
ERR_FAIL_COND_V(err != OK, BAKE_ERROR_CANT_CREATE_IMAGE);
}
if (set_path) {
tex->set_path(image_path);
}
new_light_data->add_user(E->get().path, tex);
}
}
int csubdiv = subdiv_value[capture_subdiv];
AABB bounds = AABB(-extents, extents * 2);
new_light_data->set_cell_subdiv(csubdiv);
new_light_data->set_bounds(bounds);
new_light_data->set_octree(baker.create_capture_octree(csubdiv));
{
Transform to_bounds;
to_bounds.basis.scale(Vector3(bounds.get_longest_axis_size(), bounds.get_longest_axis_size(), bounds.get_longest_axis_size()));
to_bounds.origin = bounds.position;
Transform to_grid;
to_grid.basis.scale(Vector3(1 << (csubdiv - 1), 1 << (csubdiv - 1), 1 << (csubdiv - 1)));
Transform to_cell_space = to_grid * to_bounds.affine_inverse();
new_light_data->set_cell_space_transform(to_cell_space);
}
if (bake_end_function) {
bake_end_function();
}
//create the data for visual server
if (p_create_visual_debug) {
MultiMeshInstance *mmi = memnew(MultiMeshInstance);
mmi->set_multimesh(baker.create_debug_multimesh(VoxelLightBaker::DEBUG_LIGHT));
add_child(mmi);
#ifdef TOOLS_ENABLED
if (get_tree()->get_edited_scene_root() == this) {
mmi->set_owner(this);
} else {
mmi->set_owner(get_owner());
}
#else
mmi->set_owner(get_owner());
#endif
}
set_light_data(new_light_data);
return BAKE_ERROR_OK;
}
void BakedLightmap::_notification(int p_what) {
if (p_what == NOTIFICATION_READY) {
if (light_data.is_valid()) {
_assign_lightmaps();
}
request_ready(); //will need ready again if re-enters tree
}
if (p_what == NOTIFICATION_EXIT_TREE) {
if (light_data.is_valid()) {
_clear_lightmaps();
}
}
}
void BakedLightmap::_assign_lightmaps() {
ERR_FAIL_COND(!light_data.is_valid());
for (int i = 0; i < light_data->get_user_count(); i++) {
Node *node = get_node(light_data->get_user_path(i));
VisualInstance *vi = Object::cast_to<VisualInstance>(node);
ERR_CONTINUE(!vi);
Ref<Texture> lightmap = light_data->get_user_lightmap(i);
ERR_CONTINUE(!lightmap.is_valid());
VS::get_singleton()->instance_set_use_lightmap(vi->get_instance(), get_instance(), lightmap->get_rid());
}
}
void BakedLightmap::_clear_lightmaps() {
ERR_FAIL_COND(!light_data.is_valid());
for (int i = 0; i < light_data->get_user_count(); i++) {
Node *node = get_node(light_data->get_user_path(i));
VisualInstance *vi = Object::cast_to<VisualInstance>(node);
ERR_CONTINUE(!vi);
VS::get_singleton()->instance_set_use_lightmap(vi->get_instance(), RID(), RID());
}
}
void BakedLightmap::set_light_data(const Ref<BakedLightmapData> &p_data) {
if (light_data.is_valid()) {
if (is_inside_tree()) {
_clear_lightmaps();
}
set_base(RID());
}
light_data = p_data;
if (light_data.is_valid()) {
set_base(light_data->get_rid());
if (is_inside_tree()) {
_assign_lightmaps();
}
}
}
Ref<BakedLightmapData> BakedLightmap::get_light_data() const {
return light_data;
}
void BakedLightmap::_debug_bake() {
bake(get_parent(), true);
}
void BakedLightmap::set_propagation(float p_propagation) {
propagation = p_propagation;
}
float BakedLightmap::get_propagation() const {
return propagation;
}
void BakedLightmap::set_energy(float p_energy) {
energy = p_energy;
}
float BakedLightmap::get_energy() const {
return energy;
}
void BakedLightmap::set_bake_quality(BakeQuality p_quality) {
bake_quality = p_quality;
}
BakedLightmap::BakeQuality BakedLightmap::get_bake_quality() const {
return bake_quality;
}
void BakedLightmap::set_bake_mode(BakeMode p_mode) {
bake_mode = p_mode;
}
BakedLightmap::BakeMode BakedLightmap::get_bake_mode() const {
return bake_mode;
}
void BakedLightmap::set_image_path(const String &p_path) {
image_path = p_path;
}
String BakedLightmap::get_image_path() const {
return image_path;
}
AABB BakedLightmap::get_aabb() const {
return AABB(-extents, extents * 2);
}
PoolVector<Face3> BakedLightmap::get_faces(uint32_t p_usage_flags) const {
return PoolVector<Face3>();
}
void BakedLightmap::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_light_data", "data"), &BakedLightmap::set_light_data);
ClassDB::bind_method(D_METHOD("get_light_data"), &BakedLightmap::get_light_data);
ClassDB::bind_method(D_METHOD("set_bake_subdiv", "bake_subdiv"), &BakedLightmap::set_bake_subdiv);
ClassDB::bind_method(D_METHOD("get_bake_subdiv"), &BakedLightmap::get_bake_subdiv);
ClassDB::bind_method(D_METHOD("set_capture_subdiv", "capture_subdiv"), &BakedLightmap::set_capture_subdiv);
ClassDB::bind_method(D_METHOD("get_capture_subdiv"), &BakedLightmap::get_capture_subdiv);
ClassDB::bind_method(D_METHOD("set_bake_quality", "bake_quality"), &BakedLightmap::set_bake_quality);
ClassDB::bind_method(D_METHOD("get_bake_quality"), &BakedLightmap::get_bake_quality);
ClassDB::bind_method(D_METHOD("set_bake_mode", "bake_mode"), &BakedLightmap::set_bake_mode);
ClassDB::bind_method(D_METHOD("get_bake_mode"), &BakedLightmap::get_bake_mode);
ClassDB::bind_method(D_METHOD("set_extents", "extents"), &BakedLightmap::set_extents);
ClassDB::bind_method(D_METHOD("get_extents"), &BakedLightmap::get_extents);
ClassDB::bind_method(D_METHOD("set_propagation", "propagation"), &BakedLightmap::set_propagation);
ClassDB::bind_method(D_METHOD("get_propagation"), &BakedLightmap::get_propagation);
ClassDB::bind_method(D_METHOD("set_energy", "energy"), &BakedLightmap::set_energy);
ClassDB::bind_method(D_METHOD("get_energy"), &BakedLightmap::get_energy);
ClassDB::bind_method(D_METHOD("set_hdr", "hdr"), &BakedLightmap::set_hdr);
ClassDB::bind_method(D_METHOD("is_hdr"), &BakedLightmap::is_hdr);
ClassDB::bind_method(D_METHOD("set_image_path", "image_path"), &BakedLightmap::set_image_path);
ClassDB::bind_method(D_METHOD("get_image_path"), &BakedLightmap::get_image_path);
ClassDB::bind_method(D_METHOD("bake", "from_node", "create_visual_debug"), &BakedLightmap::bake, DEFVAL(Variant()), DEFVAL(false));
ClassDB::bind_method(D_METHOD("debug_bake"), &BakedLightmap::_debug_bake);
ClassDB::set_method_flags(get_class_static(), _scs_create("debug_bake"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_subdiv", PROPERTY_HINT_ENUM, "128,256,512,1024,2048,4096"), "set_bake_subdiv", "get_bake_subdiv");
ADD_PROPERTY(PropertyInfo(Variant::INT, "capture_subdiv", PROPERTY_HINT_ENUM, "128,256,512"), "set_capture_subdiv", "get_capture_subdiv");
ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_quality", PROPERTY_HINT_ENUM, "Low,Medium,High"), "set_bake_quality", "get_bake_quality");
ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_mode", PROPERTY_HINT_ENUM, "ConeTrace,RayTrace"), "set_bake_mode", "get_bake_mode");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "propagation", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_propagation", "get_propagation");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_RANGE, "0,32,0.01"), "set_energy", "get_energy");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hdr"), "set_hdr", "is_hdr");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "image_path", PROPERTY_HINT_DIR), "set_image_path", "get_image_path");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents"), "set_extents", "get_extents");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_data", PROPERTY_HINT_RESOURCE_TYPE, "BakedIndirectLightData"), "set_light_data", "get_light_data");
BIND_ENUM_CONSTANT(SUBDIV_128);
BIND_ENUM_CONSTANT(SUBDIV_256);
BIND_ENUM_CONSTANT(SUBDIV_512);
BIND_ENUM_CONSTANT(SUBDIV_1024);
BIND_ENUM_CONSTANT(SUBDIV_2048);
BIND_ENUM_CONSTANT(SUBDIV_4096);
BIND_ENUM_CONSTANT(SUBDIV_MAX);
BIND_ENUM_CONSTANT(BAKE_QUALITY_LOW);
BIND_ENUM_CONSTANT(BAKE_QUALITY_MEDIUM);
BIND_ENUM_CONSTANT(BAKE_QUALITY_HIGH);
BIND_ENUM_CONSTANT(BAKE_MODE_CONE_TRACE);
BIND_ENUM_CONSTANT(BAKE_MODE_RAY_TRACE);
}
BakedLightmap::BakedLightmap() {
extents = Vector3(10, 10, 10);
bake_subdiv = SUBDIV_256;
capture_subdiv = SUBDIV_128;
bake_quality = BAKE_QUALITY_MEDIUM;
bake_mode = BAKE_MODE_CONE_TRACE;
energy = 1;
propagation = 1;
hdr = false;
image_path = ".";
}

189
scene/3d/baked_lightmap.h Normal file
View File

@ -0,0 +1,189 @@
#ifndef BAKED_INDIRECT_LIGHT_H
#define BAKED_INDIRECT_LIGHT_H
#include "multimesh_instance.h"
#include "scene/3d/light.h"
#include "scene/3d/visual_instance.h"
class BakedLightmapData : public Resource {
GDCLASS(BakedLightmapData, Resource);
RID baked_light;
AABB bounds;
float energy;
int cell_subdiv;
Transform cell_space_xform;
struct User {
NodePath path;
Ref<Texture> lightmap;
};
Vector<User> users;
void _set_user_data(const Array &p_data);
Array _get_user_data() const;
protected:
static void _bind_methods();
public:
void set_bounds(const AABB &p_bounds);
AABB get_bounds() const;
void set_octree(const PoolVector<uint8_t> &p_octree);
PoolVector<uint8_t> get_octree() const;
void set_cell_space_transform(const Transform &p_xform);
Transform get_cell_space_transform() const;
void set_cell_subdiv(int p_cell_subdiv);
int get_cell_subdiv() const;
void set_energy(float p_energy);
float get_energy() const;
void add_user(const NodePath &p_path, const Ref<Texture> &p_lightmap);
int get_user_count() const;
NodePath get_user_path(int p_user) const;
Ref<Texture> get_user_lightmap(int p_user) const;
void clear_users();
virtual RID get_rid() const;
BakedLightmapData();
~BakedLightmapData();
};
class BakedLightmap : public VisualInstance {
GDCLASS(BakedLightmap, VisualInstance);
public:
enum Subdiv {
SUBDIV_128,
SUBDIV_256,
SUBDIV_512,
SUBDIV_1024,
SUBDIV_2048,
SUBDIV_4096,
SUBDIV_MAX
};
enum BakeQuality {
BAKE_QUALITY_LOW,
BAKE_QUALITY_MEDIUM,
BAKE_QUALITY_HIGH
};
enum BakeMode {
BAKE_MODE_CONE_TRACE,
BAKE_MODE_RAY_TRACE,
};
enum BakeError {
BAKE_ERROR_OK,
BAKE_ERROR_NO_SAVE_PATH,
BAKE_ERROR_NO_MESHES,
BAKE_ERROR_CANT_CREATE_IMAGE,
BAKE_ERROR_USER_ABORTED
};
typedef void (*BakeBeginFunc)(int);
typedef bool (*BakeStepFunc)(int, const String &);
typedef void (*BakeEndFunc)();
private:
Subdiv bake_subdiv;
Subdiv capture_subdiv;
Vector3 extents;
float propagation;
float energy;
BakeQuality bake_quality;
BakeMode bake_mode;
bool hdr;
String image_path;
Ref<BakedLightmapData> light_data;
struct PlotMesh {
Ref<Material> override_material;
Vector<Ref<Material> > instance_materials;
Ref<Mesh> mesh;
Transform local_xform;
NodePath path;
};
struct PlotLight {
Light *light;
Transform local_xform;
};
void _find_meshes_and_lights(Node *p_at_node, List<PlotMesh> &plot_meshes, List<PlotLight> &plot_lights);
void _debug_bake();
void _assign_lightmaps();
void _clear_lightmaps();
static bool _bake_time(void *ud, float p_secs, float p_progress);
struct BakeTimeData {
String text;
int pass;
uint64_t last_step;
};
protected:
static void _bind_methods();
void _notification(int p_what);
public:
static BakeBeginFunc bake_begin_function;
static BakeStepFunc bake_step_function;
static BakeEndFunc bake_end_function;
void set_light_data(const Ref<BakedLightmapData> &p_data);
Ref<BakedLightmapData> get_light_data() const;
void set_bake_subdiv(Subdiv p_subdiv);
Subdiv get_bake_subdiv() const;
void set_capture_subdiv(Subdiv p_subdiv);
Subdiv get_capture_subdiv() const;
void set_extents(const Vector3 &p_extents);
Vector3 get_extents() const;
void set_propagation(float p_propagation);
float get_propagation() const;
void set_energy(float p_energy);
float get_energy() const;
void set_bake_quality(BakeQuality p_quality);
BakeQuality get_bake_quality() const;
void set_bake_mode(BakeMode p_mode);
BakeMode get_bake_mode() const;
void set_hdr(bool p_enable);
bool is_hdr() const;
void set_image_path(const String &p_path);
String get_image_path() const;
AABB get_aabb() const;
PoolVector<Face3> get_faces(uint32_t p_usage_flags) const;
BakeError bake(Node *p_from_node, bool p_create_visual_debug = false);
BakedLightmap();
};
VARIANT_ENUM_CAST(BakedLightmap::Subdiv);
VARIANT_ENUM_CAST(BakedLightmap::BakeQuality);
VARIANT_ENUM_CAST(BakedLightmap::BakeMode);
VARIANT_ENUM_CAST(BakedLightmap::BakeError);
#endif // BAKED_INDIRECT_LIGHT_H

File diff suppressed because it is too large Load Diff

View File

@ -100,67 +100,6 @@ public:
typedef void (*BakeEndFunc)(); typedef void (*BakeEndFunc)();
private: 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)
float normal[3];
uint32_t used_sides;
float alpha; //used for upsampling
int level;
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;
normal[i] = 0;
}
alpha = 0;
used_sides = 0;
level = 0;
}
};
Vector<Cell> bake_cells;
int cell_subdiv;
struct MaterialCache {
//128x128 textures
Vector<Color> albedo;
Vector<Color> emission;
};
Vector<Color> _get_bake_texture(Ref<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<Material> override_material;
Vector<Ref<Material> > instance_materials;
Ref<Mesh> mesh;
Transform local_xform;
};
Transform to_cell_space;
List<PlotMesh> mesh_list;
};
Ref<GIProbeData> probe_data; Ref<GIProbeData> probe_data;
RID gi_probe; RID gi_probe;
@ -175,19 +114,14 @@ private:
bool interior; bool interior;
bool compress; bool compress;
int color_scan_cell_width; struct PlotMesh {
int bake_texture_size; Ref<Material> override_material;
Vector<Ref<Material> > instance_materials;
Vector<Color> _get_bake_texture(Ref<Image> p_image, const Color &p_color_mul, const Color &p_color_add); Ref<Mesh> mesh;
Baker::MaterialCache _get_material_cache(Ref<Material> p_material, Baker *p_baker); Transform local_xform;
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, const Vector<Ref<Material> > &p_materials, const Ref<Material> &p_override_material);
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 _find_meshes(Node *p_at_node, List<PlotMesh> &plot_meshes);
void _debug_bake(); void _debug_bake();
protected: protected:

View File

@ -142,6 +142,14 @@ PoolVector<Face3> Light::get_faces(uint32_t p_usage_flags) const {
return PoolVector<Face3>(); return PoolVector<Face3>();
} }
void Light::set_bake_mode(BakeMode p_mode) {
bake_mode = p_mode;
}
Light::BakeMode Light::get_bake_mode() const {
return bake_mode;
}
void Light::_update_visibility() { void Light::_update_visibility() {
if (!is_inside_tree()) if (!is_inside_tree())
@ -219,12 +227,16 @@ void Light::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_shadow_color", "shadow_color"), &Light::set_shadow_color); ClassDB::bind_method(D_METHOD("set_shadow_color", "shadow_color"), &Light::set_shadow_color);
ClassDB::bind_method(D_METHOD("get_shadow_color"), &Light::get_shadow_color); ClassDB::bind_method(D_METHOD("get_shadow_color"), &Light::get_shadow_color);
ClassDB::bind_method(D_METHOD("set_bake_mode", "bake_mode"), &Light::set_bake_mode);
ClassDB::bind_method(D_METHOD("get_bake_mode"), &Light::get_bake_mode);
ADD_GROUP("Light", "light_"); ADD_GROUP("Light", "light_");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "light_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_color", "get_color"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "light_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_color", "get_color");
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "light_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_ENERGY); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "light_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_ENERGY);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "light_indirect_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_INDIRECT_ENERGY); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "light_indirect_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_INDIRECT_ENERGY);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "light_negative"), "set_negative", "is_negative"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "light_negative"), "set_negative", "is_negative");
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "light_specular", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SPECULAR); ADD_PROPERTYI(PropertyInfo(Variant::REAL, "light_specular", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SPECULAR);
ADD_PROPERTY(PropertyInfo(Variant::INT, "light_bake_mode", PROPERTY_HINT_ENUM, "Disable,Indirect,All"), "set_bake_mode", "get_bake_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "light_cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask"); ADD_PROPERTY(PropertyInfo(Variant::INT, "light_cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask");
ADD_GROUP("Shadow", "shadow_"); ADD_GROUP("Shadow", "shadow_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_enabled"), "set_shadow", "has_shadow"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_enabled"), "set_shadow", "has_shadow");
@ -252,6 +264,10 @@ void Light::_bind_methods() {
BIND_ENUM_CONSTANT(PARAM_SHADOW_BIAS); BIND_ENUM_CONSTANT(PARAM_SHADOW_BIAS);
BIND_ENUM_CONSTANT(PARAM_SHADOW_BIAS_SPLIT_SCALE); BIND_ENUM_CONSTANT(PARAM_SHADOW_BIAS_SPLIT_SCALE);
BIND_ENUM_CONSTANT(PARAM_MAX); BIND_ENUM_CONSTANT(PARAM_MAX);
BIND_ENUM_CONSTANT(BAKE_DISABLED);
BIND_ENUM_CONSTANT(BAKE_INDIRECT);
BIND_ENUM_CONSTANT(BAKE_ALL);
} }
Light::Light(VisualServer::LightType p_type) { Light::Light(VisualServer::LightType p_type) {
@ -267,6 +283,7 @@ Light::Light(VisualServer::LightType p_type) {
VS::get_singleton()->instance_set_base(get_instance(), light); VS::get_singleton()->instance_set_base(get_instance(), light);
reverse_cull = false; reverse_cull = false;
bake_mode = BAKE_INDIRECT;
editor_only = false; editor_only = false;
set_color(Color(1, 1, 1, 1)); set_color(Color(1, 1, 1, 1));

View File

@ -63,6 +63,12 @@ public:
PARAM_MAX = VS::LIGHT_PARAM_MAX PARAM_MAX = VS::LIGHT_PARAM_MAX
}; };
enum BakeMode {
BAKE_DISABLED,
BAKE_INDIRECT,
BAKE_ALL
};
private: private:
Color color; Color color;
float param[PARAM_MAX]; float param[PARAM_MAX];
@ -74,6 +80,7 @@ private:
VS::LightType type; VS::LightType type;
bool editor_only; bool editor_only;
void _update_visibility(); void _update_visibility();
BakeMode bake_mode;
// bind helpers // bind helpers
@ -114,6 +121,9 @@ public:
void set_shadow_reverse_cull_face(bool p_enable); void set_shadow_reverse_cull_face(bool p_enable);
bool get_shadow_reverse_cull_face() const; bool get_shadow_reverse_cull_face() const;
void set_bake_mode(BakeMode p_mode);
BakeMode get_bake_mode() const;
virtual AABB get_aabb() const; virtual AABB get_aabb() const;
virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const; virtual PoolVector<Face3> get_faces(uint32_t p_usage_flags) const;
@ -122,6 +132,7 @@ public:
}; };
VARIANT_ENUM_CAST(Light::Param); VARIANT_ENUM_CAST(Light::Param);
VARIANT_ENUM_CAST(Light::BakeMode);
class DirectionalLight : public Light { class DirectionalLight : public Light {

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,148 @@
#ifndef VOXEL_LIGHT_BAKER_H
#define VOXEL_LIGHT_BAKER_H
#include "scene/3d/mesh_instance.h"
#include "scene/resources/multimesh.h"
class VoxelLightBaker {
public:
enum DebugMode {
DEBUG_ALBEDO,
DEBUG_LIGHT
};
enum BakeQuality {
BAKE_QUALITY_LOW,
BAKE_QUALITY_MEDIUM,
BAKE_QUALITY_HIGH
};
enum BakeMode {
BAKE_MODE_CONE_TRACE,
BAKE_MODE_RAY_TRACE,
};
private:
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)
float normal[3];
uint32_t used_sides;
float alpha; //used for upsampling
int level;
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;
normal[i] = 0;
}
alpha = 0;
used_sides = 0;
level = 0;
}
};
Vector<Cell> bake_cells;
int cell_subdiv;
struct Light {
int x, y, z;
float accum[6][3]; //rgb anisotropic
float direct_accum[6][3]; //for direct bake
int next_leaf;
};
int first_leaf;
Vector<Light> bake_light;
struct MaterialCache {
//128x128 textures
Vector<Color> albedo;
Vector<Color> emission;
};
Map<Ref<Material>, MaterialCache> material_cache;
int leaf_voxel_count;
bool direct_lights_baked;
AABB original_bounds;
AABB po2_bounds;
int axis_cell_size[3];
Transform to_cell_space;
int color_scan_cell_width;
int bake_texture_size;
float cell_size;
float propagation;
float energy;
BakeQuality bake_quality;
BakeMode bake_mode;
int max_original_cells;
void _init_light_plot(int p_idx, int p_level, int p_x, int p_y, int p_z, uint32_t p_parent);
Vector<Color> _get_bake_texture(Ref<Image> p_image, const Color &p_color_mul, const Color &p_color_add);
MaterialCache _get_material_cache(Ref<Material> p_material);
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 MaterialCache &p_material, const AABB &p_aabb);
void _fixup_plot(int p_idx, int p_level);
void _debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<MultiMesh> &p_multimesh, int &idx, DebugMode p_mode);
void _check_init_light();
uint32_t _find_cell_at_pos(const Cell *cells, int x, int y, int z);
struct LightMap {
Vector3 light;
Vector3 pos;
Vector3 normal;
};
void _plot_triangle(Vector2 *vertices, Vector3 *positions, Vector3 *normals, LightMap *pixels, int width, int height);
_FORCE_INLINE_ void _sample_baked_octree_filtered_and_anisotropic(const Vector3 &p_posf, const Vector3 &p_direction, float p_level, Vector3 &r_color, float &r_alpha);
_FORCE_INLINE_ Vector3 _voxel_cone_trace(const Vector3 &p_pos, const Vector3 &p_normal, float p_aperture);
_FORCE_INLINE_ Vector3 _compute_pixel_light_at_pos(const Vector3 &p_pos, const Vector3 &p_normal);
_FORCE_INLINE_ Vector3 _compute_ray_trace_at_pos(const Vector3 &p_pos, const Vector3 &p_normal);
public:
void begin_bake(int p_subdiv, const AABB &p_bounds);
void plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material> > &p_materials, const Ref<Material> &p_override_material);
void begin_bake_light(BakeQuality p_quality = BAKE_QUALITY_MEDIUM, BakeMode p_bake_mode = BAKE_MODE_CONE_TRACE, float p_propagation = 0.85, float p_energy = 1);
void plot_light_directional(const Vector3 &p_direction, const Color &p_color, float p_energy, float p_indirect_energy, bool p_direct);
void plot_light_omni(const Vector3 &p_pos, const Color &p_color, float p_energy, float p_indirect_energy, float p_radius, float p_attenutation, bool p_direct);
void plot_light_spot(const Vector3 &p_pos, const Vector3 &p_axis, const Color &p_color, float p_energy, float p_indirect_energy, float p_radius, float p_attenutation, float p_spot_angle, float p_spot_attenuation, bool p_direct);
void end_bake();
struct LightMapData {
int width;
int height;
PoolVector<float> light;
};
Error make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh, LightMapData &r_lightmap, bool (*p_bake_time_func)(void *, float, float) = NULL, void *p_bake_time_ud = NULL);
PoolVector<int> create_gi_probe_data();
Ref<MultiMesh> create_debug_multimesh(DebugMode p_mode = DEBUG_ALBEDO);
PoolVector<uint8_t> create_capture_octree(int p_subdiv);
float get_cell_size() const;
Transform get_to_cell_space_xform() const;
VoxelLightBaker();
};
#endif // VOXEL_LIGHT_BAKER_H

View File

@ -177,8 +177,8 @@ void Node::_propagate_ready() {
} }
data.blocked--; data.blocked--;
if (data.ready_first) { if (data.ready_first) {
notification(NOTIFICATION_READY);
data.ready_first = false; data.ready_first = false;
notification(NOTIFICATION_READY);
} }
} }

View File

@ -160,6 +160,7 @@
#include "scene/3d/area.h" #include "scene/3d/area.h"
#include "scene/3d/arvr_nodes.h" #include "scene/3d/arvr_nodes.h"
#include "scene/3d/audio_stream_player_3d.h" #include "scene/3d/audio_stream_player_3d.h"
#include "scene/3d/baked_lightmap.h"
#include "scene/3d/bone_attachment.h" #include "scene/3d/bone_attachment.h"
#include "scene/3d/camera.h" #include "scene/3d/camera.h"
#include "scene/3d/collision_polygon.h" #include "scene/3d/collision_polygon.h"
@ -375,6 +376,8 @@ void register_scene_types() {
ClassDB::register_class<ReflectionProbe>(); ClassDB::register_class<ReflectionProbe>();
ClassDB::register_class<GIProbe>(); ClassDB::register_class<GIProbe>();
ClassDB::register_class<GIProbeData>(); ClassDB::register_class<GIProbeData>();
ClassDB::register_class<BakedLightmap>();
ClassDB::register_class<BakedLightmapData>();
ClassDB::register_class<AnimationTreePlayer>(); ClassDB::register_class<AnimationTreePlayer>();
ClassDB::register_class<Particles>(); ClassDB::register_class<Particles>();
ClassDB::register_class<Position3D>(); ClassDB::register_class<Position3D>();

View File

@ -645,7 +645,7 @@ void SpatialMaterial::_update_shader() {
code += "\tvec2 base_uv = UV;\n"; code += "\tvec2 base_uv = UV;\n";
} }
if ((features[FEATURE_DETAIL] && detail_uv == DETAIL_UV_2) || (features[FEATURE_AMBIENT_OCCLUSION] && flags[FLAG_AO_ON_UV2])) { if ((features[FEATURE_DETAIL] && detail_uv == DETAIL_UV_2) || (features[FEATURE_AMBIENT_OCCLUSION] && flags[FLAG_AO_ON_UV2]) || (features[FEATURE_EMISSION] && flags[FLAG_EMISSION_ON_UV2])) {
code += "\tvec2 base_uv2 = UV2;\n"; code += "\tvec2 base_uv2 = UV2;\n";
} }
@ -729,11 +729,20 @@ void SpatialMaterial::_update_shader() {
} }
if (features[FEATURE_EMISSION]) { if (features[FEATURE_EMISSION]) {
if (flags[FLAG_UV1_USE_TRIPLANAR]) { if (flags[FLAG_EMISSION_ON_UV2]) {
code += "\tvec3 emission_tex = triplanar_texture(texture_emission,uv1_power_normal,uv1_triplanar_pos).rgb;\n"; if (flags[FLAG_UV2_USE_TRIPLANAR]) {
code += "\tvec3 emission_tex = triplanar_texture(texture_emission,uv2_power_normal,uv2_triplanar_pos).rgb;\n";
} else {
code += "\tvec3 emission_tex = texture(texture_emission,base_uv2).rgb;\n";
}
} else { } else {
code += "\tvec3 emission_tex = texture(texture_emission,base_uv).rgb;\n"; if (flags[FLAG_UV1_USE_TRIPLANAR]) {
code += "\tvec3 emission_tex = triplanar_texture(texture_emission,uv1_power_normal,uv1_triplanar_pos).rgb;\n";
} else {
code += "\tvec3 emission_tex = texture(texture_emission,base_uv).rgb;\n";
}
} }
if (emission_op == EMISSION_OP_ADD) { if (emission_op == EMISSION_OP_ADD) {
code += "\tEMISSION = (emission.rgb+emission_tex)*emission_energy;\n"; code += "\tEMISSION = (emission.rgb+emission_tex)*emission_energy;\n";
} else { } else {
@ -1892,6 +1901,7 @@ void SpatialMaterial::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "emission", PROPERTY_HINT_COLOR_NO_ALPHA), "set_emission", "get_emission"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "emission", PROPERTY_HINT_COLOR_NO_ALPHA), "set_emission", "get_emission");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_emission_energy", "get_emission_energy"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "emission_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_emission_energy", "get_emission_energy");
ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_operator", PROPERTY_HINT_ENUM, "Add,Multiply"), "set_emission_operator", "get_emission_operator"); ADD_PROPERTY(PropertyInfo(Variant::INT, "emission_operator", PROPERTY_HINT_ENUM, "Add,Multiply"), "set_emission_operator", "get_emission_operator");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "emission_on_uv2"), "set_flag", "get_flag", FLAG_EMISSION_ON_UV2);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "emission_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_EMISSION); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "emission_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture", TEXTURE_EMISSION);
ADD_GROUP("NormalMap", "normal_"); ADD_GROUP("NormalMap", "normal_");
@ -2034,6 +2044,7 @@ void SpatialMaterial::_bind_methods() {
BIND_ENUM_CONSTANT(FLAG_UV1_USE_TRIPLANAR); BIND_ENUM_CONSTANT(FLAG_UV1_USE_TRIPLANAR);
BIND_ENUM_CONSTANT(FLAG_UV2_USE_TRIPLANAR); BIND_ENUM_CONSTANT(FLAG_UV2_USE_TRIPLANAR);
BIND_ENUM_CONSTANT(FLAG_AO_ON_UV2); BIND_ENUM_CONSTANT(FLAG_AO_ON_UV2);
BIND_ENUM_CONSTANT(FLAG_EMISSION_ON_UV2);
BIND_ENUM_CONSTANT(FLAG_USE_ALPHA_SCISSOR); BIND_ENUM_CONSTANT(FLAG_USE_ALPHA_SCISSOR);
BIND_ENUM_CONSTANT(FLAG_TRIPLANAR_USE_WORLD); BIND_ENUM_CONSTANT(FLAG_TRIPLANAR_USE_WORLD);
BIND_ENUM_CONSTANT(FLAG_ALBEDO_TEXTURE_FORCE_SRGB); BIND_ENUM_CONSTANT(FLAG_ALBEDO_TEXTURE_FORCE_SRGB);

View File

@ -184,6 +184,7 @@ public:
FLAG_UV2_USE_TRIPLANAR, FLAG_UV2_USE_TRIPLANAR,
FLAG_TRIPLANAR_USE_WORLD, FLAG_TRIPLANAR_USE_WORLD,
FLAG_AO_ON_UV2, FLAG_AO_ON_UV2,
FLAG_EMISSION_ON_UV2,
FLAG_USE_ALPHA_SCISSOR, FLAG_USE_ALPHA_SCISSOR,
FLAG_ALBEDO_TEXTURE_FORCE_SRGB, FLAG_ALBEDO_TEXTURE_FORCE_SRGB,
FLAG_MAX FLAG_MAX
@ -234,7 +235,7 @@ private:
uint64_t blend_mode : 2; uint64_t blend_mode : 2;
uint64_t depth_draw_mode : 2; uint64_t depth_draw_mode : 2;
uint64_t cull_mode : 2; uint64_t cull_mode : 2;
uint64_t flags : 13; uint64_t flags : 14;
uint64_t detail_blend_mode : 2; uint64_t detail_blend_mode : 2;
uint64_t diffuse_mode : 3; uint64_t diffuse_mode : 3;
uint64_t specular_mode : 2; uint64_t specular_mode : 2;

View File

@ -1123,27 +1123,29 @@ Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texe
PoolVector<int> rindices = arrays[Mesh::ARRAY_INDEX]; PoolVector<int> rindices = arrays[Mesh::ARRAY_INDEX];
int ic = rindices.size(); int ic = rindices.size();
int index_ofs = indices.size();
if (ic == 0) { if (ic == 0) {
indices.resize(index_ofs + vc);
face_materials.resize((index_ofs + vc) / 3);
for (int j = 0; j < vc; j++) {
indices[index_ofs + j] = vertex_ofs + j;
}
for (int j = 0; j < vc / 3; j++) { for (int j = 0; j < vc / 3; j++) {
face_materials[(index_ofs / 3) + j] = i; if (Face3(r[j * 3 + 0], r[j * 3 + 1], r[j * 3 + 2]).is_degenerate())
continue;
indices.push_back(vertex_ofs + j * 3 + 0);
indices.push_back(vertex_ofs + j * 3 + 1);
indices.push_back(vertex_ofs + j * 3 + 2);
face_materials.push_back(i);
} }
} else { } else {
PoolVector<int>::Read ri = rindices.read(); PoolVector<int>::Read ri = rindices.read();
indices.resize(index_ofs + ic);
face_materials.resize((index_ofs + ic) / 3);
for (int j = 0; j < ic; j++) {
indices[index_ofs + j] = vertex_ofs + ri[j];
}
for (int j = 0; j < ic / 3; j++) { for (int j = 0; j < ic / 3; j++) {
face_materials[(index_ofs / 3) + j] = i; if (Face3(r[ri[j * 3 + 0]], r[ri[j * 3 + 1]], r[ri[j * 3 + 2]]).is_degenerate())
continue;
indices.push_back(vertex_ofs + ri[j * 3 + 0]);
indices.push_back(vertex_ofs + ri[j * 3 + 1]);
indices.push_back(vertex_ofs + ri[j * 3 + 2]);
face_materials.push_back(i);
} }
} }

View File

@ -112,6 +112,10 @@ public:
SelfList<InstanceBase> dependency_item; SelfList<InstanceBase> dependency_item;
InstanceBase *lightmap_capture;
RID lightmap;
Vector<Color> lightmap_capture_data; //in a array (12 values) to avoid wasting space if unused. Alpha is unused, but needed to send to shader
virtual void base_removed() = 0; virtual void base_removed() = 0;
virtual void base_changed() = 0; virtual void base_changed() = 0;
virtual void base_material_changed() = 0; virtual void base_material_changed() = 0;
@ -126,6 +130,7 @@ public:
depth_layer = 0; depth_layer = 0;
layer_mask = 1; layer_mask = 1;
baked_light = false; baked_light = false;
lightmap_capture = NULL;
} }
}; };
@ -437,6 +442,32 @@ public:
virtual RID gi_probe_dynamic_data_create(int p_width, int p_height, int p_depth, GIProbeCompression p_compression) = 0; virtual RID gi_probe_dynamic_data_create(int p_width, int p_height, int p_depth, GIProbeCompression p_compression) = 0;
virtual void gi_probe_dynamic_data_update(RID p_gi_probe_data, int p_depth_slice, int p_slice_count, int p_mipmap, const void *p_data) = 0; virtual void gi_probe_dynamic_data_update(RID p_gi_probe_data, int p_depth_slice, int p_slice_count, int p_mipmap, const void *p_data) = 0;
/* LIGHTMAP CAPTURE */
struct LightmapCaptureOctree {
enum {
CHILD_EMPTY = 0xFFFFFFFF
};
uint16_t light[6][3]; //anisotropic light
float alpha;
uint32_t children[8];
};
virtual RID lightmap_capture_create() = 0;
virtual void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds) = 0;
virtual AABB lightmap_capture_get_bounds(RID p_capture) const = 0;
virtual void lightmap_capture_set_octree(RID p_capture, const PoolVector<uint8_t> &p_octree) = 0;
virtual PoolVector<uint8_t> lightmap_capture_get_octree(RID p_capture) const = 0;
virtual void lightmap_capture_set_octree_cell_transform(RID p_capture, const Transform &p_xform) = 0;
virtual Transform lightmap_capture_get_octree_cell_transform(RID p_capture) const = 0;
virtual void lightmap_capture_set_octree_cell_subdiv(RID p_capture, int p_subdiv) = 0;
virtual int lightmap_capture_get_octree_cell_subdiv(RID p_capture) const = 0;
virtual void lightmap_capture_set_energy(RID p_capture, float p_energy) = 0;
virtual float lightmap_capture_get_energy(RID p_capture) const = 0;
virtual const PoolVector<LightmapCaptureOctree> *lightmap_capture_get_octree_ptr(RID p_capture) const = 0;
/* PARTICLES */ /* PARTICLES */
virtual RID particles_create() = 0; virtual RID particles_create() = 0;

View File

@ -361,6 +361,24 @@ public:
BIND2(gi_probe_set_dynamic_data, RID, const PoolVector<int> &) BIND2(gi_probe_set_dynamic_data, RID, const PoolVector<int> &)
BIND1RC(PoolVector<int>, gi_probe_get_dynamic_data, RID) BIND1RC(PoolVector<int>, gi_probe_get_dynamic_data, RID)
/* LIGHTMAP CAPTURE */
BIND0R(RID, lightmap_capture_create)
BIND2(lightmap_capture_set_bounds, RID, const AABB &)
BIND1RC(AABB, lightmap_capture_get_bounds, RID)
BIND2(lightmap_capture_set_octree, RID, const PoolVector<uint8_t> &)
BIND1RC(PoolVector<uint8_t>, lightmap_capture_get_octree, RID)
BIND2(lightmap_capture_set_octree_cell_transform, RID, const Transform &)
BIND1RC(Transform, lightmap_capture_get_octree_cell_transform, RID)
BIND2(lightmap_capture_set_octree_cell_subdiv, RID, int)
BIND1RC(int, lightmap_capture_get_octree_cell_subdiv, RID)
BIND2(lightmap_capture_set_energy, RID, float)
BIND1RC(float, lightmap_capture_get_energy, RID)
/* PARTICLES */ /* PARTICLES */
BIND0R(RID, particles_create) BIND0R(RID, particles_create)
@ -504,6 +522,7 @@ public:
BIND3(instance_set_blend_shape_weight, RID, int, float) BIND3(instance_set_blend_shape_weight, RID, int, float)
BIND3(instance_set_surface_material, RID, int, RID) BIND3(instance_set_surface_material, RID, int, RID)
BIND2(instance_set_visible, RID, bool) BIND2(instance_set_visible, RID, bool)
BIND3(instance_set_use_lightmap, RID, RID, RID)
BIND2(instance_set_custom_aabb, RID, AABB) BIND2(instance_set_custom_aabb, RID, AABB)

View File

@ -132,6 +132,19 @@ void *VisualServerScene::_instance_pair(void *p_self, OctreeElementID, Instance
geom->reflection_dirty = true; geom->reflection_dirty = true;
return E; //this element should make freeing faster
} else if (B->base_type == VS::INSTANCE_LIGHTMAP_CAPTURE && ((1 << A->base_type) & VS::INSTANCE_GEOMETRY_MASK)) {
InstanceLightmapCaptureData *lightmap_capture = static_cast<InstanceLightmapCaptureData *>(B->base_data);
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
InstanceLightmapCaptureData::PairInfo pinfo;
pinfo.geometry = A;
pinfo.L = geom->lightmap_captures.push_back(B);
List<InstanceLightmapCaptureData::PairInfo>::Element *E = lightmap_capture->geometries.push_back(pinfo);
((VisualServerScene *)p_self)->_instance_queue_update(A, false, false); //need to update capture
return E; //this element should make freeing faster 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)) { } else if (B->base_type == VS::INSTANCE_GI_PROBE && ((1 << A->base_type) & VS::INSTANCE_GEOMETRY_MASK)) {
@ -193,6 +206,16 @@ void VisualServerScene::_instance_unpair(void *p_self, OctreeElementID, Instance
reflection_probe->geometries.erase(E); reflection_probe->geometries.erase(E);
geom->reflection_dirty = true; geom->reflection_dirty = true;
} else if (B->base_type == VS::INSTANCE_LIGHTMAP_CAPTURE && ((1 << A->base_type) & VS::INSTANCE_GEOMETRY_MASK)) {
InstanceLightmapCaptureData *lightmap_capture = static_cast<InstanceLightmapCaptureData *>(B->base_data);
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(A->base_data);
List<InstanceLightmapCaptureData::PairInfo>::Element *E = reinterpret_cast<List<InstanceLightmapCaptureData::PairInfo>::Element *>(udata);
geom->lightmap_captures.erase(E->get().L);
lightmap_capture->geometries.erase(E);
((VisualServerScene *)p_self)->_instance_queue_update(A, false, false); //need to update capture
} else if (B->base_type == VS::INSTANCE_GI_PROBE && ((1 << A->base_type) & VS::INSTANCE_GEOMETRY_MASK)) { } else if (B->base_type == VS::INSTANCE_GI_PROBE && ((1 << A->base_type) & VS::INSTANCE_GEOMETRY_MASK)) {
@ -344,6 +367,14 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) {
reflection_probe_render_list.remove(&reflection_probe->update_list); reflection_probe_render_list.remove(&reflection_probe->update_list);
} }
} break; } break;
case VS::INSTANCE_LIGHTMAP_CAPTURE: {
InstanceLightmapCaptureData *lightmap_capture = static_cast<InstanceLightmapCaptureData *>(instance->base_data);
//erase dependencies, since no longer a lightmap
while (lightmap_capture->users.front()) {
instance_set_use_lightmap(lightmap_capture->users.front()->get()->self, RID(), RID());
}
} break;
case VS::INSTANCE_GI_PROBE: { case VS::INSTANCE_GI_PROBE: {
InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data); InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(instance->base_data);
@ -355,6 +386,14 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) {
VSG::storage->free(gi_probe->dynamic.probe_data); VSG::storage->free(gi_probe->dynamic.probe_data);
} }
if (instance->lightmap_capture) {
Instance *capture = (Instance *)instance->lightmap_capture;
InstanceLightmapCaptureData *lightmap_capture = static_cast<InstanceLightmapCaptureData *>(capture->base_data);
lightmap_capture->users.erase(instance);
instance->lightmap_capture = NULL;
instance->lightmap = RID();
}
VSG::scene_render->free(gi_probe->probe_instance); VSG::scene_render->free(gi_probe->probe_instance);
} break; } break;
@ -412,6 +451,12 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) {
reflection_probe->instance = VSG::scene_render->reflection_probe_instance_create(p_base); reflection_probe->instance = VSG::scene_render->reflection_probe_instance_create(p_base);
} break; } break;
case VS::INSTANCE_LIGHTMAP_CAPTURE: {
InstanceLightmapCaptureData *lightmap_capture = memnew(InstanceLightmapCaptureData);
instance->base_data = lightmap_capture;
//lightmap_capture->instance = VSG::scene_render->lightmap_capture_instance_create(p_base);
} break;
case VS::INSTANCE_GI_PROBE: { case VS::INSTANCE_GI_PROBE: {
InstanceGIProbeData *gi_probe = memnew(InstanceGIProbeData); InstanceGIProbeData *gi_probe = memnew(InstanceGIProbeData);
@ -590,6 +635,12 @@ void VisualServerScene::instance_set_visible(RID p_instance, bool p_visible) {
instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << VS::INSTANCE_REFLECTION_PROBE, p_visible ? VS::INSTANCE_GEOMETRY_MASK : 0); instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << VS::INSTANCE_REFLECTION_PROBE, p_visible ? VS::INSTANCE_GEOMETRY_MASK : 0);
} }
} break;
case VS::INSTANCE_LIGHTMAP_CAPTURE: {
if (instance->octree_id && instance->scenario) {
instance->scenario->octree.set_pairable(instance->octree_id, p_visible, 1 << VS::INSTANCE_LIGHTMAP_CAPTURE, p_visible ? VS::INSTANCE_GEOMETRY_MASK : 0);
}
} break; } break;
case VS::INSTANCE_GI_PROBE: { case VS::INSTANCE_GI_PROBE: {
if (instance->octree_id && instance->scenario) { if (instance->octree_id && instance->scenario) {
@ -599,11 +650,35 @@ void VisualServerScene::instance_set_visible(RID p_instance, bool p_visible) {
} break; } break;
} }
} }
inline bool is_geometry_instance(VisualServer::InstanceType p_type) { inline bool is_geometry_instance(VisualServer::InstanceType p_type) {
return p_type == VS::INSTANCE_MESH || p_type == VS::INSTANCE_MULTIMESH || p_type == VS::INSTANCE_PARTICLES || p_type == VS::INSTANCE_IMMEDIATE; return p_type == VS::INSTANCE_MESH || p_type == VS::INSTANCE_MULTIMESH || p_type == VS::INSTANCE_PARTICLES || p_type == VS::INSTANCE_IMMEDIATE;
} }
void VisualServerScene::instance_set_use_lightmap(RID p_instance, RID p_lightmap_instance, RID p_lightmap) {
Instance *instance = instance_owner.get(p_instance);
ERR_FAIL_COND(!instance);
ERR_FAIL_COND(!is_geometry_instance(instance->base_type));
if (instance->lightmap_capture) {
InstanceLightmapCaptureData *lightmap_capture = static_cast<InstanceLightmapCaptureData *>(((Instance *)instance->lightmap_capture)->base_data);
lightmap_capture->users.erase(instance);
instance->lightmap = RID();
instance->lightmap_capture = NULL;
}
if (p_lightmap_instance.is_valid()) {
Instance *lightmap_instance = instance_owner.get(p_lightmap_instance);
ERR_FAIL_COND(!lightmap_instance);
ERR_FAIL_COND(lightmap_instance->base_type != VS::INSTANCE_LIGHTMAP_CAPTURE);
instance->lightmap_capture = lightmap_instance;
InstanceLightmapCaptureData *lightmap_capture = static_cast<InstanceLightmapCaptureData *>(((Instance *)instance->lightmap_capture)->base_data);
lightmap_capture->users.insert(instance);
instance->lightmap = p_lightmap;
}
}
void VisualServerScene::instance_set_custom_aabb(RID p_instance, AABB p_aabb) { void VisualServerScene::instance_set_custom_aabb(RID p_instance, AABB p_aabb) {
Instance *instance = instance_owner.get(p_instance); Instance *instance = instance_owner.get(p_instance);
@ -811,6 +886,15 @@ void VisualServerScene::_update_instance(Instance *p_instance) {
light->shadow_dirty = true; light->shadow_dirty = true;
} }
} }
if (!p_instance->lightmap_capture && geom->lightmap_captures.size()) {
//affected by lightmap captures, must update capture info!
_update_instance_lightmap_captures(p_instance);
} else {
if (!p_instance->lightmap_capture_data.empty()) {
!p_instance->lightmap_capture_data.resize(0); //not in use, clear capture data
}
}
} }
p_instance->mirror = p_instance->transform.basis.determinant() < 0.0; p_instance->mirror = p_instance->transform.basis.determinant() < 0.0;
@ -832,7 +916,7 @@ void VisualServerScene::_update_instance(Instance *p_instance) {
uint32_t pairable_mask = 0; uint32_t pairable_mask = 0;
bool pairable = false; bool pairable = false;
if (p_instance->base_type == VS::INSTANCE_LIGHT || p_instance->base_type == VS::INSTANCE_REFLECTION_PROBE) { if (p_instance->base_type == VS::INSTANCE_LIGHT || p_instance->base_type == VS::INSTANCE_REFLECTION_PROBE || p_instance->base_type == VS::INSTANCE_LIGHTMAP_CAPTURE) {
pairable_mask = p_instance->visible ? VS::INSTANCE_GEOMETRY_MASK : 0; pairable_mask = p_instance->visible ? VS::INSTANCE_GEOMETRY_MASK : 0;
pairable = true; pairable = true;
@ -916,6 +1000,11 @@ void VisualServerScene::_update_instance_aabb(Instance *p_instance) {
new_aabb = VSG::storage->gi_probe_get_bounds(p_instance->base); new_aabb = VSG::storage->gi_probe_get_bounds(p_instance->base);
} break;
case VisualServer::INSTANCE_LIGHTMAP_CAPTURE: {
new_aabb = VSG::storage->lightmap_capture_get_bounds(p_instance->base);
} break; } break;
default: {} default: {}
@ -928,6 +1017,237 @@ void VisualServerScene::_update_instance_aabb(Instance *p_instance) {
p_instance->aabb = new_aabb; p_instance->aabb = new_aabb;
} }
_FORCE_INLINE_ static void _light_capture_sample_octree(const RasterizerStorage::LightmapCaptureOctree *p_octree, int p_cell_subdiv, const Vector3 &p_pos, const Vector3 &p_dir, float p_level, Vector3 &r_color, float &r_alpha) {
static const Vector3 aniso_normal[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)
};
int size = 1 << (p_cell_subdiv - 1);
int clamp_v = size - 1;
//first of all, clamp
Vector3 pos;
pos.x = CLAMP(p_pos.x, 0, clamp_v);
pos.y = CLAMP(p_pos.y, 0, clamp_v);
pos.z = CLAMP(p_pos.z, 0, clamp_v);
float level = (p_cell_subdiv - 1) - p_level;
int target_level;
float level_filter;
if (level <= 0.0) {
level_filter = 0;
target_level = 0;
} else {
target_level = Math::ceil(level);
level_filter = target_level - level;
}
Vector3 color[2][8];
float alpha[2][8];
zeromem(alpha, sizeof(float) * 2 * 8);
//find cell at given level first
for (int c = 0; c < 2; c++) {
int current_level = MAX(0, target_level - c);
int level_cell_size = (1 << (p_cell_subdiv - 1)) >> current_level;
for (int n = 0; n < 8; n++) {
int x = int(pos.x);
int y = int(pos.y);
int z = int(pos.z);
if (n & 1)
x += level_cell_size;
if (n & 2)
y += level_cell_size;
if (n & 4)
z += level_cell_size;
int ofs_x = 0;
int ofs_y = 0;
int ofs_z = 0;
x = CLAMP(x, 0, clamp_v);
y = CLAMP(y, 0, clamp_v);
z = CLAMP(z, 0, clamp_v);
int half = size / 2;
uint32_t cell = 0;
for (int i = 0; i < current_level; i++) {
const RasterizerStorage::LightmapCaptureOctree *bc = &p_octree[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 == RasterizerStorage::LightmapCaptureOctree::CHILD_EMPTY)
break;
half >>= 1;
}
if (cell == RasterizerStorage::LightmapCaptureOctree::CHILD_EMPTY) {
alpha[c][n] = 0;
} else {
alpha[c][n] = p_octree[cell].alpha;
for (int i = 0; i < 6; i++) {
//anisotropic read light
float amount = p_dir.dot(aniso_normal[i]);
if (amount < 0)
amount = 0;
color[c][n].x += p_octree[cell].light[i][0] / 1024.0 * amount;
color[c][n].y += p_octree[cell].light[i][1] / 1024.0 * amount;
color[c][n].z += p_octree[cell].light[i][2] / 1024.0 * amount;
}
}
//print_line("\tlev " + itos(c) + " - " + itos(n) + " alpha: " + rtos(cells[test_cell].alpha) + " col: " + color[c][n]);
}
}
float target_level_size = size >> target_level;
Vector3 pos_fract[2];
pos_fract[0].x = Math::fmod(pos.x, target_level_size) / target_level_size;
pos_fract[0].y = Math::fmod(pos.y, target_level_size) / target_level_size;
pos_fract[0].z = Math::fmod(pos.z, target_level_size) / target_level_size;
target_level_size = size >> MAX(0, target_level - 1);
pos_fract[1].x = Math::fmod(pos.x, target_level_size) / target_level_size;
pos_fract[1].y = Math::fmod(pos.y, target_level_size) / target_level_size;
pos_fract[1].z = Math::fmod(pos.z, target_level_size) / target_level_size;
float alpha_interp[2];
Vector3 color_interp[2];
for (int i = 0; i < 2; i++) {
Vector3 color_x00 = color[i][0].linear_interpolate(color[i][1], pos_fract[i].x);
Vector3 color_xy0 = color[i][2].linear_interpolate(color[i][3], pos_fract[i].x);
Vector3 blend_z0 = color_x00.linear_interpolate(color_xy0, pos_fract[i].y);
Vector3 color_x0z = color[i][4].linear_interpolate(color[i][5], pos_fract[i].x);
Vector3 color_xyz = color[i][6].linear_interpolate(color[i][7], pos_fract[i].x);
Vector3 blend_z1 = color_x0z.linear_interpolate(color_xyz, pos_fract[i].y);
color_interp[i] = blend_z0.linear_interpolate(blend_z1, pos_fract[i].z);
float alpha_x00 = Math::lerp(alpha[i][0], alpha[i][1], pos_fract[i].x);
float alpha_xy0 = Math::lerp(alpha[i][2], alpha[i][3], pos_fract[i].x);
float alpha_z0 = Math::lerp(alpha_x00, alpha_xy0, pos_fract[i].y);
float alpha_x0z = Math::lerp(alpha[i][4], alpha[i][5], pos_fract[i].x);
float alpha_xyz = Math::lerp(alpha[i][6], alpha[i][7], pos_fract[i].x);
float alpha_z1 = Math::lerp(alpha_x0z, alpha_xyz, pos_fract[i].y);
alpha_interp[i] = Math::lerp(alpha_z0, alpha_z1, pos_fract[i].z);
}
r_color = color_interp[0].linear_interpolate(color_interp[1], level_filter);
r_alpha = Math::lerp(alpha_interp[0], alpha_interp[1], level_filter);
// print_line("pos: " + p_posf + " level " + rtos(p_level) + " down to " + itos(target_level) + "." + rtos(level_filter) + " color " + r_color + " alpha " + rtos(r_alpha));
}
_FORCE_INLINE_ static Color _light_capture_voxel_cone_trace(const RasterizerStorage::LightmapCaptureOctree *p_octree, const Vector3 &p_pos, const Vector3 &p_dir, float p_aperture, int p_cell_subdiv) {
float bias = 0.0; //no need for bias here
float max_distance = (Vector3(1, 1, 1) * (1 << (p_cell_subdiv - 1))).length();
float dist = bias;
float alpha = 0.0;
Vector3 color;
Vector3 scolor;
float salpha;
while (dist < max_distance && alpha < 0.95) {
float diameter = MAX(1.0, 2.0 * p_aperture * dist);
_light_capture_sample_octree(p_octree, p_cell_subdiv, p_pos + dist * p_dir, p_dir, log2(diameter), scolor, salpha);
float a = (1.0 - alpha);
color += scolor * a;
alpha += a * salpha;
dist += diameter * 0.5;
}
return Color(color.x, color.y, color.z, alpha);
}
void VisualServerScene::_update_instance_lightmap_captures(Instance *p_instance) {
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data);
static const Vector3 cone_traces[12] = {
Vector3(0, 0, 1),
Vector3(0.866025, 0, 0.5),
Vector3(0.267617, 0.823639, 0.5),
Vector3(-0.700629, 0.509037, 0.5),
Vector3(-0.700629, -0.509037, 0.5),
Vector3(0.267617, -0.823639, 0.5),
Vector3(0, 0, -1),
Vector3(0.866025, 0, -0.5),
Vector3(0.267617, 0.823639, -0.5),
Vector3(-0.700629, 0.509037, -0.5),
Vector3(-0.700629, -0.509037, -0.5),
Vector3(0.267617, -0.823639, -0.5)
};
float cone_aperture = 0.577; // tan(angle) 60 degrees
if (p_instance->lightmap_capture_data.empty()) {
p_instance->lightmap_capture_data.resize(12);
}
//print_line("update captures for pos: " + p_instance->transform.origin);
zeromem(p_instance->lightmap_capture_data.ptrw(), 12 * sizeof(Color));
//this could use some sort of blending..
for (List<Instance *>::Element *E = geom->lightmap_captures.front(); E; E = E->next()) {
const PoolVector<RasterizerStorage::LightmapCaptureOctree> *octree = VSG::storage->lightmap_capture_get_octree_ptr(E->get()->base);
//print_line("octree size: " + itos(octree->size()));
if (octree->size() == 0)
continue;
Transform to_cell_xform = VSG::storage->lightmap_capture_get_octree_cell_transform(E->get()->base);
int cell_subdiv = VSG::storage->lightmap_capture_get_octree_cell_subdiv(E->get()->base);
to_cell_xform = to_cell_xform * E->get()->transform.affine_inverse();
PoolVector<RasterizerStorage::LightmapCaptureOctree>::Read octree_r = octree->read();
Vector3 pos = to_cell_xform.xform(p_instance->transform.origin);
for (int i = 0; i < 12; i++) {
Vector3 dir = to_cell_xform.basis.xform(cone_traces[i]).normalized();
Color capture = _light_capture_voxel_cone_trace(octree_r.ptr(), pos, dir, cone_aperture, cell_subdiv);
p_instance->lightmap_capture_data[i] += capture;
}
}
}
void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario) { void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario) {
InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data); InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data);
@ -2188,6 +2508,8 @@ void VisualServerScene::_bake_gi_probe_light(const GIProbeDataHeader *header, co
InstanceGIProbeData::LocalData *light = &local_data[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 to(light->pos[0] + 0.5, light->pos[1] + 0.5, light->pos[2] + 0.5);
to += -light_axis.sign() * 0.47; //make it more likely to receive a ray
Vector3 norm( Vector3 norm(
(((cells[idx].normal >> 16) & 0xFF) / 255.0) * 2.0 - 1.0, (((cells[idx].normal >> 16) & 0xFF) / 255.0) * 2.0 - 1.0,
(((cells[idx].normal >> 8) & 0xFF) / 255.0) * 2.0 - 1.0, (((cells[idx].normal >> 8) & 0xFF) / 255.0) * 2.0 - 1.0,
@ -2254,6 +2576,8 @@ void VisualServerScene::_bake_gi_probe_light(const GIProbeDataHeader *header, co
InstanceGIProbeData::LocalData *light = &local_data[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 to(light->pos[0] + 0.5, light->pos[1] + 0.5, light->pos[2] + 0.5);
to += (light_pos - to).sign() * 0.47; //make it more likely to receive a ray
Vector3 norm( Vector3 norm(
(((cells[idx].normal >> 16) & 0xFF) / 255.0) * 2.0 - 1.0, (((cells[idx].normal >> 16) & 0xFF) / 255.0) * 2.0 - 1.0,
(((cells[idx].normal >> 8) & 0xFF) / 255.0) * 2.0 - 1.0, (((cells[idx].normal >> 8) & 0xFF) / 255.0) * 2.0 - 1.0,
@ -2927,12 +3251,12 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) {
} }
} }
_instance_update_list.remove(&p_instance->update_item);
_update_instance(p_instance); _update_instance(p_instance);
p_instance->update_aabb = false; p_instance->update_aabb = false;
p_instance->update_materials = false; p_instance->update_materials = false;
_instance_update_list.remove(&p_instance->update_item);
} }
void VisualServerScene::update_dirty_instances() { void VisualServerScene::update_dirty_instances() {

View File

@ -281,6 +281,8 @@ public:
List<Instance *> gi_probes; List<Instance *> gi_probes;
bool gi_probes_dirty; bool gi_probes_dirty;
List<Instance *> lightmap_captures;
InstanceGeometryData() { InstanceGeometryData() {
lighting_dirty = false; lighting_dirty = false;
@ -445,6 +447,20 @@ public:
SelfList<InstanceGIProbeData>::List gi_probe_update_list; SelfList<InstanceGIProbeData>::List gi_probe_update_list;
struct InstanceLightmapCaptureData : public InstanceBaseData {
struct PairInfo {
List<Instance *>::Element *L; //iterator in geometry
Instance *geometry;
};
List<PairInfo> geometries;
Set<Instance *> users;
InstanceLightmapCaptureData() {
}
};
Instance *instance_cull_result[MAX_INSTANCE_CULL]; Instance *instance_cull_result[MAX_INSTANCE_CULL];
Instance *instance_shadow_cull_result[MAX_INSTANCE_CULL]; //used for generating shadowmaps Instance *instance_shadow_cull_result[MAX_INSTANCE_CULL]; //used for generating shadowmaps
Instance *light_cull_result[MAX_LIGHTS_CULLED]; Instance *light_cull_result[MAX_LIGHTS_CULLED];
@ -466,6 +482,7 @@ public:
virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight); virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight);
virtual void instance_set_surface_material(RID p_instance, int p_surface, RID p_material); virtual void instance_set_surface_material(RID p_instance, int p_surface, RID p_material);
virtual void instance_set_visible(RID p_instance, bool p_visible); virtual void instance_set_visible(RID p_instance, bool p_visible);
virtual void instance_set_use_lightmap(RID p_instance, RID p_lightmap_instance, RID p_lightmap);
virtual void instance_set_custom_aabb(RID p_insatnce, AABB aabb); virtual void instance_set_custom_aabb(RID p_insatnce, AABB aabb);
@ -489,6 +506,7 @@ public:
_FORCE_INLINE_ void _update_instance(Instance *p_instance); _FORCE_INLINE_ void _update_instance(Instance *p_instance);
_FORCE_INLINE_ void _update_instance_aabb(Instance *p_instance); _FORCE_INLINE_ void _update_instance_aabb(Instance *p_instance);
_FORCE_INLINE_ void _update_dirty_instance(Instance *p_instance); _FORCE_INLINE_ void _update_dirty_instance(Instance *p_instance);
_FORCE_INLINE_ void _update_instance_lightmap_captures(Instance *p_instance);
_FORCE_INLINE_ void _light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario); _FORCE_INLINE_ void _light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario);

View File

@ -294,6 +294,22 @@ public:
FUNC2(gi_probe_set_dynamic_data, RID, const PoolVector<int> &) FUNC2(gi_probe_set_dynamic_data, RID, const PoolVector<int> &)
FUNC1RC(PoolVector<int>, gi_probe_get_dynamic_data, RID) FUNC1RC(PoolVector<int>, gi_probe_get_dynamic_data, RID)
/* LIGHTMAP CAPTURE */
FUNCRID(lightmap_capture)
FUNC2(lightmap_capture_set_bounds, RID, const AABB &)
FUNC1RC(AABB, lightmap_capture_get_bounds, RID)
FUNC2(lightmap_capture_set_octree, RID, const PoolVector<uint8_t> &)
FUNC1RC(PoolVector<uint8_t>, lightmap_capture_get_octree, RID)
FUNC2(lightmap_capture_set_octree_cell_transform, RID, const Transform &)
FUNC1RC(Transform, lightmap_capture_get_octree_cell_transform, RID)
FUNC2(lightmap_capture_set_octree_cell_subdiv, RID, int)
FUNC1RC(int, lightmap_capture_get_octree_cell_subdiv, RID)
FUNC2(lightmap_capture_set_energy, RID, float)
FUNC1RC(float, lightmap_capture_get_energy, RID)
/* PARTICLES */ /* PARTICLES */
FUNCRID(particles) FUNCRID(particles)
@ -425,6 +441,8 @@ public:
FUNC3(instance_set_blend_shape_weight, RID, int, float) FUNC3(instance_set_blend_shape_weight, RID, int, float)
FUNC3(instance_set_surface_material, RID, int, RID) FUNC3(instance_set_surface_material, RID, int, RID)
FUNC2(instance_set_visible, RID, bool) FUNC2(instance_set_visible, RID, bool)
FUNC3(instance_set_use_lightmap, RID, RID, RID)
FUNC2(instance_set_custom_aabb, RID, AABB) FUNC2(instance_set_custom_aabb, RID, AABB)
FUNC2(instance_attach_skeleton, RID, RID) FUNC2(instance_attach_skeleton, RID, RID)

View File

@ -485,6 +485,20 @@ public:
virtual void gi_probe_set_compress(RID p_probe, bool p_enable) = 0; virtual void gi_probe_set_compress(RID p_probe, bool p_enable) = 0;
virtual bool gi_probe_is_compressed(RID p_probe) const = 0; virtual bool gi_probe_is_compressed(RID p_probe) const = 0;
/* LIGHTMAP CAPTURE */
virtual RID lightmap_capture_create() = 0;
virtual void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds) = 0;
virtual AABB lightmap_capture_get_bounds(RID p_capture) const = 0;
virtual void lightmap_capture_set_octree(RID p_capture, const PoolVector<uint8_t> &p_octree) = 0;
virtual void lightmap_capture_set_octree_cell_transform(RID p_capture, const Transform &p_xform) = 0;
virtual Transform lightmap_capture_get_octree_cell_transform(RID p_capture) const = 0;
virtual void lightmap_capture_set_octree_cell_subdiv(RID p_capture, int p_subdiv) = 0;
virtual int lightmap_capture_get_octree_cell_subdiv(RID p_capture) const = 0;
virtual PoolVector<uint8_t> lightmap_capture_get_octree(RID p_capture) const = 0;
virtual void lightmap_capture_set_energy(RID p_capture, float p_energy) = 0;
virtual float lightmap_capture_get_energy(RID p_capture) const = 0;
/* PARTICLES API */ /* PARTICLES API */
virtual RID particles_create() = 0; virtual RID particles_create() = 0;
@ -735,6 +749,7 @@ public:
INSTANCE_LIGHT, INSTANCE_LIGHT,
INSTANCE_REFLECTION_PROBE, INSTANCE_REFLECTION_PROBE,
INSTANCE_GI_PROBE, INSTANCE_GI_PROBE,
INSTANCE_LIGHTMAP_CAPTURE,
INSTANCE_MAX, INSTANCE_MAX,
/*INSTANCE_BAKED_LIGHT_SAMPLER,*/ /*INSTANCE_BAKED_LIGHT_SAMPLER,*/
@ -755,6 +770,8 @@ public:
virtual void instance_set_surface_material(RID p_instance, int p_surface, RID p_material) = 0; virtual void instance_set_surface_material(RID p_instance, int p_surface, RID p_material) = 0;
virtual void instance_set_visible(RID p_instance, bool p_visible) = 0; virtual void instance_set_visible(RID p_instance, bool p_visible) = 0;
virtual void instance_set_use_lightmap(RID p_instance, RID p_lightmap_instance, RID p_lightmap) = 0;
virtual void instance_set_custom_aabb(RID p_instance, AABB aabb) = 0; virtual void instance_set_custom_aabb(RID p_instance, AABB aabb) = 0;
virtual void instance_attach_skeleton(RID p_instance, RID p_skeleton) = 0; virtual void instance_attach_skeleton(RID p_instance, RID p_skeleton) = 0;