diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2020-07-11 15:46:02 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2020-07-11 15:46:02 +0300 |
commit | 5e1212368510e97e519d151ce19d77ed56f1a565 (patch) | |
tree | a18d5b5e4cfa472526b7eec563ab24694a2d31b6 /source/blender/draw/intern | |
parent | b0da78084bd73fd1bec25570da12515f127f1fd1 (diff) |
DRW: Add common point cloud rendering functions
Diffstat (limited to 'source/blender/draw/intern')
-rw-r--r-- | source/blender/draw/intern/draw_cache.c | 9 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache.h | 1 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl.h | 1 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl_pointcloud.c | 127 | ||||
-rw-r--r-- | source/blender/draw/intern/shaders/common_pointcloud_lib.glsl | 136 |
5 files changed, 249 insertions, 25 deletions
diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 9f30cd85957..0a2cd106fd2 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -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: @@ -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..6279d6d8ea0 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -144,6 +144,7 @@ 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); /* 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..897703c71ec 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,8 +46,12 @@ 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; /* settings to determine if cache is invalid */ bool is_dirty; @@ -109,8 +114,11 @@ 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); } void DRW_pointcloud_batch_cache_free(PointCloud *pointcloud) @@ -128,46 +136,117 @@ static void pointcloud_batch_cache_ensure_pos(Object *ob, PointCloudBatchCache * PointCloud *pointcloud = ob->data; static GPUVertFormat format = {0}; - static uint pos_id; - static uint radius_id; 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); + GPU_vertformat_attr_add(&format, "ptcloud", GPU_COMP_F32, 4, 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__); - for (int i = 0; i < pointcloud->totpoint; i++) { - /* TODO: add default radius to PointCloud data structure. */ - radius[i] = 0.01f; + float(*vbo_data)[4] = (float(*)[4])cache->pos->data; + + for (int i = 0; i < pointcloud->totpoint; i++) { + copy_v3_v3(vbo_data[i], pointcloud->co[i]); + if (pointcloud->radius) { + vbo_data[i][3] = pointcloud->radius[i]; + } + else { + vbo_data[i][3] = 0.01f; } - GPU_vertbuf_attr_fill(cache->pos, radius_id, radius); - MEM_freeN(radius); } } +static const float bone_box_smooth_normals[8][3] = { + {M_SQRT3, -M_SQRT3, M_SQRT3}, + {M_SQRT3, -M_SQRT3, -M_SQRT3}, + {-M_SQRT3, -M_SQRT3, -M_SQRT3}, + {-M_SQRT3, -M_SQRT3, M_SQRT3}, + {M_SQRT3, M_SQRT3, M_SQRT3}, + {M_SQRT3, M_SQRT3, -M_SQRT3}, + {-M_SQRT3, M_SQRT3, -M_SQRT3}, + {-M_SQRT3, M_SQRT3, M_SQRT3}, +}; + +static const uint bone_box_solid_tris[12][3] = { + {0, 2, 1}, /* bottom */ + {0, 3, 2}, + + {0, 1, 5}, /* sides */ + {0, 5, 4}, + + {1, 2, 6}, + {1, 6, 5}, + + {2, 3, 7}, + {2, 7, 6}, + + {3, 0, 4}, + {3, 4, 7}, + + {4, 5, 6}, /* top */ + {4, 6, 7}, +}; + +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", 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(bone_box_smooth_normals)); + + GPU_vertbuf_attr_fill(cache->geom, pos, bone_box_smooth_normals); + + GPUIndexBufBuilder builder; + GPU_indexbuf_init(&builder, + GPU_PRIM_TRIS, + ARRAY_SIZE(bone_box_solid_tris), + ARRAY_SIZE(bone_box_smooth_normals)); + + for (int i = 0; i < ARRAY_SIZE(bone_box_solid_tris); i++) { + GPU_indexbuf_add_tri_verts(&builder, UNPACK3(bone_box_solid_tris[i])); + } + + cache->geom_indices = GPU_indexbuf_build(&builder); +} + 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->batch; + return cache->surface; } int DRW_pointcloud_material_count_get(PointCloud *pointcloud) 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..9636495a539 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_pointcloud_lib.glsl @@ -0,0 +1,136 @@ +/** + * Library to create hairs dynamically from control points. + * This is less bandwidth intensive than fetching the vertex attributes + * but does more ALU work per vertex. This also reduces the amount + * of data the CPU has to precompute and transfer for each update. + */ + +/** + * hairStrandsRes: Number of points per hair strand. + * 2 - no subdivision + * 3+ - 1 or more interpolated points per hair. + */ +uniform int hairStrandsRes = 8; + +/** + * hairThicknessRes : Subdiv around the hair. + * 1 - Wire Hair: Only one pixel thick, independent of view distance. + * 2 - Polystrip Hair: Correct width, flat if camera is parallel. + * 3+ - Cylinder Hair: Massive calculation but potentially perfect. Still need proper support. + */ +uniform int hairThicknessRes = 1; + +/* Hair thickness shape. */ +uniform float hairRadRoot = 0.01; +uniform float hairRadTip = 0.0; +uniform float hairRadShape = 0.5; +uniform bool hairCloseTip = true; + +uniform vec4 hairDupliMatrix[4]; + +/* -- Per control points -- */ +uniform samplerBuffer hairPointBuffer; /* RGBA32F */ +#define point_position xyz +#define point_time w /* Position along the hair length */ + +/* -- Per strands data -- */ +uniform usamplerBuffer hairStrandBuffer; /* R32UI */ +uniform usamplerBuffer hairStrandSegBuffer; /* R16UI */ + +/* Not used, use one buffer per uv layer */ +// uniform samplerBuffer hairUVBuffer; /* RG32F */ +// uniform samplerBuffer hairColBuffer; /* RGBA16 linear color */ + +/* -- Subdivision stage -- */ +/** + * We use a transform feedback to preprocess the strands and add more subdivision to it. + * For the moment these are simple smooth interpolation but one could hope to see the full + * children particle modifiers being evaluated at this stage. + * + * If no more subdivision is needed, we can skip this step. + */ + +#ifdef HAIR_PHASE_SUBDIV +int hair_get_base_id(float local_time, int strand_segments, out float interp_time) +{ + float time_per_strand_seg = 1.0 / float(strand_segments); + + float ratio = local_time / time_per_strand_seg; + interp_time = fract(ratio); + + return int(ratio); +} + +void hair_get_interp_attrs( + out vec4 data0, out vec4 data1, out vec4 data2, out vec4 data3, out float interp_time) +{ + float local_time = float(gl_VertexID % hairStrandsRes) / float(hairStrandsRes - 1); + + int hair_id = gl_VertexID / hairStrandsRes; + int strand_offset = int(texelFetch(hairStrandBuffer, hair_id).x); + int strand_segments = int(texelFetch(hairStrandSegBuffer, hair_id).x); + + int id = hair_get_base_id(local_time, strand_segments, interp_time); + + int ofs_id = id + strand_offset; + + data0 = texelFetch(hairPointBuffer, ofs_id - 1); + data1 = texelFetch(hairPointBuffer, ofs_id); + data2 = texelFetch(hairPointBuffer, ofs_id + 1); + data3 = texelFetch(hairPointBuffer, ofs_id + 2); + + if (id <= 0) { + /* root points. Need to reconstruct previous data. */ + data0 = data1 * 2.0 - data2; + } + if (id + 1 >= strand_segments) { + /* tip points. Need to reconstruct next data. */ + data3 = data2 * 2.0 - data1; + } +} +#endif + +/* -- Drawing stage -- */ +/** + * For final drawing, the vertex index and the number of vertex per segment + */ + +#ifndef HAIR_PHASE_SUBDIV +int hair_get_strand_id(void) +{ + return gl_VertexID / (hairStrandsRes * hairThicknessRes); +} + +int hair_get_base_id(void) +{ + return gl_VertexID / hairThicknessRes; +} + +/* Copied from cycles. */ +float hair_shaperadius(float shape, float root, float tip, float time) +{ + float radius = 1.0 - time; + + if (shape < 0.0) { + radius = pow(radius, 1.0 + shape); + } + else { + radius = pow(radius, 1.0 / (1.0 - shape)); + } + + if (hairCloseTip && (time > 0.99)) { + return 0.0; + } + + return (radius * (root - tip)) + tip; +} + +# ifdef OS_MAC +in float dummy; +# endif + +vec3 pointcloud_get_pos() +{ +} + +#endif |