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:
authorLukas Tönne <lukas.toenne@gmail.com>2017-08-14 09:58:02 +0300
committerLukas Tönne <lukas.toenne@gmail.com>2017-08-14 09:58:02 +0300
commitb0717ad91eedb64fa23a7ac16403d3fc166e447a (patch)
treeeed9d3061d44ef55fb131140710f10017621424d
parent91fd0a487d95e604c1c245905895123eeaf2ca0e (diff)
Hair drawing data based on the new DNA hair groups.
-rw-r--r--source/blender/blenkernel/BKE_editstrands.h10
-rw-r--r--source/blender/blenkernel/BKE_hair.h40
-rw-r--r--source/blender/blenkernel/intern/editstrands.c34
-rw-r--r--source/blender/blenkernel/intern/hair.c115
-rw-r--r--source/blender/blenkernel/intern/hair_draw.c144
-rw-r--r--source/blender/draw/CMakeLists.txt1
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c332
-rw-r--r--source/blender/draw/engines/eevee/shaders/hair_lib.glsl8
-rw-r--r--source/blender/draw/intern/draw_cache.c10
-rw-r--r--source/blender/draw/intern/draw_cache.h6
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h9
-rw-r--r--source/blender/draw/intern/draw_cache_impl_hair.c310
-rw-r--r--source/blender/draw/intern/draw_cache_impl_strands.c8
-rw-r--r--source/blender/draw/intern/draw_hair.c2
-rw-r--r--source/blender/draw/intern/draw_manager.c6
-rw-r--r--source/blender/editors/hair/hair_object_particles.c2
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 = &half;
+ }
+ }
+
+ /* 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 = &half;
+ }
+ }
+
+ /* 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 = &half;
- }
- }
-
- /* 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;
}