diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2020-07-15 21:10:45 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2020-07-15 21:10:45 +0300 |
commit | 058514aa0abfbbeb87a89d863a2cdc85b5bdb5c4 (patch) | |
tree | 5eeb9adf61396e50046f53f10a77d1fbb4a397e5 /source/blender/draw/intern | |
parent | d4d810f817afc61618bec6f3b0a0ade5d0111d3c (diff) |
PointCloud: Initial rendering support for Workbench
Also includes outline overlays. Removes the temp overlay drawing
We make the geometry follow camera like billboards this uses less
geometry. Currently we use half octahedron for now. Goal would be
to use icospheres.
This patch also optimize the case when pointcloud has uniform radius.
However we should premultiply the radius prop by the default radius
beforehand to avoid a multiplication on CPU.
Using geometry instead of pseudo raytraced spheres is more scalable as
we can render as low as 1 or 2 triangle to a full half sphere and can
integrate easily in the render pipeline using a low amount of code.
Reviewed By: brecht
Differential Revision: https://developer.blender.org/D8301
Diffstat (limited to 'source/blender/draw/intern')
-rw-r--r-- | source/blender/draw/intern/draw_cache.c | 13 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache.h | 1 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl.h | 4 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl_pointcloud.c | 160 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_manager_data.c | 2 | ||||
-rw-r--r-- | source/blender/draw/intern/shaders/common_pointcloud_lib.glsl | 39 | ||||
-rw-r--r-- | source/blender/draw/intern/shaders/common_view_lib.glsl | 1 |
7 files changed, 192 insertions, 28 deletions
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 9f30cd85957..20e346375a7 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -829,7 +829,7 @@ GPUBatch *DRW_cache_object_face_wireframe_get(Object *ob) case OB_HAIR: return NULL; case OB_POINTCLOUD: - return NULL; + return DRW_pointcloud_batch_cache_get_dots(ob); case OB_VOLUME: return DRW_cache_volume_face_wireframe_get(ob); case OB_GPENCIL: { @@ -880,7 +880,7 @@ GPUBatch *DRW_cache_object_surface_get(Object *ob) case OB_HAIR: return NULL; case OB_POINTCLOUD: - return NULL; + return DRW_cache_pointcloud_surface_get(ob); case OB_VOLUME: return NULL; default: @@ -958,7 +958,7 @@ GPUBatch **DRW_cache_object_surface_material_get(struct Object *ob, case OB_HAIR: return NULL; case OB_POINTCLOUD: - return NULL; + return DRW_cache_pointcloud_surface_shaded_get(ob, gpumat_array, gpumat_array_len); case OB_VOLUME: return NULL; default: @@ -3289,9 +3289,16 @@ GPUBatch *DRW_cache_lattice_vert_overlay_get(Object *ob) GPUBatch *DRW_cache_pointcloud_get_dots(Object *object) { + BLI_assert(object->type == OB_POINTCLOUD); return DRW_pointcloud_batch_cache_get_dots(object); } +GPUBatch *DRW_cache_pointcloud_surface_get(Object *object) +{ + BLI_assert(object->type == OB_POINTCLOUD); + return DRW_pointcloud_batch_cache_get_surface(object); +} + /* -------------------------------------------------------------------- */ /** \name Volume * \{ */ diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h index 2f289bf4110..1ea53c91cb3 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -215,6 +215,7 @@ struct GPUBatch *DRW_cache_hair_edge_detection_get(struct Object *ob, bool *r_is /* PointCloud */ struct GPUBatch *DRW_cache_pointcloud_get_dots(struct Object *obj); +struct GPUBatch *DRW_cache_pointcloud_surface_get(struct Object *obj); /* Volume */ typedef struct DRWVolumeGrid { diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index 5cf1c24af0b..96d351794e6 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -144,6 +144,10 @@ int DRW_hair_material_count_get(struct Hair *hair); int DRW_pointcloud_material_count_get(struct PointCloud *pointcloud); struct GPUBatch *DRW_pointcloud_batch_cache_get_dots(struct Object *ob); +struct GPUBatch *DRW_pointcloud_batch_cache_get_surface(struct Object *ob); +struct GPUBatch **DRW_cache_pointcloud_surface_shaded_get(struct Object *ob, + struct GPUMaterial **gpumat_array, + uint gpumat_array_len); /* Volume */ int DRW_volume_material_count_get(struct Volume *volume); diff --git a/source/blender/draw/intern/draw_cache_impl_pointcloud.c b/source/blender/draw/intern/draw_cache_impl_pointcloud.c index 53939b35285..91baf9fa15e 100644 --- a/source/blender/draw/intern/draw_cache_impl_pointcloud.c +++ b/source/blender/draw/intern/draw_cache_impl_pointcloud.c @@ -28,6 +28,7 @@ #include "MEM_guardedalloc.h" #include "BLI_math_base.h" +#include "BLI_math_vector.h" #include "BLI_utildefines.h" #include "DNA_object_types.h" @@ -45,11 +46,18 @@ static void pointcloud_batch_cache_clear(PointCloud *pointcloud); /* PointCloud GPUBatch Cache */ typedef struct PointCloudBatchCache { - GPUVertBuf *pos; - GPUBatch *batch; + GPUVertBuf *pos; /* Position and radius. */ + GPUVertBuf *geom; /* Instanced geometry for each point in the cloud (small sphere). */ + GPUIndexBuf *geom_indices; + + GPUBatch *dots; + GPUBatch *surface; + GPUBatch **surface_per_mat; /* settings to determine if cache is invalid */ bool is_dirty; + + int mat_len; } PointCloudBatchCache; /* GPUBatch cache management. */ @@ -57,7 +65,14 @@ typedef struct PointCloudBatchCache { static bool pointcloud_batch_cache_valid(PointCloud *pointcloud) { PointCloudBatchCache *cache = pointcloud->batch_cache; - return (cache && cache->is_dirty == false); + + if (cache == NULL) { + return false; + } + if (cache->mat_len != DRW_pointcloud_material_count_get(pointcloud)) { + return false; + } + return cache->is_dirty == false; } static void pointcloud_batch_cache_init(PointCloud *pointcloud) @@ -71,6 +86,10 @@ static void pointcloud_batch_cache_init(PointCloud *pointcloud) memset(cache, 0, sizeof(*cache)); } + cache->mat_len = DRW_pointcloud_material_count_get(pointcloud); + cache->surface_per_mat = MEM_callocN(sizeof(GPUBatch *) * cache->mat_len, + "pointcloud suface_per_mat"); + cache->is_dirty = false; } @@ -109,8 +128,18 @@ static void pointcloud_batch_cache_clear(PointCloud *pointcloud) return; } - GPU_BATCH_DISCARD_SAFE(cache->batch); + GPU_BATCH_DISCARD_SAFE(cache->dots); + GPU_BATCH_DISCARD_SAFE(cache->surface); GPU_VERTBUF_DISCARD_SAFE(cache->pos); + GPU_VERTBUF_DISCARD_SAFE(cache->geom); + GPU_INDEXBUF_DISCARD_SAFE(cache->geom_indices); + + if (cache->surface_per_mat) { + for (int i = 0; i < cache->mat_len; i++) { + GPU_BATCH_DISCARD_SAFE(cache->surface_per_mat[i]); + } + } + MEM_SAFE_FREE(cache->surface_per_mat); } void DRW_pointcloud_batch_cache_free(PointCloud *pointcloud) @@ -126,35 +155,83 @@ static void pointcloud_batch_cache_ensure_pos(Object *ob, PointCloudBatchCache * } PointCloud *pointcloud = ob->data; + const bool has_radius = pointcloud->radius != NULL; static GPUVertFormat format = {0}; - static uint pos_id; - static uint radius_id; + static uint pos; if (format.attr_len == 0) { /* initialize vertex format */ - pos_id = GPU_vertformat_attr_add(&format, "pointcloud_pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - radius_id = GPU_vertformat_attr_add( - &format, "pointcloud_radius", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + /* From the opengl wiki: + * Note that size does not have to exactly match the size used by the vertex shader. If the + * vertex shader has fewer components than the attribute provides, then the extras are ignored. + * If the vertex shader has more components than the array provides, the extras are given + * values from the vector (0, 0, 0, 1) for the missing XYZW components. + */ + int comp_len = has_radius ? 4 : 3; + pos = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, comp_len, GPU_FETCH_FLOAT); } - GPU_VERTBUF_DISCARD_SAFE(cache->pos); cache->pos = GPU_vertbuf_create_with_format(&format); GPU_vertbuf_data_alloc(cache->pos, pointcloud->totpoint); - GPU_vertbuf_attr_fill(cache->pos, pos_id, pointcloud->co); - if (pointcloud->radius) { - GPU_vertbuf_attr_fill(cache->pos, radius_id, pointcloud->radius); - } - else if (pointcloud->totpoint) { - /* TODO: optimize for constant radius by not including in vertex buffer at all? */ - float *radius = MEM_malloc_arrayN(pointcloud->totpoint, sizeof(float), __func__); + if (has_radius) { + float(*vbo_data)[4] = (float(*)[4])cache->pos->data; for (int i = 0; i < pointcloud->totpoint; i++) { - /* TODO: add default radius to PointCloud data structure. */ - radius[i] = 0.01f; + copy_v3_v3(vbo_data[i], pointcloud->co[i]); + /* TODO(fclem) remove multiplication here. Here only for keeping the size correct for now. */ + vbo_data[i][3] = pointcloud->radius[i] * 100.0f; } - GPU_vertbuf_attr_fill(cache->pos, radius_id, radius); - MEM_freeN(radius); } + else { + GPU_vertbuf_attr_fill(cache->pos, pos, pointcloud->co); + } +} + +static const float half_octahedron_normals[5][3] = { + {0.0f, 0.0f, 1.0f}, + {1.0f, 0.0f, 0.0f}, + {0.0f, 1.0f, 0.0f}, + {-1.0f, 0.0f, 0.0f}, + {0.0f, -1.0f, 0.0f}, +}; + +static const uint half_octahedron_tris[4][3] = { + {0, 1, 2}, + {0, 2, 3}, + {0, 3, 4}, + {0, 4, 1}, +}; + +static void pointcloud_batch_cache_ensure_geom(Object *UNUSED(ob), PointCloudBatchCache *cache) +{ + if (cache->geom != NULL) { + return; + } + + static GPUVertFormat format = {0}; + static uint pos; + if (format.attr_len == 0) { + /* initialize vertex format */ + pos = GPU_vertformat_attr_add(&format, "pos_inst", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + GPU_vertformat_alias_add(&format, "nor"); + } + + cache->geom = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(cache->geom, ARRAY_SIZE(half_octahedron_normals)); + + GPU_vertbuf_attr_fill(cache->geom, pos, half_octahedron_normals); + + GPUIndexBufBuilder builder; + GPU_indexbuf_init(&builder, + GPU_PRIM_TRIS, + ARRAY_SIZE(half_octahedron_tris), + ARRAY_SIZE(half_octahedron_normals)); + + for (int i = 0; i < ARRAY_SIZE(half_octahedron_tris); i++) { + GPU_indexbuf_add_tri_verts(&builder, UNPACK3(half_octahedron_tris[i])); + } + + cache->geom_indices = GPU_indexbuf_build(&builder); } GPUBatch *DRW_pointcloud_batch_cache_get_dots(Object *ob) @@ -162,12 +239,47 @@ GPUBatch *DRW_pointcloud_batch_cache_get_dots(Object *ob) PointCloud *pointcloud = ob->data; PointCloudBatchCache *cache = pointcloud_batch_cache_get(pointcloud); - if (cache->batch == NULL) { + if (cache->dots == NULL) { pointcloud_batch_cache_ensure_pos(ob, cache); - cache->batch = GPU_batch_create(GPU_PRIM_POINTS, cache->pos, NULL); + cache->dots = GPU_batch_create(GPU_PRIM_POINTS, cache->pos, NULL); + } + + return cache->dots; +} + +GPUBatch *DRW_pointcloud_batch_cache_get_surface(Object *ob) +{ + PointCloud *pointcloud = ob->data; + PointCloudBatchCache *cache = pointcloud_batch_cache_get(pointcloud); + + if (cache->surface == NULL) { + pointcloud_batch_cache_ensure_pos(ob, cache); + pointcloud_batch_cache_ensure_geom(ob, cache); + + cache->surface = GPU_batch_create(GPU_PRIM_TRIS, cache->geom, cache->geom_indices); + GPU_batch_instbuf_add_ex(cache->surface, cache->pos, false); + } + + return cache->surface; +} + +GPUBatch **DRW_cache_pointcloud_surface_shaded_get(Object *ob, + struct GPUMaterial **UNUSED(gpumat_array), + uint gpumat_array_len) +{ + PointCloud *pointcloud = ob->data; + PointCloudBatchCache *cache = pointcloud_batch_cache_get(pointcloud); + BLI_assert(cache->mat_len == gpumat_array_len); + + if (cache->surface_per_mat[0] == NULL) { + pointcloud_batch_cache_ensure_pos(ob, cache); + pointcloud_batch_cache_ensure_geom(ob, cache); + + cache->surface_per_mat[0] = GPU_batch_create(GPU_PRIM_TRIS, cache->geom, cache->geom_indices); + GPU_batch_instbuf_add_ex(cache->surface_per_mat[0], cache->pos, false); } - return cache->batch; + return cache->surface_per_mat; } int DRW_pointcloud_material_count_get(PointCloud *pointcloud) diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index 5dc40bcdc76..9d8050504ab 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -793,10 +793,10 @@ void DRW_shgroup_call_range( drw_command_draw_range(shgroup, geom, handle, v_sta, v_ct); } +/* A count of 0 instance will use the default number of instance in the batch. */ void DRW_shgroup_call_instance_range( DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint i_sta, uint i_ct) { - BLI_assert(i_ct > 0); BLI_assert(geom != NULL); if (G.f & G_FLAG_PICKSEL) { drw_command_set_select_id(shgroup, NULL, DST.select_id); diff --git a/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl b/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl new file mode 100644 index 00000000000..36b67f2bd60 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl @@ -0,0 +1,39 @@ + +/* NOTE: To be used with UNIFORM_RESOURCE_ID and INSTANCED_ATTR as define. */ +#pragma BLENDER_REQUIRE(common_view_lib.glsl) + +in vec4 pos; /* Position and radius. */ + +/* ---- Instanced attribs ---- */ + +in vec3 pos_inst; +in vec3 nor; + +mat3 pointcloud_get_facing_matrix(vec3 p) +{ + mat3 facing_mat; + facing_mat[2] = normalize(ViewMatrixInverse[3].xyz - p); + facing_mat[1] = normalize(cross(ViewMatrixInverse[0].xyz, facing_mat[2])); + facing_mat[0] = cross(facing_mat[1], facing_mat[2]); + return facing_mat; +} + +/* Return world position and normal. */ +void pointcloud_get_pos_and_nor(out vec3 outpos, out vec3 outnor) +{ + vec3 p = point_object_to_world(pos.xyz); + mat3 facing_mat = pointcloud_get_facing_matrix(p); + + float radius = dot(abs(mat3(ModelMatrix) * pos.www), vec3(1.0 / 3.0)); + /* TODO(fclem) remove multiplication here. Here only for keeping the size correct for now. */ + radius *= 0.01; + outpos = p + (facing_mat * pos_inst) * radius; + outnor = facing_mat * nor; +} + +vec3 pointcloud_get_pos(void) +{ + vec3 outpos, outnor; + pointcloud_get_pos_and_nor(outpos, outnor); + return outpos; +}
\ No newline at end of file diff --git a/source/blender/draw/intern/shaders/common_view_lib.glsl b/source/blender/draw/intern/shaders/common_view_lib.glsl index 2188c38ee63..095bc64a19e 100644 --- a/source/blender/draw/intern/shaders/common_view_lib.glsl +++ b/source/blender/draw/intern/shaders/common_view_lib.glsl @@ -175,6 +175,7 @@ uniform mat4 ModelMatrixInverse; #define normal_object_to_world(n) (transpose(mat3(ModelMatrixInverse)) * n) #define normal_world_to_object(n) (transpose(mat3(ModelMatrix)) * n) #define normal_world_to_view(n) (mat3(ViewMatrix) * n) +#define normal_view_to_world(n) (mat3(ViewMatrixInverse) * n) #define point_object_to_ndc(p) (ViewProjectionMatrix * vec4((ModelMatrix * vec4(p, 1.0)).xyz, 1.0)) #define point_object_to_view(p) ((ViewMatrix * vec4((ModelMatrix * vec4(p, 1.0)).xyz, 1.0)).xyz) |