EEVEE: Add correct volumetric support for point clouds

Since 4.5 the point clouds are out of experimental.

The drawing of pointcloud did not allow for correct volume
estimation as the shape are not rendered as closed objects
(i.e. the backfaces were not rendered).

This patch renders the backfaces for the volume occupancy
pass by rendering the pointcloud twice and flipping the
shape alignment matrix. This reverse the winding and
does a backface hit as it would do for a sphere primitive.

This solution even if not perfect avoids adding more
geometry in the Index Buffer. The geometry approach might
be preferable in the future if we find a way to render
the spheres without an IBO or with a JIT generated IBO.

Rel  #141490

Pull Request: https://projects.blender.org/blender/blender/pulls/142095
This commit is contained in:
Clément Foucault
2025-07-24 12:05:29 +02:00
committed by Clément Foucault
parent 34e176d255
commit 50e876f21d
3 changed files with 19 additions and 3 deletions

View File

@@ -264,18 +264,28 @@ void SyncModule::sync_pointcloud(Object *ob, ObjectHandle &ob_handle, const Obje
Material &material = inst_.materials.material_get(
ob, has_motion, material_slot - 1, MAT_GEOM_POINTCLOUD);
auto drawcall_add = [&](MaterialPass &matpass) {
auto drawcall_add = [&](MaterialPass &matpass, bool dual_sided = false) {
if (matpass.sub_pass == nullptr) {
return;
}
PassMain::Sub &object_pass = matpass.sub_pass->sub("Point Cloud Sub Pass");
gpu::Batch *geometry = pointcloud_sub_pass_setup(object_pass, ob, matpass.gpumat);
object_pass.draw(geometry, res_handle);
if (dual_sided) {
/* WORKAROUND: Hack to generate backfaces. Should also be baked into the Index Buf too at
* some point in the future. */
object_pass.push_constant("ptcloud_backface", false);
object_pass.draw(geometry, res_handle);
object_pass.push_constant("ptcloud_backface", true);
object_pass.draw(geometry, res_handle);
}
else {
object_pass.draw(geometry, res_handle);
}
};
if (material.has_volume) {
/* Only support single volume material for now. */
drawcall_add(material.volume_occupancy);
drawcall_add(material.volume_occupancy, true);
drawcall_add(material.volume_material);
inst_.volume.object_sync(ob_handle);

View File

@@ -64,6 +64,7 @@ GPU_SHADER_NAMED_INTERFACE_END(pointcloud_interp_flat)
GPU_SHADER_CREATE_INFO(eevee_geom_pointcloud)
ADDITIONAL_INFO(eevee_shared)
PUSH_CONSTANT(bool, ptcloud_backface)
DEFINE("MAT_GEOM_POINTCLOUD")
VERTEX_SOURCE("eevee_geom_pointcloud_vert.glsl")
VERTEX_OUT(eevee_surf_iface)

View File

@@ -27,6 +27,11 @@ float3x3 pointcloud_get_facing_matrix(float3 p)
{
float3x3 facing_mat;
facing_mat[2] = drw_world_incident_vector(p);
# ifdef MAT_GEOM_POINTCLOUD
if (ptcloud_backface) {
facing_mat[2] = -facing_mat[2];
}
# endif
facing_mat[1] = normalize(cross(drw_view().viewinv[0].xyz, facing_mat[2]));
facing_mat[0] = cross(facing_mat[1], facing_mat[2]);
return facing_mat;