You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-05 12:10:55 +00:00
Merge pull request #107839 from Rudolph-B/Occlusion-Culling-Optimization
Minor Optimization to Occlusion Culling
This commit is contained in:
@@ -45,20 +45,6 @@ Vector3 Vector3::rotated(const Vector3 &p_axis, real_t p_angle) const {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 Vector3::clamp(const Vector3 &p_min, const Vector3 &p_max) const {
|
|
||||||
return Vector3(
|
|
||||||
CLAMP(x, p_min.x, p_max.x),
|
|
||||||
CLAMP(y, p_min.y, p_max.y),
|
|
||||||
CLAMP(z, p_min.z, p_max.z));
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector3 Vector3::clampf(real_t p_min, real_t p_max) const {
|
|
||||||
return Vector3(
|
|
||||||
CLAMP(x, p_min, p_max),
|
|
||||||
CLAMP(y, p_min, p_max),
|
|
||||||
CLAMP(z, p_min, p_max));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Vector3::snap(const Vector3 &p_step) {
|
void Vector3::snap(const Vector3 &p_step) {
|
||||||
x = Math::snapped(x, p_step.x);
|
x = Math::snapped(x, p_step.x);
|
||||||
y = Math::snapped(y, p_step.y);
|
y = Math::snapped(y, p_step.y);
|
||||||
|
|||||||
@@ -106,6 +106,20 @@ struct [[nodiscard]] Vector3 {
|
|||||||
return Vector3(MAX(x, p_scalar), MAX(y, p_scalar), MAX(z, p_scalar));
|
return Vector3(MAX(x, p_scalar), MAX(y, p_scalar), MAX(z, p_scalar));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector3 clamp(const Vector3 &p_min, const Vector3 &p_max) const {
|
||||||
|
return Vector3(
|
||||||
|
CLAMP(x, p_min.x, p_max.x),
|
||||||
|
CLAMP(y, p_min.y, p_max.y),
|
||||||
|
CLAMP(z, p_min.z, p_max.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 clampf(real_t p_min, real_t p_max) const {
|
||||||
|
return Vector3(
|
||||||
|
CLAMP(x, p_min, p_max),
|
||||||
|
CLAMP(y, p_min, p_max),
|
||||||
|
CLAMP(z, p_min, p_max));
|
||||||
|
}
|
||||||
|
|
||||||
_FORCE_INLINE_ real_t length() const;
|
_FORCE_INLINE_ real_t length() const;
|
||||||
_FORCE_INLINE_ real_t length_squared() const;
|
_FORCE_INLINE_ real_t length_squared() const;
|
||||||
|
|
||||||
@@ -151,8 +165,6 @@ struct [[nodiscard]] Vector3 {
|
|||||||
_FORCE_INLINE_ Vector3 sign() const;
|
_FORCE_INLINE_ Vector3 sign() const;
|
||||||
_FORCE_INLINE_ Vector3 ceil() const;
|
_FORCE_INLINE_ Vector3 ceil() const;
|
||||||
_FORCE_INLINE_ Vector3 round() const;
|
_FORCE_INLINE_ Vector3 round() const;
|
||||||
Vector3 clamp(const Vector3 &p_min, const Vector3 &p_max) const;
|
|
||||||
Vector3 clampf(real_t p_min, real_t p_max) const;
|
|
||||||
|
|
||||||
_FORCE_INLINE_ real_t distance_to(const Vector3 &p_to) const;
|
_FORCE_INLINE_ real_t distance_to(const Vector3 &p_to) const;
|
||||||
_FORCE_INLINE_ real_t distance_squared_to(const Vector3 &p_to) const;
|
_FORCE_INLINE_ real_t distance_squared_to(const Vector3 &p_to) const;
|
||||||
|
|||||||
@@ -2824,6 +2824,7 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
|
|||||||
|
|
||||||
Transform3D inv_cam_transform = cull_data.cam_transform.inverse();
|
Transform3D inv_cam_transform = cull_data.cam_transform.inverse();
|
||||||
float z_near = cull_data.camera_matrix->get_z_near();
|
float z_near = cull_data.camera_matrix->get_z_near();
|
||||||
|
bool is_orthogonal = cull_data.camera_matrix->is_orthogonal();
|
||||||
|
|
||||||
for (uint64_t i = p_from; i < p_to; i++) {
|
for (uint64_t i = p_from; i < p_to; i++) {
|
||||||
bool mesh_visible = false;
|
bool mesh_visible = false;
|
||||||
@@ -2838,7 +2839,7 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
|
|||||||
#define VIS_RANGE_CHECK ((idata.visibility_index == -1) || _visibility_range_check<false>(cull_data.scenario->instance_visibility[idata.visibility_index], cull_data.cam_transform.origin, cull_data.visibility_viewport_mask) == 0)
|
#define VIS_RANGE_CHECK ((idata.visibility_index == -1) || _visibility_range_check<false>(cull_data.scenario->instance_visibility[idata.visibility_index], cull_data.cam_transform.origin, cull_data.visibility_viewport_mask) == 0)
|
||||||
#define VIS_PARENT_CHECK (_visibility_parent_check(cull_data, idata))
|
#define VIS_PARENT_CHECK (_visibility_parent_check(cull_data, idata))
|
||||||
#define VIS_CHECK (visibility_check < 0 ? (visibility_check = (visibility_flags != InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK || (VIS_RANGE_CHECK && VIS_PARENT_CHECK))) : visibility_check)
|
#define VIS_CHECK (visibility_check < 0 ? (visibility_check = (visibility_flags != InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK || (VIS_RANGE_CHECK && VIS_PARENT_CHECK))) : visibility_check)
|
||||||
#define OCCLUSION_CULLED (cull_data.occlusion_buffer != nullptr && (cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_IGNORE_OCCLUSION_CULLING) == 0 && cull_data.occlusion_buffer->is_occluded(cull_data.scenario->instance_aabbs[i].bounds, cull_data.cam_transform.origin, inv_cam_transform, *cull_data.camera_matrix, z_near, cull_data.scenario->instance_data[i].occlusion_timeout))
|
#define OCCLUSION_CULLED (cull_data.occlusion_buffer != nullptr && (cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_IGNORE_OCCLUSION_CULLING) == 0 && cull_data.occlusion_buffer->is_occluded(cull_data.scenario->instance_aabbs[i].bounds, cull_data.cam_transform.origin, inv_cam_transform, *cull_data.camera_matrix, z_near, is_orthogonal, cull_data.scenario->instance_data[i].occlusion_timeout))
|
||||||
|
|
||||||
if (!HIDDEN_BY_VISIBILITY_CHECKS) {
|
if (!HIDDEN_BY_VISIBILITY_CHECKS) {
|
||||||
if ((LAYER_CHECK && IN_FRUSTUM(cull_data.cull->frustum) && VIS_CHECK && !OCCLUSION_CULLED) || (cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_IGNORE_ALL_CULLING)) {
|
if ((LAYER_CHECK && IN_FRUSTUM(cull_data.cull->frustum) && VIS_CHECK && !OCCLUSION_CULLED) || (cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_IGNORE_ALL_CULLING)) {
|
||||||
|
|||||||
@@ -32,23 +32,8 @@
|
|||||||
|
|
||||||
RendererSceneOcclusionCull *RendererSceneOcclusionCull::singleton = nullptr;
|
RendererSceneOcclusionCull *RendererSceneOcclusionCull::singleton = nullptr;
|
||||||
|
|
||||||
const Vector3 RendererSceneOcclusionCull::HZBuffer::corners[8] = {
|
|
||||||
Vector3(0, 0, 0),
|
|
||||||
Vector3(0, 0, 1),
|
|
||||||
Vector3(0, 1, 0),
|
|
||||||
Vector3(0, 1, 1),
|
|
||||||
Vector3(1, 0, 0),
|
|
||||||
Vector3(1, 0, 1),
|
|
||||||
Vector3(1, 1, 0),
|
|
||||||
Vector3(1, 1, 1)
|
|
||||||
};
|
|
||||||
|
|
||||||
bool RendererSceneOcclusionCull::HZBuffer::occlusion_jitter_enabled = false;
|
bool RendererSceneOcclusionCull::HZBuffer::occlusion_jitter_enabled = false;
|
||||||
|
|
||||||
bool RendererSceneOcclusionCull::HZBuffer::is_empty() const {
|
|
||||||
return sizes.is_empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RendererSceneOcclusionCull::HZBuffer::clear() {
|
void RendererSceneOcclusionCull::HZBuffer::clear() {
|
||||||
if (sizes.is_empty()) {
|
if (sizes.is_empty()) {
|
||||||
return; // Already cleared
|
return; // Already cleared
|
||||||
|
|||||||
@@ -41,8 +41,6 @@ protected:
|
|||||||
public:
|
public:
|
||||||
class HZBuffer {
|
class HZBuffer {
|
||||||
protected:
|
protected:
|
||||||
static const Vector3 corners[8];
|
|
||||||
|
|
||||||
LocalVector<float> data;
|
LocalVector<float> data;
|
||||||
LocalVector<Size2i> sizes;
|
LocalVector<Size2i> sizes;
|
||||||
LocalVector<float *> mips;
|
LocalVector<float *> mips;
|
||||||
@@ -55,7 +53,7 @@ public:
|
|||||||
uint64_t occlusion_frame = 0;
|
uint64_t occlusion_frame = 0;
|
||||||
Size2i occlusion_buffer_size;
|
Size2i occlusion_buffer_size;
|
||||||
|
|
||||||
_FORCE_INLINE_ bool _is_occluded(const real_t p_bounds[6], const Vector3 &p_cam_position, const Transform3D &p_cam_inv_transform, const Projection &p_cam_projection, real_t p_near) const {
|
_FORCE_INLINE_ bool _is_occluded(const real_t p_bounds[6], const Vector3 &p_cam_position, const Transform3D &p_cam_inv_transform, const Projection &p_cam_projection, real_t p_near, bool p_is_orthogonal) const {
|
||||||
if (is_empty()) {
|
if (is_empty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -79,27 +77,27 @@ public:
|
|||||||
Vector2 rect_max = Vector2(FLT_MIN, FLT_MIN);
|
Vector2 rect_max = Vector2(FLT_MIN, FLT_MIN);
|
||||||
|
|
||||||
for (int j = 0; j < 8; j++) {
|
for (int j = 0; j < 8; j++) {
|
||||||
const Vector3 &c = RendererSceneOcclusionCull::HZBuffer::corners[j];
|
// Bitmask to cycle through the corners of the AABB.
|
||||||
Vector3 nc = Vector3(1, 1, 1) - c;
|
Vector3 corner = Vector3(
|
||||||
Vector3 corner = Vector3(p_bounds[0] * c.x + p_bounds[3] * nc.x, p_bounds[1] * c.y + p_bounds[4] * nc.y, p_bounds[2] * c.z + p_bounds[5] * nc.z);
|
j & 4 ? p_bounds[0] : p_bounds[3],
|
||||||
|
j & 2 ? p_bounds[1] : p_bounds[4],
|
||||||
|
j & 1 ? p_bounds[2] : p_bounds[5]);
|
||||||
Vector3 view = p_cam_inv_transform.xform(corner);
|
Vector3 view = p_cam_inv_transform.xform(corner);
|
||||||
|
|
||||||
// When using an orthogonal camera, the closest point of an AABB to the camera is guaranteed to be a corner.
|
// When using an orthogonal camera, the closest point of an AABB to the camera is guaranteed to be a corner.
|
||||||
if (p_cam_projection.is_orthogonal()) {
|
if (p_is_orthogonal) {
|
||||||
min_depth = MIN(min_depth, -view.z);
|
min_depth = MIN(min_depth, -view.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
Plane vp = Plane(view, 1.0);
|
Vector3 projected = p_cam_projection.xform(view);
|
||||||
Plane projected = p_cam_projection.xform4(vp);
|
|
||||||
|
|
||||||
float w = projected.d;
|
if (-view.z < 0.0) {
|
||||||
if (w < 1.0) {
|
|
||||||
rect_min = Vector2(0.0f, 0.0f);
|
rect_min = Vector2(0.0f, 0.0f);
|
||||||
rect_max = Vector2(1.0f, 1.0f);
|
rect_max = Vector2(1.0f, 1.0f);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 normalized = Vector2(projected.normal.x / w * 0.5f + 0.5f, projected.normal.y / w * 0.5f + 0.5f);
|
Vector2 normalized = Vector2(projected.x * 0.5f + 0.5f, projected.y * 0.5f + 0.5f);
|
||||||
rect_min = rect_min.min(normalized);
|
rect_min = rect_min.min(normalized);
|
||||||
rect_max = rect_max.max(normalized);
|
rect_max = rect_max.max(normalized);
|
||||||
}
|
}
|
||||||
@@ -159,7 +157,10 @@ public:
|
|||||||
public:
|
public:
|
||||||
static bool occlusion_jitter_enabled;
|
static bool occlusion_jitter_enabled;
|
||||||
|
|
||||||
bool is_empty() const;
|
_FORCE_INLINE_ bool is_empty() const {
|
||||||
|
return sizes.is_empty();
|
||||||
|
}
|
||||||
|
|
||||||
virtual void clear();
|
virtual void clear();
|
||||||
virtual void resize(const Size2i &p_size);
|
virtual void resize(const Size2i &p_size);
|
||||||
|
|
||||||
@@ -168,8 +169,8 @@ public:
|
|||||||
// Thin wrapper around _is_occluded(),
|
// Thin wrapper around _is_occluded(),
|
||||||
// allowing occlusion timers to delay the disappearance
|
// allowing occlusion timers to delay the disappearance
|
||||||
// of objects to prevent flickering when using jittering.
|
// of objects to prevent flickering when using jittering.
|
||||||
_FORCE_INLINE_ bool is_occluded(const real_t p_bounds[6], const Vector3 &p_cam_position, const Transform3D &p_cam_inv_transform, const Projection &p_cam_projection, real_t p_near, uint64_t &r_occlusion_timeout) const {
|
_FORCE_INLINE_ bool is_occluded(const real_t p_bounds[6], const Vector3 &p_cam_position, const Transform3D &p_cam_inv_transform, const Projection &p_cam_projection, real_t p_near, bool p_is_orthogonal, uint64_t &r_occlusion_timeout) const {
|
||||||
bool occluded = _is_occluded(p_bounds, p_cam_position, p_cam_inv_transform, p_cam_projection, p_near);
|
bool occluded = _is_occluded(p_bounds, p_cam_position, p_cam_inv_transform, p_cam_projection, p_near, p_is_orthogonal);
|
||||||
|
|
||||||
// Special case, temporal jitter disabled,
|
// Special case, temporal jitter disabled,
|
||||||
// so we don't use occlusion timers.
|
// so we don't use occlusion timers.
|
||||||
|
|||||||
Reference in New Issue
Block a user