EEVEE Next: Point Clouds #109832

Merged
Miguel Pozo merged 13 commits from pragma37/blender:eevee-next-point-clouds into main 2023-07-14 17:23:36 +02:00
14 changed files with 216 additions and 12 deletions

View File

@ -495,6 +495,7 @@ set(GLSL_SRC
engines/eevee_next/shaders/eevee_geom_curves_vert.glsl
engines/eevee_next/shaders/eevee_geom_gpencil_vert.glsl
engines/eevee_next/shaders/eevee_geom_mesh_vert.glsl
engines/eevee_next/shaders/eevee_geom_point_cloud_vert.glsl
engines/eevee_next/shaders/eevee_geom_world_vert.glsl
engines/eevee_next/shaders/eevee_hiz_debug_frag.glsl
engines/eevee_next/shaders/eevee_hiz_update_comp.glsl

View File

@ -175,7 +175,7 @@ void Instance::scene_sync()
void Instance::object_sync(Object *ob)
{
const bool is_renderable_type = ELEM(
ob->type, OB_CURVES, OB_GPENCIL_LEGACY, OB_MESH, OB_LAMP, OB_LIGHTPROBE);
ob->type, OB_CURVES, OB_GPENCIL_LEGACY, OB_MESH, OB_POINTCLOUD, OB_LAMP, OB_LIGHTPROBE);
const int ob_visibility = DRW_object_visibility_in_active_context(ob);
const bool partsys_is_visible = (ob_visibility & OB_VISIBLE_PARTICLES) != 0 &&
(ob->type == OB_MESH);
@ -208,6 +208,8 @@ void Instance::object_sync(Object *ob)
case OB_MESH:
sync.sync_mesh(ob, ob_handle, res_handle, ob_ref);
break;
case OB_POINTCLOUD:
sync.sync_point_cloud(ob, ob_handle, res_handle, ob_ref);
case OB_VOLUME:
break;
case OB_CURVES:

View File

@ -39,6 +39,7 @@ enum eMaterialPipeline {
enum eMaterialGeometry {
MAT_GEOM_MESH = 0,
MAT_GEOM_POINT_CLOUD,
MAT_GEOM_CURVES,
MAT_GEOM_GPENCIL,
MAT_GEOM_VOLUME,
@ -102,6 +103,8 @@ static inline eMaterialGeometry to_material_geometry(const Object *ob)
return MAT_GEOM_VOLUME;
case OB_GPENCIL_LEGACY:
return MAT_GEOM_GPENCIL;
case OB_POINTCLOUD:
return MAT_GEOM_POINT_CLOUD;
default:
return MAT_GEOM_MESH;
}

View File

@ -314,6 +314,7 @@ void ShaderModule::material_create_info_ammend(GPUMaterial *gpumat, GPUCodegenOu
case MAT_GEOM_MESH:
/** Noop. */
break;
case MAT_GEOM_POINT_CLOUD:
case MAT_GEOM_CURVES:
/** Hair attributes come from sampler buffer. Transfer attributes to sampler. */
for (auto &input : info.vertex_inputs_) {
@ -382,8 +383,7 @@ void ShaderModule::material_create_info_ammend(GPUMaterial *gpumat, GPUCodegenOu
}
pragma37 marked this conversation as resolved Outdated

At this point, just test for MAT_GEOM_VOLUME and MAT_GEOM_WORLD.

At this point, just test for MAT_GEOM_VOLUME and MAT_GEOM_WORLD.
{
/* Only mesh and curves support vertex displacement for now. */
if (ELEM(geometry_type, MAT_GEOM_MESH, MAT_GEOM_CURVES, MAT_GEOM_GPENCIL)) {
if (!ELEM(geometry_type, MAT_GEOM_WORLD, MAT_GEOM_VOLUME)) {
vert_gen << "vec3 nodetree_displacement()\n";
vert_gen << "{\n";
vert_gen << ((codegen.displacement) ? codegen.displacement : "return vec3(0);\n");
@ -444,6 +444,9 @@ void ShaderModule::material_create_info_ammend(GPUMaterial *gpumat, GPUCodegenOu
case MAT_GEOM_MESH:
info.additional_info("eevee_geom_mesh");
break;
case MAT_GEOM_POINT_CLOUD:
info.additional_info("eevee_geom_point_cloud");
break;
}
/* Pipeline Info. */

View File

@ -18,6 +18,8 @@
#include "DNA_modifier_types.h"
#include "DNA_particle_types.h"
#include "draw_common.hh"
#include "eevee_instance.hh"
namespace blender::eevee {
@ -154,6 +156,49 @@ void SyncModule::sync_mesh(Object *ob,
/** \} */
/* -------------------------------------------------------------------- */
/** \name Point Cloud
* \{ */
void SyncModule::sync_point_cloud(Object *ob,
ObjectHandle &ob_handle,
ResourceHandle res_handle,
const ObjectRef &ob_ref)
{
int material_slot = 1;
bool has_motion = inst_.velocity.step_object_sync(
ob, ob_handle.object_key, res_handle, ob_handle.recalc);
Material &material = inst_.materials.material_get(
ob, has_motion, material_slot - 1, MAT_GEOM_POINT_CLOUD);
auto drawcall_add = [&](MaterialPass &matpass) {
if (matpass.sub_pass == nullptr) {
return;
}
PassMain::Sub &object_pass = matpass.sub_pass->sub("Point Cloud Sub Pass");
GPUBatch *geometry = point_cloud_sub_pass_setup(object_pass, ob, matpass.gpumat);
object_pass.draw(geometry, res_handle);
};
drawcall_add(material.shading);
drawcall_add(material.prepass);
drawcall_add(material.shadow);
inst_.cryptomatte.sync_object(ob, res_handle);
GPUMaterial *gpu_material =
inst_.materials.material_array_get(ob, has_motion).gpu_materials[material_slot - 1];
::Material *mat = GPU_material_get_material(gpu_material);
inst_.cryptomatte.sync_material(mat);
bool is_caster = material.shadow.sub_pass != nullptr;
bool is_alpha_blend = material.is_alpha_blend_transparent;
inst_.shadows.sync_object(ob_handle, res_handle, is_caster, is_alpha_blend);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name GPencil
* \{ */

View File

@ -164,6 +164,10 @@ class SyncModule {
ObjectHandle &ob_handle,
ResourceHandle res_handle,
const ObjectRef &ob_ref);
void sync_point_cloud(Object *ob,
ObjectHandle &ob_handle,
ResourceHandle res_handle,
const ObjectRef &ob_ref);
void sync_gpencil(Object *ob, ObjectHandle &ob_handle, ResourceHandle res_handle);
void sync_curves(Object *ob,
ObjectHandle &ob_handle,

View File

@ -17,6 +17,8 @@
#include "DEG_depsgraph_query.h"
#include "DNA_rigidbody_types.h"
#include "draw_cache_impl.h"
#include "eevee_instance.hh"
// #include "eevee_renderpasses.hh"
#include "eevee_shader.hh"
@ -129,6 +131,9 @@ bool VelocityModule::step_object_sync(Object *ob,
case OB_CURVES:
data.pos_buf = DRW_curves_pos_buffer_get(ob);
break;
case OB_POINTCLOUD:
data.pos_buf = DRW_pointcloud_position_and_radius_buffer_get(ob);
break;
default:
data.pos_buf = DRW_cache_object_pos_vertbuf_get(ob);
break;

View File

@ -60,6 +60,56 @@ vec3 attr_load_uv(vec3 attr)
/** \} */
#elif defined(MAT_GEOM_POINT_CLOUD)
/* -------------------------------------------------------------------- */
/** \name Point Cloud
*
* Point Cloud objects loads attributes from buffers through sampler buffers.
* \{ */
# pragma BLENDER_REQUIRE(common_pointcloud_lib.glsl)
# ifdef OBINFO_LIB
vec3 attr_load_orco(vec4 orco)
{
vec3 P = pointcloud_get_pos();
vec3 lP = transform_point(ModelMatrixInverse, P);
return OrcoTexCoFactors[0].xyz + lP * OrcoTexCoFactors[1].xyz;
}
# endif
vec4 attr_load_tangent(samplerBuffer cd_buf)
{
return pointcloud_get_customdata_vec4(cd_buf);
}
vec3 attr_load_uv(samplerBuffer cd_buf)
{
return pointcloud_get_customdata_vec3(cd_buf);
}
vec4 attr_load_color(samplerBuffer cd_buf)
{
return pointcloud_get_customdata_vec4(cd_buf);
}
vec4 attr_load_vec4(samplerBuffer cd_buf)
{
return pointcloud_get_customdata_vec4(cd_buf);
}
vec3 attr_load_vec3(samplerBuffer cd_buf)
{
return pointcloud_get_customdata_vec3(cd_buf);
}
vec2 attr_load_vec2(samplerBuffer cd_buf)
{
return pointcloud_get_customdata_vec2(cd_buf);
}
float attr_load_float(samplerBuffer cd_buf)
{
return pointcloud_get_customdata_float(cd_buf);
}
/** \} */
#elif defined(MAT_GEOM_GPENCIL)
/* -------------------------------------------------------------------- */

View File

@ -0,0 +1,48 @@
#pragma BLENDER_REQUIRE(gpu_shader_math_rotation_lib.glsl)
#pragma BLENDER_REQUIRE(common_pointcloud_lib.glsl)
#pragma BLENDER_REQUIRE(common_view_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_attributes_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl)
void main()
{
DRW_VIEW_FROM_RESOURCE_ID;
#ifdef MAT_SHADOW
shadow_interp.view_id = drw_view_id;
#endif
init_interface();
point_cloud_interp.id = pointcloud_get_point_id();
pointcloud_get_pos_and_radius(point_cloud_interp.position, point_cloud_interp.radius);
pointcloud_get_pos_and_nor(interp.P, interp.N);
#ifdef MAT_SHADOW
/* Since point clouds always face the view, camera and shadow orientation don't match.
* Apply a bias to avoid self-shadow issues. */
pragma37 marked this conversation as resolved Outdated

I guess the issue you had is that shadow map geometry was not matching the camera one producing self shadowing.
Instead of making the shadow camera dependent (that does not work with shadow map caching), I suggest to add a bias in the shadow map shader for point cloud. From my calculation, a bias equal to the point radius should be enough to remove any self shadowing.

This should remove the need for all this logic.

I guess the issue you had is that shadow map geometry was not matching the camera one producing self shadowing. Instead of making the shadow camera dependent (that does not work with shadow map caching), I suggest to add a bias in the shadow map shader for point cloud. From my calculation, a bias equal to the point radius should be enough to remove any self shadowing. This should remove the need for all this logic.
/* TODO(fclem): remove multiplication here. Here only for keeping the size correct for now. */
float actual_radius = point_cloud_interp.radius * 0.01;
interp.P -= cameraVec(interp.P) * actual_radius;
#endif
#ifdef MAT_VELOCITY
vec3 lP = point_world_to_object(point_cloud_interp.position);
vec3 prv, nxt;
velocity_local_pos_get(lP, point_cloud_interp.id, prv, nxt);
/* FIXME(fclem): Evaluating before displacement avoid displacement being treated as motion but
* ignores motion from animated displacement. Supporting animated displacement motion vectors
* would require evaluating the nodetree multiple time with different nodetree UBOs evaluated at
* different times, but also with different attributes (maybe we could assume static attribute at
* least). */
velocity_vertex(prv, lP, nxt, motion.prev, motion.next);
#endif
init_globals();
attrib_load();
interp.P += nodetree_displacement();
gl_Position = point_world_to_ndc(interp.P);
}

View File

@ -38,6 +38,25 @@ GPU_SHADER_CREATE_INFO(eevee_geom_mesh)
.vertex_source("eevee_geom_mesh_vert.glsl")
.additional_info("draw_modelmat_new", "draw_resource_id_varying", "draw_view");
GPU_SHADER_INTERFACE_INFO(eevee_surf_point_cloud_iface, "point_cloud_interp")
.smooth(Type::FLOAT, "radius")
.smooth(Type::VEC3, "position")
.flat(Type::INT, "id");
pragma37 marked this conversation as resolved Outdated

no uppercase.

no uppercase.
GPU_SHADER_CREATE_INFO(eevee_geom_point_cloud)
.additional_info("eevee_shared")
.define("MAT_GEOM_POINT_CLOUD")
.vertex_source("eevee_geom_point_cloud_vert.glsl")
.vertex_out(eevee_surf_point_cloud_iface)
/* TODO(Miguel Pozo): Remove once we get rid of old EEVEE. */
pragma37 marked this conversation as resolved Outdated

Add todo to remove after old EEVEE is removed.

Add todo to remove after old EEVEE is removed.
.define("pointRadius", "point_cloud_interp.radius")
.define("pointPosition", "point_cloud_interp.position")
.define("pointID", "point_cloud_interp.id")
.additional_info("draw_pointcloud_new",
"draw_modelmat_new",
"draw_resource_id_varying",
"draw_view");
GPU_SHADER_CREATE_INFO(eevee_geom_gpencil)
.additional_info("eevee_shared")
.define("MAT_GEOM_GPENCIL")
@ -223,7 +242,8 @@ GPU_SHADER_CREATE_INFO(eevee_material_stub)
EEVEE_MAT_FINAL_VARIATION(prefix##_world, "eevee_geom_world", __VA_ARGS__) \
EEVEE_MAT_FINAL_VARIATION(prefix##_gpencil, "eevee_geom_gpencil", __VA_ARGS__) \
EEVEE_MAT_FINAL_VARIATION(prefix##_curves, "eevee_geom_curves", __VA_ARGS__) \
EEVEE_MAT_FINAL_VARIATION(prefix##_mesh, "eevee_geom_mesh", __VA_ARGS__)
EEVEE_MAT_FINAL_VARIATION(prefix##_mesh, "eevee_geom_mesh", __VA_ARGS__) \
EEVEE_MAT_FINAL_VARIATION(prefix##_point_cloud, "eevee_geom_point_cloud", __VA_ARGS__)
# define EEVEE_MAT_PIPE_VARIATIONS(name, ...) \
EEVEE_MAT_GEOM_VARIATIONS(name##_world, "eevee_surf_world", __VA_ARGS__) \

View File

@ -152,6 +152,8 @@ void DRW_curves_batch_cache_create_requested(struct Object *ob);
int DRW_pointcloud_material_count_get(struct PointCloud *pointcloud);
struct GPUVertBuf *DRW_pointcloud_position_and_radius_buffer_get(struct Object *ob);
struct GPUVertBuf **DRW_pointcloud_evaluated_attribute(struct PointCloud *pointcloud,
const char *name);
struct GPUBatch *DRW_pointcloud_batch_cache_get_dots(struct Object *ob);

View File

@ -387,6 +387,12 @@ GPUBatch *DRW_pointcloud_batch_cache_get_dots(Object *ob)
return DRW_batch_request(&cache->eval_cache.dots);
}
GPUVertBuf *DRW_pointcloud_position_and_radius_buffer_get(Object *ob)
{
PointCloud &pointcloud = *static_cast<PointCloud *>(ob->data);
return pointcloud_position_and_radius_get(&pointcloud);
}
GPUVertBuf **DRW_pointcloud_evaluated_attribute(PointCloud *pointcloud, const char *name)
{
PointCloudBatchCache &cache = *pointcloud_batch_cache_get(*pointcloud);

View File

@ -98,6 +98,8 @@ void DRW_pointcloud_free()
}
#include "draw_common.hh"
/* For drw_curves_get_attribute_sampler_name. */
#include "draw_curves_private.hh"
namespace blender::draw {
template<typename PassT>
@ -119,14 +121,20 @@ GPUBatch *point_cloud_sub_pass_setup_implementation(PassT &sub_ps,
sub_ps.bind_texture("ptcloud_pos_rad_tx", pos_rad_buf);
if (gpu_material != nullptr) {
/* Only single material supported for now. */
GPUBatch **geom = pointcloud_surface_shaded_get(&pointcloud, &gpu_material, 1);
return geom[0];
}
else {
GPUBatch *geom = pointcloud_surface_get(&pointcloud);
return geom;
ListBase gpu_attrs = GPU_material_attributes(gpu_material);
LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) {
GPUVertBuf **attribute_buf = DRW_pointcloud_evaluated_attribute(&pointcloud, gpu_attr->name);
if (attribute_buf) {
char sampler_name[32];
/** NOTE: Reusing curve attribute function. */
drw_curves_get_attribute_sampler_name(gpu_attr->name, sampler_name);
sub_ps.bind_texture(sampler_name, attribute_buf);
}
}
}
GPUBatch *geom = pointcloud_surface_get(&pointcloud);
return geom;
}
GPUBatch *point_cloud_sub_pass_setup(PassMain::Sub &sub_ps,

View File

@ -10,7 +10,10 @@
int pointcloud_get_point_id()
{
# ifdef GPU_VERTEX_SHADER
return gl_VertexID / 32;
# endif
return 0;
}
mat3 pointcloud_get_facing_matrix(vec3 p)
@ -40,8 +43,12 @@ void pointcloud_get_pos_nor_radius(out vec3 outpos, out vec3 outnor, out float o
mat3 facing_mat = pointcloud_get_facing_matrix(p);
int vert_id = 0;
# ifdef GPU_VERTEX_SHADER
/* NOTE: Avoid modulo by non-power-of-two in shader. See Index buffer setup. */
int vert_id = gl_VertexID % 32;
vert_id = gl_VertexID % 32;
# endif
vec3 pos_inst = vec3(0.0);
switch (vert_id) {