Adding back lightmaps pt1.

This commit is contained in:
Relintai 2024-07-15 17:36:28 +02:00
parent 0c95ddb60d
commit 98cbf1026a
24 changed files with 1051 additions and 13 deletions

View File

@ -64,10 +64,13 @@
Will only show the shadows casted from this object. Will only show the shadows casted from this object.
In other words, the actual mesh will not be visible, only the shadows casted from the mesh will be. In other words, the actual mesh will not be visible, only the shadows casted from the mesh will be.
</constant> </constant>
<constant name="FLAG_DRAW_NEXT_FRAME_IF_VISIBLE" value="0" enum="Flags"> <constant name="FLAG_USE_BAKED_LIGHT" value="0" enum="Flags">
Will allow the GeometryInstance to be used when baking lights using a [GIProbe] or [BakedLightmap].
</constant>
<constant name="FLAG_DRAW_NEXT_FRAME_IF_VISIBLE" value="1" enum="Flags">
Unused in this class, exposed for consistency with [enum RenderingServer.InstanceFlags]. Unused in this class, exposed for consistency with [enum RenderingServer.InstanceFlags].
</constant> </constant>
<constant name="FLAG_MAX" value="1" enum="Flags"> <constant name="FLAG_MAX" value="2" enum="Flags">
Represents the size of the [enum Flags] enum. Represents the size of the [enum Flags] enum.
</constant> </constant>
</constants> </constants>

View File

@ -3292,10 +3292,13 @@
<constant name="INSTANCE_GEOMETRY_MASK" value="14" enum="InstanceType"> <constant name="INSTANCE_GEOMETRY_MASK" value="14" enum="InstanceType">
A combination of the flags of geometry instances (mesh, multimesh, immediate and particles). A combination of the flags of geometry instances (mesh, multimesh, immediate and particles).
</constant> </constant>
<constant name="INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE" value="0" enum="InstanceFlags"> <constant name="INSTANCE_FLAG_USE_BAKED_LIGHT" value="1" enum="InstanceFlags">
Allows the instance to be used in baked lighting.
</constant>
<constant name="INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE" value="2" enum="InstanceFlags">
When set, manually requests to draw geometry on next frame. When set, manually requests to draw geometry on next frame.
</constant> </constant>
<constant name="INSTANCE_FLAG_MAX" value="1" enum="InstanceFlags"> <constant name="INSTANCE_FLAG_MAX" value="2" enum="InstanceFlags">
Represents the size of the [enum InstanceFlags] enum. Represents the size of the [enum InstanceFlags] enum.
</constant> </constant>
<constant name="SHADOW_CASTING_SETTING_OFF" value="0" enum="ShadowCastingSetting"> <constant name="SHADOW_CASTING_SETTING_OFF" value="0" enum="ShadowCastingSetting">

View File

@ -551,6 +551,71 @@ public:
void instance_add_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) {} void instance_add_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) {}
void instance_remove_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) {} void instance_remove_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) {}
/* LIGHTMAP CAPTURE */
struct Instantiable : public RID_Data {
SelfList<RasterizerScene::InstanceBase>::List instance_list;
_FORCE_INLINE_ void instance_change_notify(bool p_aabb = true, bool p_materials = true) {
SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first();
while (instances) {
instances->self()->base_changed(p_aabb, p_materials);
instances = instances->next();
}
}
_FORCE_INLINE_ void instance_remove_deps() {
SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first();
while (instances) {
SelfList<RasterizerScene::InstanceBase> *next = instances->next();
instances->self()->base_removed();
instances = next;
}
}
Instantiable() {}
virtual ~Instantiable() {
}
};
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;
void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds) {}
AABB lightmap_capture_get_bounds(RID p_capture) const { return AABB(); }
void lightmap_capture_set_octree(RID p_capture, const PoolVector<uint8_t> &p_octree) {}
RID lightmap_capture_create() {
LightmapCapture *capture = memnew(LightmapCapture);
return lightmap_capture_data_owner.make_rid(capture);
}
PoolVector<uint8_t> 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>());
return PoolVector<uint8_t>();
}
void lightmap_capture_set_octree_cell_transform(RID p_capture, const Transform &p_xform) {}
Transform lightmap_capture_get_octree_cell_transform(RID p_capture) const { return Transform(); }
void lightmap_capture_set_octree_cell_subdiv(RID p_capture, int p_subdiv) {}
int lightmap_capture_get_octree_cell_subdiv(RID p_capture) const { return 0; }
void lightmap_capture_set_energy(RID p_capture, float p_energy) {}
float lightmap_capture_get_energy(RID p_capture) const { return 0.0; }
void lightmap_capture_set_interior(RID p_capture, bool p_interior) {}
bool lightmap_capture_is_interior(RID p_capture) const { return false; }
const PoolVector<LightmapCaptureOctree> *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;
}
/* RENDER TARGET */ /* RENDER TARGET */
RID render_target_create() { return RID(); } RID render_target_create() { return RID(); }
@ -579,6 +644,8 @@ public:
RS::InstanceType get_base_type(RID p_rid) const { RS::InstanceType get_base_type(RID p_rid) const {
if (mesh_owner.owns(p_rid)) { if (mesh_owner.owns(p_rid)) {
return RS::INSTANCE_MESH; return RS::INSTANCE_MESH;
} else if (lightmap_capture_data_owner.owns(p_rid)) {
return RS::INSTANCE_LIGHTMAP_CAPTURE;
} }
return RS::INSTANCE_NONE; return RS::INSTANCE_NONE;
@ -595,6 +662,11 @@ public:
DummyMesh *mesh = mesh_owner.getornull(p_rid); DummyMesh *mesh = mesh_owner.getornull(p_rid);
mesh_owner.free(p_rid); mesh_owner.free(p_rid);
memdelete(mesh); memdelete(mesh);
} else if (lightmap_capture_data_owner.owns(p_rid)) {
// delete the lightmap
LightmapCapture *lightmap_capture = lightmap_capture_data_owner.getornull(p_rid);
lightmap_capture_data_owner.free(p_rid);
memdelete(lightmap_capture);
} else { } else {
return false; return false;
} }

View File

@ -1209,7 +1209,13 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G
copy = true; copy = true;
} }
e->light_mode = LIGHTMODE_NORMAL; if (e->instance->lightmap.is_valid()) {
e->light_mode = LIGHTMODE_LIGHTMAP;
} else if (!e->instance->lightmap_capture_data.empty()) {
e->light_mode = LIGHTMODE_LIGHTMAP_CAPTURE;
} else {
e->light_mode = LIGHTMODE_NORMAL;
}
} }
} }
@ -2294,6 +2300,10 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
using_fog = true; using_fog = true;
} }
RasterizerStorageGLES2::Texture *prev_lightmap = nullptr;
float lightmap_energy = 1.0;
bool prev_use_lightmap_capture = false;
storage->info.render.draw_call_count += p_element_count; storage->info.render.draw_call_count += p_element_count;
for (int i = 0; i < p_element_count; i++) { for (int i = 0; i < p_element_count; i++) {
@ -2307,8 +2317,11 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
LightInstance *light = nullptr; LightInstance *light = nullptr;
ReflectionProbeInstance *refprobe_1 = nullptr; ReflectionProbeInstance *refprobe_1 = nullptr;
ReflectionProbeInstance *refprobe_2 = nullptr; ReflectionProbeInstance *refprobe_2 = nullptr;
RasterizerStorageGLES2::Texture *lightmap = nullptr;
bool use_lightmap_capture = false;
bool rebind_light = false; bool rebind_light = false;
bool rebind_reflection = false; bool rebind_reflection = false;
bool rebind_lightmap = false;
if (!p_shadow && material->shader) { if (!p_shadow && material->shader) {
bool unshaded = material->shader->spatial.unshaded; bool unshaded = material->shader->spatial.unshaded;
@ -2432,6 +2445,34 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
rebind = true; rebind = true;
rebind_reflection = true; rebind_reflection = true;
} }
use_lightmap_capture = !unshaded && !accum_pass && !e->instance->lightmap_capture_data.empty();
if (use_lightmap_capture != prev_use_lightmap_capture) {
state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTMAP_CAPTURE, use_lightmap_capture);
rebind = true;
}
if (!unshaded && !accum_pass && e->instance->lightmap.is_valid()) {
lightmap = storage->texture_owner.getornull(e->instance->lightmap);
lightmap_energy = 1.0;
if (lightmap) {
RasterizerStorageGLES2::LightmapCapture *capture = storage->lightmap_capture_data_owner.getornull(e->instance->lightmap_capture->base);
if (capture) {
lightmap_energy = capture->energy;
}
}
}
if (lightmap != prev_lightmap) {
state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTMAP, lightmap != nullptr);
if (lightmap != nullptr) {
WRAPPED_GL_ACTIVE_TEXTURE(GL_TEXTURE0 + storage->config.max_texture_image_units - 4);
glBindTexture(GL_TEXTURE_2D, lightmap->tex_id);
}
rebind = true;
rebind_lightmap = true;
}
} }
bool depth_prepass = false; bool depth_prepass = false;
@ -2533,6 +2574,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
//rebind all these //rebind all these
rebind_light = true; rebind_light = true;
rebind_reflection = true; rebind_reflection = true;
rebind_lightmap = true;
if (using_fog) { if (using_fog) {
state.scene_shader.set_uniform(SceneShaderGLES2::FOG_COLOR_BASE, p_env->fog_color); state.scene_shader.set_uniform(SceneShaderGLES2::FOG_COLOR_BASE, p_env->fog_color);
@ -2579,8 +2621,19 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
_setup_refprobes(refprobe_1, refprobe_2, p_view_transform, p_env); _setup_refprobes(refprobe_1, refprobe_2, p_view_transform, p_env);
} }
if (rebind_lightmap && lightmap) {
state.scene_shader.set_uniform(SceneShaderGLES2::LIGHTMAP_ENERGY, lightmap_energy);
if (storage->config.use_lightmap_filter_bicubic) {
state.scene_shader.set_uniform(SceneShaderGLES2::LIGHTMAP_TEXTURE_SIZE, Vector2(lightmap->width, lightmap->height));
}
}
state.scene_shader.set_uniform(SceneShaderGLES2::WORLD_TRANSFORM, e->instance->transform); state.scene_shader.set_uniform(SceneShaderGLES2::WORLD_TRANSFORM, e->instance->transform);
if (use_lightmap_capture) { //this is per instance, must be set always if present
glUniform4fv(state.scene_shader.get_uniform_location(SceneShaderGLES2::LIGHTMAP_CAPTURES), 12, (const GLfloat *)e->instance->lightmap_capture_data.ptr());
}
_render_geometry(e); _render_geometry(e);
prev_geometry = e->geometry; prev_geometry = e->geometry;
@ -2592,6 +2645,8 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
prev_light = light; prev_light = light;
prev_refprobe_1 = refprobe_1; prev_refprobe_1 = refprobe_1;
prev_refprobe_2 = refprobe_2; prev_refprobe_2 = refprobe_2;
prev_lightmap = lightmap;
prev_use_lightmap_capture = use_lightmap_capture;
} }
_setup_light_type(nullptr, nullptr); //clear light stuff _setup_light_type(nullptr, nullptr); //clear light stuff
@ -2608,6 +2663,8 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements,
state.scene_shader.set_conditional(SceneShaderGLES2::USE_VERTEX_LIGHTING, false); state.scene_shader.set_conditional(SceneShaderGLES2::USE_VERTEX_LIGHTING, false);
state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE1, false); state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE1, false);
state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE2, false); state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE2, false);
state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTMAP, false);
state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTMAP_CAPTURE, false);
state.scene_shader.set_conditional(SceneShaderGLES2::FOG_DEPTH_ENABLED, false); state.scene_shader.set_conditional(SceneShaderGLES2::FOG_DEPTH_ENABLED, false);
state.scene_shader.set_conditional(SceneShaderGLES2::FOG_HEIGHT_ENABLED, false); state.scene_shader.set_conditional(SceneShaderGLES2::FOG_HEIGHT_ENABLED, false);
state.scene_shader.set_conditional(SceneShaderGLES2::USE_DEPTH_PREPASS, false); state.scene_shader.set_conditional(SceneShaderGLES2::USE_DEPTH_PREPASS, false);
@ -3967,6 +4024,10 @@ void RasterizerSceneGLES2::initialize() {
directional_shadow_create(); directional_shadow_create();
if (storage->config.use_lightmap_filter_bicubic) {
state.scene_shader.add_custom_define("#define USE_LIGHTMAP_FILTER_BICUBIC\n");
}
shadow_filter_mode = SHADOW_FILTER_NEAREST; shadow_filter_mode = SHADOW_FILTER_NEAREST;
glFrontFace(GL_CW); glFrontFace(GL_CW);

View File

@ -558,6 +558,8 @@ public:
enum LightMode { enum LightMode {
LIGHTMODE_NORMAL, LIGHTMODE_NORMAL,
LIGHTMODE_UNSHADED, LIGHTMODE_UNSHADED,
LIGHTMODE_LIGHTMAP,
LIGHTMODE_LIGHTMAP_CAPTURE,
}; };
struct RenderList { struct RenderList {

View File

@ -4649,6 +4649,127 @@ int RasterizerStorageGLES2::reflection_probe_get_resolution(RID p_probe) const {
return reflection_probe->resolution; return reflection_probe->resolution;
} }
///////
RID RasterizerStorageGLES2::lightmap_capture_create() {
LightmapCapture *capture = memnew(LightmapCapture);
return lightmap_capture_data_owner.make_rid(capture);
}
void RasterizerStorageGLES2::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(true, false);
}
AABB RasterizerStorageGLES2::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 RasterizerStorageGLES2::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();
memcpy(w.ptr(), r.ptr(), p_octree.size());
}
capture->instance_change_notify(true, false);
}
PoolVector<uint8_t> RasterizerStorageGLES2::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();
memcpy(w.ptr(), r.ptr(), ret.size());
}
return ret;
}
void RasterizerStorageGLES2::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 RasterizerStorageGLES2::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 RasterizerStorageGLES2::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 RasterizerStorageGLES2::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 RasterizerStorageGLES2::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;
if (!capture->update_list.in_list()) {
capture_update_list.add(&capture->update_list);
}
}
float RasterizerStorageGLES2::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;
}
void RasterizerStorageGLES2::lightmap_capture_set_interior(RID p_capture, bool p_interior) {
LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
ERR_FAIL_COND(!capture);
capture->interior = p_interior;
if (!capture->update_list.in_list()) {
capture_update_list.add(&capture->update_list);
}
}
bool RasterizerStorageGLES2::lightmap_capture_is_interior(RID p_capture) const {
const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
ERR_FAIL_COND_V(!capture, false);
return capture->interior;
}
void RasterizerStorageGLES2::update_dirty_captures() {
while (capture_update_list.first()) {
LightmapCapture *capture = capture_update_list.first()->self();
capture->instance_change_notify(false, true);
capture_update_list.remove(capture_update_list.first());
}
}
const PoolVector<RasterizerStorage::LightmapCaptureOctree> *RasterizerStorageGLES2::lightmap_capture_get_octree_ptr(RID p_capture) const {
const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture);
ERR_FAIL_COND_V(!capture, nullptr);
return &capture->octree;
}
//////// ////////
void RasterizerStorageGLES2::instance_add_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) { void RasterizerStorageGLES2::instance_add_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) {
@ -4688,6 +4809,10 @@ void RasterizerStorageGLES2::instance_add_dependency(RID p_base, RasterizerScene
inst = light_owner.getornull(p_base); inst = light_owner.getornull(p_base);
ERR_FAIL_COND(!inst); ERR_FAIL_COND(!inst);
} break; } break;
case RS::INSTANCE_LIGHTMAP_CAPTURE: {
inst = lightmap_capture_data_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;
default: { default: {
ERR_FAIL(); ERR_FAIL();
} }
@ -4720,6 +4845,10 @@ void RasterizerStorageGLES2::instance_remove_dependency(RID p_base, RasterizerSc
inst = light_owner.getornull(p_base); inst = light_owner.getornull(p_base);
ERR_FAIL_COND(!inst); ERR_FAIL_COND(!inst);
} break; } break;
case RS::INSTANCE_LIGHTMAP_CAPTURE: {
inst = lightmap_capture_data_owner.getornull(p_base);
ERR_FAIL_COND(!inst);
} break;
default: { default: {
ERR_FAIL(); ERR_FAIL();
} }
@ -5626,6 +5755,8 @@ RS::InstanceType RasterizerStorageGLES2::get_base_type(RID p_rid) const {
return RS::INSTANCE_IMMEDIATE; return RS::INSTANCE_IMMEDIATE;
} else if (reflection_probe_owner.owns(p_rid)) { } else if (reflection_probe_owner.owns(p_rid)) {
return RS::INSTANCE_REFLECTION_PROBE; return RS::INSTANCE_REFLECTION_PROBE;
} else if (lightmap_capture_data_owner.owns(p_rid)) {
return RS::INSTANCE_LIGHTMAP_CAPTURE;
} else { } else {
return RS::INSTANCE_NONE; return RS::INSTANCE_NONE;
} }
@ -5816,6 +5947,15 @@ bool RasterizerStorageGLES2::free(RID p_rid) {
memdelete(reflection_probe); memdelete(reflection_probe);
return true; return true;
} else if (lightmap_capture_data_owner.owns(p_rid)) {
// delete the texture
LightmapCapture *lightmap_capture = lightmap_capture_data_owner.get(p_rid);
lightmap_capture->instance_remove_deps();
lightmap_capture_data_owner.free(p_rid);
memdelete(lightmap_capture);
return true;
} else if (canvas_occluder_owner.owns(p_rid)) { } else if (canvas_occluder_owner.owns(p_rid)) {
CanvasOccluder *co = canvas_occluder_owner.get(p_rid); CanvasOccluder *co = canvas_occluder_owner.get(p_rid);
if (co->index_id) { if (co->index_id) {
@ -6341,6 +6481,9 @@ void RasterizerStorageGLES2::initialize() {
config.force_vertex_shading = GLOBAL_GET("rendering/quality/shading/force_vertex_shading"); config.force_vertex_shading = GLOBAL_GET("rendering/quality/shading/force_vertex_shading");
config.use_fast_texture_filter = GLOBAL_GET("rendering/quality/filters/use_nearest_mipmap_filter"); config.use_fast_texture_filter = GLOBAL_GET("rendering/quality/filters/use_nearest_mipmap_filter");
GLOBAL_DEF_RST("rendering/quality/lightmapping/use_bicubic_sampling", true);
GLOBAL_DEF_RST("rendering/quality/lightmapping/use_bicubic_sampling.mobile", false);
config.use_lightmap_filter_bicubic = GLOBAL_GET("rendering/quality/lightmapping/use_bicubic_sampling");
config.use_physical_light_attenuation = GLOBAL_GET("rendering/quality/shading/use_physical_light_attenuation"); config.use_physical_light_attenuation = GLOBAL_GET("rendering/quality/shading/use_physical_light_attenuation");
@ -6372,6 +6515,7 @@ void RasterizerStorageGLES2::update_dirty_resources() {
update_dirty_blend_shapes(); update_dirty_blend_shapes();
update_dirty_skeletons(); update_dirty_skeletons();
update_dirty_multimeshes(); update_dirty_multimeshes();
update_dirty_captures();
} }
RasterizerStorageGLES2::RasterizerStorageGLES2() { RasterizerStorageGLES2::RasterizerStorageGLES2() {

View File

@ -60,6 +60,7 @@ public:
bool use_fast_texture_filter; bool use_fast_texture_filter;
bool use_anisotropic_filter; bool use_anisotropic_filter;
bool use_skeleton_software; bool use_skeleton_software;
bool use_lightmap_filter_bicubic;
bool use_physical_light_attenuation; bool use_physical_light_attenuation;
int max_vertex_texture_image_units; int max_vertex_texture_image_units;
@ -1048,6 +1049,48 @@ public:
virtual float reflection_probe_get_origin_max_distance(RID p_probe) const; virtual float reflection_probe_get_origin_max_distance(RID p_probe) const;
virtual bool reflection_probe_renders_shadows(RID p_probe) const; virtual bool reflection_probe_renders_shadows(RID p_probe) const;
/* LIGHTMAP */
struct LightmapCapture : public Instantiable {
PoolVector<LightmapCaptureOctree> octree;
AABB bounds;
Transform cell_xform;
int cell_subdiv;
float energy;
bool interior;
SelfList<LightmapCapture> update_list;
LightmapCapture() :
update_list(this) {
energy = 1.0;
cell_subdiv = 1;
interior = false;
}
};
SelfList<LightmapCapture>::List capture_update_list;
void update_dirty_captures();
mutable RID_Owner<LightmapCapture> lightmap_capture_data_owner;
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 void lightmap_capture_set_interior(RID p_capture, bool p_interior);
virtual bool lightmap_capture_is_interior(RID p_capture) const;
virtual const PoolVector<LightmapCaptureOctree> *lightmap_capture_get_octree_ptr(RID p_capture) const;
/* INSTANCE */ /* INSTANCE */
virtual void instance_add_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance); virtual void instance_add_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance);

View File

@ -53,7 +53,7 @@ attribute vec4 color_attrib; // attrib:3
attribute vec2 uv_attrib; // attrib:4 attribute vec2 uv_attrib; // attrib:4
#endif #endif
#if defined(ENABLE_UV2_INTERP) #if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP)
attribute vec2 uv2_attrib; // attrib:5 attribute vec2 uv2_attrib; // attrib:5
#endif #endif
@ -143,7 +143,7 @@ varying vec4 color_interp;
varying vec2 uv_interp; varying vec2 uv_interp;
#endif #endif
#if defined(ENABLE_UV2_INTERP) #if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP)
varying vec2 uv2_interp; varying vec2 uv2_interp;
#endif #endif
@ -305,7 +305,9 @@ uniform highp mat4 refprobe1_local_matrix;
varying mediump vec4 refprobe1_reflection_normal_blend; varying mediump vec4 refprobe1_reflection_normal_blend;
uniform highp vec3 refprobe1_box_extents; uniform highp vec3 refprobe1_box_extents;
#ifndef USE_LIGHTMAP
varying mediump vec3 refprobe1_ambient_normal; varying mediump vec3 refprobe1_ambient_normal;
#endif
#endif //reflection probe1 #endif //reflection probe1
@ -315,7 +317,9 @@ uniform highp mat4 refprobe2_local_matrix;
varying mediump vec4 refprobe2_reflection_normal_blend; varying mediump vec4 refprobe2_reflection_normal_blend;
uniform highp vec3 refprobe2_box_extents; uniform highp vec3 refprobe2_box_extents;
#ifndef USE_LIGHTMAP
varying mediump vec3 refprobe2_ambient_normal; varying mediump vec3 refprobe2_ambient_normal;
#endif
#endif //reflection probe2 #endif //reflection probe2
@ -392,7 +396,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
@ -678,7 +682,9 @@ VERTEX_SHADER_CODE
refprobe1_reflection_normal_blend.a = blend; refprobe1_reflection_normal_blend.a = blend;
} }
#ifndef USE_LIGHTMAP
refprobe1_ambient_normal = (refprobe1_local_matrix * vec4(normal_interp, 0.0)).xyz; refprobe1_ambient_normal = (refprobe1_local_matrix * vec4(normal_interp, 0.0)).xyz;
#endif
} }
#endif //USE_REFLECTION_PROBE1 #endif //USE_REFLECTION_PROBE1
@ -696,7 +702,9 @@ VERTEX_SHADER_CODE
refprobe2_reflection_normal_blend.a = blend; refprobe2_reflection_normal_blend.a = blend;
} }
#ifndef USE_LIGHTMAP
refprobe2_ambient_normal = (refprobe2_local_matrix * vec4(normal_interp, 0.0)).xyz; refprobe2_ambient_normal = (refprobe2_local_matrix * vec4(normal_interp, 0.0)).xyz;
#endif
} }
#endif //USE_REFLECTION_PROBE2 #endif //USE_REFLECTION_PROBE2
@ -819,8 +827,9 @@ uniform highp sampler2D depth_texture; //texunit:-4
#ifdef USE_VERTEX_LIGHTING #ifdef USE_VERTEX_LIGHTING
varying mediump vec4 refprobe1_reflection_normal_blend; varying mediump vec4 refprobe1_reflection_normal_blend;
#ifndef USE_LIGHTMAP
varying mediump vec3 refprobe1_ambient_normal; varying mediump vec3 refprobe1_ambient_normal;
#endif
#else #else
@ -845,8 +854,9 @@ uniform vec4 refprobe1_ambient;
#ifdef USE_VERTEX_LIGHTING #ifdef USE_VERTEX_LIGHTING
varying mediump vec4 refprobe2_reflection_normal_blend; varying mediump vec4 refprobe2_reflection_normal_blend;
#ifndef USE_LIGHTMAP
varying mediump vec3 refprobe2_ambient_normal; varying mediump vec3 refprobe2_ambient_normal;
#endif
#else #else
@ -873,7 +883,9 @@ uniform vec4 refprobe2_ambient;
void reflection_process(samplerCube reflection_map, void reflection_process(samplerCube reflection_map,
#ifdef USE_VERTEX_LIGHTING #ifdef USE_VERTEX_LIGHTING
vec3 ref_normal, vec3 ref_normal,
#ifndef USE_LIGHTMAP
vec3 amb_normal, vec3 amb_normal,
#endif
float ref_blend, float ref_blend,
#else //no vertex lighting #else //no vertex lighting
@ -936,6 +948,8 @@ void reflection_process(samplerCube reflection_map,
reflection_accum += reflection; reflection_accum += reflection;
#ifndef USE_LIGHTMAP
vec4 ambient_out; vec4 ambient_out;
#ifndef USE_VERTEX_LIGHTING #ifndef USE_VERTEX_LIGHTING
@ -951,10 +965,84 @@ void reflection_process(samplerCube reflection_map,
ambient_out.a = blend; ambient_out.a = blend;
ambient_out.rgb *= blend; ambient_out.rgb *= blend;
ambient_accum += ambient_out; ambient_accum += ambient_out;
#endif
} }
#endif //use refprobe 1 or 2 #endif //use refprobe 1 or 2
#ifdef USE_LIGHTMAP
uniform mediump sampler2D lightmap; //texunit:-4
uniform mediump float lightmap_energy;
#if defined(USE_LIGHTMAP_FILTER_BICUBIC)
uniform mediump vec2 lightmap_texture_size;
// w0, w1, w2, and w3 are the four cubic B-spline basis functions
float w0(float a) {
return (1.0 / 6.0) * (a * (a * (-a + 3.0) - 3.0) + 1.0);
}
float w1(float a) {
return (1.0 / 6.0) * (a * a * (3.0 * a - 6.0) + 4.0);
}
float w2(float a) {
return (1.0 / 6.0) * (a * (a * (-3.0 * a + 3.0) + 3.0) + 1.0);
}
float w3(float a) {
return (1.0 / 6.0) * (a * a * a);
}
// g0 and g1 are the two amplitude functions
float g0(float a) {
return w0(a) + w1(a);
}
float g1(float a) {
return w2(a) + w3(a);
}
// h0 and h1 are the two offset functions
float h0(float a) {
return -1.0 + w1(a) / (w0(a) + w1(a));
}
float h1(float a) {
return 1.0 + w3(a) / (w2(a) + w3(a));
}
vec4 texture2D_bicubic(sampler2D tex, vec2 uv) {
vec2 texel_size = vec2(1.0) / lightmap_texture_size;
uv = uv * lightmap_texture_size + vec2(0.5);
vec2 iuv = floor(uv);
vec2 fuv = fract(uv);
float g0x = g0(fuv.x);
float g1x = g1(fuv.x);
float h0x = h0(fuv.x);
float h1x = h1(fuv.x);
float h0y = h0(fuv.y);
float h1y = h1(fuv.y);
vec2 p0 = (vec2(iuv.x + h0x, iuv.y + h0y) - vec2(0.5)) * texel_size;
vec2 p1 = (vec2(iuv.x + h1x, iuv.y + h0y) - vec2(0.5)) * texel_size;
vec2 p2 = (vec2(iuv.x + h0x, iuv.y + h1y) - vec2(0.5)) * texel_size;
vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - vec2(0.5)) * texel_size;
return (g0(fuv.y) * (g0x * texture2D(tex, p0) + g1x * texture2D(tex, p1))) +
(g1(fuv.y) * (g0x * texture2D(tex, p2) + g1x * texture2D(tex, p3)));
}
#endif //USE_LIGHTMAP_FILTER_BICUBIC
#endif
#ifdef USE_LIGHTMAP_CAPTURE
uniform mediump vec4 lightmap_captures[12];
#endif
#ifdef USE_RADIANCE_MAP #ifdef USE_RADIANCE_MAP
uniform samplerCube radiance_map; // texunit:-2 uniform samplerCube radiance_map; // texunit:-2
@ -1064,7 +1152,7 @@ varying vec4 color_interp;
varying vec2 uv_interp; varying vec2 uv_interp;
#endif #endif
#if defined(ENABLE_UV2_INTERP) #if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP)
varying vec2 uv2_interp; varying vec2 uv2_interp;
#endif #endif
@ -1666,6 +1754,7 @@ FRAGMENT_SHADER_CODE
specular_light = textureCubeLod(radiance_map, ref_vec, roughness * RADIANCE_MAX_LOD).xyz * bg_energy; specular_light = textureCubeLod(radiance_map, ref_vec, roughness * RADIANCE_MAX_LOD).xyz * bg_energy;
specular_light *= horizon * horizon; specular_light *= horizon * horizon;
#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);
vec3 env_ambient = textureCubeLod(radiance_map, ambient_dir, 4.0).xyz * bg_energy; vec3 env_ambient = textureCubeLod(radiance_map, ambient_dir, 4.0).xyz * bg_energy;
@ -1673,6 +1762,7 @@ FRAGMENT_SHADER_CODE
ambient_light = mix(ambient_color.rgb, env_ambient, ambient_sky_contribution); ambient_light = mix(ambient_color.rgb, env_ambient, ambient_sky_contribution);
} }
#endif
#else #else
@ -1693,7 +1783,9 @@ FRAGMENT_SHADER_CODE
reflection_process(reflection_probe1, reflection_process(reflection_probe1,
#ifdef USE_VERTEX_LIGHTING #ifdef USE_VERTEX_LIGHTING
refprobe1_reflection_normal_blend.rgb, refprobe1_reflection_normal_blend.rgb,
#ifndef USE_LIGHTMAP
refprobe1_ambient_normal, refprobe1_ambient_normal,
#endif
refprobe1_reflection_normal_blend.a, refprobe1_reflection_normal_blend.a,
#else #else
normal, vertex_interp, refprobe1_local_matrix, normal, vertex_interp, refprobe1_local_matrix,
@ -1709,7 +1801,9 @@ FRAGMENT_SHADER_CODE
reflection_process(reflection_probe2, reflection_process(reflection_probe2,
#ifdef USE_VERTEX_LIGHTING #ifdef USE_VERTEX_LIGHTING
refprobe2_reflection_normal_blend.rgb, refprobe2_reflection_normal_blend.rgb,
#ifndef USE_LIGHTMAP
refprobe2_ambient_normal, refprobe2_ambient_normal,
#endif
refprobe2_reflection_normal_blend.a, refprobe2_reflection_normal_blend.a,
#else #else
normal, vertex_interp, refprobe2_local_matrix, normal, vertex_interp, refprobe2_local_matrix,
@ -1724,9 +1818,11 @@ FRAGMENT_SHADER_CODE
specular_light = reflection_accum.rgb / reflection_accum.a; specular_light = reflection_accum.rgb / reflection_accum.a;
} }
#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
#endif // defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2) #endif // defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2)
@ -1750,6 +1846,51 @@ FRAGMENT_SHADER_CODE
#endif #endif
} }
#ifdef USE_LIGHTMAP
//ambient light will come entirely from lightmap is lightmap is used
#if defined(USE_LIGHTMAP_FILTER_BICUBIC)
ambient_light = texture2D_bicubic(lightmap, uv2_interp).rgb * lightmap_energy;
#else
ambient_light = texture2D(lightmap, uv2_interp).rgb * lightmap_energy;
#endif
#endif
#ifdef USE_LIGHTMAP_CAPTURE
{
vec3 cone_dirs[12];
cone_dirs[0] = vec3(0.0, 0.0, 1.0);
cone_dirs[1] = vec3(0.866025, 0.0, 0.5);
cone_dirs[2] = vec3(0.267617, 0.823639, 0.5);
cone_dirs[3] = vec3(-0.700629, 0.509037, 0.5);
cone_dirs[4] = vec3(-0.700629, -0.509037, 0.5);
cone_dirs[5] = vec3(0.267617, -0.823639, 0.5);
cone_dirs[6] = vec3(0.0, 0.0, -1.0);
cone_dirs[7] = vec3(0.866025, 0.0, -0.5);
cone_dirs[8] = vec3(0.267617, 0.823639, -0.5);
cone_dirs[9] = vec3(-0.700629, 0.509037, -0.5);
cone_dirs[10] = vec3(-0.700629, -0.509037, -0.5);
cone_dirs[11] = 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;
// Alpha channel is used to indicate if dynamic objects keep the environment lighting
if (lightmap_captures[0].a > 0.5) {
ambient_light += captured.rgb;
} else {
ambient_light = captured.rgb;
}
}
#endif
#endif //BASE PASS #endif //BASE PASS
// //

View File

@ -572,6 +572,9 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("editors/3d/default_z_near", 0.05); _initial_set("editors/3d/default_z_near", 0.05);
_initial_set("editors/3d/default_z_far", 500.0); _initial_set("editors/3d/default_z_far", 500.0);
_initial_set("editors/3d/lightmap_baking_number_of_cpu_threads", 0);
hints["editors/3d/lightmap_baking_number_of_cpu_threads"] = PropertyInfo(Variant::INT, "editors/3d/lightmap_baking_number_of_cpu_threads", PROPERTY_HINT_RANGE, "-2,128,1", PROPERTY_USAGE_DEFAULT);
// 3D: Navigation // 3D: Navigation
_initial_set("editors/3d/navigation/navigation_scheme", 0); _initial_set("editors/3d/navigation/navigation_scheme", 0);
_initial_set("editors/3d/navigation/invert_y_axis", false); _initial_set("editors/3d/navigation/invert_y_axis", false);

View File

@ -204,6 +204,10 @@ bool ResourceImporterScene::get_option_visibility(const String &p_option, const
return false; return false;
} }
if (p_option == "meshes/lightmap_texel_size" && int(p_options["meshes/light_baking"]) < 2) {
return false;
}
return true; return true;
} }

View File

@ -285,6 +285,23 @@ void MeshInstanceEditor::_menu_option(int p_option) {
case MENU_OPTION_CREATE_OUTLINE_MESH: { case MENU_OPTION_CREATE_OUTLINE_MESH: {
outline_dialog->popup_centered(Vector2(200, 90)); outline_dialog->popup_centered(Vector2(200, 90));
} break; } break;
case MENU_OPTION_CREATE_UV2: {
Ref<ArrayMesh> mesh2 = node->get_mesh();
if (!mesh2.is_valid()) {
err_dialog->set_text(TTR("Contained Mesh is not of type ArrayMesh."));
err_dialog->popup_centered_minsize();
return;
}
/*
Error err = mesh2->lightmap_unwrap(node->get_global_transform());
if (err != OK) {
err_dialog->set_text(TTR("UV Unwrap failed, mesh may not be manifold?"));
err_dialog->popup_centered_minsize();
return;
}
*/
} break;
case MENU_OPTION_DEBUG_UV1: { case MENU_OPTION_DEBUG_UV1: {
Ref<Mesh> mesh2 = node->get_mesh(); Ref<Mesh> mesh2 = node->get_mesh();
if (!mesh2.is_valid()) { if (!mesh2.is_valid()) {
@ -481,6 +498,7 @@ MeshInstanceEditor::MeshInstanceEditor() {
options->get_popup()->add_separator(); options->get_popup()->add_separator();
options->get_popup()->add_item(TTR("View UV1"), MENU_OPTION_DEBUG_UV1); options->get_popup()->add_item(TTR("View UV1"), MENU_OPTION_DEBUG_UV1);
options->get_popup()->add_item(TTR("View UV2"), MENU_OPTION_DEBUG_UV2); options->get_popup()->add_item(TTR("View UV2"), MENU_OPTION_DEBUG_UV2);
options->get_popup()->add_item(TTR("Unwrap UV2 for Lightmap/AO"), MENU_OPTION_CREATE_UV2);
options->get_popup()->connect("id_pressed", this, "_menu_option"); options->get_popup()->connect("id_pressed", this, "_menu_option");

View File

@ -61,6 +61,7 @@ class MeshInstanceEditor : public Control {
MENU_OPTION_CREATE_MULTIPLE_CONVEX_COLLISION_SHAPES, MENU_OPTION_CREATE_MULTIPLE_CONVEX_COLLISION_SHAPES,
MENU_OPTION_CREATE_NAVMESH, MENU_OPTION_CREATE_NAVMESH,
MENU_OPTION_CREATE_OUTLINE_MESH, MENU_OPTION_CREATE_OUTLINE_MESH,
MENU_OPTION_CREATE_UV2,
MENU_OPTION_DEBUG_UV1, MENU_OPTION_DEBUG_UV1,
MENU_OPTION_DEBUG_UV2, MENU_OPTION_DEBUG_UV2,
}; };

View File

@ -257,6 +257,23 @@ Ref<Material> GeometryInstance::get_material_overlay() const {
return material_overlay; return material_overlay;
} }
void GeometryInstance::set_generate_lightmap(bool p_enabled) {
generate_lightmap = p_enabled;
}
bool GeometryInstance::get_generate_lightmap() {
return generate_lightmap;
}
void GeometryInstance::set_lightmap_scale(LightmapScale p_scale) {
ERR_FAIL_INDEX(p_scale, LIGHTMAP_SCALE_MAX);
lightmap_scale = p_scale;
}
GeometryInstance::LightmapScale GeometryInstance::get_lightmap_scale() const {
return lightmap_scale;
}
void GeometryInstance::_notification(int p_what) { void GeometryInstance::_notification(int p_what) {
} }
@ -317,6 +334,12 @@ void GeometryInstance::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_cast_shadows_setting", "shadow_casting_setting"), &GeometryInstance::set_cast_shadows_setting); ClassDB::bind_method(D_METHOD("set_cast_shadows_setting", "shadow_casting_setting"), &GeometryInstance::set_cast_shadows_setting);
ClassDB::bind_method(D_METHOD("get_cast_shadows_setting"), &GeometryInstance::get_cast_shadows_setting); ClassDB::bind_method(D_METHOD("get_cast_shadows_setting"), &GeometryInstance::get_cast_shadows_setting);
ClassDB::bind_method(D_METHOD("set_generate_lightmap", "enabled"), &GeometryInstance::set_generate_lightmap);
ClassDB::bind_method(D_METHOD("get_generate_lightmap"), &GeometryInstance::get_generate_lightmap);
ClassDB::bind_method(D_METHOD("set_lightmap_scale", "scale"), &GeometryInstance::set_lightmap_scale);
ClassDB::bind_method(D_METHOD("get_lightmap_scale"), &GeometryInstance::get_lightmap_scale);
ClassDB::bind_method(D_METHOD("set_extra_cull_margin", "margin"), &GeometryInstance::set_extra_cull_margin); ClassDB::bind_method(D_METHOD("set_extra_cull_margin", "margin"), &GeometryInstance::set_extra_cull_margin);
ClassDB::bind_method(D_METHOD("get_extra_cull_margin"), &GeometryInstance::get_extra_cull_margin); ClassDB::bind_method(D_METHOD("get_extra_cull_margin"), &GeometryInstance::get_extra_cull_margin);
@ -330,13 +353,25 @@ void GeometryInstance::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "cast_shadow", PROPERTY_HINT_ENUM, "Off,On,Double-Sided,Shadows Only"), "set_cast_shadows_setting", "get_cast_shadows_setting"); ADD_PROPERTY(PropertyInfo(Variant::INT, "cast_shadow", PROPERTY_HINT_ENUM, "Off,On,Double-Sided,Shadows Only"), "set_cast_shadows_setting", "get_cast_shadows_setting");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "extra_cull_margin", PROPERTY_HINT_RANGE, "0,16384,0.01"), "set_extra_cull_margin", "get_extra_cull_margin"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "extra_cull_margin", PROPERTY_HINT_RANGE, "0,16384,0.01"), "set_extra_cull_margin", "get_extra_cull_margin");
ADD_GROUP("Baked Light", "");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "use_in_baked_light"), "set_flag", "get_flag", FLAG_USE_BAKED_LIGHT);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "generate_lightmap"), "set_generate_lightmap", "get_generate_lightmap");
ADD_PROPERTY(PropertyInfo(Variant::INT, "lightmap_scale", PROPERTY_HINT_ENUM, "1x,2x,4x,8x"), "set_lightmap_scale", "get_lightmap_scale");
//ADD_SIGNAL( MethodInfo("visibility_changed")); //ADD_SIGNAL( MethodInfo("visibility_changed"));
BIND_ENUM_CONSTANT(LIGHTMAP_SCALE_1X);
BIND_ENUM_CONSTANT(LIGHTMAP_SCALE_2X);
BIND_ENUM_CONSTANT(LIGHTMAP_SCALE_4X);
BIND_ENUM_CONSTANT(LIGHTMAP_SCALE_8X);
BIND_ENUM_CONSTANT(LIGHTMAP_SCALE_MAX);
BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_OFF); BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_OFF);
BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_ON); BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_ON);
BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_DOUBLE_SIDED); BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_DOUBLE_SIDED);
BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_SHADOWS_ONLY); BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_SHADOWS_ONLY);
BIND_ENUM_CONSTANT(FLAG_USE_BAKED_LIGHT);
BIND_ENUM_CONSTANT(FLAG_DRAW_NEXT_FRAME_IF_VISIBLE); BIND_ENUM_CONSTANT(FLAG_DRAW_NEXT_FRAME_IF_VISIBLE);
BIND_ENUM_CONSTANT(FLAG_MAX); BIND_ENUM_CONSTANT(FLAG_MAX);
} }
@ -348,4 +383,6 @@ GeometryInstance::GeometryInstance() {
shadow_casting_setting = SHADOW_CASTING_SETTING_ON; shadow_casting_setting = SHADOW_CASTING_SETTING_ON;
extra_cull_margin = 0; extra_cull_margin = 0;
generate_lightmap = true;
lightmap_scale = LightmapScale::LIGHTMAP_SCALE_1X;
} }

View File

@ -98,10 +98,19 @@ class GeometryInstance : public VisualInstance {
public: public:
enum Flags { enum Flags {
FLAG_USE_BAKED_LIGHT = RS::INSTANCE_FLAG_USE_BAKED_LIGHT,
FLAG_DRAW_NEXT_FRAME_IF_VISIBLE = RS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, FLAG_DRAW_NEXT_FRAME_IF_VISIBLE = RS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE,
FLAG_MAX = RS::INSTANCE_FLAG_MAX, FLAG_MAX = RS::INSTANCE_FLAG_MAX,
}; };
enum LightmapScale {
LIGHTMAP_SCALE_1X,
LIGHTMAP_SCALE_2X,
LIGHTMAP_SCALE_4X,
LIGHTMAP_SCALE_8X,
LIGHTMAP_SCALE_MAX,
};
enum ShadowCastingSetting { enum ShadowCastingSetting {
SHADOW_CASTING_SETTING_OFF = RS::SHADOW_CASTING_SETTING_OFF, SHADOW_CASTING_SETTING_OFF = RS::SHADOW_CASTING_SETTING_OFF,
SHADOW_CASTING_SETTING_ON = RS::SHADOW_CASTING_SETTING_ON, SHADOW_CASTING_SETTING_ON = RS::SHADOW_CASTING_SETTING_ON,
@ -111,6 +120,8 @@ public:
private: private:
bool flags[FLAG_MAX]; bool flags[FLAG_MAX];
bool generate_lightmap;
LightmapScale lightmap_scale;
ShadowCastingSetting shadow_casting_setting; ShadowCastingSetting shadow_casting_setting;
Ref<Material> material_override; Ref<Material> material_override;
Ref<Material> material_overlay; Ref<Material> material_overlay;
@ -128,6 +139,12 @@ public:
void set_cast_shadows_setting(ShadowCastingSetting p_shadow_casting_setting); void set_cast_shadows_setting(ShadowCastingSetting p_shadow_casting_setting);
ShadowCastingSetting get_cast_shadows_setting() const; ShadowCastingSetting get_cast_shadows_setting() const;
void set_generate_lightmap(bool p_enabled);
bool get_generate_lightmap();
void set_lightmap_scale(LightmapScale p_scale);
LightmapScale get_lightmap_scale() const;
virtual void set_material_override(const Ref<Material> &p_material); virtual void set_material_override(const Ref<Material> &p_material);
Ref<Material> get_material_override() const; Ref<Material> get_material_override() const;
@ -143,6 +160,7 @@ public:
}; };
VARIANT_ENUM_CAST(GeometryInstance::Flags); VARIANT_ENUM_CAST(GeometryInstance::Flags);
VARIANT_ENUM_CAST(GeometryInstance::LightmapScale);
VARIANT_ENUM_CAST(GeometryInstance::ShadowCastingSetting); VARIANT_ENUM_CAST(GeometryInstance::ShadowCastingSetting);
#endif #endif

View File

@ -594,9 +594,21 @@ Ref<Mesh> Mesh::create_outline(float p_margin) const {
return newmesh; return newmesh;
} }
void Mesh::set_lightmap_size_hint(const Vector2i &p_size) {
lightmap_size_hint = p_size;
}
Size2i Mesh::get_lightmap_size_hint() const {
return lightmap_size_hint;
}
void Mesh::_bind_methods() { void Mesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_aabb"), &Mesh::get_aabb); ClassDB::bind_method(D_METHOD("get_aabb"), &Mesh::get_aabb);
ClassDB::bind_method(D_METHOD("set_lightmap_size_hint", "size"), &Mesh::set_lightmap_size_hint);
ClassDB::bind_method(D_METHOD("get_lightmap_size_hint"), &Mesh::get_lightmap_size_hint);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "lightmap_size_hint"), "set_lightmap_size_hint", "get_lightmap_size_hint");
ClassDB::bind_method(D_METHOD("get_surface_count"), &Mesh::get_surface_count); ClassDB::bind_method(D_METHOD("get_surface_count"), &Mesh::get_surface_count);
ClassDB::bind_method(D_METHOD("surface_get_arrays", "surf_idx"), &Mesh::surface_get_arrays); ClassDB::bind_method(D_METHOD("surface_get_arrays", "surf_idx"), &Mesh::surface_get_arrays);
ClassDB::bind_method(D_METHOD("surface_get_blend_shape_arrays", "surf_idx"), &Mesh::surface_get_blend_shape_arrays); ClassDB::bind_method(D_METHOD("surface_get_blend_shape_arrays", "surf_idx"), &Mesh::surface_get_blend_shape_arrays);

View File

@ -46,6 +46,7 @@ class Mesh : public Resource {
mutable Ref<TriangleMesh> triangle_mesh; //cached mutable Ref<TriangleMesh> triangle_mesh; //cached
mutable Vector<Vector3> debug_lines; mutable Vector<Vector3> debug_lines;
Size2i lightmap_size_hint;
protected: protected:
static void _bind_methods(); static void _bind_methods();
@ -169,6 +170,9 @@ public:
virtual AABB get_aabb() const = 0; virtual AABB get_aabb() const = 0;
virtual void set_storage_mode(StorageMode p_storage_mode); virtual void set_storage_mode(StorageMode p_storage_mode);
void set_lightmap_size_hint(const Vector2i &p_size);
Size2i get_lightmap_size_hint() const;
void clear_cache() const; void clear_cache() const;
typedef Vector<PoolVector<Vector3>> (*ConvexDecompositionFunc)(const real_t *p_vertices, int p_vertex_count, const uint32_t *p_triangles, int p_triangle_count, int p_max_convex_hulls, Vector<PoolVector<uint32_t>> *r_convex_indices); typedef Vector<PoolVector<Vector3>> (*ConvexDecompositionFunc)(const real_t *p_vertices, int p_vertex_count, const uint32_t *p_triangles, int p_triangle_count, int p_max_convex_hulls, Vector<PoolVector<uint32_t>> *r_convex_indices);

View File

@ -118,6 +118,7 @@ public:
bool mirror : 1; bool mirror : 1;
bool receive_shadows : 1; bool receive_shadows : 1;
bool visible : 1; bool visible : 1;
bool baked_light : 1; //this flag is only to know if it actually did use baked light
bool redraw_if_visible : 1; bool redraw_if_visible : 1;
bool on_interpolate_list : 1; bool on_interpolate_list : 1;
@ -134,6 +135,12 @@ 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
int lightmap_slice;
Rect2 lightmap_uv_rect;
virtual void base_removed() = 0; virtual void base_removed() = 0;
virtual void base_changed(bool p_aabb, bool p_materials) = 0; virtual void base_changed(bool p_aabb, bool p_materials) = 0;
InstanceBase() : InstanceBase() :
@ -144,7 +151,11 @@ public:
visible = true; visible = true;
depth_layer = 0; depth_layer = 0;
layer_mask = 1; layer_mask = 1;
baked_light = false;
redraw_if_visible = false; redraw_if_visible = false;
lightmap_capture = nullptr;
lightmap_slice = -1;
lightmap_uv_rect = Rect2(0, 0, 1, 1);
on_interpolate_list = false; on_interpolate_list = false;
on_interpolate_transform_list = false; on_interpolate_transform_list = false;
interpolated = true; interpolated = true;
@ -504,6 +515,33 @@ public:
virtual void instance_add_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) = 0; virtual void instance_add_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) = 0;
virtual void instance_remove_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) = 0; virtual void instance_remove_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) = 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 void lightmap_capture_set_interior(RID p_capture, bool p_interior) = 0;
virtual bool lightmap_capture_is_interior(RID p_capture) const = 0;
virtual const PoolVector<LightmapCaptureOctree> *lightmap_capture_get_octree_ptr(RID p_capture) const = 0;
/* RENDER TARGET */ /* RENDER TARGET */
enum RenderTargetFlags { enum RenderTargetFlags {

View File

@ -359,6 +359,27 @@ public:
BIND2(reflection_probe_set_cull_mask, RID, uint32_t) BIND2(reflection_probe_set_cull_mask, RID, uint32_t)
BIND2(reflection_probe_set_resolution, RID, int) BIND2(reflection_probe_set_resolution, RID, int)
/* 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)
BIND2(lightmap_capture_set_interior, RID, bool)
BIND1RC(bool, lightmap_capture_is_interior, RID)
#undef BINDBASE #undef BINDBASE
//from now on, calls forwarded to this singleton //from now on, calls forwarded to this singleton
#define BINDBASE RSG::scene #define BINDBASE RSG::scene
@ -485,6 +506,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)
BIND5(instance_set_use_lightmap, RID, RID, RID, int, const Rect2 &)
BIND2(instance_set_custom_aabb, RID, AABB) BIND2(instance_set_custom_aabb, RID, AABB)

View File

@ -286,6 +286,18 @@ void *RenderingServerScene::_instance_pair(void *p_self, SpatialPartitionID, Ins
} }
geom->lighting_dirty = true; geom->lighting_dirty = true;
return E; //this element should make freeing faster
} else if (B->base_type == RS::INSTANCE_LIGHTMAP_CAPTURE && ((1 << A->base_type) & RS::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);
((RenderingServerScene *)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 == RS::INSTANCE_REFLECTION_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) { } else if (B->base_type == RS::INSTANCE_REFLECTION_PROBE && ((1 << A->base_type) & RS::INSTANCE_GEOMETRY_MASK)) {
InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(B->base_data); InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(B->base_data);
@ -339,6 +351,16 @@ void RenderingServerScene::_instance_unpair(void *p_self, SpatialPartitionID, In
reflection_probe->geometries.erase(E); reflection_probe->geometries.erase(E);
geom->reflection_dirty = true; geom->reflection_dirty = true;
} else if (B->base_type == RS::INSTANCE_LIGHTMAP_CAPTURE && ((1 << A->base_type) & RS::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);
((RenderingServerScene *)p_self)->_instance_queue_update(A, false, false); //need to update capture
} }
} }
@ -473,6 +495,13 @@ void RenderingServerScene::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 RS::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(), -1, Rect2(0, 0, 1, 1));
}
} break;
default: { default: {
} }
} }
@ -527,6 +556,11 @@ void RenderingServerScene::instance_set_base(RID p_instance, RID p_base) {
reflection_probe->instance = RSG::scene_render->reflection_probe_instance_create(p_base); reflection_probe->instance = RSG::scene_render->reflection_probe_instance_create(p_base);
} break; } break;
case RS::INSTANCE_LIGHTMAP_CAPTURE: {
InstanceLightmapCaptureData *lightmap_capture = memnew(InstanceLightmapCaptureData);
instance->base_data = lightmap_capture;
//lightmap_capture->instance = RSG::scene_render->lightmap_capture_instance_create(p_base);
} break;
default: { default: {
} }
@ -961,6 +995,12 @@ void RenderingServerScene::instance_set_visible(RID p_instance, bool p_visible)
instance->scenario->sps->set_pairable(instance, p_visible, 1 << RS::INSTANCE_REFLECTION_PROBE, p_visible ? RS::INSTANCE_GEOMETRY_MASK : 0); instance->scenario->sps->set_pairable(instance, p_visible, 1 << RS::INSTANCE_REFLECTION_PROBE, p_visible ? RS::INSTANCE_GEOMETRY_MASK : 0);
} }
} break;
case RS::INSTANCE_LIGHTMAP_CAPTURE: {
if (instance->spatial_partition_id && instance->scenario) {
instance->scenario->sps->set_pairable(instance, p_visible, 1 << RS::INSTANCE_LIGHTMAP_CAPTURE, p_visible ? RS::INSTANCE_GEOMETRY_MASK : 0);
}
} break; } break;
default: { default: {
// if we haven't called set_pairable, we STILL need to do a collision check // if we haven't called set_pairable, we STILL need to do a collision check
@ -975,6 +1015,36 @@ inline bool is_geometry_instance(RenderingServer::InstanceType p_type) {
return p_type == RS::INSTANCE_MESH || p_type == RS::INSTANCE_MULTIMESH || p_type == RS::INSTANCE_IMMEDIATE; return p_type == RS::INSTANCE_MESH || p_type == RS::INSTANCE_MULTIMESH || p_type == RS::INSTANCE_IMMEDIATE;
} }
void RenderingServerScene::instance_set_use_lightmap(RID p_instance, RID p_lightmap_instance, RID p_lightmap, int p_lightmap_slice, const Rect2 &p_lightmap_uv_rect) {
Instance *instance = instance_owner.get(p_instance);
ERR_FAIL_COND(!instance);
instance->lightmap = RID();
instance->lightmap_slice = -1;
instance->lightmap_uv_rect = Rect2(0, 0, 1, 1);
instance->baked_light = false;
if (instance->lightmap_capture) {
InstanceLightmapCaptureData *lightmap_capture = static_cast<InstanceLightmapCaptureData *>(((Instance *)instance->lightmap_capture)->base_data);
lightmap_capture->users.erase(instance);
instance->lightmap_capture = nullptr;
}
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 != RS::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;
instance->lightmap_slice = p_lightmap_slice;
instance->lightmap_uv_rect = p_lightmap_uv_rect;
instance->baked_light = true;
}
}
void RenderingServerScene::instance_set_custom_aabb(RID p_instance, AABB p_aabb) { void RenderingServerScene::instance_set_custom_aabb(RID p_instance, AABB p_aabb) {
Instance *instance = instance_owner.get(p_instance); Instance *instance = instance_owner.get(p_instance);
ERR_FAIL_COND(!instance); ERR_FAIL_COND(!instance);
@ -1729,6 +1799,13 @@ void RenderingServerScene::_update_instance(Instance *p_instance) {
reflection_probe->reflection_dirty = true; reflection_probe->reflection_dirty = true;
} }
if (p_instance->base_type == RS::INSTANCE_LIGHTMAP_CAPTURE) {
InstanceLightmapCaptureData *capture = static_cast<InstanceLightmapCaptureData *>(p_instance->base_data);
for (List<InstanceLightmapCaptureData::PairInfo>::Element *E = capture->geometries.front(); E; E = E->next()) {
_instance_queue_update(E->get().geometry, false, true);
}
}
if (p_instance->aabb.has_no_surface()) { if (p_instance->aabb.has_no_surface()) {
return; return;
} }
@ -1743,6 +1820,15 @@ void RenderingServerScene::_update_instance(Instance *p_instance) {
light->make_shadow_dirty(); light->make_shadow_dirty();
} }
} }
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 = instance_xform->basis.determinant() < 0.0; p_instance->mirror = instance_xform->basis.determinant() < 0.0;
@ -1762,7 +1848,7 @@ void RenderingServerScene::_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 == RS::INSTANCE_LIGHT || p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE) { if (p_instance->base_type == RS::INSTANCE_LIGHT || p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE || p_instance->base_type == RS::INSTANCE_LIGHTMAP_CAPTURE) {
pairable_mask = p_instance->visible ? RS::INSTANCE_GEOMETRY_MASK : 0; pairable_mask = p_instance->visible ? RS::INSTANCE_GEOMETRY_MASK : 0;
pairable = true; pairable = true;
} }
@ -1824,6 +1910,10 @@ void RenderingServerScene::_update_instance_aabb(Instance *p_instance) {
case RenderingServer::INSTANCE_REFLECTION_PROBE: { case RenderingServer::INSTANCE_REFLECTION_PROBE: {
new_aabb = RSG::storage->reflection_probe_get_aabb(p_instance->base); new_aabb = RSG::storage->reflection_probe_get_aabb(p_instance->base);
} break;
case RenderingServer::INSTANCE_LIGHTMAP_CAPTURE: {
new_aabb = RSG::storage->lightmap_capture_get_bounds(p_instance->base);
} break; } break;
default: { default: {
} }
@ -1966,6 +2056,254 @@ void RenderingServerScene::_update_dirty_instance(Instance *p_instance) {
p_instance->update_materials = false; p_instance->update_materials = false;
} }
_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];
memset(alpha, 0, 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] = 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) {
constexpr float ONE_1024TH = 1.0 / 1024.0;
color[c][n].x += p_octree[cell].light[i][0] * ONE_1024TH * amount;
color[c][n].y += p_octree[cell].light[i][1] * ONE_1024TH * amount;
color[c][n].z += p_octree[cell].light[i][2] * ONE_1024TH * 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];
float target_level_size_inv = 1.0f / target_level_size;
real_t res;
res = pos.x * target_level_size_inv;
pos_fract[0].x = res - (int)res;
res = pos.y * target_level_size_inv;
pos_fract[0].y = res - (int)res;
res = pos.z * target_level_size_inv;
pos_fract[0].z = res - (int)res;
target_level_size = size >> MAX(0, target_level - 1);
target_level_size_inv = 1.0f / target_level_size;
res = pos.x * target_level_size_inv;
pos_fract[1].x = res - (int)res;
res = pos.y * target_level_size_inv;
pos_fract[1].y = res - (int)res;
res = pos.z * target_level_size_inv;
pos_fract[1].z = res - (int)res;
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 RenderingServerScene::_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);
for (int i = 0; i < 12; i++) {
new (&p_instance->lightmap_capture_data.ptrw()[i]) Color;
}
bool interior = true;
//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 = RSG::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 = RSG::storage->lightmap_capture_get_octree_cell_transform(E->get()->base);
int cell_subdiv = RSG::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);
const float capture_energy = RSG::storage->lightmap_capture_get_energy(E->get()->base);
interior = interior && RSG::storage->lightmap_capture_is_interior(E->get()->base);
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);
capture.r *= capture_energy;
capture.g *= capture_energy;
capture.b *= capture_energy;
p_instance->lightmap_capture_data.write[i] += capture;
}
}
p_instance->lightmap_capture_data.write[0].a = interior ? 0.0f : 1.0f;
}
bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario, uint32_t p_visible_layers) { bool RenderingServerScene::_light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario, uint32_t p_visible_layers) {
InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data); InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data);
@ -2846,6 +3184,7 @@ bool RenderingServerScene::free(RID p_rid) {
_interpolation_data.notify_free_instance(p_rid, *instance); _interpolation_data.notify_free_instance(p_rid, *instance);
instance_set_use_lightmap(p_rid, RID(), RID(), -1, Rect2(0, 0, 1, 1));
instance_set_scenario(p_rid, RID()); instance_set_scenario(p_rid, RID());
instance_set_base(p_rid, RID()); instance_set_base(p_rid, RID());
instance_geometry_set_material_override(p_rid, RID()); instance_geometry_set_material_override(p_rid, RID());

View File

@ -418,6 +418,8 @@ public:
List<Instance *> reflection_probes; List<Instance *> reflection_probes;
bool reflection_dirty; bool reflection_dirty;
List<Instance *> lightmap_captures;
InstanceGeometryData() { InstanceGeometryData() {
lighting_dirty = true; lighting_dirty = true;
reflection_dirty = true; reflection_dirty = true;
@ -521,6 +523,19 @@ public:
} }
}; };
struct InstanceLightmapCaptureData : public InstanceBaseData {
struct PairInfo {
List<Instance *>::Element *L; //iterator in geometry
Instance *geometry;
};
List<PairInfo> geometries;
RBSet<Instance *> users;
InstanceLightmapCaptureData() {
}
};
int instance_cull_count; int instance_cull_count;
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
@ -547,6 +562,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, int p_lightmap_slice, const Rect2 &p_lightmap_uv_rect);
virtual void instance_set_custom_aabb(RID p_instance, AABB p_aabb); virtual void instance_set_custom_aabb(RID p_instance, AABB p_aabb);
@ -753,6 +769,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_ bool _light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario, uint32_t p_visible_layers = 0xFFFFFF); _FORCE_INLINE_ bool _light_instance_update_shadow(Instance *p_instance, const Transform p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, RID p_shadow_atlas, Scenario *p_scenario, uint32_t p_visible_layers = 0xFFFFFF);

View File

@ -153,6 +153,7 @@ void RenderingServerWrapMT::finish() {
omni_light_free_cached_ids(); omni_light_free_cached_ids();
spot_light_free_cached_ids(); spot_light_free_cached_ids();
reflection_probe_free_cached_ids(); reflection_probe_free_cached_ids();
lightmap_capture_free_cached_ids();
camera_free_cached_ids(); camera_free_cached_ids();
viewport_free_cached_ids(); viewport_free_cached_ids();
environment_free_cached_ids(); environment_free_cached_ids();

View File

@ -283,6 +283,24 @@ public:
FUNC2(reflection_probe_set_cull_mask, RID, uint32_t) FUNC2(reflection_probe_set_cull_mask, RID, uint32_t)
FUNC2(reflection_probe_set_resolution, RID, int) FUNC2(reflection_probe_set_resolution, RID, int)
/* 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)
FUNC2(lightmap_capture_set_interior, RID, bool)
FUNC1RC(bool, lightmap_capture_is_interior, RID)
/* CAMERA API */ /* CAMERA API */
FUNCRID(camera) FUNCRID(camera)
@ -397,6 +415,7 @@ 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)
FUNC5(instance_set_use_lightmap, RID, RID, RID, int, const Rect2 &)
FUNC2(instance_set_custom_aabb, RID, AABB) FUNC2(instance_set_custom_aabb, RID, AABB)

View File

@ -2023,6 +2023,19 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("reflection_probe_set_enable_shadows", "probe", "enable"), &RenderingServer::reflection_probe_set_enable_shadows); ClassDB::bind_method(D_METHOD("reflection_probe_set_enable_shadows", "probe", "enable"), &RenderingServer::reflection_probe_set_enable_shadows);
ClassDB::bind_method(D_METHOD("reflection_probe_set_cull_mask", "probe", "layers"), &RenderingServer::reflection_probe_set_cull_mask); ClassDB::bind_method(D_METHOD("reflection_probe_set_cull_mask", "probe", "layers"), &RenderingServer::reflection_probe_set_cull_mask);
ClassDB::bind_method(D_METHOD("lightmap_capture_create"), &RenderingServer::lightmap_capture_create);
ClassDB::bind_method(D_METHOD("lightmap_capture_set_bounds", "capture", "bounds"), &RenderingServer::lightmap_capture_set_bounds);
ClassDB::bind_method(D_METHOD("lightmap_capture_get_bounds", "capture"), &RenderingServer::lightmap_capture_get_bounds);
ClassDB::bind_method(D_METHOD("lightmap_capture_set_octree", "capture", "octree"), &RenderingServer::lightmap_capture_set_octree);
ClassDB::bind_method(D_METHOD("lightmap_capture_set_octree_cell_transform", "capture", "xform"), &RenderingServer::lightmap_capture_set_octree_cell_transform);
ClassDB::bind_method(D_METHOD("lightmap_capture_get_octree_cell_transform", "capture"), &RenderingServer::lightmap_capture_get_octree_cell_transform);
ClassDB::bind_method(D_METHOD("lightmap_capture_set_octree_cell_subdiv", "capture", "subdiv"), &RenderingServer::lightmap_capture_set_octree_cell_subdiv);
ClassDB::bind_method(D_METHOD("lightmap_capture_get_octree_cell_subdiv", "capture"), &RenderingServer::lightmap_capture_get_octree_cell_subdiv);
ClassDB::bind_method(D_METHOD("lightmap_capture_get_octree", "capture"), &RenderingServer::lightmap_capture_get_octree);
ClassDB::bind_method(D_METHOD("lightmap_capture_set_energy", "capture", "energy"), &RenderingServer::lightmap_capture_set_energy);
ClassDB::bind_method(D_METHOD("lightmap_capture_get_energy", "capture"), &RenderingServer::lightmap_capture_get_energy);
ClassDB::bind_method(D_METHOD("lightmap_capture_set_interior", "capture", "interior"), &RenderingServer::lightmap_capture_set_interior);
ClassDB::bind_method(D_METHOD("lightmap_capture_is_interior", "capture"), &RenderingServer::lightmap_capture_is_interior);
#endif #endif
ClassDB::bind_method(D_METHOD("camera_create"), &RenderingServer::camera_create); ClassDB::bind_method(D_METHOD("camera_create"), &RenderingServer::camera_create);
@ -2111,6 +2124,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("instance_set_blend_shape_weight", "instance", "shape", "weight"), &RenderingServer::instance_set_blend_shape_weight); ClassDB::bind_method(D_METHOD("instance_set_blend_shape_weight", "instance", "shape", "weight"), &RenderingServer::instance_set_blend_shape_weight);
ClassDB::bind_method(D_METHOD("instance_set_surface_material", "instance", "surface", "material"), &RenderingServer::instance_set_surface_material); ClassDB::bind_method(D_METHOD("instance_set_surface_material", "instance", "surface", "material"), &RenderingServer::instance_set_surface_material);
ClassDB::bind_method(D_METHOD("instance_set_visible", "instance", "visible"), &RenderingServer::instance_set_visible); ClassDB::bind_method(D_METHOD("instance_set_visible", "instance", "visible"), &RenderingServer::instance_set_visible);
ClassDB::bind_method(D_METHOD("instance_set_use_lightmap", "instance", "lightmap_instance", "lightmap", "lightmap_slice", "lightmap_uv_rect"), &RenderingServer::instance_set_use_lightmap, DEFVAL(-1), DEFVAL(Rect2(0, 0, 1, 1)));
ClassDB::bind_method(D_METHOD("instance_set_custom_aabb", "instance", "aabb"), &RenderingServer::instance_set_custom_aabb); ClassDB::bind_method(D_METHOD("instance_set_custom_aabb", "instance", "aabb"), &RenderingServer::instance_set_custom_aabb);
ClassDB::bind_method(D_METHOD("instance_attach_skeleton", "instance", "skeleton"), &RenderingServer::instance_attach_skeleton); ClassDB::bind_method(D_METHOD("instance_attach_skeleton", "instance", "skeleton"), &RenderingServer::instance_attach_skeleton);
ClassDB::bind_method(D_METHOD("instance_set_exterior", "instance", "enabled"), &RenderingServer::instance_set_exterior); ClassDB::bind_method(D_METHOD("instance_set_exterior", "instance", "enabled"), &RenderingServer::instance_set_exterior);
@ -2403,9 +2417,11 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(INSTANCE_IMMEDIATE); BIND_ENUM_CONSTANT(INSTANCE_IMMEDIATE);
BIND_ENUM_CONSTANT(INSTANCE_LIGHT); BIND_ENUM_CONSTANT(INSTANCE_LIGHT);
BIND_ENUM_CONSTANT(INSTANCE_REFLECTION_PROBE); BIND_ENUM_CONSTANT(INSTANCE_REFLECTION_PROBE);
BIND_ENUM_CONSTANT(INSTANCE_LIGHTMAP_CAPTURE);
BIND_ENUM_CONSTANT(INSTANCE_MAX); BIND_ENUM_CONSTANT(INSTANCE_MAX);
BIND_ENUM_CONSTANT(INSTANCE_GEOMETRY_MASK); BIND_ENUM_CONSTANT(INSTANCE_GEOMETRY_MASK);
BIND_ENUM_CONSTANT(INSTANCE_FLAG_USE_BAKED_LIGHT);
BIND_ENUM_CONSTANT(INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE); BIND_ENUM_CONSTANT(INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE);
BIND_ENUM_CONSTANT(INSTANCE_FLAG_MAX); BIND_ENUM_CONSTANT(INSTANCE_FLAG_MAX);

View File

@ -526,6 +526,22 @@ public:
virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) = 0; virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) = 0;
virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution) = 0; virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution) = 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;
virtual void lightmap_capture_set_interior(RID p_capture, bool p_interior) = 0;
virtual bool lightmap_capture_is_interior(RID p_capture) const = 0;
/* CAMERA API */ /* CAMERA API */
virtual RID camera_create() = 0; virtual RID camera_create() = 0;
@ -757,6 +773,7 @@ public:
INSTANCE_IMMEDIATE, INSTANCE_IMMEDIATE,
INSTANCE_LIGHT, INSTANCE_LIGHT,
INSTANCE_REFLECTION_PROBE, INSTANCE_REFLECTION_PROBE,
INSTANCE_LIGHTMAP_CAPTURE,
INSTANCE_MAX, INSTANCE_MAX,
INSTANCE_GEOMETRY_MASK = (1 << INSTANCE_MESH) | (1 << INSTANCE_MULTIMESH) | (1 << INSTANCE_IMMEDIATE) INSTANCE_GEOMETRY_MASK = (1 << INSTANCE_MESH) | (1 << INSTANCE_MULTIMESH) | (1 << INSTANCE_IMMEDIATE)
@ -778,6 +795,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, int p_lightmap_slice, const Rect2 &p_lightmap_uv_rect) = 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;
@ -874,7 +893,8 @@ public:
Array _instances_cull_convex_bind(const Array &p_convex, RID p_scenario = RID()) const; Array _instances_cull_convex_bind(const Array &p_convex, RID p_scenario = RID()) const;
enum InstanceFlags { enum InstanceFlags {
INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, INSTANCE_FLAG_USE_BAKED_LIGHT,
INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE,
INSTANCE_FLAG_MAX INSTANCE_FLAG_MAX
}; };