Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2020-07-11 15:46:02 +0300
committerClément Foucault <foucault.clem@gmail.com>2020-07-11 15:46:02 +0300
commit5e1212368510e97e519d151ce19d77ed56f1a565 (patch)
treea18d5b5e4cfa472526b7eec563ab24694a2d31b6 /source/blender/draw/intern
parentb0da78084bd73fd1bec25570da12515f127f1fd1 (diff)
DRW: Add common point cloud rendering functions
Diffstat (limited to 'source/blender/draw/intern')
-rw-r--r--source/blender/draw/intern/draw_cache.c9
-rw-r--r--source/blender/draw/intern/draw_cache.h1
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h1
-rw-r--r--source/blender/draw/intern/draw_cache_impl_pointcloud.c127
-rw-r--r--source/blender/draw/intern/shaders/common_pointcloud_lib.glsl136
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