Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize Occlusion culling jitter #99974

Merged
merged 1 commit into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 21 additions & 20 deletions modules/raycast/raycast_occlusion_cull.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,23 +80,22 @@ void RaycastOcclusionCull::RaycastHZBuffer::resize(const Size2i &p_size) {
memset(camera_ray_masks.ptr(), ~0, camera_rays_tile_count * TILE_RAYS * sizeof(uint32_t));
}

void RaycastOcclusionCull::RaycastHZBuffer::update_camera_rays(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal) {
void RaycastOcclusionCull::RaycastHZBuffer::update_camera_rays(const Transform3D &p_cam_transform, const Vector3 &p_near_bottom_left, const Vector2 &p_near_extents, real_t p_z_far, bool p_cam_orthogonal) {
CameraRayThreadData td;
td.thread_count = WorkerThreadPool::get_singleton()->get_thread_count();

td.z_near = p_cam_projection.get_z_near();
td.z_far = p_cam_projection.get_z_far() * 1.05f;
td.z_near = -p_near_bottom_left.z;
td.z_far = p_z_far * 1.05f;
td.camera_pos = p_cam_transform.origin;
td.camera_dir = -p_cam_transform.basis.get_column(2);
td.camera_orthogonal = p_cam_orthogonal;

// Calculate the world coordinates of the viewport.
Vector2 viewport_half = p_cam_projection.get_viewport_half_extents();
td.pixel_corner = p_cam_transform.xform(Vector3(-viewport_half.x, -viewport_half.y, -p_cam_projection.get_z_near()));
Vector3 top_corner_world = p_cam_transform.xform(Vector3(-viewport_half.x, viewport_half.y, -p_cam_projection.get_z_near()));
Vector3 left_corner_world = p_cam_transform.xform(Vector3(viewport_half.x, -viewport_half.y, -p_cam_projection.get_z_near()));
td.pixel_corner = p_cam_transform.xform(p_near_bottom_left);
Vector3 top_corner_world = p_cam_transform.xform(p_near_bottom_left + Vector3(0, p_near_extents.y, 0));
Vector3 right_corner_world = p_cam_transform.xform(p_near_bottom_left + Vector3(p_near_extents.x, 0, 0));

td.pixel_u_interp = left_corner_world - td.pixel_corner;
td.pixel_u_interp = right_corner_world - td.pixel_corner;
td.pixel_v_interp = top_corner_world - td.pixel_corner;

debug_tex_range = td.z_far;
Expand Down Expand Up @@ -526,14 +525,14 @@ void RaycastOcclusionCull::buffer_set_size(RID p_buffer, const Vector2i &p_size)
buffers[p_buffer].resize(p_size);
}

Projection RaycastOcclusionCull::_jitter_projection(const Projection &p_cam_projection, const Size2i &p_viewport_size) {
Vector2 RaycastOcclusionCull::_jitter_half_extents(const Vector2 &p_half_extents, const Size2i &p_viewport_size) {
if (!_jitter_enabled) {
return p_cam_projection;
return p_half_extents;
}

// Prevent divide by zero when using NULL viewport.
if ((p_viewport_size.x <= 0) || (p_viewport_size.y <= 0)) {
return p_cam_projection;
return p_half_extents;
}

int32_t frame = Engine::get_singleton()->get_frames_drawn();
Expand Down Expand Up @@ -570,16 +569,16 @@ Projection RaycastOcclusionCull::_jitter_projection(const Projection &p_cam_proj
} break;
}

// The multiplier here determines the divergence from center,
// and is to some extent a balancing act.
// Higher divergence gives fewer false hidden, but more false shown.
jitter *= Vector2(p_half_extents.x / (float)p_viewport_size.x, p_half_extents.y / (float)p_viewport_size.y);

// The multiplier here determines the jitter magnitude in pixels.
// It seems like a value of 0.66 matches well the above jittering pattern as it generates subpixel samples at 0, 1/3 and 2/3
// Higher magnitude gives fewer false hidden, but more false shown.
// False hidden is obvious to viewer, false shown is not.
// False shown can lower percentage that are occluded, and therefore performance.
jitter *= Vector2(1 / (float)p_viewport_size.x, 1 / (float)p_viewport_size.y) * 0.9f;
jitter *= 0.66f;

Projection correction;
correction.add_jitter_offset(jitter);
return correction * p_cam_projection;
return p_half_extents + jitter;
}

void RaycastOcclusionCull::buffer_update(RID p_buffer, const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal) {
Expand All @@ -596,9 +595,11 @@ void RaycastOcclusionCull::buffer_update(RID p_buffer, const Transform3D &p_cam_
Scenario &scenario = scenarios[buffer.scenario_rid];
scenario.update();

Projection jittered_proj = _jitter_projection(p_cam_projection, buffer.get_occlusion_buffer_size());
Vector2 viewport_half = p_cam_projection.get_viewport_half_extents();
Vector2 jitter_viewport_half = _jitter_half_extents(viewport_half, buffer.get_occlusion_buffer_size());
Vector3 near_bottom_left = Vector3(-jitter_viewport_half.x, -jitter_viewport_half.y, -p_cam_projection.get_z_near());

buffer.update_camera_rays(p_cam_transform, jittered_proj, p_cam_orthogonal);
buffer.update_camera_rays(p_cam_transform, near_bottom_left, 2 * viewport_half, p_cam_projection.get_z_far(), p_cam_orthogonal);

scenario.raycast(buffer.camera_rays, buffer.camera_ray_masks.ptr(), buffer.camera_rays_tile_count);
buffer.sort_rays(-p_cam_transform.basis.get_column(2), p_cam_orthogonal);
Expand Down
4 changes: 2 additions & 2 deletions modules/raycast/raycast_occlusion_cull.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class RaycastOcclusionCull : public RendererSceneOcclusionCull {
virtual void clear() override;
virtual void resize(const Size2i &p_size) override;
void sort_rays(const Vector3 &p_camera_dir, bool p_orthogonal);
void update_camera_rays(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal);
void update_camera_rays(const Transform3D &p_cam_transform, const Vector3 &p_near_bottom_left, const Vector2 &p_near_extents, real_t p_z_far, bool p_cam_orthogonal);

~RaycastHZBuffer();
};
Expand Down Expand Up @@ -166,7 +166,7 @@ class RaycastOcclusionCull : public RendererSceneOcclusionCull {
bool _jitter_enabled = false;

void _init_embree();
Projection _jitter_projection(const Projection &p_cam_projection, const Size2i &p_viewport_size);
Vector2 _jitter_half_extents(const Vector2 &p_half_extents, const Size2i &p_viewport_size);

public:
virtual bool is_occluder(RID p_rid) override;
Expand Down
Loading