GPv3: Reverse Curve node #113702
|
@ -22,9 +22,9 @@
|
|||
|
||||
namespace blender::eevee {
|
||||
|
||||
bool VolumeModule::GridAABB::init(Object *ob, const Camera &camera, const VolumesInfoData &data)
|
||||
VolumeModule::GridAABB::GridAABB(Object *ob, const Camera &camera, const VolumesInfoData &data)
|
||||
{
|
||||
/* Returns the unified volume grid cell index of a world space coordinate. */
|
||||
/* Returns the unified volume grid cell corner of a world space coordinate. */
|
||||
auto to_global_grid_coords = [&](float3 wP) -> int3 {
|
||||
const float4x4 &view_matrix = camera.data_get().viewmat;
|
||||
const float4x4 &projection_matrix = camera.data_get().winmat;
|
||||
|
@ -38,41 +38,32 @@ bool VolumeModule::GridAABB::init(Object *ob, const Camera &camera, const Volume
|
|||
data.depth_distribution,
|
||||
data.coord_scale,
|
||||
ndc_coords);
|
||||
|
||||
return int3(grid_coords * float3(data.tex_size));
|
||||
/* Round to nearest grid corner. */
|
||||
return int3(grid_coords * float3(data.tex_size) + 0.5);
|
||||
};
|
||||
|
||||
const BoundBox &bbox = *BKE_object_boundbox_get(ob);
|
||||
min = int3(INT32_MAX);
|
||||
max = int3(INT32_MIN);
|
||||
|
||||
for (float3 corner : bbox.vec) {
|
||||
corner = math::transform_point(float4x4(ob->object_to_world), corner);
|
||||
int3 grid_coord = to_global_grid_coords(corner);
|
||||
min = math::min(min, grid_coord);
|
||||
max = math::max(max, grid_coord);
|
||||
for (float3 l_corner : bbox.vec) {
|
||||
float3 w_corner = math::transform_point(float4x4(ob->object_to_world), l_corner);
|
||||
/* Note that this returns the nearest cell corner coordinate.
|
||||
* So sub-froxel AABB will effectively return the same coordinate
|
||||
* for each corner (making it empty and skipped) unless it
|
||||
* cover the center of the froxel. */
|
||||
math::min_max(to_global_grid_coords(w_corner), min, max);
|
||||
}
|
||||
|
||||
bool is_visible = false;
|
||||
for (int i : IndexRange(3)) {
|
||||
is_visible = is_visible || (min[i] >= 0 && min[i] < data.tex_size[i]);
|
||||
is_visible = is_visible || (max[i] >= 0 && max[i] < data.tex_size[i]);
|
||||
}
|
||||
|
||||
min = math::clamp(min, int3(0), data.tex_size);
|
||||
max = math::clamp(max, int3(0), data.tex_size);
|
||||
|
||||
return is_visible;
|
||||
}
|
||||
|
||||
bool VolumeModule::GridAABB::overlaps(const GridAABB &aabb)
|
||||
bool VolumeModule::GridAABB::is_empty() const
|
||||
{
|
||||
for (int i : IndexRange(3)) {
|
||||
if (min[i] > aabb.max[i] || max[i] < aabb.min[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return math::reduce_min(max - min) <= 0;
|
||||
}
|
||||
|
||||
VolumeModule::GridAABB VolumeModule::GridAABB::intersect(const GridAABB &other) const
|
||||
{
|
||||
return {math::min(this->max, other.max), math::max(this->min, other.min)};
|
||||
}
|
||||
|
||||
void VolumeModule::init()
|
||||
|
@ -180,8 +171,11 @@ void VolumeModule::sync_object(Object *ob,
|
|||
return;
|
||||
}
|
||||
|
||||
GridAABB aabb;
|
||||
if (!aabb.init(ob, inst_.camera, data_)) {
|
||||
GridAABB object_aabb(ob, inst_.camera, data_);
|
||||
/* Remember that these are cells corners, so this extents to `tex_size`. */
|
||||
GridAABB view_aabb(int3(0), data_.tex_size);
|
||||
if (object_aabb.intersect(view_aabb).is_empty()) {
|
||||
/* Skip invisible object with respect to raster grid and bounds density. */
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -191,27 +185,25 @@ void VolumeModule::sync_object(Object *ob,
|
|||
enabled_ = true;
|
||||
|
||||
/* Add a barrier at the start of a subpass or when 2 volumes overlaps. */
|
||||
if (!subpass_aabbs_.contains_as(shader)) {
|
||||
if (!subpass_aabbs_.contains_as(shader) == false) {
|
||||
object_pass->barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
|
||||
subpass_aabbs_.add(shader, {aabb});
|
||||
subpass_aabbs_.add(shader, {object_aabb});
|
||||
}
|
||||
else {
|
||||
Vector<GridAABB> &aabbs = subpass_aabbs_.lookup(shader);
|
||||
for (GridAABB &_aabb : aabbs) {
|
||||
if (aabb.overlaps(_aabb)) {
|
||||
for (GridAABB &other_aabb : aabbs) {
|
||||
if (object_aabb.intersect(other_aabb).is_empty() == false) {
|
||||
object_pass->barrier(GPU_BARRIER_SHADER_IMAGE_ACCESS);
|
||||
aabbs.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
aabbs.append(aabb);
|
||||
aabbs.append(object_aabb);
|
||||
}
|
||||
|
||||
int3 grid_size = aabb.max - aabb.min + int3(1);
|
||||
|
||||
object_pass->push_constant("drw_ResourceID", int(res_handle.resource_index()));
|
||||
object_pass->push_constant("grid_coords_min", aabb.min);
|
||||
object_pass->dispatch(math::divide_ceil(grid_size, int3(VOLUME_GROUP_SIZE)));
|
||||
object_pass->push_constant("grid_coords_min", object_aabb.min);
|
||||
object_pass->dispatch(math::divide_ceil(object_aabb.extent(), int3(VOLUME_GROUP_SIZE)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -79,12 +79,25 @@ class VolumeModule {
|
|||
/* Axis aligned bounding box in the volume grid.
|
||||
* Used for frustum culling and volumes overlapping detection. */
|
||||
struct GridAABB {
|
||||
/* Represent min and max grid corners covered by a volume.
|
||||
* So a volume covering the first froxel will have min={0,0,0} and max={1,1,1}.
|
||||
* A volume with min={0,0,0} and max={0,0,0} covers nothing. */
|
||||
int3 min, max;
|
||||
|
||||
/* Returns true if visible. */
|
||||
bool init(Object *ob, const Camera &camera, const VolumesInfoData &data);
|
||||
GridAABB(int3 min_, int3 max_) : min(min_), max(max_){};
|
||||
GridAABB(Object *ob, const Camera &camera, const VolumesInfoData &data);
|
||||
|
||||
bool overlaps(const GridAABB &aabb);
|
||||
/** Returns the intersection between this AABB and the \a other AABB. */
|
||||
GridAABB intersect(const GridAABB &other) const;
|
||||
|
||||
/** Returns true if volume covers no froxel. */
|
||||
bool is_empty() const;
|
||||
|
||||
/** Returns the extent of the volume. */
|
||||
int3 extent() const
|
||||
{
|
||||
return max - min;
|
||||
}
|
||||
};
|
||||
/* Stores a vector of volume AABBs for each material pass,
|
||||
* so we can detect overlapping volumes and place GPU barriers where needed
|
||||
|
|
Loading…
Reference in New Issue