diff options
author | Lukas Tönne <lukas.toenne@gmail.com> | 2017-08-14 09:58:02 +0300 |
---|---|---|
committer | Lukas Tönne <lukas.toenne@gmail.com> | 2017-08-14 09:58:02 +0300 |
commit | b0717ad91eedb64fa23a7ac16403d3fc166e447a (patch) | |
tree | eed9d3061d44ef55fb131140710f10017621424d /source | |
parent | 91fd0a487d95e604c1c245905895123eeaf2ca0e (diff) |
Hair drawing data based on the new DNA hair groups.
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenkernel/BKE_editstrands.h | 10 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_hair.h | 40 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/editstrands.c | 34 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/hair.c | 115 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/hair_draw.c | 144 | ||||
-rw-r--r-- | source/blender/draw/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_materials.c | 332 | ||||
-rw-r--r-- | source/blender/draw/engines/eevee/shaders/hair_lib.glsl | 8 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache.c | 10 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache.h | 6 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl.h | 9 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl_hair.c | 310 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl_strands.c | 8 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_hair.c | 2 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_manager.c | 6 | ||||
-rw-r--r-- | source/blender/editors/hair/hair_object_particles.c | 2 |
16 files changed, 812 insertions, 225 deletions
diff --git a/source/blender/blenkernel/BKE_editstrands.h b/source/blender/blenkernel/BKE_editstrands.h index 1e0ed8cf3c4..991776deda3 100644 --- a/source/blender/blenkernel/BKE_editstrands.h +++ b/source/blender/blenkernel/BKE_editstrands.h @@ -51,11 +51,8 @@ typedef struct BMEditStrands { /* Scalp mesh for fixing root vertices */ struct DerivedMesh *root_dm; - - /* Hair fibers (optional) */ - struct HairFiber *hair_fibers; - int hair_totfibers; - unsigned int hair_seed; + struct HairPattern *hair_pattern; + struct HairGroup *hair_group; int flag; @@ -81,9 +78,6 @@ void BKE_editstrands_free(struct BMEditStrands *es); /* === Hair Fibers === */ -bool BKE_editstrands_hair_ensure(struct BMEditStrands *es); -void BKE_editstrands_hair_free(struct BMEditStrands *es); - int* BKE_editstrands_hair_get_fiber_lengths(struct BMEditStrands *es, int subdiv); void BKE_editstrands_hair_get_texture_buffer_size(struct BMEditStrands *es, int subdiv, int *r_size, int *r_strand_map_start, int *r_strand_vertex_start, int *r_fiber_start); diff --git a/source/blender/blenkernel/BKE_hair.h b/source/blender/blenkernel/BKE_hair.h index 1c079168500..b5dc42b0974 100644 --- a/source/blender/blenkernel/BKE_hair.h +++ b/source/blender/blenkernel/BKE_hair.h @@ -55,25 +55,13 @@ void BKE_hair_group_moveto(struct HairPattern *hair, struct HairGroup *group, in void BKE_hair_group_name_set(struct HairPattern *hair, struct HairGroup *group, const char *name); -/* ================================= */ - -typedef struct HairFiber { - /* Sample on the scalp mesh for the root vertex */ - MeshSample root; - /* Indices of control strands for interpolation */ - unsigned int parent_index[4]; - /* Weights of control strands for interpolation */ - float parent_weight[4]; - /* Parametric distance to the primary control strand */ - float root_distance[2]; -} HairFiber; - -bool BKE_hair_fiber_get_location(const struct HairFiber *fiber, struct DerivedMesh *root_dm, float loc[3]); -bool BKE_hair_fiber_get_vectors(const struct HairFiber *fiber, struct DerivedMesh *root_dm, - float loc[3], float nor[3], float tang[3]); -bool BKE_hair_fiber_get_matrix(const struct HairFiber *fiber, struct DerivedMesh *root_dm, float mat[4][4]); +void BKE_hair_update_groups(struct HairPattern *hair); + +/* === Draw Buffer Texture === */ typedef struct HairDrawDataInterface { + const struct HairGroup *group; + int (*get_num_strands)(const struct HairDrawDataInterface* hairdata); int (*get_num_verts)(const struct HairDrawDataInterface* hairdata); @@ -82,18 +70,11 @@ typedef struct HairDrawDataInterface { void (*get_strand_vertices)(const struct HairDrawDataInterface* hairdata, float (*r_positions)[3]); } HairDrawDataInterface; -struct HairFiber* BKE_hair_fibers_create(const struct HairDrawDataInterface *hairdata, - struct DerivedMesh *scalp, unsigned int amount, - unsigned int seed); - -int* BKE_hair_strands_get_fiber_lengths(const struct HairFiber *fibers, int totfibers, - const struct HairDrawDataInterface *hairdata, int subdiv); - -void BKE_hair_strands_get_texture_buffer_size(const struct HairDrawDataInterface *hairdata, int totfibers, int subdiv, +int* BKE_hair_strands_get_fiber_lengths(const struct HairDrawDataInterface *hairdata, int subdiv); +void BKE_hair_strands_get_texture_buffer_size(const struct HairDrawDataInterface *hairdata, int subdiv, int *r_size, int *r_strand_map_start, int *r_strand_vertex_start, int *r_fiber_start); -void BKE_hair_strands_get_texture_buffer(const struct HairDrawDataInterface *hairdata, struct DerivedMesh *scalp, - const struct HairFiber *fibers, int totfibers, int subdiv, +void BKE_hair_strands_get_texture_buffer(const struct HairDrawDataInterface *hairdata, int subdiv, struct DerivedMesh *scalp, void *texbuffer); /* === Draw Cache === */ @@ -102,11 +83,12 @@ enum { BKE_HAIR_BATCH_DIRTY_ALL = 0, }; void BKE_hair_batch_cache_dirty(struct HairGroup *group, int mode); +void BKE_hair_batch_cache_all_dirty(struct HairPattern *hair, int mode); void BKE_hair_batch_cache_free(struct HairGroup *group); -int* BKE_hair_get_fiber_lengths(struct HairGroup *group, int subdiv); +int* BKE_hair_group_get_fiber_lengths(struct HairGroup *group, int subdiv); void BKE_hair_group_get_texture_buffer_size(struct HairGroup *group, int subdiv, int *r_size, int *r_strand_map_start, int *r_strand_vertex_start, int *r_fiber_start); -void BKE_hair_group_get_texture_buffer(struct HairGroup *group, struct DerivedMesh *scalp, int subdiv, void *texbuffer); +void BKE_hair_group_get_texture_buffer(struct HairGroup *group, int subdiv, struct DerivedMesh *scalp, void *texbuffer); #endif diff --git a/source/blender/blenkernel/intern/editstrands.c b/source/blender/blenkernel/intern/editstrands.c index 723590be4a6..adbb4b707aa 100644 --- a/source/blender/blenkernel/intern/editstrands.c +++ b/source/blender/blenkernel/intern/editstrands.c @@ -124,7 +124,6 @@ void BKE_editstrands_update_linked_customdata(BMEditStrands *UNUSED(es)) void BKE_editstrands_free(BMEditStrands *es) { BKE_editstrands_batch_cache_free(es); - BKE_editstrands_hair_free(es); if (es->base.bm) BM_mesh_free(es->base.bm); @@ -200,6 +199,7 @@ static void get_strand_vertices(const HairDrawDataInterface* hairdata_, float (* static EditStrandsView editstrands_get_view(BMEditStrands *edit) { EditStrandsView hairdata; + hairdata.base.group = edit->hair_group; hairdata.base.get_num_strands = get_num_strands; hairdata.base.get_num_verts = get_num_verts; hairdata.base.get_strand_lengths = get_strand_lengths; @@ -209,48 +209,24 @@ static EditStrandsView editstrands_get_view(BMEditStrands *edit) return hairdata; } -bool BKE_editstrands_hair_ensure(BMEditStrands *es) -{ - if (!es->root_dm || es->hair_totfibers == 0) { - BKE_editstrands_hair_free(es); - return false; - } - - if (!es->hair_fibers) { - EditStrandsView strands = editstrands_get_view(es); - es->hair_fibers = BKE_hair_fibers_create(&strands.base, es->root_dm, es->hair_totfibers, es->hair_seed); - } - - return true; -} - -void BKE_editstrands_hair_free(BMEditStrands *es) -{ - if (es->hair_fibers) - { - MEM_freeN(es->hair_fibers); - es->hair_fibers = NULL; - } -} - int* BKE_editstrands_hair_get_fiber_lengths(BMEditStrands *es, int subdiv) { EditStrandsView strands = editstrands_get_view(es); - return BKE_hair_strands_get_fiber_lengths(es->hair_fibers, es->hair_totfibers, &strands.base, subdiv); + return BKE_hair_strands_get_fiber_lengths(&strands.base, subdiv); } void BKE_editstrands_hair_get_texture_buffer_size(BMEditStrands *es, int subdiv, int *r_size, int *r_strand_map_start, int *r_strand_vertex_start, int *r_fiber_start) { EditStrandsView strands = editstrands_get_view(es); - BKE_hair_strands_get_texture_buffer_size(&strands.base, es->hair_totfibers, subdiv, r_size, - r_strand_map_start, r_strand_vertex_start, r_fiber_start); + BKE_hair_strands_get_texture_buffer_size(&strands.base, subdiv, + r_size, r_strand_map_start, r_strand_vertex_start, r_fiber_start); } void BKE_editstrands_hair_get_texture_buffer(BMEditStrands *es, int subdiv, void *texbuffer) { EditStrandsView strands = editstrands_get_view(es); - BKE_hair_strands_get_texture_buffer(&strands.base, es->root_dm, es->hair_fibers, es->hair_totfibers, subdiv, texbuffer); + BKE_hair_strands_get_texture_buffer(&strands.base, subdiv, es->root_dm, texbuffer); } /* === Constraints === */ diff --git a/source/blender/blenkernel/intern/hair.c b/source/blender/blenkernel/intern/hair.c index 9c01fcbf788..7dc1916d29c 100644 --- a/source/blender/blenkernel/intern/hair.c +++ b/source/blender/blenkernel/intern/hair.c @@ -29,6 +29,7 @@ * \ingroup bke */ +#include <limits.h> #include <string.h> #include "MEM_guardedalloc.h" @@ -37,6 +38,7 @@ #include "BLI_kdtree.h" #include "BLI_listbase.h" #include "BLI_rand.h" +#include "BLI_sort.h" #include "BLI_string_utf8.h" #include "BLI_string_utils.h" @@ -69,12 +71,27 @@ HairPattern* BKE_hair_copy(HairPattern *hair) return nhair; } +static void hair_group_free(HairGroup *group) +{ + BKE_hair_batch_cache_free(group); + + if (group->strands_parent_index) { + MEM_freeN(group->strands_parent_index); + } + if (group->strands_parent_weight) { + MEM_freeN(group->strands_parent_weight); + } +} + void BKE_hair_free(struct HairPattern *hair) { if (hair->follicles) { MEM_freeN(hair->follicles); } + for (HairGroup *group = hair->groups.first; group; group = group->next) { + hair_group_free(group); + } BLI_freelistN(&hair->groups); MEM_freeN(hair); @@ -122,6 +139,10 @@ void BKE_hair_follicles_generate(HairPattern *hair, DerivedMesh *scalp, int coun } BKE_mesh_sample_free_generator(gen); + + BKE_hair_batch_cache_all_dirty(hair, BKE_HAIR_BATCH_DIRTY_ALL); + + BKE_hair_update_groups(hair); } HairGroup* BKE_hair_group_new(HairPattern *hair, int type) @@ -152,6 +173,8 @@ void BKE_hair_group_remove(HairPattern *hair, HairGroup *group) BLI_assert(BLI_findindex(&hair->groups, group) >= 0); BLI_remlink(&hair->groups, group); + + hair_group_free(group); MEM_freeN(group); } @@ -184,6 +207,85 @@ void BKE_hair_group_name_set(HairPattern *hair, HairGroup *group, const char *na BLI_uniquename(&hair->groups, group, DATA_("Group"), '.', offsetof(HairGroup, name), sizeof(group->name)); } +#define HAIR_FOLLICLE_GROUP_NONE INT_MAX + +static void hair_claim_group_follicle(HairGroup *group, int group_index, int *follicle_group, int i) +{ + if (follicle_group[i] == HAIR_FOLLICLE_GROUP_NONE) { + follicle_group[i] = group_index; + ++group->num_follicles; + } +} + +static void hair_group_follicles_normals(HairPattern *hair, HairGroup *group, int group_index, int *follicle_group) +{ + const int num_follicles = hair->num_follicles; + for (int i = 0; i < num_follicles; ++i) { + // claim all + hair_claim_group_follicle(group, group_index, follicle_group, i); + } +} + +static void hair_group_follicles_strands(HairPattern *hair, HairGroup *group, int group_index, int *follicle_group) +{ + // TODO + UNUSED_VARS(hair, group, group_index, follicle_group); +} + +typedef struct HairFollicleSortContext { + const HairFollicle *start; + const int *follicle_group; +} HairFollicleSortContext; + +static int cmpHairFollicleByGroup(const void *a, const void *b, void *ctx_) +{ + const HairFollicleSortContext *ctx = (const HairFollicleSortContext *)ctx_; + const size_t ia = (const HairFollicle *)a - ctx->start; + const size_t ib = (const HairFollicle *)b - ctx->start; + return ctx->follicle_group[ib] - ctx->follicle_group[ia]; +} + +void BKE_hair_update_groups(HairPattern *hair) +{ + const int num_follicles = hair->num_follicles; + int *follicle_group = MEM_mallocN(sizeof(int) * num_follicles, "hair follicle group index"); + for (int i = 0; i < num_follicles; ++i) { + follicle_group[i] = HAIR_FOLLICLE_GROUP_NONE; + } + + int group_index = 0; + for (HairGroup *group = hair->groups.first; group; group = group->next, ++group_index) { + // Note: follicles array is sorted below + if (group->prev) { + group->follicles = group->prev->follicles + group->prev->num_follicles; + } + else { + group->follicles = hair->follicles; + } + + group->num_follicles = 0; + switch (group->type) { + case HAIR_GROUP_TYPE_NORMALS: + hair_group_follicles_normals(hair, group, group_index, follicle_group); + break; + case HAIR_GROUP_TYPE_STRANDS: + hair_group_follicles_strands(hair, group, group_index, follicle_group); + break; + } + } + + { + HairFollicleSortContext ctx; + ctx.start = hair->follicles; + ctx.follicle_group = follicle_group; + BLI_qsort_r(hair->follicles, num_follicles, sizeof(HairFollicle), cmpHairFollicleByGroup, &ctx); + } + + MEM_freeN(follicle_group); + + BKE_hair_batch_cache_all_dirty(hair, BKE_HAIR_BATCH_DIRTY_ALL); +} + /* ================================= */ typedef struct HairGroupStrandsView { @@ -237,6 +339,7 @@ static void get_strand_vertices(const HairDrawDataInterface* hairdata_, float (* static HairGroupStrandsView hair_strands_get_view(HairGroup *group) { HairGroupStrandsView hairdata; + hairdata.base.group = group; hairdata.base.get_num_strands = get_num_strands; hairdata.base.get_num_verts = get_num_verts; hairdata.base.get_strand_lengths = get_strand_lengths; @@ -260,17 +363,23 @@ static HairGroupStrandsView hair_strands_get_view(HairGroup *group) return hairdata; } +int* BKE_hair_group_get_fiber_lengths(HairGroup *group, int subdiv) +{ + HairGroupStrandsView hairdata = hair_strands_get_view(group); + return BKE_hair_strands_get_fiber_lengths(&hairdata.base, subdiv); +} + void BKE_hair_group_get_texture_buffer_size(HairGroup *group, int subdiv, int *r_size, int *r_strand_map_start, int *r_strand_vertex_start, int *r_fiber_start) { HairGroupStrandsView hairdata = hair_strands_get_view(group); - BKE_hair_strands_get_texture_buffer_size(&hairdata.base, group->num_follicles, subdiv, + BKE_hair_strands_get_texture_buffer_size(&hairdata.base, subdiv, r_size, r_strand_map_start, r_strand_vertex_start, r_fiber_start); } -void BKE_hair_group_get_texture_buffer(HairGroup *group, DerivedMesh *scalp, int subdiv, void *buffer) +void BKE_hair_group_get_texture_buffer(HairGroup *group, int subdiv, DerivedMesh *scalp, void *buffer) { HairGroupStrandsView hairdata = hair_strands_get_view(group); - BKE_hair_strands_get_texture_buffer(&hairdata.base, scalp, NULL, 0, subdiv, buffer); + BKE_hair_strands_get_texture_buffer(&hairdata.base, subdiv, scalp, buffer); } diff --git a/source/blender/blenkernel/intern/hair_draw.c b/source/blender/blenkernel/intern/hair_draw.c index e64b2e8ece1..7bd88c02658 100644 --- a/source/blender/blenkernel/intern/hair_draw.c +++ b/source/blender/blenkernel/intern/hair_draw.c @@ -37,12 +37,13 @@ #include "BLI_kdtree.h" #include "BLI_rand.h" +#include "DNA_hair_types.h" + #include "BKE_DerivedMesh.h" #include "BKE_mesh_sample.h" #include "BKE_hair.h" -#include "bmesh.h" - +#if 0 bool BKE_hair_fiber_get_location(const HairFiber *fiber, DerivedMesh *root_dm, float loc[3]) { float nor[3], tang[3]; @@ -255,49 +256,74 @@ HairFiber* BKE_hair_fibers_create(const HairDrawDataInterface *hairdata, return fibers; } +#endif static int hair_get_strand_subdiv_numverts(int numstrands, int numverts, int subdiv) { return ((numverts - numstrands) << subdiv) + numstrands; } +BLI_INLINE int hair_get_strand_subdiv_length(int orig_length, int subdiv) +{ + return ((orig_length - 1) << subdiv) + 1; +} + static void hair_get_strand_subdiv_lengths(int *lengths, const int *orig_lengths, int num_strands, int subdiv) { for (int i = 0; i < num_strands; ++i) { - lengths[i] = ((orig_lengths[i] - 1) << subdiv) + 1; + lengths[i] = hair_get_strand_subdiv_length(orig_lengths[i], subdiv); } } -int* BKE_hair_strands_get_fiber_lengths(const HairFiber *fibers, int totfibers, const HairDrawDataInterface *hairdata, int subdiv) +int* BKE_hair_strands_get_fiber_lengths(const HairDrawDataInterface *hairdata, int subdiv) { + if (!hairdata->group) { + return NULL; + } + + const int totfibers = hairdata->group->num_follicles; int *fiber_length = MEM_mallocN(sizeof(int) * totfibers, "fiber length"); - - const int num_strands = hairdata->get_num_strands(hairdata); - int *lengths = MEM_mallocN(sizeof(int) * num_strands, "strand length"); - hairdata->get_strand_lengths(hairdata, lengths); - hair_get_strand_subdiv_lengths(lengths, lengths, num_strands, subdiv); - for (int i = 0; i < totfibers; ++i) { - - // Calculate the length of the fiber from the weighted average of its control strands - float fiblen = 0.0f; - for (int k = 0; k < 4; ++k) { - int si = fibers[i].parent_index[k]; - float sw = fibers[i].parent_weight[k]; - if (si == STRAND_INDEX_NONE || sw == 0.0f) { - break; + switch (hairdata->group->type) { + case HAIR_GROUP_TYPE_NORMALS: { + const int length = hair_get_strand_subdiv_length(2, subdiv); + for (int i = 0; i < totfibers; ++i) { + fiber_length[i] = length; } - BLI_assert(si < num_strands); + break; + } + case HAIR_GROUP_TYPE_STRANDS: { + const int num_strands = hairdata->get_num_strands(hairdata); + int *lengths = MEM_mallocN(sizeof(int) * num_strands, "strand length"); + hairdata->get_strand_lengths(hairdata, lengths); + hair_get_strand_subdiv_lengths(lengths, lengths, num_strands, subdiv); - fiblen += (float)lengths[si] * sw; + for (int i = 0; i < totfibers; ++i) { + // Calculate the length of the fiber from the weighted average of its control strands + float fiblen = 0.0f; + const int *parent_index = hairdata->group->strands_parent_index[i]; + const float *parent_weight = hairdata->group->strands_parent_weight[i]; + + for (int k = 0; k < 4; ++k) { + int si = parent_index[k]; + float sw = parent_weight[k]; + if (si == STRAND_INDEX_NONE || sw == 0.0f) { + break; + } + BLI_assert(si < num_strands); + + fiblen += (float)lengths[si] * sw; + } + + // use rounded number of segments + fiber_length[i] = (int)(fiblen + 0.5f); + } + + MEM_freeN(lengths); + break; } - - // use rounded number of segments - fiber_length[i] = (int)(fiblen + 0.5f); } - MEM_freeN(lengths); - return fiber_length; } @@ -483,38 +509,55 @@ static void hair_get_strand_buffer(DerivedMesh *scalp, int numstrands, int numve } } -static void hair_get_fiber_buffer(const HairFiber *fibers, int totfibers, DerivedMesh *scalp, +static void hair_get_fiber_buffer(const HairGroup *group, DerivedMesh *scalp, HairFiberTextureBuffer *fiber_buf) { - const HairFiber *fiber = fibers; + const int totfibers = group->num_follicles; HairFiberTextureBuffer *fb = fiber_buf; float nor[3], tang[3]; - for (int i = 0; i < totfibers; ++i, ++fiber, ++fb) { - memcpy(fb->parent_index, fiber->parent_index, sizeof(fb->parent_index)); - memcpy(fb->parent_weight, fiber->parent_weight, sizeof(fb->parent_weight)); - - BKE_mesh_sample_eval(scalp, &fiber->root, fb->root_position, nor, tang); + switch (group->type) { + case HAIR_GROUP_TYPE_NORMALS: { + const unsigned int parent_index[4] = {STRAND_INDEX_NONE, STRAND_INDEX_NONE, STRAND_INDEX_NONE, STRAND_INDEX_NONE}; + const float parent_weight[4] = {0.0f, 0.0f, 0.0f ,0.0f}; + for (int i = 0; i < totfibers; ++i, ++fb) { + memcpy(fb->parent_index, parent_index, sizeof(fb->parent_index)); + memcpy(fb->parent_weight, parent_weight, sizeof(fb->parent_weight)); + + BKE_mesh_sample_eval(scalp, &group->follicles[i].mesh_sample, fb->root_position, nor, tang); + } + break; + } + case HAIR_GROUP_TYPE_STRANDS: { + BLI_assert(group->strands_parent_index != NULL); + BLI_assert(group->strands_parent_weight != NULL); + for (int i = 0; i < totfibers; ++i, ++fb) { + memcpy(fb->parent_index, group->strands_parent_index[i], sizeof(fb->parent_index)); + memcpy(fb->parent_weight, group->strands_parent_weight[i], sizeof(fb->parent_weight)); + + BKE_mesh_sample_eval(scalp, &group->follicles[i].mesh_sample, fb->root_position, nor, tang); + } + break; + } } } -void BKE_hair_strands_get_texture_buffer_size(const HairDrawDataInterface *hairdata, int totfibers, int subdiv, +void BKE_hair_strands_get_texture_buffer_size(const HairDrawDataInterface *hairdata, int subdiv, int *r_size, int *r_strand_map_start, int *r_strand_vertex_start, int *r_fiber_start) { const int totstrands = hairdata->get_num_strands(hairdata); const int totverts = hairdata->get_num_verts(hairdata); - hair_get_texture_buffer_size(totstrands, totverts, subdiv, totfibers, + hair_get_texture_buffer_size(totstrands, totverts, subdiv, hairdata->group->num_follicles, r_size, r_strand_map_start, r_strand_vertex_start, r_fiber_start); } -void BKE_hair_strands_get_texture_buffer(const HairDrawDataInterface *hairdata, DerivedMesh *scalp, - const HairFiber *fibers, int totfibers, int subdiv, +void BKE_hair_strands_get_texture_buffer(const HairDrawDataInterface *hairdata, int subdiv, DerivedMesh *scalp, void *buffer) { const int totstrands = hairdata->get_num_strands(hairdata); const int totverts_orig = hairdata->get_num_verts(hairdata); int size, strand_map_start, strand_vertex_start, fiber_start; - hair_get_texture_buffer_size(totstrands, totverts_orig, subdiv, totfibers, + hair_get_texture_buffer_size(totstrands, totverts_orig, subdiv, hairdata->group->num_follicles, &size, &strand_map_start, &strand_vertex_start, &fiber_start); int *lengths_orig = MEM_mallocN(sizeof(int) * totstrands, "strand lengths"); @@ -528,10 +571,33 @@ void BKE_hair_strands_get_texture_buffer(const HairDrawDataInterface *hairdata, lengths_orig, vertco_orig, roots, (HairStrandMapTextureBuffer*)((char*)buffer + strand_map_start), (HairStrandVertexTextureBuffer*)((char*)buffer + strand_vertex_start)); - hair_get_fiber_buffer(fibers, totfibers, scalp, - (HairFiberTextureBuffer*)((char*)buffer + fiber_start)); + hair_get_fiber_buffer(hairdata->group, scalp, (HairFiberTextureBuffer*)((char*)buffer + fiber_start)); MEM_freeN(lengths_orig); MEM_freeN(vertco_orig); MEM_freeN(roots); } + +void (*BKE_hair_batch_cache_dirty_cb)(HairGroup *group, int mode) = NULL; +void (*BKE_hair_batch_cache_free_cb)(HairGroup *group) = NULL; + +void BKE_hair_batch_cache_dirty(HairGroup *group, int mode) +{ + if (group->draw_batch_cache) { + BKE_hair_batch_cache_dirty_cb(group, mode); + } +} + +void BKE_hair_batch_cache_all_dirty(struct HairPattern *hair, int mode) +{ + for (HairGroup *group = hair->groups.first; group; group = group->next) { + BKE_hair_batch_cache_dirty(group, mode); + } +} + +void BKE_hair_batch_cache_free(HairGroup *group) +{ + if (group->draw_batch_cache || group->draw_texture_cache) { + BKE_hair_batch_cache_free_cb(group); + } +} diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index c6b07c76d83..bcedcfc0f0a 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -57,6 +57,7 @@ set(SRC intern/draw_cache.c intern/draw_cache_impl_curve.c intern/draw_cache_impl_displist.c + intern/draw_cache_impl_hair.c intern/draw_cache_impl_lattice.c intern/draw_cache_impl_mesh.c intern/draw_cache_impl_particles.c diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index e91ffeaa6b8..3cc6ca81171 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -25,19 +25,23 @@ #include "DRW_render.h" -#include "DNA_world_types.h" +#include "DNA_hair_types.h" #include "DNA_modifier_types.h" #include "DNA_view3d_types.h" +#include "DNA_world_types.h" #include "BLI_dynstr.h" #include "BLI_ghash.h" #include "BLI_alloca.h" +#include "BKE_DerivedMesh.h" #include "BKE_editstrands.h" #include "BKE_particle.h" #include "BKE_paint.h" #include "BKE_pbvh.h" +#include "DEG_depsgraph.h" + #include "GPU_material.h" #include "GPU_texture.h" @@ -1003,6 +1007,219 @@ static void material_transparent( } } +static void material_particle_hair(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata, + Object *ob, ParticleSystem *psys, ModifierData *md) +{ + EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; + EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + GHash *material_hash = stl->g_data->hair_material_hash; + + if (!psys_check_enabled(ob, psys, false)) { + return; + } + + ParticleSettings *part = psys->part; + bool use_hair = false; + bool use_fibers = false; + float mat[4][4]; + struct Gwn_Batch *hair_geom = NULL; + const DRWHairFiberTextureBuffer *fiber_buffer = NULL; + GPUTexture **fiber_texture = NULL; + + if (ob->mode & OB_MODE_HAIR_EDIT) { + BMEditStrands *edit = psys->hairedit; + const HairEditSettings *tsettings = &scene->toolsettings->hair_edit; + if (edit &&tsettings->hair_draw_mode == HAIR_DRAW_FIBERS && edit->hair_group) { + use_hair = true; + use_fibers = true; + copy_m4_m4(mat, ob->obmat); + + hair_geom = DRW_cache_editstrands_get_hair_fibers(edit, true, tsettings->hair_draw_subdiv, &fiber_buffer); + + if (!edit->texture) { + edit->texture = DRW_texture_create_2D(fiber_buffer->width, fiber_buffer->height, + DRW_TEX_RG_32, 0, fiber_buffer->data); + } + fiber_texture = (GPUTexture **)(&edit->texture); + } + } + else { + int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; + if (draw_as == PART_DRAW_PATH && (psys->pathcache || psys->childcache)) { + use_hair = true; + unit_m4(mat); + hair_geom = DRW_cache_particles_get_hair(psys, md); + } + } + + if (use_hair) { + Material *ma = give_current_material(ob, part->omat); + if (ma == NULL) { + ma = &defmaterial; + } + + if (!use_fibers) { + DRW_shgroup_call_add(stl->g_data->depth_shgrp, hair_geom, mat); + DRW_shgroup_call_add(stl->g_data->depth_shgrp_clip, hair_geom, mat); + } + else { + DRW_shgroup_call_add(stl->g_data->depth_shgrp_hair_fibers, hair_geom, mat); + DRW_hair_shader_uniforms(stl->g_data->depth_shgrp_hair_fibers, scene, + fiber_texture, fiber_buffer); + + DRW_shgroup_call_add(stl->g_data->depth_shgrp_hair_fibers_clip, hair_geom, mat); + DRW_hair_shader_uniforms(stl->g_data->depth_shgrp_hair_fibers_clip, scene, + fiber_texture, fiber_buffer); + } + + DRWShadingGroup *shgrp = BLI_ghash_lookup(material_hash, (const void *)ma); + if (!shgrp) { + float *color_p = &ma->r; + float *metal_p = &ma->ray_mirror; + float *spec_p = &ma->spec; + float *rough_p = &ma->gloss_mir; + + if (ma->use_nodes && ma->nodetree) { + struct GPUMaterial *gpumat = EEVEE_material_hair_get(scene, ma, + use_fibers, stl->effects->use_ao, stl->effects->use_bent_normals); + + shgrp = DRW_shgroup_material_create(gpumat, psl->material_pass); + if (shgrp) { + add_standard_uniforms(shgrp, sldata, vedata, NULL); + + BLI_ghash_insert(material_hash, ma, shgrp); + } + else { + /* Shader failed : pink color */ + static float col[3] = {1.0f, 0.0f, 1.0f}; + static float half = 0.5f; + + color_p = col; + metal_p = spec_p = rough_p = ½ + } + } + + /* Fallback to default shader */ + if (shgrp == NULL) { + shgrp = EEVEE_default_shading_group_get(sldata, vedata, true, use_fibers, + false, stl->effects->use_ao, stl->effects->use_bent_normals, stl->effects->use_ssr); + DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1); + DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1); + DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1); + DRW_shgroup_uniform_float(shgrp, "roughness", rough_p, 1); + + BLI_ghash_insert(material_hash, ma, shgrp); + } + } + + if (shgrp) { + DRW_shgroup_call_add(shgrp, hair_geom, mat); + + if (use_fibers) { + DRW_hair_shader_uniforms(shgrp, scene, + fiber_texture, fiber_buffer); + } + } + } +} + +static void material_hair(EEVEE_SceneLayerData *sldata, EEVEE_Data *vedata, Object *ob, HairGroup *group) +{ + EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; + EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + GHash *material_hash = stl->g_data->hair_material_hash; + const HairEditSettings *tsettings = &scene->toolsettings->hair_edit; + + float mat[4][4]; + copy_m4_m4(mat, ob->obmat); + + const DRWHairFiberTextureBuffer *fiber_buffer = NULL; + struct Gwn_Batch *hair_geom; + { + DerivedMesh *scalp = NULL; + if (ob->derivedFinal) { + scalp = ob->derivedFinal; + } + else { + EvaluationContext eval_ctx = {0}; + DEG_evaluation_context_init(&eval_ctx, DAG_EVAL_VIEWPORT); + scalp = mesh_get_derived_final(&eval_ctx, scene, ob, CD_MASK_BAREMESH); + } + hair_geom = DRW_cache_hair_get_fibers(group, tsettings->hair_draw_subdiv, scalp, &fiber_buffer); + } + + if (!group->draw_texture_cache) { + group->draw_texture_cache = DRW_texture_create_2D(fiber_buffer->width, fiber_buffer->height, + DRW_TEX_RG_32, 0, fiber_buffer->data); + } + GPUTexture **fiber_texture = (GPUTexture **)(&group->draw_texture_cache); + + // TODO + Material *ma = NULL;/*give_current_material(ob, omat);*/ + if (ma == NULL) { + ma = &defmaterial; + } + + DRW_shgroup_call_add(stl->g_data->depth_shgrp_hair_fibers, hair_geom, mat); + DRW_hair_shader_uniforms(stl->g_data->depth_shgrp_hair_fibers, scene, + fiber_texture, fiber_buffer); + + DRW_shgroup_call_add(stl->g_data->depth_shgrp_hair_fibers_clip, hair_geom, mat); + DRW_hair_shader_uniforms(stl->g_data->depth_shgrp_hair_fibers_clip, scene, + fiber_texture, fiber_buffer); + + DRWShadingGroup *shgrp = BLI_ghash_lookup(material_hash, (const void *)ma); + if (!shgrp) { + float *color_p = &ma->r; + float *metal_p = &ma->ray_mirror; + float *spec_p = &ma->spec; + float *rough_p = &ma->gloss_mir; + + if (ma->use_nodes && ma->nodetree) { + struct GPUMaterial *gpumat = EEVEE_material_hair_get(scene, ma, + true, stl->effects->use_ao, stl->effects->use_bent_normals); + + shgrp = DRW_shgroup_material_create(gpumat, psl->material_pass); + if (shgrp) { + add_standard_uniforms(shgrp, sldata, vedata, NULL); + + BLI_ghash_insert(material_hash, ma, shgrp); + } + else { + /* Shader failed : pink color */ + static float col[3] = {1.0f, 0.0f, 1.0f}; + static float half = 0.5f; + + color_p = col; + metal_p = spec_p = rough_p = ½ + } + } + + /* Fallback to default shader */ + if (shgrp == NULL) { + shgrp = EEVEE_default_shading_group_get(sldata, vedata, true, true, + false, stl->effects->use_ao, stl->effects->use_bent_normals, stl->effects->use_ssr); + DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1); + DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1); + DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1); + DRW_shgroup_uniform_float(shgrp, "roughness", rough_p, 1); + + BLI_ghash_insert(material_hash, ma, shgrp); + } + } + + if (shgrp) { + DRW_shgroup_call_add(shgrp, hair_geom, mat); + + DRW_hair_shader_uniforms(shgrp, scene, + fiber_texture, fiber_buffer); + } +} + void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sldata, Object *ob) { EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; @@ -1132,116 +1349,15 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_SceneLayerData *sl if (ob->type == OB_MESH) { if (ob != draw_ctx->scene->obedit) { - material_hash = stl->g_data->hair_material_hash; - for (ModifierData *md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_ParticleSystem) { ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys; - - if (psys_check_enabled(ob, psys, false)) { - ParticleSettings *part = psys->part; - bool use_hair = false; - bool use_fibers = false; - float mat[4][4]; - struct Gwn_Batch *hair_geom = NULL; - const DRWHairFiberTextureBuffer *fiber_buffer = NULL; - GPUTexture **fiber_texture = NULL; - - if (ob->mode & OB_MODE_HAIR_EDIT) { - BMEditStrands *edit = psys->hairedit; - const HairEditSettings *tsettings = &scene->toolsettings->hair_edit; - if (edit &&tsettings->hair_draw_mode == HAIR_DRAW_FIBERS && BKE_editstrands_hair_ensure(edit)) { - use_hair = true; - use_fibers = true; - copy_m4_m4(mat, ob->obmat); - - hair_geom = DRW_cache_editstrands_get_hair_fibers(edit, true, tsettings->hair_draw_subdiv, &fiber_buffer); - - if (!edit->texture) { - edit->texture = DRW_texture_create_2D(fiber_buffer->width, fiber_buffer->height, - DRW_TEX_RG_32, 0, fiber_buffer->data); - } - fiber_texture = (GPUTexture **)(&edit->texture); - } - } - else { - int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; - if (draw_as == PART_DRAW_PATH && (psys->pathcache || psys->childcache)) { - use_hair = true; - unit_m4(mat); - hair_geom = DRW_cache_particles_get_hair(psys, md); - } - } - - if (use_hair) { - Material *ma = give_current_material(ob, part->omat); - if (ma == NULL) { - ma = &defmaterial; - } - - if (!use_fibers) { - DRW_shgroup_call_add(stl->g_data->depth_shgrp, hair_geom, mat); - DRW_shgroup_call_add(stl->g_data->depth_shgrp_clip, hair_geom, mat); - } - else { - DRW_shgroup_call_add(stl->g_data->depth_shgrp_hair_fibers, hair_geom, mat); - DRW_hair_shader_uniforms(stl->g_data->depth_shgrp_hair_fibers, scene, - fiber_texture, fiber_buffer); - - DRW_shgroup_call_add(stl->g_data->depth_shgrp_hair_fibers_clip, hair_geom, mat); - DRW_hair_shader_uniforms(stl->g_data->depth_shgrp_hair_fibers_clip, scene, - fiber_texture, fiber_buffer); - } - - DRWShadingGroup *shgrp = BLI_ghash_lookup(material_hash, (const void *)ma); - if (!shgrp) { - float *color_p = &ma->r; - float *metal_p = &ma->ray_mirror; - float *spec_p = &ma->spec; - float *rough_p = &ma->gloss_mir; - - if (ma->use_nodes && ma->nodetree) { - struct GPUMaterial *gpumat = EEVEE_material_hair_get(scene, ma, - use_fibers, stl->effects->use_ao, stl->effects->use_bent_normals); - - shgrp = DRW_shgroup_material_create(gpumat, psl->material_pass); - if (shgrp) { - add_standard_uniforms(shgrp, sldata, vedata, NULL); - - BLI_ghash_insert(material_hash, ma, shgrp); - } - else { - /* Shader failed : pink color */ - static float col[3] = {1.0f, 0.0f, 1.0f}; - static float half = 0.5f; - - color_p = col; - metal_p = spec_p = rough_p = ½ - } - } - - /* Fallback to default shader */ - if (shgrp == NULL) { - shgrp = EEVEE_default_shading_group_get(sldata, vedata, true, use_fibers, - false, stl->effects->use_ao, stl->effects->use_bent_normals, stl->effects->use_ssr); - DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1); - DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1); - DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1); - DRW_shgroup_uniform_float(shgrp, "roughness", rough_p, 1); - - BLI_ghash_insert(material_hash, ma, shgrp); - } - } - - if (shgrp) { - DRW_shgroup_call_add(shgrp, hair_geom, mat); - - if (use_fibers) { - DRW_hair_shader_uniforms(shgrp, scene, - fiber_texture, fiber_buffer); - } - } - } + material_particle_hair(sldata, vedata, ob, psys, md); + } + else if (md->type == eModifierType_Hair) { + HairModifierData *hmd = (HairModifierData *)md; + for (HairGroup *group = hmd->hair->groups.first; group; group = group->next) { + material_hair(sldata, vedata, ob, group); } } } diff --git a/source/blender/draw/engines/eevee/shaders/hair_lib.glsl b/source/blender/draw/engines/eevee/shaders/hair_lib.glsl index 0611ea5d2d9..c6a4950839b 100644 --- a/source/blender/draw/engines/eevee/shaders/hair_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/hair_lib.glsl @@ -147,10 +147,12 @@ void deform_fiber(DeformParams params, #define FIBER_RIBBON -uniform sampler2D strand_data; +uniform sampler2D fiber_data; + +uniform int fiber_start; uniform int strand_map_start; uniform int strand_vertex_start; -uniform int fiber_start; + uniform float ribbon_width; uniform vec2 viewport_size; @@ -159,7 +161,7 @@ uniform vec2 viewport_size; vec2 read_texdata(int offset) { ivec2 offset2 = ivec2(offset % HAIR_SHADER_TEX_WIDTH, offset / HAIR_SHADER_TEX_WIDTH); - return texelFetch(strand_data, offset2, 0).rg; + return texelFetch(fiber_data, offset2, 0).rg; } mat4 mat4_from_vectors(vec3 nor, vec3 tang, vec3 co) diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 7981b565089..9a4000cc0f2 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -2615,3 +2615,13 @@ Gwn_Batch *DRW_cache_editstrands_get_hair_fibers(struct BMEditStrands *es, bool { return DRW_editstrands_batch_cache_get_hair_fibers(es, use_ribbons, subdiv, r_buffer); } + +/* -------------------------------------------------------------------- */ + +/** \name Hair */ + +Gwn_Batch *DRW_cache_hair_get_fibers(struct HairGroup *group, int subdiv, struct DerivedMesh *scalp, + const struct DRWHairFiberTextureBuffer **r_buffer) +{ + return DRW_hair_batch_cache_get_fibers(group, subdiv, scalp, r_buffer); +} diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h index c536bd81084..b6853c1fd3c 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -31,7 +31,9 @@ struct GPUMaterial; struct Object; struct ModifierData; struct BMEditStrands; +struct HairGroup; struct DRWHairFiberTextureBuffer; +struct DerivedMesh; void DRW_shape_cache_free(void); @@ -167,4 +169,8 @@ struct Gwn_Batch *DRW_cache_editstrands_get_wires(struct BMEditStrands *es); struct Gwn_Batch *DRW_cache_editstrands_get_hair_fibers(struct BMEditStrands *es, bool use_ribbons, int subdiv, const struct DRWHairFiberTextureBuffer **r_buffer); +/* Hair */ +struct Gwn_Batch *DRW_cache_hair_get_fibers(struct HairGroup *group, int subdiv, struct DerivedMesh *scalp, + const struct DRWHairFiberTextureBuffer **r_buffer); + #endif /* __DRAW_CACHE_H__ */ diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index a6f4c486e2f..f026b7452df 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -33,7 +33,9 @@ struct CurveCache; struct ParticleSystem; struct ModifierData; struct BMEditStrands; +struct HairGroup; struct DRWHairFiberTextureBuffer; +struct DerivedMesh; struct Curve; struct Lattice; @@ -52,6 +54,9 @@ void DRW_lattice_batch_cache_free(struct Lattice *lt); void DRW_particle_batch_cache_dirty(struct ParticleSystem *psys, int mode); void DRW_particle_batch_cache_free(struct ParticleSystem *psys); +void DRW_hair_batch_cache_dirty(struct HairGroup *group, int mode); +void DRW_hair_batch_cache_free(struct HairGroup *group); + void DRW_editstrands_batch_cache_dirty(struct BMEditStrands *es, int mode); void DRW_editstrands_batch_cache_free(struct BMEditStrands *es); @@ -115,4 +120,8 @@ struct Gwn_Batch *DRW_editstrands_batch_cache_get_points(struct BMEditStrands *e struct Gwn_Batch *DRW_editstrands_batch_cache_get_hair_fibers(struct BMEditStrands *es, bool use_ribbons, int subdiv, const struct DRWHairFiberTextureBuffer **r_buffer); +/* Hair */ +struct Gwn_Batch *DRW_hair_batch_cache_get_fibers(struct HairGroup *group, int subdiv, struct DerivedMesh *scalp, + const struct DRWHairFiberTextureBuffer **r_buffer); + #endif /* __DRAW_CACHE_IMPL_H__ */ diff --git a/source/blender/draw/intern/draw_cache_impl_hair.c b/source/blender/draw/intern/draw_cache_impl_hair.c new file mode 100644 index 00000000000..94a22a610e1 --- /dev/null +++ b/source/blender/draw/intern/draw_cache_impl_hair.c @@ -0,0 +1,310 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017 by Blender Foundation. + * All rights reserved. + * + * Contributor(s): Blender Foundation, Mike Erwin, Dalai Felinto + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file draw_cache_impl_strands.c + * \ingroup draw + * + * \brief Strands API for render engines + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_utildefines.h" +#include "BLI_math_vector.h" +#include "BLI_ghash.h" + +#include "DNA_hair_types.h" +#include "DNA_scene_types.h" + +#include "BKE_hair.h" + +#include "GPU_batch.h" +#include "GPU_extensions.h" +#include "GPU_texture.h" + +#include "draw_common.h" +#include "draw_cache_impl.h" /* own include */ +#include "DRW_render.h" + +// timing +//#define DEBUG_TIME +#ifdef DEBUG_TIME +# include "PIL_time_utildefines.h" +#else +# define TIMEIT_START(var) +# define TIMEIT_VALUE(var) +# define TIMEIT_VALUE_PRINT(var) +# define TIMEIT_END(var) +# define TIMEIT_BENCH(expr, id) (expr) +# define TIMEIT_BLOCK_INIT(var) +# define TIMEIT_BLOCK_START(var) +# define TIMEIT_BLOCK_END(var) +# define TIMEIT_BLOCK_STATS(var) +#endif + +/* ---------------------------------------------------------------------- */ +/* Hair Gwn_Batch Cache */ + +typedef struct HairBatchCache { + Gwn_VertBuf *verts; + Gwn_IndexBuf *segments; + + Gwn_Batch *fibers; + + DRWHairFiberTextureBuffer texbuffer; + + /* settings to determine if cache is invalid */ + bool is_dirty; +} HairBatchCache; + +/* Gwn_Batch cache management. */ + +static void hair_batch_cache_clear(HairGroup *group); + +static bool hair_batch_cache_valid(HairGroup *group) +{ + HairBatchCache *cache = group->draw_batch_cache; + + if (cache == NULL) { + return false; + } + + if (cache->is_dirty) { + return false; + } + + return true; +} + +static void hair_batch_cache_init(HairGroup *group) +{ + HairBatchCache *cache = group->draw_batch_cache; + + if (!cache) { + cache = group->draw_batch_cache = MEM_callocN(sizeof(*cache), __func__); + } + else { + memset(cache, 0, sizeof(*cache)); + } + + cache->is_dirty = false; +} + +static HairBatchCache *hair_batch_cache_get(HairGroup *group) +{ + if (!hair_batch_cache_valid(group)) { + hair_batch_cache_clear(group); + hair_batch_cache_init(group); + } + return group->draw_batch_cache; +} + +void DRW_hair_batch_cache_dirty(HairGroup *group, int mode) +{ + HairBatchCache *cache = group->draw_batch_cache; + if (cache == NULL) { + return; + } + switch (mode) { + case BKE_HAIR_BATCH_DIRTY_ALL: + cache->is_dirty = true; + break; + default: + BLI_assert(0); + } +} + +static void hair_batch_cache_clear(HairGroup *group) +{ + HairBatchCache *cache = group->draw_batch_cache; + + if (group->draw_texture_cache) { + GPU_texture_free(group->draw_texture_cache); + group->draw_texture_cache = NULL; + } + + if (cache) { + GWN_BATCH_DISCARD_SAFE(cache->fibers); + GWN_VERTBUF_DISCARD_SAFE(cache->verts); + GWN_INDEXBUF_DISCARD_SAFE(cache->segments); + + { + DRWHairFiberTextureBuffer *buffer = &cache->texbuffer; + if (buffer->data) { + MEM_freeN(buffer->data); + buffer->data = NULL; + } + buffer->fiber_start = 0; + buffer->strand_map_start = 0; + buffer->strand_vertex_start = 0; + buffer->width = 0; + buffer->height = 0; + } + } +} + +void DRW_hair_batch_cache_free(HairGroup *group) +{ + hair_batch_cache_clear(group); + MEM_SAFE_FREE(group->draw_batch_cache); +} + +static void hair_batch_cache_ensure_fibers(HairGroup *group, HairBatchCache *cache, int subdiv) +{ + TIMEIT_START(hair_batch_cache_ensure_fibers); + + GWN_VERTBUF_DISCARD_SAFE(cache->verts); + GWN_INDEXBUF_DISCARD_SAFE(cache->segments); + + const int totfibers = group->num_follicles; + int *fiber_lengths = BKE_hair_group_get_fiber_lengths(group, subdiv); + int totpoint = 0; + for (int i = 0; i < totfibers; ++i) { + totpoint += fiber_lengths[i]; + } + const int totseg = totpoint - totfibers; + + static Gwn_VertFormat format = { 0 }; + static unsigned curve_param_id, fiber_index_id; + + /* initialize vertex format */ + if (format.attrib_ct == 0) { + fiber_index_id = GWN_vertformat_attr_add(&format, "fiber_index", GWN_COMP_I32, 1, GWN_FETCH_INT); + curve_param_id = GWN_vertformat_attr_add(&format, "curve_param", GWN_COMP_F32, 1, GWN_FETCH_FLOAT); + } + + cache->verts = GWN_vertbuf_create_with_format(&format); + + Gwn_IndexBufBuilder elb; + { + TIMEIT_START(data_alloc); + Gwn_PrimType prim_type; + unsigned prim_ct, vert_ct; + prim_type = GWN_PRIM_TRIS; + prim_ct = 2 * totseg; + vert_ct = 2 * totpoint; + + GWN_vertbuf_data_alloc(cache->verts, vert_ct); + GWN_indexbuf_init(&elb, prim_type, prim_ct, vert_ct); + TIMEIT_END(data_alloc); + } + + TIMEIT_START(data_fill); + TIMEIT_BLOCK_INIT(GWN_vertbuf_attr_set); + TIMEIT_BLOCK_INIT(GWN_indexbuf_add_tri_verts); + int vi = 0; + for (int i = 0; i < totfibers; ++i) { + const int fiblen = fiber_lengths[i]; + const float da = fiblen > 1 ? 1.0f / (fiblen-1) : 0.0f; + + float a = 0.0f; + for (int k = 0; k < fiblen; ++k) { + TIMEIT_BLOCK_START(GWN_vertbuf_attr_set); + GWN_vertbuf_attr_set(cache->verts, fiber_index_id, vi, &i); + GWN_vertbuf_attr_set(cache->verts, curve_param_id, vi, &a); + GWN_vertbuf_attr_set(cache->verts, fiber_index_id, vi+1, &i); + GWN_vertbuf_attr_set(cache->verts, curve_param_id, vi+1, &a); + TIMEIT_BLOCK_END(GWN_vertbuf_attr_set); + + if (k > 0) { + TIMEIT_BLOCK_START(GWN_indexbuf_add_tri_verts); + GWN_indexbuf_add_tri_verts(&elb, vi-2, vi-1, vi+1); + GWN_indexbuf_add_tri_verts(&elb, vi+1, vi, vi-2); + TIMEIT_BLOCK_END(GWN_indexbuf_add_tri_verts); + } + + vi += 2; + a += da; + } + } + TIMEIT_BLOCK_STATS(GWN_vertbuf_attr_set); + TIMEIT_BLOCK_STATS(GWN_indexbuf_add_tri_verts); +#ifdef DEBUG_TIME + printf("Total GWN time: %f\n", _timeit_var_GWN_vertbuf_attr_set + _timeit_var_GWN_indexbuf_add_tri_verts); +#endif + fflush(stdout); + TIMEIT_END(data_fill); + + MEM_freeN(fiber_lengths); + + TIMEIT_BENCH(cache->segments = GWN_indexbuf_build(&elb), indexbuf_build); + + TIMEIT_END(hair_batch_cache_ensure_fibers); +} + +static void hair_batch_cache_ensure_texbuffer(HairGroup *group, HairBatchCache *cache, int subdiv, struct DerivedMesh *scalp) +{ + DRWHairFiberTextureBuffer *buffer = &cache->texbuffer; + static const int elemsize = 8; + const int width = GPU_max_texture_size(); + const int align = width * elemsize; + + // Offsets in bytes + int b_size, b_strand_map_start, b_strand_vertex_start, b_fiber_start; + BKE_hair_group_get_texture_buffer_size(group, subdiv, &b_size, + &b_strand_map_start, &b_strand_vertex_start, &b_fiber_start); + // Pad for alignment + b_size += align - b_size % align; + + // Convert to element size as texture offsets + const int size = b_size / elemsize; + const int height = size / width; + + buffer->data = MEM_mallocN(b_size, "hair fiber texture buffer"); + BKE_hair_group_get_texture_buffer(group, subdiv, scalp, buffer->data); + + buffer->width = width; + buffer->height = height; + buffer->strand_map_start = b_strand_map_start / elemsize; + buffer->strand_vertex_start = b_strand_vertex_start / elemsize; + buffer->fiber_start = b_fiber_start / elemsize; +} + +Gwn_Batch *DRW_hair_batch_cache_get_fibers(HairGroup *group, int subdiv, struct DerivedMesh *scalp, + const DRWHairFiberTextureBuffer **r_buffer) +{ + HairBatchCache *cache = hair_batch_cache_get(group); + + TIMEIT_START(DRW_hair_batch_cache_get_fibers); + + if (cache->fibers == NULL) { + TIMEIT_BENCH(hair_batch_cache_ensure_fibers(group, cache, subdiv), + hair_batch_cache_ensure_fibers); + + TIMEIT_BENCH(cache->fibers = GWN_batch_create(GWN_PRIM_TRIS, cache->verts, cache->segments), + GWN_batch_create); + + TIMEIT_BENCH(hair_batch_cache_ensure_texbuffer(group, cache, subdiv, scalp), + hair_batch_cache_ensure_texbuffer); + } + + if (r_buffer) { + *r_buffer = &cache->texbuffer; + } + + TIMEIT_END(DRW_hair_batch_cache_get_fibers); + + return cache->fibers; +} diff --git a/source/blender/draw/intern/draw_cache_impl_strands.c b/source/blender/draw/intern/draw_cache_impl_strands.c index fc87e765001..fdf401c3641 100644 --- a/source/blender/draw/intern/draw_cache_impl_strands.c +++ b/source/blender/draw/intern/draw_cache_impl_strands.c @@ -35,6 +35,7 @@ #include "BLI_math_vector.h" #include "BLI_ghash.h" +#include "DNA_hair_types.h" #include "DNA_scene_types.h" #include "BKE_editstrands.h" @@ -390,12 +391,13 @@ static void editstrands_batch_cache_ensure_hair_fibers(BMEditStrands *es, Strand GWN_VERTBUF_DISCARD_SAFE(cache->hair.verts); GWN_INDEXBUF_DISCARD_SAFE(cache->hair.segments); + const int totfibers = es->hair_group->num_follicles; int *fiber_lengths = BKE_editstrands_hair_get_fiber_lengths(es, subdiv); int totpoint = 0; - for (int i = 0; i < es->hair_totfibers; ++i) { + for (int i = 0; i < totfibers; ++i) { totpoint += fiber_lengths[i]; } - const int totseg = totpoint - es->hair_totfibers; + const int totseg = totpoint - totfibers; static Gwn_VertFormat format = { 0 }; static unsigned curve_param_id, fiber_index_id; @@ -433,7 +435,7 @@ static void editstrands_batch_cache_ensure_hair_fibers(BMEditStrands *es, Strand TIMEIT_BLOCK_INIT(GWN_vertbuf_attr_set); TIMEIT_BLOCK_INIT(GWN_indexbuf_add_tri_verts); int vi = 0; - for (int i = 0; i < es->hair_totfibers; ++i) { + for (int i = 0; i < totfibers; ++i) { const int fiblen = fiber_lengths[i]; const float da = fiblen > 1 ? 1.0f / (fiblen-1) : 0.0f; diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c index 0a357518381..f4e5f211efe 100644 --- a/source/blender/draw/intern/draw_hair.c +++ b/source/blender/draw/intern/draw_hair.c @@ -52,7 +52,7 @@ void DRW_hair_shader_uniforms(DRWShadingGroup *shgrp, Scene *scene, DRW_shgroup_uniform_vec2(shgrp, "viewport_size", DRW_viewport_size_get(), 1); DRW_shgroup_uniform_float(shgrp, "ribbon_width", &tsettings->hair_draw_size, 1); - DRW_shgroup_uniform_buffer(shgrp, "strand_data", fibertex); + DRW_shgroup_uniform_buffer(shgrp, "fiber_data", fibertex); DRW_shgroup_uniform_int(shgrp, "strand_map_start", &texbuffer->strand_map_start, 1); DRW_shgroup_uniform_int(shgrp, "strand_vertex_start", &texbuffer->strand_vertex_start, 1); DRW_shgroup_uniform_int(shgrp, "fiber_start", &texbuffer->fiber_start, 1); diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index df08053c0b5..40f136a07f0 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -3614,6 +3614,9 @@ void DRW_engines_register(void) /* BKE: editstrands.c */ extern void *BKE_editstrands_batch_cache_dirty_cb; extern void *BKE_editstrands_batch_cache_free_cb; + /* BKE: hair.c */ + extern void *BKE_hair_batch_cache_dirty_cb; + extern void *BKE_hair_batch_cache_free_cb; BKE_curve_batch_cache_dirty_cb = DRW_curve_batch_cache_dirty; BKE_curve_batch_cache_free_cb = DRW_curve_batch_cache_free; @@ -3629,6 +3632,9 @@ void DRW_engines_register(void) BKE_editstrands_batch_cache_dirty_cb = DRW_editstrands_batch_cache_dirty; BKE_editstrands_batch_cache_free_cb = DRW_editstrands_batch_cache_free; + + BKE_hair_batch_cache_dirty_cb = DRW_hair_batch_cache_dirty; + BKE_hair_batch_cache_free_cb = DRW_hair_batch_cache_free; } } diff --git a/source/blender/editors/hair/hair_object_particles.c b/source/blender/editors/hair/hair_object_particles.c index f39ccdec6e2..3aa446db983 100644 --- a/source/blender/editors/hair/hair_object_particles.c +++ b/source/blender/editors/hair/hair_object_particles.c @@ -74,8 +74,6 @@ bool ED_hair_object_init_particle_edit(struct EvaluationContext *eval_ctx, Scene dm = NULL; psys->hairedit = BKE_editstrands_create(bm, dm); - psys->hairedit->hair_totfibers = psys->totchild; - psys->hairedit->hair_seed = psys->seed; } return true; } |