Skip to content

Commit

Permalink
Implement lod_{max,min}_distance and _hysteresis
Browse files Browse the repository at this point in the history
closes #6375
  • Loading branch information
Windfisch committed Nov 19, 2018
1 parent 634aa4f commit 40074ca
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 7 deletions.
2 changes: 2 additions & 0 deletions doc/classes/GeometryInstance.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@
</member>
<member name="lod_max_hysteresis" type="float" setter="set_lod_max_hysteresis" getter="get_lod_max_hysteresis">
The GeometryInstance's max LOD margin.
Margins are symmetrical around [member lod_max_distance].
</member>
<member name="lod_min_distance" type="float" setter="set_lod_min_distance" getter="get_lod_min_distance">
The GeometryInstance's min LOD distance.
</member>
<member name="lod_min_hysteresis" type="float" setter="set_lod_min_hysteresis" getter="get_lod_min_hysteresis">
The GeometryInstance's min LOD margin.
Margins are symmetrical around [member lod_min_distance].
</member>
<member name="material_override" type="Material" setter="set_material_override" getter="get_material_override">
The material override for the whole geometry.
Expand Down
52 changes: 47 additions & 5 deletions servers/visual/visual_server_scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "core/os/os.h"
#include "visual_server_global.h"
#include "visual_server_raster.h"

/* CAMERA API */

RID VisualServerScene::camera_create() {
Expand Down Expand Up @@ -859,6 +860,14 @@ void VisualServerScene::instance_geometry_set_material_override(RID p_instance,
}

void VisualServerScene::instance_geometry_set_draw_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) {

Instance *instance = instance_owner.get(p_instance);
ERR_FAIL_COND(!instance);

instance->lod_begin = p_min;
instance->lod_end = p_max;
instance->lod_begin_hysteresis = p_min_margin;
instance->lod_end_hysteresis = p_max_margin;
}
void VisualServerScene::instance_geometry_set_as_instance_lod(RID p_instance, RID p_as_lod_of_instance) {
}
Expand Down Expand Up @@ -1710,7 +1719,7 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario, Size2 p_view
} break;
}

_prepare_scene(camera->transform, camera_matrix, ortho, camera->env, camera->visible_layers, p_scenario, p_shadow_atlas, RID());
_prepare_scene(camera->transform, camera_matrix, ortho, camera->env, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), &camera->lod_hysteresis_visible_state);
_render_scene(camera->transform, camera_matrix, ortho, camera->env, p_scenario, p_shadow_atlas, RID(), -1);
#endif
}
Expand Down Expand Up @@ -1789,17 +1798,17 @@ void VisualServerScene::render_camera(Ref<ARVRInterface> &p_interface, ARVRInter
mono_transform *= apply_z_shift;

// now prepare our scene with our adjusted transform projection matrix
_prepare_scene(mono_transform, combined_matrix, false, camera->env, camera->visible_layers, p_scenario, p_shadow_atlas, RID());
_prepare_scene(mono_transform, combined_matrix, false, camera->env, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), &camera->lod_hysteresis_visible_state);
} else if (p_eye == ARVRInterface::EYE_MONO) {
// For mono render, prepare as per usual
_prepare_scene(cam_transform, camera_matrix, false, camera->env, camera->visible_layers, p_scenario, p_shadow_atlas, RID());
_prepare_scene(cam_transform, camera_matrix, false, camera->env, camera->visible_layers, p_scenario, p_shadow_atlas, RID(), &camera->lod_hysteresis_visible_state);
}

// And render our scene...
_render_scene(cam_transform, camera_matrix, false, camera->env, p_scenario, p_shadow_atlas, RID(), -1);
};

void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe) {
void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, OAHashMap<uint32_t, bool> *lod_visible_state) {
// Note, in stereo rendering:
// - p_cam_transform will be a transform in the middle of our two eyes
// - p_cam_projection is a wider frustrum that encompasses both eyes
Expand Down Expand Up @@ -1964,6 +1973,39 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca

ins->depth = near_plane.distance_to(ins->transform.origin);
ins->depth_layer = CLAMP(int(ins->depth * 16 / z_far), 0, 15);

// if lod is active, and the instance is not within its lod range, don't render it
if (ins->lod_begin > 0.f || ins->lod_end > 0.f) { // lod valid
float lod_begin_with_hys = ins->lod_begin;
float lod_end_with_hys = ins->lod_end;
bool prev_lod_state = false;
if (lod_visible_state != nullptr)
lod_visible_state->lookup(ins->self.get_id(), prev_lod_state);

if (prev_lod_state) {
lod_begin_with_hys -= ins->lod_begin_hysteresis / 2.f;
lod_end_with_hys += ins->lod_end_hysteresis / 2.f;
} else {
lod_begin_with_hys += ins->lod_begin_hysteresis / 2.f;
lod_end_with_hys -= ins->lod_end_hysteresis / 2.f;
}

if (ins->lod_begin <= 0.f) {
lod_begin_with_hys = -Math_INF;
}
if (ins->lod_end <= 0.f) {
lod_end_with_hys = +Math_INF;
}

if (lod_begin_with_hys <= ins->depth && ins->depth < lod_end_with_hys) {
if (lod_visible_state)
lod_visible_state->set(ins->self.get_id(), true);
} else {
if (lod_visible_state)
lod_visible_state->set(ins->self.get_id(), false);
keep = false;
}
}
}

if (!keep) {
Expand Down Expand Up @@ -2214,7 +2256,7 @@ bool VisualServerScene::_render_reflection_probe_step(Instance *p_instance, int
shadow_atlas = scenario->reflection_probe_shadow_atlas;
}

_prepare_scene(xform, cm, false, RID(), VSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, shadow_atlas, reflection_probe->instance);
_prepare_scene(xform, cm, false, RID(), VSG::storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, nullptr /* no LOD hysteresis handling */);
_render_scene(xform, cm, false, RID(), p_instance->scenario->self, shadow_atlas, reflection_probe->instance, p_step);

} else {
Expand Down
6 changes: 4 additions & 2 deletions servers/visual/visual_server_scene.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "core/allocators.h"
#include "core/math/geometry.h"
#include "core/math/octree.h"
#include "core/oa_hash_map.h"
#include "core/os/semaphore.h"
#include "core/os/thread.h"
#include "core/self_list.h"
Expand Down Expand Up @@ -90,6 +91,8 @@ class VisualServerScene {

Transform transform;

OAHashMap<uint32_t, bool> lod_hysteresis_visible_state;

Camera() {

visible_layers = 0xFFFFFFFF;
Expand Down Expand Up @@ -178,7 +181,6 @@ class VisualServerScene {
float lod_end;
float lod_begin_hysteresis;
float lod_end_hysteresis;
RID lod_instance;

uint64_t last_render_pass;
uint64_t last_frame_pass;
Expand Down Expand Up @@ -487,7 +489,7 @@ class VisualServerScene {

_FORCE_INLINE_ bool _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 _prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe);
void _prepare_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, uint32_t p_visible_layers, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, OAHashMap<uint32_t, bool> *lod_visible_state);
void _render_scene(const Transform p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, RID p_force_environment, RID p_scenario, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass);
void render_empty_scene(RID p_scenario, RID p_shadow_atlas);

Expand Down

0 comments on commit 40074ca

Please sign in to comment.